~drizzle-trunk/drizzle/development

390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
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 <config.h>
492.3.25 by Lee
Changes to get drizzle building on Solaris 10 (SPARC)
21
#include <signal.h>
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
22
543 by Monty Taylor
Renamed drizzle_common again. Removed sql_common. (empty)
23
#include <drizzled/common.h>
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
24
#include <libdrizzle/libdrizzle.h>
542 by Monty Taylor
Cleaned up the last commit.
25
#include <libdrizzle/pack.h>
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
26
#include <libdrizzle/errmsg.h>
27
#include <libdrizzle/drizzle.h>
538 by Monty Taylor
Moved gettext.h into drizzled in anticipation of the new client lib.
28
#include <drizzled/gettext.h>
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
29
#include <libdrizzle/net_serv.h>
30
#include <libdrizzle/drizzle_data.h>
31
#include <libdrizzle/local_infile.h>
32
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
33
#include "libdrizzle_priv.h"
34
35
#include <vio/violite.h>
36
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <stdarg.h>
40
#include <string.h>
41
#include <netdb.h>
42
#include <assert.h>
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
43
#include <pwd.h>
44
#include <sys/socket.h>
45
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
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[DRIZZLE_ERRMSG_SIZE];
54
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
55
/*
56
  Note that the drizzle argument must be initialized with drizzle_init()
57
  before calling drizzle_connect !
58
*/
59
60
61
62
static DRIZZLE_METHODS client_methods=
63
{
64
  cli_read_query_result,                       /* read_query_result */
65
  cli_advanced_command,                        /* advanced_command */
66
  cli_read_rows,                               /* read_rows */
67
  cli_use_result,                              /* use_result */
68
  cli_fetch_lengths,                           /* fetch_lengths */
69
  cli_flush_use_result,                        /* flush_use_result */
70
  cli_list_fields,                             /* list_fields */
71
  cli_unbuffered_fetch,                        /* unbuffered_fetch */
72
  cli_read_statistics,                         /* read_statistics */
73
  cli_read_query_result,                       /* next_result */
74
  cli_read_change_user_result,                 /* read_change_user_result */
75
};
76
77
78
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
79
/****************************************************************************
80
  Init DRIZZLE structure or allocate one
81
****************************************************************************/
82
83
DRIZZLE *
84
drizzle_create(DRIZZLE *ptr)
85
{
86
87
  if (!drizzle_client_init)
88
  {
89
    drizzle_client_init=true;
90
91
    if (!drizzle_get_default_port())
92
    {
93
      drizzle_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")))
395 by Brian Aker
Fixed uint/ushort issue in libdrizzle
110
          drizzle_set_default_port((uint32_t) ntohs((uint16_t) serv_ptr->s_port));
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
111
#endif
112
        if ((env = getenv("DRIZZLE_TCP_PORT")))
395 by Brian Aker
Fixed uint/ushort issue in libdrizzle
113
          drizzle_set_default_port((uint32_t) atoi(env));
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
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
    {
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
127
      drizzle_set_error(NULL, CR_OUT_OF_MEMORY, sqlstate_get_unknown());
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
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;
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
139
  strcpy(ptr->net.sqlstate, sqlstate_get_not_error());
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
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
    drizzle_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 drizzle_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 drizzle_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
}
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
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
drizzle_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 __attribute__((__unused__)),
206
                uint32_t client_flag)
207
{
208
  char          buff[NAME_LEN+USERNAME_LENGTH+100];
209
  char          *end,*host_info=NULL;
210
  uint32_t         pkt_length;
211
  NET           *net= &drizzle->net;
212
213
  drizzle->methods= &client_methods;
214
  net->vio = 0;        /* If something goes wrong */
215
  drizzle->client_flag=0;      /* For handshake */
216
217
  /* Some empty-string-tests are done because of ODBC */
218
  if (!host || !host[0])
219
    host=drizzle->options.host;
220
  if (!user || !user[0])
221
  {
222
    user=drizzle->options.user;
223
    if (!user)
224
      user= "";
225
  }
226
  if (!passwd)
227
  {
228
    passwd=drizzle->options.password;
229
    if (!passwd)
230
      passwd= "";
231
  }
232
  if (!db || !db[0])
233
    db=drizzle->options.db;
234
  if (!port)
235
    port=drizzle->options.port;
236
237
  drizzle->server_status=SERVER_STATUS_AUTOCOMMIT;
238
239
  /*
240
    Part 0: Grab a socket and connect it to the server
241
  */
242
  if (!net->vio)
243
  {
244
    struct addrinfo *res_lst, hints, *t_res;
245
    int gai_errno;
246
    char port_buf[NI_MAXSERV];
247
248
    if (!port)
249
      port= drizzle_port;
250
251
    if (!host)
252
      host= LOCAL_HOST;
253
254
    snprintf(host_info=buff, sizeof(buff)-1, ER(CR_TCP_CONNECTION), host);
255
256
    memset(&hints, 0, sizeof(hints));
257
    hints.ai_socktype= SOCK_STREAM;
258
259
    snprintf(port_buf, NI_MAXSERV, "%d", port);
260
    gai_errno= getaddrinfo(host, port_buf, &hints, &res_lst);
261
262
    if (gai_errno != 0)
263
    {
264
      drizzle_set_extended_error(drizzle, CR_UNKNOWN_HOST, sqlstate_get_unknown(),
265
                                 ER(CR_UNKNOWN_HOST), host, errno);
266
267
      goto error;
268
    }
269
270
    for (t_res= res_lst; t_res != NULL; t_res= t_res->ai_next)
271
    {
272
      int sock= socket(t_res->ai_family, t_res->ai_socktype,
273
                       t_res->ai_protocol);
274
      if (sock < 0)
275
        continue;
276
277
      net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
278
      if (! net->vio )
279
      {
280
        close(sock);
281
        continue;
282
      }
283
284
      if (connect_with_timeout(sock, t_res->ai_addr, t_res->ai_addrlen, drizzle->options.connect_timeout))
285
      {
286
        vio_delete(net->vio);
287
        net->vio= 0;
288
        continue;
289
      }
290
      break;
291
    }
292
293
    freeaddrinfo(res_lst);
294
  }
295
296
  if (!net->vio)
297
  {
298
    drizzle_set_extended_error(drizzle, CR_CONN_HOST_ERROR, sqlstate_get_unknown(),
299
                               ER(CR_CONN_HOST_ERROR), host, errno);
300
    goto error;
301
  }
302
303
  if (my_net_init(net, net->vio))
304
  {
305
    vio_delete(net->vio);
306
    net->vio = 0;
307
    drizzle_set_error(drizzle, CR_OUT_OF_MEMORY, sqlstate_get_unknown());
308
    goto error;
309
  }
310
  vio_keepalive(net->vio,true);
311
312
  /* If user set read_timeout, let it override the default */
313
  if (drizzle->options.read_timeout)
314
    my_net_set_read_timeout(net, drizzle->options.read_timeout);
315
316
  /* If user set write_timeout, let it override the default */
317
  if (drizzle->options.write_timeout)
318
    my_net_set_write_timeout(net, drizzle->options.write_timeout);
319
320
  if (drizzle->options.max_allowed_packet)
321
    net->max_packet_size= drizzle->options.max_allowed_packet;
322
323
  /* Get version info */
324
  drizzle->protocol_version= PROTOCOL_VERSION;  /* Assume this */
325
  if (drizzle->options.connect_timeout &&
326
      vio_poll_read(net->vio, drizzle->options.connect_timeout))
327
  {
328
    drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
329
                               ER(CR_SERVER_LOST_INITIAL_COMM_WAIT),
330
                               errno);
331
    goto error;
332
  }
333
334
  /*
335
    Part 1: Connection established, read and parse first packet
336
  */
337
338
  if ((pkt_length=cli_safe_read(drizzle)) == packet_error)
339
  {
340
    if (drizzle->net.last_errno == CR_SERVER_LOST)
341
      drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
342
                                 ER(CR_SERVER_LOST_INITIAL_COMM_READ),
343
                                 errno);
344
    goto error;
345
  }
346
  /* Check if version of protocol matches current one */
347
348
  drizzle->protocol_version= net->read_pos[0];
349
  if (drizzle->protocol_version != PROTOCOL_VERSION)
350
  {
351
    drizzle_set_extended_error(drizzle, CR_VERSION_ERROR, sqlstate_get_unknown(),
352
                               ER(CR_VERSION_ERROR), drizzle->protocol_version,
353
                               PROTOCOL_VERSION);
354
    goto error;
355
  }
356
  end= strchr((char*) net->read_pos+1, '\0');
357
  drizzle->thread_id=uint4korr(end+1);
358
  end+=5;
359
  /*
360
    Scramble is split into two parts because old clients does not understand
361
    long scrambles; here goes the first part.
362
  */
363
  strncpy(drizzle->scramble, end, SCRAMBLE_LENGTH_323);
364
  end+= SCRAMBLE_LENGTH_323+1;
365
395 by Brian Aker
Fixed uint/ushort issue in libdrizzle
366
  if (pkt_length >= (uint32_t) (end+1 - (char*) net->read_pos))
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
367
    drizzle->server_capabilities=uint2korr(end);
395 by Brian Aker
Fixed uint/ushort issue in libdrizzle
368
  if (pkt_length >= (uint32_t) (end+18 - (char*) net->read_pos))
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
369
  {
370
    /* New protocol with 16 bytes to describe server characteristics */
371
    drizzle->server_language=end[2];
372
    drizzle->server_status=uint2korr(end+3);
373
  }
374
  end+= 18;
395 by Brian Aker
Fixed uint/ushort issue in libdrizzle
375
  if (pkt_length >= (uint32_t) (end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1 -
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
376
                            (char *) net->read_pos))
377
    strncpy(drizzle->scramble+SCRAMBLE_LENGTH_323, end,
378
            SCRAMBLE_LENGTH-SCRAMBLE_LENGTH_323);
379
  else
380
    drizzle->server_capabilities&= ~CLIENT_SECURE_CONNECTION;
381
382
  if (drizzle->options.secure_auth && passwd[0] &&
383
      !(drizzle->server_capabilities & CLIENT_SECURE_CONNECTION))
384
  {
385
    drizzle_set_error(drizzle, CR_SECURE_AUTH, sqlstate_get_unknown());
386
    goto error;
387
  }
388
389
  /* Save connection information */
390
  if (!(drizzle->host_info= (char *)malloc(strlen(host_info)+1+strlen(host)+1
391
                                           +(end - (char*) net->read_pos))) ||
392
      !(drizzle->user=strdup(user)) ||
393
      !(drizzle->passwd=strdup(passwd)))
394
  {
395
    drizzle_set_error(drizzle, CR_OUT_OF_MEMORY, sqlstate_get_unknown());
396
    goto error;
397
  }
398
  drizzle->host= drizzle->host_info+strlen(host_info)+1;
399
  drizzle->server_version= drizzle->host+strlen(host)+1;
400
  strcpy(drizzle->host_info,host_info);
401
  strcpy(drizzle->host,host);
402
  strcpy(drizzle->server_version,(char*) net->read_pos+1);
403
  drizzle->port=port;
404
405
  /*
406
    Part 2: format and send client info to the server for access check
407
  */
408
409
  client_flag|=drizzle->options.client_flag;
410
  client_flag|=CLIENT_CAPABILITIES;
411
  if (client_flag & CLIENT_MULTI_STATEMENTS)
412
    client_flag|= CLIENT_MULTI_RESULTS;
413
414
  if (db)
415
    client_flag|=CLIENT_CONNECT_WITH_DB;
416
417
  /* Remove options that server doesn't support */
418
  client_flag= ((client_flag &
419
                 ~(CLIENT_COMPRESS | CLIENT_SSL)) |
420
                (client_flag & drizzle->server_capabilities));
421
  client_flag&= ~CLIENT_COMPRESS;
422
423
  int4store(buff, client_flag);
424
  int4store(buff+4, net->max_packet_size);
425
  buff[8]= (char) 45; // utf8 charset number
426
  memset(buff+9, 0, 32-9);
427
  end= buff+32;
428
429
  drizzle->client_flag=client_flag;
430
431
  /* This needs to be changed as it's not useful with big packets */
432
  if (user && user[0])
433
    strncpy(end,user,USERNAME_LENGTH);          /* Max user name */
434
  else
435
    read_user_name((char*) end);
436
437
  /* We have to handle different version of handshake here */
438
  end= strchr(end, '\0') + 1;
439
  if (passwd[0])
440
  {
441
    {
442
      *end++= SCRAMBLE_LENGTH;
443
      memset(end, 0, SCRAMBLE_LENGTH-1);
444
      memcpy(end, passwd, strlen(passwd));
445
      end+= SCRAMBLE_LENGTH;
446
    }
447
  }
448
  else
449
    *end++= '\0';                               /* empty password */
450
451
  /* Add database if needed */
452
  if (db && (drizzle->server_capabilities & CLIENT_CONNECT_WITH_DB))
453
  {
454
    end= strncpy(end, db, NAME_LEN) + NAME_LEN + 1;
455
    drizzle->db= strdup(db);
456
    db= 0;
457
  }
458
  /* Write authentication package */
459
  if (my_net_write(net, (unsigned char*) buff, (size_t) (end-buff)) || net_flush(net))
460
  {
461
    drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
462
                               ER(CR_SERVER_LOST_SEND_AUTH),
463
                               errno);
464
    goto error;
465
  }
466
467
  /*
468
    Part 3: Authorization data's been sent. Now server can reply with
469
    OK-packet, or re-request scrambled password.
470
  */
471
472
  if ((pkt_length=cli_safe_read(drizzle)) == packet_error)
473
  {
474
    if (drizzle->net.last_errno == CR_SERVER_LOST)
475
      drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
476
                                 ER(CR_SERVER_LOST_READ_AUTH),
477
                                 errno);
478
    goto error;
479
  }
480
481
  if (client_flag & CLIENT_COMPRESS)    /* We will use compression */
482
    net->compress=1;
483
484
485
  if (db && drizzle_select_db(drizzle, db))
486
  {
487
    if (drizzle->net.last_errno == CR_SERVER_LOST)
488
      drizzle_set_extended_error(drizzle, CR_SERVER_LOST, sqlstate_get_unknown(),
489
                                 ER(CR_SERVER_LOST_SETTING_DB),
490
                                 errno);
491
    goto error;
492
  }
493
494
495
  return(drizzle);
496
497
error:
498
  {
499
    /* Free alloced memory */
500
    drizzle_disconnect(drizzle);
501
    drizzle_close_free(drizzle);
502
    if (!(((uint32_t) client_flag) & CLIENT_REMEMBER_OPTIONS))
503
      drizzle_close_free_options(drizzle);
504
  }
505
  return(0);
506
}
507
508
509
510
511
/**************************************************************************
512
  Set current database
513
**************************************************************************/
514
515
int
516
drizzle_select_db(DRIZZLE *drizzle, const char *db)
517
{
518
  int error;
519
520
  if ((error=simple_command(drizzle,COM_INIT_DB, (const unsigned char*) db,
521
                            (uint32_t) strlen(db),0)))
522
    return(error);
523
  if (drizzle->db != NULL)
524
    free(drizzle->db);
525
  drizzle->db=strdup(db);
526
  return(0);
527
}
528
529
bool drizzle_reconnect(DRIZZLE *drizzle)
530
{
531
  DRIZZLE tmp_drizzle;
532
  assert(drizzle);
533
534
  if (!drizzle->reconnect ||
535
      (drizzle->server_status & SERVER_STATUS_IN_TRANS) || !drizzle->host_info)
536
  {
537
    /* Allow reconnect next time */
538
    drizzle->server_status&= ~SERVER_STATUS_IN_TRANS;
539
    drizzle_set_error(drizzle, CR_SERVER_GONE_ERROR, sqlstate_get_unknown());
540
    return(1);
541
  }
542
  drizzle_create(&tmp_drizzle);
543
  tmp_drizzle.options= drizzle->options;
544
  tmp_drizzle.options.my_cnf_file= tmp_drizzle.options.my_cnf_group= 0;
545
546
  if (!drizzle_connect(&tmp_drizzle,drizzle->host,drizzle->user,drizzle->passwd,
547
                       drizzle->db, drizzle->port, 0,
548
                       drizzle->client_flag | CLIENT_REMEMBER_OPTIONS))
549
  {
550
    drizzle->net.last_errno= tmp_drizzle.net.last_errno;
551
    strcpy(drizzle->net.last_error, tmp_drizzle.net.last_error);
552
    strcpy(drizzle->net.sqlstate, tmp_drizzle.net.sqlstate);
553
    return(1);
554
  }
555
556
  tmp_drizzle.reconnect= 1;
557
  tmp_drizzle.free_me= drizzle->free_me;
558
559
  /* Don't free options as these are now used in tmp_drizzle */
560
  memset(&drizzle->options, 0, sizeof(drizzle->options));
561
  drizzle->free_me=0;
562
  drizzle_close(drizzle);
563
  *drizzle=tmp_drizzle;
564
  net_clear(&drizzle->net, 1);
565
  drizzle->affected_rows= ~(uint64_t) 0;
566
  return(0);
567
}
568
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
569
/**************************************************************************
570
  Shut down connection
571
**************************************************************************/
572
573
void drizzle_disconnect(DRIZZLE *drizzle)
574
{
575
  int save_errno= errno;
576
  if (drizzle->net.vio != 0)
577
  {
578
    vio_delete(drizzle->net.vio);
579
    drizzle->net.vio= 0;          /* Marker */
580
  }
581
  net_end(&drizzle->net);
582
  free_old_query(drizzle);
583
  errno= save_errno;
584
}
585
586
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
587
/*************************************************************************
588
  Send a QUIT to the server and close the connection
589
  If handle is alloced by DRIZZLE connect free it.
590
*************************************************************************/
591
592
void drizzle_close_free_options(DRIZZLE *drizzle)
593
{
594
  if (drizzle->options.user != NULL)
595
    free(drizzle->options.user);
596
  if (drizzle->options.host != NULL)
597
    free(drizzle->options.host);
598
  if (drizzle->options.password != NULL)
599
    free(drizzle->options.password);
600
  if (drizzle->options.db != NULL)
601
    free(drizzle->options.db);
602
  if (drizzle->options.my_cnf_file != NULL)
603
    free(drizzle->options.my_cnf_file);
604
  if (drizzle->options.my_cnf_group != NULL)
605
    free(drizzle->options.my_cnf_group);
606
  if (drizzle->options.client_ip != NULL)
607
    free(drizzle->options.client_ip);
608
  memset(&drizzle->options, 0, sizeof(drizzle->options));
609
  return;
610
}
611
612
613
void drizzle_close_free(DRIZZLE *drizzle)
614
{
615
  if (drizzle->host_info != NULL)
616
    free((unsigned char*) drizzle->host_info);
617
  if (drizzle->user != NULL)
618
    free(drizzle->user);
619
  if (drizzle->passwd != NULL)
620
    free(drizzle->passwd);
621
  if (drizzle->db != NULL)
622
    free(drizzle->db);
623
  if (drizzle->info_buffer != NULL)
624
    free(drizzle->info_buffer);
625
  drizzle->info_buffer= 0;
626
627
  /* Clear pointers for better safety */
628
  drizzle->host_info= drizzle->user= drizzle->passwd= drizzle->db= 0;
629
}
630
631
632
void drizzle_close(DRIZZLE *drizzle)
633
{
634
  if (drizzle)          /* Some simple safety */
635
  {
636
    /* If connection is still up, send a QUIT message */
637
    if (drizzle->net.vio != 0)
638
    {
639
      free_old_query(drizzle);
640
      drizzle->status=DRIZZLE_STATUS_READY; /* Force command */
641
      drizzle->reconnect=0;
642
      simple_command(drizzle,COM_QUIT,(unsigned char*) 0,0,1);
643
      drizzle_disconnect(drizzle);      /* Sets drizzle->net.vio= 0 */
644
    }
645
    drizzle_close_free_options(drizzle);
646
    drizzle_close_free(drizzle);
647
    if (drizzle->free_me)
648
      free((unsigned char*) drizzle);
649
  }
650
  return;
651
}
652
653
654
bool cli_read_query_result(DRIZZLE *drizzle)
655
{
656
  unsigned char *pos;
657
  uint32_t field_count;
658
  DRIZZLE_DATA *fields;
659
  uint32_t length;
660
661
  if ((length = cli_safe_read(drizzle)) == packet_error)
662
    return(1);
663
  free_old_query(drizzle);    /* Free old result */
664
get_info:
665
  pos=(unsigned char*) drizzle->net.read_pos;
666
  if ((field_count= net_field_length(&pos)) == 0)
667
  {
668
    drizzle->affected_rows= net_field_length_ll(&pos);
669
    drizzle->insert_id=    net_field_length_ll(&pos);
670
671
    drizzle->server_status= uint2korr(pos); pos+=2;
672
    drizzle->warning_count= uint2korr(pos); pos+=2;
673
674
    if (pos < drizzle->net.read_pos+length && net_field_length(&pos))
675
      drizzle->info=(char*) pos;
676
    return(0);
677
  }
678
  if (field_count == NULL_LENGTH)    /* LOAD DATA LOCAL INFILE */
679
  {
680
    int error;
681
682
    if (!(drizzle->options.client_flag & CLIENT_LOCAL_FILES))
683
    {
684
      drizzle_set_error(drizzle, CR_MALFORMED_PACKET, sqlstate_get_unknown());
685
      return(1);
686
    }
687
688
    error= handle_local_infile(drizzle,(char*) pos);
689
    if ((length= cli_safe_read(drizzle)) == packet_error || error)
690
      return(1);
691
    goto get_info;        /* Get info packet */
692
  }
693
  if (!(drizzle->server_status & SERVER_STATUS_AUTOCOMMIT))
694
    drizzle->server_status|= SERVER_STATUS_IN_TRANS;
695
696
  if (!(fields=cli_read_rows(drizzle,(DRIZZLE_FIELD*)0, 7)))
697
    return(1);
395 by Brian Aker
Fixed uint/ushort issue in libdrizzle
698
  if (!(drizzle->fields= unpack_fields(fields, (uint32_t) field_count, 0)))
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
699
    return(1);
700
  drizzle->status= DRIZZLE_STATUS_GET_RESULT;
395 by Brian Aker
Fixed uint/ushort issue in libdrizzle
701
  drizzle->field_count= (uint32_t) field_count;
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
702
  return(0);
703
}
704
705
706
/*
707
  Send the query and return so we can do something else.
708
  Needs to be followed by drizzle_read_query_result() when we want to
709
  finish processing it.
710
*/
711
712
int32_t
713
drizzle_send_query(DRIZZLE *drizzle, const char* query, uint32_t length)
714
{
715
  return(simple_command(drizzle, COM_QUERY, (unsigned char*) query, length, 1));
716
}
717
718
719
int32_t
720
drizzle_real_query(DRIZZLE *drizzle, const char *query, uint32_t length)
721
{
722
  if (drizzle_send_query(drizzle,query,length))
723
    return(1);
724
  return((int) (*drizzle->methods->read_query_result)(drizzle));
725
}
726
727
728
/**************************************************************************
729
  Alloc result struct for buffered results. All rows are read to buffer.
730
  drizzle_data_seek may be used.
731
**************************************************************************/
732
733
DRIZZLE_RES * drizzle_store_result(DRIZZLE *drizzle)
734
{
735
  DRIZZLE_RES *result;
736
737
  if (!drizzle->fields)
738
    return(0);
739
  if (drizzle->status != DRIZZLE_STATUS_GET_RESULT)
740
  {
741
    drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC, sqlstate_get_unknown());
742
    return(0);
743
  }
744
  drizzle->status=DRIZZLE_STATUS_READY;    /* server is ready */
395 by Brian Aker
Fixed uint/ushort issue in libdrizzle
745
  if (!(result=(DRIZZLE_RES*) malloc((uint32_t) (sizeof(DRIZZLE_RES)+
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
746
                sizeof(uint32_t) *
747
                drizzle->field_count))))
748
  {
749
    drizzle_set_error(drizzle, CR_OUT_OF_MEMORY, sqlstate_get_unknown());
750
    return(0);
751
  }
752
  memset(result, 0,(sizeof(DRIZZLE_RES)+ sizeof(uint32_t) *
753
                    drizzle->field_count));
754
  result->methods= drizzle->methods;
755
  result->eof= 1;        /* Marker for buffered */
756
  result->lengths= (uint32_t*) (result+1);
757
  if (!(result->data=
758
  (*drizzle->methods->read_rows)(drizzle,drizzle->fields,drizzle->field_count)))
759
  {
760
    free((unsigned char*) result);
761
    return(0);
762
  }
763
  drizzle->affected_rows= result->row_count= result->data->rows;
764
  result->data_cursor=  result->data->data;
765
  result->fields=  drizzle->fields;
766
  result->field_count=  drizzle->field_count;
767
  /* The rest of result members is zeroed in malloc */
768
  drizzle->fields=0;        /* fields is now in result */
769
  /* just in case this was mistakenly called after drizzle_stmt_execute() */
770
  drizzle->unbuffered_fetch_owner= 0;
771
  return(result);        /* Data fetched */
772
}
773
774
775
/**************************************************************************
776
  Alloc struct for use with unbuffered reads. Data is fetched by domand
777
  when calling to drizzle_fetch_row.
778
  DRIZZLE_DATA_seek is a noop.
779
780
  No other queries may be specified with the same DRIZZLE handle.
781
  There shouldn't be much processing per row because DRIZZLE server shouldn't
782
  have to wait for the client (and will not wait more than 30 sec/packet).
783
**************************************************************************/
784
785
DRIZZLE_RES * cli_use_result(DRIZZLE *drizzle)
786
{
787
  DRIZZLE_RES *result;
788
789
  if (!drizzle->fields)
790
    return(0);
791
  if (drizzle->status != DRIZZLE_STATUS_GET_RESULT)
792
  {
793
    drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC, sqlstate_get_unknown());
794
    return(0);
795
  }
796
  if (!(result=(DRIZZLE_RES*) malloc(sizeof(*result)+
797
                                     sizeof(uint32_t)*drizzle->field_count)))
798
    return(0);
799
  memset(result, 0, sizeof(*result)+ sizeof(uint32_t)*drizzle->field_count);
800
  result->lengths=(uint32_t*) (result+1);
801
  result->methods= drizzle->methods;
802
  if (!(result->row=(DRIZZLE_ROW)
803
        malloc(sizeof(result->row[0])*(drizzle->field_count+1))))
804
  {          /* Ptrs: to one row */
805
    free((unsigned char*) result);
806
    return(0);
807
  }
808
  result->fields=  drizzle->fields;
809
  result->field_count=  drizzle->field_count;
810
  result->current_field=0;
811
  result->handle=  drizzle;
812
  result->current_row=  0;
813
  drizzle->fields=0;      /* fields is now in result */
814
  drizzle->status=DRIZZLE_STATUS_USE_RESULT;
815
  drizzle->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled;
816
  return(result);      /* Data is read to be fetched */
817
}
818
819
820
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
821
/**
822
   Set the internal error message to DRIZZLE handler
823
824
   @param drizzle connection handle (client side)
825
   @param errcode  CR_ error code, passed to ER macro to get
826
   error text
827
   @parma sqlstate SQL standard sqlstate
828
*/
829
830
void drizzle_set_error(DRIZZLE *drizzle, int errcode, const char *sqlstate)
831
{
832
  NET *net;
833
  assert(drizzle != 0);
834
835
  if (drizzle)
836
  {
837
    net= &drizzle->net;
838
    net->last_errno= errcode;
839
    strcpy(net->last_error, ER(errcode));
840
    strcpy(net->sqlstate, sqlstate);
841
  }
842
  else
843
  {
844
    drizzle_server_last_errno= errcode;
845
    strcpy(drizzle_server_last_error, ER(errcode));
846
  }
847
  return;
848
}
849
850
851
unsigned int drizzle_errno(const DRIZZLE *drizzle)
852
{
853
  return drizzle ? drizzle->net.last_errno : drizzle_server_last_errno;
854
}
855
856
857
const char * drizzle_error(const DRIZZLE *drizzle)
858
{
859
  return drizzle ? _(drizzle->net.last_error) : _(drizzle_server_last_error);
860
}
861
862
/**
863
   Set an error message on the client.
864
865
   @param drizzle connection handle
866
   @param errcode   CR_* errcode, for client errors
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
867
   @param sqlstate  SQL standard sql state, sqlstate_get_unknown() for the
390.1.5 by Monty Taylor
Moved more functions into drizzle.c as part of the split of code.
868
   majority of client errors.
869
   @param format    error message template, in sprintf format
870
   @param ...       variable number of arguments
871
*/
872
873
void drizzle_set_extended_error(DRIZZLE *drizzle, int errcode,
874
                                const char *sqlstate,
875
                                const char *format, ...)
876
{
877
  NET *net;
878
  va_list args;
879
  assert(drizzle != 0);
880
881
  net= &drizzle->net;
882
  net->last_errno= errcode;
883
  va_start(args, format);
884
  vsnprintf(net->last_error, sizeof(net->last_error)-1,
885
            format, args);
886
  va_end(args);
887
  strcpy(net->sqlstate, sqlstate);
888
889
  return;
890
}
390.1.6 by Monty Taylor
Oh dear god the changes. The changes. I'd tell you what they are, but I'd just be making stuff up. Suffice it to day it's mostly all around splitting files in libdrizzle into different files and removing interdepends. And whatever else I happened to see...
891
892
893
894
/*
895
  Flush result set sent from server
896
*/
897
898
void cli_flush_use_result(DRIZZLE *drizzle)
899
{
900
  /* Clear the current execution status */
901
  for (;;)
902
  {
903
    uint32_t pkt_len;
904
    if ((pkt_len=cli_safe_read(drizzle)) == packet_error)
905
      break;
906
    if (pkt_len <= 8 && drizzle->net.read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA)
907
    {
908
      char *pos= (char*) drizzle->net.read_pos + 1;
909
      drizzle->warning_count=uint2korr(pos); pos+=2;
910
      drizzle->server_status=uint2korr(pos); pos+=2;
911
912
      break;                            /* End of data */
913
    }
914
  }
915
  return;
916
}
917
918
/**************************************************************************
919
  Get column lengths of the current row
920
  If one uses drizzle_use_result, res->lengths contains the length information,
921
  else the lengths are calculated from the offset between pointers.
922
**************************************************************************/
923
924
void cli_fetch_lengths(uint32_t *to, DRIZZLE_ROW column, uint32_t field_count)
925
{
926
  uint32_t *prev_length;
927
  char *start=0;
928
  DRIZZLE_ROW end;
929
930
  prev_length=0;        /* Keep gcc happy */
931
  for (end=column + field_count + 1 ; column != end ; column++, to++)
932
  {
933
    if (!*column)
934
    {
935
      *to= 0;          /* Null */
936
      continue;
937
    }
938
    if (start)          /* Found end of prev string */
939
      *prev_length= (uint32_t) (*column-start-1);
940
    start= *column;
941
    prev_length= to;
942
  }
943
}
944