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