~drizzle-trunk/drizzle/development

1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
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
1799.2.4 by Monty Taylor
Made BSD files reference root BSD file.
8
 * the COPYING.BSD file in the root source directory for full text.
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
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
}