X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Finterfaces%2Fecpg%2Fpreproc%2Fpreproc.y;h=0c1a9cc984c049018334d8456f1086945153fa81;hb=44d5be0e5308e951c0c5dc522b4bcacf2bcbc476;hp=2a8aefbfe5744d72ca9bdf90240f2511c10c83e3;hpb=67ddac35db84eadce597cb32cae39ce35c8d784a;p=postgresql diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 2a8aefbfe5..b0d126e9ba 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -1,24 +1,41 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.198 2002/09/22 21:54:31 tgl Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.373 2008/10/04 21:56:55 tgl Exp $ */ /* Copyright comment */ %{ #include "postgres_fe.h" #include "extern.h" +#include + +/* Location tracking support --- simpler than bison's default */ +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do { \ + if (N) \ + (Current) = (Rhs)[1]; \ + else \ + (Current) = (Rhs)[0]; \ + } while (0) + +/* + * The %name-prefix option below will make bison call base_yylex, but we + * really want it to call filtered_base_yylex (see parser.c). + */ +#define base_yylex filtered_base_yylex /* * Variables containing simple states. */ int struct_level = 0; int braces_open; /* brace level counter */ -char errortext[128]; +int ecpg_informix_var = 0; char *connection = NULL; char *input_filename = NULL; static int QueryIsRule = 0, FoundInto = 0; static int initializer = 0; +static int pacounter = 1; +static char pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the size we need */ 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 */ @@ -27,28 +44,58 @@ struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL }; /* also store struct type so we can do a sizeof() later */ static char *ECPGstruct_sizeof = NULL; -struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, NULL, {NULL}}; +/* for forward declarations we have to store some data as well */ +static char *forward_name = NULL; + +struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, NULL, NULL, {NULL}, 0}; struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL}; -struct ECPGtype ecpg_query = {ECPGt_char_variable, 0L, NULL, {NULL}}; +struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, {NULL}, 0}; /* * Handle parsing errors and warnings */ void -mmerror(int error_code, enum errortype type, char * error) +mmerror(int error_code, enum errortype type, char * error, ...) { + va_list ap; + + /* internationalize the error message string */ + error = _(error); + + fprintf(stderr, "%s:%d: ", input_filename, yylineno); + + switch(type) + { + case ET_WARNING: + fprintf(stderr, _("WARNING: ")); + break; + case ET_ERROR: + case ET_FATAL: + fprintf(stderr, _("ERROR: ")); + break; + } + + va_start(ap, error); + vfprintf(stderr, error, ap); + va_end(ap); + + fprintf(stderr, "\n"); + switch(type) { case ET_WARNING: - fprintf(stderr, "%s:%d: WARNING: %s\n", input_filename, yylineno, error); break; case ET_ERROR: - fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error); ret_value = error_code; break; case ET_FATAL: - fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error); + if (yyin) + fclose(yyin); + if (yyout) + fclose(yyout); + if (unlink(output_filename) != 0 && *output_filename != '-') + fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename); exit(error_code); } } @@ -125,6 +172,7 @@ make3_str(char *str1, char *str2, char *str3) return(res_str); } +/* and the rest */ static char * make_name(void) { @@ -135,12 +183,201 @@ make_name(void) return(name); } +static char * +create_questionmarks(char *name, bool array) +{ + struct variable *p = find_variable(name); + int count; + char *result = EMPTY; + + /* In case we have a struct, we have to print as many "?" as there are attributes in the struct + * An array is only allowed together with an element argument + * This is essantially only used for inserts, but using a struct as input parameter is an error anywhere else + * so we don't have to worry here. */ + + if (p->type->type == ECPGt_struct || (array && p->type->type == ECPGt_array && p->type->u.element->type == ECPGt_struct)) + { + struct ECPGstruct_member *m; + + if (p->type->type == ECPGt_struct) + m = p->type->u.members; + else + m = p->type->u.element->u.members; + + for (count = 0; m != NULL; m=m->next, count++); + } + else + count = 1; + + for (; count > 0; count --) + { + sprintf(pacounter_buffer, "$%d", pacounter++); + result = cat_str(3, result, strdup(pacounter_buffer), make_str(" , ")); + } + + /* removed the trailing " ," */ + + result[strlen(result)-3] = '\0'; + return(result); +} + +static char * +adjust_informix(struct arguments *list) +{ + /* Informix accepts DECLARE with variables that are out of scope when OPEN is called. + * for instance you can declare variables in a function, and then subsequently use them + * { + * declare_vars(); + * exec sql ... which uses vars declared in the above function + * + * This breaks standard and leads to some very dangerous programming. + * Since they do, we have to work around and accept their syntax as well. + * But we will do so ONLY in Informix mode. + * We have to change the variables to our own struct and just store the pointer instead of the variable + */ + + struct arguments *ptr; + char *result = make_str(""); + + for (ptr = list; ptr != NULL; ptr = ptr->next) + { + char temp[20]; /* this should be sufficient unless you have 8 byte integers */ + char *original_var; + + /* change variable name to "ECPG_informix_get_var()" */ + original_var = ptr->variable->name; + sprintf(temp, "%d))", ecpg_informix_var); + + if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char && ptr->variable->type->type != ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1) + { + ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"), ptr->variable->type->u.element->lineno), ptr->variable->type->size), 0); + sprintf(temp, "%d, (", ecpg_informix_var++); + } + else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char || ptr->variable->type->type == ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1) + { + ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0); + sprintf(temp, "%d, (", ecpg_informix_var++); + } + else + { + ptr->variable = new_variable(cat_str(4, make_str("*("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0); + sprintf(temp, "%d, &(", ecpg_informix_var++); + } + + /* create call to "ECPG_informix_set_var(, . )" */ + result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var), make_str("), __LINE__);\n")); + + /* now the indicator if there is one */ + if (ptr->indicator->type->type != ECPGt_NO_INDICATOR) + { + /* change variable name to "ECPG_informix_get_var()" */ + original_var = ptr->indicator->name; + sprintf(temp, "%d))", ecpg_informix_var); + + /* create call to "ECPG_informix_set_var(, . )" */ + if (atoi(ptr->indicator->type->size) > 1) + { + ptr->indicator = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->indicator->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->indicator->type->type, ptr->indicator->type->size, ptr->variable->type->lineno), 0); + sprintf(temp, "%d, (", ecpg_informix_var++); + } + else + { + ptr->indicator = new_variable(cat_str(4, make_str("*("), mm_strdup(ecpg_type_name(ptr->indicator->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->indicator->type->type, ptr->indicator->type->size, ptr->variable->type->lineno), 0); + sprintf(temp, "%d, &(", ecpg_informix_var++); + } + result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var), make_str("), __LINE__);\n")); + } + } + + return result; +} + +static struct cursor * +add_additional_variables(char *name, bool insert) +{ + struct cursor *ptr; + struct arguments *p; + + for (ptr = cur; ptr != NULL; ptr=ptr->next) + { + if (strcmp(ptr->name, name) == 0) + break; + } + + if (ptr == NULL) + { + mmerror(PARSE_ERROR, ET_ERROR, "trying to access an undeclared cursor \"%s\"\n", name); + return NULL; + } + + if (insert) + { + /* add all those input variables that were given earlier + * note that we have to append here but have to keep the existing order */ + for (p = ptr->argsinsert; p; p = p->next) + add_variable_to_tail(&argsinsert, p->variable, p->indicator); + } + + /* add all those output variables that were given earlier */ + for (p = ptr->argsresult; p; p = p->next) + add_variable_to_tail(&argsresult, p->variable, p->indicator); + + return ptr; +} + +static void +add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enum, char *type_dimension, char *type_index, int initializer, int array) +{ + /* add entry to list */ + struct typedefs *ptr, *this; + + if ((type_enum == ECPGt_struct || + type_enum == ECPGt_union) && + initializer == 1) + mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in typedef command"); + else + { + for (ptr = types; ptr != NULL; ptr = ptr->next) + { + if (strcmp(name, ptr->name) == 0) + /* re-definition is a bug */ + mmerror(PARSE_ERROR, ET_ERROR, "type %s already defined", name); + } + adjust_array(type_enum, &dimension, &length, type_dimension, type_index, array, true); + + this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); + + /* initial definition */ + this->next = types; + this->name = name; + this->brace_level = braces_open; + this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); + this->type->type_enum = type_enum; + this->type->type_str = mm_strdup(name); + this->type->type_dimension = dimension; /* dimension of array */ + this->type->type_index = length; /* length of string */ + this->type->type_sizeof = ECPGstruct_sizeof; + this->struct_member_list = (type_enum == ECPGt_struct || type_enum == ECPGt_union) ? + ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL; + + if (type_enum != ECPGt_varchar && + type_enum != ECPGt_char && + type_enum != ECPGt_unsigned_char && + atoi(this->type->type_index) >= 0) + mmerror(PARSE_ERROR, ET_ERROR, "no multidimensional array support for simple data types"); + + types = this; + } +} %} +%name-prefix="base_yy" +%locations + %union { double dval; - int ival; char *str; + int ival; struct when action; struct index index; int tagname; @@ -148,23 +385,25 @@ make_name(void) enum ECPGttype type_enum; enum ECPGdtype dtype_enum; struct fetch_desc descriptor; + struct su_symbol struct_union; + struct prep prep; } /* special embedded SQL token */ %token SQL_ALLOCATE SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK - SQL_CALL SQL_CARDINALITY SQL_CONNECT SQL_CONNECTION - SQL_CONTINUE SQL_COUNT SQL_CURRENT SQL_DATA + SQL_CALL SQL_CARDINALITY SQL_CONNECT + SQL_COUNT SQL_DATA SQL_DATETIME_INTERVAL_CODE - SQL_DATETIME_INTERVAL_PRECISION SQL_DEALLOCATE - SQL_DESCRIPTOR SQL_DISCONNECT SQL_ENUM SQL_FOUND + SQL_DATETIME_INTERVAL_PRECISION SQL_DESCRIBE + SQL_DESCRIPTOR SQL_DISCONNECT SQL_FOUND SQL_FREE SQL_GET SQL_GO SQL_GOTO SQL_IDENTIFIED SQL_INDICATOR SQL_KEY_MEMBER SQL_LENGTH - SQL_LONG SQL_NAME SQL_NULLABLE SQL_OCTET_LENGTH - SQL_OPEN SQL_PREPARE SQL_RELEASE SQL_REFERENCE + SQL_LONG SQL_NULLABLE SQL_OCTET_LENGTH + SQL_OPEN SQL_OUTPUT SQL_REFERENCE SQL_RETURNED_LENGTH SQL_RETURNED_OCTET_LENGTH SQL_SCALE SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL SQL_SQLERROR SQL_SQLPRINT SQL_SQLWARNING SQL_START SQL_STOP - SQL_STRUCT SQL_UNSIGNED SQL_VALUE SQL_VAR SQL_WHENEVER + SQL_STRUCT SQL_UNSIGNED SQL_VAR SQL_WHENEVER /* C token */ %token S_ADD S_AND S_ANYTHING S_AUTO S_CONST S_DEC S_DIV @@ -177,100 +416,119 @@ make_name(void) %token TYPECAST /* ordinary key words in alphabetical order */ -%token ABORT_TRANS ABSOLUTE ACCESS ACTION ADD AFTER - AGGREGATE ALL ALTER ANALYSE ANALYZE AND ANY AS ASC ASSERTION - AT AUTHORIZATION +%token ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER + AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC + ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION - BACKWARD BEFORE BEGIN_TRANS BETWEEN BIGINT BINARY BIT BOTH - BOOLEAN BY + BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT + BOOLEAN_P BOTH BY - CACHE CALLED CASCADE CASE CAST CHAIN CHAR_P CHARACTER - CHARACTERISTICS CHECK CHECKPOINT CLOSE CLUSTER COALESCE COLLATE - COLUMN COMMENT COMMIT COMMITTED CONSTRAINT CONSTRAINTS COPY - CREATE CREATEDB CREATEUSER CROSS CURRENT_DATE CURRENT_TIME - CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE + CACHE CALLED CASCADE CASCADED CASE CAST CHAIN CHAR_P + CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE + CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT + COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS + CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB + CREATEROLE CREATEUSER CROSS CSV CTYPE CURRENT_P CURRENT_DATE CURRENT_ROLE + CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE - DATABASE DAY_P DEC DECIMAL DECLARE DEFAULT DEFERRABLE DEFERRED - DEFINER DELETE_P DELIMITERS DESC DISTINCT DO DOMAIN_P DOUBLE DROP - EACH ELSE ENCODING ENCRYPTED END_TRANS ESCAPE EXCEPT EXCLUSIVE - EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT + DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS + DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC + DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP - FALSE_P FETCH FLOAT_P FOR FORCE FOREIGN FORWARD FREEZE FROM - FULL FUNCTION + EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT EXCLUSIVE EXCLUDING + EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT - GLOBAL GRANT GROUP_P - HANDLER HAVING HOUR_P + FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD FREEZE FROM + FULL FUNCTION - ILIKE IMMEDIATE IMMUTABLE IMPLICIT IN_P INCREMENT INDEX INHERITS - INITIALLY INNER_P INOUT INPUT INSENSITIVE INSERT INSTEAD INT - INTEGER INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION - - JOIN - KEY + GLOBAL GRANT GRANTED GREATEST GROUP_P - LANCOMPILER LANGUAGE LEADING LEFT LEVEL LIKE LIMIT LISTEN - LOAD LOCAL LOCATION LOCK_P + HANDLER HAVING HEADER_P HOLD HOUR_P - MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE + IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P + INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY + INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER + INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION - NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB - NOCREATEUSER NONE NOT NOTHING NOTIFY NOTNULL NULL_P NULLIF - NUMERIC + JOIN - OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR ORDER - OUT_P OUTER_P OVERLAPS OWNER + KEY - PARTIAL PASSWORD PATH_P PENDANT POSITION PRECISION PRIMARY - PRIOR PRIVILEGES PROCEDURE PROCEDURAL + LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEAST LEFT LEVEL + LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION + LOCK_P LOGIN_P - READ REAL REFERENCES REINDEX RELATIVE RENAME REPLACE RESET - RESTRICT RETURNS REVOKE RIGHT ROLLBACK ROW RULE + MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE - SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE SERIALIZABLE - SESSION SESSION_USER SET SETOF SHARE SHOW SMALLINT SOME - STABLE START STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT - SUBSTRING SYSID + NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB + NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER + NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC - TABLE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP TO TOAST - TRAILING TRANSACTION TRIGGER TRIM TRUE_P TRUNCATE TRUSTED TYPE_P - UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL UPDATE USAGE - USER USING + OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR ORDER + OUT_P OUTER_P OVERLAPS OVERLAY OWNED OWNER - VACUUM VALID VALUES VARCHAR VARYING VERBOSE VERSION VIEW VOLATILE - WHEN WHERE WITH WITHOUT WORK - YEAR_P - ZONE + PARSER PARTIAL PASSWORD PLACING PLANS POSITION + PRECISION PRESERVE PREPARE PREPARED PRIMARY + PRIOR PRIVILEGES PROCEDURAL PROCEDURE + + QUOTE + + READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REINDEX RELATIVE_P RELEASE RENAME + REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURNING RETURNS REVOKE + RIGHT ROLE ROLLBACK ROW ROWS RULE + + SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE + SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE + SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE_P START STATEMENT + STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P + SYMMETRIC SYSID SYSTEM_P + + TABLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP TO + TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P TRUNCATE TRUSTED TYPE_P + + UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL + UPDATE USER USING + + VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING + VERBOSE VERSION_P VIEW VOLATILE + WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE + + XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE + XMLPI XMLROOT XMLSERIALIZE + + YEAR_P YES_P + + ZONE /* The grammar thinks these are keywords, but they are not in the keywords.c * list and so can never be entered directly. The filter in parser.c * creates these tokens when required. */ -%token UNIONJOIN +%token NULLS_FIRST NULLS_LAST WITH_CASCADED WITH_LOCAL WITH_CHECK -/* Special keywords, not in the query language - see the "lex" file */ -%token IDENT SCONST Op CSTRING CVARIABLE CPP_LINE IP BITCONST +/* Special token types, not actually keywords - see the "lex" file */ +%token IDENT SCONST Op CSTRING CVARIABLE CPP_LINE IP BCONST +%token XCONST DOLCONST ECONST NCONST %token ICONST PARAM %token FCONST -/* these are not real. they are here so that they get generated as #define's*/ -%token OP - /* precedence: lowest to highest */ +%nonassoc SET /* see relation_expr_opt_alias */ %left UNION EXCEPT %left INTERSECT -%left JOIN UNIONJOIN CROSS LEFT FULL RIGHT INNER_P NATURAL %left OR %left AND %right NOT %right '=' %nonassoc '<' '>' -%nonassoc LIKE ILIKE +%nonassoc LIKE ILIKE SIMILAR %nonassoc ESCAPE %nonassoc OVERLAPS %nonassoc BETWEEN %nonassoc IN_P -%left POSTFIXOP /* dummy for postfix Op rules */ -%left Op /* multi-character ops and user-defined operators */ +%left POSTFIXOP /* dummy for postfix Op rules */ +%nonassoc IDENT /* to support target_el without AS */ +%left Op OPERATOR /* multi-character ops and user-defined operators */ %nonassoc NOTNULL %nonassoc ISNULL %nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN @@ -284,120 +542,152 @@ make_name(void) %left '(' ')' %left TYPECAST %left '.' +%left JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL +/* kluge to keep xml_whitespace_option from causing shift/reduce conflicts */ +%right PRESERVE STRIP_P -%type Iconst Fconst Sconst TransactionStmt CreateStmt UserId +%type Iconst Fconst Sconst TransactionStmt CreateStmt RoleId %type CreateAsElement OptCreateAs CreateAsList CreateAsStmt -%type key_reference comment_text ConstraintDeferrabilitySpec +%type comment_text ConstraintDeferrabilitySpec TableElementList %type key_match ColLabel SpecialRuleRelation ColId columnDef -%type ColConstraint ColConstraintElem drop_type Bitconst -%type OptTableElementList OptTableElement TableConstraint -%type ConstraintElem key_actions ColQualList type_name DropSchemaStmt -%type target_list target_el update_target_list alias_clause -%type update_target_el opt_id qualified_name database_name -%type access_method attr_name index_name name func_name -%type file_name AexprConst c_expr ConstTypename var_list -%type in_expr_nodes a_expr b_expr TruncateStmt CommentStmt -%type opt_indirection expr_list extract_list extract_arg +%type ColConstraint ColConstraintElem drop_type Bconst Iresult +%type TableConstraint OptTableElementList Xconst opt_transaction +%type ConstraintElem key_actions ColQualList cluster_index_specification +%type target_list target_el alias_clause type_func_name_keyword +%type qualified_name database_name alter_using type_function_name +%type access_method attr_name index_name name func_name opt_restart_seqs +%type file_name AexprConst c_expr ConstTypename var_list +%type a_expr b_expr TruncateStmt CommentStmt OnCommitOption opt_by +%type opt_indirection expr_list extract_list extract_arg OptSeqOptList %type position_list substr_list substr_from alter_column_default -%type trim_list in_expr substr_for attrs drop_behavior -%type Typename SimpleTypename Generic Numeric opt_float opt_numeric -%type opt_decimal Character character opt_varying opt_charset -%type opt_collate opt_timezone opt_interval table_ref -%type row_expr row_descriptor row_list ConstDatetime opt_chain +%type trim_list in_expr substr_for attrs TableFuncElement +%type Typename SimpleTypename Numeric opt_float DiscardStmt +%type Character character opt_varying opt_charset enum_val_list +%type opt_timezone opt_interval table_ref fetch_direction +%type ConstDatetime AlterDomainStmt AlterSeqStmt table_func_column %type SelectStmt into_clause OptTemp ConstraintAttributeSpec %type opt_table opt_all sort_clause sortby_list ConstraintAttr -%type sortby OptUseOp qualified_name_list name_list ColId_or_Sconst -%type group_clause having_clause from_clause opt_distinct -%type join_outer where_clause relation_expr sub_type opt_arg -%type opt_column_list insert_rest InsertStmt OptimizableStmt -%type columnList DeleteStmt LockStmt UpdateStmt CursorStmt -%type NotifyStmt columnElem copy_dirn UnlistenStmt copy_null +%type sortby qualified_name_list name_list ColId_or_Sconst +%type group_clause having_clause from_clause opt_distinct opt_hold +%type join_outer where_clause relation_expr sub_type arg_class +%type opt_column_list insert_rest InsertStmt param_name +%type columnList DeleteStmt UpdateStmt DeclareCursorStmt +%type NotifyStmt columnElem UnlistenStmt TableElement fetch_count %type copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary -%type opt_with_copy FetchStmt direction fetch_how_many from_in +%type FetchStmt from_in CreateOpClassStmt returning_clause %type ClosePortalStmt DropStmt VacuumStmt AnalyzeStmt opt_verbose -%type opt_full func_arg OptWithOids opt_freeze opt_ecpg_into +%type opt_full func_arg OptWith opt_freeze alter_table_cmd %type analyze_keyword opt_name_list ExplainStmt index_params -%type index_list func_index index_elem opt_class access_method_clause +%type index_elem opt_class access_method_clause alter_table_cmds %type index_opt_unique IndexStmt func_return ConstInterval -%type func_args_list func_args opt_with def_arg +%type func_args_list func_args opt_with def_arg overlay_placing %type def_elem def_list definition DefineStmt select_with_parens %type opt_instead event RuleActionList opt_using CreateAssertStmt %type RuleActionStmtOrEmpty RuleActionMulti func_as reindex_type -%type RuleStmt opt_column opt_name oper_argtypes NumConst -%type MathOp RemoveFuncStmt aggr_argtype for_update_clause -%type RemoveAggrStmt opt_procedural select_no_parens -%type RemoveOperStmt RenameStmt all_Op opt_Trusted opt_lancompiler +%type RuleStmt opt_column oper_argtypes NumConst var_name +%type MathOp RemoveFuncStmt ECPGunreserved_con opt_database_name +%type RemoveAggrStmt opt_procedural select_no_parens CreateCastStmt +%type RemoveOperStmt RenameStmt all_Op opt_trusted opt_lancompiler %type VariableSetStmt var_value zone_value VariableShowStmt -%type VariableResetStmt AlterTableStmt from_list -%type opt_trans user_list OptUserList OptUserElem relation_name -%type CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList -%type OptSeqElem TriggerForSpec TriggerForOpt TriggerForType +%type VariableResetStmt AlterTableStmt from_list overlay_list +%type relation_name OptTableSpace LockStmt opt_lock table_func_column_list +%type CreateUserStmt AlterUserStmt CreateSeqStmt SeqOptList +%type SeqOptElem TriggerForSpec TriggerForOpt TriggerForType %type DropTrigStmt TriggerOneEvent TriggerEvents RuleActionStmt -%type TriggerActionTime CreateTrigStmt DropPLangStmt +%type TriggerActionTime CreateTrigStmt DropPLangStmt DropCastStmt %type CreatePLangStmt TriggerFuncArgs TriggerFuncArg simple_select -%type ViewStmt LoadStmt CreatedbStmt createdb_opt_item +%type ViewStmt LoadStmt CreatedbStmt createdb_opt_item ExplainableStmt %type createdb_opt_list opt_encoding OptInherit opt_equal -%type AlterUserSetStmt privilege_list privilege privilege_target -%type opt_grant_grant_option opt_revoke_grant_option -%type function_with_argtypes_list function_with_argtypes -%type DropdbStmt ClusterStmt grantee RevokeStmt Bit +%type privilege_list privilege privilege_target opt_if_exists +%type opt_grant_grant_option cursor_options DropOwnedStmt +%type transaction_mode_list_or_empty transaction_mode_list +%type function_with_argtypes_list function_with_argtypes IntConstVar +%type DropdbStmt ClusterStmt grantee RevokeStmt Bit DropOpClassStmt %type GrantStmt privileges PosAllConst constraints_set_list -%type opt_cursor ConstraintsSetStmt AllConst CreateDomainStmt +%type ConstraintsSetStmt AllConst CreateDomainStmt opt_nowait %type case_expr when_clause_list case_default case_arg when_clause -%type select_clause opt_select_limit select_limit_value +%type select_clause opt_select_limit select_limit_value opt_recheck %type ConstraintTimeSpec AlterDatabaseSetStmt DropAssertStmt %type select_offset_value ReindexStmt join_type opt_boolean -%type join_qual update_list AlterSchemaStmt joined_table -%type opt_level opt_lock lock_type OptGroupList OptGroupElem -%type OptConstrFromTable OptTempTableName StringConst -%type constraints_set_mode comment_type opt_empty_parentheses +%type join_qual joined_table opclass_item relation_expr_opt_alias +%type lock_type array_expr_list ReassignOwnedStmt for_locking_item +%type OptConstrFromTable OptTempTableName StringConst array_expr +%type constraints_set_mode comment_type opt_check_option %type CreateGroupStmt AlterGroupStmt DropGroupStmt key_delete %type opt_force key_update CreateSchemaStmt PosIntStringConst %type IntConst PosIntConst grantee_list func_type opt_or_replace -%type select_limit opt_for_update_clause CheckPointStmt +%type select_limit CheckPointStmt ECPGColId old_aggr_list %type OptSchemaName OptSchemaEltList schema_stmt opt_drop_behavior %type handler_name any_name_list any_name opt_as insert_column_list -%type columnref dotted_name function_name insert_target_el -%type insert_target_list insert_column_item DropRuleStmt -%type createfunc_opt_item set_rest var_list_or_default +%type columnref values_clause AllConstVar prep_type_clause ExecuteStmt +%type insert_column_item DropRuleStmt ctext_expr execute_param_clause +%type createfunc_opt_item set_rest %type CreateFunctionStmt createfunc_opt_list func_table -%type DropUserStmt - +%type DropUserStmt copy_from copy_opt_list copy_opt_item +%type opt_oids TableLikeClause key_action opt_definition +%type cast_context row qual_Op qual_all_Op opt_default +%type CreateConversionStmt any_operator opclass_item_list +%type iso_level type_list CharacterWithLength ConstCharacter +%type CharacterWithoutLength BitWithLength BitWithoutLength +%type ConstBit GenericType TableFuncElementList opt_analyze +%type opt_sort_clause subquery_Op transaction_mode_item %type ECPGWhenever ECPGConnect connection_target ECPGOpen -%type indicator ECPGExecute ECPGPrepare ecpg_using ecpg_into -%type storage_clause opt_initializer c_anything -%type variable_list variable c_thing c_term +%type indicator ecpg_using ecpg_into DeallocateStmt +%type storage_declaration storage_clause opt_initializer c_anything +%type variable_list variable c_thing c_term ECPGKeywords_vanames %type opt_pointer ECPGDisconnect dis_name storage_modifier -%type stmt ECPGRelease execstring server_name +%type execstring server_name ECPGVarDeclaration func_expr %type connection_object opt_server opt_port c_stuff c_stuff_item %type user_name opt_user char_variable ora_user ident opt_reference -%type quoted_ident_stringvar var_type_declarations -%type db_prefix server opt_options opt_connection_name c_list -%type ECPGSetConnection ECPGTypedef c_args ECPGKeywords -%type enum_type civar civarind ECPGCursorStmt ECPGDeallocate -%type ECPGFree ECPGDeclare ECPGVar opt_at enum_definition -%type struct_type s_struct vt_declarations variable_declarations -%type var_declaration type_declaration -%type s_union union_type ECPGSetAutocommit on_off -%type ECPGAllocateDescr ECPGDeallocateDescr symbol opt_symbol -%type ECPGGetDescriptorHeader ECPGColLabel -%type reserved_keyword unreserved_keyword -%type col_name_keyword func_name_keyword -%type ECPGTypeName variablelist - -%type ECPGGetDescriptor +%type var_type_declarations quoted_ident_stringvar ECPGKeywords_rest +%type db_prefix server connect_options opt_options opt_connection_name c_list +%type ECPGSetConnection ECPGTypedef c_args ECPGKeywords ECPGCKeywords +%type enum_type civar civarind ECPGCursorStmt PreparableStmt +%type ECPGFree ECPGDeclare ECPGVar at enum_definition opt_opt_value +%type struct_union_type s_struct_union vt_declarations execute_rest +%type var_declaration type_declaration single_vt_declaration +%type ECPGSetAutocommit on_off variable_declarations ECPGDescribe +%type ECPGAllocateDescr ECPGDeallocateDescr symbol opt_output +%type ECPGGetDescriptorHeader ECPGColLabel SetResetClause AlterUserSetStmt +%type reserved_keyword unreserved_keyword ecpg_interval opt_ecpg_using +%type col_name_keyword precision opt_scale ECPGExecuteImmediateStmt +%type ECPGTypeName using_list ECPGColLabelCommon UsingConst +%type using_descriptor into_descriptor opt_nulls_order opt_asc_desc +%type prepared_name struct_union_type_with_symbol OptConsTableSpace +%type ECPGunreserved ECPGunreserved_interval cvariable opt_bit_field +%type AlterOwnerStmt OptTableSpaceOwner CreateTableSpaceStmt +%type DropTableSpaceStmt indirection indirection_el ECPGSetDescriptorHeader +%type AlterDatabaseStmt CreateRoleStmt OptRoleList AlterRoleStmt AlterRoleSetStmt +%type DropRoleStmt add_drop opt_validator common_func_opt_item +%type opt_grant_admin_option AlterFunctionStmt alterfunc_opt_list opt_restrict +%type AlterObjectSchemaStmt alterdb_opt_list for_locking_clause opt_for_locking_clause +%type locked_rels_list opt_granted_by RevokeRoleStmt alterdb_opt_item using_clause +%type GrantRoleStmt opt_asymmetric aggr_args old_aggr_definition +%type old_aggr_elem for_locking_items TableLikeOptionList TableLikeOption +%type set_target_list set_clause_list set_clause multiple_set_clause +%type ctext_expr_list ctext_row single_set_clause set_target opt_type_modifiers +%type opclass_drop_list opclass_drop DropOpFamilyStmt opt_opfamily +%type CreateOpFamilyStmt AlterOpFamilyStmt create_as_target +%type xml_attributes xml_attribute_list document_or_content xml_whitespace_option +%type opt_xml_root_standalone xml_root_version xml_attribute_el +%type where_or_current_clause AlterTSConfigurationStmt AlterTSDictionaryStmt + +%type s_struct_union_symbol + +%type ECPGGetDescriptor ECPGSetDescriptor %type simple_type signed_type unsigned_type %type descriptor_item desc_header_item -%type type +%type var_type + +%type PrepareStmt %type action -%type opt_array_bounds opt_type_array_bounds +%type opt_array_bounds -%type Iresult %% prog: statements; @@ -405,97 +695,167 @@ statements: /*EMPTY*/ | statements statement ; -statement: ecpgstart opt_at stmt ';' { connection = NULL; } +statement: ecpgstart at stmt ';' { connection = NULL; } | ecpgstart stmt ';' + | ecpgstart ECPGVarDeclaration + { + fprintf(yyout, "%s", $2); + free($2); + output_line_number(); + } | ECPGDeclaration | c_thing { fprintf(yyout, "%s", $1); free($1); } | CPP_LINE { fprintf(yyout, "%s", $1); free($1); } | '{' { braces_open++; fputs("{", yyout); } - | '}' { remove_variables(braces_open--); fputs("}", yyout); } + | '}' { remove_typedefs(braces_open); remove_variables(braces_open--); fputs("}", yyout); } ; -opt_at: AT connection_target +at: AT connection_object { connection = $2; /* - * if we have a variable as connection - * target, remove it from the variable + * Do we have a variable as connection target? + * Remove the variable from the variable * list or else it will be used twice */ if (argsinsert != NULL) argsinsert = NULL; - }; - -stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); } - | AlterGroupStmt { output_statement($1, 0, connection); } - | AlterSchemaStmt { output_statement($1, 0, connection); } - | AlterTableStmt { output_statement($1, 0, connection); } - | AlterUserStmt { output_statement($1, 0, connection); } - | AlterUserSetStmt { output_statement($1, 0, connection); } - | ClosePortalStmt { output_statement($1, 0, connection); } - | CommentStmt { output_statement($1, 0, connection); } - | CopyStmt { output_statement($1, 0, connection); } - | CreateStmt { output_statement($1, 0, connection); } - | CreateAsStmt { output_statement($1, 0, connection); } - | CreateDomainStmt { output_statement($1, 0, connection); } - | CreateFunctionStmt { output_statement($1, 0, connection); } - | CreateSchemaStmt { output_statement($1, 0, connection); } - | CreateGroupStmt { output_statement($1, 0, connection); } - | CreateSeqStmt { output_statement($1, 0, connection); } - | CreatePLangStmt { output_statement($1, 0, connection); } - | CreateAssertStmt { output_statement($1, 0, connection); } - | CreateTrigStmt { output_statement($1, 0, connection); } - | CreateUserStmt { output_statement($1, 0, connection); } - | ClusterStmt { output_statement($1, 0, connection); } - | DefineStmt { output_statement($1, 0, connection); } - | DropStmt { output_statement($1, 0, connection); } - | DropSchemaStmt { output_statement($1, 0, connection); } - | TruncateStmt { output_statement($1, 0, connection); } - | DropGroupStmt { output_statement($1, 0, connection); } - | DropPLangStmt { output_statement($1, 0, connection); } - | DropAssertStmt { output_statement($1, 0, connection); } - | DropTrigStmt { output_statement($1, 0, connection); } - | DropRuleStmt { output_statement($1, 0, connection); } - | DropUserStmt { output_statement($1, 0, connection); } - | ExplainStmt { output_statement($1, 0, connection); } - | FetchStmt { output_statement($1, 1, connection); } - | GrantStmt { output_statement($1, 0, connection); } - | IndexStmt { output_statement($1, 0, connection); } - | ListenStmt { output_statement($1, 0, connection); } - | UnlistenStmt { output_statement($1, 0, connection); } - | LockStmt { output_statement($1, 0, connection); } - | NotifyStmt { output_statement($1, 0, connection); } - | ReindexStmt { output_statement($1, 0, connection); } - | RemoveAggrStmt { output_statement($1, 0, connection); } - | RemoveOperStmt { output_statement($1, 0, connection); } - | RemoveFuncStmt { output_statement($1, 0, connection); } - | RenameStmt { output_statement($1, 0, connection); } - | RevokeStmt { output_statement($1, 0, connection); } - | OptimizableStmt - { - if (strncmp($1, "/* " , sizeof("/* ")-1) == 0) - output_simple_statement($1); + } + ; + +stmt: AlterDatabaseStmt { output_statement($1, 0, ECPGst_normal); } + | AlterDatabaseSetStmt { output_statement($1, 0, ECPGst_normal); } + | AlterDomainStmt { output_statement($1, 0, ECPGst_normal); } + | AlterFunctionStmt { output_statement($1, 0, ECPGst_normal); } + | AlterGroupStmt { output_statement($1, 0, ECPGst_normal); } + | AlterObjectSchemaStmt { output_statement($1, 0, ECPGst_normal); } + | AlterOwnerStmt { output_statement($1, 0, ECPGst_normal); } + | AlterSeqStmt { output_statement($1, 0, ECPGst_normal); } + | AlterTableStmt { output_statement($1, 0, ECPGst_normal); } + | AlterRoleSetStmt { output_statement($1, 0, ECPGst_normal); } + | AlterRoleStmt { output_statement($1, 0, ECPGst_normal); } + | AlterTSConfigurationStmt { output_statement($1, 0, ECPGst_normal); } + | AlterTSDictionaryStmt { output_statement($1, 0, ECPGst_normal); } + | AlterUserStmt { output_statement($1, 0, ECPGst_normal); } + | AlterUserSetStmt { output_statement($1, 0, ECPGst_normal); } + | AnalyzeStmt { output_statement($1, 0, ECPGst_normal); } + | CheckPointStmt { output_statement($1, 0, ECPGst_normal); } + | ClosePortalStmt + { + if (INFORMIX_MODE) + { + /* + * Informix also has a CLOSE DATABASE command that + * essantially works like a DISCONNECT CURRENT + * as far as I know. + */ + if (pg_strcasecmp($1+strlen("close "), "database") == 0) + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for close database statement\n"); + + fprintf(yyout, "{ ECPGdisconnect(__LINE__, \"CURRENT\");"); + whenever_action(2); + free($1); + } + else + output_statement($1, 0, ECPGst_normal); + } else - output_statement($1, 1, connection); + output_statement($1, 0, ECPGst_normal); + } + | ClusterStmt { output_statement($1, 0, ECPGst_normal); } + | CommentStmt { output_statement($1, 0, ECPGst_normal); } + | ConstraintsSetStmt { output_statement($1, 0, ECPGst_normal); } + | CopyStmt { output_statement($1, 0, ECPGst_normal); } + | CreateAsStmt { output_statement($1, 0, ECPGst_normal); } + | CreateAssertStmt { output_statement($1, 0, ECPGst_normal); } + | CreateCastStmt { output_statement($1, 0, ECPGst_normal); } + | CreateConversionStmt { output_statement($1, 0, ECPGst_normal); } + | CreateDomainStmt { output_statement($1, 0, ECPGst_normal); } + | CreateFunctionStmt { output_statement($1, 0, ECPGst_normal); } + | CreateGroupStmt { output_statement($1, 0, ECPGst_normal); } + | CreatePLangStmt { output_statement($1, 0, ECPGst_normal); } + | CreateOpClassStmt { output_statement($1, 0, ECPGst_normal); } + | CreateOpFamilyStmt { output_statement($1, 0, ECPGst_normal); } + | AlterOpFamilyStmt { output_statement($1, 0, ECPGst_normal); } + | CreateRoleStmt { output_statement($1, 0, ECPGst_normal); } + | CreateSchemaStmt { output_statement($1, 0, ECPGst_normal); } + | CreateSeqStmt { output_statement($1, 0, ECPGst_normal); } + | CreateStmt { output_statement($1, 0, ECPGst_normal); } + | CreateTableSpaceStmt { output_statement($1, 0, ECPGst_normal); } + | CreateTrigStmt { output_statement($1, 0, ECPGst_normal); } + | CreateUserStmt { output_statement($1, 0, ECPGst_normal); } + | CreatedbStmt { output_statement($1, 0, ECPGst_normal); } + | DeallocateStmt + { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for deallocate statement\n"); + + output_deallocate_prepare_statement($1); } - | RuleStmt { output_statement($1, 0, connection); } + | DeclareCursorStmt { output_simple_statement($1); } + | DefineStmt { output_statement($1, 0, ECPGst_normal); } + | DeleteStmt { output_statement($1, 1, ECPGst_normal); } + | DiscardStmt { output_statement($1, 1, ECPGst_normal); } + | DropAssertStmt { output_statement($1, 0, ECPGst_normal); } + | DropCastStmt { output_statement($1, 0, ECPGst_normal); } + | DropGroupStmt { output_statement($1, 0, ECPGst_normal); } + | DropOpClassStmt { output_statement($1, 0, ECPGst_normal); } + | DropOpFamilyStmt { output_statement($1, 0, ECPGst_normal); } + | DropOwnedStmt { output_statement($1, 0, ECPGst_normal); } + | DropPLangStmt { output_statement($1, 0, ECPGst_normal); } + | DropRoleStmt { output_statement($1, 0, ECPGst_normal); } + | DropRuleStmt { output_statement($1, 0, ECPGst_normal); } + | DropStmt { output_statement($1, 0, ECPGst_normal); } + | DropTableSpaceStmt { output_statement($1, 0, ECPGst_normal); } + | DropTrigStmt { output_statement($1, 0, ECPGst_normal); } + | DropUserStmt { output_statement($1, 0, ECPGst_normal); } + | DropdbStmt { output_statement($1, 0, ECPGst_normal); } + | ExplainStmt { output_statement($1, 0, ECPGst_normal); } + | ExecuteStmt { output_statement($1, 1, ECPGst_execute); } + | FetchStmt { output_statement($1, 1, ECPGst_normal); } + | GrantStmt { output_statement($1, 0, ECPGst_normal); } + | GrantRoleStmt { output_statement($1, 0, ECPGst_normal); } + | IndexStmt { output_statement($1, 0, ECPGst_normal); } + | InsertStmt { output_statement($1, 1, ECPGst_normal); } + | ListenStmt { output_statement($1, 0, ECPGst_normal); } + | LoadStmt { output_statement($1, 0, ECPGst_normal); } + | LockStmt { output_statement($1, 0, ECPGst_normal); } + | NotifyStmt { output_statement($1, 0, ECPGst_normal); } + | PrepareStmt { + if ($1.type == NULL || strlen($1.type) == 0) /* use PQprepare without type parameters */ + output_prepare_statement($1.name, $1.stmt); + else /* use PQexec and let backend do its stuff */ + { + char *txt = cat_str(5, make_str("prepare"), $1.name, $1.type, make_str("as"), $1.stmt); + output_statement(txt, 0, ECPGst_normal); + } + } + | ReassignOwnedStmt { output_statement($1, 0, ECPGst_normal); } + | ReindexStmt { output_statement($1, 0, ECPGst_normal); } + | RemoveAggrStmt { output_statement($1, 0, ECPGst_normal); } + | RemoveOperStmt { output_statement($1, 0, ECPGst_normal); } + | RemoveFuncStmt { output_statement($1, 0, ECPGst_normal); } + | RenameStmt { output_statement($1, 0, ECPGst_normal); } + | RevokeStmt { output_statement($1, 0, ECPGst_normal); } + | RevokeRoleStmt { output_statement($1, 0, ECPGst_normal); } + | RuleStmt { output_statement($1, 0, ECPGst_normal); } + | SelectStmt { output_statement($1, 1, ECPGst_normal); } | TransactionStmt { fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1); whenever_action(2); free($1); } - | ViewStmt { output_statement($1, 0, connection); } - | LoadStmt { output_statement($1, 0, connection); } - | CreatedbStmt { output_statement($1, 0, connection); } - | DropdbStmt { output_statement($1, 0, connection); } - | VacuumStmt { output_statement($1, 0, connection); } - | AnalyzeStmt { output_statement($1, 0, connection); } - | VariableSetStmt { output_statement($1, 0, connection); } - | VariableShowStmt { output_statement($1, 0, connection); } - | VariableResetStmt { output_statement($1, 0, connection); } - | ConstraintsSetStmt { output_statement($1, 0, connection); } - | CheckPointStmt { output_statement($1, 0, connection); } + | TruncateStmt { output_statement($1, 0, ECPGst_normal); } + | UnlistenStmt { output_statement($1, 0, ECPGst_normal); } + | UpdateStmt { output_statement($1, 1, ECPGst_normal); } + | VacuumStmt { output_statement($1, 0, ECPGst_normal); } + | VariableSetStmt { output_statement($1, 0, ECPGst_normal); } + | VariableShowStmt { output_statement($1, 0, ECPGst_normal); } + | VariableResetStmt { output_statement($1, 0, ECPGst_normal); } + | ViewStmt { output_statement($1, 0, ECPGst_normal); } | ECPGAllocateDescr { fprintf(yyout,"ECPGallocate_desc(__LINE__, %s);",$1); @@ -505,9 +865,9 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); } | ECPGConnect { if (connection) - mmerror(PARSE_ERROR, ET_ERROR, "no at option for connect statement.\n"); + mmerror(PARSE_ERROR, ET_ERROR, "no at option for connect statement\n"); - fprintf(yyout, "{ ECPGconnect(__LINE__, %s, %d); ", $1, autocommit); + fprintf(yyout, "{ ECPGconnect(__LINE__, %d, %s, %d); ", compat, $1, autocommit); reset_variables(); whenever_action(2); free($1); @@ -516,18 +876,10 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); } { output_simple_statement($1); } - | ECPGDeallocate - { - if (connection) - mmerror(PARSE_ERROR, ET_ERROR, "no at option for connect statement.\n"); - - fputc('{', yyout); - fputs($1, yyout); - whenever_action(2); - free($1); - } | ECPGDeallocateDescr { + if (connection) + mmerror(PARSE_ERROR, ET_ERROR, "no at option for deallocate statement\n"); fprintf(yyout,"ECPGdeallocate_desc(__LINE__, %s);",$1); whenever_action(0); free($1); @@ -536,22 +888,35 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); } { output_simple_statement($1); } + | ECPGDescribe + { + fprintf(yyout, "{ ECPGdescribe(__LINE__, %s,", $1); + dump_variables(argsresult, 1); + fputs("ECPGt_EORT);", yyout); + fprintf(yyout, "}"); + output_line_number(); + + /* whenever_action(2); */ + free($1); + } | ECPGDisconnect { if (connection) - mmerror(PARSE_ERROR, ET_ERROR, "no at option for disconnect statement.\n"); + mmerror(PARSE_ERROR, ET_ERROR, "no at option for disconnect statement\n"); - fprintf(yyout, "{ ECPGdisconnect(__LINE__, %s);", $1); + fprintf(yyout, "{ ECPGdisconnect(__LINE__, %s);", + $1 ? $1 : "\"CURRENT\""); whenever_action(2); free($1); } - | ECPGExecute - { - output_statement($1, 0, connection); - } + | ECPGExecuteImmediateStmt { output_statement($1, 0, ECPGst_exec_immediate); } | ECPGFree { - fprintf(yyout, "{ ECPGdeallocate(__LINE__, \"%s\");", $1); + const char *con = connection ? connection : "NULL"; + if (strcmp($1, "all")) + fprintf(yyout, "{ ECPGdeallocate(__LINE__, %d, %s, \"%s\");", compat, con, $1); + else + fprintf(yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con); whenever_action(2); free($1); @@ -572,39 +937,14 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); } | ECPGOpen { struct cursor *ptr; - struct arguments *p; - - for (ptr = cur; ptr != NULL; ptr=ptr->next) - { - if (strcmp(ptr->name, $1) == 0) - break; - } - if (ptr == NULL) + if ((ptr = add_additional_variables($1, true)) != NULL) { - snprintf(errortext, sizeof(errortext), "trying to open undeclared cursor %s\n", $1); - mmerror(PARSE_ERROR, ET_ERROR, errortext); + connection = ptr->connection ? mm_strdup(ptr->connection) : NULL; + output_statement(mm_strdup(ptr->command), 0, 0); + ptr->opened = true; } - - /* merge variables given in prepare statement with those given here */ - for (p = ptr->argsinsert; p; p = p->next) - append_variable(&argsinsert, p->variable, p->indicator); - - for (p = ptr->argsresult; p; p = p->next) - add_variable(&argsresult, p->variable, p->indicator); - - output_statement(mm_strdup(ptr->command), 0, ptr->connection ? mm_strdup(ptr->connection) : NULL); - } - | ECPGPrepare - { - if (connection) - mmerror(PARSE_ERROR, ET_ERROR, "no at option for set connection statement.\n"); - - fprintf(yyout, "{ ECPGprepare(__LINE__, %s);", $1); - whenever_action(2); - free($1); } - | ECPGRelease { /* output already done */ } | ECPGSetAutocommit { fprintf(yyout, "{ ECPGsetcommit(__LINE__, \"%s\", %s);", $1, connection ? connection : "NULL"); @@ -614,16 +954,29 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); } | ECPGSetConnection { if (connection) - mmerror(PARSE_ERROR, ET_ERROR, "no at option for set connection statement.\n"); + mmerror(PARSE_ERROR, ET_ERROR, "no at option for set connection statement\n"); fprintf(yyout, "{ ECPGsetconn(__LINE__, %s);", $1); whenever_action(2); free($1); } + | ECPGSetDescriptor + { + lookup_descriptor($1.name, connection); + output_set_descr($1.name, $1.str); + free($1.name); + free($1.str); + } + | ECPGSetDescriptorHeader + { + lookup_descriptor($1, connection); + output_set_descr_header($1); + free($1); + } | ECPGTypedef { if (connection) - mmerror(PARSE_ERROR, ET_ERROR, "no at option for typedef statement.\n"); + mmerror(PARSE_ERROR, ET_ERROR, "no at option for typedef statement\n"); fprintf(yyout, "%s", $1); free($1); @@ -632,14 +985,14 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); } | ECPGVar { if (connection) - mmerror(PARSE_ERROR, ET_ERROR, "no at option for var statement.\n"); + mmerror(PARSE_ERROR, ET_ERROR, "no at option for var statement\n"); output_simple_statement($1); } | ECPGWhenever { if (connection) - mmerror(PARSE_ERROR, ET_ERROR, "no at option for whenever statement.\n"); + mmerror(PARSE_ERROR, ET_ERROR, "no at option for whenever statement\n"); output_simple_statement($1); } @@ -652,150 +1005,166 @@ stmt: AlterDatabaseSetStmt { output_statement($1, 0, connection); } /***************************************************************************** * - * Create a new Postgres DBMS user + * Create a new Postgres DBMS role * * *****************************************************************************/ -CreateUserStmt: CREATE USER UserId OptUserList - { $$ = cat_str(3, make_str("create user"), $3, $4); } - | CREATE USER UserId WITH OptUserList - { $$ = cat_str(4, make_str("create user"), $3, make_str("with"), $5); } +CreateRoleStmt: CREATE ROLE RoleId opt_with OptRoleList + { $$ = cat_str(4, make_str("create role"), $3, make_str("with"), $5); } ; -/***************************************************************************** - * - * Alter a postgresql DBMS user - * - * - *****************************************************************************/ - -AlterUserStmt: ALTER USER UserId OptUserList - { $$ = cat_str(3, make_str("alter user"), $3, $4); } - | ALTER USER UserId WITH OptUserList - { $$ = cat_str(4, make_str("alter user"), $3, make_str("with"), $5); } +opt_with: WITH { $$ = make_str("with"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -AlterUserSetStmt: ALTER USER UserId SET set_rest - { $$ = cat_str(4, make_str("alter user"), $3, make_str("set"), $5); } - | ALTER USER UserId VariableResetStmt - { $$ = cat_str(3, make_str("alter user"), $3, $4); } - ; +/* + * Options for CREATE ROLE and ALTER ROLE (also used by CREATE/ALTER USER + * for backwards compatibility). Note: the only option required by SQL99 + * is "WITH ADMIN name". + */ +OptRoleList: + PASSWORD Sconst { $$ = cat2_str(make_str("password"), $2); } + | PASSWORD NULL_P { $$ = make_str("password null"); } + | ENCRYPTED PASSWORD Sconst { $$ = cat2_str(make_str("encrypted password"), $3); } + | UNENCRYPTED PASSWORD Sconst { $$ = cat2_str(make_str("unencrypted password"), $3); } + | SUPERUSER_P { $$ = make_str("superuser"); } + | NOSUPERUSER { $$ = make_str("nosuperuser"); } + | INHERIT { $$ = make_str("inherit"); } + | NOINHERIT { $$ = make_str("noinherit"); } + | CREATEDB { $$ = make_str("createdb"); } + | NOCREATEDB { $$ = make_str("nocreatedb"); } + | CREATEROLE { $$ = make_str("createrole"); } + | NOCREATEROLE { $$ = make_str("nocreaterole"); } + | LOGIN_P { $$ = make_str("login"); } + | NOLOGIN_P { $$ = make_str("nologin"); } + | CONNECTION LIMIT IntConst { $$ = cat2_str(make_str("connection limit"), $3); } + | VALID UNTIL Sconst { $$ = cat2_str(make_str("valid until"), $3); } + | USER name_list { $$ = cat2_str(make_str("user"), $2); } + | SYSID PosIntConst { $$ = cat2_str(make_str("sysid"), $2); } + | ADMIN name_list { $$ = cat2_str(make_str("admin"), $2); } + | ROLE name_list { $$ = cat2_str(make_str("role"), $2); } + | IN_P ROLE name_list { $$ = cat2_str(make_str("in role"), $3); } + | IN_P GROUP_P name_list { $$ = cat2_str(make_str("in group"), $3); } + ; /***************************************************************************** * - * Drop a postgresql DBMS user - * + * Create a new Postgres DBMS user (role with implied login ability) * *****************************************************************************/ -DropUserStmt: DROP USER user_list - { $$ = cat2_str(make_str("drop user"), $3);} + +CreateUserStmt: + CREATE USER RoleId opt_with OptRoleList + {$$ = cat_str(4, make_str("create user"), $3, $4, $5); } + ; + + /***************************************************************************** + * + * Alter a postgresql DBMS role + * + * + *****************************************************************************/ + + AlterRoleStmt: ALTER ROLE RoleId opt_with OptRoleList + { $$ = cat_str(4, make_str("alter role"), $3, $4, $5); } ; -/* - * Options for CREATE USER and ALTER USER - */ -OptUserList: OptUserList OptUserElem { $$ = cat2_str($1, $2); } - | /* EMPTY */ { $$ = EMPTY; } - ; - -OptUserElem: PASSWORD Sconst - { $$ = cat2_str(make_str("password"), $2); } - | SYSID Iconst - { $$ = cat2_str(make_str("sysid"), $2); } - | CREATEDB - { $$ = make_str("createdb"); } - | NOCREATEDB - { $$ = make_str("nocreatedb"); } - | CREATEUSER - { $$ = make_str("createuser"); } - | NOCREATEUSER - { $$ = make_str("nocreateuser"); } - | IN_P GROUP_P user_list - { $$ = cat2_str(make_str("in group"), $3); } - | VALID UNTIL Sconst - { $$ = cat2_str(make_str("valid until"), $3); } - ; - -user_list: user_list ',' UserId - { $$ = cat_str(3, $1, make_str(","), $3); } - | UserId - { $$ = $1; } + AlterRoleSetStmt: ALTER ROLE RoleId SetResetClause + { $$ = cat_str(3, make_str("alter role"), $3, $4); } ; -/***************************************************************************** - * - * Create a postgresql group - * - * - ****************************************************************************/ -CreateGroupStmt: CREATE GROUP_P UserId OptGroupList - { $$ = cat_str(3, make_str("create group"), $3, $4); } - | CREATE GROUP_P UserId WITH OptGroupList - { $$ = cat_str(4, make_str("create group"), $3, make_str("with"), $5); } + /***************************************************************************** + * + * Alter a postgresql DBMS user + * + *****************************************************************************/ + + AlterUserStmt: ALTER USER RoleId opt_with OptRoleList + { $$ = cat_str(4, make_str("alter user"), $3, $4, $5); }; + + AlterUserSetStmt: ALTER USER RoleId SetResetClause + { $$ = cat_str(3, make_str("alter user"), $3, $4); } ; -/* - * Options for CREATE GROUP - */ -OptGroupList: OptGroupList OptGroupElem { $$ = cat2_str($1, $2); } - | /* EMPTY */ { $$ = EMPTY; } + /***************************************************************************** + * + * Drop a postgresql DBMS role + * + * + *****************************************************************************/ + DropRoleStmt: DROP ROLE name_list + { $$ = cat2_str(make_str("drop role"), $3);} + | DROP ROLE IF_P EXISTS name_list + { $$ = cat2_str(make_str("drop role if exists"), $5);} + ; + + /***************************************************************************** + * + * Drop a postgresql DBMS user + * + * + *****************************************************************************/ + DropUserStmt: DROP USER name_list + { $$ = cat2_str(make_str("drop user"), $3);} + | DROP USER IF_P EXISTS name_list + { $$ = cat2_str(make_str("drop user if exists"), $5);} + ; -OptGroupElem: USER user_list - { $$ = cat2_str(make_str("user"), $2); } - | SYSID Iconst - { $$ = cat2_str(make_str("sysid"), $2); } + /***************************************************************************** + * + * Create a postgresql group + * + * + ****************************************************************************/ + CreateGroupStmt: CREATE GROUP_P RoleId opt_with OptRoleList + { $$ = cat_str(4, make_str("create group"), $3, $4, $5); } ; + /***************************************************************************** + * + * Alter a postgresql group + * + * + *****************************************************************************/ + AlterGroupStmt: ALTER GROUP_P RoleId add_drop USER name_list + { $$ = cat_str(5, make_str("alter group"), $3, $4, make_str("user"), $6); } + ; -/***************************************************************************** - * - * Alter a postgresql group - * - * - *****************************************************************************/ -AlterGroupStmt: ALTER GROUP_P UserId ADD USER user_list - { $$ = cat_str(4, make_str("alter group"), $3, make_str("add user"), $6); } - | ALTER GROUP_P UserId DROP USER user_list - { $$ = cat_str(4, make_str("alter group"), $3, make_str("drop user"), $6); } + add_drop: ADD_P { $$ = make_str("add"); } + | DROP { $$ = make_str("drop"); } ; -/***************************************************************************** - * - * Drop a postgresql group - * - * - *****************************************************************************/ -DropGroupStmt: DROP GROUP_P UserId + /***************************************************************************** + * + * Drop a postgresql group + * + * + *****************************************************************************/ + DropGroupStmt: DROP GROUP_P name_list { $$ = cat2_str(make_str("drop group"), $3); } + | DROP GROUP_P IF_P EXISTS name_list + { $$ = cat2_str(make_str("drop group if exists"), $5); } ; -/***************************************************************************** - * - * Manipulate a schema - * - * - *****************************************************************************/ + /***************************************************************************** + * + * Manipulate a schema + * + * + *****************************************************************************/ -CreateSchemaStmt: CREATE SCHEMA UserId OptSchemaName AUTHORIZATION UserId OptSchemaEltList - { $$ = cat_str(6, make_str("create scheme"), $3, $4, make_str("authorization"), $6, $7); } + CreateSchemaStmt: CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList + { $$ = cat_str(5, make_str("create schema"), $3, make_str("authorization"), $5, $6); } | CREATE SCHEMA ColId OptSchemaEltList - { $$ = cat_str(3, make_str("create scheme"), $3, $4); } + { $$ = cat_str(3, make_str("create schema"), $3, $4); } ; -AlterSchemaStmt: ALTER SCHEMA ColId - { $$ = cat2_str(make_str("alter scheme"), $3); } - ; - -DropSchemaStmt: DROP SCHEMA ColId - { $$ = cat2_str(make_str("drop scheme"), $3); } + OptSchemaName: ColId { $$ = $1; } + | /* EMPTY */ { $$ = EMPTY; } ; -OptSchemaName: ColId { $$ = $1; } - | /* EMPTY */ { $$ = EMPTY; } - ; - OptSchemaEltList: OptSchemaEltList schema_stmt { $$ = cat2_str($1, $2); } | /* EMPTY */ { $$ = EMPTY; } ; @@ -805,9 +1174,12 @@ OptSchemaEltList: OptSchemaEltList schema_stmt { $$ = cat2_str($1, $2); * statement (in addition to by themselves). */ schema_stmt: CreateStmt { $$ = $1; } - | GrantStmt { $$ = $1; } - | ViewStmt { $$ = $1; } - ; + | IndexStmt { $$ = $1; } + | CreateSeqStmt { $$ = $1; } + | CreateTrigStmt { $$ = $1; } + | GrantStmt { $$ = $1; } + | ViewStmt { $$ = $1; } + ; @@ -827,44 +1199,65 @@ VariableSetStmt: SET set_rest { $$ = cat2_str(make_str("set session"), $3 ); } ; -set_rest: ColId TO var_list_or_default +set_rest: /* Generic SET syntaxes: */ + var_name TO var_list { $$ = cat_str(3, $1, make_str("to"), $3); } - | ColId "=" var_list_or_default - { $$ = cat_str(3, $1, make_str("="), $3); } + | var_name "=" var_list + { $$ = cat_str(3, $1, make_str("="), $3); } + | var_name TO DEFAULT + { $$ = cat2_str($1, make_str("to default")); } + | var_name "=" DEFAULT + { $$ = cat2_str($1, make_str("= default")); } + | var_name FROM CURRENT_P + { $$ = cat2_str($1, make_str("from current")); } + /* Special syntaxes mandated by SQL standard: */ | TIME ZONE zone_value { $$ = cat2_str(make_str("time zone"), $3); } - | TRANSACTION ISOLATION LEVEL opt_level - { $$ = cat2_str(make_str("transaction isolation level"), $4); } - | SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL opt_level - { $$ = cat2_str(make_str("session characteristics as transaction isolation level"), $7); } + | TRANSACTION transaction_mode_list + { $$ = cat2_str(make_str("transaction"), $2); } + | SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list + { $$ = cat2_str(make_str("session characteristics as transaction"), $5); } | NAMES opt_encoding { $$ = cat2_str(make_str("names"), $2); } + | ROLE ColId_or_Sconst + { $$ = cat2_str(make_str("role"), $2); } | SESSION AUTHORIZATION ColId_or_Sconst { $$ = cat2_str(make_str("session authorization"), $3); } - | SESSION AUTHORIZATION DEFAULT + | SESSION AUTHORIZATION DEFAULT { $$ = make_str("session authorization default"); } + | XML_P OPTION document_or_content + { $$ = cat2_str(make_str("xml option"), $3); } ; -var_list_or_default: var_list - { $$ = $1; } - | DEFAULT - { $$ = make_str("default"); } +var_name: ECPGColId { $$ = $1; } + | var_name '.' ColId { $$ = cat_str(3, $1, make_str("."), $3); } ; + var_list: var_value { $$ = $1; } | var_list ',' var_value { $$ = cat_str(3, $1, make_str(","), $3); } ; - -opt_level: READ COMMITTED { $$ = make_str("read committed"); } - | SERIALIZABLE { $$ = make_str("serializable"); } - ; +iso_level: READ UNCOMMITTED { $$ = make_str("read uncommitted"); } + | READ COMMITTED { $$ = make_str("read committed"); } + | REPEATABLE READ { $$ = make_str("repeatable read"); } + | SERIALIZABLE { $$ = make_str("serializable"); } + ; var_value: opt_boolean { $$ = $1; } - | AllConst { $$ = $1; } - | ColId { $$ = $1; } + | AllConst { /* we have to check for a variable here because it has to be + replaced with its value on the client side */ + if ($1[1] == '$') + { + $$ = make_str("$0"); + free($1); + } + else + $$ = $1; + } + | ColId { $$ = $1; } ; opt_boolean: TRUE_P { $$ = make_str("true"); } @@ -881,14 +1274,14 @@ opt_boolean: TRUE_P { $$ = make_str("true"); } * so use IDENT and reject anything which is a reserved word. */ zone_value: AllConst { $$ = $1; } - | IDENT { $$ = $1; } + | ident { $$ = $1; } | ConstInterval StringConst opt_interval { $$ = cat_str(3, $1, $2, $3); } | ConstInterval '(' PosIntConst ')' StringConst opt_interval { $$ = cat_str(6, $1, make_str("("), $3, make_str(")"), $5, $6); } - | DEFAULT + | DEFAULT { $$ = make_str("default"); } - | LOCAL + | LOCAL { $$ = make_str("local"); } ; @@ -901,19 +1294,22 @@ ColId_or_Sconst: ColId { $$ = $1; } | StringConst { $$ = $1; } ; -VariableShowStmt: SHOW ColId +VariableShowStmt: SHOW var_name ecpg_into { $$ = cat2_str(make_str("show"), $2); } - | SHOW TIME ZONE + | SHOW TIME ZONE ecpg_into { $$ = make_str("show time zone"); } - | SHOW TRANSACTION ISOLATION LEVEL + | SHOW TRANSACTION ISOLATION LEVEL ecpg_into { $$ = make_str("show transaction isolation level"); } - | SHOW SESSION AUTHORIZATION + | SHOW SESSION AUTHORIZATION ecpg_into { $$ = make_str("show session authorization"); } | SHOW ALL - { $$ = make_str("show all"); } + { + mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL not implemented"); + $$ = EMPTY; + } ; -VariableResetStmt: RESET ColId +VariableResetStmt: RESET var_name { $$ = cat2_str(make_str("reset"), $2); } | RESET TIME ZONE { $$ = make_str("reset time zone"); } @@ -925,13 +1321,19 @@ VariableResetStmt: RESET ColId { $$ = make_str("reset all"); } ; +/* SetResetClause allows SET or RESET without LOCAL */ +SetResetClause: + SET set_rest { $$ = cat2_str(make_str("set"), $2); } + | VariableResetStmt { $$ = $1; } + ; + 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"); } - | name_list + | qualified_name_list { $$ = $1; } ; @@ -945,47 +1347,127 @@ constraints_set_mode: DEFERRED { $$ = make_str("deferred"); } CheckPointStmt: CHECKPOINT { $$= make_str("checkpoint"); } ; +DiscardStmt: + DISCARD ALL { $$ = make_str("discard all"); } + | DISCARD TEMP { $$ = make_str("discard temp"); } + | DISCARD TEMPORARY { $$ = make_str("discard temporary"); } + | DISCARD PLANS { $$ = make_str("discard plans"); } + ; /***************************************************************************** * - * ALTER TABLE variations + * ALTER [ TABLE | INDEX | SEQUENCE | VIEW ] variations * *****************************************************************************/ AlterTableStmt: -/* ALTER TABLE ADD [COLUMN] */ - ALTER TABLE relation_expr ADD opt_column columnDef - { $$ = cat_str(5, make_str("alter table"), $3, make_str("add"), $5, $6); } -/* ALTER TABLE ALTER [COLUMN] {SET DEFAULT |DROP DEFAULT} */ - | ALTER TABLE relation_expr ALTER opt_column ColId alter_column_default - { $$ = cat_str(6, make_str("alter table"), $3, make_str("alter"), $5, $6, $7); } -/* ALTER TABLE ALTER [COLUMN] DROP NOT NULL */ - | ALTER TABLE relation_expr ALTER opt_column ColId DROP NOT NULL_P - { $$ = cat_str(6, make_str("alter table"), $3, make_str("alter"), $5, $6, make_str("drop not null")); } -/* ALTER TABLE ALTER [COLUMN] SET NOT NULL */ - | ALTER TABLE relation_expr ALTER opt_column ColId SET NOT NULL_P - { $$ = cat_str(6, make_str("alter table"), $3, make_str("alter"), $5, $6, make_str("set not null")); } -/* ALTER TABLE ALTER [COLUMN] SET STATISTICS */ - | ALTER TABLE relation_expr ALTER opt_column ColId SET STATISTICS Iconst - { $$ = cat_str(7, make_str("alter table"), $3, make_str("alter"), $5, $6, make_str("set statistics"), $9); } -/* ALTER TABLE ALTER [COLUMN] SET STORAGE */ - | ALTER TABLE relation_expr ALTER opt_column ColId SET STORAGE ColId - { $$ = cat_str(7, make_str("alter table"), $3, make_str("alter"), $5, $6, make_str("set storage"), $9); } -/* ALTER TABLE DROP [COLUMN] {RESTRICT|CASCADE} */ - | ALTER TABLE relation_expr DROP opt_column ColId drop_behavior - { $$ = cat_str(6, make_str("alter table"), $3, make_str("drop"), $5, $6, $7); } -/* ALTER TABLE ADD CONSTRAINT ... */ - | ALTER TABLE relation_expr ADD TableConstraint - { $$ = cat_str(4, make_str("alter table"), $3, make_str("add"), $5); } -/* ALTER TABLE DROP CONSTRAINT ... */ - | ALTER TABLE relation_expr DROP CONSTRAINT name drop_behavior - { $$ = cat_str(5, make_str("alter table"), $3, make_str("drop constraint"), $6, $7); } - /* ALTER TABLE CREATE TOAST TABLE */ - | ALTER TABLE qualified_name CREATE TOAST TABLE - { $$ = cat_str(3, make_str("alter table"), $3, make_str("create toast table")); } -/* ALTER TABLE OWNER TO UserId */ - | ALTER TABLE qualified_name OWNER TO UserId - { $$ = cat_str(4, make_str("alter table"), $3, make_str("owner to"), $6); } + ALTER TABLE relation_expr alter_table_cmds + { $$ = cat_str(3, make_str("alter table"), $3, $4); } + | ALTER INDEX relation_expr alter_table_cmds + { $$ = cat_str(3, make_str("alter index"), $3, $4); } + | ALTER SEQUENCE relation_expr alter_table_cmds + { $$ = cat_str(3, make_str("alter sequence"), $3, $4); } + | ALTER VIEW relation_expr alter_table_cmds + { $$ = cat_str(3, make_str("alter view"), $3, $4); } + ; + +alter_table_cmds: + alter_table_cmd { $$ = $1; } + | alter_table_cmds ',' alter_table_cmd { $$ = cat_str(3, $1, make_str(","), $3); } + ; + +alter_table_cmd: +/* ALTER TABLE ADD [COLUMN] */ + ADD_P opt_column columnDef + { $$ = cat_str(3, make_str("add"), $2, $3); } +/* ALTER TABLE ALTER [COLUMN] {SET DEFAULT |DROP DEFAULT} */ + | ALTER opt_column ColId alter_column_default + { $$ = cat_str(4, make_str("alter"), $2, $3, $4); } +/* ALTER TABLE ALTER [COLUMN] DROP NOT NULL */ + | ALTER opt_column ColId DROP NOT NULL_P + { $$ = cat_str(4, make_str("alter"), $2, $3, make_str("drop not null")); } +/* ALTER TABLE ALTER [COLUMN] SET NOT NULL */ + | ALTER opt_column ColId SET NOT NULL_P + { $$ = cat_str(4, make_str("alter"), $2, $3, make_str("set not null")); } +/* ALTER TABLE ALTER [COLUMN] SET STATISTICS */ + | ALTER opt_column ColId SET STATISTICS PosIntConst + { $$ = cat_str(5, make_str("alter"), $2, $3, make_str("set statistics"), $6); } +/* ALTER TABLE ALTER [COLUMN] SET STORAGE */ + | ALTER opt_column ColId SET STORAGE ColId + { $$ = cat_str(5, make_str("alter"), $2, $3, make_str("set storage"), $6); } +/* ALTER TABLE DROP [COLUMN] {RESTRICT|CASCADE} */ + | DROP opt_column ColId opt_drop_behavior + { $$ = cat_str(4, make_str("drop"), $2, $3, $4); } +/* ALTER TABLE ALTER [COLUMN] TYPE [ USING ] */ + | ALTER opt_column ColId TYPE_P Typename alter_using + { $$ = cat_str(6, make_str("alter"), $2, $3, make_str("type"), $5, $6); } +/* ALTER TABLE ADD CONSTRAINT ... */ + | ADD_P TableConstraint + { $$ = cat_str(2, make_str("add"), $2); } +/* ALTER TABLE DROP CONSTRAINT ... */ + | DROP CONSTRAINT name opt_drop_behavior + { $$ = cat_str(3, make_str("drop constraint"), $3, $4); } +/* ALTER TABLE SET WITHOUT OIDS */ + | SET WITHOUT OIDS + { $$ = make_str("set without oids"); } +/* ALTER TABLE CLUSTER ON */ + | CLUSTER ON name + { $$ = cat_str(2, make_str("cluster on"), $3); } +/* ALTER TABLE SET WITHOUT CLUSTER */ + | SET WITHOUT CLUSTER + { $$ = make_str("set without cluster"); } +/* ALTER TABLE ENABLE TRIGGER */ + | ENABLE_P TRIGGER name + { $$ = cat2_str(make_str("enable trigger"), $3); } +/* ALTER TABLE ENABLE ALWAYS TRIGGER */ + | ENABLE_P ALWAYS TRIGGER name + { $$ = cat2_str(make_str("enable always trigger"), $4); } +/* ALTER TABLE ENABLE REPLICA TRIGGER */ + | ENABLE_P REPLICA TRIGGER name + { $$ = cat2_str(make_str("enable replica trigger"), $4); } +/* ALTER TABLE ENABLE TRIGGER ALL */ + | ENABLE_P TRIGGER ALL + { $$ = make_str("enable trigger all"); } +/* ALTER TABLE ENABLE TRIGGER USER */ + | ENABLE_P TRIGGER USER + { $$ = make_str("enable trigger user"); } +/* ALTER TABLE DISABLE TRIGGER */ + | DISABLE_P TRIGGER name + { $$ = cat2_str(make_str("disable trigger"), $3); } +/* ALTER TABLE DISABLE TRIGGER ALL */ + | DISABLE_P TRIGGER ALL + { $$ = make_str("disable trigger all"); } +/* ALTER TABLE DISABLE TRIGGER USER */ + | DISABLE_P TRIGGER USER + { $$ = make_str("disable trigger user"); } +/* ALTER TABLE ENABLE RULE */ + | ENABLE_P RULE name + { $$ = cat2_str(make_str("enable rule"), $3); } +/* ALTER TABLE ENABLE ALWAYS RULE */ + | ENABLE_P ALWAYS RULE name + { $$ = cat2_str(make_str("enable always rule"), $4); } +/* ALTER TABLE ENABLE REPLICA RULE */ + | ENABLE_P REPLICA RULE name + { $$ = cat2_str(make_str("enable replica rule"), $4); } +/* ALTER TABLE DISABLE RULE */ + | DISABLE_P RULE name + { $$ = cat2_str(make_str("disable rule"), $3); } +/* ALTER TABLE ALTER INHERITS ADD */ + | INHERIT qualified_name + { $$ = cat2_str(make_str("inherit"), $2); } +/* ALTER TABLE NO INHERITS */ + | NO INHERIT qualified_name + { $$ = cat2_str(make_str("no inherit"), $3); } + /* ALTER OWNER TO RoleId */ + | OWNER TO RoleId + { $$ = cat2_str(make_str("owner to"), $3); } + /* ALTER SET TABLESPACE */ + | SET TABLESPACE name + { $$ = cat2_str(make_str("set tablespace"), $3); } + | SET definition + { $$ = cat2_str(make_str("set"), $2); } + | RESET definition + { $$ = cat2_str(make_str("reset"), $2); } ; alter_column_default: @@ -993,63 +1475,90 @@ alter_column_default: | DROP DEFAULT { $$ = make_str("drop default"); } ; -drop_behavior: CASCADE { $$ = make_str("cascade"); } +opt_drop_behavior: CASCADE { $$ = make_str("cascade"); } | RESTRICT { $$ = make_str("restrict"); } - ; - -opt_drop_behavior: CASCADE { $$ = make_str("cascade"); } - | RESTRICT { $$ = make_str("restrict"); } | /* EMPTY */ { $$ = EMPTY; } ; - -/***************************************************************************** - * - * QUERY : - * close - * - *****************************************************************************/ - -ClosePortalStmt: CLOSE opt_id { $$ = cat2_str(make_str("close"), $2); } - ; -opt_id: ColId { $$ = $1; } - | /*EMPTY*/ { $$ = NULL; } +alter_using: USING a_expr { $$ = cat2_str(make_str("using"), $2); } + | /* EMPTY */ { $$ = EMPTY; } ; /***************************************************************************** * * QUERY : - * COPY [BINARY] FROM/TO - * [USING DELIMITERS ] + * close * *****************************************************************************/ -CopyStmt: COPY opt_binary qualified_name opt_with_copy copy_dirn copy_file_name copy_delimiter copy_null - { $$ = cat_str(8, make_str("copy"), $2, $3, $4, $5, $6, $7, $8); } +ClosePortalStmt: CLOSE name + { $$ = cat2_str(make_str("close"), $2); } + | CLOSE ALL + { $$ = make_str("close all"); } + ; + +CopyStmt: COPY opt_binary qualified_name opt_oids copy_from + copy_file_name copy_delimiter opt_with copy_opt_list + { + if (strcmp($5, "to") == 0 && strcmp($6, "stdin") == 0) + mmerror(PARSE_ERROR, ET_ERROR, "copy to stdin not possible\n"); + else if (strcmp($5, "from") == 0 && strcmp($6, "stdout") == 0) + mmerror(PARSE_ERROR, ET_ERROR, "copy from stdout not possible\n"); + else if (strcmp($5, "from") == 0 && strcmp($6, "stdin") == 0) + mmerror(PARSE_ERROR, ET_WARNING, "copy from stdin not implemented\n"); + + $$ = cat_str(9, make_str("copy"), $2, $3, $4, $5, $6, $7, $8, $9); + } + | COPY select_with_parens TO copy_file_name opt_with copy_opt_list + { + if (strcmp($4, "stdin") == 0) + mmerror(PARSE_ERROR, ET_ERROR, "copy to stdin is not possible\n"); + + $$ = cat_str(6, make_str("copy"), $2, make_str("to"), $4, $5, $6); + } ; -copy_dirn: TO { $$ = make_str("to"); } +copy_from: TO { $$ = make_str("to"); } | FROM { $$ = make_str("from"); } ; -/* - * copy_file_name NULL indicates stdio is used. Whether stdin or stdout is - * used depends on the direction. (It really doesn't make sense to copy from - * stdout. We silently correct the "typo". - AY 9/94 - */ -copy_file_name: StringConst { $$ = $1; } +copy_file_name: StringConst { $$ = $1; } | STDIN { $$ = make_str("stdin"); } | STDOUT { $$ = make_str("stdout"); } ; -opt_binary: BINARY { $$ = make_str("binary"); } - | /*EMPTY*/ { $$ = EMPTY; } +copy_opt_list: copy_opt_list copy_opt_item { $$ = cat2_str($1, $2); } + | /* EMPTY */ { $$ = EMPTY; } ; -opt_with_copy: WITH OIDS { $$ = make_str("with oids"); } - | /*EMPTY*/ { $$ = EMPTY; } +copy_opt_item: BINARY { $$ = make_str("binary"); } + | OIDS { $$ = make_str("oids"); } + | DELIMITER opt_as StringConst + { $$ = cat_str(3, make_str("delimiter"), $2, $3); } + | NULL_P opt_as StringConst + { $$ = cat_str(3, make_str("null"), $2, $3); } + | CSV { $$ = make_str("csv"); } + | HEADER_P { $$ = make_str("header"); } + | QUOTE opt_as Sconst + { $$ = cat_str(3, make_str("quote"), $2, $3); } + | ESCAPE opt_as Sconst + { $$ = cat_str(3, make_str("escape"), $2, $3); } + | FORCE QUOTE columnList + { $$ = cat2_str(make_str("force quote"), $3); } + | FORCE NOT NULL_P columnList + { $$ = cat2_str(make_str("force not null"), $4); } + ; +opt_binary: BINARY { $$ = make_str("binary"); } + | /* EMPTY */ { $$ = EMPTY; } + ; + +opt_oids: WITH OIDS { $$ = make_str("with oids"); } + | /* EMPTY */ { $$ = EMPTY; } + ; + + /* * the default copy delimiter is tab but the user can configure it */ @@ -1063,22 +1572,19 @@ opt_using: USING { $$ = make_str("using"); } | /* EMPTY */ { $$ = EMPTY; } ; -copy_null: WITH NULL_P AS StringConst - { $$ = cat2_str(make_str("with null as"), $4); } - | /* EMPTY */ - { $$ = EMPTY; } - ; - /***************************************************************************** * * QUERY : - * CREATE relname + * CREATE TABLE relname * *****************************************************************************/ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' - OptInherit OptWithOids - { $$ = cat_str(9, make_str("create"), $2, make_str("table"), $4, make_str("("), $6, make_str(")"), $8, $9); } + OptInherit OptWith OnCommitOption OptTableSpace + { $$ = cat_str(11, make_str("create"), $2, make_str("table"), $4, make_str("("), $6, make_str(")"), $8, $9, $10, $11); } + | CREATE OptTemp TABLE qualified_name OF qualified_name + '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace + { $$ = cat_str(12, make_str("create"), $2, make_str("table"), $4, make_str("of"), $6, make_str("("), $8, make_str(")"), $10, $11, $12); } ; /* @@ -1090,40 +1596,30 @@ OptTemp: TEMPORARY { $$ = make_str("temporary"); } | TEMP { $$ = make_str("temp"); } | LOCAL TEMPORARY { $$ = make_str("local temporary"); } | LOCAL TEMP { $$ = make_str("local temp"); } - | GLOBAL TEMPORARY - { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE TABLE / GLOBAL TEMPORARY will be passed to backend"); - $$ = make_str("global temporary"); - } - | GLOBAL TEMP - { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE TABLE / GLOBAL TEMP will be passed to backend"); - $$ = make_str("global temp"); - } + | GLOBAL TEMPORARY { $$ = make_str("global temporary"); } + | GLOBAL TEMP { $$ = make_str("global temp"); } | /*EMPTY*/ { $$ = EMPTY; } ; -OptTableElementList: OptTableElementList ',' OptTableElement - { $$ = cat_str(3, $1, make_str(","), $3); } - | OptTableElement + +OptTableElementList: TableElementList { $$ = $1; } | /*EMPTY*/ { $$ = EMPTY; } ; +TableElementList: TableElement + { $$ = $1; } + | TableElementList ',' TableElement + { $$ = cat_str(3, $1, make_str(","), $3); } + ; -OptTableElement: columnDef { $$ = $1; } - | TableConstraint { $$ = $1; } +TableElement: columnDef { $$ = $1; } + | TableLikeClause { $$ = $1; } + | TableConstraint { $$ = $1; } ; -columnDef: ColId Typename ColQualList opt_collate - { - if (strlen($4) > 0) - { - snprintf(errortext, sizeof(errortext), "Currently unsupported CREATE TABLE / COLLATE %s will be passed to backend", $4); - mmerror(PARSE_ERROR, ET_WARNING, errortext); - } - $$ = cat_str(4, $1, $2, $3, $4); - } +columnDef: ColId Typename ColQualList + {$$ = cat_str(3, $1, $2, $3); } ; ColQualList: ColQualList ColConstraint { $$ = cat2_str($1,$2); } @@ -1151,10 +1647,10 @@ ColConstraintElem: NOT NULL_P { $$ = make_str("not null"); } | NULL_P { $$ = make_str("null"); } - | UNIQUE - { $$ = make_str("unique"); } - | PRIMARY KEY - { $$ = make_str("primary key"); } + | UNIQUE opt_definition OptConsTableSpace + { $$ = cat_str(3, make_str("unique"), $2, $3); } + | PRIMARY KEY opt_definition OptConsTableSpace + { $$ = cat_str(3, make_str("primary key"), $3, $4); } | CHECK '(' a_expr ')' { $$ = cat_str(3, make_str("check ("), $3, make_str(")")); } | DEFAULT b_expr @@ -1175,11 +1671,29 @@ ColConstraintElem: NOT NULL_P * there is no parsing conflict. */ ConstraintAttr: DEFERRABLE { $$ = make_str("deferrable"); } - | NOT DEFERRABLE { $$ = make_str("not deferrable"); } + | NOT DEFERRABLE { $$ = make_str("not deferrable"); } | INITIALLY DEFERRED { $$ = make_str("initially deferred"); } | INITIALLY IMMEDIATE { $$ = make_str("initially immediate"); } ; +TableLikeClause: LIKE qualified_name TableLikeOptionList + {$$ = cat_str(3, make_str("like"), $2, $3); } + ; + +TableLikeOptionList: TableLikeOptionList TableLikeOption + { $$ = cat2_str($1, $2); } + | /* EMPTY */ { $$ = EMPTY; } + ; + +TableLikeOption: + INCLUDING DEFAULTS { $$ = make_str("including defaults"); } + | EXCLUDING DEFAULTS { $$ = make_str("excluding defaults"); } + | INCLUDING CONSTRAINTS { $$ = make_str("including constraints"); } + | EXCLUDING CONSTRAINTS { $$ = make_str("excluding constraints"); } + | INCLUDING INDEXES { $$ = make_str("including indexes"); } + | EXCLUDING INDEXES { $$ = make_str("excluding indexes"); } + ; + /* ConstraintElem specifies constraint syntax which is not embedded into * a column definition. ColConstraintElem specifies the embedded form. * - thomas 1997-12-03 @@ -1192,24 +1706,24 @@ TableConstraint: CONSTRAINT name ConstraintElem ConstraintElem: CHECK '(' a_expr ')' { $$ = cat_str(3, make_str("check("), $3, make_str(")")); } - | UNIQUE '(' columnList ')' - { $$ = cat_str(3, make_str("unique("), $3, make_str(")")); } - | PRIMARY KEY '(' columnList ')' - { $$ = cat_str(3, make_str("primary key("), $4, make_str(")")); } + | UNIQUE '(' columnList ')' opt_definition OptConsTableSpace + { $$ = cat_str(5, make_str("unique("), $3, make_str(")"), $5, $6); } + | PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace + { $$ = cat_str(5, make_str("primary key("), $4, make_str(")"), $6, $7); } | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name opt_column_list key_match key_actions ConstraintAttributeSpec { $$ = cat_str(8, make_str("foreign key("), $4, make_str(") references"), $7, $8, $9, $10, $11); } ; opt_column_list: '(' columnList ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } - | /*EMPTY*/ { $$ = EMPTY; } - ; + | /*EMPTY*/ { $$ = EMPTY; } + ; columnList: columnList ',' columnElem - { $$ = cat_str(3, $1, make_str(","), $3); } - | columnElem - { $$ = $1; } - ; + { $$ = cat_str(3, $1, make_str(","), $3); } + | columnElem + { $$ = $1; } + ; columnElem: ColId { $$ = $1; } ; @@ -1218,7 +1732,7 @@ key_match: MATCH FULL { $$ = make_str("match full"); } | MATCH PARTIAL { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported FOREIGN KEY/MATCH PARTIAL will be passed to backend"); + mmerror(PARSE_ERROR, ET_WARNING, "currently unsupported FOREIGN KEY/MATCH PARTIAL will be passed to backend"); $$ = make_str("match partial"); } | /*EMPTY*/ @@ -1232,58 +1746,78 @@ key_actions: key_delete { $$ = $1; } | /*EMPTY*/ { $$ = EMPTY; } ; -key_delete: ON DELETE_P key_reference +key_delete: ON DELETE_P key_action { $$ = cat2_str(make_str("on delete"), $3); } ; -key_update: ON UPDATE key_reference +key_update: ON UPDATE key_action { $$ = cat2_str(make_str("on update"), $3); } ; -key_reference: NO ACTION { $$ = make_str("no action"); } +key_action: 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"); } ; -OptInherit: INHERITS '(' qualified_name_list ')' +OptInherit: INHERITS '(' qualified_name_list ')' { $$ = cat_str(3, make_str("inherits ("), $3, make_str(")")); } - | /*EMPTY*/ + | /*EMPTY*/ { $$ = EMPTY; } ; -OptWithOids: WITH OIDS { $$ = make_str("with oids"); } - | WITHOUT OIDS { $$ = make_str("without oids"); } +OptWith: WITH definition { $$ = cat2_str(make_str("with"), $2); } + | WITH OIDS { $$ = make_str("with oids"); } + | WITHOUT OIDS { $$ = make_str("without oids"); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +OnCommitOption: ON COMMIT DROP { $$ = make_str("on commit drop"); } + | ON COMMIT DELETE_P ROWS { $$ = make_str("on commit delete rows"); } + | ON COMMIT PRESERVE ROWS { $$ = make_str("on commit preserve rows"); } | /*EMPTY*/ { $$ = EMPTY; } ; +OptTableSpace: TABLESPACE name { $$ = cat2_str(make_str("tablespace"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +OptConsTableSpace: USING INDEX TABLESPACE name { $$ = cat2_str(make_str("using index tablespace"), $4); } + | /*EMPTY*/ { $$ = EMPTY; } + ; /* * Note: CREATE TABLE ... AS SELECT ... is just another spelling for * SELECT ... INTO. */ -CreateAsStmt: CREATE OptTemp TABLE qualified_name OptCreateAs AS - { FoundInto = 0; } +CreateAsStmt: CREATE OptTemp TABLE create_as_target AS + { FoundInto = 0; } SelectStmt { if (FoundInto == 1) - mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE / AS SELECT may not specify INTO"); + mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE / AS SELECT cannot specify INTO"); + + $$ = cat_str(6, make_str("create"), $2, make_str("table"), $4, make_str("as"), $7); + } + ; - $$ = cat_str(7, make_str("create"), $2, make_str("table"), $4, $5, make_str("as"), $8); +create_as_target: qualified_name OptCreateAs OptWith OnCommitOption OptTableSpace + { + $$ = cat_str(5, $1, $2, $3, $4, $5); } ; -OptCreateAs: '(' CreateAsList ')' +OptCreateAs: '(' CreateAsList ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } - | /*EMPTY*/ + | /*EMPTY*/ { $$ = EMPTY; } ; -CreateAsList: CreateAsList ',' CreateAsElement +CreateAsList: CreateAsList ',' CreateAsElement { $$ = cat_str(3, $1, make_str(","), $3); } - | CreateAsElement + | CreateAsElement { $$ = $1; } ; @@ -1294,29 +1828,54 @@ CreateAsElement: ColId { $$ = $1; } * * QUERY : * CREATE SEQUENCE seqname + * ALTER SEQUENCE seqname * *****************************************************************************/ -CreateSeqStmt: CREATE OptTemp SEQUENCE qualified_name OptSeqList - { $$ = cat_str(4, make_str("create sequence"), $2, $4, $5); } +CreateSeqStmt: CREATE OptTemp SEQUENCE qualified_name OptSeqOptList + { $$ = cat_str(5, make_str("create"), $2, make_str("sequence"), $4, $5); } ; -OptSeqList: OptSeqList OptSeqElem { $$ = cat2_str($1, $2); } - | /*EMPTY*/ { $$ = EMPTY; } +AlterSeqStmt: ALTER SEQUENCE relation_expr SeqOptList + { $$ = cat_str(3,make_str("alter sequence"), $3, $4); } ; -OptSeqElem: CACHE NumConst +OptSeqOptList: SeqOptList { $$ = $1; } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +SeqOptList: SeqOptElem { $$ = $1; } + | SeqOptList SeqOptElem { $$ = cat2_str($1, $2); } + ; + +SeqOptElem: CACHE NumConst { $$ = cat2_str(make_str("cache"), $2); } | CYCLE { $$ = make_str("cycle"); } - | INCREMENT NumConst - { $$ = cat2_str(make_str("increment"), $2); } + | NO CYCLE + { $$ = make_str("no cycle"); } + | INCREMENT opt_by NumConst + { $$ = cat_str(3, make_str("increment"), $2, $3); } | MAXVALUE NumConst { $$ = cat2_str(make_str("maxvalue"), $2); } | MINVALUE NumConst { $$ = cat2_str(make_str("minvalue"), $2); } - | START NumConst - { $$ = cat2_str(make_str("start"), $2); } + | NO MAXVALUE + { $$ = make_str("no maxvalue"); } + | NO MINVALUE + { $$ = make_str("no minvalue"); } + | OWNED BY any_name + { $$ = cat2_str(make_str("owned by"), $3); } + | START opt_with NumConst + { $$ = cat_str(3, make_str("start"), $2, $3); } + | RESTART + { $$ = make_str("restart"); } + | RESTART opt_with NumConst + { $$ = cat_str(3, make_str("restart"), $2, $3); } + ; + +opt_by: BY { $$ = make_str("by"); } + | /*EMPTY*/ { $$ = EMPTY; } ; /***************************************************************************** @@ -1327,39 +1886,79 @@ OptSeqElem: CACHE NumConst * *****************************************************************************/ -CreatePLangStmt: CREATE opt_Trusted opt_procedural LANGUAGE ColId_or_Sconst - HANDLER handler_name opt_lancompiler - { $$ = cat_str(8, make_str("create"), $2, $3, make_str("language"), $5, make_str("handler"), $7, $8); } +CreatePLangStmt: CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst + { $$ = cat_str(5, make_str("create"), $2, $3, make_str("language"), $5); } + | CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst + HANDLER handler_name opt_validator opt_lancompiler + { $$ = cat_str(9, make_str("create"), $2, $3, make_str("language"), $5, make_str("handler"), $7, $8, $9); } ; -opt_Trusted: TRUSTED { $$ = make_str("trusted"); } +opt_trusted: TRUSTED { $$ = make_str("trusted"); } | /*EMPTY*/ { $$ = EMPTY; } ; /* This ought to be just func_name, but that causes reduce/reduce conflicts * (CREATE LANGUAGE is the only place where func_name isn't followed by '('). - * Work around by using name and dotted_name separately. + * Work around by using simple names instead. */ -handler_name: name - { $$ = $1; } - | dotted_name - { $$ = $1; /* XXX changing soon */ } - ; +handler_name: name { $$ = $1; } + | name attrs { $$ = cat2_str($1, $2); } + ; +opt_validator: VALIDATOR handler_name + { $$ = cat2_str(make_str("validator"), $2); } + | /*EMPTY*/ + { $$ = ""; } + ; opt_lancompiler: LANCOMPILER StringConst { $$ = cat2_str(make_str("lancompiler"), $2); } | /*EMPTY*/ { $$ = ""; } ; -DropPLangStmt: DROP opt_procedural LANGUAGE StringConst - { $$ = cat_str(4, make_str("drop"), $2, make_str("language"), $4); } +DropPLangStmt: DROP opt_procedural LANGUAGE StringConst opt_drop_behavior + { $$ = cat_str(5, make_str("drop"), $2, make_str("language"), $4, $5); } + | DROP opt_procedural LANGUAGE IF_P EXISTS StringConst opt_drop_behavior + { $$ = cat_str(5, make_str("drop"), $2, make_str("language if exists"), $6, $7); } ; opt_procedural: PROCEDURAL { $$ = make_str("prcedural"); } | /*EMPTY*/ { $$ = EMPTY; } ; +/***************************************************************************** + * + * QUERY: + * CREATE TABLESPACE tablespace LOCATION '/path/to/tablespace/' + * + *****************************************************************************/ + +CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst + { $$ = cat_str(5,make_str("create tablespace"), $3, $4, make_str("location"), $6); } + ; + +OptTableSpaceOwner: OWNER name { $$ = cat2_str(make_str("owner"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +/***************************************************************************** + * + * QUERY : + * DROP TABLESPACE + * + * No need for drop behaviour as we cannot implement dependencies for + * objects in other databases; we can only support RESTRICT. + * + ****************************************************************************/ + + +DropTableSpaceStmt: DROP TABLESPACE name + { $$ = cat2_str(make_str("drop tablespace"), $3); } + | DROP TABLESPACE IF_P EXISTS name + { $$ = cat2_str(make_str("drop tablespace if exists"), $5); } + ; + + /***************************************************************************** * * QUERIES : @@ -1369,13 +1968,11 @@ opt_procedural: PROCEDURAL { $$ = make_str("prcedural"); } *****************************************************************************/ CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON - qualified_name TriggerForSpec - EXECUTE PROCEDURE - name '(' TriggerFuncArgs ')' + qualified_name TriggerForSpec EXECUTE PROCEDURE name + '(' TriggerFuncArgs ')' { $$ = 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 - qualified_name OptConstrFromTable - ConstraintAttributeSpec + qualified_name OptConstrFromTable ConstraintAttributeSpec FOR EACH ROW EXECUTE PROCEDURE func_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(")")); } @@ -1400,6 +1997,8 @@ TriggerOneEvent: INSERT { $$ = make_str("insert"); } TriggerForSpec: FOR TriggerForOpt TriggerForType { $$ = cat_str(3, make_str("for"), $2, $3); } + | /* EMPTY */ + { $$ = EMPTY; } ; TriggerForOpt: EACH { $$ = make_str("each"); } @@ -1418,12 +2017,12 @@ TriggerFuncArgs: TriggerFuncArg { $$ = EMPTY; } ; -TriggerFuncArg: PosAllConst { $$ = $1; } - | ColId { $$ = $1; } +TriggerFuncArg: PosAllConst { $$ = $1; } + | ColId { $$ = $1; } ; OptConstrFromTable: /* Empty */ { $$ = EMPTY; } - | FROM qualified_name { $$ = cat2_str(make_str("from"), $2); } + | FROM qualified_name { $$ = cat2_str(make_str("from"), $2); } ; ConstraintAttributeSpec: ConstraintDeferrabilitySpec { $$ = $1; } @@ -1442,22 +2041,28 @@ ConstraintAttributeSpec: ConstraintDeferrabilitySpec { $$ = $1; } $$ = cat2_str($1, $2); } + | /* EMPTY */ + { + $$ = EMPTY; + } ; -ConstraintDeferrabilitySpec: NOT DEFERRABLE +ConstraintDeferrabilitySpec: NOT DEFERRABLE { $$ = make_str("not deferrable"); } - | DEFERRABLE + | DEFERRABLE { $$ = make_str("deferrable"); } ; -ConstraintTimeSpec: INITIALLY IMMEDIATE +ConstraintTimeSpec: INITIALLY IMMEDIATE { $$ = make_str("initially immediate"); } - | INITIALLY DEFERRED + | INITIALLY DEFERRED { $$ = make_str("initially deferred"); } ; -DropTrigStmt: DROP TRIGGER name ON qualified_name - { $$ = cat_str(4, make_str("drop trigger"), $3, make_str("on"), $5); } +DropTrigStmt: DROP TRIGGER name ON qualified_name opt_drop_behavior + { $$ = cat_str(5, make_str("drop trigger"), $3, make_str("on"), $5, $6); } + | DROP TRIGGER IF_P EXISTS name ON qualified_name opt_drop_behavior + { $$ = cat_str(5, make_str("drop trigger if exists"), $5, make_str("on"), $7, $8); } ; /***************************************************************************** @@ -1468,21 +2073,21 @@ DropTrigStmt: DROP TRIGGER name ON qualified_name * *****************************************************************************/ CreateAssertStmt: CREATE ASSERTION name - CHECK '(' a_expr ')' ConstraintAttributeSpec - { - mmerror(PARSE_ERROR, ET_ERROR, "CREATE ASSERTION is not yet supported"); - $$ = cat_str(6, make_str("create assertion"), $3, make_str("check ("), $6, make_str(")"), $8); - } + CHECK '(' a_expr ')' ConstraintAttributeSpec + { + mmerror(PARSE_ERROR, ET_ERROR, "CREATE ASSERTION is not yet supported"); + $$ = cat_str(6, make_str("create assertion"), $3, make_str("check ("), $6, make_str(")"), $8); + } ; DropAssertStmt: DROP ASSERTION name - { - mmerror(PARSE_ERROR, ET_ERROR, "DROP ASSERTION is not yet supported"); - $$ = cat2_str(make_str("drop assertion"), $3); - } - ; + { + mmerror(PARSE_ERROR, ET_ERROR, "DROP ASSERTION is not yet supported"); + $$ = cat2_str(make_str("drop assertion"), $3); + } + ; + - /***************************************************************************** * * QUERY : @@ -1490,15 +2095,31 @@ DropAssertStmt: DROP ASSERTION name * *****************************************************************************/ -DefineStmt: CREATE AGGREGATE func_name definition +DefineStmt: CREATE AGGREGATE func_name aggr_args definition + { $$ = cat_str(4, make_str("create aggregate"), $3, $4, $5); } + | CREATE AGGREGATE func_name old_aggr_definition { $$ = cat_str(3, make_str("create aggregate"), $3, $4); } | CREATE OPERATOR all_Op definition { $$ = cat_str(3, make_str("create operator"), $3, $4); } | CREATE TYPE_P any_name definition { $$ = cat_str(3, make_str("create type"), $3, $4); } - ; - -definition: '(' def_list ')' + | CREATE TYPE_P any_name + { $$ = cat2_str(make_str("create type"), $3); } + | CREATE TYPE_P any_name AS '(' TableFuncElementList ')' + { $$ = cat_str(5, make_str("create type"), $3, make_str("as ("), $6, make_str(")")); } + | CREATE TYPE_P any_name AS ENUM_P '(' enum_val_list ')' + { $$ = cat_str(5, make_str("create type"), $3, make_str("as enum ("), $7, make_str(")")); } + | CREATE TEXT_P SEARCH PARSER any_name definition + { $$ = cat_str(3, make_str("create text search parser"), $5, $6); } + | CREATE TEXT_P SEARCH DICTIONARY any_name definition + { $$ = cat_str(3, make_str("create text search dictionary"), $5, $6); } + | CREATE TEXT_P SEARCH TEMPLATE any_name definition + { $$ = cat_str(3, make_str("create text search template"), $5, $6); } + | CREATE TEXT_P SEARCH CONFIGURATION any_name definition + { $$ = cat_str(3, make_str("create text search configuration"), $5, $6); } + ; + +definition: '(' def_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } ; @@ -1511,145 +2132,311 @@ def_elem: ColLabel '=' def_arg { $$ = cat_str(3, $1, make_str("="), $3); } ; /* Note: any simple identifier will be returned as a type name! */ -def_arg: func_return { $$ = $1; } - | all_Op { $$ = $1; } - | AllConst { $$ = $1; } +def_arg: func_type { $$ = $1; } + | reserved_keyword { $$ = $1; } + | qual_all_Op { $$ = $1; } + | AllConst { $$ = $1; } + ; + +aggr_args: '(' type_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | '(' '*' ')' { $$ = make_str("(*)"); } + ; + +old_aggr_definition: '(' old_aggr_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + ; + +old_aggr_list: old_aggr_elem { $$ = $1; } + | old_aggr_list ',' old_aggr_elem { $$ = cat_str(3, $1, make_str(","), $3); } + ; + +old_aggr_elem: ident '=' def_arg { $$ = cat_str(3, $1, make_str("="), $3); } + ; + +enum_val_list: StringConst { $$ = $1; } + | enum_val_list ',' StringConst { $$ = cat_str(3, $1, make_str(","), $3);} + ; + +CreateOpClassStmt: CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename + USING access_method opt_opfamily AS opclass_item_list + { + $$ = cat_str(10, make_str("create operator class"), $4, $5, make_str("for type"), $8, make_str("using"), $10, $11, make_str("as"), $13); + } + ; + +opclass_item_list: opclass_item { $$ = $1; } + | opclass_item_list ',' opclass_item { $$ = cat_str(3, $1, make_str(","), $3); } + ; + +opclass_item: OPERATOR PosIntConst any_operator opt_recheck + { $$ = cat_str(4, make_str("operator"), $2, $3, $4); } + | OPERATOR PosIntConst any_operator '(' oper_argtypes ')' opt_recheck + { $$ = cat_str(7, make_str("operator"), $2, $3, make_str("("), $5, make_str(")"), $7); } + | FUNCTION PosIntConst func_name func_args + { $$ = cat_str(4, make_str("function"), $2, $3, $4); } + | FUNCTION PosIntConst '(' type_list ')' func_name func_args + { $$ = cat_str(7, make_str("function"), $2, make_str("("), $4, make_str(")"), $6, $7); } + | STORAGE Typename + { $$ = cat2_str(make_str("storage"), $2); } + ; + +opt_default: DEFAULT { $$ = make_str("default"); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +opt_opfamily: FAMILY any_name { $$ = cat2_str(make_str("family"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +opt_recheck: RECHECK { + mmerror(PARSE_ERROR, ET_WARNING, "no longer supported RECHECK OPTION will be passed to backend"); + $$ = make_str("recheck"); + } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +CreateOpFamilyStmt: CREATE OPERATOR FAMILY any_name USING access_method + { $$ = cat_str(4, make_str("create operator family"), $4, make_str("using"), $6); } + ; + +AlterOpFamilyStmt: ALTER OPERATOR FAMILY any_name USING access_method ADD_P opclass_item_list + { $$ = cat_str(6, make_str("alter operator family"), $4, make_str("using"), $6, make_str("add"), $8); } + | ALTER OPERATOR FAMILY any_name USING access_method DROP opclass_drop_list + { $$ = cat_str(6, make_str("alter operator family"), $4, make_str("using"), $6, make_str("drop"), $8); } + ; + +opclass_drop_list: opclass_drop { $$ = $1; } + | opclass_drop_list ',' opclass_drop { $$ = cat_str(3, $1, make_str(","), $3); } + ; + +opclass_drop: + OPERATOR PosIntConst '(' type_list ')' + { $$ = cat_str(5, make_str("operator"), $2, make_str("("), $4, make_str(")")); } + | FUNCTION PosIntConst '(' type_list ')' + { $$ = cat_str(5, make_str("function"), $2, make_str("("), $4, make_str(")")); } + ; + +DropOpClassStmt: DROP OPERATOR CLASS any_name USING access_method opt_drop_behavior + { $$ = cat_str(5,make_str("drop operator class"), $4, make_str("using"), $6, $7); } + | DROP OPERATOR CLASS IF_P EXISTS any_name USING access_method opt_drop_behavior + { $$ = cat_str(5,make_str("drop operator class if exists"), $6, make_str("using"), $8, $9); } + ; + +DropOpFamilyStmt: DROP OPERATOR FAMILY any_name USING access_method opt_drop_behavior + { $$ = cat_str(5,make_str("drop operator family"), $4, make_str("using"), $6, $7); } + | DROP OPERATOR FAMILY IF_P EXISTS any_name USING access_method opt_drop_behavior + { $$ = cat_str(5,make_str("drop operator family if exists"), $6, make_str("using"), $8, $9); } + ; + +/***************************************************************************** + * + * QUERY: + * + * DROP OWNED BY username [, username ...] [ RESTRICT | CASCADE ] + * REASSIGN OWNED BY username [, username ...] TO username + * + *****************************************************************************/ +DropOwnedStmt: + DROP OWNED BY name_list opt_drop_behavior + {$$ = cat_str(3, make_str("drop owned by"), $4, $5); } + ; + +ReassignOwnedStmt: + REASSIGN OWNED BY name_list TO name + {$$ = cat_str(4, make_str("reassign owned by"), $4, make_str("to"), $6); } ; /***************************************************************************** * * QUERY: * - * DROP itemtype itemname [, itemname ...] + * DROP itemtype [ IF EXISTS ] itemname [, itemname ...] [ RESTRICT | CASCADE ] * *****************************************************************************/ -DropStmt: DROP drop_type any_name_list opt_drop_behavior +DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior + { $$ = cat_str(5, make_str("drop"), $2, make_str("if exists"), $5, $6); } + | DROP drop_type any_name_list opt_drop_behavior { $$ = cat_str(4, make_str("drop"), $2, $3, $4); } ; -drop_type: TABLE { $$ = make_str("table"); } - | SEQUENCE { $$ = make_str("sequence"); } - | VIEW { $$ = make_str("view"); } - | INDEX { $$ = make_str("index"); } - | TYPE_P { $$ = make_str("type"); } - | DOMAIN_P { $$ = make_str("domain"); } +drop_type: TABLE { $$ = make_str("table"); } + | SEQUENCE { $$ = make_str("sequence"); } + | VIEW { $$ = make_str("view"); } + | INDEX { $$ = make_str("index"); } + | TYPE_P { $$ = make_str("type"); } + | DOMAIN_P { $$ = make_str("domain"); } + | CONVERSION_P { $$ = make_str("conversion"); } + | SCHEMA { $$ = make_str("schema"); } + | TEXT_P SEARCH PARSER { $$ = make_str("text search parser"); } + | TEXT_P SEARCH DICTIONARY { $$ = make_str("text search dictionary"); } + | TEXT_P SEARCH TEMPLATE { $$ = make_str("text search template"); } + | TEXT_P SEARCH CONFIGURATION { $$ = make_str("text search configuration"); } ; any_name_list: any_name - { $$ = $1; } - | any_name_list ',' any_name - { $$ = cat_str(3, $1, make_str(","), $3); } - ; + { $$ = $1; } + | any_name_list ',' any_name + { $$ = cat_str(3, $1, make_str(","), $3); } + ; + +any_name: ColId { $$ = $1; } + | ColId attrs { $$ = cat2_str($1, $2); } + ; + +attrs: '.' attr_name { $$ = cat2_str(make_str("."), $2); } + | attrs '.' attr_name { $$ = cat_str(3, $1, make_str("."), $3); } + ; -any_name: ColId - { $$ = $1; } - | dotted_name - { $$ = $1; } - ; /***************************************************************************** * * QUERY: - * truncate table relname + * truncate table relname1, relname2, .... * *****************************************************************************/ -TruncateStmt: TRUNCATE opt_table qualified_name - { $$ = cat_str(3, make_str("truncate table"), $2, $3); } +TruncateStmt: TRUNCATE opt_table qualified_name_list opt_restart_seqs opt_drop_behavior + { $$ = cat_str(5, make_str("truncate table"), $2, $3, $4, $5); } ; +opt_restart_seqs: + CONTINUE_P IDENTITY_P { $$ = cat2_str(make_str("continue"), make_str("identity")); } + | RESTART IDENTITY_P { $$ = cat2_str(make_str("restart"), make_str("identity")); } + | /* EMPTY */ { $$ = EMPTY; } + ; + /***************************************************************************** * * QUERY: - * fetch/move [forward | backward] [ # | all ] [ in ] - * fetch [ forward | backward | absolute | relative ] - * [ # | all | next | prior ] [ [ in | from ] ] + * fetch/move * *****************************************************************************/ -FetchStmt: FETCH direction fetch_how_many from_in name ecpg_into - { - if (strcmp($2, "relative") == 0 && atol($3) == 0L) - mmerror(PARSE_ERROR, ET_ERROR, "FETCH/RELATIVE at current position is not supported"); +/* This is different from the backend as we try to be compatible with many other + * embedded SQL implementations. So we accept their syntax as well and + * translate it to the PGSQL syntax. */ - $$ = cat_str(5, make_str("fetch"), $2, $3, $4, $5); - } - | FETCH fetch_how_many from_in name ecpg_into - { $$ = cat_str(4, make_str("fetch"), $2, $3, $4); } - | FETCH direction from_in name ecpg_into - { $$ = cat_str(4, make_str("fetch"), $2, $3, $4); } +FetchStmt: FETCH fetch_direction from_in name ecpg_into + { + add_additional_variables($4, false); + $$ = cat_str(4, make_str("fetch"), $2, $3, $4); + } + | FETCH fetch_direction name ecpg_into + { + add_additional_variables($3, false); + $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3); + } | FETCH from_in name ecpg_into - { $$ = cat_str(3, make_str("fetch"), $2, $3); } + { + add_additional_variables($3, false); + $$ = cat_str(3, make_str("fetch"), $2, $3); + } | FETCH name ecpg_into - { $$ = 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 + { + add_additional_variables($2, false); + $$ = cat2_str(make_str("fetch"), $2); + } + | FETCH fetch_direction from_in name + { + add_additional_variables($4, false); + $$ = cat_str(4, make_str("fetch"), $2, $3, $4); + } + | FETCH fetch_direction name + { + add_additional_variables($3, false); + $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3); + } + | FETCH from_in name + { + add_additional_variables($3, false); + $$ = cat_str(3, make_str("fetch"), $2, $3); + } + | FETCH name + { + add_additional_variables($2, false); + $$ = cat2_str(make_str("fetch"), $2); + } + | MOVE fetch_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 { $$ = cat2_str(make_str("move"), $2); } ; -direction: FORWARD { $$ = make_str("forward"); } - | BACKWARD { $$ = make_str("backward"); } - | RELATIVE { $$ = make_str("relative"); } - | ABSOLUTE - { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported FETCH/ABSOLUTE will be passed to backend, backend will use RELATIVE"); - $$ = make_str("absolute"); - } - ; - -fetch_how_many: IntConst { $$ = $1; } - | ALL { $$ = make_str("all"); } - | NEXT { $$ = make_str("next"); } +fetch_direction: NEXT { $$ = make_str("next"); } | PRIOR { $$ = make_str("prior"); } + | FIRST_P { $$ = make_str("first"); } + | LAST_P { $$ = make_str("last"); } + | ABSOLUTE_P fetch_count { $$ = cat2_str(make_str("absolute"), $2); } + | RELATIVE_P fetch_count { $$ = cat2_str(make_str("relative"), $2); } + | fetch_count { $$ = $1; } + | ALL { $$ = make_str("all"); } + | FORWARD { $$ = make_str("forward"); } + | FORWARD fetch_count { $$ = cat2_str(make_str("forward"), $2); } + | FORWARD ALL { $$ = make_str("forward all"); } + | BACKWARD { $$ = make_str("backward"); } + | BACKWARD fetch_count { $$ = cat2_str(make_str("backward"), $2); } + | BACKWARD ALL { $$ = make_str("backward all"); } ; +fetch_count: IntConst { + if ($1[1] == '$') + { + /* a variable here has to be replaced on the client side, thus we have to use '$0' here */ + $$ = make_str("$0"); + free($1); + } + else + $$ = $1; + } + from_in: IN_P { $$ = make_str("in"); } - | FROM { $$ = make_str("from"); } + | 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 | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW ] - * | AGGREGATE () | FUNCTION - * (arg1, arg2, ...) | OPERATOR - * (leftoperand_typ rightoperand_typ) | TRIGGER ON - * | RULE 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 AGGREGATE func_name '(' aggr_argtype ')' IS comment_text - { $$ = cat_str(6, make_str("comment on aggregate"), $4, make_str("("), $6, make_str(") is"), $9); } + | COMMENT ON AGGREGATE func_name aggr_args IS comment_text + { $$ = cat_str(5, make_str("comment on aggregate"), $4, $5, make_str("is"), $7); } | COMMENT ON FUNCTION func_name func_args IS comment_text { $$ = cat_str(5, make_str("comment on function"), $4, $5, make_str("is"), $7); } | COMMENT ON OPERATOR all_Op '(' oper_argtypes ')' IS comment_text { $$ = cat_str(6, make_str("comment on operator"), $4, make_str("("), $6, make_str(") is"), $9); } - | COMMENT ON TRIGGER name ON qualified_name IS comment_text + | COMMENT ON TRIGGER name ON any_name IS comment_text { $$ = cat_str(6, make_str("comment on trigger"), $4, make_str("on"), $6, make_str("is"), $8); } | COMMENT ON RULE name ON any_name IS comment_text { $$ = cat_str(6, make_str("comment on rule"), $4, make_str("on"), $6, make_str("is"), $8); } | COMMENT ON RULE name IS comment_text { $$ = cat_str(4, make_str("comment on rule"), $4, make_str("is"), $6); } + | COMMENT ON OPERATOR CLASS any_name USING access_method IS comment_text + { $$ = cat_str(6, make_str("comment on operator class"), $5, make_str("using"), $7, make_str("is"), $9); } + | COMMENT ON OPERATOR FAMILY any_name USING access_method IS comment_text + { $$ = cat_str(6, make_str("comment on operator family"), $5, make_str("using"), $7, make_str("is"), $9); } + | COMMENT ON LARGE_P OBJECT_P NumConst IS comment_text + { $$ = cat_str(4, make_str("comment on large object"), $5, make_str("is"), $7); } + | COMMENT ON CAST '(' Typename AS Typename ')' IS comment_text + { $$ = cat_str(6, make_str("comment on cast ("), $5, make_str("as"), $7, make_str(") is"), $10); } + | COMMENT ON opt_procedural LANGUAGE any_name IS comment_text + { $$ = cat_str(6, make_str("comment on"), $3, make_str("language"), $5, make_str("is"), $7); } + | COMMENT ON TEXT_P SEARCH PARSER any_name IS comment_text + { $$ = cat_str(4, make_str("comment on test search parser"), $6, make_str("is"), $8); } + | COMMENT ON TEXT_P SEARCH DICTIONARY any_name IS comment_text + { $$ = cat_str(4, make_str("comment on test search dictionary"), $6, make_str("is"), $8); } + | COMMENT ON TEXT_P SEARCH TEMPLATE any_name IS comment_text + { $$ = cat_str(4, make_str("comment on test search template"), $6, make_str("is"), $8); } + | COMMENT ON TEXT_P SEARCH CONFIGURATION any_name IS comment_text + { $$ = cat_str(4, make_str("comment on test search configuration"), $6, make_str("is"), $8); } ; comment_type: COLUMN { $$ = make_str("column"); } - | DATABASE { $$ = make_str("database"); } - | SCHEMA { $$ = make_str("schema"); } - | INDEX { $$ = make_str("idnex"); } - | SEQUENCE { $$ = make_str("sequence"); } - | TABLE { $$ = make_str("table"); } - | DOMAIN_P { $$ = make_str("domain"); } - | TYPE_P { $$ = make_str("type"); } - | VIEW { $$ = make_str("view"); } + | DATABASE { $$ = make_str("database"); } + | SCHEMA { $$ = make_str("schema"); } + | INDEX { $$ = make_str("idnex"); } + | SEQUENCE { $$ = make_str("sequence"); } + | TABLE { $$ = make_str("table"); } + | DOMAIN_P { $$ = make_str("domain"); } + | TYPE_P { $$ = make_str("type"); } + | VIEW { $$ = make_str("view"); } + | CONVERSION_P { $$ = make_str("conversion"); } + | TABLESPACE { $$ = make_str("tablespace"); } + | ROLE { $$ = make_str("role"); } ; comment_text: StringConst { $$ = $1; } @@ -1667,8 +2454,10 @@ GrantStmt: GRANT privileges ON privilege_target TO grantee_list opt_grant_grant_ { $$ = cat_str(7, make_str("grant"), $2, make_str("on"), $4, make_str("to"), $6, $7); } ; -RevokeStmt: REVOKE opt_revoke_grant_option privileges ON privilege_target FROM grantee_list - { $$ = cat_str(8, make_str("revoke"), $2, $3, make_str("on"), $5, make_str("from"), $7); } +RevokeStmt: REVOKE privileges ON privilege_target FROM grantee_list opt_drop_behavior + {$$ = cat_str(7, make_str("revoke"), $2, make_str("on"), $4, make_str("from"), $6, $7); } + | REVOKE GRANT OPTION FOR privileges ON privilege_target FROM grantee_list opt_drop_behavior + {$$ = cat_str(7, make_str("revoke grant option for"), $5, make_str("on"), $7, make_str("from"), $9, $10); } ; privileges: ALL PRIVILEGES { $$ = make_str("all privileges"); } @@ -1676,64 +2465,52 @@ privileges: ALL PRIVILEGES { $$ = make_str("all privileges"); } | privilege_list { $$ = $1; } ; -privilege_list: privilege +privilege_list: privilege { $$ = $1; } - | privilege_list ',' privilege + | privilege_list ',' privilege { $$ = cat_str(3, $1, make_str(","), $3); } ; privilege: SELECT { $$ = make_str("select"); } - | INSERT { $$ = make_str("insert"); } - | UPDATE { $$ = make_str("update"); } - | DELETE_P { $$ = make_str("delete"); } - | RULE { $$ = make_str("rule"); } | REFERENCES { $$ = make_str("references"); } - | TRIGGER { $$ = make_str("trigger"); } - | EXECUTE { $$ = make_str("execute"); } - | USAGE { $$ = make_str("usage"); } | CREATE { $$ = make_str("create"); } - | TEMPORARY { $$ = make_str("temporary"); } - | TEMP { $$ = make_str("temp"); } + | ColId { $$ = $1; } ; -privilege_target: qualified_name_list +privilege_target: qualified_name_list { $$ = $1; } - | TABLE qualified_name_list + | TABLE qualified_name_list { $$ = cat2_str(make_str("table"), $2); } + | SEQUENCE qualified_name_list + { $$ = cat2_str(make_str("sequence"), $2); } | FUNCTION function_with_argtypes_list { $$ = cat2_str(make_str("function"), $2); } | DATABASE name_list { $$ = cat2_str(make_str("database"), $2); } - | LANGUAGE name_list + | LANGUAGE name_list { $$ = cat2_str(make_str("language") , $2); } - | SCHEMA name_list + | SCHEMA name_list { $$ = cat2_str(make_str("schema") , $2); } + | TABLESPACE name_list + { $$ = cat2_str(make_str("tablespace") , $2); } ; -grantee_list: grantee +grantee_list: grantee { $$ = $1; } - | grantee_list ',' grantee + | grantee_list ',' grantee { $$ = cat_str(3, $1, make_str(","), $3); } ; -grantee: ColId { $$ = $1; } - | GROUP_P ColId { $$ = cat2_str(make_str("group"), $2); } +grantee: RoleId { $$ = $1; } + | GROUP_P RoleId { $$ = cat2_str(make_str("group"), $2); } ; opt_grant_grant_option: WITH GRANT OPTION { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported GRANT/WITH GRANT OPTION will be passed to backend"); - $$ = make_str("with grant option"); - } - | /*EMPTY*/ { $$ = EMPTY; } - ; - -opt_revoke_grant_option: GRANT OPTION FOR - { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported REVOKE/GRANT OPTION FOR will be passed to backend"); + mmerror(PARSE_ERROR, ET_WARNING, "currently unsupported GRANT/WITH GRANT OPTION will be passed to backend"); $$ = make_str("with grant option"); } - | /*EMPTY*/ { $$ = EMPTY; } + | /*EMPTY*/ { $$ = EMPTY; } ; function_with_argtypes_list: function_with_argtypes @@ -1744,46 +2521,71 @@ function_with_argtypes_list: function_with_argtypes function_with_argtypes: func_name func_args { $$ = cat2_str($1, $2); }; +/***************************************************************************** + * + * GRANT and REVOKE ROLE statements + * + *****************************************************************************/ + +GrantRoleStmt: + GRANT privilege_list TO name_list opt_grant_admin_option opt_granted_by + { $$ = cat_str(6, make_str("grant"), $2, make_str("to"), $4, $5, $6); } + ; + +RevokeRoleStmt: + REVOKE privilege_list FROM name_list opt_granted_by opt_drop_behavior + { $$ = cat_str(6, make_str("revoke"), $2, make_str("from"), $4, $5, $6); } + ; + +opt_grant_admin_option: WITH ADMIN OPTION { $$ = make_str("with admin option"); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +opt_granted_by: GRANTED BY RoleId { $$ = cat2_str(make_str("granted by"), $3); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + /***************************************************************************** * * QUERY: - * create index on - * [ using ] "(" ( with )+ ")" - * [ where ] + * QUERY: CREATE INDEX + * + * Note: we can't factor CONCURRENTLY into a separate production without + * making it a reserved word. + * + * Note: we cannot put TABLESPACE clause after WHERE clause unless we are + * willing to make TABLESPACE a fully reserved word. * *****************************************************************************/ IndexStmt: CREATE index_opt_unique INDEX index_name ON qualified_name - access_method_clause '(' index_params ')' where_clause - { $$ = cat_str(11, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11); } + access_method_clause '(' index_params ')' opt_definition OptTableSpace where_clause + { $$ = cat_str(13, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11, $12, $13); } + | CREATE index_opt_unique INDEX CONCURRENTLY index_name ON qualified_name + access_method_clause '(' index_params ')' opt_definition OptTableSpace where_clause + { $$ = cat_str(13, make_str("create"), $2, make_str("index concurrently"), $5, make_str("on"), $7, $8, make_str("("), $10, make_str(")"), $12, $13, $14); } ; index_opt_unique: UNIQUE { $$ = make_str("unique"); } | /*EMPTY*/ { $$ = EMPTY; } ; -access_method_clause: USING access_method +access_method_clause: USING access_method { $$ = cat2_str(make_str("using"), $2); } - | /*EMPTY*/ + | /*EMPTY*/ { $$ = EMPTY; } ; -index_params: index_list { $$ = $1; } - | func_index { $$ = $1; } - ; - -index_list: index_list ',' index_elem - { $$ = cat_str(3, $1, make_str(","), $3); } - | index_elem - { $$ = $1; } - ; - -func_index: func_name '(' name_list ')' opt_class - { $$ = cat_str(5, $1, make_str("("), $3, ")", $5); } +index_params: index_elem { $$ = $1; } + | index_params ',' index_elem { $$ = cat_str(3, $1, make_str(","), $3); } ; -index_elem: attr_name opt_class - { $$ = cat2_str($1, $2); } +index_elem: ColId opt_class opt_asc_desc opt_nulls_order + { $$ = cat_str(4, $1, $2, $3, $4); } + | func_expr opt_class opt_asc_desc opt_nulls_order + { $$ = cat_str(4, $1, $2, $3, $4); } + | '(' a_expr ')' opt_class opt_asc_desc opt_nulls_order + { $$ = cat_str(6, make_str("("), $2, make_str(")"), $4, $5, $6); } ; opt_class: any_name { $$ = $1; } @@ -1791,44 +2593,31 @@ opt_class: any_name { $$ = $1; } | /*EMPTY*/ { $$ = EMPTY; } ; - -/***************************************************************************** - * - * QUERY: - * execute recipe - * - *****************************************************************************/ -/* NOT USED -RecipeStmt: EXECUTE RECIPE recipe_name - { - $$ = cat2_str(make_str("execute recipe"), $3); - } +opt_asc_desc: ASC { $$ = make_str("asc"); } + | DESC { $$ = make_str("desc"); } + | /*EMPTY*/ { $$ = EMPTY; } ; -*/ -/***************************************************************************** - * - * QUERY: - * create [or replace] function - * [( { , })] - * returns - * as - * language [with parameters] - * - *****************************************************************************/ + +opt_nulls_order: NULLS_FIRST { $$ = make_str("nulls first"); } + | NULLS_LAST { $$ = make_str("nulls last"); } + | /*EMPTY*/ { $$ = EMPTY; } + ; CreateFunctionStmt: CREATE opt_or_replace FUNCTION func_name func_args - RETURNS func_return createfunc_opt_list opt_with + RETURNS func_return createfunc_opt_list opt_definition { $$ = cat_str(8, make_str("create"), $2, make_str("function"), $4, $5, make_str("returns"), $7, $8); } + | CREATE opt_or_replace FUNCTION func_name func_args + RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition + { $$ = cat_str(9, make_str("create"), $2, make_str("function"), $4, $5, make_str("returns table ("), $9, make_str(")"), $11, $12); } + | CREATE opt_or_replace FUNCTION func_name func_args + createfunc_opt_list opt_definition + { $$ = cat_str(6, make_str("create"), $2, make_str("function"), $4, $5, $6, $7); } ; opt_or_replace: OR REPLACE { $$ = make_str("or replace"); } | /*EMPTY*/ { $$ = EMPTY; } ; -opt_with: WITH definition { $$ = cat2_str(make_str("with"), $2); } - | /*EMPTY*/ { $$ = EMPTY; } - ; - func_args: '(' func_args_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } | '(' ')' @@ -1841,30 +2630,18 @@ func_args_list: func_arg { $$ = cat_str(3, $1, make_str(","), $3); } ; -func_arg: opt_arg func_type - { - /* We can catch over-specified arguments here if we want to, - * but for now better to silently swallow typmod, etc. - * - thomas 2000-03-22 - */ - $$ = cat2_str($1, $2); - } - | func_type { $$ = $1; } +func_arg: arg_class param_name func_type { $$ = cat_str(3, $1, $2, $3); } + | param_name arg_class func_type { $$ = cat_str(3, $1, $2, $3); } + | param_name func_type { $$ = cat2_str($1, $2); } + | arg_class func_type { $$ = cat2_str($1, $2); } + | func_type { $$ = $1; } ; -opt_arg: IN_P { $$ = make_str("in"); } - | OUT_P - { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE FUNCTION/OUT will be passed to backend"); - - $$ = make_str("out"); - } - | INOUT - { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE FUNCTION/INOUT will be passed to backend"); - - $$ = make_str("inout"); - } +arg_class: IN_P { $$ = make_str("in"); } + | OUT_P { $$ = make_str("out"); } + | INOUT { $$ = make_str("inout"); } + | IN_P OUT_P { $$ = make_str("in out"); } + | VARIADIC { $$ = make_str("variadic"); } ; func_as: StringConst @@ -1873,6 +2650,8 @@ func_as: StringConst { $$ = cat_str(3, $1, make_str(","), $3); } ; +param_name: type_function_name { $$ = $1; }; + func_return: func_type { /* We can catch over-specified arguments here if we want to, @@ -1885,8 +2664,10 @@ func_return: func_type func_type: Typename { $$ = $1; } - | type_name attrs '%' TYPE_P + | type_function_name attrs '%' TYPE_P { $$ = cat_str(3, $1, $2, make_str("% type")); } + | SETOF type_function_name attrs '%' TYPE_P + { $$ = cat_str(4, make_str("setof"), $2, $3, make_str("% type")); } ; @@ -1896,22 +2677,19 @@ createfunc_opt_list: createfunc_opt_item { $$ = cat2_str($1, $2); } ; -createfunc_opt_item: AS func_as - { $$ = cat2_str(make_str("as"), $2); } - | LANGUAGE ColId_or_Sconst - { $$ = cat2_str(make_str("language"), $2); } +common_func_opt_item: + CALLED ON NULL_P INPUT_P + { $$ = make_str("called on null input"); } + | RETURNS NULL_P ON NULL_P INPUT_P + { $$ = make_str("returns null on null input"); } + | STRICT_P + { $$ = make_str("strict"); } | IMMUTABLE { $$ = make_str("immutable"); } | STABLE { $$ = make_str("stable"); } | VOLATILE { $$ = make_str("volatile"); } - | CALLED ON NULL_P INPUT - { $$ = make_str("called on null input"); } - | RETURNS NULL_P ON NULL_P INPUT - { $$ = make_str("returns null on null input"); } - | STRICT - { $$ = make_str("strict"); } | EXTERNAL SECURITY DEFINER { $$ = make_str("external security definer"); } | EXTERNAL SECURITY INVOKER @@ -1920,8 +2698,45 @@ createfunc_opt_item: AS func_as { $$ = make_str("security definer"); } | SECURITY INVOKER { $$ = make_str("security invoker"); } - | IMPLICIT CAST - { $$ = make_str("implicit cast"); } + | COST NumConst + { $$ = cat2_str(make_str("cost"), $2); } + | ROWS NumConst + { $$ = cat2_str(make_str("rows"), $2); } + | SetResetClause + { $$ = $1; } + ; + +createfunc_opt_item: AS func_as + { $$ = cat2_str(make_str("as"), $2); } + | LANGUAGE ColId_or_Sconst + { $$ = cat2_str(make_str("language"), $2); } + | common_func_opt_item + { $$ = $1; } + ; + +opt_definition: WITH definition { $$ = cat2_str(make_str("with"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +table_func_column: param_name func_type { $$ = cat2_str($1, $2); } + ; + +table_func_column_list: + table_func_column { $$ = $1; } + | table_func_column_list ',' table_func_column { $$ = cat_str(3, $1, make_str(","), $3); } + ; + +AlterFunctionStmt: + ALTER FUNCTION function_with_argtypes alterfunc_opt_list opt_restrict + { $$ = cat_str(4, make_str("alter function"), $3, $4, $5); } + ; + +alterfunc_opt_list: common_func_opt_item { $$ = $1; } + | alterfunc_opt_list common_func_opt_item { $$ = cat2_str($1, $2);} + ; + +opt_restrict: RESTRICT { $$ = make_str("restrict"); } + | /*EMPTY*/ { $$ = EMPTY; } ; /***************************************************************************** @@ -1929,30 +2744,34 @@ createfunc_opt_item: AS func_as * QUERY: * * DROP FUNCTION funcname (arg1, arg2, ...) - * DROP AGGREGATE aggname (aggtype) + * DROP AGGREGATE (arg1, ...) [ RESTRICT | CASCADE ] * DROP OPERATOR opname (leftoperand_typ rightoperand_typ) * *****************************************************************************/ -RemoveFuncStmt: DROP FUNCTION func_name func_args - { $$ = cat_str(3, make_str("drop function"), $3, $4); } +RemoveFuncStmt: DROP FUNCTION func_name func_args opt_drop_behavior + { $$ = cat_str(4, make_str("drop function"), $3, $4, $5); } + | DROP FUNCTION IF_P EXISTS func_name func_args opt_drop_behavior + { $$ = cat_str(4, make_str("drop function if exists"), $5, $6, $7); } ; -RemoveAggrStmt: DROP AGGREGATE func_name '(' aggr_argtype ')' - { $$ = cat_str(5, make_str("drop aggregate"), $3, make_str("("), $5, make_str(")")); } +RemoveAggrStmt: DROP AGGREGATE func_name aggr_args opt_drop_behavior + { $$ = cat_str(4, make_str("drop aggregate"), $3, $4, $5); } + | DROP AGGREGATE IF_P EXISTS func_name aggr_args opt_drop_behavior + { $$ = cat_str(4, make_str("drop aggregate if exists"), $5, $6, $7); } ; -aggr_argtype: Typename { $$ = $1; } - | '*' { $$ = make_str("*"); } - ; - - -RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')' - { $$ = cat_str(5, make_str("drop operator"), $3, make_str("("), $5, make_str(")")); } +RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')' opt_drop_behavior + { $$ = cat_str(6, make_str("drop operator"), $3, make_str("("), $5, make_str(")"), $7); } + | DROP OPERATOR IF_P EXISTS any_operator '(' oper_argtypes ')' opt_drop_behavior + { $$ = cat_str(6, make_str("drop operator if exists"), $5, make_str("("), $7, make_str(")"), $9); } ; oper_argtypes: Typename - { mmerror(PARSE_ERROR, ET_ERROR, "parser: argument type missing (use NONE for unary operators)"); } + { + mmerror(PARSE_ERROR, ET_ERROR, "parser: argument type missing (use NONE for unary operators)"); + $$ = make_str("none"); + } | Typename ',' Typename { $$ = cat_str(3, $1, make_str(","), $3); } | NONE ',' Typename /* left unary */ @@ -1961,6 +2780,34 @@ oper_argtypes: Typename { $$ = cat2_str($1, make_str(", none")); } ; +any_operator: + all_Op + { $$ = $1; } + | ColId '.' any_operator + { $$ = cat_str(3, $1, make_str("."), $3); } + ; + +CreateCastStmt: CREATE CAST '(' Typename AS Typename ')' + WITH FUNCTION function_with_argtypes cast_context + { $$ = cat_str(6, make_str("create cast ("), $4, make_str("as"), $6, make_str(") with function"), $10); } + | CREATE CAST '(' Typename AS Typename ')' + WITHOUT FUNCTION cast_context + { $$ = cat_str(6, make_str("create cast ("), $4, make_str("as"), $6, make_str(") without function"), $10); } + ; + +cast_context: AS ASSIGNMENT { $$ = make_str("as assignment"); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + + +DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_behavior + { $$ = cat_str(8, make_str("drop cast"), $3, make_str("("), $5, make_str("as"), $7, make_str(")"), $9); } + ; + +opt_if_exists: IF_P EXISTS { $$ = make_str("if exists"); } + | /* EMPTY */ { $$ = EMPTY; } + ; + /***************************************************************************** * * QUERY: @@ -1970,6 +2817,8 @@ oper_argtypes: Typename *****************************************************************************/ ReindexStmt: REINDEX reindex_type qualified_name opt_force { $$ = cat_str(4, make_str("reindex"), $2, $3, $4); } + | REINDEX SYSTEM_P name opt_force + { $$ = cat_str(3, make_str("reindex system"), $3, $4); } | REINDEX DATABASE name opt_force { $$ = cat_str(3, make_str("reindex database"), $3, $4); } ; @@ -1990,18 +2839,113 @@ opt_force: FORCE { $$ = make_str("force"); } * *****************************************************************************/ -RenameStmt: ALTER TABLE relation_expr RENAME opt_column opt_name TO name +RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name + { $$ = cat_str(5, make_str("alter aggregate"), $3, $4, make_str("rename to"), $7); } + | ALTER CONVERSION_P any_name RENAME TO name + { $$ = cat_str(4, make_str("alter conversion"), $3, make_str("rename to"), $6); } + | ALTER DATABASE database_name RENAME TO database_name + { $$ = cat_str(4, make_str("alter database"), $3, make_str("rename to"), $6); } + | ALTER FUNCTION function_with_argtypes RENAME TO name + { $$ = cat_str(4, make_str("alter function"), $3, make_str("rename to"), $6); } + | ALTER GROUP_P RoleId RENAME TO RoleId + { $$ = cat_str(4, make_str("alter group"), $3, make_str("rename to"), $6); } + | ALTER opt_procedural LANGUAGE name RENAME TO name + { $$ = cat_str(6, make_str("alter"), $2, make_str("language"), $4, make_str("rename to"), $7); } + | ALTER OPERATOR CLASS any_name USING access_method RENAME TO name + { $$ = cat_str(6, make_str("alter operator class"), $4, make_str("using"), $6, make_str("rename to"), $9); } + | ALTER OPERATOR FAMILY any_name USING access_method RENAME TO name + { $$ = cat_str(6, make_str("alter operator family"), $4, make_str("using"), $6, make_str("rename to"), $9); } + | ALTER SCHEMA name RENAME TO name + { $$ = cat_str(4, make_str("alter schema"), $3, make_str("rename to"), $6); } + | ALTER TABLE relation_expr RENAME TO name + { $$ = cat_str(4, make_str("alter table"), $3, make_str("rename to"), $6); } + | ALTER TABLE relation_expr SET SCHEMA name + { $$ = cat_str(4, make_str("alter table"), $3, make_str("set schema"), $6); } + | ALTER SEQUENCE relation_expr RENAME TO name + { $$ = cat_str(4, make_str("alter sequence"), $3, make_str("rename to"), $6); } + | ALTER VIEW relation_expr RENAME TO name + { $$ = cat_str(4, make_str("alter view"), $3, make_str("rename to"), $6); } + | ALTER INDEX relation_expr RENAME TO name + { $$ = cat_str(4, make_str("alter index"), $3, make_str("rename to"), $6); } + | ALTER TABLE relation_expr RENAME opt_column name TO name { $$ = cat_str(7, make_str("alter table"), $3, make_str("rename"), $5, $6, make_str("to"), $8); } - | ALTER TRIGGER name ON relation_expr RENAME TO name + | ALTER TRIGGER name ON relation_expr RENAME TO name { $$ = cat_str(6, make_str("alter trigger"), $3, make_str("on"), $5, make_str("rename to"), $8); } + | ALTER USER RoleId RENAME TO RoleId + { $$ = cat_str(4, make_str("alter user"), $3, make_str("rename to"), $6); } + | ALTER TABLESPACE name RENAME TO name + { $$ = cat_str(4, make_str("alter tablespace"), $3, make_str("rename to"), $6); } + | ALTER TEXT_P SEARCH PARSER any_name RENAME TO name + { $$ = cat_str(4, make_str("alter text search parser"), $5, make_str("rename to"), $8); } + | ALTER TEXT_P SEARCH DICTIONARY any_name RENAME TO name + { $$ = cat_str(4, make_str("alter text search dictionary"), $5, make_str("rename to"), $8); } + | ALTER TEXT_P SEARCH TEMPLATE any_name RENAME TO name + { $$ = cat_str(4, make_str("alter text search template"), $5, make_str("rename to"), $8); } + | ALTER TEXT_P SEARCH CONFIGURATION any_name RENAME TO name + { $$ = cat_str(4, make_str("alter text search configuration"), $5, make_str("rename to"), $8); } + | ALTER TYPE_P any_name RENAME TO name + { $$ = cat_str(4, make_str("alter type"), $3, make_str("rename to"), $6); } ; -opt_name: name { $$ = $1; } +opt_column: COLUMN { $$ = make_str("column"); } | /*EMPTY*/ { $$ = EMPTY; } ; -opt_column: COLUMN { $$ = make_str("column"); } - | /*EMPTY*/ { $$ = EMPTY; } +/***************************************************************************** + * + * ALTER THING name SET SCHEMA name + * + *****************************************************************************/ + +AlterObjectSchemaStmt: + ALTER AGGREGATE func_name aggr_args SET SCHEMA name + { $$ = cat_str(5, make_str("alter aggregate"), $3, $4, make_str("set schema"), $7); } + | ALTER DOMAIN_P any_name SET SCHEMA name + { $$ = cat_str(4, make_str("alter domain"), $3, make_str("set schema"), $6); } + | ALTER FUNCTION function_with_argtypes SET SCHEMA name + { $$ = cat_str(4, make_str("alter function"), $3, make_str("set schema"), $6); } + | ALTER SEQUENCE relation_expr SET SCHEMA name + { $$ = cat_str(4, make_str("alter sequence"), $3, make_str("set schema"), $6); } + | ALTER VIEW relation_expr SET SCHEMA name + { $$ = cat_str(4, make_str("alter sequence"), $3, make_str("set schema"), $6); } + | ALTER TYPE_P any_name SET SCHEMA name + { $$ = cat_str(4, make_str("alter type"), $3, make_str("set schema"), $6); } + ; + +/***************************************************************************** + * + * ALTER THING name OWNER TO newname + * + *****************************************************************************/ + +AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId + { $$ = cat_str(5, make_str("alter aggregate"), $3, $4, make_str("owner to"), $7); } + | ALTER CONVERSION_P any_name OWNER TO RoleId + { $$ = cat_str(4, make_str("alter conversion"), $3, make_str("owner to"), $6); } + | ALTER DATABASE database_name OWNER TO RoleId + { $$ = cat_str(4, make_str("alter database"), $3, make_str("owner to"), $6); } + | ALTER DOMAIN_P database_name OWNER TO RoleId + { $$ = cat_str(4, make_str("alter domain"), $3, make_str("owner to"), $6); } + | ALTER FUNCTION function_with_argtypes OWNER TO RoleId + { $$ = cat_str(4, make_str("alter function"), $3, make_str("owner to"), $6); } + | ALTER opt_procedural LANGUAGE name OWNER TO RoleId + { $$ = cat_str(6, make_str("alter"), $2, make_str("language"), $4, make_str("owner to"), $7); } + | ALTER OPERATOR any_operator '(' oper_argtypes ')' OWNER TO RoleId + { $$ = cat_str(6, make_str("alter operator"), $3, make_str("("), $5, make_str(") owner to"), $9); } + | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId + { $$ = cat_str(6, make_str("alter operator class"), $4, make_str("using"), $6, make_str("owner to"), $9); } + | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId + { $$ = cat_str(6, make_str("alter operator family"), $4, make_str("using"), $6, make_str("owner to"), $9); } + | ALTER SCHEMA name OWNER TO RoleId + { $$ = cat_str(4, make_str("alter schema"), $3, make_str("owner to"), $6); } + | ALTER TYPE_P any_name OWNER TO RoleId + { $$ = cat_str(4, make_str("alter type"), $3, make_str("owner to"), $6); } + | ALTER TABLESPACE name OWNER TO RoleId + { $$ = cat_str(4, make_str("alter tablespace"), $3, make_str("owner to"), $6); } + | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId + { $$ = cat_str(4, make_str("alter text search dictionary"), $5, make_str("owner to"), $8); } + | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId + { $$ = cat_str(4, make_str("alter text search configuration"), $5, make_str("owner to"), $8); } ; @@ -2011,13 +2955,13 @@ opt_column: COLUMN { $$ = make_str("column"); } * *****************************************************************************/ -RuleStmt: CREATE RULE name AS +RuleStmt: CREATE opt_or_replace RULE name AS { QueryIsRule=1; } ON event TO qualified_name where_clause DO opt_instead RuleActionList { QueryIsRule=0; - $$ = cat_str(10, make_str("create rule"), $3, make_str("as on"), $7, make_str("to"), $9, $10, make_str("do"), $12, $13); + $$ = cat_str(12, make_str("create"), $2, make_str("rule"), $4, make_str("as on"), $8, make_str("to"), $10, $11, make_str("do"), $13, $14); } ; @@ -2041,22 +2985,26 @@ RuleActionStmt: SelectStmt ; RuleActionStmtOrEmpty: RuleActionStmt { $$ = $1; } - | /*EMPTY*/ { $$ = EMPTY; } - ; + | /*EMPTY*/ { $$ = EMPTY; } + ; /* change me to select, update, etc. some day */ event: SELECT { $$ = make_str("select"); } | UPDATE { $$ = make_str("update"); } | DELETE_P { $$ = make_str("delete"); } | INSERT { $$ = make_str("insert"); } - ; + | TRUNCATE { $$ = make_str("truncate"); } + ; opt_instead: INSTEAD { $$ = make_str("instead"); } + | ALSO { $$ = make_str("also"); } | /*EMPTY*/ { $$ = EMPTY; } ; -DropRuleStmt: DROP RULE name ON qualified_name - { $$ = cat_str(4, make_str("drop rule"), $3, make_str("on"), $5);} +DropRuleStmt: DROP RULE name ON qualified_name opt_drop_behavior + { $$ = cat_str(5, make_str("drop rule"), $3, make_str("on"), $5, $6);} + | DROP RULE IF_P EXISTS name ON qualified_name opt_drop_behavior + { $$ = cat_str(5, make_str("drop rule if exists"), $5, make_str("on"), $7, $8);} ; /***************************************************************************** @@ -2067,15 +3015,15 @@ DropRuleStmt: DROP RULE name ON qualified_name * *****************************************************************************/ -NotifyStmt: NOTIFY qualified_name - { $$ = cat2_str(make_str("notify"), $2); } +NotifyStmt: NOTIFY ColId + { $$ = cat2_str(make_str("notify"), $2); } ; -ListenStmt: LISTEN qualified_name - { $$ = cat2_str(make_str("listen"), $2); } +ListenStmt: LISTEN ColId + { $$ = cat2_str(make_str("listen"), $2); } ; -UnlistenStmt: UNLISTEN qualified_name +UnlistenStmt: UNLISTEN ColId { $$ = cat2_str(make_str("unlisten"), $2); } | UNLISTEN '*' { $$ = make_str("unlisten *"); } @@ -2090,41 +3038,82 @@ UnlistenStmt: UNLISTEN qualified_name * (also older versions END / ABORT) * *****************************************************************************/ -TransactionStmt: ABORT_TRANS opt_trans { $$ = make_str("rollback"); } - | BEGIN_TRANS opt_trans { $$ = make_str("begin transaction"); } - | COMMIT opt_trans { $$ = make_str("commit"); } - | COMMIT opt_trans opt_chain { $$ = cat2_str(make_str("commit"), $3); } - | END_TRANS opt_trans { $$ = make_str("commit"); } - | ROLLBACK opt_trans { $$ = make_str("rollback"); } - | ROLLBACK opt_trans opt_chain { $$ = cat2_str(make_str("rollback"), $3); } - ; - -opt_trans: WORK { $$ = EMPTY; } +TransactionStmt: ABORT_P opt_transaction { $$ = make_str("rollback"); } + | BEGIN_P opt_transaction transaction_mode_list_or_empty { $$ = cat2_str(make_str("begin transaction"), $3); } + | START TRANSACTION transaction_mode_list_or_empty { $$ = cat2_str(make_str("start transaction"), $3); } + | COMMIT opt_transaction { $$ = make_str("commit"); } + | END_P opt_transaction { $$ = make_str("commit"); } + | ROLLBACK opt_transaction { $$ = make_str("rollback"); } + | SAVEPOINT ColId { $$ = cat2_str(make_str("savepoint"), $2); } + | RELEASE SAVEPOINT ColId { $$ = cat2_str(make_str("release savepoint"), $3); } + | RELEASE ColId { $$ = cat2_str(make_str("release"), $2); } + | ROLLBACK opt_transaction TO SAVEPOINT ColId { $$ = cat_str(4, make_str("rollback"), $2, make_str("to savepoint"), $5); } + | ROLLBACK opt_transaction TO ColId { $$ = cat_str(4, make_str("rollback"), $2, make_str("to"), $4); } + | PREPARE TRANSACTION StringConst { $$ = cat2_str(make_str("prepare transaction"), $3); } + | COMMIT PREPARED StringConst { $$ = cat2_str(make_str("commit prepared"), $3); } + | ROLLBACK PREPARED StringConst { $$ = cat2_str(make_str("rollback prepared"), $3); } + ; + +opt_transaction: WORK { $$ = EMPTY; } | TRANSACTION { $$ = EMPTY; } | /*EMPTY*/ { $$ = EMPTY; } ; -opt_chain: AND NO CHAIN - { $$ = make_str("and no chain"); } - | AND CHAIN - { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported COMMIT/CHAIN will be passed to backend"); +transaction_mode_item: + ISOLATION LEVEL iso_level + { $$ = cat2_str(make_str("isolation level"), $3); } + | READ ONLY { $$ = make_str("read only"); } + | READ WRITE { $$ = make_str("read write"); } + ; - $$ = make_str("and chain"); - } +transaction_mode_list: + transaction_mode_item { $$ = $1; } + | transaction_mode_list ',' transaction_mode_item { $$ = cat_str(3, $1, make_str(","), $3); } + | transaction_mode_list transaction_mode_item { $$ = cat_str(3, $1, make_str(" "), $2); } + ; + +transaction_mode_list_or_empty: + transaction_mode_list { $$ = $1; } + | /* EMPTY */ { $$ = EMPTY; } ; /***************************************************************************** * - * QUERY: - * define view '('target-list ')' [where ] + * QUERY: + * CREATE [ OR REPLACE ] [ TEMP ] VIEW '('target-list ')' + * AS [ WITH [ CASCADED | LOCAL ] CHECK OPTION ] * *****************************************************************************/ -ViewStmt: CREATE VIEW qualified_name opt_column_list AS SelectStmt - { $$ = cat_str(5, make_str("create view"), $3, $4, make_str("as"), $6); } +ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list AS SelectStmt opt_check_option + { $$ = cat_str(8, make_str("create"), $2, make_str("view"), $4, $5, make_str("as"), $7, $8); } + | CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list AS SelectStmt opt_check_option + { $$ = cat_str(8, make_str("create or replace"), $4, make_str("view"), $6, $7, make_str("as"), $9, $10); } ; +/* + * We use merged tokens here to avoid creating shift/reduce conflicts against + * a whole lot of other uses of WITH. + */ +opt_check_option: + WITH_CHECK OPTION + { + mmerror(PARSE_ERROR, ET_ERROR, "WITH CHECK OPTION not implemented"); + $$ = EMPTY; + } + | WITH_CASCADED CHECK OPTION + { + mmerror(PARSE_ERROR, ET_ERROR, "WITH CHECK OPTION not implemented"); + $$ = EMPTY; + } + | WITH_LOCAL CHECK OPTION + { + mmerror(PARSE_ERROR, ET_ERROR, "WITH CHECK OPTION not implemented"); + $$ = EMPTY; + } + | /* EMPTY */ + { $$ = EMPTY; } + ; /***************************************************************************** * @@ -2157,7 +3146,11 @@ createdb_opt_list: createdb_opt_item { $$ = cat2_str($1, $2); } ; -createdb_opt_item: LOCATION opt_equal StringConst +createdb_opt_item: TABLESPACE opt_equal name + { $$ = cat_str(3,make_str("tablespace"), $2, $3); } + | TABLESPACE opt_equal DEFAULT + { $$ = cat_str(3, make_str("tablespace"), $2, make_str("default")); } + | LOCATION opt_equal StringConst { $$ = cat_str(3,make_str("location"), $2, $3); } | LOCATION opt_equal DEFAULT { $$ = cat_str(3, make_str("location"), $2, make_str("default")); } @@ -2169,6 +3162,8 @@ createdb_opt_item: LOCATION opt_equal StringConst { $$ = cat_str(3, make_str("encoding"), $2, $3); } | ENCODING opt_equal DEFAULT { $$ = cat_str(3, make_str("encoding"), $2, make_str("default")); } + | CONNECTION LIMIT opt_equal PosIntConst + { $$ = cat_str(3, make_str("connection limit"), $3, $4); } | OWNER opt_equal name { $$ = cat_str(3, make_str("owner"), $2, $3); } | OWNER opt_equal DEFAULT @@ -2187,21 +3182,34 @@ opt_equal: '=' { $$ = make_str("="); } * *****************************************************************************/ -AlterDatabaseSetStmt: ALTER DATABASE database_name SET set_rest - { $$ = cat_str(4, make_str("alter database"), $3, make_str("set"), $5); } - | ALTER DATABASE database_name VariableResetStmt +AlterDatabaseStmt: ALTER DATABASE database_name opt_with alterdb_opt_list + { $$ = cat_str(4, make_str("alter database"), $3, $4, $5); } + ; + +AlterDatabaseSetStmt: ALTER DATABASE database_name SetResetClause { $$ = cat_str(3, make_str("alter database"), $3, $4); } ; +alterdb_opt_list: + alterdb_opt_list alterdb_opt_item { $$ = cat2_str($1, $2);} + | /* EMPTY */ { $$ = EMPTY; } + ; + +alterdb_opt_item: + CONNECTION LIMIT opt_equal PosIntConst { $$ = cat_str(3, make_str("connection limit"), $3, $4); } + ; + /***************************************************************************** * - * DROP DATABASE + * DROP DATABASE [ IF EXISTS ] * * *****************************************************************************/ DropdbStmt: DROP DATABASE database_name { $$ = cat2_str(make_str("drop database"), $3); } + | DROP DATABASE IF_P EXISTS database_name + { $$ = cat2_str(make_str("drop database if exists"), $5); } ; @@ -2211,27 +3219,76 @@ DropdbStmt: DROP DATABASE database_name * *****************************************************************************/ -CreateDomainStmt: CREATE DOMAIN_P any_name opt_as Typename ColQualList opt_collate - { - $$ = cat_str(6, make_str("create domain"), $3, $4, $5, $6, $7); - } +CreateDomainStmt: CREATE DOMAIN_P any_name opt_as Typename ColQualList + { + $$ = cat_str(5, make_str("create domain"), $3, $4, $5, $6); + } + ; + +AlterDomainStmt: + ALTER DOMAIN_P any_name alter_column_default + { $$ = cat_str(3, make_str("alter domain"), $3, $4); } + | ALTER DOMAIN_P any_name DROP NOT NULL_P + { $$ = cat_str(3, make_str("alter domain"), $3, make_str("drop not null")); } + | ALTER DOMAIN_P any_name SET NOT NULL_P + { $$ = cat_str(3, make_str("alter domain"), $3, make_str("set not null")); } + | ALTER DOMAIN_P any_name ADD_P TableConstraint + { $$ = cat_str(4, make_str("alter domain"), $3, make_str("add"), $5); } + | ALTER DOMAIN_P any_name DROP CONSTRAINT name opt_drop_behavior + { $$ = cat_str(5, make_str("alter domain"), $3, make_str("drop constraint"), $6, $7); } ; - + opt_as: AS {$$ = make_str("as"); } - | /* EMPTY */ {$$ = EMPTY; } - ; - + | /* EMPTY */ {$$ = EMPTY; } + ; + +AlterTSDictionaryStmt: + ALTER TEXT_P SEARCH DICTIONARY any_name definition + { $$ = cat_str(3, make_str("alter text search dictionary"), $5, $6); } + ; + +AlterTSConfigurationStmt: + ALTER TEXT_P SEARCH CONFIGURATION any_name ADD_P MAPPING FOR name_list WITH any_name_list + { $$ = cat_str(6, make_str("alter text search configuration"), $5, make_str("add mapping for"), $9, make_str("with"), $11); } + | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list WITH any_name_list + { $$ = cat_str(6, make_str("alter text search configuration"), $5, make_str("alter mapping for"), $9, make_str("with"), $11); } + | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING REPLACE any_name WITH any_name + { $$ = cat_str(6, make_str("alter text search configuration"), $5, make_str("alter mapping replace"), $9, make_str("with"), $11); } + | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list REPLACE any_name WITH any_name + { $$ = cat_str(8, make_str("alter text search configuration"), $5, make_str("alter mapping for"), $9, make_str("replace"), $11, make_str("with"), $13); } + | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING FOR name_list + { $$ = cat_str(4, make_str("alter text search configuration"), $5, make_str("drop mapping for"), $9); } + | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING IF_P EXISTS FOR name_list + { $$ = cat_str(4, make_str("alter text search configuration"), $5, make_str("drop mapping if exists for"), $11); } + ; + +CreateConversionStmt: + CREATE opt_default CONVERSION_P any_name FOR StringConst + TO StringConst FROM any_name + { $$ = cat_str(10, make_str("create"), $2, make_str("conversion"), $4, make_str("for"), $6, make_str("to"), $8, make_str("from"), $10); } + ; + /***************************************************************************** * * QUERY: - * cluster on + * cluster on + * cluster + * cluster * *****************************************************************************/ -ClusterStmt: CLUSTER index_name ON qualified_name - { $$ = cat_str(4, make_str("cluster"), $2, make_str("on"), $4); } +ClusterStmt: CLUSTER qualified_name cluster_index_specification + { $$ = cat_str(3,make_str("cluster"), $2, $3); } + | CLUSTER + { $$ = make_str("cluster"); } + | CLUSTER qualified_name ON qualified_name + { $$ = cat_str(4, make_str("cluster"), $2, make_str("on"), $4); } ; +cluster_index_specification: + USING index_name { $$ = cat2_str(make_str("using"), $2); } + | /*EMPTY*/ { $$ = EMPTY; } + ; /***************************************************************************** * @@ -2256,7 +3313,7 @@ AnalyzeStmt: analyze_keyword opt_verbose ; analyze_keyword: ANALYZE { $$ = make_str("analyze"); } - | ANALYSE { $$ = make_str("analyse"); } + | ANALYSE { $$ = make_str("analyse"); } ; opt_verbose: VERBOSE { $$ = make_str("verbose"); } @@ -2285,31 +3342,67 @@ opt_name_list: '(' name_list ')' * *****************************************************************************/ -ExplainStmt: EXPLAIN opt_verbose OptimizableStmt - { $$ = cat_str(3, make_str("explain"), $2, $3); } - | EXPLAIN analyze_keyword opt_verbose OptimizableStmt +ExplainStmt: EXPLAIN opt_analyze opt_verbose ExplainableStmt { $$ = cat_str(4, make_str("explain"), $2, $3, $4); } ; +ExplainableStmt: + SelectStmt + | InsertStmt + | UpdateStmt + | DeleteStmt + | DeclareCursorStmt + | ExecuteStmt + ; +opt_analyze: + analyze_keyword { $$ = $1; } + | /* EMPTY */ { $$ = EMPTY; } + ; -/***************************************************************************** - * * - * Optimizable Stmts: * - * * - * one of the five queries processed by the planner * - * * - * [ultimately] produces query-trees as specified * - * in the query-spec document in ~postgres/ref * - * * - *****************************************************************************/ +PrepareStmt: PREPARE prepared_name prep_type_clause AS PreparableStmt + { + $$.name = $2; + $$.type = $3; + $$.stmt = cat_str(3, make_str("\""), $5, make_str("\"")); + } + | PREPARE prepared_name FROM execstring /* ECPG addon */ + { + $$.name = $2; + $$.type = NULL; + $$.stmt = $4; + } + ; -OptimizableStmt: SelectStmt - | CursorStmt - | UpdateStmt +PreparableStmt: + SelectStmt | InsertStmt + | UpdateStmt | DeleteStmt ; +prep_type_clause: '(' type_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | /* EMPTY */ { $$ = EMPTY; } + ; + +ExecuteStmt: EXECUTE prepared_name execute_param_clause execute_rest /* execute_rest is an ecpg addon */ + { + /* $$ = cat_str(3, make_str("ECPGprepared_statement("), connection, $2, make_str("__LINE__)"));*/ + $$ = $2; + } + | CREATE OptTemp TABLE create_as_target AS + EXECUTE prepared_name execute_param_clause + { $$ = cat_str(7, make_str("create"), $2, make_str("table"), $4, make_str("as execute"), $7, $8); } + ; + +execute_param_clause: '(' expr_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | /* EMPTY */ { $$ = EMPTY; } + ; + +DeallocateStmt: DEALLOCATE prepared_name { $$ = $2; } + | DEALLOCATE PREPARE prepared_name { $$ = $3; } + | DEALLOCATE ALL { $$ = make_str("all"); } + | DEALLOCATE PREPARE ALL { $$ = make_str("all"); } + ; /***************************************************************************** * @@ -2318,20 +3411,17 @@ OptimizableStmt: SelectStmt * *****************************************************************************/ -InsertStmt: INSERT INTO qualified_name insert_rest - { $$ = cat_str(3, make_str("insert into"), $3, $4); } +InsertStmt: INSERT INTO qualified_name insert_rest returning_clause + { $$ = cat_str(4, make_str("insert into"), $3, $4, $5); } ; -insert_rest: VALUES '(' insert_target_list ')' - { $$ = cat_str(3, make_str("values("), $3, make_str(")")); } - | DEFAULT VALUES - { $$ = make_str("default values"); } - | SelectStmt +insert_rest: + SelectStmt { $$ = $1; } - | '(' insert_column_list ')' VALUES '(' insert_target_list ')' - { $$ = cat_str(5, make_str("("), $2, make_str(") values ("), $6, make_str(")")); } | '(' insert_column_list ')' SelectStmt { $$ = cat_str(4, make_str("("), $2, make_str(")"), $4); } + | DEFAULT VALUES + { $$ = make_str("default values"); } ; insert_column_list: insert_column_list ',' insert_column_item @@ -2344,6 +3434,9 @@ insert_column_item: ColId opt_indirection { $$ = cat2_str($1, $2); } ; +returning_clause: RETURNING target_list { $$ = cat2_str(make_str("returning"), $2); } + | /* EMPTY */ { $$ = EMPTY; } + ; /***************************************************************************** * @@ -2352,12 +3445,16 @@ insert_column_item: ColId opt_indirection * *****************************************************************************/ -DeleteStmt: DELETE_P FROM relation_expr where_clause - { $$ = cat_str(3, make_str("delete from"), $3, $4); } +DeleteStmt: DELETE_P FROM relation_expr_opt_alias using_clause where_or_current_clause returning_clause + { $$ = cat_str(5, make_str("delete from"), $3, $4, $5, $6); } + ; + +using_clause: USING from_list { $$ = cat2_str(make_str("using"), $2); } + | /* EMPTY */ { $$ = EMPTY; } ; -LockStmt: LOCK_P opt_table qualified_name_list opt_lock - { $$ = cat_str(4, make_str("lock"), $2, $3, $4); } +LockStmt: LOCK_P opt_table qualified_name_list opt_lock opt_nowait + { $$ = cat_str(5, make_str("lock"), $2, $3, $4, $5); } ; opt_lock: IN_P lock_type MODE @@ -2376,6 +3473,10 @@ lock_type: ACCESS SHARE { $$ = make_str("access share"); } | ACCESS EXCLUSIVE { $$ = make_str("access exclusive"); } ; +opt_nowait: NOWAIT { $$ = make_str("nowait"); } + | /* EMPTY */ { $$ = EMPTY; } + ; + /***************************************************************************** * * QUERY: @@ -2383,13 +3484,37 @@ lock_type: ACCESS SHARE { $$ = make_str("access share"); } * *****************************************************************************/ -UpdateStmt: UPDATE relation_expr - SET update_target_list +UpdateStmt: UPDATE relation_expr_opt_alias + SET set_clause_list from_clause - where_clause - {$$ = cat_str(6, make_str("update"), $2, make_str("set"), $4, $5, $6); } + where_or_current_clause + returning_clause + {$$ = cat_str(7, make_str("update"), $2, make_str("set"), $4, $5, $6, $7); } + ; + +set_clause_list: + set_clause { $$ = $1; } + | set_clause_list ',' set_clause { $$ = cat_str(3, $1, make_str(","), $3); } ; +set_clause: + single_set_clause { $$ = $1; } + | multiple_set_clause { $$ = $1; } + ; + +single_set_clause: + set_target '=' ctext_expr { $$ = cat_str(3, $1, make_str("="), $3); }; + +multiple_set_clause: + '(' set_target_list ')' '=' ctext_row { $$ = cat_str(4, make_str("("), $2, make_str(")="), $5); }; + +set_target: + ColId opt_indirection { $$ = cat2_str($1, $2); }; + +set_target_list: + set_target { $$ = $1; } + | set_target_list ',' set_target { $$ = cat_str(3, $1, make_str(","), $3); } + ; /***************************************************************************** * @@ -2397,18 +3522,15 @@ UpdateStmt: UPDATE relation_expr * CURSOR STATEMENTS * *****************************************************************************/ -CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt +DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt { struct cursor *ptr, *this; for (ptr = cur; ptr != NULL; ptr = ptr->next) { if (strcmp($2, ptr->name) == 0) - { - /* re-definition is a bug */ - snprintf(errortext, sizeof(errortext), "cursor %s already defined", $2); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + /* re-definition is a bug */ + mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" already defined", $2); } this = (struct cursor *) mm_alloc(sizeof(struct cursor)); @@ -2417,23 +3539,37 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt this->next = cur; this->name = $2; this->connection = connection; - this->command = cat_str(5, make_str("declare"), mm_strdup($2), $3, make_str("cursor for"), $6); + this->opened = false; + this->command = cat_str(7, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for"), $7); this->argsinsert = argsinsert; this->argsresult = argsresult; argsinsert = argsresult = NULL; - cur = this; - $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/")); + if (INFORMIX_MODE) + $$ = cat_str(5, adjust_informix(this->argsinsert), adjust_informix(this->argsresult), make_str("/*"), mm_strdup(this->command), make_str("*/")); + else + $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/")); } ; -opt_cursor: BINARY { $$ = make_str("binary"); } - | INSENSITIVE { $$ = make_str("insensitive"); } - | SCROLL { $$ = make_str("scroll"); } - | INSENSITIVE SCROLL { $$ = make_str("insensitive scroll"); } - | /*EMPTY*/ { $$ = EMPTY; } - ; +cursor_options: /* EMPTY */ { $$ = EMPTY; } + | cursor_options BINARY { $$ = cat2_str($1, make_str("binary")); } + | cursor_options INSENSITIVE { $$ = cat2_str($1, make_str("insensitive")); } + | cursor_options SCROLL { $$ = cat2_str($1, make_str("scroll")); } + | cursor_options NO SCROLL { $$ = cat2_str($1, make_str("no scroll")); } + ; + +opt_hold: /* EMPTY */ + { + if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit == true) + $$ = make_str("with hold"); + else + $$ = EMPTY; + } + | WITH HOLD { $$ = make_str("with hold"); } + | WITHOUT HOLD { $$ = make_str("without hold"); } + ; /***************************************************************************** * @@ -2456,12 +3592,12 @@ select_with_parens: '(' select_no_parens ')' select_no_parens: simple_select { $$ = $1; } - | select_clause sort_clause opt_for_update_clause opt_select_limit - { $$ = cat_str(4, $1, $2, $3, $4); } - | select_clause for_update_clause opt_select_limit - { $$ = cat_str(3, $1, $2, $3); } - | select_clause select_limit + | select_clause sort_clause { $$ = cat2_str($1, $2); } + | select_clause opt_sort_clause for_locking_clause opt_select_limit + { $$ = cat_str(4, $1, $2, $3, $4); } + | select_clause opt_sort_clause select_limit opt_for_locking_clause + { $$ = cat_str(4, $1, $2, $3, $4); } ; select_clause: simple_select { $$ = $1; } @@ -2472,6 +3608,8 @@ simple_select: SELECT opt_distinct target_list into_clause from_clause where_clause group_clause having_clause { $$ = cat_str(8, make_str("select"), $2, $3, $4, $5, $6, $7, $8); } + | values_clause + { $$ = $1; } | select_clause UNION opt_all select_clause { $$ = cat_str(4, $1, make_str("union"), $3, $4); } | select_clause INTERSECT opt_all select_clause @@ -2505,15 +3643,9 @@ OptTempTableName: TEMPORARY opt_table qualified_name | LOCAL TEMP opt_table qualified_name { $$ = cat_str(3, make_str("local temp"), $3, $4); } | GLOBAL TEMPORARY opt_table qualified_name - { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE TABLE / GLOBAL TEMPORARY will be passed to backend"); - $$ = cat_str(3, make_str("global temporary"), $3, $4); - } + { $$ = cat_str(3, make_str("global temporary"), $3, $4); } | GLOBAL TEMP opt_table qualified_name - { - mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE TABLE / GLOBAL TEMP will be passed to backend"); - $$ = cat_str(3, make_str("global temp"), $3, $4); - } + { $$ = cat_str(3, make_str("global temp"), $3, $4); } | TABLE qualified_name { $$ = cat2_str(make_str("table"), $2); } | qualified_name @@ -2538,6 +3670,10 @@ opt_distinct: DISTINCT { $$ = EMPTY; } ; +opt_sort_clause: sort_clause { $$ = $1; } + | /* EMPTY */ { $$ = EMPTY; } + ; + sort_clause: ORDER BY sortby_list { $$ = cat2_str(make_str("order by"), $3); } ; @@ -2546,14 +3682,10 @@ sortby_list: sortby { $$ = $1; } | sortby_list ',' sortby { $$ = cat_str(3, $1, make_str(","), $3); } ; -sortby: a_expr OptUseOp - { $$ = cat2_str($1, $2); } - ; - -OptUseOp: USING all_Op { $$ = cat2_str(make_str("using"), $2); } - | ASC { $$ = make_str("asc"); } - | DESC { $$ = make_str("desc"); } - | /*EMPTY*/ { $$ = EMPTY; } +sortby: a_expr USING qual_all_Op opt_nulls_order + { $$ = cat_str(4, $1, make_str("using"), $3, $4); } + | a_expr opt_asc_desc opt_nulls_order + { $$ = cat_str(3, $1, $2, $3); } ; select_limit: LIMIT select_limit_value OFFSET select_offset_value @@ -2565,30 +3697,21 @@ select_limit: LIMIT select_limit_value OFFSET select_offset_value | OFFSET select_offset_value { $$ = cat2_str(make_str("offset"), $2); } | LIMIT select_limit_value ',' select_offset_value - { mmerror(PARSE_ERROR, ET_WARNING, "No longer supported LIMIT #,# syntax passed to backend."); } + { + mmerror(PARSE_ERROR, ET_WARNING, "no longer supported LIMIT #,# syntax passed to backend"); + $$ = cat_str(4, make_str("limit"), $2, make_str(","), $4); + } ; opt_select_limit: select_limit { $$ = $1; } | /*EMPTY*/ { $$ = EMPTY; } ; -select_limit_value: PosIntConst - { - if (atoi($1) < 0) - mmerror(PARSE_ERROR, ET_ERROR, "LIMIT must not be negative"); - $$ = $1; - } - | ALL { $$ = make_str("all"); } - | PARAM { $$ = make_name(); } +select_limit_value: a_expr { $$ = $1; } + | ALL { $$ = make_str("all"); } ; -select_offset_value: PosIntConst - { - if (atoi($1) < 0) - mmerror(PARSE_ERROR, ET_ERROR, "OFFSET must not be negative"); - $$ = $1; - } - | PARAM { $$ = make_name(); } +select_offset_value: a_expr { $$ = $1; } ; /* @@ -2610,18 +3733,37 @@ having_clause: HAVING a_expr { $$ = EMPTY; } ; -for_update_clause: FOR UPDATE update_list - { $$ = make_str("for update"); } - | FOR READ ONLY - { $$ = make_str("for read only"); } +for_locking_clause: + for_locking_items { $$ = $1; } + | FOR READ ONLY { $$ = make_str("for read only");} ; -opt_for_update_clause: for_update_clause { $$ = $1; } - | /* EMPTY */ { $$ = EMPTY; } +opt_for_locking_clause: + for_locking_clause { $$ = $1; } + | /* EMPTY */ { $$ = EMPTY; } ; -update_list: OF name_list { $$ = cat2_str(make_str("of"), $2); } - | /* EMPTY */ { $$ = EMPTY; } +for_locking_items: + for_locking_item { $$ = $1; } + | for_locking_items for_locking_item { $$ = cat2_str($1, $2); } + ; + +for_locking_item: + FOR UPDATE locked_rels_list opt_nowait + { $$ = cat_str(3, make_str("for update"), $3, $4); } + | FOR SHARE locked_rels_list opt_nowait + { $$ = cat_str(3, make_str("for share"), $3, $4); } + ; + +locked_rels_list: + OF name_list { $$ = cat2_str(make_str("of"), $2); } + | /* EMPTY */ { $$ = EMPTY; } + ; + +values_clause: VALUES ctext_row + { $$ = cat2_str(make_str("values"), $2); } + | values_clause ',' ctext_row + { $$ = cat_str(3, $1, make_str(","), $3); } ; /***************************************************************************** @@ -2650,19 +3792,28 @@ from_list: from_list ',' table_ref { $$ = cat_str(3, $1, make_str(","), $3); } table_ref: relation_expr { $$ = $1; } | relation_expr alias_clause - { $$= cat2_str($1, $2); } + { $$ = cat2_str($1, $2); } | func_table { $$ = $1; } | func_table alias_clause - { $$= cat2_str($1, $2); } + { $$ = cat2_str($1, $2); } + | func_table AS '(' TableFuncElementList ')' + { $$ = cat_str(4, $1, make_str("as ("), $4, make_str(")")); } + | func_table AS ColId '(' TableFuncElementList ')' + { $$ = cat_str(6, $1, make_str("as"), $3, make_str("("), $5, make_str(")"));} + | func_table ColId '(' TableFuncElementList ')' + { $$ = cat_str(5, $1, $2, make_str("("), $4, make_str(")")); } | select_with_parens - {mmerror(PARSE_ERROR, ET_ERROR, "sub-SELECT in FROM must have an alias");} + { + mmerror(PARSE_ERROR, ET_ERROR, "sub-SELECT in FROM must have an alias"); + $$ = $1; + } | select_with_parens alias_clause - { $$=cat2_str($1, $2); } + { $$ = cat2_str($1, $2); } | joined_table { $$ = $1; } | '(' joined_table ')' alias_clause - { $$=cat_str(4, make_str("("), $2, make_str(")"), $4); } + { $$ = cat_str(4, make_str("("), $2, make_str(")"), $4); } ; /* @@ -2686,8 +3837,6 @@ joined_table: '(' joined_table ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } | table_ref CROSS JOIN table_ref { $$ = cat_str(3, $1, make_str("cross join"), $4); } - | table_ref UNIONJOIN table_ref - { $$ = cat_str(3, $1, make_str("unionjoin"), $3); } | table_ref join_type JOIN table_ref join_qual { $$ = cat_str(5, $1, $2, make_str("join"), $4, $5); } | table_ref JOIN table_ref join_qual @@ -2737,19 +3886,40 @@ relation_expr: qualified_name | qualified_name '*' { /* inheritance query */ $$ = cat2_str($1, make_str("*")); } | ONLY qualified_name - { /* inheritance query */ $$ = cat2_str(make_str("ONLY "), $2); } + { /* inheritance query */ $$ = cat2_str(make_str("only "), $2); } + | ONLY '(' qualified_name ')' + { /* inheritance query */ $$ = cat_str(3, make_str("only ("), $3, make_str(")")); } ; -func_table: func_name '(' ')' - { $$ = cat2_str($1, make_str("()")); } - | func_name '(' expr_list ')' - { $$ = cat_str(4, $1, make_str("("), $3, make_str(")")); } - ; +relation_expr_opt_alias: relation_expr %prec UMINUS + { $$ = $1; } + | relation_expr ColId + { $$ = cat2_str($1, $2); } + | relation_expr AS ColId + { $$ = cat_str(3, $1, make_str("as"), $3); } + ; + +func_table: func_expr { $$ = $1; } + ; where_clause: WHERE a_expr { $$ = cat2_str(make_str("where"), $2); } | /*EMPTY*/ { $$ = EMPTY; /* no qualifiers */ } ; +where_or_current_clause: WHERE a_expr { $$ = cat2_str(make_str("where"), $2); } + | WHERE CURRENT_P OF name { $$ = cat2_str(make_str("where current of"), $4); } + | WHERE CURRENT_P OF PARAM { $$ = make_str("where current of param"); } + | /*EMPTY*/ { $$ = EMPTY; /* no qualifiers */ } + ; + +TableFuncElementList: TableFuncElement + { $$ = $1; } + | TableFuncElementList ',' TableFuncElement + { $$ = cat_str(3, $1, make_str(","), $3); } + ; + +TableFuncElement: ColId Typename { $$ = cat2_str($1, $2); } + ; /***************************************************************************** * @@ -2763,69 +3933,77 @@ where_clause: WHERE a_expr { $$ = cat2_str(make_str("where"), $2); } Typename: SimpleTypename opt_array_bounds { $$ = cat2_str($1, $2.str); } - | SETOF SimpleTypename - { $$ = cat2_str(make_str("setof"), $2); } + | SETOF SimpleTypename opt_array_bounds + { $$ = cat_str(3, make_str("setof"), $2, $3); } + | SimpleTypename ARRAY '[' PosIntConst ']' + { $$ = cat_str(4, $1, make_str("array ["), $4, make_str("]")); } + | SETOF SimpleTypename ARRAY '[' PosIntConst ']' + { $$ = cat_str(5, make_str("setof"), $2, make_str("array ["), $5, make_str("]")); } ; opt_array_bounds: '[' ']' opt_array_bounds { - $$.index1 = 0; + $$.index1 = make_str("0"); $$.index2 = $3.index1; $$.str = cat2_str(make_str("[]"), $3.str); } | '[' Iresult ']' opt_array_bounds { - char *txt = mm_alloc(20L); - - sprintf (txt, "%d", $2); - $$.index1 = $2; + $$.index1 = strdup($2); $$.index2 = $4.index1; - $$.str = cat_str(4, make_str("["), txt, make_str("]"), $4.str); + $$.str = cat_str(4, make_str("["), $2, make_str("]"), $4.str); } | /* EMPTY */ { - $$.index1 = -1; - $$.index2 = -1; + $$.index1 = make_str("-1"); + $$.index2 = make_str("-1"); $$.str= EMPTY; } ; -Iresult: PosIntConst { $$ = atol($1); } - | '(' Iresult ')' { $$ = $2; } - | Iresult '+' Iresult { $$ = $1 + $3; } - | Iresult '-' Iresult { $$ = $1 - $3; } - | Iresult '*' Iresult { $$ = $1 * $3; } - | Iresult '/' Iresult { $$ = $1 / $3; } - | Iresult '%' Iresult { $$ = $1 % $3; } +Iresult: PosIntConst { $$ = $1; } + | '(' Iresult ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | Iresult '+' Iresult { $$ = cat_str(3, $1, make_str("+"), $3); } + | Iresult '-' Iresult { $$ = cat_str(3, $1, make_str("-"), $3); } + | Iresult '*' Iresult { $$ = cat_str(3, $1, make_str("*"), $3); } + | Iresult '/' Iresult { $$ = cat_str(3, $1, make_str("/"), $3); } + | Iresult '%' Iresult { $$ = cat_str(3, $1, make_str("%"), $3); } + | Sconst { $$ = $1; } + | ColId { $$ = $1; } ; -SimpleTypename: ConstTypename - { $$ = $1; } +SimpleTypename: GenericType { $$ = $1; } + | ConstDatetime { $$ = $1; } + | Numeric { $$ = $1; } + | Bit { $$ = $1; } + | Character { $$ = $1; } | ConstInterval opt_interval { $$ = cat2_str($1, $2); } | ConstInterval '(' PosIntConst ')' opt_interval { $$ = cat_str(5, $1, make_str("("), $3, make_str(")"), $5); } - | type_name attrs - { $$ = cat2_str($1, $2);} ; -ConstTypename: Generic { $$ = $1; } +ConstTypename: Numeric { $$ = $1; } + | ConstBit { $$ = $1; } + | ConstCharacter { $$ = $1; } | ConstDatetime { $$ = $1; } - | Numeric { $$ = $1; } - | Bit { $$ = $1; } - | Character { $$ = $1; } ; -Generic: type_name { $$ = $1; } +GenericType: type_function_name opt_type_modifiers { $$ = cat2_str($1, $2); } + | type_function_name attrs opt_type_modifiers { $$ = cat_str(3, $1, $2, $3); } ; +opt_type_modifiers: '(' expr_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } + | /* EMPTY */ { $$ = EMPTY; } + ; + /* SQL92 numeric data types * Check FLOAT() precision limits assuming IEEE floating types. * Provide real DECIMAL() and NUMERIC() implementations now - Jan 1998-12-30 * - thomas 1997-09-18 */ -Numeric: INT +Numeric: INT_P { $$ = make_str("int"); } | INTEGER { $$ = make_str("integer"); } @@ -2837,15 +4015,15 @@ Numeric: INT { $$ = make_str("real"); } | FLOAT_P opt_float { $$ = cat2_str(make_str("float"), $2); } - | DOUBLE PRECISION + | DOUBLE_P PRECISION { $$ = make_str("double precision"); } - | DECIMAL opt_decimal + | DECIMAL_P opt_type_modifiers { $$ = cat2_str(make_str("decimal"), $2); } - | DEC opt_decimal + | DEC opt_type_modifiers { $$ = cat2_str(make_str("dec"), $2); } - | NUMERIC opt_numeric + | NUMERIC opt_type_modifiers { $$ = cat2_str(make_str("numeric"), $2); } - | BOOLEAN + | BOOLEAN_P { $$ = make_str("boolean"); } ; @@ -2855,29 +4033,24 @@ opt_float: '(' PosIntConst ')' { $$ = EMPTY; } ; -opt_numeric: '(' PosIntConst ',' PosIntConst ')' - { $$ = cat_str(5, make_str("("), $2, make_str(","), $4, make_str(")")); } - | '(' PosIntConst ')' - { $$ = cat_str(3, make_str("("), $2, make_str(")")); } - | /*EMPTY*/ - { $$ = EMPTY; } - ; - -opt_decimal: '(' PosIntConst ',' PosIntConst ')' - { $$ = cat_str(5, make_str("("), $2, make_str(","), $4, make_str(")")); } - | '(' PosIntConst ')' - { $$ = cat_str(3, make_str("("), $2, make_str(")")); } - | /*EMPTY*/ - { $$ = EMPTY; } - ; - /* * SQL92 bit-field data types * The following implements BIT() and BIT VARYING(). */ -Bit: BIT opt_varying '(' PosIntConst ')' + +Bit: BitWithLength { $$ = $1; } + | BitWithoutLength { $$ = $1; } + ; + +ConstBit: BitWithLength { $$ = $1; } + | BitWithoutLength { $$ = $1; } + ; + +BitWithLength: BIT opt_varying '(' expr_list ')' { $$ = cat_str(5, make_str("bit"), $2, make_str("("), $4, make_str(")")); } - | BIT opt_varying + ; + +BitWithoutLength: BIT opt_varying { $$ = cat2_str(make_str("bit"), $2); } ; @@ -2886,9 +4059,19 @@ Bit: BIT opt_varying '(' PosIntConst ')' * The following implements CHAR() and VARCHAR(). * - ay 6/95 */ -Character: character '(' PosIntConst ')' opt_charset +Character: CharacterWithLength { $$ = $1; } + | CharacterWithoutLength { $$ = $1; } + ; + +ConstCharacter: CharacterWithLength { $$ = $1; } + | CharacterWithoutLength { $$ = $1; } + ; + +CharacterWithLength: character '(' PosIntConst ')' opt_charset { $$ = cat_str(5, $1, make_str("("), $3, make_str(")"), $5); } - | character opt_charset + ; + +CharacterWithoutLength: character opt_charset { $$ = cat2_str($1, $2); } ; @@ -2918,12 +4101,6 @@ opt_charset: CHARACTER SET ColId { $$ = EMPTY; } ; -opt_collate: COLLATE ColId - { $$ = cat2_str(make_str("collate"), $2); } - | /*EMPTY*/ - { $$ = EMPTY; } - ; - ConstDatetime: TIMESTAMP '(' PosIntConst ')' opt_timezone { $$ = cat_str(4, make_str("timestamp("), $3, make_str(")"), $5); } | TIMESTAMP opt_timezone @@ -2969,53 +4146,6 @@ opt_interval: YEAR_P { $$ = make_str("year"); } * *****************************************************************************/ -/* Expressions using row descriptors - * Define row_descriptor to allow yacc to break the reduce/reduce conflict - * with singleton expressions. - */ -row_expr: '(' row_descriptor ')' IN_P select_with_parens - { $$ = cat_str(4, make_str("("), $2, make_str(") in "), $5); } - | '(' row_descriptor ')' NOT IN_P select_with_parens - { $$ = cat_str(4, make_str("("), $2, make_str(") not in "), $6); } - | '(' row_descriptor ')' all_Op sub_type select_with_parens - { $$ = cat_str(6, make_str("("), $2, make_str(")"), $4, $5, $6); } - | '(' row_descriptor ')' all_Op select_with_parens - { $$ = cat_str(5, make_str("("), $2, make_str(")"), $4, $5); } - | '(' row_descriptor ')' all_Op '(' row_descriptor ')' - { $$ = cat_str(7, make_str("("), $2, make_str(")"), $4, make_str("("), $6, make_str(")")); } - | '(' row_descriptor ')' OVERLAPS '(' row_descriptor ')' - { $$ = cat_str(5, make_str("("), $2, make_str(") overlaps ("), $6, make_str(")")); } - ; - -row_descriptor: row_list ',' a_expr - { $$ = cat_str(3, $1, make_str(","), $3); } - ; - -sub_type: ANY { $$ = make_str("ANY"); } - | SOME { $$ = make_str("SOME"); } - | ALL { $$ = make_str("ALL"); } - ; - - -row_list: row_list ',' a_expr - { $$ = cat_str(3, $1, make_str(","), $3); } - | a_expr - { $$ = $1; } - ; - -all_Op: Op | MathOp; - -MathOp: '+' { $$ = 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. * @@ -3036,7 +4166,7 @@ a_expr: c_expr { $$ = $1; } | a_expr TYPECAST Typename { $$ = cat_str(3, $1, make_str("::"), $3); } - | a_expr AT TIME ZONE c_expr + | a_expr AT TIME ZONE a_expr { $$ = cat_str(3, $1, make_str("at time zone"), $5); } /* * These operators must be called out explicitly in order to make use @@ -3051,14 +4181,6 @@ a_expr: c_expr { $$ = cat2_str(make_str("+"), $2); } | '-' a_expr %prec UMINUS { $$ = cat2_str(make_str("-"), $2); } - | '%' a_expr - { $$ = cat2_str(make_str("%"), $2); } - | '^' a_expr - { $$ = cat2_str(make_str("^"), $2); } - | a_expr '%' - { $$ = cat2_str($1, make_str("%")); } - | a_expr '^' - { $$ = cat2_str($1, make_str("^")); } | a_expr '+' a_expr { $$ = cat_str(3, $1, make_str("+"), $3); } | a_expr '-' a_expr @@ -3077,11 +4199,11 @@ a_expr: c_expr { $$ = cat_str(3, $1, make_str(">"), $3); } | a_expr '=' a_expr { $$ = cat_str(3, $1, make_str("="), $3); } - | a_expr Op a_expr + | a_expr qual_Op a_expr %prec Op { $$ = cat_str(3, $1, $2, $3); } - | Op a_expr + | qual_Op a_expr %prec Op { $$ = cat2_str($1, $2); } - | a_expr Op %prec POSTFIXOP + | a_expr qual_Op %prec POSTFIXOP { $$ = cat2_str($1, $2); } | a_expr AND a_expr { $$ = cat_str(3, $1, make_str("and"), $3); } @@ -3105,6 +4227,14 @@ a_expr: c_expr { $$ = cat_str(3, $1, make_str("not ilike"), $4); } | a_expr NOT ILIKE a_expr ESCAPE a_expr { $$ = cat_str(5, $1, make_str("not ilike"), $4, make_str("escape"), $6); } + | a_expr SIMILAR TO a_expr %prec SIMILAR + { $$ = cat_str(3, $1, make_str("similar to"), $4); } + | a_expr SIMILAR TO a_expr ESCAPE a_expr + { $$ = cat_str(5, $1, make_str("similar to"), $4, make_str("escape"), $6); } + | a_expr NOT SIMILAR TO a_expr %prec SIMILAR + { $$ = cat_str(3, $1, make_str("not similar to"), $5); } + | a_expr NOT SIMILAR TO a_expr ESCAPE a_expr + { $$ = cat_str(5, $1, make_str("not similar to"), $5, make_str("escape"), $7); } | a_expr ISNULL { $$ = cat2_str($1, make_str("isnull")); } | a_expr IS NULL_P @@ -3113,6 +4243,8 @@ a_expr: c_expr { $$ = cat2_str($1, make_str("notnull")); } | a_expr IS NOT NULL_P { $$ = cat2_str($1, make_str("is not null")); } + | row OVERLAPS row + { $$ = cat_str(3, $1, make_str("overlaps"), $3); } /* 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. @@ -3134,18 +4266,36 @@ a_expr: c_expr { $$ = cat2_str($1, make_str("is unknown")); } | a_expr IS NOT UNKNOWN { $$ = cat2_str($1, make_str("is not unknown")); } - | a_expr BETWEEN b_expr AND b_expr %prec BETWEEN - { $$ = cat_str(5, $1, make_str("between"), $3, make_str("and"), $5); } - | a_expr NOT BETWEEN b_expr AND b_expr %prec BETWEEN - { $$ = cat_str(5, $1, make_str("not between"), $4, make_str("and"), $6); } + | a_expr IS DISTINCT FROM a_expr %prec IS + { $$ = cat_str(3, $1, make_str("is distinct from"), $5); } + | a_expr IS NOT DISTINCT FROM a_expr %prec IS + { $$ = cat_str(3, $1, make_str("is not distinct from"), $6); } + | a_expr IS OF '(' type_list ')' %prec IS + { $$ = cat_str(4, $1, make_str("is of ("), $5, make_str(")")); } + | a_expr IS NOT OF '(' type_list ')' %prec IS + { $$ = cat_str(4, $1, make_str("is not of ("), $6, make_str(")")); } + | a_expr BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN + { $$ = cat_str(6, $1, make_str("between"), $3, $4, make_str("and"), $6); } + | a_expr NOT BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN + { $$ = cat_str(6, $1, make_str("not between"), $4, $5, make_str("and"), $7); } + | a_expr BETWEEN SYMMETRIC b_expr AND b_expr %prec BETWEEN + { $$ = cat_str(5, $1, make_str("between symmetric"), $4, make_str("and"), $6); } + | a_expr NOT BETWEEN SYMMETRIC b_expr AND b_expr %prec BETWEEN + { $$ = cat_str(5, $1, make_str("not between symmetric"), $5, make_str("and"), $7); } | a_expr IN_P in_expr - { $$ = cat_str(3, $1, make_str(" in"), $3); } + { $$ = cat_str(3, $1, make_str("in"), $3); } | a_expr NOT IN_P in_expr - { $$ = cat_str(3, $1, make_str(" not in "), $4); } - | a_expr all_Op sub_type select_with_parens %prec Op + { $$ = cat_str(3, $1, make_str("not in"), $4); } + | a_expr subquery_Op sub_type select_with_parens %prec Op { $$ = cat_str(4, $1, $2, $3, $4); } - | row_expr - { $$ = $1; } + | a_expr subquery_Op sub_type '(' a_expr ')' %prec Op + { $$ = cat_str(6, $1, $2, $3, make_str("("), $5, make_str(")")); } + | UNIQUE select_with_parens + { $$ = cat2_str(make_str("unique"), $2); } + | a_expr IS DOCUMENT_P + { $$ = cat2_str($1, make_str("is document")); } + | a_expr IS NOT DOCUMENT_P + { $$ = cat2_str($1, make_str("is not document")); } ; /* Restricted expressions @@ -3162,14 +4312,6 @@ b_expr: c_expr { $$ = cat_str(3, $1, make_str("::"), $3); } | '-' b_expr %prec UMINUS { $$ = cat2_str(make_str("-"), $2); } - | '%' b_expr - { $$ = cat2_str(make_str("%"), $2); } - | '^' b_expr - { $$ = cat2_str(make_str("^"), $2); } - | b_expr '%' - { $$ = cat2_str($1, make_str("%")); } - | b_expr '^' - { $$ = cat2_str($1, make_str("^")); } | b_expr '+' b_expr { $$ = cat_str(3, $1, make_str("+"), $3); } | b_expr '-' b_expr @@ -3190,10 +4332,22 @@ b_expr: c_expr { $$ = cat_str(3, $1, make_str("="), $3); } | b_expr Op b_expr { $$ = cat_str(3, $1, $2, $3); } - | Op b_expr + | qual_Op b_expr %prec Op { $$ = cat2_str($1, $2); } - | b_expr Op %prec POSTFIXOP + | b_expr qual_Op %prec POSTFIXOP { $$ = cat2_str($1, $2); } + | b_expr IS DISTINCT FROM b_expr %prec IS + { $$ = cat_str(3, $1, make_str("is distinct from"), $5); } + | b_expr IS NOT DISTINCT FROM b_expr %prec IS + { $$ = cat_str(3, $1, make_str("is not distinct from"), $6); } + | b_expr IS OF '(' b_expr ')' %prec IS + { $$ = cat_str(4, $1, make_str("is of ("), $5, make_str(")")); } + | b_expr IS NOT OF '(' b_expr ')' %prec IS + { $$ = cat_str(4, $1, make_str("is not of ("), $6, make_str(")")); } + | b_expr IS DOCUMENT_P + { $$ = cat2_str($1, make_str("is document")); } + | b_expr IS NOT DOCUMENT_P + { $$ = cat2_str($1, make_str("is not document")); } ; /* @@ -3204,24 +4358,46 @@ b_expr: c_expr * inside parentheses, such as function arguments; that cannot introduce * ambiguity to the b_expr syntax. */ -c_expr: columnref +c_expr: columnref { $$ = $1; } | AexprConst { $$ = $1; } - | PARAM attrs opt_indirection - { $$ = cat_str(3, make_str("param"), $2, $3); } - | '(' a_expr ')' - { $$ = cat_str(3, make_str("("), $2, make_str(")")); } - | '(' a_expr ')' attrs opt_indirection - { $$ = cat_str(5, make_str("("), $2, make_str(")"), $4, $5); } - | CAST '(' a_expr AS Typename ')' - { $$ = cat_str(5, make_str("cast("), $3, make_str("as"), $5, make_str(")")); } + | PARAM opt_indirection + { $$ = cat2_str(make_str("param"), $2); } + | '(' a_expr ')' opt_indirection + { $$ = cat_str(4, make_str("("), $2, make_str(")"), $4); } | case_expr { $$ = $1; } - | func_name '(' ')' + | func_expr + { $$ = $1; } + | select_with_parens %prec UMINUS + { $$ = $1; } + | EXISTS select_with_parens + { $$ = cat2_str(make_str("exists"), $2); } + | ARRAY select_with_parens + { $$ = cat2_str(make_str("array"), $2); } + | ARRAY array_expr + { $$ = cat2_str(make_str("array"), $2); } + | row + { $$ = $1; } + ; + +/* + * func_expr is split out from c_expr just so that we have a classification + * for "everything that is a function call or looks like one". This isn't + * very important, but it saves us having to document which variants are + * legal in the backwards-compatible functional-index syntax for CREATE INDEX. + * (Note that many of the special SQL functions wouldn't actually make any + * sense as functional index entries, but we ignore that consideration here.) + */ +func_expr: func_name '(' ')' { $$ = cat2_str($1, make_str("()")); } | func_name '(' expr_list ')' { $$ = cat_str(4, $1, make_str("("), $3, make_str(")")); } + | func_name '(' VARIADIC a_expr ')' + { $$ = cat_str(4, $1, make_str("( variadic "), $4, make_str(")")); } + | func_name '(' expr_list ',' VARIADIC a_expr ')' + { $$ = cat_str(6, $1, make_str("("), $3, make_str(", variadic "), $6, make_str(")")); } | func_name '(' ALL expr_list ')' { $$ = cat_str(4, $1, make_str("( all"), $4, make_str(")")); } | func_name '(' DISTINCT expr_list ')' @@ -3230,26 +4406,42 @@ c_expr: columnref { $$ = cat2_str($1, make_str("(*)")); } | CURRENT_DATE { $$ = make_str("current_date"); } - | CURRENT_TIME opt_empty_parentheses - { $$ = cat2_str(make_str("current_time"), $2); } - | CURRENT_TIME '(' PosIntConst ')' + | CURRENT_TIME { $$ = make_str("current_time"); } - | CURRENT_TIMESTAMP opt_empty_parentheses - { $$ = cat2_str(make_str("current_timestamp"), $2); } - | CURRENT_TIMESTAMP '(' PosIntConst ')' + | CURRENT_TIME '(' PosIntConst ')' + { $$ = cat_str(3, make_str("current_time ("), $3, make_str(")")); } + | CURRENT_TIMESTAMP { $$ = make_str("current_timestamp"); } - | CURRENT_USER opt_empty_parentheses - { $$ = cat2_str(make_str("current_user"), $2); } - | SESSION_USER opt_empty_parentheses - { $$ = cat2_str(make_str("session_user"), $2); } - | USER opt_empty_parentheses - { $$ = cat2_str(make_str("user"), $2); } + | CURRENT_TIMESTAMP '(' PosIntConst ')' + { $$ = cat_str(3, make_str("current_timestamp ("), $3, make_str(")")); } + | LOCALTIME + { $$ = make_str("localtime"); } + | LOCALTIME '(' PosIntConst ')' + { $$ = cat_str(3, make_str("localtime ("), $3, make_str(")")); } + | LOCALTIMESTAMP + { $$ = make_str("local_timestamp"); } + | LOCALTIMESTAMP '(' PosIntConst ')' + { $$ = cat_str(3, make_str("locale_timestamp ("), $3, make_str(")")); } + | CURRENT_ROLE + { $$ = make_str("current_role"); } + | CURRENT_USER + { $$ = make_str("current_user"); } + | SESSION_USER + { $$ = make_str("session_user"); } + | USER + { $$ = make_str("user"); } + | CAST '(' a_expr AS Typename ')' + { $$ = cat_str(5, make_str("cast("), $3, make_str("as"), $5, make_str(")")); } | EXTRACT '(' extract_list ')' { $$ = cat_str(3, make_str("extract("), $3, make_str(")")); } + | OVERLAY '(' overlay_list ')' + { $$ = cat_str(3, make_str("overlay("), $3, make_str(")")); } | POSITION '(' position_list ')' { $$ = cat_str(3, make_str("position("), $3, make_str(")")); } | SUBSTRING '(' substr_list ')' { $$ = cat_str(3, make_str("substring("), $3, make_str(")")); } + | TREAT '(' a_expr AS Typename ')' + { $$ = cat_str(5, make_str("treat("), $3, make_str("as"), $5, make_str(")")); } /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */ | TRIM '(' BOTH trim_list ')' { $$ = cat_str(3, make_str("trim(both"), $4, make_str(")")); } @@ -3259,29 +4451,144 @@ c_expr: columnref { $$ = cat_str(3, make_str("trim(trailing"), $4, make_str(")")); } | TRIM '(' trim_list ')' { $$ = cat_str(3, make_str("trim("), $3, make_str(")")); } - | select_with_parens %prec UMINUS - { $$ = $1; } - | EXISTS select_with_parens - { $$ = cat2_str(make_str("exists"), $2); } + | NULLIF '(' a_expr ',' a_expr ')' + { $$ = cat_str(5, make_str("nullif("), $3, make_str(","), $5, make_str(")")); } + | COALESCE '(' expr_list ')' + { $$ = cat_str(3, make_str("coalesce("), $3, make_str(")")); } + | GREATEST '(' expr_list ')' + { $$ = cat_str(3, make_str("greatest("), $3, make_str(")")); } + | LEAST '(' expr_list ')' + { $$ = cat_str(3, make_str("least("), $3, make_str(")")); } + | XMLCONCAT '(' expr_list ')' + { $$ = cat_str(3, make_str("xmlconcat("), $3, make_str(")")); } + | XMLELEMENT '(' NAME_P ColLabel ')' + { $$ = cat_str(3, make_str("xmlelement( name"), $4, make_str(")")); } + | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')' + { $$ = cat_str(5, make_str("xmlelement( name"), $4, make_str(","), $6, make_str(")")); } + | XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')' + { $$ = cat_str(5, make_str("xmlelement( name"), $4, make_str(","), $6, make_str(")")); } + | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')' + { $$ = cat_str(7, make_str("xmlelement( name"), $4, make_str(","), $6, make_str(","), $8, make_str(")")); } + | XMLFOREST '(' xml_attribute_list ')' + { $$ = cat_str(3, make_str("xmlforest("), $3, make_str(")")); } + | XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')' + { $$ = cat_str(5, make_str("xmlparse("), $3, $4, $5, make_str(")")); } + | XMLPI '(' NAME_P ColLabel ')' + { $$ = cat_str(3, make_str("xmlpi( name"), $4, make_str(")")); } + | XMLPI '(' NAME_P ColLabel ',' a_expr ')' + { $$ = cat_str(5, make_str("xmlpi( name"), $4, make_str(","), $6, make_str(")")); } + | XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')' + { $$ = cat_str(6, make_str("xmlroot("), $3, make_str(","), $5, $6, make_str(")")); } ; + /* - * This used to use ecpg_expr, but since there is no shift/reduce conflict - * anymore, we can remove ecpg_expr. - MM + * SQL/XML support */ -opt_indirection: '[' a_expr ']' opt_indirection - { $$ = cat_str(4, make_str("["), $2, make_str("]"), $4); } - | '[' a_expr ':' a_expr ']' opt_indirection - { $$ = cat_str(6, make_str("["), $2, make_str(":"), $4, make_str("]"), $6); } - | /* EMPTY */ - { $$ = EMPTY; } + +xml_root_version: VERSION_P a_expr + { $$ = cat2_str(make_str("version"), $2); } + | VERSION_P NO VALUE_P + { $$ = make_str("version no value"); } + ; + +opt_xml_root_standalone: ',' STANDALONE_P YES_P + { $$ = make_str(", standalone yes"); } + | ',' STANDALONE_P NO + { $$ = make_str(", standalone no"); } + | ',' STANDALONE_P NO VALUE_P + { $$ = make_str(", standalone no value"); } + | /*EMPTY*/ + { $$ = EMPTY; } + ; + +xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' + { $$ = cat_str(3, make_str("xmlattributes("), $3, make_str(")")); } + ; + +xml_attribute_list: xml_attribute_el + { $$ = $1; } + | xml_attribute_list ',' xml_attribute_el + { $$ = cat_str(3, $1, make_str(","), $3); } + ; + +xml_attribute_el: a_expr AS ColLabel + { $$ = cat_str(3, $1, make_str("as"), $3); } + | a_expr + { $$ = $1; } + ; + +document_or_content: DOCUMENT_P { $$ = make_str("document"); } + | CONTENT_P { $$ = make_str("content"); } + ; + +xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = make_str("preserve whitespace"); } + | STRIP_P WHITESPACE_P { $$ = make_str("strip whitespace"); } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +row: ROW '(' expr_list ')' + { $$ = cat_str(3, make_str("row ("), $3, make_str(")")); } + | ROW '(' ')' + { $$ = make_str("row()"); } + | '(' expr_list ',' a_expr ')' + { $$ = cat_str(5, make_str("("), $2, make_str(","), $4, make_str(")")); } + ; + +sub_type: ANY { $$ = make_str("ANY"); } + | SOME { $$ = make_str("SOME"); } + | ALL { $$ = make_str("ALL"); } + ; + +all_Op: Op { $$ = $1; } + | MathOp { $$ = $1; } + ; + +MathOp: '+' { $$ = make_str("+"); } + | '-' { $$ = make_str("-"); } + | '*' { $$ = make_str("*"); } + | '%' { $$ = make_str("%"); } + | '^' { $$ = make_str("^"); } + | '/' { $$ = make_str("/"); } + | '<' { $$ = make_str("<"); } + | '>' { $$ = make_str(">"); } + | '=' { $$ = make_str("="); } + ; + +qual_Op: Op { $$ = $1; } + | OPERATOR '(' any_operator ')' { $$ = cat_str(3, make_str("operator ("), $3, make_str(")")); } + ; + +qual_all_Op: all_Op { $$ = $1; } + | OPERATOR '(' any_operator ')' { $$ = cat_str(3, make_str("operator ("), $3, make_str(")")); } + ; + +subquery_Op: all_Op { $$ = $1; } + | OPERATOR '(' any_operator ')' { $$ = cat_str(3, make_str("operator ("), $3, make_str(")")); } + | LIKE { $$ = make_str("like"); } + | NOT LIKE { $$ = make_str("not like"); } + | ILIKE { $$ = make_str("ilike"); } + | NOT ILIKE { $$ = make_str("not ilike"); } ; expr_list: a_expr { $$ = $1; } | expr_list ',' a_expr { $$ = cat_str(3, $1, make_str(","), $3); } - | expr_list USING a_expr - { $$ = cat_str(3, $1, make_str("using"), $3); } + ; + +type_list: Typename + { $$ = $1; } + | type_list ',' Typename + { $$ = cat_str(3, $1, ',', $3); } + ; + +array_expr: '[' expr_list ']' { $$ = cat_str(3, make_str("["), $2, make_str("]")); } + | '[' array_expr_list ']' { $$ = cat_str(3, make_str("["), $2, make_str("]")); } + | '[' ']' { $$ = make_str("[]"); } + ; + +array_expr_list: array_expr { $$ = $1; } + | array_expr_list ',' array_expr { $$ = cat_str(3, $1, make_str(","), $3); } ; extract_list: extract_arg FROM a_expr @@ -3290,11 +4597,7 @@ extract_list: extract_arg FROM a_expr { $$ = EMPTY; } ; -/* Allow delimited string SCONST in extract_arg as an SQL extension. - * - thomas 2001-04-12 - */ - -extract_arg: IDENT { $$ = $1; } +extract_arg: ident { $$ = $1; } | YEAR_P { $$ = make_str("year"); } | MONTH_P { $$ = make_str("month"); } | DAY_P { $$ = make_str("day"); } @@ -3304,6 +4607,17 @@ extract_arg: IDENT { $$ = $1; } | StringConst { $$ = $1; } ; +overlay_list: + a_expr overlay_placing substr_from substr_for + { $$ = cat_str(4, $1, 42, $3, $4); } + | a_expr overlay_placing substr_from + { $$ = cat_str(3, $1, $2, $3); } + ; + +overlay_placing: + PLACING a_expr { $$ = cat2_str(make_str("placing"), $2); } + ; + /* position_list uses b_expr not a_expr to avoid conflict with general IN */ position_list: b_expr IN_P b_expr { $$ = cat_str(3, $1, make_str("in"), $3); } @@ -3343,37 +4657,15 @@ trim_list: a_expr FROM expr_list in_expr: select_with_parens { $$ = $1; } - | '(' in_expr_nodes ')' + | '(' expr_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); } ; -in_expr_nodes: a_expr - { $$ = $1; } - | in_expr_nodes ',' a_expr - { $$ = cat_str(3, $1, make_str(","), $3);} - ; - /* Case clause * Define SQL92-style case clause. - * Allow all four forms described in the standard: - * - Full specification - * CASE WHEN a = b THEN c ... ELSE d END - * - Implicit argument - * CASE a WHEN b THEN c ... ELSE d END - * - Conditional NULL - * NULLIF(x,y) - * same as CASE WHEN x = y THEN NULL ELSE x END - * - Conditional substitution from list, use first non-null argument - * COALESCE(a,b,...) - * same as CASE WHEN a IS NOT NULL THEN a WHEN b IS NOT NULL THEN b ... END - * - thomas 1998-11-09 */ -case_expr: CASE case_arg when_clause_list case_default END_TRANS +case_expr: CASE case_arg when_clause_list case_default END_P { $$ = cat_str(5, make_str("case"), $2, $3, $4, make_str("end")); } - | NULLIF '(' a_expr ',' a_expr ')' - { $$ = cat_str(5, make_str("nullif("), $3, make_str(","), $5, make_str(")")); } - | COALESCE '(' expr_list ')' - { $$ = cat_str(3, make_str("coalesce("), $3, make_str(")")); } ; when_clause_list: when_clause_list when_clause @@ -3393,77 +4685,140 @@ case_default: ELSE a_expr ; case_arg: a_expr { $$ = $1; } - | /*EMPTY*/ { $$ = EMPTY; } + | /*EMPTY*/ { $$ = EMPTY; } ; -columnref: relation_name opt_indirection - { $$ = cat2_str($1, $2); } - | dotted_name opt_indirection - { $$ = cat2_str($1, $2); } - ; - -dotted_name: relation_name attrs - { $$ = cat2_str($1, $2); } +columnref: relation_name { $$ = $1; } + | relation_name indirection { $$ = cat2_str($1, $2); } ; -attrs: '.' attr_name - { $$ = cat2_str(make_str("."), $2); } - | '.' '*' - { $$ = make_str(".*"); } - | '.' attr_name attrs - { $$ = cat_str(3, make_str("."), $2, $3); } +indirection_el: + '.' attr_name { $$ = cat2_str(make_str("."), $2); } + | '.' '*' { $$ = make_str(".*"); } + | '[' a_expr ']' { $$ = cat_str(3, make_str("["), $2, make_str("]")); } + | '[' a_expr ':' a_expr ']' { $$ = cat_str(5, make_str("["), $2, make_str(":"), $4, make_str("]")); } ; -opt_empty_parentheses: '(' ')' { $$ = make_str("()"); } - | /*EMPTY*/ { $$ = EMPTY; } +indirection: indirection_el { $$ = $1; } + | indirection indirection_el { $$ = cat2_str($1, $2); } + ; + +opt_indirection: + /*EMPTY*/ { $$ = EMPTY; } + | opt_indirection indirection_el { $$ = cat2_str($1, $2);} + ; + +opt_asymmetric: ASYMMETRIC { $$ = make_str("asymmetric"); } + | /*EMPTY*/ { $$ = EMPTY; } ; +ctext_expr: + a_expr { $$ = $1; } + | DEFAULT { $$ = make_str("default"); } + ; + +ctext_expr_list: + ctext_expr { $$ = $1; } + | ctext_expr_list ',' ctext_expr { $$ = cat_str(3, $1, make_str(","), $3); } + ; + +ctext_row: '(' ctext_expr_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")"));}; /***************************************************************************** * - * target lists + * target lists for SELECT * *****************************************************************************/ -/* Target lists as found in SELECT ... and INSERT VALUES ( ... ) */ target_list: target_list ',' target_el { $$ = cat_str(3, $1, make_str(","), $3); } | target_el { $$ = $1; } ; -/* AS is not optional because shift/red conflict with unary ops */ target_el: a_expr AS ColLabel { $$ = cat_str(3, $1, make_str("as"), $3); } + /* + * We support omitting AS only for column labels that aren't + * any known keyword. There is an ambiguity against postfix + * operators: is "a ! b" an infix expression, or a postfix + * expression and a column label? We prefer to resolve this + * as an infix expression, which we accomplish by assigning + * IDENT a precedence higher than POSTFIXOP. + */ + | a_expr IDENT + { $$ = cat_str(3, $1, make_str("as"), $2); } | a_expr { $$ = $1; } | '*' { $$ = make_str("*"); } ; -/* Target list as found in UPDATE table SET ... */ -update_target_list: update_target_list ',' update_target_el - { $$ = cat_str(3, $1, make_str(","),$3); } - | update_target_el - { $$ = $1; } - | '*' - { $$ = make_str("*"); } - ; +/* INFORMIX workaround, no longer needed +update_target_list: '(' inf_col_list ')' '=' '(' inf_val_list ')' + { + struct inf_compat_col *ptrc; + struct inf_compat_val *ptrv; + char *cols = make_str( "(" ); + char *vals = make_str( "(" ); -update_target_el: ColId opt_indirection '=' a_expr - { $$ = cat_str(4, $1, $2, make_str("="), $4); } + for (ptrc = informix_col, ptrv = informix_val; ptrc != NULL && ptrv != NULL; ptrc = ptrc->next, ptrv = ptrv->next) + { + if ( ptrc->next != NULL ) + { + cols = cat_str(4, cols, ptrc->name, ptrc->indirection, make_str(",") ); + } + else + { + cols = cat_str(4, cols, ptrc->name, ptrc->indirection, make_str(")") ); + } + if (ptrv->next != NULL ) + vals = cat_str(3, vals, ptrv->val, make_str("," ) ); + else + vals = cat_str( 3, vals, ptrv->val, make_str(")") ); + } + $$ = cat_str( 3, cols, make_str("="), vals ); + } ; -insert_target_list: insert_target_list ',' insert_target_el - { $$ = cat_str(3, $1, make_str(","), $3); } - | insert_target_el - { $$ = $1; } - ; +inf_col_list: ColId opt_indirection + { + struct inf_compat_col *ptr = mm_alloc(sizeof(struct inf_compat_col)); + + ptr->name = $1; + ptr->indirection = $2; + ptr->next = NULL; + informix_col = ptr; + } + | ColId opt_indirection ',' inf_col_list + { + struct inf_compat_col *ptr = mm_alloc(sizeof(struct inf_compat_col)); -insert_target_el: target_el { $$ = $1; } - | DEFAULT { $$ = make_str("default"); } + ptr->name = $1; + ptr->indirection = $2; + ptr->next = informix_col; + informix_col = ptr; + } ; +inf_val_list: a_expr + { + struct inf_compat_val *ptr = mm_alloc(sizeof(struct inf_compat_val)); + + ptr->val = $1; + ptr->next = NULL; + informix_val = ptr; + } + | a_expr ',' inf_val_list + { + struct inf_compat_val *ptr = mm_alloc(sizeof(struct inf_compat_val)); + + ptr->val = $1; + ptr->next = informix_val; + informix_val = ptr; + } + ; +*/ /***************************************************************************** * @@ -3483,8 +4838,8 @@ qualified_name_list: qualified_name qualified_name: relation_name { $$ = $1; } - | dotted_name - { $$ = $1; } + | relation_name indirection + { $$ = cat2_str($1, $2); } ; name_list: name @@ -3494,26 +4849,18 @@ name_list: name ; -name: ColId { $$ = $1; }; -database_name: ColId { $$ = $1; }; -access_method: ColId { $$ = $1; }; -attr_name: ColId { $$ = $1; }; -index_name: ColId { $$ = $1; }; +name: ColId { $$ = $1; }; +database_name: ColId { $$ = $1; }; +access_method: ColId { $$ = $1; }; +attr_name: ColLabel { $$ = $1; }; +index_name: ColId { $$ = $1; }; -file_name: StringConst { $$ = $1; }; +file_name: StringConst { $$ = $1; }; -/* func_name will soon return a List ... but not yet */ -/* -func_name: function_name - { $$ = makeList1(makeString($1)); } - | dotted_name - { $$ = $1; } - ; -*/ -func_name: function_name - { $$ = $1; } - | dotted_name +func_name: type_function_name { $$ = $1; } + | relation_name indirection + { $$ = cat2_str($1, $2); } ; @@ -3528,8 +4875,6 @@ AexprConst: PosAllConst { $$ = cat_str(3, $1, $2, $3); } | ConstInterval '(' PosIntConst ')' StringConst opt_interval { $$ = cat_str(6, $1, make_str("("), $3, make_str(")"), $5, $6); } - | PARAM opt_indirection - { $$ = cat2_str(make_str("param"), $2); } | TRUE_P { $$ = make_str("true"); } | FALSE_P @@ -3537,59 +4882,141 @@ AexprConst: PosAllConst | NULL_P { $$ = make_str("null"); } | civarind - { $$ = make_str("?"); } + { $$ = $1; } ; Iconst: ICONST { $$ = make_name();}; Fconst: FCONST { $$ = make_name();}; -Bitconst: BITCONST { $$ = make_name();}; +Bconst: BCONST { $$ = make_name();}; +Xconst: XCONST { $$ = make_name();}; Sconst: SCONST { + /* could have been input as '' or $$ */ $$ = (char *)mm_alloc(strlen($1) + 3); $$[0]='\''; - strcpy($$+1, $1); - $$[strlen($1)+2]='\0'; + strcpy($$+1, $1); $$[strlen($1)+1]='\''; + $$[strlen($1)+2]='\0'; free($1); } - ; + | ECONST + { + /* escaped quote starting with E */ + $$ = (char *)mm_alloc(strlen($1) + 4); + $$[0]='E'; + $$[1]='\''; + strcpy($$+2, $1); + $$[strlen($1)+2]='\''; + $$[strlen($1)+3]='\0'; + free($1); + } + | NCONST + { + /* escaped quote starting with rNE */ + $$ = (char *)mm_alloc(strlen($1) + 4); + $$[0]='N'; + $$[1]='\''; + strcpy($$+2, $1); + $$[strlen($1)+2]='\''; + $$[strlen($1)+3]='\0'; + free($1); + } + | DOLCONST + { + $$ = $1; + } + ; PosIntConst: Iconst { $$ = $1; } - | civar { $$ = make_str("?"); } + | civar { $$ = $1; } ; IntConst: PosIntConst { $$ = $1; } | '-' PosIntConst { $$ = cat2_str(make_str("-"), $2); } ; +IntConstVar: Iconst + { + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + + sprintf(length, "%d", (int) strlen($1)); + new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); + $$ = $1; + } + | cvariable { $$ = $1; } + ; + +AllConstVar: Fconst + { + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + + sprintf(length, "%d", (int) strlen($1)); + new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); + $$ = $1; + } + | IntConstVar { $$ = $1; } + | '-' Fconst + { + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + char *var = cat2_str(make_str("-"), $2); + + sprintf(length, "%d", (int) strlen(var)); + new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); + $$ = var; + } + | '-' Iconst + { + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + char *var = cat2_str(make_str("-"), $2); + + sprintf(length, "%d", (int) strlen(var)); + new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); + $$ = var; + } + | Sconst + { + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + char *var = $1 + 1; + + var[strlen(var) - 1] = '\0'; + sprintf(length, "%d", (int) strlen(var)); + new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); + $$ = var; + } + ; + StringConst: Sconst { $$ = $1; } - | civar { $$ = make_str("?"); } + | civar { $$ = $1; } ; PosIntStringConst: Iconst { $$ = $1; } - | Sconst { $$ = $1; } - | civar { $$ = make_str("?"); } + | Sconst { $$ = $1; } + | civar { $$ = $1; } ; NumConst: Fconst { $$ = $1; } - | Iconst { $$ = $1; } + | Iconst { $$ = $1; } | '-' Fconst { $$ = cat2_str(make_str("-"), $2); } | '-' Iconst { $$ = cat2_str(make_str("-"), $2); } - | civar { $$ = make_str("?"); } + | civar { $$ = $1; } ; AllConst: Sconst { $$ = $1; } - | NumConst { $$ = $1; } + | NumConst { $$ = $1; } ; -PosAllConst: Sconst { $$ = $1; } - | Fconst { $$ = $1; } - | Iconst { $$ = $1; } - | Bitconst { $$ = $1; } - | civar { $$ = make_str("?"); } +PosAllConst: Sconst { $$ = $1; } + | Fconst { $$ = $1; } + | Iconst { $$ = $1; } + | Bconst { $$ = $1; } + | Xconst { $$ = $1; } + | func_name Sconst { $$ = cat2_str($1, $2); } + | func_name '(' expr_list ')' Sconst + { $$ = cat_str(5, $1, make_str("("), $3, make_str(")"), $5); } + | civar { $$ = $1; } ; -UserId: ColId { $$ = $1;}; +RoleId: ColId { $$ = $1;}; SpecialRuleRelation: OLD { @@ -3617,85 +5044,68 @@ SpecialRuleRelation: OLD ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user { $$ = cat_str(5, $3, make_str(","), $5, make_str(","), $4); } | SQL_CONNECT TO DEFAULT - { $$ = make_str("NULL,NULL,NULL,\"DEFAULT\""); } + { $$ = make_str("NULL, NULL, NULL, \"DEFAULT\""); } /* also allow ORACLE syntax */ | SQL_CONNECT ora_user - { $$ = cat_str(3, make_str("NULL,"), $2, make_str(",NULL")); } + { $$ = cat_str(3, make_str("NULL,"), $2, make_str(", NULL")); } + | DATABASE connection_target + { $$ = cat2_str($2, make_str(", NULL, NULL, NULL")); } ; -connection_target: database_name opt_server opt_port +connection_target: opt_database_name opt_server opt_port { /* old style: dbname[@server][:port] */ if (strlen($2) > 0 && *($2) != '@') - { - snprintf(errortext, sizeof(errortext), - "Expected '@', found '%s'", $2); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } - - $$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\"")); + mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\", found \"%s\"", $2); + + /* C strings need to be handled differently */ + if ($1[0] == '\"') + $$ = $1; + else + $$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\"")); } - | db_prefix ':' server opt_port '/' database_name opt_options + | db_prefix ':' server opt_port '/' opt_database_name opt_options { /* new style: :postgresql://server[:port][/dbname] */ if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql")) != 0) - { - snprintf(errortext, sizeof(errortext), "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported"); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "only protocols \"tcp\" and \"unix\" and database type \"postgresql\" are supported"); if (strncmp($3, "//", strlen("//")) != 0) - { - snprintf(errortext, sizeof(errortext), "Expected '://', found '%s'", $3); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "expected \"://\", found \"%s\"", $3); if (strncmp($1, "unix", strlen("unix")) == 0 && strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 && strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0) - { - snprintf(errortext, sizeof(errortext), "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//")); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "unix domain sockets only work on \"localhost\" but not on \"%s\"", $3 + strlen("//")); $$ = make3_str(make3_str(make_str("\""), $1, make_str(":")), $3, make3_str(make3_str($4, make_str("/"), $6), $7, make_str("\""))); } - | StringConst + | char_variable { - if ($1[0] == '\"') - $$ = $1; - else if (strcmp($1, "?") == 0) /* variable */ - { - enum ECPGttype type = argsinsert->variable->type->type; - - /* if array see what's inside */ - if (type == ECPGt_array) - type = argsinsert->variable->type->u.element->type; - - /* handle varchars */ - if (type == ECPGt_varchar) - $$ = make2_str(mm_strdup(argsinsert->variable->name), make_str(".arr")); - else - $$ = mm_strdup(argsinsert->variable->name); - } - else - $$ = make3_str(make_str("\""), $1, make_str("\"")); + $$ = $1; + } + | Sconst + { + /* We can only process double quoted strings not single quotes ones, + * so we change the quotes. + * Note, that the rule for Sconst adds these single quotes. */ + $1[0] = '\"'; + $1[strlen($1)-1] = '\"'; + $$ = $1; } ; -db_prefix: ident CVARIABLE +opt_database_name: database_name { $$ = $1; } + | /*EMPTY*/ { $$ = EMPTY; } + ; + +db_prefix: ident cvariable { if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0) - { - snprintf(errortext, sizeof(errortext), "Expected 'postgresql', found '%s'", $2); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "expected \"postgresql\", found \"%s\"", $2); if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0) - { - snprintf(errortext, sizeof(errortext), "Illegal connection type %s", $1); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "illegal connection type %s", $1); $$ = make3_str($1, make_str(":"), $2); } @@ -3704,10 +5114,7 @@ db_prefix: ident CVARIABLE server: Op server_name { if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0) - { - snprintf(errortext, sizeof(errortext), "Expected '@' or '://', found '%s'", $1); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", $1); $$ = make2_str($1, $2); } @@ -3723,15 +5130,15 @@ server_name: ColId { $$ = $1; } ; opt_port: ':' PosIntConst { $$ = make2_str(make_str(":"), $2); } - | /*EMPTY*/ { $$ = EMPTY; } + | /*EMPTY*/ { $$ = EMPTY; } ; -opt_connection_name: AS connection_target { $$ = $2; } +opt_connection_name: AS connection_object { $$ = $2; } | /*EMPTY*/ { $$ = make_str("NULL"); } ; opt_user: USER ora_user { $$ = $2; } - | /*EMPTY*/ { $$ = make_str("NULL,NULL"); } + | /*EMPTY*/ { $$ = make_str("NULL, NULL"); } ; ora_user: user_name @@ -3744,7 +5151,7 @@ ora_user: user_name { $$ = cat_str(3, $1, make_str(","), $3); } ; -user_name: UserId +user_name: RoleId { if ($1[0] == '\"') $$ = $1; @@ -3755,7 +5162,7 @@ user_name: UserId { if ($1[0] == '\"') $$ = $1; - else if (strcmp($1, "?") == 0) /* variable */ + else if ($1[1] == '$') /* variable */ { enum ECPGttype type = argsinsert->variable->type->type; @@ -3774,65 +5181,88 @@ user_name: UserId } ; -char_variable: CVARIABLE +char_variable: cvariable { - /* check if we have a char variable */ + /* check if we have a string variable */ struct variable *p = find_variable($1); enum ECPGttype type = p->type->type; - /* if array see what's inside */ - if (type == ECPGt_array) - type = p->type->u.element->type; - - switch (type) - { - case ECPGt_char: - case ECPGt_unsigned_char: - $$ = $1; - break; - case ECPGt_varchar: - $$ = make2_str($1, make_str(".arr")); - break; - default: + /* If we have just one character this is not a string */ + if (atol(p->type->size) == 1) mmerror(PARSE_ERROR, ET_ERROR, "invalid datatype"); - break; + else + { + /* if array see what's inside */ + if (type == ECPGt_array) + type = p->type->u.element->type; + + switch (type) + { + case ECPGt_char: + case ECPGt_unsigned_char: + $$ = $1; + break; + case ECPGt_varchar: + $$ = make2_str($1, make_str(".arr")); + break; + default: + mmerror(PARSE_ERROR, ET_ERROR, "invalid datatype"); + $$ = $1; + break; + } } } ; -opt_options: Op ColId +opt_options: Op connect_options { if (strlen($1) == 0) mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); if (strcmp($1, "?") != 0) - { - snprintf(errortext, sizeof(errortext), "unrecognised token '%s'", $1); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $1); $$ = make2_str(make_str("?"), $2); } | /*EMPTY*/ { $$ = EMPTY; } ; +connect_options: ColId opt_opt_value + { $$ = make2_str($1, $2); } + | ColId opt_opt_value Op connect_options + { + if (strlen($3) == 0) + mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); + + if (strcmp($3, "&") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $3); + + $$ = cat_str(3, make2_str($1, $2), $3, $4); + } + ; + +opt_opt_value: /*EMPTY*/ + { $$ = EMPTY; } + | '=' Iconst + { $$ = make2_str(make_str("="), $2); } + | '=' IDENT + { $$ = make2_str(make_str("="), $2); } + ; /* * Declare a prepared cursor. The syntax is different from the standard * declare statement, so we create a new rule. */ -ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident +ECPGCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR prepared_name { struct cursor *ptr, *this; struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable)); + const char *con = connection ? connection : "NULL"; for (ptr = cur; ptr != NULL; ptr = ptr->next) { if (strcmp($2, ptr->name) == 0) - { - /* re-definition is a bug */ - snprintf(errortext, sizeof(errortext), "cursor %s already defined", $2); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } + /* re-definition is a bug */ + mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" already defined", $2); } this = (struct cursor *) mm_alloc(sizeof(struct cursor)); @@ -3841,17 +5271,17 @@ ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident this->next = cur; this->name = $2; this->connection = connection; - this->command = cat_str(4, make_str("declare"), mm_strdup($2), $3, make_str("cursor for ?")); + this->command = cat_str(6, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for $1")); this->argsresult = NULL; thisquery->type = &ecpg_query; thisquery->brace_level = 0; thisquery->next = NULL; - thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($6)); - sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $6); + thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen($7)); + sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7); this->argsinsert = NULL; - add_variable(&(this->argsinsert), thisquery, &no_indicator); + add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator); cur = this; @@ -3859,15 +5289,36 @@ ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident } ; +ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring + { + /* execute immediate means prepare the statement and + * immediately execute it */ + $$ = $3; + }; /* - * the exec sql deallocate prepare command to deallocate a previously - * prepared statement + * variable decalartion outside exec sql declare block */ -ECPGDeallocate: SQL_DEALLOCATE SQL_PREPARE ident - { $$ = cat_str(3, make_str("ECPGdeallocate(__LINE__, \""), $3, make_str("\");")); }; +ECPGVarDeclaration: single_vt_declaration; + +single_vt_declaration: type_declaration { $$ = $1; } + | var_declaration { $$ = $1; } + ; + +precision: NumConst { $$ = $1; }; + +opt_scale: ',' NumConst { $$ = $2; } + | /* EMPTY */ { $$ = EMPTY; } + ; + +ecpg_interval: opt_interval { $$ = $1; } + | YEAR_P TO MINUTE_P { $$ = make_str("year to minute"); } + | YEAR_P TO SECOND_P { $$ = make_str("year to second"); } + | DAY_P TO DAY_P { $$ = make_str("day to day"); } + | MONTH_P TO MONTH_P { $$ = make_str("month to month"); } + ; /* - * variable declaration inside the exec sql declare block + * variable declaration inside exec sql declare block */ ECPGDeclaration: sql_startdeclare { fputs("/* exec sql begin declare section */", yyout); } @@ -3879,22 +5330,24 @@ ECPGDeclaration: sql_startdeclare } ; -sql_startdeclare: ecpgstart BEGIN_TRANS DECLARE SQL_SECTION ';' {}; +sql_startdeclare: ecpgstart BEGIN_P DECLARE SQL_SECTION ';' {}; -sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION ';' {}; +sql_enddeclare: ecpgstart END_P DECLARE SQL_SECTION ';' {}; var_type_declarations: /*EMPTY*/ { $$ = EMPTY; } | vt_declarations { $$ = $1; } + | CPP_LINE { $$ = $1; } ; vt_declarations: var_declaration { $$ = $1; } | type_declaration { $$ = $1; } | vt_declarations var_declaration { $$ = cat2_str($1, $2); } | vt_declarations type_declaration { $$ = cat2_str($1, $2); } + | vt_declarations CPP_LINE { $$ = cat2_str($1, $2); } ; -variable_declarations: var_declaration { $$ = $1; } - | variable_declarations var_declaration { $$ = cat2_str($1, $2); } +variable_declarations: var_declaration { $$ = $1; } + | variable_declarations var_declaration { $$ = cat2_str($1, $2); } ; type_declaration: S_TYPEDEF @@ -3903,134 +5356,129 @@ type_declaration: S_TYPEDEF /* an initializer specified */ initializer = 0; } - type opt_pointer ECPGColLabel opt_type_array_bounds ';' + var_type opt_pointer ECPGColLabelCommon opt_array_bounds ';' { - /* add entry to list */ - struct typedefs *ptr, *this; - int dimension = $6.index1; - int length = $6.index2; + add_typedef($5, $6.index1, $6.index2, $3.type_enum, $3.type_dimension, $3.type_index, initializer, *$4 ? 1 : 0); - if (($3.type_enum == ECPGt_struct || - $3.type_enum == ECPGt_union) && - initializer == 1) - { - mmerror(PARSE_ERROR, ET_ERROR, "Initializer not allowed in typedef command"); - - } - else - { - for (ptr = types; ptr != NULL; ptr = ptr->next) - { - if (strcmp($5, ptr->name) == 0) - { - /* re-definition is a bug */ - snprintf(errortext, sizeof(errortext), "Type %s already defined", $5); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } - } - - adjust_array($3.type_enum, &dimension, &length, $3.type_dimension, $3.type_index, *$4?1:0); - - this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); - - /* initial definition */ - this->next = types; - this->name = $5; - this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); - this->type->type_enum = $3.type_enum; - this->type->type_str = mm_strdup($5); - this->type->type_dimension = dimension; /* dimension of array */ - this->type->type_index = length; /* lenght of string */ - this->type->type_sizeof = ECPGstruct_sizeof; - this->struct_member_list = ($3.type_enum == ECPGt_struct || $3.type_enum == ECPGt_union) ? - struct_member_list[struct_level] : NULL; - - if ($3.type_enum != ECPGt_varchar && - $3.type_enum != ECPGt_char && - $3.type_enum != ECPGt_unsigned_char && - this->type->type_index >= 0) - mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types"); - - types = this; - } - - fprintf(yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4?"*":"", $5, $6.str); + fprintf(yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4 ? "*" : "", $5, $6.str); output_line_number(); $$ = make_str(""); }; -var_declaration: storage_clause storage_modifier +var_declaration: storage_declaration + var_type { - actual_storage[struct_level] = cat2_str(mm_strdup($1), mm_strdup($2)); + actual_type[struct_level].type_enum = $2.type_enum; + actual_type[struct_level].type_dimension = $2.type_dimension; + actual_type[struct_level].type_index = $2.type_index; + actual_type[struct_level].type_sizeof = $2.type_sizeof; + actual_startline[struct_level] = hashline_number(); } - type + variable_list ';' { - 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; - actual_type[struct_level].type_sizeof = $4.type_sizeof; + $$ = cat_str(5, actual_startline[struct_level], $1, $2.type_str, $4, make_str(";\n")); + } + | var_type + { + 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; + actual_type[struct_level].type_sizeof = $1.type_sizeof; - /* 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; - } + actual_startline[struct_level] = hashline_number(); } variable_list ';' { - $$ = cat_str(6, actual_startline[struct_level], $1, $2, $4.type_str, $6, make_str(";\n")); + $$ = cat_str(4, actual_startline[struct_level], $1.type_str, $3, make_str(";\n")); + } + | struct_union_type_with_symbol ';' + { + $$ = cat2_str($1, make_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; } +opt_bit_field: ':' Iconst { $$ =cat2_str(make_str(":"), $2); } + | /* EMPTY */ { $$ = EMPTY; } ; -storage_modifier : S_CONST { $$ = make_str("const"); } - | S_VOLATILE { $$ = make_str("volatile"); } - | /*EMPTY*/ { $$ = EMPTY; } +storage_declaration: storage_clause storage_modifier + {$$ = cat2_str ($1, $2); } + | storage_clause {$$ = $1; } + | storage_modifier {$$ = $1; } ; -type: simple_type +storage_clause : S_EXTERN { $$ = make_str("extern"); } + | S_STATIC { $$ = make_str("static"); } + | S_REGISTER { $$ = make_str("register"); } + | S_AUTO { $$ = make_str("auto"); } + ; + +storage_modifier : S_CONST { $$ = make_str("const"); } + | S_VOLATILE { $$ = make_str("volatile"); } + ; + +var_type: simple_type { $$.type_enum = $1; - $$.type_str = mm_strdup(ECPGtype_name($1)); - $$.type_dimension = -1; - $$.type_index = -1; + $$.type_str = mm_strdup(ecpg_type_name($1)); + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); $$.type_sizeof = NULL; } - | struct_type + | struct_union_type { - $$.type_enum = ECPGt_struct; $$.type_str = $1; - $$.type_dimension = -1; - $$.type_index = -1; - $$.type_sizeof = ECPGstruct_sizeof; + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); + + if (strncmp($1, "struct", sizeof("struct")-1) == 0) + { + $$.type_enum = ECPGt_struct; + $$.type_sizeof = ECPGstruct_sizeof; + } + else + { + $$.type_enum = ECPGt_union; + $$.type_sizeof = NULL; + } } - | union_type + | enum_type { - $$.type_enum = ECPGt_union; $$.type_str = $1; - $$.type_dimension = -1; - $$.type_index = -1; + $$.type_enum = ECPGt_int; + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); $$.type_sizeof = NULL; } - | enum_type + | ECPGColLabelCommon '(' precision opt_scale ')' { - $$.type_str = $1; - $$.type_enum = ECPGt_int; - $$.type_dimension = -1; - $$.type_index = -1; + if (strcmp($1, "numeric") == 0) + { + $$.type_enum = ECPGt_numeric; + $$.type_str = make_str("numeric"); + } + else if (strcmp($1, "decimal") == 0) + { + $$.type_enum = ECPGt_decimal; + $$.type_str = make_str("decimal"); + } + else + { + mmerror(PARSE_ERROR, ET_ERROR, "only numeric/decimal have precision/scale argument"); + $$.type_enum = ECPGt_numeric; + $$.type_str = make_str("numeric"); + } + + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); $$.type_sizeof = NULL; } - | ECPGColLabel + | ECPGColLabelCommon ecpg_interval { + if (strlen($2) != 0 && strcmp ($1, "datetime") != 0 && strcmp ($1, "interval") != 0) + mmerror (PARSE_ERROR, ET_ERROR, "interval specification not allowed here"); + /* * Check for type names that the SQL grammar treats as * unreserved keywords @@ -4038,25 +5486,73 @@ type: simple_type if (strcmp($1, "varchar") == 0) { $$.type_enum = ECPGt_varchar; - $$.type_str = make_str("varchar"); - $$.type_dimension = -1; - $$.type_index = -1; + $$.type_str = EMPTY; /*make_str("varchar");*/ + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); $$.type_sizeof = NULL; } else if (strcmp($1, "float") == 0) { $$.type_enum = ECPGt_float; $$.type_str = make_str("float"); - $$.type_dimension = -1; - $$.type_index = -1; + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); $$.type_sizeof = NULL; } else if (strcmp($1, "double") == 0) { $$.type_enum = ECPGt_double; $$.type_str = make_str("double"); - $$.type_dimension = -1; - $$.type_index = -1; + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); + $$.type_sizeof = NULL; + } + else if (strcmp($1, "numeric") == 0) + { + $$.type_enum = ECPGt_numeric; + $$.type_str = make_str("numeric"); + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); + $$.type_sizeof = NULL; + } + else if (strcmp($1, "decimal") == 0) + { + $$.type_enum = ECPGt_decimal; + $$.type_str = make_str("decimal"); + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); + $$.type_sizeof = NULL; + } + else if (strcmp($1, "date") == 0) + { + $$.type_enum = ECPGt_date; + $$.type_str = make_str("date"); + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); + $$.type_sizeof = NULL; + } + else if (strcmp($1, "timestamp") == 0) + { + $$.type_enum = ECPGt_timestamp; + $$.type_str = make_str("timestamp"); + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); + $$.type_sizeof = NULL; + } + else if (strcmp($1, "interval") == 0) + { + $$.type_enum = ECPGt_interval; + $$.type_str = make_str("interval"); + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); + $$.type_sizeof = NULL; + } + else if (strcmp($1, "datetime") == 0) + { + $$.type_enum = ECPGt_timestamp; + $$.type_str = make_str("timestamp"); + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); $$.type_sizeof = NULL; } else @@ -4068,55 +5564,145 @@ type: simple_type $$.type_enum = this->type->type_enum; $$.type_dimension = this->type->type_dimension; $$.type_index = this->type->type_index; + if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) + $$.type_sizeof = this->type->type_sizeof; + else + $$.type_sizeof = cat_str(3, make_str("sizeof("), mm_strdup(this->name), make_str(")")); + + struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); + } + } + | s_struct_union_symbol + { + /* this is for named structs/unions */ + char *name; + struct typedefs *this; + bool forward = (forward_name != NULL && strcmp($1.symbol, forward_name) == 0 && strcmp($1.su, "struct") == 0); + + name = cat2_str($1.su, $1.symbol); + /* Do we have a forward definition? */ + if (!forward) + { + /* No */ + + this = get_typedef(name); + $$.type_str = mm_strdup(this->name); + $$.type_enum = this->type->type_enum; + $$.type_dimension = this->type->type_dimension; + $$.type_index = this->type->type_index; $$.type_sizeof = this->type->type_sizeof; struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); + free(name); + } + else + { + $$.type_str = name; + $$.type_enum = ECPGt_long; + $$.type_dimension = make_str("-1"); + $$.type_index = make_str("-1"); + $$.type_sizeof = make_str(""); + struct_member_list[struct_level] = NULL; } } ; -enum_type: SQL_ENUM opt_symbol enum_definition +enum_type: ENUM_P symbol enum_definition { $$ = cat_str(3, make_str("enum"), $2, $3); } - | SQL_ENUM symbol + | ENUM_P enum_definition + { $$ = cat2_str(make_str("enum"), $2); } + | ENUM_P 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 '}' +struct_union_type_with_symbol: s_struct_union_symbol + { + struct_member_list[struct_level++] = NULL; + if (struct_level >= STRUCT_DEPTH) + mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition"); + forward_name = mm_strdup($1.symbol); + } + '{' variable_declarations '}' { + struct typedefs *ptr, *this; + struct this_type su_type; + ECPGfree_struct_member(struct_member_list[struct_level]); - free(actual_storage[struct_level--]); - $$ = cat_str(4, $1, make_str("{"), $3, make_str("}")); + struct_member_list[struct_level] = NULL; + struct_level--; + if (strncmp($1.su, "struct", sizeof("struct")-1) == 0) + su_type.type_enum = ECPGt_struct; + else + su_type.type_enum = ECPGt_union; + su_type.type_str = cat2_str($1.su, $1.symbol); + free(forward_name); + forward_name = NULL; + + /* This is essantially a typedef but needs the keyword struct/union as well. + * So we create the typedef for each struct definition with symbol */ + for (ptr = types; ptr != NULL; ptr = ptr->next) + { + if (strcmp(su_type.type_str, ptr->name) == 0) + /* re-definition is a bug */ + mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" already defined", su_type.type_str); + } + + this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); + + /* initial definition */ + this->next = types; + this->name = mm_strdup(su_type.type_str); + this->brace_level = braces_open; + this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); + this->type->type_enum = su_type.type_enum; + this->type->type_str = mm_strdup(su_type.type_str); + this->type->type_dimension = make_str("-1"); /* dimension of array */ + this->type->type_index = make_str("-1"); /* length of string */ + this->type->type_sizeof = ECPGstruct_sizeof; + this->struct_member_list = struct_member_list[struct_level]; + + types = this; + $$ = cat_str(4, su_type.type_str, make_str("{"), $4, make_str("}")); } ; -union_type: s_union '{' variable_declarations '}' +struct_union_type: struct_union_type_with_symbol { $$ = $1; } + | s_struct_union + { + struct_member_list[struct_level++] = NULL; + if (struct_level >= STRUCT_DEPTH) + mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition"); + } + '{' variable_declarations '}' { ECPGfree_struct_member(struct_member_list[struct_level]); - free(actual_storage[struct_level--]); - $$ = cat_str(4, $1, make_str("{"), $3, make_str("}")); + struct_member_list[struct_level] = NULL; + struct_level--; + $$ = cat_str(4, $1, make_str("{"), $4, make_str("}")); } ; -s_struct: SQL_STRUCT opt_symbol +s_struct_union_symbol: SQL_STRUCT symbol { - struct_member_list[struct_level++] = NULL; - $$ = cat2_str(make_str("struct"), $2); - ECPGstruct_sizeof = cat_str(3, make_str("sizeof("), strdup($$), make_str(")")); - if (struct_level >= STRUCT_DEPTH) - mmerror(PARSE_ERROR, ET_ERROR, "Too many levels in nested structure definition"); + $$.su = make_str("struct"); + $$.symbol = $2; + ECPGstruct_sizeof = cat_str(3, make_str("sizeof("), cat2_str(mm_strdup($$.su), mm_strdup($$.symbol)), make_str(")")); + } + | UNION symbol + { + $$.su = make_str("union"); + $$.symbol = $2; } ; -s_union: UNION opt_symbol +s_struct_union: SQL_STRUCT { - struct_member_list[struct_level++] = NULL; - if (struct_level >= STRUCT_DEPTH) - mmerror(PARSE_ERROR, ET_ERROR, "Too many levels in nested structure definition"); - - $$ = cat2_str(make_str("union"), $2); + ECPGstruct_sizeof = make_str(""); /* This must not be NULL to distinguish from simple types. */ + $$ = make_str("struct"); } + | UNION { $$ = make_str("union"); } ; simple_type: unsigned_type { $$=$1; } @@ -4124,11 +5710,11 @@ simple_type: unsigned_type { $$=$1; } ; unsigned_type: SQL_UNSIGNED SQL_SHORT { $$ = ECPGt_unsigned_short; } - | SQL_UNSIGNED SQL_SHORT INT { $$ = ECPGt_unsigned_short; } + | SQL_UNSIGNED SQL_SHORT INT_P { $$ = ECPGt_unsigned_short; } | SQL_UNSIGNED { $$ = ECPGt_unsigned_int; } - | SQL_UNSIGNED INT { $$ = ECPGt_unsigned_int; } + | SQL_UNSIGNED INT_P { $$ = ECPGt_unsigned_int; } | SQL_UNSIGNED SQL_LONG { $$ = ECPGt_unsigned_long; } - | SQL_UNSIGNED SQL_LONG INT { $$ = ECPGt_unsigned_long; } + | SQL_UNSIGNED SQL_LONG INT_P { $$ = ECPGt_unsigned_long; } | SQL_UNSIGNED SQL_LONG SQL_LONG { #ifdef HAVE_LONG_LONG_INT_64 @@ -4137,7 +5723,7 @@ unsigned_type: SQL_UNSIGNED SQL_SHORT { $$ = ECPGt_unsigned_short; } $$ = ECPGt_unsigned_long; #endif } - | SQL_UNSIGNED SQL_LONG SQL_LONG INT + | SQL_UNSIGNED SQL_LONG SQL_LONG INT_P { #ifdef HAVE_LONG_LONG_INT_64 $$ = ECPGt_unsigned_long_long; @@ -4149,10 +5735,10 @@ unsigned_type: SQL_UNSIGNED SQL_SHORT { $$ = ECPGt_unsigned_short; } ; signed_type: SQL_SHORT { $$ = ECPGt_short; } - | SQL_SHORT INT { $$ = ECPGt_short; } - | INT { $$ = ECPGt_int; } + | SQL_SHORT INT_P { $$ = ECPGt_short; } + | INT_P { $$ = ECPGt_int; } | SQL_LONG { $$ = ECPGt_long; } - | SQL_LONG INT { $$ = ECPGt_long; } + | SQL_LONG INT_P { $$ = ECPGt_long; } | SQL_LONG SQL_LONG { #ifdef HAVE_LONG_LONG_INT_64 @@ -4161,7 +5747,7 @@ signed_type: SQL_SHORT { $$ = ECPGt_short; } $$ = ECPGt_long; #endif } - | SQL_LONG SQL_LONG INT + | SQL_LONG SQL_LONG INT_P { #ifdef HAVE_LONG_LONG_INT_64 $$ = ECPGt_long_long; @@ -4171,6 +5757,7 @@ signed_type: SQL_SHORT { $$ = ECPGt_short; } } | SQL_BOOL { $$ = ECPGt_bool; } | CHAR_P { $$ = ECPGt_char; } + | DOUBLE_P { $$ = ECPGt_double; } ; opt_signed: SQL_SIGNED @@ -4183,72 +5770,79 @@ variable_list: variable { $$ = cat_str(3, $1, make_str(","), $3); } ; -variable: opt_pointer ECPGColLabel opt_array_bounds opt_initializer +variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initializer { struct ECPGtype * type; - int dimension = $3.index1; /* dimension of array */ - int length = $3.index2; /* lenght of string */ - char dim[14L], ascii_len[12]; + char *dimension = $3.index1; /* dimension of array */ + char *length = $3.index2; /* length of string */ + char dim[14L]; + char *vcn; - adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1)); + adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1), false); switch (actual_type[struct_level].type_enum) { case ECPGt_struct: case ECPGt_union: - if (dimension < 0) + if (atoi(dimension) < 0) type = ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_sizeof); else type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_sizeof), dimension); - $$ = cat_str(4, $1, mm_strdup($2), $3.str, $4); + $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); break; case ECPGt_varchar: - if (dimension < 0) - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length); + if (atoi(dimension) < 0) + type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, yylineno); else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension); - - switch(dimension) - { - case 0: - case -1: - case 1: + type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, yylineno), dimension); + + if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1) *dim = '\0'; - break; - default: - sprintf(dim, "[%d]", dimension); - break; - } - sprintf(ascii_len, "%d", length); - - if (length == 0) + else + sprintf(dim, "[%s]", dimension); + /* cannot check for atoi <= 0 because a defined constant will yield 0 here as well */ + if (atoi(length) < 0 || strcmp(length, "0") == 0) mmerror(PARSE_ERROR, ET_ERROR, "pointer to varchar are not implemented"); - if (dimension == 0) - $$ = 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); + /* make sure varchar struct name is unique by adding linenumer of its definition */ + vcn = (char *) mm_alloc(strlen($2) + sizeof(int) * CHAR_BIT * 10 / 3); + sprintf(vcn, "%s_%d", $2, yylineno); + if (strcmp(dimension, "0") == 0) + $$ = cat_str(7, make2_str(make_str(" struct varchar_"), vcn), make_str(" { int len; char arr["), mm_strdup(length), make_str("]; } *"), mm_strdup($2), $4, $5); else - $$ = 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); + $$ = cat_str(8, make2_str(make_str(" struct varchar_"), vcn), make_str(" { int len; char arr["), mm_strdup(length), make_str("]; } "), mm_strdup($2), mm_strdup(dim), $4, $5); break; case ECPGt_char: case ECPGt_unsigned_char: - if (dimension == -1) - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length); + if (atoi(dimension) == -1) + { + int i = strlen($5); + + if (atoi(length) == -1 && i > 0) /* char [] = "string" */ + { + /* if we have an initializer but no string size set, let's use the initializer's length */ + free(length); + length = mm_alloc(i+sizeof("sizeof()")); + sprintf(length, "sizeof(%s)", $5+2); + } + type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0); + } else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension); + type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0), dimension); - $$ = cat_str(4, $1, mm_strdup($2), $3.str, $4); + $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); break; default: - if (dimension < 0) - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, 1); + if (atoi(dimension) < 0) + type = ECPGmake_simple_type(actual_type[struct_level].type_enum, make_str("1"), 0); else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension); + type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, make_str("1"), 0), dimension); - $$ = cat_str(4, $1, mm_strdup($2), $3.str, $4); + $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); break; } @@ -4276,8 +5870,7 @@ opt_pointer: /*EMPTY*/ { $$ = EMPTY; } ; /* - * As long as the prepare statement is not supported by the backend, we will - * try to simulate it here so we get dynamic SQL + * We try to simulate the correct DECLARE syntax here so we get dynamic SQL */ ECPGDeclare: DECLARE STATEMENT ident { @@ -4291,48 +5884,22 @@ ECPGDeclare: DECLARE STATEMENT ident ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; } ; -dis_name: connection_object { $$ = $1; } - | SQL_CURRENT { $$ = make_str("\"CURRENT\""); } - | ALL { $$ = make_str("\"ALL\""); } - | /*EMPTY*/ { $$ = make_str("\"CURRENT\""); } +dis_name: connection_object { $$ = $1; } + | CURRENT_P { $$ = make_str("\"CURRENT\""); } + | ALL { $$ = make_str("\"ALL\""); } + | /* EMPTY */ { $$ = make_str("\"CURRENT\""); } ; -connection_object: connection_target { $$ = $1; } - | DEFAULT { $$ = make_str("\"DEFAULT\""); } +connection_object: database_name { $$ = make3_str(make_str("\""), $1, make_str("\"")); } + | DEFAULT { $$ = make_str("\"DEFAULT\""); } + | char_variable { $$ = $1; } ; -/* - * execute a given string as sql command - */ -ECPGExecute : EXECUTE IMMEDIATE execstring - { - struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable)); - - thisquery->type = &ecpg_query; - thisquery->brace_level = 0; - thisquery->next = NULL; - thisquery->name = $3; - - add_variable(&argsinsert, thisquery, &no_indicator); - - $$ = make_str("?"); - } - | EXECUTE ident - { - struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable)); - - thisquery->type = &ecpg_query; - thisquery->brace_level = 0; - thisquery->next = NULL; - thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($2)); - sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $2); - - add_variable(&argsinsert, thisquery, &no_indicator); - } - ecpg_using opt_ecpg_into - { - $$ = make_str("?"); - } +execute_rest: ecpg_using ecpg_into { $$ = EMPTY; } + | ecpg_into ecpg_using { $$ = EMPTY; } + | ecpg_using { $$ = EMPTY; } + | ecpg_into { $$ = EMPTY; } + | /* EMPTY */ { $$ = EMPTY; } ; execstring: char_variable @@ -4341,147 +5908,218 @@ execstring: char_variable { $$ = make3_str(make_str("\""), $1, make_str("\"")); } ; +prepared_name: name { + if ($1[0] == '\"' && $1[strlen($1)-1] == '\"') /* already quoted? */ + $$ = $1; + else /* not quoted => convert to lowercase */ + { + int i; + + for (i = 0; i< strlen($1); i++) + $1[i] = tolower((unsigned char) $1[i]); + + $$ = make3_str(make_str("\""), $1, make_str("\"")); + } + } + | char_variable { $$ = $1; } + ; + /* * the exec sql free command to deallocate a previously * prepared statement */ -ECPGFree: SQL_FREE ident { $$ = $2; }; +ECPGFree: SQL_FREE name { $$ = $2; } + | SQL_FREE ALL { $$ = make_str("all"); } + ; /* * open is an open cursor, at the moment this has to be removed */ -ECPGOpen: SQL_OPEN name ecpg_using { $$ = $2; }; +ECPGOpen: SQL_OPEN name opt_ecpg_using { $$ = $2; }; -ecpg_using: /*EMPTY*/ { $$ = EMPTY; } - | USING variablelist - { - /* mmerror ("open cursor with variables not implemented yet"); */ - $$ = EMPTY; - } +opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; } + | ecpg_using { $$ = $1; } ; -opt_sql: /*EMPTY*/ | SQL_SQL; +ecpg_using: USING using_list { $$ = EMPTY; } + | using_descriptor { $$ = $1; } + ; -ecpg_into: INTO into_list +using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { + add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator); $$ = EMPTY; } - | INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar + ; + +into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { - add_variable(&argsresult, descriptor_variable($4,0), &no_indicator); + add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator); $$ = EMPTY; } ; -opt_ecpg_into: /*EMPTY*/ { $$ = EMPTY; } - | ecpg_into { $$ = $1; } +opt_sql: /*EMPTY*/ | SQL_SQL; + +ecpg_into: INTO into_list { $$ = EMPTY; } + | into_descriptor { $$ = $1; } ; -variable: civarind | civar +using_list: UsingConst | UsingConst ',' using_list; + +UsingConst: AllConst + { + if ($1[1] != '$') /* found a constant */ + { + char *length = mm_alloc(32); + + sprintf(length, "%d", (int) strlen($1)); + add_variable_to_head(&argsinsert, new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); + } + } + | civarind { $$ = EMPTY; } ; -variablelist: variable | variable ',' variablelist; + /* - * As long as the prepare statement is not supported by the backend, we will - * try to simulate it here so we get dynamic SQL + * We accept descibe but do nothing with it so far. */ -ECPGPrepare: SQL_PREPARE ident FROM execstring - { $$ = cat2_str(make3_str(make_str("\""), $2, make_str("\",")), $4); } - ; +ECPGDescribe: SQL_DESCRIBE INPUT_P name using_descriptor + { + const char *con = connection ? connection : "NULL"; + mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement\n"); + $$ = (char *) mm_alloc(sizeof("1, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3)); + sprintf($$, "1, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3); + } + | SQL_DESCRIBE opt_output name using_descriptor + { + const char *con = connection ? connection : "NULL"; + mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement\n"); + $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3)); + sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3); + } + | SQL_DESCRIBE opt_output name into_descriptor + { + const char *con = connection ? connection : "NULL"; + mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement\n"); + $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3)); + sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3); + } + ; + +opt_output: SQL_OUTPUT { $$ = make_str("output"); } + | /* EMPTY */ { $$ = EMPTY; } + ; /* * dynamic SQL: descriptor based access - * written by Christof Petig + * originall written by Christof Petig + * and Peter Eisentraut */ /* - * deallocate a descriptor + * allocate a descriptor */ -ECPGDeallocateDescr: SQL_DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar +ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar { - drop_descriptor($3,connection); + add_descriptor($3,connection); $$ = $3; } ; + /* - * allocate a descriptor + * deallocate a descriptor */ -ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar +ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar { - add_descriptor($3,connection); + drop_descriptor($3,connection); $$ = $3; - }; + } + ; /* - * read from descriptor + * manipulate a descriptor header */ -ECPGGetDescHeaderItem: CVARIABLE '=' desc_header_item +ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems + { $$ = $3; } + ; + +ECPGGetDescHeaderItems: ECPGGetDescHeaderItem + | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem + ; + +ECPGGetDescHeaderItem: cvariable '=' desc_header_item { push_assignment($1, $3); } ; -desc_header_item: SQL_COUNT { $$ = ECPGd_count; } + +ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems + { $$ = $3; } ; -ECPGGetDescItem: CVARIABLE '=' descriptor_item { push_assignment($1, $3); }; +ECPGSetDescHeaderItems: ECPGSetDescHeaderItem + | ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem + ; -descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } - | SQL_DATA { $$ = ECPGd_data; } - | SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; } - | SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; } - | SQL_INDICATOR { $$ = ECPGd_indicator; } - | SQL_KEY_MEMBER { $$ = ECPGd_key_member; } - | SQL_LENGTH { $$ = ECPGd_length; } - | SQL_NAME { $$ = ECPGd_name; } - | SQL_NULLABLE { $$ = ECPGd_nullable; } - | SQL_OCTET_LENGTH { $$ = ECPGd_octet; } - | PRECISION { $$ = ECPGd_precision; } - | SQL_RETURNED_LENGTH { $$ = ECPGd_length; } - | SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; } - | SQL_SCALE { $$ = ECPGd_scale; } - | TYPE_P { $$ = ECPGd_type; } +ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar + { + push_assignment($3, $1); + } ; -ECPGGetDescHeaderItems: ECPGGetDescHeaderItem - | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem + +desc_header_item: SQL_COUNT { $$ = ECPGd_count; } + ; + +/* + * manipulate a descriptor + */ + +ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems + { $$.str = $5; $$.name = $3; } ; ECPGGetDescItems: ECPGGetDescItem | ECPGGetDescItems ',' ECPGGetDescItem ; -ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar - ECPGGetDescHeaderItems - { $$ = $3; } - ; +ECPGGetDescItem: cvariable '=' descriptor_item { push_assignment($1, $3); }; -ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar - SQL_VALUE CVARIABLE ECPGGetDescItems - { $$.str = $5; $$.name = $3; } - | SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGGetDescItems + +ECPGSetDescriptor: SET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGSetDescItems { $$.str = $5; $$.name = $3; } ; -/* - * for compatibility with ORACLE we will also allow the keyword RELEASE - * after a transaction statement to disconnect from the database. - */ +ECPGSetDescItems: ECPGSetDescItem + | ECPGSetDescItems ',' ECPGSetDescItem + ; -ECPGRelease: TransactionStmt SQL_RELEASE +ECPGSetDescItem: descriptor_item '=' AllConstVar { - if (strcmp($1, "begin") == 0) - mmerror(PARSE_ERROR, ET_ERROR, "RELEASE does not make sense when beginning a transaction"); - - fprintf(yyout, "ECPGtrans(__LINE__, %s, \"%s\");", - connection ? connection : "NULL", $1); - whenever_action(0); - fprintf(yyout, "ECPGdisconnect(__LINE__, \"\");"); - whenever_action(0); - free($1); + push_assignment($3, $1); } ; + +descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } + | SQL_DATA { $$ = ECPGd_data; } + | SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; } + | SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; } + | SQL_INDICATOR { $$ = ECPGd_indicator; } + | SQL_KEY_MEMBER { $$ = ECPGd_key_member; } + | SQL_LENGTH { $$ = ECPGd_length; } + | NAME_P { $$ = ECPGd_name; } + | SQL_NULLABLE { $$ = ECPGd_nullable; } + | SQL_OCTET_LENGTH { $$ = ECPGd_octet; } + | PRECISION { $$ = ECPGd_precision; } + | SQL_RETURNED_LENGTH { $$ = ECPGd_length; } + | SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; } + | SQL_SCALE { $$ = ECPGd_scale; } + | TYPE_P { $$ = ECPGd_type; } + ; + /* * set/reset the automatic transaction mode, this needs a differnet handling * as the other set commands @@ -4498,8 +6136,9 @@ on_off: ON { $$ = make_str("on"); } * set the actual connection, this needs a differnet handling as the other * set commands */ -ECPGSetConnection: SET SQL_CONNECTION TO connection_object { $$ = $4; } - | SET SQL_CONNECTION '=' connection_object { $$ = $4; } +ECPGSetConnection: SET CONNECTION TO connection_object { $$ = $4; } + | SET CONNECTION '=' connection_object { $$ = $4; } + | SET CONNECTION connection_object { $$ = $3; } ; /* @@ -4511,53 +6150,9 @@ ECPGTypedef: TYPE_P /* an initializer specified */ initializer = 0; } - ColLabel IS type opt_type_array_bounds opt_reference + ECPGColLabelCommon IS var_type opt_array_bounds opt_reference { - /* add entry to list */ - struct typedefs *ptr, *this; - int dimension = $6.index1; - int length = $6.index2; - - if (($5.type_enum == ECPGt_struct || - $5.type_enum == ECPGt_union) && - initializer == 1) - mmerror(PARSE_ERROR, ET_ERROR, "Initializer not allowed in EXEC SQL TYPE command"); - else - { - for (ptr = types; ptr != NULL; ptr = ptr->next) - { - if (strcmp($3, ptr->name) == 0) - { - /* re-definition is a bug */ - snprintf(errortext, sizeof(errortext), "Type %s already defined", $3); - mmerror(PARSE_ERROR, ET_ERROR, errortext); - } - } - - adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0); - - this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); - - /* initial definition */ - this->next = types; - this->name = $3; - this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); - this->type->type_enum = $5.type_enum; - this->type->type_str = mm_strdup($3); - this->type->type_dimension = dimension; /* dimension of array */ - this->type->type_index = length; /* lenght of string */ - this->type->type_sizeof = ECPGstruct_sizeof; - this->struct_member_list = ($5.type_enum == ECPGt_struct || $5.type_enum == ECPGt_union) ? - struct_member_list[struct_level] : NULL; - - if ($5.type_enum != ECPGt_varchar && - $5.type_enum != ECPGt_char && - $5.type_enum != ECPGt_unsigned_char && - this->type->type_index >= 0) - mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types"); - - types = this; - } + add_typedef($3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *$7 ? 1 : 0); if (auto_create_c == false) $$ = cat_str(7, make_str("/* exec sql type"), mm_strdup($3), make_str("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, make_str("*/")); @@ -4566,44 +6161,6 @@ ECPGTypedef: TYPE_P } ; -opt_type_array_bounds: '[' ']' opt_type_array_bounds - { - $$.index1 = 0; - $$.index2 = $3.index1; - $$.str = cat2_str(make_str("[]"), $3.str); - } - | '(' ')' opt_type_array_bounds - { - $$.index1 = 0; - $$.index2 = $3.index1; - $$.str = cat2_str(make_str("[]"), $3.str); - } - | '[' Iresult ']' opt_type_array_bounds - { - char *txt = mm_alloc(20L); - - sprintf (txt, "%d", $2); - $$.index1 = $2; - $$.index2 = $4.index1; - $$.str = cat_str(4, make_str("["), txt, make_str("]"), $4.str); - } - | '(' Iresult ')' opt_type_array_bounds - { - char *txt = mm_alloc(20L); - - sprintf (txt, "%d", $2); - $$.index1 = $2; - $$.index2 = $4.index1; - $$.str = cat_str(4, make_str("["), txt, make_str("]"), $4.str); - } - | /* EMPTY */ - { - $$.index1 = -1; - $$.index2 = -1; - $$.str= EMPTY; - } - ; - opt_reference: SQL_REFERENCE { $$ = make_str("reference"); } | /*EMPTY*/ { $$ = EMPTY; } ; @@ -4617,54 +6174,54 @@ ECPGVar: SQL_VAR /* an initializer specified */ initializer = 0; } - ColLabel IS type opt_type_array_bounds opt_reference + ColLabel IS var_type opt_array_bounds opt_reference { struct variable *p = find_variable($3); - int dimension = $6.index1; - int length = $6.index2; + char *dimension = $6.index1; + char *length = $6.index2; struct ECPGtype * type; if (($5.type_enum == ECPGt_struct || $5.type_enum == ECPGt_union) && initializer == 1) - mmerror(PARSE_ERROR, ET_ERROR, "Initializer not allowed in EXEC SQL VAR command"); + mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in EXEC SQL VAR command"); else { - adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0); + adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0, false); switch ($5.type_enum) { case ECPGt_struct: case ECPGt_union: - if (dimension < 0) + if (atoi(dimension) < 0) type = ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_sizeof); else type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum,$5.type_sizeof), dimension); break; case ECPGt_varchar: - if (dimension == -1) - type = ECPGmake_simple_type($5.type_enum, length); + if (atoi(dimension) == -1) + type = ECPGmake_simple_type($5.type_enum, length, 0); else - type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length), dimension); + type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension); break; case ECPGt_char: case ECPGt_unsigned_char: - if (dimension == -1) - type = ECPGmake_simple_type($5.type_enum, length); + if (atoi(dimension) == -1) + type = ECPGmake_simple_type($5.type_enum, length, 0); else - type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length), dimension); + type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension); break; default: - if (length >= 0) - mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types"); + if (atoi(length) >= 0) + mmerror(PARSE_ERROR, ET_ERROR, "no multidimensional array support for simple data types"); - if (dimension < 0) - type = ECPGmake_simple_type($5.type_enum, 1); + if (atoi(dimension) < 0) + type = ECPGmake_simple_type($5.type_enum, make_str("1"), 0); else - type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, 1), dimension); + type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, make_str("1"), 0), dimension); break; } @@ -4684,23 +6241,23 @@ ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action { when_error.code = $3.code; when_error.command = $3.command; - $$ = cat_str(3, make_str("/* exec sql whenever sqlerror "), $3.str, make_str("; */\n")); + $$ = cat_str(3, make_str("/* exec sql whenever sqlerror "), $3.str, make_str("; */")); } | SQL_WHENEVER NOT SQL_FOUND action { when_nf.code = $4.code; when_nf.command = $4.command; - $$ = cat_str(3, make_str("/* exec sql whenever not found "), $4.str, make_str("; */\n")); + $$ = cat_str(3, make_str("/* exec sql whenever not found "), $4.str, make_str("; */")); } | SQL_WHENEVER SQL_SQLWARNING action { when_warn.code = $3.code; when_warn.command = $3.command; - $$ = cat_str(3, make_str("/* exec sql whenever sql_warning "), $3.str, make_str("; */\n")); + $$ = cat_str(3, make_str("/* exec sql whenever sql_warning "), $3.str, make_str("; */")); } ; -action : SQL_CONTINUE +action : CONTINUE_P { $$.code = W_NOTHING; $$.command = NULL; @@ -4748,61 +6305,67 @@ action : SQL_CONTINUE $$.command = cat_str(4, $2, make_str("("), $4, make_str(")")); $$.str = cat2_str(make_str("call"), mm_strdup($$.command)); } + | SQL_CALL name + { + $$.code = W_DO; + $$.command = cat2_str($2, make_str("()")); + $$.str = cat2_str(make_str("call"), mm_strdup($$.command)); + } ; /* some other stuff for ecpg */ /* additional unreserved keywords */ -ECPGKeywords: SQL_BREAK { $$ = make_str("break"); } - | SQL_CALL { $$ = make_str("call"); } - | SQL_CARDINALITY { $$ = make_str("cardinality"); } - | SQL_CONNECT { $$ = make_str("connect"); } - | SQL_CONTINUE { $$ = make_str("continue"); } - | SQL_COUNT { $$ = make_str("count"); } - | SQL_DATA { $$ = make_str("data"); } +ECPGKeywords: ECPGKeywords_vanames { $$ = $1; } + | ECPGKeywords_rest { $$ = $1; } + ; + +ECPGKeywords_vanames: SQL_BREAK { $$ = make_str("break"); } + | SQL_CALL { $$ = make_str("call"); } + | SQL_CARDINALITY { $$ = make_str("cardinality"); } + | SQL_COUNT { $$ = make_str("count"); } + | SQL_DATA { $$ = make_str("data"); } | SQL_DATETIME_INTERVAL_CODE { $$ = make_str("datetime_interval_code"); } | SQL_DATETIME_INTERVAL_PRECISION { $$ = make_str("datetime_interval_precision"); } - | 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_KEY_MEMBER { $$ = make_str("key_member"); } - | SQL_LENGTH { $$ = make_str("length"); } - | SQL_NAME { $$ = make_str("name"); } - | SQL_NULLABLE { $$ = make_str("nullable"); } - | SQL_OCTET_LENGTH { $$ = make_str("octet_length"); } - | SQL_OPEN { $$ = make_str("open"); } - | SQL_PREPARE { $$ = make_str("prepare"); } - | SQL_RELEASE { $$ = make_str("release"); } + | 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_KEY_MEMBER { $$ = make_str("key_member"); } + | SQL_LENGTH { $$ = make_str("length"); } + | SQL_NULLABLE { $$ = make_str("nullable"); } + | SQL_OCTET_LENGTH { $$ = make_str("octet_length"); } | SQL_RETURNED_LENGTH { $$ = make_str("returned_length"); } - | SQL_RETURNED_OCTET_LENGTH { $$ = make_str("returned_octet_length"); } - | SQL_SCALE { $$ = make_str("scale"); } - | SQL_SECTION { $$ = make_str("section"); } - | SQL_SQLERROR { $$ = make_str("sqlerror"); } - | SQL_SQLPRINT { $$ = make_str("sqlprint"); } - | SQL_SQLWARNING { $$ = make_str("sqlwarning"); } - | SQL_STOP { $$ = make_str("stop"); } - | SQL_VAR { $$ = make_str("var"); } - | SQL_WHENEVER { $$ = make_str("whenever"); } + | SQL_RETURNED_OCTET_LENGTH { $$ = make_str("returned_octet_length"); } + | SQL_SCALE { $$ = make_str("scale"); } + | SQL_SECTION { $$ = make_str("section"); } + | SQL_SQL { $$ = make_str("sql"); } + | SQL_SQLERROR { $$ = make_str("sqlerror"); } + | SQL_SQLPRINT { $$ = make_str("sqlprint"); } + | SQL_SQLWARNING { $$ = make_str("sqlwarning"); } + | SQL_STOP { $$ = make_str("stop"); } ; -/* additional keywords that can be SQL type names (but not ECPGColLabels) */ -ECPGTypeName: SQL_BOOL { $$ = make_str("bool"); } - | SQL_LONG { $$ = make_str("long"); } - | SQL_SHORT { $$ = make_str("short"); } - | SQL_STRUCT { $$ = make_str("struct"); } - | SQL_SIGNED { $$ = make_str("signed"); } - | SQL_UNSIGNED { $$ = make_str("unsigned"); } +ECPGKeywords_rest: SQL_CONNECT { $$ = make_str("connect"); } + | SQL_DESCRIBE { $$ = make_str("describe"); } + | SQL_DISCONNECT { $$ = make_str("disconnect"); } + | SQL_OPEN { $$ = make_str("open"); } + | SQL_VAR { $$ = make_str("var"); } + | SQL_WHENEVER { $$ = make_str("whenever"); } ; -opt_symbol: symbol { $$ = $1; } - | /*EMPTY*/ { $$ = EMPTY; } +/* additional keywords that can be SQL type names (but not ECPGColLabels) */ +ECPGTypeName: SQL_BOOL { $$ = make_str("bool"); } + | SQL_LONG { $$ = make_str("long"); } + | SQL_OUTPUT { $$ = make_str("output"); } + | SQL_SHORT { $$ = make_str("short"); } + | SQL_STRUCT { $$ = make_str("struct"); } + | SQL_SIGNED { $$ = make_str("signed"); } + | SQL_UNSIGNED { $$ = make_str("unsigned"); } ; -symbol: ColLabel { $$ = $1; } +symbol: ColLabel { $$ = $1; } ; /* @@ -4816,49 +6379,69 @@ symbol: ColLabel { $$ = $1; } * is chosen in part to make keywords acceptable as names wherever possible. */ -/* Column identifier --- names that can be column, table, etc names. - */ -ColId: ident { $$ = $1; } - | unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | CHAR_P { $$ = make_str("char"); } +ECPGColId:ident { $$ = $1; } + | ECPGunreserved_interval { $$ = $1; } + | ECPGunreserved_con { $$ = $1; } + | col_name_keyword { $$ = $1; } + | ECPGKeywords { $$ = $1; } + | ECPGCKeywords { $$ = $1; } + | CHAR_P { $$ = make_str("char"); } + | VALUES { $$ = make_str("values"); } ; - -/* Type identifier --- names that can be type names. +/* Column identifier --- names that can be column, table, etc names. */ -type_name: ident { $$ = $1; } - | unreserved_keyword { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | ECPGTypeName { $$ = $1; } - ; - -/* Function identifier --- names that can be function names. +ColId: ident { $$ = $1; } + | unreserved_keyword { $$ = $1; } + | col_name_keyword { $$ = $1; } + | ECPGKeywords { $$ = $1; } + | ECPGCKeywords { $$ = $1; } + | CHAR_P { $$ = make_str("char"); } + | VALUES { $$ = make_str("values"); } + ; +/* Type/function identifier --- names that can be type names. */ -function_name: ident { $$ = $1; } - | unreserved_keyword { $$ = $1; } - | func_name_keyword { $$ = $1; } - | ECPGKeywords { $$ = $1; } +type_function_name: ident { $$ = $1; } + | unreserved_keyword { $$ = $1; } + | type_func_name_keyword { $$ = $1; } + | ECPGKeywords { $$ = $1; } + | ECPGTypeName { $$ = $1; } + | ECPGCKeywords { $$ = $1; } ; /* Column label --- allowed labels in "AS" clauses. * This presently includes *all* Postgres keywords. */ -ColLabel: ECPGColLabel { $$ = $1; } - | ECPGTypeName { $$ = $1; } - | CHAR_P { $$ = make_str("char"); } - | INT { $$ = make_str("int"); } - | UNION { $$ = make_str("union"); } +ColLabel: ECPGColLabel { $$ = $1; } + | ECPGTypeName { $$ = $1; } + | CHAR_P { $$ = make_str("char"); } + | INPUT_P { $$ = make_str("input"); } + | INT_P { $$ = make_str("int"); } + | UNION { $$ = make_str("union"); } + | TO { $$ = make_str("to"); } + | ECPGCKeywords { $$ = $1; } + | ECPGunreserved_interval { $$ = $1; } + ; + +ECPGColLabelCommon: ident { $$ = $1; } + | col_name_keyword { $$ = $1; } + | type_func_name_keyword { $$ = $1; } + | ECPGKeywords_vanames { $$ = $1; } ; -ECPGColLabel: ident { $$ = $1; } - | unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | func_name_keyword { $$ = $1; } - | reserved_keyword { $$ = $1; } - | ECPGKeywords { $$ = $1; } +ECPGColLabel: ECPGColLabelCommon { $$ = $1; } + | reserved_keyword { $$ = $1; } + | ECPGunreserved { $$ = $1; } + | ECPGKeywords_rest { $$ = $1; } ; +ECPGCKeywords: 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"); } + | S_TYPEDEF { $$ = make_str("typedef"); } + | S_VOLATILE { $$ = make_str("volatile"); } + ; /* * Keyword classification lists. Generally, every keyword present in @@ -4871,162 +6454,256 @@ ECPGColLabel: ident { $$ = $1; } /* "Unreserved" keywords --- available for use as any kind of name. */ -unreserved_keyword: - ABORT_TRANS { $$ = make_str("abort"); } - | ABSOLUTE { $$ = make_str("absolute"); } - | ACCESS { $$ = make_str("access"); } - | ACTION { $$ = make_str("action"); } - | ADD { $$ = make_str("add"); } - | AFTER { $$ = make_str("after"); } - | AGGREGATE { $$ = make_str("aggregate"); } - | ALTER { $$ = make_str("alter"); } - | ASSERTION { $$ = make_str("assertion"); } - | AT { $$ = make_str("at"); } - | BACKWARD { $$ = make_str("backward"); } - | BEFORE { $$ = make_str("before"); } - | BEGIN_TRANS { $$ = make_str("begin"); } - | BY { $$ = make_str("by"); } - | CACHE { $$ = make_str("cache"); } - | CASCADE { $$ = make_str("cascade"); } - | CHAIN { $$ = make_str("chain"); } - | CHARACTERISTICS { $$ = make_str("characteristics"); } - | CHECKPOINT { $$ = make_str("checkpoint"); } - | CLOSE { $$ = make_str("close"); } - | CLUSTER { $$ = make_str("cluster"); } - | COMMENT { $$ = make_str("comment"); } - | COMMIT { $$ = make_str("commit"); } - | COMMITTED { $$ = make_str("committed"); } - | CONSTRAINTS { $$ = make_str("constraints"); } - | COPY { $$ = make_str("copy"); } - | CREATEDB { $$ = make_str("createdb"); } - | CREATEUSER { $$ = make_str("createuser"); } - | CURSOR { $$ = make_str("cursor"); } - | CYCLE { $$ = make_str("cycle"); } - | DATABASE { $$ = make_str("database"); } - | DAY_P { $$ = make_str("day"); } - | DECLARE { $$ = make_str("declare"); } - | DEFERRED { $$ = make_str("deferred"); } - | DELETE_P { $$ = make_str("delete"); } - | DELIMITERS { $$ = make_str("delimiters"); } - | DOMAIN_P { $$ = make_str("domain"); } - | DOUBLE { $$ = make_str("double"); } - | DROP { $$ = make_str("drop"); } - | EACH { $$ = make_str("each"); } - | ENCODING { $$ = make_str("encoding"); } - | ENCRYPTED { $$ = make_str("encrypted"); } - | ESCAPE { $$ = make_str("escape"); } - | EXCLUSIVE { $$ = make_str("exclusive"); } - | EXECUTE { $$ = make_str("execute"); } - | EXPLAIN { $$ = make_str("explain"); } - | FETCH { $$ = make_str("fetch"); } - | FORCE { $$ = make_str("force"); } - | FORWARD { $$ = make_str("forward"); } - | FUNCTION { $$ = make_str("function"); } - | GLOBAL { $$ = make_str("global"); } - | HANDLER { $$ = make_str("handler"); } - | HOUR_P { $$ = make_str("hour"); } - | IMMEDIATE { $$ = make_str("immediate"); } - | INCREMENT { $$ = make_str("increment"); } - | INDEX { $$ = make_str("index"); } - | INHERITS { $$ = make_str("inherits"); } - | INOUT { $$ = make_str("inout"); } - | INSENSITIVE { $$ = make_str("insensitive"); } - | INSERT { $$ = make_str("insert"); } - | INSTEAD { $$ = make_str("instead"); } - | ISOLATION { $$ = make_str("isolation"); } - | KEY { $$ = make_str("key"); } - | LANGUAGE { $$ = make_str("language"); } - | LANCOMPILER { $$ = make_str("lancompiler"); } - | LEVEL { $$ = make_str("level"); } - | LISTEN { $$ = make_str("listen"); } - | LOAD { $$ = make_str("load"); } - | LOCAL { $$ = make_str("local"); } - | LOCATION { $$ = make_str("location"); } - | LOCK_P { $$ = make_str("lock"); } - | MATCH { $$ = make_str("match"); } - | MAXVALUE { $$ = make_str("maxvalue"); } - | MINUTE_P { $$ = make_str("minute"); } - | MINVALUE { $$ = make_str("minvalue"); } - | MODE { $$ = make_str("mode"); } - | MONTH_P { $$ = make_str("month"); } - | MOVE { $$ = make_str("move"); } - | NAMES { $$ = make_str("names"); } - | NATIONAL { $$ = make_str("national"); } - | NEXT { $$ = make_str("next"); } - | NO { $$ = make_str("no"); } - | NOCREATEDB { $$ = make_str("nocreatedb"); } - | NOCREATEUSER { $$ = make_str("nocreateuser"); } - | NOTHING { $$ = make_str("nothing"); } - | NOTIFY { $$ = make_str("notify"); } - | OF { $$ = make_str("of"); } - | OIDS { $$ = make_str("oids"); } - | OPERATOR { $$ = make_str("operator"); } - | OPTION { $$ = make_str("option"); } - | OUT_P { $$ = make_str("out"); } - | OWNER { $$ = make_str("owner"); } - | PARTIAL { $$ = make_str("partial"); } - | PASSWORD { $$ = make_str("password"); } - | PATH_P { $$ = make_str("path"); } - | PENDANT { $$ = make_str("pendant"); } - | PRECISION { $$ = make_str("precision"); } - | PRIOR { $$ = make_str("prior"); } - | PRIVILEGES { $$ = make_str("privileges"); } - | PROCEDURAL { $$ = make_str("procedural"); } - | PROCEDURE { $$ = make_str("procedure"); } - | READ { $$ = make_str("read"); } - | REINDEX { $$ = make_str("reindex"); } - | RELATIVE { $$ = make_str("relative"); } - | RENAME { $$ = make_str("rename"); } - | REPLACE { $$ = make_str("replace"); } - | RESET { $$ = make_str("reset"); } - | RESTRICT { $$ = make_str("restrict"); } - | RETURNS { $$ = make_str("returns"); } - | REVOKE { $$ = make_str("revoke"); } - | ROLLBACK { $$ = make_str("rollback"); } - | ROW { $$ = make_str("row"); } - | RULE { $$ = make_str("rule"); } - | SCHEMA { $$ = make_str("schema"); } - | SCROLL { $$ = make_str("scroll"); } - | SECOND_P { $$ = make_str("second"); } - | SESSION { $$ = make_str("session"); } - | SEQUENCE { $$ = make_str("sequence"); } - | SERIALIZABLE { $$ = make_str("serializable"); } - | SET { $$ = make_str("set"); } - | SHARE { $$ = make_str("share"); } - | SHOW { $$ = make_str("show"); } - | START { $$ = make_str("start"); } - | STATEMENT { $$ = make_str("statement"); } - | STATISTICS { $$ = make_str("statistics"); } - | STDIN { $$ = make_str("stdin"); } - | STDOUT { $$ = make_str("stdout"); } - | STORAGE { $$ = make_str("storage"); } - | SYSID { $$ = make_str("sysid"); } - | TEMP { $$ = make_str("temp"); } - | TEMPLATE { $$ = make_str("template"); } - | TEMPORARY { $$ = make_str("temporary"); } - | TOAST { $$ = make_str("toast"); } - | TRANSACTION { $$ = make_str("transaction"); } - | TRIGGER { $$ = make_str("trigger"); } - | TRUNCATE { $$ = make_str("truncate"); } - | TRUSTED { $$ = make_str("trusted"); } - | TYPE_P { $$ = make_str("type"); } - | UNENCRYPTED { $$ = make_str("unencrypted"); } - | UNKNOWN { $$ = make_str("unknown"); } - | UNLISTEN { $$ = make_str("unlisten"); } - | UNTIL { $$ = make_str("until"); } - | UPDATE { $$ = make_str("update"); } - | USAGE { $$ = make_str("usage"); } - | VACUUM { $$ = make_str("vacuum"); } - | VALID { $$ = make_str("valid"); } - | VALUES { $$ = make_str("values"); } - | VARYING { $$ = make_str("varying"); } - | VERSION { $$ = make_str("version"); } - | VIEW { $$ = make_str("view"); } - | WITH { $$ = make_str("with"); } - | WITHOUT { $$ = make_str("without"); } - | WORK { $$ = make_str("work"); } - | YEAR_P { $$ = make_str("year"); } - | ZONE { $$ = make_str("zone"); } +/* The following symbols must be excluded from ECPGColLabel and directly included into ColLabel + to enable C variables to get names from ECPGColLabel: + DAY_P, HOUR_P, MINUTE_P, MONTH_P, SECOND_P, YEAR_P + */ +unreserved_keyword: ECPGunreserved_interval | ECPGunreserved; + +ECPGunreserved_interval: DAY_P { $$ = make_str("day"); } + | HOUR_P { $$ = make_str("hour"); } + | MINUTE_P { $$ = make_str("minute"); } + | MONTH_P { $$ = make_str("month"); } + | SECOND_P { $$ = make_str("second"); } + | YEAR_P { $$ = make_str("year"); } + ; + +/* The following symbol must be excluded from var_name but still included in ColId + to enable ecpg special postgresql variables with this name: CONNECTION + */ +ECPGunreserved: ECPGunreserved_con { $$ = $1; } + | CONNECTION { $$ = make_str("connection"); } + ; + +ECPGunreserved_con: ABORT_P { $$ = make_str("abort"); } + | ABSOLUTE_P { $$ = make_str("absolute"); } + | ACCESS { $$ = make_str("access"); } + | ACTION { $$ = make_str("action"); } + | ADD_P { $$ = make_str("add"); } + | ADMIN { $$ = make_str("admin"); } + | AFTER { $$ = make_str("after"); } + | AGGREGATE { $$ = make_str("aggregate"); } + | ALSO { $$ = make_str("also"); } + | ALTER { $$ = make_str("alter"); } + | ALWAYS { $$ = make_str("always"); } + | ASSERTION { $$ = make_str("assertion"); } + | ASSIGNMENT { $$ = make_str("assignment"); } + | AT { $$ = make_str("at"); } + | BACKWARD { $$ = make_str("backward"); } + | BEFORE { $$ = make_str("before"); } + | BEGIN_P { $$ = make_str("begin"); } + | BY { $$ = make_str("by"); } + | CACHE { $$ = make_str("cache"); } + | CASCADE { $$ = make_str("cascade"); } + | CASCADED { $$ = make_str("cascaded"); } + | CHAIN { $$ = make_str("chain"); } + | CHARACTERISTICS { $$ = make_str("characteristics"); } + | CHECKPOINT { $$ = make_str("checkpoint"); } + | CLASS { $$ = make_str("class"); } + | CLOSE { $$ = make_str("close"); } + | CLUSTER { $$ = make_str("cluster"); } + | COMMENT { $$ = make_str("comment"); } + | COMMIT { $$ = make_str("commit"); } + | COMMITTED { $$ = make_str("committed"); } + | CONCURRENTLY { $$ = make_str("concurrently"); } + | CONFIGURATION { $$ = make_str("configuration"); } +/* | CONNECTION { $$ = make_str("connection"); }*/ + | CONSTRAINTS { $$ = make_str("constraints"); } + | CONTENT_P { $$ = make_str("content"); } + | CONTINUE_P { $$ = make_str("continue"); } + | CONVERSION_P { $$ = make_str("conversion"); } + | COPY { $$ = make_str("copy"); } + | COST { $$ = make_str("cost"); } + | CREATEDB { $$ = make_str("createdb"); } + | CREATEROLE { $$ = make_str("createrole"); } + | CREATEUSER { $$ = make_str("createuser"); } + | CSV { $$ = make_str("csv"); } + | CURSOR { $$ = make_str("cursor"); } + | CYCLE { $$ = make_str("cycle"); } + | DATABASE { $$ = make_str("database"); } +/* | DAY_P { $$ = make_str("day"); }*/ + | DEALLOCATE { $$ = make_str("deallocate"); } + | DECLARE { $$ = make_str("declare"); } + | DEFAULTS { $$ = make_str("defaults"); } + | DEFERRED { $$ = make_str("deferred"); } + | DELETE_P { $$ = make_str("delete"); } + | DELIMITER { $$ = make_str("delimiter"); } + | DELIMITERS { $$ = make_str("delimiters"); } + | DICTIONARY { $$ = make_str("dictionary"); } + | DISABLE_P { $$ = make_str("disable"); } + | DISCARD { $$ = make_str("discard"); } + | DOCUMENT_P { $$ = make_str("document"); } + | DOMAIN_P { $$ = make_str("domain"); } + | DOUBLE_P { $$ = make_str("double"); } + | DROP { $$ = make_str("drop"); } + | EACH { $$ = make_str("each"); } + | ENABLE_P { $$ = make_str("enable"); } + | ENCODING { $$ = make_str("encoding"); } + | ENCRYPTED { $$ = make_str("encrypted"); } +/* | ENUM_P { $$ = make_str("enum"); }*/ + | ESCAPE { $$ = make_str("escape"); } + | EXCLUDING { $$ = make_str("excluding"); } + | EXCLUSIVE { $$ = make_str("exclusive"); } + | EXECUTE { $$ = make_str("execute"); } + | EXPLAIN { $$ = make_str("explain"); } + | EXTERNAL { $$ = make_str("external"); } + | FAMILY { $$ = make_str("family"); } + | FETCH { $$ = make_str("fetch"); } + | FIRST_P { $$ = make_str("first"); } + | FORCE { $$ = make_str("force"); } + | FORWARD { $$ = make_str("forward"); } + | FUNCTION { $$ = make_str("function"); } + | GLOBAL { $$ = make_str("global"); } + | GRANTED { $$ = make_str("granted"); } + | HANDLER { $$ = make_str("handler"); } + | HEADER_P { $$ = make_str("header"); } + | HOLD { $$ = make_str("hold"); } +/* | HOUR_P { $$ = make_str("hour"); }*/ + | IDENTITY_P { $$ = make_str("identity"); } + | IF_P { $$ = make_str("if"); } + | IMMEDIATE { $$ = make_str("immediate"); } + | IMMUTABLE { $$ = make_str("immutable"); } + | IMPLICIT_P { $$ = make_str("implicit"); } + | INCLUDING { $$ = make_str("including"); } + | INCREMENT { $$ = make_str("increment"); } + | INDEX { $$ = make_str("index"); } + | INDEXES { $$ = make_str("indexes"); } + | INHERIT { $$ = make_str("inherit"); } + | INHERITS { $$ = make_str("inherits"); } + | INSENSITIVE { $$ = make_str("insensitive"); } + | INSERT { $$ = make_str("insert"); } + | INSTEAD { $$ = make_str("instead"); } + | ISOLATION { $$ = make_str("isolation"); } + | KEY { $$ = make_str("key"); } + | LANCOMPILER { $$ = make_str("lancompiler"); } + | LANGUAGE { $$ = make_str("language"); } + | LARGE_P { $$ = make_str("large"); } + | LAST_P { $$ = make_str("last"); } + | LEVEL { $$ = make_str("level"); } + | LISTEN { $$ = make_str("listen"); } + | LOAD { $$ = make_str("load"); } + | LOCAL { $$ = make_str("local"); } + | LOCATION { $$ = make_str("location"); } + | LOCK_P { $$ = make_str("lock"); } + | LOGIN_P { $$ = make_str("login"); } + | MAPPING { $$ = make_str("mapping"); } + | MATCH { $$ = make_str("match"); } + | MAXVALUE { $$ = make_str("maxvalue"); } +/* | MINUTE_P { $$ = make_str("minute"); }*/ + | MINVALUE { $$ = make_str("minvalue"); } + | MODE { $$ = make_str("mode"); } +/* | MONTH_P { $$ = make_str("month"); }*/ + | MOVE { $$ = make_str("move"); } + | NAME_P { $$ = make_str("name"); } + | NAMES { $$ = make_str("names"); } + | NEXT { $$ = make_str("next"); } + | NO { $$ = make_str("no"); } + | NOCREATEDB { $$ = make_str("nocreatedb"); } + | NOCREATEROLE { $$ = make_str("nocreaterole"); } + | NOCREATEUSER { $$ = make_str("nocreateuser"); } + | NOINHERIT { $$ = make_str("noinherit"); } + | NOLOGIN_P { $$ = make_str("nologin"); } + | NOSUPERUSER { $$ = make_str("nosuperuser"); } + | NOTHING { $$ = make_str("nothing"); } + | NOTIFY { $$ = make_str("notify"); } + | NOWAIT { $$ = make_str("nowait"); } + | NULLS_P { $$ = make_str("nulls"); } + | OBJECT_P { $$ = make_str("object"); } + | OF { $$ = make_str("of"); } + | OIDS { $$ = make_str("oids"); } + | OPERATOR { $$ = make_str("operator"); } + | OPTION { $$ = make_str("option"); } + | OWNED { $$ = make_str("owned"); } + | OWNER { $$ = make_str("owner"); } + | PARSER { $$ = make_str("parser"); } + | PARTIAL { $$ = make_str("partial"); } + | PASSWORD { $$ = make_str("password"); } + | PLANS { $$ = make_str("plans"); } + | PREPARE { $$ = make_str("prepare"); } + | PREPARED { $$ = make_str("prepared"); } + | PRESERVE { $$ = make_str("preserver"); } + | PRIOR { $$ = make_str("prior"); } + | PRIVILEGES { $$ = make_str("privileges"); } + | PROCEDURAL { $$ = make_str("procedural"); } + | PROCEDURE { $$ = make_str("procedure"); } + | QUOTE { $$ = make_str("quote"); } + | READ { $$ = make_str("read"); } + | REASSIGN { $$ = make_str("reassign"); } + | RECHECK { $$ = make_str("recheck"); } + | REINDEX { $$ = make_str("reindex"); } + | RELATIVE_P { $$ = make_str("relative"); } + | RELEASE { $$ = make_str("release"); } + | RENAME { $$ = make_str("rename"); } + | REPEATABLE { $$ = make_str("repeatable"); } + | REPLACE { $$ = make_str("replace"); } + | REPLICA { $$ = make_str("replica"); } + | RESET { $$ = make_str("reset"); } + | RESTART { $$ = make_str("restart"); } + | RESTRICT { $$ = make_str("restrict"); } + | RETURNS { $$ = make_str("returns"); } + | REVOKE { $$ = make_str("revoke"); } + | ROLE { $$ = make_str("role"); } + | ROLLBACK { $$ = make_str("rollback"); } + | ROWS { $$ = make_str("rows"); } + | RULE { $$ = make_str("rule"); } + | SAVEPOINT { $$ = make_str("savepoint"); } + | SCHEMA { $$ = make_str("schema"); } + | SCROLL { $$ = make_str("scroll"); } + | SEARCH { $$ = make_str("search"); } +/* | SECOND_P { $$ = make_str("second"); }*/ + | SEQUENCE { $$ = make_str("sequence"); } + | SERIALIZABLE { $$ = make_str("serializable"); } + | SESSION { $$ = make_str("session"); } + | SET { $$ = make_str("set"); } + | SHARE { $$ = make_str("share"); } + | SHOW { $$ = make_str("show"); } + | SIMPLE { $$ = make_str("simple"); } + | STABLE { $$ = make_str("stable"); } + | STANDALONE_P { $$ = make_str("standalone"); } + | START { $$ = make_str("start"); } + | STATEMENT { $$ = make_str("statement"); } + | STATISTICS { $$ = make_str("statistics"); } + | STDIN { $$ = make_str("stdin"); } + | STDOUT { $$ = make_str("stdout"); } + | STORAGE { $$ = make_str("storage"); } + | STRICT_P { $$ = make_str("strict"); } + | STRIP_P { $$ = make_str("strip"); } + | SUPERUSER_P { $$ = make_str("superuser"); } + | SYSTEM_P { $$ = make_str("system"); } + | SYSID { $$ = make_str("sysid"); } + | TABLESPACE { $$ = make_str("tablespace"); } + | TEMP { $$ = make_str("temp"); } + | TEMPLATE { $$ = make_str("template"); } + | TEMPORARY { $$ = make_str("temporary"); } + | TEXT_P { $$ = make_str("text"); } + | TRANSACTION { $$ = make_str("transaction"); } + | TRIGGER { $$ = make_str("trigger"); } + | TRUNCATE { $$ = make_str("truncate"); } + | TRUSTED { $$ = make_str("trusted"); } + | TYPE_P { $$ = make_str("type"); } + | UNCOMMITTED { $$ = make_str("uncommitted"); } + | UNENCRYPTED { $$ = make_str("unencrypted"); } + | UNKNOWN { $$ = make_str("unknown"); } + | UNLISTEN { $$ = make_str("unlisten"); } + | UNTIL { $$ = make_str("until"); } + | UPDATE { $$ = make_str("update"); } + | VACUUM { $$ = make_str("vacuum"); } + | VALID { $$ = make_str("valid"); } + | VALIDATOR { $$ = make_str("validator"); } + | VALUE_P { $$ = make_str("value"); } + | VARYING { $$ = make_str("varying"); } + | VERSION_P { $$ = make_str("version"); } + | VIEW { $$ = make_str("view"); } + | VOLATILE { $$ = make_str("volatile"); } + | WHITESPACE_P { $$ = make_str("whitespace"); } + | WITH { $$ = make_str("with"); } + | WITHOUT { $$ = make_str("without"); } + | WORK { $$ = make_str("work"); } + | WRITE { $$ = make_str("write"); } + | XML_P { $$ = make_str("xml"); } + | YES_P { $$ = make_str("yes"); } +/* | YEAR_P { $$ = make_str("year"); }*/ + | ZONE { $$ = make_str("zone"); } ; /* Column identifier --- keywords that can be column, table, etc names. @@ -5048,28 +6725,47 @@ col_name_keyword: | CHARACTER { $$ = make_str("character"); } | COALESCE { $$ = make_str("coalesce"); } | DEC { $$ = make_str("dec"); } - | DECIMAL { $$ = make_str("decimal"); } + | DECIMAL_P { $$ = make_str("decimal"); } | EXISTS { $$ = make_str("exists"); } | EXTRACT { $$ = make_str("extract"); } | FLOAT_P { $$ = make_str("float"); } -/* INT must be excluded from ECPGColLabel because of conflict - | INT { $$ = make_str("int"); } + | GREATEST { $$ = make_str("greatest"); } + | INOUT { $$ = make_str("inout"); } +/* INT must be excluded from ECPGColLabel because of conflict + | INT_P { $$ = make_str("int"); } */ | INTEGER { $$ = make_str("integer"); } | INTERVAL { $$ = make_str("interval"); } + | LEAST { $$ = make_str("least"); } + | NATIONAL { $$ = make_str("national"); } | NCHAR { $$ = make_str("nchar"); } | NONE { $$ = make_str("none"); } | NULLIF { $$ = make_str("nullif"); } | NUMERIC { $$ = make_str("numeric"); } + | OUT_P { $$ = make_str("out"); } + | OVERLAY { $$ = make_str("overlay"); } | POSITION { $$ = make_str("position"); } + | PRECISION { $$ = make_str("precision"); } | REAL { $$ = make_str("real"); } + | ROW { $$ = make_str("row"); } | SETOF { $$ = make_str("setof"); } | SMALLINT { $$ = make_str("smallint"); } | SUBSTRING { $$ = make_str("substring"); } | TIME { $$ = make_str("time"); } | TIMESTAMP { $$ = make_str("timestamp"); } + | TREAT { $$ = make_str("treat"); } | TRIM { $$ = make_str("trim"); } + /* VALUES creates a shift/reduce problem if listed here + | VALUES { $$ = make_str("values"); } */ | VARCHAR { $$ = make_str("varchar"); } + | XMLATTRIBUTES { $$ = make_str("xmlattributes"); } + | XMLCONCAT { $$ = make_str("xmlconcat"); } + | XMLELEMENT { $$ = make_str("xmlelement"); } + | XMLFOREST { $$ = make_str("xmlforest"); } + | XMLPARSE { $$ = make_str("xmlparse"); } + | XMLPI { $$ = make_str("xmlpi"); } + | XMLROOT { $$ = make_str("xmlroot"); } + | XMLSERIALIZE { $$ = make_str("xmlserialize"); } ; /* Function identifier --- keywords that can be function names. @@ -5082,27 +6778,27 @@ col_name_keyword: * productions in a_expr to support the goofy SQL9x argument syntax. * - thomas 2000-11-28 */ -func_name_keyword: - AUTHORIZATION { $$ = make_str("authorization"); } - | BETWEEN { $$ = make_str("between"); } - | BINARY { $$ = make_str("binary"); } - | CROSS { $$ = make_str("cross"); } - | FREEZE { $$ = make_str("freeze"); } - | FULL { $$ = make_str("full"); } - | ILIKE { $$ = make_str("ilike"); } - | IN_P { $$ = make_str("in"); } - | INNER_P { $$ = make_str("inner"); } - | IS { $$ = make_str("is"); } - | ISNULL { $$ = make_str("isnull"); } - | JOIN { $$ = make_str("join"); } - | LEFT { $$ = make_str("left"); } - | LIKE { $$ = make_str("like"); } - | NATURAL { $$ = make_str("natural"); } - | NOTNULL { $$ = make_str("notnull"); } - | OUTER_P { $$ = make_str("outer"); } - | OVERLAPS { $$ = make_str("overlaps"); } - | RIGHT { $$ = make_str("right"); } - | VERBOSE { $$ = make_str("verbose"); } +type_func_name_keyword: + AUTHORIZATION { $$ = make_str("authorization"); } + | BETWEEN { $$ = make_str("between"); } + | BINARY { $$ = make_str("binary"); } + | CROSS { $$ = make_str("cross"); } + | FREEZE { $$ = make_str("freeze"); } + | FULL { $$ = make_str("full"); } + | ILIKE { $$ = make_str("ilike"); } + | INNER_P { $$ = make_str("inner"); } + | IS { $$ = make_str("is"); } + | ISNULL { $$ = make_str("isnull"); } + | JOIN { $$ = make_str("join"); } + | LEFT { $$ = make_str("left"); } + | LIKE { $$ = make_str("like"); } + | NATURAL { $$ = make_str("natural"); } + | NOTNULL { $$ = make_str("notnull"); } + | OUTER_P { $$ = make_str("outer"); } + | OVERLAPS { $$ = make_str("overlaps"); } + | RIGHT { $$ = make_str("right"); } + | SIMILAR { $$ = make_str("similar"); } + | VERBOSE { $$ = make_str("verbose"); } ; /* Reserved keyword --- these keywords are usable only as a ColLabel. @@ -5112,121 +6808,165 @@ func_name_keyword: * forced to. */ reserved_keyword: - ALL { $$ = make_str("all"); } - | ANALYSE { $$ = make_str("analyse"); } /* British */ - | ANALYZE { $$ = make_str("analyze"); } - | AND { $$ = make_str("and"); } - | ANY { $$ = make_str("any"); } - | AS { $$ = make_str("as"); } - | ASC { $$ = make_str("asc"); } - | BOTH { $$ = make_str("both"); } - | CASE { $$ = make_str("case"); } - | CAST { $$ = make_str("cast"); } - | CHECK { $$ = make_str("check"); } - | COLLATE { $$ = make_str("collate"); } - | COLUMN { $$ = make_str("column"); } - | CONSTRAINT { $$ = make_str("constraint"); } - | CREATE { $$ = make_str("create"); } - | CURRENT_DATE { $$ = make_str("current_date"); } - | CURRENT_TIME { $$ = make_str("current_time"); } - | CURRENT_TIMESTAMP { $$ = make_str("current_timestamp"); } - | CURRENT_USER { $$ = make_str("current_user"); } - | DEFAULT { $$ = make_str("default"); } - | DEFERRABLE { $$ = make_str("deferrable"); } - | DESC { $$ = make_str("desc"); } - | DISTINCT { $$ = make_str("distinct"); } - | DO { $$ = make_str("do"); } - | ELSE { $$ = make_str("else"); } - | END_TRANS { $$ = make_str("end"); } - | EXCEPT { $$ = make_str("except"); } - | FALSE_P { $$ = make_str("false"); } - | FOR { $$ = make_str("for"); } - | FOREIGN { $$ = make_str("foreign"); } - | FROM { $$ = make_str("from"); } - | GRANT { $$ = make_str("grant"); } - | GROUP_P { $$ = make_str("group"); } - | HAVING { $$ = make_str("having"); } - | INITIALLY { $$ = make_str("initially"); } - | INTERSECT { $$ = make_str("intersect"); } - | INTO { $$ = make_str("into"); } - | LEADING { $$ = make_str("leading"); } - | LIMIT { $$ = make_str("limit"); } - | NEW { $$ = make_str("new"); } - | NOT { $$ = make_str("not"); } - | NULL_P { $$ = make_str("null"); } - | OFF { $$ = make_str("off"); } - | OFFSET { $$ = make_str("offset"); } - | OLD { $$ = make_str("old"); } - | ON { $$ = make_str("on"); } - | ONLY { $$ = make_str("only"); } - | OR { $$ = make_str("or"); } - | ORDER { $$ = make_str("order"); } - | PRIMARY { $$ = make_str("primary"); } - | REFERENCES { $$ = make_str("references"); } - | SELECT { $$ = make_str("select"); } - | SESSION_USER { $$ = make_str("session_user"); } - | SOME { $$ = make_str("some"); } - | TABLE { $$ = make_str("table"); } - | THEN { $$ = make_str("then"); } - | TO { $$ = make_str("to"); } - | TRAILING { $$ = make_str("trailing"); } - | TRUE_P { $$ = make_str("true"); } + ALL { $$ = make_str("all"); } + | ANALYSE { $$ = make_str("analyse"); } /* British */ + | ANALYZE { $$ = make_str("analyze"); } + | AND { $$ = make_str("and"); } + | ANY { $$ = make_str("any"); } + | ARRAY { $$ = make_str("array"); } + | AS { $$ = make_str("as"); } + | ASC { $$ = make_str("asc"); } + | ASYMMETRIC { $$ = make_str("asymmetric"); } + | BOTH { $$ = make_str("both"); } + | CASE { $$ = make_str("case"); } + | CAST { $$ = make_str("cast"); } + | CHECK { $$ = make_str("check"); } + | COLLATE { $$ = make_str("collate"); } + | COLUMN { $$ = make_str("column"); } + | CONSTRAINT { $$ = make_str("constraint"); } + | CREATE { $$ = make_str("create"); } + | CURRENT_P { $$ = make_str("current"); } + | CURRENT_DATE { $$ = make_str("current_date"); } + | CURRENT_TIME { $$ = make_str("current_time"); } + | CURRENT_TIMESTAMP { $$ = make_str("current_timestamp"); } + | CURRENT_ROLE { $$ = make_str("current_role"); } + | CURRENT_USER { $$ = make_str("current_user"); } + | DEFAULT { $$ = make_str("default"); } + | DEFERRABLE { $$ = make_str("deferrable"); } + | DESC { $$ = make_str("desc"); } + | DISTINCT { $$ = make_str("distinct"); } + | DO { $$ = make_str("do"); } + | ELSE { $$ = make_str("else"); } + | END_P { $$ = make_str("end"); } + | EXCEPT { $$ = make_str("except"); } + | FALSE_P { $$ = make_str("false"); } + | FOR { $$ = make_str("for"); } + | FOREIGN { $$ = make_str("foreign"); } + | FROM { $$ = make_str("from"); } + | GRANT { $$ = make_str("grant"); } + | GROUP_P { $$ = make_str("group"); } + | HAVING { $$ = make_str("having"); } + | IN_P { $$ = make_str("in"); } + | INITIALLY { $$ = make_str("initially"); } + | INTERSECT { $$ = make_str("intersect"); } + | INTO { $$ = make_str("into"); } + | LEADING { $$ = make_str("leading"); } + | LIMIT { $$ = make_str("limit"); } + | NEW { $$ = make_str("new"); } + | NOT { $$ = make_str("not"); } + | NULL_P { $$ = make_str("null"); } + | OFF { $$ = make_str("off"); } + | OFFSET { $$ = make_str("offset"); } + | OLD { $$ = make_str("old"); } + | ON { $$ = make_str("on"); } + | ONLY { $$ = make_str("only"); } + | OR { $$ = make_str("or"); } + | ORDER { $$ = make_str("order"); } + | PRIMARY { $$ = make_str("primary"); } + | REFERENCES { $$ = make_str("references"); } + | RETURNING { $$ = make_str("returning"); } + | SELECT { $$ = make_str("select"); } + | SESSION_USER { $$ = make_str("session_user"); } + | SOME { $$ = make_str("some"); } + | SYMMETRIC { $$ = make_str("symmetric"); } + | TABLE { $$ = make_str("table"); } + | THEN { $$ = make_str("then"); } +/* TO must be excluded from ECPGColLabel because of a conflict in variable name parsing + | TO { $$ = make_str("to"); } + */ + | TRAILING { $$ = make_str("trailing"); } + | TRUE_P { $$ = make_str("true"); } /* UNION must be excluded from ECPGColLabel because of conflict with s_union - | UNION { $$ = make_str("union"); } + | UNION { $$ = make_str("union"); } */ - | UNIQUE { $$ = make_str("unique"); } - | USER { $$ = make_str("user"); } - | USING { $$ = make_str("using"); } - | WHEN { $$ = make_str("when"); } - | WHERE { $$ = make_str("where"); } + | UNIQUE { $$ = make_str("unique"); } + | USER { $$ = make_str("user"); } + | USING { $$ = make_str("using"); } + | VARIADIC { $$ = make_str("variadic"); } + | WHEN { $$ = make_str("when"); } + | WHERE { $$ = make_str("where"); } ; into_list : coutputvariable | into_list ',' coutputvariable ; -ecpgstart: SQL_START { reset_variables(); } +ecpgstart: SQL_START { + reset_variables(); + pacounter = 1; + } ; c_args: /*EMPTY*/ { $$ = EMPTY; } | c_list { $$ = $1; } ; -coutputvariable: CVARIABLE indicator - { add_variable(&argsresult, find_variable($1), find_variable($2)); } - | CVARIABLE - { add_variable(&argsresult, find_variable($1), &no_indicator); } +coutputvariable: cvariable indicator + { add_variable_to_head(&argsresult, find_variable($1), find_variable($2)); } + | cvariable + { add_variable_to_head(&argsresult, find_variable($1), &no_indicator); } ; -civarind: CVARIABLE indicator +civarind: cvariable indicator { - if ($2 != NULL && (find_variable($2))->type->type == ECPGt_array) + if (find_variable($2)->type->type == ECPGt_array) mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input"); - add_variable(&argsinsert, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2)); + add_variable_to_head(&argsinsert, find_variable($1), find_variable($2)); + $$ = create_questionmarks($1, false); } ; -civar: CVARIABLE +civar: cvariable { - add_variable(&argsinsert, find_variable($1), &no_indicator); - $$ = $1; + add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); + $$ = create_questionmarks($1, false); } ; -indicator: CVARIABLE { check_indicator((find_variable($1))->type); $$ = $1; } - | SQL_INDICATOR CVARIABLE { check_indicator((find_variable($2))->type); $$ = $2; } +indicator: cvariable { check_indicator((find_variable($1))->type); $$ = $1; } + | SQL_INDICATOR cvariable { check_indicator((find_variable($2))->type); $$ = $2; } | SQL_INDICATOR name { check_indicator((find_variable($2))->type); $$ = $2; } ; -ident: IDENT { $$ = $1; } - | CSTRING { $$ = make3_str(make_str("\""), $1, make_str("\"")); } +cvariable: CVARIABLE + { + /* As long as multidimensional arrays are not implemented we have to check for those here */ + char *ptr = $1; + int brace_open=0, brace = false; + + for (; *ptr; ptr++) + { + switch (*ptr) + { + case '[': + if (brace) + mmerror(PARSE_ERROR, ET_FATAL, "no multidimensional array support for simple data types"); + brace_open++; + break; + case ']': + brace_open--; + if (brace_open == 0) + brace = true; + break; + case '\t': + case ' ': + break; + default: + if (brace_open == 0) + brace = false; + break; + } + } + $$ = $1; + } + ; +ident: IDENT { $$ = $1; } + | CSTRING { $$ = make3_str(make_str("\""), $1, make_str("\"")); } ; -quoted_ident_stringvar: IDENT - { $$ = make3_str(make_str("\""), $1, make_str("\"")); } - | CSTRING +quoted_ident_stringvar: name { $$ = make3_str(make_str("\""), $1, make_str("\"")); } | char_variable { $$ = make3_str(make_str("("), $1, make_str(")")); } @@ -5242,7 +6982,7 @@ c_stuff_item: c_anything { $$ = $1; } { $$ = cat_str(3, make_str("("), $2, make_str(")")); } ; -c_stuff: c_stuff_item { $$ = $1; } +c_stuff: c_stuff_item { $$ = $1; } | c_stuff c_stuff_item { $$ = cat2_str($1, $2); } ; @@ -5255,72 +6995,92 @@ 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_thing: c_anything { $$ = $1; } + | '(' { $$ = make_str("("); } + | ')' { $$ = make_str(")"); } + | ',' { $$ = make_str(","); } + | ';' { $$ = make_str(";"); } ; -c_anything: IDENT { $$ = $1; } - | CSTRING { $$ = make3_str(make_str("\""), $1, make_str("\"")); } - | PosIntConst { $$ = $1; } - | Fconst { $$ = $1; } - | Sconst { $$ = $1; } - | '*' { $$ = make_str("*"); } - | '+' { $$ = make_str("+"); } - | '-' { $$ = make_str("-"); } - | '/' { $$ = make_str("/"); } - | '%' { $$ = make_str("%"); } - | NULL_P { $$ = make_str("NULL"); } - | S_ADD { $$ = make_str("+="); } - | S_AND { $$ = make_str("&&"); } - | S_ANYTHING { $$ = make_name(); } - | S_AUTO { $$ = make_str("auto"); } - | S_CONST { $$ = make_str("const"); } - | S_DEC { $$ = make_str("--"); } - | S_DIV { $$ = make_str("/="); } - | S_DOTPOINT { $$ = make_str(".*"); } - | S_EQUAL { $$ = make_str("=="); } - | S_EXTERN { $$ = make_str("extern"); } - | S_INC { $$ = make_str("++"); } - | S_LSHIFT { $$ = make_str("<<"); } - | S_MEMBER { $$ = make_str("->"); } - | S_MEMPOINT { $$ = make_str("->*"); } - | S_MOD { $$ = make_str("%="); } - | S_MUL { $$ = make_str("*="); } - | S_NEQUAL { $$ = make_str("!="); } - | S_OR { $$ = make_str("||"); } - | S_REGISTER { $$ = make_str("register"); } - | S_RSHIFT { $$ = make_str(">>"); } - | S_STATIC { $$ = make_str("static"); } - | S_SUB { $$ = make_str("-="); } - | S_TYPEDEF { $$ = make_str("typedef"); } - | SQL_BOOL { $$ = make_str("bool"); } - | SQL_ENUM { $$ = make_str("enum"); } - | 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_P { $$ = make_str("char"); } - | DOUBLE { $$ = make_str("double"); } - | FLOAT_P { $$ = make_str("float"); } - | UNION { $$ = make_str("union"); } - | VARCHAR { $$ = make_str("varchar"); } - | '[' { $$ = make_str("["); } - | ']' { $$ = make_str("]"); } - | '=' { $$ = make_str("="); } +c_anything: IDENT { $$ = $1; } + | CSTRING { $$ = make3_str(make_str("\""), $1, make_str("\"")); } + | Iconst { $$ = $1; } + | Fconst { $$ = $1; } + | Sconst { $$ = $1; } + | '*' { $$ = make_str("*"); } + | '+' { $$ = make_str("+"); } + | '-' { $$ = make_str("-"); } + | '/' { $$ = make_str("/"); } + | '%' { $$ = make_str("%"); } + | NULL_P { $$ = make_str("NULL"); } + | S_ADD { $$ = make_str("+="); } + | S_AND { $$ = make_str("&&"); } + | S_ANYTHING { $$ = make_name(); } + | S_AUTO { $$ = make_str("auto"); } + | S_CONST { $$ = make_str("const"); } + | S_DEC { $$ = make_str("--"); } + | S_DIV { $$ = make_str("/="); } + | S_DOTPOINT { $$ = make_str(".*"); } + | S_EQUAL { $$ = make_str("=="); } + | S_EXTERN { $$ = make_str("extern"); } + | S_INC { $$ = make_str("++"); } + | S_LSHIFT { $$ = make_str("<<"); } + | S_MEMBER { $$ = make_str("->"); } + | S_MEMPOINT { $$ = make_str("->*"); } + | S_MOD { $$ = make_str("%="); } + | S_MUL { $$ = make_str("*="); } + | S_NEQUAL { $$ = make_str("!="); } + | S_OR { $$ = make_str("||"); } + | S_REGISTER { $$ = make_str("register"); } + | S_RSHIFT { $$ = make_str(">>"); } + | S_STATIC { $$ = make_str("static"); } + | S_SUB { $$ = make_str("-="); } + | S_TYPEDEF { $$ = make_str("typedef"); } + | S_VOLATILE { $$ = make_str("volatile"); } + | SQL_BOOL { $$ = make_str("bool"); } + | ENUM_P { $$ = make_str("enum"); } + | HOUR_P { $$ = make_str("hour"); } + | INT_P { $$ = make_str("int"); } + | SQL_LONG { $$ = make_str("long"); } + | MINUTE_P { $$ = make_str("minute"); } + | MONTH_P { $$ = make_str("month"); } + | SECOND_P { $$ = make_str("second"); } + | SQL_SHORT { $$ = make_str("short"); } + | SQL_SIGNED { $$ = make_str("signed"); } + | SQL_STRUCT { $$ = make_str("struct"); } + | SQL_UNSIGNED { $$ = make_str("unsigned"); } + | YEAR_P { $$ = make_str("year"); } + | CHAR_P { $$ = make_str("char"); } + | FLOAT_P { $$ = make_str("float"); } + | TO { $$ = make_str("to"); } + | UNION { $$ = make_str("union"); } + | VARCHAR { $$ = make_str("varchar"); } + | '[' { $$ = make_str("["); } + | ']' { $$ = make_str("]"); } + | '=' { $$ = make_str("="); } + | ':' { $$ = make_str(":"); } ; %% -void yyerror( char * error) +void base_yyerror(const char * error) { char buf[1024]; - snprintf(buf,sizeof buf,"%s at or near \"%s\"", error, token_start ? token_start : yytext); + snprintf(buf,sizeof buf, _("%s at or near \"%s\""), error, token_start ? token_start : yytext); buf[sizeof(buf)-1]=0; mmerror(PARSE_ERROR, ET_ERROR, buf); } + +void parser_init(void) +{ + /* This function is empty. It only exists for compatibility with the backend parser right now. */ +} + +/* + * Must undefine base_yylex before including pgc.c, since we want it + * to create the function base_yylex not filtered_base_yylex. + */ +#undef base_yylex + +#include "pgc.c"