X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Finterfaces%2Fecpg%2Fpreproc%2Fpreproc.y;h=0c492febf015490705312f59f4ce8e30ebbdd78e;hb=35ba9de276150fd3d589509a86ae651924f34cb3;hp=02caacf4cf47524754c8d73dc235a8cb9e5afc5b;hpb=9f0ffa22417e47bca7655b809bd043dad4ac4601;p=postgresql diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 02caacf4cf..0c492febf0 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -1,5 +1,7 @@ /* Copyright comment */ %{ +#include + #include "postgres.h" #include "access/htup.h" #include "catalog/catname.h" @@ -13,7 +15,7 @@ #include "mb/pg_wchar.h" #endif -#define STRUCT_DEPTH 128 +#define EMPTY make_str("") /* * Variables containing simple states. @@ -21,9 +23,14 @@ int struct_level = 0; char errortext[128]; static char *connection = NULL; -static int QueryIsRule = 0, ForUpdateNotAllowed = 0; +static char *descriptor_name = NULL; +static char *descriptor_index= NULL; +static int QueryIsRule = 0, ForUpdateNotAllowed = 0, FoundInto = 0; +static int FoundSort = 0; +static int initializer = 0; static struct this_type actual_type[STRUCT_DEPTH]; static char *actual_storage[STRUCT_DEPTH]; +static char *actual_startline[STRUCT_DEPTH]; /* temporarily store struct members while creating the data structure */ struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL }; @@ -33,6 +40,33 @@ struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL}; struct ECPGtype ecpg_query = {ECPGt_char_variable, 0L, {NULL}}; +/* variable lookup */ + +static struct variable * find_variable(char * name); +static void whenever_action(int mode); + +/* + * Handle parsing errors and warnings + */ +void +mmerror(enum errortype type, char * error) +{ + + switch(type) + { + case ET_WARN: + 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 = PARSE_ERROR; + break; + case ET_FATAL: + fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error); + exit(PARSE_ERROR); + } +} + /* * Handle the filename and line numbering. */ @@ -42,7 +76,7 @@ void output_line_number() { if (input_filename) - fprintf(yyout, "\n#line %d \"%s\"\n", yylineno + 1, input_filename); + fprintf(yyout, "\n#line %d \"%s\"\n", yylineno, input_filename); } static void @@ -53,10 +87,279 @@ output_simple_statement(char *cmd) free(cmd); } +/* + * assignment handling function (descriptor) + */ + +static struct assignment *assignments; + +static 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; + } +} + +static 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); +} + +static 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); +} + /* * store the whenever action here */ -static struct when when_error, when_nf, when_warn; +struct when when_error, when_nf, when_warn; static void print_action(struct when *w) @@ -130,8 +433,6 @@ new_variable(const char * name, struct ECPGtype * type) return(p); } -static struct variable * find_variable(char * name); - static struct variable * find_struct_member(char *name, char *str, struct ECPGstruct_member *members) { @@ -192,13 +493,13 @@ find_struct(char * name, char *next) if (p->type->typ != ECPGt_struct && p->type->typ != ECPGt_union) { sprintf(errortext, "variable %s is not a pointer", name); - yyerror (errortext); + 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); - yyerror (errortext); + mmerror(ET_FATAL, errortext); } /* restore the name, we will need it later on */ @@ -212,7 +513,7 @@ find_struct(char * name, char *next) if (p->type->typ != ECPGt_struct && p->type->typ != ECPGt_union) { sprintf(errortext, "variable %s is neither a structure nor a union", name); - yyerror (errortext); + mmerror(ET_FATAL, errortext); } /* restore the name, we will need it later on */ @@ -254,7 +555,7 @@ find_variable(char * name) if (p == NULL) { sprintf(errortext, "The variable %s is not declared", name); - yyerror(errortext); + mmerror(ET_FATAL, errortext); } return(p); @@ -369,32 +670,72 @@ check_indicator(struct ECPGtype *var) check_indicator(var->u.element); break; default: - yyerror ("indicator variable must be integer type"); + mmerror(ET_ERROR, "indicator variable must be integer type"); break; } } -static char * -make1_str(const char *str) -{ - char * res_str = (char *)mm_alloc(strlen(str) + 1); +/* + * descriptor name lookup + */ + +static struct descriptor *descriptors; - strcpy(res_str, str); - return res_str; +static 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; } -static char * -make2_str(char *str1, char *str2) -{ - char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1); +static 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); +} - strcpy(res_str, str1); - strcat(res_str, str2); - free(str1); - free(str2); - return(res_str); +static 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; } +/* + * string concatenation + */ + static char * cat2_str(char *str1, char *str2) { @@ -409,109 +750,59 @@ cat2_str(char *str1, char *str2) } static char * -make3_str(char *str1, char *str2, char * str3) -{ - char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 1); - - strcpy(res_str, str1); - strcat(res_str, str2); - strcat(res_str, str3); - free(str1); - free(str2); - free(str3); - return(res_str); -} +cat_str(int count, ...) +{ + va_list args; + int i; + char *res_str; -static char * -cat3_str(char *str1, char *str2, char * str3) -{ - char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 3); - - strcpy(res_str, str1); - strcat(res_str, " "); - strcat(res_str, str2); - strcat(res_str, " "); - strcat(res_str, str3); - free(str1); - free(str2); - free(str3); - return(res_str); -} + va_start(args, count); -static char * -make4_str(char *str1, char *str2, char *str3, char *str4) -{ - char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + strlen(str4) + 1); - - strcpy(res_str, str1); - strcat(res_str, str2); - strcat(res_str, str3); - strcat(res_str, str4); - free(str1); - free(str2); - free(str3); - free(str4); - return(res_str); + res_str = va_arg(args, char *); + + /* now add all other strings */ + for (i = 1; i < count; i++) + res_str = cat2_str(res_str, va_arg(args, char *)); + + va_end(args); + + return(res_str); } static char * -cat4_str(char *str1, char *str2, char *str3, char *str4) -{ - char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + strlen(str4) + 4); - - strcpy(res_str, str1); - strcat(res_str, " "); - strcat(res_str, str2); - strcat(res_str, " "); - strcat(res_str, str3); - strcat(res_str, " "); - strcat(res_str, str4); - free(str1); - free(str2); - free(str3); - free(str4); - return(res_str); +make_str(const char *str) +{ + char * res_str = (char *)mm_alloc(strlen(str) + 1); + + strcpy(res_str, str); + return res_str; } static char * -make5_str(char *str1, char *str2, char *str3, char *str4, char *str5) -{ - char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + strlen(str4) + strlen(str5) + 1); - - strcpy(res_str, str1); - strcat(res_str, str2); - strcat(res_str, str3); - strcat(res_str, str4); - strcat(res_str, str5); +make2_str(char *str1, char *str2) +{ + char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1); + + strcpy(res_str, str1); + strcat(res_str, str2); free(str1); free(str2); - free(str3); - free(str4); - free(str5); - return(res_str); -} + return(res_str); +} static char * -cat5_str(char *str1, char *str2, char *str3, char *str4, char *str5) -{ - char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + strlen(str4) + strlen(str5) + 5); - - strcpy(res_str, str1); - strcat(res_str, " "); - strcat(res_str, str2); - strcat(res_str, " "); +make3_str(char *str1, char *str2, char *str3) +{ + char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) +strlen(str3) + 1); + + strcpy(res_str, str1); + strcat(res_str, str2); strcat(res_str, str3); - strcat(res_str, " "); - strcat(res_str, str4); - strcat(res_str, " "); - strcat(res_str, str5); free(str1); free(str2); free(str3); - free(str4); - free(str5); - return(res_str); -} + return(res_str); +} static char * make_name(void) @@ -523,6 +814,20 @@ make_name(void) return(name); } +static char * +hashline_number() +{ + if (input_filename) + { + char* line = mm_alloc(strlen("\n#line %d \"%s\"\n") + 21 + strlen(input_filename)); + sprintf(line, "\n#line %d \"%s\"\n", yylineno, input_filename); + + return line; + } + + return EMPTY; +} + static void output_statement(char * stmt, int mode) { @@ -531,9 +836,13 @@ output_statement(char * stmt, int mode) fprintf(yyout, "{ ECPGdo(__LINE__, %s, \"", connection ? connection : "NULL"); /* do this char by char as we have to filter '\"' */ - for (i = 0;i < j; i++) + for (i = 0;i < j; i++) { if (stmt[i] != '\"') fputc(stmt[i], yyout); + else + fputs("\\\"", yyout); + } + fputs("\", ", yyout); /* dump variables to C file*/ @@ -548,6 +857,32 @@ output_statement(char * stmt, int mode) free(connection); } +static 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); +} + static struct typedefs * get_typedef(char *name) { @@ -557,7 +892,7 @@ get_typedef(char *name) if (!this) { sprintf(errortext, "invalid datatype '%s'", name); - yyerror(errortext); + mmerror(ET_FATAL, errortext); } return(this); @@ -569,7 +904,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim if (type_index >= 0) { if (*length >= 0) - yyerror("No multi-dimensional array support"); + mmerror(ET_FATAL, "No multi-dimensional array support"); *length = type_index; } @@ -577,7 +912,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim if (type_dimension >= 0) { if (*dimension >= 0 && *length >= 0) - yyerror("No multi-dimensional array support"); + mmerror(ET_FATAL, "No multi-dimensional array support"); if (*dimension >= 0) *length = *dimension; @@ -586,7 +921,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim } if (*length >= 0 && *dimension >= 0 && pointer) - yyerror("No multi-dimensional array support"); + mmerror(ET_FATAL, "No multi-dimensional array support"); switch (type_enum) { @@ -600,7 +935,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim } if (*length >= 0) - yyerror("No multi-dimensional array support for structures"); + mmerror(ET_FATAL, "No multi-dimensional array support for structures"); break; case ECPGt_varchar: @@ -638,7 +973,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim } if (*length >= 0) - yyerror("No multi-dimensional array support for simple data types"); + mmerror(ET_FATAL, "No multi-dimensional array support for simple data types"); break; } @@ -658,21 +993,20 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim } /* special embedded SQL token */ -%token SQL_AT SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK +%token SQL_ALLOCATE SQL_AT SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK %token SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE -%token SQL_DEALLOCATE SQL_DISCONNECT SQL_ENUM -%token SQL_FOUND SQL_FREE SQL_GO SQL_GOTO -%token SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_INT SQL_LONG +%token SQL_DEALLOCATE SQL_DESCRIPTOR SQL_DISCONNECT SQL_ENUM +%token SQL_FOUND SQL_FREE SQL_GET SQL_GO SQL_GOTO +%token SQL_IDENTIFIED SQL_INDICATOR SQL_INT SQL_LONG %token SQL_OFF SQL_OPEN SQL_PREPARE SQL_RELEASE SQL_REFERENCE -%token SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQLERROR SQL_SQLPRINT +%token SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL +%token SQL_SQLERROR SQL_SQLPRINT %token SQL_SQLWARNING SQL_START SQL_STOP SQL_STRUCT SQL_UNSIGNED -%token SQL_VAR SQL_WHENEVER +%token SQL_VALUE SQL_VAR SQL_WHENEVER /* C token */ -%token S_ANYTHING S_AUTO S_BOOL S_CHAR S_CONST S_DOUBLE S_ENUM S_EXTERN -%token S_FLOAT S_INT S -%token S_LONG S_REGISTER S_SHORT S_SIGNED S_STATIC S_STRUCT -%token S_UNION S_UNSIGNED S_VARCHAR +%token S_ANYTHING S_AUTO S_CONST S_EXTERN +%token S_REGISTER S_STATIC S_VOLATILE /* I need this and don't know where it is defined inside the backend */ %token TYPECAST @@ -682,9 +1016,9 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim BEGIN_TRANS, BETWEEN, BOTH, BY, CASCADE, CASE, CAST, CHAR, CHARACTER, CHECK, CLOSE, COALESCE, COLLATE, COLUMN, COMMIT, - CONSTRAINT, CREATE, CROSS, CURRENT, CURRENT_DATE, CURRENT_TIME, - CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, - DAY_P, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP, + CONSTRAINT, CONSTRAINTS, CREATE, CROSS, CURRENT, CURRENT_DATE, + CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, + DAY_P, DEC, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP, ELSE, END_TRANS, EXCEPT, EXECUTE, EXISTS, EXTRACT, FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL, GLOBAL, GRANT, GROUP, HAVING, HOUR_P, @@ -695,7 +1029,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P, PARTIAL, POSITION, PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, PUBLIC, READ, REFERENCES, RELATIVE, REVOKE, RIGHT, ROLLBACK, - SCROLL, SECOND_P, SELECT, SET, SUBSTRING, + SCROLL, SECOND_P, SELECT, SESSION_USER, SET, SUBSTRING, TABLE, TEMP, TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE, TO, TRAILING, TRANSACTION, TRIM, TRUE_P, UNION, UNIQUE, UPDATE, USER, USING, @@ -703,7 +1037,11 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim WHEN, WHERE, WITH, WORK, YEAR_P, ZONE /* Keywords (in SQL3 reserved words) */ -%token TRIGGER +%token DEFERRABLE, DEFERRED, + IMMEDIATE, INITIALLY, + PENDANT, + RESTRICT, + TRIGGER /* Keywords (in SQL92 non-reserved words) */ %token COMMITTED, SERIALIZABLE, TYPE_P @@ -716,7 +1054,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim */ %token ABORT_TRANS, ACCESS, AFTER, AGGREGATE, ANALYZE, BACKWARD, BEFORE, BINARY, - CACHE, CLUSTER, COPY, CREATEDB, CREATEUSER, CYCLE, + CACHE, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE, DATABASE, DELIMITERS, DO, EACH, ENCODING, EXCLUSIVE, EXPLAIN, EXTEND, FORWARD, FUNCTION, HANDLER, @@ -726,8 +1064,8 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL, OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL, RENAME, RESET, RETURNS, ROW, RULE, - SERIAL, SEQUENCE, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, - TRUSTED, + SEQUENCE, SERIAL, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, SYSID + TRUNCATE, TRUSTED, UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION /* Special keywords, not in the query language - see the "lex" file */ @@ -762,90 +1100,104 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim %right UMINUS %left '.' %left '[' ']' -%nonassoc TYPECAST +%left TYPECAST %left UNION INTERSECT EXCEPT %type Iconst Fconst Sconst TransactionStmt CreateStmt UserId %type CreateAsElement OptCreateAs CreateAsList CreateAsStmt -%type OptInherit key_reference key_action -%type key_match constraint_expr ColLabel SpecialRuleRelation -%type ColId default_expr ColQualifier columnDef ColQualList -%type ColConstraint ColConstraintElem default_list NumericOnly FloatOnly +%type OptInherit key_reference key_action comment_text +%type key_match ColLabel SpecialRuleRelation ColId columnDef +%type ColConstraint ColConstraintElem NumericOnly FloatOnly %type OptTableElementList OptTableElement TableConstraint -%type ConstraintElem key_actions constraint_list ColPrimaryKey -%type target_list target_el update_target_list +%type ConstraintElem key_actions ColPrimaryKey ColQualList +%type target_list target_el update_target_list alias_clause %type update_target_el opt_id relation_name database_name %type access_method attr_name class index_name name func_name -%type file_name AexprConst ParamNo TypeId -%type in_expr_nodes not_in_expr_nodes a_expr b_expr +%type file_name AexprConst ParamNo TypeId c_expr ColQualListWithNull +%type in_expr_nodes a_expr b_expr TruncateStmt CommentStmt %type opt_indirection expr_list extract_list extract_arg -%type position_list substr_list substr_from -%type trim_list in_expr substr_for not_in_expr attr attrs +%type position_list substr_list substr_from alter_column_action +%type trim_list in_expr substr_for attr attrs drop_behavior %type Typename SimpleTypename Generic Numeric generic opt_float opt_numeric %type opt_decimal Character character opt_varying opt_charset %type opt_collate Datetime datetime opt_timezone opt_interval %type numeric a_expr_or_null row_expr row_descriptor row_list %type SelectStmt SubSelect result OptTemp OptTempType OptTempScope -%type opt_table opt_union opt_unique sort_clause sortby_list +%type opt_table opt_all sort_clause sortby_list ColQualifier %type sortby OptUseOp opt_inh_star relation_name_list name_list -%type group_clause having_clause from_clause c_list -%type table_list join_outer where_clause relation_expr row_op sub_type +%type group_clause having_clause from_clause opt_distinct +%type join_outer where_clause relation_expr sub_type %type opt_column_list insert_rest InsertStmt OptimizableStmt %type columnList DeleteStmt LockStmt UpdateStmt CursorStmt -%type NotifyStmt columnElem copy_dirn c_expr UnlistenStmt +%type NotifyStmt columnElem copy_dirn UnlistenStmt copy_null %type copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary -%type opt_with_copy FetchStmt opt_direction fetch_how_many opt_portal_name -%type ClosePortalStmt DestroyStmt VacuumStmt opt_verbose +%type opt_with_copy FetchStmt direction fetch_how_many from_in +%type ClosePortalStmt DropStmt VacuumStmt opt_verbose %type opt_analyze opt_va_list va_list ExplainStmt index_params %type index_list func_index index_elem opt_type opt_class access_method_clause %type index_opt_unique IndexStmt set_opt func_return def_rest %type func_args_list func_args opt_with ProcedureStmt def_arg %type def_elem def_list definition def_name def_type DefineStmt -%type opt_instead event event_object RuleActionList, -%type RuleActionBlock RuleActionMulti join_list -%type RuleStmt opt_column opt_name oper_argtypes +%type opt_instead event event_object RuleActionList opt_using +%type RuleActionStmtOrEmpty RuleActionMulti func_as +%type RuleStmt opt_column opt_name oper_argtypes sysid_clause %type MathOp RemoveFuncStmt aggr_argtype for_update_clause %type RemoveAggrStmt remove_type RemoveStmt ExtendStmt %type RemoveOperStmt RenameStmt all_Op user_valid_clause %type VariableSetStmt var_value zone_value VariableShowStmt -%type VariableResetStmt AddAttrStmt alter_clause DropUserStmt +%type VariableResetStmt AlterTableStmt DropUserStmt from_list %type user_passwd_clause user_createdb_clause opt_trans -%type user_createuser_clause user_group_list user_group_clause +%type user_createuser_clause user_list user_group_clause %type CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList %type OptSeqElem TriggerForSpec TriggerForOpt TriggerForType %type DropTrigStmt TriggerOneEvent TriggerEvents RuleActionStmt %type TriggerActionTime CreateTrigStmt DropPLangStmt PLangTrusted %type CreatePLangStmt IntegerOnly TriggerFuncArgs TriggerFuncArg -%type ViewStmt LoadStmt CreatedbStmt opt_database1 opt_database2 location -%type DestroydbStmt ClusterStmt grantee RevokeStmt encoding +%type ViewStmt LoadStmt CreatedbStmt createdb_opt_encoding +%type createdb_opt_location opt_encoding AlterTableStmt +%type DropdbStmt ClusterStmt grantee RevokeStmt table_expr %type GrantStmt privileges operation_commalist operation -%type opt_cursor opt_lmode +%type opt_cursor opt_lmode ConstraintsSetStmt comment_tg %type case_expr when_clause_list case_default case_arg when_clause %type select_clause opt_select_limit select_limit_value -%type select_offset_value table_list using_expr join_expr -%type using_list from_expr table_expr join_clause join_type +%type select_offset_value using_expr join_expr +%type using_list from_expr join_clause join_type %type join_qual update_list join_clause join_clause_with_union -%type opt_level opt_lock lock_type +%type opt_level opt_lock lock_type users_in_new_group_clause +%type OptConstrFromTable comment_op ConstraintAttributeSpec +%type constraints_set_list constraints_set_namelist comment_fn +%type constraints_set_mode comment_type comment_cl comment_ag +%type ConstraintDeferrabilitySpec ConstraintTimeSpec +%type CreateGroupStmt AlterGroupStmt DropGroupStmt +%type ColConstraintWithNull ColConstraintElemWithNull +%type join_expr_with_union +/*** +#ifdef ENABLE_ORACLE_JOIN_SYNTAX +%type oracle_list oracle_expr oracle_outer +#endif +***/ -%type ECPGWhenever ECPGConnect connection_target ECPGOpen opt_using -%type indicator ECPGExecute ecpg_expr dotext ECPGPrepare -%type storage_clause opt_initializer vartext c_anything blockstart -%type blockend variable_list variable var_anything do_anything -%type opt_pointer cvariable ECPGDisconnect dis_name +%type ECPGWhenever ECPGConnect connection_target ECPGOpen +%type indicator ECPGExecute ECPGPrepare ecpg_using +%type storage_clause opt_initializer c_anything blockstart +%type blockend variable_list variable c_thing c_term +%type opt_pointer cvariable ECPGDisconnect dis_name storage_modifier %type stmt symbol opt_symbol ECPGRelease execstring server_name -%type connection_object opt_server opt_port c_thing opt_reference +%type connection_object opt_server opt_port c_stuff opt_reference %type user_name opt_user char_variable ora_user ident -%type db_prefix server opt_options opt_connection_name -%type ECPGSetConnection c_line cpp_line s_enum ECPGTypedef +%type db_prefix server opt_options opt_connection_name c_list +%type ECPGSetConnection cpp_line ECPGTypedef c_args %type enum_type civariableonly ECPGCursorStmt ECPGDeallocate -%type ECPGFree ECPGDeclare ECPGVar sql_variable_declarations -%type sql_declaration sql_variable_list sql_variable opt_at -%type struct_type s_struct declaration variable_declarations +%type ECPGFree ECPGDeclare ECPGVar opt_at enum_definition +%type struct_type s_struct declaration declarations variable_declarations %type s_struct s_union union_type ECPGSetAutocommit on_off +%type ECPGAllocateDescr ECPGDeallocateDescr +%type ECPGGetDescriptor ECPGGetDescriptorHeader +%type FetchDescriptorStmt -%type simple_type varchar_type +%type simple_type signed_type unsigned_type varchar_type -%type type ctype +%type type %type action @@ -868,25 +1220,31 @@ statement: ecpgstart opt_at stmt ';' { connection = NULL; } opt_at: SQL_AT connection_target { connection = $2; } -stmt: AddAttrStmt { output_statement($1, 0); } +stmt: AlterTableStmt { output_statement($1, 0); } + | AlterGroupStmt { output_statement($1, 0); } | AlterUserStmt { output_statement($1, 0); } | ClosePortalStmt { output_statement($1, 0); } + | CommentStmt { output_statement($1, 0); } | CopyStmt { output_statement($1, 0); } | CreateStmt { output_statement($1, 0); } | CreateAsStmt { output_statement($1, 0); } + | CreateGroupStmt { output_statement($1, 0); } | CreateSeqStmt { output_statement($1, 0); } | CreatePLangStmt { output_statement($1, 0); } | CreateTrigStmt { output_statement($1, 0); } | CreateUserStmt { output_statement($1, 0); } | ClusterStmt { output_statement($1, 0); } | DefineStmt { output_statement($1, 0); } - | DestroyStmt { output_statement($1, 0); } + | DropStmt { output_statement($1, 0); } + | TruncateStmt { output_statement($1, 0); } + | DropGroupStmt { output_statement($1, 0); } | DropPLangStmt { output_statement($1, 0); } | DropTrigStmt { output_statement($1, 0); } | DropUserStmt { output_statement($1, 0); } | ExtendStmt { output_statement($1, 0); } | ExplainStmt { output_statement($1, 0); } | FetchStmt { output_statement($1, 1); } + | FetchDescriptorStmt { output_statement_desc($1, 1); } | GrantStmt { output_statement($1, 0); } | IndexStmt { output_statement($1, 0); } | ListenStmt { output_statement($1, 0); } @@ -914,14 +1272,19 @@ stmt: AddAttrStmt { output_statement($1, 0); } | ViewStmt { output_statement($1, 0); } | LoadStmt { output_statement($1, 0); } | CreatedbStmt { output_statement($1, 0); } - | DestroydbStmt { output_statement($1, 0); } + | DropdbStmt { output_statement($1, 0); } | VacuumStmt { output_statement($1, 0); } | VariableSetStmt { output_statement($1, 0); } | VariableShowStmt { output_statement($1, 0); } | VariableResetStmt { output_statement($1, 0); } + | ConstraintsSetStmt { output_statement($1, 0); } + | ECPGAllocateDescr { fprintf(yyout,"ECPGallocate_desc(__LINE__, \"%s\");",$1); + whenever_action(0); + free($1); + } | ECPGConnect { if (connection) - yyerror("no at option for connect statement.\n"); + mmerror(ET_ERROR, "no at option for connect statement.\n"); fprintf(yyout, "{ ECPGconnect(__LINE__, %s, %d);", $1, autocommit); whenever_action(2); @@ -932,19 +1295,23 @@ stmt: AddAttrStmt { output_statement($1, 0); } } | ECPGDeallocate { if (connection) - yyerror("no at option for connect statement.\n"); + mmerror(ET_ERROR, "no at option for connect statement.\n"); fputc('{', yyout); fputs($1, yyout); whenever_action(2); free($1); } + | ECPGDeallocateDescr { fprintf(yyout,"ECPGdeallocate_desc(__LINE__, \"%s\");",$1); + whenever_action(0); + free($1); + } | ECPGDeclare { output_simple_statement($1); } | ECPGDisconnect { if (connection) - yyerror("no at option for disconnect statement.\n"); + mmerror(ET_ERROR, "no at option for disconnect statement.\n"); fprintf(yyout, "{ ECPGdisconnect(__LINE__, \"%s\");", $1); whenever_action(2); @@ -954,10 +1321,19 @@ stmt: AddAttrStmt { output_statement($1, 0); } output_statement($1, 0); } | ECPGFree { - fprintf(yyout, "{ ECPGdeallocate(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1); + fprintf(yyout, "{ ECPGdeallocate(__LINE__, \"%s\");", $1); + whenever_action(2); free($1); } + | ECPGGetDescriptor { + lookup_descriptor($1,connection); + output_get_descr($1); + } + | ECPGGetDescriptorHeader { + lookup_descriptor($1,connection); + output_get_descr_header($1); + } | ECPGOpen { struct cursor *ptr; @@ -970,7 +1346,7 @@ stmt: AddAttrStmt { output_statement($1, 0); } if (ptr == NULL) { sprintf(errortext, "trying to open undeclared cursor %s\n", $1); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } fprintf(yyout, "{ ECPGdo(__LINE__, %s, \"%s\",", ptr->connection ? ptr->connection : "NULL", ptr->command); @@ -985,7 +1361,7 @@ stmt: AddAttrStmt { output_statement($1, 0); } } | ECPGPrepare { if (connection) - yyerror("no at option for set connection statement.\n"); + mmerror(ET_ERROR, "no at option for set connection statement.\n"); fprintf(yyout, "{ ECPGprepare(__LINE__, %s);", $1); whenever_action(2); @@ -999,7 +1375,7 @@ stmt: AddAttrStmt { output_statement($1, 0); } } | ECPGSetConnection { if (connection) - yyerror("no at option for set connection statement.\n"); + mmerror(ET_ERROR, "no at option for set connection statement.\n"); fprintf(yyout, "{ ECPGsetconn(__LINE__, %s);", $1); whenever_action(2); @@ -1007,19 +1383,19 @@ stmt: AddAttrStmt { output_statement($1, 0); } } | ECPGTypedef { if (connection) - yyerror("no at option for typedef statement.\n"); + mmerror(ET_ERROR, "no at option for typedef statement.\n"); output_simple_statement($1); } | ECPGVar { if (connection) - yyerror("no at option for var statement.\n"); + mmerror(ET_ERROR, "no at option for var statement.\n"); output_simple_statement($1); } | ECPGWhenever { if (connection) - yyerror("no at option for whenever statement.\n"); + mmerror(ET_ERROR, "no at option for whenever statement.\n"); output_simple_statement($1); } @@ -1037,69 +1413,89 @@ stmt: AddAttrStmt { output_statement($1, 0); } * *****************************************************************************/ -CreateUserStmt: CREATE USER UserId user_passwd_clause user_createdb_clause - user_createuser_clause user_group_clause user_valid_clause +CreateUserStmt: CREATE USER UserId + user_createdb_clause user_createuser_clause user_group_clause + user_valid_clause { - $$ = cat3_str(cat5_str(make1_str("create user"), $3, $4, $5, $6), $7, $8); + $$ = cat_str(6, make_str("create user"), $3, $4, $5, $6, $7); } + | CREATE USER UserId WITH sysid_clause user_passwd_clause + user_createdb_clause user_createuser_clause user_group_clause + user_valid_clause + { + $$ = cat_str(9, make_str("create user"), $3, make_str("with"), $5, $6, $7, $8, $9, $10); + } ; /***************************************************************************** * - * Alter a postresql DBMS user + * Alter a postgresql DBMS user * * *****************************************************************************/ -AlterUserStmt: ALTER USER UserId user_passwd_clause user_createdb_clause - user_createuser_clause user_group_clause user_valid_clause +AlterUserStmt: ALTER USER UserId user_createdb_clause + user_createuser_clause user_valid_clause + { + $$ = cat_str(5, make_str("alter user"), $3, $4, $5, $6); + } + | ALTER USER UserId WITH PASSWORD Sconst + user_createdb_clause + user_createuser_clause user_valid_clause { - $$ = cat3_str(cat5_str(make1_str("alter user"), $3, $4, $5, $6), $7, $8); + $$ = cat_str(7, make_str("alter user"), $3, make_str("with password"), $6, $7, $8, $9); } ; /***************************************************************************** * - * Drop a postresql DBMS user + * Drop a postgresql DBMS user * * *****************************************************************************/ -DropUserStmt: DROP USER UserId +DropUserStmt: DROP USER user_list { - $$ = cat2_str(make1_str("drop user"), $3); + $$ = cat2_str(make_str("drop user"), $3); } ; -user_passwd_clause: WITH PASSWORD UserId { $$ = cat2_str(make1_str("with password") , $3); } - | /*EMPTY*/ { $$ = make1_str(""); } +user_passwd_clause: PASSWORD Sconst { $$ = cat2_str(make_str("password") , $2); } + | /*EMPTY*/ { $$ = EMPTY; } ; +sysid_clause: SYSID Iconst { if (atoi($2) <= 0) + mmerror(ET_ERROR, "sysid must be positive"); + + $$ = cat2_str(make_str("sysid"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + user_createdb_clause: CREATEDB { - $$ = make1_str("createdb"); + $$ = make_str("createdb"); } | NOCREATEDB { - $$ = make1_str("nocreatedb"); + $$ = make_str("nocreatedb"); } - | /*EMPTY*/ { $$ = make1_str(""); } + | /*EMPTY*/ { $$ = EMPTY; } ; user_createuser_clause: CREATEUSER { - $$ = make1_str("createuser"); + $$ = make_str("createuser"); } | NOCREATEUSER { - $$ = make1_str("nocreateuser"); + $$ = make_str("nocreateuser"); } | /*EMPTY*/ { $$ = NULL; } ; -user_group_list: user_group_list ',' UserId +user_list: user_list ',' UserId { - $$ = cat3_str($1, make1_str(","), $3); + $$ = cat_str(3, $1, make_str(","), $3); } | UserId { @@ -1107,14 +1503,68 @@ user_group_list: user_group_list ',' UserId } ; -user_group_clause: IN GROUP user_group_list { $$ = cat2_str(make1_str("in group"), $3); } - | /*EMPTY*/ { $$ = make1_str(""); } +user_group_clause: IN GROUP user_list + { + $$ = cat2_str(make_str("in group"), $3); + } + | /*EMPTY*/ { $$ = EMPTY; } ; -user_valid_clause: VALID UNTIL Sconst { $$ = cat2_str(make1_str("valid until"), $3); } - | /*EMPTY*/ { $$ = make1_str(""); } +user_valid_clause: VALID UNTIL Sconst { $$ = cat2_str(make_str("valid until"), $3); } + | /*EMPTY*/ { $$ = EMPTY; } ; + +/***************************************************************************** + * + * Create a postgresql group + * + * + ****************************************************************************/ +CreateGroupStmt: CREATE GROUP UserId + { + $$ = cat2_str(make_str("create group"), $3); + } + | CREATE GROUP UserId WITH sysid_clause users_in_new_group_clause + { + $$ = cat_str(5, make_str("create group"), $3, make_str("with"), $5, $6); + } + ; + +users_in_new_group_clause: USER user_list { $$ = cat2_str(make_str("user"), $2); } + | /* EMPTY */ { $$ = EMPTY; } + ; + + +/***************************************************************************** + * + * Alter a postgresql group + * + * + *****************************************************************************/ +AlterGroupStmt: ALTER GROUP UserId ADD USER user_list + { + $$ = cat_str(4, make_str("alter group"), $3, make_str("add user"), $6); + } + | ALTER GROUP UserId DROP USER user_list + { + $$ = cat_str(4, make_str("alter group"), $3, make_str("drop user"), $6); + } + ; + +/***************************************************************************** + * + * Drop a postgresql group + * + * + *****************************************************************************/ +DropGroupStmt: DROP GROUP UserId + { + $$ = cat2_str(make_str("drop group"), $3); + } + ; + + /***************************************************************************** * * Set PG internal variable @@ -1126,103 +1576,161 @@ user_valid_clause: VALID UNTIL Sconst { $$ = cat2_str(make1_str("valid until" VariableSetStmt: SET ColId TO var_value { - $$ = cat4_str(make1_str("set"), $2, make1_str("to"), $4); + $$ = cat_str(4, make_str("set"), $2, make_str("to"), $4); } | SET ColId '=' var_value { - $$ = cat4_str(make1_str("set"), $2, make1_str("="), $4); + $$ = cat_str(4, make_str("set"), $2, make_str("="), $4); } | SET TIME ZONE zone_value { - $$ = cat2_str(make1_str("set time zone"), $4); + $$ = cat2_str(make_str("set time zone"), $4); } | SET TRANSACTION ISOLATION LEVEL opt_level { - $$ = cat2_str(make1_str("set transaction isolation level"), $5); + $$ = cat2_str(make_str("set transaction isolation level"), $5); } - | SET NAMES encoding + | SET NAMES opt_encoding { -#ifdef MB - $$ = cat2_str(make1_str("set names"), $3); +#ifdef MULTIBYTE + $$ = cat2_str(make_str("set names"), $3); #else - yyerror("SET NAMES is not supported"); + mmerror(ET_ERROR, "SET NAMES is not supported."); #endif } ; -opt_level: READ COMMITTED { $$ = make1_str("read committed"); } - | SERIALIZABLE { $$ = make1_str("serializable"); } +opt_level: READ COMMITTED { $$ = make_str("read committed"); } + | SERIALIZABLE { $$ = make_str("serializable"); } ; var_value: Sconst { $$ = $1; } - | DEFAULT { $$ = make1_str("default"); } + | DEFAULT { $$ = make_str("default"); } ; zone_value: Sconst { $$ = $1; } - | DEFAULT { $$ = make1_str("default"); } - | LOCAL { $$ = make1_str("local"); } + | DEFAULT { $$ = make_str("default"); } + | LOCAL { $$ = make_str("local"); } + ; + +opt_encoding: Sconst { $$ = $1; } + | DEFAULT { $$ = make_str("default"); } + | /*EMPTY*/ { $$ = EMPTY; } ; VariableShowStmt: SHOW ColId { - $$ = cat2_str(make1_str("show"), $2); + $$ = cat2_str(make_str("show"), $2); } | SHOW TIME ZONE { - $$ = make1_str("show time zone"); + $$ = make_str("show time zone"); } | SHOW TRANSACTION ISOLATION LEVEL { - $$ = make1_str("show transaction isolation level"); + $$ = make_str("show transaction isolation level"); } ; VariableResetStmt: RESET ColId { - $$ = cat2_str(make1_str("reset"), $2); + $$ = cat2_str(make_str("reset"), $2); } | RESET TIME ZONE { - $$ = make1_str("reset time zone"); + $$ = make_str("reset time zone"); } | RESET TRANSACTION ISOLATION LEVEL { - $$ = make1_str("reset transaction isolation level"); + $$ = make_str("reset transaction isolation level"); } ; - -/***************************************************************************** +ConstraintsSetStmt: SET CONSTRAINTS constraints_set_list constraints_set_mode + { + $$ = cat_str(3, make_str("set constraints"), $3, $4); + } + ; + +constraints_set_list: ALL + { + $$ = make_str("all"); + } + | constraints_set_namelist + { + $$ = $1; + } + ; + + +constraints_set_namelist: IDENT + { + $$ = $1; + } + | constraints_set_namelist ',' IDENT + { + $$ = cat_str(3, $1, make_str(","), $3); + } + ; + +constraints_set_mode: DEFERRED + { + $$ = make_str("deferred"); + } + | IMMEDIATE + { + $$ = make_str("immediate"); + } + ; + +/***************************************************************************** * * QUERY : - * addattr ( attr1 = type1 .. attrn = typen ) to [*] + * + * ALTER TABLE variations * *****************************************************************************/ -AddAttrStmt: ALTER TABLE relation_name opt_inh_star alter_clause - { - $$ = cat4_str(make1_str("alter table"), $3, $4, $5); - } +AlterTableStmt: +/* ALTER TABLE ADD [COLUMN] */ + ALTER TABLE relation_name opt_inh_star ADD opt_column columnDef + { + $$ = cat_str(6, make_str("alter table"), $3, $4, make_str("add"), $6, $7); + } +/* ALTER TABLE ALTER [COLUMN] {SET DEFAULT |DROP +DEFAULT} */ + | ALTER TABLE relation_name opt_inh_star ALTER opt_column ColId + alter_column_action + { + $$ = cat_str(7, make_str("alter table"), $3, $4, make_str("alter"), $6, $7, $8); + } +/* ALTER TABLE DROP [COLUMN] {RESTRICT|CASCADE} */ + | ALTER TABLE relation_name opt_inh_star DROP opt_column ColId drop_behavior + { + $$ = cat_str(7, make_str("alter table"), $3, $4, make_str("drop"), $6, $7, $8); + } +/* ALTER TABLE ADD CONSTRAINT ... */ + | ALTER TABLE relation_name opt_inh_star ADD TableConstraint + { + $$ = cat_str(5, make_str("alter table"), $3, $4, make_str("add"), $6); + } +/* ALTER TABLE DROP CONSTRAINT ... */ + | ALTER TABLE relation_name opt_inh_star DROP CONSTRAINT name drop_behavior + { + $$ = cat_str(6, make_str("alter table"), $3, $4, make_str("drop constraint"), $7, $8); + } ; -alter_clause: ADD opt_column columnDef - { - $$ = cat3_str(make1_str("add"), $2, $3); - } - | ADD '(' OptTableElementList ')' - { - $$ = make3_str(make1_str("add("), $3, make1_str(")")); - } - | DROP opt_column ColId - { yyerror("ALTER TABLE/DROP COLUMN not yet implemented"); } - | ALTER opt_column ColId SET DEFAULT default_expr - { yyerror("ALTER TABLE/ALTER COLUMN/SET DEFAULT not yet implemented"); } - | ALTER opt_column ColId DROP DEFAULT - { yyerror("ALTER TABLE/ALTER COLUMN/DROP DEFAULT not yet implemented"); } - | ADD ConstraintElem - { yyerror("ALTER TABLE/ADD CONSTRAINT not yet implemented"); } - ; +alter_column_action: + SET DEFAULT a_expr { $$ = cat2_str(make_str("set default"), $3); } + | SET DEFAULT NULL_P { $$ = make_str("set default null"); } + | DROP DEFAULT { $$ = make_str("drop default"); } + ; + +drop_behavior: CASCADE { $$ = make_str("cascade"); } + | RESTRICT { $$ = make_str("restrict"); } + ; /***************************************************************************** * @@ -1233,7 +1741,7 @@ alter_clause: ADD opt_column columnDef ClosePortalStmt: CLOSE opt_id { - $$ = cat2_str(make1_str("close"), $2); + $$ = cat2_str(make_str("close"), $2); } ; @@ -1249,16 +1757,16 @@ opt_id: ColId { $$ = $1; } * *****************************************************************************/ -CopyStmt: COPY opt_binary relation_name opt_with_copy copy_dirn copy_file_name copy_delimiter +CopyStmt: COPY opt_binary relation_name opt_with_copy copy_dirn copy_file_name copy_delimiter copy_null { - $$ = cat3_str(cat5_str(make1_str("copy"), $2, $3, $4, $5), $6, $7); + $$ = cat_str(8, make_str("copy"), $2, $3, $4, $5, $6, $7, $8); } ; copy_dirn: TO - { $$ = make1_str("to"); } + { $$ = make_str("to"); } | FROM - { $$ = make1_str("from"); } + { $$ = make_str("from"); } ; /* @@ -1267,26 +1775,32 @@ copy_dirn: TO * stdout. We silently correct the "typo". - AY 9/94 */ copy_file_name: Sconst { $$ = $1; } - | STDIN { $$ = make1_str("stdin"); } - | STDOUT { $$ = make1_str("stdout"); } + | STDIN { $$ = make_str("stdin"); } + | STDOUT { $$ = make_str("stdout"); } ; -opt_binary: BINARY { $$ = make1_str("binary"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_binary: BINARY { $$ = make_str("binary"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_with_copy: WITH OIDS { $$ = make1_str("with oids"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_with_copy: WITH OIDS { $$ = make_str("with oids"); } + | /*EMPTY*/ { $$ = EMPTY; } ; /* * the default copy delimiter is tab but the user can configure it */ -copy_delimiter: USING DELIMITERS Sconst { $$ = cat2_str(make1_str("using delimiters"), $3); } - | /*EMPTY*/ { $$ = make1_str(""); } +copy_delimiter: opt_using DELIMITERS Sconst { $$ = cat_str(3, $1, make_str("delimiters"), $3); } + | /*EMPTY*/ { $$ = EMPTY; } ; +opt_using: USING { $$ = make_str("using"); } + | /* EMPTY */ { $$ = EMPTY; } + ; +copy_null: WITH NULL_P AS Sconst { $$ = cat2_str(make_str("with null as"), $4); } + | /* EMPTY */ { $$ = EMPTY; } + ; /***************************************************************************** * @@ -1298,7 +1812,7 @@ copy_delimiter: USING DELIMITERS Sconst { $$ = cat2_str(make1_str("using delim CreateStmt: CREATE OptTemp TABLE relation_name '(' OptTableElementList ')' OptInherit { - $$ = cat3_str(cat4_str(make1_str("create"), $2, make1_str("table"), $4), make3_str(make1_str("("), $6, make1_str(")")), $8); + $$ = cat_str(8, make_str("create"), $2, make_str("table"), $4, make_str("("), $6, make_str(")"), $8); } ; @@ -1306,29 +1820,29 @@ OptTemp: OptTempType { $$ = $1; } | OptTempScope OptTempType { $$ = cat2_str($1,$2); } ; -OptTempType: TEMP { $$ = make1_str("temp"); } - | TEMPORARY { $$ = make1_str("temporary"); } - | /* EMPTY */ { $$ = make1_str(""); } +OptTempType: TEMP { $$ = make_str("temp"); } + | TEMPORARY { $$ = make_str("temporary"); } + | /* EMPTY */ { $$ = EMPTY; } ; OptTempScope: GLOBAL { - yyerror("GLOBAL TEMPORARY TABLE is not currently supported"); - $$ = make1_str("global"); + mmerror(ET_ERROR, "GLOBAL TEMPORARY TABLE is not currently supported"); + $$ = make_str("global"); } - | LOCAL { $$ = make1_str("local"); } + | LOCAL { $$ = make_str("local"); } ; OptTableElementList: OptTableElementList ',' OptTableElement { - $$ = cat3_str($1, make1_str(","), $3); + $$ = cat_str(3, $1, make_str(","), $3); } | OptTableElement { $$ = $1; } - | /*EMPTY*/ { $$ = make1_str(""); } + | /*EMPTY*/ { $$ = EMPTY; } ; OptTableElement: columnDef { $$ = $1; } @@ -1337,175 +1851,104 @@ OptTableElement: columnDef { $$ = $1; } columnDef: ColId Typename ColQualifier { - $$ = cat3_str($1, $2, $3); + $$ = cat_str(3, $1, $2, $3); } | ColId SERIAL ColPrimaryKey { - $$ = make3_str($1, make1_str(" serial "), $3); + $$ = cat_str(3, $1, make_str(" serial "), $3); } ; -ColQualifier: ColQualList { $$ = $1; } - | /*EMPTY*/ { $$ = make1_str(""); } +ColQualifier: ColQualList { $$ = $1; } + | NULL_P ColQualListWithNull { $$ = cat2_str(make_str("null"), $2); } + | NULL_P { $$ = make_str("null"); } + | /*EMPTY*/ { $$ = EMPTY; } ; ColQualList: ColQualList ColConstraint { $$ = cat2_str($1,$2); } - | ColConstraint { $$ = $1; } + | ColConstraint { $$ = $1; } ; +ColQualListWithNull: ColQualListWithNull ColConstraintWithNull + { $$ = cat2_str($1, $2); } + | ColConstraintWithNull + { $$ = $1; } ColPrimaryKey: PRIMARY KEY { - $$ = make1_str("primary key"); + $$ = make_str("primary key"); } | /*EMPTY*/ { - $$ = make1_str(""); + $$ = EMPTY; } ; ColConstraint: CONSTRAINT name ColConstraintElem { - $$ = cat3_str(make1_str("constraint"), $2, $3); + $$ = cat_str(3, make_str("constraint"), $2, $3); } | ColConstraintElem { $$ = $1; } ; +ColConstraintWithNull: + CONSTRAINT name ColConstraintElemWithNull + { $$ = cat_str(3, make_str("constraint"), $2, $3); } + | ColConstraintElemWithNull + { $$ = $1; } + ; + /* DEFAULT NULL is already the default for Postgres. - * Bue define it here and carry it forward into the system + * But define it here and carry it forward into the system * to make it explicit. * - thomas 1998-09-13 + * * WITH NULL and NULL are not SQL92-standard syntax elements, * so leave them out. Use DEFAULT NULL to explicitly indicate * that a column may have that value. WITH NULL leads to * shift/reduce conflicts with WITH TIME ZONE anyway. * - thomas 1999-01-08 + * + * DEFAULT expression must be b_expr not a_expr to prevent shift/reduce + * conflict on NOT (since NOT might start a subsequent NOT NULL constraint, + * or be part of a_expr NOT LIKE or similar constructs). */ -ColConstraintElem: CHECK '(' constraint_expr ')' - { - $$ = make3_str(make1_str("check("), $3, make1_str(")")); - } - | DEFAULT NULL_P - { - $$ = make1_str("default null"); - } - | DEFAULT default_expr - { - $$ = cat2_str(make1_str("default"), $2); - } - | NOT NULL_P - { - $$ = make1_str("not null"); - } - | UNIQUE +ColConstraintElem: ColConstraintElemWithNull + { + $$ = $1; + } + | NOT NULL_P + { + $$ = make_str("not null"); + } + | UNIQUE { - $$ = make1_str("unique"); + $$ = make_str("unique"); } | PRIMARY KEY { - $$ = make1_str("primary key"); - } - | REFERENCES ColId opt_column_list key_match key_actions - { - fprintf(stderr, "CREATE TABLE/FOREIGN KEY clause ignored; not yet implemented"); - $$ = make1_str(""); + $$ = make_str("primary key"); } - ; + ; + -default_list: default_list ',' default_expr +ColConstraintElemWithNull: CHECK '(' a_expr ')' { - $$ = cat3_str($1, make1_str(","), $3); + $$ = cat_str(3, make_str("check("), $3, make_str(")")); } - | default_expr + | DEFAULT NULL_P { - $$ = $1; + $$ = make_str("default null"); } - ; - -/* The Postgres default column value is NULL. - * Rather than carrying DEFAULT NULL forward as a clause, - * let's just have it be a no-op. - | NULL_P - { $$ = make1_str("null"); } - * - thomas 1998-09-13 - */ - -default_expr: AexprConst - { $$ = $1; } - | '-' default_expr %prec UMINUS - { $$ = cat2_str(make1_str("-"), $2); } - | default_expr '+' default_expr - { $$ = cat3_str($1, make1_str("+"), $3); } - | default_expr '-' default_expr - { $$ = cat3_str($1, make1_str("-"), $3); } - | default_expr '/' default_expr - { $$ = cat3_str($1, make1_str("/"), $3); } - | default_expr '%' default_expr - { $$ = cat3_str($1, make1_str("%"), $3); } - | default_expr '*' default_expr - { $$ = cat3_str($1, make1_str("*"), $3); } - | default_expr '^' default_expr - { $$ = cat3_str($1, make1_str("^"), $3); } - | default_expr '=' default_expr - { yyerror("boolean expressions not supported in DEFAULT"); } - | default_expr '<' default_expr - { yyerror("boolean expressions not supported in DEFAULT"); } - | default_expr '>' default_expr - { yyerror("boolean expressions not supported in DEFAULT"); } -/* not possible in embedded sql - | ':' default_expr - { $$ = cat2_str(make1_str(":"), $2); } -*/ - | ';' default_expr - { $$ = cat2_str(make1_str(";"), $2); } - | '|' default_expr - { $$ = cat2_str(make1_str("|"), $2); } - | default_expr TYPECAST Typename - { $$ = cat3_str($1, make1_str("::"), $3); } - | CAST '(' default_expr AS Typename ')' - { - $$ = cat3_str(make2_str(make1_str("cast("), $3) , make1_str("as"), make2_str($5, make1_str(")"))); - } - | '(' default_expr ')' - { $$ = make3_str(make1_str("("), $2, make1_str(")")); } - | func_name '(' ')' - { $$ = cat2_str($1, make1_str("()")); } - | func_name '(' default_list ')' - { $$ = cat2_str($1, make3_str(make1_str("("), $3, make1_str(")"))); } - | default_expr Op default_expr - { - if (!strcmp("<=", $2) || !strcmp(">=", $2)) - yyerror("boolean expressions not supported in DEFAULT"); - $$ = cat3_str($1, $2, $3); - } - | Op default_expr - { $$ = cat2_str($1, $2); } - | default_expr Op - { $$ = cat2_str($1, $2); } - /* XXX - thomas 1997-10-07 v6.2 function-specific code to be changed */ - | CURRENT_DATE - { $$ = make1_str("current_date"); } - | CURRENT_TIME - { $$ = make1_str("current_time"); } - | CURRENT_TIME '(' Iconst ')' + | DEFAULT b_expr { - if ($3 != 0) - fprintf(stderr, "CURRENT_TIME(%s) precision not implemented; zero used instead",$3); - $$ = "current_time"; + $$ = cat2_str(make_str("default"), $2); } - | CURRENT_TIMESTAMP - { $$ = make1_str("current_timestamp"); } - | CURRENT_TIMESTAMP '(' Iconst ')' + | REFERENCES ColId opt_column_list key_match key_actions { - if ($3 != 0) - fprintf(stderr, "CURRENT_TIMESTAMP(%s) precision not implemented; zero used instead",$3); - $$ = "current_timestamp"; + $$ = cat_str(5, make_str("references"), $2, $3, $4, $5); } - | CURRENT_USER - { $$ = make1_str("current_user"); } - | USER - { $$ = make1_str("user"); } ; /* ConstraintElem specifies constraint syntax which is not embedded into @@ -1514,185 +1957,84 @@ default_expr: AexprConst */ TableConstraint: CONSTRAINT name ConstraintElem { - $$ = cat3_str(make1_str("constraint"), $2, $3); + $$ = cat_str(3, make_str("constraint"), $2, $3); } | ConstraintElem { $$ = $1; } ; -ConstraintElem: CHECK '(' constraint_expr ')' +ConstraintElem: CHECK '(' a_expr ')' { - $$ = make3_str(make1_str("check("), $3, make1_str(")")); + $$ = cat_str(3, make_str("check("), $3, make_str(")")); } | UNIQUE '(' columnList ')' { - $$ = make3_str(make1_str("unique("), $3, make1_str(")")); + $$ = cat_str(3, make_str("unique("), $3, make_str(")")); } | PRIMARY KEY '(' columnList ')' { - $$ = make3_str(make1_str("primary key("), $4, make1_str(")")); + $$ = cat_str(3, make_str("primary key("), $4, make_str(")")); } | FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list key_match key_actions { - fprintf(stderr, "CREATE TABLE/FOREIGN KEY clause ignored; not yet implemented"); - $$ = ""; + $$ = cat_str(7, make_str("foreign key("), $4, make_str(") references"), $7, $8, $9, $10); } ; -constraint_list: constraint_list ',' constraint_expr - { - $$ = cat3_str($1, make1_str(","), $3); - } - | constraint_expr - { - $$ = $1; - } +key_match: MATCH FULL + { + $$ = make_str("match full"); + } + | MATCH PARTIAL + { + mmerror(ET_WARN, "FOREIGN KEY match type PARTIAL not implemented yet"); + $$ = make_str("match partial"); + } + | /*EMPTY*/ + { + $$ = EMPTY; + } ; -constraint_expr: AexprConst - { $$ = $1; } - | NULL_P - { $$ = make1_str("null"); } - | ColId - { - $$ = $1; - } - | '-' constraint_expr %prec UMINUS - { $$ = cat2_str(make1_str("-"), $2); } - | constraint_expr '+' constraint_expr - { $$ = cat3_str($1, make1_str("+"), $3); } - | constraint_expr '-' constraint_expr - { $$ = cat3_str($1, make1_str("-"), $3); } - | constraint_expr '/' constraint_expr - { $$ = cat3_str($1, make1_str("/"), $3); } - | constraint_expr '%' constraint_expr - { $$ = cat3_str($1, make1_str("%"), $3); } - | constraint_expr '*' constraint_expr - { $$ = cat3_str($1, make1_str("*"), $3); } - | constraint_expr '^' constraint_expr - { $$ = cat3_str($1, make1_str("^"), $3); } - | constraint_expr '=' constraint_expr - { $$ = cat3_str($1, make1_str("="), $3); } - | constraint_expr '<' constraint_expr - { $$ = cat3_str($1, make1_str("<"), $3); } - | constraint_expr '>' constraint_expr - { $$ = cat3_str($1, make1_str(">"), $3); } -/* this one doesn't work with embedded sql anyway - | ':' constraint_expr - { $$ = cat2_str(make1_str(":"), $2); } -*/ - | ';' constraint_expr - { $$ = cat2_str(make1_str(";"), $2); } - | '|' constraint_expr - { $$ = cat2_str(make1_str("|"), $2); } - | constraint_expr TYPECAST Typename - { - $$ = cat3_str($1, make1_str("::"), $3); - } - | CAST '(' constraint_expr AS Typename ')' - { - $$ = cat3_str(make2_str(make1_str("cast("), $3), make1_str("as"), make2_str($5, make1_str(")"))); - } - | '(' constraint_expr ')' - { $$ = make3_str(make1_str("("), $2, make1_str(")")); } - | func_name '(' ')' - { - { $$ = cat2_str($1, make1_str("()")); } - } - | func_name '(' constraint_list ')' - { - $$ = cat2_str($1, make3_str(make1_str("("), $3, make1_str(")"))); - } - | constraint_expr Op constraint_expr - { $$ = cat3_str($1, $2, $3); } - | constraint_expr LIKE constraint_expr - { $$ = cat3_str($1, make1_str("like"), $3); } - | constraint_expr NOT LIKE constraint_expr - { $$ = cat3_str($1, make1_str("not like"), $4); } - | constraint_expr AND constraint_expr - { $$ = cat3_str($1, make1_str("and"), $3); } - | constraint_expr OR constraint_expr - { $$ = cat3_str($1, make1_str("or"), $3); } - | NOT constraint_expr - { $$ = cat2_str(make1_str("not"), $2); } - | Op constraint_expr - { $$ = cat2_str($1, $2); } - | constraint_expr Op - { $$ = cat2_str($1, $2); } - | constraint_expr ISNULL - { $$ = cat2_str($1, make1_str("isnull")); } - | constraint_expr IS NULL_P - { $$ = cat2_str($1, make1_str("is null")); } - | constraint_expr NOTNULL - { $$ = cat2_str($1, make1_str("notnull")); } - | constraint_expr IS NOT NULL_P - { $$ = cat2_str($1, make1_str("is not null")); } - | constraint_expr IS TRUE_P - { $$ = cat2_str($1, make1_str("is true")); } - | constraint_expr IS FALSE_P - { $$ = cat2_str($1, make1_str("is false")); } - | constraint_expr IS NOT TRUE_P - { $$ = cat2_str($1, make1_str("is not true")); } - | constraint_expr IS NOT FALSE_P - { $$ = cat2_str($1, make1_str("is not false")); } - | constraint_expr IN '(' c_list ')' - { $$ = cat4_str($1, make1_str("in ("), $4, make1_str(")")); } - | constraint_expr NOT IN '(' c_list ')' - { $$ = cat4_str($1, make1_str("not in ("), $5, make1_str(")")); } - | constraint_expr BETWEEN c_expr AND c_expr - { $$ = cat5_str($1, make1_str("between"), $3, make1_str("and"), $5); } - | constraint_expr NOT BETWEEN c_expr AND c_expr - { $$ = cat5_str($1, make1_str("not between"), $4, make1_str("and"), $6); } - ; -c_list: c_list ',' c_expr - { - $$ = make3_str($1, make1_str(", "), $3); - } - | c_expr - { - $$ = $1; - } - -c_expr: AexprConst - { - $$ = $1; - } - -key_match: MATCH FULL { $$ = make1_str("match full"); } - | MATCH PARTIAL { $$ = make1_str("match partial"); } - | /*EMPTY*/ { $$ = make1_str(""); } +key_actions: key_action key_action { $$ = cat2_str($1, $2); } + | key_action { $$ = $1; } + | /*EMPTY*/ { $$ = EMPTY; } ; -key_actions: key_action key_action { $$ = cat2_str($1, $2); } - | key_action { $$ = $1; } - | /*EMPTY*/ { $$ = make1_str(""); } +key_action: ON DELETE key_reference { $$ = cat2_str(make_str("on delete"), $3); } + | ON UPDATE key_reference { $$ = cat2_str(make_str("on update"), $3); } ; -key_action: ON DELETE key_reference { $$ = cat2_str(make1_str("on delete"), $3); } - | ON UPDATE key_reference { $$ = cat2_str(make1_str("on update"), $3); } +key_reference: NO ACTION { $$ = make_str("no action"); } + | RESTRICT { $$ = make_str("restrict"); } + | CASCADE { $$ = make_str("cascade"); } + | SET DEFAULT { $$ = make_str("set default"); } + | SET NULL_P { $$ = make_str("set null"); } ; -key_reference: NO ACTION { $$ = make1_str("no action"); } - | CASCADE { $$ = make1_str("cascade"); } - | SET DEFAULT { $$ = make1_str("set default"); } - | SET NULL_P { $$ = make1_str("set null"); } +OptInherit: INHERITS '(' relation_name_list ')' { $$ = cat_str(3, make_str("inherits ("), $3, make_str(")")); } + | /*EMPTY*/ { $$ = EMPTY; } ; -OptInherit: INHERITS '(' relation_name_list ')' { $$ = make3_str(make1_str("inherits ("), $3, make1_str(")")); } - | /*EMPTY*/ { $$ = make1_str(""); } - ; +/* + * Note: CREATE TABLE ... AS SELECT ... is just another spelling for + * SELECT ... INTO. + */ -CreateAsStmt: CREATE OptTemp TABLE relation_name OptCreateAs AS SubSelect +CreateAsStmt: CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt { - $$ = cat5_str(cat3_str(make1_str("create"), $2, make1_str("table")), $4, $5, make1_str("as"), $7); + if (FoundInto == 1) + mmerror(ET_ERROR, "CREATE TABLE/AS SELECT may not specify INTO"); + + $$ = cat_str(7, make_str("create"), $2, make_str("table"), $4, $5, make_str("as"), $7); } ; -OptCreateAs: '(' CreateAsList ')' { $$ = make3_str(make1_str("("), $2, make1_str(")")); } - | /*EMPTY*/ { $$ = make1_str(""); } +OptCreateAs: '(' CreateAsList ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | /*EMPTY*/ { $$ = EMPTY; } ; -CreateAsList: CreateAsList ',' CreateAsElement { $$ = cat3_str($1, make1_str(","), $3); } +CreateAsList: CreateAsList ',' CreateAsElement { $$ = cat_str(3, $1, make_str(","), $3); } | CreateAsElement { $$ = $1; } ; @@ -1708,38 +2050,38 @@ CreateAsElement: ColId { $$ = $1; } CreateSeqStmt: CREATE SEQUENCE relation_name OptSeqList { - $$ = cat3_str(make1_str("create sequence"), $3, $4); + $$ = cat_str(3, make_str("create sequence"), $3, $4); } ; OptSeqList: OptSeqList OptSeqElem { $$ = cat2_str($1, $2); } - | { $$ = make1_str(""); } + | { $$ = EMPTY; } ; OptSeqElem: CACHE IntegerOnly { - $$ = cat2_str(make1_str("cache"), $2); + $$ = cat2_str(make_str("cache"), $2); } | CYCLE { - $$ = make1_str("cycle"); + $$ = make_str("cycle"); } | INCREMENT IntegerOnly { - $$ = cat2_str(make1_str("increment"), $2); + $$ = cat2_str(make_str("increment"), $2); } | MAXVALUE IntegerOnly { - $$ = cat2_str(make1_str("maxvalue"), $2); + $$ = cat2_str(make_str("maxvalue"), $2); } | MINVALUE IntegerOnly { - $$ = cat2_str(make1_str("minvalue"), $2); + $$ = cat2_str(make_str("minvalue"), $2); } | START IntegerOnly { - $$ = cat2_str(make1_str("start"), $2); + $$ = cat2_str(make_str("start"), $2); } ; @@ -1752,7 +2094,7 @@ FloatOnly: Fconst } | '-' Fconst { - $$ = cat2_str(make1_str("-"), $2); + $$ = cat2_str(make_str("-"), $2); } ; @@ -1763,7 +2105,7 @@ IntegerOnly: Iconst } | '-' Iconst { - $$ = cat2_str(make1_str("-"), $2); + $$ = cat2_str(make_str("-"), $2); } ; @@ -1778,16 +2120,16 @@ IntegerOnly: Iconst CreatePLangStmt: CREATE PLangTrusted PROCEDURAL LANGUAGE Sconst HANDLER def_name LANCOMPILER Sconst { - $$ = cat4_str(cat5_str(make1_str("create"), $2, make1_str("precedural language"), $5, make1_str("handler")), $7, make1_str("langcompiler"), $9); + $$ = cat_str(8, make_str("create"), $2, make_str("precedural language"), $5, make_str("handler"), $7, make_str("langcompiler"), $9); } ; -PLangTrusted: TRUSTED { $$ = make1_str("trusted"); } - | { $$ = make1_str(""); } +PLangTrusted: TRUSTED { $$ = make_str("trusted"); } + | { $$ = EMPTY; } DropPLangStmt: DROP PROCEDURAL LANGUAGE Sconst { - $$ = cat2_str(make1_str("drop procedural language"), $4); + $$ = cat2_str(make_str("drop procedural language"), $4); } ; @@ -1803,12 +2145,20 @@ CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON relation_name TriggerForSpec EXECUTE PROCEDURE name '(' TriggerFuncArgs ')' { - $$ = cat2_str(cat5_str(cat5_str(make1_str("create trigger"), $3, $4, $5, make1_str("on")), $7, $8, make1_str("execute procedure"), $11), make3_str(make1_str("("), $13, make1_str(")"))); + $$ = cat_str(12, make_str("create trigger"), $3, $4, $5, make_str("on"), $7, $8, make_str("execute procedure"), $11, make_str("("), $13, make_str(")")); + } + | CREATE CONSTRAINT TRIGGER name AFTER TriggerEvents ON + relation_name OptConstrFromTable + ConstraintAttributeSpec + FOR EACH ROW EXECUTE PROCEDURE + name '(' TriggerFuncArgs ')' + { + $$ = cat_str(13, make_str("create constraint trigger"), $4, make_str("after"), $6, make_str("on"), $8, $9, $10, make_str("for each row execute procedure"), $16, make_str("("), $18, make_str(")")); } ; -TriggerActionTime: BEFORE { $$ = make1_str("before"); } - | AFTER { $$ = make1_str("after"); } +TriggerActionTime: BEFORE { $$ = make_str("before"); } + | AFTER { $$ = make_str("after"); } ; TriggerEvents: TriggerOneEvent @@ -1817,39 +2167,39 @@ TriggerEvents: TriggerOneEvent } | TriggerOneEvent OR TriggerOneEvent { - $$ = cat3_str($1, make1_str("or"), $3); + $$ = cat_str(3, $1, make_str("or"), $3); } | TriggerOneEvent OR TriggerOneEvent OR TriggerOneEvent { - $$ = cat5_str($1, make1_str("or"), $3, make1_str("or"), $5); + $$ = cat_str(5, $1, make_str("or"), $3, make_str("or"), $5); } ; -TriggerOneEvent: INSERT { $$ = make1_str("insert"); } - | DELETE { $$ = make1_str("delete"); } - | UPDATE { $$ = make1_str("update"); } +TriggerOneEvent: INSERT { $$ = make_str("insert"); } + | DELETE { $$ = make_str("delete"); } + | UPDATE { $$ = make_str("update"); } ; TriggerForSpec: FOR TriggerForOpt TriggerForType { - $$ = cat3_str(make1_str("for"), $2, $3); + $$ = cat_str(3, make_str("for"), $2, $3); } ; -TriggerForOpt: EACH { $$ = make1_str("each"); } - | /*EMPTY*/ { $$ = make1_str(""); } +TriggerForOpt: EACH { $$ = make_str("each"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -TriggerForType: ROW { $$ = make1_str("row"); } - | STATEMENT { $$ = make1_str("statement"); } +TriggerForType: ROW { $$ = make_str("row"); } + | STATEMENT { $$ = make_str("statement"); } ; TriggerFuncArgs: TriggerFuncArg { $$ = $1; } | TriggerFuncArgs ',' TriggerFuncArg - { $$ = cat3_str($1, make1_str(","), $3); } + { $$ = cat_str(3, $1, make_str(","), $3); } | /*EMPTY*/ - { $$ = make1_str(""); } + { $$ = EMPTY; } ; TriggerFuncArg: Iconst @@ -1864,9 +2214,61 @@ TriggerFuncArg: Iconst | ident { $$ = $1; } ; +OptConstrFromTable: /* Empty */ + { + $$ = EMPTY; + } + | FROM relation_name + { + $$ = cat2_str(make_str("from"), $2); + } + ; + +ConstraintAttributeSpec: ConstraintDeferrabilitySpec + { $$ = $1; } + | ConstraintDeferrabilitySpec ConstraintTimeSpec + { + if (strcmp($1, "deferrable") != 0 && strcmp($2, "initially deferrable") == 0 ) + mmerror(ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE"); + + $$ = cat2_str($1, $2); + } + | ConstraintTimeSpec + { $$ = $1; } + | ConstraintTimeSpec ConstraintDeferrabilitySpec + { + if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 ) + mmerror(ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE"); + + $$ = cat2_str($1, $2); + } + | /* Empty */ + { $$ = 0; } + ; + +ConstraintDeferrabilitySpec: NOT DEFERRABLE + { + $$ = make_str("not deferrable"); + } + | DEFERRABLE + { + $$ = make_str("deferrable"); + } + ; + +ConstraintTimeSpec: INITIALLY IMMEDIATE + { + $$ = make_str("initially immediate"); + } + | INITIALLY DEFERRED + { + $$ = make_str("initially deferrable"); + } + ; + DropTrigStmt: DROP TRIGGER name ON relation_name { - $$ = cat4_str(make1_str("drop trigger"), $3, make1_str("on"), $5); + $$ = cat_str(4, make_str("drop trigger"), $3, make_str("on"), $5); } ; @@ -1879,7 +2281,7 @@ DropTrigStmt: DROP TRIGGER name ON relation_name DefineStmt: CREATE def_type def_rest { - $$ = cat3_str(make1_str("create"), $2, $3); + $$ = cat_str(3, make_str("create"), $2, $3); } ; @@ -1889,27 +2291,26 @@ def_rest: def_name definition } ; -def_type: OPERATOR { $$ = make1_str("operator"); } - | TYPE_P { $$ = make1_str("type"); } - | AGGREGATE { $$ = make1_str("aggregate"); } +def_type: OPERATOR { $$ = make_str("operator"); } + | TYPE_P { $$ = make_str("type"); } + | AGGREGATE { $$ = make_str("aggregate"); } ; -def_name: PROCEDURE { $$ = make1_str("procedure"); } - | JOIN { $$ = make1_str("join"); } +def_name: PROCEDURE { $$ = make_str("procedure"); } + | JOIN { $$ = make_str("join"); } | ColId { $$ = $1; } - | MathOp { $$ = $1; } - | Op { $$ = $1; } + | all_Op { $$ = $1; } ; -definition: '(' def_list ')' { $$ = make3_str(make1_str("("), $2, make1_str(")")); } +definition: '(' def_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } ; def_list: def_elem { $$ = $1; } - | def_list ',' def_elem { $$ = cat3_str($1, make1_str(","), $3); } + | def_list ',' def_elem { $$ = cat_str(3, $1, make_str(","), $3); } ; def_elem: def_name '=' def_arg { - $$ = cat3_str($1, make1_str("="), $3); + $$ = cat_str(3, $1, make_str("="), $3); } | def_name { @@ -1917,7 +2318,7 @@ def_elem: def_name '=' def_arg { } | DEFAULT '=' def_arg { - $$ = cat2_str(make1_str("default ="), $3); + $$ = cat2_str(make_str("default ="), $3); } ; @@ -1927,28 +2328,38 @@ def_arg: ColId { $$ = $1; } | Sconst { $$ = $1; } | SETOF ColId { - $$ = cat2_str(make1_str("setof"), $2); + $$ = cat2_str(make_str("setof"), $2); } ; /***************************************************************************** * * QUERY: - * destroy [, .. ] + * drop [, .. ] * *****************************************************************************/ -DestroyStmt: DROP TABLE relation_name_list +DropStmt: DROP TABLE relation_name_list { - $$ = cat2_str(make1_str("drop table"), $3); + $$ = cat2_str(make_str("drop table"), $3); } | DROP SEQUENCE relation_name_list { - $$ = cat2_str(make1_str("drop sequence"), $3); + $$ = cat2_str(make_str("drop sequence"), $3); } ; - +/***************************************************************************** + * + * QUERY: + * truncate table relname + * + *****************************************************************************/ +TruncateStmt: TRUNCATE opt_table relation_name + { + $$ = cat2_str(make_str("drop table"), $3); + } + ; /***************************************************************************** * @@ -1959,44 +2370,131 @@ DestroyStmt: DROP TABLE relation_name_list * *****************************************************************************/ -FetchStmt: FETCH opt_direction fetch_how_many opt_portal_name INTO into_list +FetchStmt: FETCH direction fetch_how_many from_in name INTO into_list { - if (strncmp($2, "relative", strlen("relative")) == 0 && atol($3) == 0L) - yyerror("FETCH/RELATIVE at current position is not supported"); + if (strcmp($2, "relative") == 0 && atol($3) == 0L) + mmerror(ET_ERROR, "FETCH/RELATIVE at current position is not supported"); - $$ = cat4_str(make1_str("fetch"), $2, $3, $4); + $$ = cat_str(5, make_str("fetch"), $2, $3, $4, $5); + } + | FETCH fetch_how_many from_in name INTO into_list + { + $$ = cat_str(4, make_str("fetch"), $2, $3, $4); } - | MOVE opt_direction fetch_how_many opt_portal_name + | FETCH direction from_in name INTO into_list + { + $$ = cat_str(4, make_str("fetch"), $2, $3, $4); + } + | FETCH from_in name INTO into_list + { + $$ = cat_str(3, make_str("fetch"), $2, $3); + } + | FETCH name INTO into_list + { + $$ = cat2_str(make_str("fetch"), $2); + } + | MOVE direction fetch_how_many from_in name + { + $$ = cat_str(5, make_str("move"), $2, $3, $4, $5); + } + | MOVE fetch_how_many from_in name + { + $$ = cat_str(4, make_str("move"), $2, $3, $4); + } + | MOVE direction from_in name + { + $$ = cat_str(4, make_str("move"), $2, $3, $4); + } + | MOVE from_in name + { + $$ = cat_str(3, make_str("move"), $2, $3); + } + | MOVE name { - $$ = cat4_str(make1_str("fetch"), $2, $3, $4); + $$ = cat2_str(make_str("move"), $2); } ; -opt_direction: FORWARD { $$ = make1_str("forward"); } - | BACKWARD { $$ = make1_str("backward"); } - | RELATIVE { $$ = make1_str("relative"); } - | ABSOLUTE - { - fprintf(stderr, "FETCH/ABSOLUTE not supported, using RELATIVE"); - $$ = make1_str("absolute"); +direction: FORWARD { $$ = make_str("forward"); } + | BACKWARD { $$ = make_str("backward"); } + | RELATIVE { $$ = make_str("relative"); } + | ABSOLUTE { + mmerror(ET_WARN, "FETCH/ABSOLUTE not supported, backend will use RELATIVE"); + $$ = make_str("absolute"); } - | /*EMPTY*/ { $$ = make1_str(""); /* default */ } ; fetch_how_many: Iconst { $$ = $1; } - | '-' Iconst { $$ = make2_str(make1_str("-"), $2); } - | ALL { $$ = make1_str("all"); } - | NEXT { $$ = make1_str("next"); } - | PRIOR { $$ = make1_str("prior"); } - | /*EMPTY*/ { $$ = make1_str(""); /*default*/ } + | '-' Iconst { $$ = cat2_str(make_str("-"), $2); } + | ALL { $$ = make_str("all"); } + | NEXT { $$ = make_str("next"); } + | PRIOR { $$ = make_str("prior"); } ; -opt_portal_name: IN name { $$ = cat2_str(make1_str("in"), $2); } - | FROM name { $$ = cat2_str(make1_str("from"), $2); } -/* | name { $$ = cat2_str(make1_str("in"), $1); */ - | /*EMPTY*/ { $$ = make1_str(""); } +from_in: IN { $$ = make_str("in"); } + | FROM { $$ = make_str("from"); } + ; + +/***************************************************************************** + * + * The COMMENT ON statement can take different forms based upon the type of + * the object associated with the comment. The form of the statement is: + * + * COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] + * | AGGREGATE | FUNCTION + * (arg1, arg2, ...) | OPERATOR + * (leftoperand_typ rightoperand_typ) | TRIGGER ON + * ] IS 'text' + * + *****************************************************************************/ +CommentStmt: COMMENT ON comment_type name IS comment_text + { + $$ = cat_str(5, make_str("comment on"), $3, $4, make_str("is"), $6); + } + | COMMENT ON comment_cl relation_name '.' attr_name IS comment_text + { + $$ = cat_str(7, make_str("comment on"), $3, $4, make_str("."), $6, make_str("is"), $8); + } + | COMMENT ON comment_ag name aggr_argtype IS comment_text + { + $$ = cat_str(6, make_str("comment on"), $3, $4, $5, make_str("is"), $7); + } + | COMMENT ON comment_fn func_name func_args IS comment_text + { + $$ = cat_str(6, make_str("comment on"), $3, $4, $5, make_str("is"), $7); + } + | COMMENT ON comment_op all_Op '(' oper_argtypes ')' IS comment_text + { + $$ = cat_str(7, make_str("comment on"), $3, $4, make_str("("), $6, make_str(") is"), $9); + } + | COMMENT ON comment_tg name ON relation_name IS comment_text + { + $$ = cat_str(7, make_str("comment on"), $3, $4, make_str("on"), $6, make_str("is"), $8); + } + ; + +comment_type: DATABASE { $$ = make_str("database"); } + | INDEX { $$ = make_str("idnex"); } + | RULE { $$ = make_str("rule"); } + | SEQUENCE { $$ = make_str("sequence"); } + | TABLE { $$ = make_str("table"); } + | TYPE_P { $$ = make_str("type"); } + | VIEW { $$ = make_str("view"); } ; +comment_cl: COLUMN { $$ = make_str("column"); } + +comment_ag: AGGREGATE { $$ = make_str("aggregate"); } + +comment_fn: FUNCTION { $$ = make_str("function"); } + +comment_op: OPERATOR { $$ = make_str("operator"); } + +comment_tg: TRIGGER { $$ = make_str("trigger"); } + +comment_text: Sconst { $$ = $1; } + | NULL_P { $$ = make_str("null"); } + ; /***************************************************************************** * @@ -2007,17 +2505,17 @@ opt_portal_name: IN name { $$ = cat2_str(make1_str("in"), $2); } GrantStmt: GRANT privileges ON relation_name_list TO grantee opt_with_grant { - $$ = cat2_str(cat5_str(make1_str("grant"), $2, make1_str("on"), $4, make1_str("to")), $6); + $$ = cat_str(7, make_str("grant"), $2, make_str("on"), $4, make_str("to"), $6); } ; privileges: ALL PRIVILEGES { - $$ = make1_str("all privileges"); + $$ = make_str("all privileges"); } | ALL { - $$ = make1_str("all"); + $$ = make_str("all"); } | operation_commalist { @@ -2031,39 +2529,39 @@ operation_commalist: operation } | operation_commalist ',' operation { - $$ = cat3_str($1, make1_str(","), $3); + $$ = cat_str(3, $1, make_str(","), $3); } ; operation: SELECT { - $$ = make1_str("select"); + $$ = make_str("select"); } | INSERT { - $$ = make1_str("insert"); + $$ = make_str("insert"); } | UPDATE { - $$ = make1_str("update"); + $$ = make_str("update"); } | DELETE { - $$ = make1_str("delete"); + $$ = make_str("delete"); } | RULE { - $$ = make1_str("rule"); + $$ = make_str("rule"); } ; grantee: PUBLIC { - $$ = make1_str("public"); + $$ = make_str("public"); } | GROUP ColId { - $$ = cat2_str(make1_str("group"), $2); + $$ = cat2_str(make_str("group"), $2); } | ColId { @@ -2073,7 +2571,7 @@ grantee: PUBLIC opt_with_grant: WITH GRANT OPTION { - yyerror("WITH GRANT OPTION is not supported. Only relation owners can set privileges"); + mmerror(ET_ERROR, "WITH GRANT OPTION is not supported. Only relation owners can set privileges"); } | /*EMPTY*/ ; @@ -2088,7 +2586,7 @@ opt_with_grant: WITH GRANT OPTION RevokeStmt: REVOKE privileges ON relation_name_list FROM grantee { - $$ = cat2_str(cat5_str(make1_str("revoke"), $2, make1_str("on"), $4, make1_str("from")), $6); + $$ = cat_str(7, make_str("revoke"), $2, make_str("on"), $4, make_str("from"), $6); } ; @@ -2109,41 +2607,41 @@ IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name { /* should check that access_method is valid, etc ... but doesn't */ - $$ = cat5_str(cat5_str(make1_str("create"), $2, make1_str("index"), $4, make1_str("on")), $6, $7, make3_str(make1_str("("), $9, make1_str(")")), $11); + $$ = cat_str(11, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11); } ; -index_opt_unique: UNIQUE { $$ = make1_str("unique"); } - | /*EMPTY*/ { $$ = make1_str(""); } +index_opt_unique: UNIQUE { $$ = make_str("unique"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -access_method_clause: USING access_method { $$ = cat2_str(make1_str("using"), $2); } - | /*EMPTY*/ { $$ = make1_str(""); } +access_method_clause: USING access_method { $$ = cat2_str(make_str("using"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } ; index_params: index_list { $$ = $1; } | func_index { $$ = $1; } ; -index_list: index_list ',' index_elem { $$ = cat3_str($1, make1_str(","), $3); } +index_list: index_list ',' index_elem { $$ = cat_str(3, $1, make_str(","), $3); } | index_elem { $$ = $1; } ; func_index: func_name '(' name_list ')' opt_type opt_class { - $$ = cat4_str($1, make3_str(make1_str("("), $3, ")"), $5, $6); + $$ = cat_str(6, $1, make_str("("), $3, ")", $5, $6); } ; index_elem: attr_name opt_type opt_class { - $$ = cat3_str($1, $2, $3); + $$ = cat_str(3, $1, $2, $3); } ; -opt_type: ':' Typename { $$ = cat2_str(make1_str(":"), $2); } - | FOR Typename { $$ = cat2_str(make1_str("for"), $2); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_type: ':' Typename { $$ = cat2_str(make_str(":"), $2); } + | FOR Typename { $$ = cat2_str(make_str("for"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } ; /* opt_class "WITH class" conflicts with preceeding opt_type @@ -2153,8 +2651,8 @@ opt_type: ':' Typename { $$ = cat2_str(make1_str(":"), $2); } * | WITH class { $$ = $2; } */ opt_class: class { $$ = $1; } - | USING class { $$ = cat2_str(make1_str("using"), $2); } - | /*EMPTY*/ { $$ = make1_str(""); } + | USING class { $$ = cat2_str(make_str("using"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } ; /***************************************************************************** @@ -2166,7 +2664,7 @@ opt_class: class { $$ = $1; } ExtendStmt: EXTEND INDEX index_name where_clause { - $$ = cat3_str(make1_str("extend index"), $3, $4); + $$ = cat_str(3, make_str("extend index"), $3, $4); } ; @@ -2180,7 +2678,7 @@ ExtendStmt: EXTEND INDEX index_name where_clause /* NOT USED RecipeStmt: EXECUTE RECIPE recipe_name { - $$ = cat2_str(make1_str("execute recipe"), $3); + $$ = cat2_str(make_str("execute recipe"), $3); } ; */ @@ -2201,32 +2699,35 @@ RecipeStmt: EXECUTE RECIPE recipe_name *****************************************************************************/ ProcedureStmt: CREATE FUNCTION func_name func_args - RETURNS func_return opt_with AS Sconst LANGUAGE Sconst + RETURNS func_return opt_with AS func_as LANGUAGE Sconst { - $$ = cat2_str(cat5_str(cat5_str(make1_str("create function"), $3, $4, make1_str("returns"), $6), $7, make1_str("as"), $9, make1_str("language")), $11); + $$ = cat_str(10, make_str("create function"), $3, $4, make_str("returns"), $6, $7, make_str("as"), $9, make_str("language"), $11); } -opt_with: WITH definition { $$ = cat2_str(make1_str("with"), $2); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_with: WITH definition { $$ = cat2_str(make_str("with"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } ; -func_args: '(' func_args_list ')' { $$ = make3_str(make1_str("("), $2, make1_str(")")); } - | '(' ')' { $$ = make1_str("()"); } +func_args: '(' func_args_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | '(' ')' { $$ = make_str("()"); } ; func_args_list: TypeId { $$ = $1; } | func_args_list ',' TypeId - { $$ = cat3_str($1, make1_str(","), $3); } + { $$ = cat_str(3, $1, make_str(","), $3); } ; +func_as: Sconst { $$ = $1; } + | Sconst ',' Sconst { $$ = cat_str(3, $1, make_str(","), $3); } + func_return: set_opt TypeId { $$ = cat2_str($1, $2); } ; -set_opt: SETOF { $$ = make1_str("setof"); } - | /*EMPTY*/ { $$ = make1_str(""); } +set_opt: SETOF { $$ = make_str("setof"); } + | /*EMPTY*/ { $$ = EMPTY; } ; @@ -2249,63 +2750,51 @@ set_opt: SETOF { $$ = make1_str("setof"); } RemoveStmt: DROP remove_type name { - $$ = cat3_str(make1_str("drop"), $2, $3); + $$ = cat_str(3, make_str("drop"), $2, $3); } ; -remove_type: TYPE_P { $$ = make1_str("type"); } - | INDEX { $$ = make1_str("index"); } - | RULE { $$ = make1_str("rule"); } - | VIEW { $$ = make1_str("view"); } +remove_type: TYPE_P { $$ = make_str("type"); } + | INDEX { $$ = make_str("index"); } + | RULE { $$ = make_str("rule"); } + | VIEW { $$ = make_str("view"); } ; RemoveAggrStmt: DROP AGGREGATE name aggr_argtype { - $$ = cat3_str(make1_str("drop aggregate"), $3, $4); + $$ = cat_str(3, make_str("drop aggregate"), $3, $4); } ; aggr_argtype: name { $$ = $1; } - | '*' { $$ = make1_str("*"); } + | '*' { $$ = make_str("*"); } ; RemoveFuncStmt: DROP FUNCTION func_name func_args { - $$ = cat3_str(make1_str("drop function"), $3, $4); + $$ = cat_str(3, make_str("drop function"), $3, $4); } ; RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')' { - $$ = cat3_str(make1_str("drop operator"), $3, make3_str(make1_str("("), $5, make1_str(")"))); + $$ = cat_str(5, make_str("drop operator"), $3, make_str("("), $5, make_str(")")); } ; -all_Op: Op | MathOp; - -MathOp: '+' { $$ = make1_str("+"); } - | '-' { $$ = make1_str("-"); } - | '*' { $$ = make1_str("*"); } - | '%' { $$ = make1_str("%"); } - | '/' { $$ = make1_str("/"); } - | '<' { $$ = make1_str("<"); } - | '>' { $$ = make1_str(">"); } - | '=' { $$ = make1_str("="); } - ; - oper_argtypes: name { - yyerror("parser: argument type missing (use NONE for unary operators)"); + mmerror(ET_ERROR, "parser: argument type missing (use NONE for unary operators)"); } | name ',' name - { $$ = cat3_str($1, make1_str(","), $3); } + { $$ = cat_str(3, $1, make_str(","), $3); } | NONE ',' name /* left unary */ - { $$ = cat2_str(make1_str("none,"), $3); } + { $$ = cat2_str(make_str("none,"), $3); } | name ',' NONE /* right unary */ - { $$ = cat2_str($1, make1_str(", none")); } + { $$ = cat2_str($1, make_str(", none")); } ; @@ -2320,16 +2809,16 @@ oper_argtypes: name RenameStmt: ALTER TABLE relation_name opt_inh_star RENAME opt_column opt_name TO name { - $$ = cat4_str(cat5_str(make1_str("alter table"), $3, $4, make1_str("rename"), $6), $7, make1_str("to"), $9); + $$ = cat_str(8, make_str("alter table"), $3, $4, make_str("rename"), $6, $7, make_str("to"), $9); } ; opt_name: name { $$ = $1; } - | /*EMPTY*/ { $$ = make1_str(""); } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_column: COLUMN { $$ = make1_str("colmunn"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_column: COLUMN { $$ = make_str("colmunn"); } + | /*EMPTY*/ { $$ = EMPTY; } ; @@ -2347,27 +2836,22 @@ RuleStmt: CREATE RULE name AS ON event TO event_object where_clause DO opt_instead RuleActionList { - $$ = cat2_str(cat5_str(cat5_str(make1_str("create rule"), $3, make1_str("as on"), $7, make1_str("to")), $9, $10, make1_str("do"), $12), $13); + $$ = cat_str(10, make_str("create rule"), $3, make_str("as on"), $7, make_str("to"), $9, $10, make_str("do"), $12, $13); } ; -RuleActionList: NOTHING { $$ = make1_str("nothing"); } +RuleActionList: NOTHING { $$ = make_str("nothing"); } | SelectStmt { $$ = $1; } | RuleActionStmt { $$ = $1; } - | '[' RuleActionBlock ']' { $$ = cat3_str(make1_str("["), $2, make1_str("]")); } - | '(' RuleActionBlock ')' { $$ = cat3_str(make1_str("("), $2, make1_str(")")); } + | '[' RuleActionMulti ']' { $$ = cat_str(3, make_str("["), $2, make_str("]")); } + | '(' RuleActionMulti ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } ; -RuleActionBlock: RuleActionMulti { $$ = $1; } - | RuleActionStmt { $$ = $1; } - ; - -RuleActionMulti: RuleActionMulti RuleActionStmt - { $$ = cat2_str($1, $2); } - | RuleActionMulti RuleActionStmt ';' - { $$ = cat3_str($1, $2, make1_str(";")); } - | RuleActionStmt ';' - { $$ = cat2_str($1, make1_str(";")); } +/* the thrashing around here is to discard "empty" statements... */ +RuleActionMulti: RuleActionMulti ';' RuleActionStmtOrEmpty + { $$ = cat_str(3, $1, make_str(";"), $3); } + | RuleActionStmtOrEmpty + { $$ = cat2_str($1, make_str(";")); } ; RuleActionStmt: InsertStmt @@ -2375,10 +2859,13 @@ RuleActionStmt: InsertStmt | DeleteStmt | NotifyStmt ; +RuleActionStmtOrEmpty: RuleActionStmt { $$ = $1; } + | /*EMPTY*/ { $$ = EMPTY; } + ; event_object: relation_name '.' attr_name { - $$ = make3_str($1, make1_str("."), $3); + $$ = make3_str($1, make_str("."), $3); } | relation_name { @@ -2387,14 +2874,14 @@ event_object: relation_name '.' attr_name ; /* change me to select, update, etc. some day */ -event: SELECT { $$ = make1_str("select"); } - | UPDATE { $$ = make1_str("update"); } - | DELETE { $$ = make1_str("delete"); } - | INSERT { $$ = make1_str("insert"); } +event: SELECT { $$ = make_str("select"); } + | UPDATE { $$ = make_str("update"); } + | DELETE { $$ = make_str("delete"); } + | INSERT { $$ = make_str("insert"); } ; -opt_instead: INSTEAD { $$ = make1_str("instead"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_instead: INSTEAD { $$ = make_str("instead"); } + | /*EMPTY*/ { $$ = EMPTY; } ; @@ -2408,23 +2895,23 @@ opt_instead: INSTEAD { $$ = make1_str("instead"); } NotifyStmt: NOTIFY relation_name { - $$ = cat2_str(make1_str("notify"), $2); + $$ = cat2_str(make_str("notify"), $2); } ; ListenStmt: LISTEN relation_name { - $$ = cat2_str(make1_str("listen"), $2); + $$ = cat2_str(make_str("listen"), $2); } ; UnlistenStmt: UNLISTEN relation_name { - $$ = cat2_str(make1_str("unlisten"), $2); + $$ = cat2_str(make_str("unlisten"), $2); } | UNLISTEN '*' { - $$ = make1_str("unlisten *"); + $$ = make_str("unlisten *"); } ; @@ -2432,19 +2919,15 @@ UnlistenStmt: UNLISTEN relation_name * * Transactions: * - * abort transaction - * (ABORT) - * begin transaction - * (BEGIN) - * end transaction - * (END) + * BEGIN / COMMIT / ROLLBACK + * (also older versions END / ABORT) * *****************************************************************************/ -TransactionStmt: ABORT_TRANS opt_trans { $$ = make1_str("rollback"); } - | BEGIN_TRANS opt_trans { $$ = make1_str("begin transaction"); } - | COMMIT opt_trans { $$ = make1_str("commit"); } - | END_TRANS opt_trans { $$ = make1_str("commit"); } - | ROLLBACK opt_trans { $$ = make1_str("rollback"); } +TransactionStmt: ABORT_TRANS opt_trans { $$ = make_str("rollback"); } + | BEGIN_TRANS opt_trans { $$ = make_str("begin transaction"); } + | COMMIT opt_trans { $$ = make_str("commit"); } + | END_TRANS opt_trans { $$ = make_str("commit"); } + | ROLLBACK opt_trans { $$ = make_str("rollback"); } opt_trans: WORK { $$ = ""; } | TRANSACTION { $$ = ""; } @@ -2460,7 +2943,7 @@ opt_trans: WORK { $$ = ""; } ViewStmt: CREATE VIEW name AS SelectStmt { - $$ = cat4_str(make1_str("create view"), $3, make1_str("as"), $5); + $$ = cat_str(4, make_str("create view"), $3, make_str("as"), $5); } ; @@ -2468,68 +2951,76 @@ ViewStmt: CREATE VIEW name AS SelectStmt /***************************************************************************** * * QUERY: - * load make1_str("filename") + * load make_str("filename") * *****************************************************************************/ LoadStmt: LOAD file_name { - $$ = cat2_str(make1_str("load"), $2); + $$ = cat2_str(make_str("load"), $2); } ; /***************************************************************************** * - * QUERY: - * createdb dbname + * CREATE DATABASE + * * *****************************************************************************/ -CreatedbStmt: CREATE DATABASE database_name WITH opt_database1 opt_database2 - { - if (strlen($5) == 0 || strlen($6) == 0) - yyerror("CREATE DATABASE WITH requires at least an option"); -#ifndef MULTIBYTE - if (strlen($6) != 0) - yyerror("WITH ENCODING is not supported"); -#endif - $$ = cat5_str(make1_str("create database"), $3, make1_str("with"), $5, $6); - } +CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb_opt_encoding + { + if (strlen($5) == 0 || strlen($6) == 0) + mmerror(ET_ERROR, "CREATE DATABASE WITH requires at least an option"); + + $$ = cat_str(5, make_str("create database"), $3, make_str("with"), $5, $6); + } | CREATE DATABASE database_name - { - $$ = cat2_str(make1_str("create database"), $3); - } + { + $$ = cat2_str(make_str("create database"), $3); + } ; -opt_database1: LOCATION '=' location { $$ = cat2_str(make1_str("location ="), $3); } - | /*EMPTY*/ { $$ = make1_str(""); } +createdb_opt_location: LOCATION '=' Sconst { $$ = cat2_str(make_str("location ="), $3); } + | LOCATION '=' DEFAULT { $$ = make_str("location = default"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_database2: ENCODING '=' encoding { $$ = cat2_str(make1_str("encoding ="), $3); } +createdb_opt_encoding: ENCODING '=' Sconst + { +#ifndef MULTIBYTE + mmerror(ET_ERROR, "Multi-byte support is not enabled."); +#endif + $$ = cat2_str(make_str("encoding ="), $3); + } + | ENCODING '=' Iconst + { +#ifndef MULTIBYTE + mmerror(ET_ERROR, "Multi-byte support is not enabled."); +#endif + $$ = cat2_str(make_str("encoding ="), $3); + } + | ENCODING '=' DEFAULT + { +#ifndef MULTIBYTE + mmerror(ET_ERROR, "Multi-byte support is not enabled."); +#endif + $$ = make_str("encoding = default"); + } | /*EMPTY*/ { $$ = NULL; } ; -location: Sconst { $$ = $1; } - | DEFAULT { $$ = make1_str("default"); } - | /*EMPTY*/ { $$ = make1_str(""); } - ; - -encoding: Sconst { $$ = $1; } - | DEFAULT { $$ = make1_str("default"); } - | /*EMPTY*/ { $$ = make1_str(""); } - ; - /***************************************************************************** * - * QUERY: - * destroydb dbname + * DROP DATABASE + * * *****************************************************************************/ -DestroydbStmt: DROP DATABASE database_name +DropdbStmt: DROP DATABASE database_name { - $$ = cat2_str(make1_str("drop database"), $3); + $$ = cat2_str(make_str("drop database"), $3); } ; @@ -2543,7 +3034,7 @@ DestroydbStmt: DROP DATABASE database_name ClusterStmt: CLUSTER index_name ON relation_name { - $$ = cat4_str(make1_str("cluster"), $2, make1_str("on"), $4); + $$ = cat_str(4, make_str("cluster"), $2, make_str("on"), $4); } ; @@ -2557,32 +3048,32 @@ ClusterStmt: CLUSTER index_name ON relation_name VacuumStmt: VACUUM opt_verbose opt_analyze { - $$ = cat3_str(make1_str("vacuum"), $2, $3); + $$ = cat_str(3, make_str("vacuum"), $2, $3); } | VACUUM opt_verbose opt_analyze relation_name opt_va_list { if ( strlen($5) > 0 && strlen($4) == 0 ) - yyerror("parser: syntax error at or near \"(\""); - $$ = cat5_str(make1_str("vacuum"), $2, $3, $4, $5); + mmerror(ET_ERROR, "VACUUM syntax error at or near \"(\"\n\tRelations name must be specified"); + $$ = cat_str(5, make_str("vacuum"), $2, $3, $4, $5); } ; -opt_verbose: VERBOSE { $$ = make1_str("verbose"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_verbose: VERBOSE { $$ = make_str("verbose"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_analyze: ANALYZE { $$ = make1_str("analyse"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_analyze: ANALYZE { $$ = make_str("analyse"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_va_list: '(' va_list ')' { $$ = make3_str(make1_str("("), $2, make1_str(")")); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_va_list: '(' va_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | /*EMPTY*/ { $$ = EMPTY; } ; va_list: name { $$=$1; } | va_list ',' name - { $$=cat3_str($1, make1_str(","), $3); } + { $$=cat_str(3, $1, make_str(","), $3); } ; @@ -2595,7 +3086,7 @@ va_list: name ExplainStmt: EXPLAIN opt_verbose OptimizableStmt { - $$ = cat3_str(make1_str("explain"), $2, $3); + $$ = cat_str(3, make_str("explain"), $2, $3); } ; @@ -2634,39 +3125,48 @@ OptimizableStmt: SelectStmt * the same statements without any shift/reduce conflicts */ InsertStmt: INSERT INTO relation_name insert_rest { - $$ = cat3_str(make1_str("insert into"), $3, $4); + $$ = cat_str(3, make_str("insert into"), $3, $4); } ; insert_rest: VALUES '(' target_list ')' { - $$ = make3_str(make1_str("values("), $3, make1_str(")")); + $$ = cat_str(3, make_str("values("), $3, make_str(")")); } | DEFAULT VALUES { - $$ = make1_str("default values"); + $$ = make_str("default values"); } +/* We want the full power of SelectStatements including INTERSECT and EXCEPT + * for insertion. However, we can't support sort or limit clauses. + */ | SelectStmt { + if (FoundSort != 0) + mmerror(ET_ERROR, "ORDER BY is not allowed in INSERT/SELECT"); + $$ = $1; } | '(' columnList ')' VALUES '(' target_list ')' { - $$ = make5_str(make1_str("("), $2, make1_str(") values ("), $6, make1_str(")")); + $$ = cat_str(5, make_str("("), $2, make_str(") values ("), $6, make_str(")")); } | '(' columnList ')' SelectStmt { - $$ = make4_str(make1_str("("), $2, make1_str(")"), $4); + if (FoundSort != 0) + mmerror(ET_ERROR, "ORDER BY is not all owed in INSERT/SELECT"); + + $$ = cat_str(4, make_str("("), $2, make_str(")"), $4); } ; -opt_column_list: '(' columnList ')' { $$ = make3_str(make1_str("("), $2, make1_str(")")); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_column_list: '(' columnList ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | /*EMPTY*/ { $$ = EMPTY; } ; columnList: columnList ',' columnElem - { $$ = cat3_str($1, make1_str(","), $3); } + { $$ = cat_str(3, $1, make_str(","), $3); } | columnElem { $$ = $1; } ; @@ -2688,28 +3188,28 @@ columnElem: ColId opt_indirection DeleteStmt: DELETE FROM relation_name where_clause { - $$ = cat3_str(make1_str("delete from"), $3, $4); + $$ = cat_str(3, make_str("delete from"), $3, $4); } ; LockStmt: LOCK_P opt_table relation_name opt_lock { - $$ = cat4_str(make1_str("lock"), $2, $3, $4); + $$ = cat_str(4, make_str("lock"), $2, $3, $4); } ; -opt_lock: IN lock_type MODE { $$ = cat3_str(make1_str("in"), $2, make1_str("mode")); } - | /*EMPTY*/ { $$ = make1_str("");} +opt_lock: IN lock_type MODE { $$ = cat_str(3, make_str("in"), $2, make_str("mode")); } + | /*EMPTY*/ { $$ = EMPTY;} ; -lock_type: SHARE ROW EXCLUSIVE { $$ = make1_str("share row exclusive"); } - | ROW opt_lmode { $$ = cat2_str(make1_str("row"), $2);} - | ACCESS opt_lmode { $$ = cat2_str(make1_str("access"), $2);} +lock_type: SHARE ROW EXCLUSIVE { $$ = make_str("share row exclusive"); } + | ROW opt_lmode { $$ = cat2_str(make_str("row"), $2);} + | ACCESS opt_lmode { $$ = cat2_str(make_str("access"), $2);} | opt_lmode { $$ = $1; } ; -opt_lmode: SHARE { $$ = make1_str("share"); } - | EXCLUSIVE { $$ = make1_str("exclusive"); } +opt_lmode: SHARE { $$ = make_str("share"); } + | EXCLUSIVE { $$ = make_str("exclusive"); } ; /***************************************************************************** @@ -2724,7 +3224,7 @@ UpdateStmt: UPDATE relation_name from_clause where_clause { - $$ = cat2_str(cat5_str(make1_str("update"), $2, make1_str("set"), $4, $5), $6); + $$ = cat_str(6, make_str("update"), $2, make_str("set"), $4, $5, $6); } ; @@ -2747,7 +3247,7 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR { /* re-definition is a bug */ sprintf(errortext, "cursor %s already defined", $2); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } } @@ -2757,22 +3257,22 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR this->next = cur; this->name = $2; this->connection = connection; - this->command = cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for"), $7); + this->command = cat_str(5, make_str("declare"), mm_strdup($2), $3, make_str("cursor for"), $7); this->argsinsert = argsinsert; this->argsresult = argsresult; argsinsert = argsresult = NULL; cur = this; - $$ = cat3_str(make1_str("/*"), mm_strdup(this->command), make1_str("*/")); + $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/")); } ; -opt_cursor: BINARY { $$ = make1_str("binary"); } - | INSENSITIVE { $$ = make1_str("insensitive"); } - | SCROLL { $$ = make1_str("scroll"); } - | INSENSITIVE SCROLL { $$ = make1_str("insensitive scroll"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_cursor: BINARY { $$ = make_str("binary"); } + | INSENSITIVE { $$ = make_str("insensitive"); } + | SCROLL { $$ = make_str("scroll"); } + | INSENSITIVE SCROLL { $$ = make_str("insensitive scroll"); } + | /*EMPTY*/ { $$ = EMPTY; } ; /***************************************************************************** @@ -2788,14 +3288,16 @@ opt_cursor: BINARY { $$ = make1_str("binary"); } * unionClause and intersectClause (NIL if no set operations were present) */ -SelectStmt: select_clause sort_clause for_update_clause opt_select_limit - { - if (strlen($3) > 0 && ForUpdateNotAllowed != 0) - yyerror("FOR UPDATE is not allowed in this context"); +SelectStmt: select_clause + { FoundSort = 0; } + sort_clause for_update_clause opt_select_limit + { + if (strlen($4) > 0 && ForUpdateNotAllowed != 0) + mmerror(ET_ERROR, "FOR UPDATE is not allowed in this context"); - ForUpdateNotAllowed = 0; - $$ = cat4_str($1, $2, $3, $4); - } + ForUpdateNotAllowed = 0; + $$ = cat_str(4, $1, $3, $4, $5); + } /* This rule parses Select statements including UNION INTERSECT and EXCEPT. * '(' and ')' can be used to specify the order of the operations @@ -2806,64 +3308,70 @@ SelectStmt: select_clause sort_clause for_update_clause opt_select_limit */ select_clause: '(' select_clause ')' { - $$ = make3_str(make1_str("("), $2, make1_str(")")); + $$ = cat_str(3, make_str("("), $2, make_str(")")); } | SubSelect { - $$ = $1; + FoundInto = 0; + $$ = $1; } | select_clause EXCEPT select_clause { - $$ = cat3_str($1, make1_str("except"), $3); + $$ = cat_str(3, $1, make_str("except"), $3); ForUpdateNotAllowed = 1; } - | select_clause UNION opt_union select_clause + | select_clause UNION opt_all select_clause { - $$ = cat4_str($1, make1_str("union"), $3, $4); + $$ = cat_str(4, $1, make_str("union"), $3, $4); ForUpdateNotAllowed = 1; } - | select_clause INTERSECT opt_union select_clause + | select_clause INTERSECT opt_all select_clause { - $$ = cat3_str($1, make1_str("intersect"), $3); + $$ = cat_str(3, $1, make_str("intersect"), $3); ForUpdateNotAllowed = 1; } ; -SubSelect: SELECT opt_unique target_list +SubSelect: SELECT opt_distinct target_list result from_clause where_clause group_clause having_clause { - $$ = cat4_str(cat5_str(make1_str("select"), $2, $3, $4, $5), $6, $7, $8); if (strlen($7) > 0 || strlen($8) > 0) ForUpdateNotAllowed = 1; + $$ = cat_str(8, make_str("select"), $2, $3, $4, $5, $6, $7, $8); } ; -result: INTO OptTemp opt_table relation_name { $$= cat4_str(make1_str("into"), $2, $3, $4); } - | INTO into_list { $$ = make1_str(""); } - | /*EMPTY*/ { $$ = make1_str(""); } +result: INTO OptTemp opt_table relation_name { FoundInto = 1; + $$= cat_str(4, make_str("into"), $2, $3, $4); + } + | INTO into_list { $$ = EMPTY; } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_table: TABLE { $$ = make1_str("table"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_table: TABLE { $$ = make_str("table"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_union: ALL { $$ = make1_str("all"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_all: ALL { $$ = make_str("all"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_unique: DISTINCT { $$ = make1_str("distinct"); } - | DISTINCT ON ColId { $$ = cat2_str(make1_str("distinct on"), $3); } - | ALL { $$ = make1_str("all"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_distinct: DISTINCT { $$ = make_str("distinct"); } + | DISTINCT ON '(' expr_list ')' { $$ = cat_str(3, make_str("distinct on ("), $4, make_str(")")); } + | ALL { $$ = make_str("all"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -sort_clause: ORDER BY sortby_list { $$ = cat2_str(make1_str("order by"), $3); } - | /*EMPTY*/ { $$ = make1_str(""); } +sort_clause: ORDER BY sortby_list { + FoundSort = 1; + $$ = cat2_str(make_str("order by"), $3); + } + | /*EMPTY*/ { $$ = EMPTY; } ; sortby_list: sortby { $$ = $1; } - | sortby_list ',' sortby { $$ = cat3_str($1, make1_str(","), $3); } + | sortby_list ',' sortby { $$ = cat_str(3, $1, make_str(","), $3); } ; sortby: a_expr OptUseOp @@ -2872,30 +3380,28 @@ sortby: a_expr OptUseOp } ; -OptUseOp: USING Op { $$ = cat2_str(make1_str("using"), $2); } - | USING '<' { $$ = make1_str("using <"); } - | USING '>' { $$ = make1_str("using >"); } - | ASC { $$ = make1_str("asc"); } - | DESC { $$ = make1_str("desc"); } - | /*EMPTY*/ { $$ = make1_str(""); } +OptUseOp: USING all_Op { $$ = cat2_str(make_str("using"), $2); } + | ASC { $$ = make_str("asc"); } + | DESC { $$ = make_str("desc"); } + | /*EMPTY*/ { $$ = EMPTY; } ; opt_select_limit: LIMIT select_limit_value ',' select_offset_value - { $$ = cat4_str(make1_str("limit"), $2, make1_str(","), $4); } + { $$ = cat_str(4, make_str("limit"), $2, make_str(","), $4); } | LIMIT select_limit_value OFFSET select_offset_value - { $$ = cat4_str(make1_str("limit"), $2, make1_str("offset"), $4); } + { $$ = cat_str(4, make_str("limit"), $2, make_str("offset"), $4); } | LIMIT select_limit_value - { $$ = cat2_str(make1_str("limit"), $2); } + { $$ = cat2_str(make_str("limit"), $2); } | OFFSET select_offset_value LIMIT select_limit_value - { $$ = cat4_str(make1_str("offset"), $2, make1_str("limit"), $4); } + { $$ = cat_str(4, make_str("offset"), $2, make_str("limit"), $4); } | OFFSET select_offset_value - { $$ = cat2_str(make1_str("offset"), $2); } + { $$ = cat2_str(make_str("offset"), $2); } | /* EMPTY */ - { $$ = make1_str(""); } + { $$ = EMPTY; } ; select_limit_value: Iconst { $$ = $1; } - | ALL { $$ = make1_str("all"); } + | ALL { $$ = make_str("all"); } | PARAM { $$ = make_name(); } ; @@ -2910,8 +3416,8 @@ select_offset_value: Iconst { $$ = $1; } * ...however, recursive addattr and rename supported. make special * cases for these. */ -opt_inh_star: '*' { $$ = make1_str("*"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_inh_star: '*' { $$ = make_str("*"); } + | /*EMPTY*/ { $$ = EMPTY; } ; relation_name_list: name_list { $$ = $1; }; @@ -2919,167 +3425,167 @@ relation_name_list: name_list { $$ = $1; }; name_list: name { $$ = $1; } | name_list ',' name - { $$ = cat3_str($1, make1_str(","), $3); } + { $$ = cat_str(3, $1, make_str(","), $3); } ; -group_clause: GROUP BY expr_list { $$ = cat2_str(make1_str("group by"), $3); } - | /*EMPTY*/ { $$ = make1_str(""); } +group_clause: GROUP BY expr_list { $$ = cat2_str(make_str("group by"), $3); } + | /*EMPTY*/ { $$ = EMPTY; } ; having_clause: HAVING a_expr { - $$ = cat2_str(make1_str("having"), $2); + $$ = cat2_str(make_str("having"), $2); } - | /*EMPTY*/ { $$ = make1_str(""); } + | /*EMPTY*/ { $$ = EMPTY; } ; for_update_clause: FOR UPDATE update_list { - $$ = make1_str("for update"); + $$ = make_str("for update"); } | FOR READ ONLY { - $$ = make1_str("for read only"); + $$ = make_str("for read only"); } | /* EMPTY */ { - $$ = make1_str(""); + $$ = EMPTY; } ; update_list: OF va_list { - $$ = cat2_str(make1_str("of"), $2); + $$ = cat2_str(make_str("of"), $2); } | /* EMPTY */ { - $$ = make1_str(""); + $$ = EMPTY; } ; /***************************************************************************** * * clauses common to all Optimizable Stmts: - * from_clause - - * where_clause - + * from_clause - allow list of both JOIN expressions and table names + * where_clause - qualifications for joins or restrictions * *****************************************************************************/ -from_clause: FROM from_expr +from_clause: FROM from_list { $$ = cat2_str(make_str("from"), $2); } +/*** +#ifdef ENABLE_ORACLE_JOIN_SYNTAX + | FROM oracle_list { $$ = cat2_str(make_str("from"), $2); } +#endif +***/ + | FROM from_expr { $$ = cat2_str(make_str("from"), $2); } + | /* EMPTY */ { $$ = EMPTY; } + ; + +from_list: from_list ',' table_expr { $$ = cat_str(3, $1, make_str(","), $3); } + | table_expr { $$ = $1; } + ; + +/*********** + * This results in one shift/reduce conflict, presumably due to the trailing "( + * - Thomas 1999-09-20 + * +#ifdef ENABLE_ORACLE_JOIN_SYNTAX +oracle_list: oracle_expr { $$ = $1; } + ; + +oracle_expr: ColId ',' ColId oracle_outer { - $$ = cat2_str(make1_str("from"), $2); + mmerror(ET_ERROR, "Oracle OUTER JOIN not yet supported"); + $$ = cat_str(3, $1, make_str(","), $3); } } - | /* EMPTY */ + | oracle_outer ColId ',' ColId { - $$ = make1_str(""); + mmerror(ET_ERROR, "Oracle OUTER JOIN not yet supported"); + $$ = cat_str(4, $1, $2, make_str(","), $3); } } + ; +oracle_outer: '(' '+' ')' { $$ = make_str("(+)"); } + ; +#endif +*************/ -from_expr: '(' join_clause_with_union ')' - { $$ = make3_str(make1_str("("), $2, make1_str(")")); } +from_expr: '(' join_clause_with_union ')' alias_clause + { $$ = cat_str(4, make_str("("), $2, make_str(")"), $4); } | join_clause { $$ = $1; } - | table_list - { $$ = $1; } ; -table_list: table_list ',' table_expr - { $$ = make3_str($1, make1_str(","), $3); } - | table_expr - { $$ = $1; } - ; - -table_expr: relation_expr AS ColLabel - { - $$ = cat3_str($1, make1_str("as"), $3); - } - | relation_expr ColId +table_expr: relation_expr alias_clause { $$ = cat2_str($1, $2); } - | relation_expr - { - $$ = $1; - } ; +alias_clause: AS ColId '(' name_list ')' + { $$ = cat_str(5, make_str("as"), $2, make_str("("), $4, make_str(")")); } + | AS ColId + { $$ = cat2_str(make_str("as"), $2); } + | ColId '(' name_list ')' + { $$ = cat_str(4, $1, make_str("("), $3, make_str(")")); } + | ColId + { $$ = $1; } + | /*EMPTY*/ + { $$ = EMPTY; } + ; + /* A UNION JOIN is the same as a FULL OUTER JOIN which *omits* * all result rows which would have matched on an INNER JOIN. - * Let's reject this for now. - thomas 1999-01-08 + * Syntactically, must enclose the UNION JOIN in parens to avoid + * conflicts with SELECT/UNION. */ -join_clause_with_union: join_clause - { $$ = $1; } - | table_expr UNION JOIN table_expr - { yyerror("UNION JOIN not yet implemented"); } - ; - -join_clause: table_expr join_list - { - $$ = cat2_str($1, $2); - } - ; - -join_list: join_list join_expr - { - $$ = cat2_str($1, $2); - } - | join_expr - { - $$ = $1; - } +join_clause: join_clause join_expr + { $$ = cat2_str($1, $2); } + | table_expr join_expr + { $$ = cat2_str($1, $2); } ; /* This is everything but the left side of a join. * Note that a CROSS JOIN is the same as an unqualified * inner join, so just pass back the right-side table. * A NATURAL JOIN implicitly matches column names between - * tables, so we'll collect those during the later transformation. + * tables, and the shape is determined by which columns are + * in common. We'll collect columns during the later transformations. */ - join_expr: join_type JOIN table_expr join_qual { - $$ = cat4_str($1, make1_str("join"), $3, $4); + $$ = cat_str(4, $1, make_str("join"), $3, $4); } | NATURAL join_type JOIN table_expr { - $$ = cat4_str(make1_str("natural"), $2, make1_str("join"), $4); + $$ = cat_str(4, make_str("natural"), $2, make_str("join"), $4); } | CROSS JOIN table_expr - { $$ = cat2_str(make1_str("cross join"), $3); } + { $$ = cat2_str(make_str("cross join"), $3); } ; -/* OUTER is just noise... */ -join_type: FULL join_outer - { - $$ = cat2_str(make1_str("full"), $2); - fprintf(stderr,"FULL OUTER JOIN not yet implemented\n"); - } - | LEFT join_outer - { - $$ = cat2_str(make1_str("left"), $2); - fprintf(stderr,"LEFT OUTER JOIN not yet implemented\n"); - } - | RIGHT join_outer - { - $$ = cat2_str(make1_str("right"), $2); - fprintf(stderr,"RIGHT OUTER JOIN not yet implemented\n"); - } - | OUTER_P - { - $$ = make1_str("outer"); - fprintf(stderr,"OUTER JOIN not yet implemented\n"); - } - | INNER_P - { - $$ = make1_str("inner"); - } - | /* EMPTY */ - { - $$ = make1_str(""); - } +join_clause_with_union: join_clause_with_union join_expr_with_union + { $$ = cat2_str($1, $2); } + | table_expr join_expr_with_union + { $$ = cat2_str($1, $2); } + ; + +join_expr_with_union: join_expr + { $$ = $1; } + | UNION JOIN table_expr + { $$ = cat2_str(make_str("union join"), $3); } + ; +/* OUTER is just noise... */ +join_type: FULL join_outer { $$ = cat2_str(make_str("full"), $2); } + | LEFT join_outer { $$ = cat2_str(make_str("left"), $2); } + | RIGHT join_outer { $$ = cat2_str(make_str("right"), $2); } + | OUTER_P { $$ = make_str("outer"); } + | INNER_P { $$ = make_str("inner"); } + | /* EMPTY */ { $$ = EMPTY; } + ; -join_outer: OUTER_P { $$ = make1_str("outer"); } - | /*EMPTY*/ { $$ = make1_str(""); /* no qualifiers */ } +join_outer: OUTER_P { $$ = make_str("outer"); } + | /*EMPTY*/ { $$ = EMPTY; /* no qualifiers */ } ; /* JOIN qualification clauses @@ -3090,11 +3596,11 @@ join_outer: OUTER_P { $$ = make1_str("outer"); } * - thomas 1999-01-07 */ -join_qual: USING '(' using_list ')' { $$ = make3_str(make1_str("using ("), $3, make1_str(")")); } - | ON a_expr { $$ = cat2_str(make1_str("on"), $2); } +join_qual: USING '(' using_list ')' { $$ = cat_str(3, make_str("using ("), $3, make_str(")")); } + | ON a_expr { $$ = cat2_str(make_str("on"), $2); } ; -using_list: using_list ',' using_expr { $$ = make3_str($1, make1_str(","), $3); } +using_list: using_list ',' using_expr { $$ = cat_str(3, $1, make_str(","), $3); } | using_expr { $$ = $1; } ; @@ -3104,8 +3610,8 @@ using_expr: ColId } ; -where_clause: WHERE a_expr { $$ = cat2_str(make1_str("where"), $2); } - | /*EMPTY*/ { $$ = make1_str(""); /* no qualifiers */ } +where_clause: WHERE a_expr { $$ = cat2_str(make_str("where"), $2); } + | /*EMPTY*/ { $$ = EMPTY; /* no qualifiers */ } ; relation_expr: relation_name @@ -3116,14 +3622,14 @@ relation_expr: relation_name | relation_name '*' %prec '=' { /* inheritance query */ - $$ = cat2_str($1, make1_str("*")); + $$ = cat2_str($1, make_str("*")); } opt_array_bounds: '[' ']' opt_array_bounds { $$.index1 = 0; $$.index2 = $3.index1; - $$.str = cat2_str(make1_str("[]"), $3.str); + $$.str = cat2_str(make_str("[]"), $3.str); } | '[' Iresult ']' opt_array_bounds { @@ -3132,13 +3638,13 @@ opt_array_bounds: '[' ']' opt_array_bounds sprintf (txt, "%d", $2); $$.index1 = $2; $$.index2 = $4.index1; - $$.str = cat4_str(make1_str("["), txt, make1_str("]"), $4.str); + $$.str = cat_str(4, make_str("["), txt, make_str("]"), $4.str); } | /* EMPTY */ { $$.index1 = -1; $$.index2 = -1; - $$.str= make1_str(""); + $$.str= EMPTY; } ; @@ -3168,7 +3674,7 @@ Typename: SimpleTypename opt_array_bounds } | SETOF SimpleTypename { - $$ = cat2_str(make1_str("setof"), $2); + $$ = cat2_str(make_str("setof"), $2); } ; @@ -3185,40 +3691,39 @@ Generic: generic ; generic: ident { $$ = $1; } - | TYPE_P { $$ = make1_str("type"); } - | SQL_AT { $$ = make1_str("at"); } - | SQL_AUTOCOMMIT { $$ = make1_str("autocommit"); } - | SQL_BOOL { $$ = make1_str("bool"); } - | SQL_BREAK { $$ = make1_str("break"); } - | SQL_CALL { $$ = make1_str("call"); } - | SQL_CONNECT { $$ = make1_str("connect"); } - | SQL_CONNECTION { $$ = make1_str("connection"); } - | SQL_CONTINUE { $$ = make1_str("continue"); } - | SQL_DEALLOCATE { $$ = make1_str("deallocate"); } - | SQL_DISCONNECT { $$ = make1_str("disconnect"); } - | SQL_FOUND { $$ = make1_str("found"); } - | SQL_GO { $$ = make1_str("go"); } - | SQL_GOTO { $$ = make1_str("goto"); } - | SQL_IDENTIFIED { $$ = make1_str("identified"); } - | SQL_IMMEDIATE { $$ = make1_str("immediate"); } - | SQL_INDICATOR { $$ = make1_str("indicator"); } - | SQL_INT { $$ = make1_str("int"); } - | SQL_LONG { $$ = make1_str("long"); } - | SQL_OFF { $$ = make1_str("off"); } - | SQL_OPEN { $$ = make1_str("open"); } - | SQL_PREPARE { $$ = make1_str("prepare"); } - | SQL_RELEASE { $$ = make1_str("release"); } - | SQL_SECTION { $$ = make1_str("section"); } - | SQL_SHORT { $$ = make1_str("short"); } - | SQL_SIGNED { $$ = make1_str("signed"); } - | SQL_SQLERROR { $$ = make1_str("sqlerror"); } - | SQL_SQLPRINT { $$ = make1_str("sqlprint"); } - | SQL_SQLWARNING { $$ = make1_str("sqlwarning"); } - | SQL_STOP { $$ = make1_str("stop"); } - | SQL_STRUCT { $$ = make1_str("struct"); } - | SQL_UNSIGNED { $$ = make1_str("unsigned"); } - | SQL_VAR { $$ = make1_str("var"); } - | SQL_WHENEVER { $$ = make1_str("whenever"); } + | TYPE_P { $$ = make_str("type"); } + | SQL_AT { $$ = make_str("at"); } + | SQL_AUTOCOMMIT { $$ = make_str("autocommit"); } + | SQL_BOOL { $$ = make_str("bool"); } + | SQL_BREAK { $$ = make_str("break"); } + | SQL_CALL { $$ = make_str("call"); } + | SQL_CONNECT { $$ = make_str("connect"); } + | SQL_CONNECTION { $$ = make_str("connection"); } + | SQL_CONTINUE { $$ = make_str("continue"); } + | SQL_DEALLOCATE { $$ = make_str("deallocate"); } + | SQL_DISCONNECT { $$ = make_str("disconnect"); } + | SQL_FOUND { $$ = make_str("found"); } + | SQL_GO { $$ = make_str("go"); } + | SQL_GOTO { $$ = make_str("goto"); } + | SQL_IDENTIFIED { $$ = make_str("identified"); } + | SQL_INDICATOR { $$ = make_str("indicator"); } + | SQL_INT { $$ = make_str("int"); } + | SQL_LONG { $$ = make_str("long"); } + | SQL_OFF { $$ = make_str("off"); } + | SQL_OPEN { $$ = make_str("open"); } + | SQL_PREPARE { $$ = make_str("prepare"); } + | SQL_RELEASE { $$ = make_str("release"); } + | SQL_SECTION { $$ = make_str("section"); } + | SQL_SHORT { $$ = make_str("short"); } + | SQL_SIGNED { $$ = make_str("signed"); } + | SQL_SQLERROR { $$ = make_str("sqlerror"); } + | SQL_SQLPRINT { $$ = make_str("sqlprint"); } + | SQL_SQLWARNING { $$ = make_str("sqlwarning"); } + | SQL_STOP { $$ = make_str("stop"); } + | SQL_STRUCT { $$ = make_str("struct"); } + | SQL_UNSIGNED { $$ = make_str("unsigned"); } + | SQL_VAR { $$ = make_str("var"); } + | SQL_WHENEVER { $$ = make_str("whenever"); } ; /* SQL92 numeric data types @@ -3228,43 +3733,47 @@ generic: ident { $$ = $1; } */ Numeric: FLOAT opt_float { - $$ = cat2_str(make1_str("float"), $2); + $$ = cat2_str(make_str("float"), $2); } | DOUBLE PRECISION { - $$ = make1_str("double precision"); + $$ = make_str("double precision"); } | DECIMAL opt_decimal { - $$ = cat2_str(make1_str("decimal"), $2); + $$ = cat2_str(make_str("decimal"), $2); + } + | DEC opt_decimal + { + $$ = cat2_str(make_str("dec"), $2); } | NUMERIC opt_numeric { - $$ = cat2_str(make1_str("numeric"), $2); + $$ = cat2_str(make_str("numeric"), $2); } ; numeric: FLOAT - { $$ = make1_str("float"); } + { $$ = make_str("float"); } | DOUBLE PRECISION - { $$ = make1_str("double precision"); } + { $$ = make_str("double precision"); } | DECIMAL - { $$ = make1_str("decimal"); } + { $$ = make_str("decimal"); } | NUMERIC - { $$ = make1_str("numeric"); } + { $$ = make_str("numeric"); } ; opt_float: '(' Iconst ')' { if (atol($2) < 1) - yyerror("precision for FLOAT must be at least 1"); + mmerror(ET_ERROR, "precision for FLOAT must be at least 1"); else if (atol($2) >= 16) - yyerror("precision for FLOAT must be less than 16"); - $$ = make3_str(make1_str("("), $2, make1_str(")")); + mmerror(ET_ERROR, "precision for FLOAT must be less than 16"); + $$ = cat_str(3, make_str("("), $2, make_str(")")); } | /*EMPTY*/ { - $$ = make1_str(""); + $$ = EMPTY; } ; @@ -3272,25 +3781,25 @@ opt_numeric: '(' Iconst ',' Iconst ')' { if (atol($2) < 1 || atol($2) > NUMERIC_MAX_PRECISION) { sprintf(errortext, "NUMERIC precision %s must be between 1 and %d", $2, NUMERIC_MAX_PRECISION); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } if (atol($4) < 0 || atol($4) > atol($2)) { sprintf(errortext, "NUMERIC scale %s must be between 0 and precision %s", $4, $2); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - $$ = cat3_str(make2_str(make1_str("("), $2), make1_str(","), make2_str($4, make1_str(")"))); + $$ = cat_str(5, make_str("("), $2, make_str(","), $4, make_str(")")); } | '(' Iconst ')' { if (atol($2) < 1 || atol($2) > NUMERIC_MAX_PRECISION) { sprintf(errortext, "NUMERIC precision %s must be between 1 and %d", $2, NUMERIC_MAX_PRECISION); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - $$ = make3_str(make1_str("("), $2, make1_str(")")); + $$ = cat_str(3, make_str("("), $2, make_str(")")); } | /*EMPTY*/ { - $$ = make1_str(""); + $$ = EMPTY; } ; @@ -3298,46 +3807,47 @@ opt_decimal: '(' Iconst ',' Iconst ')' { if (atol($2) < 1 || atol($2) > NUMERIC_MAX_PRECISION) { sprintf(errortext, "NUMERIC precision %s must be between 1 and %d", $2, NUMERIC_MAX_PRECISION); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } if (atol($4) < 0 || atol($4) > atol($2)) { sprintf(errortext, "NUMERIC scale %s must be between 0 and precision %s", $4, $2); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - $$ = cat3_str(make2_str(make1_str("("), $2), make1_str(","), make2_str($4, make1_str(")"))); + $$ = cat_str(5, make_str("("), $2, make_str(","), $4, make_str(")")); } | '(' Iconst ')' { if (atol($2) < 1 || atol($2) > NUMERIC_MAX_PRECISION) { sprintf(errortext, "NUMERIC precision %s must be between 1 and %d", $2, NUMERIC_MAX_PRECISION); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - $$ = make3_str(make1_str("("), $2, make1_str(")")); + $$ = cat_str(3, make_str("("), $2, make_str(")")); } | /*EMPTY*/ { - $$ = make1_str(""); + $$ = EMPTY; } ; -/* SQL92 character data types +/* + * SQL92 character data types * The following implements CHAR() and VARCHAR(). * - ay 6/95 */ Character: character '(' Iconst ')' { - if (strncasecmp($1, "char", strlen("char")) && strncasecmp($1, "varchar", strlen("varchar"))) - yyerror("internal parsing error; unrecognized character type"); - if (atol($3) < 1) { - sprintf(errortext, "length for '%s' type must be at least 1",$1); - yyerror(errortext); + if (atol($3) < 1) + { + sprintf(errortext, "length for type '%s' type must be at least 1",$1); + mmerror(ET_ERROR, errortext); } - else if (atol($3) > MaxAttrSize) { + else if (atol($3) > MaxAttrSize) + { sprintf(errortext, "length for type '%s' cannot exceed %ld", $1, MaxAttrSize); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - $$ = cat2_str($1, make3_str(make1_str("("), $3, make1_str(")"))); + $$ = cat_str(4, $1, make_str("("), $3, make_str(")")); } | character { @@ -3347,27 +3857,30 @@ Character: character '(' Iconst ')' character: CHARACTER opt_varying opt_charset opt_collate { - if (strlen($4) > 0) - fprintf(stderr, "COLLATE %s not yet implemented",$4); + if (strlen($4) > 0) + { + sprintf(errortext, "COLLATE %s not yet implemented", $4); + mmerror(ET_WARN, errortext); + } - $$ = cat4_str(make1_str("character"), $2, $3, $4); + $$ = cat_str(4, make_str("character"), $2, $3, $4); } - | CHAR opt_varying { $$ = cat2_str(make1_str("char"), $2); } - | VARCHAR { $$ = make1_str("varchar"); } - | NATIONAL CHARACTER opt_varying { $$ = cat2_str(make1_str("national character"), $3); } - | NCHAR opt_varying { $$ = cat2_str(make1_str("nchar"), $2); } + | CHAR opt_varying { $$ = cat2_str(make_str("char"), $2); } + | VARCHAR { $$ = make_str("varchar"); } + | NATIONAL CHARACTER opt_varying { $$ = cat2_str(make_str("national character"), $3); } + | NCHAR opt_varying { $$ = cat2_str(make_str("nchar"), $2); } ; -opt_varying: VARYING { $$ = make1_str("varying"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_varying: VARYING { $$ = make_str("varying"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_charset: CHARACTER SET ColId { $$ = cat2_str(make1_str("character set"), $3); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_charset: CHARACTER SET ColId { $$ = cat2_str(make_str("character set"), $3); } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_collate: COLLATE ColId { $$ = cat2_str(make1_str("collate"), $2); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_collate: COLLATE ColId { $$ = cat2_str(make_str("collate"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } ; Datetime: datetime @@ -3376,45 +3889,45 @@ Datetime: datetime } | TIMESTAMP opt_timezone { - $$ = cat2_str(make1_str("timestamp"), $2); + $$ = cat2_str(make_str("timestamp"), $2); } | TIME { - $$ = make1_str("time"); + $$ = make_str("time"); } | INTERVAL opt_interval { - $$ = cat2_str(make1_str("interval"), $2); + $$ = cat2_str(make_str("interval"), $2); } ; -datetime: YEAR_P { $$ = make1_str("year"); } - | MONTH_P { $$ = make1_str("month"); } - | DAY_P { $$ = make1_str("day"); } - | HOUR_P { $$ = make1_str("hour"); } - | MINUTE_P { $$ = make1_str("minute"); } - | SECOND_P { $$ = make1_str("second"); } +datetime: YEAR_P { $$ = make_str("year"); } + | MONTH_P { $$ = make_str("month"); } + | DAY_P { $$ = make_str("day"); } + | HOUR_P { $$ = make_str("hour"); } + | MINUTE_P { $$ = make_str("minute"); } + | SECOND_P { $$ = make_str("second"); } ; -opt_timezone: WITH TIME ZONE { $$ = make1_str("with time zone"); } - | /*EMPTY*/ { $$ = make1_str(""); } +opt_timezone: WITH TIME ZONE { $$ = make_str("with time zone"); } + | /*EMPTY*/ { $$ = EMPTY; } ; opt_interval: datetime { $$ = $1; } - | YEAR_P TO MONTH_P { $$ = make1_str("year to #month"); } - | DAY_P TO HOUR_P { $$ = make1_str("day to hour"); } - | DAY_P TO MINUTE_P { $$ = make1_str("day to minute"); } - | DAY_P TO SECOND_P { $$ = make1_str("day to second"); } - | HOUR_P TO MINUTE_P { $$ = make1_str("hour to minute"); } - | MINUTE_P TO SECOND_P { $$ = make1_str("minute to second"); } - | HOUR_P TO SECOND_P { $$ = make1_str("hour to second"); } - | /*EMPTY*/ { $$ = make1_str(""); } + | YEAR_P TO MONTH_P { $$ = make_str("year to #month"); } + | DAY_P TO HOUR_P { $$ = make_str("day to hour"); } + | DAY_P TO MINUTE_P { $$ = make_str("day to minute"); } + | DAY_P TO SECOND_P { $$ = make_str("day to second"); } + | HOUR_P TO MINUTE_P { $$ = make_str("hour to minute"); } + | MINUTE_P TO SECOND_P { $$ = make_str("minute to second"); } + | HOUR_P TO SECOND_P { $$ = make_str("hour to second"); } + | /*EMPTY*/ { $$ = EMPTY; } ; /***************************************************************************** * - * expression grammar, still needs some cleanup + * expression grammar * *****************************************************************************/ @@ -3422,66 +3935,50 @@ a_expr_or_null: a_expr { $$ = $1; } | NULL_P { - $$ = make1_str("null"); + $$ = make_str("null"); } ; /* Expressions using row descriptors * Define row_descriptor to allow yacc to break the reduce/reduce conflict * with singleton expressions. - * Eliminated lots of code by defining row_op and sub_type clauses. - * However, can not consolidate EXPR_LINK case with others subselects - * due to shift/reduce conflict with the non-subselect clause (the parser - * would have to look ahead more than one token to resolve the conflict). - * - thomas 1998-05-09 */ row_expr: '(' row_descriptor ')' IN '(' SubSelect ')' { - $$ = make5_str(make1_str("("), $2, make1_str(") in ("), $6, make1_str(")")); + $$ = cat_str(5, make_str("("), $2, make_str(") in ("), $6, make_str(")")); } | '(' row_descriptor ')' NOT IN '(' SubSelect ')' { - $$ = make5_str(make1_str("("), $2, make1_str(") not in ("), $7, make1_str(")")); + $$ = cat_str(5, make_str("("), $2, make_str(") not in ("), $7, make_str(")")); } - | '(' row_descriptor ')' row_op sub_type '(' SubSelect ')' + | '(' row_descriptor ')' all_Op sub_type '(' SubSelect ')' { - $$ = make4_str(make5_str(make1_str("("), $2, make1_str(")"), $4, $5), make1_str("("), $7, make1_str(")")); + $$ = cat_str(8, make_str("("), $2, make_str(")"), $4, $5, make_str("("), $7, make_str(")")); } - | '(' row_descriptor ')' row_op '(' SubSelect ')' + | '(' row_descriptor ')' all_Op '(' SubSelect ')' { - $$ = make3_str(make5_str(make1_str("("), $2, make1_str(")"), $4, make1_str("(")), $6, make1_str(")")); + $$ = cat_str(7, make_str("("), $2, make_str(")"), $4, make_str("("), $6, make_str(")")); } - | '(' row_descriptor ')' row_op '(' row_descriptor ')' + | '(' row_descriptor ')' all_Op '(' row_descriptor ')' { - $$ = cat3_str(make3_str(make1_str("("), $2, make1_str(")")), $4, make3_str(make1_str("("), $6, make1_str(")"))); + $$ = cat_str(7, make_str("("), $2, make_str(")"), $4, make_str("("), $6, make_str(")")); } ; row_descriptor: row_list ',' a_expr { - $$ = cat3_str($1, make1_str(","), $3); + $$ = cat_str(3, $1, make_str(","), $3); } ; -row_op: Op { $$ = $1; } - | '<' { $$ = "<"; } - | '=' { $$ = "="; } - | '>' { $$ = ">"; } - | '+' { $$ = "+"; } - | '-' { $$ = "-"; } - | '*' { $$ = "*"; } - | '%' { $$ = "%"; } - | '/' { $$ = "/"; } - ; - -sub_type: ANY { $$ = make1_str("ANY"); } - | ALL { $$ = make1_str("ALL"); } +sub_type: ANY { $$ = make_str("ANY"); } + | ALL { $$ = make_str("ALL"); } ; row_list: row_list ',' a_expr { - $$ = cat3_str($1, make1_str(","), $3); + $$ = cat_str(3, $1, make_str(","), $3); } | a_expr { @@ -3489,525 +3986,385 @@ row_list: row_list ',' a_expr } ; +all_Op: Op | MathOp; + +MathOp: '+' { $$ = make_str("+"); } + | '-' { $$ = make_str("-"); } + | '*' { $$ = make_str("*"); } + | '%' { $$ = make_str("%"); } + | '^' { $$ = make_str("^"); } + | '|' { $$ = make_str("|"); } + | '/' { $$ = make_str("/"); } + | '<' { $$ = make_str("<"); } + | '>' { $$ = make_str(">"); } + | '=' { $$ = make_str("="); } + ; + /* General expressions * This is the heart of the expression syntax. - * Note that the BETWEEN clause looks similar to a boolean expression - * and so we must define b_expr which is almost the same as a_expr - * but without the boolean expressions. - * All operations/expressions are allowed in a BETWEEN clause - * if surrounded by parens. + * + * We have two expression types: a_expr is the unrestricted kind, and + * b_expr is a subset that must be used in some places to avoid shift/reduce + * conflicts. For example, we can't do BETWEEN as "BETWEEN a_expr AND a_expr" + * because that use of AND conflicts with AND as a boolean operator. So, + * b_expr is used in BETWEEN and we remove boolean keywords from b_expr. + * + * Note that '(' a_expr ')' is a b_expr, so an unrestricted expression can + * always be used by surrounding it with parens. + * + * c_expr is all the productions that are common to a_expr and b_expr; + * it's factored out just to eliminate redundant coding. */ -a_expr: attr - { - $$ = $1; - } - | row_expr - { $$ = $1; } - | AexprConst - { $$ = $1; } - | ColId opt_indirection - { - $$ = cat2_str($1, $2); - } +a_expr: c_expr + { $$ = $1; } + | a_expr TYPECAST Typename + { $$ = cat_str(3, $1, make_str("::"), $3); } + /* + * Can't collapse this into prior rule by using a_expr_or_null; + * that creates reduce/reduce conflicts. Grumble. + */ + | NULL_P TYPECAST Typename + { + $$ = cat2_str(make_str("null::"), $3); + } + /* + * These operators must be called out explicitly in order to make use + * of yacc/bison's automatic operator-precedence handling. All other + * operator names are handled by the generic productions using "Op", + * below; and all those operators will have the same precedence. + * + * If you add more explicitly-known operators, be sure to add them + * also to b_expr and to the MathOp list above. + */ | '-' a_expr %prec UMINUS - { $$ = cat2_str(make1_str("-"), $2); } + { $$ = cat2_str(make_str("-"), $2); } | '%' a_expr - { $$ = cat2_str(make1_str("%"), $2); } + { $$ = cat2_str(make_str("%"), $2); } | '^' a_expr - { $$ = cat2_str(make1_str("^"), $2); } + { $$ = cat2_str(make_str("^"), $2); } + | '|' a_expr + { $$ = cat2_str(make_str("|"), $2); } +/* not possible in embedded sql | ':' a_expr + { $$ = cat2_str(make_str(":"), $2); } +*/ + | ';' a_expr + { $$ = cat2_str(make_str(";"), $2); } | a_expr '%' - { $$ = cat2_str($1, make1_str("%")); } + { $$ = cat2_str($1, make_str("%")); } | a_expr '^' - { $$ = cat2_str($1, make1_str("^")); } + { $$ = cat2_str($1, make_str("^")); } + | a_expr '|' + { $$ = cat2_str($1, make_str("|")); } | a_expr '+' a_expr - { $$ = cat3_str($1, make1_str("+"), $3); } + { $$ = cat_str(3, $1, make_str("+"), $3); } | a_expr '-' a_expr - { $$ = cat3_str($1, make1_str("-"), $3); } + { $$ = cat_str(3, $1, make_str("-"), $3); } + | a_expr '*' a_expr + { $$ = cat_str(3, $1, make_str("*"), $3); } | a_expr '/' a_expr - { $$ = cat3_str($1, make1_str("/"), $3); } + { $$ = cat_str(3, $1, make_str("/"), $3); } | a_expr '%' a_expr - { $$ = cat3_str($1, make1_str("%"), $3); } - | a_expr '*' a_expr - { $$ = cat3_str($1, make1_str("*"), $3); } + { $$ = cat_str(3, $1, make_str("%"), $3); } | a_expr '^' a_expr - { $$ = cat3_str($1, make1_str("^"), $3); } + { $$ = cat_str(3, $1, make_str("^"), $3); } + | a_expr '|' a_expr + { $$ = cat_str(3, $1, make_str("|"), $3); } | a_expr '<' a_expr - { $$ = cat3_str($1, make1_str("<"), $3); } + { $$ = cat_str(3, $1, make_str("<"), $3); } | a_expr '>' a_expr - { $$ = cat3_str($1, make1_str(">"), $3); } + { $$ = cat_str(3, $1, make_str(">"), $3); } | a_expr '=' NULL_P - { $$ = cat2_str($1, make1_str("= NULL")); } + { $$ = cat2_str($1, make_str("= NULL")); } + /* We allow this for standards-broken SQL products, like MS stuff */ | NULL_P '=' a_expr - { $$ = cat2_str(make1_str("= NULL"), $3); } + { $$ = cat2_str(make_str("= NULL"), $3); } | a_expr '=' a_expr - { $$ = cat3_str($1, make1_str("="), $3); } -/* not possible in embedded sql | ':' a_expr - { $$ = cat2_str(make1_str(":"), $2); } -*/ - | ';' a_expr - { $$ = cat2_str(make1_str(";"), $2); } - | '|' a_expr - { $$ = cat2_str(make1_str("|"), $2); } - | a_expr TYPECAST Typename - { - $$ = cat3_str($1, make1_str("::"), $3); - } - | CAST '(' a_expr AS Typename ')' - { - $$ = cat3_str(make2_str(make1_str("cast("), $3), make1_str("as"), make2_str($5, make1_str(")"))); - } - | '(' a_expr_or_null ')' - { $$ = make3_str(make1_str("("), $2, make1_str(")")); } + { $$ = cat_str(3, $1, make_str("="), $3); } | a_expr Op a_expr - { $$ = cat3_str($1, $2, $3); } - | a_expr LIKE a_expr - { $$ = cat3_str($1, make1_str("like"), $3); } - | a_expr NOT LIKE a_expr - { $$ = cat3_str($1, make1_str("not like"), $4); } + { $$ = cat_str(3, $1, $2, $3); } | Op a_expr { $$ = cat2_str($1, $2); } | a_expr Op { $$ = cat2_str($1, $2); } - | func_name '(' '*' ')' - { - $$ = cat2_str($1, make1_str("(*)")); - } - | func_name '(' ')' - { - $$ = cat2_str($1, make1_str("()")); - } - | func_name '(' expr_list ')' - { - $$ = make4_str($1, make1_str("("), $3, make1_str(")")); - } - | CURRENT_DATE - { - $$ = make1_str("current_date"); - } - | CURRENT_TIME - { - $$ = make1_str("current_time"); - } - | CURRENT_TIME '(' Iconst ')' - { - if (atol($3) != 0) - fprintf(stderr,"CURRENT_TIME(%s) precision not implemented; zero used instead", $3); - $$ = make1_str("current_time"); - } - | CURRENT_TIMESTAMP - { - $$ = make1_str("current_timestamp"); - } - | CURRENT_TIMESTAMP '(' Iconst ')' - { - if (atol($3) != 0) - fprintf(stderr,"CURRENT_TIMESTAMP(%s) precision not implemented; zero used instead",$3); - $$ = make1_str("current_timestamp"); - } - | CURRENT_USER - { - $$ = make1_str("current_user"); - } - | USER - { - $$ = make1_str("user"); - } - | EXISTS '(' SubSelect ')' - { - $$ = make3_str(make1_str("exists("), $3, make1_str(")")); - } - | EXTRACT '(' extract_list ')' - { - $$ = make3_str(make1_str("extract("), $3, make1_str(")")); - } - | POSITION '(' position_list ')' - { - $$ = make3_str(make1_str("position("), $3, make1_str(")")); - } - | SUBSTRING '(' substr_list ')' - { - $$ = make3_str(make1_str("substring("), $3, make1_str(")")); - } - /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */ - | TRIM '(' BOTH trim_list ')' - { - $$ = make3_str(make1_str("trim(both"), $4, make1_str(")")); - } - | TRIM '(' LEADING trim_list ')' - { - $$ = make3_str(make1_str("trim(leading"), $4, make1_str(")")); - } - | TRIM '(' TRAILING trim_list ')' - { - $$ = make3_str(make1_str("trim(trailing"), $4, make1_str(")")); - } - | TRIM '(' trim_list ')' - { - $$ = make3_str(make1_str("trim("), $3, make1_str(")")); - } + | a_expr AND a_expr + { $$ = cat_str(3, $1, make_str("and"), $3); } + | a_expr OR a_expr + { $$ = cat_str(3, $1, make_str("or"), $3); } + | NOT a_expr + { $$ = cat2_str(make_str("not"), $2); } + | a_expr LIKE a_expr + { $$ = cat_str(3, $1, make_str("like"), $3); } + | a_expr NOT LIKE a_expr + { $$ = cat_str(3, $1, make_str("not like"), $4); } | a_expr ISNULL - { $$ = cat2_str($1, make1_str("isnull")); } + { $$ = cat2_str($1, make_str("isnull")); } | a_expr IS NULL_P - { $$ = cat2_str($1, make1_str("is null")); } + { $$ = cat2_str($1, make_str("is null")); } | a_expr NOTNULL - { $$ = cat2_str($1, make1_str("notnull")); } + { $$ = cat2_str($1, make_str("notnull")); } | a_expr IS NOT NULL_P - { $$ = cat2_str($1, make1_str("is not null")); } + { $$ = cat2_str($1, make_str("is not null")); } /* IS TRUE, IS FALSE, etc used to be function calls * but let's make them expressions to allow the optimizer * a chance to eliminate them if a_expr is a constant string. * - thomas 1997-12-22 */ | a_expr IS TRUE_P - { - { $$ = cat2_str($1, make1_str("is true")); } - } + { $$ = cat2_str($1, make_str("is true")); } | a_expr IS NOT FALSE_P - { - { $$ = cat2_str($1, make1_str("is not false")); } - } + { $$ = cat2_str($1, make_str("is not false")); } | a_expr IS FALSE_P - { - { $$ = cat2_str($1, make1_str("is false")); } - } + { $$ = cat2_str($1, make_str("is false")); } | a_expr IS NOT TRUE_P - { - { $$ = cat2_str($1, make1_str("is not true")); } - } + { $$ = cat2_str($1, make_str("is not true")); } | a_expr BETWEEN b_expr AND b_expr { - $$ = cat5_str($1, make1_str("between"), $3, make1_str("and"), $5); + $$ = cat_str(5, $1, make_str("between"), $3, make_str("and"), $5); } | a_expr NOT BETWEEN b_expr AND b_expr { - $$ = cat5_str($1, make1_str("not between"), $4, make1_str("and"), $6); + $$ = cat_str(5, $1, make_str("not between"), $4, make_str("and"), $6); } | a_expr IN '(' in_expr ')' { - $$ = make4_str($1, make1_str(" in ("), $4, make1_str(")")); - } - | a_expr NOT IN '(' not_in_expr ')' - { - $$ = make4_str($1, make1_str(" not in ("), $5, make1_str(")")); - } - | a_expr Op '(' SubSelect ')' - { - $$ = cat3_str($1, $2, make3_str(make1_str("("), $4, make1_str(")"))); - } - | a_expr '+' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("+("), $4, make1_str(")")); - } - | a_expr '-' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("-("), $4, make1_str(")")); - } - | a_expr '/' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("/("), $4, make1_str(")")); - } - | a_expr '%' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("%("), $4, make1_str(")")); - } - | a_expr '*' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("*("), $4, make1_str(")")); - } - | a_expr '<' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("<("), $4, make1_str(")")); - } - | a_expr '>' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str(">("), $4, make1_str(")")); - } - | a_expr '=' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("=("), $4, make1_str(")")); - } - | a_expr Op ANY '(' SubSelect ')' - { - $$ = cat3_str($1, $2, make3_str(make1_str("any("), $5, make1_str(")"))); - } - | a_expr '+' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("+ any("), $5, make1_str(")")); - } - | a_expr '-' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("- any("), $5, make1_str(")")); - } - | a_expr '/' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("/ any("), $5, make1_str(")")); - } - | a_expr '%' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("% any("), $5, make1_str(")")); - } - | a_expr '*' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("* any("), $5, make1_str(")")); - } - | a_expr '<' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("< any("), $5, make1_str(")")); - } - | a_expr '>' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("> any("), $5, make1_str(")")); - } - | a_expr '=' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("= any("), $5, make1_str(")")); - } - | a_expr Op ALL '(' SubSelect ')' - { - $$ = cat3_str($1, $2, make3_str(make1_str("all ("), $5, make1_str(")"))); - } - | a_expr '+' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("+ all("), $5, make1_str(")")); - } - | a_expr '-' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("- all("), $5, make1_str(")")); - } - | a_expr '/' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("/ all("), $5, make1_str(")")); - } - | a_expr '%' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("% all("), $5, make1_str(")")); - } - | a_expr '*' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("* all("), $5, make1_str(")")); - } - | a_expr '<' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("< all("), $5, make1_str(")")); + $$ = cat_str(4, $1, make_str(" in ("), $4, make_str(")")); } - | a_expr '>' ALL '(' SubSelect ')' + | a_expr NOT IN '(' in_expr ')' { - $$ = make4_str($1, make1_str("> all("), $5, make1_str(")")); + $$ = cat_str(4, $1, make_str(" not in ("), $5, make_str(")")); } - | a_expr '=' ALL '(' SubSelect ')' + | a_expr all_Op sub_type '(' SubSelect ')' { - $$ = make4_str($1, make1_str("= all("), $5, make1_str(")")); + $$ = cat_str(6, $1, $2, $3, make_str("("), $5, make_str(")")); } - | a_expr AND a_expr - { $$ = cat3_str($1, make1_str("and"), $3); } - | a_expr OR a_expr - { $$ = cat3_str($1, make1_str("or"), $3); } - | NOT a_expr - { $$ = cat2_str(make1_str("not"), $2); } - | case_expr + | row_expr { $$ = $1; } | cinputvariable - { $$ = make1_str("?"); } + { $$ = make_str("?"); } ; /* Restricted expressions + * * b_expr is a subset of the complete expression syntax - * defined by a_expr. b_expr is used in BETWEEN clauses - * to eliminate parser ambiguities stemming from the AND keyword. + * + * Presently, AND, NOT, IS, IN, and NULL are the a_expr keywords that would + * cause trouble in the places where b_expr is used. For simplicity, we + * just eliminate all the boolean-keyword-operator productions from b_expr. */ -b_expr: attr +b_expr: c_expr { - $$ = $1 + $$ = $1; } - | AexprConst - { $$ = $1; } - | ColId opt_indirection + | b_expr TYPECAST Typename { - $$ = cat2_str($1, $2); + $$ = cat_str(3, $1, make_str("::"), $3); } + | NULL_P TYPECAST Typename + { + $$ = cat2_str(make_str("null::"), $3); + } | '-' b_expr %prec UMINUS - { $$ = cat2_str(make1_str("-"), $2); } + { $$ = cat2_str(make_str("-"), $2); } | '%' b_expr - { $$ = cat2_str(make1_str("%"), $2); } + { $$ = cat2_str(make_str("%"), $2); } | '^' b_expr - { $$ = cat2_str(make1_str("^"), $2); } + { $$ = cat2_str(make_str("^"), $2); } + | '|' b_expr + { $$ = cat2_str(make_str("|"), $2); } +/* not possible in embedded sql | ':' b_expr + { $$ = cat2_str(make_str(":"), $2); } +*/ + | ';' b_expr + { $$ = cat2_str(make_str(";"), $2); } | b_expr '%' - { $$ = cat2_str($1, make1_str("%")); } + { $$ = cat2_str($1, make_str("%")); } | b_expr '^' - { $$ = cat2_str($1, make1_str("^")); } + { $$ = cat2_str($1, make_str("^")); } + | b_expr '|' + { $$ = cat2_str($1, make_str("|")); } | b_expr '+' b_expr - { $$ = cat3_str($1, make1_str("+"), $3); } + { $$ = cat_str(3, $1, make_str("+"), $3); } | b_expr '-' b_expr - { $$ = cat3_str($1, make1_str("-"), $3); } + { $$ = cat_str(3, $1, make_str("-"), $3); } + | b_expr '*' b_expr + { $$ = cat_str(3, $1, make_str("*"), $3); } | b_expr '/' b_expr - { $$ = cat3_str($1, make1_str("/"), $3); } + { $$ = cat_str(3, $1, make_str("/"), $3); } | b_expr '%' b_expr - { $$ = cat3_str($1, make1_str("%"), $3); } - | b_expr '*' b_expr - { $$ = cat3_str($1, make1_str("*"), $3); } + { $$ = cat_str(3, $1, make_str("%"), $3); } | b_expr '^' b_expr - { $$ = cat3_str($1, make1_str("^"), $3); } -/* not possible in embedded sql | ':' b_expr - { $$ = cat2_str(make1_str(":"), $2); } -*/ - | ';' b_expr - { $$ = cat2_str(make1_str(";"), $2); } - | '|' b_expr - { $$ = cat2_str(make1_str("|"), $2); } - | b_expr TYPECAST Typename - { - $$ = cat3_str($1, make1_str("::"), $3); - } - | CAST '(' b_expr AS Typename ')' - { - $$ = cat3_str(make2_str(make1_str("cast("), $3), make1_str("as"), make2_str($5, make1_str(")"))); - } - | '(' a_expr ')' - { $$ = make3_str(make1_str("("), $2, make1_str(")")); } + { $$ = cat_str(3, $1, make_str("^"), $3); } + | b_expr '|' b_expr + { $$ = cat_str(3, $1, make_str("|"), $3); } + | b_expr '<' b_expr + { $$ = cat_str(3, $1, make_str("<"), $3); } + | b_expr '>' b_expr + { $$ = cat_str(3, $1, make_str(">"), $3); } + | b_expr '=' b_expr + { $$ = cat_str(3, $1, make_str("="), $3); } | b_expr Op b_expr - { $$ = cat3_str($1, $2, $3); } + { $$ = cat_str(3, $1, $2, $3); } | Op b_expr { $$ = cat2_str($1, $2); } | b_expr Op { $$ = cat2_str($1, $2); } + | civariableonly + { $$ = $1; } + ; + +/* + * Productions that can be used in both a_expr and b_expr. + * + * Note: productions that refer recursively to a_expr or b_expr mostly + * cannot appear here. However, it's OK to refer to a_exprs that occur + * inside parentheses, such as function arguments; that cannot introduce + * ambiguity to the b_expr syntax. + */ +c_expr: attr + { $$ = $1; } + | ColId opt_indirection + { $$ = cat2_str($1, $2); } + | AexprConst + { $$ = $1; } + | '(' a_expr_or_null ')' + { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | CAST '(' a_expr_or_null AS Typename ')' + { $$ = cat_str(5, make_str("cast("), $3, make_str("as"), $5, make_str(")")); } + | case_expr + { $$ = $1; } | func_name '(' ')' - { - $$ = cat2_str($1, make1_str("()")); - } + { $$ = cat2_str($1, make_str("()")); } | func_name '(' expr_list ')' - { - $$ = make4_str($1, make1_str("("), $3, make1_str(")")); - } + { $$ = cat_str(4, $1, make_str("("), $3, make_str(")")); } + | func_name '(' DISTINCT expr_list ')' + { $$ = cat_str(4, $1, make_str("( distinct"), $4, make_str(")")); } + | func_name '(' '*' ')' + { $$ = cat2_str($1, make_str("(*)")); } | CURRENT_DATE - { - $$ = make1_str("current_date"); - } + { $$ = make_str("current_date"); } | CURRENT_TIME - { - $$ = make1_str("current_time"); - } + { $$ = make_str("current_time"); } | CURRENT_TIME '(' Iconst ')' { - if ($3 != 0) - fprintf(stderr,"CURRENT_TIME(%s) precision not implemented; zero used instead", $3); - $$ = make1_str("current_time"); + if (atol($3) != 0) + { + sprintf(errortext, "CURRENT_TIME(%s) precision not implemented; backend will use zero instead", $3); + mmerror(ET_WARN, errortext); + } + + $$ = make_str("current_time"); } | CURRENT_TIMESTAMP - { - $$ = make1_str("current_timestamp"); - } + { $$ = make_str("current_timestamp"); } | CURRENT_TIMESTAMP '(' Iconst ')' { if (atol($3) != 0) - fprintf(stderr,"CURRENT_TIMESTAMP(%s) precision not implemented; zero used instead",$3); - $$ = make1_str("current_timestamp"); + { + sprintf(errortext, "CURRENT_TIMESTAMP(%s) precision not implemented; backend will use zero instead", $3); + mmerror(ET_WARN, errortext); + } + + $$ = make_str("current_timestamp"); } | CURRENT_USER - { - $$ = make1_str("current_user"); - } + { $$ = make_str("current_user"); } + | SESSION_USER + { $$ = make_str("session_user"); } | USER - { - $$ = make1_str("user"); - } + { $$ = make_str("user"); } + | EXTRACT '(' extract_list ')' + { $$ = cat_str(3, make_str("extract("), $3, make_str(")")); } | POSITION '(' position_list ')' - { - $$ = make3_str(make1_str("position ("), $3, make1_str(")")); - } + { $$ = cat_str(3, make_str("position("), $3, make_str(")")); } | SUBSTRING '(' substr_list ')' - { - $$ = make3_str(make1_str("substring ("), $3, make1_str(")")); - } + { $$ = cat_str(3, make_str("substring("), $3, make_str(")")); } /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */ | TRIM '(' BOTH trim_list ')' - { - $$ = make3_str(make1_str("trim(both"), $4, make1_str(")")); - } + { $$ = cat_str(3, make_str("trim(both"), $4, make_str(")")); } | TRIM '(' LEADING trim_list ')' - { - $$ = make3_str(make1_str("trim(leading"), $4, make1_str(")")); - } + { $$ = cat_str(3, make_str("trim(leading"), $4, make_str(")")); } | TRIM '(' TRAILING trim_list ')' - { - $$ = make3_str(make1_str("trim(trailing"), $4, make1_str(")")); - } + { $$ = cat_str(3, make_str("trim(trailing"), $4, make_str(")")); } | TRIM '(' trim_list ')' - { - $$ = make3_str(make1_str("trim("), $3, make1_str(")")); - } - | civariableonly - { $$ = $1; } + { $$ = cat_str(3, make_str("trim("), $3, make_str(")")); } + | '(' SubSelect ')' + { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | EXISTS '(' SubSelect ')' + { $$ = cat_str(3, make_str("exists("), $3, make_str(")")); } ; - -opt_indirection: '[' ecpg_expr ']' opt_indirection +/* + * This used to use ecpg_expr, but since there is no shift/reduce conflict + * anymore, we can remove ecpg_expr. - MM + */ +opt_indirection: '[' a_expr ']' opt_indirection { - $$ = cat4_str(make1_str("["), $2, make1_str("]"), $4); + $$ = cat_str(4, make_str("["), $2, make_str("]"), $4); } - | '[' ecpg_expr ':' ecpg_expr ']' opt_indirection + | '[' a_expr ':' a_expr ']' opt_indirection { - $$ = cat2_str(cat5_str(make1_str("["), $2, make1_str(":"), $4, make1_str("]")), $6); + $$ = cat_str(6, make_str("["), $2, make_str(":"), $4, make_str("]"), $6); } | /* EMPTY */ - { $$ = make1_str(""); } + { $$ = EMPTY; } ; expr_list: a_expr_or_null { $$ = $1; } | expr_list ',' a_expr_or_null - { $$ = cat3_str($1, make1_str(","), $3); } + { $$ = cat_str(3, $1, make_str(","), $3); } | expr_list USING a_expr - { $$ = cat3_str($1, make1_str("using"), $3); } + { $$ = cat_str(3, $1, make_str("using"), $3); } ; extract_list: extract_arg FROM a_expr { - $$ = cat3_str($1, make1_str("from"), $3); + $$ = cat_str(3, $1, make_str("from"), $3); } | /* EMPTY */ - { $$ = make1_str(""); } + { $$ = EMPTY; } | cinputvariable - { $$ = make1_str("?"); } + { $$ = make_str("?"); } ; extract_arg: datetime { $$ = $1; } - | TIMEZONE_HOUR { $$ = make1_str("timezone_hour"); } - | TIMEZONE_MINUTE { $$ = make1_str("timezone_minute"); } + | TIMEZONE_HOUR { $$ = make_str("timezone_hour"); } + | TIMEZONE_MINUTE { $$ = make_str("timezone_minute"); } ; /* position_list uses b_expr not a_expr to avoid conflict with general IN */ position_list: b_expr IN b_expr - { $$ = cat3_str($1, make1_str("in"), $3); } + { $$ = cat_str(3, $1, make_str("in"), $3); } | /* EMPTY */ - { $$ = make1_str(""); } + { $$ = EMPTY; } ; substr_list: expr_list substr_from substr_for { - $$ = cat3_str($1, $2, $3); + $$ = cat_str(3, $1, $2, $3); } | /* EMPTY */ - { $$ = make1_str(""); } + { $$ = EMPTY; } ; substr_from: FROM expr_list - { $$ = cat2_str(make1_str("from"), $2); } + { $$ = cat2_str(make_str("from"), $2); } | /* EMPTY */ { - $$ = make1_str(""); + $$ = EMPTY; } ; substr_for: FOR expr_list - { $$ = cat2_str(make1_str("for"), $2); } + { $$ = cat2_str(make_str("for"), $2); } | /* EMPTY */ - { $$ = make1_str(""); } + { $$ = EMPTY; } ; trim_list: a_expr FROM expr_list - { $$ = cat3_str($1, make1_str("from"), $3); } + { $$ = cat_str(3, $1, make_str("from"), $3); } | FROM expr_list - { $$ = cat2_str(make1_str("from"), $2); } + { $$ = cat2_str(make_str("from"), $2); } | expr_list { $$ = $1; } ; @@ -4020,24 +4377,10 @@ in_expr: SubSelect { $$ = $1; } ; -in_expr_nodes: AexprConst - { $$ = $1; } - | in_expr_nodes ',' AexprConst - { $$ = cat3_str($1, make1_str(","), $3);} - ; - -not_in_expr: SubSelect - { - $$ = $1; - } - | not_in_expr_nodes - { $$ = $1; } - ; - -not_in_expr_nodes: AexprConst +in_expr_nodes: a_expr { $$ = $1; } - | not_in_expr_nodes ',' AexprConst - { $$ = cat3_str($1, make1_str(","), $3);} + | in_expr_nodes ',' a_expr + { $$ = cat_str(3, $1, make_str(","), $3);} ; /* Case clause @@ -4056,16 +4399,16 @@ not_in_expr_nodes: AexprConst * - thomas 1998-11-09 */ case_expr: CASE case_arg when_clause_list case_default END_TRANS - { $$ = cat5_str(make1_str("case"), $2, $3, $4, make1_str("end")); } + { $$ = cat_str(5, make_str("case"), $2, $3, $4, make_str("end")); } | NULLIF '(' a_expr ',' a_expr ')' { - $$ = cat5_str(make1_str("nullif("), $3, make1_str(","), $5, make1_str(")")); + $$ = cat_str(5, make_str("nullif("), $3, make_str(","), $5, make_str(")")); - fprintf(stderr, "NULLIF() not yet fully implemented"); + mmerror(ET_WARN, "NULLIF() not yet fully implemented"); } | COALESCE '(' expr_list ')' { - $$ = cat3_str(make1_str("coalesce("), $3, make1_str(")")); + $$ = cat_str(3, make_str("coalesce("), $3, make_str(")")); } ; @@ -4077,37 +4420,37 @@ when_clause_list: when_clause_list when_clause when_clause: WHEN a_expr THEN a_expr_or_null { - $$ = cat4_str(make1_str("when"), $2, make1_str("then"), $4); + $$ = cat_str(4, make_str("when"), $2, make_str("then"), $4); } ; -case_default: ELSE a_expr_or_null { $$ = cat2_str(make1_str("else"), $2); } - | /*EMPTY*/ { $$ = make1_str(""); } +case_default: ELSE a_expr_or_null { $$ = cat2_str(make_str("else"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } ; case_arg: a_expr { $$ = $1; } | /*EMPTY*/ - { $$ = make1_str(""); } + { $$ = EMPTY; } ; attr: relation_name '.' attrs opt_indirection { - $$ = make4_str($1, make1_str("."), $3, $4); + $$ = cat_str(4, $1, make_str("."), $3, $4); } | ParamNo '.' attrs opt_indirection { - $$ = make4_str($1, make1_str("."), $3, $4); + $$ = cat_str(4, $1, make_str("."), $3, $4); } ; attrs: attr_name { $$ = $1; } | attrs '.' attr_name - { $$ = make3_str($1, make1_str("."), $3); } + { $$ = cat_str(3, $1, make_str("."), $3); } | attrs '.' '*' - { $$ = make2_str($1, make1_str(".*")); } + { $$ = make2_str($1, make_str(".*")); } ; @@ -4119,7 +4462,7 @@ attrs: attr_name /* Target lists as found in SELECT ... and INSERT VALUES ( ... ) */ target_list: target_list ',' target_el - { $$ = cat3_str($1, make1_str(","), $3); } + { $$ = cat_str(3, $1, make_str(","), $3); } | target_el { $$ = $1; } ; @@ -4127,7 +4470,7 @@ target_list: target_list ',' target_el /* AS is not optional because shift/red conflict with unary ops */ target_el: a_expr_or_null AS ColLabel { - $$ = cat3_str($1, make1_str("as"), $3); + $$ = cat_str(3, $1, make_str("as"), $3); } | a_expr_or_null { @@ -4135,25 +4478,25 @@ target_el: a_expr_or_null AS ColLabel } | relation_name '.' '*' { - $$ = make2_str($1, make1_str(".*")); + $$ = make2_str($1, make_str(".*")); } | '*' { - $$ = make1_str("*"); + $$ = make_str("*"); } ; /* Target list as found in UPDATE table SET ... */ update_target_list: update_target_list ',' update_target_el - { $$ = cat3_str($1, make1_str(","),$3); } + { $$ = cat_str(3, $1, make_str(","),$3); } | update_target_el { $$ = $1; } - | '*' { $$ = make1_str("*"); } + | '*' { $$ = make_str("*"); } ; update_target_el: ColId opt_indirection '=' a_expr_or_null { - $$ = cat4_str($1, $2, make1_str("="), $4); + $$ = cat_str(4, $1, $2, make_str("="), $4); } ; @@ -4172,8 +4515,8 @@ relation_name: SpecialRuleRelation /* disallow refs to variable system tables */ if (strcmp(LogRelationName, $1) == 0 || strcmp(VariableRelationName, $1) == 0) { - sprintf(errortext, make1_str("%s cannot be accessed by users"),$1); - yyerror(errortext); + sprintf(errortext, make_str("%s cannot be accessed by users"),$1); + mmerror(ET_ERROR, errortext); } else $$ = $1; @@ -4222,11 +4565,11 @@ AexprConst: Iconst { $$ = $1; } | TRUE_P { - $$ = make1_str("true"); + $$ = make_str("true"); } | FALSE_P { - $$ = make1_str("false"); + $$ = make_str("false"); } ; @@ -4270,112 +4613,122 @@ TypeId: ColId */ ColId: ident { $$ = $1; } | datetime { $$ = $1; } - | ABSOLUTE { $$ = make1_str("absolute"); } - | ACCESS { $$ = make1_str("access"); } - | ACTION { $$ = make1_str("action"); } - | AFTER { $$ = make1_str("after"); } - | AGGREGATE { $$ = make1_str("aggregate"); } - | BACKWARD { $$ = make1_str("backward"); } - | BEFORE { $$ = make1_str("before"); } - | CACHE { $$ = make1_str("cache"); } - | COMMITTED { $$ = make1_str("committed"); } - | CREATEDB { $$ = make1_str("createdb"); } - | CREATEUSER { $$ = make1_str("createuser"); } - | CYCLE { $$ = make1_str("cycle"); } - | DATABASE { $$ = make1_str("database"); } - | DELIMITERS { $$ = make1_str("delimiters"); } - | DOUBLE { $$ = make1_str("double"); } - | EACH { $$ = make1_str("each"); } - | ENCODING { $$ = make1_str("encoding"); } - | EXCLUSIVE { $$ = make1_str("exclusive"); } - | FORWARD { $$ = make1_str("forward"); } - | FUNCTION { $$ = make1_str("function"); } - | HANDLER { $$ = make1_str("handler"); } - | INCREMENT { $$ = make1_str("increment"); } - | INDEX { $$ = make1_str("index"); } - | INHERITS { $$ = make1_str("inherits"); } - | INSENSITIVE { $$ = make1_str("insensitive"); } - | INSTEAD { $$ = make1_str("instead"); } - | ISNULL { $$ = make1_str("isnull"); } - | KEY { $$ = make1_str("key"); } - | LANGUAGE { $$ = make1_str("language"); } - | LANCOMPILER { $$ = make1_str("lancompiler"); } - | LOCATION { $$ = make1_str("location"); } - | MATCH { $$ = make1_str("match"); } - | MAXVALUE { $$ = make1_str("maxvalue"); } - | MINVALUE { $$ = make1_str("minvalue"); } - | MODE { $$ = make1_str("mode"); } - | NEXT { $$ = make1_str("next"); } - | NOCREATEDB { $$ = make1_str("nocreatedb"); } - | NOCREATEUSER { $$ = make1_str("nocreateuser"); } - | NOTHING { $$ = make1_str("nothing"); } - | NOTNULL { $$ = make1_str("notnull"); } - | OF { $$ = make1_str("of"); } - | OIDS { $$ = make1_str("oids"); } - | ONLY { $$ = make1_str("only"); } - | OPERATOR { $$ = make1_str("operator"); } - | OPTION { $$ = make1_str("option"); } - | PASSWORD { $$ = make1_str("password"); } - | PRIOR { $$ = make1_str("prior"); } - | PRIVILEGES { $$ = make1_str("privileges"); } - | PROCEDURAL { $$ = make1_str("procedural"); } - | READ { $$ = make1_str("read"); } -/* NOT USED | RECIPE { $$ = make1_str("recipe"); } */ - | RELATIVE { $$ = make1_str("relative"); } - | RENAME { $$ = make1_str("rename"); } - | RETURNS { $$ = make1_str("returns"); } - | ROW { $$ = make1_str("row"); } - | RULE { $$ = make1_str("rule"); } - | SCROLL { $$ = make1_str("scroll"); } - | SEQUENCE { $$ = make1_str("sequence"); } - | SERIAL { $$ = make1_str("serial"); } - | SERIALIZABLE { $$ = make1_str("serializable"); } - | SHARE { $$ = make1_str("share"); } - | START { $$ = make1_str("start"); } - | STATEMENT { $$ = make1_str("statement"); } - | STDIN { $$ = make1_str("stdin"); } - | STDOUT { $$ = make1_str("stdout"); } - | TIME { $$ = make1_str("time"); } - | TIMESTAMP { $$ = make1_str("timestamp"); } - | TIMEZONE_HOUR { $$ = make1_str("timezone_hour"); } - | TIMEZONE_MINUTE { $$ = make1_str("timezone_minute"); } - | TRIGGER { $$ = make1_str("trigger"); } - | TRUSTED { $$ = make1_str("trusted"); } - | TYPE_P { $$ = make1_str("type"); } - | VALID { $$ = make1_str("valid"); } - | VERSION { $$ = make1_str("version"); } - | ZONE { $$ = make1_str("zone"); } - | SQL_AT { $$ = make1_str("at"); } - | SQL_BOOL { $$ = make1_str("bool"); } - | SQL_BREAK { $$ = make1_str("break"); } - | SQL_CALL { $$ = make1_str("call"); } - | SQL_CONNECT { $$ = make1_str("connect"); } - | SQL_CONTINUE { $$ = make1_str("continue"); } - | SQL_DEALLOCATE { $$ = make1_str("deallocate"); } - | SQL_DISCONNECT { $$ = make1_str("disconnect"); } - | SQL_FOUND { $$ = make1_str("found"); } - | SQL_GO { $$ = make1_str("go"); } - | SQL_GOTO { $$ = make1_str("goto"); } - | SQL_IDENTIFIED { $$ = make1_str("identified"); } - | SQL_IMMEDIATE { $$ = make1_str("immediate"); } - | SQL_INDICATOR { $$ = make1_str("indicator"); } - | SQL_INT { $$ = make1_str("int"); } - | SQL_LONG { $$ = make1_str("long"); } - | SQL_OFF { $$ = make1_str("off"); } - | SQL_OPEN { $$ = make1_str("open"); } - | SQL_PREPARE { $$ = make1_str("prepare"); } - | SQL_RELEASE { $$ = make1_str("release"); } - | SQL_SECTION { $$ = make1_str("section"); } - | SQL_SHORT { $$ = make1_str("short"); } - | SQL_SIGNED { $$ = make1_str("signed"); } - | SQL_SQLERROR { $$ = make1_str("sqlerror"); } - | SQL_SQLPRINT { $$ = make1_str("sqlprint"); } - | SQL_SQLWARNING { $$ = make1_str("sqlwarning"); } - | SQL_STOP { $$ = make1_str("stop"); } - | SQL_STRUCT { $$ = make1_str("struct"); } - | SQL_UNSIGNED { $$ = make1_str("unsigned"); } - | SQL_VAR { $$ = make1_str("var"); } - | SQL_WHENEVER { $$ = make1_str("whenever"); } + | ABSOLUTE { $$ = make_str("absolute"); } + | ACCESS { $$ = make_str("access"); } + | ACTION { $$ = make_str("action"); } + | AFTER { $$ = make_str("after"); } + | AGGREGATE { $$ = make_str("aggregate"); } + | BACKWARD { $$ = make_str("backward"); } + | BEFORE { $$ = make_str("before"); } + | CACHE { $$ = make_str("cache"); } + | COMMENT { $$ = make_str("comment"); } + | COMMITTED { $$ = make_str("committed"); } + | CONSTRAINTS { $$ = make_str("constraints"); } + | CREATEDB { $$ = make_str("createdb"); } + | CREATEUSER { $$ = make_str("createuser"); } + | CYCLE { $$ = make_str("cycle"); } + | DATABASE { $$ = make_str("database"); } + | DEFERRABLE { $$ = make_str("deferrable"); } + | DEFERRED { $$ = make_str("deferred"); } + | DELIMITERS { $$ = make_str("delimiters"); } + | DOUBLE { $$ = make_str("double"); } + | EACH { $$ = make_str("each"); } + | ENCODING { $$ = make_str("encoding"); } + | EXCLUSIVE { $$ = make_str("exclusive"); } + | FORWARD { $$ = make_str("forward"); } + | FUNCTION { $$ = make_str("function"); } + | HANDLER { $$ = make_str("handler"); } + | IMMEDIATE { $$ = make_str("immediate"); } + | INCREMENT { $$ = make_str("increment"); } + | INDEX { $$ = make_str("index"); } + | INHERITS { $$ = make_str("inherits"); } + | INITIALLY { $$ = make_str("initially"); } + | INSENSITIVE { $$ = make_str("insensitive"); } + | INSTEAD { $$ = make_str("instead"); } + | ISNULL { $$ = make_str("isnull"); } + | ISOLATION { $$ = make_str("isolation"); } + | KEY { $$ = make_str("key"); } + | LANGUAGE { $$ = make_str("language"); } + | LANCOMPILER { $$ = make_str("lancompiler"); } + | LEVEL { $$ = make_str("level"); } + | LOCATION { $$ = make_str("location"); } + | MATCH { $$ = make_str("match"); } + | MAXVALUE { $$ = make_str("maxvalue"); } + | MINVALUE { $$ = make_str("minvalue"); } + | MODE { $$ = make_str("mode"); } + | NEXT { $$ = make_str("next"); } + | NOCREATEDB { $$ = make_str("nocreatedb"); } + | NOCREATEUSER { $$ = make_str("nocreateuser"); } + | NOTHING { $$ = make_str("nothing"); } + | NOTNULL { $$ = make_str("notnull"); } + | OF { $$ = make_str("of"); } + | OIDS { $$ = make_str("oids"); } + | ONLY { $$ = make_str("only"); } + | OPERATOR { $$ = make_str("operator"); } + | OPTION { $$ = make_str("option"); } + | PASSWORD { $$ = make_str("password"); } + | PENDANT { $$ = make_str("pendant"); } + | PRIOR { $$ = make_str("prior"); } + | PRIVILEGES { $$ = make_str("privileges"); } + | PROCEDURAL { $$ = make_str("procedural"); } + | READ { $$ = make_str("read"); } + | RELATIVE { $$ = make_str("relative"); } + | RENAME { $$ = make_str("rename"); } + | RESTRICT { $$ = make_str("restrict"); } + | RETURNS { $$ = make_str("returns"); } + | ROW { $$ = make_str("row"); } + | RULE { $$ = make_str("rule"); } + | SCROLL { $$ = make_str("scroll"); } + | SEQUENCE { $$ = make_str("sequence"); } + | SERIAL { $$ = make_str("serial"); } + | SERIALIZABLE { $$ = make_str("serializable"); } + | SHARE { $$ = make_str("share"); } + | START { $$ = make_str("start"); } + | STATEMENT { $$ = make_str("statement"); } + | STDIN { $$ = make_str("stdin"); } + | STDOUT { $$ = make_str("stdout"); } + | SYSID { $$ = make_str("sysid"); } + | TIME { $$ = make_str("time"); } + | TIMESTAMP { $$ = make_str("timestamp"); } + | TIMEZONE_HOUR { $$ = make_str("timezone_hour"); } + | TIMEZONE_MINUTE { $$ = make_str("timezone_minute"); } + | TRIGGER { $$ = make_str("trigger"); } + | TRUNCATE { $$ = make_str("truncate"); } + | TRUSTED { $$ = make_str("trusted"); } + | TYPE_P { $$ = make_str("type"); } + | VALID { $$ = make_str("valid"); } + | VERSION { $$ = make_str("version"); } + | ZONE { $$ = make_str("zone"); } + | SQL_AT { $$ = make_str("at"); } + | SQL_BOOL { $$ = make_str("bool"); } + | SQL_BREAK { $$ = make_str("break"); } + | SQL_CALL { $$ = make_str("call"); } + | SQL_CONNECT { $$ = make_str("connect"); } + | SQL_CONTINUE { $$ = make_str("continue"); } + | SQL_DEALLOCATE { $$ = make_str("deallocate"); } + | SQL_DISCONNECT { $$ = make_str("disconnect"); } + | SQL_FOUND { $$ = make_str("found"); } + | SQL_GO { $$ = make_str("go"); } + | SQL_GOTO { $$ = make_str("goto"); } + | SQL_IDENTIFIED { $$ = make_str("identified"); } + | SQL_INDICATOR { $$ = make_str("indicator"); } + | SQL_INT { $$ = make_str("int"); } + | SQL_LONG { $$ = make_str("long"); } + | SQL_OFF { $$ = make_str("off"); } + | SQL_OPEN { $$ = make_str("open"); } + | SQL_PREPARE { $$ = make_str("prepare"); } + | SQL_RELEASE { $$ = make_str("release"); } + | SQL_SECTION { $$ = make_str("section"); } + | SQL_SHORT { $$ = make_str("short"); } + | SQL_SIGNED { $$ = make_str("signed"); } + | SQL_SQLERROR { $$ = make_str("sqlerror"); } + | SQL_SQLPRINT { $$ = make_str("sqlprint"); } + | SQL_SQLWARNING { $$ = make_str("sqlwarning"); } + | SQL_STOP { $$ = make_str("stop"); } + | SQL_STRUCT { $$ = make_str("struct"); } + | SQL_UNSIGNED { $$ = make_str("unsigned"); } + | SQL_VAR { $$ = make_str("var"); } + | SQL_WHENEVER { $$ = make_str("whenever"); } ; /* Column label * Allowed labels in "AS" clauses. @@ -4387,59 +4740,67 @@ ColId: ident { $$ = $1; } * rather than in ColId if there was a shift/reduce conflict * when used as a full identifier. - thomas 1997-11-06 */ -ColLabel: ColId { $$ = $1; } - | ABORT_TRANS { $$ = make1_str("abort"); } - | ANALYZE { $$ = make1_str("analyze"); } - | BINARY { $$ = make1_str("binary"); } - | CASE { $$ = make1_str("case"); } - | CLUSTER { $$ = make1_str("cluster"); } - | COALESCE { $$ = make1_str("coalesce"); } - | CONSTRAINT { $$ = make1_str("constraint"); } - | COPY { $$ = make1_str("copy"); } - | CURRENT { $$ = make1_str("current"); } - | DO { $$ = make1_str("do"); } - | ELSE { $$ = make1_str("else"); } - | END_TRANS { $$ = make1_str("end"); } - | EXPLAIN { $$ = make1_str("explain"); } - | EXTEND { $$ = make1_str("extend"); } - | FALSE_P { $$ = make1_str("false"); } - | FOREIGN { $$ = make1_str("foreign"); } - | GROUP { $$ = make1_str("group"); } - | LISTEN { $$ = make1_str("listen"); } - | LOAD { $$ = make1_str("load"); } - | LOCK_P { $$ = make1_str("lock"); } - | MOVE { $$ = make1_str("move"); } - | NEW { $$ = make1_str("new"); } - | NONE { $$ = make1_str("none"); } - | NULLIF { $$ = make1_str("nullif"); } - | ORDER { $$ = make1_str("order"); } - | POSITION { $$ = make1_str("position"); } - | PRECISION { $$ = make1_str("precision"); } - | RESET { $$ = make1_str("reset"); } - | SETOF { $$ = make1_str("setof"); } - | SHOW { $$ = make1_str("show"); } - | TABLE { $$ = make1_str("table"); } - | THEN { $$ = make1_str("then"); } - | TRANSACTION { $$ = make1_str("transaction"); } - | TRUE_P { $$ = make1_str("true"); } - | VACUUM { $$ = make1_str("vacuum"); } - | VERBOSE { $$ = make1_str("verbose"); } - | WHEN { $$ = make1_str("when"); } +ColLabel: ColId { $$ = $1; } + | ABORT_TRANS { $$ = make_str("abort"); } + | ANALYZE { $$ = make_str("analyze"); } + | BINARY { $$ = make_str("binary"); } + | CASE { $$ = make_str("case"); } + | CLUSTER { $$ = make_str("cluster"); } + | COALESCE { $$ = make_str("coalesce"); } + | CONSTRAINT { $$ = make_str("constraint"); } + | COPY { $$ = make_str("copy"); } + | CURRENT { $$ = make_str("current"); } + | CURRENT_USER { $$ = make_str("current_user"); } + | DEC { $$ = make_str("dec"); } + | DECIMAL { $$ = make_str("decimal"); } + | DO { $$ = make_str("do"); } + | ELSE { $$ = make_str("else"); } + | END_TRANS { $$ = make_str("end"); } + | EXPLAIN { $$ = make_str("explain"); } + | EXTEND { $$ = make_str("extend"); } + | FALSE_P { $$ = make_str("false"); } + | FLOAT { $$ = make_str("float"); } + | FOREIGN { $$ = make_str("foreign"); } + | GLOBAL { $$ = make_str("global"); } + | GROUP { $$ = make_str("group"); } + | LISTEN { $$ = make_str("listen"); } + | LOAD { $$ = make_str("load"); } + | LOCK_P { $$ = make_str("lock"); } + | MOVE { $$ = make_str("move"); } + | NEW { $$ = make_str("new"); } + | NONE { $$ = make_str("none"); } + | NULLIF { $$ = make_str("nullif"); } + | NUMERIC { $$ = make_str("numeric"); } + | ORDER { $$ = make_str("order"); } + | POSITION { $$ = make_str("position"); } + | PRECISION { $$ = make_str("precision"); } + | RESET { $$ = make_str("reset"); } + | SESSION_USER { $$ = make_str("session_user"); } + | SETOF { $$ = make_str("setof"); } + | SHOW { $$ = make_str("show"); } + | TABLE { $$ = make_str("table"); } + | THEN { $$ = make_str("then"); } + | TRANSACTION { $$ = make_str("transaction"); } + | TRUE_P { $$ = make_str("true"); } + | USER { $$ = make_str("user"); } + | VACUUM { $$ = make_str("vacuum"); } + | VERBOSE { $$ = make_str("verbose"); } + | WHEN { $$ = make_str("when"); } ; SpecialRuleRelation: CURRENT { if (QueryIsRule) - $$ = make1_str("current"); + $$ = make_str("current"); else - yyerror("CURRENT used in non-rule query"); + mmerror(ET_ERROR, "CURRENT used in non-rule query"); } | NEW { if (QueryIsRule) - $$ = make1_str("new"); + $$ = make_str("new"); else - yyerror("NEW used in non-rule query"); + mmerror(ET_ERROR, "NEW used in non-rule query"); } ; @@ -4452,16 +4813,16 @@ SpecialRuleRelation: CURRENT */ ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user { - $$ = make5_str($3, make1_str(","), $5, make1_str(","), $4); + $$ = cat_str(5, $3, make_str(","), $5, make_str(","), $4); } | SQL_CONNECT TO DEFAULT { - $$ = make1_str("NULL,NULL,NULL,\"DEFAULT\""); + $$ = make_str("NULL,NULL,NULL,\"DEFAULT\""); } /* also allow ORACLE syntax */ | SQL_CONNECT ora_user { - $$ = make3_str(make1_str("NULL,"), $2, make1_str(",NULL")); + $$ = cat_str(3, make_str("NULL,"), $2, make_str(",NULL")); } connection_target: database_name opt_server opt_port @@ -4470,33 +4831,33 @@ connection_target: database_name opt_server opt_port if (strlen($2) > 0 && *($2) != '@') { sprintf(errortext, "parse error at or near '%s'", $2); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - $$ = make5_str(make1_str("\""), $1, $2, $3, make1_str("\"")); + $$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\"")); } | db_prefix server opt_port '/' database_name opt_options { /* new style: :postgresql://server[:port][/dbname] */ - if (strncmp($2, "://", 3) != 0) + if (strncmp($2, "://", strlen("://")) != 0) { sprintf(errortext, "parse error at or near '%s'", $2); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - if (strncmp($1, "unix", 4) == 0 && strncmp($2 + 3, "localhost", 9) != 0) + if (strncmp($1, "unix", strlen("unix")) == 0 && strncmp($2 + strlen("://"), "localhost", strlen("localhost")) != 0) { sprintf(errortext, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $2); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - if (strncmp($1, "unix", 4) != 0 && strncmp($1, "tcp", 3) != 0) + if (strncmp($1, "unix", strlen("unix")) != 0 && strncmp($1, "tcp", strlen("tcp")) != 0) { sprintf(errortext, "only protocols 'tcp' and 'unix' are supported"); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - $$ = make4_str(make5_str(make1_str("\""), $1, $2, $3, make1_str("/")), $5, $6, make1_str("\"")); + $$ = make2_str(make3_str(make_str("\""), $1, $2), make3_str(make3_str($3, make_str("/"), $5), $6, make_str("\""))); } | char_variable { @@ -4515,16 +4876,16 @@ db_prefix: ident cvariable if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0) { sprintf(errortext, "parse error at or near '%s'", $2); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0) { sprintf(errortext, "Illegal connection type %s", $1); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - $$ = make3_str($1, make1_str(":"), $2); + $$ = make3_str( $1, make_str(":"), $2); } server: Op server_name @@ -4532,51 +4893,51 @@ server: Op server_name if (strcmp($1, "@") != 0 && strcmp($1, "://") != 0) { sprintf(errortext, "parse error at or near '%s'", $1); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } $$ = make2_str($1, $2); } opt_server: server { $$ = $1; } - | /* empty */ { $$ = make1_str(""); } + | /* empty */ { $$ = EMPTY; } server_name: ColId { $$ = $1; } - | ColId '.' server_name { $$ = make3_str($1, make1_str("."), $3); } + | ColId '.' server_name { $$ = make3_str($1, make_str("."), $3); } -opt_port: ':' Iconst { $$ = make2_str(make1_str(":"), $2); } - | /* empty */ { $$ = make1_str(""); } +opt_port: ':' Iconst { $$ = make2_str(make_str(":"), $2); } + | /* empty */ { $$ = EMPTY; } opt_connection_name: AS connection_target { $$ = $2; } - | /* empty */ { $$ = make1_str("NULL"); } + | /* empty */ { $$ = make_str("NULL"); } opt_user: USER ora_user { $$ = $2; } - | /* empty */ { $$ = make1_str("NULL,NULL"); } + | /* empty */ { $$ = make_str("NULL,NULL"); } ora_user: user_name { - $$ = make2_str($1, make1_str(",NULL")); + $$ = cat2_str($1, make_str(", NULL")); } | user_name '/' user_name { - $$ = make3_str($1, make1_str(","), $3); + $$ = cat_str(3, $1, make_str(","), $3); } | user_name SQL_IDENTIFIED BY user_name { - $$ = make3_str($1, make1_str(","), $4); + $$ = cat_str(3, $1, make_str(","), $4); } | user_name USING user_name { - $$ = make3_str($1, make1_str(","), $3); + $$ = cat_str(3, $1, make_str(","), $3); } user_name: UserId { if ($1[0] == '\"') $$ = $1; else - $$ = make3_str(make1_str("\""), $1, make1_str("\"")); + $$ = make3_str(make_str("\""), $1, make_str("\"")); } | char_variable { $$ = $1; } - | SCONST { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); } + | SCONST { $$ = make3_str(make_str("\""), $1, make_str("\"")); } char_variable: cvariable { /* check if we have a char variable */ @@ -4594,10 +4955,10 @@ char_variable: cvariable $$ = $1; break; case ECPGt_varchar: - $$ = make2_str($1, make1_str(".arr")); + $$ = make2_str($1, make_str(".arr")); break; default: - yyerror("invalid datatype"); + mmerror(ET_ERROR, "invalid datatype"); break; } } @@ -4605,17 +4966,17 @@ char_variable: cvariable opt_options: Op ColId { if (strlen($1) == 0) - yyerror("parse error"); + mmerror(ET_ERROR, "parse error"); if (strcmp($1, "?") != 0) { sprintf(errortext, "parse error at or near %s", $1); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } - $$ = make2_str(make1_str("?"), $2); + $$ = make2_str(make_str("?"), $2); } - | /* empty */ { $$ = make1_str(""); } + | /* empty */ { $$ = EMPTY; } /* * Declare a prepared cursor. The syntax is different from the standard @@ -4632,7 +4993,7 @@ ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident { /* re-definition is a bug */ sprintf(errortext, "cursor %s already defined", $2); - yyerror(errortext); + mmerror(ET_ERROR, errortext); } } @@ -4642,7 +5003,7 @@ ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident this->next = cur; this->name = $2; this->connection = connection; - this->command = cat4_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for ?")); + this->command = cat_str(4, make_str("declare"), mm_strdup($2), $3, make_str("cursor for ?")); this->argsresult = NULL; thisquery->type = &ecpg_query; @@ -4656,7 +5017,7 @@ ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident cur = this; - $$ = cat3_str(make1_str("/*"), mm_strdup(this->command), make1_str("*/")); + $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/")); } ; @@ -4664,7 +5025,7 @@ ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident * the exec sql deallocate prepare command to deallocate a previously * prepared statement */ -ECPGDeallocate: SQL_DEALLOCATE SQL_PREPARE ident { $$ = make3_str(make1_str("ECPGdeallocate(__LINE__, \""), $3, make1_str("\");")); } +ECPGDeallocate: SQL_DEALLOCATE SQL_PREPARE ident { $$ = cat_str(3, make_str("ECPGdeallocate(__LINE__, \""), $3, make_str("\");")); } /* * variable declaration inside the exec sql declare block @@ -4672,7 +5033,6 @@ ECPGDeallocate: SQL_DEALLOCATE SQL_PREPARE ident { $$ = make3_str(make1_str("ECP ECPGDeclaration: sql_startdeclare { fputs("/* exec sql begin declare section */", yyout); - output_line_number(); } variable_declarations sql_enddeclare { @@ -4685,37 +5045,45 @@ sql_startdeclare : ecpgstart BEGIN_TRANS DECLARE SQL_SECTION ';' {} sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION ';' {} -variable_declarations: /* empty */ - { - $$ = make1_str(""); - } - | declaration variable_declarations - { - $$ = cat2_str($1, $2); - } +variable_declarations: /* empty */ { $$ = EMPTY; } + | declarations { $$ = $1; } + +declarations: declaration { $$ = $1; } + | declarations declaration { $$ = cat2_str($1, $2); } -declaration: storage_clause +declaration: storage_clause storage_modifier { - actual_storage[struct_level] = mm_strdup($1); + actual_storage[struct_level] = cat2_str(mm_strdup($1), mm_strdup($2)); + actual_startline[struct_level] = hashline_number(); } type { - actual_type[struct_level].type_enum = $3.type_enum; - actual_type[struct_level].type_dimension = $3.type_dimension; - actual_type[struct_level].type_index = $3.type_index; + actual_type[struct_level].type_enum = $4.type_enum; + actual_type[struct_level].type_dimension = $4.type_dimension; + actual_type[struct_level].type_index = $4.type_index; + + /* we do not need the string "varchar" for output */ + /* so replace it with an empty string */ + if ($4.type_enum == ECPGt_varchar) + { + free($4.type_str); + $4.type_str=EMPTY; + } } variable_list ';' { - $$ = cat4_str($1, $3.type_str, $5, make1_str(";\n")); + $$ = cat_str(6, actual_startline[struct_level], $1, $2, $4.type_str, $6, make_str(";\n")); } -storage_clause : S_EXTERN { $$ = make1_str("extern"); } - | S_STATIC { $$ = make1_str("static"); } - | S_SIGNED { $$ = make1_str("signed"); } - | S_CONST { $$ = make1_str("const"); } - | S_REGISTER { $$ = make1_str("register"); } - | S_AUTO { $$ = make1_str("auto"); } - | /* empty */ { $$ = make1_str(""); } +storage_clause : S_EXTERN { $$ = make_str("extern"); } + | S_STATIC { $$ = make_str("static"); } + | S_REGISTER { $$ = make_str("register"); } + | S_AUTO { $$ = make_str("auto"); } + | /* empty */ { $$ = EMPTY; } + +storage_modifier : S_CONST { $$ = make_str("const"); } + | S_VOLATILE { $$ = make_str("volatile"); } + | /* empty */ { $$ = EMPTY; } type: simple_type { @@ -4727,7 +5095,7 @@ type: simple_type | varchar_type { $$.type_enum = ECPGt_varchar; - $$.type_str = make1_str(""); + $$.type_str = make_str("varchar");; $$.type_dimension = -1; $$.type_index = -1; } @@ -4749,8 +5117,7 @@ type: simple_type { $$.type_str = $1; $$.type_enum = ECPGt_int; - - $$.type_dimension = -1; + $$.type_dimension = -1; $$.type_index = -1; } | symbol @@ -4758,66 +5125,96 @@ type: simple_type /* this is for typedef'ed types */ struct typedefs *this = get_typedef($1); - $$.type_str = (this->type->type_enum == ECPGt_varchar) ? make1_str("") : mm_strdup(this->name); + $$.type_str = (this->type->type_enum == ECPGt_varchar) ? EMPTY : mm_strdup(this->name); $$.type_enum = this->type->type_enum; $$.type_dimension = this->type->type_dimension; $$.type_index = this->type->type_index; struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); } -enum_type: s_enum '{' c_line '}' +enum_type: SQL_ENUM opt_symbol enum_definition { - $$ = cat4_str($1, make1_str("{"), $3, make1_str("}")); + $$ = cat_str(3, make_str("enum"), $2, $3); } - -s_enum: S_ENUM opt_symbol { $$ = cat2_str(make1_str("enum"), $2); } + | SQL_ENUM symbol + { + $$ = cat2_str(make_str("enum"), $2); + } + +enum_definition: '{' c_list '}' { $$ = cat_str(3, make_str("{"), $2, make_str("}")); } struct_type: s_struct '{' variable_declarations '}' { ECPGfree_struct_member(struct_member_list[struct_level]); free(actual_storage[struct_level--]); - $$ = cat4_str($1, make1_str("{"), $3, make1_str("}")); + $$ = cat_str(4, $1, make_str("{"), $3, make_str("}")); } union_type: s_union '{' variable_declarations '}' { ECPGfree_struct_member(struct_member_list[struct_level]); free(actual_storage[struct_level--]); - $$ = cat4_str($1, make1_str("{"), $3, make1_str("}")); + $$ = cat_str(4, $1, make_str("{"), $3, make_str("}")); } -s_struct : S_STRUCT opt_symbol +s_struct: SQL_STRUCT opt_symbol { struct_member_list[struct_level++] = NULL; if (struct_level >= STRUCT_DEPTH) - yyerror("Too many levels in nested structure definition"); - $$ = cat2_str(make1_str("struct"), $2); + mmerror(ET_ERROR, "Too many levels in nested structure definition"); + + /* reset this variable so we see if there was */ + /* an initializer specified */ + initializer = 0; + + $$ = cat2_str(make_str("struct"), $2); } -s_union : S_UNION opt_symbol +s_union: UNION opt_symbol { struct_member_list[struct_level++] = NULL; if (struct_level >= STRUCT_DEPTH) - yyerror("Too many levels in nested structure definition"); - $$ = cat2_str(make1_str("union"), $2); + mmerror(ET_ERROR, "Too many levels in nested structure definition"); + + /* reset this variable so we see if there was */ + /* an initializer specified */ + initializer = 0; + + $$ = cat2_str(make_str("union"), $2); } -opt_symbol: /* empty */ { $$ = make1_str(""); } +opt_symbol: /* empty */ { $$ = EMPTY; } | symbol { $$ = $1; } -simple_type: S_SHORT { $$ = ECPGt_short; } - | S_UNSIGNED S_SHORT { $$ = ECPGt_unsigned_short; } - | S_INT { $$ = ECPGt_int; } - | S_UNSIGNED S_INT { $$ = ECPGt_unsigned_int; } - | S_LONG { $$ = ECPGt_long; } - | S_UNSIGNED S_LONG { $$ = ECPGt_unsigned_long; } - | S_FLOAT { $$ = ECPGt_float; } - | S_DOUBLE { $$ = ECPGt_double; } - | S_BOOL { $$ = ECPGt_bool; }; - | S_CHAR { $$ = ECPGt_char; } - | S_UNSIGNED S_CHAR { $$ = ECPGt_unsigned_char; } +simple_type: unsigned_type { $$=$1; } + | opt_signed signed_type { $$=$2; } + ; + +unsigned_type: SQL_UNSIGNED SQL_SHORT { $$ = ECPGt_unsigned_short; } + | SQL_UNSIGNED SQL_SHORT SQL_INT { $$ = ECPGt_unsigned_short; } + | SQL_UNSIGNED { $$ = ECPGt_unsigned_int; } + | SQL_UNSIGNED SQL_INT { $$ = ECPGt_unsigned_int; } + | SQL_UNSIGNED SQL_LONG { $$ = ECPGt_unsigned_long; } + | SQL_UNSIGNED SQL_LONG SQL_INT { $$ = ECPGt_unsigned_long; } + | SQL_UNSIGNED CHAR { $$ = ECPGt_unsigned_char; } + ; + +signed_type: SQL_SHORT { $$ = ECPGt_short; } + | SQL_SHORT SQL_INT { $$ = ECPGt_short; } + | SQL_INT { $$ = ECPGt_int; } + | SQL_LONG { $$ = ECPGt_long; } + | SQL_LONG SQL_INT { $$ = ECPGt_long; } + | SQL_BOOL { $$ = ECPGt_bool; }; + | FLOAT { $$ = ECPGt_float; } + | DOUBLE { $$ = ECPGt_double; } + | CHAR { $$ = ECPGt_char; } + ; + +opt_signed: SQL_SIGNED + | /* EMPTY */ + ; -varchar_type: S_VARCHAR { $$ = ECPGt_varchar; } +varchar_type: VARCHAR { $$ = ECPGt_varchar; } variable_list: variable { @@ -4825,7 +5222,7 @@ variable_list: variable } | variable_list ',' variable { - $$ = cat3_str($1, make1_str(","), $3); + $$ = cat_str(3, $1, make_str(","), $3); } variable: opt_pointer symbol opt_array_bounds opt_initializer @@ -4846,7 +5243,7 @@ variable: opt_pointer symbol opt_array_bounds opt_initializer else type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum), dimension); - $$ = make4_str($1, mm_strdup($2), $3.str, $4); + $$ = cat_str(4, $1, mm_strdup($2), $3.str, $4); break; case ECPGt_varchar: if (dimension == -1) @@ -4868,12 +5265,12 @@ variable: opt_pointer symbol opt_array_bounds opt_initializer sprintf(ascii_len, "%d", length); if (length == 0) - yyerror ("pointer to varchar are not implemented"); + mmerror(ET_ERROR, "pointer to varchar are not implemented"); if (dimension == 0) - $$ = make4_str(make5_str(mm_strdup(actual_storage[struct_level]), make1_str(" struct varchar_"), mm_strdup($2), make1_str(" { int len; char arr["), mm_strdup(ascii_len)), make1_str("]; } *"), mm_strdup($2), $4); + $$ = cat_str(7, mm_strdup(actual_storage[struct_level]), make2_str(make_str(" struct varchar_"), mm_strdup($2)), make_str(" { int len; char arr["), mm_strdup(ascii_len), make_str("]; } *"), mm_strdup($2), $4); else - $$ = make5_str(make5_str(mm_strdup(actual_storage[struct_level]), make1_str(" struct varchar_"), mm_strdup($2), make1_str(" { int len; char arr["), mm_strdup(ascii_len)), make1_str("]; } "), mm_strdup($2), mm_strdup(dim), $4); + $$ = cat_str(8, mm_strdup(actual_storage[struct_level]), make2_str(make_str(" struct varchar_"), mm_strdup($2)), make_str(" { int len; char arr["), mm_strdup(ascii_len), make_str("]; } "), mm_strdup($2), mm_strdup(dim), $4); break; case ECPGt_char: @@ -4883,7 +5280,7 @@ variable: opt_pointer symbol opt_array_bounds opt_initializer else type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension); - $$ = make4_str($1, mm_strdup($2), $3.str, $4); + $$ = cat_str(4, $1, mm_strdup($2), $3.str, $4); break; default: if (dimension < 0) @@ -4891,7 +5288,7 @@ variable: opt_pointer symbol opt_array_bounds opt_initializer else type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension); - $$ = make4_str($1, mm_strdup($2), $3.str, $4); + $$ = cat_str(4, $1, mm_strdup($2), $3.str, $4); break; } @@ -4903,11 +5300,14 @@ variable: opt_pointer symbol opt_array_bounds opt_initializer free($2); } -opt_initializer: /* empty */ { $$ = make1_str(""); } - | '=' vartext { $$ = make2_str(make1_str("="), $2); } +opt_initializer: /* empty */ { $$ = EMPTY; } + | '=' c_term { + initializer = 1; + $$ = cat2_str(make_str("="), $2); + } -opt_pointer: /* empty */ { $$ = make1_str(""); } - | '*' { $$ = make1_str("*"); } +opt_pointer: /* empty */ { $$ = EMPTY; } + | '*' { $$ = make_str("*"); } /* * As long as the prepare statement is not supported by the backend, we will @@ -4916,7 +5316,7 @@ opt_pointer: /* empty */ { $$ = make1_str(""); } ECPGDeclare: DECLARE STATEMENT ident { /* this is only supported for compatibility */ - $$ = cat3_str(make1_str("/* declare statement"), $3, make1_str("*/")); + $$ = cat_str(3, make_str("/* declare statement"), $3, make_str("*/")); } /* * the exec sql disconnect statement: disconnect from the given database @@ -4924,17 +5324,17 @@ ECPGDeclare: DECLARE STATEMENT ident ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; } dis_name: connection_object { $$ = $1; } - | CURRENT { $$ = make1_str("CURRENT"); } - | ALL { $$ = make1_str("ALL"); } - | /* empty */ { $$ = make1_str("CURRENT"); } + | CURRENT { $$ = make_str("CURRENT"); } + | ALL { $$ = make_str("ALL"); } + | /* empty */ { $$ = make_str("CURRENT"); } connection_object: connection_target { $$ = $1; } - | DEFAULT { $$ = make1_str("DEFAULT"); } + | DEFAULT { $$ = make_str("DEFAULT"); } /* * execute a given string as sql command */ -ECPGExecute : EXECUTE SQL_IMMEDIATE execstring +ECPGExecute : EXECUTE IMMEDIATE execstring { struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable)); @@ -4945,7 +5345,7 @@ ECPGExecute : EXECUTE SQL_IMMEDIATE execstring add_variable(&argsinsert, thisquery, &no_indicator); - $$ = make1_str("?"); + $$ = make_str("?"); } | EXECUTE ident { @@ -4958,13 +5358,13 @@ ECPGExecute : EXECUTE SQL_IMMEDIATE execstring sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $2); add_variable(&argsinsert, thisquery, &no_indicator); - } opt_using + } ecpg_using { - $$ = make1_str("?"); + $$ = make_str("?"); } execstring: char_variable | - CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }; + CSTRING { $$ = make3_str(make_str("\""), $1, make_str("\"")); }; /* * the exec sql free command to deallocate a previously @@ -4975,14 +5375,14 @@ ECPGFree: SQL_FREE ident { $$ = $2; } /* * open is an open cursor, at the moment this has to be removed */ -ECPGOpen: SQL_OPEN name opt_using { +ECPGOpen: SQL_OPEN name ecpg_using { $$ = $2; }; -opt_using: /* empty */ { $$ = make1_str(""); } +ecpg_using: /* empty */ { $$ = EMPTY; } | USING variablelist { - /* yyerror ("open cursor with variables not implemented yet"); */ - $$ = make1_str(""); + /* mmerror ("open cursor with variables not implemented yet"); */ + $$ = EMPTY; } variablelist: cinputvariable | cinputvariable ',' variablelist @@ -4993,9 +5393,81 @@ variablelist: cinputvariable | cinputvariable ',' variablelist */ ECPGPrepare: SQL_PREPARE ident FROM execstring { - $$ = make4_str(make1_str("\""), $2, make1_str("\", "), $4); + $$ = cat2_str(make3_str(make_str("\""), $2, make_str("\",")), $4); } +/* + * dynamic SQL: descriptor based access + * written by Christof Petig + */ + +/* + * deallocate a descriptor + */ +ECPGDeallocateDescr: SQL_DEALLOCATE SQL_DESCRIPTOR ident +{ drop_descriptor($3,connection); + $$ = $3; +} + +/* + * allocate a descriptor + */ +ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR ident +{ add_descriptor($3,connection); + $$ = $3; +} + +/* + * read from descriptor + */ + +ECPGGetDescHeaderItem: cvariable '=' ident { + push_assignment($1,$3); +} + +ECPGGetDescItem: cvariable '=' ident { + push_assignment($1,$3); +} + | cvariable '=' TYPE_P { + push_assignment($1,"type"); +} + | cvariable '=' PRECISION { + push_assignment($1,"precision"); +} + | cvariable '=' SQL_INDICATOR { + push_assignment($1,"indicator"); +} + +ECPGGetDescHeaderItems: ECPGGetDescHeaderItem + | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem; + +ECPGGetDescItems: ECPGGetDescItem + | ECPGGetDescItems ',' ECPGGetDescItem; + +ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR ident ECPGGetDescHeaderItems +{ $$ = $3; } + +ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR ident SQL_VALUE cvariable ECPGGetDescItems +{ $$ = $3; descriptor_index=$5; } + | SQL_GET SQL_DESCRIPTOR ident SQL_VALUE Iconst ECPGGetDescItems +{ $$ = $3; descriptor_index=$5; } + +/* + * fetch [ in | from ] into sql descriptor + */ + +FetchDescriptorStmt: FETCH from_in name INTO SQL_SQL SQL_DESCRIPTOR ident + { + $$ = cat_str(3, make_str("fetch"), $2, $3); + descriptor_name=$7; + } + | FETCH name INTO SQL_SQL SQL_DESCRIPTOR ident + { + $$ = cat2_str(make_str("fetch"), $2); + descriptor_name=$6; + } + ; + /* * for compatibility with ORACLE we will also allow the keyword RELEASE * after a transaction statement to disconnect from the database. @@ -5003,12 +5475,13 @@ ECPGPrepare: SQL_PREPARE ident FROM execstring ECPGRelease: TransactionStmt SQL_RELEASE { - if (strncmp($1, "begin", 5) == 0) - yyerror("RELEASE does not make sense when beginning a transaction"); + if (strcmp($1, "begin") == 0) + mmerror(ET_ERROR, "RELEASE does not make sense when beginning a transaction"); - fprintf(yyout, "ECPGtrans(__LINE__, %s, \"%s\");", connection, $1); + fprintf(yyout, "ECPGtrans(__LINE__, %s, \"%s\");", + connection ? connection : "NULL", $1); whenever_action(0); - fprintf(yyout, "ECPGdisconnect(\"\");"); + fprintf(yyout, "ECPGdisconnect(__LINE__, \"\");"); whenever_action(0); free($1); } @@ -5022,10 +5495,10 @@ ECPGSetAutocommit: SET SQL_AUTOCOMMIT to_equal on_off $$ = $4; } -on_off: ON { $$ = make1_str("on"); } - | SQL_OFF { $$ = make1_str("off"); } +on_off: ON { $$ = make_str("on"); } + | SQL_OFF { $$ = make_str("off"); } -to_equal: TO | "="; +to_equal: TO | '='; /* * set the actual connection, this needs a differnet handling as the other @@ -5039,20 +5512,25 @@ ECPGSetConnection: SET SQL_CONNECTION to_equal connection_object /* * define a new type for embedded SQL */ -ECPGTypedef: TYPE_P symbol IS ctype opt_type_array_bounds opt_reference +ECPGTypedef: TYPE_P symbol IS type opt_type_array_bounds opt_reference { /* add entry to list */ struct typedefs *ptr, *this; int dimension = $5.index1; int length = $5.index2; + if (($4.type_enum == ECPGt_struct || + $4.type_enum == ECPGt_union) && + initializer == 1) + mmerror(ET_ERROR, "Initializer not allowed in EXEC SQL VAR command"); + for (ptr = types; ptr != NULL; ptr = ptr->next) { if (strcmp($2, ptr->name) == 0) { /* re-definition is a bug */ - sprintf(errortext, "type %s already defined", $2); - yyerror(errortext); + sprintf(errortext, "Type %s already defined", $2); + mmerror(ET_ERROR, errortext); } } @@ -5068,30 +5546,31 @@ ECPGTypedef: TYPE_P symbol IS ctype opt_type_array_bounds opt_reference this->type->type_str = mm_strdup($2); this->type->type_dimension = dimension; /* dimension of array */ this->type->type_index = length; /* lenght of string */ - this->struct_member_list = struct_member_list[struct_level]; + this->struct_member_list = ($4.type_enum == ECPGt_struct || $4.type_enum == ECPGt_union) ? + struct_member_list[struct_level] : NULL; if ($4.type_enum != ECPGt_varchar && $4.type_enum != ECPGt_char && $4.type_enum != ECPGt_unsigned_char && this->type->type_index >= 0) - yyerror("No multi-dimensional array support for simple data types"); + mmerror(ET_ERROR, "No multi-dimensional array support for simple data types"); types = this; - $$ = cat5_str(cat3_str(make1_str("/* exec sql type"), mm_strdup($2), make1_str("is")), mm_strdup($4.type_str), mm_strdup($5.str), $6, make1_str("*/")); + $$ = cat_str(7, make_str("/* exec sql type"), mm_strdup($2), make_str("is"), mm_strdup($4.type_str), mm_strdup($5.str), $6, make_str("*/")); } opt_type_array_bounds: '[' ']' opt_type_array_bounds { $$.index1 = 0; $$.index2 = $3.index1; - $$.str = cat2_str(make1_str("[]"), $3.str); + $$.str = cat2_str(make_str("[]"), $3.str); } | '(' ')' opt_type_array_bounds { $$.index1 = 0; $$.index2 = $3.index1; - $$.str = cat2_str(make1_str("[]"), $3.str); + $$.str = cat2_str(make_str("[]"), $3.str); } | '[' Iresult ']' opt_type_array_bounds { @@ -5100,7 +5579,7 @@ opt_type_array_bounds: '[' ']' opt_type_array_bounds sprintf (txt, "%d", $2); $$.index1 = $2; $$.index2 = $4.index1; - $$.str = cat4_str(make1_str("["), txt, make1_str("]"), $4.str); + $$.str = cat_str(4, make_str("["), txt, make_str("]"), $4.str); } | '(' Iresult ')' opt_type_array_bounds { @@ -5109,250 +5588,34 @@ opt_type_array_bounds: '[' ']' opt_type_array_bounds sprintf (txt, "%d", $2); $$.index1 = $2; $$.index2 = $4.index1; - $$.str = cat4_str(make1_str("["), txt, make1_str("]"), $4.str); + $$.str = cat_str(4, make_str("["), txt, make_str("]"), $4.str); } | /* EMPTY */ { $$.index1 = -1; $$.index2 = -1; - $$.str= make1_str(""); + $$.str= EMPTY; } ; -opt_reference: SQL_REFERENCE { $$ = make1_str("reference"); } - | /* empty */ { $$ = make1_str(""); } - -ctype: CHAR - { - $$.type_str = make1_str("char"); - $$.type_enum = ECPGt_char; - $$.type_index = -1; - $$.type_dimension = -1; - } - | VARCHAR - { - $$.type_str = make1_str("varchar"); - $$.type_enum = ECPGt_varchar; - $$.type_index = -1; - $$.type_dimension = -1; - } - | FLOAT - { - $$.type_str = make1_str("float"); - $$.type_enum = ECPGt_float; - $$.type_index = -1; - $$.type_dimension = -1; - } - | DOUBLE - { - $$.type_str = make1_str("double"); - $$.type_enum = ECPGt_double; - $$.type_index = -1; - $$.type_dimension = -1; - } - | opt_signed SQL_INT - { - $$.type_str = make1_str("int"); - $$.type_enum = ECPGt_int; - $$.type_index = -1; - $$.type_dimension = -1; - } - | SQL_ENUM - { - $$.type_str = make1_str("int"); - $$.type_enum = ECPGt_int; - $$.type_index = -1; - $$.type_dimension = -1; - } - | opt_signed SQL_SHORT - { - $$.type_str = make1_str("short"); - $$.type_enum = ECPGt_short; - $$.type_index = -1; - $$.type_dimension = -1; - } - | opt_signed SQL_LONG - { - $$.type_str = make1_str("long"); - $$.type_enum = ECPGt_long; - $$.type_index = -1; - $$.type_dimension = -1; - } - | SQL_BOOL - { - $$.type_str = make1_str("bool"); - $$.type_enum = ECPGt_bool; - $$.type_index = -1; - $$.type_dimension = -1; - } - | SQL_UNSIGNED SQL_INT - { - $$.type_str = make1_str("unsigned int"); - $$.type_enum = ECPGt_unsigned_int; - $$.type_index = -1; - $$.type_dimension = -1; - } - | SQL_UNSIGNED SQL_SHORT - { - $$.type_str = make1_str("unsigned short"); - $$.type_enum = ECPGt_unsigned_short; - $$.type_index = -1; - $$.type_dimension = -1; - } - | SQL_UNSIGNED SQL_LONG - { - $$.type_str = make1_str("unsigned long"); - $$.type_enum = ECPGt_unsigned_long; - $$.type_index = -1; - $$.type_dimension = -1; - } - | SQL_STRUCT - { - struct_member_list[struct_level++] = NULL; - if (struct_level >= STRUCT_DEPTH) - yyerror("Too many levels in nested structure definition"); - } '{' sql_variable_declarations '}' - { - ECPGfree_struct_member(struct_member_list[struct_level--]); - $$.type_str = cat3_str(make1_str("struct {"), $4, make1_str("}")); - $$.type_enum = ECPGt_struct; - $$.type_index = -1; - $$.type_dimension = -1; - } - | UNION - { - struct_member_list[struct_level++] = NULL; - if (struct_level >= STRUCT_DEPTH) - yyerror("Too many levels in nested structure definition"); - } '{' sql_variable_declarations '}' - { - ECPGfree_struct_member(struct_member_list[struct_level--]); - $$.type_str = cat3_str(make1_str("union {"), $4, make1_str("}")); - $$.type_enum = ECPGt_union; - $$.type_index = -1; - $$.type_dimension = -1; - } - | symbol - { - struct typedefs *this = get_typedef($1); - - $$.type_str = mm_strdup($1); - $$.type_enum = this->type->type_enum; - $$.type_dimension = this->type->type_dimension; - $$.type_index = this->type->type_index; - struct_member_list[struct_level] = this->struct_member_list; - } - -opt_signed: SQL_SIGNED | /* empty */ - -sql_variable_declarations: /* empty */ - { - $$ = make1_str(""); - } - | sql_declaration sql_variable_declarations - { - $$ = cat2_str($1, $2); - } - ; - -sql_declaration: ctype - { - actual_type[struct_level].type_enum = $1.type_enum; - actual_type[struct_level].type_dimension = $1.type_dimension; - actual_type[struct_level].type_index = $1.type_index; - } - sql_variable_list ';' - { - $$ = cat3_str($1.type_str, $3, make1_str(";")); - } - -sql_variable_list: sql_variable - { - $$ = $1; - } - | sql_variable_list ',' sql_variable - { - $$ = make3_str($1, make1_str(","), $3); - } - -sql_variable: opt_pointer symbol opt_array_bounds - { - int dimension = $3.index1; - int length = $3.index2; - struct ECPGtype * type; - char dim[14L]; - - adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1)); - - switch (actual_type[struct_level].type_enum) - { - case ECPGt_struct: - case ECPGt_union: - if (dimension < 0) - type = ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum); - else - type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum), dimension); - - break; - case ECPGt_varchar: - if (dimension == -1) - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length); - else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension); - - switch(dimension) - { - case 0: - strcpy(dim, "[]"); - break; - case -1: - case 1: - *dim = '\0'; - break; - default: - sprintf(dim, "[%d]", dimension); - break; - } - - break; - case ECPGt_char: - case ECPGt_unsigned_char: - if (dimension == -1) - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length); - else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension); - - break; - default: - if (length >= 0) - yyerror("No multi-dimensional array support for simple data types"); - - if (dimension < 0) - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, 1); - else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension); - - break; - } - - if (struct_level == 0) - new_variable($2, type); - else - ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1])); - - $$ = cat3_str($1, $2, $3.str); - } +opt_reference: SQL_REFERENCE { $$ = make_str("reference"); } + | /* empty */ { $$ = EMPTY; } /* * define the type of one variable for embedded SQL */ -ECPGVar: SQL_VAR symbol IS ctype opt_type_array_bounds opt_reference +ECPGVar: SQL_VAR symbol IS type opt_type_array_bounds opt_reference { struct variable *p = find_variable($2); int dimension = $5.index1; int length = $5.index2; struct ECPGtype * type; + if (($4.type_enum == ECPGt_struct || + $4.type_enum == ECPGt_union) && + initializer == 1) + mmerror(ET_ERROR, "Initializer not allowed in EXEC SQL VAR command"); + adjust_array($4.type_enum, &dimension, &length, $4.type_dimension, $4.type_index, strlen($6)); switch ($4.type_enum) @@ -5381,7 +5644,7 @@ ECPGVar: SQL_VAR symbol IS ctype opt_type_array_bounds opt_reference break; default: if (length >= 0) - yyerror("No multi-dimensional array support for simple data types"); + mmerror(ET_ERROR, "No multi-dimensional array support for simple data types"); if (dimension < 0) type = ECPGmake_simple_type($4.type_enum, 1); @@ -5394,7 +5657,7 @@ ECPGVar: SQL_VAR symbol IS ctype opt_type_array_bounds opt_reference ECPGfree_type(p->type); p->type = type; - $$ = cat5_str(cat3_str(make1_str("/* exec sql var"), mm_strdup($2), make1_str("is")), mm_strdup($4.type_str), mm_strdup($5.str), $6, make1_str("*/")); + $$ = cat_str(7, make_str("/* exec sql var"), mm_strdup($2), make_str("is"), mm_strdup($4.type_str), mm_strdup($5.str), $6, make_str("*/")); } /* @@ -5404,382 +5667,172 @@ ECPGVar: SQL_VAR symbol IS ctype opt_type_array_bounds opt_reference ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action { when_error.code = $3.code; when_error.command = $3.command; - $$ = cat3_str(make1_str("/* exec sql whenever sqlerror "), $3.str, make1_str("; */\n")); + $$ = cat_str(3, make_str("/* exec sql whenever sqlerror "), $3.str, make_str("; */\n")); } | SQL_WHENEVER NOT SQL_FOUND action { when_nf.code = $4.code; when_nf.command = $4.command; - $$ = cat3_str(make1_str("/* exec sql whenever not found "), $4.str, make1_str("; */\n")); + $$ = cat_str(3, make_str("/* exec sql whenever not found "), $4.str, make_str("; */\n")); } | SQL_WHENEVER SQL_SQLWARNING action { when_warn.code = $3.code; when_warn.command = $3.command; - $$ = cat3_str(make1_str("/* exec sql whenever sql_warning "), $3.str, make1_str("; */\n")); + $$ = cat_str(3, make_str("/* exec sql whenever sql_warning "), $3.str, make_str("; */\n")); } action : SQL_CONTINUE { $$.code = W_NOTHING; $$.command = NULL; - $$.str = make1_str("continue"); + $$.str = make_str("continue"); } | SQL_SQLPRINT { $$.code = W_SQLPRINT; $$.command = NULL; - $$.str = make1_str("sqlprint"); + $$.str = make_str("sqlprint"); } | SQL_STOP { $$.code = W_STOP; $$.command = NULL; - $$.str = make1_str("stop"); + $$.str = make_str("stop"); } | SQL_GOTO name { $$.code = W_GOTO; $$.command = strdup($2); - $$.str = cat2_str(make1_str("goto "), $2); + $$.str = cat2_str(make_str("goto "), $2); } | SQL_GO TO name { $$.code = W_GOTO; $$.command = strdup($3); - $$.str = cat2_str(make1_str("goto "), $3); + $$.str = cat2_str(make_str("goto "), $3); } - | DO name '(' dotext ')' { + | DO name '(' c_args ')' { $$.code = W_DO; - $$.command = make4_str($2, make1_str("("), $4, make1_str(")")); - $$.str = cat2_str(make1_str("do"), mm_strdup($$.command)); + $$.command = cat_str(4, $2, make_str("("), $4, make_str(")")); + $$.str = cat2_str(make_str("do"), mm_strdup($$.command)); } | DO SQL_BREAK { $$.code = W_BREAK; $$.command = NULL; - $$.str = make1_str("break"); + $$.str = make_str("break"); } - | SQL_CALL name '(' dotext ')' { + | SQL_CALL name '(' c_args ')' { $$.code = W_DO; - $$.command = make4_str($2, make1_str("("), $4, make1_str(")")); - $$.str = cat2_str(make1_str("call"), mm_strdup($$.command)); + $$.command = cat_str(4, $2, make_str("("), $4, make_str(")")); + $$.str = cat2_str(make_str("call"), mm_strdup($$.command)); } /* some other stuff for ecpg */ -ecpg_expr: attr - { - $$ = $1; - } - | row_expr - { $$ = $1; } - | AexprConst - { $$ = $1; } - | ColId opt_indirection - { - $$ = cat2_str($1, $2); - } +/* + * no longer used +ecpg_expr: c_expr + { $$ = $1; } + | a_expr TYPECAST Typename + { $$ = cat_str(3, $1, make_str("::"), $3); } | '-' ecpg_expr %prec UMINUS - { $$ = cat2_str(make1_str("-"), $2); } + { $$ = cat2_str(make_str("-"), $2); } | '%' ecpg_expr - { $$ = cat2_str(make1_str("%"), $2); } + { $$ = cat2_str(make_str("%"), $2); } | '^' ecpg_expr - { $$ = cat2_str(make1_str("^"), $2); } + { $$ = cat2_str(make_str("^"), $2); } + | '|' ecpg_expr + { $$ = cat2_str(make_str("|"), $2); } + | ';' a_expr + { $$ = cat2_str(make_str(";"), $2); } | a_expr '%' - { $$ = cat2_str($1, make1_str("%")); } + { $$ = cat2_str($1, make_str("%")); } | a_expr '^' - { $$ = cat2_str($1, make1_str("^")); } + { $$ = cat2_str($1, make_str("^")); } + | a_expr '|' + { $$ = cat2_str($1, make_str("|")); } | a_expr '+' ecpg_expr - { $$ = cat3_str($1, make1_str("+"), $3); } + { $$ = cat_str(3, $1, make_str("+"), $3); } | a_expr '-' ecpg_expr - { $$ = cat3_str($1, make1_str("-"), $3); } + { $$ = cat_str(3, $1, make_str("-"), $3); } + | a_expr '*' ecpg_expr + { $$ = cat_str(3, $1, make_str("*"), $3); } | a_expr '/' ecpg_expr - { $$ = cat3_str($1, make1_str("/"), $3); } + { $$ = cat_str(3, $1, make_str("/"), $3); } | a_expr '%' ecpg_expr - { $$ = cat3_str($1, make1_str("%"), $3); } - | a_expr '*' ecpg_expr - { $$ = cat3_str($1, make1_str("*"), $3); } + { $$ = cat_str(3, $1, make_str("%"), $3); } | a_expr '^' ecpg_expr - { $$ = cat3_str($1, make1_str("^"), $3); } + { $$ = cat_str(3, $1, make_str("^"), $3); } + | a_expr '|' ecpg_expr + { $$ = cat_str(3, $1, make_str("|"), $3); } | a_expr '<' ecpg_expr - { $$ = cat3_str($1, make1_str("<"), $3); } + { $$ = cat_str(3, $1, make_str("<"), $3); } | a_expr '>' ecpg_expr - { $$ = cat3_str($1, make1_str(">"), $3); } + { $$ = cat_str(3, $1, make_str(">"), $3); } | a_expr '=' NULL_P - { $$ = cat2_str($1, make1_str("= NULL")); } - | NULL_P '=' a_expr - { $$ = cat2_str(make1_str("= NULL"), $3); } + { $$ = cat2_str($1, make_str("= NULL")); } + | NULL_P '=' ecpg_expr + { $$ = cat2_str(make_str("= NULL"), $3); } | a_expr '=' ecpg_expr - { $$ = cat3_str($1, make1_str("="), $3); } - /* | ':' ecpg_expr - { $$ = cat2_str(make1_str(":"), $2); }*/ - | ';' ecpg_expr - { $$ = cat2_str(make1_str(";"), $2); } - | '|' ecpg_expr - { $$ = cat2_str(make1_str("|"), $2); } - | a_expr TYPECAST Typename - { - $$ = cat3_str($1, make1_str("::"), $3); - } - | CAST '(' a_expr AS Typename ')' - { - $$ = cat3_str(make2_str(make1_str("cast("), $3), make1_str("as"), make2_str($5, make1_str(")"))); - } - | '(' a_expr_or_null ')' - { $$ = make3_str(make1_str("("), $2, make1_str(")")); } + { $$ = cat_str(3, $1, make_str("="), $3); } | a_expr Op ecpg_expr - { $$ = cat3_str($1, $2, $3); } - | a_expr LIKE ecpg_expr - { $$ = cat3_str($1, make1_str("like"), $3); } - | a_expr NOT LIKE ecpg_expr - { $$ = cat3_str($1, make1_str("not like"), $4); } + { $$ = cat_str(3, $1, make_str("="), $3); } | Op ecpg_expr { $$ = cat2_str($1, $2); } | a_expr Op { $$ = cat2_str($1, $2); } - | func_name '(' '*' ')' - { - $$ = cat2_str($1, make1_str("(*)")); - } - | func_name '(' ')' - { - $$ = cat2_str($1, make1_str("()")); - } - | func_name '(' expr_list ')' - { - $$ = make4_str($1, make1_str("("), $3, make1_str(")")); - } - | CURRENT_DATE - { - $$ = make1_str("current_date"); - } - | CURRENT_TIME - { - $$ = make1_str("current_time"); - } - | CURRENT_TIME '(' Iconst ')' - { - if (atol($3) != 0) - fprintf(stderr,"CURRENT_TIME(%s) precision not implemented; zero used instead", $3); - $$ = make1_str("current_time"); - } - | CURRENT_TIMESTAMP - { - $$ = make1_str("current_timestamp"); - } - | CURRENT_TIMESTAMP '(' Iconst ')' - { - if (atol($3) != 0) - fprintf(stderr,"CURRENT_TIMESTAMP(%s) precision not implemented; zero used instead",$3); - $$ = make1_str("current_timestamp"); - } - | CURRENT_USER - { - $$ = make1_str("current_user"); - } - | USER - { - $$ = make1_str("user"); - } - | EXISTS '(' SubSelect ')' - { - $$ = make3_str(make1_str("exists("), $3, make1_str(")")); - } - | EXTRACT '(' extract_list ')' - { - $$ = make3_str(make1_str("extract("), $3, make1_str(")")); - } - | POSITION '(' position_list ')' - { - $$ = make3_str(make1_str("position("), $3, make1_str(")")); - } - | SUBSTRING '(' substr_list ')' - { - $$ = make3_str(make1_str("substring("), $3, make1_str(")")); - } - /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */ - | TRIM '(' BOTH trim_list ')' - { - $$ = make3_str(make1_str("trim(both"), $4, make1_str(")")); - } - | TRIM '(' LEADING trim_list ')' - { - $$ = make3_str(make1_str("trim(leading"), $4, make1_str(")")); - } - | TRIM '(' TRAILING trim_list ')' - { - $$ = make3_str(make1_str("trim(trailing"), $4, make1_str(")")); - } - | TRIM '(' trim_list ')' - { - $$ = make3_str(make1_str("trim("), $3, make1_str(")")); - } + | a_expr AND ecpg_expr + { $$ = cat_str(3, $1, make_str("and"), $3); } + | a_expr OR ecpg_expr + { $$ = cat_str(3, $1, make_str("or"), $3); } + | NOT ecpg_expr + { $$ = cat2_str(make_str("not"), $2); } + | a_expr LIKE ecpg_expr + { $$ = cat_str(3, $1, make_str("like"), $3); } + | a_expr NOT LIKE ecpg_expr + { $$ = cat_str(3, $1, make_str("not like"), $4); } | a_expr ISNULL - { $$ = cat2_str($1, make1_str("isnull")); } + { $$ = cat2_str($1, make_str("isnull")); } | a_expr IS NULL_P - { $$ = cat2_str($1, make1_str("is null")); } + { $$ = cat2_str($1, make_str("is null")); } | a_expr NOTNULL - { $$ = cat2_str($1, make1_str("notnull")); } + { $$ = cat2_str($1, make_str("notnull")); } | a_expr IS NOT NULL_P - { $$ = cat2_str($1, make1_str("is not null")); } - /* IS TRUE, IS FALSE, etc used to be function calls - * but let's make them expressions to allow the optimizer - * a chance to eliminate them if a_expr is a constant string. - * - thomas 1997-12-22 - */ + { $$ = cat2_str($1, make_str("is not null")); } | a_expr IS TRUE_P - { - { $$ = cat2_str($1, make1_str("is true")); } - } + { $$ = cat2_str($1, make_str("is true")); } | a_expr IS NOT FALSE_P - { - { $$ = cat2_str($1, make1_str("is not false")); } - } + { $$ = cat2_str($1, make_str("is not false")); } | a_expr IS FALSE_P - { - { $$ = cat2_str($1, make1_str("is false")); } - } + { $$ = cat2_str($1, make_str("is false")); } | a_expr IS NOT TRUE_P - { - { $$ = cat2_str($1, make1_str("is not true")); } - } + { $$ = cat2_str($1, make_str("is not true")); } | a_expr BETWEEN b_expr AND b_expr { - $$ = cat5_str($1, make1_str("between"), $3, make1_str("and"), $5); + $$ = cat_str(5, $1, make_str("between"), $3, make_str("and"), $5); } | a_expr NOT BETWEEN b_expr AND b_expr { - $$ = cat5_str($1, make1_str("not between"), $4, make1_str("and"), $6); + $$ = cat_str(5, $1, make_str("not between"), $4, make_str("and"), $6); } | a_expr IN '(' in_expr ')' { - $$ = make4_str($1, make1_str(" in ("), $4, make1_str(")")); - } - | a_expr NOT IN '(' not_in_expr ')' - { - $$ = make4_str($1, make1_str(" not in ("), $5, make1_str(")")); - } - | a_expr Op '(' SubSelect ')' - { - $$ = cat3_str($1, $2, make3_str(make1_str("("), $4, make1_str(")"))); - } - | a_expr '+' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("+("), $4, make1_str(")")); - } - | a_expr '-' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("-("), $4, make1_str(")")); - } - | a_expr '/' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("/("), $4, make1_str(")")); - } - | a_expr '%' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("%("), $4, make1_str(")")); - } - | a_expr '*' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("*("), $4, make1_str(")")); - } - | a_expr '<' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("<("), $4, make1_str(")")); - } - | a_expr '>' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str(">("), $4, make1_str(")")); - } - | a_expr '=' '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("=("), $4, make1_str(")")); - } - | a_expr Op ANY '(' SubSelect ')' - { - $$ = cat3_str($1, $2, make3_str(make1_str("any ("), $5, make1_str(")"))); + $$ = cat_str(4, $1, make_str(" in ("), $4, make_str(")")); } - | a_expr '+' ANY '(' SubSelect ')' + | a_expr NOT IN '(' in_expr ')' { - $$ = make4_str($1, make1_str("+ any("), $5, make1_str(")")); + $$ = cat_str(4, $1, make_str(" not in ("), $5, make_str(")")); } - | a_expr '-' ANY '(' SubSelect ')' + | a_expr all_Op sub_type '(' SubSelect ')' { - $$ = make4_str($1, make1_str("- any("), $5, make1_str(")")); + $$ = cat_str(4, $1, $2, $3, cat_str(3, make_str("("), $5, make_str(")"))); } - | a_expr '/' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("/ any("), $5, make1_str(")")); - } - | a_expr '%' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("% any("), $5, make1_str(")")); - } - | a_expr '*' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("* any("), $5, make1_str(")")); - } - | a_expr '<' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("< any("), $5, make1_str(")")); - } - | a_expr '>' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("> any("), $5, make1_str(")")); - } - | a_expr '=' ANY '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("= any("), $5, make1_str(")")); - } - | a_expr Op ALL '(' SubSelect ')' - { - $$ = cat3_str($1, $2, make3_str(make1_str("all ("), $5, make1_str(")"))); - } - | a_expr '+' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("+ all("), $5, make1_str(")")); - } - | a_expr '-' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("- all("), $5, make1_str(")")); - } - | a_expr '/' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("/ all("), $5, make1_str(")")); - } - | a_expr '%' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("% all("), $5, make1_str(")")); - } - | a_expr '*' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("* all("), $5, make1_str(")")); - } - | a_expr '<' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("< all("), $5, make1_str(")")); - } - | a_expr '>' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("> all("), $5, make1_str(")")); - } - | a_expr '=' ALL '(' SubSelect ')' - { - $$ = make4_str($1, make1_str("=all("), $5, make1_str(")")); - } - | a_expr AND ecpg_expr - { $$ = cat3_str($1, make1_str("and"), $3); } - | a_expr OR ecpg_expr - { $$ = cat3_str($1, make1_str("or"), $3); } - | NOT ecpg_expr - { $$ = cat2_str(make1_str("not"), $2); } - | case_expr + | row_expr { $$ = $1; } | civariableonly { $$ = $1; } ; +*/ into_list : coutputvariable | into_list ',' coutputvariable; ecpgstart: SQL_START { reset_variables();} -dotext: /* empty */ { $$ = make1_str(""); } - | dotext do_anything { $$ = make2_str($1, $2); } - -vartext: var_anything { $$ = $1; } - | vartext var_anything { $$ = make2_str($1, $2); } +c_args: /* empty */ { $$ = EMPTY; } + | c_list { $$ = $1; } coutputvariable : cvariable indicator { add_variable(&argsresult, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2)); @@ -5791,7 +5844,7 @@ cinputvariable : cvariable indicator { civariableonly : cvariable { add_variable(&argsinsert, find_variable($1), &no_indicator); - $$ = make1_str("?"); + $$ = make_str("?"); } cvariable: CVARIABLE { $$ = $1; } @@ -5802,7 +5855,8 @@ indicator: /* empty */ { $$ = NULL; } | SQL_INDICATOR name { check_indicator((find_variable($2))->type); $$ = $2; } ident: IDENT { $$ = $1; } - | CSTRING { $$ = $1; } + | CSTRING { $$ = make3_str(make_str("\""), $1, make_str("\"")); }; + /* * C stuff */ @@ -5811,75 +5865,75 @@ symbol: IDENT { $$ = $1; } cpp_line: CPP_LINE { $$ = $1; } -c_line: c_anything { $$ = $1; } - | c_line c_anything - { - $$ = make2_str($1, $2); - } +c_stuff: c_anything { $$ = $1; } + | c_stuff c_anything + { + $$ = cat2_str($1, $2); + } + | c_stuff '(' c_stuff ')' + { + $$ = cat_str(4, $1, make_str("("), $3, make_str(")")); + } + +c_list: c_term { $$ = $1; } + | c_list ',' c_term { $$ = cat_str(3, $1, make_str(","), $3); } -c_thing: c_anything | ';' { $$ = make1_str(";"); } +c_term: c_stuff { $$ = $1; } + | '{' c_list '}' { $$ = cat_str(3, make_str("{"), $2, make_str("}")); } + +c_thing: c_anything { $$ = $1; } + | '(' { $$ = make_str("("); } + | ')' { $$ = make_str(")"); } + | ',' { $$ = make_str(","); } + | ';' { $$ = make_str(";"); } c_anything: IDENT { $$ = $1; } - | CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); } + | CSTRING { $$ = make3_str(make_str("\""), $1, make_str("\"")); } | Iconst { $$ = $1; } | Fconst { $$ = $1; } - | '*' { $$ = make1_str("*"); } - | '+' { $$ = make1_str("+"); } - | '-' { $$ = make1_str("-"); } - | '/' { $$ = make1_str("/"); } - | '%' { $$ = make1_str("%"); } - | S_AUTO { $$ = make1_str("auto"); } - | S_BOOL { $$ = make1_str("bool"); } - | S_CHAR { $$ = make1_str("char"); } - | S_CONST { $$ = make1_str("const"); } - | S_DOUBLE { $$ = make1_str("double"); } - | S_ENUM { $$ = make1_str("enum"); } - | S_EXTERN { $$ = make1_str("extern"); } - | S_FLOAT { $$ = make1_str("float"); } - | S_INT { $$ = make1_str("int"); } - | S_LONG { $$ = make1_str("long"); } - | S_REGISTER { $$ = make1_str("register"); } - | S_SHORT { $$ = make1_str("short"); } - | S_SIGNED { $$ = make1_str("signed"); } - | S_STATIC { $$ = make1_str("static"); } - | S_STRUCT { $$ = make1_str("struct"); } - | S_UNION { $$ = make1_str("union"); } - | S_UNSIGNED { $$ = make1_str("unsigned"); } - | S_VARCHAR { $$ = make1_str("varchar"); } + | '*' { $$ = make_str("*"); } + | '+' { $$ = make_str("+"); } + | '-' { $$ = make_str("-"); } + | '/' { $$ = make_str("/"); } + | '%' { $$ = make_str("%"); } | S_ANYTHING { $$ = make_name(); } - | '[' { $$ = make1_str("["); } - | ']' { $$ = make1_str("]"); } - | '(' { $$ = make1_str("("); } - | ')' { $$ = make1_str(")"); } - | '=' { $$ = make1_str("="); } - | ',' { $$ = make1_str(","); } - -do_anything: IDENT { $$ = $1; } - | CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\""));} - | Iconst { $$ = $1; } - | Fconst { $$ = $1; } - | ',' { $$ = make1_str(","); } - -var_anything: IDENT { $$ = $1; } - | CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); } - | Iconst { $$ = $1; } - | Fconst { $$ = $1; } - | '{' c_line '}' { $$ = make3_str(make1_str("{"), $2, make1_str("}")); } + | S_AUTO { $$ = make_str("auto"); } + | S_CONST { $$ = make_str("const"); } + | S_EXTERN { $$ = make_str("extern"); } + | S_REGISTER { $$ = make_str("register"); } + | S_STATIC { $$ = make_str("static"); } + | SQL_BOOL { $$ = make_str("bool"); } + | SQL_ENUM { $$ = make_str("enum"); } + | SQL_INT { $$ = make_str("int"); } + | SQL_LONG { $$ = make_str("long"); } + | SQL_SHORT { $$ = make_str("short"); } + | SQL_SIGNED { $$ = make_str("signed"); } + | SQL_STRUCT { $$ = make_str("struct"); } + | SQL_UNSIGNED { $$ = make_str("unsigned"); } + | CHAR { $$ = make_str("char"); } + | DOUBLE { $$ = make_str("double"); } + | FLOAT { $$ = make_str("float"); } + | UNION { $$ = make_str("union"); } + | VARCHAR { $$ = make_str("varchar"); } + | '[' { $$ = make_str("["); } + | ']' { $$ = make_str("]"); } +/* | '(' { $$ = make_str("("); } + | ')' { $$ = make_str(")"); }*/ + | '=' { $$ = make_str("="); } blockstart : '{' { braces_open++; - $$ = make1_str("{"); + $$ = make_str("{"); } blockend : '}' { remove_variables(braces_open--); - $$ = make1_str("}"); + $$ = make_str("}"); } %% void yyerror(char * error) { - fprintf(stderr, "%s:%d: %s\n", input_filename, yylineno, error); - exit(PARSE_ERROR); + mmerror(ET_ERROR, error); }