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.
This commit is contained in:
parent
c7beffcc1d
commit
90326c01c9
@ -1,6 +1,6 @@
|
||||
/* 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
|
||||
@ -110,6 +110,51 @@ get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
|
||||
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
|
||||
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,...)
|
||||
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
|
||||
ECPGdeallocate_desc(int line, const char *name)
|
||||
{
|
||||
@ -425,6 +588,7 @@ ECPGallocate_desc(int line, const char *name)
|
||||
ECPGfree(new);
|
||||
return false;
|
||||
}
|
||||
new->items = NULL;
|
||||
new->result = PQmakeEmptyPGresult(NULL, 0);
|
||||
if (!new->result)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $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.
|
||||
@ -1026,6 +1026,9 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
|
||||
free(str);
|
||||
}
|
||||
break;
|
||||
|
||||
case ECPGt_descriptor:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Not implemented yet */
|
||||
@ -1046,6 +1049,7 @@ ECPGexecute(struct statement * stmt)
|
||||
PGresult *results;
|
||||
PGnotify *notify;
|
||||
struct variable *var;
|
||||
int desc_counter = 0;
|
||||
|
||||
copiedquery = ECPGstrdup(stmt->command, stmt->lineno);
|
||||
|
||||
@ -1056,64 +1060,116 @@ ECPGexecute(struct statement * stmt)
|
||||
* so on.
|
||||
*/
|
||||
var = stmt->inlist;
|
||||
|
||||
while (var)
|
||||
{
|
||||
char *newcopy = NULL;
|
||||
const char *tobeinserted = NULL;
|
||||
const char *tobeinserted;
|
||||
char *p;
|
||||
bool malloced = FALSE;
|
||||
int hostvarl = 0;
|
||||
bool malloced = FALSE;
|
||||
int hostvarl = 0;
|
||||
|
||||
if (!ECPGstore_input(stmt, var, &tobeinserted, &malloced))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Now tobeinserted points to an area that is to be inserted at
|
||||
* the first %s
|
||||
*/
|
||||
if (!(newcopy = (char *) ECPGalloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno)))
|
||||
return false;
|
||||
|
||||
strcpy(newcopy, copiedquery);
|
||||
if ((p = next_insert(newcopy + hostvarl)) == NULL)
|
||||
tobeinserted = NULL;
|
||||
/* A descriptor is a special case since it contains many variables but is listed only once. */
|
||||
if (var->type == ECPGt_descriptor)
|
||||
{
|
||||
/*
|
||||
* We have an argument but we dont have the matched up string
|
||||
* in the string
|
||||
*/
|
||||
ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
|
||||
return false;
|
||||
/* We create an additional variable list here, so the same logic applies. */
|
||||
struct variable desc_inlist;
|
||||
struct descriptor *desc;
|
||||
struct descriptor_item *desc_item;
|
||||
for (desc = all_descriptors; desc; desc = desc->next)
|
||||
{
|
||||
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
|
||||
{
|
||||
strcpy(p, tobeinserted);
|
||||
hostvarl = strlen(newcopy);
|
||||
if (!ECPGstore_input(stmt, var, &tobeinserted, &malloced))
|
||||
return false;
|
||||
}
|
||||
if (tobeinserted)
|
||||
{
|
||||
/*
|
||||
* Now tobeinserted points to an area that is to be inserted at
|
||||
* the first %s
|
||||
*/
|
||||
if (!(newcopy = (char *) ECPGalloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno)))
|
||||
return false;
|
||||
|
||||
strcpy(newcopy, copiedquery);
|
||||
if ((p = next_insert(newcopy + hostvarl)) == NULL)
|
||||
{
|
||||
/*
|
||||
* We have an argument but we dont have the matched up string
|
||||
* in the string
|
||||
*/
|
||||
ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, 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' */ );
|
||||
}
|
||||
|
||||
/*
|
||||
* The strange thing in the second argument is the rest of the
|
||||
* string from the old string
|
||||
* Now everything is safely copied to the newcopy. Lets free the
|
||||
* oldcopy and let the copiedquery get the var->value from the
|
||||
* newcopy.
|
||||
*/
|
||||
strcat(newcopy,
|
||||
copiedquery
|
||||
+ (p - newcopy)
|
||||
+ sizeof("?") - 1 /* don't count the '\0' */ );
|
||||
if (malloced)
|
||||
{
|
||||
ECPGfree((char *) tobeinserted);
|
||||
tobeinserted = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ECPGfree(copiedquery);
|
||||
copiedquery = newcopy;
|
||||
|
||||
var = var->next;
|
||||
|
||||
if (desc_counter == 0)
|
||||
var = var->next;
|
||||
}
|
||||
|
||||
/* Check if there are unmatched things left. */
|
||||
|
@ -7,39 +7,42 @@
|
||||
|
||||
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)
|
||||
|
||||
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. */
|
||||
|
||||
/* 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,
|
||||
enum ECPGttype, char *, char *, long, long, long, enum ARRAY_TYPE, enum COMPAT_MODE, bool);
|
||||
struct connection *ECPGget_connection(const char *);
|
||||
char *ECPGalloc(long, int);
|
||||
char *ECPGrealloc(void *, long, int);
|
||||
void ECPGfree(void *);
|
||||
bool ECPGinit(const struct connection *, const char *, const int);
|
||||
char *ECPGstrdup(const char *, int);
|
||||
const char *ECPGtype_name(enum ECPGttype);
|
||||
unsigned int ECPGDynamicType(Oid);
|
||||
void ECPGfree_auto_mem(void);
|
||||
void ECPGclear_auto_mem(void);
|
||||
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);
|
||||
struct connection *ECPGget_connection (const char *);
|
||||
char *ECPGalloc (long, int);
|
||||
char *ECPGrealloc (void *, long, int);
|
||||
void ECPGfree (void *);
|
||||
bool ECPGinit (const struct connection *, const char *, const int);
|
||||
char *ECPGstrdup (const char *, int);
|
||||
const char *ECPGtype_name (enum ECPGttype);
|
||||
unsigned int ECPGDynamicType (Oid);
|
||||
void ECPGfree_auto_mem (void);
|
||||
void ECPGclear_auto_mem (void);
|
||||
|
||||
struct descriptor *ecpggetdescp (int, char *);
|
||||
|
||||
/* A generic varchar type. */
|
||||
struct ECPGgeneric_varchar
|
||||
{
|
||||
int len;
|
||||
char arr[1];
|
||||
int len;
|
||||
char arr[1];
|
||||
};
|
||||
|
||||
/*
|
||||
@ -48,64 +51,79 @@ struct ECPGgeneric_varchar
|
||||
|
||||
struct ECPGtype_information_cache
|
||||
{
|
||||
struct ECPGtype_information_cache *next;
|
||||
int oid;
|
||||
bool isarray;
|
||||
struct ECPGtype_information_cache *next;
|
||||
int oid;
|
||||
bool isarray;
|
||||
};
|
||||
|
||||
/* structure to store one statement */
|
||||
struct statement
|
||||
{
|
||||
int lineno;
|
||||
char *command;
|
||||
struct connection *connection;
|
||||
enum COMPAT_MODE compat;
|
||||
bool force_indicator;
|
||||
struct variable *inlist;
|
||||
struct variable *outlist;
|
||||
int lineno;
|
||||
char *command;
|
||||
struct connection *connection;
|
||||
enum COMPAT_MODE compat;
|
||||
bool force_indicator;
|
||||
struct variable *inlist;
|
||||
struct variable *outlist;
|
||||
};
|
||||
|
||||
/* structure to store connections */
|
||||
struct connection
|
||||
{
|
||||
char *name;
|
||||
PGconn *connection;
|
||||
bool committed;
|
||||
int autocommit;
|
||||
struct ECPGtype_information_cache *cache_head;
|
||||
struct connection *next;
|
||||
char *name;
|
||||
PGconn *connection;
|
||||
bool committed;
|
||||
int autocommit;
|
||||
struct ECPGtype_information_cache *cache_head;
|
||||
struct connection *next;
|
||||
};
|
||||
|
||||
/* structure to store descriptors */
|
||||
struct descriptor
|
||||
{
|
||||
char *name;
|
||||
PGresult *result;
|
||||
struct descriptor *next;
|
||||
char *name;
|
||||
PGresult *result;
|
||||
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
|
||||
{
|
||||
enum ECPGttype type;
|
||||
void *value;
|
||||
void *pointer;
|
||||
long varcharsize;
|
||||
long arrsize;
|
||||
long offset;
|
||||
enum ECPGttype ind_type;
|
||||
void *ind_value;
|
||||
void *ind_pointer;
|
||||
long ind_varcharsize;
|
||||
long ind_arrsize;
|
||||
long ind_offset;
|
||||
struct variable *next;
|
||||
enum ECPGttype type;
|
||||
void *value;
|
||||
void *pointer;
|
||||
long varcharsize;
|
||||
long arrsize;
|
||||
long offset;
|
||||
enum ECPGttype ind_type;
|
||||
void *ind_value;
|
||||
void *ind_pointer;
|
||||
long ind_varcharsize;
|
||||
long ind_arrsize;
|
||||
long ind_offset;
|
||||
struct variable *next;
|
||||
};
|
||||
|
||||
PGresult **
|
||||
ECPGdescriptor_lvalue(int line, const char *descriptor);
|
||||
PGresult **ECPGdescriptor_lvalue (int line, const char *descriptor);
|
||||
|
||||
bool ECPGstore_result(const PGresult *results, int act_field,
|
||||
const struct statement * stmt, struct variable * var);
|
||||
bool ECPGstore_result (const PGresult * results, int act_field,
|
||||
const struct statement *stmt, struct variable *var);
|
||||
|
||||
/* SQLSTATE values generated or processed by ecpglib (intentionally
|
||||
* not exported -- users should refer to the codes directly) */
|
||||
@ -133,4 +151,4 @@ bool ECPGstore_result(const PGresult *results, int act_field,
|
||||
#define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR "YE000"
|
||||
#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);
|
||||
void ECPGraise_backend(int line, PGresult *result, PGconn *conn, int compat);
|
||||
bool ECPGget_desc_header(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 *);
|
||||
bool ECPGis_noind_null(enum ECPGttype, void *);
|
||||
|
@ -58,9 +58,7 @@ ECPGnumeric_lvalue(FILE *f, char *name)
|
||||
fputs(name, yyout);
|
||||
break;
|
||||
default:
|
||||
snprintf(errortext, sizeof errortext, "variable %s: numeric type needed"
|
||||
,name);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "variable %s: numeric type needed", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -120,8 +118,7 @@ drop_descriptor(char *name, char *connection)
|
||||
}
|
||||
}
|
||||
}
|
||||
snprintf(errortext, sizeof errortext, "unknown descriptor %s", name);
|
||||
mmerror(PARSE_ERROR, ET_WARNING, errortext);
|
||||
mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor %s", name);
|
||||
}
|
||||
|
||||
struct descriptor
|
||||
@ -143,8 +140,7 @@ lookup_descriptor(char *name, char *connection)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
snprintf(errortext, sizeof errortext, "unknown descriptor %s", name);
|
||||
mmerror(PARSE_ERROR, ET_WARNING, errortext);
|
||||
mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor %s", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -153,16 +149,13 @@ output_get_descr_header(char *desc_name)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (results->value == ECPGd_count)
|
||||
ECPGnumeric_lvalue(yyout, results->variable);
|
||||
else
|
||||
{
|
||||
snprintf(errortext, sizeof errortext, "unknown descriptor header item '%d'", results->value);
|
||||
mmerror(PARSE_ERROR, ET_WARNING, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor header item '%d'", results->value);
|
||||
}
|
||||
|
||||
drop_assignments();
|
||||
@ -175,7 +168,7 @@ output_get_descr(char *desc_name, char *index)
|
||||
{
|
||||
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)
|
||||
{
|
||||
const struct variable *v = find_variable(results->variable);
|
||||
@ -200,6 +193,116 @@ output_get_descr(char *desc_name, char *index)
|
||||
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
|
||||
variables are possible per statement. (input and output descriptor)
|
||||
And descriptors are no normal variables, so they don't belong into
|
||||
@ -211,11 +314,10 @@ struct variable *
|
||||
descriptor_variable(const char *name, int input)
|
||||
{
|
||||
static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN];
|
||||
static const struct ECPGtype descriptor_type =
|
||||
{ECPGt_descriptor, 0};
|
||||
static const struct variable varspace[2] =
|
||||
{{descriptor_names[0], (struct ECPGtype *) & descriptor_type, 0, NULL},
|
||||
{descriptor_names[1], (struct ECPGtype *) & descriptor_type, 0, NULL}
|
||||
static const struct ECPGtype descriptor_type = { ECPGt_descriptor, 0 };
|
||||
static const struct variable varspace[2] = {
|
||||
{ descriptor_names[0], (struct ECPGtype *) & descriptor_type, 0, NULL },
|
||||
{ descriptor_names[1], (struct ECPGtype *) & descriptor_type, 0, NULL }
|
||||
};
|
||||
|
||||
strncpy(descriptor_names[input], name, MAX_DESCRIPTOR_NAMELEN);
|
||||
|
@ -25,8 +25,7 @@ extern char *descriptor_name;
|
||||
extern char *connection;
|
||||
extern char *input_filename;
|
||||
extern char *yytext,
|
||||
*token_start,
|
||||
errortext[128];
|
||||
*token_start;
|
||||
|
||||
#ifdef YYDEBUG
|
||||
extern int yydebug;
|
||||
@ -63,11 +62,13 @@ extern int yylex(void);
|
||||
extern void yyerror(char *);
|
||||
extern void *mm_alloc(size_t), *mm_realloc(void *, size_t);
|
||||
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 *ScanCKeywordLookup(char *);
|
||||
extern void output_get_descr_header(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 struct variable *find_variable(char *);
|
||||
extern void whenever_action(int);
|
||||
|
@ -12,7 +12,7 @@
|
||||
*
|
||||
*
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
if (!yyin)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "Cannot open include file %s in line %d\n", yytext, yylineno);
|
||||
mmerror(NO_INCLUDE_FILE, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(NO_INCLUDE_FILE, ET_FATAL, "Cannot open include file %s in line %d\n", yytext, yylineno);
|
||||
|
||||
input_filename = mm_strdup(inc_file);
|
||||
yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $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 */
|
||||
%{
|
||||
@ -12,7 +12,6 @@
|
||||
int struct_level = 0;
|
||||
int braces_open; /* brace level counter */
|
||||
int ecpg_informix_var = 0;
|
||||
char errortext[128];
|
||||
char *connection = NULL;
|
||||
char *input_filename = NULL;
|
||||
|
||||
@ -52,19 +51,37 @@ static struct inf_compat_val
|
||||
* Handle parsing errors and warnings
|
||||
*/
|
||||
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)
|
||||
{
|
||||
case ET_WARNING:
|
||||
fprintf(stderr, "%s:%d: WARNING: %s\n", input_filename, yylineno, error);
|
||||
break;
|
||||
case ET_ERROR:
|
||||
fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
|
||||
ret_value = error_code;
|
||||
break;
|
||||
case ET_FATAL:
|
||||
fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
|
||||
exit(error_code);
|
||||
}
|
||||
}
|
||||
@ -261,8 +278,7 @@ add_additional_variables(char *name, bool insert)
|
||||
|
||||
if (ptr == NULL)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "trying to access an undeclared cursor %s\n", name);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "trying to access an undeclared cursor %s\n", name);
|
||||
return NULL;
|
||||
}
|
||||
if (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> ECPGTypeName using_list ECPGColLabelCommon UsingConst
|
||||
%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> AlterOwnerStmt OptTableSpaceOwner CreateTableSpaceStmt
|
||||
%type <str> DropTableSpaceStmt indirection indirection_el
|
||||
%type <str> DropTableSpaceStmt indirection indirection_el ECPGSetDescriptorHeader
|
||||
|
||||
%type <struct_union> s_struct_union_symbol
|
||||
|
||||
%type <descriptor> ECPGGetDescriptor
|
||||
%type <descriptor> ECPGGetDescriptor ECPGSetDescriptor
|
||||
|
||||
%type <type_enum> simple_type signed_type unsigned_type
|
||||
|
||||
@ -811,6 +827,19 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); }
|
||||
whenever_action(2);
|
||||
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
|
||||
{
|
||||
if (connection)
|
||||
@ -1925,22 +1954,22 @@ TruncateStmt: TRUNCATE opt_table qualified_name
|
||||
* embedded SQL implementations. So we accept their syntax as well and
|
||||
* 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);
|
||||
$$ = 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);
|
||||
$$ = 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);
|
||||
$$ = cat_str(3, make_str("fetch"), $2, $3);
|
||||
}
|
||||
| FETCH name ecpg_into_using
|
||||
| FETCH name ecpg_into
|
||||
{
|
||||
add_additional_variables($2, false);
|
||||
$$ = cat2_str(make_str("fetch"), $2);
|
||||
@ -2895,11 +2924,8 @@ DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt
|
||||
for (ptr = cur; ptr != NULL; ptr = ptr->next)
|
||||
{
|
||||
if (strcmp($2, ptr->name) == 0)
|
||||
{
|
||||
/* re-definition is a bug */
|
||||
snprintf(errortext, sizeof(errortext), "cursor %s already defined", $2);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
/* re-definition is a bug */
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "cursor %s already defined", $2);
|
||||
}
|
||||
|
||||
this = (struct cursor *) mm_alloc(sizeof(struct cursor));
|
||||
@ -2987,7 +3013,7 @@ into_clause: INTO OptTempTableName
|
||||
FoundInto = 1;
|
||||
$$= cat2_str(make_str("into"), $2);
|
||||
}
|
||||
| ecpg_into_using { $$ = EMPTY; }
|
||||
| ecpg_into { $$ = EMPTY; }
|
||||
| /*EMPTY*/ { $$ = EMPTY; }
|
||||
;
|
||||
|
||||
@ -4246,11 +4272,7 @@ connection_target: database_name opt_server opt_port
|
||||
{
|
||||
/* old style: dbname[@server][:port] */
|
||||
if (strlen($2) > 0 && *($2) != '@')
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext),
|
||||
"Expected '@', found '%s'", $2);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "Expected '@', found '%s'", $2);
|
||||
|
||||
$$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\""));
|
||||
}
|
||||
@ -4258,24 +4280,15 @@ connection_target: database_name opt_server opt_port
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported");
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported");
|
||||
|
||||
if (strncmp($3, "//", strlen("//")) != 0)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "Expected '://', found '%s'", $3);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "Expected '://', found '%s'", $3);
|
||||
|
||||
if (strncmp($1, "unix", strlen("unix")) == 0 &&
|
||||
strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 &&
|
||||
strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//"));
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//"));
|
||||
|
||||
$$ = 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
|
||||
db_prefix: ident cvariable
|
||||
{
|
||||
if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "Expected 'postgresql', found '%s'", $2);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "Expected 'postgresql', found '%s'", $2);
|
||||
|
||||
if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "Illegal connection type %s", $1);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "Illegal connection type %s", $1);
|
||||
|
||||
$$ = make3_str($1, make_str(":"), $2);
|
||||
}
|
||||
@ -4313,10 +4320,7 @@ db_prefix: ident cvariable
|
||||
server: Op server_name
|
||||
{
|
||||
if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "Expected '@' or '://', found '%s'", $1);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "Expected '@' or '://', found '%s'", $1);
|
||||
|
||||
$$ = make2_str($1, $2);
|
||||
}
|
||||
@ -4421,10 +4425,7 @@ opt_options: Op ColId
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
|
||||
|
||||
if (strcmp($1, "?") != 0)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "unrecognised token '%s'", $1);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "unrecognised token '%s'", $1);
|
||||
|
||||
$$ = make2_str(make_str("?"), $2);
|
||||
}
|
||||
@ -4443,11 +4444,8 @@ ECPGCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR prepared_name
|
||||
for (ptr = cur; ptr != NULL; ptr = ptr->next)
|
||||
{
|
||||
if (strcmp($2, ptr->name) == 0)
|
||||
{
|
||||
/* re-definition is a bug */
|
||||
snprintf(errortext, sizeof(errortext), "cursor %s already defined", $2);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
/* re-definition is a bug */
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "cursor %s already defined", $2);
|
||||
}
|
||||
|
||||
this = (struct cursor *) mm_alloc(sizeof(struct cursor));
|
||||
@ -4595,11 +4593,8 @@ type_declaration: S_TYPEDEF
|
||||
for (ptr = types; ptr != NULL; ptr = ptr->next)
|
||||
{
|
||||
if (strcmp($5, ptr->name) == 0)
|
||||
{
|
||||
/* re-definition is a bug */
|
||||
snprintf(errortext, sizeof(errortext), "Type %s already defined", $5);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", $5);
|
||||
}
|
||||
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
|
||||
for (ptr = types; ptr != NULL; ptr = ptr->next)
|
||||
{
|
||||
if (strcmp(su_type.type_str, ptr->name) == 0)
|
||||
{
|
||||
/* re-definition is a bug */
|
||||
snprintf(errortext, sizeof(errortext), "Type %s already defined", su_type.type_str);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", su_type.type_str);
|
||||
}
|
||||
|
||||
this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
|
||||
@ -5215,28 +5207,25 @@ opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; }
|
||||
;
|
||||
|
||||
ecpg_using: USING using_list { $$ = EMPTY; }
|
||||
| using_descriptor { $$ = $1; }
|
||||
;
|
||||
|
||||
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;
|
||||
}
|
||||
;
|
||||
|
||||
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;
|
||||
}
|
||||
;
|
||||
|
||||
opt_sql: /*EMPTY*/ | SQL_SQL;
|
||||
|
||||
ecpg_into_using: ecpg_into { $$ = EMPTY; }
|
||||
| using_descriptor { $$ = $1; }
|
||||
;
|
||||
|
||||
ecpg_into: INTO into_list { $$ = EMPTY; }
|
||||
| into_descriptor { $$ = $1; }
|
||||
;
|
||||
@ -5295,8 +5284,19 @@ opt_output: SQL_OUTPUT { $$ = make_str("output"); }
|
||||
/*
|
||||
* dynamic SQL: descriptor based access
|
||||
* 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
|
||||
*/
|
||||
@ -5308,63 +5308,85 @@ ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
|
||||
;
|
||||
|
||||
/*
|
||||
* allocate a descriptor
|
||||
*/
|
||||
ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
|
||||
{
|
||||
add_descriptor($3,connection);
|
||||
$$ = $3;
|
||||
};
|
||||
|
||||
/*
|
||||
* read from descriptor
|
||||
* manipulate a descriptor header
|
||||
*/
|
||||
|
||||
ECPGGetDescHeaderItem: cvariable '=' desc_header_item
|
||||
{ push_assignment($1, $3); }
|
||||
;
|
||||
|
||||
desc_header_item: SQL_COUNT { $$ = ECPGd_count; }
|
||||
;
|
||||
|
||||
ECPGGetDescItem: cvariable '=' descriptor_item { push_assignment($1, $3); };
|
||||
|
||||
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; }
|
||||
ECPGGetDescriptorHeader: GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems
|
||||
{ $$ = $3; }
|
||||
;
|
||||
|
||||
ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
|
||||
| ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem
|
||||
;
|
||||
|
||||
ECPGGetDescItems: ECPGGetDescItem
|
||||
| ECPGGetDescItems ',' ECPGGetDescItem
|
||||
ECPGGetDescHeaderItem: CVARIABLE '=' desc_header_item
|
||||
{ push_assignment($1, $3); }
|
||||
;
|
||||
|
||||
ECPGGetDescriptorHeader: GET SQL_DESCRIPTOR quoted_ident_stringvar
|
||||
ECPGGetDescHeaderItems
|
||||
{ $$ = $3; }
|
||||
|
||||
ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems
|
||||
{ $$ = $3; }
|
||||
|
||||
ECPGSetDescHeaderItems: ECPGSetDescHeaderItem
|
||||
| ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem
|
||||
;
|
||||
|
||||
ECPGGetDescriptor: GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE cvariable ECPGGetDescItems
|
||||
ECPGSetDescHeaderItem: desc_header_item '=' CVARIABLE
|
||||
{ push_assignment($3, $1); }
|
||||
;
|
||||
|
||||
|
||||
desc_header_item: SQL_COUNT { $$ = ECPGd_count; }
|
||||
;
|
||||
|
||||
/*
|
||||
* 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
|
||||
;
|
||||
|
||||
ECPGGetDescItem: CVARIABLE '=' descriptor_item { push_assignment($1, $3); };
|
||||
|
||||
|
||||
ECPGSetDescriptor: SET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE CVARIABLE ECPGSetDescItems
|
||||
{ $$.str = $5; $$.name = $3; }
|
||||
| SET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGSetDescItems
|
||||
{ $$.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
|
||||
* after a transaction statement to disconnect from the database.
|
||||
@ -5431,11 +5453,8 @@ ECPGTypedef: TYPE_P
|
||||
for (ptr = types; ptr != NULL; ptr = ptr->next)
|
||||
{
|
||||
if (strcmp($3, ptr->name) == 0)
|
||||
{
|
||||
/* re-definition is a bug */
|
||||
snprintf(errortext, sizeof(errortext), "Type %s already defined", $3);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", $3);
|
||||
}
|
||||
|
||||
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)
|
||||
return ("ECPGt_timestamp");
|
||||
break;
|
||||
default:
|
||||
sprintf(errortext, "illegal variable type %d\n", type);
|
||||
yyerror(errortext);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "illegal variable type %d\n", type);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -538,8 +537,7 @@ ECPGfree_type(struct ECPGtype * type)
|
||||
ECPGfree_struct_member(type->u.members);
|
||||
break;
|
||||
default:
|
||||
sprintf(errortext, "illegal variable type %d\n", type->type);
|
||||
yyerror(errortext);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "illegal variable type %d\n", type->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -598,8 +596,7 @@ get_dtype(enum ECPGdtype type)
|
||||
case ECPGd_cardinality:
|
||||
return ("ECPGd_cardinality");
|
||||
default:
|
||||
sprintf(errortext, "illegal descriptor item %d\n", type);
|
||||
yyerror(errortext);
|
||||
mmerror(PARSE_ERROR, ET_ERROR, "illegal descriptor item %d\n", type);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -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
|
||||
* be an array element */
|
||||
if (members->type->type != ECPGt_array)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "incorrectly formed variable %s", name);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "incorrectly formed variable %s", name);
|
||||
|
||||
switch (members->type->u.element->type)
|
||||
{
|
||||
@ -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));
|
||||
break;
|
||||
default:
|
||||
snprintf(errortext, sizeof(errortext), "incorrectly formed variable %s", name);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "incorrectly formed variable %s", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -134,16 +130,10 @@ find_struct(char *name, char *next, char *end)
|
||||
if (c == '-')
|
||||
{
|
||||
if (p->type->type != ECPGt_array)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "variable %s is not a pointer", name);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer", name);
|
||||
|
||||
if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "variable %s is not a pointer to a structure or a union", name);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer to a structure or a union", name);
|
||||
|
||||
/* restore the name, we will need it later */
|
||||
*next = c;
|
||||
@ -155,10 +145,7 @@ find_struct(char *name, char *next, char *end)
|
||||
if (next == end)
|
||||
{
|
||||
if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "variable %s is neither a structure nor a union", name);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "variable %s is neither a structure nor a union", name);
|
||||
|
||||
/* restore the name, we will need it later */
|
||||
*next = c;
|
||||
@ -168,16 +155,10 @@ find_struct(char *name, char *next, char *end)
|
||||
else
|
||||
{
|
||||
if (p->type->type != ECPGt_array)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "variable %s is not an array", name);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not an array", name);
|
||||
|
||||
if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "variable %s is not a pointer to a structure or a union", name);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer to a structure or a union", name);
|
||||
|
||||
/* restore the name, we will need it later */
|
||||
*next = c;
|
||||
@ -243,10 +224,8 @@ find_variable(char *name)
|
||||
*next = '\0';
|
||||
p = find_simple(name);
|
||||
if (p == NULL)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "The variable %s is not declared", name);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "The variable %s is not declared", name);
|
||||
|
||||
*next = c;
|
||||
switch (p->type->u.element->type)
|
||||
{
|
||||
@ -267,10 +246,7 @@ find_variable(char *name)
|
||||
p = find_simple(name);
|
||||
|
||||
if (p == NULL)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "The variable %s is not declared", name);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "The variable %s is not declared", name);
|
||||
|
||||
return (p);
|
||||
}
|
||||
@ -490,10 +466,7 @@ get_typedef(char *name)
|
||||
|
||||
for (this = types; this && strcmp(this->name, name); this = this->next);
|
||||
if (!this)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "invalid datatype '%s'", name);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "invalid datatype '%s'", name);
|
||||
|
||||
return (this);
|
||||
}
|
||||
@ -521,10 +494,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
|
||||
}
|
||||
|
||||
if (pointer_len > 2)
|
||||
{
|
||||
snprintf(errortext, sizeof(errortext), "No multilevel (more than 2) pointer supported %d", pointer_len);
|
||||
mmerror(PARSE_ERROR, ET_FATAL, errortext);
|
||||
}
|
||||
mmerror(PARSE_ERROR, ET_FATAL, "No multilevel (more than 2) pointer supported %d", pointer_len);
|
||||
|
||||
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");
|
||||
|
69
src/interfaces/ecpg/test/test_desc.pgc
Normal file
69
src/interfaces/ecpg/test/test_desc.pgc
Normal file
@ -0,0 +1,69 @@
|
||||
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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user