libdrizzle Public API Documentation

sqlite_server.c
Go to the documentation of this file.
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
8  * the COPYING file in this directory for full text.
9  */
10 
11 #include <errno.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <strings.h>
16 #include <unistd.h>
17 
19 #include <sqlite3.h>
20 
21 #define SQLITE_SERVER_VERSION "SQLite Server using libdrizzle 0.1"
22 
23 #define DRIZZLE_RETURN_CHECK(__ret, __function, __drizzle) \
24 { \
25  if ((__ret) != DRIZZLE_RETURN_OK) \
26  DRIZZLE_RETURN_ERROR(__function, __drizzle) \
27 }
28 
29 #define DRIZZLE_RETURN_ERROR(__function, __drizzle) \
30 { \
31  printf(__function ":%s\n", drizzle_error(__drizzle)); \
32  return; \
33 }
34 
35 #define DRIZZLE_RETURN_CHECK_VAL(__ret, __function, __drizzle) \
36 { \
37  if ((__ret) != DRIZZLE_RETURN_OK) \
38  { \
39  printf(__function ":%s\n", drizzle_error(__drizzle)); \
40  return ret; \
41  } \
42 }
43 
44 typedef struct
45 {
50  sqlite3* db;
53  uint64_t rows;
55 
56 static void server_run(sqlite_server *server);
57 static int row_cb(void *data, int field_count, char **fields, char **columns);
59 static void usage(char *name);
60 
61 int main(int argc, char *argv[])
62 {
63  int c;
64  uint32_t count= 0;
65  const char *host= NULL;
66  bool mysql= false;
67  in_port_t port= 0;
68  drizzle_return_t ret;
70  drizzle_con_st con_listen;
71 
72  server.db= NULL;
74 
75  while((c = getopt(argc, argv, "c:h:mp:v")) != -1)
76  {
77  switch(c)
78  {
79  case 'c':
80  count= (uint32_t)atoi(optarg);
81  break;
82 
83  case 'h':
84  host= optarg;
85  break;
86 
87  case 'm':
88  mysql= true;
89  break;
90 
91  case 'p':
92  port= (in_port_t)atoi(optarg);
93  break;
94 
95  case 'v':
96  server.verbose++;
97  break;
98 
99  default:
100  usage(argv[0]);
101  return 1;
102  }
103  }
104 
105  if (argc != (optind + 1))
106  {
107  usage(argv[0]);
108  return 1;
109  }
110 
111  sqlite3_open(argv[optind], &(server.db));
112  if (server.db == NULL)
113  {
114  printf("sqlite3_open: could not open sqlite3 db\n");
115  return 1;
116  }
117 
118  if (drizzle_create(&server.drizzle) == NULL)
119  {
120  printf("drizzle_create:NULL\n");
121  return 1;
122  }
123 
125  drizzle_set_verbose(&server.drizzle, server.verbose);
126 
127  if (drizzle_con_create(&server.drizzle, &con_listen) == NULL)
128  {
129  printf("drizzle_con_create:NULL\n");
130  return 1;
131  }
132 
134  drizzle_con_set_tcp(&con_listen, host, port);
135 
136  if (mysql)
138 
139  if (drizzle_con_listen(&con_listen) != DRIZZLE_RETURN_OK)
140  {
141  printf("drizzle_con_listen:%s\n", drizzle_error(&server.drizzle));
142  return 1;
143  }
144 
145  while (1)
146  {
147  (void)drizzle_con_accept(&server.drizzle, &server.con, &ret);
148  if (ret != DRIZZLE_RETURN_OK)
149  {
150  printf("drizzle_con_accept:%s\n", drizzle_error(&server.drizzle));
151  return 1;
152  }
153 
154  server_run(&server);
155 
156  drizzle_con_free(&server.con);
157 
158  if (count > 0)
159  {
160  count--;
161 
162  if (count == 0)
163  break;
164  }
165  }
166 
167  drizzle_con_free(&con_listen);
168  drizzle_free(&server.drizzle);
169  sqlite3_close(server.db);
170 
171  return 0;
172 }
173 
175 {
176  drizzle_return_t ret;
177  drizzle_command_t command;
178  uint8_t *data= NULL;
179  size_t total;
180  int sqlite_ret;
181  char *sqlite_err;
182 
183  /* Handshake packets. */
184  drizzle_con_set_protocol_version(&(server->con), 10);
185  drizzle_con_set_server_version(&(server->con), "libdrizzle+SQLite");
186  drizzle_con_set_thread_id(&(server->con), 1);
187  drizzle_con_set_scramble(&(server->con),
188  (const uint8_t *)"ABCDEFGHIJKLMNOPQRST");
190  drizzle_con_set_charset(&(server->con), 8);
193 
194  ret= drizzle_handshake_server_write(&(server->con));
195  DRIZZLE_RETURN_CHECK(ret, "drizzle_handshake_server_write",
196  &(server->drizzle))
197 
198  ret= drizzle_handshake_client_read(&(server->con));
199  DRIZZLE_RETURN_CHECK(ret, "drizzle_handshake_client_read", &(server->drizzle))
200 
201  if (drizzle_result_create(&(server->con), &(server->result)) == NULL)
202  DRIZZLE_RETURN_ERROR("drizzle_result_create", &(server->drizzle))
203 
204  ret= drizzle_result_write(&(server->con), &(server->result), true);
205  DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
206 
207  /* Command loop. */
208  while (1)
209  {
210  drizzle_result_free(&(server->result));
211  if (data != NULL)
212  free(data);
213 
214  data= drizzle_con_command_buffer(&(server->con), &command, &total, &ret);
215  if (ret == DRIZZLE_RETURN_LOST_CONNECTION ||
216  (ret == DRIZZLE_RETURN_OK && command == DRIZZLE_COMMAND_QUIT))
217  {
218  if (data != NULL)
219  free(data);
220  return;
221  }
222  DRIZZLE_RETURN_CHECK(ret, "drizzle_con_command_buffer", &(server->drizzle))
223 
224  if (server->verbose >= DRIZZLE_VERBOSE_INFO)
225  {
226  printf("Command=%u Data=%s\n", command,
227  data == NULL ? "NULL" : (char *)data);
228  }
229 
230  if (drizzle_result_create(&(server->con), &(server->result)) == NULL)
231  DRIZZLE_RETURN_ERROR("drizzle_result_create", &(server->drizzle))
232 
233  if (command != DRIZZLE_COMMAND_QUERY ||
234  !strcasecmp((char *)data, "SHOW DATABASES"))
235  {
236  ret= drizzle_result_write(&(server->con), &(server->result), true);
237  DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
238 
239  if (command == DRIZZLE_COMMAND_FIELD_LIST)
240  {
241  drizzle_result_set_eof(&(server->result), true);
242  ret= drizzle_result_write(&(server->con), &(server->result), true);
243  DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
244  }
245 
246  continue;
247  }
248 
249  if (strstr((char *)data, "@@version") != NULL)
250  {
251  ret= send_version(server);
252  if (ret != DRIZZLE_RETURN_OK)
253  return;
254 
255  continue;
256  }
257 
258  server->send_columns= true;
259  server->rows= 0;
260 
261  if (!strcasecmp((char *)data, "SHOW TABLES"))
262  {
263  sqlite_ret= sqlite3_exec(server->db,
264  "SELECT name FROM sqlite_master WHERE type='table'",
265  row_cb, server, &sqlite_err);
266  }
267  else
268  {
269  sqlite_ret= sqlite3_exec(server->db, (char *)data, row_cb, server,
270  &sqlite_err);
271  }
272 
273  if (sqlite_ret != SQLITE_OK)
274  {
275  if (sqlite_err == NULL)
276  printf("sqlite3_exec failed\n");
277  else
278  {
279  drizzle_result_set_error_code(&(server->result), (uint16_t)sqlite_ret);
280  drizzle_result_set_error(&(server->result), sqlite_err);
281  ret= drizzle_result_write(&(server->con), &(server->result), true);
282  DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
283 
284  printf("sqlite3_exec:%s\n", sqlite_err);
285  sqlite3_free(sqlite_err);
286  }
287 
288  return;
289  }
290 
291  if (server->rows == 0)
292  {
294  ret= drizzle_result_write(&(server->con), &(server->result), true);
295  DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
296  }
297  else
298  {
299  drizzle_result_set_eof(&(server->result), true);
300  ret= drizzle_result_write(&(server->con), &(server->result), true);
301  DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
302  }
303  }
304 }
305 
306 static int row_cb(void *data, int field_count, char **fields, char **columns)
307 {
309  drizzle_return_t ret;
310  int x;
311  size_t sizes[8192];
312 
313  if (server->send_columns == true)
314  {
315  server->send_columns= false;
316  drizzle_result_set_column_count(&(server->result), (uint16_t)field_count);
317 
318  ret= drizzle_result_write(&(server->con), &(server->result), false);
319  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
320 
321  if (drizzle_column_create(&(server->result), &(server->column)) == NULL)
322  {
323  DRIZZLE_RETURN_CHECK_VAL(DRIZZLE_RETURN_MEMORY, "drizzle_column_create",
324  &(server->drizzle))
325  }
326 
327  drizzle_column_set_catalog(&(server->column), "sqlite");
328  drizzle_column_set_db(&(server->column), "sqlite_db");
329  drizzle_column_set_table(&(server->column), "sqlite_table");
330  drizzle_column_set_orig_table(&(server->column), "sqlite_table");
331  drizzle_column_set_charset(&(server->column), 8);
333 
334  for (x= 0; x < field_count; x++)
335  {
336  drizzle_column_set_size(&(server->column),
337  fields[x] == NULL ?
338  0 : (uint32_t)strlen(fields[x]));
339  drizzle_column_set_name(&(server->column), columns[x]);
340  drizzle_column_set_orig_name(&(server->column), columns[x]);
341 
342  ret= drizzle_column_write(&(server->result), &(server->column));
343  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_column_write", &(server->drizzle))
344  }
345 
346  drizzle_column_free(&(server->column));
347 
348  drizzle_result_set_eof(&(server->result), true);
349 
350  ret= drizzle_result_write(&(server->con), &(server->result), false);
351  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
352  }
353 
354  for (x= 0; x < field_count; x++)
355  {
356  if (fields[x] == NULL)
357  sizes[x]= 0;
358  else
359  sizes[x]= strlen(fields[x]);
360  }
361 
362  /* This is needed for MySQL and old Drizzle protocol. */
364  sizes);
365 
366  ret= drizzle_row_write(&(server->result));
367  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_row_write", &(server->drizzle))
368 
369  for (x= 0; x < field_count; x++)
370  {
371  ret= drizzle_field_write(&(server->result), (drizzle_field_t)fields[x],
372  sizes[x], sizes[x]);
373  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_field_write", &(server->drizzle))
374  }
375 
376  server->rows++;
377 
378  return 0;
379 }
380 
382 {
383  drizzle_return_t ret;
384  drizzle_field_t fields[1];
385  size_t sizes[1];
386 
388  sizes[0]= strlen(SQLITE_SERVER_VERSION);
389 
391 
392  ret= drizzle_result_write(&(server->con), &(server->result), false);
393  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
394 
395  if (drizzle_column_create(&(server->result), &(server->column)) == NULL)
396  {
397  DRIZZLE_RETURN_CHECK_VAL(DRIZZLE_RETURN_MEMORY, "drizzle_column_create",
398  &(server->drizzle))
399  }
400 
401  drizzle_column_set_catalog(&(server->column), "sqlite");
402  drizzle_column_set_db(&(server->column), "sqlite_db");
403  drizzle_column_set_table(&(server->column), "sqlite_table");
404  drizzle_column_set_orig_table(&(server->column), "sqlite_table");
405  drizzle_column_set_charset(&(server->column), 8);
407  drizzle_column_set_size(&(server->column), (uint32_t)sizes[0]);
408  drizzle_column_set_name(&(server->column), "version");
409  drizzle_column_set_orig_name(&(server->column), "version");
410 
411  ret= drizzle_column_write(&(server->result), &(server->column));
412  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_column_write", &(server->drizzle))
413 
414  drizzle_column_free(&(server->column));
415 
416  drizzle_result_set_eof(&(server->result), true);
417 
418  ret= drizzle_result_write(&(server->con), &(server->result), false);
419  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
420 
421  /* This is needed for MySQL and old Drizzle protocol. */
422  drizzle_result_calc_row_size(&(server->result), fields, sizes);
423 
424  ret= drizzle_row_write(&(server->result));
425  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_row_write", &(server->drizzle))
426 
427  ret= drizzle_field_write(&(server->result), fields[0], sizes[0], sizes[0]);
428  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_field_write", &(server->drizzle))
429 
430  ret= drizzle_result_write(&(server->con), &(server->result), true);
431  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
432 
433  return DRIZZLE_RETURN_OK;
434 }
435 
436 static void usage(char *name)
437 {
438  printf("\nusage: %s [-c <count>] [-h <host>] [-m] [-p <port>] [-v] "
439  "<sqlite3 db file>\n", name);
440  printf("\t-c <count> - Number of connections to accept before exiting\n");
441  printf("\t-h <host> - Host to listen on\n");
442  printf("\t-m - Use the MySQL protocol\n");
443  printf("\t-p <port> - Port to listen on\n");
444  printf("\t-v - Increase verbosity level\n");
445 }