~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/oldlibdrizzle/drizzle.cc

  • Committer: Monty Taylor
  • Date: 2009-10-06 19:37:52 UTC
  • mto: This revision was merged to the branch mainline in revision 1184.
  • Revision ID: mordred@inaugust.com-20091006193752-4dx2c8u35j4em79g
Removed more server_includes.h from headers.

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