~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to examples/sqlite_server.c

  • Committer: Brian Aker
  • Date: 2010-12-18 18:24:57 UTC
  • mfrom: (1999.6.3 trunk)
  • Revision ID: brian@tangent.org-20101218182457-yi1wd0so2hml1k1w
Merge in Lee's copyright header fix

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
}