~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to examples/client.c

  • Committer: Brian Aker
  • Date: 2009-10-15 00:22:33 UTC
  • mto: (1183.1.11 merge)
  • mto: This revision was merged to the branch mainline in revision 1198.
  • Revision ID: brian@gaz-20091015002233-fa4ao2mbc67wls91
First pass of information engine. OMG, ponies... is it so much easier to
deal with creating and engine.

The list table iterator though... its ass, needs to go. We should also
abstract out share. Very few engines need a custom one. Just say'in

Show diffs side-by-side

added added

removed removed

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