mirror of https://github.com/postgres/postgres
parent
3ca3bb7d8b
commit
b3b35e98b6
@ -0,0 +1,20 @@ |
||||
descriptor statements have the following shortcomings |
||||
|
||||
- up to now the only reasonable statement is |
||||
FETCH ... INTO SQL DESCRIPTOR <name> |
||||
no input variables allowed! |
||||
|
||||
Reason: to fully support dynamic SQL the frontend/backend communication |
||||
should change to recognize input parameters. |
||||
Since this is not likely to happen in the near future and you |
||||
can cover the same functionality with the existing infrastructure |
||||
I'll leave the work to someone else. |
||||
|
||||
- string buffer overflow does not always generate warnings |
||||
(beware: terminating 0 may be missing because strncpy is used) |
||||
:var=data sets sqlwarn accordingly (but not indicator) |
||||
|
||||
- char variables pointing to NULL are not allocated on demand |
||||
|
||||
- string truncation does not show up in indicator |
||||
|
||||
@ -0,0 +1,400 @@ |
||||
/*
|
||||
* functions needed for descriptor handling |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
#include "extern.h" |
||||
|
||||
/*
|
||||
* assignment handling function (descriptor) |
||||
*/ |
||||
|
||||
struct assignment *assignments; |
||||
|
||||
void push_assignment(char *var,char *value) |
||||
{ |
||||
struct assignment *new=(struct assignment *)mm_alloc(sizeof(struct assignment)); |
||||
|
||||
new->next=assignments; |
||||
new->variable=mm_alloc(strlen(var)+1); |
||||
strcpy(new->variable,var); |
||||
new->value=mm_alloc(strlen(value)+1); |
||||
strcpy(new->value,value); |
||||
assignments=new; |
||||
} |
||||
|
||||
static void |
||||
drop_assignments(void) |
||||
{ while (assignments) |
||||
{ struct assignment *old_head=assignments; |
||||
|
||||
assignments=old_head->next; |
||||
free(old_head->variable); |
||||
free(old_head->value); |
||||
free(old_head); |
||||
} |
||||
} |
||||
|
||||
/* XXX: these should be more accurate (consider ECPGdump_a_* ) */ |
||||
static void ECPGnumeric_lvalue(FILE *f,char *name) |
||||
{ const struct variable *v=find_variable(name); |
||||
|
||||
switch(v->type->typ) |
||||
{ |
||||
case ECPGt_short: |
||||
case ECPGt_int:
|
||||
case ECPGt_long: |
||||
case ECPGt_unsigned_short: |
||||
case ECPGt_unsigned_int: |
||||
case ECPGt_unsigned_long: |
||||
fputs(name,yyout); |
||||
break; |
||||
default: |
||||
snprintf(errortext,sizeof errortext,"variable %s: numeric type needed" |
||||
,name); |
||||
mmerror(ET_ERROR,errortext); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static void ECPGstring_buffer(FILE *f,char *name) |
||||
{
|
||||
const struct variable *v=find_variable(name); |
||||
|
||||
switch(v->type->typ) |
||||
{ |
||||
case ECPGt_varchar: |
||||
fprintf(yyout,"%s.arr",name); |
||||
break; |
||||
|
||||
case ECPGt_char: |
||||
case ECPGt_unsigned_char: |
||||
fputs(name,yyout); |
||||
break; |
||||
|
||||
default: |
||||
snprintf(errortext,sizeof errortext,"variable %s: character type needed" |
||||
,name); |
||||
mmerror(ET_ERROR,errortext); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static void ECPGstring_length(FILE *f,char *name) |
||||
{ |
||||
const struct variable *v=find_variable(name); |
||||
|
||||
switch(v->type->typ) |
||||
{ case ECPGt_varchar: |
||||
case ECPGt_char: |
||||
case ECPGt_unsigned_char: |
||||
if (!v->type->size)
|
||||
{ snprintf(errortext,sizeof errortext,"zero length char variable %s for assignment", |
||||
v->name); |
||||
mmerror(ET_ERROR,errortext); |
||||
} |
||||
fprintf(yyout,"%ld",v->type->size); |
||||
break; |
||||
default: |
||||
snprintf(errortext,sizeof errortext,"variable %s: character type needed" |
||||
,name); |
||||
mmerror(ET_ERROR,errortext); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static void ECPGdata_assignment(char *variable,char *index_plus_1) |
||||
{ |
||||
const struct variable *v=find_variable(variable); |
||||
|
||||
fprintf(yyout,"\t\t\tif (!PQgetisnull(ECPGresult,0,(%s)-1))\n",index_plus_1); |
||||
switch(v->type->typ) |
||||
{ |
||||
case ECPGt_short: |
||||
case ECPGt_int: /* use the same conversion as ecpglib does */ |
||||
case ECPGt_long: |
||||
fprintf(yyout,"\t\t\t\t%s=strtol(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n" |
||||
,variable,index_plus_1); |
||||
break; |
||||
case ECPGt_unsigned_short: |
||||
case ECPGt_unsigned_int: |
||||
case ECPGt_unsigned_long: |
||||
fprintf(yyout,"\t\t\t\t%s=strtoul(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n" |
||||
,variable,index_plus_1); |
||||
break; |
||||
case ECPGt_float: |
||||
case ECPGt_double: |
||||
fprintf(yyout,"\t\t\t\t%s=strtod(PQgetvalue(ECPGresult,0,(%s)-1),NULL);\n" |
||||
,variable,index_plus_1); |
||||
break; |
||||
|
||||
case ECPGt_bool: |
||||
fprintf(yyout,"\t\t\t\t%s=PQgetvalue(ECPGresult,0,(%s)-1)[0]=='t';\n" |
||||
,variable,index_plus_1); |
||||
break; |
||||
|
||||
case ECPGt_varchar: |
||||
fprintf(yyout,"\t\t\t{\tstrncpy(%s.arr,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n" |
||||
,variable,index_plus_1,v->type->size); |
||||
fprintf(yyout,"\t\t\t\t%s.len=strlen(PQgetvalue(ECPGresult,0,(%s)-1)\n" |
||||
,variable,index_plus_1); |
||||
fprintf(yyout,"\t\t\t\tif (%s.len>%ld) { %s.len=%ld; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n" |
||||
,variable,v->type->size,variable,v->type->size); |
||||
fputs("\t\t\t}\n",yyout);
|
||||
break; |
||||
|
||||
case ECPGt_char: |
||||
case ECPGt_unsigned_char: |
||||
if (!v->type->size)
|
||||
{ |
||||
snprintf(errortext,sizeof errortext,"zero length char variable %s for DATA assignment", |
||||
v->name); |
||||
mmerror(ET_ERROR,errortext); |
||||
} |
||||
fprintf(yyout,"\t\t\t{\tstrncpy(%s,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n" |
||||
,variable,index_plus_1,v->type->size); |
||||
fprintf(yyout,"\t\t\t\tif (strlen(PQgetvalue(ECPGresult,0,(%s)-1))>=%ld)\n" |
||||
"\t\t\t\t{ %s[%ld]=0; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n" |
||||
,index_plus_1,v->type->size,variable,v->type->size-1); |
||||
fputs("\t\t\t}\n",yyout);
|
||||
break; |
||||
|
||||
default: |
||||
snprintf(errortext,sizeof errortext,"unknown variable type %d for DATA assignment" |
||||
,v->type->typ); |
||||
mmerror(ET_ERROR,errortext); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void |
||||
output_get_descr_header(char *desc_name) |
||||
{ |
||||
struct assignment *results; |
||||
|
||||
fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n" ,yylineno,desc_name); |
||||
fputs("\tif (ECPGresult)\n\t{",yyout); |
||||
for (results=assignments;results!=NULL;results=results->next) |
||||
{ |
||||
if (!strcasecmp(results->value,"count")) |
||||
{ |
||||
fputs("\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fputs("=PQnfields(ECPGresult);\n",yyout); |
||||
} |
||||
else |
||||
{ snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value); |
||||
mmerror(ET_WARN,errortext); |
||||
} |
||||
} |
||||
drop_assignments(); |
||||
fputs("}",yyout); |
||||
|
||||
whenever_action(2|1); |
||||
} |
||||
|
||||
void |
||||
output_get_descr(char *desc_name) |
||||
{ |
||||
struct assignment *results; |
||||
int flags=0; |
||||
const int DATA_SEEN=1; |
||||
const int INDICATOR_SEEN=2; |
||||
|
||||
fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n" |
||||
,yylineno,desc_name); |
||||
fputs("\tif (ECPGresult)\n\t{",yyout); |
||||
fprintf(yyout,"\tif (PQntuples(ECPGresult)<1) ECPGraise(%d,ECPG_NOT_FOUND);\n",yylineno); |
||||
fprintf(yyout,"\t\telse if (%s<1 || %s>PQnfields(ECPGresult))\n" |
||||
"\t\t\tECPGraise(%d,ECPG_INVALID_DESCRIPTOR_INDEX);\n" |
||||
,descriptor_index,descriptor_index,yylineno); |
||||
fputs("\t\telse\n\t\t{\n",yyout); |
||||
for (results=assignments;results!=NULL;results=results->next) |
||||
{ |
||||
if (!strcasecmp(results->value,"type")) |
||||
{ |
||||
fputs("\t\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fprintf(yyout,"=ECPGDynamicType(PQftype(ECPGresult,(%s)-1));\n",descriptor_index); |
||||
} |
||||
else if (!strcasecmp(results->value,"datetime_interval_code")) |
||||
{ |
||||
fputs("\t\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fprintf(yyout,"=ECPGDynamicType_DDT(PQftype(ECPGresult,(%s)-1));\n",descriptor_index); |
||||
} |
||||
else if (!strcasecmp(results->value,"length")) |
||||
{ |
||||
fputs("\t\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)-VARHDRSZ;\n",descriptor_index); |
||||
} |
||||
else if (!strcasecmp(results->value,"octet_length")) |
||||
{ |
||||
fputs("\t\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fprintf(yyout,"=PQfsize(ECPGresult,(%s)-1);\n",descriptor_index); |
||||
} |
||||
else if (!strcasecmp(results->value,"returned_length") |
||||
|| !strcasecmp(results->value,"returned_octet_length")) |
||||
{ |
||||
fputs("\t\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fprintf(yyout,"=PQgetlength(ECPGresult,0,(%s)-1);\n",descriptor_index); |
||||
} |
||||
else if (!strcasecmp(results->value,"precision")) |
||||
{ |
||||
fputs("\t\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)>>16;\n",descriptor_index); |
||||
} |
||||
else if (!strcasecmp(results->value,"scale")) |
||||
{ |
||||
fputs("\t\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fprintf(yyout,"=(PQfmod(ECPGresult,(%s)-1)-VARHDRSZ)&0xffff;\n",descriptor_index); |
||||
} |
||||
else if (!strcasecmp(results->value,"nullable")) |
||||
{ |
||||
mmerror(ET_WARN,"nullable is always 1"); |
||||
fputs("\t\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fprintf(yyout,"=1;\n"); |
||||
} |
||||
else if (!strcasecmp(results->value,"key_member")) |
||||
{ |
||||
mmerror(ET_WARN,"key_member is always 0"); |
||||
fputs("\t\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fprintf(yyout,"=0;\n"); |
||||
} |
||||
else if (!strcasecmp(results->value,"name")) |
||||
{ |
||||
fputs("\t\t\tstrncpy(",yyout); |
||||
ECPGstring_buffer(yyout,results->variable); |
||||
fprintf(yyout,",PQfname(ECPGresult,(%s)-1),",descriptor_index); |
||||
ECPGstring_length(yyout,results->variable); |
||||
fputs(");\n",yyout); |
||||
} |
||||
else if (!strcasecmp(results->value,"indicator")) |
||||
{ |
||||
flags|=INDICATOR_SEEN; |
||||
fputs("\t\t\t",yyout); |
||||
ECPGnumeric_lvalue(yyout,results->variable); |
||||
fprintf(yyout,"=-PQgetisnull(ECPGresult,0,(%s)-1);\n",descriptor_index); |
||||
} |
||||
else if (!strcasecmp(results->value,"data")) |
||||
{ |
||||
flags|=DATA_SEEN; |
||||
ECPGdata_assignment(results->variable,descriptor_index); |
||||
} |
||||
else |
||||
{ |
||||
snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value); |
||||
mmerror(ET_WARN,errortext); |
||||
} |
||||
} |
||||
if (flags==DATA_SEEN) /* no indicator */ |
||||
{ |
||||
fprintf(yyout,"\t\t\tif (PQgetisnull(ECPGresult,0,(%s)-1))\n" |
||||
"\t\t\t\tECPGraise(%d,ECPG_MISSING_INDICATOR);\n" |
||||
,descriptor_index,yylineno); |
||||
} |
||||
drop_assignments(); |
||||
fputs("\t\t}\n\t}\n",yyout); |
||||
|
||||
whenever_action(2|1); |
||||
} |
||||
|
||||
/*
|
||||
* descriptor name lookup |
||||
*/ |
||||
|
||||
static struct descriptor *descriptors; |
||||
|
||||
void add_descriptor(char *name,char *connection) |
||||
{ |
||||
struct descriptor *new=(struct descriptor *)mm_alloc(sizeof(struct descriptor)); |
||||
|
||||
new->next=descriptors; |
||||
new->name=mm_alloc(strlen(name)+1); |
||||
strcpy(new->name,name); |
||||
if (connection)
|
||||
{ new->connection=mm_alloc(strlen(connection)+1); |
||||
strcpy(new->connection,connection); |
||||
} |
||||
else new->connection=connection; |
||||
descriptors=new; |
||||
} |
||||
|
||||
void drop_descriptor(char *name,char *connection) |
||||
{ |
||||
struct descriptor *i; |
||||
struct descriptor **lastptr=&descriptors; |
||||
|
||||
for (i=descriptors;i;lastptr=&i->next,i=i->next) |
||||
{ |
||||
if (!strcmp(name,i->name)) |
||||
{ |
||||
if ((!connection && !i->connection)
|
||||
|| (connection && i->connection
|
||||
&& !strcmp(connection,i->connection))) |
||||
{ |
||||
*lastptr=i->next; |
||||
if (i->connection) free(i->connection); |
||||
free(i->name); |
||||
free(i); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
snprintf(errortext,sizeof errortext,"unknown descriptor %s",name); |
||||
mmerror(ET_WARN,errortext); |
||||
} |
||||
|
||||
struct descriptor *lookup_descriptor(char *name,char *connection) |
||||
{ |
||||
struct descriptor *i; |
||||
|
||||
for (i=descriptors;i;i=i->next) |
||||
{ |
||||
if (!strcmp(name,i->name)) |
||||
{ |
||||
if ((!connection && !i->connection)
|
||||
|| (connection && i->connection
|
||||
&& !strcmp(connection,i->connection))) |
||||
{ |
||||
return i; |
||||
} |
||||
} |
||||
} |
||||
snprintf(errortext,sizeof errortext,"unknown descriptor %s",name); |
||||
mmerror(ET_WARN,errortext); |
||||
return NULL; |
||||
} |
||||
|
||||
void |
||||
output_statement_desc(char * stmt, int mode) |
||||
{ |
||||
int i, j=strlen(stmt); |
||||
|
||||
fprintf(yyout, "{ ECPGdo_descriptor(__LINE__, %s, \"%s\", \"",
|
||||
connection ? connection : "NULL", descriptor_name); |
||||
|
||||
/* do this char by char as we have to filter '\"' */ |
||||
for (i = 0;i < j; i++) { |
||||
if (stmt[i] != '\"') |
||||
fputc(stmt[i], yyout); |
||||
else |
||||
fputs("\\\"", yyout); |
||||
} |
||||
|
||||
fputs("\");", yyout); |
||||
|
||||
mode |= 2; |
||||
whenever_action(mode); |
||||
free(stmt); |
||||
if (connection != NULL) |
||||
free(connection); |
||||
free(descriptor_name); |
||||
} |
||||
@ -0,0 +1,358 @@ |
||||
#include "postgres.h" |
||||
|
||||
#include "extern.h" |
||||
|
||||
struct variable * allvariables = NULL; |
||||
|
||||
struct variable * |
||||
new_variable(const char * name, struct ECPGtype * type) |
||||
{ |
||||
struct variable * p = (struct variable*) mm_alloc(sizeof(struct variable)); |
||||
|
||||
p->name = mm_strdup(name); |
||||
p->type = type; |
||||
p->brace_level = braces_open; |
||||
|
||||
p->next = allvariables; |
||||
allvariables = p; |
||||
|
||||
return(p); |
||||
} |
||||
|
||||
static struct variable * |
||||
find_struct_member(char *name, char *str, struct ECPGstruct_member *members) |
||||
{ |
||||
char *next = strchr(++str, '.'), c = '\0'; |
||||
|
||||
if (next != NULL) |
||||
{ |
||||
c = *next; |
||||
*next = '\0'; |
||||
} |
||||
|
||||
for (; members; members = members->next) |
||||
{ |
||||
if (strcmp(members->name, str) == 0) |
||||
{ |
||||
if (c == '\0') |
||||
{ |
||||
/* found the end */ |
||||
switch (members->typ->typ) |
||||
{ |
||||
case ECPGt_array: |
||||
return(new_variable(name, ECPGmake_array_type(members->typ->u.element, members->typ->size))); |
||||
case ECPGt_struct: |
||||
case ECPGt_union: |
||||
return(new_variable(name, ECPGmake_struct_type(members->typ->u.members, members->typ->typ))); |
||||
default: |
||||
return(new_variable(name, ECPGmake_simple_type(members->typ->typ, members->typ->size))); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
*next = c; |
||||
if (c == '-') |
||||
{ |
||||
next++; |
||||
return(find_struct_member(name, next, members->typ->u.element->u.members)); |
||||
} |
||||
else return(find_struct_member(name, next, members->typ->u.members)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return(NULL); |
||||
} |
||||
|
||||
static struct variable * |
||||
find_struct(char * name, char *next) |
||||
{ |
||||
struct variable * p; |
||||
char c = *next; |
||||
|
||||
/* first get the mother structure entry */ |
||||
*next = '\0'; |
||||
p = find_variable(name); |
||||
|
||||
if (c == '-') |
||||
{ |
||||
if (p->type->typ != ECPGt_struct && p->type->typ != ECPGt_union) |
||||
{ |
||||
sprintf(errortext, "variable %s is not a pointer", name); |
||||
mmerror(ET_FATAL, errortext); |
||||
} |
||||
|
||||
if (p->type->u.element->typ != ECPGt_struct && p->type->u.element->typ != ECPGt_union) |
||||
{ |
||||
sprintf(errortext, "variable %s is not a pointer to a structure or a union", name); |
||||
mmerror(ET_FATAL, errortext); |
||||
} |
||||
|
||||
/* restore the name, we will need it later on */ |
||||
*next = c; |
||||
next++; |
||||
|
||||
return find_struct_member(name, next, p->type->u.element->u.members); |
||||
} |
||||
else |
||||
{ |
||||
if (p->type->typ != ECPGt_struct && p->type->typ != ECPGt_union) |
||||
{ |
||||
sprintf(errortext, "variable %s is neither a structure nor a union", name); |
||||
mmerror(ET_FATAL, errortext); |
||||
} |
||||
|
||||
/* restore the name, we will need it later on */ |
||||
*next = c; |
||||
|
||||
return find_struct_member(name, next, p->type->u.members); |
||||
} |
||||
} |
||||
|
||||
static struct variable * |
||||
find_simple(char * name) |
||||
{ |
||||
struct variable * p; |
||||
|
||||
for (p = allvariables; p; p = p->next) |
||||
{ |
||||
if (strcmp(p->name, name) == 0) |
||||
return p; |
||||
} |
||||
|
||||
return(NULL); |
||||
} |
||||
|
||||
/* Note that this function will end the program in case of an unknown */ |
||||
/* variable */ |
||||
struct variable * |
||||
find_variable(char * name) |
||||
{ |
||||
char * next; |
||||
struct variable * p; |
||||
|
||||
if ((next = strchr(name, '.')) != NULL) |
||||
p = find_struct(name, next); |
||||
else if ((next = strstr(name, "->")) != NULL) |
||||
p = find_struct(name, next); |
||||
else |
||||
p = find_simple(name); |
||||
|
||||
if (p == NULL) |
||||
{ |
||||
sprintf(errortext, "The variable %s is not declared", name); |
||||
mmerror(ET_FATAL, errortext); |
||||
} |
||||
|
||||
return(p); |
||||
} |
||||
|
||||
void |
||||
remove_variables(int brace_level) |
||||
{ |
||||
struct variable * p, *prev; |
||||
|
||||
for (p = prev = allvariables; p; p = p ? p->next : NULL) |
||||
{ |
||||
if (p->brace_level >= brace_level) |
||||
{ |
||||
/* remove it */ |
||||
if (p == allvariables) |
||||
prev = allvariables = p->next; |
||||
else |
||||
prev->next = p->next; |
||||
|
||||
ECPGfree_type(p->type); |
||||
free(p->name); |
||||
free(p); |
||||
p = prev; |
||||
} |
||||
else |
||||
prev = p; |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Here are the variables that need to be handled on every request. |
||||
* These are of two kinds: input and output. |
||||
* I will make two lists for them. |
||||
*/ |
||||
|
||||
struct arguments * argsinsert = NULL; |
||||
struct arguments * argsresult = NULL; |
||||
|
||||
void |
||||
reset_variables(void) |
||||
{ |
||||
argsinsert = NULL; |
||||
argsresult = NULL; |
||||
} |
||||
|
||||
|
||||
/* Add a variable to a request. */ |
||||
void |
||||
add_variable(struct arguments ** list, struct variable * var, struct variable * ind) |
||||
{ |
||||
struct arguments * p = (struct arguments *)mm_alloc(sizeof(struct arguments)); |
||||
p->variable = var; |
||||
p->indicator = ind; |
||||
p->next = *list; |
||||
*list = p; |
||||
} |
||||
|
||||
|
||||
/* Dump out a list of all the variable on this list.
|
||||
This is a recursive function that works from the end of the list and |
||||
deletes the list as we go on. |
||||
*/ |
||||
void |
||||
dump_variables(struct arguments * list, int mode) |
||||
{ |
||||
if (list == NULL) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
/* The list is build up from the beginning so lets first dump the
|
||||
end of the list: |
||||
*/ |
||||
|
||||
dump_variables(list->next, mode); |
||||
|
||||
/* Then the current element and its indicator */ |
||||
ECPGdump_a_type(yyout, list->variable->name, list->variable->type, |
||||
(list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->name : NULL, |
||||
(list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->type : NULL, NULL, NULL); |
||||
|
||||
/* Then release the list element. */ |
||||
if (mode != 0) |
||||
free(list); |
||||
} |
||||
|
||||
void |
||||
check_indicator(struct ECPGtype *var) |
||||
{ |
||||
/* make sure this is a valid indicator variable */ |
||||
switch (var->typ) |
||||
{ |
||||
struct ECPGstruct_member *p; |
||||
|
||||
case ECPGt_short: |
||||
case ECPGt_int: |
||||
case ECPGt_long: |
||||
case ECPGt_unsigned_short: |
||||
case ECPGt_unsigned_int: |
||||
case ECPGt_unsigned_long: |
||||
break; |
||||
|
||||
case ECPGt_struct: |
||||
case ECPGt_union: |
||||
for (p = var->u.members; p; p = p->next) |
||||
check_indicator(p->typ); |
||||
break; |
||||
|
||||
case ECPGt_array: |
||||
check_indicator(var->u.element); |
||||
break; |
||||
default:
|
||||
mmerror(ET_ERROR, "indicator variable must be integer type"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
struct typedefs * |
||||
get_typedef(char *name) |
||||
{ |
||||
struct typedefs *this; |
||||
|
||||
for (this = types; this && strcmp(this->name, name); this = this->next); |
||||
if (!this) |
||||
{ |
||||
sprintf(errortext, "invalid datatype '%s'", name); |
||||
mmerror(ET_FATAL, errortext); |
||||
} |
||||
|
||||
return(this); |
||||
} |
||||
|
||||
void |
||||
adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dimension, int type_index, bool pointer) |
||||
{ |
||||
if (type_index >= 0)
|
||||
{ |
||||
if (*length >= 0) |
||||
mmerror(ET_FATAL, "No multi-dimensional array support"); |
||||
|
||||
*length = type_index; |
||||
} |
||||
|
||||
if (type_dimension >= 0) |
||||
{ |
||||
if (*dimension >= 0 && *length >= 0) |
||||
mmerror(ET_FATAL, "No multi-dimensional array support"); |
||||
|
||||
if (*dimension >= 0) |
||||
*length = *dimension; |
||||
|
||||
*dimension = type_dimension; |
||||
} |
||||
|
||||
if (*length >= 0 && *dimension >= 0 && pointer) |
||||
mmerror(ET_FATAL, "No multi-dimensional array support"); |
||||
|
||||
switch (type_enum) |
||||
{ |
||||
case ECPGt_struct: |
||||
case ECPGt_union: |
||||
/* pointer has to get dimension 0 */ |
||||
if (pointer) |
||||
{ |
||||
*length = *dimension; |
||||
*dimension = 0; |
||||
} |
||||
|
||||
if (*length >= 0) |
||||
mmerror(ET_FATAL, "No multi-dimensional array support for structures"); |
||||
|
||||
break; |
||||
case ECPGt_varchar: |
||||
/* pointer has to get dimension 0 */ |
||||
if (pointer) |
||||
*dimension = 0; |
||||
|
||||
/* one index is the string length */ |
||||
if (*length < 0) |
||||
{ |
||||
*length = *dimension; |
||||
*dimension = -1; |
||||
} |
||||
|
||||
break; |
||||
case ECPGt_char: |
||||
case ECPGt_unsigned_char: |
||||
/* pointer has to get length 0 */ |
||||
if (pointer) |
||||
*length=0; |
||||
|
||||
/* one index is the string length */ |
||||
if (*length < 0) |
||||
{ |
||||
*length = (*dimension < 0) ? 1 : *dimension; |
||||
*dimension = -1; |
||||
} |
||||
|
||||
break; |
||||
default: |
||||
/* a pointer has dimension = 0 */ |
||||
if (pointer) { |
||||
*length = *dimension; |
||||
*dimension = 0; |
||||
} |
||||
|
||||
if (*length >= 0) |
||||
mmerror(ET_FATAL, "No multi-dimensional array support for simple data types"); |
||||
|
||||
break; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue