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 "local_infile.h"
46
#include "drizzle_methods.h"
50
#include <sys/ioctl.h>
54
/* Remove client convenience wrappers */
55
#undef max_allowed_packet
56
#undef net_buffer_length
66
#include <sys/socket.h>
67
#include <netinet/in.h>
68
#include <arpa/inet.h>
73
#ifdef HAVE_SYS_SELECT_H
74
#include <sys/select.h>
82
#include <drizzled/gettext.h>
85
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
86
struct passwd *getpwuid(uid_t);
91
/*****************************************************************************
92
Read a packet from server. Give error message if socket was down
93
or packet is an error message
94
*****************************************************************************/
95
safe_read_error_hook_func safe_read_error_hook= NULL;
97
uint32_t drizzleclient_cli_safe_read(DRIZZLE *drizzle)
99
NET *net= &drizzle->net;
103
len=drizzleclient_net_read(net);
105
if (len == packet_error || len == 0)
107
if (safe_read_error_hook != NULL)
108
if (safe_read_error_hook(net))
109
return (packet_error);
110
drizzleclient_disconnect(drizzle);
111
drizzleclient_set_error(drizzle, net->last_errno == CR_NET_PACKET_TOO_LARGE ?
112
CR_NET_PACKET_TOO_LARGE : CR_SERVER_LOST,
113
drizzleclient_sqlstate_get_unknown());
114
return (packet_error);
116
if (net->read_pos[0] == 255)
120
char *pos=(char*) net->read_pos+1;
121
net->last_errno=uint2korr(pos);
126
strncpy(net->sqlstate, pos+1, LIBDRIZZLE_SQLSTATE_LENGTH);
127
pos+= LIBDRIZZLE_SQLSTATE_LENGTH+1;
132
The SQL state hasn't been received -- it should be reset to HY000
133
(unknown error sql state).
136
strcpy(net->sqlstate, drizzleclient_sqlstate_get_unknown());
139
strncpy(net->last_error,(char*) pos, min((uint32_t) len,
140
(uint32_t) sizeof(net->last_error)-1));
143
drizzleclient_set_error(drizzle, CR_UNKNOWN_ERROR, drizzleclient_sqlstate_get_unknown());
145
Cover a protocol design error: error packet does not
146
contain the server status. Therefore, the client has no way
147
to find out whether there are more result sets of
148
a multiple-result-set statement pending. Luckily, in 5.0 an
149
error always aborts execution of a statement, wherever it is
150
a multi-statement or a stored procedure, so it should be
151
safe to unconditionally turn off the flag here.
153
drizzle->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
155
return(packet_error);
161
drizzleclient_cli_advanced_command(DRIZZLE *drizzle, enum enum_server_command command,
162
const unsigned char *header, uint32_t header_length,
163
const unsigned char *arg, uint32_t arg_length, bool skip_check)
165
NET *net= &drizzle->net;
167
bool stmt_skip= false;
169
if (drizzle->net.vio == 0)
170
{ /* Do reconnect if possible */
171
if (drizzleclient_reconnect(drizzle) || stmt_skip)
174
if (drizzle->status != DRIZZLE_STATUS_READY ||
175
drizzle->server_status & SERVER_MORE_RESULTS_EXISTS)
177
drizzleclient_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC,
178
drizzleclient_sqlstate_get_unknown());
182
drizzleclient_drizzleclient_net_clear_error(net);
184
drizzle->affected_rows= ~(uint64_t) 0;
186
We don't want to clear the protocol buffer on COM_QUIT, because if
187
the previous command was a shutdown command, we may have the
188
response for the COM_QUIT already in the communication buffer
190
drizzleclient_net_clear(&drizzle->net, (command != COM_QUIT));
192
if (drizzleclient_net_write_command(net,(unsigned char) command, header, header_length,
195
if (net->last_errno == CR_NET_PACKET_TOO_LARGE)
197
drizzleclient_set_error(drizzle, CR_NET_PACKET_TOO_LARGE, drizzleclient_sqlstate_get_unknown());
200
drizzleclient_disconnect(drizzle);
201
if (drizzleclient_reconnect(drizzle) || stmt_skip)
203
if (drizzleclient_net_write_command(net,(unsigned char) command, header, header_length,
206
drizzleclient_set_error(drizzle, CR_SERVER_GONE_ERROR, drizzleclient_sqlstate_get_unknown());
212
result= ((drizzle->packet_length=drizzleclient_cli_safe_read(drizzle)) == packet_error ?
218
void drizzleclient_free_old_query(DRIZZLE *drizzle)
222
/* TODO - we need to de-alloc field storage */
223
free(drizzle->fields->catalog);
224
free(drizzle->fields->db);
225
free(drizzle->fields->table);
226
free(drizzle->fields->org_table);
227
free(drizzle->fields->name);
228
free(drizzle->fields->org_name);
229
free(drizzle->fields->def);
230
free(drizzle->fields);
233
/* init_alloc_root(&drizzle->field_alloc,8192,0); */ /* Assume rowlength < 8192 */
235
drizzle->field_count= 0; /* For API */
236
drizzle->warning_count= 0;
246
drizzleclient_free_result(DRIZZLE_RES *result)
250
DRIZZLE *drizzle= result->handle;
253
if (drizzle->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
254
drizzle->unbuffered_fetch_owner= 0;
255
if (drizzle->status == DRIZZLE_STATUS_USE_RESULT)
257
(*drizzle->methods->flush_use_result)(drizzle);
258
drizzle->status=DRIZZLE_STATUS_READY;
259
if (drizzle->unbuffered_fetch_owner)
260
*drizzle->unbuffered_fetch_owner= true;
263
drizzleclient_free_rows(result->data);
264
/* TODO: free result->fields */
266
free((unsigned char*) result->row);
267
free((unsigned char*) result);
274
/* Read all rows (fields or data) from server */
276
DRIZZLE_DATA *drizzleclient_cli_read_rows(DRIZZLE *drizzle, DRIZZLE_FIELD *DRIZZLE_FIELDs, uint32_t fields)
283
DRIZZLE_DATA *result;
284
DRIZZLE_ROWS **prev_ptr,*cur;
285
NET *net = &drizzle->net;
287
if ((pkt_len= drizzleclient_cli_safe_read(drizzle)) == packet_error)
289
if (!(result=(DRIZZLE_DATA*) malloc(sizeof(DRIZZLE_DATA))))
291
drizzleclient_set_error(drizzle, CR_OUT_OF_MEMORY,
292
drizzleclient_sqlstate_get_unknown());
295
memset(result, 0, sizeof(DRIZZLE_DATA));
296
prev_ptr= &result->data;
298
result->fields=fields;
301
The last EOF packet is either a 254 (0xFE) character followed by 1-7 status bytes.
303
This doesn't conflict with normal usage of 254 which stands for a
304
string where the length of the string is 8 bytes. (see drizzleclient_net_field_length())
307
while (*(cp=net->read_pos) != DRIZZLE_PROTOCOL_NO_MORE_DATA || pkt_len >= 8)
310
if (!(cur= (DRIZZLE_ROWS*) malloc(sizeof(DRIZZLE_ROWS))) ||
311
!(cur->data= ((DRIZZLE_ROW) malloc((fields+1)*sizeof(char *)+pkt_len))))
313
drizzleclient_free_rows(result);
314
drizzleclient_set_error(drizzle, CR_OUT_OF_MEMORY, drizzleclient_sqlstate_get_unknown());
318
prev_ptr= &cur->next;
319
to= (char*) (cur->data+fields+1);
321
for (field=0 ; field < fields ; field++)
323
if ((len= drizzleclient_net_field_length(&cp)) == NULL_LENGTH)
325
cur->data[field] = 0;
329
cur->data[field] = to;
330
if (len > (uint32_t) (end_to - to))
332
drizzleclient_free_rows(result);
333
drizzleclient_set_error(drizzle, CR_MALFORMED_PACKET,
334
drizzleclient_sqlstate_get_unknown());
343
if (DRIZZLE_FIELDs[field].max_length < len)
344
DRIZZLE_FIELDs[field].max_length=len;
348
cur->data[field]=to; /* End of last field */
349
if ((pkt_len=drizzleclient_cli_safe_read(drizzle)) == packet_error)
351
drizzleclient_free_rows(result);
355
*prev_ptr=0; /* last pointer is null */
356
if (pkt_len > 1) /* DRIZZLE 4.1 protocol */
358
drizzle->warning_count= uint2korr(cp+1);
359
drizzle->server_status= uint2korr(cp+3);
365
Read one row. Uses packet buffer as storage for fields.
366
When next packet is read, the previous field values are destroyed
371
read_one_row(DRIZZLE *drizzle, uint32_t fields, DRIZZLE_ROW row, uint32_t *lengths)
374
uint32_t pkt_len,len;
375
unsigned char *pos, *prev_pos, *end_pos;
376
NET *net= &drizzle->net;
378
if ((pkt_len=drizzleclient_cli_safe_read(drizzle)) == packet_error)
380
if (pkt_len <= 8 && net->read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA)
382
if (pkt_len > 1) /* DRIZZLE 4.1 protocol */
384
drizzle->warning_count= uint2korr(net->read_pos+1);
385
drizzle->server_status= uint2korr(net->read_pos+3);
387
return 1; /* End of data */
389
prev_pos= 0; /* allowed to write at packet[-1] */
392
for (field=0 ; field < fields ; field++)
394
if ((len= drizzleclient_net_field_length(&pos)) == NULL_LENGTH)
401
if (len > (uint32_t) (end_pos - pos))
403
drizzleclient_set_error(drizzle, CR_UNKNOWN_ERROR,
404
drizzleclient_sqlstate_get_unknown());
407
row[field] = (char*) pos;
412
*prev_pos=0; /* Terminate prev field */
415
row[field]=(char*) prev_pos+1; /* End of last field */
416
*prev_pos=0; /* Terminate last field */
421
/**************************************************************************
422
Return next row of the query results
423
**************************************************************************/
426
drizzleclient_fetch_row(DRIZZLE_RES *res)
429
{ /* Unbufferred fetch */
432
DRIZZLE *drizzle= res->handle;
433
if (drizzle->status != DRIZZLE_STATUS_USE_RESULT)
435
drizzleclient_set_error(drizzle,
436
res->unbuffered_fetch_cancelled ?
437
CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
438
drizzleclient_sqlstate_get_unknown());
440
else if (!(read_one_row(drizzle, res->field_count, res->row, res->lengths)))
443
return(res->current_row=res->row);
446
drizzle->status=DRIZZLE_STATUS_READY;
448
Reset only if owner points to us: there is a chance that somebody
449
started new query after drizzle_stmt_close():
451
if (drizzle->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
452
drizzle->unbuffered_fetch_owner= 0;
453
/* Don't clear handle in drizzleclient_free_result */
456
return((DRIZZLE_ROW) NULL);
460
if (!res->data_cursor)
462
return(res->current_row=(DRIZZLE_ROW) NULL);
464
tmp = res->data_cursor->data;
465
res->data_cursor = res->data_cursor->next;
466
return(res->current_row=tmp);
471
/**************************************************************************
472
Get column lengths of the current row
473
If one uses drizzleclient_use_result, res->lengths contains the length information,
474
else the lengths are calculated from the offset between pointers.
475
**************************************************************************/
478
drizzleclient_fetch_lengths(DRIZZLE_RES *res)
482
if (!(column=res->current_row))
483
return 0; /* Something is wrong */
485
(*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
491
drizzleclient_options(DRIZZLE *drizzle,enum drizzle_option option, const void *arg)
494
case DRIZZLE_OPT_CONNECT_TIMEOUT:
495
drizzle->options.connect_timeout= *(uint32_t*) arg;
497
case DRIZZLE_OPT_READ_TIMEOUT:
498
drizzle->options.read_timeout= *(uint32_t*) arg;
500
case DRIZZLE_OPT_WRITE_TIMEOUT:
501
drizzle->options.write_timeout= *(uint32_t*) arg;
503
case DRIZZLE_OPT_COMPRESS:
504
drizzle->options.compress= 1; /* Remember for connect */
505
drizzle->options.client_flag|= CLIENT_COMPRESS;
507
case DRIZZLE_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
508
if (!arg || (*(uint32_t*) arg) ? 1 : 0)
509
drizzle->options.client_flag|= CLIENT_LOCAL_FILES;
511
drizzle->options.client_flag&= ~CLIENT_LOCAL_FILES;
513
case DRIZZLE_READ_DEFAULT_FILE:
514
if (drizzle->options.my_cnf_file != NULL)
515
free(drizzle->options.my_cnf_file);
516
drizzle->options.my_cnf_file=strdup(arg);
518
case DRIZZLE_READ_DEFAULT_GROUP:
519
if (drizzle->options.my_cnf_group != NULL)
520
free(drizzle->options.my_cnf_group);
521
drizzle->options.my_cnf_group=strdup(arg);
523
case DRIZZLE_OPT_PROTOCOL:
525
case DRIZZLE_OPT_USE_REMOTE_CONNECTION:
526
case DRIZZLE_OPT_GUESS_CONNECTION:
527
drizzle->options.methods_to_use= option;
529
case DRIZZLE_SET_CLIENT_IP:
530
drizzle->options.client_ip= strdup(arg);
532
case DRIZZLE_SECURE_AUTH:
533
drizzle->options.secure_auth= *(const bool *) arg;
535
case DRIZZLE_REPORT_DATA_TRUNCATION:
536
drizzle->options.report_data_truncation= (*(const bool *) arg) ? 1 : 0;
538
case DRIZZLE_OPT_RECONNECT:
539
drizzle->reconnect= *(const bool *) arg;
541
case DRIZZLE_OPT_SSL_VERIFY_SERVER_CERT:
542
if (*(const bool*) arg)
543
drizzle->options.client_flag|= CLIENT_SSL_VERIFY_SERVER_CERT;
545
drizzle->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
554
/****************************************************************************
555
Functions to get information from the DRIZZLE structure
556
These are functions to make shared libraries more usable.
557
****************************************************************************/
560
uint64_t drizzleclient_num_rows(const DRIZZLE_RES *res)
562
return res->row_count;
565
unsigned int drizzleclient_num_fields(const DRIZZLE_RES *res)
567
return res->field_count;
572
Get version number for server in a form easy to test on
575
drizzleclient_get_server_version()
582
We will ensure that a newer server always has a bigger number.
585
Signed number > 323000
589
drizzleclient_get_server_version(const DRIZZLE *drizzle)
591
uint32_t major, minor, version;
592
char *pos= drizzle->server_version, *end_pos;
593
major= (uint32_t) strtoul(pos, &end_pos, 10); pos=end_pos+1;
594
minor= (uint32_t) strtoul(pos, &end_pos, 10); pos=end_pos+1;
595
version= (uint32_t) strtoul(pos, &end_pos, 10);
596
return (uint32_t) major*10000L+(uint32_t) (minor*100+version);