libdrizzle Developer Documentation

examples/sqlite_server.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 <errno.h>
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <string.h>
00015 #include <strings.h>
00016 #include <unistd.h>
00017 
00018 #include <libdrizzle/drizzle_server.h>
00019 #include <sqlite3.h>
00020 
00021 #define SQLITE_SERVER_VERSION "SQLite Server using libdrizzle 0.1"
00022 
00023 #define DRIZZLE_RETURN_CHECK(__ret, __function, __drizzle) \
00024 { \
00025   if ((__ret) != DRIZZLE_RETURN_OK) \
00026     DRIZZLE_RETURN_ERROR(__function, __drizzle) \
00027 }
00028 
00029 #define DRIZZLE_RETURN_ERROR(__function, __drizzle) \
00030 { \
00031   printf(__function ":%s\n", drizzle_error(__drizzle)); \
00032   return; \
00033 }
00034 
00035 #define DRIZZLE_RETURN_CHECK_VAL(__ret, __function, __drizzle) \
00036 { \
00037   if ((__ret) != DRIZZLE_RETURN_OK) \
00038   { \
00039     printf(__function ":%s\n", drizzle_error(__drizzle)); \
00040     return ret; \
00041   } \
00042 }
00043 
00044 typedef struct
00045 {
00046   drizzle_st drizzle;
00047   drizzle_con_st con;
00048   drizzle_result_st result;
00049   drizzle_column_st column;
00050   sqlite3* db;
00051   bool send_columns;
00052   drizzle_verbose_t verbose;
00053   uint64_t rows;
00054 } sqlite_server;
00055 
00056 static void server_run(sqlite_server *server);
00057 static int row_cb(void *data, int field_count, char **fields, char **columns);
00058 static drizzle_return_t send_version(sqlite_server *server);
00059 static void usage(char *name);
00060 
00061 int main(int argc, char *argv[])
00062 {
00063   int c;
00064   uint32_t count= 0;
00065   const char *host= NULL;
00066   bool mysql= false;
00067   in_port_t port= 0;
00068   drizzle_return_t ret;
00069   sqlite_server server;
00070   drizzle_con_st con_listen;
00071 
00072   server.db= NULL;
00073   server.verbose= DRIZZLE_VERBOSE_NEVER;
00074 
00075   while((c = getopt(argc, argv, "c:h:mp:v")) != -1)
00076   {
00077     switch(c)
00078     {
00079     case 'c':
00080       count= (uint32_t)atoi(optarg);
00081       break;
00082 
00083     case 'h':
00084       host= optarg;
00085       break;
00086 
00087     case 'm':
00088       mysql= true;
00089       break;
00090 
00091     case 'p':
00092       port= (in_port_t)atoi(optarg);
00093       break;
00094 
00095     case 'v':
00096       server.verbose++;
00097       break;
00098 
00099     default:
00100       usage(argv[0]);
00101       return 1;
00102     }
00103   }
00104 
00105   if (argc != (optind + 1))
00106   {
00107     usage(argv[0]);
00108     return 1;
00109   }
00110 
00111   sqlite3_open(argv[optind], &(server.db));
00112   if (server.db == NULL)
00113   {
00114     printf("sqlite3_open: could not open sqlite3 db\n");
00115     return 1;
00116   }
00117 
00118   if (drizzle_create(&server.drizzle) == NULL)
00119   {
00120     printf("drizzle_create:NULL\n");
00121     return 1;
00122   }
00123 
00124   drizzle_add_options(&server.drizzle, DRIZZLE_FREE_OBJECTS);
00125   drizzle_set_verbose(&server.drizzle, server.verbose);
00126 
00127   if (drizzle_con_create(&server.drizzle, &con_listen) == NULL)
00128   {
00129     printf("drizzle_con_create:NULL\n");
00130     return 1;
00131   }
00132 
00133   drizzle_con_add_options(&con_listen, DRIZZLE_CON_LISTEN);
00134   drizzle_con_set_tcp(&con_listen, host, port);
00135 
00136   if (mysql)
00137     drizzle_con_add_options(&con_listen, DRIZZLE_CON_MYSQL);
00138 
00139   if (drizzle_con_listen(&con_listen) != DRIZZLE_RETURN_OK)
00140   {
00141     printf("drizzle_con_listen:%s\n", drizzle_error(&server.drizzle));
00142     return 1;
00143   }
00144 
00145   while (1)
00146   {
00147     (void)drizzle_con_accept(&server.drizzle, &server.con, &ret);
00148     if (ret != DRIZZLE_RETURN_OK)
00149     {
00150       printf("drizzle_con_accept:%s\n", drizzle_error(&server.drizzle));
00151       return 1;
00152     }
00153 
00154     server_run(&server);
00155 
00156     drizzle_con_free(&server.con);
00157 
00158     if (count > 0)
00159     {
00160       count--;
00161 
00162       if (count == 0)
00163         break;
00164     }
00165   }
00166 
00167   drizzle_con_free(&con_listen);
00168   drizzle_free(&server.drizzle);
00169   sqlite3_close(server.db);
00170 
00171   return 0;
00172 }
00173 
00174 static void server_run(sqlite_server *server)
00175 {
00176   drizzle_return_t ret;
00177   drizzle_command_t command;
00178   uint8_t *data= NULL;
00179   size_t total;
00180   int sqlite_ret;
00181   char *sqlite_err;
00182 
00183   /* Handshake packets. */
00184   drizzle_con_set_protocol_version(&(server->con), 10);
00185   drizzle_con_set_server_version(&(server->con), "libdrizzle+SQLite");
00186   drizzle_con_set_thread_id(&(server->con), 1);
00187   drizzle_con_set_scramble(&(server->con),
00188                            (const uint8_t *)"ABCDEFGHIJKLMNOPQRST");
00189   drizzle_con_set_capabilities(&(server->con), DRIZZLE_CAPABILITIES_NONE);
00190   drizzle_con_set_charset(&(server->con), 8);
00191   drizzle_con_set_status(&(server->con), DRIZZLE_CON_STATUS_NONE);
00192   drizzle_con_set_max_packet_size(&(server->con), DRIZZLE_MAX_PACKET_SIZE);
00193 
00194   ret= drizzle_handshake_server_write(&(server->con));
00195   DRIZZLE_RETURN_CHECK(ret, "drizzle_handshake_server_write",
00196                        &(server->drizzle))
00197 
00198   ret= drizzle_handshake_client_read(&(server->con));
00199   DRIZZLE_RETURN_CHECK(ret, "drizzle_handshake_client_read", &(server->drizzle))
00200 
00201   if (drizzle_result_create(&(server->con), &(server->result)) == NULL)
00202     DRIZZLE_RETURN_ERROR("drizzle_result_create", &(server->drizzle))
00203 
00204   ret= drizzle_result_write(&(server->con), &(server->result), true);
00205   DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
00206 
00207   /* Command loop. */
00208   while (1)
00209   {
00210     drizzle_result_free(&(server->result));
00211     if (data != NULL)
00212       free(data);
00213 
00214     data= drizzle_con_command_buffer(&(server->con), &command, &total, &ret);
00215     if (ret == DRIZZLE_RETURN_LOST_CONNECTION ||
00216         (ret == DRIZZLE_RETURN_OK && command == DRIZZLE_COMMAND_QUIT))
00217     {
00218       if (data != NULL)
00219         free(data);
00220       return;
00221     }
00222     DRIZZLE_RETURN_CHECK(ret, "drizzle_con_command_buffer", &(server->drizzle))
00223 
00224     if (server->verbose >= DRIZZLE_VERBOSE_INFO)
00225     {
00226       printf("Command=%u Data=%s\n", command,
00227              data == NULL ? "NULL" : (char *)data);
00228     }
00229 
00230     if (drizzle_result_create(&(server->con), &(server->result)) == NULL)
00231       DRIZZLE_RETURN_ERROR("drizzle_result_create", &(server->drizzle))
00232 
00233     if (command != DRIZZLE_COMMAND_QUERY ||
00234         !strcasecmp((char *)data, "SHOW DATABASES"))
00235     {
00236       ret= drizzle_result_write(&(server->con), &(server->result), true);
00237       DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
00238 
00239       if (command == DRIZZLE_COMMAND_FIELD_LIST)
00240       {
00241         drizzle_result_set_eof(&(server->result), true);
00242         ret= drizzle_result_write(&(server->con), &(server->result), true);
00243         DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
00244       }
00245 
00246       continue;
00247     }
00248 
00249     if (strstr((char *)data, "@@version") != NULL)
00250     {
00251       ret= send_version(server);
00252       if (ret != DRIZZLE_RETURN_OK)
00253         return;
00254 
00255       continue;
00256     }
00257 
00258     server->send_columns= true;
00259     server->rows= 0;
00260 
00261     if (!strcasecmp((char *)data, "SHOW TABLES"))
00262     {
00263       sqlite_ret= sqlite3_exec(server->db,
00264                             "SELECT name FROM sqlite_master WHERE type='table'",
00265                                row_cb, server, &sqlite_err);
00266     }
00267     else
00268     {
00269       sqlite_ret= sqlite3_exec(server->db, (char *)data, row_cb, server,
00270                                &sqlite_err);
00271     }
00272 
00273     if (sqlite_ret != SQLITE_OK)
00274     {
00275       if (sqlite_err == NULL)
00276         printf("sqlite3_exec failed\n");
00277       else
00278       {
00279         drizzle_result_set_error_code(&(server->result), (uint16_t)sqlite_ret);
00280         drizzle_result_set_error(&(server->result), sqlite_err);
00281         ret= drizzle_result_write(&(server->con), &(server->result), true);
00282         DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
00283 
00284         printf("sqlite3_exec:%s\n", sqlite_err);
00285         sqlite3_free(sqlite_err);
00286       }
00287 
00288       return;
00289     }
00290 
00291     if (server->rows == 0)
00292     {
00293       drizzle_result_set_column_count(&(server->result), 0);
00294       ret= drizzle_result_write(&(server->con), &(server->result), true);
00295       DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
00296     }
00297     else
00298     {
00299       drizzle_result_set_eof(&(server->result), true);
00300       ret= drizzle_result_write(&(server->con), &(server->result), true);
00301       DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
00302     }
00303   }
00304 }
00305 
00306 static int row_cb(void *data, int field_count, char **fields, char **columns)
00307 {
00308   sqlite_server *server= (sqlite_server *)data;
00309   drizzle_return_t ret;
00310   int x;
00311   size_t sizes[8192];
00312 
00313   if (server->send_columns == true)
00314   {
00315     server->send_columns= false;
00316     drizzle_result_set_column_count(&(server->result), (uint16_t)field_count);
00317 
00318     ret= drizzle_result_write(&(server->con), &(server->result), false);
00319     DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
00320 
00321     if (drizzle_column_create(&(server->result), &(server->column)) == NULL)
00322     {
00323       DRIZZLE_RETURN_CHECK_VAL(DRIZZLE_RETURN_MEMORY, "drizzle_column_create",
00324                                &(server->drizzle))
00325     }
00326 
00327     drizzle_column_set_catalog(&(server->column), "sqlite");
00328     drizzle_column_set_db(&(server->column), "sqlite_db");
00329     drizzle_column_set_table(&(server->column), "sqlite_table");
00330     drizzle_column_set_orig_table(&(server->column), "sqlite_table");
00331     drizzle_column_set_charset(&(server->column), 8);
00332     drizzle_column_set_type(&(server->column), DRIZZLE_COLUMN_TYPE_VARCHAR);
00333 
00334     for (x= 0; x < field_count; x++)
00335     {
00336       drizzle_column_set_size(&(server->column),
00337                               fields[x] == NULL ?
00338                               0 : (uint32_t)strlen(fields[x]));
00339       drizzle_column_set_name(&(server->column), columns[x]);
00340       drizzle_column_set_orig_name(&(server->column), columns[x]);
00341 
00342       ret= drizzle_column_write(&(server->result), &(server->column));
00343       DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_column_write", &(server->drizzle))
00344     }
00345 
00346     drizzle_column_free(&(server->column));
00347 
00348     drizzle_result_set_eof(&(server->result), true);
00349 
00350     ret= drizzle_result_write(&(server->con), &(server->result), false);
00351     DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
00352   }
00353 
00354   for (x= 0; x < field_count; x++)
00355   {
00356     if (fields[x] == NULL)
00357       sizes[x]= 0;
00358     else
00359       sizes[x]= strlen(fields[x]);
00360   }
00361 
00362   /* This is needed for MySQL and old Drizzle protocol. */
00363   drizzle_result_calc_row_size(&(server->result), (drizzle_field_t *)fields,
00364                                sizes);
00365 
00366   ret= drizzle_row_write(&(server->result));
00367   DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_row_write", &(server->drizzle))
00368 
00369   for (x= 0; x < field_count; x++)
00370   {
00371     ret= drizzle_field_write(&(server->result), (drizzle_field_t)fields[x],
00372                              sizes[x], sizes[x]);
00373     DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_field_write", &(server->drizzle))
00374   }
00375 
00376   server->rows++;
00377 
00378   return 0;
00379 }
00380 
00381 static drizzle_return_t send_version(sqlite_server *server)
00382 {
00383   drizzle_return_t ret;
00384   drizzle_field_t fields[1];
00385   size_t sizes[1];
00386 
00387   fields[0]= (drizzle_field_t)SQLITE_SERVER_VERSION;
00388   sizes[0]= strlen(SQLITE_SERVER_VERSION);
00389 
00390   drizzle_result_set_column_count(&(server->result), 1);
00391 
00392   ret= drizzle_result_write(&(server->con), &(server->result), false);
00393   DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
00394 
00395   if (drizzle_column_create(&(server->result), &(server->column)) == NULL)
00396   {
00397     DRIZZLE_RETURN_CHECK_VAL(DRIZZLE_RETURN_MEMORY, "drizzle_column_create",
00398                              &(server->drizzle))
00399   }
00400 
00401   drizzle_column_set_catalog(&(server->column), "sqlite");
00402   drizzle_column_set_db(&(server->column), "sqlite_db");
00403   drizzle_column_set_table(&(server->column), "sqlite_table");
00404   drizzle_column_set_orig_table(&(server->column), "sqlite_table");
00405   drizzle_column_set_charset(&(server->column), 8);
00406   drizzle_column_set_type(&(server->column), DRIZZLE_COLUMN_TYPE_VARCHAR);
00407   drizzle_column_set_size(&(server->column), (uint32_t)sizes[0]);
00408   drizzle_column_set_name(&(server->column), "version");
00409   drizzle_column_set_orig_name(&(server->column), "version");
00410 
00411   ret= drizzle_column_write(&(server->result), &(server->column));
00412   DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_column_write", &(server->drizzle))
00413 
00414   drizzle_column_free(&(server->column));
00415 
00416   drizzle_result_set_eof(&(server->result), true);
00417 
00418   ret= drizzle_result_write(&(server->con), &(server->result), false);
00419   DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
00420 
00421   /* This is needed for MySQL and old Drizzle protocol. */
00422   drizzle_result_calc_row_size(&(server->result), fields, sizes);
00423 
00424   ret= drizzle_row_write(&(server->result));
00425   DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_row_write", &(server->drizzle))
00426 
00427   ret= drizzle_field_write(&(server->result), fields[0], sizes[0], sizes[0]);
00428   DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_field_write", &(server->drizzle))
00429 
00430   ret= drizzle_result_write(&(server->con), &(server->result), true);
00431   DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
00432 
00433   return DRIZZLE_RETURN_OK;
00434 }
00435 
00436 static void usage(char *name)
00437 {
00438   printf("\nusage: %s [-c <count>] [-h <host>] [-m] [-p <port>] [-v] "
00439          "<sqlite3 db file>\n", name);
00440   printf("\t-c <count> - Number of connections to accept before exiting\n");
00441   printf("\t-h <host>  - Host to listen on\n");
00442   printf("\t-m         - Use the MySQL protocol\n");
00443   printf("\t-p <port>  - Port to listen on\n");
00444   printf("\t-v         - Increase verbosity level\n");
00445 }