~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to examples/sqlite_server.c

Added libdrizzle to the tree.

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
 * 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
 
 
18
#include <libdrizzle/drizzle_server.h>
 
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
{
 
46
  drizzle_st drizzle;
 
47
  drizzle_con_st con;
 
48
  drizzle_result_st result;
 
49
  drizzle_column_st column;
 
50
  sqlite3* db;
 
51
  bool send_columns;
 
52
  drizzle_verbose_t verbose;
 
53
  uint64_t rows;
 
54
} sqlite_server;
 
55
 
 
56
static void server_run(sqlite_server *server);
 
57
static int row_cb(void *data, int field_count, char **fields, char **columns);
 
58
static drizzle_return_t send_version(sqlite_server *server);
 
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;
 
69
  sqlite_server server;
 
70
  drizzle_con_st con_listen;
 
71
 
 
72
  server.db= NULL;
 
73
  server.verbose= DRIZZLE_VERBOSE_NEVER;
 
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
 
 
124
  drizzle_add_options(&server.drizzle, DRIZZLE_FREE_OBJECTS);
 
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
 
 
133
  drizzle_con_add_options(&con_listen, DRIZZLE_CON_LISTEN);
 
134
  drizzle_con_set_tcp(&con_listen, host, port);
 
135
 
 
136
  if (mysql)
 
137
    drizzle_con_add_options(&con_listen, DRIZZLE_CON_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
 
 
174
static void server_run(sqlite_server *server)
 
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");
 
189
  drizzle_con_set_capabilities(&(server->con), DRIZZLE_CAPABILITIES_NONE);
 
190
  drizzle_con_set_charset(&(server->con), 8);
 
191
  drizzle_con_set_status(&(server->con), DRIZZLE_CON_STATUS_NONE);
 
192
  drizzle_con_set_max_packet_size(&(server->con), DRIZZLE_MAX_PACKET_SIZE);
 
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
    {
 
293
      drizzle_result_set_column_count(&(server->result), 0);
 
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
{
 
308
  sqlite_server *server= (sqlite_server *)data;
 
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);
 
332
    drizzle_column_set_type(&(server->column), DRIZZLE_COLUMN_TYPE_VARCHAR);
 
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. */
 
363
  drizzle_result_calc_row_size(&(server->result), (drizzle_field_t *)fields,
 
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
 
 
381
static drizzle_return_t send_version(sqlite_server *server)
 
382
{
 
383
  drizzle_return_t ret;
 
384
  drizzle_field_t fields[1];
 
385
  size_t sizes[1];
 
386
 
 
387
  fields[0]= (drizzle_field_t)SQLITE_SERVER_VERSION;
 
388
  sizes[0]= strlen(SQLITE_SERVER_VERSION);
 
389
 
 
390
  drizzle_result_set_column_count(&(server->result), 1);
 
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);
 
406
  drizzle_column_set_type(&(server->column), DRIZZLE_COLUMN_TYPE_VARCHAR);
 
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
}