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 "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 	mmerror(PARSE_ERROR, ET_WARNING, "descriptor \"%s\" does not exist", name);
125 }
126 
127 struct descriptor
128 		   *
lookup_descriptor(char * name,char * connection)129 lookup_descriptor(char *name, char *connection)
130 {
131 	struct descriptor *i;
132 
133 	if (name[0] != '"')
134 		return NULL;
135 
136 	for (i = descriptors; i; i = i->next)
137 	{
138 		if (strcmp(name, i->name) == 0)
139 		{
140 			if ((!connection && !i->connection)
141 				|| (connection && i->connection
142 					&& strcmp(connection, i->connection) == 0))
143 				return i;
144 		}
145 	}
146 	mmerror(PARSE_ERROR, ET_WARNING, "descriptor \"%s\" does not exist", name);
147 	return NULL;
148 }
149 
150 void
output_get_descr_header(char * desc_name)151 output_get_descr_header(char *desc_name)
152 {
153 	struct assignment *results;
154 
155 	fprintf(base_yyout, "{ ECPGget_desc_header(__LINE__, %s, &(", desc_name);
156 	for (results = assignments; results != NULL; results = results->next)
157 	{
158 		if (results->value == ECPGd_count)
159 			ECPGnumeric_lvalue(results->variable);
160 		else
161 			mmerror(PARSE_ERROR, ET_WARNING, "descriptor header item \"%d\" does not exist", results->value);
162 	}
163 
164 	drop_assignments();
165 	fprintf(base_yyout, "));\n");
166 	whenever_action(3);
167 }
168 
169 void
output_get_descr(char * desc_name,char * index)170 output_get_descr(char *desc_name, char *index)
171 {
172 	struct assignment *results;
173 
174 	fprintf(base_yyout, "{ ECPGget_desc(__LINE__, %s, %s,", desc_name, index);
175 	for (results = assignments; results != NULL; results = results->next)
176 	{
177 		const struct variable *v = find_variable(results->variable);
178 		char	   *str_zero = mm_strdup("0");
179 
180 		switch (results->value)
181 		{
182 			case ECPGd_nullable:
183 				mmerror(PARSE_ERROR, ET_WARNING, "nullable is always 1");
184 				break;
185 			case ECPGd_key_member:
186 				mmerror(PARSE_ERROR, ET_WARNING, "key_member is always 0");
187 				break;
188 			default:
189 				break;
190 		}
191 		fprintf(base_yyout, "%s,", get_dtype(results->value));
192 		ECPGdump_a_type(base_yyout, v->name, v->type, v->brace_level,
193 						NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL);
194 		free(str_zero);
195 	}
196 	drop_assignments();
197 	fputs("ECPGd_EODT);\n", base_yyout);
198 
199 	whenever_action(2 | 1);
200 }
201 
202 void
output_set_descr_header(char * desc_name)203 output_set_descr_header(char *desc_name)
204 {
205 	struct assignment *results;
206 
207 	fprintf(base_yyout, "{ ECPGset_desc_header(__LINE__, %s, (int)(", desc_name);
208 	for (results = assignments; results != NULL; results = results->next)
209 	{
210 		if (results->value == ECPGd_count)
211 			ECPGnumeric_lvalue(results->variable);
212 		else
213 			mmerror(PARSE_ERROR, ET_WARNING, "descriptor header item \"%d\" does not exist", results->value);
214 	}
215 
216 	drop_assignments();
217 	fprintf(base_yyout, "));\n");
218 	whenever_action(3);
219 }
220 
221 static const char *
descriptor_item_name(enum ECPGdtype itemcode)222 descriptor_item_name(enum ECPGdtype itemcode)
223 {
224 	switch (itemcode)
225 	{
226 		case ECPGd_cardinality:
227 			return "CARDINALITY";
228 		case ECPGd_count:
229 			return "COUNT";
230 		case ECPGd_data:
231 			return "DATA";
232 		case ECPGd_di_code:
233 			return "DATETIME_INTERVAL_CODE";
234 		case ECPGd_di_precision:
235 			return "DATETIME_INTERVAL_PRECISION";
236 		case ECPGd_indicator:
237 			return "INDICATOR";
238 		case ECPGd_key_member:
239 			return "KEY_MEMBER";
240 		case ECPGd_length:
241 			return "LENGTH";
242 		case ECPGd_name:
243 			return "NAME";
244 		case ECPGd_nullable:
245 			return "NULLABLE";
246 		case ECPGd_octet:
247 			return "OCTET_LENGTH";
248 		case ECPGd_precision:
249 			return "PRECISION";
250 		case ECPGd_ret_length:
251 			return "RETURNED_LENGTH";
252 		case ECPGd_ret_octet:
253 			return "RETURNED_OCTET_LENGTH";
254 		case ECPGd_scale:
255 			return "SCALE";
256 		case ECPGd_type:
257 			return "TYPE";
258 		default:
259 			return NULL;
260 	}
261 }
262 
263 void
output_set_descr(char * desc_name,char * index)264 output_set_descr(char *desc_name, char *index)
265 {
266 	struct assignment *results;
267 
268 	fprintf(base_yyout, "{ ECPGset_desc(__LINE__, %s, %s,", desc_name, index);
269 	for (results = assignments; results != NULL; results = results->next)
270 	{
271 		const struct variable *v = find_variable(results->variable);
272 
273 		switch (results->value)
274 		{
275 			case ECPGd_cardinality:
276 			case ECPGd_di_code:
277 			case ECPGd_di_precision:
278 			case ECPGd_precision:
279 			case ECPGd_scale:
280 				mmfatal(PARSE_ERROR, "descriptor item \"%s\" is not implemented",
281 						descriptor_item_name(results->value));
282 				break;
283 
284 			case ECPGd_key_member:
285 			case ECPGd_name:
286 			case ECPGd_nullable:
287 			case ECPGd_octet:
288 			case ECPGd_ret_length:
289 			case ECPGd_ret_octet:
290 				mmfatal(PARSE_ERROR, "descriptor item \"%s\" cannot be set",
291 						descriptor_item_name(results->value));
292 				break;
293 
294 			case ECPGd_data:
295 			case ECPGd_indicator:
296 			case ECPGd_length:
297 			case ECPGd_type:
298 				{
299 					char	   *str_zero = mm_strdup("0");
300 
301 					fprintf(base_yyout, "%s,", get_dtype(results->value));
302 					ECPGdump_a_type(base_yyout, v->name, v->type, v->brace_level,
303 						   NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL);
304 					free(str_zero);
305 				}
306 				break;
307 
308 			default:
309 				;
310 		}
311 	}
312 	drop_assignments();
313 	fputs("ECPGd_EODT);\n", base_yyout);
314 
315 	whenever_action(2 | 1);
316 }
317 
318 /* I consider dynamic allocation overkill since at most two descriptor
319    variables are possible per statement. (input and output descriptor)
320    And descriptors are no normal variables, so they don't belong into
321    the variable list.
322 */
323 
324 #define MAX_DESCRIPTOR_NAMELEN 128
325 struct variable *
descriptor_variable(const char * name,int input)326 descriptor_variable(const char *name, int input)
327 {
328 	static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN];
329 	static struct ECPGtype descriptor_type = {ECPGt_descriptor, NULL, NULL, NULL, {NULL}, 0};
330 	static struct variable varspace[2] = {
331 		{descriptor_names[0], &descriptor_type, 0, NULL},
332 		{descriptor_names[1], &descriptor_type, 0, NULL}
333 	};
334 
335 	strlcpy(descriptor_names[input], name, sizeof(descriptor_names[input]));
336 	return &varspace[input];
337 }
338 
339 struct variable *
sqlda_variable(const char * name)340 sqlda_variable(const char *name)
341 {
342 	struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
343 
344 	p->name = mm_strdup(name);
345 	p->type = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype));
346 	p->type->type = ECPGt_sqlda;
347 	p->type->size = NULL;
348 	p->type->struct_sizeof = NULL;
349 	p->type->u.element = NULL;
350 	p->type->counter = 0;
351 	p->brace_level = 0;
352 	p->next = NULL;
353 
354 	return p;
355 }
356