~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libdrizzleclient/drizzle.c

  • Committer: Jay Pipes
  • Date: 2009-02-28 17:49:22 UTC
  • mto: (910.2.6 mordred-noatomics)
  • mto: This revision was merged to the branch mainline in revision 908.
  • Revision ID: jpipes@serialcoder-20090228174922-jczgt4d0662fqmnf
Merging in old r902 temporal changes

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