~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libdrizzle/libdrizzle.c

  • Committer: Monty Taylor
  • Date: 2008-11-16 05:36:13 UTC
  • mto: (584.1.9 devel)
  • mto: This revision was merged to the branch mainline in revision 589.
  • Revision ID: monty@inaugust.com-20081116053613-bld4rqxhlkb49c02
Split out cache_row and type_holder.

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 <config.h>
 
21
#include "libdrizzle_priv.h"
 
22
 
 
23
#include <libdrizzle/libdrizzle.h>
 
24
#include <libdrizzle/pack.h>
 
25
#include <libdrizzle/errmsg.h>
 
26
#include <sys/stat.h>
 
27
#include <signal.h>
 
28
#include <time.h>
 
29
#ifdef   HAVE_PWD_H
 
30
#include <pwd.h>
 
31
#endif
 
32
 
 
33
#include <sys/socket.h>
 
34
#include <netinet/in.h>
 
35
#include <arpa/inet.h>
 
36
#include <netdb.h>
 
37
#ifdef HAVE_SELECT_H
 
38
#include <select.h>
 
39
#endif
 
40
#ifdef HAVE_SYS_SELECT_H
 
41
#include <sys/select.h>
 
42
#endif
 
43
 
 
44
#ifdef HAVE_POLL
 
45
#include <sys/poll.h>
 
46
#endif
 
47
#ifdef HAVE_SYS_UN_H
 
48
#include <sys/un.h>
 
49
#endif
 
50
#ifndef INADDR_NONE
 
51
#define INADDR_NONE  -1
 
52
#endif
 
53
 
 
54
#include <stdlib.h>
 
55
#include <string.h>
 
56
 
 
57
/* Borrowed from libicu header */
 
58
 
 
59
#define U8_IS_SINGLE(c) (((c)&0x80)==0)
 
60
#define U8_LENGTH(c) \
 
61
    ((uint32_t)(c)<=0x7f ? 1 : \
 
62
        ((uint32_t)(c)<=0x7ff ? 2 : \
 
63
            ((uint32_t)(c)<=0xd7ff ? 3 : \
 
64
                ((uint32_t)(c)<=0xdfff || (uint32_t)(c)>0x10ffff ? 0 : \
 
65
                    ((uint32_t)(c)<=0xffff ? 3 : 4)\
 
66
                ) \
 
67
            ) \
 
68
        ) \
 
69
    )
 
70
 
 
71
 
 
72
#undef net_buffer_length
 
73
#undef max_allowed_packet
 
74
 
 
75
uint32_t     net_buffer_length= 8192;
 
76
uint32_t    max_allowed_packet= 1024L*1024L*1024L;
 
77
 
 
78
unsigned int drizzle_port=0;
 
79
 
 
80
#include <errno.h>
 
81
 
 
82
 
 
83
static DRIZZLE_PARAMETERS drizzle_internal_parameters=
 
84
{&max_allowed_packet, &net_buffer_length, 0};
 
85
 
 
86
const DRIZZLE_PARAMETERS * drizzle_get_parameters(void)
 
87
{
 
88
  return &drizzle_internal_parameters;
 
89
}
 
90
 
 
91
unsigned int drizzle_get_default_port(void)
 
92
{
 
93
  return drizzle_port;
 
94
}
 
95
 
 
96
void drizzle_set_default_port(unsigned int port)
 
97
{
 
98
  drizzle_port= port;
 
99
}
 
100
 
 
101
/*
 
102
  Expand wildcard to a sql string
 
103
*/
 
104
 
 
105
static void
 
106
append_wild(char *to, char *end, const char *wild)
 
107
{
 
108
  end-=5;          /* Some extra */
 
109
  if (wild && wild[0])
 
110
  {
 
111
    to= strcpy(to," like '");
 
112
    to+= 7; /* strlen(" like '"); */
 
113
 
 
114
    while (*wild && to < end)
 
115
    {
 
116
      if (*wild == '\\' || *wild == '\'')
 
117
  *to++='\\';
 
118
      *to++= *wild++;
 
119
    }
 
120
    if (*wild)          /* Too small buffer */
 
121
      *to++='%';        /* Nicer this way */
 
122
    to[0]='\'';
 
123
    to[1]=0;
 
124
  }
 
125
}
 
126
 
 
127
/**************************************************************************
 
128
  Change user and database
 
129
**************************************************************************/
 
130
 
 
131
int cli_read_change_user_result(DRIZZLE *drizzle)
 
132
{
 
133
  uint32_t pkt_length;
 
134
 
 
135
  pkt_length= cli_safe_read(drizzle);
 
136
  
 
137
  if (pkt_length == packet_error)
 
138
    return 1;
 
139
 
 
140
  return 0;
 
141
}
 
142
 
 
143
bool drizzle_change_user(DRIZZLE *drizzle, const char *user,
 
144
                                 const char *passwd, const char *db)
 
145
{
 
146
  char buff[USERNAME_LENGTH+SCRAMBLED_PASSWORD_CHAR_LENGTH+NAME_LEN+2];
 
147
  char *end= buff;
 
148
  int rc;
 
149
 
 
150
  /* Use an empty string instead of NULL. */
 
151
 
 
152
  if (!user)
 
153
    user="";
 
154
  if (!passwd)
 
155
    passwd="";
 
156
 
 
157
  /* Store user into the buffer */
 
158
  end= strncpy(end, user, USERNAME_LENGTH) + USERNAME_LENGTH + 1;
 
159
 
 
160
  /* write scrambled password according to server capabilities */
 
161
  if (passwd[0])
 
162
  {
 
163
    {
 
164
      *end++= SCRAMBLE_LENGTH;
 
165
      end+= SCRAMBLE_LENGTH;
 
166
    }
 
167
  }
 
168
  else
 
169
    *end++= '\0';                               /* empty password */
 
170
  /* Add database if needed */
 
171
  end= strncpy(end, db ? db : "", NAME_LEN) + NAME_LEN + 1;
 
172
 
 
173
  /* Add character set number. */
 
174
  if (drizzle->server_capabilities & CLIENT_SECURE_CONNECTION)
 
175
  {
 
176
    int2store(end, (uint16_t) 45); // utf8mb4 number from mystrings/ctype-utf8.c
 
177
    end+= 2;
 
178
  }
 
179
 
 
180
  /* Write authentication package */
 
181
  (void)simple_command(drizzle,COM_CHANGE_USER, (unsigned char*) buff, (uint32_t) (end-buff), 1);
 
182
 
 
183
  rc= (*drizzle->methods->read_change_user_result)(drizzle);
 
184
 
 
185
  if (rc == 0)
 
186
  {
 
187
    /* Free old connect information */
 
188
    if(drizzle->user)
 
189
      free(drizzle->user);
 
190
    if(drizzle->passwd)
 
191
      free(drizzle->passwd);
 
192
    if(drizzle->db)
 
193
      free(drizzle->db);
 
194
 
 
195
    /* alloc new connect information */
 
196
    drizzle->user= strdup(user);
 
197
    drizzle->passwd= strdup(passwd);
 
198
    drizzle->db= db ? strdup(db) : 0;
 
199
  }
 
200
 
 
201
  return(rc);
 
202
}
 
203
 
 
204
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
 
205
struct passwd *getpwuid(uid_t);
 
206
char* getlogin(void);
 
207
#endif
 
208
 
 
209
/**************************************************************************
 
210
  Do a query. If query returned rows, free old rows.
 
211
  Read data by drizzle_store_result or by repeat call of drizzle_fetch_row
 
212
**************************************************************************/
 
213
 
 
214
int
 
215
drizzle_query(DRIZZLE *drizzle, const char *query)
 
216
{
 
217
  return drizzle_real_query(drizzle,query, (uint32_t) strlen(query));
 
218
}
 
219
 
 
220
 
 
221
/**************************************************************************
 
222
  Return next field of the query results
 
223
**************************************************************************/
 
224
 
 
225
DRIZZLE_FIELD *
 
226
drizzle_fetch_field(DRIZZLE_RES *result)
 
227
{
 
228
  if (result->current_field >= result->field_count)
 
229
    return(NULL);
 
230
  return &result->fields[result->current_field++];
 
231
}
 
232
 
 
233
 
 
234
/**************************************************************************
 
235
  Move to a specific row and column
 
236
**************************************************************************/
 
237
 
 
238
void
 
239
drizzle_data_seek(DRIZZLE_RES *result, uint64_t row)
 
240
{
 
241
  DRIZZLE_ROWS  *tmp=0;
 
242
  if (result->data)
 
243
    for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
 
244
  result->current_row=0;
 
245
  result->data_cursor = tmp;
 
246
}
 
247
 
 
248
 
 
249
/*************************************************************************
 
250
  put the row or field cursor one a position one got from DRIZZLE_ROW_tell()
 
251
  This doesn't restore any data. The next drizzle_fetch_row or
 
252
  drizzle_fetch_field will return the next row or field after the last used
 
253
*************************************************************************/
 
254
 
 
255
DRIZZLE_ROW_OFFSET
 
256
drizzle_row_seek(DRIZZLE_RES *result, DRIZZLE_ROW_OFFSET row)
 
257
{
 
258
  DRIZZLE_ROW_OFFSET return_value=result->data_cursor;
 
259
  result->current_row= 0;
 
260
  result->data_cursor= row;
 
261
  return return_value;
 
262
}
 
263
 
 
264
 
 
265
DRIZZLE_FIELD_OFFSET
 
266
drizzle_field_seek(DRIZZLE_RES *result, DRIZZLE_FIELD_OFFSET field_offset)
 
267
{
 
268
  DRIZZLE_FIELD_OFFSET return_value=result->current_field;
 
269
  result->current_field=field_offset;
 
270
  return return_value;
 
271
}
 
272
 
 
273
 
 
274
/*****************************************************************************
 
275
  List all tables in a database
 
276
  If wild is given then only the tables matching wild is returned
 
277
*****************************************************************************/
 
278
 
 
279
DRIZZLE_RES *
 
280
drizzle_list_tables(DRIZZLE *drizzle, const char *wild)
 
281
{
 
282
  char buff[255];
 
283
  char *ptr= strcpy(buff, "show tables");
 
284
  ptr+= 11; /* strlen("show tables"); */
 
285
 
 
286
  append_wild(ptr,buff+sizeof(buff),wild);
 
287
  if (drizzle_query(drizzle,buff))
 
288
    return(0);
 
289
  return (drizzle_store_result(drizzle));
 
290
}
 
291
 
 
292
 
 
293
DRIZZLE_FIELD *cli_list_fields(DRIZZLE *drizzle)
 
294
{
 
295
  DRIZZLE_DATA *query;
 
296
  if (!(query= cli_read_rows(drizzle,(DRIZZLE_FIELD*) 0, 8)))
 
297
    return NULL;
 
298
 
 
299
  drizzle->field_count= (uint32_t) query->rows;
 
300
  return unpack_fields(query, drizzle->field_count, 1);
 
301
}
 
302
 
 
303
 
 
304
/**************************************************************************
 
305
  List all fields in a table
 
306
  If wild is given then only the fields matching wild is returned
 
307
  Instead of this use query:
 
308
  show fields in 'table' like "wild"
 
309
**************************************************************************/
 
310
 
 
311
DRIZZLE_RES *
 
312
drizzle_list_fields(DRIZZLE *drizzle, const char *table, const char *wild)
 
313
{
 
314
  DRIZZLE_RES   *result;
 
315
  DRIZZLE_FIELD *fields;
 
316
  char buff[257], *end;
 
317
 
 
318
  end= strncpy(buff, table, 128) + 128;
 
319
  end= strncpy(end+1, wild ? wild : "", 128) + 128;
 
320
 
 
321
  free_old_query(drizzle);
 
322
  if (simple_command(drizzle, COM_FIELD_LIST, (unsigned char*) buff,
 
323
                     (uint32_t) (end-buff), 1) ||
 
324
      !(fields= (*drizzle->methods->list_fields)(drizzle)))
 
325
    return(NULL);
 
326
 
 
327
  if (!(result = (DRIZZLE_RES *) malloc(sizeof(DRIZZLE_RES))))
 
328
    return(NULL);
 
329
 
 
330
  memset(result, 0, sizeof(DRIZZLE_RES));
 
331
 
 
332
  result->methods= drizzle->methods;
 
333
  drizzle->fields=0;
 
334
  result->field_count = drizzle->field_count;
 
335
  result->fields= fields;
 
336
  result->eof=1;
 
337
  return(result);
 
338
}
 
339
 
 
340
/* List all running processes (threads) in server */
 
341
 
 
342
DRIZZLE_RES *
 
343
drizzle_list_processes(DRIZZLE *drizzle)
 
344
{
 
345
  DRIZZLE_DATA *fields;
 
346
  uint32_t field_count;
 
347
  unsigned char *pos;
 
348
 
 
349
  if (simple_command(drizzle,COM_PROCESS_INFO,0,0,0))
 
350
    return(0);
 
351
  free_old_query(drizzle);
 
352
  pos=(unsigned char*) drizzle->net.read_pos;
 
353
  field_count=(uint32_t) net_field_length(&pos);
 
354
  if (!(fields = (*drizzle->methods->read_rows)(drizzle,(DRIZZLE_FIELD*) 0, 7)))
 
355
    return(NULL);
 
356
  if (!(drizzle->fields=unpack_fields(fields, field_count, 0)))
 
357
    return(0);
 
358
  drizzle->status=DRIZZLE_STATUS_GET_RESULT;
 
359
  drizzle->field_count=field_count;
 
360
  return(drizzle_store_result(drizzle));
 
361
}
 
362
 
 
363
 
 
364
int
 
365
drizzle_shutdown(DRIZZLE *drizzle)
 
366
{
 
367
  return(simple_command(drizzle, COM_SHUTDOWN, 0, 0, 0));
 
368
}
 
369
 
 
370
 
 
371
int
 
372
drizzle_refresh(DRIZZLE *drizzle, uint32_t options)
 
373
{
 
374
  unsigned char bits[1];
 
375
  bits[0]= (unsigned char) options;
 
376
  return(simple_command(drizzle, COM_REFRESH, bits, 1, 0));
 
377
}
 
378
 
 
379
 
 
380
int32_t
 
381
drizzle_kill(DRIZZLE *drizzle, uint32_t pid)
 
382
{
 
383
  unsigned char buff[4];
 
384
  int4store(buff,pid);
 
385
  return(simple_command(drizzle,COM_PROCESS_KILL,buff,sizeof(buff),0));
 
386
}
 
387
 
 
388
 
 
389
int
 
390
drizzle_set_server_option(DRIZZLE *drizzle, enum enum_drizzle_set_option option)
 
391
{
 
392
  unsigned char buff[2];
 
393
  int2store(buff, (uint32_t) option);
 
394
  return(simple_command(drizzle, COM_SET_OPTION, buff, sizeof(buff), 0));
 
395
}
 
396
 
 
397
 
 
398
const char *cli_read_statistics(DRIZZLE *drizzle)
 
399
{
 
400
  drizzle->net.read_pos[drizzle->packet_length]=0;  /* End of stat string */
 
401
  if (!drizzle->net.read_pos[0])
 
402
  {
 
403
    drizzle_set_error(drizzle, CR_WRONG_HOST_INFO, sqlstate_get_unknown());
 
404
    return drizzle->net.last_error;
 
405
  }
 
406
  return (char*) drizzle->net.read_pos;
 
407
}
 
408
 
 
409
 
 
410
int
 
411
drizzle_ping(DRIZZLE *drizzle)
 
412
{
 
413
  int res;
 
414
  res= simple_command(drizzle,COM_PING,0,0,0);
 
415
  if (res == CR_SERVER_LOST && drizzle->reconnect)
 
416
    res= simple_command(drizzle,COM_PING,0,0,0);
 
417
  return(res);
 
418
}
 
419
 
 
420
 
 
421
const char *
 
422
drizzle_get_server_info(const DRIZZLE *drizzle)
 
423
{
 
424
  return((char*) drizzle->server_version);
 
425
}
 
426
 
 
427
 
 
428
const char *
 
429
drizzle_get_host_info(const DRIZZLE *drizzle)
 
430
{
 
431
  return(drizzle->host_info);
 
432
}
 
433
 
 
434
 
 
435
uint32_t
 
436
drizzle_get_proto_info(const DRIZZLE *drizzle)
 
437
{
 
438
  return (drizzle->protocol_version);
 
439
}
 
440
 
 
441
const char *
 
442
drizzle_get_client_info(void)
 
443
{
 
444
  return (char*) VERSION;
 
445
}
 
446
 
 
447
uint32_t drizzle_get_client_version(void)
 
448
{
 
449
  return DRIZZLE_VERSION_ID;
 
450
}
 
451
 
 
452
bool drizzle_eof(const DRIZZLE_RES *res)
 
453
{
 
454
  return res->eof;
 
455
}
 
456
 
 
457
const DRIZZLE_FIELD * drizzle_fetch_field_direct(const DRIZZLE_RES *res, unsigned int fieldnr)
 
458
{
 
459
  return &(res)->fields[fieldnr];
 
460
}
 
461
 
 
462
const DRIZZLE_FIELD * drizzle_fetch_fields(const DRIZZLE_RES *res)
 
463
{
 
464
  return res->fields;
 
465
}
 
466
 
 
467
DRIZZLE_ROW_OFFSET drizzle_row_tell(const DRIZZLE_RES *res)
 
468
{
 
469
  return res->data_cursor;
 
470
}
 
471
 
 
472
DRIZZLE_FIELD_OFFSET drizzle_field_tell(const DRIZZLE_RES *res)
 
473
{
 
474
  return res->current_field;
 
475
}
 
476
 
 
477
/* DRIZZLE */
 
478
 
 
479
unsigned int drizzle_field_count(const DRIZZLE *drizzle)
 
480
{
 
481
  return drizzle->field_count;
 
482
}
 
483
 
 
484
uint64_t drizzle_affected_rows(const DRIZZLE *drizzle)
 
485
{
 
486
  return drizzle->affected_rows;
 
487
}
 
488
 
 
489
uint64_t drizzle_insert_id(const DRIZZLE *drizzle)
 
490
{
 
491
  return drizzle->insert_id;
 
492
}
 
493
 
 
494
const char * drizzle_sqlstate(const DRIZZLE *drizzle)
 
495
{
 
496
  return drizzle ? drizzle->net.sqlstate : sqlstate_get_cant_connect();
 
497
}
 
498
 
 
499
uint32_t drizzle_warning_count(const DRIZZLE *drizzle)
 
500
{
 
501
  return drizzle->warning_count;
 
502
}
 
503
 
 
504
const char * drizzle_info(const DRIZZLE *drizzle)
 
505
{
 
506
  return drizzle->info;
 
507
}
 
508
 
 
509
uint32_t drizzle_thread_id(const DRIZZLE *drizzle)
 
510
{
 
511
  return drizzle->thread_id;
 
512
}
 
513
 
 
514
/****************************************************************************
 
515
  Some support functions
 
516
****************************************************************************/
 
517
 
 
518
/*
 
519
  Functions called my my_net_init() to set some application specific variables
 
520
*/
 
521
 
 
522
void my_net_local_init(NET *net)
 
523
{
 
524
  net->max_packet=   (uint32_t) net_buffer_length;
 
525
  my_net_set_read_timeout(net, CLIENT_NET_READ_TIMEOUT);
 
526
  my_net_set_write_timeout(net, CLIENT_NET_WRITE_TIMEOUT);
 
527
  net->retry_count=  1;
 
528
  net->max_packet_size= (net_buffer_length > max_allowed_packet) ?
 
529
    net_buffer_length : max_allowed_packet;
 
530
}
 
531
 
 
532
/*
 
533
  This function is used to create HEX string that you
 
534
  can use in a SQL statement in of the either ways:
 
535
    INSERT INTO blob_column VALUES (0xAABBCC);  (any DRIZZLE version)
 
536
    INSERT INTO blob_column VALUES (X'AABBCC'); 
 
537
  
 
538
  The string in "from" is encoded to a HEX string.
 
539
  The result is placed in "to" and a terminating null byte is appended.
 
540
  
 
541
  The string pointed to by "from" must be "length" bytes long.
 
542
  You must allocate the "to" buffer to be at least length*2+1 bytes long.
 
543
  Each character needs two bytes, and you need room for the terminating
 
544
  null byte. When drizzle_hex_string() returns, the contents of "to" will
 
545
  be a null-terminated string. The return value is the length of the
 
546
  encoded string, not including the terminating null character.  The return value does not contain any leading 0x or a leading X' and
 
547
  trailing '. The caller must supply whichever of those is desired.
 
548
*/
 
549
 
 
550
uint32_t
 
551
drizzle_hex_string(char *to, const char *from, uint32_t length)
 
552
{
 
553
  char *to0= to;
 
554
  const char *end;
 
555
            
 
556
  for (end= from + length; from < end; from++)
 
557
  {
 
558
    *to++= _dig_vec_upper[((unsigned char) *from) >> 4];
 
559
    *to++= _dig_vec_upper[((unsigned char) *from) & 0x0F];
 
560
  }
 
561
  *to= '\0';
 
562
  return (uint32_t) (to-to0);
 
563
}
 
564
 
 
565
/*
 
566
  Add escape characters to a string (blob?) to make it suitable for a insert
 
567
  to should at least have place for length*2+1 chars
 
568
  Returns the length of the to string
 
569
*/
 
570
 
 
571
uint32_t
 
572
drizzle_escape_string(char *to,const char *from, uint32_t length)
 
573
{
 
574
  const char *to_start= to;
 
575
  const char *end, *to_end=to_start + 2*length;
 
576
  bool overflow= false;
 
577
  for (end= from + length; from < end; from++)
 
578
  {
 
579
    uint32_t tmp_length;
 
580
    char escape= 0;
 
581
    if (!U8_IS_SINGLE(*from))
 
582
    {
 
583
      tmp_length= U8_LENGTH(*from);
 
584
      if (to + tmp_length > to_end)
 
585
      {
 
586
        overflow= true;
 
587
        break;
 
588
      }
 
589
      while (tmp_length--)
 
590
        *to++= *from++;
 
591
      from--;
 
592
      continue;
 
593
    }
 
594
    switch (*from) {
 
595
    case 0:                             /* Must be escaped for 'mysql' */
 
596
      escape= '0';
 
597
      break;
 
598
    case '\n':                          /* Must be escaped for logs */
 
599
      escape= 'n';
 
600
      break;
 
601
    case '\r':
 
602
      escape= 'r';
 
603
      break;
 
604
    case '\\':
 
605
      escape= '\\';
 
606
      break;
 
607
    case '\'':
 
608
      escape= '\'';
 
609
      break;
 
610
    case '"':                           /* Better safe than sorry */
 
611
      escape= '"';
 
612
      break;
 
613
    case '\032':                        /* This gives problems on Win32 */
 
614
      escape= 'Z';
 
615
      break;
 
616
    }
 
617
    if (escape)
 
618
    {
 
619
      if (to + 2 > to_end)
 
620
      {
 
621
        overflow= true;
 
622
        break;
 
623
      }
 
624
      *to++= '\\';
 
625
      *to++= escape;
 
626
    }
 
627
    else
 
628
    {
 
629
      if (to + 1 > to_end)
 
630
      {
 
631
        overflow= true;
 
632
        break;
 
633
      }
 
634
      *to++= *from;
 
635
    }
 
636
  }
 
637
  *to= 0;
 
638
  return overflow ? (size_t) -1 : (size_t) (to - to_start);
 
639
}
 
640
 
 
641
int cli_unbuffered_fetch(DRIZZLE *drizzle, char **row)
 
642
{
 
643
  if (packet_error == cli_safe_read(drizzle))
 
644
    return 1;
 
645
 
 
646
  *row= ((drizzle->net.read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA) ? NULL :
 
647
   (char*) (drizzle->net.read_pos+1));
 
648
  return 0;
 
649
}
 
650
 
 
651
/********************************************************************
 
652
 Transactional APIs
 
653
*********************************************************************/
 
654
 
 
655
/*
 
656
  Commit the current transaction
 
657
*/
 
658
 
 
659
bool drizzle_commit(DRIZZLE *drizzle)
 
660
{
 
661
  return((bool) drizzle_real_query(drizzle, "commit", 6));
 
662
}
 
663
 
 
664
/*
 
665
  Rollback the current transaction
 
666
*/
 
667
 
 
668
bool drizzle_rollback(DRIZZLE *drizzle)
 
669
{
 
670
  return((bool) drizzle_real_query(drizzle, "rollback", 8));
 
671
}
 
672
 
 
673
 
 
674
/*
 
675
  Set autocommit to either true or false
 
676
*/
 
677
 
 
678
bool drizzle_autocommit(DRIZZLE *drizzle, bool auto_mode)
 
679
{
 
680
  return((bool) drizzle_real_query(drizzle, auto_mode ?
 
681
                                         "set autocommit=1":"set autocommit=0",
 
682
                                         16));
 
683
}
 
684
 
 
685
 
 
686
/********************************************************************
 
687
 Multi query execution + SPs APIs
 
688
*********************************************************************/
 
689
 
 
690
/*
 
691
  Returns true/false to indicate whether any more query results exist
 
692
  to be read using drizzle_next_result()
 
693
*/
 
694
 
 
695
bool drizzle_more_results(const DRIZZLE *drizzle)
 
696
{
 
697
  return (drizzle->server_status & SERVER_MORE_RESULTS_EXISTS) ? true:false;
 
698
}
 
699
 
 
700
 
 
701
/*
 
702
  Reads and returns the next query results
 
703
*/
 
704
int drizzle_next_result(DRIZZLE *drizzle)
 
705
{
 
706
  if (drizzle->status != DRIZZLE_STATUS_READY)
 
707
  {
 
708
    drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC, sqlstate_get_unknown());
 
709
    return(1);
 
710
  }
 
711
 
 
712
  net_clear_error(&drizzle->net);
 
713
  drizzle->affected_rows= ~(uint64_t) 0;
 
714
 
 
715
  if (drizzle->server_status & SERVER_MORE_RESULTS_EXISTS)
 
716
    return((*drizzle->methods->next_result)(drizzle));
 
717
 
 
718
  return(-1);        /* No more results */
 
719
}
 
720
 
 
721
 
 
722
DRIZZLE_RES * drizzle_use_result(DRIZZLE *drizzle)
 
723
{
 
724
  return (*drizzle->methods->use_result)(drizzle);
 
725
}
 
726
 
 
727
bool drizzle_read_query_result(DRIZZLE *drizzle)
 
728
{
 
729
  return (*drizzle->methods->read_query_result)(drizzle);
 
730
}
 
731