~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/oldlibdrizzle/drizzle.cc

  • Committer: Eric Day
  • Date: 2009-09-23 19:09:31 UTC
  • mto: This revision was merged to the branch mainline in revision 1169.
  • Revision ID: eday@oddments.org-20090923190931-0xgo1un9cfwt2a2d
Client/Listen cleanup, moved globals, console plugin cleanup.

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