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>
82
#include "libdrizzle.h"
86
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
87
struct passwd *getpwuid(uid_t);
92
/*****************************************************************************
93
Read a packet from server. Give error message if socket was down
94
or packet is an error message
95
*****************************************************************************/
97
/* I'm not sure if this is even used anymore, but now that libdrizzleclient is
98
server only, this is safe to set here. */
99
extern "C" bool safe_read_error_impl(NET *net);
101
bool safe_read_error_impl(NET *net)
104
return drizzleclient_vio_was_interrupted(net->vio);
109
safe_read_error_hook_func safe_read_error_hook= safe_read_error_impl;
111
uint32_t drizzleclient_cli_safe_read(DRIZZLE *drizzle)
113
NET *net= &drizzle->net;
117
len=drizzleclient_net_read(net);
119
if (len == packet_error || len == 0)
121
if (safe_read_error_hook != NULL)
122
if (safe_read_error_hook(net))
123
return (packet_error);
124
drizzleclient_disconnect(drizzle);
125
drizzleclient_set_error(drizzle, net->last_errno == CR_NET_PACKET_TOO_LARGE ?
126
CR_NET_PACKET_TOO_LARGE : CR_SERVER_LOST,
127
drizzleclient_sqlstate_get_unknown());
128
return (packet_error);
130
if (net->read_pos[0] == 255)
134
char *pos=(char*) net->read_pos+1;
135
net->last_errno=uint2korr(pos);
140
strncpy(net->sqlstate, pos+1, LIBDRIZZLE_SQLSTATE_LENGTH);
141
pos+= LIBDRIZZLE_SQLSTATE_LENGTH+1;
146
The SQL state hasn't been received -- it should be reset to HY000
147
(unknown error sql state).
150
strcpy(net->sqlstate, drizzleclient_sqlstate_get_unknown());
153
strncpy(net->last_error,(char*) pos, min((uint32_t) len,
154
(uint32_t) sizeof(net->last_error)-1));
157
drizzleclient_set_error(drizzle, CR_UNKNOWN_ERROR, drizzleclient_sqlstate_get_unknown());
159
Cover a protocol design error: error packet does not
160
contain the server status. Therefore, the client has no way
161
to find out whether there are more result sets of
162
a multiple-result-set statement pending. Luckily, in 5.0 an
163
error always aborts execution of a statement, wherever it is
164
a multi-statement or a stored procedure, so it should be
165
safe to unconditionally turn off the flag here.
167
drizzle->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
169
return(packet_error);
175
drizzleclient_cli_advanced_command(DRIZZLE *drizzle, enum enum_server_command command,
176
const unsigned char *header, uint32_t header_length,
177
const unsigned char *arg, uint32_t arg_length, bool skip_check)
179
NET *net= &drizzle->net;
181
bool stmt_skip= false;
183
if (drizzle->net.vio == 0)
184
{ /* Do reconnect if possible */
185
if (drizzleclient_reconnect(drizzle) || stmt_skip)
188
if (drizzle->status != DRIZZLE_STATUS_READY ||
189
drizzle->server_status & SERVER_MORE_RESULTS_EXISTS)
191
drizzleclient_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC,
192
drizzleclient_sqlstate_get_unknown());
196
drizzleclient_drizzleclient_net_clear_error(net);
198
drizzle->affected_rows= ~(uint64_t) 0;
200
We don't want to clear the protocol buffer on COM_QUIT, because if
201
the previous command was a shutdown command, we may have the
202
response for the COM_QUIT already in the communication buffer
204
drizzleclient_net_clear(&drizzle->net, (command != COM_QUIT));
206
if (drizzleclient_net_write_command(net,(unsigned char) command, header, header_length,
209
if (net->last_errno == CR_NET_PACKET_TOO_LARGE)
211
drizzleclient_set_error(drizzle, CR_NET_PACKET_TOO_LARGE, drizzleclient_sqlstate_get_unknown());
214
drizzleclient_disconnect(drizzle);
215
if (drizzleclient_reconnect(drizzle) || stmt_skip)
217
if (drizzleclient_net_write_command(net,(unsigned char) command, header, header_length,
220
drizzleclient_set_error(drizzle, CR_SERVER_GONE_ERROR, drizzleclient_sqlstate_get_unknown());
226
result= ((drizzle->packet_length=drizzleclient_cli_safe_read(drizzle)) == packet_error ?
232
void drizzleclient_free_old_query(DRIZZLE *drizzle)
236
/* TODO - we need to de-alloc field storage */
237
free(drizzle->fields->catalog);
238
free(drizzle->fields->db);
239
free(drizzle->fields->table);
240
free(drizzle->fields->org_table);
241
free(drizzle->fields->name);
242
free(drizzle->fields->org_name);
243
free(drizzle->fields->def);
244
free(drizzle->fields);
247
/* init_alloc_root(&drizzle->field_alloc,8192,0); */ /* Assume rowlength < 8192 */
249
drizzle->field_count= 0; /* For API */
250
drizzle->warning_count= 0;
260
drizzleclient_free_result(DRIZZLE_RES *result)
264
DRIZZLE *drizzle= result->handle;
267
if (drizzle->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
268
drizzle->unbuffered_fetch_owner= 0;
269
if (drizzle->status == DRIZZLE_STATUS_USE_RESULT)
271
(*drizzle->methods->flush_use_result)(drizzle);
272
drizzle->status=DRIZZLE_STATUS_READY;
273
if (drizzle->unbuffered_fetch_owner)
274
*drizzle->unbuffered_fetch_owner= true;
277
drizzleclient_free_rows(result->data);
278
/* TODO: free result->fields */
280
free((unsigned char*) result->row);
281
free((unsigned char*) result);
288
/* Read all rows (fields or data) from server */
290
DRIZZLE_DATA *drizzleclient_cli_read_rows(DRIZZLE *drizzle, DRIZZLE_FIELD *DRIZZLE_FIELDs, uint32_t fields)
297
DRIZZLE_DATA *result;
298
DRIZZLE_ROWS **prev_ptr,*cur;
299
NET *net = &drizzle->net;
301
if ((pkt_len= drizzleclient_cli_safe_read(drizzle)) == packet_error)
303
if (!(result=(DRIZZLE_DATA*) malloc(sizeof(DRIZZLE_DATA))))
305
drizzleclient_set_error(drizzle, CR_OUT_OF_MEMORY,
306
drizzleclient_sqlstate_get_unknown());
309
memset(result, 0, sizeof(DRIZZLE_DATA));
310
prev_ptr= &result->data;
312
result->fields=fields;
315
The last EOF packet is either a 254 (0xFE) character followed by 1-7 status bytes.
317
This doesn't conflict with normal usage of 254 which stands for a
318
string where the length of the string is 8 bytes. (see drizzleclient_net_field_length())
321
while (*(cp=net->read_pos) != DRIZZLE_PROTOCOL_NO_MORE_DATA || pkt_len >= 8)
324
if (!(cur= (DRIZZLE_ROWS*) malloc(sizeof(DRIZZLE_ROWS))) ||
325
!(cur->data= ((DRIZZLE_ROW) malloc((fields+1)*sizeof(char *)+pkt_len))))
327
drizzleclient_free_rows(result);
328
drizzleclient_set_error(drizzle, CR_OUT_OF_MEMORY, drizzleclient_sqlstate_get_unknown());
332
prev_ptr= &cur->next;
333
to= (char*) (cur->data+fields+1);
335
for (field=0 ; field < fields ; field++)
337
if ((len= drizzleclient_net_field_length(&cp)) == NULL_LENGTH)
339
cur->data[field] = 0;
343
cur->data[field] = to;
344
if (len > (uint32_t) (end_to - to))
346
drizzleclient_free_rows(result);
347
drizzleclient_set_error(drizzle, CR_MALFORMED_PACKET,
348
drizzleclient_sqlstate_get_unknown());
357
if (DRIZZLE_FIELDs[field].max_length < len)
358
DRIZZLE_FIELDs[field].max_length=len;
362
cur->data[field]=to; /* End of last field */
363
if ((pkt_len=drizzleclient_cli_safe_read(drizzle)) == packet_error)
365
drizzleclient_free_rows(result);
369
*prev_ptr=0; /* last pointer is null */
370
if (pkt_len > 1) /* DRIZZLE 4.1 protocol */
372
drizzle->warning_count= uint2korr(cp+1);
373
drizzle->server_status= uint2korr(cp+3);
379
Read one row. Uses packet buffer as storage for fields.
380
When next packet is read, the previous field values are destroyed
385
read_one_row(DRIZZLE *drizzle, uint32_t fields, DRIZZLE_ROW row, uint32_t *lengths)
388
uint32_t pkt_len,len;
389
unsigned char *pos, *prev_pos, *end_pos;
390
NET *net= &drizzle->net;
392
if ((pkt_len=drizzleclient_cli_safe_read(drizzle)) == packet_error)
394
if (pkt_len <= 8 && net->read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA)
396
if (pkt_len > 1) /* DRIZZLE 4.1 protocol */
398
drizzle->warning_count= uint2korr(net->read_pos+1);
399
drizzle->server_status= uint2korr(net->read_pos+3);
401
return 1; /* End of data */
403
prev_pos= 0; /* allowed to write at packet[-1] */
406
for (field=0 ; field < fields ; field++)
408
if ((len= drizzleclient_net_field_length(&pos)) == NULL_LENGTH)
415
if (len > (uint32_t) (end_pos - pos))
417
drizzleclient_set_error(drizzle, CR_UNKNOWN_ERROR,
418
drizzleclient_sqlstate_get_unknown());
421
row[field] = (char*) pos;
426
*prev_pos=0; /* Terminate prev field */
429
row[field]=(char*) prev_pos+1; /* End of last field */
430
*prev_pos=0; /* Terminate last field */
435
/**************************************************************************
436
Return next row of the query results
437
**************************************************************************/
440
drizzleclient_fetch_row(DRIZZLE_RES *res)
443
{ /* Unbufferred fetch */
446
DRIZZLE *drizzle= res->handle;
447
if (drizzle->status != DRIZZLE_STATUS_USE_RESULT)
449
drizzleclient_set_error(drizzle,
450
res->unbuffered_fetch_cancelled ?
451
CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
452
drizzleclient_sqlstate_get_unknown());
454
else if (!(read_one_row(drizzle, res->field_count, res->row, res->lengths)))
457
return(res->current_row=res->row);
460
drizzle->status=DRIZZLE_STATUS_READY;
462
Reset only if owner points to us: there is a chance that somebody
463
started new query after drizzle_stmt_close():
465
if (drizzle->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
466
drizzle->unbuffered_fetch_owner= 0;
467
/* Don't clear handle in drizzleclient_free_result */
470
return((DRIZZLE_ROW) NULL);
474
if (!res->data_cursor)
476
return(res->current_row=(DRIZZLE_ROW) NULL);
478
tmp = res->data_cursor->data;
479
res->data_cursor = res->data_cursor->next;
480
return(res->current_row=tmp);
485
/**************************************************************************
486
Get column lengths of the current row
487
If one uses drizzleclient_use_result, res->lengths contains the length information,
488
else the lengths are calculated from the offset between pointers.
489
**************************************************************************/
492
drizzleclient_fetch_lengths(DRIZZLE_RES *res)
496
if (!(column=res->current_row))
497
return 0; /* Something is wrong */
499
(*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
505
drizzleclient_options(DRIZZLE *drizzle,enum drizzle_option option, const void *arg)
508
case DRIZZLE_OPT_CONNECT_TIMEOUT:
509
drizzle->options.connect_timeout= *(uint32_t*) arg;
511
case DRIZZLE_OPT_READ_TIMEOUT:
512
drizzle->options.read_timeout= *(uint32_t*) arg;
514
case DRIZZLE_OPT_WRITE_TIMEOUT:
515
drizzle->options.write_timeout= *(uint32_t*) arg;
517
case DRIZZLE_OPT_COMPRESS:
518
drizzle->options.compress= 1; /* Remember for connect */
519
drizzle->options.client_flag|= CLIENT_COMPRESS;
521
case DRIZZLE_READ_DEFAULT_FILE:
522
if (drizzle->options.my_cnf_file != NULL)
523
free(drizzle->options.my_cnf_file);
524
drizzle->options.my_cnf_file=strdup((char *)arg);
526
case DRIZZLE_READ_DEFAULT_GROUP:
527
if (drizzle->options.my_cnf_group != NULL)
528
free(drizzle->options.my_cnf_group);
529
drizzle->options.my_cnf_group=strdup((char *)arg);
531
case DRIZZLE_OPT_PROTOCOL:
533
case DRIZZLE_OPT_USE_REMOTE_CONNECTION:
534
case DRIZZLE_OPT_GUESS_CONNECTION:
535
drizzle->options.methods_to_use= option;
537
case DRIZZLE_SET_CLIENT_IP:
538
drizzle->options.client_ip= strdup((char *)arg);
540
case DRIZZLE_SECURE_AUTH:
541
drizzle->options.secure_auth= *(const bool *) arg;
543
case DRIZZLE_REPORT_DATA_TRUNCATION:
544
drizzle->options.report_data_truncation= (*(const bool *) arg) ? 1 : 0;
546
case DRIZZLE_OPT_RECONNECT:
547
drizzle->reconnect= *(const bool *) arg;
549
case DRIZZLE_OPT_SSL_VERIFY_SERVER_CERT:
550
if (*(const bool*) arg)
551
drizzle->options.client_flag|= CLIENT_SSL_VERIFY_SERVER_CERT;
553
drizzle->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
562
/****************************************************************************
563
Functions to get information from the DRIZZLE structure
564
These are functions to make shared libraries more usable.
565
****************************************************************************/
568
uint64_t drizzleclient_num_rows(const DRIZZLE_RES *res)
570
return res->row_count;
573
unsigned int drizzleclient_num_fields(const DRIZZLE_RES *res)
575
return res->field_count;
580
Get version number for server in a form easy to test on
583
drizzleclient_get_server_version()
590
We will ensure that a newer server always has a bigger number.
593
Signed number > 323000
597
drizzleclient_get_server_version(const DRIZZLE *drizzle)
599
uint32_t major, minor, version;
600
char *pos= drizzle->server_version, *end_pos;
601
major= (uint32_t) strtoul(pos, &end_pos, 10); pos=end_pos+1;
602
minor= (uint32_t) strtoul(pos, &end_pos, 10); pos=end_pos+1;
603
version= (uint32_t) strtoul(pos, &end_pos, 10);
604
return (uint32_t) major*10000L+(uint32_t) (minor*100+version);