libdrizzle Developer Documentation

examples/client.c
Go to the documentation of this file.
00001 /*
00002  * Drizzle Client & Protocol Library
00003  *
00004  * Copyright (C) 2008 Eric Day (eday@oddments.org)
00005  * All rights reserved.
00006  *
00007  * Use and distribution licensed under the BSD license.  See
00008  * the COPYING file in this directory for full text.
00009  */
00010 
00011 #include "config.h"
00012 
00013 #include <errno.h>
00014 #include <stdbool.h>
00015 #include <stdint.h>
00016 #include <stdio.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #include <unistd.h>
00020 
00021 #include <libdrizzle/drizzle_client.h>
00022 
00023 typedef enum
00024 {
00025   CLIENT_QUERY,
00026   CLIENT_FIELDS,
00027   CLIENT_ROWS
00028 } client_state;
00029 
00030 typedef enum
00031 {
00032   BUFFER_NONE,
00033   BUFFER_FIELD,
00034   BUFFER_ROW,
00035   BUFFER_ALL
00036 } buffer_level;
00037 
00038 typedef struct
00039 {
00040   drizzle_con_st con;
00041   drizzle_result_st result;
00042   drizzle_column_st column;
00043   client_state state;
00044   uint64_t row;
00045 } client_con_st;
00046 
00047 typedef struct
00048 {
00049   drizzle_st drizzle;
00050   bool mysql_protocol;
00051   client_con_st *client_con_list;
00052   uint32_t client_con_count;
00053   buffer_level level;
00054   char *query;
00055   size_t query_len;
00056 } client_st;
00057 
00058 char client_process(client_st *client, client_con_st *client_con);
00059 void con_info(drizzle_con_st *con);
00060 void result_info(drizzle_result_st *result);
00061 void column_info(drizzle_column_st *column);
00062 
00063 #define CLIENT_ERROR(__function, __ret, __client) { \
00064     printf(__function ":%d:%s\n", __ret, \
00065            drizzle_error(&((__client)->drizzle))); \
00066     exit(1); }
00067 
00068 int main(int argc, char *argv[])
00069 {
00070   client_st client;
00071   int c;
00072   char blocking= 0;
00073   drizzle_return_t ret;
00074   uint32_t x;
00075   int wait_for_connections= 0;
00076   drizzle_con_st *con;
00077   client_con_st *client_con;
00078   char *host= NULL;
00079   in_port_t port= 0;
00080   char *user= NULL;
00081   char *password= NULL;
00082   char *db= NULL;
00083 
00084   memset(&client, 0, sizeof(client_st));
00085 
00086   /* Use one connection by default. */
00087   client.client_con_count= 1;
00088 
00089   while ((c = getopt(argc, argv, "bB:c:d:h:Hmp:P:u:")) != -1)
00090   {
00091     switch(c)
00092     {
00093     case 'b':
00094       blocking= 1;
00095       break;
00096 
00097     case 'B':
00098       if (!strcasecmp(optarg, "none"))
00099         client.level= BUFFER_NONE;
00100       else if (!strcasecmp(optarg, "field"))
00101         client.level= BUFFER_FIELD;
00102       else if (!strcasecmp(optarg, "row"))
00103         client.level= BUFFER_ROW;
00104       else if (!strcasecmp(optarg, "all"))
00105         client.level= BUFFER_ALL;
00106       else
00107       {
00108         printf("Invalid buffer level: %s\n", optarg);
00109         exit(0);
00110       }
00111       break;
00112 
00113     case 'c':
00114       client.client_con_count= (uint32_t)atoi(optarg);
00115       break;
00116 
00117     case 'd':
00118       db= optarg;
00119       break;
00120 
00121     case 'h':
00122       host= optarg;
00123       break;
00124 
00125     case 'm':
00126       client.mysql_protocol= true;
00127       break;
00128 
00129     case 'p':
00130       password= optarg;
00131       break;
00132 
00133     case 'P':
00134       port= (in_port_t)atoi(optarg);
00135       break;
00136 
00137     case 'u':
00138       user= optarg;
00139       break;
00140 
00141     case 'H':
00142     default:
00143       printf("\nUsage: %s [options] [query]\n", argv[0]);
00144       printf("\t-b            - Use blocking sockets\n");
00145       printf("\t-B <level>    - Use buffer <level>, options are:\n");
00146       printf("\t                none - Don't buffer anything (default)\n");
00147       printf("\t                field - Only buffer individual fields\n");
00148       printf("\t                row - Only buffer individual rows\n");
00149       printf("\t                all - Buffer entire result\n");
00150       printf("\t-c <cons>     - Create <cons> connections\n");
00151       printf("\t-d <db>       - Use <db> for the connection\n");
00152       printf("\t-h <host>     - Connect to <host>\n");
00153       printf("\t-H            - Print this help menu\n");
00154       printf("\t-m            - Use MySQL protocol\n");
00155       printf("\t-p <password> - Use <password> for authentication\n");
00156       printf("\t-P <port>     - Connect to <port>\n");
00157       printf("\t-u <user>     - Use <user> for authentication\n");
00158       exit(0);
00159     }
00160   }
00161 
00162   if (argc != optind)
00163   {
00164     client.query= argv[optind];
00165     client.query_len= strlen(client.query);
00166   }
00167 
00168   if (client.client_con_count > 0)
00169   {
00170     client.client_con_list= calloc(client.client_con_count,
00171                                    sizeof(client_con_st));
00172     if (client.client_con_list == NULL)
00173     {
00174       printf("calloc:%d\n", errno);
00175       exit(1);
00176     }
00177   }
00178 
00179   /* This may fail if there is other initialization that fails. See docs. */
00180   if (drizzle_create(&(client.drizzle)) == NULL)
00181   {
00182     printf("drizzle_create failed\n");
00183     exit(1);
00184   }
00185 
00186   if (blocking == 0)
00187     drizzle_add_options(&(client.drizzle), DRIZZLE_NON_BLOCKING);
00188 
00189   /* Start all connections, and if in non-blocking mode, return as soon as the
00190      connection would block. In blocking mode, this completes the entire
00191      connection/query/result. */
00192   for (x= 0; x < client.client_con_count; x++)
00193   {
00194     /* This may fail if there is other initialization that fails. See docs. */
00195     con= drizzle_con_add_tcp(&(client.drizzle),
00196                               &(client.client_con_list[x].con),
00197                               host, port, user, password, db,
00198                               client.mysql_protocol ? DRIZZLE_CON_MYSQL : 0);
00199     if (con == NULL)
00200       CLIENT_ERROR("drizzle_con_add_tcp", 0, &client);
00201     drizzle_con_set_context(&(client.client_con_list[x].con),
00202                             &(client.client_con_list[x]));
00203 
00204     if (client_process(&client, &(client.client_con_list[x])) == 1)
00205       wait_for_connections++;
00206   }
00207 
00208   /* If in non-blocking mode, continue to process connections as they become
00209      ready. Loop exits when all connections have completed. */
00210   while (wait_for_connections != 0)
00211   {
00212     ret= drizzle_con_wait(&(client.drizzle));
00213     if (ret != DRIZZLE_RETURN_OK)
00214       CLIENT_ERROR("drizzle_con_wait", ret, &client);
00215 
00216     while ((con= drizzle_con_ready(&(client.drizzle))) != NULL)
00217     {
00218       client_con= (client_con_st *)drizzle_con_context(con);
00219 
00220       if (client_process(&client, client_con) == 0)
00221         wait_for_connections--;
00222     }
00223   }
00224 
00225   for (x= 0; x < client.client_con_count; x++)
00226     drizzle_con_free(&(client.client_con_list[x].con));
00227 
00228   drizzle_free(&(client.drizzle));
00229 
00230   if (client.client_con_list != NULL)
00231     free(client.client_con_list);
00232 
00233   return 0;
00234 }
00235 
00236 char client_process(client_st *client, client_con_st *client_con)
00237 {
00238   drizzle_return_t ret;
00239   drizzle_column_st *column;
00240   size_t offset= 0;
00241   size_t length;
00242   size_t total;
00243   drizzle_field_t field;
00244   drizzle_row_t row;
00245   size_t *field_sizes;
00246   uint16_t x;
00247 
00248   switch (client_con->state)
00249   {
00250   case CLIENT_QUERY:
00251     if (client->query == NULL)
00252       break;
00253 
00254     /* This may fail if some allocation fails, but it will set ret. */
00255     (void)drizzle_query(&(client_con->con), &(client_con->result),
00256                         client->query, client->query_len, &ret);
00257     if (ret == DRIZZLE_RETURN_IO_WAIT)
00258       return 1;
00259     else if (ret != DRIZZLE_RETURN_OK)
00260       CLIENT_ERROR("drizzle_query", ret, client);
00261 
00262     result_info(&(client_con->result));
00263 
00264     if (drizzle_result_column_count(&(client_con->result)) == 0)
00265       break;
00266 
00267     client_con->state= CLIENT_FIELDS;
00268 
00269   case CLIENT_FIELDS:
00270     if (client->level == BUFFER_ALL)
00271     {
00272       ret= drizzle_result_buffer(&(client_con->result));
00273       if (ret == DRIZZLE_RETURN_IO_WAIT)
00274         return 1;
00275       else if (ret != DRIZZLE_RETURN_OK)
00276         CLIENT_ERROR("drizzle_result_buffer", ret, client);
00277 
00278       while ((column= drizzle_column_next(&(client_con->result))) != NULL)
00279         column_info(column);
00280     }
00281     else
00282     {
00283       while (1)
00284       {
00285         column= drizzle_column_read(&(client_con->result),
00286                                     &(client_con->column), &ret);
00287         if (ret == DRIZZLE_RETURN_IO_WAIT)
00288           return 1;
00289         else if (ret != DRIZZLE_RETURN_OK)
00290           CLIENT_ERROR("drizzle_column_read", ret, client);
00291 
00292         if (column == NULL)
00293           break;
00294 
00295         column_info(column);
00296         drizzle_column_free(column);
00297       }
00298     }
00299 
00300     client_con->state= CLIENT_ROWS;
00301 
00302   case CLIENT_ROWS:
00303     if (client->level == BUFFER_ALL)
00304     {
00305       /* Everything has been buffered, just loop through and print. */
00306       while ((row= drizzle_row_next(&(client_con->result))) != NULL)
00307       {
00308         field_sizes= drizzle_row_field_sizes(&(client_con->result));
00309 
00310         printf("Row: %" PRId64 "\n",
00311                drizzle_row_current(&(client_con->result)));
00312 
00313         for (x= 0; x < drizzle_result_column_count(&(client_con->result)); x++)
00314         {
00315           if (row[x] == NULL)
00316             printf("     (NULL)\n");
00317           else
00318           {
00319             printf("     (%zd) %.*s\n", field_sizes[x], (int32_t)field_sizes[x],
00320                    row[x]);
00321           }
00322         }
00323 
00324         printf("\n");
00325       }
00326 
00327       drizzle_result_free(&(client_con->result));
00328       break;
00329     }
00330 
00331     while (1)
00332     {
00333       if (client->level == BUFFER_NONE || client->level == BUFFER_FIELD)
00334       {
00335         /* Still need to read a row at a time, and then each field. */
00336         if (client_con->row == 0)
00337         {
00338           client_con->row= drizzle_row_read(&(client_con->result), &ret);
00339           if (ret == DRIZZLE_RETURN_IO_WAIT)
00340           {
00341             client_con->row= 0;
00342             return 1;
00343           }
00344           else if (ret != DRIZZLE_RETURN_OK)
00345             CLIENT_ERROR("drizzle_row", ret, client);
00346 
00347           if (client_con->row == 0)
00348           {
00349             drizzle_result_free(&(client_con->result));
00350             break;
00351           }
00352 
00353           printf("Row: %" PRId64 "\n", client_con->row);
00354         }
00355 
00356         while (1)
00357         {
00358           if (client->level == BUFFER_FIELD)
00359           {
00360             /* Since an entire field is buffered, we don't need to worry about
00361                partial reads. */
00362             field= drizzle_field_buffer(&(client_con->result), &total, &ret);
00363             length= total;
00364           }
00365           else
00366           {
00367             field= drizzle_field_read(&(client_con->result), &offset, &length,
00368                                       &total, &ret);
00369           }
00370 
00371           if (ret == DRIZZLE_RETURN_IO_WAIT)
00372             return 1;
00373           else if (ret == DRIZZLE_RETURN_ROW_END)
00374             break;
00375           else if (ret != DRIZZLE_RETURN_OK)
00376             CLIENT_ERROR("drizzle_field_read", ret, client);
00377 
00378           if (field == NULL)
00379             printf("     (NULL)");
00380           else if (offset > 0)
00381             printf("%.*s", (int32_t)length, field);
00382           else
00383             printf("     (%zd) %.*s", total, (int32_t)length, field);
00384 
00385           if (offset + length == total)
00386             printf("\n");
00387 
00388           /* If we buffered the entire field, be sure to free it. */
00389           if (client->level == BUFFER_FIELD)
00390             drizzle_field_free(field);
00391         }
00392 
00393         client_con->row= 0;
00394         printf("\n");
00395       }
00396       else if (client->level == BUFFER_ROW)
00397       {
00398         /* The entire row will be buffered here, so no need to worry about
00399            partial reads. */
00400         row = drizzle_row_buffer(&(client_con->result), &ret);
00401         if (ret == DRIZZLE_RETURN_IO_WAIT)
00402           return 1;
00403         else if (ret != DRIZZLE_RETURN_OK)
00404           CLIENT_ERROR("drizzle_row", ret, client);
00405 
00406         /* This marks the end of rows. */
00407         if (row == NULL)
00408           break;
00409 
00410         field_sizes= drizzle_row_field_sizes(&(client_con->result));
00411 
00412         printf("Row: %" PRId64 "\n",
00413                drizzle_row_current(&(client_con->result)));
00414 
00415         for (x= 0; x < drizzle_result_column_count(&(client_con->result)); x++)
00416         {
00417           if (row[x] == NULL)
00418             printf("     (NULL)\n");
00419           else
00420           {
00421             printf("     (%zd) %.*s\n", field_sizes[x], (int32_t)field_sizes[x],
00422                    row[x]);
00423           }
00424         }
00425 
00426         drizzle_row_free(&(client_con->result), row);
00427         printf("\n");
00428       }
00429     }
00430 
00431     drizzle_result_free(&(client_con->result));
00432     break;
00433 
00434   default:
00435     /* This should be impossible. */
00436     return 1;
00437   }
00438 
00439   return 0;
00440 }
00441 
00442 void con_info(drizzle_con_st *con)
00443 {
00444   printf("Connected: protocol_version=%u\n"
00445          "                    version=%s\n"
00446          "                  thread_id=%u\n"
00447          "               capabilities=%u\n"
00448          "                   language=%u\n"
00449          "                     status=%u\n\n",
00450          drizzle_con_protocol_version(con), drizzle_con_server_version(con),
00451          drizzle_con_thread_id(con), drizzle_con_capabilities(con),
00452          drizzle_con_charset(con), drizzle_con_status(con));
00453 }
00454 
00455 void result_info(drizzle_result_st *result)
00456 {
00457   printf("Result:     row_count=%" PRId64 "\n"
00458          "            insert_id=%" PRId64 "\n"
00459          "        warning_count=%u\n"
00460          "         column_count=%u\n\n",
00461          drizzle_result_row_count(result),
00462          drizzle_result_insert_id(result),
00463          drizzle_result_warning_count(result),
00464          drizzle_result_column_count(result));
00465 }
00466 
00467 void column_info(drizzle_column_st *column)
00468 {
00469   printf("Field:   catalog=%s\n"
00470          "              db=%s\n"
00471          "           table=%s\n"
00472          "       org_table=%s\n"
00473          "            name=%s\n"
00474          "        org_name=%s\n"
00475          "         charset=%u\n"
00476          "            size=%u\n"
00477          "        max_size=%zu\n"
00478          "            type=%u\n"
00479          "           flags=%u\n\n",
00480          drizzle_column_catalog(column), drizzle_column_db(column),
00481          drizzle_column_table(column), drizzle_column_orig_table(column),
00482          drizzle_column_name(column), drizzle_column_orig_name(column),
00483          drizzle_column_charset(column), drizzle_column_size(column),
00484          drizzle_column_max_size(column), drizzle_column_type(column),
00485          drizzle_column_flags(column));
00486 }