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