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 0 : descriptor_key_init(void)
35 : {
36 0 : pthread_key_create(&descriptor_key, descriptor_destructor);
37 0 : }
38 :
39 : static struct descriptor *
40 0 : get_descriptors(void)
41 : {
42 0 : pthread_once(&descriptor_once, descriptor_key_init);
43 0 : return (struct descriptor *) pthread_getspecific(descriptor_key);
44 : }
45 :
46 : static void
47 0 : set_descriptors(struct descriptor *value)
48 : {
49 0 : pthread_setspecific(descriptor_key, value);
50 0 : }
51 :
52 : /* old internal convenience function that might go away later */
53 : static PGresult *
54 0 : ecpg_result_by_descriptor(int line, const char *name)
55 : {
56 0 : struct descriptor *desc = ecpg_find_desc(line, name);
57 :
58 0 : if (desc == NULL)
59 0 : return NULL;
60 0 : return desc->result;
61 0 : }
62 :
63 : static unsigned int
64 0 : ecpg_dynamic_type_DDT(Oid type)
65 : {
66 0 : switch (type)
67 : {
68 : case DATEOID:
69 0 : return SQL3_DDT_DATE;
70 : case TIMEOID:
71 0 : return SQL3_DDT_TIME;
72 : case TIMESTAMPOID:
73 0 : return SQL3_DDT_TIMESTAMP;
74 : case TIMESTAMPTZOID:
75 0 : return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;
76 : case TIMETZOID:
77 0 : return SQL3_DDT_TIME_WITH_TIME_ZONE;
78 : default:
79 0 : return SQL3_DDT_ILLEGAL;
80 : }
81 0 : }
82 :
83 : bool
84 0 : ECPGget_desc_header(int lineno, const char *desc_name, int *count)
85 : {
86 0 : PGresult *ECPGresult;
87 0 : struct sqlca_t *sqlca = ECPGget_sqlca();
88 :
89 0 : 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 0 : ecpg_init_sqlca(sqlca);
97 0 : ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
98 0 : if (!ECPGresult)
99 0 : return false;
100 :
101 0 : *count = PQnfields(ECPGresult);
102 0 : sqlca->sqlerrd[2] = 1;
103 0 : ecpg_log("ECPGget_desc_header: found %d attributes\n", *count);
104 0 : return true;
105 0 : }
106 :
107 : static bool
108 0 : get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
109 : {
110 0 : switch (vartype)
111 : {
112 : case ECPGt_short:
113 0 : *(short *) var = (short) value;
114 0 : break;
115 : case ECPGt_int:
116 0 : *(int *) var = value;
117 0 : break;
118 : case ECPGt_long:
119 0 : *(long *) var = (long) value;
120 0 : break;
121 : case ECPGt_unsigned_short:
122 0 : *(unsigned short *) var = (unsigned short) value;
123 0 : break;
124 : case ECPGt_unsigned_int:
125 0 : *(unsigned int *) var = (unsigned int) value;
126 0 : break;
127 : case ECPGt_unsigned_long:
128 0 : *(unsigned long *) var = (unsigned long) value;
129 0 : break;
130 : case ECPGt_long_long:
131 0 : *(long long int *) var = (long long int) value;
132 0 : break;
133 : case ECPGt_unsigned_long_long:
134 0 : *(unsigned long long int *) var = (unsigned long long int) value;
135 0 : break;
136 : case ECPGt_float:
137 0 : *(float *) var = (float) value;
138 0 : break;
139 : case ECPGt_double:
140 0 : *(double *) var = (double) value;
141 0 : break;
142 : 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 0 : return true;
148 0 : }
149 :
150 : static bool
151 0 : set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
152 : {
153 0 : switch (vartype)
154 : {
155 : case ECPGt_short:
156 0 : *target = *(const short *) var;
157 0 : break;
158 : case ECPGt_int:
159 0 : *target = *(const int *) var;
160 0 : break;
161 : case ECPGt_long:
162 0 : *target = *(const long *) var;
163 0 : break;
164 : case ECPGt_unsigned_short:
165 0 : *target = *(const unsigned short *) var;
166 0 : break;
167 : case ECPGt_unsigned_int:
168 0 : *target = *(const unsigned int *) var;
169 0 : break;
170 : case ECPGt_unsigned_long:
171 0 : *target = *(const unsigned long *) var;
172 0 : break;
173 : case ECPGt_long_long:
174 0 : *target = *(const long long int *) var;
175 0 : break;
176 : case ECPGt_unsigned_long_long:
177 0 : *target = *(const unsigned long long int *) var;
178 0 : break;
179 : case ECPGt_float:
180 0 : *target = *(const float *) var;
181 0 : break;
182 : case ECPGt_double:
183 0 : *target = *(const double *) var;
184 0 : break;
185 : 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 0 : return true;
191 0 : }
192 :
193 : static bool
194 0 : get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
195 : {
196 0 : switch (vartype)
197 : {
198 : case ECPGt_char:
199 : case ECPGt_unsigned_char:
200 : case ECPGt_string:
201 0 : strncpy(var, value, varcharsize);
202 0 : break;
203 : case ECPGt_varchar:
204 : {
205 0 : struct ECPGgeneric_varchar *variable =
206 0 : (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 0 : }
217 0 : break;
218 : 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 0 : return true;
224 0 : }
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 0 : ECPGget_desc(int lineno, const char *desc_name, int index,...)
235 : {
236 0 : va_list args;
237 0 : PGresult *ECPGresult;
238 0 : enum ECPGdtype type;
239 0 : int ntuples,
240 : act_tuple;
241 0 : struct variable data_var;
242 0 : struct sqlca_t *sqlca = ECPGget_sqlca();
243 0 : bool alloc_failed = (sqlca == NULL);
244 :
245 0 : 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 0 : va_start(args, index);
253 0 : ecpg_init_sqlca(sqlca);
254 0 : ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
255 0 : if (!ECPGresult)
256 : {
257 0 : va_end(args);
258 0 : return false;
259 : }
260 :
261 0 : ntuples = PQntuples(ECPGresult);
262 :
263 0 : 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 0 : ecpg_log("ECPGget_desc: reading items for tuple %d\n", index);
271 0 : --index;
272 :
273 0 : type = va_arg(args, enum ECPGdtype);
274 :
275 0 : memset(&data_var, 0, sizeof data_var);
276 0 : data_var.type = ECPGt_EORT;
277 0 : data_var.ind_type = ECPGt_NO_INDICATOR;
278 :
279 0 : while (type != ECPGd_EODT)
280 : {
281 0 : char type_str[20];
282 0 : long varcharsize;
283 0 : long offset;
284 0 : long arrsize;
285 0 : enum ECPGttype vartype;
286 0 : void *var;
287 :
288 0 : vartype = va_arg(args, enum ECPGttype);
289 0 : var = va_arg(args, void *);
290 0 : varcharsize = va_arg(args, long);
291 0 : arrsize = va_arg(args, long);
292 0 : offset = va_arg(args, long);
293 :
294 0 : switch (type)
295 : {
296 : case (ECPGd_indicator):
297 0 : RETURN_IF_NO_DATA;
298 0 : data_var.ind_type = vartype;
299 0 : data_var.ind_pointer = var;
300 0 : data_var.ind_varcharsize = varcharsize;
301 0 : data_var.ind_arrsize = arrsize;
302 0 : data_var.ind_offset = offset;
303 0 : if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0)
304 0 : data_var.ind_value = *((void **) (data_var.ind_pointer));
305 : else
306 0 : data_var.ind_value = data_var.ind_pointer;
307 0 : break;
308 :
309 : case ECPGd_data:
310 0 : RETURN_IF_NO_DATA;
311 0 : data_var.type = vartype;
312 0 : data_var.pointer = var;
313 0 : data_var.varcharsize = varcharsize;
314 0 : data_var.arrsize = arrsize;
315 0 : data_var.offset = offset;
316 0 : if (data_var.arrsize == 0 || data_var.varcharsize == 0)
317 0 : data_var.value = *((void **) (data_var.pointer));
318 : else
319 0 : data_var.value = data_var.pointer;
320 0 : break;
321 :
322 : case ECPGd_name:
323 0 : if (!get_char_item(lineno, var, vartype, PQfname(ECPGresult, index), varcharsize))
324 : {
325 0 : va_end(args);
326 0 : return false;
327 : }
328 :
329 0 : ecpg_log("ECPGget_desc: NAME = %s\n", PQfname(ECPGresult, index));
330 0 : break;
331 :
332 : 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 : 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 : case ECPGd_scale:
351 0 : 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 0 : ecpg_log("ECPGget_desc: SCALE = %d\n", (PQfmod(ECPGresult, index) - VARHDRSZ) & 0xffff);
358 0 : break;
359 :
360 : case ECPGd_precision:
361 0 : if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) >> 16))
362 : {
363 0 : va_end(args);
364 0 : return false;
365 : }
366 :
367 0 : ecpg_log("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16);
368 0 : break;
369 :
370 : case ECPGd_octet:
371 0 : if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index)))
372 : {
373 0 : va_end(args);
374 0 : return false;
375 : }
376 :
377 0 : ecpg_log("ECPGget_desc: OCTET_LENGTH = %d\n", PQfsize(ECPGresult, index));
378 0 : break;
379 :
380 : case ECPGd_length:
381 0 : if (!get_int_item(lineno, var, vartype, PQfmod(ECPGresult, index) - VARHDRSZ))
382 : {
383 0 : va_end(args);
384 0 : return false;
385 : }
386 :
387 0 : ecpg_log("ECPGget_desc: LENGTH = %d\n", PQfmod(ECPGresult, index) - VARHDRSZ);
388 0 : break;
389 :
390 : case ECPGd_type:
391 0 : 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 0 : ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type(PQftype(ECPGresult, index)));
398 0 : break;
399 :
400 : case ECPGd_di_code:
401 0 : 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 0 : ecpg_log("ECPGget_desc: TYPE = %d\n", ecpg_dynamic_type_DDT(PQftype(ECPGresult, index)));
408 0 : break;
409 :
410 : 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 : case ECPGd_ret_length:
421 : case ECPGd_ret_octet:
422 :
423 0 : RETURN_IF_NO_DATA;
424 :
425 : /*
426 : * this is like ECPGstore_result
427 : */
428 0 : 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 0 : 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 0 : 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 0 : }
449 :
450 0 : for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
451 : {
452 0 : if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index)))
453 : {
454 0 : va_end(args);
455 0 : return false;
456 : }
457 0 : var = (char *) var + offset;
458 0 : ecpg_log("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index));
459 0 : }
460 0 : break;
461 :
462 : 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 0 : type = va_arg(args, enum ECPGdtype);
470 0 : }
471 :
472 0 : if (data_var.type != ECPGt_EORT)
473 : {
474 0 : struct statement stmt;
475 :
476 0 : memset(&stmt, 0, sizeof stmt);
477 0 : 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 0 : Assert(ecpg_clocale);
492 0 : 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 0 : stmt.connection = ecpg_get_connection(NULL);
510 0 : ecpg_store_result(ECPGresult, index, &stmt, &data_var);
511 :
512 : #ifdef HAVE_USELOCALE
513 0 : if (stmt.oldlocale != (locale_t) 0)
514 0 : 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 0 : }
527 0 : 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 0 : 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 0 : 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 0 : 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 0 : }
561 :
562 0 : for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
563 : {
564 0 : 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 0 : data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset;
570 0 : ecpg_log("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
571 0 : }
572 0 : }
573 0 : sqlca->sqlerrd[2] = ntuples;
574 0 : va_end(args);
575 0 : return true;
576 0 : }
577 :
578 : #undef RETURN_IF_NO_DATA
579 :
580 : bool
581 0 : ECPGset_desc_header(int lineno, const char *desc_name, int count)
582 : {
583 0 : struct descriptor *desc = ecpg_find_desc(lineno, desc_name);
584 :
585 0 : if (desc == NULL)
586 0 : return false;
587 0 : desc->count = count;
588 0 : return true;
589 0 : }
590 :
591 : static void
592 0 : set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
593 : char *tobeinserted)
594 : {
595 0 : if (var->type != ECPGt_bytea)
596 0 : desc_item->is_binary = false;
597 :
598 : else
599 : {
600 0 : struct ECPGgeneric_bytea *variable =
601 0 : (struct ECPGgeneric_bytea *) (var->value);
602 :
603 0 : desc_item->is_binary = true;
604 0 : desc_item->data_len = variable->len;
605 0 : }
606 :
607 0 : ecpg_free(desc_item->data); /* free() takes care of a potential NULL value */
608 0 : desc_item->data = tobeinserted;
609 0 : }
610 :
611 :
612 : bool
613 0 : ECPGset_desc(int lineno, const char *desc_name, int index,...)
614 : {
615 0 : va_list args;
616 0 : struct descriptor *desc;
617 0 : struct descriptor_item *desc_item;
618 0 : struct variable *var;
619 :
620 0 : desc = ecpg_find_desc(lineno, desc_name);
621 0 : if (desc == NULL)
622 0 : return false;
623 :
624 0 : for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
625 : {
626 0 : if (desc_item->num == index)
627 0 : break;
628 0 : }
629 :
630 0 : if (desc_item == NULL)
631 : {
632 0 : desc_item = (struct descriptor_item *) ecpg_alloc(sizeof(*desc_item), lineno);
633 0 : if (!desc_item)
634 0 : return false;
635 0 : desc_item->num = index;
636 0 : if (desc->count < index)
637 0 : desc->count = index;
638 0 : desc_item->next = desc->items;
639 0 : desc->items = desc_item;
640 0 : }
641 :
642 0 : if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
643 0 : return false;
644 :
645 0 : va_start(args, index);
646 :
647 0 : for (;;)
648 : {
649 0 : enum ECPGdtype itemtype;
650 0 : char *tobeinserted = NULL;
651 :
652 0 : itemtype = va_arg(args, enum ECPGdtype);
653 :
654 0 : if (itemtype == ECPGd_EODT)
655 0 : break;
656 :
657 0 : var->type = va_arg(args, enum ECPGttype);
658 0 : var->pointer = va_arg(args, char *);
659 :
660 0 : var->varcharsize = va_arg(args, long);
661 0 : var->arrsize = va_arg(args, long);
662 0 : var->offset = va_arg(args, long);
663 :
664 0 : if (var->arrsize == 0 || var->varcharsize == 0)
665 0 : var->value = *((char **) (var->pointer));
666 : else
667 0 : 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 0 : if (var->arrsize < 0)
674 0 : var->arrsize = 0;
675 0 : if (var->varcharsize < 0)
676 0 : var->varcharsize = 0;
677 :
678 0 : var->next = NULL;
679 :
680 0 : switch (itemtype)
681 : {
682 : case ECPGd_data:
683 : {
684 0 : 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 0 : set_desc_attr(desc_item, var, tobeinserted);
692 0 : tobeinserted = NULL;
693 0 : break;
694 : }
695 :
696 : case ECPGd_indicator:
697 0 : set_int_item(lineno, &desc_item->indicator, var->pointer, var->type);
698 0 : break;
699 :
700 : case ECPGd_length:
701 0 : set_int_item(lineno, &desc_item->length, var->pointer, var->type);
702 0 : break;
703 :
704 : case ECPGd_precision:
705 0 : set_int_item(lineno, &desc_item->precision, var->pointer, var->type);
706 0 : break;
707 :
708 : case ECPGd_scale:
709 0 : set_int_item(lineno, &desc_item->scale, var->pointer, var->type);
710 0 : break;
711 :
712 : case ECPGd_type:
713 0 : set_int_item(lineno, &desc_item->type, var->pointer, var->type);
714 0 : break;
715 :
716 : default:
717 : {
718 0 : 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 0 : }
726 : }
727 0 : }
728 0 : ecpg_free(var);
729 0 : va_end(args);
730 :
731 0 : return true;
732 0 : }
733 :
734 : /* Free the descriptor and items in it. */
735 : static void
736 0 : descriptor_free(struct descriptor *desc)
737 : {
738 0 : struct descriptor_item *desc_item;
739 :
740 0 : for (desc_item = desc->items; desc_item;)
741 : {
742 0 : struct descriptor_item *di;
743 :
744 0 : ecpg_free(desc_item->data);
745 0 : di = desc_item;
746 0 : desc_item = desc_item->next;
747 0 : ecpg_free(di);
748 0 : }
749 :
750 0 : ecpg_free(desc->name);
751 0 : PQclear(desc->result);
752 0 : ecpg_free(desc);
753 0 : }
754 :
755 : bool
756 0 : ECPGdeallocate_desc(int line, const char *name)
757 : {
758 0 : struct descriptor *desc;
759 0 : struct descriptor *prev;
760 0 : struct sqlca_t *sqlca = ECPGget_sqlca();
761 :
762 0 : 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 0 : ecpg_init_sqlca(sqlca);
770 0 : for (desc = get_descriptors(), prev = NULL; desc; prev = desc, desc = desc->next)
771 : {
772 0 : if (strcmp(name, desc->name) == 0)
773 : {
774 0 : if (prev)
775 0 : prev->next = desc->next;
776 : else
777 0 : set_descriptors(desc->next);
778 0 : descriptor_free(desc);
779 0 : return true;
780 : }
781 0 : }
782 0 : ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
783 0 : return false;
784 0 : }
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 0 : }
797 0 : }
798 :
799 : bool
800 0 : ECPGallocate_desc(int line, const char *name)
801 : {
802 0 : struct descriptor *new;
803 0 : struct sqlca_t *sqlca = ECPGget_sqlca();
804 :
805 0 : 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 0 : ecpg_init_sqlca(sqlca);
813 0 : new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line);
814 0 : if (!new)
815 0 : return false;
816 0 : new->next = get_descriptors();
817 0 : new->name = ecpg_alloc(strlen(name) + 1, line);
818 0 : if (!new->name)
819 : {
820 0 : ecpg_free(new);
821 0 : return false;
822 : }
823 0 : new->count = -1;
824 0 : new->items = NULL;
825 0 : new->result = PQmakeEmptyPGresult(NULL, 0);
826 0 : 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 0 : strcpy(new->name, name);
834 0 : set_descriptors(new);
835 0 : return true;
836 0 : }
837 :
838 : /* Find descriptor with name in the connection. */
839 : struct descriptor *
840 0 : ecpg_find_desc(int line, const char *name)
841 : {
842 0 : struct descriptor *desc;
843 :
844 0 : for (desc = get_descriptors(); desc; desc = desc->next)
845 : {
846 0 : if (strcmp(name, desc->name) == 0)
847 0 : return desc;
848 0 : }
849 :
850 0 : ecpg_raise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
851 0 : return NULL; /* not found */
852 0 : }
853 :
854 : bool
855 0 : ECPGdescribe(int line, int compat, bool input, const char *connection_name, const char *stmt_name,...)
856 : {
857 0 : bool ret = false;
858 0 : struct connection *con;
859 0 : struct prepared_statement *prep;
860 0 : PGresult *res;
861 0 : va_list args;
862 :
863 : /* DESCRIBE INPUT is not yet supported */
864 0 : if (input)
865 : {
866 0 : ecpg_raise(line, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, "DESCRIBE INPUT");
867 0 : return ret;
868 : }
869 :
870 0 : con = ecpg_get_connection(connection_name);
871 0 : 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 0 : prep = ecpg_find_prepared_statement(stmt_name, con, NULL);
878 0 : 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 0 : va_start(args, stmt_name);
885 :
886 0 : for (;;)
887 : {
888 0 : enum ECPGttype type;
889 0 : void *ptr;
890 :
891 : /* variable type */
892 0 : type = va_arg(args, enum ECPGttype);
893 :
894 0 : if (type == ECPGt_EORT)
895 0 : break;
896 :
897 : /* rest of variable parameters */
898 0 : ptr = va_arg(args, void *);
899 0 : (void) va_arg(args, long); /* skip args */
900 0 : (void) va_arg(args, long);
901 0 : (void) va_arg(args, long);
902 :
903 : /* variable indicator */
904 0 : (void) va_arg(args, enum ECPGttype);
905 0 : (void) va_arg(args, void *); /* skip args */
906 0 : (void) va_arg(args, long);
907 0 : (void) va_arg(args, long);
908 0 : (void) va_arg(args, long);
909 :
910 0 : switch (type)
911 : {
912 : case ECPGt_descriptor:
913 : {
914 0 : char *name = ptr;
915 0 : struct descriptor *desc = ecpg_find_desc(line, name);
916 :
917 0 : if (desc == NULL)
918 0 : break;
919 :
920 0 : res = PQdescribePrepared(con->connection, stmt_name);
921 0 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
922 0 : break;
923 :
924 0 : PQclear(desc->result);
925 :
926 0 : desc->result = res;
927 0 : ret = true;
928 0 : break;
929 0 : }
930 : case ECPGt_sqlda:
931 : {
932 0 : if (INFORMIX_MODE(compat))
933 : {
934 0 : struct sqlda_compat **_sqlda = ptr;
935 0 : struct sqlda_compat *sqlda;
936 :
937 0 : res = PQdescribePrepared(con->connection, stmt_name);
938 0 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
939 0 : break;
940 :
941 0 : sqlda = ecpg_build_compat_sqlda(line, res, -1, compat);
942 0 : if (sqlda)
943 : {
944 0 : struct sqlda_compat *sqlda_old = *_sqlda;
945 0 : struct sqlda_compat *sqlda_old1;
946 :
947 0 : 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 0 : *_sqlda = sqlda;
955 0 : ret = true;
956 0 : }
957 :
958 0 : PQclear(res);
959 0 : }
960 : else
961 : {
962 0 : struct sqlda_struct **_sqlda = ptr;
963 0 : struct sqlda_struct *sqlda;
964 :
965 0 : res = PQdescribePrepared(con->connection, stmt_name);
966 0 : if (!ecpg_check_PQresult(res, line, con->connection, compat))
967 0 : break;
968 :
969 0 : sqlda = ecpg_build_native_sqlda(line, res, -1, compat);
970 0 : if (sqlda)
971 : {
972 0 : struct sqlda_struct *sqlda_old = *_sqlda;
973 0 : struct sqlda_struct *sqlda_old1;
974 :
975 0 : 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 0 : *_sqlda = sqlda;
983 0 : ret = true;
984 0 : }
985 :
986 0 : PQclear(res);
987 0 : }
988 0 : break;
989 : }
990 : default:
991 : /* nothing else may come */
992 : ;
993 0 : }
994 0 : }
995 :
996 0 : va_end(args);
997 :
998 0 : return ret;
999 0 : }
|