libdrizzle Developer Documentation

client.c
Go to the documentation of this file.
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 file in this directory for full text.
9  */
10 
11 #include "config.h"
12 
13 #include <errno.h>
14 #include <stdbool.h>
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 
22 
23 typedef enum
24 {
28 } client_state;
29 
30 typedef enum
31 {
36 } buffer_level;
37 
38 typedef struct
39 {
44  uint64_t row;
46 
47 typedef struct
48 {
52  uint32_t client_con_count;
54  char *query;
55  size_t query_len;
56 } client_st;
57 
58 char client_process(client_st *client, client_con_st *client_con);
59 void con_info(drizzle_con_st *con);
60 void result_info(drizzle_result_st *result);
61 void column_info(drizzle_column_st *column);
62 
63 #define CLIENT_ERROR(__function, __ret, __client) { \
64  printf(__function ":%d:%s\n", __ret, \
65  drizzle_error(&((__client)->drizzle))); \
66  exit(1); }
67 
68 int main(int argc, char *argv[])
69 {
70  client_st client;
71  int c;
72  char blocking= 0;
73  drizzle_return_t ret;
74  uint32_t x;
75  int wait_for_connections= 0;
76  drizzle_con_st *con;
77  client_con_st *client_con;
78  char *host= NULL;
79  in_port_t port= 0;
80  char *user= NULL;
81  char *password= NULL;
82  char *db= NULL;
83 
84  memset(&client, 0, sizeof(client_st));
85 
86  /* Use one connection by default. */
87  client.client_con_count= 1;
88 
89  while ((c = getopt(argc, argv, "bB:c:d:h:Hmp:P:u:")) != -1)
90  {
91  switch(c)
92  {
93  case 'b':
94  blocking= 1;
95  break;
96 
97  case 'B':
98  if (!strcasecmp(optarg, "none"))
99  client.level= BUFFER_NONE;
100  else if (!strcasecmp(optarg, "field"))
101  client.level= BUFFER_FIELD;
102  else if (!strcasecmp(optarg, "row"))
103  client.level= BUFFER_ROW;
104  else if (!strcasecmp(optarg, "all"))
105  client.level= BUFFER_ALL;
106  else
107  {
108  printf("Invalid buffer level: %s\n", optarg);
109  exit(0);
110  }
111  break;
112 
113  case 'c':
114  client.client_con_count= (uint32_t)atoi(optarg);
115  break;
116 
117  case 'd':
118  db= optarg;
119  break;
120 
121  case 'h':
122  host= optarg;
123  break;
124 
125  case 'm':
126  client.mysql_protocol= true;
127  break;
128 
129  case 'p':
130  password= optarg;
131  break;
132 
133  case 'P':
134  port= (in_port_t)atoi(optarg);
135  break;
136 
137  case 'u':
138  user= optarg;
139  break;
140 
141  case 'H':
142  default:
143  printf("\nUsage: %s [options] [query]\n", argv[0]);
144  printf("\t-b - Use blocking sockets\n");
145  printf("\t-B <level> - Use buffer <level>, options are:\n");
146  printf("\t none - Don't buffer anything (default)\n");
147  printf("\t field - Only buffer individual fields\n");
148  printf("\t row - Only buffer individual rows\n");
149  printf("\t all - Buffer entire result\n");
150  printf("\t-c <cons> - Create <cons> connections\n");
151  printf("\t-d <db> - Use <db> for the connection\n");
152  printf("\t-h <host> - Connect to <host>\n");
153  printf("\t-H - Print this help menu\n");
154  printf("\t-m - Use MySQL protocol\n");
155  printf("\t-p <password> - Use <password> for authentication\n");
156  printf("\t-P <port> - Connect to <port>\n");
157  printf("\t-u <user> - Use <user> for authentication\n");
158  exit(0);
159  }
160  }
161 
162  if (argc != optind)
163  {
164  client.query= argv[optind];
165  client.query_len= strlen(client.query);
166  }
167 
168  if (client.client_con_count > 0)
169  {
170  client.client_con_list= calloc(client.client_con_count,
171  sizeof(client_con_st));
172  if (client.client_con_list == NULL)
173  {
174  printf("calloc:%d\n", errno);
175  exit(1);
176  }
177  }
178 
179  /* This may fail if there is other initialization that fails. See docs. */
180  if (drizzle_create(&(client.drizzle)) == NULL)
181  {
182  printf("drizzle_create failed\n");
183  exit(1);
184  }
185 
186  if (blocking == 0)
188 
189  /* Start all connections, and if in non-blocking mode, return as soon as the
190  connection would block. In blocking mode, this completes the entire
191  connection/query/result. */
192  for (x= 0; x < client.client_con_count; x++)
193  {
194  /* This may fail if there is other initialization that fails. See docs. */
195  con= drizzle_con_add_tcp(&(client.drizzle),
196  &(client.client_con_list[x].con),
197  host, port, user, password, db,
198  client.mysql_protocol ? DRIZZLE_CON_MYSQL : 0);
199  if (con == NULL)
200  CLIENT_ERROR("drizzle_con_add_tcp", 0, &client);
202  &(client.client_con_list[x]));
203 
204  if (client_process(&client, &(client.client_con_list[x])) == 1)
205  wait_for_connections++;
206  }
207 
208  /* If in non-blocking mode, continue to process connections as they become
209  ready. Loop exits when all connections have completed. */
210  while (wait_for_connections != 0)
211  {
212  ret= drizzle_con_wait(&(client.drizzle));
213  if (ret != DRIZZLE_RETURN_OK)
214  CLIENT_ERROR("drizzle_con_wait", ret, &client);
215 
216  while ((con= drizzle_con_ready(&(client.drizzle))) != NULL)
217  {
218  client_con= (client_con_st *)drizzle_con_context(con);
219 
220  if (client_process(&client, client_con) == 0)
221  wait_for_connections--;
222  }
223  }
224 
225  for (x= 0; x < client.client_con_count; x++)
226  drizzle_con_free(&(client.client_con_list[x].con));
227 
228  drizzle_free(&(client.drizzle));
229 
230  if (client.client_con_list != NULL)
231  free(client.client_con_list);
232 
233  return 0;
234 }
235 
236 char client_process(client_st *client, client_con_st *client_con)
237 {
238  drizzle_return_t ret;
239  drizzle_column_st *column;
240  size_t offset= 0;
241  size_t length;
242  size_t total;
243  drizzle_field_t field;
244  drizzle_row_t row;
245  size_t *field_sizes;
246  uint16_t x;
247 
248  switch (client_con->state)
249  {
250  case CLIENT_QUERY:
251  if (client->query == NULL)
252  break;
253 
254  /* This may fail if some allocation fails, but it will set ret. */
255  (void)drizzle_query(&(client_con->con), &(client_con->result),
256  client->query, client->query_len, &ret);
257  if (ret == DRIZZLE_RETURN_IO_WAIT)
258  return 1;
259  else if (ret != DRIZZLE_RETURN_OK)
260  CLIENT_ERROR("drizzle_query", ret, client);
261 
262  result_info(&(client_con->result));
263 
264  if (drizzle_result_column_count(&(client_con->result)) == 0)
265  break;
266 
267  client_con->state= CLIENT_FIELDS;
268 
269  case CLIENT_FIELDS:
270  if (client->level == BUFFER_ALL)
271  {
272  ret= drizzle_result_buffer(&(client_con->result));
273  if (ret == DRIZZLE_RETURN_IO_WAIT)
274  return 1;
275  else if (ret != DRIZZLE_RETURN_OK)
276  CLIENT_ERROR("drizzle_result_buffer", ret, client);
277 
278  while ((column= drizzle_column_next(&(client_con->result))) != NULL)
279  column_info(column);
280  }
281  else
282  {
283  while (1)
284  {
285  column= drizzle_column_read(&(client_con->result),
286  &(client_con->column), &ret);
287  if (ret == DRIZZLE_RETURN_IO_WAIT)
288  return 1;
289  else if (ret != DRIZZLE_RETURN_OK)
290  CLIENT_ERROR("drizzle_column_read", ret, client);
291 
292  if (column == NULL)
293  break;
294 
295  column_info(column);
296  drizzle_column_free(column);
297  }
298  }
299 
300  client_con->state= CLIENT_ROWS;
301 
302  case CLIENT_ROWS:
303  if (client->level == BUFFER_ALL)
304  {
305  /* Everything has been buffered, just loop through and print. */
306  while ((row= drizzle_row_next(&(client_con->result))) != NULL)
307  {
308  field_sizes= drizzle_row_field_sizes(&(client_con->result));
309 
310  printf("Row: %" PRId64 "\n",
311  drizzle_row_current(&(client_con->result)));
312 
313  for (x= 0; x < drizzle_result_column_count(&(client_con->result)); x++)
314  {
315  if (row[x] == NULL)
316  printf(" (NULL)\n");
317  else
318  {
319  printf(" (%zd) %.*s\n", field_sizes[x], (int32_t)field_sizes[x],
320  row[x]);
321  }
322  }
323 
324  printf("\n");
325  }
326 
327  drizzle_result_free(&(client_con->result));
328  break;
329  }
330 
331  while (1)
332  {
333  if (client->level == BUFFER_NONE || client->level == BUFFER_FIELD)
334  {
335  /* Still need to read a row at a time, and then each field. */
336  if (client_con->row == 0)
337  {
338  client_con->row= drizzle_row_read(&(client_con->result), &ret);
339  if (ret == DRIZZLE_RETURN_IO_WAIT)
340  {
341  client_con->row= 0;
342  return 1;
343  }
344  else if (ret != DRIZZLE_RETURN_OK)
345  CLIENT_ERROR("drizzle_row", ret, client);
346 
347  if (client_con->row == 0)
348  {
349  drizzle_result_free(&(client_con->result));
350  break;
351  }
352 
353  printf("Row: %" PRId64 "\n", client_con->row);
354  }
355 
356  while (1)
357  {
358  if (client->level == BUFFER_FIELD)
359  {
360  /* Since an entire field is buffered, we don't need to worry about
361  partial reads. */
362  field= drizzle_field_buffer(&(client_con->result), &total, &ret);
363  length= total;
364  }
365  else
366  {
367  field= drizzle_field_read(&(client_con->result), &offset, &length,
368  &total, &ret);
369  }
370 
371  if (ret == DRIZZLE_RETURN_IO_WAIT)
372  return 1;
373  else if (ret == DRIZZLE_RETURN_ROW_END)
374  break;
375  else if (ret != DRIZZLE_RETURN_OK)
376  CLIENT_ERROR("drizzle_field_read", ret, client);
377 
378  if (field == NULL)
379  printf(" (NULL)");
380  else if (offset > 0)
381  printf("%.*s", (int32_t)length, field);
382  else
383  printf(" (%zd) %.*s", total, (int32_t)length, field);
384 
385  if (offset + length == total)
386  printf("\n");
387 
388  /* If we buffered the entire field, be sure to free it. */
389  if (client->level == BUFFER_FIELD)
390  drizzle_field_free(field);
391  }
392 
393  client_con->row= 0;
394  printf("\n");
395  }
396  else if (client->level == BUFFER_ROW)
397  {
398  /* The entire row will be buffered here, so no need to worry about
399  partial reads. */
400  row = drizzle_row_buffer(&(client_con->result), &ret);
401  if (ret == DRIZZLE_RETURN_IO_WAIT)
402  return 1;
403  else if (ret != DRIZZLE_RETURN_OK)
404  CLIENT_ERROR("drizzle_row", ret, client);
405 
406  /* This marks the end of rows. */
407  if (row == NULL)
408  break;
409 
410  field_sizes= drizzle_row_field_sizes(&(client_con->result));
411 
412  printf("Row: %" PRId64 "\n",
413  drizzle_row_current(&(client_con->result)));
414 
415  for (x= 0; x < drizzle_result_column_count(&(client_con->result)); x++)
416  {
417  if (row[x] == NULL)
418  printf(" (NULL)\n");
419  else
420  {
421  printf(" (%zd) %.*s\n", field_sizes[x], (int32_t)field_sizes[x],
422  row[x]);
423  }
424  }
425 
426  drizzle_row_free(&(client_con->result), row);
427  printf("\n");
428  }
429  }
430 
431  drizzle_result_free(&(client_con->result));
432  break;
433 
434  default:
435  /* This should be impossible. */
436  return 1;
437  }
438 
439  return 0;
440 }
441 
443 {
444  printf("Connected: protocol_version=%u\n"
445  " version=%s\n"
446  " thread_id=%u\n"
447  " capabilities=%u\n"
448  " language=%u\n"
449  " status=%u\n\n",
453 }
454 
456 {
457  printf("Result: row_count=%" PRId64 "\n"
458  " insert_id=%" PRId64 "\n"
459  " warning_count=%u\n"
460  " column_count=%u\n\n",
461  drizzle_result_row_count(result),
462  drizzle_result_insert_id(result),
465 }
466 
468 {
469  printf("Field: catalog=%s\n"
470  " db=%s\n"
471  " table=%s\n"
472  " org_table=%s\n"
473  " name=%s\n"
474  " org_name=%s\n"
475  " charset=%u\n"
476  " size=%u\n"
477  " max_size=%zu\n"
478  " type=%u\n"
479  " flags=%u\n\n",
480  drizzle_column_catalog(column), drizzle_column_db(column),
485  drizzle_column_flags(column));
486 }