~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to examples/client.cc

Fix merge issues with 1.0 CC fix.

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-2.0/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
    fprintf(stderr, __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
  client_con_st *client_con;
 
104
  char *host= NULL;
 
105
  in_port_t port= 0;
 
106
  char *user= NULL;
 
107
  char *password= NULL;
 
108
  char *db= NULL;
 
109
 
 
110
  memset(&client, 0, sizeof(client_st));
 
111
 
 
112
  /* Use one connection by default. */
 
113
  client.client_con_count= 1;
 
114
 
 
115
  while ((c = getopt(argc, argv, "bB:c:d:h:Hmp:P:u:")) != -1)
 
116
  {
 
117
    switch(c)
 
118
    {
 
119
    case 'b':
 
120
      blocking= 1;
 
121
      break;
 
122
 
 
123
    case 'B':
 
124
      if (!strcasecmp(optarg, "none"))
 
125
        client.level= BUFFER_NONE;
 
126
      else if (!strcasecmp(optarg, "field"))
 
127
        client.level= BUFFER_FIELD;
 
128
      else if (!strcasecmp(optarg, "row"))
 
129
        client.level= BUFFER_ROW;
 
130
      else if (!strcasecmp(optarg, "all"))
 
131
        client.level= BUFFER_ALL;
 
132
      else
 
133
      {
 
134
        fprintf(stderr, "Invalid buffer level: %s\n", optarg);
 
135
        exit(0);
 
136
      }
 
137
      break;
 
138
 
 
139
    case 'c':
 
140
      client.client_con_count= (uint32_t)atoi(optarg);
 
141
      break;
 
142
 
 
143
    case 'd':
 
144
      db= optarg;
 
145
      break;
 
146
 
 
147
    case 'h':
 
148
      host= optarg;
 
149
      break;
 
150
 
 
151
    case 'm':
 
152
      client.mysql_protocol= true;
 
153
      break;
 
154
 
 
155
    case 'p':
 
156
      password= optarg;
 
157
      break;
 
158
 
 
159
    case 'P':
 
160
      port= (in_port_t)atoi(optarg);
 
161
      break;
 
162
 
 
163
    case 'u':
 
164
      user= optarg;
 
165
      break;
 
166
 
 
167
    case 'H':
 
168
    default:
 
169
      printf("\nUsage: %s [options] [query]\n", argv[0]);
 
170
      printf("\t-b            - Use blocking sockets\n");
 
171
      printf("\t-B <level>    - Use buffer <level>, options are:\n");
 
172
      printf("\t                none - Don't buffer anything (default)\n");
 
173
      printf("\t                field - Only buffer individual fields\n");
 
174
      printf("\t                row - Only buffer individual rows\n");
 
175
      printf("\t                all - Buffer entire result\n");
 
176
      printf("\t-c <cons>     - Create <cons> connections\n");
 
177
      printf("\t-d <db>       - Use <db> for the connection\n");
 
178
      printf("\t-h <host>     - Connect to <host>\n");
 
179
      printf("\t-H            - Print this help menu\n");
 
180
      printf("\t-m            - Use MySQL protocol\n");
 
181
      printf("\t-p <password> - Use <password> for authentication\n");
 
182
      printf("\t-P <port>     - Connect to <port>\n");
 
183
      printf("\t-u <user>     - Use <user> for authentication\n");
 
184
      exit(0);
 
185
    }
 
186
  }
 
187
 
 
188
  if (argc != optind)
 
189
  {
 
190
    client.query= argv[optind];
 
191
    client.query_len= strlen(client.query);
 
192
  }
 
193
 
 
194
  if (client.client_con_count > 0)
 
195
  {
 
196
    client.client_con_list= (client_con_st *)calloc(client.client_con_count,
 
197
                                                    sizeof(client_con_st));
 
198
    if (client.client_con_list == NULL)
 
199
    {
 
200
      fprintf(stderr, "calloc:%d\n", errno);
 
201
      exit(1);
 
202
    }
 
203
  }
 
204
 
 
205
  /* This may fail if there is other initialization that fails. See docs. */
 
206
  if ((client.drizzle= drizzle_create()) == NULL)
 
207
  {
 
208
    fprintf(stderr, "drizzle_create failed\n");
 
209
    exit(1);
 
210
  }
 
211
 
 
212
  if (blocking == 0)
 
213
  {
 
214
    drizzle_set_option(client.drizzle, DRIZZLE_NON_BLOCKING, true);
 
215
  }
 
216
 
 
217
  /* Start all connections, and if in non-blocking mode, return as soon as the
 
218
     connection would block. In blocking mode, this completes the entire
 
219
     connection/query/result. */
 
220
  for (x= 0; x < client.client_con_count; x++)
 
221
  {
 
222
    /* This may fail if there is other initialization that fails. See docs. */
 
223
    drizzle_con_st *con= drizzle_con_add_tcp(client.drizzle,
 
224
                                             host, port, user, password, db,
 
225
                                             client.mysql_protocol
 
226
                                             ? DRIZZLE_CON_MYSQL
 
227
                                             : DRIZZLE_CON_NONE);
 
228
    if (con == NULL)
 
229
    {
 
230
      CLIENT_ERROR("drizzle_con_add_tcp", 0, &client);
 
231
    }
 
232
    drizzle_con_set_context(&(client.client_con_list[x].con),
 
233
                            &(client.client_con_list[x]));
 
234
 
 
235
    if (client_process(&client, &(client.client_con_list[x])) == 1)
 
236
      wait_for_connections++;
 
237
  }
 
238
 
 
239
  /* If in non-blocking mode, continue to process connections as they become
 
240
     ready. Loop exits when all connections have completed. */
 
241
  while (wait_for_connections != 0)
 
242
  {
 
243
    ret= drizzle_con_wait(client.drizzle);
 
244
    if (ret != DRIZZLE_RETURN_OK)
 
245
    {
 
246
      CLIENT_ERROR("drizzle_con_wait", ret, &client);
 
247
    }
 
248
 
 
249
    drizzle_con_st* con;
 
250
    while ((con= drizzle_con_ready(client.drizzle)) != NULL)
 
251
    {
 
252
      client_con= (client_con_st *)drizzle_con_context(con);
 
253
 
 
254
      if (client_process(&client, client_con) == 0)
 
255
      {
 
256
        wait_for_connections--;
 
257
      }
 
258
    }
 
259
  }
 
260
 
 
261
  for (x= 0; x < client.client_con_count; x++)
 
262
  {
 
263
    drizzle_con_free(&(client.client_con_list[x].con));
 
264
  }
 
265
 
 
266
  drizzle_free(client.drizzle);
 
267
 
 
268
  free(client.client_con_list);
 
269
 
 
270
  return 0;
 
271
}
 
272
 
 
273
char client_process(client_st *client, client_con_st *client_con)
 
274
{
 
275
  drizzle_return_t ret;
 
276
  drizzle_column_st *column;
 
277
  size_t offset= 0;
 
278
  size_t length;
 
279
  size_t total;
 
280
  drizzle_field_t field;
 
281
  drizzle_row_t row;
 
282
  size_t *field_sizes;
 
283
  uint16_t x;
 
284
 
 
285
  switch (client_con->state)
 
286
  {
 
287
  case CLIENT_QUERY:
 
288
    if (client->query == NULL)
 
289
      break;
 
290
 
 
291
    /* This may fail if some allocation fails, but it will set ret. */
 
292
    (void)drizzle_query(&(client_con->con), &(client_con->result),
 
293
                        client->query, client->query_len, &ret);
 
294
    if (ret == DRIZZLE_RETURN_IO_WAIT)
 
295
    {
 
296
      return 1;
 
297
    }
 
298
    else if (ret != DRIZZLE_RETURN_OK)
 
299
    {
 
300
      CLIENT_ERROR("drizzle_query", ret, client);
 
301
    }
 
302
 
 
303
    result_info(&(client_con->result));
 
304
 
 
305
    if (drizzle_result_column_count(&(client_con->result)) == 0)
 
306
    {
 
307
      break;
 
308
    }
 
309
 
 
310
    client_con->state= CLIENT_FIELDS;
 
311
 
 
312
  case CLIENT_FIELDS:
 
313
    if (client->level == BUFFER_ALL)
 
314
    {
 
315
      ret= drizzle_result_buffer(&(client_con->result));
 
316
      if (ret == DRIZZLE_RETURN_IO_WAIT)
 
317
      {
 
318
        return 1;
 
319
      }
 
320
      else if (ret != DRIZZLE_RETURN_OK)
 
321
      {
 
322
        CLIENT_ERROR("drizzle_result_buffer", ret, client);
 
323
      }
 
324
 
 
325
      while ((column= drizzle_column_next(&(client_con->result))) != NULL)
 
326
        column_info(column);
 
327
    }
 
328
    else
 
329
    {
 
330
      while (1)
 
331
      {
 
332
        column= drizzle_column_read(&(client_con->result),
 
333
                                    &(client_con->column), &ret);
 
334
        if (ret == DRIZZLE_RETURN_IO_WAIT)
 
335
        {
 
336
          return 1;
 
337
        }
 
338
        else if (ret != DRIZZLE_RETURN_OK)
 
339
        {
 
340
          CLIENT_ERROR("drizzle_column_read", ret, client);
 
341
        }
 
342
 
 
343
        if (column == NULL)
 
344
          break;
 
345
 
 
346
        column_info(column);
 
347
        drizzle_column_free(column);
 
348
      }
 
349
    }
 
350
 
 
351
    client_con->state= CLIENT_ROWS;
 
352
 
 
353
  case CLIENT_ROWS:
 
354
    if (client->level == BUFFER_ALL)
 
355
    {
 
356
      /* Everything has been buffered, just loop through and print. */
 
357
      while ((row= drizzle_row_next(&(client_con->result))) != NULL)
 
358
      {
 
359
        field_sizes= drizzle_row_field_sizes(&(client_con->result));
 
360
 
 
361
        printf("Row: %" PRId64 "\n", drizzle_row_current(&(client_con->result)));
 
362
 
 
363
        for (x= 0; x < drizzle_result_column_count(&(client_con->result)); x++)
 
364
        {
 
365
          if (row[x] == NULL)
 
366
          {
 
367
            printf("     (NULL)\n");
 
368
          }
 
369
          else
 
370
          {
 
371
            printf("     (%"PRIu64") %.*s\n", static_cast<uint64_t>(field_sizes[x]), (int32_t)field_sizes[x], row[x]);
 
372
          }
 
373
        }
 
374
 
 
375
        printf("\n");
 
376
      }
 
377
 
 
378
      drizzle_result_free(&(client_con->result));
 
379
      break;
 
380
    }
 
381
 
 
382
    while (1)
 
383
    {
 
384
      if (client->level == BUFFER_NONE || client->level == BUFFER_FIELD)
 
385
      {
 
386
        /* Still need to read a row at a time, and then each field. */
 
387
        if (client_con->row == 0)
 
388
        {
 
389
          client_con->row= drizzle_row_read(&(client_con->result), &ret);
 
390
          if (ret == DRIZZLE_RETURN_IO_WAIT)
 
391
          {
 
392
            client_con->row= 0;
 
393
            return 1;
 
394
          }
 
395
          else if (ret != DRIZZLE_RETURN_OK)
 
396
            CLIENT_ERROR("drizzle_row", ret, client);
 
397
 
 
398
          if (client_con->row == 0)
 
399
          {
 
400
            drizzle_result_free(&(client_con->result));
 
401
            break;
 
402
          }
 
403
 
 
404
          printf("Row: %" PRId64 "\n", client_con->row);
 
405
        }
 
406
 
 
407
        while (1)
 
408
        {
 
409
          if (client->level == BUFFER_FIELD)
 
410
          {
 
411
            /* Since an entire field is buffered, we don't need to worry about
 
412
               partial reads. */
 
413
            field= drizzle_field_buffer(&(client_con->result), &total, &ret);
 
414
            length= total;
 
415
          }
 
416
          else
 
417
          {
 
418
            field= drizzle_field_read(&(client_con->result), &offset, &length,
 
419
                                      &total, &ret);
 
420
          }
 
421
 
 
422
          if (ret == DRIZZLE_RETURN_IO_WAIT)
 
423
            return 1;
 
424
          else if (ret == DRIZZLE_RETURN_ROW_END)
 
425
            break;
 
426
          else if (ret != DRIZZLE_RETURN_OK)
 
427
            CLIENT_ERROR("drizzle_field_read", ret, client);
 
428
 
 
429
          if (field == NULL)
 
430
          {
 
431
            printf("     (NULL)");
 
432
          }
 
433
          else if (offset > 0)
 
434
          {
 
435
            printf("%.*s", (int32_t)length, field);
 
436
          }
 
437
          else
 
438
          {
 
439
            printf("     (%" PRIu64 " %.*s", (uint64_t)total, (int32_t)length, field);
 
440
          }
 
441
 
 
442
          if (offset + length == total)
 
443
          {
 
444
            printf("\n");
 
445
          }
 
446
 
 
447
          /* If we buffered the entire field, be sure to free it. */
 
448
          if (client->level == BUFFER_FIELD)
 
449
            drizzle_field_free(field);
 
450
        }
 
451
 
 
452
        client_con->row= 0;
 
453
        printf("\n");
 
454
      }
 
455
      else if (client->level == BUFFER_ROW)
 
456
      {
 
457
        /* The entire row will be buffered here, so no need to worry about
 
458
           partial reads. */
 
459
        row = drizzle_row_buffer(&(client_con->result), &ret);
 
460
        if (ret == DRIZZLE_RETURN_IO_WAIT)
 
461
          return 1;
 
462
        else if (ret != DRIZZLE_RETURN_OK)
 
463
          CLIENT_ERROR("drizzle_row", ret, client);
 
464
 
 
465
        /* This marks the end of rows. */
 
466
        if (row == NULL)
 
467
          break;
 
468
 
 
469
        field_sizes= drizzle_row_field_sizes(&(client_con->result));
 
470
 
 
471
        printf("Row: %" PRId64 "\n",
 
472
               static_cast<uint64_t>(drizzle_row_current(&(client_con->result))));
 
473
 
 
474
        for (x= 0; x < drizzle_result_column_count(&(client_con->result)); x++)
 
475
        {
 
476
          if (row[x] == NULL)
 
477
            printf("     (NULL)\n");
 
478
          else
 
479
          {
 
480
            printf("     (%" PRIu64 " %.*s\n", static_cast<uint64_t>(field_sizes[x]), (int32_t)field_sizes[x],
 
481
                   row[x]);
 
482
          }
 
483
        }
 
484
 
 
485
        drizzle_row_free(&(client_con->result), row);
 
486
        printf("\n");
 
487
      }
 
488
    }
 
489
 
 
490
    drizzle_result_free(&(client_con->result));
 
491
    break;
 
492
 
 
493
  default:
 
494
    /* This should be impossible. */
 
495
    return 1;
 
496
  }
 
497
 
 
498
  return 0;
 
499
}
 
500
 
 
501
void con_info(drizzle_con_st *con)
 
502
{
 
503
  printf("Connected: protocol_version=%u\n"
 
504
         "                    version=%s\n"
 
505
         "                  thread_id=%u\n"
 
506
         "               capabilities=%u\n"
 
507
         "                   language=%u\n"
 
508
         "                     status=%u\n\n",
 
509
         drizzle_con_protocol_version(con), drizzle_con_server_version(con),
 
510
         drizzle_con_thread_id(con), drizzle_con_capabilities(con),
 
511
         drizzle_con_charset(con), drizzle_con_status(con));
 
512
}
 
513
 
 
514
void result_info(drizzle_result_st *result)
 
515
{
 
516
  printf("Result:     row_count=%" PRId64 "\n"
 
517
         "            insert_id=%" PRId64 "\n"
 
518
         "        warning_count=%u\n"
 
519
         "         column_count=%u\n"
 
520
         "        affected_rows=%" PRId64 "\n\n",
 
521
         drizzle_result_row_count(result),
 
522
         drizzle_result_insert_id(result),
 
523
         drizzle_result_warning_count(result),
 
524
         drizzle_result_column_count(result),
 
525
         drizzle_result_affected_rows(result));
 
526
}
 
527
 
 
528
void column_info(drizzle_column_st *column)
 
529
{
 
530
  printf("Field:   catalog=%s\n"
 
531
         "              db=%s\n"
 
532
         "           table=%s\n"
 
533
         "       org_table=%s\n"
 
534
         "            name=%s\n"
 
535
         "        org_name=%s\n"
 
536
         "         charset=%u\n"
 
537
         "            size=%u\n"
 
538
         "        max_size=%" PRIu64 "\n"
 
539
         "            type=%u\n"
 
540
         "           flags=%u\n\n",
 
541
         drizzle_column_catalog(column), drizzle_column_db(column),
 
542
         drizzle_column_table(column), drizzle_column_orig_table(column),
 
543
         drizzle_column_name(column), drizzle_column_orig_name(column),
 
544
         drizzle_column_charset(column), drizzle_column_size(column),
 
545
         static_cast<uint64_t>(drizzle_column_max_size(column)), drizzle_column_type(column),
 
546
         drizzle_column_flags(column));
 
547
}