~drizzle-trunk/drizzle/development

1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
1
/*
2
 * Drizzle Client & Protocol Library
3
 *
4
 * Copyright (C) 2008 Eric Day (eday@oddments.org)
5
 * All rights reserved.
6
 *
7
 * Use and distribution licensed under the BSD license.  See
1799.2.3 by Monty Taylor
Reference root BSD copying file.
8
 * the COPYING.BSD file in the root source directory for full text.
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
9
 */
10
11
/**
12
 * @file
13
 * @brief Drizzle Definitions
14
 */
15
16
#include "libdrizzle/common.h"
17
18
19
/**
20
 * @addtogroup drizzle_static Static Drizzle Declarations
21
 * @ingroup drizzle
22
 * @{
23
 */
24
25
/**
26
 * Names of the verbose levels provided.
27
 */
28
static const char *_verbose_name[DRIZZLE_VERBOSE_MAX]=
29
{
30
  "NEVER",
31
  "FATAL",
32
  "ERROR",
33
  "INFO",
34
  "DEBUG",
35
  "CRAZY"
36
};
37
38
/** @} */
39
40
/*
41
 * Common Definitions
42
 */
43
44
const char *drizzle_version(void)
45
{
46
  return PACKAGE_VERSION;
47
}
48
49
const char *drizzle_bugreport(void)
50
{
51
  return PACKAGE_BUGREPORT;
52
}
53
54
const char *drizzle_verbose_name(drizzle_verbose_t verbose)
55
{
56
  if (verbose >= DRIZZLE_VERBOSE_MAX)
57
    return "UNKNOWN";
58
59
  return _verbose_name[verbose];
60
}
61
62
drizzle_st *drizzle_create(drizzle_st *drizzle)
63
{
64
#if defined(_WIN32)
65
  /* if it is MS windows, invoke WSAStartup */
66
  WSADATA wsaData;
67
  if ( WSAStartup( MAKEWORD(2,2), &wsaData ) != 0 )
68
    printf("Error at WSAStartup()\n");
69
#endif
1877.1.5 by Andrew Hutchings
Fix min() usage for 32bit
70
  struct sigaction act;
71
72
  act.sa_handler = SIG_IGN;
73
  sigaction(SIGPIPE, &act, NULL);
74
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
75
  if (drizzle == NULL)
76
  {
77
    drizzle= malloc(sizeof(drizzle_st));
78
    if (drizzle == NULL)
79
      return NULL;
80
81
    drizzle->options= DRIZZLE_ALLOCATED;
82
  }
83
  else
84
    drizzle->options= DRIZZLE_NONE;
85
86
  /* @todo remove this default free flag with new API. */
87
  drizzle->options|= DRIZZLE_FREE_OBJECTS;
88
  drizzle->error_code= 0;
89
  /* drizzle->options set above */
90
  drizzle->verbose= DRIZZLE_VERBOSE_NEVER;
91
  drizzle->con_count= 0;
92
  drizzle->pfds_size= 0;
93
  drizzle->query_count= 0;
94
  drizzle->query_new= 0;
95
  drizzle->query_running= 0;
96
  drizzle->last_errno= 0;
97
  drizzle->timeout= -1;
98
  drizzle->con_list= NULL;
99
  drizzle->context= NULL;
100
  drizzle->context_free_fn= NULL;
101
  drizzle->event_watch_fn= NULL;
102
  drizzle->event_watch_context= NULL;
103
  drizzle->log_fn= NULL;
104
  drizzle->log_context= NULL;
105
  drizzle->pfds= NULL;
106
  drizzle->query_list= NULL;
107
  drizzle->sqlstate[0]= 0;
108
  drizzle->last_error[0]= 0;
109
110
  return drizzle;
111
}
112
113
drizzle_st *drizzle_clone(drizzle_st *drizzle, const drizzle_st *from)
114
{
115
  drizzle_con_st *con;
116
117
  drizzle= drizzle_create(drizzle);
118
  if (drizzle == NULL)
119
    return NULL;
120
121
  drizzle->options|= (from->options & (drizzle_options_t)~DRIZZLE_ALLOCATED);
122
123
  for (con= from->con_list; con != NULL; con= con->next)
124
  {
125
    if (drizzle_con_clone(drizzle, NULL, con) == NULL)
126
    {
127
      drizzle_free(drizzle);
128
      return NULL;
129
    }
130
  }
131
132
  return drizzle;
133
}
134
135
void drizzle_free(drizzle_st *drizzle)
136
{
137
  if (drizzle->context != NULL && drizzle->context_free_fn != NULL)
138
    drizzle->context_free_fn(drizzle, drizzle->context);
139
140
  if (drizzle->options & DRIZZLE_FREE_OBJECTS)
141
  {
142
    drizzle_con_free_all(drizzle);
143
    drizzle_query_free_all(drizzle);
144
  }
145
  else if (drizzle->options & DRIZZLE_ASSERT_DANGLING)
146
  {
147
    assert(drizzle->con_list == NULL);
148
    assert(drizzle->con_list == NULL);
149
  }
150
151
  if (drizzle->pfds != NULL)
152
    free(drizzle->pfds);
153
154
  if (drizzle->options & DRIZZLE_ALLOCATED)
155
    free(drizzle);
156
#if defined(_WIN32)
157
  /* if it is MS windows, invoke WSACleanup() at the end*/
158
  WSACleanup();
159
#endif
160
}
161
162
const char *drizzle_error(const drizzle_st *drizzle)
163
{
164
  return (const char *)drizzle->last_error;
165
}
166
167
int drizzle_errno(const drizzle_st *drizzle)
168
{
169
  return drizzle->last_errno;
170
}
171
172
uint16_t drizzle_error_code(const drizzle_st *drizzle)
173
{
174
  return drizzle->error_code;
175
}
176
177
const char *drizzle_sqlstate(const drizzle_st *drizzle)
178
{
179
  return drizzle->sqlstate;
180
}
181
182
drizzle_options_t drizzle_options(const drizzle_st *drizzle)
183
{
184
  return drizzle->options;
185
}
186
187
void drizzle_set_options(drizzle_st *drizzle, drizzle_options_t options)
188
{
189
  drizzle->options= options;
190
}
191
192
void drizzle_add_options(drizzle_st *drizzle, drizzle_options_t options)
193
{
194
  drizzle->options|= options;
195
}
196
197
void drizzle_remove_options(drizzle_st *drizzle, drizzle_options_t options)
198
{
199
  drizzle->options&= ~options;
200
}
201
202
void *drizzle_context(const drizzle_st *drizzle)
203
{
204
  return drizzle->context;
205
}
206
207
void drizzle_set_context(drizzle_st *drizzle, void *context)
208
{
209
  drizzle->context= context;
210
}
211
212
void drizzle_set_context_free_fn(drizzle_st *drizzle,
213
                                 drizzle_context_free_fn *function)
214
{
215
  drizzle->context_free_fn= function;
216
}
217
218
int drizzle_timeout(const drizzle_st *drizzle)
219
{
220
  return drizzle->timeout;
221
}
222
223
void drizzle_set_timeout(drizzle_st *drizzle, int timeout)
224
{
225
  drizzle->timeout= timeout;
226
}
227
228
drizzle_verbose_t drizzle_verbose(const drizzle_st *drizzle)
229
{
230
  return drizzle->verbose;
231
}
232
233
void drizzle_set_verbose(drizzle_st *drizzle, drizzle_verbose_t verbose)
234
{
235
  drizzle->verbose= verbose;
236
}
237
238
void drizzle_set_log_fn(drizzle_st *drizzle, drizzle_log_fn *function,
239
                        void *context)
240
{
241
  drizzle->log_fn= function;
242
  drizzle->log_context= context;
243
}
244
245
void drizzle_set_event_watch_fn(drizzle_st *drizzle,
246
                                drizzle_event_watch_fn *function,
247
                                void *context)
248
{
249
  drizzle->event_watch_fn= function;
250
  drizzle->event_watch_context= context;
251
}
252
253
drizzle_con_st *drizzle_con_create(drizzle_st *drizzle, drizzle_con_st *con)
254
{
255
  if (con == NULL)
256
  {
257
    con= malloc(sizeof(drizzle_con_st));
258
    if (con == NULL)
259
    {
260
      if (drizzle != NULL)
261
        drizzle_set_error(drizzle, "drizzle_con_create", "malloc");
262
      return NULL;
263
    }
264
265
    con->options= DRIZZLE_CON_ALLOCATED;
266
  }
267
  else
268
    con->options= 0;
269
270
  if (drizzle->con_list != NULL)
271
    drizzle->con_list->prev= con;
272
  con->next= drizzle->con_list;
273
  con->prev= NULL;
274
  drizzle->con_list= con;
275
  drizzle->con_count++;
276
277
  con->packet_number= 0;
278
  con->protocol_version= 0;
279
  con->state_current= 0;
280
  con->events= 0;
281
  con->revents= 0;
282
  con->capabilities= DRIZZLE_CAPABILITIES_NONE;
283
  con->charset= 0;
284
  con->command= 0;
285
  con->options|= DRIZZLE_CON_MYSQL;
286
  con->socket_type= DRIZZLE_CON_SOCKET_TCP;
287
  con->status= DRIZZLE_CON_STATUS_NONE;
288
  con->max_packet_size= DRIZZLE_MAX_PACKET_SIZE;
289
  con->result_count= 0;
290
  con->thread_id= 0;
291
  con->backlog= DRIZZLE_DEFAULT_BACKLOG;
292
  con->fd= -1;
293
  con->buffer_size= 0;
294
  con->command_offset= 0;
295
  con->command_size= 0;
296
  con->command_total= 0;
297
  con->packet_size= 0;
298
  con->addrinfo_next= NULL;
299
  con->buffer_ptr= con->buffer;
300
  con->command_buffer= NULL;
301
  con->command_data= NULL;
302
  con->context= NULL;
303
  con->context_free_fn= NULL;
304
  con->drizzle= drizzle;
305
  /* con->next set above */
306
  /* con->prev set above */
307
  con->query= NULL;
308
  /* con->result doesn't need to be set */
309
  con->result_list= NULL;
310
  con->scramble= NULL;
311
  con->socket.tcp.addrinfo= NULL;
312
  con->socket.tcp.host= NULL;
313
  con->socket.tcp.port= 0;
314
  /* con->buffer doesn't need to be set */
315
  con->db[0]= 0;
316
  con->password[0]= 0;
317
  /* con->scramble_buffer doesn't need to be set */
318
  con->server_version[0]= 0;
319
  /* con->state_stack doesn't need to be set */
320
  con->user[0]= 0;
321
322
  return con;
323
}
324
325
drizzle_con_st *drizzle_con_clone(drizzle_st *drizzle, drizzle_con_st *con,
326
                                  const drizzle_con_st *from)
327
{
328
  con= drizzle_con_create(drizzle, con);
329
  if (con == NULL)
330
    return NULL;
331
332
  /* Clear "operational" options such as IO status. */
333
  con->options|= (from->options & (drizzle_con_options_t)~(
334
                  DRIZZLE_CON_ALLOCATED|DRIZZLE_CON_READY|
335
                  DRIZZLE_CON_NO_RESULT_READ|DRIZZLE_CON_IO_READY|
336
                  DRIZZLE_CON_LISTEN));
337
  con->backlog= from->backlog;
338
  strcpy(con->db, from->db);
339
  strcpy(con->password, from->password);
340
  strcpy(con->user, from->user);
341
342
  switch (from->socket_type)
343
  {
344
  case DRIZZLE_CON_SOCKET_TCP:
345
    drizzle_con_set_tcp(con, from->socket.tcp.host, from->socket.tcp.port);
346
    break;
347
348
  case DRIZZLE_CON_SOCKET_UDS:
349
    drizzle_con_set_uds(con, from->socket.uds.sockaddr.sun_path);
350
    break;
351
352
  default:
353
    break;
354
  }
355
356
  return con;
357
}
358
359
void drizzle_con_free(drizzle_con_st *con)
360
{
361
  if (con->context != NULL && con->context_free_fn != NULL)
362
    con->context_free_fn(con, con->context);
363
364
  if (con->drizzle->options & DRIZZLE_FREE_OBJECTS)
365
    drizzle_result_free_all(con);
366
  else if (con->drizzle->options & DRIZZLE_ASSERT_DANGLING)
367
    assert(con->result_list == NULL);
368
369
  if (con->fd != -1)
370
    drizzle_con_close(con);
371
372
  drizzle_con_reset_addrinfo(con);
373
374
  if (con->drizzle->con_list == con)
375
    con->drizzle->con_list= con->next;
376
  if (con->prev != NULL)
377
    con->prev->next= con->next;
378
  if (con->next != NULL)
379
    con->next->prev= con->prev;
380
  con->drizzle->con_count--;
381
382
  if (con->options & DRIZZLE_CON_ALLOCATED)
383
    free(con);
384
}
385
386
void drizzle_con_free_all(drizzle_st *drizzle)
387
{
388
  while (drizzle->con_list != NULL)
389
    drizzle_con_free(drizzle->con_list);
390
}
391
392
drizzle_return_t drizzle_con_wait(drizzle_st *drizzle)
393
{
394
  drizzle_con_st *con;
395
  struct pollfd *pfds;
396
  uint32_t x;
397
  int ret;
398
  drizzle_return_t dret;
399
400
  if (drizzle->pfds_size < drizzle->con_count)
401
  {
402
    pfds= realloc(drizzle->pfds, drizzle->con_count * sizeof(struct pollfd));
403
    if (pfds == NULL)
404
    {
405
      drizzle_set_error(drizzle, "drizzle_con_wait", "realloc");
406
      return DRIZZLE_RETURN_MEMORY;
407
    }
408
409
    drizzle->pfds= pfds;
410
    drizzle->pfds_size= drizzle->con_count;
411
  }
412
  else
413
    pfds= drizzle->pfds;
414
415
  x= 0;
416
  for (con= drizzle->con_list; con != NULL; con= con->next)
417
  {
418
    if (con->events == 0)
419
      continue;
420
421
    pfds[x].fd= con->fd;
422
    pfds[x].events= con->events;
423
    pfds[x].revents= 0;
424
    x++;
425
  }
426
427
  if (x == 0)
428
  {
429
    drizzle_set_error(drizzle, "drizzle_con_wait",
430
                      "no active file descriptors");
431
    return DRIZZLE_RETURN_NO_ACTIVE_CONNECTIONS;
432
  }
433
434
  while (1)
435
  {
436
    drizzle_log_crazy(drizzle, "poll count=%d timeout=%d", x,
437
                      drizzle->timeout);
438
439
    ret= poll(pfds, x, drizzle->timeout);
440
441
    drizzle_log_crazy(drizzle, "poll return=%d errno=%d", ret, errno);
442
443
    if (ret == -1)
444
    {
445
      if (errno == EINTR)
446
        continue;
447
448
      drizzle_set_error(drizzle, "drizzle_con_wait", "poll:%d", errno);
449
      drizzle->last_errno= errno;
450
      return DRIZZLE_RETURN_ERRNO;
451
    }
452
453
    break;
454
  }
455
456
  if (ret == 0)
457
  {
458
    drizzle_set_error(drizzle, "drizzle_con_wait", "timeout reached");
459
    return DRIZZLE_RETURN_TIMEOUT;
460
  }
461
462
  x= 0;
463
  for (con= drizzle->con_list; con != NULL; con= con->next)
464
  {
465
    if (con->events == 0)
466
      continue;
467
468
    dret= drizzle_con_set_revents(con, pfds[x].revents);
469
    if (dret != DRIZZLE_RETURN_OK)
470
      return dret;
471
472
    x++;
473
  }
474
475
  return DRIZZLE_RETURN_OK;
476
}
477
478
drizzle_con_st *drizzle_con_ready(drizzle_st *drizzle)
479
{
480
  drizzle_con_st *con;
481
482
  /* We can't keep state between calls since connections may be removed during
483
     processing. If this list ever gets big, we may want something faster. */
484
485
  for (con= drizzle->con_list; con != NULL; con= con->next)
486
  {
487
    if (con->options & DRIZZLE_CON_IO_READY)
488
    {
489
      con->options&= (drizzle_con_options_t)~DRIZZLE_CON_IO_READY;
490
      return con;
491
    }
492
  }
493
494
  return NULL;
495
}
496
497
drizzle_con_st *drizzle_con_ready_listen(drizzle_st *drizzle)
498
{
499
  drizzle_con_st *con;
500
501
  /* We can't keep state between calls since connections may be removed during
502
     processing. If this list ever gets big, we may want something faster. */
503
504
  for (con= drizzle->con_list; con != NULL; con= con->next)
505
  {
506
    if ((con->options & (DRIZZLE_CON_IO_READY | DRIZZLE_CON_LISTEN)) ==
507
        (DRIZZLE_CON_IO_READY | DRIZZLE_CON_LISTEN))
508
    {
509
      con->options&= (drizzle_con_options_t)~DRIZZLE_CON_IO_READY;
510
      return con;
511
    }
512
  }
513
514
  return NULL;
515
}
516
517
/*
518
 * Client Definitions
519
 */
520
521
drizzle_con_st *drizzle_con_add_tcp(drizzle_st *drizzle, drizzle_con_st *con,
522
                                    const char *host, in_port_t port,
523
                                    const char *user, const char *password,
524
                                    const char *db,
525
                                    drizzle_con_options_t options)
526
{
527
  con= drizzle_con_create(drizzle, con);
528
  if (con == NULL)
529
    return NULL;
530
531
  drizzle_con_set_tcp(con, host, port);
532
  drizzle_con_set_auth(con, user, password);
533
  drizzle_con_set_db(con, db);
534
  drizzle_con_add_options(con, options);
535
536
  return con;
537
}
538
539
drizzle_con_st *drizzle_con_add_uds(drizzle_st *drizzle, drizzle_con_st *con,
540
                                    const char *uds, const char *user,
541
                                    const char *password, const char *db,
542
                                    drizzle_con_options_t options)
543
{
544
  con= drizzle_con_create(drizzle, con);
545
  if (con == NULL)
546
    return NULL;
547
548
  drizzle_con_set_uds(con, uds);
549
  drizzle_con_set_auth(con, user, password);
550
  drizzle_con_set_db(con, db);
551
  drizzle_con_add_options(con, options);
552
553
  return con;
554
}
555
556
/*
557
 * Server Definitions
558
 */
559
560
drizzle_con_st *drizzle_con_add_tcp_listen(drizzle_st *drizzle,
561
                                           drizzle_con_st *con,
562
                                           const char *host, in_port_t port,
563
                                           int backlog,
564
                                           drizzle_con_options_t options)
565
{
566
  con= drizzle_con_create(drizzle, con);
567
  if (con == NULL)
568
    return NULL;
569
570
  drizzle_con_set_tcp(con, host, port);
571
  drizzle_con_set_backlog(con, backlog);
572
  drizzle_con_add_options(con, DRIZZLE_CON_LISTEN | options);
573
574
  return con;
575
}
576
577
drizzle_con_st *drizzle_con_add_uds_listen(drizzle_st *drizzle,
578
                                           drizzle_con_st *con,
579
                                           const char *uds, int backlog,
580
                                           drizzle_con_options_t options)
581
{
582
  con= drizzle_con_create(drizzle, con);
583
  if (con == NULL)
584
    return NULL;
585
586
  drizzle_con_set_uds(con, uds);
587
  drizzle_con_set_backlog(con, backlog);
588
  drizzle_con_add_options(con, DRIZZLE_CON_LISTEN | options);
589
590
  return con;
591
}
592
593
drizzle_con_st *drizzle_con_accept(drizzle_st *drizzle, drizzle_con_st *con,
594
                                   drizzle_return_t *ret_ptr)
595
{
596
  drizzle_con_st *ready;
597
  int fd;
598
599
  while (1)
600
  {
601
    if ((ready= drizzle_con_ready_listen(drizzle)) != NULL)
602
    {
603
      fd= accept(ready->fd, NULL, NULL);
604
605
      con= drizzle_con_create(drizzle, con);
606
      if (con == NULL)
607
      {
608
        (void)close(fd);
609
        *ret_ptr= DRIZZLE_RETURN_MEMORY;
610
        return NULL;
611
      }
612
613
      *ret_ptr= drizzle_con_set_fd(con, fd);
614
      if (*ret_ptr != DRIZZLE_RETURN_OK)
615
      {
616
        (void)close(fd);
617
        return NULL;
618
      }
619
620
      if (ready->options & DRIZZLE_CON_MYSQL)
621
        drizzle_con_add_options(con, DRIZZLE_CON_MYSQL);
622
623
      *ret_ptr= DRIZZLE_RETURN_OK;
624
      return con;
625
    }
626
627
    if (drizzle->options & DRIZZLE_NON_BLOCKING)
628
    {
629
      *ret_ptr= DRIZZLE_RETURN_IO_WAIT;
630
      return NULL;
631
    }
632
633
    for (ready= drizzle->con_list; ready != NULL; ready= ready->next)
634
    {
635
      if (ready->options & DRIZZLE_CON_LISTEN)
636
        drizzle_con_set_events(ready, POLLIN);
637
    }
638
639
    *ret_ptr= drizzle_con_wait(drizzle);
640
    if (*ret_ptr != DRIZZLE_RETURN_OK)
641
      return NULL;
642
  }
643
}
644
645
/*
646
 * Local Definitions
647
 */
648
649
void drizzle_set_error(drizzle_st *drizzle, const char *function,
650
                       const char *format, ...)
651
{
652
  size_t size;
653
  char *ptr;
654
  char log_buffer[DRIZZLE_MAX_ERROR_SIZE];
655
  va_list args;
656
657
  size= strlen(function);
658
  ptr= memcpy(log_buffer, function, size);
659
  ptr+= size;
660
  ptr[0]= ':';
661
  size++;
662
  ptr++;
663
664
  va_start(args, format);
665
  size+= (size_t)vsnprintf(ptr, DRIZZLE_MAX_ERROR_SIZE - size, format, args);
666
  va_end(args);
667
668
  if (drizzle->log_fn == NULL)
669
  {
670
    if (size >= DRIZZLE_MAX_ERROR_SIZE)
671
      size= DRIZZLE_MAX_ERROR_SIZE - 1;
672
673
    memcpy(drizzle->last_error, log_buffer, size + 1);
674
  }
675
  else
676
    drizzle->log_fn(log_buffer, DRIZZLE_VERBOSE_ERROR, drizzle->log_context);
677
}
678
679
void drizzle_log(drizzle_st *drizzle, drizzle_verbose_t verbose,
680
                 const char *format, va_list args)
681
{
682
  char log_buffer[DRIZZLE_MAX_ERROR_SIZE];
683
684
  if (drizzle->log_fn == NULL)
685
  {
686
    printf("%5s: ", drizzle_verbose_name(verbose));
687
    vprintf(format, args);
688
    printf("\n");
689
  }
690
  else
691
  {
692
    vsnprintf(log_buffer, DRIZZLE_MAX_ERROR_SIZE, format, args);
693
    drizzle->log_fn(log_buffer, verbose, drizzle->log_context);
694
  }
695
}