diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:17:33 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:17:33 +0000 |
commit | 5e45211a64149b3c659b90ff2de6fa982a5a93ed (patch) | |
tree | 739caf8c461053357daa9f162bef34516c7bf452 /src/interfaces/ecpg/preproc/descriptor.c | |
parent | Initial commit. (diff) | |
download | postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.tar.xz postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.zip |
Adding upstream version 15.5.upstream/15.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/interfaces/ecpg/preproc/descriptor.c')
-rw-r--r-- | src/interfaces/ecpg/preproc/descriptor.c | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/src/interfaces/ecpg/preproc/descriptor.c b/src/interfaces/ecpg/preproc/descriptor.c new file mode 100644 index 0000000..35d9471 --- /dev/null +++ b/src/interfaces/ecpg/preproc/descriptor.c @@ -0,0 +1,367 @@ +/* + * functions needed for descriptor handling + * + * src/interfaces/ecpg/preproc/descriptor.c + * + * since descriptor might be either a string constant or a string var + * we need to check for a constant if we expect a constant + */ + +#include "postgres_fe.h" + +#include "preproc_extern.h" + +/* + * assignment handling function (descriptor) + */ + +static struct assignment *assignments; + +void +push_assignment(char *var, enum ECPGdtype value) +{ + struct assignment *new = (struct assignment *) mm_alloc(sizeof(struct assignment)); + + new->next = assignments; + new->variable = mm_alloc(strlen(var) + 1); + strcpy(new->variable, var); + new->value = value; + assignments = new; +} + +static void +drop_assignments(void) +{ + while (assignments) + { + struct assignment *old_head = assignments; + + assignments = old_head->next; + free(old_head->variable); + free(old_head); + } +} + +static void +ECPGnumeric_lvalue(char *name) +{ + const struct variable *v = find_variable(name); + + switch (v->type->type) + { + case ECPGt_short: + case ECPGt_int: + case ECPGt_long: + case ECPGt_long_long: + case ECPGt_unsigned_short: + case ECPGt_unsigned_int: + case ECPGt_unsigned_long: + case ECPGt_unsigned_long_long: + case ECPGt_const: + fputs(name, base_yyout); + break; + default: + mmerror(PARSE_ERROR, ET_ERROR, "variable \"%s\" must have a numeric type", name); + break; + } +} + +/* + * descriptor name lookup + */ + +static struct descriptor *descriptors; + +void +add_descriptor(char *name, char *connection) +{ + struct descriptor *new; + + if (name[0] != '"') + return; + + new = (struct descriptor *) mm_alloc(sizeof(struct descriptor)); + + new->next = descriptors; + new->name = mm_alloc(strlen(name) + 1); + strcpy(new->name, name); + if (connection) + { + new->connection = mm_alloc(strlen(connection) + 1); + strcpy(new->connection, connection); + } + else + new->connection = connection; + descriptors = new; +} + +void +drop_descriptor(char *name, char *connection) +{ + struct descriptor *i; + struct descriptor **lastptr = &descriptors; + + if (name[0] != '"') + return; + + for (i = descriptors; i; lastptr = &i->next, i = i->next) + { + if (strcmp(name, i->name) == 0) + { + if ((!connection && !i->connection) + || (connection && i->connection + && strcmp(connection, i->connection) == 0)) + { + *lastptr = i->next; + if (i->connection) + free(i->connection); + free(i->name); + free(i); + return; + } + } + } + if (connection) + mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to connection %s does not exist", name, connection); + else + mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to the default connection does not exist", name); +} + +struct descriptor + * +lookup_descriptor(char *name, char *connection) +{ + struct descriptor *i; + + if (name[0] != '"') + return NULL; + + for (i = descriptors; i; i = i->next) + { + if (strcmp(name, i->name) == 0) + { + if ((!connection && !i->connection) + || (connection && i->connection + && strcmp(connection, i->connection) == 0)) + return i; + if (connection && !i->connection) + { + /* overwrite descriptor's connection */ + i->connection = mm_strdup(connection); + return i; + } + } + } + if (connection) + mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to connection %s does not exist", name, connection); + else + mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to the default connection does not exist", name); + return NULL; +} + +void +output_get_descr_header(char *desc_name) +{ + struct assignment *results; + + fprintf(base_yyout, "{ ECPGget_desc_header(__LINE__, %s, &(", desc_name); + for (results = assignments; results != NULL; results = results->next) + { + if (results->value == ECPGd_count) + ECPGnumeric_lvalue(results->variable); + else + mmerror(PARSE_ERROR, ET_WARNING, "descriptor header item \"%d\" does not exist", results->value); + } + + drop_assignments(); + fprintf(base_yyout, "));\n"); + whenever_action(3); +} + +void +output_get_descr(char *desc_name, char *index) +{ + struct assignment *results; + + fprintf(base_yyout, "{ ECPGget_desc(__LINE__, %s, %s,", desc_name, index); + for (results = assignments; results != NULL; results = results->next) + { + const struct variable *v = find_variable(results->variable); + char *str_zero = mm_strdup("0"); + + switch (results->value) + { + case ECPGd_nullable: + mmerror(PARSE_ERROR, ET_WARNING, "nullable is always 1"); + break; + case ECPGd_key_member: + mmerror(PARSE_ERROR, ET_WARNING, "key_member is always 0"); + break; + default: + break; + } + fprintf(base_yyout, "%s,", get_dtype(results->value)); + ECPGdump_a_type(base_yyout, v->name, v->type, v->brace_level, + NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL); + free(str_zero); + } + drop_assignments(); + fputs("ECPGd_EODT);\n", base_yyout); + + whenever_action(2 | 1); +} + +void +output_set_descr_header(char *desc_name) +{ + struct assignment *results; + + fprintf(base_yyout, "{ ECPGset_desc_header(__LINE__, %s, (int)(", desc_name); + for (results = assignments; results != NULL; results = results->next) + { + if (results->value == ECPGd_count) + ECPGnumeric_lvalue(results->variable); + else + mmerror(PARSE_ERROR, ET_WARNING, "descriptor header item \"%d\" does not exist", results->value); + } + + drop_assignments(); + fprintf(base_yyout, "));\n"); + whenever_action(3); +} + +static const char * +descriptor_item_name(enum ECPGdtype itemcode) +{ + switch (itemcode) + { + case ECPGd_cardinality: + return "CARDINALITY"; + case ECPGd_count: + return "COUNT"; + case ECPGd_data: + return "DATA"; + case ECPGd_di_code: + return "DATETIME_INTERVAL_CODE"; + case ECPGd_di_precision: + return "DATETIME_INTERVAL_PRECISION"; + case ECPGd_indicator: + return "INDICATOR"; + case ECPGd_key_member: + return "KEY_MEMBER"; + case ECPGd_length: + return "LENGTH"; + case ECPGd_name: + return "NAME"; + case ECPGd_nullable: + return "NULLABLE"; + case ECPGd_octet: + return "OCTET_LENGTH"; + case ECPGd_precision: + return "PRECISION"; + case ECPGd_ret_length: + return "RETURNED_LENGTH"; + case ECPGd_ret_octet: + return "RETURNED_OCTET_LENGTH"; + case ECPGd_scale: + return "SCALE"; + case ECPGd_type: + return "TYPE"; + default: + return NULL; + } +} + +void +output_set_descr(char *desc_name, char *index) +{ + struct assignment *results; + + fprintf(base_yyout, "{ ECPGset_desc(__LINE__, %s, %s,", desc_name, index); + for (results = assignments; results != NULL; results = results->next) + { + const struct variable *v = find_variable(results->variable); + + switch (results->value) + { + case ECPGd_cardinality: + case ECPGd_di_code: + case ECPGd_di_precision: + case ECPGd_precision: + case ECPGd_scale: + mmfatal(PARSE_ERROR, "descriptor item \"%s\" is not implemented", + descriptor_item_name(results->value)); + break; + + case ECPGd_key_member: + case ECPGd_name: + case ECPGd_nullable: + case ECPGd_octet: + case ECPGd_ret_length: + case ECPGd_ret_octet: + mmfatal(PARSE_ERROR, "descriptor item \"%s\" cannot be set", + descriptor_item_name(results->value)); + break; + + case ECPGd_data: + case ECPGd_indicator: + case ECPGd_length: + case ECPGd_type: + { + char *str_zero = mm_strdup("0"); + + fprintf(base_yyout, "%s,", get_dtype(results->value)); + ECPGdump_a_type(base_yyout, v->name, v->type, v->brace_level, + NULL, NULL, -1, NULL, NULL, str_zero, NULL, NULL); + free(str_zero); + } + break; + + default: + ; + } + } + drop_assignments(); + fputs("ECPGd_EODT);\n", base_yyout); + + whenever_action(2 | 1); +} + +/* I consider dynamic allocation overkill since at most two descriptor + variables are possible per statement. (input and output descriptor) + And descriptors are no normal variables, so they don't belong into + the variable list. +*/ + +#define MAX_DESCRIPTOR_NAMELEN 128 +struct variable * +descriptor_variable(const char *name, int input) +{ + static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN]; + static struct ECPGtype descriptor_type = {ECPGt_descriptor, NULL, NULL, NULL, {NULL}, 0}; + static struct variable varspace[2] = { + {descriptor_names[0], &descriptor_type, 0, NULL}, + {descriptor_names[1], &descriptor_type, 0, NULL} + }; + + strlcpy(descriptor_names[input], name, sizeof(descriptor_names[input])); + return &varspace[input]; +} + +struct variable * +sqlda_variable(const char *name) +{ + struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable)); + + p->name = mm_strdup(name); + p->type = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype)); + p->type->type = ECPGt_sqlda; + p->type->size = NULL; + p->type->struct_sizeof = NULL; + p->type->u.element = NULL; + p->type->counter = 0; + p->brace_level = 0; + p->next = NULL; + + return p; +} |