~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to examples/sqlite_server.c

fix pthread atomics. operator precedence is important. The unit test now passes.

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.BSD file in the root source 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= (sqlite_server*)malloc(sizeof(sqlite_server));
70
 
  drizzle_con_st *con_listen= (drizzle_con_st*)malloc(sizeof(drizzle_con_st));
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
 
  free(con_listen);
171
 
  free(server);
172
 
 
173
 
  return 0;
174
 
}
175
 
 
176
 
static void server_run(sqlite_server *server)
177
 
{
178
 
  drizzle_return_t ret;
179
 
  drizzle_command_t command;
180
 
  uint8_t *data= NULL;
181
 
  size_t total;
182
 
  int sqlite_ret;
183
 
  char *sqlite_err;
184
 
 
185
 
  /* Handshake packets. */
186
 
  drizzle_con_set_protocol_version(&(server->con), 10);
187
 
  drizzle_con_set_server_version(&(server->con), "libdrizzle+SQLite");
188
 
  drizzle_con_set_thread_id(&(server->con), 1);
189
 
  drizzle_con_set_scramble(&(server->con),
190
 
                           (const uint8_t *)"ABCDEFGHIJKLMNOPQRST");
191
 
  drizzle_con_set_capabilities(&(server->con), DRIZZLE_CAPABILITIES_NONE);
192
 
  drizzle_con_set_charset(&(server->con), 8);
193
 
  drizzle_con_set_status(&(server->con), DRIZZLE_CON_STATUS_NONE);
194
 
  drizzle_con_set_max_packet_size(&(server->con), DRIZZLE_MAX_PACKET_SIZE);
195
 
 
196
 
  ret= drizzle_handshake_server_write(&(server->con));
197
 
  DRIZZLE_RETURN_CHECK(ret, "drizzle_handshake_server_write",
198
 
                       &(server->drizzle))
199
 
 
200
 
  ret= drizzle_handshake_client_read(&(server->con));
201
 
  DRIZZLE_RETURN_CHECK(ret, "drizzle_handshake_client_read", &(server->drizzle))
202
 
 
203
 
  if (drizzle_result_create(&(server->con), &(server->result)) == NULL)
204
 
    DRIZZLE_RETURN_ERROR("drizzle_result_create", &(server->drizzle))
205
 
 
206
 
  ret= drizzle_result_write(&(server->con), &(server->result), true);
207
 
  DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
208
 
 
209
 
  /* Command loop. */
210
 
  while (1)
211
 
  {
212
 
    drizzle_result_free(&(server->result));
213
 
    if (data != NULL)
214
 
      free(data);
215
 
 
216
 
    data= drizzle_con_command_buffer(&(server->con), &command, &total, &ret);
217
 
    if (ret == DRIZZLE_RETURN_LOST_CONNECTION ||
218
 
        (ret == DRIZZLE_RETURN_OK && command == DRIZZLE_COMMAND_QUIT))
219
 
    {
220
 
      if (data != NULL)
221
 
        free(data);
222
 
      return;
223
 
    }
224
 
    DRIZZLE_RETURN_CHECK(ret, "drizzle_con_command_buffer", &(server->drizzle))
225
 
 
226
 
    if (server->verbose >= DRIZZLE_VERBOSE_INFO)
227
 
    {
228
 
      printf("Command=%u Data=%s\n", command,
229
 
             data == NULL ? "NULL" : (char *)data);
230
 
    }
231
 
 
232
 
    if (drizzle_result_create(&(server->con), &(server->result)) == NULL)
233
 
      DRIZZLE_RETURN_ERROR("drizzle_result_create", &(server->drizzle))
234
 
 
235
 
    if (command != DRIZZLE_COMMAND_QUERY ||
236
 
        !strcasecmp((char *)data, "SHOW DATABASES"))
237
 
    {
238
 
      ret= drizzle_result_write(&(server->con), &(server->result), true);
239
 
      DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
240
 
 
241
 
      if (command == DRIZZLE_COMMAND_FIELD_LIST)
242
 
      {
243
 
        drizzle_result_set_eof(&(server->result), true);
244
 
        ret= drizzle_result_write(&(server->con), &(server->result), true);
245
 
        DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
246
 
      }
247
 
 
248
 
      continue;
249
 
    }
250
 
 
251
 
    if (strstr((char *)data, "@@version") != NULL)
252
 
    {
253
 
      ret= send_version(server);
254
 
      if (ret != DRIZZLE_RETURN_OK)
255
 
        return;
256
 
 
257
 
      continue;
258
 
    }
259
 
 
260
 
    server->send_columns= true;
261
 
    server->rows= 0;
262
 
 
263
 
    if (!strcasecmp((char *)data, "SHOW TABLES"))
264
 
    {
265
 
      sqlite_ret= sqlite3_exec(server->db,
266
 
                            "SELECT name FROM sqlite_master WHERE type='table'",
267
 
                               row_cb, server, &sqlite_err);
268
 
    }
269
 
    else
270
 
    {
271
 
      sqlite_ret= sqlite3_exec(server->db, (char *)data, row_cb, server,
272
 
                               &sqlite_err);
273
 
    }
274
 
 
275
 
    if (sqlite_ret != SQLITE_OK)
276
 
    {
277
 
      if (sqlite_err == NULL)
278
 
        printf("sqlite3_exec failed\n");
279
 
      else
280
 
      {
281
 
        drizzle_result_set_error_code(&(server->result), (uint16_t)sqlite_ret);
282
 
        drizzle_result_set_error(&(server->result), sqlite_err);
283
 
        ret= drizzle_result_write(&(server->con), &(server->result), true);
284
 
        DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
285
 
 
286
 
        printf("sqlite3_exec:%s\n", sqlite_err);
287
 
        sqlite3_free(sqlite_err);
288
 
      }
289
 
 
290
 
      return;
291
 
    }
292
 
 
293
 
    if (server->rows == 0)
294
 
    {
295
 
      drizzle_result_set_column_count(&(server->result), 0);
296
 
      ret= drizzle_result_write(&(server->con), &(server->result), true);
297
 
      DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
298
 
    }
299
 
    else
300
 
    {
301
 
      drizzle_result_set_eof(&(server->result), true);
302
 
      ret= drizzle_result_write(&(server->con), &(server->result), true);
303
 
      DRIZZLE_RETURN_CHECK(ret, "drizzle_result_write", &(server->drizzle))
304
 
    }
305
 
  }
306
 
}
307
 
 
308
 
static int row_cb(void *data, int field_count, char **fields, char **columns)
309
 
{
310
 
  sqlite_server *server= (sqlite_server *)data;
311
 
  drizzle_return_t ret;
312
 
  int x;
313
 
  size_t *sizes= (size_t*)malloc(sizeof(size_t)*8192);
314
 
 
315
 
  if (server->send_columns == true)
316
 
  {
317
 
    server->send_columns= false;
318
 
    drizzle_result_set_column_count(&(server->result), (uint16_t)field_count);
319
 
 
320
 
    ret= drizzle_result_write(&(server->con), &(server->result), false);
321
 
    DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
322
 
 
323
 
    if (drizzle_column_create(&(server->result), &(server->column)) == NULL)
324
 
    {
325
 
      DRIZZLE_RETURN_CHECK_VAL(DRIZZLE_RETURN_MEMORY, "drizzle_column_create",
326
 
                               &(server->drizzle))
327
 
    }
328
 
 
329
 
    drizzle_column_set_catalog(&(server->column), "sqlite");
330
 
    drizzle_column_set_db(&(server->column), "sqlite_db");
331
 
    drizzle_column_set_table(&(server->column), "sqlite_table");
332
 
    drizzle_column_set_orig_table(&(server->column), "sqlite_table");
333
 
    drizzle_column_set_charset(&(server->column), 8);
334
 
    drizzle_column_set_type(&(server->column), DRIZZLE_COLUMN_TYPE_VARCHAR);
335
 
 
336
 
    for (x= 0; x < field_count; x++)
337
 
    {
338
 
      drizzle_column_set_size(&(server->column),
339
 
                              fields[x] == NULL ?
340
 
                              0 : (uint32_t)strlen(fields[x]));
341
 
      drizzle_column_set_name(&(server->column), columns[x]);
342
 
      drizzle_column_set_orig_name(&(server->column), columns[x]);
343
 
 
344
 
      ret= drizzle_column_write(&(server->result), &(server->column));
345
 
      DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_column_write", &(server->drizzle))
346
 
    }
347
 
 
348
 
    drizzle_column_free(&(server->column));
349
 
 
350
 
    drizzle_result_set_eof(&(server->result), true);
351
 
 
352
 
    ret= drizzle_result_write(&(server->con), &(server->result), false);
353
 
    DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
354
 
  }
355
 
 
356
 
  for (x= 0; x < field_count; x++)
357
 
  {
358
 
    if (fields[x] == NULL)
359
 
      sizes[x]= 0;
360
 
    else
361
 
      sizes[x]= strlen(fields[x]);
362
 
  }
363
 
 
364
 
  /* This is needed for MySQL and old Drizzle protocol. */
365
 
  drizzle_result_calc_row_size(&(server->result), (drizzle_field_t *)fields,
366
 
                               sizes);
367
 
 
368
 
  ret= drizzle_row_write(&(server->result));
369
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_row_write", &(server->drizzle))
370
 
 
371
 
  for (x= 0; x < field_count; x++)
372
 
  {
373
 
    ret= drizzle_field_write(&(server->result), (drizzle_field_t)fields[x],
374
 
                             sizes[x], sizes[x]);
375
 
    DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_field_write", &(server->drizzle))
376
 
  }
377
 
 
378
 
  server->rows++;
379
 
 
380
 
  free(sizes);
381
 
 
382
 
  return 0;
383
 
}
384
 
 
385
 
static drizzle_return_t send_version(sqlite_server *server)
386
 
{
387
 
  drizzle_return_t ret;
388
 
  drizzle_field_t fields[1];
389
 
  size_t sizes[1];
390
 
 
391
 
  fields[0]= (drizzle_field_t)SQLITE_SERVER_VERSION;
392
 
  sizes[0]= strlen(SQLITE_SERVER_VERSION);
393
 
 
394
 
  drizzle_result_set_column_count(&(server->result), 1);
395
 
 
396
 
  ret= drizzle_result_write(&(server->con), &(server->result), false);
397
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
398
 
 
399
 
  if (drizzle_column_create(&(server->result), &(server->column)) == NULL)
400
 
  {
401
 
    DRIZZLE_RETURN_CHECK_VAL(DRIZZLE_RETURN_MEMORY, "drizzle_column_create",
402
 
                             &(server->drizzle))
403
 
  }
404
 
 
405
 
  drizzle_column_set_catalog(&(server->column), "sqlite");
406
 
  drizzle_column_set_db(&(server->column), "sqlite_db");
407
 
  drizzle_column_set_table(&(server->column), "sqlite_table");
408
 
  drizzle_column_set_orig_table(&(server->column), "sqlite_table");
409
 
  drizzle_column_set_charset(&(server->column), 8);
410
 
  drizzle_column_set_type(&(server->column), DRIZZLE_COLUMN_TYPE_VARCHAR);
411
 
  drizzle_column_set_size(&(server->column), (uint32_t)sizes[0]);
412
 
  drizzle_column_set_name(&(server->column), "version");
413
 
  drizzle_column_set_orig_name(&(server->column), "version");
414
 
 
415
 
  ret= drizzle_column_write(&(server->result), &(server->column));
416
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_column_write", &(server->drizzle))
417
 
 
418
 
  drizzle_column_free(&(server->column));
419
 
 
420
 
  drizzle_result_set_eof(&(server->result), true);
421
 
 
422
 
  ret= drizzle_result_write(&(server->con), &(server->result), false);
423
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
424
 
 
425
 
  /* This is needed for MySQL and old Drizzle protocol. */
426
 
  drizzle_result_calc_row_size(&(server->result), fields, sizes);
427
 
 
428
 
  ret= drizzle_row_write(&(server->result));
429
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_row_write", &(server->drizzle))
430
 
 
431
 
  ret= drizzle_field_write(&(server->result), fields[0], sizes[0], sizes[0]);
432
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_field_write", &(server->drizzle))
433
 
 
434
 
  ret= drizzle_result_write(&(server->con), &(server->result), true);
435
 
  DRIZZLE_RETURN_CHECK_VAL(ret, "drizzle_result_write", &(server->drizzle))
436
 
 
437
 
  return DRIZZLE_RETURN_OK;
438
 
}
439
 
 
440
 
static void usage(char *name)
441
 
{
442
 
  printf("\nusage: %s [-c <count>] [-h <host>] [-m] [-p <port>] [-v] "
443
 
         "<sqlite3 db file>\n", name);
444
 
  printf("\t-c <count> - Number of connections to accept before exiting\n");
445
 
  printf("\t-h <host>  - Host to listen on\n");
446
 
  printf("\t-m         - Use the MySQL protocol\n");
447
 
  printf("\t-p <port>  - Port to listen on\n");
448
 
  printf("\t-v         - Increase verbosity level\n");
449
 
}