~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;
1929.1.35 by Stewart Smith
typo
69
  sqlite_server *server= (sqlite_server*)malloc(sizeof(sqlite_server));
1929.1.33 by Stewart Smith
fix large stack usag ein examples/sqlite_server.c:
70
  drizzle_con_st *con_listen= (drizzle_con_st*)malloc(sizeof(drizzle_con_st));
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
71
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
72
  server->db= NULL;
73
  server->verbose= DRIZZLE_VERBOSE_NEVER;
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
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':
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
96
      server->verbose++;
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
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
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
111
  sqlite3_open(argv[optind], &(server->db));
112
  if (server->db == NULL)
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
113
  {
114
    printf("sqlite3_open: could not open sqlite3 db\n");
115
    return 1;
116
  }
117
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
118
  if (drizzle_create(&(server->drizzle)) == NULL)
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
119
  {
120
    printf("drizzle_create:NULL\n");
121
    return 1;
122
  }
123
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
124
  drizzle_add_options(&(server->drizzle), DRIZZLE_FREE_OBJECTS);
125
  drizzle_set_verbose(&(server->drizzle), server->verbose);
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
126
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
127
  if (drizzle_con_create(&(server->drizzle), con_listen) == NULL)
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
128
  {
129
    printf("drizzle_con_create:NULL\n");
130
    return 1;
131
  }
132
1929.1.33 by Stewart Smith
fix large stack usag ein examples/sqlite_server.c:
133
  drizzle_con_add_options(con_listen, DRIZZLE_CON_LISTEN);
134
  drizzle_con_set_tcp(con_listen, host, port);
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
135
136
  if (mysql)
1929.1.33 by Stewart Smith
fix large stack usag ein examples/sqlite_server.c:
137
    drizzle_con_add_options(con_listen, DRIZZLE_CON_MYSQL);
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
138
1929.1.33 by Stewart Smith
fix large stack usag ein examples/sqlite_server.c:
139
  if (drizzle_con_listen(con_listen) != DRIZZLE_RETURN_OK)
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
140
  {
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
141
    printf("drizzle_con_listen:%s\n", drizzle_error(&(server->drizzle)));
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
142
    return 1;
143
  }
144
145
  while (1)
146
  {
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
147
    (void)drizzle_con_accept(&(server->drizzle), &(server->con), &ret);
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
148
    if (ret != DRIZZLE_RETURN_OK)
149
    {
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
150
      printf("drizzle_con_accept:%s\n", drizzle_error(&(server->drizzle)));
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
151
      return 1;
152
    }
153
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
154
    server_run(server);
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
155
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
156
    drizzle_con_free(&(server->con));
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
157
158
    if (count > 0)
159
    {
160
      count--;
161
162
      if (count == 0)
163
        break;
164
    }
165
  }
166
1929.1.33 by Stewart Smith
fix large stack usag ein examples/sqlite_server.c:
167
  drizzle_con_free(con_listen);
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
168
  drizzle_free(&(server->drizzle));
169
  sqlite3_close(server->db);
1929.1.33 by Stewart Smith
fix large stack usag ein examples/sqlite_server.c:
170
  free(con_listen);
1929.1.34 by Stewart Smith
fix sqlite_server stack usage
171
  free(server);
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
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;
1929.1.36 by Stewart Smith
one last sqlite_server stack fix
313
  size_t *sizes= (size_t*)malloc(sizeof(size_t)*8192);
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
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
1929.1.36 by Stewart Smith
one last sqlite_server stack fix
380
  free(sizes);
381
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
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
}