Line data Source code
1 : /* dynamic SQL support routines
2 : *
3 : * src/interfaces/ecpg/ecpglib/descriptor.c
4 : */
5 :
6 : #define POSTGRES_ECPG_INTERNAL
7 : #include "postgres_fe.h"
8 :
9 : #include "catalog/pg_type_d.h"
10 : #include "ecpg-pthread-win32.h"
11 : #include "ecpgerrno.h"
12 : #include "ecpglib.h"
13 : #include "ecpglib_extern.h"
14 : #include "ecpgtype.h"
15 : #include "sql3types.h"
16 : #include "sqlca.h"
17 : #include "sqlda.h"
18 :
19 : static void descriptor_free(struct descriptor *desc);
20 :
21 : /* We manage descriptors separately for each thread. */
22 : static pthread_key_t descriptor_key;
23 : static pthread_once_t descriptor_once = PTHREAD_ONCE_INIT;
24 :
25 : static void descriptor_deallocate_all(struct descriptor *list);
26 :
27 : static void
28 0 : descriptor_destructor(void *arg)
29 : {
30 0 : descriptor_deallocate_all(arg);
31 0 : }
32 :
33 : static void
34 36 : descriptor_key_init(void)
35 : {
36 36 : pthread_key_create(&descriptor_key, descriptor_destructor);
37 36 : }
38 :
39 : static struct descriptor *
40 6400584 : get_descriptors(void)
41 : {
42 6400584 : pthread_once(&descriptor_once, descriptor_key_init);
43 6400584 : return (struct descriptor *) pthread_getspecific(descriptor_key);
44 : }
45 :
46 : static void
47 6400108 : set_descriptors(struct descriptor *value)
48 : {
49 6400108 : pthread_setspecific(descriptor_key, value);
50 6400108 : }
51 :
52 : /* old internal convenience function that might go away later */
53 : static PGresult *
54 292 : ecpg_result_by_descriptor(int line, const char *name)
55 : {
56 292 : struct descriptor *desc = ecpg_find_desc(line, name);
57 :
58 292 : if (desc == NULL)
59 0 : return NULL;
60 292 : return desc->result;
61 : }
62 :
63 : static unsigned int
64 32 : ecpg_dynamic_type_DDT(Oid type)
65 : {
66 32 : switch (type)
67 : {
68 32 : case DATEOID:
69 32 : return SQL3_DDT_DATE;
70 0 : case TIMEOID:
71 0 : return SQL3_DDT_TIME;
72 0 : case TIMESTAMPOID:
73 0 : return SQL3_DDT_TIMESTAMP;
74 0 : case TIMESTAMPTZOID:
75 0 : return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;
76 0 : case TIMETZOID:
77 0 : return SQL3_DDT_TIME_WITH_TIME_ZONE;
78 0 : default:
79 0 : return SQL3_DDT_ILLEGAL;
80 : }
81 : }
82 :
83 : bool
84 48 : ECPGget_desc_header(int lineno, const char *desc_name, int *count)
85 : {
86 : PGresult *ECPGresult;
87 48 : struct sqlca_t *sqlca = ECPGget_sqlca();
88 :
89 48 : if (sqlca == NULL)
90 : {
91 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
92 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
93 0 : return false;
94 : }
95 :
96 48 : ecpg_init_sqlca(sqlca);
97 48 : ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
98 48 : if (!ECPGresult)
99 0 : return false;
100 :
101 48 : *count = PQnfields(ECPGresult);
102 48 : sqlca->sqlerrd[2] = 1;
103 48 : ecpg_log("ECPGget_desc_header: found %d attributes\n", *count);
104 48 : return true;
105 : }
106 :
107 : static bool
108 412 : get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
109 : {
110 412 : switch (vartype)
111 : {
112 0 : case ECPGt_short:
113 0 : *(short *) var = (short) value;
114 0 : break;
115 412 : case ECPGt_int:
116 412 : *(int *) var = (int) value;
117 412 : break;
118 0 : case ECPGt_long:
119 0 : *(long *) var = (long) value;
120 0 : break;
121 0 : case ECPGt_unsigned_short:
122 0 : *(unsigned short *) var = (unsigned short) value;
123 0 : break;
124 0 : case ECPGt_unsigned_int:
125 0 : *(unsigned int *) var = (unsigned int) value;
126 0 : break;
127 0 : case ECPGt_unsigned_long:
128 0 : *(unsigned long *) var = (unsigned long) value;
129 0 : break;
130 0 : case ECPGt_long_long:
131 0 : *(long long int *) var = (long long int) value;
132 0 : break;
133 0 : case ECPGt_unsigned_long_long:
134 0 : *(unsigned long long int *) var = (unsigned long long int) value;
135 0 : break;
136 0 : case ECPGt_float:
137 0 : *(float *) var = (float) value;
138 0 : break;
139 0 : case ECPGt_double:
140 0 : *(double *) var = (double) value;
141 0 : break;
142 0 : default:
143 0 : ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
144 0 : return false;
145 : }
146 :
147 412 : return true;
148 : }
149 :
150 : static bool
151 16 : set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
152 : {
153 16 : switch (vartype)
154 : {
155 0 : case ECPGt_short:
156 0 : *target = *(const short *) var;
157 0 : break;
158 16 : case ECPGt_int:
159 16 : *target = *(const int *) var;
160 16 : break;
161 0 : case ECPGt_long:
162 0 : *target = *(const long *) var;
163 0 : break;
164 0 : case ECPGt_unsigned_short:
165 0 : *target = *(const unsigned short *) var;
166 0 : break;
167 0 : case ECPGt_unsigned_int:
168 0 : *target = *(const unsigned int *) var;
169 0 : break;
170 0 : case ECPGt_unsigned_long:
171 0 : *target = *(const unsigned long *) var;
172 0 : break;
173 0 : case ECPGt_long_long:
174 0 : *target = *(const long long int *) var;
175 0 : break;
176 0 : case ECPGt_unsigned_long_long:
177 0 : *target = *(const unsigned long long int *) var;
178 0 : break;
179 0 : case ECPGt_float:
180 0 : *target = *(const float *) var;
181 0 : break;
182 0 : case ECPGt_double:
183 0 : *target = *(const double *) var;
184 0 : break;
185 0 : default:
186 0 : ecpg_raise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
187 0 : return false;
188 : }
189 :
190 16 : return true;
191 : }
192 :
193 : static bool
194 120 : get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
195 : {
196 120 : switch (vartype)
197 : {
198 120 : case ECPGt_char:
199 : case ECPGt_unsigned_char:
200 : case ECPGt_string:
201 120 : strncpy(var, value, varcharsize);
202 120 : break;
203 0 : case ECPGt_varchar:
204 : {
205 0 : struct ECPGgeneric_varchar *variable =
206 : (struct ECPGgeneric_varchar *) var;
207 :
208 0 : if (varcharsize == 0)
209 0 : memcpy(variable->arr, value, strlen(value));
210 : else
211 0 : strncpy(variable->arr, value, varcharsize);
212 :
213 0 : variable->len = strlen(value);
214 0 : if (varcharsize > 0 && variable->len > varcharsize)
215 0 : variable->len = varcharsize;
216 : }
217 0 : break;
218 0 : default:
219 0 : ecpg_raise(lineno, ECPG_VAR_NOT_CHAR, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
220 0 : return false;
221 : }
222 :
223 120 : return true;
224 : }
225 :
226 : #define RETURN_IF_NO_DATA if (ntuples < 1) \
227 : { \
228 : va_end(args); \
229 : ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL); \
230 : return false; \
231 : }
232 :
233 : bool
234 244 : ECPGget_desc(int lineno, const char *desc_name, int index,...)
235 : {
236 : va_list args;
237 : PGresult *ECPGresult;
238 : enum ECPGdtype type;
239 : int ntuples,
240 : act_tuple;
241 : struct variable data_var;
242 244 : struct sqlca_t *sqlca = ECPGget_sqlca();
243 244 : bool alloc_failed = (sqlca == NULL);
244 :
245 244 : if (alloc_failed)
246 : {
247 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
248 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
249 0 : return false;
250 : }
251 :
252 244 : va_start(args, index);
253 244 : ecpg_init_sqlca(sqlca);
254 244 : ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
255 244 : if (!ECPGresult)
256 : {
257 0 : va_end(args);
258 0 : return false;
259 : }
260 :
261 244 : ntuples = PQntuples(ECPGresult);
262 :
263 244 : if (index < 1 || index > PQnfields(ECPGresult))
264 : {
265 0 : ecpg_raise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
266 0 : va_end(args);
267 0 : return false;
268 : }
269 :
270 244 : ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
271 244 : --index;
272 :
273 244 : type = va_arg(args, enum ECPGdtype);
274 :
275 244 : memset(&data_var, 0, sizeof data_var);
276 244 : data_var.type = ECPGt_EORT;
277 244 : data_var.ind_type = ECPGt_NO_INDICATOR;
278 :
279 936 : while (type != ECPGd_EODT)
280 : {
281 : char type_str[20];
282 : long varcharsize;
283 : long offset;
284 : long arrsize;
285 : enum ECPGttype vartype;
286 : void *var;
287 :
288 692 : vartype = va_arg(args, enum ECPGttype);
289 692 : var = va_arg(args, void *);
290 692 : varcharsize = va_arg(args, long);
291 692 : arrsize = va_arg(args, long);
292 692 : offset = va_arg(args, long);
293 :
294 692 : switch (type)
295 : {
296 104 : case (ECPGd_indicator):
297 104 : RETURN_IF_NO_DATA;
298 104 : data_var.ind_type = vartype;
299 104 : data_var.ind_pointer = var;
300 104 : data_var.ind_varcharsize = varcharsize;
301 104 : data_var.ind_arrsize = arrsize;
302 104 : data_var.ind_offset = offset;
303 104 : if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0)
304 40 : data_var.ind_value = *((void **) (data_var.ind_pointer));
305 : else
306 64 : data_var.ind_value = data_var.ind_pointer;
307 104 : break;
308 :
309 112 : case ECPGd_data:
310 112 : RETURN_IF_NO_DATA;
311 112 : data_var.type = vartype;
312 112 : data_var.pointer = var;
313 112 : data_var.varcharsize = varcharsize;
314 112 : data_var.arrsize = arrsize;
315 112 : data_var.offset = offset;
316 112 : if (data_var.arrsize == 0 || data_var.varcharsize == 0)
317 40 : data_var.value = *((void **) (data_var.pointer));
318 : else
319 72 : data_var.value = data_var.pointer;
320 112 : break;
321 :
322 120 : case ECPGd_name:
323 120 : if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
324 : {
325 0 : va_end(args);
326 0 : return false;
327 : }
328 :
329 120 : ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
330 120 : break;
331 :
332 0 : case ECPGd_nullable:
333 0 : if (!get_int_item(lineno, var, vartype, 1))
334 : {
335 0 : va_end(args);
336 0 : return false;
337 : }
338 :
339 0 : break;
340 :
341 0 : case ECPGd_key_member:
342 0 : if (!get_int_item(lineno, var, vartype, 0))
343 : {
344 0 : va_end(args);
345 0 : return false;
346 : }
347 :
348 0 : break;
349 :
350 56 : case ECPGd_scale:
351 56 : if (!get_int_item(lineno, var, vartype, (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff))
352 : {
353 0 : va_end(args);
354 0 : return false;
355 : }
356 :
357 56 : ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
358 56 : break;
359 :
360 56 : case ECPGd_precision:
361 56 : if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
362 : {
363 0 : va_end(args);
364 0 : return false;
365 : }
366 :
367 56 : ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
368 56 : break;
369 :
370 56 : case ECPGd_octet:
371 56 : if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
372 : {
373 0 : va_end(args);
374 0 : return false;
375 : }
376 :
377 56 : ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
378 56 : break;
379 :
380 60 : case ECPGd_length:
381 60 : if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
382 : {
383 0 : va_end(args);
384 0 : return false;
385 : }
386 :
387 60 : ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
388 60 : break;
389 :
390 56 : case ECPGd_type:
391 56 : if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type(PQftype(ECPGresult, index))))
392 : {
393 0 : va_end(args);
394 0 : return false;
395 : }
396 :
397 56 : ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
398 56 : break;
399 :
400 16 : case ECPGd_di_code:
401 16 : if (!get_int_item(lineno, var, vartype, ecpg_dynamic_type_DDT(PQftype(ECPGresult, index))))
402 : {
403 0 : va_end(args);
404 0 : return false;
405 : }
406 :
407 16 : ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
408 16 : break;
409 :
410 0 : case ECPGd_cardinality:
411 0 : if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult)))
412 : {
413 0 : va_end(args);
414 0 : return false;
415 : }
416 :
417 0 : ecpg_log("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult));
418 0 : break;
419 :
420 56 : case ECPGd_ret_length:
421 : case ECPGd_ret_octet:
422 :
423 56 : RETURN_IF_NO_DATA;
424 :
425 : /*
426 : * this is like ECPGstore_result
427 : */
428 56 : if (arrsize > 0 && ntuples > arrsize)
429 : {
430 0 : ecpg_log("ECPGget_desc on line %d: incorrect number of matches; %d don't fit into array of %ld\n",
431 : lineno, ntuples, arrsize);
432 0 : ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
433 0 : va_end(args);
434 0 : return false;
435 : }
436 : /* allocate storage if needed */
437 56 : if (arrsize == 0 && *(void **) var == NULL)
438 : {
439 0 : void *mem = ecpg_auto_alloc(offset * ntuples, lineno);
440 :
441 0 : if (!mem)
442 : {
443 0 : va_end(args);
444 0 : return false;
445 : }
446 0 : *(void **) var = mem;
447 0 : var = mem;
448 : }
449 :
450 112 : for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
451 : {
452 56 : if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
453 : {
454 0 : va_end(args);
455 0 : return false;
456 : }
457 56 : var = (char *) var + offset;
458 56 : ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
459 : }
460 56 : break;
461 :
462 0 : default:
463 0 : snprintf(type_str, sizeof(type_str), "%d", type);
464 0 : ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
465 0 : va_end(args);
466 0 : return false;
467 : }
468 :
469 692 : type = va_arg(args, enum ECPGdtype);
470 : }
471 :
472 244 : if (data_var.type != ECPGt_EORT)
473 : {
474 : struct statement stmt;
475 :
476 112 : memset(&stmt, 0, sizeof stmt);
477 112 : stmt.lineno = lineno;
478 :
479 : /* Make sure we do NOT honor the locale for numeric input */
480 : /* since the database gives the standard decimal point */
481 : /* (see comments in execute.c) */
482 : #ifdef HAVE_USELOCALE
483 :
484 : /*
485 : * To get here, the above PQnfields() test must have found nonzero
486 : * fields. One needs a connection to create such a descriptor. (EXEC
487 : * SQL SET DESCRIPTOR can populate the descriptor's "items", but it
488 : * can't change the descriptor's PQnfields().) Any successful
489 : * connection initializes ecpg_clocale.
490 : */
491 : Assert(ecpg_clocale);
492 112 : stmt.oldlocale = uselocale(ecpg_clocale);
493 : #else
494 : #ifdef WIN32
495 : stmt.oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
496 : #endif
497 : stmt.oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL),
498 : lineno, &alloc_failed);
499 : if (alloc_failed)
500 : {
501 : va_end(args);
502 : return false;
503 : }
504 :
505 : setlocale(LC_NUMERIC, "C");
506 : #endif
507 :
508 : /* desperate try to guess something sensible */
509 112 : stmt.connection = ecpg_get_connection(NULL);
510 112 : ecpg_store_result(ECPGresult, index, &stmt, &data_var);
511 :
512 : #ifdef HAVE_USELOCALE
513 112 : if (stmt.oldlocale != (locale_t) 0)
514 112 : uselocale(stmt.oldlocale);
515 : #else
516 : if (stmt.oldlocale)
517 : {
518 : setlocale(LC_NUMERIC, stmt.oldlocale);
519 : ecpg_free(stmt.oldlocale);
520 : }
521 : #ifdef WIN32
522 : if (stmt.oldthreadlocale != -1)
523 : _configthreadlocale(stmt.oldthreadlocale);
524 : #endif
525 : #endif
526 : }
527 132 : else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
528 :
529 : /*
530 : * ind_type != NO_INDICATOR should always have ind_pointer != NULL but
531 : * since this might be changed manually in the .c file let's play it
532 : * safe
533 : */
534 : {
535 : /*
536 : * this is like ECPGstore_result but since we don't have a data
537 : * variable at hand, we can't call it
538 : */
539 56 : if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize)
540 : {
541 0 : ecpg_log("ECPGget_desc on line %d: incorrect number of matches (indicator); %d don't fit into array of %ld\n",
542 : lineno, ntuples, data_var.ind_arrsize);
543 0 : ecpg_raise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
544 0 : va_end(args);
545 0 : return false;
546 : }
547 :
548 : /* allocate storage if needed */
549 56 : if (data_var.ind_arrsize == 0 && data_var.ind_value == NULL)
550 : {
551 0 : void *mem = ecpg_auto_alloc(data_var.ind_offset * ntuples, lineno);
552 :
553 0 : if (!mem)
554 : {
555 0 : va_end(args);
556 0 : return false;
557 : }
558 0 : *(void **) data_var.ind_pointer = mem;
559 0 : data_var.ind_value = mem;
560 : }
561 :
562 112 : for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
563 : {
564 56 : if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index)))
565 : {
566 0 : va_end(args);
567 0 : return false;
568 : }
569 56 : data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
570 56 : ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
571 : }
572 : }
573 244 : sqlca->sqlerrd[2] = ntuples;
574 244 : va_end(args);
575 244 : return true;
576 : }
577 :
578 : #undef RETURN_IF_NO_DATA
579 :
580 : bool
581 4 : ECPGset_desc_header(int lineno, const char *desc_name, int count)
582 : {
583 4 : struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
584 :
585 4 : if (desc == NULL)
586 0 : return false;
587 4 : desc->count = count;
588 4 : return true;
589 : }
590 :
591 : static void
592 44 : set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
593 : char *tobeinserted)
594 : {
595 44 : if (var->type != ECPGt_bytea)
596 36 : desc_item->is_binary = false;
597 :
598 : else
599 : {
600 8 : struct ECPGgeneric_bytea *variable =
601 : (struct ECPGgeneric_bytea *) (var->value);
602 :
603 8 : desc_item->is_binary = true;
604 8 : desc_item->data_len = variable->len;
605 : }
606 :
607 44 : ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
608 44 : desc_item->data = tobeinserted;
609 44 : }
610 :
611 :
612 : bool
613 44 : ECPGset_desc(int lineno, const char *desc_name, int index,...)
614 : {
615 : va_list args;
616 : struct descriptor *desc;
617 : struct descriptor_item *desc_item;
618 : struct variable *var;
619 :
620 44 : desc = ecpg_find_desc(lineno, desc_name);
621 44 : if (desc == NULL)
622 0 : return false;
623 :
624 68 : for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
625 : {
626 52 : if (desc_item->num == index)
627 28 : break;
628 : }
629 :
630 44 : if (desc_item == NULL)
631 : {
632 16 : desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
633 16 : if (!desc_item)
634 0 : return false;
635 16 : desc_item->num = index;
636 16 : if (desc->count < index)
637 16 : desc->count = index;
638 16 : desc_item->next = desc->items;
639 16 : desc->items = desc_item;
640 : }
641 :
642 44 : if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
643 0 : return false;
644 :
645 44 : va_start(args, index);
646 :
647 : for (;;)
648 60 : {
649 : enum ECPGdtype itemtype;
650 104 : char *tobeinserted = NULL;
651 :
652 104 : itemtype = va_arg(args, enum ECPGdtype);
653 :
654 104 : if (itemtype == ECPGd_EODT)
655 44 : break;
656 :
657 60 : var->type = va_arg(args, enum ECPGttype);
658 60 : var->pointer = va_arg(args, char *);
659 :
660 60 : var->varcharsize = va_arg(args, long);
661 60 : var->arrsize = va_arg(args, long);
662 60 : var->offset = va_arg(args, long);
663 :
664 60 : if (var->arrsize == 0 || var->varcharsize == 0)
665 0 : var->value = *((char **) (var->pointer));
666 : else
667 60 : var->value = var->pointer;
668 :
669 : /*
670 : * negative values are used to indicate an array without given bounds
671 : */
672 : /* reset to zero for us */
673 60 : if (var->arrsize < 0)
674 0 : var->arrsize = 0;
675 60 : if (var->varcharsize < 0)
676 0 : var->varcharsize = 0;
677 :
678 60 : var->next = NULL;
679 :
680 60 : switch (itemtype)
681 : {
682 44 : case ECPGd_data:
683 : {
684 44 : if (!ecpg_store_input(lineno, true, var, &tobeinserted, false))
685 : {
686 0 : ecpg_free(var);
687 0 : va_end(args);
688 0 : return false;
689 : }
690 :
691 44 : set_desc_attr(desc_item, var, tobeinserted);
692 44 : tobeinserted = NULL;
693 44 : break;
694 : }
695 :
696 16 : case ECPGd_indicator:
697 16 : set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
698 16 : break;
699 :
700 0 : case ECPGd_length:
701 0 : set_int_item(lineno, &desc_item->length, var->pointer, var->type);
702 0 : break;
703 :
704 0 : case ECPGd_precision:
705 0 : set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
706 0 : break;
707 :
708 0 : case ECPGd_scale:
709 0 : set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
710 0 : break;
711 :
712 0 : case ECPGd_type:
713 0 : set_int_item(lineno, &desc_item->type, var->pointer, var->type);
714 0 : break;
715 :
716 0 : default:
717 : {
718 : char type_str[20];
719 :
720 0 : snprintf(type_str, sizeof(type_str), "%d", itemtype);
721 0 : ecpg_raise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
722 0 : ecpg_free(var);
723 0 : va_end(args);
724 0 : return false;
725 : }
726 : }
727 : }
728 44 : ecpg_free(var);
729 44 : va_end(args);
730 :
731 44 : return true;
732 : }
733 :
734 : /* Free the descriptor and items in it. */
735 : static void
736 3200060 : descriptor_free(struct descriptor *desc)
737 : {
738 : struct descriptor_item *desc_item;
739 :
740 3200068 : for (desc_item = desc->items; desc_item;)
741 : {
742 : struct descriptor_item *di;
743 :
744 8 : ecpg_free(desc_item->data);
745 8 : di = desc_item;
746 8 : desc_item = desc_item->next;
747 8 : ecpg_free(di);
748 : }
749 :
750 3200060 : ecpg_free(desc->name);
751 3200060 : PQclear(desc->result);
752 3200060 : ecpg_free(desc);
753 3200060 : }
754 :
755 : bool
756 3200060 : ECPGdeallocate_desc(int line, const char *name)
757 : {
758 : struct descriptor *desc;
759 : struct descriptor *prev;
760 3200060 : struct sqlca_t *sqlca = ECPGget_sqlca();
761 :
762 3200060 : if (sqlca == NULL)
763 : {
764 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY,
765 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
766 0 : return false;
767 : }
768 :
769 3200060 : ecpg_init_sqlca(sqlca);
770 3200080 : for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
771 : {
772 3200080 : if (strcmp(name, desc->name) == 0)
773 : {
774 3200060 : if (prev)
775 20 : prev->next = desc->next;
776 : else
777 3200040 : set_descriptors(desc->next);
778 3200060 : descriptor_free(desc);
779 3200060 : return true;
780 : }
781 : }
782 0 : ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
783 0 : return false;
784 : }
785 :
786 : /* Deallocate all descriptors in the list */
787 : static void
788 0 : descriptor_deallocate_all(struct descriptor *list)
789 : {
790 0 : while (list)
791 : {
792 0 : struct descriptor *next = list->next;
793 :
794 0 : descriptor_free(list);
795 0 : list = next;
796 : }
797 0 : }
798 :
799 : bool
800 3200068 : ECPGallocate_desc(int line, const char *name)
801 : {
802 : struct descriptor *new;
803 3200068 : struct sqlca_t *sqlca = ECPGget_sqlca();
804 :
805 3200068 : if (sqlca == NULL)
806 : {
807 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY,
808 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
809 0 : return false;
810 : }
811 :
812 3200068 : ecpg_init_sqlca(sqlca);
813 3200068 : new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
814 3200068 : if (!new)
815 0 : return false;
816 3200068 : new->next = get_descriptors();
817 3200068 : new->name = ecpg_alloc(strlen(name) + 1, line);
818 3200068 : if (!new->name)
819 : {
820 0 : ecpg_free(new);
821 0 : return false;
822 : }
823 3200068 : new->count = -1;
824 3200068 : new->items = NULL;
825 3200068 : new->result = PQmakeEmptyPGresult(NULL, 0);
826 3200068 : if (!new->result)
827 : {
828 0 : ecpg_free(new->name);
829 0 : ecpg_free(new);
830 0 : ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
831 0 : return false;
832 : }
833 3200068 : strcpy(new->name, name);
834 3200068 : set_descriptors(new);
835 3200068 : return true;
836 : }
837 :
838 : /* Find descriptor with name in the connection. */
839 : struct descriptor *
840 456 : ecpg_find_desc(int line, const char *name)
841 : {
842 : struct descriptor *desc;
843 :
844 636 : for (desc = get_descriptors(); desc; desc = desc->next)
845 : {
846 636 : if (strcmp(name, desc->name) == 0)
847 456 : return desc;
848 : }
849 :
850 0 : ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
851 0 : return NULL; /* not found */
852 : }
853 :
854 : bool
855 84 : ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
856 : {
857 84 : bool ret = false;
858 : struct connection *con;
859 : struct prepared_statement *prep;
860 : PGresult *res;
861 : va_list args;
862 :
863 : /* DESCRIBE INPUT is not yet supported */
864 84 : if (input)
865 : {
866 0 : ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
867 0 : return ret;
868 : }
869 :
870 84 : con = ecpg_get_connection(connection_name);
871 84 : if (!con)
872 : {
873 0 : ecpg_raise(line, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
874 0 : connection_name ? connection_name : ecpg_gettext("NULL"));
875 0 : return ret;
876 : }
877 84 : prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
878 84 : if (!prep)
879 : {
880 0 : ecpg_raise(line, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt_name);
881 0 : return ret;
882 : }
883 :
884 84 : va_start(args, stmt_name);
885 :
886 : for (;;)
887 84 : {
888 : enum ECPGttype type;
889 : void *ptr;
890 :
891 : /* variable type */
892 168 : type = va_arg(args, enum ECPGttype);
893 :
894 168 : if (type == ECPGt_EORT)
895 84 : break;
896 :
897 : /* rest of variable parameters */
898 84 : ptr = va_arg(args, void *);
899 84 : (void) va_arg(args, long); /* skip args */
900 84 : (void) va_arg(args, long);
901 84 : (void) va_arg(args, long);
902 :
903 : /* variable indicator */
904 84 : (void) va_arg(args, enum ECPGttype);
905 84 : (void) va_arg(args, void *); /* skip args */
906 84 : (void) va_arg(args, long);
907 84 : (void) va_arg(args, long);
908 84 : (void) va_arg(args, long);
909 :
910 84 : switch (type)
911 : {
912 36 : case ECPGt_descriptor:
913 : {
914 36 : char *name = ptr;
915 36 : struct descriptor *desc = ecpg_find_desc(line, name);
916 :
917 36 : if (desc == NULL)
918 0 : break;
919 :
920 36 : res = PQdescribePrepared(con->connection, stmt_name);
921 36 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
922 0 : break;
923 :
924 36 : PQclear(desc->result);
925 :
926 36 : desc->result = res;
927 36 : ret = true;
928 36 : break;
929 : }
930 48 : case ECPGt_sqlda:
931 : {
932 48 : if (INFORMIX_MODE(compat))
933 24 : {
934 24 : struct sqlda_compat **_sqlda = ptr;
935 : struct sqlda_compat *sqlda;
936 :
937 24 : res = PQdescribePrepared(con->connection, stmt_name);
938 24 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
939 0 : break;
940 :
941 24 : sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
942 24 : if (sqlda)
943 : {
944 24 : struct sqlda_compat *sqlda_old = *_sqlda;
945 : struct sqlda_compat *sqlda_old1;
946 :
947 24 : while (sqlda_old)
948 : {
949 0 : sqlda_old1 = sqlda_old->desc_next;
950 0 : free(sqlda_old);
951 0 : sqlda_old = sqlda_old1;
952 : }
953 :
954 24 : *_sqlda = sqlda;
955 24 : ret = true;
956 : }
957 :
958 24 : PQclear(res);
959 : }
960 : else
961 : {
962 24 : struct sqlda_struct **_sqlda = ptr;
963 : struct sqlda_struct *sqlda;
964 :
965 24 : res = PQdescribePrepared(con->connection, stmt_name);
966 24 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
967 0 : break;
968 :
969 24 : sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
970 24 : if (sqlda)
971 : {
972 24 : struct sqlda_struct *sqlda_old = *_sqlda;
973 : struct sqlda_struct *sqlda_old1;
974 :
975 24 : while (sqlda_old)
976 : {
977 0 : sqlda_old1 = sqlda_old->desc_next;
978 0 : free(sqlda_old);
979 0 : sqlda_old = sqlda_old1;
980 : }
981 :
982 24 : *_sqlda = sqlda;
983 24 : ret = true;
984 : }
985 :
986 24 : PQclear(res);
987 : }
988 48 : break;
989 : }
990 84 : default:
991 : /* nothing else may come */
992 : ;
993 : }
994 : }
995 :
996 84 : va_end(args);
997 :
998 84 : return ret;
999 : }
|