Hi,
one of our clients wants to port their application suite
from Informix to PostgreSQL, they use constructs like
SELECT * INTO :tablerec FROM table ...
where "tablerec" mirrors the table fields in a C struct.
Currently ECPG dumps core on this, more exactly aborts on it
in ecpg_type_name().
Patch is attached that solves it by introducing add_struct_to_head()
called from rule "coutputvariable" that also catches C unions now,
emitting an error because unions cannot be unambiguously unrolled.
It tries to handle NULL indicator, expecting a struct with at least
the same amount of members.
Best regards,
Zoltán Böszörményi
--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics
----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/
diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.trailer pgsql85dev.5struct/src/interfaces/ecpg/preproc/ecpg.trailer
*** pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.trailer 2009-07-14 21:36:58.000000000 +0200
--- pgsql85dev.5struct/src/interfaces/ecpg/preproc/ecpg.trailer 2009-07-17 12:24:30.000000000 +0200
*************** c_args: /*EMPTY*/ { $$ = EMPTY; }
*** 1835,1843 ****
;
coutputvariable: cvariable indicator
! { add_variable_to_head(&argsresult, find_variable($1), find_variable($2)); }
| cvariable
! { add_variable_to_head(&argsresult, find_variable($1), &no_indicator); }
;
--- 1835,1873 ----
;
coutputvariable: cvariable indicator
! {
! struct variable *var = find_variable($1);
!
! switch (var->type->type)
! {
! case ECPGt_struct:
! add_struct_to_head(&argsresult, var, find_variable($2));
! break;
! case ECPGt_union:
! mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is a union", var->name);
! break;
! default:
! add_variable_to_head(&argsresult, var, find_variable($2));
! break;
! }
! }
| cvariable
! {
! struct variable *var = find_variable($1);
!
! switch (var->type->type)
! {
! case ECPGt_struct:
! add_struct_to_head(&argsresult, var, &no_indicator);
! break;
! case ECPGt_union:
! mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is a union", var->name);
! break;
! default:
! add_variable_to_head(&argsresult, var, &no_indicator);
! break;
! }
! }
;
diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/extern.h pgsql85dev.5struct/src/interfaces/ecpg/preproc/extern.h
*** pgsql85dev.4string/src/interfaces/ecpg/preproc/extern.h 2009-07-14 21:36:58.000000000 +0200
--- pgsql85dev.5struct/src/interfaces/ecpg/preproc/extern.h 2009-07-17 12:24:30.000000000 +0200
*************** extern struct descriptor *lookup_descrip
*** 91,96 ****
--- 91,97 ----
extern struct variable *descriptor_variable(const char *name, int input);
extern struct variable *sqlda_variable(const char *name);
extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *);
+ extern void add_struct_to_head(struct arguments **, struct variable *, struct variable *);
extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *);
extern void remove_variable_from_list(struct arguments ** list, struct variable * var);
extern void dump_variables(struct arguments *, int);
diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/variable.c pgsql85dev.5struct/src/interfaces/ecpg/preproc/variable.c
*** pgsql85dev.4string/src/interfaces/ecpg/preproc/variable.c 2009-07-14 21:36:58.000000000 +0200
--- pgsql85dev.5struct/src/interfaces/ecpg/preproc/variable.c 2009-07-17 12:24:30.000000000 +0200
*************** add_variable_to_head(struct arguments **
*** 382,387 ****
--- 382,461 ----
*list = p;
}
+ /*
+ * Insert a struct's members unrolled into our request list.
+ * This is needed for the case when the user says
+ *
+ * SELECT * INTO :mystruct FROM ...
+ * or
+ * SELECT a.*, b.* INTO :struct_a, :struct_b FROM a, b ...
+ *
+ * Just in case, implement it recursively.
+ */
+ void
+ add_struct_to_head(struct arguments ** list, struct variable * var, struct variable * ind)
+ {
+ struct ECPGstruct_member *member;
+ struct ECPGstruct_member *ind_member = NULL;
+ bool no_ind;
+
+ if (var->type->type != ECPGt_struct)
+ mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is not a struct", var->name);
+
+ no_ind = (ind == &no_indicator);
+
+ if (!no_ind && ind->type->type != ECPGt_struct)
+ mmerror(INDICATOR_NOT_STRUCT, ET_FATAL, "struct variable \"%s\" was associated with a non-struct indicator variable ", var->name);
+
+ member = var->type->u.members;
+ if (!no_ind)
+ ind_member = ind->type->u.members;
+
+ while (member && (no_ind || ind_member))
+ {
+ char *newvarname;
+ char *newindname;
+ struct variable *newvar;
+ struct variable *newind = &no_indicator;
+
+ newvarname = mm_alloc(strlen(var->name) + strlen(member->name) + 2);
+ sprintf(newvarname, "%s.%s", var->name, member->name);
+ newvar = find_variable(newvarname);
+ if (newvar == NULL)
+ mmerror(PARSE_ERROR, ET_FATAL, "internal error: variable \"%s\" is not found", newvarname);
+
+ if (!no_ind)
+ {
+ newindname = mm_alloc(strlen(ind->name) + strlen(ind_member->name) + 2);
+ sprintf(newindname, "%s.%s", ind->name, ind_member->name);
+ newind = find_variable(newindname);
+ if (newind == NULL)
+ mmerror(PARSE_ERROR, ET_FATAL, "internal error: variable \"%s\" is not found", newvarname);
+ }
+
+ switch (newvar->type->type)
+ {
+ case ECPGt_struct:
+ add_struct_to_head(list, newvar, newind);
+ break;
+ case ECPGt_union:
+ mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is a union", newvarname);
+ break;
+ default:
+ add_variable_to_head(list, newvar, newind);
+ break;
+ }
+ free(newvarname);
+
+ member = member->next;
+ if (!no_ind)
+ ind_member = ind_member->next;
+ }
+
+ if (member != NULL && !no_ind && ind_member == NULL)
+ mmerror(PARSE_ERROR, ET_FATAL, "indicator struct has less members than variable struct");
+ }
+
/* Append a new variable to our request list. */
void
add_variable_to_tail(struct arguments ** list, struct variable * var, struct variable * ind)
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers