~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libdrizzle/drizzle.c

  • Committer: Monty Taylor
  • Date: 2008-07-09 16:42:25 UTC
  • mto: (77.6.1 glibclient-merge)
  • mto: This revision was merged to the branch mainline in revision 112.
  • Revision ID: monty@inaugust.com-20080709164225-2r6n4j98nhxh031l
Moved test to tests... 

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
 
    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