~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.4 by Monty Taylor
Made BSD files reference root BSD 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
#include "config.h"
12
13
#include <errno.h>
14
#include <stdbool.h>
15
#include <stdint.h>
16
#include <stdio.h>
17
#include <stdlib.h>
18
#include <string.h>
19
#include <unistd.h>
20
21
#include <libdrizzle/drizzle_client.h>
22
23
typedef enum
24
{
25
  CLIENT_QUERY,
26
  CLIENT_FIELDS,
27
  CLIENT_ROWS
28
} client_state;
29
30
typedef enum
31
{
32
  BUFFER_NONE,
33
  BUFFER_FIELD,
34
  BUFFER_ROW,
35
  BUFFER_ALL
36
} buffer_level;
37
38
typedef struct
39
{
40
  drizzle_con_st con;
41
  drizzle_result_st result;
42
  drizzle_column_st column;
43
  client_state state;
44
  uint64_t row;
45
} client_con_st;
46
47
typedef struct
48
{
49
  drizzle_st drizzle;
50
  bool mysql_protocol;
51
  client_con_st *client_con_list;
52
  uint32_t client_con_count;
53
  buffer_level level;
54
  char *query;
55
  size_t query_len;
56
} client_st;
57
58
char client_process(client_st *client, client_con_st *client_con);
59
void con_info(drizzle_con_st *con);
60
void result_info(drizzle_result_st *result);
61
void column_info(drizzle_column_st *column);
62
63
#define CLIENT_ERROR(__function, __ret, __client) { \
64
    printf(__function ":%d:%s\n", __ret, \
65
           drizzle_error(&((__client)->drizzle))); \
66
    exit(1); }
67
68
int main(int argc, char *argv[])
69
{
70
  client_st client;
71
  int c;
72
  char blocking= 0;
73
  drizzle_return_t ret;
74
  uint32_t x;
75
  int wait_for_connections= 0;
76
  drizzle_con_st *con;
77
  client_con_st *client_con;
78
  char *host= NULL;
79
  in_port_t port= 0;
80
  char *user= NULL;
81
  char *password= NULL;
82
  char *db= NULL;
83
84
  memset(&client, 0, sizeof(client_st));
85
86
  /* Use one connection by default. */
87
  client.client_con_count= 1;
88
89
  while ((c = getopt(argc, argv, "bB:c:d:h:Hmp:P:u:")) != -1)
90
  {
91
    switch(c)
92
    {
93
    case 'b':
94
      blocking= 1;
95
      break;
96
97
    case 'B':
98
      if (!strcasecmp(optarg, "none"))
99
        client.level= BUFFER_NONE;
100
      else if (!strcasecmp(optarg, "field"))
101
        client.level= BUFFER_FIELD;
102
      else if (!strcasecmp(optarg, "row"))
103
        client.level= BUFFER_ROW;
104
      else if (!strcasecmp(optarg, "all"))
105
        client.level= BUFFER_ALL;
106
      else
107
      {
108
        printf("Invalid buffer level: %s\n", optarg);
109
        exit(0);
110
      }
111
      break;
112
113
    case 'c':
114
      client.client_con_count= (uint32_t)atoi(optarg);
115
      break;
116
117
    case 'd':
118
      db= optarg;
119
      break;
120
121
    case 'h':
122
      host= optarg;
123
      break;
124
125
    case 'm':
126
      client.mysql_protocol= true;
127
      break;
128
129
    case 'p':
130
      password= optarg;
131
      break;
132
133
    case 'P':
134
      port= (in_port_t)atoi(optarg);
135
      break;
136
137
    case 'u':
138
      user= optarg;
139
      break;
140
141
    case 'H':
142
    default:
143
      printf("\nUsage: %s [options] [query]\n", argv[0]);
144
      printf("\t-b            - Use blocking sockets\n");
145
      printf("\t-B <level>    - Use buffer <level>, options are:\n");
146
      printf("\t                none - Don't buffer anything (default)\n");
147
      printf("\t                field - Only buffer individual fields\n");
148
      printf("\t                row - Only buffer individual rows\n");
149
      printf("\t                all - Buffer entire result\n");
150
      printf("\t-c <cons>     - Create <cons> connections\n");
151
      printf("\t-d <db>       - Use <db> for the connection\n");
152
      printf("\t-h <host>     - Connect to <host>\n");
153
      printf("\t-H            - Print this help menu\n");
154
      printf("\t-m            - Use MySQL protocol\n");
155
      printf("\t-p <password> - Use <password> for authentication\n");
156
      printf("\t-P <port>     - Connect to <port>\n");
157
      printf("\t-u <user>     - Use <user> for authentication\n");
158
      exit(0);
159
    }
160
  }
161
162
  if (argc != optind)
163
  {
164
    client.query= argv[optind];
165
    client.query_len= strlen(client.query);
166
  }
167
168
  if (client.client_con_count > 0)
169
  {
170
    client.client_con_list= calloc(client.client_con_count,
171
                                   sizeof(client_con_st));
172
    if (client.client_con_list == NULL)
173
    {
174
      printf("calloc:%d\n", errno);
175
      exit(1);
176
    }
177
  }
178
179
  /* This may fail if there is other initialization that fails. See docs. */
180
  if (drizzle_create(&(client.drizzle)) == NULL)
181
  {
182
    printf("drizzle_create failed\n");
183
    exit(1);
184
  }
185
186
  if (blocking == 0)
187
    drizzle_add_options(&(client.drizzle), DRIZZLE_NON_BLOCKING);
188
189
  /* Start all connections, and if in non-blocking mode, return as soon as the
190
     connection would block. In blocking mode, this completes the entire
191
     connection/query/result. */
192
  for (x= 0; x < client.client_con_count; x++)
193
  {
194
    /* This may fail if there is other initialization that fails. See docs. */
195
    con= drizzle_con_add_tcp(&(client.drizzle),
196
                              &(client.client_con_list[x].con),
197
                              host, port, user, password, db,
198
                              client.mysql_protocol ? DRIZZLE_CON_MYSQL : 0);
199
    if (con == NULL)
200
      CLIENT_ERROR("drizzle_con_add_tcp", 0, &client);
201
    drizzle_con_set_context(&(client.client_con_list[x].con),
202
                            &(client.client_con_list[x]));
203
204
    if (client_process(&client, &(client.client_con_list[x])) == 1)
205
      wait_for_connections++;
206
  }
207
208
  /* If in non-blocking mode, continue to process connections as they become
209
     ready. Loop exits when all connections have completed. */
210
  while (wait_for_connections != 0)
211
  {
212
    ret= drizzle_con_wait(&(client.drizzle));
213
    if (ret != DRIZZLE_RETURN_OK)
214
      CLIENT_ERROR("drizzle_con_wait", ret, &client);
215
216
    while ((con= drizzle_con_ready(&(client.drizzle))) != NULL)
217
    {
218
      client_con= (client_con_st *)drizzle_con_context(con);
219
220
      if (client_process(&client, client_con) == 0)
221
        wait_for_connections--;
222
    }
223
  }
224
225
  for (x= 0; x < client.client_con_count; x++)
226
    drizzle_con_free(&(client.client_con_list[x].con));
227
228
  drizzle_free(&(client.drizzle));
229
230
  if (client.client_con_list != NULL)
231
    free(client.client_con_list);
232
233
  return 0;
234
}
235
236
char client_process(client_st *client, client_con_st *client_con)
237
{
238
  drizzle_return_t ret;
239
  drizzle_column_st *column;
240
  size_t offset= 0;
241
  size_t length;
242
  size_t total;
243
  drizzle_field_t field;
244
  drizzle_row_t row;
245
  size_t *field_sizes;
246
  uint16_t x;
247
248
  switch (client_con->state)
249
  {
250
  case CLIENT_QUERY:
251
    if (client->query == NULL)
252
      break;
253
254
    /* This may fail if some allocation fails, but it will set ret. */
255
    (void)drizzle_query(&(client_con->con), &(client_con->result),
256
                        client->query, client->query_len, &ret);
257
    if (ret == DRIZZLE_RETURN_IO_WAIT)
258
      return 1;
259
    else if (ret != DRIZZLE_RETURN_OK)
260
      CLIENT_ERROR("drizzle_query", ret, client);
261
262
    result_info(&(client_con->result));
263
264
    if (drizzle_result_column_count(&(client_con->result)) == 0)
265
      break;
266
267
    client_con->state= CLIENT_FIELDS;
268
269
  case CLIENT_FIELDS:
270
    if (client->level == BUFFER_ALL)
271
    {
272
      ret= drizzle_result_buffer(&(client_con->result));
273
      if (ret == DRIZZLE_RETURN_IO_WAIT)
274
        return 1;
275
      else if (ret != DRIZZLE_RETURN_OK)
276
        CLIENT_ERROR("drizzle_result_buffer", ret, client);
277
278
      while ((column= drizzle_column_next(&(client_con->result))) != NULL)
279
        column_info(column);
280
    }
281
    else
282
    {
283
      while (1)
284
      {
285
        column= drizzle_column_read(&(client_con->result),
286
                                    &(client_con->column), &ret);
287
        if (ret == DRIZZLE_RETURN_IO_WAIT)
288
          return 1;
289
        else if (ret != DRIZZLE_RETURN_OK)
290
          CLIENT_ERROR("drizzle_column_read", ret, client);
291
292
        if (column == NULL)
293
          break;
294
295
        column_info(column);
296
        drizzle_column_free(column);
297
      }
298
    }
299
300
    client_con->state= CLIENT_ROWS;
301
302
  case CLIENT_ROWS:
303
    if (client->level == BUFFER_ALL)
304
    {
305
      /* Everything has been buffered, just loop through and print. */
306
      while ((row= drizzle_row_next(&(client_con->result))) != NULL)
307
      {
308
        field_sizes= drizzle_row_field_sizes(&(client_con->result));
309
310
        printf("Row: %" PRId64 "\n",
311
               drizzle_row_current(&(client_con->result)));
312
313
        for (x= 0; x < drizzle_result_column_count(&(client_con->result)); x++)
314
        {
315
          if (row[x] == NULL)
316
            printf("     (NULL)\n");
317
          else
318
          {
319
            printf("     (%zd) %.*s\n", field_sizes[x], (int32_t)field_sizes[x],
320
                   row[x]);
321
          }
322
        }
323
324
        printf("\n");
325
      }
326
327
      drizzle_result_free(&(client_con->result));
328
      break;
329
    }
330
331
    while (1)
332
    {
333
      if (client->level == BUFFER_NONE || client->level == BUFFER_FIELD)
334
      {
335
        /* Still need to read a row at a time, and then each field. */
336
        if (client_con->row == 0)
337
        {
338
          client_con->row= drizzle_row_read(&(client_con->result), &ret);
339
          if (ret == DRIZZLE_RETURN_IO_WAIT)
340
          {
341
            client_con->row= 0;
342
            return 1;
343
          }
344
          else if (ret != DRIZZLE_RETURN_OK)
345
            CLIENT_ERROR("drizzle_row", ret, client);
346
347
          if (client_con->row == 0)
348
          {
349
            drizzle_result_free(&(client_con->result));
350
            break;
351
          }
352
353
          printf("Row: %" PRId64 "\n", client_con->row);
354
        }
355
356
        while (1)
357
        {
358
          if (client->level == BUFFER_FIELD)
359
          {
360
            /* Since an entire field is buffered, we don't need to worry about
361
               partial reads. */
362
            field= drizzle_field_buffer(&(client_con->result), &total, &ret);
363
            length= total;
364
          }
365
          else
366
          {
367
            field= drizzle_field_read(&(client_con->result), &offset, &length,
368
                                      &total, &ret);
369
          }
370
371
          if (ret == DRIZZLE_RETURN_IO_WAIT)
372
            return 1;
373
          else if (ret == DRIZZLE_RETURN_ROW_END)
374
            break;
375
          else if (ret != DRIZZLE_RETURN_OK)
376
            CLIENT_ERROR("drizzle_field_read", ret, client);
377
378
          if (field == NULL)
379
            printf("     (NULL)");
380
          else if (offset > 0)
381
            printf("%.*s", (int32_t)length, field);
382
          else
383
            printf("     (%zd) %.*s", total, (int32_t)length, field);
384
385
          if (offset + length == total)
386
            printf("\n");
387
388
          /* If we buffered the entire field, be sure to free it. */
389
          if (client->level == BUFFER_FIELD)
390
            drizzle_field_free(field);
391
        }
392
393
        client_con->row= 0;
394
        printf("\n");
395
      }
396
      else if (client->level == BUFFER_ROW)
397
      {
398
        /* The entire row will be buffered here, so no need to worry about
399
           partial reads. */
400
        row = drizzle_row_buffer(&(client_con->result), &ret);
401
        if (ret == DRIZZLE_RETURN_IO_WAIT)
402
          return 1;
403
        else if (ret != DRIZZLE_RETURN_OK)
404
          CLIENT_ERROR("drizzle_row", ret, client);
405
406
        /* This marks the end of rows. */
407
        if (row == NULL)
408
          break;
409
410
        field_sizes= drizzle_row_field_sizes(&(client_con->result));
411
412
        printf("Row: %" PRId64 "\n",
413
               drizzle_row_current(&(client_con->result)));
414
415
        for (x= 0; x < drizzle_result_column_count(&(client_con->result)); x++)
416
        {
417
          if (row[x] == NULL)
418
            printf("     (NULL)\n");
419
          else
420
          {
421
            printf("     (%zd) %.*s\n", field_sizes[x], (int32_t)field_sizes[x],
422
                   row[x]);
423
          }
424
        }
425
426
        drizzle_row_free(&(client_con->result), row);
427
        printf("\n");
428
      }
429
    }
430
431
    drizzle_result_free(&(client_con->result));
432
    break;
433
434
  default:
435
    /* This should be impossible. */
436
    return 1;
437
  }
438
439
  return 0;
440
}
441
442
void con_info(drizzle_con_st *con)
443
{
444
  printf("Connected: protocol_version=%u\n"
445
         "                    version=%s\n"
446
         "                  thread_id=%u\n"
447
         "               capabilities=%u\n"
448
         "                   language=%u\n"
449
         "                     status=%u\n\n",
450
         drizzle_con_protocol_version(con), drizzle_con_server_version(con),
451
         drizzle_con_thread_id(con), drizzle_con_capabilities(con),
452
         drizzle_con_charset(con), drizzle_con_status(con));
453
}
454
455
void result_info(drizzle_result_st *result)
456
{
457
  printf("Result:     row_count=%" PRId64 "\n"
458
         "            insert_id=%" PRId64 "\n"
459
         "        warning_count=%u\n"
460
         "         column_count=%u\n"
461
         "        affected_rows=%" PRId64 "\n\n",
462
         drizzle_result_row_count(result),
463
         drizzle_result_insert_id(result),
464
         drizzle_result_warning_count(result),
465
         drizzle_result_column_count(result),
466
         drizzle_result_affected_rows(result));
467
}
468
469
void column_info(drizzle_column_st *column)
470
{
471
  printf("Field:   catalog=%s\n"
472
         "              db=%s\n"
473
         "           table=%s\n"
474
         "       org_table=%s\n"
475
         "            name=%s\n"
476
         "        org_name=%s\n"
477
         "         charset=%u\n"
478
         "            size=%u\n"
479
         "        max_size=%zu\n"
480
         "            type=%u\n"
481
         "           flags=%u\n\n",
482
         drizzle_column_catalog(column), drizzle_column_db(column),
483
         drizzle_column_table(column), drizzle_column_orig_table(column),
484
         drizzle_column_name(column), drizzle_column_orig_name(column),
485
         drizzle_column_charset(column), drizzle_column_size(column),
486
         drizzle_column_max_size(column), drizzle_column_type(column),
487
         drizzle_column_flags(column));
488
}