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