~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libdrizzle/drizzle.c

  • Committer: Monty
  • Date: 2008-11-07 05:51:15 UTC
  • mto: This revision was merged to the branch mainline in revision 579.
  • Revision ID: mordred@palanthas.inaugust.com-20081107055115-0275gvq62buzls77
Fixed a decimal sign thing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 Sun Microsystems, Inc.
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
 
 
20
#include <config.h>
 
21
#include <signal.h>
 
22
#include <errno.h>
 
23
 
 
24
#include <drizzled/common.h>
 
25
#include <libdrizzle/libdrizzle.h>
 
26
#include <libdrizzle/pack.h>
 
27
#include <libdrizzle/errmsg.h>
 
28
#include <libdrizzle/drizzle.h>
 
29
#include <drizzled/gettext.h>
 
30
#include <libdrizzle/net_serv.h>
 
31
#include <libdrizzle/drizzle_data.h>
 
32
#include <libdrizzle/local_infile.h>
 
33
 
 
34
#include "libdrizzle_priv.h"
 
35
 
 
36
#include <stdio.h>
 
37
#include <stdlib.h>
 
38
#include <stdarg.h>
 
39
#include <string.h>
 
40
#include <netdb.h>
 
41
#include <assert.h>
 
42
#include <pwd.h>
 
43
#include <sys/socket.h>
 
44
 
 
45
 
 
46
#define CONNECT_TIMEOUT 0
 
47
 
 
48
static bool drizzle_client_init= false;
 
49
unsigned int drizzle_server_last_errno;
 
50
 
 
51
/* Server error code and message */
 
52
char drizzle_server_last_error[LIBDRIZZLE_ERRMSG_SIZE];
 
53
 
 
54
/*
 
55
  Note that the drizzle argument must be initialized with drizzle_init()
 
56
  before calling drizzle_connect !
 
57
*/
 
58
 
 
59
 
 
60
 
 
61
static DRIZZLE_METHODS client_methods=
 
62
{
 
63
  cli_read_query_result,                       /* read_query_result */
 
64
  cli_advanced_command,                        /* advanced_command */
 
65
  cli_read_rows,                               /* read_rows */
 
66
  cli_use_result,                              /* use_result */
 
67
  cli_fetch_lengths,                           /* fetch_lengths */
 
68
  cli_flush_use_result,                        /* flush_use_result */
 
69
  cli_list_fields,                             /* list_fields */
 
70
  cli_unbuffered_fetch,                        /* unbuffered_fetch */
 
71
  cli_read_statistics,                         /* read_statistics */
 
72
  cli_read_query_result,                       /* next_result */
 
73
  cli_read_change_user_result,                 /* read_change_user_result */
 
74
};
 
75
 
 
76
 
 
77
 
 
78
/****************************************************************************
 
79
  Init DRIZZLE structure or allocate one
 
80
****************************************************************************/
 
81
 
 
82
DRIZZLE *
 
83
drizzle_create(DRIZZLE *ptr)
 
84
{
 
85
 
 
86
  if (!drizzle_client_init)
 
87
  {
 
88
    drizzle_client_init=true;
 
89
 
 
90
    if (!drizzle_get_default_port())
 
91
    {
 
92
      drizzle_set_default_port(DRIZZLE_PORT);
 
93
      {
 
94
        struct servent *serv_ptr;
 
95
        char *env;
 
96
 
 
97
        /*
 
98
          if builder specifically requested a default port, use that
 
99
          (even if it coincides with our factory default).
 
100
          only if they didn't do we check /etc/services (and, failing
 
101
          on that, fall back to the factory default of 4427).
 
102
          either default can be overridden by the environment variable
 
103
          DRIZZLE_TCP_PORT, which in turn can be overridden with command
 
104
          line options.
 
105
        */
 
106
 
 
107
#if DRIZZLE_PORT_DEFAULT == 0
 
108
        if ((serv_ptr = getservbyname("drizzle", "tcp")))
 
109
          drizzle_set_default_port((uint32_t) ntohs((uint16_t) serv_ptr->s_port));
 
110
#endif
 
111
        if ((env = getenv("DRIZZLE_TCP_PORT")))
 
112
          drizzle_set_default_port((uint32_t) atoi(env));
 
113
      }
 
114
    }
 
115
#if defined(SIGPIPE)
 
116
    (void) signal(SIGPIPE, SIG_IGN);
 
117
#endif
 
118
  }
 
119
 
 
120
  if (ptr == NULL)
 
121
  {
 
122
    ptr= (DRIZZLE *) malloc(sizeof(DRIZZLE));
 
123
 
 
124
    if (ptr == NULL)
 
125
    {
 
126
      drizzle_set_error(NULL, CR_OUT_OF_MEMORY, sqlstate_get_unknown());
 
127
      return 0;
 
128
    }
 
129
    memset(ptr, 0, sizeof(DRIZZLE));
 
130
    ptr->free_me=1;
 
131
  }
 
132
  else
 
133
  {
 
134
    memset(ptr, 0, sizeof(DRIZZLE));
 
135
  }
 
136
 
 
137
  ptr->options.connect_timeout= CONNECT_TIMEOUT;
 
138
  strcpy(ptr->net.sqlstate, sqlstate_get_not_error());
 
139
 
 
140
  /*
 
141
    Only enable LOAD DATA INFILE by default if configured with
 
142
    --enable-local-infile
 
143
  */
 
144
 
 
145
#if defined(ENABLED_LOCAL_INFILE)
 
146
  ptr->options.client_flag|= CLIENT_LOCAL_FILES;
 
147
#endif
 
148
 
 
149
  ptr->options.methods_to_use= DRIZZLE_OPT_GUESS_CONNECTION;
 
150
  ptr->options.report_data_truncation= true;  /* default */
 
151
 
 
152
  /*
 
153
    By default we don't reconnect because it could silently corrupt data (after
 
154
    reconnection you potentially lose table locks, user variables, session
 
155
    variables (transactions but they are specifically dealt with in
 
156
    drizzle_reconnect()).
 
157
    This is a change: < 5.0.3 drizzle->reconnect was set to 1 by default.
 
158
    How this change impacts existing apps:
 
159
    - existing apps which relyed on the default will see a behaviour change;
 
160
    they will have to set reconnect=1 after drizzle_connect().
 
161
    - existing apps which explicitely asked for reconnection (the only way they
 
162
    could do it was by setting drizzle.reconnect to 1 after drizzle_connect())
 
163
    will not see a behaviour change.
 
164
    - existing apps which explicitely asked for no reconnection
 
165
    (drizzle.reconnect=0) will not see a behaviour change.
 
166
  */
 
167
  ptr->reconnect= 0;
 
168
 
 
169
  return ptr;
 
170
}
 
171
 
 
172
 
 
173
static void read_user_name(char *name)
 
174
{
 
175
  if (geteuid() == 0)
 
176
    strcpy(name,"root");    /* allow use of surun */
 
177
  else
 
178
  {
 
179
#ifdef HAVE_GETPWUID
 
180
    struct passwd *skr;
 
181
    const char *str;
 
182
    if ((str=getlogin()) == NULL)
 
183
    {
 
184
      if ((skr=getpwuid(geteuid())) != NULL)
 
185
  str=skr->pw_name;
 
186
      else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
 
187
         !(str=getenv("LOGIN")))
 
188
  str="UNKNOWN_USER";
 
189
    }
 
190
    strncpy(name,str,USERNAME_LENGTH);
 
191
#elif HAVE_CUSERID
 
192
    (void) cuserid(name);
 
193
#else
 
194
    strcpy(name,"UNKNOWN_USER");
 
195
#endif
 
196
  }
 
197
  return;
 
198
}
 
199
 
 
200
DRIZZLE *
 
201
drizzle_connect(DRIZZLE *drizzle,const char *host, const char *user,
 
202
                const char *passwd, const char *db,
 
203
                uint32_t port,
 
204
                const char * unix_port __attribute__((__unused__)),
 
205
                uint32_t client_flag)
 
206
{
 
207
  char          buff[NAME_LEN+USERNAME_LENGTH+100];
 
208
  char          *end,*host_info=NULL;
 
209
  uint32_t         pkt_length;
 
210
  NET           *net= &drizzle->net;
 
211
 
 
212
  drizzle->methods= &client_methods;
 
213
  net->vio = 0;        /* If something goes wrong */
 
214
  drizzle->client_flag=0;      /* For handshake */
 
215
 
 
216
  /* Some empty-string-tests are done because of ODBC */
 
217
  if (!host || !host[0])
 
218
    host=drizzle->options.host;
 
219
  if (!user || !user[0])
 
220
  {
 
221
    user=drizzle->options.user;
 
222
    if (!user)
 
223
      user= "";
 
224
  }
 
225
  if (!passwd)
 
226
  {
 
227
    passwd=drizzle->options.password;
 
228
    if (!passwd)
 
229
      passwd= "";
 
230
  }
 
231
  if (!db || !db[0])
 
232
    db=drizzle->options.db;
 
233
  if (!port)
 
234
    port=drizzle->options.port;
 
235
 
 
236
  drizzle->server_status=SERVER_STATUS_AUTOCOMMIT;
 
237
 
 
238
  /*
 
239
    Part 0: Grab a socket and connect it to the server
 
240
  */
 
241
  if (!net->vio)
 
242
  {
 
243
    struct addrinfo *res_lst, hints, *t_res;
 
244
    int gai_errno;
 
245
    char port_buf[NI_MAXSERV];
 
246
 
 
247
    if (!port)
 
248
      port= drizzle_port;
 
249
 
 
250
    if (!host)
 
251
      host= LOCAL_HOST;
 
252
 
 
253
    snprintf(host_info=buff, sizeof(buff)-1, ER(CR_TCP_CONNECTION), host);
 
254
 
 
255
    memset(&hints, 0, sizeof(hints));
 
256
    hints.ai_socktype= SOCK_STREAM;
 
257
 
 
258
    snprintf(port_buf, NI_MAXSERV, "%d", port);
 
259
    gai_errno= getaddrinfo(host, port_buf, &hints, &res_lst);
 
260
 
 
261
    if (gai_errno != 0)
 
262
    {
 
263
      drizzle_set_extended_error(drizzle, CR_UNKNOWN_HOST, sqlstate_get_unknown(),
 
264
                                 ER(CR_UNKNOWN_HOST), host, errno);
 
265
 
 
266
      goto error;
 
267
    }
 
268
 
 
269
    for (t_res= res_lst; t_res != NULL; t_res= t_res->ai_next)
 
270
    {
 
271
      int sock= socket(t_res->ai_family, t_res->ai_socktype,
 
272
                       t_res->ai_protocol);
 
273
      if (sock < 0)
 
274
        continue;
 
275
 
 
276
      net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
 
277
      if (! net->vio )
 
278
      {
 
279
        close(sock);
 
280
        continue;
 
281
      }
 
282
 
 
283
      if (connect_with_timeout(sock, t_res->ai_addr, t_res->ai_addrlen, drizzle->options.connect_timeout))
 
284
      {
 
285
        vio_delete(net->vio);
 
286
        net->vio= 0;
 
287
        continue;
 
288
      }
 
289
      break;
 
290
    }
 
291
 
 
292
    freeaddrinfo(res_lst);
 
293
  }
 
294
 
 
295
  if (!net->vio)
 
296
  {
 
297
    drizzle_set_extended_error(drizzle, CR_CONN_HOST_ERROR, sqlstate_get_unknown(),
 
298
                               ER(CR_CONN_HOST_ERROR), host, errno);
 
299
    goto error;
 
300
  }
 
301
 
 
302
  if (my_net_init(net, net->vio))
 
303
  {
 
304
    vio_delete(net->vio);
 
305
    net->vio = 0;
 
306
    drizzle_set_error(drizzle, CR_OUT_OF_MEMORY, sqlstate_get_unknown());
 
307
    goto error;
 
308
  }
 
309
  vio_keepalive(net->vio,true);
 
310
 
 
311
  /* If user set read_timeout, let it override the default */
 
312
  if (drizzle->options.read_timeout)
 
313
    my_net_set_read_timeout(net, drizzle->options.read_timeout);
 
314
 
 
315
  /* If user set write_timeout, let it override the default */
 
316
  if (drizzle->options.write_timeout)
 
317
    my_net_set_write_timeout(net, drizzle->options.write_timeout);
 
318
 
 
319
  if (drizzle->options.max_allowed_packet)
 
320
    net->max_packet_size= drizzle->options.max_allowed_packet;
 
321
 
 
322
  /* Get version info */
 
323
  drizzle->protocol_version= PROTOCOL_VERSION;  /* Assume this */
 
324
  if (drizzle->options.connect_timeout &&
 
325
      vio_poll_read(net->vio, drizzle->options.connect_timeout))
 
326
  {
 
327
    drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
 
328
                               ER(CR_SERVER_LOST_INITIAL_COMM_WAIT),
 
329
                               errno);
 
330
    goto error;
 
331
  }
 
332
 
 
333
  /*
 
334
    Part 1: Connection established, read and parse first packet
 
335
  */
 
336
 
 
337
  if ((pkt_length=cli_safe_read(drizzle)) == packet_error)
 
338
  {
 
339
    if (drizzle->net.last_errno == CR_SERVER_LOST)
 
340
      drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
 
341
                                 ER(CR_SERVER_LOST_INITIAL_COMM_READ),
 
342
                                 errno);
 
343
    goto error;
 
344
  }
 
345
  /* Check if version of protocol matches current one */
 
346
 
 
347
  drizzle->protocol_version= net->read_pos[0];
 
348
  if (drizzle->protocol_version != PROTOCOL_VERSION)
 
349
  {
 
350
    drizzle_set_extended_error(drizzle, CR_VERSION_ERROR, sqlstate_get_unknown(),
 
351
                               ER(CR_VERSION_ERROR), drizzle->protocol_version,
 
352
                               PROTOCOL_VERSION);
 
353
    goto error;
 
354
  }
 
355
  end= strchr((char*) net->read_pos+1, '\0');
 
356
  drizzle->thread_id=uint4korr(end+1);
 
357
  end+=5;
 
358
  /*
 
359
    Scramble is split into two parts because old clients does not understand
 
360
    long scrambles; here goes the first part.
 
361
  */
 
362
  strncpy(drizzle->scramble, end, SCRAMBLE_LENGTH_323);
 
363
  end+= SCRAMBLE_LENGTH_323+1;
 
364
 
 
365
  if (pkt_length >= (uint32_t) (end+1 - (char*) net->read_pos))
 
366
    drizzle->server_capabilities=uint2korr(end);
 
367
  if (pkt_length >= (uint32_t) (end+18 - (char*) net->read_pos))
 
368
  {
 
369
    /* New protocol with 16 bytes to describe server characteristics */
 
370
    drizzle->server_language=end[2];
 
371
    drizzle->server_status=uint2korr(end+3);
 
372
  }
 
373
  end+= 18;
 
374
  if (pkt_length >= (uint32_t) (end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1 -
 
375
                            (char *) net->read_pos))
 
376
    strncpy(drizzle->scramble+SCRAMBLE_LENGTH_323, end,
 
377
            SCRAMBLE_LENGTH-SCRAMBLE_LENGTH_323);
 
378
  else
 
379
    drizzle->server_capabilities&= ~CLIENT_SECURE_CONNECTION;
 
380
 
 
381
  if (drizzle->options.secure_auth && passwd[0] &&
 
382
      !(drizzle->server_capabilities & CLIENT_SECURE_CONNECTION))
 
383
  {
 
384
    drizzle_set_error(drizzle, CR_SECURE_AUTH, sqlstate_get_unknown());
 
385
    goto error;
 
386
  }
 
387
 
 
388
  /* Save connection information */
 
389
  if (!(drizzle->host_info= (char *)malloc(strlen(host_info)+1+strlen(host)+1
 
390
                                           +(end - (char*) net->read_pos))) ||
 
391
      !(drizzle->user=strdup(user)) ||
 
392
      !(drizzle->passwd=strdup(passwd)))
 
393
  {
 
394
    drizzle_set_error(drizzle, CR_OUT_OF_MEMORY, sqlstate_get_unknown());
 
395
    goto error;
 
396
  }
 
397
  drizzle->host= drizzle->host_info+strlen(host_info)+1;
 
398
  drizzle->server_version= drizzle->host+strlen(host)+1;
 
399
  strcpy(drizzle->host_info,host_info);
 
400
  strcpy(drizzle->host,host);
 
401
  strcpy(drizzle->server_version,(char*) net->read_pos+1);
 
402
  drizzle->port=port;
 
403
 
 
404
  /*
 
405
    Part 2: format and send client info to the server for access check
 
406
  */
 
407
 
 
408
  client_flag|=drizzle->options.client_flag;
 
409
  client_flag|=CLIENT_CAPABILITIES;
 
410
  if (client_flag & CLIENT_MULTI_STATEMENTS)
 
411
    client_flag|= CLIENT_MULTI_RESULTS;
 
412
 
 
413
  if (db)
 
414
    client_flag|=CLIENT_CONNECT_WITH_DB;
 
415
 
 
416
  /* Remove options that server doesn't support */
 
417
  client_flag= ((client_flag &
 
418
                 ~(CLIENT_COMPRESS | CLIENT_SSL)) |
 
419
                (client_flag & drizzle->server_capabilities));
 
420
  client_flag&= ~CLIENT_COMPRESS;
 
421
 
 
422
  int4store(buff, client_flag);
 
423
  int4store(buff+4, net->max_packet_size);
 
424
  buff[8]= (char) 45; // utf8 charset number
 
425
  memset(buff+9, 0, 32-9);
 
426
  end= buff+32;
 
427
 
 
428
  drizzle->client_flag=client_flag;
 
429
 
 
430
  /* This needs to be changed as it's not useful with big packets */
 
431
  if (user && user[0])
 
432
    strncpy(end,user,USERNAME_LENGTH);          /* Max user name */
 
433
  else
 
434
    read_user_name((char*) end);
 
435
 
 
436
  /* We have to handle different version of handshake here */
 
437
  end= strchr(end, '\0') + 1;
 
438
  if (passwd[0])
 
439
  {
 
440
    {
 
441
      *end++= SCRAMBLE_LENGTH;
 
442
      memset(end, 0, SCRAMBLE_LENGTH-1);
 
443
      memcpy(end, passwd, strlen(passwd));
 
444
      end+= SCRAMBLE_LENGTH;
 
445
    }
 
446
  }
 
447
  else
 
448
    *end++= '\0';                               /* empty password */
 
449
 
 
450
  /* Add database if needed */
 
451
  if (db && (drizzle->server_capabilities & CLIENT_CONNECT_WITH_DB))
 
452
  {
 
453
    end= strncpy(end, db, NAME_LEN) + NAME_LEN + 1;
 
454
    drizzle->db= strdup(db);
 
455
    db= 0;
 
456
  }
 
457
  /* Write authentication package */
 
458
  if (my_net_write(net, (unsigned char*) buff, (size_t) (end-buff)) || net_flush(net))
 
459
  {
 
460
    drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
 
461
                               ER(CR_SERVER_LOST_SEND_AUTH),
 
462
                               errno);
 
463
    goto error;
 
464
  }
 
465
 
 
466
  /*
 
467
    Part 3: Authorization data's been sent. Now server can reply with
 
468
    OK-packet, or re-request scrambled password.
 
469
  */
 
470
 
 
471
  if ((pkt_length=cli_safe_read(drizzle)) == packet_error)
 
472
  {
 
473
    if (drizzle->net.last_errno == CR_SERVER_LOST)
 
474
      drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
 
475
                                 ER(CR_SERVER_LOST_READ_AUTH),
 
476
                                 errno);
 
477
    goto error;
 
478
  }
 
479
 
 
480
  if (client_flag & CLIENT_COMPRESS)    /* We will use compression */
 
481
    net->compress=1;
 
482
 
 
483
 
 
484
  if (db && drizzle_select_db(drizzle, db))
 
485
  {
 
486
    if (drizzle->net.last_errno == CR_SERVER_LOST)
 
487
      drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
 
488
                                 ER(CR_SERVER_LOST_SETTING_DB),
 
489
                                 errno);
 
490
    goto error;
 
491
  }
 
492
 
 
493
 
 
494
  return(drizzle);
 
495
 
 
496
error:
 
497
  {
 
498
    /* Free alloced memory */
 
499
    drizzle_disconnect(drizzle);
 
500
    drizzle_close_free(drizzle);
 
501
    if (!(((uint32_t) client_flag) & CLIENT_REMEMBER_OPTIONS))
 
502
      drizzle_close_free_options(drizzle);
 
503
  }
 
504
  return(0);
 
505
}
 
506
 
 
507
 
 
508
 
 
509
 
 
510
/**************************************************************************
 
511
  Set current database
 
512
**************************************************************************/
 
513
 
 
514
int
 
515
drizzle_select_db(DRIZZLE *drizzle, const char *db)
 
516
{
 
517
  int error;
 
518
 
 
519
  if ((error=simple_command(drizzle,COM_INIT_DB, (const unsigned char*) db,
 
520
                            (uint32_t) strlen(db),0)))
 
521
    return(error);
 
522
  if (drizzle->db != NULL)
 
523
    free(drizzle->db);
 
524
  drizzle->db=strdup(db);
 
525
  return(0);
 
526
}
 
527
 
 
528
bool drizzle_reconnect(DRIZZLE *drizzle)
 
529
{
 
530
  DRIZZLE tmp_drizzle;
 
531
  assert(drizzle);
 
532
 
 
533
  if (!drizzle->reconnect ||
 
534
      (drizzle->server_status & SERVER_STATUS_IN_TRANS) || !drizzle->host_info)
 
535
  {
 
536
    /* Allow reconnect next time */
 
537
    drizzle->server_status&= ~SERVER_STATUS_IN_TRANS;
 
538
    drizzle_set_error(drizzle, CR_SERVER_GONE_ERROR, sqlstate_get_unknown());
 
539
    return(1);
 
540
  }
 
541
  drizzle_create(&tmp_drizzle);
 
542
  tmp_drizzle.options= drizzle->options;
 
543
  tmp_drizzle.options.my_cnf_file= tmp_drizzle.options.my_cnf_group= 0;
 
544
 
 
545
  if (!drizzle_connect(&tmp_drizzle,drizzle->host,drizzle->user,drizzle->passwd,
 
546
                       drizzle->db, drizzle->port, 0,
 
547
                       drizzle->client_flag | CLIENT_REMEMBER_OPTIONS))
 
548
  {
 
549
    drizzle->net.last_errno= tmp_drizzle.net.last_errno;
 
550
    strcpy(drizzle->net.last_error, tmp_drizzle.net.last_error);
 
551
    strcpy(drizzle->net.sqlstate, tmp_drizzle.net.sqlstate);
 
552
    return(1);
 
553
  }
 
554
 
 
555
  tmp_drizzle.reconnect= 1;
 
556
  tmp_drizzle.free_me= drizzle->free_me;
 
557
 
 
558
  /* Don't free options as these are now used in tmp_drizzle */
 
559
  memset(&drizzle->options, 0, sizeof(drizzle->options));
 
560
  drizzle->free_me=0;
 
561
  drizzle_close(drizzle);
 
562
  *drizzle=tmp_drizzle;
 
563
  net_clear(&drizzle->net, 1);
 
564
  drizzle->affected_rows= ~(uint64_t) 0;
 
565
  return(0);
 
566
}
 
567
 
 
568
/**************************************************************************
 
569
  Shut down connection
 
570
**************************************************************************/
 
571
 
 
572
void drizzle_disconnect(DRIZZLE *drizzle)
 
573
{
 
574
  int save_errno= errno;
 
575
  if (drizzle->net.vio != 0)
 
576
  {
 
577
    vio_delete(drizzle->net.vio);
 
578
    drizzle->net.vio= 0;          /* Marker */
 
579
  }
 
580
  net_end(&drizzle->net);
 
581
  free_old_query(drizzle);
 
582
  errno= save_errno;
 
583
}
 
584
 
 
585
 
 
586
/*************************************************************************
 
587
  Send a QUIT to the server and close the connection
 
588
  If handle is alloced by DRIZZLE connect free it.
 
589
*************************************************************************/
 
590
 
 
591
void drizzle_close_free_options(DRIZZLE *drizzle)
 
592
{
 
593
  if (drizzle->options.user != NULL)
 
594
    free(drizzle->options.user);
 
595
  if (drizzle->options.host != NULL)
 
596
    free(drizzle->options.host);
 
597
  if (drizzle->options.password != NULL)
 
598
    free(drizzle->options.password);
 
599
  if (drizzle->options.db != NULL)
 
600
    free(drizzle->options.db);
 
601
  if (drizzle->options.my_cnf_file != NULL)
 
602
    free(drizzle->options.my_cnf_file);
 
603
  if (drizzle->options.my_cnf_group != NULL)
 
604
    free(drizzle->options.my_cnf_group);
 
605
  if (drizzle->options.client_ip != NULL)
 
606
    free(drizzle->options.client_ip);
 
607
  memset(&drizzle->options, 0, sizeof(drizzle->options));
 
608
  return;
 
609
}
 
610
 
 
611
 
 
612
void drizzle_close_free(DRIZZLE *drizzle)
 
613
{
 
614
  if (drizzle->host_info != NULL)
 
615
    free((unsigned char*) drizzle->host_info);
 
616
  if (drizzle->user != NULL)
 
617
    free(drizzle->user);
 
618
  if (drizzle->passwd != NULL)
 
619
    free(drizzle->passwd);
 
620
  if (drizzle->db != NULL)
 
621
    free(drizzle->db);
 
622
  if (drizzle->info_buffer != NULL)
 
623
    free(drizzle->info_buffer);
 
624
  drizzle->info_buffer= 0;
 
625
 
 
626
  /* Clear pointers for better safety */
 
627
  drizzle->host_info= drizzle->user= drizzle->passwd= drizzle->db= 0;
 
628
}
 
629
 
 
630
 
 
631
void drizzle_close(DRIZZLE *drizzle)
 
632
{
 
633
  if (drizzle)          /* Some simple safety */
 
634
  {
 
635
    /* If connection is still up, send a QUIT message */
 
636
    if (drizzle->net.vio != 0)
 
637
    {
 
638
      free_old_query(drizzle);
 
639
      drizzle->status=DRIZZLE_STATUS_READY; /* Force command */
 
640
      drizzle->reconnect=0;
 
641
      simple_command(drizzle,COM_QUIT,(unsigned char*) 0,0,1);
 
642
      drizzle_disconnect(drizzle);      /* Sets drizzle->net.vio= 0 */
 
643
    }
 
644
    drizzle_close_free_options(drizzle);
 
645
    drizzle_close_free(drizzle);
 
646
    if (drizzle->free_me)
 
647
      free((unsigned char*) drizzle);
 
648
  }
 
649
  return;
 
650
}
 
651
 
 
652
 
 
653
bool cli_read_query_result(DRIZZLE *drizzle)
 
654
{
 
655
  unsigned char *pos;
 
656
  uint32_t field_count;
 
657
  DRIZZLE_DATA *fields;
 
658
  uint32_t length;
 
659
 
 
660
  if ((length = cli_safe_read(drizzle)) == packet_error)
 
661
    return(1);
 
662
  free_old_query(drizzle);    /* Free old result */
 
663
get_info:
 
664
  pos=(unsigned char*) drizzle->net.read_pos;
 
665
  if ((field_count= net_field_length(&pos)) == 0)
 
666
  {
 
667
    drizzle->affected_rows= net_field_length_ll(&pos);
 
668
    drizzle->insert_id=    net_field_length_ll(&pos);
 
669
 
 
670
    drizzle->server_status= uint2korr(pos); pos+=2;
 
671
    drizzle->warning_count= uint2korr(pos); pos+=2;
 
672
 
 
673
    if (pos < drizzle->net.read_pos+length && net_field_length(&pos))
 
674
      drizzle->info=(char*) pos;
 
675
    return(0);
 
676
  }
 
677
  if (field_count == NULL_LENGTH)    /* LOAD DATA LOCAL INFILE */
 
678
  {
 
679
    int error;
 
680
 
 
681
    if (!(drizzle->options.client_flag & CLIENT_LOCAL_FILES))
 
682
    {
 
683
      drizzle_set_error(drizzle, CR_MALFORMED_PACKET, sqlstate_get_unknown());
 
684
      return(1);
 
685
    }
 
686
 
 
687
    error= handle_local_infile(drizzle,(char*) pos);
 
688
    if ((length= cli_safe_read(drizzle)) == packet_error || error)
 
689
      return(1);
 
690
    goto get_info;        /* Get info packet */
 
691
  }
 
692
  if (!(drizzle->server_status & SERVER_STATUS_AUTOCOMMIT))
 
693
    drizzle->server_status|= SERVER_STATUS_IN_TRANS;
 
694
 
 
695
  if (!(fields=cli_read_rows(drizzle,(DRIZZLE_FIELD*)0, 7)))
 
696
    return(1);
 
697
  if (!(drizzle->fields= unpack_fields(fields, (uint32_t) field_count, 0)))
 
698
    return(1);
 
699
  drizzle->status= DRIZZLE_STATUS_GET_RESULT;
 
700
  drizzle->field_count= (uint32_t) field_count;
 
701
  return(0);
 
702
}
 
703
 
 
704
 
 
705
/*
 
706
  Send the query and return so we can do something else.
 
707
  Needs to be followed by drizzle_read_query_result() when we want to
 
708
  finish processing it.
 
709
*/
 
710
 
 
711
int32_t
 
712
drizzle_send_query(DRIZZLE *drizzle, const char* query, uint32_t length)
 
713
{
 
714
  return(simple_command(drizzle, COM_QUERY, (unsigned char*) query, length, 1));
 
715
}
 
716
 
 
717
 
 
718
int32_t
 
719
drizzle_real_query(DRIZZLE *drizzle, const char *query, uint32_t length)
 
720
{
 
721
  if (drizzle_send_query(drizzle,query,length))
 
722
    return(1);
 
723
  return((int) (*drizzle->methods->read_query_result)(drizzle));
 
724
}
 
725
 
 
726
 
 
727
/**************************************************************************
 
728
  Alloc result struct for buffered results. All rows are read to buffer.
 
729
  drizzle_data_seek may be used.
 
730
**************************************************************************/
 
731
 
 
732
DRIZZLE_RES * drizzle_store_result(DRIZZLE *drizzle)
 
733
{
 
734
  DRIZZLE_RES *result;
 
735
 
 
736
  if (!drizzle->fields)
 
737
    return(0);
 
738
  if (drizzle->status != DRIZZLE_STATUS_GET_RESULT)
 
739
  {
 
740
    drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC, sqlstate_get_unknown());
 
741
    return(0);
 
742
  }
 
743
  drizzle->status=DRIZZLE_STATUS_READY;    /* server is ready */
 
744
  if (!(result=(DRIZZLE_RES*) malloc((uint32_t) (sizeof(DRIZZLE_RES)+
 
745
                sizeof(uint32_t) *
 
746
                drizzle->field_count))))
 
747
  {
 
748
    drizzle_set_error(drizzle, CR_OUT_OF_MEMORY, sqlstate_get_unknown());
 
749
    return(0);
 
750
  }
 
751
  memset(result, 0,(sizeof(DRIZZLE_RES)+ sizeof(uint32_t) *
 
752
                    drizzle->field_count));
 
753
  result->methods= drizzle->methods;
 
754
  result->eof= 1;        /* Marker for buffered */
 
755
  result->lengths= (uint32_t*) (result+1);
 
756
  if (!(result->data=
 
757
  (*drizzle->methods->read_rows)(drizzle,drizzle->fields,drizzle->field_count)))
 
758
  {
 
759
    free((unsigned char*) result);
 
760
    return(0);
 
761
  }
 
762
  drizzle->affected_rows= result->row_count= result->data->rows;
 
763
  result->data_cursor=  result->data->data;
 
764
  result->fields=  drizzle->fields;
 
765
  result->field_count=  drizzle->field_count;
 
766
  /* The rest of result members is zeroed in malloc */
 
767
  drizzle->fields=0;        /* fields is now in result */
 
768
  /* just in case this was mistakenly called after drizzle_stmt_execute() */
 
769
  drizzle->unbuffered_fetch_owner= 0;
 
770
  return(result);        /* Data fetched */
 
771
}
 
772
 
 
773
 
 
774
/**************************************************************************
 
775
  Alloc struct for use with unbuffered reads. Data is fetched by domand
 
776
  when calling to drizzle_fetch_row.
 
777
  DRIZZLE_DATA_seek is a noop.
 
778
 
 
779
  No other queries may be specified with the same DRIZZLE handle.
 
780
  There shouldn't be much processing per row because DRIZZLE server shouldn't
 
781
  have to wait for the client (and will not wait more than 30 sec/packet).
 
782
**************************************************************************/
 
783
 
 
784
DRIZZLE_RES * cli_use_result(DRIZZLE *drizzle)
 
785
{
 
786
  DRIZZLE_RES *result;
 
787
 
 
788
  if (!drizzle->fields)
 
789
    return(0);
 
790
  if (drizzle->status != DRIZZLE_STATUS_GET_RESULT)
 
791
  {
 
792
    drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC, sqlstate_get_unknown());
 
793
    return(0);
 
794
  }
 
795
  if (!(result=(DRIZZLE_RES*) malloc(sizeof(*result)+
 
796
                                     sizeof(uint32_t)*drizzle->field_count)))
 
797
    return(0);
 
798
  memset(result, 0, sizeof(*result)+ sizeof(uint32_t)*drizzle->field_count);
 
799
  result->lengths=(uint32_t*) (result+1);
 
800
  result->methods= drizzle->methods;
 
801
  if (!(result->row=(DRIZZLE_ROW)
 
802
        malloc(sizeof(result->row[0])*(drizzle->field_count+1))))
 
803
  {          /* Ptrs: to one row */
 
804
    free((unsigned char*) result);
 
805
    return(0);
 
806
  }
 
807
  result->fields=  drizzle->fields;
 
808
  result->field_count=  drizzle->field_count;
 
809
  result->current_field=0;
 
810
  result->handle=  drizzle;
 
811
  result->current_row=  0;
 
812
  drizzle->fields=0;      /* fields is now in result */
 
813
  drizzle->status=DRIZZLE_STATUS_USE_RESULT;
 
814
  drizzle->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled;
 
815
  return(result);      /* Data is read to be fetched */
 
816
}
 
817
 
 
818
 
 
819
 
 
820
/**
 
821
   Set the internal error message to DRIZZLE handler
 
822
 
 
823
   @param drizzle connection handle (client side)
 
824
   @param errcode  CR_ error code, passed to ER macro to get
 
825
   error text
 
826
   @parma sqlstate SQL standard sqlstate
 
827
*/
 
828
 
 
829
void drizzle_set_error(DRIZZLE *drizzle, int errcode, const char *sqlstate)
 
830
{
 
831
  NET *net;
 
832
  assert(drizzle != 0);
 
833
 
 
834
  if (drizzle)
 
835
  {
 
836
    net= &drizzle->net;
 
837
    net->last_errno= errcode;
 
838
    strcpy(net->last_error, ER(errcode));
 
839
    strcpy(net->sqlstate, sqlstate);
 
840
  }
 
841
  else
 
842
  {
 
843
    drizzle_server_last_errno= errcode;
 
844
    strcpy(drizzle_server_last_error, ER(errcode));
 
845
  }
 
846
  return;
 
847
}
 
848
 
 
849
 
 
850
unsigned int drizzle_errno(const DRIZZLE *drizzle)
 
851
{
 
852
  return drizzle ? drizzle->net.last_errno : drizzle_server_last_errno;
 
853
}
 
854
 
 
855
 
 
856
const char * drizzle_error(const DRIZZLE *drizzle)
 
857
{
 
858
  return drizzle ? _(drizzle->net.last_error) : _(drizzle_server_last_error);
 
859
}
 
860
 
 
861
/**
 
862
   Set an error message on the client.
 
863
 
 
864
   @param drizzle connection handle
 
865
   @param errcode   CR_* errcode, for client errors
 
866
   @param sqlstate  SQL standard sql state, sqlstate_get_unknown() for the
 
867
   majority of client errors.
 
868
   @param format    error message template, in sprintf format
 
869
   @param ...       variable number of arguments
 
870
*/
 
871
 
 
872
void drizzle_set_extended_error(DRIZZLE *drizzle, int errcode,
 
873
                                const char *sqlstate,
 
874
                                const char *format, ...)
 
875
{
 
876
  NET *net;
 
877
  va_list args;
 
878
  assert(drizzle != 0);
 
879
 
 
880
  net= &drizzle->net;
 
881
  net->last_errno= errcode;
 
882
  va_start(args, format);
 
883
  vsnprintf(net->last_error, sizeof(net->last_error)-1,
 
884
            format, args);
 
885
  va_end(args);
 
886
  strcpy(net->sqlstate, sqlstate);
 
887
 
 
888
  return;
 
889
}
 
890
 
 
891
 
 
892
 
 
893
/*
 
894
  Flush result set sent from server
 
895
*/
 
896
 
 
897
void cli_flush_use_result(DRIZZLE *drizzle)
 
898
{
 
899
  /* Clear the current execution status */
 
900
  for (;;)
 
901
  {
 
902
    uint32_t pkt_len;
 
903
    if ((pkt_len=cli_safe_read(drizzle)) == packet_error)
 
904
      break;
 
905
    if (pkt_len <= 8 && drizzle->net.read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA)
 
906
    {
 
907
      char *pos= (char*) drizzle->net.read_pos + 1;
 
908
      drizzle->warning_count=uint2korr(pos); pos+=2;
 
909
      drizzle->server_status=uint2korr(pos); pos+=2;
 
910
 
 
911
      break;                            /* End of data */
 
912
    }
 
913
  }
 
914
  return;
 
915
}
 
916
 
 
917
/**************************************************************************
 
918
  Get column lengths of the current row
 
919
  If one uses drizzle_use_result, res->lengths contains the length information,
 
920
  else the lengths are calculated from the offset between pointers.
 
921
**************************************************************************/
 
922
 
 
923
void cli_fetch_lengths(uint32_t *to, DRIZZLE_ROW column, uint32_t field_count)
 
924
{
 
925
  uint32_t *prev_length;
 
926
  char *start=0;
 
927
  DRIZZLE_ROW end;
 
928
 
 
929
  prev_length=0;        /* Keep gcc happy */
 
930
  for (end=column + field_count + 1 ; column != end ; column++, to++)
 
931
  {
 
932
    if (!*column)
 
933
    {
 
934
      *to= 0;          /* Null */
 
935
      continue;
 
936
    }
 
937
    if (start)          /* Found end of prev string */
 
938
      *prev_length= (uint32_t) (*column-start-1);
 
939
    start= *column;
 
940
    prev_length= to;
 
941
  }
 
942
}
 
943