~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libdrizzle/drizzle.c

  • Committer: Monty Taylor
  • Date: 2009-01-06 18:48:07 UTC
  • mto: This revision was merged to the branch mainline in revision 762.
  • Revision ID: mordred@inaugust.com-20090106184807-cen092lvb8mc3z4k
Enabled deadlock_innodb.

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 <drizzled/global.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_get_default_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
    size_t db_len= strlen(db);
 
454
 
 
455
    if (db_len >= NAME_LEN)
 
456
      db_len= NAME_LEN - 1;
 
457
    end= memcpy(end, db, db_len);
 
458
    end[db_len]= 0;
 
459
    end+= (db_len + 1);
 
460
 
 
461
    drizzle->db= strdup(db);
 
462
    db= 0;
 
463
  }
 
464
  /* Write authentication package */
 
465
  if (my_net_write(net, (unsigned char*) buff, (size_t) (end-buff)) || net_flush(net))
 
466
  {
 
467
    drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
 
468
                               ER(CR_SERVER_LOST_SEND_AUTH),
 
469
                               errno);
 
470
    goto error;
 
471
  }
 
472
 
 
473
  /*
 
474
    Part 3: Authorization data's been sent. Now server can reply with
 
475
    OK-packet, or re-request scrambled password.
 
476
  */
 
477
 
 
478
  if ((pkt_length=cli_safe_read(drizzle)) == packet_error)
 
479
  {
 
480
    if (drizzle->net.last_errno == CR_SERVER_LOST)
 
481
      drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
 
482
                                 ER(CR_SERVER_LOST_READ_AUTH),
 
483
                                 errno);
 
484
    goto error;
 
485
  }
 
486
 
 
487
  if (client_flag & CLIENT_COMPRESS)    /* We will use compression */
 
488
    net->compress=1;
 
489
 
 
490
 
 
491
  if (db && drizzle_select_db(drizzle, db))
 
492
  {
 
493
    if (drizzle->net.last_errno == CR_SERVER_LOST)
 
494
      drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
 
495
                                 ER(CR_SERVER_LOST_SETTING_DB),
 
496
                                 errno);
 
497
    goto error;
 
498
  }
 
499
 
 
500
 
 
501
  return(drizzle);
 
502
 
 
503
error:
 
504
  {
 
505
    /* Free alloced memory */
 
506
    drizzle_disconnect(drizzle);
 
507
    drizzle_close_free(drizzle);
 
508
    if (!(((uint32_t) client_flag) & CLIENT_REMEMBER_OPTIONS))
 
509
      drizzle_close_free_options(drizzle);
 
510
  }
 
511
  return(0);
 
512
}
 
513
 
 
514
 
 
515
 
 
516
 
 
517
/**************************************************************************
 
518
  Set current database
 
519
**************************************************************************/
 
520
 
 
521
int
 
522
drizzle_select_db(DRIZZLE *drizzle, const char *db)
 
523
{
 
524
  int error;
 
525
 
 
526
  if ((error=simple_command(drizzle,COM_INIT_DB, (const unsigned char*) db,
 
527
                            (uint32_t) strlen(db),0)))
 
528
    return(error);
 
529
  if (drizzle->db != NULL)
 
530
    free(drizzle->db);
 
531
  drizzle->db=strdup(db);
 
532
  return(0);
 
533
}
 
534
 
 
535
bool drizzle_reconnect(DRIZZLE *drizzle)
 
536
{
 
537
  DRIZZLE tmp_drizzle;
 
538
  assert(drizzle);
 
539
 
 
540
  if (!drizzle->reconnect ||
 
541
      (drizzle->server_status & SERVER_STATUS_IN_TRANS) || !drizzle->host_info)
 
542
  {
 
543
    /* Allow reconnect next time */
 
544
    drizzle->server_status&= ~SERVER_STATUS_IN_TRANS;
 
545
    drizzle_set_error(drizzle, CR_SERVER_GONE_ERROR, sqlstate_get_unknown());
 
546
    return(1);
 
547
  }
 
548
  drizzle_create(&tmp_drizzle);
 
549
  tmp_drizzle.options= drizzle->options;
 
550
  tmp_drizzle.options.my_cnf_file= tmp_drizzle.options.my_cnf_group= 0;
 
551
 
 
552
  if (!drizzle_connect(&tmp_drizzle,drizzle->host,drizzle->user,drizzle->passwd,
 
553
                       drizzle->db, drizzle->port, 0,
 
554
                       drizzle->client_flag | CLIENT_REMEMBER_OPTIONS))
 
555
  {
 
556
    drizzle->net.last_errno= tmp_drizzle.net.last_errno;
 
557
    strcpy(drizzle->net.last_error, tmp_drizzle.net.last_error);
 
558
    strcpy(drizzle->net.sqlstate, tmp_drizzle.net.sqlstate);
 
559
    return(1);
 
560
  }
 
561
 
 
562
  tmp_drizzle.reconnect= 1;
 
563
  tmp_drizzle.free_me= drizzle->free_me;
 
564
 
 
565
  /* Don't free options as these are now used in tmp_drizzle */
 
566
  memset(&drizzle->options, 0, sizeof(drizzle->options));
 
567
  drizzle->free_me=0;
 
568
  drizzle_close(drizzle);
 
569
  *drizzle=tmp_drizzle;
 
570
  net_clear(&drizzle->net, 1);
 
571
  drizzle->affected_rows= ~(uint64_t) 0;
 
572
  return(0);
 
573
}
 
574
 
 
575
/**************************************************************************
 
576
  Shut down connection
 
577
**************************************************************************/
 
578
 
 
579
void drizzle_disconnect(DRIZZLE *drizzle)
 
580
{
 
581
  int save_errno= errno;
 
582
  if (drizzle->net.vio != 0)
 
583
  {
 
584
    vio_delete(drizzle->net.vio);
 
585
    drizzle->net.vio= 0;          /* Marker */
 
586
  }
 
587
  net_end(&drizzle->net);
 
588
  free_old_query(drizzle);
 
589
  errno= save_errno;
 
590
}
 
591
 
 
592
 
 
593
/*************************************************************************
 
594
  Send a QUIT to the server and close the connection
 
595
  If handle is alloced by DRIZZLE connect free it.
 
596
*************************************************************************/
 
597
 
 
598
void drizzle_close_free_options(DRIZZLE *drizzle)
 
599
{
 
600
  if (drizzle->options.user != NULL)
 
601
    free(drizzle->options.user);
 
602
  if (drizzle->options.host != NULL)
 
603
    free(drizzle->options.host);
 
604
  if (drizzle->options.password != NULL)
 
605
    free(drizzle->options.password);
 
606
  if (drizzle->options.db != NULL)
 
607
    free(drizzle->options.db);
 
608
  if (drizzle->options.my_cnf_file != NULL)
 
609
    free(drizzle->options.my_cnf_file);
 
610
  if (drizzle->options.my_cnf_group != NULL)
 
611
    free(drizzle->options.my_cnf_group);
 
612
  if (drizzle->options.client_ip != NULL)
 
613
    free(drizzle->options.client_ip);
 
614
  memset(&drizzle->options, 0, sizeof(drizzle->options));
 
615
  return;
 
616
}
 
617
 
 
618
 
 
619
void drizzle_close_free(DRIZZLE *drizzle)
 
620
{
 
621
  if (drizzle->host_info != NULL)
 
622
    free((unsigned char*) drizzle->host_info);
 
623
  if (drizzle->user != NULL)
 
624
    free(drizzle->user);
 
625
  if (drizzle->passwd != NULL)
 
626
    free(drizzle->passwd);
 
627
  if (drizzle->db != NULL)
 
628
    free(drizzle->db);
 
629
  if (drizzle->info_buffer != NULL)
 
630
    free(drizzle->info_buffer);
 
631
  drizzle->info_buffer= 0;
 
632
 
 
633
  /* Clear pointers for better safety */
 
634
  drizzle->host_info= drizzle->user= drizzle->passwd= drizzle->db= 0;
 
635
}
 
636
 
 
637
 
 
638
void drizzle_close(DRIZZLE *drizzle)
 
639
{
 
640
  if (drizzle)          /* Some simple safety */
 
641
  {
 
642
    /* If connection is still up, send a QUIT message */
 
643
    if (drizzle->net.vio != 0)
 
644
    {
 
645
      free_old_query(drizzle);
 
646
      drizzle->status=DRIZZLE_STATUS_READY; /* Force command */
 
647
      drizzle->reconnect=0;
 
648
      simple_command(drizzle,COM_QUIT,(unsigned char*) 0,0,1);
 
649
      drizzle_disconnect(drizzle);      /* Sets drizzle->net.vio= 0 */
 
650
    }
 
651
    drizzle_close_free_options(drizzle);
 
652
    drizzle_close_free(drizzle);
 
653
    if (drizzle->free_me)
 
654
      free((unsigned char*) drizzle);
 
655
  }
 
656
  return;
 
657
}
 
658
 
 
659
 
 
660
bool cli_read_query_result(DRIZZLE *drizzle)
 
661
{
 
662
  unsigned char *pos;
 
663
  uint32_t field_count;
 
664
  DRIZZLE_DATA *fields;
 
665
  uint32_t length;
 
666
 
 
667
  if ((length = cli_safe_read(drizzle)) == packet_error)
 
668
    return(1);
 
669
  free_old_query(drizzle);    /* Free old result */
 
670
get_info:
 
671
  pos=(unsigned char*) drizzle->net.read_pos;
 
672
  if ((field_count= net_field_length(&pos)) == 0)
 
673
  {
 
674
    drizzle->affected_rows= net_field_length_ll(&pos);
 
675
    drizzle->insert_id=    net_field_length_ll(&pos);
 
676
 
 
677
    drizzle->server_status= uint2korr(pos); pos+=2;
 
678
    drizzle->warning_count= uint2korr(pos); pos+=2;
 
679
 
 
680
    if (pos < drizzle->net.read_pos+length && net_field_length(&pos))
 
681
      drizzle->info=(char*) pos;
 
682
    return(0);
 
683
  }
 
684
  if (field_count == NULL_LENGTH)    /* LOAD DATA LOCAL INFILE */
 
685
  {
 
686
    int error;
 
687
 
 
688
    if (!(drizzle->options.client_flag & CLIENT_LOCAL_FILES))
 
689
    {
 
690
      drizzle_set_error(drizzle, CR_MALFORMED_PACKET, sqlstate_get_unknown());
 
691
      return(1);
 
692
    }
 
693
 
 
694
    error= handle_local_infile(drizzle,(char*) pos);
 
695
    if ((length= cli_safe_read(drizzle)) == packet_error || error)
 
696
      return(1);
 
697
    goto get_info;        /* Get info packet */
 
698
  }
 
699
  if (!(drizzle->server_status & SERVER_STATUS_AUTOCOMMIT))
 
700
    drizzle->server_status|= SERVER_STATUS_IN_TRANS;
 
701
 
 
702
  if (!(fields=cli_read_rows(drizzle,(DRIZZLE_FIELD*)0, 7)))
 
703
    return(1);
 
704
  if (!(drizzle->fields= unpack_fields(fields, (uint32_t) field_count, 0)))
 
705
    return(1);
 
706
  drizzle->status= DRIZZLE_STATUS_GET_RESULT;
 
707
  drizzle->field_count= (uint32_t) field_count;
 
708
  return(0);
 
709
}
 
710
 
 
711
 
 
712
/*
 
713
  Send the query and return so we can do something else.
 
714
  Needs to be followed by drizzle_read_query_result() when we want to
 
715
  finish processing it.
 
716
*/
 
717
 
 
718
int32_t
 
719
drizzle_send_query(DRIZZLE *drizzle, const char* query, uint32_t length)
 
720
{
 
721
  return(simple_command(drizzle, COM_QUERY, (unsigned char*) query, length, 1));
 
722
}
 
723
 
 
724
 
 
725
int32_t
 
726
drizzle_real_query(DRIZZLE *drizzle, const char *query, uint32_t length)
 
727
{
 
728
  if (drizzle_send_query(drizzle,query,length))
 
729
    return(1);
 
730
  return((int) (*drizzle->methods->read_query_result)(drizzle));
 
731
}
 
732
 
 
733
 
 
734
/**************************************************************************
 
735
  Alloc result struct for buffered results. All rows are read to buffer.
 
736
  drizzle_data_seek may be used.
 
737
**************************************************************************/
 
738
 
 
739
DRIZZLE_RES * drizzle_store_result(DRIZZLE *drizzle)
 
740
{
 
741
  DRIZZLE_RES *result;
 
742
 
 
743
  if (!drizzle->fields)
 
744
    return(0);
 
745
  if (drizzle->status != DRIZZLE_STATUS_GET_RESULT)
 
746
  {
 
747
    drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC, sqlstate_get_unknown());
 
748
    return(0);
 
749
  }
 
750
  drizzle->status=DRIZZLE_STATUS_READY;    /* server is ready */
 
751
  if (!(result=(DRIZZLE_RES*) malloc((uint32_t) (sizeof(DRIZZLE_RES)+
 
752
                sizeof(uint32_t) *
 
753
                drizzle->field_count))))
 
754
  {
 
755
    drizzle_set_error(drizzle, CR_OUT_OF_MEMORY, sqlstate_get_unknown());
 
756
    return(0);
 
757
  }
 
758
  memset(result, 0,(sizeof(DRIZZLE_RES)+ sizeof(uint32_t) *
 
759
                    drizzle->field_count));
 
760
  result->methods= drizzle->methods;
 
761
  result->eof= 1;        /* Marker for buffered */
 
762
  result->lengths= (uint32_t*) (result+1);
 
763
  if (!(result->data=
 
764
  (*drizzle->methods->read_rows)(drizzle,drizzle->fields,drizzle->field_count)))
 
765
  {
 
766
    free((unsigned char*) result);
 
767
    return(0);
 
768
  }
 
769
  drizzle->affected_rows= result->row_count= result->data->rows;
 
770
  result->data_cursor=  result->data->data;
 
771
  result->fields=  drizzle->fields;
 
772
  result->field_count=  drizzle->field_count;
 
773
  /* The rest of result members is zeroed in malloc */
 
774
  drizzle->fields=0;        /* fields is now in result */
 
775
  /* just in case this was mistakenly called after drizzle_stmt_execute() */
 
776
  drizzle->unbuffered_fetch_owner= 0;
 
777
  return(result);        /* Data fetched */
 
778
}
 
779
 
 
780
 
 
781
/**************************************************************************
 
782
  Alloc struct for use with unbuffered reads. Data is fetched by domand
 
783
  when calling to drizzle_fetch_row.
 
784
  DRIZZLE_DATA_seek is a noop.
 
785
 
 
786
  No other queries may be specified with the same DRIZZLE handle.
 
787
  There shouldn't be much processing per row because DRIZZLE server shouldn't
 
788
  have to wait for the client (and will not wait more than 30 sec/packet).
 
789
**************************************************************************/
 
790
 
 
791
DRIZZLE_RES * cli_use_result(DRIZZLE *drizzle)
 
792
{
 
793
  DRIZZLE_RES *result;
 
794
 
 
795
  if (!drizzle->fields)
 
796
    return(0);
 
797
  if (drizzle->status != DRIZZLE_STATUS_GET_RESULT)
 
798
  {
 
799
    drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC, sqlstate_get_unknown());
 
800
    return(0);
 
801
  }
 
802
  if (!(result=(DRIZZLE_RES*) malloc(sizeof(*result)+
 
803
                                     sizeof(uint32_t)*drizzle->field_count)))
 
804
    return(0);
 
805
  memset(result, 0, sizeof(*result)+ sizeof(uint32_t)*drizzle->field_count);
 
806
  result->lengths=(uint32_t*) (result+1);
 
807
  result->methods= drizzle->methods;
 
808
  if (!(result->row=(DRIZZLE_ROW)
 
809
        malloc(sizeof(result->row[0])*(drizzle->field_count+1))))
 
810
  {          /* Ptrs: to one row */
 
811
    free((unsigned char*) result);
 
812
    return(0);
 
813
  }
 
814
  result->fields=  drizzle->fields;
 
815
  result->field_count=  drizzle->field_count;
 
816
  result->current_field=0;
 
817
  result->handle=  drizzle;
 
818
  result->current_row=  0;
 
819
  drizzle->fields=0;      /* fields is now in result */
 
820
  drizzle->status=DRIZZLE_STATUS_USE_RESULT;
 
821
  drizzle->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled;
 
822
  return(result);      /* Data is read to be fetched */
 
823
}
 
824
 
 
825
 
 
826
 
 
827
/**
 
828
   Set the internal error message to DRIZZLE handler
 
829
 
 
830
   @param drizzle connection handle (client side)
 
831
   @param errcode  CR_ error code, passed to ER macro to get
 
832
   error text
 
833
   @parma sqlstate SQL standard sqlstate
 
834
*/
 
835
 
 
836
void drizzle_set_error(DRIZZLE *drizzle, int errcode, const char *sqlstate)
 
837
{
 
838
  NET *net;
 
839
  assert(drizzle != 0);
 
840
 
 
841
  if (drizzle)
 
842
  {
 
843
    net= &drizzle->net;
 
844
    net->last_errno= errcode;
 
845
    strcpy(net->last_error, ER(errcode));
 
846
    strcpy(net->sqlstate, sqlstate);
 
847
  }
 
848
  else
 
849
  {
 
850
    drizzle_server_last_errno= errcode;
 
851
    strcpy(drizzle_server_last_error, ER(errcode));
 
852
  }
 
853
  return;
 
854
}
 
855
 
 
856
 
 
857
unsigned int drizzle_errno(const DRIZZLE *drizzle)
 
858
{
 
859
  return drizzle ? drizzle->net.last_errno : drizzle_server_last_errno;
 
860
}
 
861
 
 
862
 
 
863
const char * drizzle_error(const DRIZZLE *drizzle)
 
864
{
 
865
  return drizzle ? _(drizzle->net.last_error) : _(drizzle_server_last_error);
 
866
}
 
867
 
 
868
/**
 
869
   Set an error message on the client.
 
870
 
 
871
   @param drizzle connection handle
 
872
   @param errcode   CR_* errcode, for client errors
 
873
   @param sqlstate  SQL standard sql state, sqlstate_get_unknown() for the
 
874
   majority of client errors.
 
875
   @param format    error message template, in sprintf format
 
876
   @param ...       variable number of arguments
 
877
*/
 
878
 
 
879
void drizzle_set_extended_error(DRIZZLE *drizzle, int errcode,
 
880
                                const char *sqlstate,
 
881
                                const char *format, ...)
 
882
{
 
883
  NET *net;
 
884
  va_list args;
 
885
  assert(drizzle != 0);
 
886
 
 
887
  net= &drizzle->net;
 
888
  net->last_errno= errcode;
 
889
  va_start(args, format);
 
890
  vsnprintf(net->last_error, sizeof(net->last_error)-1,
 
891
            format, args);
 
892
  va_end(args);
 
893
  strcpy(net->sqlstate, sqlstate);
 
894
 
 
895
  return;
 
896
}
 
897
 
 
898
 
 
899
 
 
900
/*
 
901
  Flush result set sent from server
 
902
*/
 
903
 
 
904
void cli_flush_use_result(DRIZZLE *drizzle)
 
905
{
 
906
  /* Clear the current execution status */
 
907
  for (;;)
 
908
  {
 
909
    uint32_t pkt_len;
 
910
    if ((pkt_len=cli_safe_read(drizzle)) == packet_error)
 
911
      break;
 
912
    if (pkt_len <= 8 && drizzle->net.read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA)
 
913
    {
 
914
      char *pos= (char*) drizzle->net.read_pos + 1;
 
915
      drizzle->warning_count=uint2korr(pos); pos+=2;
 
916
      drizzle->server_status=uint2korr(pos); pos+=2;
 
917
 
 
918
      break;                            /* End of data */
 
919
    }
 
920
  }
 
921
  return;
 
922
}
 
923
 
 
924
/**************************************************************************
 
925
  Get column lengths of the current row
 
926
  If one uses drizzle_use_result, res->lengths contains the length information,
 
927
  else the lengths are calculated from the offset between pointers.
 
928
**************************************************************************/
 
929
 
 
930
void cli_fetch_lengths(uint32_t *to, DRIZZLE_ROW column, uint32_t field_count)
 
931
{
 
932
  uint32_t *prev_length;
 
933
  char *start=0;
 
934
  DRIZZLE_ROW end;
 
935
 
 
936
  prev_length=0;        /* Keep gcc happy */
 
937
  for (end=column + field_count + 1 ; column != end ; column++, to++)
 
938
  {
 
939
    if (!*column)
 
940
    {
 
941
      *to= 0;          /* Null */
 
942
      continue;
 
943
    }
 
944
    if (start)          /* Found end of prev string */
 
945
      *prev_length= (uint32_t) (*column-start-1);
 
946
    start= *column;
 
947
    prev_length= to;
 
948
  }
 
949
}
 
950