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 libdrizzle.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
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
42
#include <libdrizzle/libdrizzle.h>
43
#include <libdrizzle/net_serv.h>
44
#include "libdrizzle_priv.h"
45
#include <libdrizzle/pack.h>
48
#include <sys/ioctl.h>
52
/* Remove client convenience wrappers */
53
#undef max_allowed_packet
54
#undef net_buffer_length
56
#include <libdrizzle/errmsg.h>
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>
82
#include "local_infile.h"
91
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
92
struct passwd *getpwuid(uid_t);
98
/*****************************************************************************
99
Read a packet from server. Give error message if socket was down
100
or packet is an error message
101
*****************************************************************************/
102
safe_read_error_hook_func safe_read_error_hook= NULL;
104
uint32_t cli_safe_read(DRIZZLE *drizzle)
106
NET *net= &drizzle->net;
110
len=my_net_read(net);
112
if (len == packet_error || len == 0)
114
if (safe_read_error_hook != NULL)
115
if (safe_read_error_hook(net))
116
return (packet_error);
117
drizzle_disconnect(drizzle);
118
drizzle_set_error(drizzle, net->last_errno == CR_NET_PACKET_TOO_LARGE ?
119
CR_NET_PACKET_TOO_LARGE : CR_SERVER_LOST,
120
sqlstate_get_unknown());
121
return (packet_error);
123
if (net->read_pos[0] == 255)
127
char *pos=(char*) net->read_pos+1;
128
net->last_errno=uint2korr(pos);
133
strncpy(net->sqlstate, pos+1, LIBDRIZZLE_SQLSTATE_LENGTH);
134
pos+= LIBDRIZZLE_SQLSTATE_LENGTH+1;
139
The SQL state hasn't been received -- it should be reset to HY000
140
(unknown error sql state).
143
strcpy(net->sqlstate, sqlstate_get_unknown());
146
strncpy(net->last_error,(char*) pos, min((uint32_t) len,
147
(uint32_t) sizeof(net->last_error)-1));
150
drizzle_set_error(drizzle, CR_UNKNOWN_ERROR, sqlstate_get_unknown());
152
Cover a protocol design error: error packet does not
153
contain the server status. Therefore, the client has no way
154
to find out whether there are more result sets of
155
a multiple-result-set statement pending. Luckily, in 5.0 an
156
error always aborts execution of a statement, wherever it is
157
a multi-statement or a stored procedure, so it should be
158
safe to unconditionally turn off the flag here.
160
drizzle->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
162
return(packet_error);
168
cli_advanced_command(DRIZZLE *drizzle, enum enum_server_command command,
169
const unsigned char *header, uint32_t header_length,
170
const unsigned char *arg, uint32_t arg_length, bool skip_check)
172
NET *net= &drizzle->net;
174
bool stmt_skip= false;
176
if (drizzle->net.vio == 0)
177
{ /* Do reconnect if possible */
178
if (drizzle_reconnect(drizzle) || stmt_skip)
181
if (drizzle->status != DRIZZLE_STATUS_READY ||
182
drizzle->server_status & SERVER_MORE_RESULTS_EXISTS)
184
drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC,
185
sqlstate_get_unknown());
189
net_clear_error(net);
191
drizzle->affected_rows= ~(uint64_t) 0;
193
We don't want to clear the protocol buffer on COM_QUIT, because if
194
the previous command was a shutdown command, we may have the
195
response for the COM_QUIT already in the communication buffer
197
net_clear(&drizzle->net, (command != COM_QUIT));
199
if (net_write_command(net,(unsigned char) command, header, header_length,
202
if (net->last_errno == CR_NET_PACKET_TOO_LARGE)
204
drizzle_set_error(drizzle, CR_NET_PACKET_TOO_LARGE, sqlstate_get_unknown());
207
drizzle_disconnect(drizzle);
208
if (drizzle_reconnect(drizzle) || stmt_skip)
210
if (net_write_command(net,(unsigned char) command, header, header_length,
213
drizzle_set_error(drizzle, CR_SERVER_GONE_ERROR, sqlstate_get_unknown());
219
result= ((drizzle->packet_length=cli_safe_read(drizzle)) == packet_error ?
225
void free_old_query(DRIZZLE *drizzle)
229
/* TODO - we need to de-alloc field storage */
230
free(drizzle->fields->catalog);
231
free(drizzle->fields->db);
232
free(drizzle->fields->table);
233
free(drizzle->fields->org_table);
234
free(drizzle->fields->name);
235
free(drizzle->fields->org_name);
236
free(drizzle->fields->def);
237
free(drizzle->fields);
240
/* init_alloc_root(&drizzle->field_alloc,8192,0); */ /* Assume rowlength < 8192 */
242
drizzle->field_count= 0; /* For API */
243
drizzle->warning_count= 0;
253
drizzle_free_result(DRIZZLE_RES *result)
257
DRIZZLE *drizzle= result->handle;
260
if (drizzle->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
261
drizzle->unbuffered_fetch_owner= 0;
262
if (drizzle->status == DRIZZLE_STATUS_USE_RESULT)
264
(*drizzle->methods->flush_use_result)(drizzle);
265
drizzle->status=DRIZZLE_STATUS_READY;
266
if (drizzle->unbuffered_fetch_owner)
267
*drizzle->unbuffered_fetch_owner= true;
270
free_rows(result->data);
271
/* TODO: free result->fields */
273
free((unsigned char*) result->row);
274
free((unsigned char*) result);
281
/* Read all rows (fields or data) from server */
283
DRIZZLE_DATA *cli_read_rows(DRIZZLE *drizzle, DRIZZLE_FIELD *DRIZZLE_FIELDs, uint32_t fields)
290
DRIZZLE_DATA *result;
291
DRIZZLE_ROWS **prev_ptr,*cur;
292
NET *net = &drizzle->net;
294
if ((pkt_len= cli_safe_read(drizzle)) == packet_error)
296
if (!(result=(DRIZZLE_DATA*) malloc(sizeof(DRIZZLE_DATA))))
298
drizzle_set_error(drizzle, CR_OUT_OF_MEMORY,
299
sqlstate_get_unknown());
302
memset(result, 0, sizeof(DRIZZLE_DATA));
303
prev_ptr= &result->data;
305
result->fields=fields;
308
The last EOF packet is either a 254 (0xFE) character followed by 1-7 status bytes.
310
This doesn't conflict with normal usage of 254 which stands for a
311
string where the length of the string is 8 bytes. (see net_field_length())
314
while (*(cp=net->read_pos) != DRIZZLE_PROTOCOL_NO_MORE_DATA || pkt_len >= 8)
317
if (!(cur= (DRIZZLE_ROWS*) malloc(sizeof(DRIZZLE_ROWS))) ||
318
!(cur->data= ((DRIZZLE_ROW) malloc((fields+1)*sizeof(char *)+pkt_len))))
321
drizzle_set_error(drizzle, CR_OUT_OF_MEMORY, sqlstate_get_unknown());
325
prev_ptr= &cur->next;
326
to= (char*) (cur->data+fields+1);
328
for (field=0 ; field < fields ; field++)
330
if ((len= net_field_length(&cp)) == NULL_LENGTH)
332
cur->data[field] = 0;
336
cur->data[field] = to;
337
if (len > (uint32_t) (end_to - to))
340
drizzle_set_error(drizzle, CR_MALFORMED_PACKET,
341
sqlstate_get_unknown());
350
if (DRIZZLE_FIELDs[field].max_length < len)
351
DRIZZLE_FIELDs[field].max_length=len;
355
cur->data[field]=to; /* End of last field */
356
if ((pkt_len=cli_safe_read(drizzle)) == packet_error)
362
*prev_ptr=0; /* last pointer is null */
363
if (pkt_len > 1) /* DRIZZLE 4.1 protocol */
365
drizzle->warning_count= uint2korr(cp+1);
366
drizzle->server_status= uint2korr(cp+3);
372
Read one row. Uses packet buffer as storage for fields.
373
When next packet is read, the previous field values are destroyed
378
read_one_row(DRIZZLE *drizzle, uint32_t fields, DRIZZLE_ROW row, uint32_t *lengths)
381
uint32_t pkt_len,len;
382
unsigned char *pos, *prev_pos, *end_pos;
383
NET *net= &drizzle->net;
385
if ((pkt_len=cli_safe_read(drizzle)) == packet_error)
387
if (pkt_len <= 8 && net->read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA)
389
if (pkt_len > 1) /* DRIZZLE 4.1 protocol */
391
drizzle->warning_count= uint2korr(net->read_pos+1);
392
drizzle->server_status= uint2korr(net->read_pos+3);
394
return 1; /* End of data */
396
prev_pos= 0; /* allowed to write at packet[-1] */
399
for (field=0 ; field < fields ; field++)
401
if ((len= net_field_length(&pos)) == NULL_LENGTH)
408
if (len > (uint32_t) (end_pos - pos))
410
drizzle_set_error(drizzle, CR_UNKNOWN_ERROR,
411
sqlstate_get_unknown());
414
row[field] = (char*) pos;
419
*prev_pos=0; /* Terminate prev field */
422
row[field]=(char*) prev_pos+1; /* End of last field */
423
*prev_pos=0; /* Terminate last field */
428
/**************************************************************************
429
Return next row of the query results
430
**************************************************************************/
433
drizzle_fetch_row(DRIZZLE_RES *res)
436
{ /* Unbufferred fetch */
439
DRIZZLE *drizzle= res->handle;
440
if (drizzle->status != DRIZZLE_STATUS_USE_RESULT)
442
drizzle_set_error(drizzle,
443
res->unbuffered_fetch_cancelled ?
444
CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
445
sqlstate_get_unknown());
447
else if (!(read_one_row(drizzle, res->field_count, res->row, res->lengths)))
450
return(res->current_row=res->row);
453
drizzle->status=DRIZZLE_STATUS_READY;
455
Reset only if owner points to us: there is a chance that somebody
456
started new query after drizzle_stmt_close():
458
if (drizzle->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
459
drizzle->unbuffered_fetch_owner= 0;
460
/* Don't clear handle in drizzle_free_result */
463
return((DRIZZLE_ROW) NULL);
467
if (!res->data_cursor)
469
return(res->current_row=(DRIZZLE_ROW) NULL);
471
tmp = res->data_cursor->data;
472
res->data_cursor = res->data_cursor->next;
473
return(res->current_row=tmp);
478
/**************************************************************************
479
Get column lengths of the current row
480
If one uses drizzle_use_result, res->lengths contains the length information,
481
else the lengths are calculated from the offset between pointers.
482
**************************************************************************/
485
drizzle_fetch_lengths(DRIZZLE_RES *res)
489
if (!(column=res->current_row))
490
return 0; /* Something is wrong */
492
(*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
498
drizzle_options(DRIZZLE *drizzle,enum drizzle_option option, const void *arg)
501
case DRIZZLE_OPT_CONNECT_TIMEOUT:
502
drizzle->options.connect_timeout= *(uint32_t*) arg;
504
case DRIZZLE_OPT_READ_TIMEOUT:
505
drizzle->options.read_timeout= *(uint32_t*) arg;
507
case DRIZZLE_OPT_WRITE_TIMEOUT:
508
drizzle->options.write_timeout= *(uint32_t*) arg;
510
case DRIZZLE_OPT_COMPRESS:
511
drizzle->options.compress= 1; /* Remember for connect */
512
drizzle->options.client_flag|= CLIENT_COMPRESS;
514
case DRIZZLE_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
515
if (!arg || (*(uint32_t*) arg) ? 1 : 0)
516
drizzle->options.client_flag|= CLIENT_LOCAL_FILES;
518
drizzle->options.client_flag&= ~CLIENT_LOCAL_FILES;
520
case DRIZZLE_READ_DEFAULT_FILE:
521
if (drizzle->options.my_cnf_file != NULL)
522
free(drizzle->options.my_cnf_file);
523
drizzle->options.my_cnf_file=strdup(arg);
525
case DRIZZLE_READ_DEFAULT_GROUP:
526
if (drizzle->options.my_cnf_group != NULL)
527
free(drizzle->options.my_cnf_group);
528
drizzle->options.my_cnf_group=strdup(arg);
530
case DRIZZLE_OPT_PROTOCOL:
532
case DRIZZLE_OPT_USE_REMOTE_CONNECTION:
533
case DRIZZLE_OPT_GUESS_CONNECTION:
534
drizzle->options.methods_to_use= option;
536
case DRIZZLE_SET_CLIENT_IP:
537
drizzle->options.client_ip= strdup(arg);
539
case DRIZZLE_SECURE_AUTH:
540
drizzle->options.secure_auth= *(const bool *) arg;
542
case DRIZZLE_REPORT_DATA_TRUNCATION:
543
drizzle->options.report_data_truncation= (*(const bool *) arg) ? 1 : 0;
545
case DRIZZLE_OPT_RECONNECT:
546
drizzle->reconnect= *(const bool *) arg;
548
case DRIZZLE_OPT_SSL_VERIFY_SERVER_CERT:
549
if (*(const bool*) arg)
550
drizzle->options.client_flag|= CLIENT_SSL_VERIFY_SERVER_CERT;
552
drizzle->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
561
/****************************************************************************
562
Functions to get information from the DRIZZLE structure
563
These are functions to make shared libraries more usable.
564
****************************************************************************/
567
uint64_t drizzle_num_rows(const DRIZZLE_RES *res)
569
return res->row_count;
572
unsigned int drizzle_num_fields(const DRIZZLE_RES *res)
574
return res->field_count;
579
Get version number for server in a form easy to test on
582
drizzle_get_server_version()
589
We will ensure that a newer server always has a bigger number.
592
Signed number > 323000
596
drizzle_get_server_version(const DRIZZLE *drizzle)
598
uint32_t major, minor, version;
599
char *pos= drizzle->server_version, *end_pos;
600
major= (uint32_t) strtoul(pos, &end_pos, 10); pos=end_pos+1;
601
minor= (uint32_t) strtoul(pos, &end_pos, 10); pos=end_pos+1;
602
version= (uint32_t) strtoul(pos, &end_pos, 10);
603
return (uint32_t) major*10000L+(uint32_t) (minor*100+version);