1 /*
2  * functions needed for descriptor handling
3  *
4  * src/interfaces/ecpg/preproc/descriptor.c
5  *
6  * since descriptor might be either a string constant or a string var
7  * we need to check for a constant if we expect a constant
8  */
9 
10 #include "postgres_fe.h"
11 
12 #include "preproc_extern.h"
13 
14 /*
15  * assignment handling function (descriptor)
16  */
17 
18 static struct assignment *assignments;
19 
20 void
push_assignment(char * var,enum ECPGdtype value)21 push_assignment(char *var, enum ECPGdtype value)
22 {
23 	struct assignment *new = (struct assignment *) mm_alloc(sizeof(struct assignment));
24 
25 	new->next = assignments;
26 	new->variable = mm_alloc(strlen(var) + 1);
27 	strcpy(new->variable, var);
28 	new->value = value;
29 	assignments = new;
30 }
31 
32 static void
drop_assignments(void)33 drop_assignments(void)
34 {
35 	while (assignments)
36 	{
37 		struct assignment *old_head = assignments;
38 
39 		assignments = old_head->next;
40 		free(old_head->variable);
41 		free(old_head);
42 	}
43 }
44 
45 static void
ECPGnumeric_lvalue(char * name)46 ECPGnumeric_lvalue(char *name)
47 {
48 	const struct variable *v = find_variable(name);
49 
50 	switch (v->type->type)
51 	{
52 		case ECPGt_short:
53 		case ECPGt_int:
54 		case ECPGt_long:
55 		case ECPGt_long_long:
56 		case ECPGt_unsigned_short:
57 		case ECPGt_unsigned_int:
58 		case ECPGt_unsigned_long:
59 		case ECPGt_unsigned_long_long:
60 		case ECPGt_const:
61 			fputs(name, base_yyout);
62 			break;
63 		default:
64 			mmerror(PARSE_ERROR, ET_ERROR, "variable \"%s\" must have a numeric type", name);
65 			break;
66 	}
67 }
68 
69 /*
70  * descriptor name lookup
71  */
72 
73 static struct descriptor *descriptors;
74 
75 void
add_descriptor(char * name,char * connection)76 add_descriptor(char *name, char *connection)
77 {
78 	struct descriptor *new;
79 
80 	if (name[0] != '"')
81 		return;
82 
83 	new = (struct descriptor *) mm_alloc(sizeof(struct descriptor));
84 
85 	new->next = descriptors;
86 	new->name = mm_alloc(strlen(name) + 1);
87 	strcpy(new->name, name);
88 	if (connection)
89 	{
90 		new->connection = mm_alloc(strlen(connection) + 1);
91 		strcpy(new->connection, connection);
92 	}
93 	else
94 		new->connection = connection;
95 	descriptors = new;
96 }
97 
98 void
drop_descriptor(char * name,char * connection)99 drop_descriptor(char *name, char *connection)
100 {
101 	struct descriptor *i;
102 	struct descriptor **lastptr = &descriptors;
103 
104 	if (name[0] != '"')
105 		return;
106 
107 	for (i = descriptors; i; lastptr = &i->next, i = i->next)
108 	{
109 		if (strcmp(name, i->name) == 0)
110 		{
111 			if ((!connection && !i->connection)
112 				|| (connection && i->connection
113 					&& strcmp(connection, i->connection) == 0))
114 			{
115 				*lastptr = i->next;
116 				if (i->connection)
117 					free(i->connection);
118 				free(i->name);
119 				free(i);
120 				return;
121 			}
122 		}
123 	}
124 	if (connection)
125 		mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to connection %s does not exist", name, connection);
126 	else
127 		mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to the default connection does not exist", name);
128 }
129 
130 struct descriptor
131 		   *
lookup_descriptor(char * name,char * connection)132 lookup_descriptor(char *name, char *connection)
133 {
134 	struct descriptor *i;
135 
136 	if (name[0] != '"')
137 		return NULL;
138 
139 	for (i = descriptors; i; i = i->next)
140 	{
141 		if (strcmp(name, i->name) == 0)
142 		{
143 			if ((!connection && !i->connection)
144 				|| (connection && i->connection
145 					&& strcmp(connection, i->connection) == 0))
146 				return i;
147 			if (connection && !i->connection)
148 			{
149 				/* overwrite descriptor's connection */
150 				i->connection = mm_strdup(connection);
151 				return i;
152 			}
153 		}
154 	}
155 	if (connection)
156 		mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to connection %s does not exist", name, connection);
157 	else
158 		mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to the default connection does not exist", name);
159 	return NULL;
160 }
161 
162 void
output_get_descr_header(char * desc_name)163 output_get_descr_header(char *desc_name)
164 {
165 	struct assignment *results;
166 
167 	fprintf(base_yyout, "{ ECPGget_desc_header(__LINE__, %s, &(", desc_name);
168 	for (results = assignments; results != NULL; results = results->next)
169 	{
170 		if (results->value == ECPGd_count)
171 			ECPGnumeric_lvalue(results->variable);
172 		else
173 			mmerror(PARSE_ERROR, ET_WARNING, "descriptor header item \"%d\" does not exist", results->value);
174 	}
175 
176 	drop_assignments();
177 	fprintf(base_yyout, "));\n");
178 	whenever_action(3);
179 }
180 
181 void
output_get_descr(char * desc_name,char * index)182 output_get_descr(char *desc_name, char *index)
183 {
184 	struct assignment *results;
185 
186 	fprintf(base_yyout, "{ ECPGget_desc(__LINE__, %s, %s,", desc_name, index);
187 	for (results = assignments; results != NULL; results = results->next)
188 	{
189 		const struct variable *v = find_variable(results->variable);
190 		char	   *str_zero = mm_strdup("0");
191 
192 		switch (results->value)
193 		{
194 			case ECPGd_nullable:
195 				mmerror(PARSE_ERROR, ET_WARNING, "nullable is always 1");
196 				break;
197 			case ECPGd_key_member:
198 				mmerror(PARSE_ERROR, ET_WARNING, "key_member is always 0");
199 				break;
200 			default:
201 				break;
202 		}
203 		fprintf(base_yyout, "%s,", get_dtype(results->value));
204 		ECPGdump_a_type(base_yyout, v->name, v->type, v->brace_level,
205 						NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL);
206 		free(str_zero);
207 	}
208 	drop_assignments();
209 	fputs("ECPGd_EODT);\n", base_yyout);
210 
211 	whenever_action(2 | 1);
212 }
213 
214 void
output_set_descr_header(char * desc_name)215 output_set_descr_header(char *desc_name)
216 {
217 	struct assignment *results;
218 
219 	fprintf(base_yyout, "{ ECPGset_desc_header(__LINE__, %s, (int)(", desc_name);
220 	for (results = assignments; results != NULL; results = results->next)
221 	{
222 		if (results->value == ECPGd_count)
223 			ECPGnumeric_lvalue(results->variable);
224 		else
225 			mmerror(PARSE_ERROR, ET_WARNING, "descriptor header item \"%d\" does not exist", results->value);
226 	}
227 
228 	drop_assignments();
229 	fprintf(base_yyout, "));\n");
230 	whenever_action(3);
231 }
232 
233 static const char *
descriptor_item_name(enum ECPGdtype itemcode)234 descriptor_item_name(enum ECPGdtype itemcode)
235 {
236 	switch (itemcode)
237 	{
238 		case ECPGd_cardinality:
239 			return "CARDINALITY";
240 		case ECPGd_count:
241 			return "COUNT";
242 		case ECPGd_data:
243 			return "DATA";
244 		case ECPGd_di_code:
245 			return "DATETIME_INTERVAL_CODE";
246 		case ECPGd_di_precision:
247 			return "DATETIME_INTERVAL_PRECISION";
248 		case ECPGd_indicator:
249 			return "INDICATOR";
250 		case ECPGd_key_member:
251 			return "KEY_MEMBER";
252 		case ECPGd_length:
253 			return "LENGTH";
254 		case ECPGd_name:
255 			return "NAME";
256 		case ECPGd_nullable:
257 			return "NULLABLE";
258 		case ECPGd_octet:
259 			return "OCTET_LENGTH";
260 		case ECPGd_precision:
261 			return "PRECISION";
262 		case ECPGd_ret_length:
263 			return "RETURNED_LENGTH";
264 		case ECPGd_ret_octet:
265 			return "RETURNED_OCTET_LENGTH";
266 		case ECPGd_scale:
267 			return "SCALE";
268 		case ECPGd_type:
269 			return "TYPE";
270 		default:
271 			return NULL;
272 	}
273 }
274 
275 void
output_set_descr(char * desc_name,char * index)276 output_set_descr(char *desc_name, char *index)
277 {
278 	struct assignment *results;
279 
280 	fprintf(base_yyout, "{ ECPGset_desc(__LINE__, %s, %s,", desc_name, index);
281 	for (results = assignments; results != NULL; results = results->next)
282 	{
283 		const struct variable *v = find_variable(results->variable);
284 
285 		switch (results->value)
286 		{
287 			case ECPGd_cardinality:
288 			case ECPGd_di_code:
289 			case ECPGd_di_precision:
290 			case ECPGd_precision:
291 			case ECPGd_scale:
292 				mmfatal(PARSE_ERROR, "descriptor item \"%s\" is not implemented",
293 						descriptor_item_name(results->value));
294 				break;
295 
296 			case ECPGd_key_member:
297 			case ECPGd_name:
298 			case ECPGd_nullable:
299 			case ECPGd_octet:
300 			case ECPGd_ret_length:
301 			case ECPGd_ret_octet:
302 				mmfatal(PARSE_ERROR, "descriptor item \"%s\" cannot be set",
303 						descriptor_item_name(results->value));
304 				break;
305 
306 			case ECPGd_data:
307 			case ECPGd_indicator:
308 			case ECPGd_length:
309 			case ECPGd_type:
310 				{
311 					char	   *str_zero = mm_strdup("0");
312 
313 					fprintf(base_yyout, "%s,", get_dtype(results->value));
314 					ECPGdump_a_type(base_yyout, v->name, v->type, v->brace_level,
315 									NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL);
316 					free(str_zero);
317 				}
318 				break;
319 
320 			default:
321 				;
322 		}
323 	}
324 	drop_assignments();
325 	fputs("ECPGd_EODT);\n", base_yyout);
326 
327 	whenever_action(2 | 1);
328 }
329 
330 /* I consider dynamic allocation overkill since at most two descriptor
331    variables are possible per statement. (input and output descriptor)
332    And descriptors are no normal variables, so they don't belong into
333    the variable list.
334 */
335 
336 #define MAX_DESCRIPTOR_NAMELEN 128
337 struct variable *
descriptor_variable(const char * name,int input)338 descriptor_variable(const char *name, int input)
339 {
340 	static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN];
341 	static struct ECPGtype descriptor_type = {ECPGt_descriptor, NULL, NULL, NULL, {NULL}, 0};
342 	static struct variable varspace[2] = {
343 		{descriptor_names[0], &descriptor_type, 0, NULL},
344 		{descriptor_names[1], &descriptor_type, 0, NULL}
345 	};
346 
347 	strlcpy(descriptor_names[input], name, sizeof(descriptor_names[input]));
348 	return &varspace[input];
349 }
350 
351 struct variable *
sqlda_variable(const char * name)352 sqlda_variable(const char *name)
353 {
354 	struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
355 
356 	p->name = mm_strdup(name);
357 	p->type = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype));
358 	p->type->type = ECPGt_sqlda;
359 	p->type->size = NULL;
360 	p->type->struct_sizeof = NULL;
361 	p->type->u.element = NULL;
362 	p->type->counter = 0;
363 	p->brace_level = 0;
364 	p->next = NULL;
365 
366 	return p;
367 }
368