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
20
#include "libdrizzle.h"
21
#include "libdrizzle_priv.h"
30
#include <sys/socket.h>
31
#include <netinet/in.h>
32
#include <arpa/inet.h>
37
#ifdef HAVE_SYS_SELECT_H
38
#include <sys/select.h>
48
#define INADDR_NONE -1
54
#include <sql_common.h>
55
#include <drizzled/version.h>
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;
81
#define SOCKET_ERROR -1
84
If allowed through some configuration, then this needs to
87
#define MAX_LONG_DATA_LENGTH 8192
88
#define unsigned_field(A) ((A)->flags & UNSIGNED_FLAG)
91
static DRIZZLE_PARAMETERS drizzle_internal_parameters=
92
{&max_allowed_packet, &net_buffer_length, 0};
94
const DRIZZLE_PARAMETERS * drizzle_get_parameters(void)
96
return &drizzle_internal_parameters;
99
unsigned int drizzle_get_default_port(void)
104
void drizzle_set_default_port(unsigned int port)
110
Expand wildcard to a sql string
114
append_wild(char *to, char *end, const char *wild)
116
end-=5; /* Some extra */
119
to= strcpy(to," like '");
120
to+= 7; /* strlen(" like '"); */
122
while (*wild && to < end)
124
if (*wild == '\\' || *wild == '\'')
128
if (*wild) /* Too small buffer */
129
*to++='%'; /* Nicer this way */
135
/**************************************************************************
136
Change user and database
137
**************************************************************************/
139
int cli_read_change_user_result(DRIZZLE *drizzle)
143
pkt_length= cli_safe_read(drizzle);
145
if (pkt_length == packet_error)
151
bool drizzle_change_user(DRIZZLE *drizzle, const char *user,
152
const char *passwd, const char *db)
154
char buff[USERNAME_LENGTH+SCRAMBLED_PASSWORD_CHAR_LENGTH+NAME_LEN+2];
158
/* Use an empty string instead of NULL. */
165
/* Store user into the buffer */
166
end= strncpy(end, user, USERNAME_LENGTH) + USERNAME_LENGTH + 1;
168
/* write scrambled password according to server capabilities */
172
*end++= SCRAMBLE_LENGTH;
173
end+= SCRAMBLE_LENGTH;
177
*end++= '\0'; /* empty password */
178
/* Add database if needed */
179
end= strncpy(end, db ? db : "", NAME_LEN) + NAME_LEN + 1;
181
/* Add character set number. */
182
if (drizzle->server_capabilities & CLIENT_SECURE_CONNECTION)
184
int2store(end, (uint16_t) 45); // utf8mb4 number from mystrings/ctype-utf8.c
188
/* Write authentication package */
189
(void)simple_command(drizzle,COM_CHANGE_USER, (unsigned char*) buff, (uint32_t) (end-buff), 1);
191
rc= (*drizzle->methods->read_change_user_result)(drizzle);
195
/* Free old connect information */
199
free(drizzle->passwd);
203
/* alloc new connect information */
204
drizzle->user= strdup(user);
205
drizzle->passwd= strdup(passwd);
206
drizzle->db= db ? strdup(db) : 0;
212
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
213
struct passwd *getpwuid(uid_t);
214
char* getlogin(void);
217
/**************************************************************************
218
Do a query. If query returned rows, free old rows.
219
Read data by drizzle_store_result or by repeat call of drizzle_fetch_row
220
**************************************************************************/
223
drizzle_query(DRIZZLE *drizzle, const char *query)
225
return drizzle_real_query(drizzle,query, (uint32_t) strlen(query));
229
/**************************************************************************
230
Return next field of the query results
231
**************************************************************************/
234
drizzle_fetch_field(DRIZZLE_RES *result)
236
if (result->current_field >= result->field_count)
238
return &result->fields[result->current_field++];
242
/**************************************************************************
243
Move to a specific row and column
244
**************************************************************************/
247
drizzle_data_seek(DRIZZLE_RES *result, uint64_t row)
251
for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
252
result->current_row=0;
253
result->data_cursor = tmp;
257
/*************************************************************************
258
put the row or field cursor one a position one got from DRIZZLE_ROW_tell()
259
This doesn't restore any data. The next drizzle_fetch_row or
260
drizzle_fetch_field will return the next row or field after the last used
261
*************************************************************************/
264
drizzle_row_seek(DRIZZLE_RES *result, DRIZZLE_ROW_OFFSET row)
266
DRIZZLE_ROW_OFFSET return_value=result->data_cursor;
267
result->current_row= 0;
268
result->data_cursor= row;
274
drizzle_field_seek(DRIZZLE_RES *result, DRIZZLE_FIELD_OFFSET field_offset)
276
DRIZZLE_FIELD_OFFSET return_value=result->current_field;
277
result->current_field=field_offset;
282
/*****************************************************************************
283
List all tables in a database
284
If wild is given then only the tables matching wild is returned
285
*****************************************************************************/
288
drizzle_list_tables(DRIZZLE *drizzle, const char *wild)
291
char *ptr= strcpy(buff, "show tables");
292
ptr+= 11; /* strlen("show tables"); */
294
append_wild(ptr,buff+sizeof(buff),wild);
295
if (drizzle_query(drizzle,buff))
297
return (drizzle_store_result(drizzle));
301
DRIZZLE_FIELD *cli_list_fields(DRIZZLE *drizzle)
304
if (!(query= cli_read_rows(drizzle,(DRIZZLE_FIELD*) 0, 8)))
307
drizzle->field_count= (uint32_t) query->rows;
308
return unpack_fields(query, drizzle->field_count, 1);
312
/**************************************************************************
313
List all fields in a table
314
If wild is given then only the fields matching wild is returned
315
Instead of this use query:
316
show fields in 'table' like "wild"
317
**************************************************************************/
320
drizzle_list_fields(DRIZZLE *drizzle, const char *table, const char *wild)
323
DRIZZLE_FIELD *fields;
324
char buff[257], *end;
326
end= strncpy(buff, table, 128) + 128;
327
end= strncpy(end+1, wild ? wild : "", 128) + 128;
329
free_old_query(drizzle);
330
if (simple_command(drizzle, COM_FIELD_LIST, (unsigned char*) buff,
331
(uint32_t) (end-buff), 1) ||
332
!(fields= (*drizzle->methods->list_fields)(drizzle)))
335
if (!(result = (DRIZZLE_RES *) malloc(sizeof(DRIZZLE_RES))))
338
memset(result, 0, sizeof(DRIZZLE_RES));
340
result->methods= drizzle->methods;
342
result->field_count = drizzle->field_count;
343
result->fields= fields;
348
/* List all running processes (threads) in server */
351
drizzle_list_processes(DRIZZLE *drizzle)
353
DRIZZLE_DATA *fields;
354
uint32_t field_count;
357
if (simple_command(drizzle,COM_PROCESS_INFO,0,0,0))
359
free_old_query(drizzle);
360
pos=(unsigned char*) drizzle->net.read_pos;
361
field_count=(uint32_t) net_field_length(&pos);
362
if (!(fields = (*drizzle->methods->read_rows)(drizzle,(DRIZZLE_FIELD*) 0, 7)))
364
if (!(drizzle->fields=unpack_fields(fields, field_count, 0)))
366
drizzle->status=DRIZZLE_STATUS_GET_RESULT;
367
drizzle->field_count=field_count;
368
return(drizzle_store_result(drizzle));
373
drizzle_shutdown(DRIZZLE *drizzle)
375
return(simple_command(drizzle, COM_SHUTDOWN, 0, 0, 0));
380
drizzle_refresh(DRIZZLE *drizzle, uint32_t options)
382
unsigned char bits[1];
383
bits[0]= (unsigned char) options;
384
return(simple_command(drizzle, COM_REFRESH, bits, 1, 0));
389
drizzle_kill(DRIZZLE *drizzle, uint32_t pid)
391
unsigned char buff[4];
393
return(simple_command(drizzle,COM_PROCESS_KILL,buff,sizeof(buff),0));
398
drizzle_set_server_option(DRIZZLE *drizzle, enum enum_drizzle_set_option option)
400
unsigned char buff[2];
401
int2store(buff, (uint32_t) option);
402
return(simple_command(drizzle, COM_SET_OPTION, buff, sizeof(buff), 0));
406
const char *cli_read_statistics(DRIZZLE *drizzle)
408
drizzle->net.read_pos[drizzle->packet_length]=0; /* End of stat string */
409
if (!drizzle->net.read_pos[0])
411
drizzle_set_error(drizzle, CR_WRONG_HOST_INFO, sqlstate_get_unknown());
412
return drizzle->net.last_error;
414
return (char*) drizzle->net.read_pos;
419
drizzle_ping(DRIZZLE *drizzle)
422
res= simple_command(drizzle,COM_PING,0,0,0);
423
if (res == CR_SERVER_LOST && drizzle->reconnect)
424
res= simple_command(drizzle,COM_PING,0,0,0);
430
drizzle_get_server_info(const DRIZZLE *drizzle)
432
return((char*) drizzle->server_version);
437
drizzle_get_host_info(const DRIZZLE *drizzle)
439
return(drizzle->host_info);
444
drizzle_get_proto_info(const DRIZZLE *drizzle)
446
return (drizzle->protocol_version);
450
drizzle_get_client_info(void)
452
return (char*) DRIZZLE_SERVER_VERSION;
455
uint32_t drizzle_get_client_version(void)
457
return DRIZZLE_VERSION_ID;
460
bool drizzle_eof(const DRIZZLE_RES *res)
465
const DRIZZLE_FIELD * drizzle_fetch_field_direct(const DRIZZLE_RES *res, unsigned int fieldnr)
467
return &(res)->fields[fieldnr];
470
const DRIZZLE_FIELD * drizzle_fetch_fields(const DRIZZLE_RES *res)
475
DRIZZLE_ROW_OFFSET drizzle_row_tell(const DRIZZLE_RES *res)
477
return res->data_cursor;
480
DRIZZLE_FIELD_OFFSET drizzle_field_tell(const DRIZZLE_RES *res)
482
return res->current_field;
487
unsigned int drizzle_field_count(const DRIZZLE *drizzle)
489
return drizzle->field_count;
492
uint64_t drizzle_affected_rows(const DRIZZLE *drizzle)
494
return drizzle->affected_rows;
497
uint64_t drizzle_insert_id(const DRIZZLE *drizzle)
499
return drizzle->insert_id;
502
const char * drizzle_sqlstate(const DRIZZLE *drizzle)
504
return drizzle ? drizzle->net.sqlstate : sqlstate_get_cant_connect();
507
uint32_t drizzle_warning_count(const DRIZZLE *drizzle)
509
return drizzle->warning_count;
512
const char * drizzle_info(const DRIZZLE *drizzle)
514
return drizzle->info;
517
uint32_t drizzle_thread_id(const DRIZZLE *drizzle)
519
return drizzle->thread_id;
522
/****************************************************************************
523
Some support functions
524
****************************************************************************/
527
Functions called my my_net_init() to set some application specific variables
530
void my_net_local_init(NET *net)
532
net->max_packet= (uint32_t) net_buffer_length;
533
my_net_set_read_timeout(net, CLIENT_NET_READ_TIMEOUT);
534
my_net_set_write_timeout(net, CLIENT_NET_WRITE_TIMEOUT);
536
net->max_packet_size= (net_buffer_length > max_allowed_packet) ?
537
net_buffer_length : max_allowed_packet;
541
This function is used to create HEX string that you
542
can use in a SQL statement in of the either ways:
543
INSERT INTO blob_column VALUES (0xAABBCC); (any DRIZZLE version)
544
INSERT INTO blob_column VALUES (X'AABBCC');
546
The string in "from" is encoded to a HEX string.
547
The result is placed in "to" and a terminating null byte is appended.
549
The string pointed to by "from" must be "length" bytes long.
550
You must allocate the "to" buffer to be at least length*2+1 bytes long.
551
Each character needs two bytes, and you need room for the terminating
552
null byte. When drizzle_hex_string() returns, the contents of "to" will
553
be a null-terminated string. The return value is the length of the
554
encoded string, not including the terminating null character. The return value does not contain any leading 0x or a leading X' and
555
trailing '. The caller must supply whichever of those is desired.
559
drizzle_hex_string(char *to, const char *from, uint32_t length)
564
for (end= from + length; from < end; from++)
566
*to++= _dig_vec_upper[((unsigned char) *from) >> 4];
567
*to++= _dig_vec_upper[((unsigned char) *from) & 0x0F];
570
return (uint32_t) (to-to0);
574
Add escape characters to a string (blob?) to make it suitable for a insert
575
to should at least have place for length*2+1 chars
576
Returns the length of the to string
580
drizzle_escape_string(char *to,const char *from, uint32_t length)
582
const char *to_start= to;
583
const char *end, *to_end=to_start + 2*length;
584
bool overflow= false;
585
for (end= from + length; from < end; from++)
589
if (!U8_IS_SINGLE(*from))
591
tmp_length= U8_LENGTH(*from);
592
if (to + tmp_length > to_end)
603
case 0: /* Must be escaped for 'mysql' */
606
case '\n': /* Must be escaped for logs */
618
case '"': /* Better safe than sorry */
621
case '\032': /* This gives problems on Win32 */
646
return overflow ? (size_t) -1 : (size_t) (to - to_start);
649
int cli_unbuffered_fetch(DRIZZLE *drizzle, char **row)
651
if (packet_error == cli_safe_read(drizzle))
654
*row= ((drizzle->net.read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA) ? NULL :
655
(char*) (drizzle->net.read_pos+1));
659
/********************************************************************
661
*********************************************************************/
664
Commit the current transaction
667
bool drizzle_commit(DRIZZLE *drizzle)
669
return((bool) drizzle_real_query(drizzle, "commit", 6));
673
Rollback the current transaction
676
bool drizzle_rollback(DRIZZLE *drizzle)
678
return((bool) drizzle_real_query(drizzle, "rollback", 8));
683
Set autocommit to either true or false
686
bool drizzle_autocommit(DRIZZLE *drizzle, bool auto_mode)
688
return((bool) drizzle_real_query(drizzle, auto_mode ?
689
"set autocommit=1":"set autocommit=0",
694
/********************************************************************
695
Multi query execution + SPs APIs
696
*********************************************************************/
699
Returns true/false to indicate whether any more query results exist
700
to be read using drizzle_next_result()
703
bool drizzle_more_results(const DRIZZLE *drizzle)
705
return (drizzle->server_status & SERVER_MORE_RESULTS_EXISTS) ? true:false;
710
Reads and returns the next query results
712
int drizzle_next_result(DRIZZLE *drizzle)
714
if (drizzle->status != DRIZZLE_STATUS_READY)
716
drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC, sqlstate_get_unknown());
720
net_clear_error(&drizzle->net);
721
drizzle->affected_rows= ~(uint64_t) 0;
723
if (drizzle->server_status & SERVER_MORE_RESULTS_EXISTS)
724
return((*drizzle->methods->next_result)(drizzle));
726
return(-1); /* No more results */
730
DRIZZLE_RES * drizzle_use_result(DRIZZLE *drizzle)
732
return (*drizzle->methods->use_result)(drizzle);
735
bool drizzle_read_query_result(DRIZZLE *drizzle)
737
return (*drizzle->methods->read_query_result)(drizzle);