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
#include "libdrizzle_priv.h"
23
#include <libdrizzle/libdrizzle.h>
24
#include <libdrizzle/pack.h>
25
#include <libdrizzle/errmsg.h>
33
#include <sys/socket.h>
34
#include <netinet/in.h>
35
#include <arpa/inet.h>
40
#ifdef HAVE_SYS_SELECT_H
41
#include <sys/select.h>
51
#define INADDR_NONE -1
57
/* Borrowed from libicu header */
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)\
72
#undef net_buffer_length
73
#undef max_allowed_packet
75
uint32_t net_buffer_length= 8192;
76
uint32_t max_allowed_packet= 1024L*1024L*1024L;
78
unsigned int drizzle_port=0;
83
static DRIZZLE_PARAMETERS drizzle_internal_parameters=
84
{&max_allowed_packet, &net_buffer_length, 0};
86
const DRIZZLE_PARAMETERS * drizzle_get_parameters(void)
88
return &drizzle_internal_parameters;
91
unsigned int drizzle_get_default_port(void)
96
void drizzle_set_default_port(unsigned int port)
102
Expand wildcard to a sql string
106
append_wild(char *to, char *end, const char *wild)
108
end-=5; /* Some extra */
111
to= strcpy(to," like '");
112
to+= 7; /* strlen(" like '"); */
114
while (*wild && to < end)
116
if (*wild == '\\' || *wild == '\'')
120
if (*wild) /* Too small buffer */
121
*to++='%'; /* Nicer this way */
127
/**************************************************************************
128
Change user and database
129
**************************************************************************/
131
int cli_read_change_user_result(DRIZZLE *drizzle)
135
pkt_length= cli_safe_read(drizzle);
137
if (pkt_length == packet_error)
143
bool drizzle_change_user(DRIZZLE *drizzle, const char *user,
144
const char *passwd, const char *db)
146
char buff[USERNAME_LENGTH+SCRAMBLED_PASSWORD_CHAR_LENGTH+NAME_LEN+2];
150
/* Use an empty string instead of NULL. */
157
/* Store user into the buffer */
158
end= strncpy(end, user, USERNAME_LENGTH) + USERNAME_LENGTH + 1;
160
/* write scrambled password according to server capabilities */
164
*end++= SCRAMBLE_LENGTH;
165
end+= SCRAMBLE_LENGTH;
169
*end++= '\0'; /* empty password */
170
/* Add database if needed */
171
end= strncpy(end, db ? db : "", NAME_LEN) + NAME_LEN + 1;
173
/* Add character set number. */
174
if (drizzle->server_capabilities & CLIENT_SECURE_CONNECTION)
176
int2store(end, (uint16_t) 45); // utf8mb4 number from mystrings/ctype-utf8.c
180
/* Write authentication package */
181
(void)simple_command(drizzle,COM_CHANGE_USER, (unsigned char*) buff, (uint32_t) (end-buff), 1);
183
rc= (*drizzle->methods->read_change_user_result)(drizzle);
187
/* Free old connect information */
191
free(drizzle->passwd);
195
/* alloc new connect information */
196
drizzle->user= strdup(user);
197
drizzle->passwd= strdup(passwd);
198
drizzle->db= db ? strdup(db) : 0;
204
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
205
struct passwd *getpwuid(uid_t);
206
char* getlogin(void);
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
**************************************************************************/
215
drizzle_query(DRIZZLE *drizzle, const char *query)
217
return drizzle_real_query(drizzle,query, (uint32_t) strlen(query));
221
/**************************************************************************
222
Return next field of the query results
223
**************************************************************************/
226
drizzle_fetch_field(DRIZZLE_RES *result)
228
if (result->current_field >= result->field_count)
230
return &result->fields[result->current_field++];
234
/**************************************************************************
235
Move to a specific row and column
236
**************************************************************************/
239
drizzle_data_seek(DRIZZLE_RES *result, uint64_t row)
243
for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
244
result->current_row=0;
245
result->data_cursor = tmp;
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
*************************************************************************/
256
drizzle_row_seek(DRIZZLE_RES *result, DRIZZLE_ROW_OFFSET row)
258
DRIZZLE_ROW_OFFSET return_value=result->data_cursor;
259
result->current_row= 0;
260
result->data_cursor= row;
266
drizzle_field_seek(DRIZZLE_RES *result, DRIZZLE_FIELD_OFFSET field_offset)
268
DRIZZLE_FIELD_OFFSET return_value=result->current_field;
269
result->current_field=field_offset;
274
/*****************************************************************************
275
List all tables in a database
276
If wild is given then only the tables matching wild is returned
277
*****************************************************************************/
280
drizzle_list_tables(DRIZZLE *drizzle, const char *wild)
283
char *ptr= strcpy(buff, "show tables");
284
ptr+= 11; /* strlen("show tables"); */
286
append_wild(ptr,buff+sizeof(buff),wild);
287
if (drizzle_query(drizzle,buff))
289
return (drizzle_store_result(drizzle));
293
DRIZZLE_FIELD *cli_list_fields(DRIZZLE *drizzle)
296
if (!(query= cli_read_rows(drizzle,(DRIZZLE_FIELD*) 0, 8)))
299
drizzle->field_count= (uint32_t) query->rows;
300
return unpack_fields(query, drizzle->field_count, 1);
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
**************************************************************************/
312
drizzle_list_fields(DRIZZLE *drizzle, const char *table, const char *wild)
315
DRIZZLE_FIELD *fields;
316
char buff[257], *end;
318
end= strncpy(buff, table, 128) + 128;
319
end= strncpy(end+1, wild ? wild : "", 128) + 128;
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)))
327
if (!(result = (DRIZZLE_RES *) malloc(sizeof(DRIZZLE_RES))))
330
memset(result, 0, sizeof(DRIZZLE_RES));
332
result->methods= drizzle->methods;
334
result->field_count = drizzle->field_count;
335
result->fields= fields;
340
/* List all running processes (threads) in server */
343
drizzle_list_processes(DRIZZLE *drizzle)
345
DRIZZLE_DATA *fields;
346
uint32_t field_count;
349
if (simple_command(drizzle,COM_PROCESS_INFO,0,0,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)))
356
if (!(drizzle->fields=unpack_fields(fields, field_count, 0)))
358
drizzle->status=DRIZZLE_STATUS_GET_RESULT;
359
drizzle->field_count=field_count;
360
return(drizzle_store_result(drizzle));
365
drizzle_shutdown(DRIZZLE *drizzle)
367
return(simple_command(drizzle, COM_SHUTDOWN, 0, 0, 0));
372
drizzle_refresh(DRIZZLE *drizzle, uint32_t options)
374
unsigned char bits[1];
375
bits[0]= (unsigned char) options;
376
return(simple_command(drizzle, COM_REFRESH, bits, 1, 0));
381
drizzle_kill(DRIZZLE *drizzle, uint32_t pid)
383
unsigned char buff[4];
385
return(simple_command(drizzle,COM_PROCESS_KILL,buff,sizeof(buff),0));
390
drizzle_set_server_option(DRIZZLE *drizzle, enum enum_drizzle_set_option option)
392
unsigned char buff[2];
393
int2store(buff, (uint32_t) option);
394
return(simple_command(drizzle, COM_SET_OPTION, buff, sizeof(buff), 0));
398
const char *cli_read_statistics(DRIZZLE *drizzle)
400
drizzle->net.read_pos[drizzle->packet_length]=0; /* End of stat string */
401
if (!drizzle->net.read_pos[0])
403
drizzle_set_error(drizzle, CR_WRONG_HOST_INFO, sqlstate_get_unknown());
404
return drizzle->net.last_error;
406
return (char*) drizzle->net.read_pos;
411
drizzle_ping(DRIZZLE *drizzle)
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);
422
drizzle_get_server_info(const DRIZZLE *drizzle)
424
return((char*) drizzle->server_version);
429
drizzle_get_host_info(const DRIZZLE *drizzle)
431
return(drizzle->host_info);
436
drizzle_get_proto_info(const DRIZZLE *drizzle)
438
return (drizzle->protocol_version);
442
drizzle_get_client_info(void)
444
return (char*) VERSION;
447
uint32_t drizzle_get_client_version(void)
449
return DRIZZLE_VERSION_ID;
452
bool drizzle_eof(const DRIZZLE_RES *res)
457
const DRIZZLE_FIELD * drizzle_fetch_field_direct(const DRIZZLE_RES *res, unsigned int fieldnr)
459
return &(res)->fields[fieldnr];
462
const DRIZZLE_FIELD * drizzle_fetch_fields(const DRIZZLE_RES *res)
467
DRIZZLE_ROW_OFFSET drizzle_row_tell(const DRIZZLE_RES *res)
469
return res->data_cursor;
472
DRIZZLE_FIELD_OFFSET drizzle_field_tell(const DRIZZLE_RES *res)
474
return res->current_field;
479
unsigned int drizzle_field_count(const DRIZZLE *drizzle)
481
return drizzle->field_count;
484
uint64_t drizzle_affected_rows(const DRIZZLE *drizzle)
486
return drizzle->affected_rows;
489
uint64_t drizzle_insert_id(const DRIZZLE *drizzle)
491
return drizzle->insert_id;
494
const char * drizzle_sqlstate(const DRIZZLE *drizzle)
496
return drizzle ? drizzle->net.sqlstate : sqlstate_get_cant_connect();
499
uint32_t drizzle_warning_count(const DRIZZLE *drizzle)
501
return drizzle->warning_count;
504
const char * drizzle_info(const DRIZZLE *drizzle)
506
return drizzle->info;
509
uint32_t drizzle_thread_id(const DRIZZLE *drizzle)
511
return drizzle->thread_id;
514
/****************************************************************************
515
Some support functions
516
****************************************************************************/
519
Functions called my my_net_init() to set some application specific variables
522
void my_net_local_init(NET *net)
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);
528
net->max_packet_size= (net_buffer_length > max_allowed_packet) ?
529
net_buffer_length : max_allowed_packet;
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');
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.
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.
551
drizzle_hex_string(char *to, const char *from, uint32_t length)
556
for (end= from + length; from < end; from++)
558
*to++= _dig_vec_upper[((unsigned char) *from) >> 4];
559
*to++= _dig_vec_upper[((unsigned char) *from) & 0x0F];
562
return (uint32_t) (to-to0);
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
572
drizzle_escape_string(char *to,const char *from, uint32_t length)
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++)
581
if (!U8_IS_SINGLE(*from))
583
tmp_length= U8_LENGTH(*from);
584
if (to + tmp_length > to_end)
595
case 0: /* Must be escaped for 'mysql' */
598
case '\n': /* Must be escaped for logs */
610
case '"': /* Better safe than sorry */
613
case '\032': /* This gives problems on Win32 */
638
return overflow ? (size_t) -1 : (size_t) (to - to_start);
641
int cli_unbuffered_fetch(DRIZZLE *drizzle, char **row)
643
if (packet_error == cli_safe_read(drizzle))
646
*row= ((drizzle->net.read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA) ? NULL :
647
(char*) (drizzle->net.read_pos+1));
651
/********************************************************************
653
*********************************************************************/
656
Commit the current transaction
659
bool drizzle_commit(DRIZZLE *drizzle)
661
return((bool) drizzle_real_query(drizzle, "commit", 6));
665
Rollback the current transaction
668
bool drizzle_rollback(DRIZZLE *drizzle)
670
return((bool) drizzle_real_query(drizzle, "rollback", 8));
675
Set autocommit to either true or false
678
bool drizzle_autocommit(DRIZZLE *drizzle, bool auto_mode)
680
return((bool) drizzle_real_query(drizzle, auto_mode ?
681
"set autocommit=1":"set autocommit=0",
686
/********************************************************************
687
Multi query execution + SPs APIs
688
*********************************************************************/
691
Returns true/false to indicate whether any more query results exist
692
to be read using drizzle_next_result()
695
bool drizzle_more_results(const DRIZZLE *drizzle)
697
return (drizzle->server_status & SERVER_MORE_RESULTS_EXISTS) ? true:false;
702
Reads and returns the next query results
704
int drizzle_next_result(DRIZZLE *drizzle)
706
if (drizzle->status != DRIZZLE_STATUS_READY)
708
drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC, sqlstate_get_unknown());
712
net_clear_error(&drizzle->net);
713
drizzle->affected_rows= ~(uint64_t) 0;
715
if (drizzle->server_status & SERVER_MORE_RESULTS_EXISTS)
716
return((*drizzle->methods->next_result)(drizzle));
718
return(-1); /* No more results */
722
DRIZZLE_RES * drizzle_use_result(DRIZZLE *drizzle)
724
return (*drizzle->methods->use_result)(drizzle);
727
bool drizzle_read_query_result(DRIZZLE *drizzle)
729
return (*drizzle->methods->read_query_result)(drizzle);