1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems, Inc.
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.
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.
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
21
This file is included by both libdrizzleclient.c (the DRIZZLE client C API)
22
and the drizzled server to connect to another DRIZZLE server.
24
The differences for the two cases are:
26
- Things that only works for the client:
27
- Trying to automaticly determinate user name if not supplied to
28
drizzleclient_connect()
29
- Support for reading local file with LOAD DATA LOCAL
30
- SHARED memory handling
33
- Things that only works for the server
34
- Alarm handling on connect
36
In all other cases, the code should be idential for the client and
41
#include "libdrizzle_priv.h"
45
#include "drizzle_methods.h"
49
#include <sys/ioctl.h>
53
/* Remove client convenience wrappers */
54
#undef max_allowed_packet
55
#undef net_buffer_length
65
#include <sys/socket.h>
66
#include <netinet/in.h>
67
#include <arpa/inet.h>
72
#ifdef HAVE_SYS_SELECT_H
73
#include <sys/select.h>
81
#include <drizzled/gettext.h>
84
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
85
struct passwd *getpwuid(uid_t);
90
/*****************************************************************************
91
Read a packet from server. Give error message if socket was down
92
or packet is an error message
93
*****************************************************************************/
94
safe_read_error_hook_func safe_read_error_hook= NULL;
96
uint32_t drizzleclient_cli_safe_read(DRIZZLE *drizzle)
98
NET *net= &drizzle->net;
102
len=drizzleclient_net_read(net);
104
if (len == packet_error || len == 0)
106
if (safe_read_error_hook != NULL)
107
if (safe_read_error_hook(net))
108
return (packet_error);
109
drizzleclient_disconnect(drizzle);
110
drizzleclient_set_error(drizzle, net->last_errno == CR_NET_PACKET_TOO_LARGE ?
111
CR_NET_PACKET_TOO_LARGE : CR_SERVER_LOST,
112
drizzleclient_sqlstate_get_unknown());
113
return (packet_error);
115
if (net->read_pos[0] == 255)
119
char *pos=(char*) net->read_pos+1;
120
net->last_errno=uint2korr(pos);
125
strncpy(net->sqlstate, pos+1, LIBDRIZZLE_SQLSTATE_LENGTH);
126
pos+= LIBDRIZZLE_SQLSTATE_LENGTH+1;
131
The SQL state hasn't been received -- it should be reset to HY000
132
(unknown error sql state).
135
strcpy(net->sqlstate, drizzleclient_sqlstate_get_unknown());
138
strncpy(net->last_error,(char*) pos, min((uint32_t) len,
139
(uint32_t) sizeof(net->last_error)-1));
142
drizzleclient_set_error(drizzle, CR_UNKNOWN_ERROR, drizzleclient_sqlstate_get_unknown());
144
Cover a protocol design error: error packet does not
145
contain the server status. Therefore, the client has no way
146
to find out whether there are more result sets of
147
a multiple-result-set statement pending. Luckily, in 5.0 an
148
error always aborts execution of a statement, wherever it is
149
a multi-statement or a stored procedure, so it should be
150
safe to unconditionally turn off the flag here.
152
drizzle->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
154
return(packet_error);
160
drizzleclient_cli_advanced_command(DRIZZLE *drizzle, enum enum_server_command command,
161
const unsigned char *header, uint32_t header_length,
162
const unsigned char *arg, uint32_t arg_length, bool skip_check)
164
NET *net= &drizzle->net;
166
bool stmt_skip= false;
168
if (drizzle->net.vio == 0)
169
{ /* Do reconnect if possible */
170
if (drizzleclient_reconnect(drizzle) || stmt_skip)
173
if (drizzle->status != DRIZZLE_STATUS_READY ||
174
drizzle->server_status & SERVER_MORE_RESULTS_EXISTS)
176
drizzleclient_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC,
177
drizzleclient_sqlstate_get_unknown());
181
drizzleclient_drizzleclient_net_clear_error(net);
183
drizzle->affected_rows= ~(uint64_t) 0;
185
We don't want to clear the protocol buffer on COM_QUIT, because if
186
the previous command was a shutdown command, we may have the
187
response for the COM_QUIT already in the communication buffer
189
drizzleclient_net_clear(&drizzle->net, (command != COM_QUIT));
191
if (drizzleclient_net_write_command(net,(unsigned char) command, header, header_length,
194
if (net->last_errno == CR_NET_PACKET_TOO_LARGE)
196
drizzleclient_set_error(drizzle, CR_NET_PACKET_TOO_LARGE, drizzleclient_sqlstate_get_unknown());
199
drizzleclient_disconnect(drizzle);
200
if (drizzleclient_reconnect(drizzle) || stmt_skip)
202
if (drizzleclient_net_write_command(net,(unsigned char) command, header, header_length,
205
drizzleclient_set_error(drizzle, CR_SERVER_GONE_ERROR, drizzleclient_sqlstate_get_unknown());
211
result= ((drizzle->packet_length=drizzleclient_cli_safe_read(drizzle)) == packet_error ?
217
void drizzleclient_free_old_query(DRIZZLE *drizzle)
221
/* TODO - we need to de-alloc field storage */
222
free(drizzle->fields->catalog);
223
free(drizzle->fields->db);
224
free(drizzle->fields->table);
225
free(drizzle->fields->org_table);
226
free(drizzle->fields->name);
227
free(drizzle->fields->org_name);
228
free(drizzle->fields->def);
229
free(drizzle->fields);
232
/* init_alloc_root(&drizzle->field_alloc,8192,0); */ /* Assume rowlength < 8192 */
234
drizzle->field_count= 0; /* For API */
235
drizzle->warning_count= 0;
245
drizzleclient_free_result(DRIZZLE_RES *result)
249
DRIZZLE *drizzle= result->handle;
252
if (drizzle->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
253
drizzle->unbuffered_fetch_owner= 0;
254
if (drizzle->status == DRIZZLE_STATUS_USE_RESULT)
256
(*drizzle->methods->flush_use_result)(drizzle);
257
drizzle->status=DRIZZLE_STATUS_READY;
258
if (drizzle->unbuffered_fetch_owner)
259
*drizzle->unbuffered_fetch_owner= true;
262
drizzleclient_free_rows(result->data);
263
/* TODO: free result->fields */
265
free((unsigned char*) result->row);
266
free((unsigned char*) result);
273
/* Read all rows (fields or data) from server */
275
DRIZZLE_DATA *drizzleclient_cli_read_rows(DRIZZLE *drizzle, DRIZZLE_FIELD *DRIZZLE_FIELDs, uint32_t fields)
282
DRIZZLE_DATA *result;
283
DRIZZLE_ROWS **prev_ptr,*cur;
284
NET *net = &drizzle->net;
286
if ((pkt_len= drizzleclient_cli_safe_read(drizzle)) == packet_error)
288
if (!(result=(DRIZZLE_DATA*) malloc(sizeof(DRIZZLE_DATA))))
290
drizzleclient_set_error(drizzle, CR_OUT_OF_MEMORY,
291
drizzleclient_sqlstate_get_unknown());
294
memset(result, 0, sizeof(DRIZZLE_DATA));
295
prev_ptr= &result->data;
297
result->fields=fields;
300
The last EOF packet is either a 254 (0xFE) character followed by 1-7 status bytes.
302
This doesn't conflict with normal usage of 254 which stands for a
303
string where the length of the string is 8 bytes. (see drizzleclient_net_field_length())
306
while (*(cp=net->read_pos) != DRIZZLE_PROTOCOL_NO_MORE_DATA || pkt_len >= 8)
309
if (!(cur= (DRIZZLE_ROWS*) malloc(sizeof(DRIZZLE_ROWS))) ||
310
!(cur->data= ((DRIZZLE_ROW) malloc((fields+1)*sizeof(char *)+pkt_len))))
312
drizzleclient_free_rows(result);
313
drizzleclient_set_error(drizzle, CR_OUT_OF_MEMORY, drizzleclient_sqlstate_get_unknown());
317
prev_ptr= &cur->next;
318
to= (char*) (cur->data+fields+1);
320
for (field=0 ; field < fields ; field++)
322
if ((len= drizzleclient_net_field_length(&cp)) == NULL_LENGTH)
324
cur->data[field] = 0;
328
cur->data[field] = to;
329
if (len > (uint32_t) (end_to - to))
331
drizzleclient_free_rows(result);
332
drizzleclient_set_error(drizzle, CR_MALFORMED_PACKET,
333
drizzleclient_sqlstate_get_unknown());
342
if (DRIZZLE_FIELDs[field].max_length < len)
343
DRIZZLE_FIELDs[field].max_length=len;
347
cur->data[field]=to; /* End of last field */
348
if ((pkt_len=drizzleclient_cli_safe_read(drizzle)) == packet_error)
350
drizzleclient_free_rows(result);
354
*prev_ptr=0; /* last pointer is null */
355
if (pkt_len > 1) /* DRIZZLE 4.1 protocol */
357
drizzle->warning_count= uint2korr(cp+1);
358
drizzle->server_status= uint2korr(cp+3);
364
Read one row. Uses packet buffer as storage for fields.
365
When next packet is read, the previous field values are destroyed
370
read_one_row(DRIZZLE *drizzle, uint32_t fields, DRIZZLE_ROW row, uint32_t *lengths)
373
uint32_t pkt_len,len;
374
unsigned char *pos, *prev_pos, *end_pos;
375
NET *net= &drizzle->net;
377
if ((pkt_len=drizzleclient_cli_safe_read(drizzle)) == packet_error)
379
if (pkt_len <= 8 && net->read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA)
381
if (pkt_len > 1) /* DRIZZLE 4.1 protocol */
383
drizzle->warning_count= uint2korr(net->read_pos+1);
384
drizzle->server_status= uint2korr(net->read_pos+3);
386
return 1; /* End of data */
388
prev_pos= 0; /* allowed to write at packet[-1] */
391
for (field=0 ; field < fields ; field++)
393
if ((len= drizzleclient_net_field_length(&pos)) == NULL_LENGTH)
400
if (len > (uint32_t) (end_pos - pos))
402
drizzleclient_set_error(drizzle, CR_UNKNOWN_ERROR,
403
drizzleclient_sqlstate_get_unknown());
406
row[field] = (char*) pos;
411
*prev_pos=0; /* Terminate prev field */
414
row[field]=(char*) prev_pos+1; /* End of last field */
415
*prev_pos=0; /* Terminate last field */
420
/**************************************************************************
421
Return next row of the query results
422
**************************************************************************/
425
drizzleclient_fetch_row(DRIZZLE_RES *res)
428
{ /* Unbufferred fetch */
431
DRIZZLE *drizzle= res->handle;
432
if (drizzle->status != DRIZZLE_STATUS_USE_RESULT)
434
drizzleclient_set_error(drizzle,
435
res->unbuffered_fetch_cancelled ?
436
CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
437
drizzleclient_sqlstate_get_unknown());
439
else if (!(read_one_row(drizzle, res->field_count, res->row, res->lengths)))
442
return(res->current_row=res->row);
445
drizzle->status=DRIZZLE_STATUS_READY;
447
Reset only if owner points to us: there is a chance that somebody
448
started new query after drizzle_stmt_close():
450
if (drizzle->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
451
drizzle->unbuffered_fetch_owner= 0;
452
/* Don't clear handle in drizzleclient_free_result */
455
return((DRIZZLE_ROW) NULL);
459
if (!res->data_cursor)
461
return(res->current_row=(DRIZZLE_ROW) NULL);
463
tmp = res->data_cursor->data;
464
res->data_cursor = res->data_cursor->next;
465
return(res->current_row=tmp);
470
/**************************************************************************
471
Get column lengths of the current row
472
If one uses drizzleclient_use_result, res->lengths contains the length information,
473
else the lengths are calculated from the offset between pointers.
474
**************************************************************************/
477
drizzleclient_fetch_lengths(DRIZZLE_RES *res)
481
if (!(column=res->current_row))
482
return 0; /* Something is wrong */
484
(*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
490
drizzleclient_options(DRIZZLE *drizzle,enum drizzle_option option, const void *arg)
493
case DRIZZLE_OPT_CONNECT_TIMEOUT:
494
drizzle->options.connect_timeout= *(uint32_t*) arg;
496
case DRIZZLE_OPT_READ_TIMEOUT:
497
drizzle->options.read_timeout= *(uint32_t*) arg;
499
case DRIZZLE_OPT_WRITE_TIMEOUT:
500
drizzle->options.write_timeout= *(uint32_t*) arg;
502
case DRIZZLE_OPT_COMPRESS:
503
drizzle->options.compress= 1; /* Remember for connect */
504
drizzle->options.client_flag|= CLIENT_COMPRESS;
506
case DRIZZLE_READ_DEFAULT_FILE:
507
if (drizzle->options.my_cnf_file != NULL)
508
free(drizzle->options.my_cnf_file);
509
drizzle->options.my_cnf_file=strdup(arg);
511
case DRIZZLE_READ_DEFAULT_GROUP:
512
if (drizzle->options.my_cnf_group != NULL)
513
free(drizzle->options.my_cnf_group);
514
drizzle->options.my_cnf_group=strdup(arg);
516
case DRIZZLE_OPT_PROTOCOL:
518
case DRIZZLE_OPT_USE_REMOTE_CONNECTION:
519
case DRIZZLE_OPT_GUESS_CONNECTION:
520
drizzle->options.methods_to_use= option;
522
case DRIZZLE_SET_CLIENT_IP:
523
drizzle->options.client_ip= strdup(arg);
525
case DRIZZLE_SECURE_AUTH:
526
drizzle->options.secure_auth= *(const bool *) arg;
528
case DRIZZLE_REPORT_DATA_TRUNCATION:
529
drizzle->options.report_data_truncation= (*(const bool *) arg) ? 1 : 0;
531
case DRIZZLE_OPT_RECONNECT:
532
drizzle->reconnect= *(const bool *) arg;
534
case DRIZZLE_OPT_SSL_VERIFY_SERVER_CERT:
535
if (*(const bool*) arg)
536
drizzle->options.client_flag|= CLIENT_SSL_VERIFY_SERVER_CERT;
538
drizzle->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
547
/****************************************************************************
548
Functions to get information from the DRIZZLE structure
549
These are functions to make shared libraries more usable.
550
****************************************************************************/
553
uint64_t drizzleclient_num_rows(const DRIZZLE_RES *res)
555
return res->row_count;
558
unsigned int drizzleclient_num_fields(const DRIZZLE_RES *res)
560
return res->field_count;
565
Get version number for server in a form easy to test on
568
drizzleclient_get_server_version()
575
We will ensure that a newer server always has a bigger number.
578
Signed number > 323000
582
drizzleclient_get_server_version(const DRIZZLE *drizzle)
584
uint32_t major, minor, version;
585
char *pos= drizzle->server_version, *end_pos;
586
major= (uint32_t) strtoul(pos, &end_pos, 10); pos=end_pos+1;
587
minor= (uint32_t) strtoul(pos, &end_pos, 10); pos=end_pos+1;
588
version= (uint32_t) strtoul(pos, &end_pos, 10);
589
return (uint32_t) major*10000L+(uint32_t) (minor*100+version);