Commit 90326c01 authored by Michael Meskes's avatar Michael Meskes

Added SET DESCRIPTOR command.

	Note that this still has some bugs. The functionality is there though, it's just a matter of fixing the bugs now.
Cleaned up error handling in preprocessor.
parent c7beffcc
/* dynamic SQL support routines /* dynamic SQL support routines
* *
* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.7 2003/11/29 19:52:08 pgsql Exp $ * $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.8 2004/06/30 15:01:56 meskes Exp $
*/ */
#define POSTGRES_ECPG_INTERNAL #define POSTGRES_ECPG_INTERNAL
...@@ -110,6 +110,51 @@ get_int_item(int lineno, void *var, enum ECPGttype vartype, int value) ...@@ -110,6 +110,51 @@ get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
return (true); return (true);
} }
static bool
set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
{
switch (vartype)
{
case ECPGt_short:
*target = *(short *) var;
break;
case ECPGt_int:
*target = *(int *) var;
break;
case ECPGt_long:
*target = *(long *) var;
break;
case ECPGt_unsigned_short:
*target = *(unsigned short *) var;
break;
case ECPGt_unsigned_int:
*target = *(unsigned int *) var;
break;
case ECPGt_unsigned_long:
*target = *(unsigned long *) var;
break;
#ifdef HAVE_LONG_LONG_INT_64
case ECPGt_long_long:
*target = *(long long int *) var;
break;
case ECPGt_unsigned_long_long:
*target = *(unsigned long long int *) var;
break;
#endif /* HAVE_LONG_LONG_INT_64 */
case ECPGt_float:
*target = *(float *) var;
break;
case ECPGt_double:
*target = *(double *) var;
break;
default:
ECPGraise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
return (false);
}
return true;
}
static bool static bool
get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize) get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
{ {
...@@ -385,6 +430,124 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) ...@@ -385,6 +430,124 @@ ECPGget_desc(int lineno, char *desc_name, int index,...)
return (true); return (true);
} }
bool
ECPGset_desc(int lineno, char *desc_name, int index,...)
{
va_list args;
struct descriptor *desc;
struct descriptor_item *desc_item, *last_di;
for (desc = all_descriptors; desc; desc = desc->next)
{
if (strcmp(desc_name, desc->name)==0)
break;
}
if (desc == NULL)
{
ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, desc_name);
return false;
}
for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
{
if (desc_item->num == index)
break;
}
if (desc_item == NULL)
{
desc_item = ECPGalloc(sizeof(*desc_item), lineno);
desc_item->num = index;
desc_item->next = desc->items;
desc->items = desc_item;
}
va_start(args, index);
do
{
enum ECPGdtype itemtype;
long varcharsize;
long offset;
long arrsize;
enum ECPGttype vartype;
void *var;
itemtype = va_arg(args, enum ECPGdtype);
if (itemtype == ECPGd_EODT)
break;
vartype = va_arg(args, enum ECPGttype);
var = va_arg(args, void *);
varcharsize = va_arg(args, long);
arrsize = va_arg(args, long);
offset = va_arg(args, long);
switch (itemtype)
{
case ECPGd_data:
{
// FIXME: how to do this in general?
switch (vartype)
{
case ECPGt_char:
desc_item->data = strdup((char *)var);
break;
case ECPGt_int:
{
char buf[20];
snprintf(buf, 20, "%d", *(int *)var);
desc_item->data = strdup(buf);
break;
}
default:
abort();
}
break;
}
case ECPGd_indicator:
set_int_item(lineno, &desc_item->indicator, var, vartype);
break;
case ECPGd_length:
set_int_item(lineno, &desc_item->length, var, vartype);
break;
case ECPGd_precision:
set_int_item(lineno, &desc_item->precision, var, vartype);
break;
case ECPGd_scale:
set_int_item(lineno, &desc_item->scale, var, vartype);
break;
case ECPGd_type:
set_int_item(lineno, &desc_item->type, var, vartype);
break;
default:
{
char type_str[20];
snprintf(type_str, sizeof(type_str), "%d", itemtype);
ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
return false;
}
}
/*if (itemtype == ECPGd_data)
{
free(desc_item->data);
desc_item->data = NULL;
}*/
}
while (true);
return true;
}
bool bool
ECPGdeallocate_desc(int line, const char *name) ECPGdeallocate_desc(int line, const char *name)
{ {
...@@ -425,6 +588,7 @@ ECPGallocate_desc(int line, const char *name) ...@@ -425,6 +588,7 @@ ECPGallocate_desc(int line, const char *name)
ECPGfree(new); ECPGfree(new);
return false; return false;
} }
new->items = NULL;
new->result = PQmakeEmptyPGresult(NULL, 0); new->result = PQmakeEmptyPGresult(NULL, 0);
if (!new->result) if (!new->result)
{ {
......
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.34 2004/06/27 12:28:40 meskes Exp $ */ /* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.35 2004/06/30 15:01:56 meskes Exp $ */
/* /*
* The aim is to get a simpler inteface to the database routines. * The aim is to get a simpler inteface to the database routines.
...@@ -1026,6 +1026,9 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, ...@@ -1026,6 +1026,9 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
free(str); free(str);
} }
break; break;
case ECPGt_descriptor:
break;
default: default:
/* Not implemented yet */ /* Not implemented yet */
...@@ -1046,6 +1049,7 @@ ECPGexecute(struct statement * stmt) ...@@ -1046,6 +1049,7 @@ ECPGexecute(struct statement * stmt)
PGresult *results; PGresult *results;
PGnotify *notify; PGnotify *notify;
struct variable *var; struct variable *var;
int desc_counter = 0;
copiedquery = ECPGstrdup(stmt->command, stmt->lineno); copiedquery = ECPGstrdup(stmt->command, stmt->lineno);
...@@ -1056,64 +1060,116 @@ ECPGexecute(struct statement * stmt) ...@@ -1056,64 +1060,116 @@ ECPGexecute(struct statement * stmt)
* so on. * so on.
*/ */
var = stmt->inlist; var = stmt->inlist;
while (var) while (var)
{ {
char *newcopy = NULL; char *newcopy = NULL;
const char *tobeinserted = NULL; const char *tobeinserted;
char *p; char *p;
bool malloced = FALSE; bool malloced = FALSE;
int hostvarl = 0; int hostvarl = 0;
if (!ECPGstore_input(stmt, var, &tobeinserted, &malloced))
return false;
/* tobeinserted = NULL;
* Now tobeinserted points to an area that is to be inserted at /* A descriptor is a special case since it contains many variables but is listed only once. */
* the first %s if (var->type == ECPGt_descriptor)
*/
if (!(newcopy = (char *) ECPGalloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno)))
return false;
strcpy(newcopy, copiedquery);
if ((p = next_insert(newcopy + hostvarl)) == NULL)
{ {
/* /* We create an additional variable list here, so the same logic applies. */
* We have an argument but we dont have the matched up string struct variable desc_inlist;
* in the string struct descriptor *desc;
*/ struct descriptor_item *desc_item;
ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL); for (desc = all_descriptors; desc; desc = desc->next)
return false; {
if (strcmp(var->pointer, desc->name) == 0)
break;
}
if (desc == NULL)
{
ECPGraise(stmt->lineno, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, var->pointer);
return false;
}
desc_counter++;
for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
{
if (desc_item->num == desc_counter)
{
desc_inlist.type = ECPGt_char;
desc_inlist.value = desc_item->data;
desc_inlist.pointer = &(desc_item->data);
desc_inlist.varcharsize = strlen(desc_item->data);
desc_inlist.arrsize = 1;
desc_inlist.offset = 0;
desc_inlist.ind_type = ECPGt_NO_INDICATOR;
desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
if (!ECPGstore_input(stmt, &desc_inlist, &tobeinserted, &malloced))
return false;
break;
}
}
if (!desc_item) /* no more entries found in descriptor */
desc_counter = 0;
} }
else else
{ {
strcpy(p, tobeinserted); if (!ECPGstore_input(stmt, var, &tobeinserted, &malloced))
hostvarl = strlen(newcopy); return false;
}
if (tobeinserted)
{
/* /*
* The strange thing in the second argument is the rest of the * Now tobeinserted points to an area that is to be inserted at
* string from the old string * the first %s
*/ */
strcat(newcopy, if (!(newcopy = (char *) ECPGalloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno)))
copiedquery return false;
+ (p - newcopy)
+ sizeof("?") - 1 /* don't count the '\0' */ );
}
/* strcpy(newcopy, copiedquery);
* Now everything is safely copied to the newcopy. Lets free the if ((p = next_insert(newcopy + hostvarl)) == NULL)
* oldcopy and let the copiedquery get the var->value from the {
* newcopy. /*
*/ * We have an argument but we dont have the matched up string
if (malloced) * in the string
{ */
ECPGfree((char *) tobeinserted); ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
tobeinserted = NULL; return false;
} }
else
{
strcpy(p, tobeinserted);
hostvarl = strlen(newcopy);
/*
* The strange thing in the second argument is the rest of the
* string from the old string
*/
strcat(newcopy,
copiedquery
+ (p - newcopy)
+ sizeof("?") - 1 /* don't count the '\0' */ );
}
ECPGfree(copiedquery); /*
copiedquery = newcopy; * Now everything is safely copied to the newcopy. Lets free the
* oldcopy and let the copiedquery get the var->value from the
* newcopy.
*/
if (malloced)
{
ECPGfree((char *) tobeinserted);
tobeinserted = NULL;
}
var = var->next; ECPGfree(copiedquery);
copiedquery = newcopy;
}
if (desc_counter == 0)
var = var->next;
} }
/* Check if there are unmatched things left. */ /* Check if there are unmatched things left. */
......
...@@ -7,39 +7,42 @@ ...@@ -7,39 +7,42 @@
enum COMPAT_MODE enum COMPAT_MODE
{ {
ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX, ECPG_COMPAT_INFORMIX_SE ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX, ECPG_COMPAT_INFORMIX_SE
}; };
#define INFORMIX_MODE(X) ((X) == ECPG_COMPAT_INFORMIX || (X) == ECPG_COMPAT_INFORMIX_SE) #define INFORMIX_MODE(X) ((X) == ECPG_COMPAT_INFORMIX || (X) == ECPG_COMPAT_INFORMIX_SE)
enum ARRAY_TYPE enum ARRAY_TYPE
{ {
ECPG_ARRAY_NOT_SET, ECPG_ARRAY_ARRAY, ECPG_ARRAY_VECTOR, ECPG_ARRAY_NONE ECPG_ARRAY_NOT_SET, ECPG_ARRAY_ARRAY, ECPG_ARRAY_VECTOR, ECPG_ARRAY_NONE
}; };
/* Here are some methods used by the lib. */ /* Here are some methods used by the lib. */
/* Returns a pointer to a string containing a simple type name. */ /* Returns a pointer to a string containing a simple type name. */
void ECPGadd_mem(void *ptr, int lineno); void ECPGadd_mem (void *ptr, int lineno);
bool ECPGget_data(const PGresult *, int, int, int, enum ECPGttype type, bool ECPGget_data (const PGresult *, int, int, int, enum ECPGttype type,
enum ECPGttype, char *, char *, long, long, long, enum ARRAY_TYPE, enum COMPAT_MODE, bool); enum ECPGttype, char *, char *, long, long, long,
struct connection *ECPGget_connection(const char *); enum ARRAY_TYPE, enum COMPAT_MODE, bool);
char *ECPGalloc(long, int); struct connection *ECPGget_connection (const char *);
char *ECPGrealloc(void *, long, int); char *ECPGalloc (long, int);
void ECPGfree(void *); char *ECPGrealloc (void *, long, int);
bool ECPGinit(const struct connection *, const char *, const int); void ECPGfree (void *);
char *ECPGstrdup(const char *, int); bool ECPGinit (const struct connection *, const char *, const int);
const char *ECPGtype_name(enum ECPGttype); char *ECPGstrdup (const char *, int);
unsigned int ECPGDynamicType(Oid); const char *ECPGtype_name (enum ECPGttype);
void ECPGfree_auto_mem(void); unsigned int ECPGDynamicType (Oid);
void ECPGclear_auto_mem(void); void ECPGfree_auto_mem (void);
void ECPGclear_auto_mem (void);
struct descriptor *ecpggetdescp (int, char *);
/* A generic varchar type. */ /* A generic varchar type. */
struct ECPGgeneric_varchar struct ECPGgeneric_varchar
{ {
int len; int len;
char arr[1]; char arr[1];
}; };
/* /*
...@@ -48,64 +51,79 @@ struct ECPGgeneric_varchar ...@@ -48,64 +51,79 @@ struct ECPGgeneric_varchar
struct ECPGtype_information_cache struct ECPGtype_information_cache
{ {
struct ECPGtype_information_cache *next; struct ECPGtype_information_cache *next;
int oid; int oid;
bool isarray; bool isarray;
}; };
/* structure to store one statement */ /* structure to store one statement */
struct statement struct statement
{ {
int lineno; int lineno;
char *command; char *command;
struct connection *connection; struct connection *connection;
enum COMPAT_MODE compat; enum COMPAT_MODE compat;
bool force_indicator; bool force_indicator;
struct variable *inlist; struct variable *inlist;
struct variable *outlist; struct variable *outlist;
}; };
/* structure to store connections */ /* structure to store connections */
struct connection struct connection
{ {
char *name; char *name;
PGconn *connection; PGconn *connection;
bool committed; bool committed;
int autocommit; int autocommit;
struct ECPGtype_information_cache *cache_head; struct ECPGtype_information_cache *cache_head;
struct connection *next; struct connection *next;
}; };
/* structure to store descriptors */ /* structure to store descriptors */
struct descriptor struct descriptor
{ {
char *name; char *name;
PGresult *result; PGresult *result;
struct descriptor *next; struct descriptor *next;
int count;
struct descriptor_item *items;
};
extern struct descriptor *all_descriptors;
struct descriptor_item
{
int num;
char *data;
int indicator;
int length;
int precision;
int scale;
int type;
struct descriptor_item *next;
}; };
struct variable struct variable
{ {
enum ECPGttype type; enum ECPGttype type;
void *value; void *value;
void *pointer; void *pointer;
long varcharsize; long varcharsize;
long arrsize; long arrsize;
long offset; long offset;
enum ECPGttype ind_type; enum ECPGttype ind_type;
void *ind_value; void *ind_value;
void *ind_pointer; void *ind_pointer;
long ind_varcharsize; long ind_varcharsize;
long ind_arrsize; long ind_arrsize;
long ind_offset; long ind_offset;
struct variable *next; struct variable *next;
}; };
PGresult ** PGresult **ECPGdescriptor_lvalue (int line, const char *descriptor);
ECPGdescriptor_lvalue(int line, const char *descriptor);
bool ECPGstore_result(const PGresult *results, int act_field, bool ECPGstore_result (const PGresult * results, int act_field,
const struct statement * stmt, struct variable * var); const struct statement *stmt, struct variable *var);
/* SQLSTATE values generated or processed by ecpglib (intentionally /* SQLSTATE values generated or processed by ecpglib (intentionally
* not exported -- users should refer to the codes directly) */ * not exported -- users should refer to the codes directly) */
...@@ -133,4 +151,4 @@ bool ECPGstore_result(const PGresult *results, int act_field, ...@@ -133,4 +151,4 @@ bool ECPGstore_result(const PGresult *results, int act_field,
#define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR "YE000" #define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR "YE000"
#define ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY "YE001" #define ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY "YE001"
#endif /* _ECPG_LIB_EXTERN_H */ #endif /* _ECPG_LIB_EXTERN_H */
...@@ -76,6 +76,8 @@ void ECPGraise(int line, int code, const char *sqlstate, const char *str); ...@@ -76,6 +76,8 @@ void ECPGraise(int line, int code, const char *sqlstate, const char *str);
void ECPGraise_backend(int line, PGresult *result, PGconn *conn, int compat); void ECPGraise_backend(int line, PGresult *result, PGconn *conn, int compat);
bool ECPGget_desc_header(int, char *, int *); bool ECPGget_desc_header(int, char *, int *);
bool ECPGget_desc(int, char *, int,...); bool ECPGget_desc(int, char *, int,...);
bool ECPGset_desc_header(int, char *, int *);
bool ECPGset_desc(int, char *, int,...);
void ECPGset_noind_null(enum ECPGttype, void *); void ECPGset_noind_null(enum ECPGttype, void *);
bool ECPGis_noind_null(enum ECPGttype, void *); bool ECPGis_noind_null(enum ECPGttype, void *);
......
...@@ -58,9 +58,7 @@ ECPGnumeric_lvalue(FILE *f, char *name) ...@@ -58,9 +58,7 @@ ECPGnumeric_lvalue(FILE *f, char *name)
fputs(name, yyout); fputs(name, yyout);
break; break;
default: default:
snprintf(errortext, sizeof errortext, "variable %s: numeric type needed" mmerror(PARSE_ERROR, ET_ERROR, "variable %s: numeric type needed", name);
,name);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
break; break;
} }
} }
...@@ -120,8 +118,7 @@ drop_descriptor(char *name, char *connection) ...@@ -120,8 +118,7 @@ drop_descriptor(char *name, char *connection)
} }
} }
} }
snprintf(errortext, sizeof errortext, "unknown descriptor %s", name); mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor %s", name);
mmerror(PARSE_ERROR, ET_WARNING, errortext);
} }
struct descriptor struct descriptor
...@@ -143,8 +140,7 @@ lookup_descriptor(char *name, char *connection) ...@@ -143,8 +140,7 @@ lookup_descriptor(char *name, char *connection)
return i; return i;
} }
} }
snprintf(errortext, sizeof errortext, "unknown descriptor %s", name); mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor %s", name);
mmerror(PARSE_ERROR, ET_WARNING, errortext);
return NULL; return NULL;
} }
...@@ -153,16 +149,13 @@ output_get_descr_header(char *desc_name) ...@@ -153,16 +149,13 @@ output_get_descr_header(char *desc_name)
{ {
struct assignment *results; struct assignment *results;
fprintf(yyout, "{ ECPGget_desc_header(%d, %s, &(", yylineno, desc_name); fprintf(yyout, "{ ECPGget_desc_header(__LINE__, %s, &(", desc_name);
for (results = assignments; results != NULL; results = results->next) for (results = assignments; results != NULL; results = results->next)
{ {
if (results->value == ECPGd_count) if (results->value == ECPGd_count)
ECPGnumeric_lvalue(yyout, results->variable); ECPGnumeric_lvalue(yyout, results->variable);
else else
{ mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor header item '%d'", results->value);
snprintf(errortext, sizeof errortext, "unknown descriptor header item '%d'", results->value);
mmerror(PARSE_ERROR, ET_WARNING, errortext);
}
} }
drop_assignments(); drop_assignments();
...@@ -175,7 +168,7 @@ output_get_descr(char *desc_name, char *index) ...@@ -175,7 +168,7 @@ output_get_descr(char *desc_name, char *index)
{ {
struct assignment *results; struct assignment *results;
fprintf(yyout, "{ ECPGget_desc(%d, %s, %s,", yylineno, desc_name, index); fprintf(yyout, "{ ECPGget_desc(__LINE__, %s, %s,", desc_name, index);
for (results = assignments; results != NULL; results = results->next) for (results = assignments; results != NULL; results = results->next)
{ {
const struct variable *v = find_variable(results->variable); const struct variable *v = find_variable(results->variable);
...@@ -200,6 +193,116 @@ output_get_descr(char *desc_name, char *index) ...@@ -200,6 +193,116 @@ output_get_descr(char *desc_name, char *index)
whenever_action(2 | 1); whenever_action(2 | 1);
} }
void
output_set_descr_header(char *desc_name)
{
struct assignment *results;
fprintf(yyout, "{ ECPGset_desc_header(__LINE__, %s, &(", desc_name);
for (results = assignments; results != NULL; results = results->next)
{
if (results->value == ECPGd_count)
ECPGnumeric_lvalue(yyout, results->variable);
else
mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor header item '%d'", results->value);
}
drop_assignments();
fprintf(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(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:
mmerror(PARSE_ERROR, ET_FATAL, "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:
mmerror(PARSE_ERROR, ET_FATAL, "descriptor item %s cannot be set",
descriptor_item_name(results->value));
break;
case ECPGd_data:
case ECPGd_indicator:
case ECPGd_length:
case ECPGd_type:
fprintf(yyout, "%s,", get_dtype(results->value));
ECPGdump_a_type(yyout, v->name, v->type, NULL, NULL, NULL, NULL, make_str("0"), NULL, NULL);
break;
default:
;
}
}
drop_assignments();
fputs("ECPGd_EODT);\n", yyout);
whenever_action(2 | 1);
}
/* I consider dynamic allocation overkill since at most two descriptor /* I consider dynamic allocation overkill since at most two descriptor
variables are possible per statement. (input and output descriptor) variables are possible per statement. (input and output descriptor)
And descriptors are no normal variables, so they don't belong into And descriptors are no normal variables, so they don't belong into
...@@ -211,11 +314,10 @@ struct variable * ...@@ -211,11 +314,10 @@ struct variable *
descriptor_variable(const char *name, int input) descriptor_variable(const char *name, int input)
{ {
static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN]; static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN];
static const struct ECPGtype descriptor_type = static const struct ECPGtype descriptor_type = { ECPGt_descriptor, 0 };
{ECPGt_descriptor, 0}; static const struct variable varspace[2] = {
static const struct variable varspace[2] = { descriptor_names[0], (struct ECPGtype *) & descriptor_type, 0, NULL },
{{descriptor_names[0], (struct ECPGtype *) & descriptor_type, 0, NULL}, { descriptor_names[1], (struct ECPGtype *) & descriptor_type, 0, NULL }
{descriptor_names[1], (struct ECPGtype *) & descriptor_type, 0, NULL}
}; };
strncpy(descriptor_names[input], name, MAX_DESCRIPTOR_NAMELEN); strncpy(descriptor_names[input], name, MAX_DESCRIPTOR_NAMELEN);
......
...@@ -25,8 +25,7 @@ extern char *descriptor_name; ...@@ -25,8 +25,7 @@ extern char *descriptor_name;
extern char *connection; extern char *connection;
extern char *input_filename; extern char *input_filename;
extern char *yytext, extern char *yytext,
*token_start, *token_start;
errortext[128];
#ifdef YYDEBUG #ifdef YYDEBUG
extern int yydebug; extern int yydebug;
...@@ -63,11 +62,13 @@ extern int yylex(void); ...@@ -63,11 +62,13 @@ extern int yylex(void);
extern void yyerror(char *); extern void yyerror(char *);
extern void *mm_alloc(size_t), *mm_realloc(void *, size_t); extern void *mm_alloc(size_t), *mm_realloc(void *, size_t);
extern char *mm_strdup(const char *); extern char *mm_strdup(const char *);
extern void mmerror(int, enum errortype, char *); extern void mmerror(int, enum errortype, char *, ...);
extern ScanKeyword *ScanECPGKeywordLookup(char *); extern ScanKeyword *ScanECPGKeywordLookup(char *);
extern ScanKeyword *ScanCKeywordLookup(char *); extern ScanKeyword *ScanCKeywordLookup(char *);
extern void output_get_descr_header(char *); extern void output_get_descr_header(char *);
extern void output_get_descr(char *, char *); extern void output_get_descr(char *, char *);
extern void output_set_descr_header(char *);
extern void output_set_descr(char *, char *);
extern void push_assignment(char *, enum ECPGdtype); extern void push_assignment(char *, enum ECPGdtype);
extern struct variable *find_variable(char *); extern struct variable *find_variable(char *);
extern void whenever_action(int); extern void whenever_action(int);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.128 2004/05/05 15:03:04 meskes Exp $ * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.129 2004/06/30 15:01:57 meskes Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1164,10 +1164,7 @@ parse_include(void) ...@@ -1164,10 +1164,7 @@ parse_include(void)
} }
} }
if (!yyin) if (!yyin)
{ mmerror(NO_INCLUDE_FILE, ET_FATAL, "Cannot open include file %s in line %d\n", yytext, yylineno);
snprintf(errortext, sizeof(errortext), "Cannot open include file %s in line %d\n", yytext, yylineno);
mmerror(NO_INCLUDE_FILE, ET_FATAL, errortext);
}
input_filename = mm_strdup(inc_file); input_filename = mm_strdup(inc_file);
yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE )); yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
......
/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.289 2004/06/27 12:28:42 meskes Exp $ */ /* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.290 2004/06/30 15:01:57 meskes Exp $ */
/* Copyright comment */ /* Copyright comment */
%{ %{
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
int struct_level = 0; int struct_level = 0;
int braces_open; /* brace level counter */ int braces_open; /* brace level counter */
int ecpg_informix_var = 0; int ecpg_informix_var = 0;
char errortext[128];
char *connection = NULL; char *connection = NULL;
char *input_filename = NULL; char *input_filename = NULL;
...@@ -52,19 +51,37 @@ static struct inf_compat_val ...@@ -52,19 +51,37 @@ static struct inf_compat_val
* Handle parsing errors and warnings * Handle parsing errors and warnings
*/ */
void void
mmerror(int error_code, enum errortype type, char * error) mmerror(int error_code, enum errortype type, char * error, ...)
{ {
va_list ap;
fprintf(stderr, "%s:%d: ", input_filename, yylineno);
switch(type)
{
case ET_WARNING:
fprintf(stderr, "WARNING: ");
break;
case ET_ERROR:
case ET_FATAL:
fprintf(stderr, "ERROR: ");
break;
}
va_start(ap, error);
vfprintf(stderr, error, ap);
va_end(ap);
fprintf(stderr, "\n");
switch(type) switch(type)
{ {
case ET_WARNING: case ET_WARNING:
fprintf(stderr, "%s:%d: WARNING: %s\n", input_filename, yylineno, error);
break; break;
case ET_ERROR: case ET_ERROR:
fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
ret_value = error_code; ret_value = error_code;
break; break;
case ET_FATAL: case ET_FATAL:
fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
exit(error_code); exit(error_code);
} }
} }
...@@ -261,8 +278,7 @@ add_additional_variables(char *name, bool insert) ...@@ -261,8 +278,7 @@ add_additional_variables(char *name, bool insert)
if (ptr == NULL) if (ptr == NULL)
{ {
snprintf(errortext, sizeof(errortext), "trying to access an undeclared cursor %s\n", name); mmerror(PARSE_ERROR, ET_ERROR, "trying to access an undeclared cursor %s\n", name);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
return NULL; return NULL;
} }
if (insert) if (insert)
...@@ -540,14 +556,14 @@ add_additional_variables(char *name, bool insert) ...@@ -540,14 +556,14 @@ add_additional_variables(char *name, bool insert)
%type <str> col_name_keyword func_name_keyword precision opt_scale %type <str> col_name_keyword func_name_keyword precision opt_scale
%type <str> ECPGTypeName using_list ECPGColLabelCommon UsingConst %type <str> ECPGTypeName using_list ECPGColLabelCommon UsingConst
%type <str> inf_val_list inf_col_list using_descriptor into_descriptor %type <str> inf_val_list inf_col_list using_descriptor into_descriptor
%type <str> ecpg_into_using prepared_name struct_union_type_with_symbol %type <str> prepared_name struct_union_type_with_symbol
%type <str> ECPGunreserved ECPGunreserved_interval cvariable %type <str> ECPGunreserved ECPGunreserved_interval cvariable
%type <str> AlterOwnerStmt OptTableSpaceOwner CreateTableSpaceStmt %type <str> AlterOwnerStmt OptTableSpaceOwner CreateTableSpaceStmt
%type <str> DropTableSpaceStmt indirection indirection_el %type <str> DropTableSpaceStmt indirection indirection_el ECPGSetDescriptorHeader
%type <struct_union> s_struct_union_symbol %type <struct_union> s_struct_union_symbol
%type <descriptor> ECPGGetDescriptor %type <descriptor> ECPGGetDescriptor ECPGSetDescriptor
%type <type_enum> simple_type signed_type unsigned_type %type <type_enum> simple_type signed_type unsigned_type
...@@ -811,6 +827,19 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); } ...@@ -811,6 +827,19 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); }
whenever_action(2); whenever_action(2);
free($1); free($1);
} }
| ECPGSetDescriptor
{
lookup_descriptor($1.name, connection);
output_set_descr($1.name, $1.str);
free($1.name);
free($1.str);
}
| ECPGSetDescriptorHeader
{
lookup_descriptor($1, connection);
output_set_descr_header($1);
free($1);
}
| ECPGTypedef | ECPGTypedef
{ {
if (connection) if (connection)
...@@ -1925,22 +1954,22 @@ TruncateStmt: TRUNCATE opt_table qualified_name ...@@ -1925,22 +1954,22 @@ TruncateStmt: TRUNCATE opt_table qualified_name
* embedded SQL implementations. So we accept their syntax as well and * embedded SQL implementations. So we accept their syntax as well and
* translate it to the PGSQL syntax. */ * translate it to the PGSQL syntax. */
FetchStmt: FETCH fetch_direction from_in name ecpg_into_using FetchStmt: FETCH fetch_direction from_in name ecpg_into
{ {
add_additional_variables($4, false); add_additional_variables($4, false);
$$ = cat_str(4, make_str("fetch"), $2, $3, $4); $$ = cat_str(4, make_str("fetch"), $2, $3, $4);
} }
| FETCH fetch_direction name ecpg_into_using | FETCH fetch_direction name ecpg_into
{ {
add_additional_variables($3, false); add_additional_variables($3, false);
$$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3); $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3);
} }
| FETCH from_in name ecpg_into_using | FETCH from_in name ecpg_into
{ {
add_additional_variables($3, false); add_additional_variables($3, false);
$$ = cat_str(3, make_str("fetch"), $2, $3); $$ = cat_str(3, make_str("fetch"), $2, $3);
} }
| FETCH name ecpg_into_using | FETCH name ecpg_into
{ {
add_additional_variables($2, false); add_additional_variables($2, false);
$$ = cat2_str(make_str("fetch"), $2); $$ = cat2_str(make_str("fetch"), $2);
...@@ -2895,11 +2924,8 @@ DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt ...@@ -2895,11 +2924,8 @@ DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt
for (ptr = cur; ptr != NULL; ptr = ptr->next) for (ptr = cur; ptr != NULL; ptr = ptr->next)
{ {
if (strcmp($2, ptr->name) == 0) if (strcmp($2, ptr->name) == 0)
{ /* re-definition is a bug */
/* re-definition is a bug */ mmerror(PARSE_ERROR, ET_ERROR, "cursor %s already defined", $2);
snprintf(errortext, sizeof(errortext), "cursor %s already defined", $2);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
} }
this = (struct cursor *) mm_alloc(sizeof(struct cursor)); this = (struct cursor *) mm_alloc(sizeof(struct cursor));
...@@ -2987,7 +3013,7 @@ into_clause: INTO OptTempTableName ...@@ -2987,7 +3013,7 @@ into_clause: INTO OptTempTableName
FoundInto = 1; FoundInto = 1;
$$= cat2_str(make_str("into"), $2); $$= cat2_str(make_str("into"), $2);
} }
| ecpg_into_using { $$ = EMPTY; } | ecpg_into { $$ = EMPTY; }
| /*EMPTY*/ { $$ = EMPTY; } | /*EMPTY*/ { $$ = EMPTY; }
; ;
...@@ -4246,11 +4272,7 @@ connection_target: database_name opt_server opt_port ...@@ -4246,11 +4272,7 @@ connection_target: database_name opt_server opt_port
{ {
/* old style: dbname[@server][:port] */ /* old style: dbname[@server][:port] */
if (strlen($2) > 0 && *($2) != '@') if (strlen($2) > 0 && *($2) != '@')
{ mmerror(PARSE_ERROR, ET_ERROR, "Expected '@', found '%s'", $2);
snprintf(errortext, sizeof(errortext),
"Expected '@', found '%s'", $2);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
$$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\"")); $$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\""));
} }
...@@ -4258,24 +4280,15 @@ connection_target: database_name opt_server opt_port ...@@ -4258,24 +4280,15 @@ connection_target: database_name opt_server opt_port
{ {
/* new style: <tcp|unix>:postgresql://server[:port][/dbname] */ /* new style: <tcp|unix>:postgresql://server[:port][/dbname] */
if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql")) != 0) if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql")) != 0)
{ mmerror(PARSE_ERROR, ET_ERROR, "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported");
snprintf(errortext, sizeof(errortext), "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported");
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
if (strncmp($3, "//", strlen("//")) != 0) if (strncmp($3, "//", strlen("//")) != 0)
{ mmerror(PARSE_ERROR, ET_ERROR, "Expected '://', found '%s'", $3);
snprintf(errortext, sizeof(errortext), "Expected '://', found '%s'", $3);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
if (strncmp($1, "unix", strlen("unix")) == 0 && if (strncmp($1, "unix", strlen("unix")) == 0 &&
strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 && strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 &&
strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0) strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0)
{ mmerror(PARSE_ERROR, ET_ERROR, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//"));
snprintf(errortext, sizeof(errortext), "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//"));
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
$$ = make3_str(make3_str(make_str("\""), $1, make_str(":")), $3, make3_str(make3_str($4, make_str("/"), $6), $7, make_str("\""))); $$ = make3_str(make3_str(make_str("\""), $1, make_str(":")), $3, make3_str(make3_str($4, make_str("/"), $6), $7, make_str("\"")));
} }
...@@ -4295,16 +4308,10 @@ connection_target: database_name opt_server opt_port ...@@ -4295,16 +4308,10 @@ connection_target: database_name opt_server opt_port
db_prefix: ident cvariable db_prefix: ident cvariable
{ {
if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0) if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
{ mmerror(PARSE_ERROR, ET_ERROR, "Expected 'postgresql', found '%s'", $2);
snprintf(errortext, sizeof(errortext), "Expected 'postgresql', found '%s'", $2);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0) if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0)
{ mmerror(PARSE_ERROR, ET_ERROR, "Illegal connection type %s", $1);
snprintf(errortext, sizeof(errortext), "Illegal connection type %s", $1);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
$$ = make3_str($1, make_str(":"), $2); $$ = make3_str($1, make_str(":"), $2);
} }
...@@ -4313,10 +4320,7 @@ db_prefix: ident cvariable ...@@ -4313,10 +4320,7 @@ db_prefix: ident cvariable
server: Op server_name server: Op server_name
{ {
if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0) if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0)
{ mmerror(PARSE_ERROR, ET_ERROR, "Expected '@' or '://', found '%s'", $1);
snprintf(errortext, sizeof(errortext), "Expected '@' or '://', found '%s'", $1);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
$$ = make2_str($1, $2); $$ = make2_str($1, $2);
} }
...@@ -4421,10 +4425,7 @@ opt_options: Op ColId ...@@ -4421,10 +4425,7 @@ opt_options: Op ColId
mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
if (strcmp($1, "?") != 0) if (strcmp($1, "?") != 0)
{ mmerror(PARSE_ERROR, ET_ERROR, "unrecognised token '%s'", $1);
snprintf(errortext, sizeof(errortext), "unrecognised token '%s'", $1);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
$$ = make2_str(make_str("?"), $2); $$ = make2_str(make_str("?"), $2);
} }
...@@ -4443,11 +4444,8 @@ ECPGCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR prepared_name ...@@ -4443,11 +4444,8 @@ ECPGCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR prepared_name
for (ptr = cur; ptr != NULL; ptr = ptr->next) for (ptr = cur; ptr != NULL; ptr = ptr->next)
{ {
if (strcmp($2, ptr->name) == 0) if (strcmp($2, ptr->name) == 0)
{ /* re-definition is a bug */
/* re-definition is a bug */ mmerror(PARSE_ERROR, ET_ERROR, "cursor %s already defined", $2);
snprintf(errortext, sizeof(errortext), "cursor %s already defined", $2);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
} }
this = (struct cursor *) mm_alloc(sizeof(struct cursor)); this = (struct cursor *) mm_alloc(sizeof(struct cursor));
...@@ -4595,11 +4593,8 @@ type_declaration: S_TYPEDEF ...@@ -4595,11 +4593,8 @@ type_declaration: S_TYPEDEF
for (ptr = types; ptr != NULL; ptr = ptr->next) for (ptr = types; ptr != NULL; ptr = ptr->next)
{ {
if (strcmp($5, ptr->name) == 0) if (strcmp($5, ptr->name) == 0)
{
/* re-definition is a bug */ /* re-definition is a bug */
snprintf(errortext, sizeof(errortext), "Type %s already defined", $5); mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", $5);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
} }
adjust_array($3.type_enum, &dimension, &length, $3.type_dimension, $3.type_index, *$4?1:0, true); adjust_array($3.type_enum, &dimension, &length, $3.type_dimension, $3.type_index, *$4?1:0, true);
...@@ -4912,11 +4907,8 @@ struct_union_type_with_symbol: s_struct_union_symbol ...@@ -4912,11 +4907,8 @@ struct_union_type_with_symbol: s_struct_union_symbol
for (ptr = types; ptr != NULL; ptr = ptr->next) for (ptr = types; ptr != NULL; ptr = ptr->next)
{ {
if (strcmp(su_type.type_str, ptr->name) == 0) if (strcmp(su_type.type_str, ptr->name) == 0)
{
/* re-definition is a bug */ /* re-definition is a bug */
snprintf(errortext, sizeof(errortext), "Type %s already defined", su_type.type_str); mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", su_type.type_str);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
} }
this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
...@@ -5215,28 +5207,25 @@ opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; } ...@@ -5215,28 +5207,25 @@ opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; }
; ;
ecpg_using: USING using_list { $$ = EMPTY; } ecpg_using: USING using_list { $$ = EMPTY; }
| using_descriptor { $$ = $1; }
; ;
using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
{ {
add_variable_to_head(&argsresult, descriptor_variable($4,0), &no_indicator); add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator);
$$ = EMPTY; $$ = EMPTY;
} }
; ;
into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
{ {
add_variable_to_head(&argsresult, descriptor_variable($4,0), &no_indicator); add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator);
$$ = EMPTY; $$ = EMPTY;
} }
; ;
opt_sql: /*EMPTY*/ | SQL_SQL; opt_sql: /*EMPTY*/ | SQL_SQL;
ecpg_into_using: ecpg_into { $$ = EMPTY; }
| using_descriptor { $$ = $1; }
;
ecpg_into: INTO into_list { $$ = EMPTY; } ecpg_into: INTO into_list { $$ = EMPTY; }
| into_descriptor { $$ = $1; } | into_descriptor { $$ = $1; }
; ;
...@@ -5295,8 +5284,19 @@ opt_output: SQL_OUTPUT { $$ = make_str("output"); } ...@@ -5295,8 +5284,19 @@ opt_output: SQL_OUTPUT { $$ = make_str("output"); }
/* /*
* dynamic SQL: descriptor based access * dynamic SQL: descriptor based access
* written by Christof Petig <christof.petig@wtal.de> * written by Christof Petig <christof.petig@wtal.de>
* and Peter Eisentraut <peter.eisentraut@credativ.de>
*/ */
/*
* allocate a descriptor
*/
ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
{
add_descriptor($3,connection);
$$ = $3;
};
/* /*
* deallocate a descriptor * deallocate a descriptor
*/ */
...@@ -5308,63 +5308,85 @@ ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar ...@@ -5308,63 +5308,85 @@ ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
; ;
/* /*
* allocate a descriptor * manipulate a descriptor header
*/ */
ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
{
add_descriptor($3,connection);
$$ = $3;
};
/* ECPGGetDescriptorHeader: GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems
* read from descriptor { $$ = $3; }
*/ ;
ECPGGetDescHeaderItem: cvariable '=' desc_header_item ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
| ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem
;
ECPGGetDescHeaderItem: CVARIABLE '=' desc_header_item
{ push_assignment($1, $3); } { push_assignment($1, $3); }
; ;
desc_header_item: SQL_COUNT { $$ = ECPGd_count; }
ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems
{ $$ = $3; }
ECPGSetDescHeaderItems: ECPGSetDescHeaderItem
| ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem
;
ECPGSetDescHeaderItem: desc_header_item '=' CVARIABLE
{ push_assignment($3, $1); }
; ;
ECPGGetDescItem: cvariable '=' descriptor_item { push_assignment($1, $3); };
descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } desc_header_item: SQL_COUNT { $$ = ECPGd_count; }
| SQL_DATA { $$ = ECPGd_data; }
| SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; }
| SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; }
| SQL_INDICATOR { $$ = ECPGd_indicator; }
| SQL_KEY_MEMBER { $$ = ECPGd_key_member; }
| SQL_LENGTH { $$ = ECPGd_length; }
| SQL_NAME { $$ = ECPGd_name; }
| SQL_NULLABLE { $$ = ECPGd_nullable; }
| SQL_OCTET_LENGTH { $$ = ECPGd_octet; }
| PRECISION { $$ = ECPGd_precision; }
| SQL_RETURNED_LENGTH { $$ = ECPGd_length; }
| SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; }
| SQL_SCALE { $$ = ECPGd_scale; }
| TYPE_P { $$ = ECPGd_type; }
; ;
ECPGGetDescHeaderItems: ECPGGetDescHeaderItem /*
| ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem * manipulate a descriptor
*/
ECPGGetDescriptor: GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE CVARIABLE ECPGGetDescItems
{ $$.str = $5; $$.name = $3; }
| GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGGetDescItems
{ $$.str = $5; $$.name = $3; }
; ;
ECPGGetDescItems: ECPGGetDescItem ECPGGetDescItems: ECPGGetDescItem
| ECPGGetDescItems ',' ECPGGetDescItem | ECPGGetDescItems ',' ECPGGetDescItem
; ;
ECPGGetDescriptorHeader: GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescItem: CVARIABLE '=' descriptor_item { push_assignment($1, $3); };
ECPGGetDescHeaderItems
{ $$ = $3; }
;
ECPGGetDescriptor: GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE cvariable ECPGGetDescItems ECPGSetDescriptor: SET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE CVARIABLE ECPGSetDescItems
{ $$.str = $5; $$.name = $3; } { $$.str = $5; $$.name = $3; }
| GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGGetDescItems | SET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGSetDescItems
{ $$.str = $5; $$.name = $3; } { $$.str = $5; $$.name = $3; }
; ;
ECPGSetDescItems: ECPGSetDescItem
| ECPGSetDescItems ',' ECPGSetDescItem
;
ECPGSetDescItem: descriptor_item '=' CVARIABLE { push_assignment($3, $1); };
descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; }
| SQL_DATA { $$ = ECPGd_data; }
| SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; }
| SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; }
| SQL_INDICATOR { $$ = ECPGd_indicator; }
| SQL_KEY_MEMBER { $$ = ECPGd_key_member; }
| SQL_LENGTH { $$ = ECPGd_length; }
| SQL_NAME { $$ = ECPGd_name; }
| SQL_NULLABLE { $$ = ECPGd_nullable; }
| SQL_OCTET_LENGTH { $$ = ECPGd_octet; }
| PRECISION { $$ = ECPGd_precision; }
| SQL_RETURNED_LENGTH { $$ = ECPGd_length; }
| SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; }
| SQL_SCALE { $$ = ECPGd_scale; }
| TYPE_P { $$ = ECPGd_type; }
;
/* /*
* for compatibility with ORACLE we will also allow the keyword RELEASE * for compatibility with ORACLE we will also allow the keyword RELEASE
* after a transaction statement to disconnect from the database. * after a transaction statement to disconnect from the database.
...@@ -5431,11 +5453,8 @@ ECPGTypedef: TYPE_P ...@@ -5431,11 +5453,8 @@ ECPGTypedef: TYPE_P
for (ptr = types; ptr != NULL; ptr = ptr->next) for (ptr = types; ptr != NULL; ptr = ptr->next)
{ {
if (strcmp($3, ptr->name) == 0) if (strcmp($3, ptr->name) == 0)
{
/* re-definition is a bug */ /* re-definition is a bug */
snprintf(errortext, sizeof(errortext), "Type %s already defined", $3); mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", $3);
mmerror(PARSE_ERROR, ET_ERROR, errortext);
}
} }
adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0, false); adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0, false);
......
...@@ -195,8 +195,7 @@ get_type(enum ECPGttype type) ...@@ -195,8 +195,7 @@ get_type(enum ECPGttype type)
return ("ECPGt_timestamp"); return ("ECPGt_timestamp");
break; break;
default: default:
sprintf(errortext, "illegal variable type %d\n", type); mmerror(PARSE_ERROR, ET_ERROR, "illegal variable type %d\n", type);
yyerror(errortext);
} }
return NULL; return NULL;
...@@ -538,8 +537,7 @@ ECPGfree_type(struct ECPGtype * type) ...@@ -538,8 +537,7 @@ ECPGfree_type(struct ECPGtype * type)
ECPGfree_struct_member(type->u.members); ECPGfree_struct_member(type->u.members);
break; break;
default: default:
sprintf(errortext, "illegal variable type %d\n", type->type); mmerror(PARSE_ERROR, ET_ERROR, "illegal variable type %d\n", type->type);
yyerror(errortext);
break; break;
} }
} }
...@@ -598,8 +596,7 @@ get_dtype(enum ECPGdtype type) ...@@ -598,8 +596,7 @@ get_dtype(enum ECPGdtype type)
case ECPGd_cardinality: case ECPGd_cardinality:
return ("ECPGd_cardinality"); return ("ECPGd_cardinality");
default: default:
sprintf(errortext, "illegal descriptor item %d\n", type); mmerror(PARSE_ERROR, ET_ERROR, "illegal descriptor item %d\n", type);
yyerror(errortext);
} }
return NULL; return NULL;
......
...@@ -84,10 +84,7 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member * members, in ...@@ -84,10 +84,7 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member * members, in
case '\0': /* found the end, but this time it has to case '\0': /* found the end, but this time it has to
* be an array element */ * be an array element */
if (members->type->type != ECPGt_array) if (members->type->type != ECPGt_array)
{ mmerror(PARSE_ERROR, ET_FATAL, "incorrectly formed variable %s", name);
snprintf(errortext, sizeof(errortext), "incorrectly formed variable %s", name);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
}
switch (members->type->u.element->type) switch (members->type->u.element->type)
{ {
...@@ -110,8 +107,7 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member * members, in ...@@ -110,8 +107,7 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member * members, in
return (find_struct_member(name, end, members->type->u.members, brace_level)); return (find_struct_member(name, end, members->type->u.members, brace_level));
break; break;
default: default:
snprintf(errortext, sizeof(errortext), "incorrectly formed variable %s", name); mmerror(PARSE_ERROR, ET_FATAL, "incorrectly formed variable %s", name);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
break; break;
} }
} }
...@@ -134,16 +130,10 @@ find_struct(char *name, char *next, char *end) ...@@ -134,16 +130,10 @@ find_struct(char *name, char *next, char *end)
if (c == '-') if (c == '-')
{ {
if (p->type->type != ECPGt_array) if (p->type->type != ECPGt_array)
{ mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer", name);
snprintf(errortext, sizeof(errortext), "variable %s is not a pointer", name);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
}
if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union) if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
{ mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer to a structure or a union", name);
snprintf(errortext, sizeof(errortext), "variable %s is not a pointer to a structure or a union", name);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
}
/* restore the name, we will need it later */ /* restore the name, we will need it later */
*next = c; *next = c;
...@@ -155,10 +145,7 @@ find_struct(char *name, char *next, char *end) ...@@ -155,10 +145,7 @@ find_struct(char *name, char *next, char *end)
if (next == end) if (next == end)
{ {
if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union) if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
{ mmerror(PARSE_ERROR, ET_FATAL, "variable %s is neither a structure nor a union", name);
snprintf(errortext, sizeof(errortext), "variable %s is neither a structure nor a union", name);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
}
/* restore the name, we will need it later */ /* restore the name, we will need it later */
*next = c; *next = c;
...@@ -168,16 +155,10 @@ find_struct(char *name, char *next, char *end) ...@@ -168,16 +155,10 @@ find_struct(char *name, char *next, char *end)
else else
{ {
if (p->type->type != ECPGt_array) if (p->type->type != ECPGt_array)
{ mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not an array", name);
snprintf(errortext, sizeof(errortext), "variable %s is not an array", name);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
}
if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union) if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
{ mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer to a structure or a union", name);
snprintf(errortext, sizeof(errortext), "variable %s is not a pointer to a structure or a union", name);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
}
/* restore the name, we will need it later */ /* restore the name, we will need it later */
*next = c; *next = c;
...@@ -243,10 +224,8 @@ find_variable(char *name) ...@@ -243,10 +224,8 @@ find_variable(char *name)
*next = '\0'; *next = '\0';
p = find_simple(name); p = find_simple(name);
if (p == NULL) if (p == NULL)
{ mmerror(PARSE_ERROR, ET_FATAL, "The variable %s is not declared", name);
snprintf(errortext, sizeof(errortext), "The variable %s is not declared", name);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
}
*next = c; *next = c;
switch (p->type->u.element->type) switch (p->type->u.element->type)
{ {
...@@ -267,10 +246,7 @@ find_variable(char *name) ...@@ -267,10 +246,7 @@ find_variable(char *name)
p = find_simple(name); p = find_simple(name);
if (p == NULL) if (p == NULL)
{ mmerror(PARSE_ERROR, ET_FATAL, "The variable %s is not declared", name);
snprintf(errortext, sizeof(errortext), "The variable %s is not declared", name);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
}
return (p); return (p);
} }
...@@ -490,10 +466,7 @@ get_typedef(char *name) ...@@ -490,10 +466,7 @@ get_typedef(char *name)
for (this = types; this && strcmp(this->name, name); this = this->next); for (this = types; this && strcmp(this->name, name); this = this->next);
if (!this) if (!this)
{ mmerror(PARSE_ERROR, ET_FATAL, "invalid datatype '%s'", name);
snprintf(errortext, sizeof(errortext), "invalid datatype '%s'", name);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
}
return (this); return (this);
} }
...@@ -521,10 +494,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty ...@@ -521,10 +494,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
} }
if (pointer_len > 2) if (pointer_len > 2)
{ mmerror(PARSE_ERROR, ET_FATAL, "No multilevel (more than 2) pointer supported %d", pointer_len);
snprintf(errortext, sizeof(errortext), "No multilevel (more than 2) pointer supported %d", pointer_len);
mmerror(PARSE_ERROR, ET_FATAL, errortext);
}
if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char) if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char)
mmerror(PARSE_ERROR, ET_FATAL, "No pointer to pointer supported for this type"); mmerror(PARSE_ERROR, ET_FATAL, "No pointer to pointer supported for this type");
......
EXEC SQL WHENEVER SQLERROR SQLPRINT;
int
main()
{
EXEC SQL BEGIN DECLARE SECTION;
char *stmt1 = "INSERT INTO test1 VALUES (?, ?)";
char *stmt2 = "SELECT * from test1 where a = ? and b = ?";
int val1 = 1;
char val2[] = "one", val2output[] = "AAA";
int val1output = 2, val2i = 0;
int val2null = 1;
EXEC SQL END DECLARE SECTION;
FILE *dbgs;
if ((dbgs = fopen("log", "w")) != NULL)
ECPGdebug(1, dbgs);
EXEC SQL ALLOCATE DESCRIPTOR indesc;
EXEC SQL ALLOCATE DESCRIPTOR outdesc;
EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = :val1;
EXEC SQL SET DESCRIPTOR indesc VALUE 2 INDICATOR = :val2i, DATA = :val2;
EXEC SQL CONNECT TO mm;
EXEC SQL CREATE TABLE test1 (a int, b text);
EXEC SQL PREPARE foo1 FROM :stmt1;
EXEC SQL PREPARE foo2 FROM :stmt2;
EXEC SQL EXECUTE foo1 USING DESCRIPTOR indesc;
//EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = 2;
EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = :val1output;
EXEC SQL SET DESCRIPTOR indesc VALUE 2 INDICATOR = :val2null, DATA = :val2;
EXEC SQL EXECUTE foo1 USING DESCRIPTOR indesc;
EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = :val1;
EXEC SQL SET DESCRIPTOR indesc VALUE 2 INDICATOR = :val2i, DATA = :val2;
EXEC SQL EXECUTE foo2 USING DESCRIPTOR indesc INTO DESCRIPTOR outdesc;
EXEC SQL GET DESCRIPTOR outdesc VALUE 1 :val2output = DATA;
printf("output = %s\n", val2output);
EXEC SQL DECLARE c CURSOR FOR foo2;
EXEC SQL OPEN c USING DESCRIPTOR indesc;
EXEC SQL FETCH next FROM c INTO :val1output, :val2output;
printf("val1=%d val2=%s\n", val1output, val2output);
EXEC SQL CLOSE c;
EXEC SQL SELECT * INTO :val1output, :val2output FROM test1 where a = 2;
printf("val1=%d val2=%s\n", val1output, val2output);
EXEC SQL DROP TABLE test1;
EXEC SQL DISCONNECT;
EXEC SQL DEALLOCATE DESCRIPTOR indesc;
EXEC SQL DEALLOCATE DESCRIPTOR outdesc;
if (dbgs != NULL)
fclose(dbgs);
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment