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 <drizzled/global.h>
21
#include "libdrizzle_priv.h"
23
#include "libdrizzle.h"
34
#include <sys/socket.h>
35
#include <netinet/in.h>
36
#include <arpa/inet.h>
41
#ifdef HAVE_SYS_SELECT_H
42
#include <sys/select.h>
52
#define INADDR_NONE -1
57
#include <mystrings/utf8.h>
60
#undef net_buffer_length
61
#undef max_allowed_packet
63
uint32_t net_buffer_length= 8192;
64
uint32_t max_allowed_packet= 1024L*1024L*1024L;
66
unsigned int drizzle_port=0;
71
static DRIZZLE_PARAMETERS drizzle_internal_parameters=
72
{&max_allowed_packet, &net_buffer_length, 0};
74
const DRIZZLE_PARAMETERS * drizzle_get_parameters(void)
76
return &drizzle_internal_parameters;
79
unsigned int drizzle_get_default_port(void)
84
void drizzle_set_default_port(unsigned int port)
90
Expand wildcard to a sql string
94
append_wild(char *to, char *end, const char *wild)
96
end-=5; /* Some extra */
99
to= strcpy(to," like '");
100
to+= 7; /* strlen(" like '"); */
102
while (*wild && to < end)
104
if (*wild == '\\' || *wild == '\'')
108
if (*wild) /* Too small buffer */
109
*to++='%'; /* Nicer this way */
115
/**************************************************************************
116
Change user and database
117
**************************************************************************/
119
int cli_read_change_user_result(DRIZZLE *drizzle)
123
pkt_length= cli_safe_read(drizzle);
125
if (pkt_length == packet_error)
131
bool drizzle_change_user(DRIZZLE *drizzle, const char *user,
132
const char *passwd, const char *db)
134
char buff[USERNAME_LENGTH+SCRAMBLED_PASSWORD_CHAR_LENGTH+NAME_LEN+2];
138
/* Use an empty string instead of NULL. */
145
/* Store user into the buffer */
146
end= strncpy(end, user, USERNAME_LENGTH) + USERNAME_LENGTH + 1;
148
/* write scrambled password according to server capabilities */
152
*end++= SCRAMBLE_LENGTH;
153
end+= SCRAMBLE_LENGTH;
157
*end++= '\0'; /* empty password */
158
/* Add database if needed */
159
end= strncpy(end, db ? db : "", NAME_LEN) + NAME_LEN + 1;
161
/* Add character set number. */
162
if (drizzle->server_capabilities & CLIENT_SECURE_CONNECTION)
164
int2store(end, (uint16_t) 45); // utf8mb4 number from mystrings/ctype-utf8.c
168
/* Write authentication package */
169
(void)simple_command(drizzle,COM_CHANGE_USER, (unsigned char*) buff, (uint32_t) (end-buff), 1);
171
rc= (*drizzle->methods->read_change_user_result)(drizzle);
175
/* Free old connect information */
179
free(drizzle->passwd);
183
/* alloc new connect information */
184
drizzle->user= strdup(user);
185
drizzle->passwd= strdup(passwd);
186
drizzle->db= db ? strdup(db) : 0;
192
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
193
struct passwd *getpwuid(uid_t);
194
char* getlogin(void);
197
/**************************************************************************
198
Do a query. If query returned rows, free old rows.
199
Read data by drizzle_store_result or by repeat call of drizzle_fetch_row
200
**************************************************************************/
203
drizzle_query(DRIZZLE *drizzle, const char *query)
205
return drizzle_real_query(drizzle,query, (uint32_t) strlen(query));
209
/**************************************************************************
210
Return next field of the query results
211
**************************************************************************/
214
drizzle_fetch_field(DRIZZLE_RES *result)
216
if (result->current_field >= result->field_count)
218
return &result->fields[result->current_field++];
222
/**************************************************************************
223
Move to a specific row and column
224
**************************************************************************/
227
drizzle_data_seek(DRIZZLE_RES *result, uint64_t row)
231
for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
232
result->current_row=0;
233
result->data_cursor = tmp;
237
/*************************************************************************
238
put the row or field cursor one a position one got from DRIZZLE_ROW_tell()
239
This doesn't restore any data. The next drizzle_fetch_row or
240
drizzle_fetch_field will return the next row or field after the last used
241
*************************************************************************/
244
drizzle_row_seek(DRIZZLE_RES *result, DRIZZLE_ROW_OFFSET row)
246
DRIZZLE_ROW_OFFSET return_value=result->data_cursor;
247
result->current_row= 0;
248
result->data_cursor= row;
254
drizzle_field_seek(DRIZZLE_RES *result, DRIZZLE_FIELD_OFFSET field_offset)
256
DRIZZLE_FIELD_OFFSET return_value=result->current_field;
257
result->current_field=field_offset;
262
/*****************************************************************************
263
List all tables in a database
264
If wild is given then only the tables matching wild is returned
265
*****************************************************************************/
268
drizzle_list_tables(DRIZZLE *drizzle, const char *wild)
271
char *ptr= strcpy(buff, "show tables");
272
ptr+= 11; /* strlen("show tables"); */
274
append_wild(ptr,buff+sizeof(buff),wild);
275
if (drizzle_query(drizzle,buff))
277
return (drizzle_store_result(drizzle));
281
DRIZZLE_FIELD *cli_list_fields(DRIZZLE *drizzle)
284
if (!(query= cli_read_rows(drizzle,(DRIZZLE_FIELD*) 0, 8)))
287
drizzle->field_count= (uint32_t) query->rows;
288
return unpack_fields(query, drizzle->field_count, 1);
292
/**************************************************************************
293
List all fields in a table
294
If wild is given then only the fields matching wild is returned
295
Instead of this use query:
296
show fields in 'table' like "wild"
297
**************************************************************************/
300
drizzle_list_fields(DRIZZLE *drizzle, const char *table, const char *wild)
303
DRIZZLE_FIELD *fields;
304
char buff[257], *end;
306
end= strncpy(buff, table, 128) + 128;
307
end= strncpy(end+1, wild ? wild : "", 128) + 128;
309
free_old_query(drizzle);
310
if (simple_command(drizzle, COM_FIELD_LIST, (unsigned char*) buff,
311
(uint32_t) (end-buff), 1) ||
312
!(fields= (*drizzle->methods->list_fields)(drizzle)))
315
if (!(result = (DRIZZLE_RES *) malloc(sizeof(DRIZZLE_RES))))
318
memset(result, 0, sizeof(DRIZZLE_RES));
320
result->methods= drizzle->methods;
322
result->field_count = drizzle->field_count;
323
result->fields= fields;
328
/* List all running processes (threads) in server */
331
drizzle_list_processes(DRIZZLE *drizzle)
333
DRIZZLE_DATA *fields;
334
uint32_t field_count;
337
if (simple_command(drizzle,COM_PROCESS_INFO,0,0,0))
339
free_old_query(drizzle);
340
pos=(unsigned char*) drizzle->net.read_pos;
341
field_count=(uint32_t) net_field_length(&pos);
342
if (!(fields = (*drizzle->methods->read_rows)(drizzle,(DRIZZLE_FIELD*) 0, 7)))
344
if (!(drizzle->fields=unpack_fields(fields, field_count, 0)))
346
drizzle->status=DRIZZLE_STATUS_GET_RESULT;
347
drizzle->field_count=field_count;
348
return(drizzle_store_result(drizzle));
353
drizzle_shutdown(DRIZZLE *drizzle)
355
return(simple_command(drizzle, COM_SHUTDOWN, 0, 0, 0));
360
drizzle_refresh(DRIZZLE *drizzle, uint32_t options)
362
unsigned char bits[1];
363
bits[0]= (unsigned char) options;
364
return(simple_command(drizzle, COM_REFRESH, bits, 1, 0));
369
drizzle_kill(DRIZZLE *drizzle, uint32_t pid)
371
unsigned char buff[4];
373
return(simple_command(drizzle,COM_PROCESS_KILL,buff,sizeof(buff),0));
378
drizzle_set_server_option(DRIZZLE *drizzle, enum enum_drizzle_set_option option)
380
unsigned char buff[2];
381
int2store(buff, (uint32_t) option);
382
return(simple_command(drizzle, COM_SET_OPTION, buff, sizeof(buff), 0));
386
const char *cli_read_statistics(DRIZZLE *drizzle)
388
drizzle->net.read_pos[drizzle->packet_length]=0; /* End of stat string */
389
if (!drizzle->net.read_pos[0])
391
drizzle_set_error(drizzle, CR_WRONG_HOST_INFO, sqlstate_get_unknown());
392
return drizzle->net.last_error;
394
return (char*) drizzle->net.read_pos;
399
drizzle_ping(DRIZZLE *drizzle)
402
res= simple_command(drizzle,COM_PING,0,0,0);
403
if (res == CR_SERVER_LOST && drizzle->reconnect)
404
res= simple_command(drizzle,COM_PING,0,0,0);
410
drizzle_get_server_info(const DRIZZLE *drizzle)
412
return((char*) drizzle->server_version);
417
drizzle_get_host_info(const DRIZZLE *drizzle)
419
return(drizzle->host_info);
424
drizzle_get_proto_info(const DRIZZLE *drizzle)
426
return (drizzle->protocol_version);
430
drizzle_get_client_info(void)
432
return (char*) VERSION;
435
uint32_t drizzle_get_client_version(void)
437
return DRIZZLE_VERSION_ID;
440
bool drizzle_eof(const DRIZZLE_RES *res)
445
const DRIZZLE_FIELD * drizzle_fetch_field_direct(const DRIZZLE_RES *res, unsigned int fieldnr)
447
return &(res)->fields[fieldnr];
450
const DRIZZLE_FIELD * drizzle_fetch_fields(const DRIZZLE_RES *res)
455
DRIZZLE_ROW_OFFSET drizzle_row_tell(const DRIZZLE_RES *res)
457
return res->data_cursor;
460
DRIZZLE_FIELD_OFFSET drizzle_field_tell(const DRIZZLE_RES *res)
462
return res->current_field;
467
unsigned int drizzle_field_count(const DRIZZLE *drizzle)
469
return drizzle->field_count;
472
uint64_t drizzle_affected_rows(const DRIZZLE *drizzle)
474
return drizzle->affected_rows;
477
uint64_t drizzle_insert_id(const DRIZZLE *drizzle)
479
return drizzle->insert_id;
482
const char * drizzle_sqlstate(const DRIZZLE *drizzle)
484
return drizzle ? drizzle->net.sqlstate : sqlstate_get_cant_connect();
487
uint32_t drizzle_warning_count(const DRIZZLE *drizzle)
489
return drizzle->warning_count;
492
const char * drizzle_info(const DRIZZLE *drizzle)
494
return drizzle->info;
497
uint32_t drizzle_thread_id(const DRIZZLE *drizzle)
499
return drizzle->thread_id;
502
/****************************************************************************
503
Some support functions
504
****************************************************************************/
507
Functions called my my_net_init() to set some application specific variables
510
void my_net_local_init(NET *net)
512
net->max_packet= (uint32_t) net_buffer_length;
513
my_net_set_read_timeout(net, CLIENT_NET_READ_TIMEOUT);
514
my_net_set_write_timeout(net, CLIENT_NET_WRITE_TIMEOUT);
516
net->max_packet_size= (net_buffer_length > max_allowed_packet) ?
517
net_buffer_length : max_allowed_packet;
521
Add escape characters to a string (blob?) to make it suitable for a insert
522
to should at least have place for length*2+1 chars
523
Returns the length of the to string
527
drizzle_escape_string(char *to,const char *from, uint32_t length)
529
const char *to_start= to;
530
const char *end, *to_end=to_start + 2*length;
531
bool overflow= false;
532
for (end= from + length; from < end; from++)
536
if (!U8_IS_SINGLE(*from))
538
tmp_length= U8_LENGTH(*(uint32_t*)from);
539
if (to + tmp_length > to_end)
550
case 0: /* Must be escaped for 'mysql' */
553
case '\n': /* Must be escaped for logs */
565
case '"': /* Better safe than sorry */
568
case '\032': /* This gives problems on Win32 */
593
return overflow ? (size_t) -1 : (size_t) (to - to_start);
596
int cli_unbuffered_fetch(DRIZZLE *drizzle, char **row)
598
if (packet_error == cli_safe_read(drizzle))
601
*row= ((drizzle->net.read_pos[0] == DRIZZLE_PROTOCOL_NO_MORE_DATA) ? NULL :
602
(char*) (drizzle->net.read_pos+1));
606
/********************************************************************
608
*********************************************************************/
611
Commit the current transaction
614
bool drizzle_commit(DRIZZLE *drizzle)
616
return((bool) drizzle_real_query(drizzle, "commit", 6));
620
Rollback the current transaction
623
bool drizzle_rollback(DRIZZLE *drizzle)
625
return((bool) drizzle_real_query(drizzle, "rollback", 8));
630
Set autocommit to either true or false
633
bool drizzle_autocommit(DRIZZLE *drizzle, bool auto_mode)
635
return((bool) drizzle_real_query(drizzle, auto_mode ?
636
"set autocommit=1":"set autocommit=0",
641
/********************************************************************
642
Multi query execution + SPs APIs
643
*********************************************************************/
646
Returns true/false to indicate whether any more query results exist
647
to be read using drizzle_next_result()
650
bool drizzle_more_results(const DRIZZLE *drizzle)
652
return (drizzle->server_status & SERVER_MORE_RESULTS_EXISTS) ? true:false;
657
Reads and returns the next query results
659
int drizzle_next_result(DRIZZLE *drizzle)
661
if (drizzle->status != DRIZZLE_STATUS_READY)
663
drizzle_set_error(drizzle, CR_COMMANDS_OUT_OF_SYNC, sqlstate_get_unknown());
667
net_clear_error(&drizzle->net);
668
drizzle->affected_rows= ~(uint64_t) 0;
670
if (drizzle->server_status & SERVER_MORE_RESULTS_EXISTS)
671
return((*drizzle->methods->next_result)(drizzle));
673
return(-1); /* No more results */
677
DRIZZLE_RES * drizzle_use_result(DRIZZLE *drizzle)
679
return (*drizzle->methods->use_result)(drizzle);
682
bool drizzle_read_query_result(DRIZZLE *drizzle)
684
return (*drizzle->methods->read_query_result)(drizzle);