~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to examples/sqlite_server.c

  • Committer: Monty Taylor
  • Date: 2009-03-04 02:48:12 UTC
  • mto: (917.1.2 mordred)
  • mto: This revision was merged to the branch mainline in revision 918.
  • Revision ID: mordred@inaugust.com-20090304024812-5wb6wpye5c1iitbq
Applied atomic patch to current 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
 
 * 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
 
      server->verbose++;
124
 
      break;
125
 
 
126
 
    default:
127
 
      usage(argv[0]);
128
 
      return 1;
129
 
    }
130
 
  }
131
 
 
132
 
  if (argc != (optind + 1))
133
 
  {
134
 
    usage(argv[0]);
135
 
    return 1;
136
 
  }
137
 
 
138
 
  sqlite3_open(argv[optind], &(server->db));
139
 
  if (server->db == NULL)
140
 
  {
141
 
    printf("sqlite3_open: could not open sqlite3 db\n");
142
 
    return 1;
143
 
  }
144
 
 
145
 
  if (drizzle_create(&(server->drizzle)) == NULL)
146
 
  {
147
 
    printf("drizzle_create:NULL\n");
148
 
    return 1;
149
 
  }
150
 
 
151
 
  drizzle_add_options(&(server->drizzle), DRIZZLE_FREE_OBJECTS);
152
 
  drizzle_set_verbose(&(server->drizzle), server->verbose);
153
 
 
154
 
  if (drizzle_con_create(&(server->drizzle), con_listen) == NULL)
155
 
  {
156
 
    printf("drizzle_con_create:NULL\n");
157
 
    return 1;
158
 
  }
159
 
 
160
 
  drizzle_con_add_options(con_listen, DRIZZLE_CON_LISTEN);
161
 
  drizzle_con_set_tcp(con_listen, host, port);
162
 
 
163
 
  if (mysql)
164
 
    drizzle_con_add_options(con_listen, DRIZZLE_CON_MYSQL);
165
 
 
166
 
  if (drizzle_con_listen(con_listen) != DRIZZLE_RETURN_OK)
167
 
  {
168
 
    printf("drizzle_con_listen:%s\n", drizzle_error(&(server->drizzle)));
169
 
    return 1;
170
 
  }
171
 
 
172
 
  while (1)
173
 
  {
174
 
    (void)drizzle_con_accept(&(server->drizzle), &(server->con), &ret);
175
 
    if (ret != DRIZZLE_RETURN_OK)
176
 
    {
177
 
      printf("drizzle_con_accept:%s\n", drizzle_error(&(server->drizzle)));
178
 
      return 1;
179
 
    }
180
 
 
181
 
    server_run(server);
182
 
 
183
 
    drizzle_con_free(&(server->con));
184
 
 
185
 
    if (count > 0)
186
 
    {
187
 
      count--;
188
 
 
189
 
      if (count == 0)
190
 
        break;
191
 
    }
192
 
  }
193
 
 
194
 
  drizzle_con_free(con_listen);
195
 
  drizzle_free(&(server->drizzle));
196
 
  sqlite3_close(server->db);
197
 
  free(con_listen);
198
 
  free(server);
199
 
 
200
 
  return 0;
201
 
}
202
 
 
203
 
static void server_run(sqlite_server *server)
204
 
{
205
 
  drizzle_return_t ret;
206
 
  drizzle_command_t command;
207
 
  uint8_t *data= NULL;
208
 
  size_t total;
209
 
  int sqlite_ret;
210
 
  char *sqlite_err;
211
 
 
212
 
  /* Handshake packets. */
213
 
  drizzle_con_set_protocol_version(&(server->con), 10);
214
 
  drizzle_con_set_server_version(&(server->con), "libdrizzle+SQLite");
215
 
  drizzle_con_set_thread_id(&(server->con), 1);
216
 
  drizzle_con_set_scramble(&(server->con),
217
 
                           (const uint8_t *)"ABCDEFGHIJKLMNOPQRST");
218
 
  drizzle_con_set_capabilities(&(server->con), DRIZZLE_CAPABILITIES_NONE);
219
 
  drizzle_con_set_charset(&(server->con), 8);
220
 
  drizzle_con_set_status(&(server->con), DRIZZLE_CON_STATUS_NONE);
221
 
  drizzle_con_set_max_packet_size(&(server->con), DRIZZLE_MAX_PACKET_SIZE);
222
 
 
223
 
  ret= drizzle_handshake_server_write(&(server->con));
224
 
  DRIZZLE_RETURN_CHECK(ret, "drizzle_handshake_server_write",
225
 
                       &(server->drizzle))
226
 
 
227
 
  ret= drizzle_handshake_client_read(&(server->con));
228
 
  DRIZZLE_RETURN_CHECK(ret, "drizzle_handshake_client_read", &(server->drizzle))
229
 
 
230
 
  if (drizzle_result_create(&(server->con), &(server->result)) == NULL)
231
 
    DRIZZLE_RETURN_ERROR("drizzle_result_create", &(server->drizzle))
232
 
 
233
 
  ret= drizzle_result_write(&(server->con), &(server->result), true);
234
 
  DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
235
 
 
236
 
  /* Command loop. */
237
 
  while (1)
238
 
  {
239
 
    drizzle_result_free(&(server->result));
240
 
    if (data != NULL)
241
 
      free(data);
242
 
 
243
 
    data= drizzle_con_command_buffer(&(server->con), &command, &total, &ret);
244
 
    if (ret == DRIZZLE_RETURN_LOST_CONNECTION ||
245
 
        (ret == DRIZZLE_RETURN_OK && command == DRIZZLE_COMMAND_QUIT))
246
 
    {
247
 
      if (data != NULL)
248
 
        free(data);
249
 
      return;
250
 
    }
251
 
    DRIZZLE_RETURN_CHECK(ret, "drizzle_con_command_buffer", &(server->drizzle))
252
 
 
253
 
    if (server->verbose >= DRIZZLE_VERBOSE_INFO)
254
 
    {
255
 
      printf("Command=%u Data=%s\n", command,
256
 
             data == NULL ? "NULL" : (char *)data);
257
 
    }
258
 
 
259
 
    if (drizzle_result_create(&(server->con), &(server->result)) == NULL)
260
 
      DRIZZLE_RETURN_ERROR("drizzle_result_create", &(server->drizzle))
261
 
 
262
 
    if (command != DRIZZLE_COMMAND_QUERY ||
263
 
        !strcasecmp((char *)data, "SHOW DATABASES"))
264
 
    {
265
 
      ret= drizzle_result_write(&(server->con), &(server->result), true);
266
 
      DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
267
 
 
268
 
      if (command == DRIZZLE_COMMAND_FIELD_LIST)
269
 
      {
270
 
        drizzle_result_set_eof(&(server->result), true);
271
 
        ret= drizzle_result_write(&(server->con), &(server->result), true);
272
 
        DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
273
 
      }
274
 
 
275
 
      continue;
276
 
    }
277
 
 
278
 
    if (strstr((char *)data, "@@version") != NULL)
279
 
    {
280
 
      ret= send_version(server);
281
 
      if (ret != DRIZZLE_RETURN_OK)
282
 
        return;
283
 
 
284
 
      continue;
285
 
    }
286
 
 
287
 
    server->send_columns= true;
288
 
    server->rows= 0;
289
 
 
290
 
    if (!strcasecmp((char *)data, "SHOW TABLES"))
291
 
    {
292
 
      sqlite_ret= sqlite3_exec(server->db,
293
 
                            "SELECT name FROM sqlite_master WHERE type='table'",
294
 
                               row_cb, server, &sqlite_err);
295
 
    }
296
 
    else
297
 
    {
298
 
      sqlite_ret= sqlite3_exec(server->db, (char *)data, row_cb, server,
299
 
                               &sqlite_err);
300
 
    }
301
 
 
302
 
    if (sqlite_ret != SQLITE_OK)
303
 
    {
304
 
      if (sqlite_err == NULL)
305
 
        printf("sqlite3_exec failed\n");
306
 
      else
307
 
      {
308
 
        drizzle_result_set_error_code(&(server->result), (uint16_t)sqlite_ret);
309
 
        drizzle_result_set_error(&(server->result), sqlite_err);
310
 
        ret= drizzle_result_write(&(server->con), &(server->result), true);
311
 
        DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
312
 
 
313
 
        printf("sqlite3_exec:%s\n", sqlite_err);
314
 
        sqlite3_free(sqlite_err);
315
 
      }
316
 
 
317
 
      return;
318
 
    }
319
 
 
320
 
    if (server->rows == 0)
321
 
    {
322
 
      drizzle_result_set_column_count(&(server->result), 0);
323
 
      ret= drizzle_result_write(&(server->con), &(server->result), true);
324
 
      DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
325
 
    }
326
 
    else
327
 
    {
328
 
      drizzle_result_set_eof(&(server->result), true);
329
 
      ret= drizzle_result_write(&(server->con), &(server->result), true);
330
 
      DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
331
 
    }
332
 
  }
333
 
}
334
 
 
335
 
static int row_cb(void *data, int field_count, char **fields, char **columns)
336
 
{
337
 
  sqlite_server *server= (sqlite_server *)data;
338
 
  drizzle_return_t ret;
339
 
  int x;
340
 
  size_t *sizes= (size_t*)malloc(sizeof(size_t)*8192);
341
 
 
342
 
  if (server->send_columns == true)
343
 
  {
344
 
    server->send_columns= false;
345
 
    drizzle_result_set_column_count(&(server->result), (uint16_t)field_count);
346
 
 
347
 
    ret= drizzle_result_write(&(server->con), &(server->result), false);
348
 
    DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
349
 
 
350
 
    if (drizzle_column_create(&(server->result), &(server->column)) == NULL)
351
 
    {
352
 
      DRIZZLE_RETURN_CHECK_VAL(DRIZZLE_RETURN_MEMORY, "drizzle_column_create",
353
 
                               &(server->drizzle))
354
 
    }
355
 
 
356
 
    drizzle_column_set_catalog(&(server->column), "sqlite");
357
 
    drizzle_column_set_db(&(server->column), "sqlite_db");
358
 
    drizzle_column_set_table(&(server->column), "sqlite_table");
359
 
    drizzle_column_set_orig_table(&(server->column), "sqlite_table");
360
 
    drizzle_column_set_charset(&(server->column), 8);
361
 
    drizzle_column_set_type(&(server->column), DRIZZLE_COLUMN_TYPE_VARCHAR);
362
 
 
363
 
    for (x= 0; x < field_count; x++)
364
 
    {
365
 
      drizzle_column_set_size(&(server->column),
366
 
                              fields[x] == NULL ?
367
 
                              0 : (uint32_t)strlen(fields[x]));
368
 
      drizzle_column_set_name(&(server->column), columns[x]);
369
 
      drizzle_column_set_orig_name(&(server->column), columns[x]);
370
 
 
371
 
      ret= drizzle_column_write(&(server->result), &(server->column));
372
 
      DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_column_write", &(server->drizzle))
373
 
    }
374
 
 
375
 
    drizzle_column_free(&(server->column));
376
 
 
377
 
    drizzle_result_set_eof(&(server->result), true);
378
 
 
379
 
    ret= drizzle_result_write(&(server->con), &(server->result), false);
380
 
    DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
381
 
  }
382
 
 
383
 
  for (x= 0; x < field_count; x++)
384
 
  {
385
 
    if (fields[x] == NULL)
386
 
      sizes[x]= 0;
387
 
    else
388
 
      sizes[x]= strlen(fields[x]);
389
 
  }
390
 
 
391
 
  /* This is needed for MySQL and old Drizzle protocol. */
392
 
  drizzle_result_calc_row_size(&(server->result), (drizzle_field_t *)fields,
393
 
                               sizes);
394
 
 
395
 
  ret= drizzle_row_write(&(server->result));
396
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_row_write", &(server->drizzle))
397
 
 
398
 
  for (x= 0; x < field_count; x++)
399
 
  {
400
 
    ret= drizzle_field_write(&(server->result), (drizzle_field_t)fields[x],
401
 
                             sizes[x], sizes[x]);
402
 
    DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_field_write", &(server->drizzle))
403
 
  }
404
 
 
405
 
  server->rows++;
406
 
 
407
 
  free(sizes);
408
 
 
409
 
  return 0;
410
 
}
411
 
 
412
 
static drizzle_return_t send_version(sqlite_server *server)
413
 
{
414
 
  drizzle_return_t ret;
415
 
  drizzle_field_t fields[1];
416
 
  size_t sizes[1];
417
 
 
418
 
  fields[0]= (drizzle_field_t)SQLITE_SERVER_VERSION;
419
 
  sizes[0]= strlen(SQLITE_SERVER_VERSION);
420
 
 
421
 
  drizzle_result_set_column_count(&(server->result), 1);
422
 
 
423
 
  ret= drizzle_result_write(&(server->con), &(server->result), false);
424
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
425
 
 
426
 
  if (drizzle_column_create(&(server->result), &(server->column)) == NULL)
427
 
  {
428
 
    DRIZZLE_RETURN_CHECK_VAL(DRIZZLE_RETURN_MEMORY, "drizzle_column_create",
429
 
                             &(server->drizzle))
430
 
  }
431
 
 
432
 
  drizzle_column_set_catalog(&(server->column), "sqlite");
433
 
  drizzle_column_set_db(&(server->column), "sqlite_db");
434
 
  drizzle_column_set_table(&(server->column), "sqlite_table");
435
 
  drizzle_column_set_orig_table(&(server->column), "sqlite_table");
436
 
  drizzle_column_set_charset(&(server->column), 8);
437
 
  drizzle_column_set_type(&(server->column), DRIZZLE_COLUMN_TYPE_VARCHAR);
438
 
  drizzle_column_set_size(&(server->column), (uint32_t)sizes[0]);
439
 
  drizzle_column_set_name(&(server->column), "version");
440
 
  drizzle_column_set_orig_name(&(server->column), "version");
441
 
 
442
 
  ret= drizzle_column_write(&(server->result), &(server->column));
443
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_column_write", &(server->drizzle))
444
 
 
445
 
  drizzle_column_free(&(server->column));
446
 
 
447
 
  drizzle_result_set_eof(&(server->result), true);
448
 
 
449
 
  ret= drizzle_result_write(&(server->con), &(server->result), false);
450
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
451
 
 
452
 
  /* This is needed for MySQL and old Drizzle protocol. */
453
 
  drizzle_result_calc_row_size(&(server->result), fields, sizes);
454
 
 
455
 
  ret= drizzle_row_write(&(server->result));
456
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_row_write", &(server->drizzle))
457
 
 
458
 
  ret= drizzle_field_write(&(server->result), fields[0], sizes[0], sizes[0]);
459
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_field_write", &(server->drizzle))
460
 
 
461
 
  ret= drizzle_result_write(&(server->con), &(server->result), true);
462
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
463
 
 
464
 
  return DRIZZLE_RETURN_OK;
465
 
}
466
 
 
467
 
static void usage(char *name)
468
 
{
469
 
  printf("\nusage: %s [-c <count>] [-h <host>] [-m] [-p <port>] [-v] "
470
 
         "<sqlite3 db file>\n", name);
471
 
  printf("\t-c <count> - Number of connections to accept before exiting\n");
472
 
  printf("\t-h <host>  - Host to listen on\n");
473
 
  printf("\t-m         - Use the MySQL protocol\n");
474
 
  printf("\t-p <port>  - Port to listen on\n");
475
 
  printf("\t-v         - Increase verbosity level\n");
476
 
}