~drizzle-trunk/libdrizzle/jenkins-Libdrizzle-78

58.2.1 by Andrew Hutchings
Initial prepared statement support
1
/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2
 *
3
 * Drizzle Client & Protocol Library
4
 *
5
 * Copyright (C) 2012 Andrew Hutchings (andrew@linuxjedi.co.uk)
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions are
10
 * met:
11
 *
12
 *     * Redistributions of source code must retain the above copyright
13
 * notice, this list of conditions and the following disclaimer.
14
 *
15
 *     * Redistributions in binary form must reproduce the above
16
 * copyright notice, this list of conditions and the following disclaimer
17
 * in the documentation and/or other materials provided with the
18
 * distribution.
19
 *
20
 *     * The names of its contributors may not be used to endorse or
21
 * promote products derived from this software without specific prior
22
 * written permission.
23
 *
24
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
 *
36
 */
37
38
#include "config.h"
39
#include "libdrizzle/common.h"
40
41
drizzle_stmt_st *drizzle_stmt_prepare(drizzle_st *con, const char *statement, size_t size, drizzle_return_t *ret_ptr)
42
{
43
  drizzle_stmt_st *stmt= (drizzle_stmt_st*)malloc(sizeof(drizzle_stmt_st));
44
  if (stmt == NULL)
45
  {
46
    *ret_ptr= DRIZZLE_RETURN_MEMORY;
47
    drizzle_set_error(con, __func__, "malloc");
48
    return NULL;
49
  }
50
  stmt->execute_result= NULL;
51
  stmt->param_count= 0;
52
  stmt->id= 0;
53
  stmt->query_params= NULL;
54
  stmt->result_params= NULL;
55
  stmt->null_bitmap_length= 0;
56
  stmt->null_bitmap= NULL;
57
  stmt->new_bind= true;
58
  con->stmt= stmt;
59
  stmt->con= con;
60
61
  stmt->prepare_result= drizzle_command_write(con, NULL, DRIZZLE_COMMAND_STMT_PREPARE,
62
                                      statement, size, size, ret_ptr);
63
  if (*ret_ptr != DRIZZLE_RETURN_OK)
64
  {
65
    free(stmt);
66
    con->stmt= NULL;
67
    return NULL;
68
  }
69
70
  /* Don't get the unused parameter packets.  Format is the same as column
71
   * packets.  Deliberate off-by-one for the EOF packet */
72
  if (stmt->param_count)
73
  {
74
    uint16_t param_num;
75
    for (param_num= 0; param_num <= stmt->param_count; param_num++)
76
    {
77
      *ret_ptr= drizzle_column_skip(stmt->prepare_result);
78
      if ((*ret_ptr != DRIZZLE_RETURN_OK) && (*ret_ptr != DRIZZLE_RETURN_EOF))
79
      {
80
        free(stmt);
81
        return NULL;
82
      }
83
    }
84
  }
85
  
86
  /* Reset column counter which is incremented when skipping parameter packets
87
   * and then buffer the columns */
88
89
  stmt->prepare_result->column_current= 0;
90
  drizzle_column_buffer(stmt->prepare_result);
91
92
  /* Parameter count can then be used to figure out the length of the null
93
   * bitmap mask */
94
95
  stmt->null_bitmap_length= (stmt->param_count + 7) / 8;
96
  stmt->null_bitmap= (uint8_t*)calloc(stmt->null_bitmap_length, 1);
97
  if (stmt->null_bitmap == NULL)
98
  {
99
    free(stmt);
100
    *ret_ptr= DRIZZLE_RETURN_MEMORY;
101
    drizzle_set_error(con, __func__, "malloc");
102
    return NULL;
103
  }
104
105
  /* Also use the parameter count to allocate the parameters */
106
  stmt->query_params= (drizzle_bind_st*)calloc(stmt->param_count, sizeof(drizzle_bind_st));
107
  stmt->state= DRIZZLE_STMT_PREPARED;
108
  stmt->fields= stmt->prepare_result->column_buffer;
109
110
  return stmt;
111
}
112
113
drizzle_return_t drizzle_stmt_bind_param(drizzle_stmt_st *stmt, uint16_t param_num, drizzle_column_type_t type, void *data, uint32_t length, drizzle_bind_options_t options)
114
{
115
  if ((stmt == NULL) || (param_num >= stmt->param_count) || (data == NULL))
116
  {
117
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
118
  }
119
  if (stmt->state < DRIZZLE_STMT_PREPARED)
120
  {
121
    drizzle_set_error(stmt->con, __func__, "stmt object has bot been prepared");
122
    return DRIZZLE_RETURN_STMT_ERROR;
123
  }
124
125
  stmt->query_params[param_num].type= type;
126
  stmt->query_params[param_num].data= data;
127
  stmt->query_params[param_num].length= length;
128
  stmt->query_params[param_num].options= options;
129
  stmt->query_params[param_num].is_bound= true;
130
131
  return DRIZZLE_RETURN_OK;
132
}
133
134
drizzle_return_t drizzle_stmt_execute(drizzle_stmt_st *stmt)
135
{
136
  uint16_t current_param;
137
  drizzle_bind_st *param_ptr;
138
  size_t param_lengths= 0;
139
  size_t buffer_size= 0;
140
  uint8_t *buffer;
141
  uint8_t *buffer_pos;
142
  uint8_t *data_pos;
143
  drizzle_return_t ret;
144
145
  /* Calculate param lengths */
146
  for (current_param= 0; current_param < stmt->param_count; current_param++)
147
  {
148
    if (!stmt->query_params[current_param].is_bound)
149
    {
150
      drizzle_set_error(stmt->con, __func__, "parameter %d has not been bound", current_param);
151
      return DRIZZLE_RETURN_STMT_ERROR;
152
    }
153
    /* parameter length + 8 byte header */
154
    param_lengths+= stmt->query_params[current_param].length + 8;
155
  }
156
157
  buffer_size= 4 /* Statement ID */
158
             + 1 /* Flags */
159
             + 4 /* Reserved (always set to 1) */
160
             + stmt->null_bitmap_length /* Null bitmap length */
161
             + 1 /* New parameters bound flag */
162
             + (stmt->param_count * 2) /* Parameter type data */
163
             + param_lengths; /* Parameter data */
164
165
  buffer = (uint8_t*)malloc(buffer_size);
166
  if (buffer == NULL)
167
  {
168
    drizzle_set_error(stmt->con, __func__, "malloc");
169
    return DRIZZLE_RETURN_MEMORY;
170
  }
171
  buffer_pos= buffer;
172
173
  /* Statement ID */
174
  drizzle_set_byte4(buffer, stmt->id);
175
  /* Flags (not currently used) */
176
  buffer[4]= 0;
177
  /* Reserved, protocol specifies set to 1 */
178
  drizzle_set_byte4(&buffer[5], 1);
179
  buffer_pos+= 9;
180
  /* Null bitmap */
181
  memcpy(buffer_pos, stmt->null_bitmap, stmt->null_bitmap_length);
182
  buffer_pos+= stmt->null_bitmap_length;
183
  /* New parameters bound flag
184
   * If set to 1 then we need to leave a gap between the parameters type data
185
   * and the actually data, so we keep track of a second pointer in the
186
   * buffer for this
187
   * */
188
  if (stmt->new_bind)
189
  {
190
    *buffer_pos= 1;
191
    buffer_pos++;
192
    /* Each param has a 2 byte data type header so the data pointer should be
193
     * moved to this */
194
    data_pos= buffer_pos + (stmt->param_count * 2);
195
  }
196
  else
197
  {
198
    *buffer_pos= 0;
199
    buffer_pos++;
200
    data_pos= buffer_pos;
201
  }
202
  
203
  /* Go through each param copying to buffer 
204
   * In an ideal world we would do this without the copy
205
   * */
206
  for (current_param= 0; current_param < stmt->param_count; current_param++)
207
  {
208
    uint16_t short_value;
209
    uint32_t long_value;
210
    uint64_t longlong_value;
211
    param_ptr= &stmt->query_params[current_param];
212
213
    if (stmt->new_bind)
214
    {
215
      uint16_t type= (uint16_t)param_ptr->type;
216
      if (param_ptr->options & DRIZZLE_BIND_OPTION_UNSIGNED)
217
      {
218
        /* Set the unsigned bit flag on the type data */
219
        type |= 0x8000;
220
      }
221
      drizzle_set_byte2(buffer_pos, type);
222
      buffer_pos+= 2;
223
    }
224
225
    if (param_ptr->options & DRIZZLE_BIND_OPTION_LONG_DATA)
226
    {
227
      /* Long data is sent separately, not in this buffer */
228
      continue;
229
    }
230
231
    switch(param_ptr->type)
232
    {
233
      case DRIZZLE_COLUMN_TYPE_NULL:
234
        /* Toggle the bit for this column in the bitmap */
235
        *stmt->null_bitmap |= (current_param ^ 2);
236
        break;
237
      case DRIZZLE_COLUMN_TYPE_TINY:
238
        *data_pos= *(uint8_t*)param_ptr->data;
239
        data_pos++;
240
        break;
241
      case DRIZZLE_COLUMN_TYPE_SHORT:
242
        short_value= *(uint16_t*)param_ptr->data;
243
        drizzle_set_byte2(data_pos, short_value);
244
        data_pos+= 2;
245
        break;
246
      case DRIZZLE_COLUMN_TYPE_LONG:
247
        long_value= *(uint32_t*)param_ptr->data;
248
        drizzle_set_byte4(data_pos, long_value);
249
        data_pos+= 4;
250
        break;
251
      case DRIZZLE_COLUMN_TYPE_LONGLONG:
252
        longlong_value= *(uint64_t*)param_ptr->data;
253
        drizzle_set_byte8(data_pos, longlong_value);
254
        data_pos+= 8;
255
        break;
256
      case DRIZZLE_COLUMN_TYPE_FLOAT:
257
        /* Float and double don't need to be packed apparently */
258
        memcpy(data_pos, param_ptr->data, 4);
259
        data_pos+= 4;
260
        break;
261
      case DRIZZLE_COLUMN_TYPE_DOUBLE:
262
        memcpy(data_pos, param_ptr->data, 8);
263
        data_pos+= 8;
264
        break;
265
      case DRIZZLE_COLUMN_TYPE_TIME:
266
        data_pos= drizzle_pack_time((drizzle_datetime_st*)param_ptr->data, data_pos);
267
        break;
268
      case DRIZZLE_COLUMN_TYPE_DATE:
269
      case DRIZZLE_COLUMN_TYPE_DATETIME:
270
      case DRIZZLE_COLUMN_TYPE_TIMESTAMP:
271
        data_pos= drizzle_pack_datetime((drizzle_datetime_st*)param_ptr->data, data_pos);
272
        break;
273
      case DRIZZLE_COLUMN_TYPE_TINY_BLOB:
274
      case DRIZZLE_COLUMN_TYPE_MEDIUM_BLOB:
275
      case DRIZZLE_COLUMN_TYPE_LONG_BLOB:
276
      case DRIZZLE_COLUMN_TYPE_BLOB:
277
      case DRIZZLE_COLUMN_TYPE_VARCHAR:
278
      case DRIZZLE_COLUMN_TYPE_VAR_STRING:
279
      case DRIZZLE_COLUMN_TYPE_STRING:
280
      case DRIZZLE_COLUMN_TYPE_DECIMAL:
281
      case DRIZZLE_COLUMN_TYPE_NEWDECIMAL:
282
        data_pos= drizzle_pack_binary((uint8_t*)param_ptr->data, param_ptr->length, data_pos);
283
        break;
284
      /* These types aren't handled yet, most are for older MySQL versions */
285
      case DRIZZLE_COLUMN_TYPE_INT24:
286
      case DRIZZLE_COLUMN_TYPE_YEAR:
287
      case DRIZZLE_COLUMN_TYPE_NEWDATE:
288
      case DRIZZLE_COLUMN_TYPE_ENUM:
289
      case DRIZZLE_COLUMN_TYPE_SET:
290
      case DRIZZLE_COLUMN_TYPE_GEOMETRY:
291
      case DRIZZLE_COLUMN_TYPE_BIT:
292
      default:
293
        drizzle_set_error(stmt->con, __func__, "unknown type when filling buffer");
294
        free(buffer);
295
        return DRIZZLE_RETURN_UNEXPECTED_DATA;
296
        break;
297
    }
298
  }
299
  if (stmt->execute_result)
300
  {
301
    drizzle_result_free(stmt->execute_result);
302
    stmt->execute_result= NULL;
303
  }
304
305
  /* Set buffer size to what we actually used */
306
  buffer_size= data_pos - buffer;
307
308
  stmt->execute_result= drizzle_command_write(stmt->con, stmt->execute_result, DRIZZLE_COMMAND_STMT_EXECUTE, buffer, buffer_size, buffer_size, &ret);
309
310
  if (ret == DRIZZLE_RETURN_OK)
311
  {
312
    stmt->state= DRIZZLE_STMT_EXECUTED;
313
  }
314
  else
315
  {
316
    free(buffer);
317
    return ret;
318
  }
319
320
  stmt->new_bind= false;
321
  
322
  stmt->execute_result->binary_rows= true;
323
324
  stmt->execute_result->options= (drizzle_result_options_t)((uint8_t)stmt->execute_result->options | (uint8_t)DRIZZLE_RESULT_BINARY_ROWS);
325
326
  if (stmt->execute_result->column_count > 0)
327
  {
328
    ret= drizzle_column_buffer(stmt->execute_result);
329
    stmt->result_params= (drizzle_bind_st*)calloc(stmt->execute_result->column_count, sizeof(drizzle_bind_st));
330
  }
331
332
  free(buffer);
333
  return ret;
334
}
335
336
drizzle_return_t drizzle_stmt_send_long_data(drizzle_stmt_st *stmt, uint16_t param_num, uint8_t *data, size_t len)
337
{
338
  drizzle_return_t ret;
339
  uint8_t *buffer;
340
341
  if ((stmt == NULL) || (param_num >= stmt->param_count))
342
  {
343
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
344
  }
345
346
  if (stmt->state < DRIZZLE_STMT_PREPARED)
347
  {
348
    drizzle_set_error(stmt->con, __func__, "stmt object has bot been prepared");
349
    return DRIZZLE_RETURN_STMT_ERROR;
350
  }
351
352
353
  /* TODO: rework drizzle_command_write so we can send a header and we don't
354
   * need this copy
355
   * */
356
  buffer= (uint8_t*)malloc(len + 6);
357
358
  drizzle_set_byte4(buffer, stmt->id);
359
  drizzle_set_byte2(&buffer[4], param_num);
360
  memcpy(&buffer[6], data, len);
361
362
  stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options | (uint8_t)DRIZZLE_CON_NO_RESULT_READ);
363
  drizzle_command_write(stmt->con, NULL, DRIZZLE_COMMAND_STMT_SEND_LONG_DATA,
364
                        buffer, len+6, len+6, &ret);
365
  stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options & (uint8_t)~DRIZZLE_CON_NO_RESULT_READ);
366
  stmt->query_params[param_num].options= (drizzle_bind_options_t)((uint8_t)stmt->query_params[param_num].options | (uint8_t)DRIZZLE_BIND_OPTION_LONG_DATA);
367
368
  free(buffer);
369
  return ret;
370
}
371
372
drizzle_return_t drizzle_stmt_reset(drizzle_stmt_st *stmt)
373
{
374
  drizzle_return_t ret;
375
  uint8_t buffer[4];
376
  uint16_t current_param;
377
378
  if (stmt == NULL)
379
  {
380
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
381
  }
382
383
  for (current_param= 0; current_param < stmt->param_count; current_param++)
384
  {
385
    stmt->query_params[current_param].options= (drizzle_bind_options_t)((uint8_t)stmt->query_params[current_param].options & (uint8_t)~DRIZZLE_BIND_OPTION_LONG_DATA);
386
  }
387
388
  drizzle_set_byte4(buffer, stmt->id);
389
  stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options | (uint8_t)DRIZZLE_CON_NO_RESULT_READ);
390
  drizzle_command_write(stmt->con, NULL, DRIZZLE_COMMAND_STMT_RESET, buffer, 4,
391
                        4, &ret);
392
  stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options & (uint8_t)~DRIZZLE_CON_NO_RESULT_READ);
393
  if (stmt->execute_result)
394
  {
395
    drizzle_result_free(stmt->execute_result);
396
    stmt->execute_result= NULL;
397
  }
398
  stmt->state= DRIZZLE_STMT_PREPARED;
399
  free(stmt->result_params);
400
401
  return ret;
402
}
403
404
drizzle_return_t drizzle_stmt_fetch(drizzle_stmt_st *stmt)
405
{
406
  drizzle_return_t ret= DRIZZLE_RETURN_OK;
407
  uint16_t column_counter= 0;
408
  drizzle_row_t row;
409
  drizzle_column_st *column;
410
411
  if (stmt == NULL)
412
  {
413
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
414
  }
415
416
  if (stmt->state < DRIZZLE_STMT_EXECUTED)
417
  {
418
    drizzle_set_error(stmt->con, __func__, "statement has not been executed");
419
    return DRIZZLE_RETURN_UNEXPECTED_DATA;
420
  }
421
  stmt->con->result= stmt->execute_result;
422
423
  /* Determine how to read the row based on whether or not it is already
424
   * buffered */
425
426
  if (stmt->execute_result->options & DRIZZLE_RESULT_BUFFER_ROW)
427
  {
428
    row= drizzle_row_next(stmt->execute_result);
429
  }
430
  else
431
  {
432
    row= drizzle_row_buffer(stmt->execute_result, &ret);
433
  }
434
435
  if (row == NULL)
436
  {
437
    return DRIZZLE_RETURN_ROW_END;
438
  }
439
  drizzle_column_seek(stmt->execute_result, 0);
440
441
  while((column= drizzle_column_next(stmt->execute_result)))
442
  {
443
    drizzle_bind_st *param= &stmt->result_params[column_counter];
444
    /* if this row is null in the result bitmap */
445
    if (*stmt->execute_result->null_bitmap & ((column_counter^2) << 2))
446
    {
447
      param->options = (drizzle_bind_options_t)((uint8_t)param->options | (uint8_t) DRIZZLE_BIND_OPTION_NULL);
448
      param->length= 0;
449
    }
450
    else
451
    {
452
      uint16_t short_data;
453
      uint32_t long_data;
454
      uint64_t longlong_data;
455
      param->length= stmt->execute_result->field_sizes[column_counter];
456
      if (column->flags & DRIZZLE_COLUMN_FLAGS_UNSIGNED)
457
      {
458
        param->options = (drizzle_bind_options_t)((uint8_t)param->options | (uint8_t) DRIZZLE_BIND_OPTION_UNSIGNED);
459
      }
460
461
      param->data= realloc(param->data, param->length);
58.2.2 by Andrew Hutchings
Fixups to statement and column
462
      param->type= column->type;
58.2.1 by Andrew Hutchings
Initial prepared statement support
463
464
      switch(column->type)
465
      {
466
        case DRIZZLE_COLUMN_TYPE_NULL:
467
          /* I don't think this one should happen, but cover it anyway */
468
          param->length= 0;
469
          break;
470
        case DRIZZLE_COLUMN_TYPE_TINY:
471
          *(uint8_t*)param->data= *row[column_counter];
472
          break;
473
        case DRIZZLE_COLUMN_TYPE_SHORT:
474
        case DRIZZLE_COLUMN_TYPE_YEAR:
475
          short_data= drizzle_get_byte2(row[column_counter]);
476
          memcpy(param->data, &short_data, 2);
477
          break;
478
        case DRIZZLE_COLUMN_TYPE_INT24:
479
        case DRIZZLE_COLUMN_TYPE_LONG:
480
          long_data= drizzle_get_byte4(row[column_counter]);
481
          memcpy(param->data, &long_data, 4);
482
          break;
483
        case DRIZZLE_COLUMN_TYPE_LONGLONG:
484
          longlong_data= drizzle_get_byte8(row[column_counter]);
485
          memcpy(param->data, &longlong_data, 8);
486
          break;
487
        case DRIZZLE_COLUMN_TYPE_FLOAT:
488
          memcpy(param->data, row[column_counter], 4);
489
          break;
490
        case DRIZZLE_COLUMN_TYPE_DOUBLE:
491
          memcpy(param->data, row[column_counter], 8);
492
          break;
493
        case DRIZZLE_COLUMN_TYPE_TIME:
494
          drizzle_unpack_time(row[column_counter], param->length, (uint8_t*)param->data);
495
          break;
496
        case DRIZZLE_COLUMN_TYPE_DATE:
497
        case DRIZZLE_COLUMN_TYPE_DATETIME:
498
        case DRIZZLE_COLUMN_TYPE_TIMESTAMP:
499
          drizzle_unpack_datetime(row[column_counter], param->length, (uint8_t*)param->data);
500
          break;
501
        case DRIZZLE_COLUMN_TYPE_TINY_BLOB:
502
        case DRIZZLE_COLUMN_TYPE_MEDIUM_BLOB:
503
        case DRIZZLE_COLUMN_TYPE_LONG_BLOB:
504
        case DRIZZLE_COLUMN_TYPE_BLOB:
505
        case DRIZZLE_COLUMN_TYPE_BIT:
506
        case DRIZZLE_COLUMN_TYPE_STRING:
507
        case DRIZZLE_COLUMN_TYPE_VAR_STRING:
508
        case DRIZZLE_COLUMN_TYPE_DECIMAL:
509
        case DRIZZLE_COLUMN_TYPE_NEWDECIMAL:
510
        case DRIZZLE_COLUMN_TYPE_NEWDATE:
511
          memcpy(param->data, row[column_counter], param->length);
512
          break;
513
        /* These types aren't handled yet, most are for older MySQL versions */
514
        case DRIZZLE_COLUMN_TYPE_VARCHAR:
515
        case DRIZZLE_COLUMN_TYPE_ENUM:
516
        case DRIZZLE_COLUMN_TYPE_SET:
517
        case DRIZZLE_COLUMN_TYPE_GEOMETRY:
518
        default:
519
          drizzle_set_error(stmt->con, __func__, "Unknown data type found");
520
          ret= DRIZZLE_RETURN_UNEXPECTED_DATA;
521
          break;
522
      }
523
    }
524
    column_counter++;
525
    if (ret == DRIZZLE_RETURN_UNEXPECTED_DATA)
526
    {
527
      break;
528
    }
529
      
530
  }
531
  stmt->state= DRIZZLE_STMT_FETCHED;
532
  if (!(stmt->execute_result->options & DRIZZLE_RESULT_BUFFER_ROW))
533
  {
534
    drizzle_row_free(stmt->execute_result, row);
535
  }
536
537
  return ret;
538
}
539
540
drizzle_return_t drizzle_stmt_buffer(drizzle_stmt_st *stmt)
541
{
542
  if (stmt == NULL)
543
  {
544
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
545
  }
546
  if (stmt->state >= DRIZZLE_STMT_FETCHED)
547
  {
548
    drizzle_set_error(stmt->con, __func__, "data set has already been read");
549
    return DRIZZLE_RETURN_UNEXPECTED_DATA;
550
  }
551
552
  stmt->con->result= stmt->execute_result;
553
  stmt->state= DRIZZLE_STMT_FETCHED;
554
555
  return drizzle_result_buffer(stmt->execute_result);
556
}
557
558
drizzle_return_t drizzle_stmt_close(drizzle_stmt_st *stmt)
559
{
560
  uint8_t buffer[4];
561
  drizzle_return_t ret;
562
563
  if (stmt == NULL)
564
  {
565
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
566
  }
567
568
  free(stmt->null_bitmap);
569
  free(stmt->query_params);
64.1.1 by Andrew Hutchings
Fix valgrind errors and leaks
570
  if (stmt->result_params)
571
  {
572
    free(stmt->result_params->data);
573
    free(stmt->result_params);
574
  }
58.2.1 by Andrew Hutchings
Initial prepared statement support
575
  if (stmt->execute_result)
576
  {
577
    drizzle_result_free(stmt->execute_result);
578
  }
579
  if (stmt->prepare_result)
580
  {
581
    drizzle_result_free(stmt->prepare_result);
582
  }
583
584
  drizzle_set_byte4(buffer, stmt->id);
585
  stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options | (uint8_t)DRIZZLE_CON_NO_RESULT_READ);
586
  drizzle_command_write(stmt->con, NULL, DRIZZLE_COMMAND_STMT_CLOSE, buffer, 4,
587
                        4, &ret);
588
  stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options & (uint8_t)~DRIZZLE_CON_NO_RESULT_READ);
589
  free(stmt);
590
  return ret;
591
}
592
593
drizzle_column_type_t drizzle_stmt_item_type(drizzle_stmt_st *stmt, uint16_t column_number)
594
{
595
  if ((stmt == NULL) || (stmt->result_params == NULL))
596
  {
597
    return DRIZZLE_COLUMN_TYPE_NONE;
598
  }
599
  return stmt->result_params[column_number].type;
600
}
601
602
void *drizzle_stmt_item_data(drizzle_stmt_st *stmt, uint16_t column_number)
603
{
604
  if ((stmt == NULL) || (stmt->result_params == NULL))
605
  {
606
    return NULL;
607
  }
608
  return stmt->result_params[column_number].data;
609
}
610
611
uint32_t drizzle_stmt_item_length(drizzle_stmt_st *stmt, uint16_t column_number)
612
{
613
  if ((stmt == NULL) || (stmt->result_params == NULL))
614
  { 
615
    return 0;
616
  }
617
  return stmt->result_params[column_number].length;
618
}
619
620
drizzle_bind_options_t drizzle_stmt_item_options(drizzle_stmt_st *stmt, uint16_t column_number)
621
{
622
  if ((stmt == NULL) || (stmt->result_params == NULL))
623
  { 
624
    return DRIZZLE_BIND_OPTION_NONE;
625
  }
626
  return stmt->result_params[column_number].options;
627
}
628
629
uint16_t drizzle_stmt_column_count(drizzle_stmt_st *stmt)
630
{
631
  if ((stmt == NULL) || (stmt->prepare_result == NULL))
632
  {
633
    return 0;
634
  }
635
636
  return stmt->prepare_result->column_count;
637
}
638
639
uint64_t drizzle_stmt_affected_rows(drizzle_stmt_st *stmt)
640
{
641
  if ((stmt == NULL) || (stmt->execute_result == NULL))
642
  {
643
    return 0;
644
  }
645
  
646
  return stmt->execute_result->affected_rows;
647
}
648
649
uint64_t drizzle_stmt_insert_id(drizzle_stmt_st *stmt)
650
{
651
  if ((stmt == NULL) || (stmt->execute_result == NULL))
652
  {
653
    return 0;
654
  }
655
656
  return stmt->execute_result->insert_id;
657
}
658
659
uint16_t drizzle_stmt_param_count(drizzle_stmt_st *stmt)
660
{
661
  if (stmt == NULL)
662
  {
663
    return 0;
664
  }
665
666
  return stmt->param_count;
667
}
668
669
uint64_t drizzle_stmt_row_count(drizzle_stmt_st *stmt)
670
{
671
  if ((stmt == NULL) || (stmt->execute_result == NULL))
672
  {
673
    return 0;
674
  }
675
676
  return stmt->execute_result->row_count;
677
}