~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to examples/sqlite_server.c

Merge Stewart's dead code removal

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