5115 lines
154 KiB
Plaintext
5115 lines
154 KiB
Plaintext
/* Copyright comment */
|
|
%{
|
|
#include <stdarg.h>
|
|
|
|
#include "postgres.h"
|
|
#include "access/htup.h"
|
|
#include "catalog/catname.h"
|
|
#include "utils/numeric.h"
|
|
#include "utils/memutils.h"
|
|
#include "storage/bufpage.h"
|
|
|
|
#include "extern.h"
|
|
|
|
#ifdef MULTIBYTE
|
|
#include "mb/pg_wchar.h"
|
|
#endif
|
|
|
|
/*
|
|
* Variables containing simple states.
|
|
*/
|
|
int struct_level = 0;
|
|
int braces_open; /* brace level counter */
|
|
char errortext[128];
|
|
char *connection = NULL;
|
|
char *input_filename = NULL;
|
|
|
|
static int QueryIsRule = 0, ForUpdateNotAllowed = 0, FoundInto = 0;
|
|
static int FoundSort = 0;
|
|
static int initializer = 0;
|
|
static struct this_type actual_type[STRUCT_DEPTH];
|
|
static char *actual_storage[STRUCT_DEPTH];
|
|
static char *actual_startline[STRUCT_DEPTH];
|
|
|
|
/* temporarily store struct members while creating the data structure */
|
|
struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL };
|
|
|
|
struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}};
|
|
struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
|
|
|
|
struct ECPGtype ecpg_query = {ECPGt_char_variable, 0L, {NULL}};
|
|
|
|
/*
|
|
* Handle parsing errors and warnings
|
|
*/
|
|
void
|
|
mmerror(enum errortype type, char * error)
|
|
{
|
|
switch(type)
|
|
{
|
|
case ET_WARN:
|
|
fprintf(stderr, "%s:%d: WARNING: %s\n", input_filename, yylineno, error);
|
|
break;
|
|
case ET_ERROR:
|
|
fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
|
|
ret_value = PARSE_ERROR;
|
|
break;
|
|
case ET_FATAL:
|
|
fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
|
|
exit(PARSE_ERROR);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* string concatenation
|
|
*/
|
|
|
|
static char *
|
|
cat2_str(char *str1, char *str2)
|
|
{
|
|
char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 2);
|
|
|
|
strcpy(res_str, str1);
|
|
strcat(res_str, " ");
|
|
strcat(res_str, str2);
|
|
free(str1);
|
|
free(str2);
|
|
return(res_str);
|
|
}
|
|
|
|
static char *
|
|
cat_str(int count, ...)
|
|
{
|
|
va_list args;
|
|
int i;
|
|
char *res_str;
|
|
|
|
va_start(args, count);
|
|
|
|
res_str = va_arg(args, char *);
|
|
|
|
/* now add all other strings */
|
|
for (i = 1; i < count; i++)
|
|
res_str = cat2_str(res_str, va_arg(args, char *));
|
|
|
|
va_end(args);
|
|
|
|
return(res_str);
|
|
}
|
|
|
|
char *
|
|
make_str(const char *str)
|
|
{
|
|
char * res_str = (char *)mm_alloc(strlen(str) + 1);
|
|
|
|
strcpy(res_str, str);
|
|
return res_str;
|
|
}
|
|
|
|
static char *
|
|
make2_str(char *str1, char *str2)
|
|
{
|
|
char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1);
|
|
|
|
strcpy(res_str, str1);
|
|
strcat(res_str, str2);
|
|
free(str1);
|
|
free(str2);
|
|
return(res_str);
|
|
}
|
|
|
|
static char *
|
|
make3_str(char *str1, char *str2, char *str3)
|
|
{
|
|
char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) +strlen(str3) + 1);
|
|
|
|
strcpy(res_str, str1);
|
|
strcat(res_str, str2);
|
|
strcat(res_str, str3);
|
|
free(str1);
|
|
free(str2);
|
|
free(str3);
|
|
return(res_str);
|
|
}
|
|
|
|
static char *
|
|
make_name(void)
|
|
{
|
|
char * name = (char *)mm_alloc(yyleng + 1);
|
|
|
|
strncpy(name, yytext, yyleng);
|
|
name[yyleng] = '\0';
|
|
return(name);
|
|
}
|
|
|
|
%}
|
|
|
|
%union {
|
|
double dval;
|
|
int ival;
|
|
char * str;
|
|
struct when action;
|
|
struct index index;
|
|
int tagname;
|
|
struct this_type type;
|
|
enum ECPGttype type_enum;
|
|
enum ECPGdtype dtype_enum;
|
|
struct fetch_desc descriptor;
|
|
}
|
|
|
|
/* special embedded SQL token */
|
|
%token SQL_ALLOCATE SQL_AT SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK
|
|
%token SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE SQL_COUNT
|
|
%token SQL_DATA SQL_DATETIME_INTERVAL_CODE SQL_DATETIME_INTERVAL_PRECISION
|
|
%token SQL_DEALLOCATE SQL_DESCRIPTOR SQL_DISCONNECT SQL_ENUM
|
|
%token SQL_FOUND SQL_FREE SQL_GET SQL_GO SQL_GOTO
|
|
%token SQL_IDENTIFIED SQL_INDICATOR SQL_INT SQL_KEY_MEMBER
|
|
%token SQL_LENGTH SQL_LONG
|
|
%token SQL_NAME SQL_NULLABLE
|
|
%token SQL_OCTET_LENGTH SQL_OFF SQL_OPEN SQL_PREPARE
|
|
%token SQL_RELEASE SQL_REFERENCE SQL_RETURNED_LENGTH
|
|
%token SQL_RETURNED_OCTET_LENGTH
|
|
%token SQL_SCALE SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL
|
|
%token SQL_SQLERROR SQL_SQLPRINT
|
|
%token SQL_SQLWARNING SQL_START SQL_STOP SQL_STRUCT SQL_UNSIGNED
|
|
%token SQL_VALUE SQL_VAR SQL_WHENEVER
|
|
|
|
/* C token */
|
|
%token S_ANYTHING S_AUTO S_CONST S_EXTERN
|
|
%token S_REGISTER S_STATIC S_VOLATILE
|
|
|
|
/* I need this and don't know where it is defined inside the backend */
|
|
%token TYPECAST
|
|
|
|
/* Keywords (in SQL92 reserved words) */
|
|
%token ABSOLUTE, ACTION, ADD, ALL, ALTER, AND, ANY, AS, ASC,
|
|
BEGIN_TRANS, BETWEEN, BOTH, BY,
|
|
CASCADE, CASE, CAST, CHAR, CHARACTER, CHECK, CLOSE,
|
|
COALESCE, COLLATE, COLUMN, COMMIT,
|
|
CONSTRAINT, CONSTRAINTS, CREATE, CROSS, CURRENT, CURRENT_DATE,
|
|
CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,
|
|
DAY_P, DEC, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP,
|
|
ELSE, END_TRANS, EXCEPT, EXECUTE, EXISTS, EXTRACT,
|
|
FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
|
|
GLOBAL, GRANT, GROUP, HAVING, HOUR_P,
|
|
IN, INNER_P, INSENSITIVE, INSERT, INTERSECT, INTERVAL, INTO, IS,
|
|
ISOLATION, JOIN, KEY, LANGUAGE, LEADING, LEFT, LEVEL, LIKE, LOCAL,
|
|
MATCH, MINUTE_P, MONTH_P, NAMES,
|
|
NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULLIF, NULL_P, NUMERIC,
|
|
OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P, OVERLAPS,
|
|
PARTIAL, POSITION, PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, PUBLIC,
|
|
READ, REFERENCES, RELATIVE, REVOKE, RIGHT, ROLLBACK,
|
|
SCROLL, SECOND_P, SELECT, SESSION_USER, SET, SUBSTRING,
|
|
TABLE, TEMP, TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR,
|
|
TIMEZONE_MINUTE, TO, TRAILING, TRANSACTION, TRIM, TRUE_P,
|
|
UNION, UNIQUE, UPDATE, USER, USING,
|
|
VALUES, VARCHAR, VARYING, VIEW,
|
|
WHEN, WHERE, WITH, WORK, YEAR_P, ZONE
|
|
|
|
/* Keywords (in SQL3 reserved words) */
|
|
%token DEFERRABLE, DEFERRED,
|
|
IMMEDIATE, INITIALLY,
|
|
PENDANT,
|
|
RESTRICT,
|
|
TRIGGER
|
|
|
|
/* Keywords (in SQL92 non-reserved words) */
|
|
%token COMMITTED, SERIALIZABLE, TYPE_P
|
|
|
|
/* Keywords for Postgres support (not in SQL92 reserved words)
|
|
*
|
|
* The CREATEDB and CREATEUSER tokens should go away
|
|
* when some sort of pg_privileges relation is introduced.
|
|
* - Todd A. Brandys 1998-01-01?
|
|
*/
|
|
%token ABORT_TRANS, ACCESS, AFTER, AGGREGATE, ANALYZE,
|
|
BACKWARD, BEFORE, BINARY,
|
|
CACHE, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE,
|
|
DATABASE, DELIMITERS, DO,
|
|
EACH, ENCODING, EXCLUSIVE, EXPLAIN, EXTEND,
|
|
FORCE, FORWARD, FUNCTION, HANDLER,
|
|
INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
|
|
LANCOMPILER, LIMIT, LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P,
|
|
MAXVALUE, MINVALUE, MODE, MOVE,
|
|
NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
|
|
OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL,
|
|
REINDEX, RENAME, RESET, RETURNS, ROW, RULE,
|
|
SEQUENCE, SERIAL, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, SYSID
|
|
TRUNCATE, TRUSTED,
|
|
UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
|
|
|
|
/* Special keywords, not in the query language - see the "lex" file */
|
|
%token <str> IDENT SCONST Op CSTRING CVARIABLE CPP_LINE
|
|
%token <ival> ICONST PARAM
|
|
%token <dval> FCONST
|
|
|
|
/* these are not real. they are here so that they get generated as #define's*/
|
|
%token OP
|
|
|
|
/* precedence */
|
|
%left OR
|
|
%left AND
|
|
%right NOT
|
|
%right '='
|
|
%nonassoc '<' '>'
|
|
%nonassoc LIKE
|
|
%nonassoc OVERLAPS
|
|
%nonassoc BETWEEN
|
|
%nonassoc IN
|
|
%left Op /* multi-character ops and user-defined operators */
|
|
%nonassoc NOTNULL
|
|
%nonassoc ISNULL
|
|
%nonassoc NULL_P
|
|
%nonassoc IS
|
|
%left '+' '-'
|
|
%left '*' '/' '%'
|
|
%left '^'
|
|
%left '|' /* this is the relation union op, not logical or */
|
|
/* Unary Operators */
|
|
%right ':'
|
|
%left ';' /* end of statement or natural log */
|
|
%right UMINUS
|
|
%left '.'
|
|
%left '[' ']'
|
|
%left TYPECAST
|
|
%left UNION INTERSECT EXCEPT
|
|
|
|
%type <str> Iconst Fconst Sconst TransactionStmt CreateStmt UserId
|
|
%type <str> CreateAsElement OptCreateAs CreateAsList CreateAsStmt
|
|
%type <str> OptInherit key_reference comment_text ConstraintDeferrabilitySpec
|
|
%type <str> key_match ColLabel SpecialRuleRelation ColId columnDef
|
|
%type <str> ColConstraint ColConstraintElem NumericOnly FloatOnly
|
|
%type <str> OptTableElementList OptTableElement TableConstraint
|
|
%type <str> ConstraintElem key_actions ColQualList
|
|
%type <str> target_list target_el update_target_list alias_clause
|
|
%type <str> update_target_el opt_id relation_name database_name
|
|
%type <str> access_method attr_name class index_name name func_name
|
|
%type <str> file_name AexprConst ParamNo TypeId c_expr
|
|
%type <str> in_expr_nodes a_expr b_expr TruncateStmt CommentStmt
|
|
%type <str> opt_indirection expr_list extract_list extract_arg
|
|
%type <str> position_list substr_list substr_from alter_column_action
|
|
%type <str> trim_list in_expr substr_for attr attrs drop_behavior
|
|
%type <str> Typename SimpleTypename Generic Numeric generic opt_float opt_numeric
|
|
%type <str> opt_decimal Character character opt_varying opt_charset
|
|
%type <str> opt_collate Datetime datetime opt_timezone opt_interval
|
|
%type <str> numeric row_expr row_descriptor row_list
|
|
%type <str> SelectStmt SubSelect result OptTemp ConstraintAttributeSpec
|
|
%type <str> opt_table opt_all sort_clause sortby_list ConstraintAttr
|
|
%type <str> sortby OptUseOp opt_inh_star relation_name_list name_list
|
|
%type <str> group_clause having_clause from_clause opt_distinct
|
|
%type <str> join_outer where_clause relation_expr sub_type
|
|
%type <str> opt_column_list insert_rest InsertStmt OptimizableStmt
|
|
%type <str> columnList DeleteStmt LockStmt UpdateStmt CursorStmt
|
|
%type <str> NotifyStmt columnElem copy_dirn UnlistenStmt copy_null
|
|
%type <str> copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary
|
|
%type <str> opt_with_copy FetchStmt direction fetch_how_many from_in
|
|
%type <str> ClosePortalStmt DropStmt VacuumStmt opt_verbose
|
|
%type <str> opt_analyze opt_va_list va_list ExplainStmt index_params
|
|
%type <str> index_list func_index index_elem opt_type opt_class access_method_clause
|
|
%type <str> index_opt_unique IndexStmt set_opt func_return def_rest
|
|
%type <str> func_args_list func_args opt_with ProcedureStmt def_arg
|
|
%type <str> def_elem def_list definition def_name def_type DefineStmt
|
|
%type <str> opt_instead event event_object RuleActionList opt_using
|
|
%type <str> RuleActionStmtOrEmpty RuleActionMulti func_as reindex_type
|
|
%type <str> RuleStmt opt_column opt_name oper_argtypes sysid_clause
|
|
%type <str> MathOp RemoveFuncStmt aggr_argtype for_update_clause
|
|
%type <str> RemoveAggrStmt remove_type RemoveStmt ExtendStmt
|
|
%type <str> RemoveOperStmt RenameStmt all_Op user_valid_clause
|
|
%type <str> VariableSetStmt var_value zone_value VariableShowStmt
|
|
%type <str> VariableResetStmt AlterTableStmt DropUserStmt from_list
|
|
%type <str> user_passwd_clause user_createdb_clause opt_trans
|
|
%type <str> user_createuser_clause user_list user_group_clause
|
|
%type <str> CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList
|
|
%type <str> OptSeqElem TriggerForSpec TriggerForOpt TriggerForType
|
|
%type <str> DropTrigStmt TriggerOneEvent TriggerEvents RuleActionStmt
|
|
%type <str> TriggerActionTime CreateTrigStmt DropPLangStmt PLangTrusted
|
|
%type <str> CreatePLangStmt IntegerOnly TriggerFuncArgs TriggerFuncArg
|
|
%type <str> ViewStmt LoadStmt CreatedbStmt createdb_opt_encoding
|
|
%type <str> createdb_opt_location opt_encoding AlterTableStmt
|
|
%type <str> DropdbStmt ClusterStmt grantee RevokeStmt table_expr
|
|
%type <str> GrantStmt privileges operation_commalist operation
|
|
%type <str> opt_cursor opt_lmode ConstraintsSetStmt comment_tg
|
|
%type <str> case_expr when_clause_list case_default case_arg when_clause
|
|
%type <str> select_clause opt_select_limit select_limit_value ConstraintTimeSpec
|
|
%type <str> select_offset_value using_expr join_expr ReindexStmt
|
|
%type <str> using_list from_expr join_clause join_type
|
|
%type <str> join_qual update_list join_clause join_clause_with_union
|
|
%type <str> opt_level opt_lock lock_type users_in_new_group_clause
|
|
%type <str> OptConstrFromTable comment_op OptTempTableName
|
|
%type <str> constraints_set_list constraints_set_namelist comment_fn
|
|
%type <str> constraints_set_mode comment_type comment_cl comment_ag
|
|
%type <str> CreateGroupStmt AlterGroupStmt DropGroupStmt key_delete
|
|
%type <str> join_expr_with_union opt_force key_update
|
|
/***
|
|
#ifdef ENABLE_ORACLE_JOIN_SYNTAX
|
|
%type <str> oracle_list oracle_expr oracle_outer
|
|
#endif
|
|
***/
|
|
|
|
%type <str> ECPGWhenever ECPGConnect connection_target ECPGOpen
|
|
%type <str> indicator ECPGExecute ECPGPrepare ecpg_using
|
|
%type <str> storage_clause opt_initializer c_anything blockstart
|
|
%type <str> blockend variable_list variable c_thing c_term
|
|
%type <str> opt_pointer cvariable ECPGDisconnect dis_name storage_modifier
|
|
%type <str> stmt ECPGRelease execstring server_name
|
|
%type <str> connection_object opt_server opt_port c_stuff opt_reference
|
|
%type <str> user_name opt_user char_variable ora_user ident
|
|
%type <str> db_prefix server opt_options opt_connection_name c_list
|
|
%type <str> ECPGSetConnection cpp_line ECPGTypedef c_args ECPGKeywords
|
|
%type <str> enum_type civariableonly ECPGCursorStmt ECPGDeallocate
|
|
%type <str> ECPGFree ECPGDeclare ECPGVar opt_at enum_definition
|
|
%type <str> struct_type s_struct declaration declarations variable_declarations
|
|
%type <str> s_struct s_union union_type ECPGSetAutocommit on_off
|
|
%type <str> ECPGAllocateDescr ECPGDeallocateDescr symbol opt_symbol
|
|
%type <str> ECPGGetDescriptorHeader ECPGColId ECPGColLabel ECPGTypeName
|
|
%type <str> ECPGLabelTypeName
|
|
|
|
%type <descriptor> ECPGFetchDescStmt ECPGGetDescriptor
|
|
|
|
%type <type_enum> simple_type signed_type unsigned_type varchar_type
|
|
|
|
%type <dtype_enum> descriptor_item desc_header_item
|
|
|
|
%type <type> type
|
|
|
|
%type <action> action
|
|
|
|
%type <index> opt_array_bounds opt_type_array_bounds
|
|
|
|
%type <ival> Iresult
|
|
%%
|
|
prog: statements;
|
|
|
|
statements: /* empty */
|
|
| statements statement
|
|
|
|
statement: ecpgstart opt_at stmt ';' { connection = NULL; }
|
|
| ecpgstart stmt ';'
|
|
| ECPGDeclaration
|
|
| c_thing { fprintf(yyout, "%s", $1); free($1); }
|
|
| cpp_line { fprintf(yyout, "%s", $1); free($1); }
|
|
| blockstart { fputs($1, yyout); free($1); }
|
|
| blockend { fputs($1, yyout); free($1); }
|
|
|
|
opt_at: SQL_AT connection_target { connection = $2; }
|
|
|
|
stmt: AlterTableStmt { output_statement($1, 0, NULL, connection); }
|
|
| AlterGroupStmt { output_statement($1, 0, NULL, connection); }
|
|
| AlterUserStmt { output_statement($1, 0, NULL, connection); }
|
|
| ClosePortalStmt { output_statement($1, 0, NULL, connection); }
|
|
| CommentStmt { output_statement($1, 0, NULL, connection); }
|
|
| CopyStmt { output_statement($1, 0, NULL, connection); }
|
|
| CreateStmt { output_statement($1, 0, NULL, connection); }
|
|
| CreateAsStmt { output_statement($1, 0, NULL, connection); }
|
|
| CreateGroupStmt { output_statement($1, 0, NULL, connection); }
|
|
| CreateSeqStmt { output_statement($1, 0, NULL, connection); }
|
|
| CreatePLangStmt { output_statement($1, 0, NULL, connection); }
|
|
| CreateTrigStmt { output_statement($1, 0, NULL, connection); }
|
|
| CreateUserStmt { output_statement($1, 0, NULL, connection); }
|
|
| ClusterStmt { output_statement($1, 0, NULL, connection); }
|
|
| DefineStmt { output_statement($1, 0, NULL, connection); }
|
|
| DropStmt { output_statement($1, 0, NULL, connection); }
|
|
| TruncateStmt { output_statement($1, 0, NULL, connection); }
|
|
| DropGroupStmt { output_statement($1, 0, NULL, connection); }
|
|
| DropPLangStmt { output_statement($1, 0, NULL, connection); }
|
|
| DropTrigStmt { output_statement($1, 0, NULL, connection); }
|
|
| DropUserStmt { output_statement($1, 0, NULL, connection); }
|
|
| ExtendStmt { output_statement($1, 0, NULL, connection); }
|
|
| ExplainStmt { output_statement($1, 0, NULL, connection); }
|
|
| FetchStmt { output_statement($1, 1, NULL, connection); }
|
|
| GrantStmt { output_statement($1, 0, NULL, connection); }
|
|
| IndexStmt { output_statement($1, 0, NULL, connection); }
|
|
| ListenStmt { output_statement($1, 0, NULL, connection); }
|
|
| UnlistenStmt { output_statement($1, 0, NULL, connection); }
|
|
| LockStmt { output_statement($1, 0, NULL, connection); }
|
|
| ProcedureStmt { output_statement($1, 0, NULL, connection); }
|
|
| ReindexStmt { output_statement($1, 0, NULL, connection); }
|
|
| RemoveAggrStmt { output_statement($1, 0, NULL, connection); }
|
|
| RemoveOperStmt { output_statement($1, 0, NULL, connection); }
|
|
| RemoveFuncStmt { output_statement($1, 0, NULL, connection); }
|
|
| RemoveStmt { output_statement($1, 0, NULL, connection); }
|
|
| RenameStmt { output_statement($1, 0, NULL, connection); }
|
|
| RevokeStmt { output_statement($1, 0, NULL, connection); }
|
|
| OptimizableStmt {
|
|
if (strncmp($1, "/* " , sizeof("/* ")-1) == 0)
|
|
output_simple_statement($1);
|
|
else
|
|
output_statement($1, 1, NULL, connection);
|
|
}
|
|
| RuleStmt { output_statement($1, 0, NULL, connection); }
|
|
| TransactionStmt {
|
|
fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
|
|
whenever_action(2);
|
|
free($1);
|
|
}
|
|
| ViewStmt { output_statement($1, 0, NULL, connection); }
|
|
| LoadStmt { output_statement($1, 0, NULL, connection); }
|
|
| CreatedbStmt { output_statement($1, 0, NULL, connection); }
|
|
| DropdbStmt { output_statement($1, 0, NULL, connection); }
|
|
| VacuumStmt { output_statement($1, 0, NULL, connection); }
|
|
| VariableSetStmt { output_statement($1, 0, NULL, connection); }
|
|
| VariableShowStmt { output_statement($1, 0, NULL, connection); }
|
|
| VariableResetStmt { output_statement($1, 0, NULL, connection); }
|
|
| ConstraintsSetStmt { output_statement($1, 0, NULL, connection); }
|
|
| ECPGAllocateDescr { fprintf(yyout,"ECPGallocate_desc(__LINE__, \"%s\");",$1);
|
|
whenever_action(0);
|
|
free($1);
|
|
}
|
|
| ECPGConnect {
|
|
if (connection)
|
|
mmerror(ET_ERROR, "no at option for connect statement.\n");
|
|
|
|
fprintf(yyout, "{ ECPGconnect(__LINE__, %s, %d);", $1, autocommit);
|
|
whenever_action(2);
|
|
free($1);
|
|
}
|
|
| ECPGCursorStmt {
|
|
output_simple_statement($1);
|
|
}
|
|
| ECPGDeallocate {
|
|
if (connection)
|
|
mmerror(ET_ERROR, "no at option for connect statement.\n");
|
|
|
|
fputc('{', yyout);
|
|
fputs($1, yyout);
|
|
whenever_action(2);
|
|
free($1);
|
|
}
|
|
| ECPGDeallocateDescr { fprintf(yyout,"ECPGdeallocate_desc(__LINE__, \"%s\");",$1);
|
|
whenever_action(0);
|
|
free($1);
|
|
}
|
|
| ECPGDeclare {
|
|
output_simple_statement($1);
|
|
}
|
|
| ECPGDisconnect {
|
|
if (connection)
|
|
mmerror(ET_ERROR, "no at option for disconnect statement.\n");
|
|
|
|
fprintf(yyout, "{ ECPGdisconnect(__LINE__, %s);", $1);
|
|
whenever_action(2);
|
|
free($1);
|
|
}
|
|
| ECPGExecute { output_statement($1, 0, NULL, connection); }
|
|
| ECPGFetchDescStmt { output_statement($1.str, 1, $1.name, connection); }
|
|
| ECPGFree {
|
|
fprintf(yyout, "{ ECPGdeallocate(__LINE__, \"%s\");", $1);
|
|
|
|
whenever_action(2);
|
|
free($1);
|
|
}
|
|
| ECPGGetDescriptor {
|
|
lookup_descriptor($1.name, connection);
|
|
output_get_descr($1.name, $1.str);
|
|
free($1.name);
|
|
free($1.str);
|
|
}
|
|
| ECPGGetDescriptorHeader {
|
|
lookup_descriptor($1, connection);
|
|
output_get_descr_header($1);
|
|
free($1);
|
|
}
|
|
| 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)
|
|
{
|
|
sprintf(errortext, "trying to open undeclared cursor %s\n", $1);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
|
|
/* 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, NULL, ptr->connection ? mm_strdup(ptr->connection) : NULL);
|
|
}
|
|
| ECPGPrepare {
|
|
if (connection)
|
|
mmerror(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");
|
|
whenever_action(2);
|
|
free($1);
|
|
}
|
|
| ECPGSetConnection {
|
|
if (connection)
|
|
mmerror(ET_ERROR, "no at option for set connection statement.\n");
|
|
|
|
fprintf(yyout, "{ ECPGsetconn(__LINE__, %s);", $1);
|
|
whenever_action(2);
|
|
free($1);
|
|
}
|
|
| ECPGTypedef {
|
|
if (connection)
|
|
mmerror(ET_ERROR, "no at option for typedef statement.\n");
|
|
|
|
output_simple_statement($1);
|
|
}
|
|
| ECPGVar {
|
|
if (connection)
|
|
mmerror(ET_ERROR, "no at option for var statement.\n");
|
|
|
|
output_simple_statement($1);
|
|
}
|
|
| ECPGWhenever {
|
|
if (connection)
|
|
mmerror(ET_ERROR, "no at option for whenever statement.\n");
|
|
|
|
output_simple_statement($1);
|
|
}
|
|
;
|
|
|
|
|
|
/*
|
|
* We start with a lot of stuff that's very similar to the backend's parsing
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Create a new Postgres DBMS user
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
CreateUserStmt: CREATE USER UserId
|
|
user_createdb_clause user_createuser_clause user_group_clause
|
|
user_valid_clause
|
|
{
|
|
$$ = cat_str(6, make_str("create user"), $3, $4, $5, $6, $7);
|
|
}
|
|
| CREATE USER UserId WITH sysid_clause user_passwd_clause
|
|
user_createdb_clause user_createuser_clause user_group_clause
|
|
user_valid_clause
|
|
{
|
|
$$ = cat_str(9, make_str("create user"), $3, make_str("with"), $5, $6, $7, $8, $9, $10);
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Alter a postgresql DBMS user
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
AlterUserStmt: ALTER USER UserId user_createdb_clause
|
|
user_createuser_clause user_valid_clause
|
|
{
|
|
$$ = cat_str(5, make_str("alter user"), $3, $4, $5, $6);
|
|
}
|
|
| ALTER USER UserId WITH PASSWORD Sconst
|
|
user_createdb_clause
|
|
user_createuser_clause user_valid_clause
|
|
{
|
|
$$ = cat_str(7, make_str("alter user"), $3, make_str("with password"), $6, $7, $8, $9);
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Drop a postgresql DBMS user
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
DropUserStmt: DROP USER user_list
|
|
{
|
|
$$ = cat2_str(make_str("drop user"), $3);
|
|
}
|
|
;
|
|
|
|
user_passwd_clause: PASSWORD Sconst { $$ = cat2_str(make_str("password") , $2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
sysid_clause: SYSID Iconst { if (atoi($2) <= 0)
|
|
mmerror(ET_ERROR, "sysid must be positive");
|
|
|
|
$$ = cat2_str(make_str("sysid"), $2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
user_createdb_clause: CREATEDB
|
|
{
|
|
$$ = make_str("createdb");
|
|
}
|
|
| NOCREATEDB
|
|
{
|
|
$$ = make_str("nocreatedb");
|
|
}
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
user_createuser_clause: CREATEUSER
|
|
{
|
|
$$ = make_str("createuser");
|
|
}
|
|
| NOCREATEUSER
|
|
{
|
|
$$ = make_str("nocreateuser");
|
|
}
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
;
|
|
|
|
user_list: user_list ',' UserId
|
|
{
|
|
$$ = cat_str(3, $1, make_str(","), $3);
|
|
}
|
|
| UserId
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
user_group_clause: IN GROUP user_list
|
|
{
|
|
$$ = cat2_str(make_str("in group"), $3);
|
|
}
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
user_valid_clause: VALID UNTIL Sconst { $$ = cat2_str(make_str("valid until"), $3); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Create a postgresql group
|
|
*
|
|
*
|
|
****************************************************************************/
|
|
CreateGroupStmt: CREATE GROUP UserId
|
|
{
|
|
$$ = cat2_str(make_str("create group"), $3);
|
|
}
|
|
| CREATE GROUP UserId WITH sysid_clause users_in_new_group_clause
|
|
{
|
|
$$ = cat_str(5, make_str("create group"), $3, make_str("with"), $5, $6);
|
|
}
|
|
;
|
|
|
|
users_in_new_group_clause: USER user_list { $$ = cat2_str(make_str("user"), $2); }
|
|
| /* EMPTY */ { $$ = EMPTY; }
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Alter a postgresql group
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
AlterGroupStmt: ALTER GROUP UserId ADD USER user_list
|
|
{
|
|
$$ = cat_str(4, make_str("alter group"), $3, make_str("add user"), $6);
|
|
}
|
|
| ALTER GROUP UserId DROP USER user_list
|
|
{
|
|
$$ = cat_str(4, make_str("alter group"), $3, make_str("drop user"), $6);
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Drop a postgresql group
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
DropGroupStmt: DROP GROUP UserId
|
|
{
|
|
$$ = cat2_str(make_str("drop group"), $3);
|
|
}
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Set PG internal variable
|
|
* SET name TO 'var_value'
|
|
* Include SQL92 syntax (thomas 1997-10-22):
|
|
* SET TIME ZONE 'var_value'
|
|
*
|
|
*****************************************************************************/
|
|
|
|
VariableSetStmt: SET ColId TO var_value
|
|
{
|
|
$$ = cat_str(4, make_str("set"), $2, make_str("to"), $4);
|
|
}
|
|
| SET ColId '=' var_value
|
|
{
|
|
$$ = cat_str(4, make_str("set"), $2, make_str("="), $4);
|
|
}
|
|
| SET TIME ZONE zone_value
|
|
{
|
|
$$ = cat2_str(make_str("set time zone"), $4);
|
|
}
|
|
| SET TRANSACTION ISOLATION LEVEL opt_level
|
|
{
|
|
$$ = cat2_str(make_str("set transaction isolation level"), $5);
|
|
}
|
|
| SET NAMES opt_encoding
|
|
{
|
|
#ifdef MULTIBYTE
|
|
$$ = cat2_str(make_str("set names"), $3);
|
|
#else
|
|
mmerror(ET_ERROR, "SET NAMES is not supported.");
|
|
#endif
|
|
}
|
|
;
|
|
|
|
opt_level: READ COMMITTED { $$ = make_str("read committed"); }
|
|
| SERIALIZABLE { $$ = make_str("serializable"); }
|
|
;
|
|
|
|
|
|
var_value: Sconst { $$ = $1; }
|
|
| DEFAULT { $$ = make_str("default"); }
|
|
;
|
|
|
|
zone_value: Sconst { $$ = $1; }
|
|
| DEFAULT { $$ = make_str("default"); }
|
|
| LOCAL { $$ = make_str("local"); }
|
|
;
|
|
|
|
opt_encoding: Sconst { $$ = $1; }
|
|
| DEFAULT { $$ = make_str("default"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
VariableShowStmt: SHOW ColId
|
|
{
|
|
$$ = cat2_str(make_str("show"), $2);
|
|
}
|
|
| SHOW TIME ZONE
|
|
{
|
|
$$ = make_str("show time zone");
|
|
}
|
|
| SHOW TRANSACTION ISOLATION LEVEL
|
|
{
|
|
$$ = make_str("show transaction isolation level");
|
|
}
|
|
;
|
|
|
|
VariableResetStmt: RESET ColId
|
|
{
|
|
$$ = cat2_str(make_str("reset"), $2);
|
|
}
|
|
| RESET TIME ZONE
|
|
{
|
|
$$ = make_str("reset time zone");
|
|
}
|
|
| RESET TRANSACTION ISOLATION LEVEL
|
|
{
|
|
$$ = make_str("reset transaction isolation level");
|
|
}
|
|
;
|
|
|
|
ConstraintsSetStmt: SET CONSTRAINTS constraints_set_list constraints_set_mode
|
|
{
|
|
$$ = cat_str(3, make_str("set constraints"), $3, $4);
|
|
}
|
|
;
|
|
|
|
constraints_set_list: ALL
|
|
{
|
|
$$ = make_str("all");
|
|
}
|
|
| constraints_set_namelist
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
|
|
constraints_set_namelist: IDENT
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| constraints_set_namelist ',' IDENT
|
|
{
|
|
$$ = cat_str(3, $1, make_str(","), $3);
|
|
}
|
|
;
|
|
|
|
constraints_set_mode: DEFERRED
|
|
{
|
|
$$ = make_str("deferred");
|
|
}
|
|
| IMMEDIATE
|
|
{
|
|
$$ = make_str("immediate");
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY :
|
|
*
|
|
* ALTER TABLE variations
|
|
*
|
|
*****************************************************************************/
|
|
|
|
AlterTableStmt:
|
|
/* ALTER TABLE <name> ADD [COLUMN] <coldef> */
|
|
ALTER TABLE relation_name opt_inh_star ADD opt_column columnDef
|
|
{
|
|
$$ = cat_str(6, make_str("alter table"), $3, $4, make_str("add"), $6, $7);
|
|
}
|
|
/* ALTER TABLE <name> ALTER [COLUMN] <colname> {SET DEFAULT <expr>|DROP
|
|
DEFAULT} */
|
|
| ALTER TABLE relation_name opt_inh_star ALTER opt_column ColId
|
|
alter_column_action
|
|
{
|
|
$$ = cat_str(7, make_str("alter table"), $3, $4, make_str("alter"), $6, $7, $8);
|
|
}
|
|
/* ALTER TABLE <name> DROP [COLUMN] <name> {RESTRICT|CASCADE} */
|
|
| ALTER TABLE relation_name opt_inh_star DROP opt_column ColId drop_behavior
|
|
{
|
|
$$ = cat_str(7, make_str("alter table"), $3, $4, make_str("drop"), $6, $7, $8);
|
|
}
|
|
/* ALTER TABLE <name> ADD CONSTRAINT ... */
|
|
| ALTER TABLE relation_name opt_inh_star ADD TableConstraint
|
|
{
|
|
$$ = cat_str(5, make_str("alter table"), $3, $4, make_str("add"), $6);
|
|
}
|
|
/* ALTER TABLE <name> DROP CONSTRAINT ... */
|
|
| ALTER TABLE relation_name opt_inh_star DROP CONSTRAINT name drop_behavior
|
|
{
|
|
$$ = cat_str(6, make_str("alter table"), $3, $4, make_str("drop constraint"), $7, $8);
|
|
}
|
|
;
|
|
|
|
alter_column_action:
|
|
SET DEFAULT a_expr { $$ = cat2_str(make_str("set default"), $3); }
|
|
| DROP DEFAULT { $$ = make_str("drop default"); }
|
|
;
|
|
|
|
drop_behavior: CASCADE { $$ = make_str("cascade"); }
|
|
| RESTRICT { $$ = make_str("restrict"); }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY :
|
|
* close <optname>
|
|
*
|
|
*****************************************************************************/
|
|
|
|
ClosePortalStmt: CLOSE opt_id
|
|
{
|
|
$$ = cat2_str(make_str("close"), $2);
|
|
}
|
|
;
|
|
|
|
opt_id: ColId { $$ = $1; }
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY :
|
|
* COPY [BINARY] <relname> FROM/TO
|
|
* [USING DELIMITERS <delimiter>]
|
|
*
|
|
*****************************************************************************/
|
|
|
|
CopyStmt: COPY opt_binary relation_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);
|
|
}
|
|
;
|
|
|
|
copy_dirn: 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: Sconst { $$ = $1; }
|
|
| STDIN { $$ = make_str("stdin"); }
|
|
| STDOUT { $$ = make_str("stdout"); }
|
|
;
|
|
|
|
opt_binary: BINARY { $$ = make_str("binary"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
opt_with_copy: WITH OIDS { $$ = make_str("with oids"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
/*
|
|
* the default copy delimiter is tab but the user can configure it
|
|
*/
|
|
copy_delimiter: opt_using DELIMITERS Sconst { $$ = cat_str(3, $1, make_str("delimiters"), $3); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
opt_using: USING { $$ = make_str("using"); }
|
|
| /* EMPTY */ { $$ = EMPTY; }
|
|
;
|
|
|
|
copy_null: WITH NULL_P AS Sconst { $$ = cat2_str(make_str("with null as"), $4); }
|
|
| /* EMPTY */ { $$ = EMPTY; }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY :
|
|
* CREATE relname
|
|
*
|
|
*****************************************************************************/
|
|
|
|
CreateStmt: CREATE OptTemp TABLE relation_name '(' OptTableElementList ')'
|
|
OptInherit
|
|
{
|
|
$$ = cat_str(8, make_str("create"), $2, make_str("table"), $4, make_str("("), $6, make_str(")"), $8);
|
|
}
|
|
;
|
|
|
|
/*
|
|
* Redundancy here is needed to avoid shift/reduce conflicts,
|
|
* since TEMP is not a reserved word. See also OptTempTableName.
|
|
*/
|
|
|
|
OptTemp: TEMPORARY { $$ = make_str("temporary"); }
|
|
| TEMP { $$ = make_str("temp"); }
|
|
| LOCAL TEMPORARY { $$ = make_str("local temporary"); }
|
|
| LOCAL TEMP { $$ = make_str("local temp"); }
|
|
| GLOBAL TEMPORARY {
|
|
mmerror(ET_ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
|
|
$$ = make_str("global temporary");
|
|
}
|
|
| GLOBAL TEMP {
|
|
mmerror(ET_ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
|
|
$$ = make_str("global temp");
|
|
}
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
OptTableElementList: OptTableElementList ',' OptTableElement
|
|
{
|
|
$$ = cat_str(3, $1, make_str(","), $3);
|
|
}
|
|
| OptTableElement
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
OptTableElement: columnDef { $$ = $1; }
|
|
| TableConstraint { $$ = $1; }
|
|
;
|
|
|
|
columnDef: ColId Typename ColQualList opt_collate
|
|
{
|
|
if (strlen($4) > 0)
|
|
{
|
|
sprintf(errortext, "CREATE TABLE/COLLATE %s not yet implemented; clause ignored", $4);
|
|
mmerror(ET_WARN, errortext);
|
|
}
|
|
$$ = cat_str(4, $1, $2, $3, $4);
|
|
}
|
|
| ColId SERIAL ColQualList opt_collate
|
|
{
|
|
if (strlen($4) > 0)
|
|
{
|
|
sprintf(errortext, "CREATE TABLE/COLLATE %s not yet implemented; clause ignored", $4);
|
|
mmerror(ET_WARN, errortext);
|
|
}
|
|
$$ = cat_str(4, $1, make_str(" serial "), $3, $4);
|
|
}
|
|
;
|
|
|
|
ColQualList: ColQualList ColConstraint { $$ = cat2_str($1,$2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
ColConstraint: CONSTRAINT name ColConstraintElem
|
|
{
|
|
$$ = cat_str(3, make_str("constraint"), $2, $3);
|
|
}
|
|
| ColConstraintElem
|
|
{ $$ = $1; }
|
|
| ConstraintAttr
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
/* DEFAULT NULL is already the default for Postgres.
|
|
* But define it here and carry it forward into the system
|
|
* to make it explicit.
|
|
* - thomas 1998-09-13
|
|
*
|
|
* WITH NULL and NULL are not SQL92-standard syntax elements,
|
|
* so leave them out. Use DEFAULT NULL to explicitly indicate
|
|
* that a column may have that value. WITH NULL leads to
|
|
* shift/reduce conflicts with WITH TIME ZONE anyway.
|
|
* - thomas 1999-01-08
|
|
*/
|
|
ColConstraintElem: NOT NULL_P
|
|
{
|
|
$$ = make_str("not null");
|
|
}
|
|
| NULL_P
|
|
{
|
|
$$ = make_str("null");
|
|
}
|
|
| UNIQUE
|
|
{
|
|
$$ = make_str("unique");
|
|
}
|
|
| PRIMARY KEY
|
|
{
|
|
$$ = make_str("primary key");
|
|
}
|
|
| CHECK '(' a_expr ')'
|
|
{
|
|
$$ = cat_str(3, make_str("check ("), $3, make_str(")"));
|
|
}
|
|
| DEFAULT b_expr
|
|
{
|
|
$$ = cat2_str(make_str("default"), $2);
|
|
}
|
|
| REFERENCES ColId opt_column_list key_match key_actions
|
|
{
|
|
$$ = cat_str(5, make_str("references"), $2, $3, $4, $5);
|
|
}
|
|
;
|
|
|
|
/*
|
|
* ConstraintAttr represents constraint attributes, which we parse as if
|
|
* they were independent constraint clauses, in order to avoid shift/reduce
|
|
* conflicts (since NOT might start either an independent NOT NULL clause
|
|
* or an attribute). analyze.c is responsible for attaching the attribute
|
|
* information to the preceding "real" constraint node, and for complaining
|
|
* if attribute clauses appear in the wrong place or wrong combinations.
|
|
*
|
|
* See also ConstraintAttributeSpec, which can be used in places where
|
|
* there is no parsing conflict.
|
|
*/
|
|
ConstraintAttr: DEFERRABLE { $$ = make_str("deferrable"); }
|
|
| NOT DEFERRABLE { $$ = make_str("not deferrable"); }
|
|
| INITIALLY DEFERRED { $$ = make_str("initially deferred"); }
|
|
| INITIALLY IMMEDIATE { $$ = make_str("initially immediate"); }
|
|
;
|
|
|
|
/* ConstraintElem specifies constraint syntax which is not embedded into
|
|
* a column definition. ColConstraintElem specifies the embedded form.
|
|
* - thomas 1997-12-03
|
|
*/
|
|
TableConstraint: CONSTRAINT name ConstraintElem
|
|
{
|
|
$$ = cat_str(3, make_str("constraint"), $2, $3);
|
|
}
|
|
| ConstraintElem
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
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(")"));
|
|
}
|
|
| FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list
|
|
key_match key_actions ConstraintAttributeSpec
|
|
{
|
|
$$ = cat_str(8, make_str("foreign key("), $4, make_str(") references"), $7, $8, $9, $10, $11);
|
|
}
|
|
;
|
|
|
|
key_match: MATCH FULL
|
|
{
|
|
$$ = make_str("match full");
|
|
}
|
|
| MATCH PARTIAL
|
|
{
|
|
mmerror(ET_WARN, "FOREIGN KEY/MATCH PARTIAL not yet implemented");
|
|
$$ = make_str("match partial");
|
|
}
|
|
| /*EMPTY*/
|
|
{
|
|
$$ = EMPTY;
|
|
}
|
|
;
|
|
|
|
key_actions: key_delete { $$ = $1; }
|
|
| key_update { $$ = $1; }
|
|
| key_delete key_update { $$ = cat2_str($1, $2); }
|
|
| key_update key_delete { $$ = cat2_str($1, $2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
key_delete: ON DELETE key_reference { $$ = cat2_str(make_str("on delete"), $3); }
|
|
|
|
key_update: ON UPDATE key_reference { $$ = cat2_str(make_str("on update"), $3); }
|
|
|
|
key_reference: NO ACTION { $$ = make_str("no action"); }
|
|
| RESTRICT { $$ = make_str("restrict"); }
|
|
| CASCADE { $$ = make_str("cascade"); }
|
|
| SET DEFAULT { $$ = make_str("set default"); }
|
|
| SET NULL_P { $$ = make_str("set null"); }
|
|
;
|
|
|
|
OptInherit: INHERITS '(' relation_name_list ')' { $$ = cat_str(3, make_str("inherits ("), $3, make_str(")")); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
/*
|
|
* Note: CREATE TABLE ... AS SELECT ... is just another spelling for
|
|
* SELECT ... INTO.
|
|
*/
|
|
|
|
CreateAsStmt: CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
|
|
{
|
|
if (FoundInto == 1)
|
|
mmerror(ET_ERROR, "CREATE TABLE/AS SELECT may not specify INTO");
|
|
|
|
$$ = cat_str(7, make_str("create"), $2, make_str("table"), $4, $5, make_str("as"), $7);
|
|
}
|
|
;
|
|
|
|
OptCreateAs: '(' CreateAsList ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
CreateAsList: CreateAsList ',' CreateAsElement { $$ = cat_str(3, $1, make_str(","), $3); }
|
|
| CreateAsElement { $$ = $1; }
|
|
;
|
|
|
|
CreateAsElement: ColId { $$ = $1; }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY :
|
|
* CREATE SEQUENCE seqname
|
|
*
|
|
*****************************************************************************/
|
|
|
|
CreateSeqStmt: CREATE SEQUENCE relation_name OptSeqList
|
|
{
|
|
$$ = cat_str(3, make_str("create sequence"), $3, $4);
|
|
}
|
|
;
|
|
|
|
OptSeqList: OptSeqList OptSeqElem
|
|
{ $$ = cat2_str($1, $2); }
|
|
| { $$ = EMPTY; }
|
|
;
|
|
|
|
OptSeqElem: CACHE IntegerOnly
|
|
{
|
|
$$ = cat2_str(make_str("cache"), $2);
|
|
}
|
|
| CYCLE
|
|
{
|
|
$$ = make_str("cycle");
|
|
}
|
|
| INCREMENT IntegerOnly
|
|
{
|
|
$$ = cat2_str(make_str("increment"), $2);
|
|
}
|
|
| MAXVALUE IntegerOnly
|
|
{
|
|
$$ = cat2_str(make_str("maxvalue"), $2);
|
|
}
|
|
| MINVALUE IntegerOnly
|
|
{
|
|
$$ = cat2_str(make_str("minvalue"), $2);
|
|
}
|
|
| START IntegerOnly
|
|
{
|
|
$$ = cat2_str(make_str("start"), $2);
|
|
}
|
|
;
|
|
|
|
NumericOnly: FloatOnly { $$ = $1; }
|
|
| IntegerOnly { $$ = $1; }
|
|
|
|
FloatOnly: Fconst
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| '-' Fconst
|
|
{
|
|
$$ = cat2_str(make_str("-"), $2);
|
|
}
|
|
;
|
|
|
|
|
|
IntegerOnly: Iconst
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| '-' Iconst
|
|
{
|
|
$$ = cat2_str(make_str("-"), $2);
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERIES :
|
|
* CREATE PROCEDURAL LANGUAGE ...
|
|
* DROP PROCEDURAL LANGUAGE ...
|
|
*
|
|
*****************************************************************************/
|
|
|
|
CreatePLangStmt: CREATE PLangTrusted PROCEDURAL LANGUAGE Sconst
|
|
HANDLER def_name LANCOMPILER Sconst
|
|
{
|
|
$$ = cat_str(8, make_str("create"), $2, make_str("precedural language"), $5, make_str("handler"), $7, make_str("langcompiler"), $9);
|
|
}
|
|
;
|
|
|
|
PLangTrusted: TRUSTED { $$ = make_str("trusted"); }
|
|
| { $$ = EMPTY; }
|
|
|
|
DropPLangStmt: DROP PROCEDURAL LANGUAGE Sconst
|
|
{
|
|
$$ = cat2_str(make_str("drop procedural language"), $4);
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERIES :
|
|
* CREATE TRIGGER ...
|
|
* DROP TRIGGER ...
|
|
*
|
|
*****************************************************************************/
|
|
|
|
CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON
|
|
relation_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
|
|
relation_name OptConstrFromTable
|
|
ConstraintAttributeSpec
|
|
FOR EACH ROW EXECUTE PROCEDURE
|
|
name '(' TriggerFuncArgs ')'
|
|
{
|
|
$$ = cat_str(13, make_str("create constraint trigger"), $4, make_str("after"), $6, make_str("on"), $8, $9, $10, make_str("for each row execute procedure"), $16, make_str("("), $18, make_str(")"));
|
|
}
|
|
;
|
|
|
|
TriggerActionTime: BEFORE { $$ = make_str("before"); }
|
|
| AFTER { $$ = make_str("after"); }
|
|
;
|
|
|
|
TriggerEvents: TriggerOneEvent
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| TriggerOneEvent OR TriggerOneEvent
|
|
{
|
|
$$ = cat_str(3, $1, make_str("or"), $3);
|
|
}
|
|
| TriggerOneEvent OR TriggerOneEvent OR TriggerOneEvent
|
|
{
|
|
$$ = cat_str(5, $1, make_str("or"), $3, make_str("or"), $5);
|
|
}
|
|
;
|
|
|
|
TriggerOneEvent: INSERT { $$ = make_str("insert"); }
|
|
| DELETE { $$ = make_str("delete"); }
|
|
| UPDATE { $$ = make_str("update"); }
|
|
;
|
|
|
|
TriggerForSpec: FOR TriggerForOpt TriggerForType
|
|
{
|
|
$$ = cat_str(3, make_str("for"), $2, $3);
|
|
}
|
|
;
|
|
|
|
TriggerForOpt: EACH { $$ = make_str("each"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
TriggerForType: ROW { $$ = make_str("row"); }
|
|
| STATEMENT { $$ = make_str("statement"); }
|
|
;
|
|
|
|
TriggerFuncArgs: TriggerFuncArg
|
|
{ $$ = $1; }
|
|
| TriggerFuncArgs ',' TriggerFuncArg
|
|
{ $$ = cat_str(3, $1, make_str(","), $3); }
|
|
| /*EMPTY*/
|
|
{ $$ = EMPTY; }
|
|
;
|
|
|
|
TriggerFuncArg: Iconst
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| Fconst
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| Sconst { $$ = $1; }
|
|
| ident { $$ = $1; }
|
|
;
|
|
|
|
OptConstrFromTable: /* Empty */
|
|
{
|
|
$$ = EMPTY;
|
|
}
|
|
| FROM relation_name
|
|
{
|
|
$$ = cat2_str(make_str("from"), $2);
|
|
}
|
|
;
|
|
|
|
ConstraintAttributeSpec: ConstraintDeferrabilitySpec
|
|
{ $$ = $1; }
|
|
| ConstraintDeferrabilitySpec ConstraintTimeSpec
|
|
{
|
|
if (strcmp($1, "deferrable") != 0 && strcmp($2, "initially deferrable") == 0 )
|
|
mmerror(ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
|
|
|
|
$$ = cat2_str($1, $2);
|
|
}
|
|
| ConstraintTimeSpec
|
|
{ $$ = $1; }
|
|
| ConstraintTimeSpec ConstraintDeferrabilitySpec
|
|
{
|
|
if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 )
|
|
mmerror(ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
|
|
|
|
$$ = cat2_str($1, $2);
|
|
}
|
|
;
|
|
|
|
ConstraintDeferrabilitySpec: NOT DEFERRABLE { $$ = make_str("not deferrable"); }
|
|
| DEFERRABLE { $$ = make_str("deferrable"); }
|
|
;
|
|
|
|
ConstraintTimeSpec: INITIALLY IMMEDIATE { $$ = make_str("initially immediate"); }
|
|
| INITIALLY DEFERRED { $$ = make_str("initially deferrable"); }
|
|
;
|
|
|
|
DropTrigStmt: DROP TRIGGER name ON relation_name
|
|
{
|
|
$$ = cat_str(4, make_str("drop trigger"), $3, make_str("on"), $5);
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY :
|
|
* define (type,operator,aggregate)
|
|
*
|
|
*****************************************************************************/
|
|
|
|
DefineStmt: CREATE def_type def_rest
|
|
{
|
|
$$ = cat_str(3, make_str("create"), $2, $3);
|
|
}
|
|
;
|
|
|
|
def_rest: def_name definition
|
|
{
|
|
$$ = cat2_str($1, $2);
|
|
}
|
|
;
|
|
|
|
def_type: OPERATOR { $$ = make_str("operator"); }
|
|
| TYPE_P { $$ = make_str("type"); }
|
|
| AGGREGATE { $$ = make_str("aggregate"); }
|
|
;
|
|
|
|
def_name: PROCEDURE { $$ = make_str("procedure"); }
|
|
| JOIN { $$ = make_str("join"); }
|
|
| ColId { $$ = $1; }
|
|
| all_Op { $$ = $1; }
|
|
;
|
|
|
|
definition: '(' def_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
|
|
;
|
|
|
|
def_list: def_elem { $$ = $1; }
|
|
| def_list ',' def_elem { $$ = cat_str(3, $1, make_str(","), $3); }
|
|
;
|
|
|
|
def_elem: def_name '=' def_arg {
|
|
$$ = cat_str(3, $1, make_str("="), $3);
|
|
}
|
|
| def_name
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| DEFAULT '=' def_arg
|
|
{
|
|
$$ = cat2_str(make_str("default ="), $3);
|
|
}
|
|
;
|
|
|
|
def_arg: ColId { $$ = $1; }
|
|
| all_Op { $$ = $1; }
|
|
| NumericOnly { $$ = $1; }
|
|
| Sconst { $$ = $1; }
|
|
| SETOF ColId
|
|
{
|
|
$$ = cat2_str(make_str("setof"), $2);
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* drop <relname1> [, <relname2> .. <relnameN> ]
|
|
*
|
|
*****************************************************************************/
|
|
|
|
DropStmt: DROP TABLE relation_name_list
|
|
{
|
|
$$ = cat2_str(make_str("drop table"), $3);
|
|
}
|
|
| DROP SEQUENCE relation_name_list
|
|
{
|
|
$$ = cat2_str(make_str("drop sequence"), $3);
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* truncate table relname
|
|
*
|
|
*****************************************************************************/
|
|
TruncateStmt: TRUNCATE opt_table relation_name
|
|
{
|
|
$$ = cat2_str(make_str("drop table"), $3);
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* fetch/move [forward | backward] [ # | all ] [ in <portalname> ]
|
|
* fetch [ forward | backward | absolute | relative ]
|
|
* [ # | all | next | prior ] [ [ in | from ] <portalname> ]
|
|
*
|
|
*****************************************************************************/
|
|
|
|
FetchStmt: FETCH direction fetch_how_many from_in name INTO into_list
|
|
{
|
|
if (strcmp($2, "relative") == 0 && atol($3) == 0L)
|
|
mmerror(ET_ERROR, "FETCH/RELATIVE at current position is not supported");
|
|
|
|
$$ = cat_str(5, make_str("fetch"), $2, $3, $4, $5);
|
|
}
|
|
| FETCH fetch_how_many from_in name INTO into_list
|
|
{
|
|
$$ = cat_str(4, make_str("fetch"), $2, $3, $4);
|
|
}
|
|
| FETCH direction from_in name INTO into_list
|
|
{
|
|
$$ = cat_str(4, make_str("fetch"), $2, $3, $4);
|
|
}
|
|
| FETCH from_in name INTO into_list
|
|
{
|
|
$$ = cat_str(3, make_str("fetch"), $2, $3);
|
|
}
|
|
| FETCH name INTO into_list
|
|
{
|
|
$$ = cat2_str(make_str("fetch"), $2);
|
|
}
|
|
| MOVE direction fetch_how_many from_in name
|
|
{
|
|
$$ = cat_str(5, make_str("move"), $2, $3, $4, $5);
|
|
}
|
|
| MOVE fetch_how_many from_in name
|
|
{
|
|
$$ = cat_str(4, make_str("move"), $2, $3, $4);
|
|
}
|
|
| MOVE direction from_in name
|
|
{
|
|
$$ = cat_str(4, make_str("move"), $2, $3, $4);
|
|
}
|
|
| MOVE from_in name
|
|
{
|
|
$$ = cat_str(3, make_str("move"), $2, $3);
|
|
}
|
|
| MOVE name
|
|
{
|
|
$$ = cat2_str(make_str("move"), $2);
|
|
}
|
|
;
|
|
|
|
direction: FORWARD { $$ = make_str("forward"); }
|
|
| BACKWARD { $$ = make_str("backward"); }
|
|
| RELATIVE { $$ = make_str("relative"); }
|
|
| ABSOLUTE {
|
|
mmerror(ET_WARN, "FETCH/ABSOLUTE not supported, backend will use RELATIVE");
|
|
$$ = make_str("absolute");
|
|
}
|
|
;
|
|
|
|
fetch_how_many: Iconst { $$ = $1; }
|
|
| '-' Iconst { $$ = cat2_str(make_str("-"), $2); }
|
|
| ALL { $$ = make_str("all"); }
|
|
| NEXT { $$ = make_str("next"); }
|
|
| PRIOR { $$ = make_str("prior"); }
|
|
;
|
|
|
|
from_in: IN { $$ = make_str("in"); }
|
|
| FROM { $$ = make_str("from"); }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* The COMMENT ON statement can take different forms based upon the type of
|
|
* the object associated with the comment. The form of the statement is:
|
|
*
|
|
* COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
|
|
* <objname> | AGGREGATE <aggname> <aggtype> | FUNCTION
|
|
* <funcname> (arg1, arg2, ...) | OPERATOR <op>
|
|
* (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
|
|
* <relname> ] IS 'text'
|
|
*
|
|
*****************************************************************************/
|
|
CommentStmt: COMMENT ON comment_type name IS comment_text
|
|
{
|
|
$$ = cat_str(5, make_str("comment on"), $3, $4, make_str("is"), $6);
|
|
}
|
|
| COMMENT ON comment_cl relation_name '.' attr_name IS comment_text
|
|
{
|
|
$$ = cat_str(7, make_str("comment on"), $3, $4, make_str("."), $6, make_str("is"), $8);
|
|
}
|
|
| COMMENT ON comment_ag name aggr_argtype IS comment_text
|
|
{
|
|
$$ = cat_str(6, make_str("comment on"), $3, $4, $5, make_str("is"), $7);
|
|
}
|
|
| COMMENT ON comment_fn func_name func_args IS comment_text
|
|
{
|
|
$$ = cat_str(6, make_str("comment on"), $3, $4, $5, make_str("is"), $7);
|
|
}
|
|
| COMMENT ON comment_op all_Op '(' oper_argtypes ')' IS comment_text
|
|
{
|
|
$$ = cat_str(7, make_str("comment on"), $3, $4, make_str("("), $6, make_str(") is"), $9);
|
|
}
|
|
| COMMENT ON comment_tg name ON relation_name IS comment_text
|
|
{
|
|
$$ = cat_str(7, make_str("comment on"), $3, $4, make_str("on"), $6, make_str("is"), $8);
|
|
}
|
|
;
|
|
|
|
comment_type: DATABASE { $$ = make_str("database"); }
|
|
| INDEX { $$ = make_str("idnex"); }
|
|
| RULE { $$ = make_str("rule"); }
|
|
| SEQUENCE { $$ = make_str("sequence"); }
|
|
| TABLE { $$ = make_str("table"); }
|
|
| TYPE_P { $$ = make_str("type"); }
|
|
| VIEW { $$ = make_str("view"); }
|
|
;
|
|
|
|
comment_cl: COLUMN { $$ = make_str("column"); }
|
|
|
|
comment_ag: AGGREGATE { $$ = make_str("aggregate"); }
|
|
|
|
comment_fn: FUNCTION { $$ = make_str("function"); }
|
|
|
|
comment_op: OPERATOR { $$ = make_str("operator"); }
|
|
|
|
comment_tg: TRIGGER { $$ = make_str("trigger"); }
|
|
|
|
comment_text: Sconst { $$ = $1; }
|
|
| NULL_P { $$ = make_str("null"); }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* GRANT [privileges] ON [relation_name_list] TO [GROUP] grantee
|
|
*
|
|
*****************************************************************************/
|
|
|
|
GrantStmt: GRANT privileges ON relation_name_list TO grantee opt_with_grant
|
|
{
|
|
$$ = cat_str(7, make_str("grant"), $2, make_str("on"), $4, make_str("to"), $6);
|
|
}
|
|
;
|
|
|
|
privileges: ALL PRIVILEGES
|
|
{
|
|
$$ = make_str("all privileges");
|
|
}
|
|
| ALL
|
|
{
|
|
$$ = make_str("all");
|
|
}
|
|
| operation_commalist
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
operation_commalist: operation
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| operation_commalist ',' operation
|
|
{
|
|
$$ = cat_str(3, $1, make_str(","), $3);
|
|
}
|
|
;
|
|
|
|
operation: SELECT
|
|
{
|
|
$$ = make_str("select");
|
|
}
|
|
| INSERT
|
|
{
|
|
$$ = make_str("insert");
|
|
}
|
|
| UPDATE
|
|
{
|
|
$$ = make_str("update");
|
|
}
|
|
| DELETE
|
|
{
|
|
$$ = make_str("delete");
|
|
}
|
|
| RULE
|
|
{
|
|
$$ = make_str("rule");
|
|
}
|
|
;
|
|
|
|
grantee: PUBLIC
|
|
{
|
|
$$ = make_str("public");
|
|
}
|
|
| GROUP ColId
|
|
{
|
|
$$ = cat2_str(make_str("group"), $2);
|
|
}
|
|
| ColId
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
opt_with_grant: WITH GRANT OPTION
|
|
{
|
|
mmerror(ET_ERROR, "WITH GRANT OPTION is not supported. Only relation owners can set privileges");
|
|
}
|
|
| /*EMPTY*/
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* REVOKE [privileges] ON [relation_name] FROM [user]
|
|
*
|
|
*****************************************************************************/
|
|
|
|
RevokeStmt: REVOKE privileges ON relation_name_list FROM grantee
|
|
{
|
|
$$ = cat_str(7, make_str("revoke"), $2, make_str("on"), $4, make_str("from"), $6);
|
|
}
|
|
;
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* create index <indexname> on <relname>
|
|
* using <access> "(" (<col> with <op>)+ ")" [with
|
|
* <target_list>]
|
|
*
|
|
* [where <qual>] is not supported anymore
|
|
*****************************************************************************/
|
|
|
|
IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
|
|
access_method_clause '(' index_params ')' opt_with
|
|
{
|
|
/* should check that access_method is valid,
|
|
etc ... but doesn't */
|
|
$$ = cat_str(11, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11);
|
|
}
|
|
;
|
|
|
|
index_opt_unique: UNIQUE { $$ = make_str("unique"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
access_method_clause: USING access_method { $$ = cat2_str(make_str("using"), $2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
index_params: index_list { $$ = $1; }
|
|
| func_index { $$ = $1; }
|
|
;
|
|
|
|
index_list: index_list ',' index_elem { $$ = cat_str(3, $1, make_str(","), $3); }
|
|
| index_elem { $$ = $1; }
|
|
;
|
|
|
|
func_index: func_name '(' name_list ')' opt_type opt_class
|
|
{
|
|
$$ = cat_str(6, $1, make_str("("), $3, ")", $5, $6);
|
|
}
|
|
;
|
|
|
|
index_elem: attr_name opt_type opt_class
|
|
{
|
|
$$ = cat_str(3, $1, $2, $3);
|
|
}
|
|
;
|
|
|
|
opt_type: ':' Typename { $$ = cat2_str(make_str(":"), $2); }
|
|
| FOR Typename { $$ = cat2_str(make_str("for"), $2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
/* opt_class "WITH class" conflicts with preceeding opt_type
|
|
* for Typename of "TIMESTAMP WITH TIME ZONE"
|
|
* So, remove "WITH class" from the syntax. OK??
|
|
* - thomas 1997-10-12
|
|
* | WITH class { $$ = $2; }
|
|
*/
|
|
opt_class: class { $$ = $1; }
|
|
| USING class { $$ = cat2_str(make_str("using"), $2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* extend index <indexname> [where <qual>]
|
|
*
|
|
*****************************************************************************/
|
|
|
|
ExtendStmt: EXTEND INDEX index_name where_clause
|
|
{
|
|
$$ = cat_str(3, make_str("extend index"), $3, $4);
|
|
}
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* execute recipe <recipeName>
|
|
*
|
|
*****************************************************************************/
|
|
/* NOT USED
|
|
RecipeStmt: EXECUTE RECIPE recipe_name
|
|
{
|
|
$$ = cat2_str(make_str("execute recipe"), $3);
|
|
}
|
|
;
|
|
*/
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* define function <fname>
|
|
* (language = <lang>, returntype = <typename>
|
|
* [, arch_pct = <percentage | pre-defined>]
|
|
* [, disk_pct = <percentage | pre-defined>]
|
|
* [, byte_pct = <percentage | pre-defined>]
|
|
* [, perbyte_cpu = <int | pre-defined>]
|
|
* [, percall_cpu = <int | pre-defined>]
|
|
* [, iscachable])
|
|
* [arg is (<type-1> { , <type-n>})]
|
|
* as <filename or code in language as appropriate>
|
|
*
|
|
*****************************************************************************/
|
|
|
|
ProcedureStmt: CREATE FUNCTION func_name func_args
|
|
RETURNS func_return opt_with AS func_as LANGUAGE Sconst
|
|
{
|
|
$$ = cat_str(10, make_str("create function"), $3, $4, make_str("returns"), $6, $7, make_str("as"), $9, make_str("language"), $11);
|
|
}
|
|
|
|
opt_with: WITH definition { $$ = cat2_str(make_str("with"), $2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
func_args: '(' func_args_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
|
|
| '(' ')' { $$ = make_str("()"); }
|
|
;
|
|
|
|
func_args_list: TypeId { $$ = $1; }
|
|
| func_args_list ',' TypeId
|
|
{ $$ = cat_str(3, $1, make_str(","), $3); }
|
|
;
|
|
|
|
func_as: Sconst { $$ = $1; }
|
|
| Sconst ',' Sconst { $$ = cat_str(3, $1, make_str(","), $3); }
|
|
|
|
func_return: set_opt TypeId
|
|
{
|
|
$$ = cat2_str($1, $2);
|
|
}
|
|
;
|
|
|
|
set_opt: SETOF { $$ = make_str("setof"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
*
|
|
* remove function <funcname>
|
|
* (REMOVE FUNCTION "funcname" (arg1, arg2, ...))
|
|
* remove aggregate <aggname>
|
|
* (REMOVE AGGREGATE "aggname" "aggtype")
|
|
* remove operator <opname>
|
|
* (REMOVE OPERATOR "opname" (leftoperand_typ rightoperand_typ))
|
|
* remove type <typename>
|
|
* (REMOVE TYPE "typename")
|
|
* remove rule <rulename>
|
|
* (REMOVE RULE "rulename")
|
|
*
|
|
*****************************************************************************/
|
|
|
|
RemoveStmt: DROP remove_type name
|
|
{
|
|
$$ = cat_str(3, make_str("drop"), $2, $3);
|
|
}
|
|
;
|
|
|
|
remove_type: TYPE_P { $$ = make_str("type"); }
|
|
| INDEX { $$ = make_str("index"); }
|
|
| RULE { $$ = make_str("rule"); }
|
|
| VIEW { $$ = make_str("view"); }
|
|
;
|
|
|
|
|
|
RemoveAggrStmt: DROP AGGREGATE name aggr_argtype
|
|
{
|
|
$$ = cat_str(3, make_str("drop aggregate"), $3, $4);
|
|
}
|
|
;
|
|
|
|
aggr_argtype: name { $$ = $1; }
|
|
| '*' { $$ = make_str("*"); }
|
|
;
|
|
|
|
|
|
RemoveFuncStmt: DROP FUNCTION func_name func_args
|
|
{
|
|
$$ = cat_str(3, make_str("drop function"), $3, $4);
|
|
}
|
|
;
|
|
|
|
|
|
RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')'
|
|
{
|
|
$$ = cat_str(5, make_str("drop operator"), $3, make_str("("), $5, make_str(")"));
|
|
}
|
|
;
|
|
|
|
oper_argtypes: name
|
|
{
|
|
mmerror(ET_ERROR, "parser: argument type missing (use NONE for unary operators)");
|
|
}
|
|
| name ',' name
|
|
{ $$ = cat_str(3, $1, make_str(","), $3); }
|
|
| NONE ',' name /* left unary */
|
|
{ $$ = cat2_str(make_str("none,"), $3); }
|
|
| name ',' NONE /* right unary */
|
|
{ $$ = cat2_str($1, make_str(", none")); }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
*
|
|
* REINDEX type <typename> [FORCE] [ALL]
|
|
*
|
|
*****************************************************************************/
|
|
ReindexStmt: REINDEX reindex_type name opt_force
|
|
{
|
|
$$ = cat_str(4, make_str("reindex"), $2, $3, $4);
|
|
}
|
|
|
|
reindex_type: INDEX { $$ = make_str("index"); }
|
|
| TABLE { $$ = make_str("table"); }
|
|
| DATABASE { $$ = make_str("database"); }
|
|
;
|
|
opt_force: FORCE { $$ = make_str("force"); }
|
|
| /* EMPTY */ { $$ = EMPTY; }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* rename <attrname1> in <relname> [*] to <attrname2>
|
|
* rename <relname1> to <relname2>
|
|
*
|
|
*****************************************************************************/
|
|
|
|
RenameStmt: ALTER TABLE relation_name opt_inh_star
|
|
RENAME opt_column opt_name TO name
|
|
{
|
|
$$ = cat_str(8, make_str("alter table"), $3, $4, make_str("rename"), $6, $7, make_str("to"), $9);
|
|
}
|
|
;
|
|
|
|
opt_name: name { $$ = $1; }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
opt_column: COLUMN { $$ = make_str("colmunn"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY: Define Rewrite Rule , Define Tuple Rule
|
|
* Define Rule <old rules >
|
|
*
|
|
* only rewrite rule is supported -- ay 9/94
|
|
*
|
|
*****************************************************************************/
|
|
|
|
RuleStmt: CREATE RULE name AS
|
|
{ QueryIsRule=1; }
|
|
ON event TO event_object where_clause
|
|
DO opt_instead RuleActionList
|
|
{
|
|
$$ = cat_str(10, make_str("create rule"), $3, make_str("as on"), $7, make_str("to"), $9, $10, make_str("do"), $12, $13);
|
|
}
|
|
;
|
|
|
|
RuleActionList: NOTHING { $$ = make_str("nothing"); }
|
|
| SelectStmt { $$ = $1; }
|
|
| RuleActionStmt { $$ = $1; }
|
|
| '[' RuleActionMulti ']' { $$ = cat_str(3, make_str("["), $2, make_str("]")); }
|
|
| '(' RuleActionMulti ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
|
|
;
|
|
|
|
/* the thrashing around here is to discard "empty" statements... */
|
|
RuleActionMulti: RuleActionMulti ';' RuleActionStmtOrEmpty
|
|
{ $$ = cat_str(3, $1, make_str(";"), $3); }
|
|
| RuleActionStmtOrEmpty
|
|
{ $$ = cat2_str($1, make_str(";")); }
|
|
;
|
|
|
|
RuleActionStmt: InsertStmt
|
|
| UpdateStmt
|
|
| DeleteStmt
|
|
| NotifyStmt
|
|
;
|
|
RuleActionStmtOrEmpty: RuleActionStmt { $$ = $1; }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
event_object: relation_name '.' attr_name
|
|
{
|
|
$$ = make3_str($1, make_str("."), $3);
|
|
}
|
|
| relation_name
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
/* change me to select, update, etc. some day */
|
|
event: SELECT { $$ = make_str("select"); }
|
|
| UPDATE { $$ = make_str("update"); }
|
|
| DELETE { $$ = make_str("delete"); }
|
|
| INSERT { $$ = make_str("insert"); }
|
|
;
|
|
|
|
opt_instead: INSTEAD { $$ = make_str("instead"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* NOTIFY <relation_name> can appear both in rule bodies and
|
|
* as a query-level command
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NotifyStmt: NOTIFY relation_name
|
|
{
|
|
$$ = cat2_str(make_str("notify"), $2);
|
|
}
|
|
;
|
|
|
|
ListenStmt: LISTEN relation_name
|
|
{
|
|
$$ = cat2_str(make_str("listen"), $2);
|
|
}
|
|
;
|
|
|
|
UnlistenStmt: UNLISTEN relation_name
|
|
{
|
|
$$ = cat2_str(make_str("unlisten"), $2);
|
|
}
|
|
| UNLISTEN '*'
|
|
{
|
|
$$ = make_str("unlisten *");
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Transactions:
|
|
*
|
|
* BEGIN / COMMIT / ROLLBACK
|
|
* (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"); }
|
|
| END_TRANS opt_trans { $$ = make_str("commit"); }
|
|
| ROLLBACK opt_trans { $$ = make_str("rollback"); }
|
|
|
|
opt_trans: WORK { $$ = ""; }
|
|
| TRANSACTION { $$ = ""; }
|
|
| /*EMPTY*/ { $$ = ""; }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* define view <viewname> '('target-list ')' [where <quals> ]
|
|
*
|
|
*****************************************************************************/
|
|
|
|
ViewStmt: CREATE VIEW name opt_column_list AS SelectStmt
|
|
{
|
|
$$ = cat_str(5, make_str("create view"), $3, $4, make_str("as"), $6);
|
|
}
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* load make_str("filename")
|
|
*
|
|
*****************************************************************************/
|
|
|
|
LoadStmt: LOAD file_name
|
|
{
|
|
$$ = cat2_str(make_str("load"), $2);
|
|
}
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* CREATE DATABASE
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb_opt_encoding
|
|
{
|
|
if (strlen($5) == 0 || strlen($6) == 0)
|
|
mmerror(ET_ERROR, "CREATE DATABASE WITH requires at least an option");
|
|
|
|
$$ = cat_str(5, make_str("create database"), $3, make_str("with"), $5, $6);
|
|
}
|
|
| CREATE DATABASE database_name
|
|
{
|
|
$$ = cat2_str(make_str("create database"), $3);
|
|
}
|
|
;
|
|
|
|
createdb_opt_location: LOCATION '=' Sconst { $$ = cat2_str(make_str("location ="), $3); }
|
|
| LOCATION '=' DEFAULT { $$ = make_str("location = default"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
createdb_opt_encoding: ENCODING '=' Sconst
|
|
{
|
|
#ifndef MULTIBYTE
|
|
mmerror(ET_ERROR, "Multi-byte support is not enabled.");
|
|
#endif
|
|
$$ = cat2_str(make_str("encoding ="), $3);
|
|
}
|
|
| ENCODING '=' Iconst
|
|
{
|
|
#ifndef MULTIBYTE
|
|
mmerror(ET_ERROR, "Multi-byte support is not enabled.");
|
|
#endif
|
|
$$ = cat2_str(make_str("encoding ="), $3);
|
|
}
|
|
| ENCODING '=' DEFAULT
|
|
{
|
|
#ifndef MULTIBYTE
|
|
mmerror(ET_ERROR, "Multi-byte support is not enabled.");
|
|
#endif
|
|
$$ = make_str("encoding = default");
|
|
}
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* DROP DATABASE
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
DropdbStmt: DROP DATABASE database_name
|
|
{
|
|
$$ = cat2_str(make_str("drop database"), $3);
|
|
}
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* cluster <index_name> on <relation_name>
|
|
*
|
|
*****************************************************************************/
|
|
|
|
ClusterStmt: CLUSTER index_name ON relation_name
|
|
{
|
|
$$ = cat_str(4, make_str("cluster"), $2, make_str("on"), $4);
|
|
}
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* vacuum
|
|
*
|
|
*****************************************************************************/
|
|
|
|
VacuumStmt: VACUUM opt_verbose opt_analyze
|
|
{
|
|
$$ = cat_str(3, make_str("vacuum"), $2, $3);
|
|
}
|
|
| VACUUM opt_verbose opt_analyze relation_name opt_va_list
|
|
{
|
|
if ( strlen($5) > 0 && strlen($4) == 0 )
|
|
mmerror(ET_ERROR, "VACUUM syntax error at or near \"(\"\n\tRelations name must be specified");
|
|
$$ = cat_str(5, make_str("vacuum"), $2, $3, $4, $5);
|
|
}
|
|
;
|
|
|
|
opt_verbose: VERBOSE { $$ = make_str("verbose"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
opt_analyze: ANALYZE { $$ = make_str("analyse"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
opt_va_list: '(' va_list ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
va_list: name
|
|
{ $$=$1; }
|
|
| va_list ',' name
|
|
{ $$=cat_str(3, $1, make_str(","), $3); }
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* EXPLAIN query
|
|
*
|
|
*****************************************************************************/
|
|
|
|
ExplainStmt: EXPLAIN opt_verbose OptimizableStmt
|
|
{
|
|
$$ = cat_str(3, make_str("explain"), $2, $3);
|
|
}
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* 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 *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
OptimizableStmt: SelectStmt
|
|
| CursorStmt
|
|
| UpdateStmt
|
|
| InsertStmt
|
|
| NotifyStmt
|
|
| DeleteStmt
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* INSERT STATEMENTS
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* This rule used 'opt_column_list' between 'relation_name' and 'insert_rest'
|
|
* originally. When the second rule of 'insert_rest' was changed to use
|
|
* the new 'SelectStmt' rule (for INTERSECT and EXCEPT) it produced a shift/red uce
|
|
* conflict. So I just changed the rules 'InsertStmt' and 'insert_rest' to accept
|
|
* the same statements without any shift/reduce conflicts */
|
|
InsertStmt: INSERT INTO relation_name insert_rest
|
|
{
|
|
$$ = cat_str(3, make_str("insert into"), $3, $4);
|
|
}
|
|
;
|
|
|
|
insert_rest: VALUES '(' target_list ')'
|
|
{
|
|
$$ = cat_str(3, make_str("values("), $3, make_str(")"));
|
|
}
|
|
| DEFAULT VALUES
|
|
{
|
|
$$ = make_str("default values");
|
|
}
|
|
/* We want the full power of SelectStatements including INTERSECT and EXCEPT
|
|
* for insertion. However, we can't support sort or limit clauses.
|
|
*/
|
|
| SelectStmt
|
|
{
|
|
if (FoundSort != 0)
|
|
mmerror(ET_ERROR, "ORDER BY is not allowed in INSERT/SELECT");
|
|
|
|
$$ = $1;
|
|
}
|
|
| '(' columnList ')' VALUES '(' target_list ')'
|
|
{
|
|
$$ = cat_str(5, make_str("("), $2, make_str(") values ("), $6, make_str(")"));
|
|
}
|
|
| '(' columnList ')' SelectStmt
|
|
{
|
|
if (FoundSort != 0)
|
|
mmerror(ET_ERROR, "ORDER BY is not all owed in INSERT/SELECT");
|
|
|
|
$$ = cat_str(4, make_str("("), $2, make_str(")"), $4);
|
|
}
|
|
;
|
|
|
|
opt_column_list: '(' columnList ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
columnList:
|
|
columnList ',' columnElem
|
|
{ $$ = cat_str(3, $1, make_str(","), $3); }
|
|
| columnElem
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
columnElem: ColId opt_indirection
|
|
{
|
|
$$ = cat2_str($1, $2);
|
|
}
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* DELETE STATEMENTS
|
|
*
|
|
*****************************************************************************/
|
|
|
|
DeleteStmt: DELETE FROM relation_name
|
|
where_clause
|
|
{
|
|
$$ = cat_str(3, make_str("delete from"), $3, $4);
|
|
}
|
|
;
|
|
|
|
LockStmt: LOCK_P opt_table relation_name opt_lock
|
|
{
|
|
$$ = cat_str(4, make_str("lock"), $2, $3, $4);
|
|
}
|
|
;
|
|
|
|
opt_lock: IN lock_type MODE { $$ = cat_str(3, make_str("in"), $2, make_str("mode")); }
|
|
| /*EMPTY*/ { $$ = EMPTY;}
|
|
;
|
|
|
|
lock_type: SHARE ROW EXCLUSIVE { $$ = make_str("share row exclusive"); }
|
|
| ROW opt_lmode { $$ = cat2_str(make_str("row"), $2);}
|
|
| ACCESS opt_lmode { $$ = cat2_str(make_str("access"), $2);}
|
|
| opt_lmode { $$ = $1; }
|
|
;
|
|
|
|
opt_lmode: SHARE { $$ = make_str("share"); }
|
|
| EXCLUSIVE { $$ = make_str("exclusive"); }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* UpdateStmt (UPDATE)
|
|
*
|
|
*****************************************************************************/
|
|
|
|
UpdateStmt: UPDATE relation_name
|
|
SET update_target_list
|
|
from_clause
|
|
where_clause
|
|
{
|
|
$$ = cat_str(6, make_str("update"), $2, make_str("set"), $4, $5, $6);
|
|
}
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* CURSOR STATEMENTS
|
|
*
|
|
*****************************************************************************/
|
|
CursorStmt: DECLARE name opt_cursor CURSOR FOR
|
|
{ ForUpdateNotAllowed = 1; }
|
|
SelectStmt
|
|
{
|
|
struct cursor *ptr, *this;
|
|
|
|
for (ptr = cur; ptr != NULL; ptr = ptr->next)
|
|
{
|
|
if (strcmp($2, ptr->name) == 0)
|
|
{
|
|
/* re-definition is a bug */
|
|
sprintf(errortext, "cursor %s already defined", $2);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
}
|
|
|
|
this = (struct cursor *) mm_alloc(sizeof(struct cursor));
|
|
|
|
/* initial definition */
|
|
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"), $7);
|
|
this->argsinsert = argsinsert;
|
|
this->argsresult = argsresult;
|
|
argsinsert = argsresult = NULL;
|
|
|
|
cur = this;
|
|
|
|
$$ = 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; }
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* SELECT STATEMENTS
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* The new 'SelectStmt' rule adapted for the optional use of INTERSECT EXCEPT a nd UNION
|
|
* accepts the use of '(' and ')' to select an order of set operations.
|
|
* The rule returns a SelectStmt Node having the set operations attached to
|
|
* unionClause and intersectClause (NIL if no set operations were present)
|
|
*/
|
|
|
|
SelectStmt: select_clause
|
|
{ FoundSort = 0; }
|
|
sort_clause for_update_clause opt_select_limit
|
|
{
|
|
if (strlen($4) > 0 && ForUpdateNotAllowed != 0)
|
|
mmerror(ET_ERROR, "FOR UPDATE is not allowed in this context");
|
|
|
|
ForUpdateNotAllowed = 0;
|
|
$$ = cat_str(4, $1, $3, $4, $5);
|
|
}
|
|
|
|
/* This rule parses Select statements including UNION INTERSECT and EXCEPT.
|
|
* '(' and ')' can be used to specify the order of the operations
|
|
* (UNION EXCEPT INTERSECT). Without the use of '(' and ')' we want the
|
|
* operations to be left associative.
|
|
*
|
|
* The sort_clause is not handled here!
|
|
*/
|
|
select_clause: '(' select_clause ')'
|
|
{
|
|
$$ = cat_str(3, make_str("("), $2, make_str(")"));
|
|
}
|
|
| SubSelect
|
|
{
|
|
FoundInto = 0;
|
|
$$ = $1;
|
|
}
|
|
| select_clause EXCEPT select_clause
|
|
{
|
|
$$ = cat_str(3, $1, make_str("except"), $3);
|
|
ForUpdateNotAllowed = 1;
|
|
}
|
|
| select_clause UNION opt_all select_clause
|
|
{
|
|
$$ = cat_str(4, $1, make_str("union"), $3, $4);
|
|
ForUpdateNotAllowed = 1;
|
|
}
|
|
| select_clause INTERSECT opt_all select_clause
|
|
{
|
|
$$ = cat_str(3, $1, make_str("intersect"), $3);
|
|
ForUpdateNotAllowed = 1;
|
|
}
|
|
;
|
|
|
|
SubSelect: SELECT opt_distinct target_list
|
|
result from_clause where_clause
|
|
group_clause having_clause
|
|
{
|
|
if (strlen($7) > 0 || strlen($8) > 0)
|
|
ForUpdateNotAllowed = 1;
|
|
$$ = cat_str(8, make_str("select"), $2, $3, $4, $5, $6, $7, $8);
|
|
}
|
|
;
|
|
|
|
result: INTO OptTempTableName {
|
|
FoundInto = 1;
|
|
$$= cat2_str(make_str("into"), $2);
|
|
}
|
|
| INTO into_list { $$ = EMPTY; }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
/*
|
|
* Redundancy here is needed to avoid shift/reduce conflicts,
|
|
* since TEMP is not a reserved word. See also OptTemp.
|
|
*
|
|
* The result is a cons cell (not a true list!) containing
|
|
* a boolean and a table name.
|
|
*/
|
|
OptTempTableName: TEMPORARY opt_table relation_name
|
|
{
|
|
$$ = cat_str(3, make_str("temporary"), $2, $3);
|
|
}
|
|
| TEMP opt_table relation_name
|
|
{
|
|
$$ = cat_str(3, make_str("temp"), $2, $3);
|
|
}
|
|
| LOCAL TEMPORARY opt_table relation_name
|
|
{
|
|
$$ = cat_str(3, make_str("local temporary"), $3, $4);
|
|
}
|
|
| LOCAL TEMP opt_table relation_name
|
|
{
|
|
$$ = cat_str(3, make_str("local temp"), $3, $4);
|
|
}
|
|
| GLOBAL TEMPORARY opt_table relation_name
|
|
{
|
|
mmerror(ET_ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
|
|
$$ = cat_str(3, make_str("global temporary"), $3, $4);
|
|
}
|
|
| GLOBAL TEMP opt_table relation_name
|
|
{
|
|
mmerror(ET_ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
|
|
$$ = cat_str(3, make_str("global temp"), $3, $4);
|
|
}
|
|
| TABLE relation_name
|
|
{
|
|
$$ = cat2_str(make_str("table"), $2);
|
|
}
|
|
| relation_name
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
opt_table: TABLE { $$ = make_str("table"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
opt_all: ALL { $$ = make_str("all"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
opt_distinct: DISTINCT { $$ = make_str("distinct"); }
|
|
| DISTINCT ON '(' expr_list ')' { $$ = cat_str(3, make_str("distinct on ("), $4, make_str(")")); }
|
|
| ALL { $$ = make_str("all"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
sort_clause: ORDER BY sortby_list {
|
|
FoundSort = 1;
|
|
$$ = cat2_str(make_str("order by"), $3);
|
|
}
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
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; }
|
|
;
|
|
|
|
opt_select_limit: LIMIT select_limit_value ',' select_offset_value
|
|
{ $$ = cat_str(4, make_str("limit"), $2, make_str(","), $4); }
|
|
| LIMIT select_limit_value OFFSET select_offset_value
|
|
{ $$ = cat_str(4, make_str("limit"), $2, make_str("offset"), $4); }
|
|
| LIMIT select_limit_value
|
|
{ $$ = cat2_str(make_str("limit"), $2); }
|
|
| OFFSET select_offset_value LIMIT select_limit_value
|
|
{ $$ = cat_str(4, make_str("offset"), $2, make_str("limit"), $4); }
|
|
| OFFSET select_offset_value
|
|
{ $$ = cat2_str(make_str("offset"), $2); }
|
|
| /* EMPTY */
|
|
{ $$ = EMPTY; }
|
|
;
|
|
|
|
select_limit_value: Iconst { $$ = $1; }
|
|
| ALL { $$ = make_str("all"); }
|
|
| PARAM { $$ = make_name(); }
|
|
;
|
|
|
|
select_offset_value: Iconst { $$ = $1; }
|
|
| PARAM { $$ = make_name(); }
|
|
;
|
|
|
|
/*
|
|
* jimmy bell-style recursive queries aren't supported in the
|
|
* current system.
|
|
*
|
|
* ...however, recursive addattr and rename supported. make special
|
|
* cases for these.
|
|
*/
|
|
opt_inh_star: '*' { $$ = make_str("*"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
relation_name_list: name_list { $$ = $1; };
|
|
|
|
name_list: name
|
|
{ $$ = $1; }
|
|
| name_list ',' name
|
|
{ $$ = cat_str(3, $1, make_str(","), $3); }
|
|
;
|
|
|
|
group_clause: GROUP BY expr_list { $$ = cat2_str(make_str("group by"), $3); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
having_clause: HAVING a_expr
|
|
{
|
|
$$ = cat2_str(make_str("having"), $2);
|
|
}
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
for_update_clause: FOR UPDATE update_list
|
|
{
|
|
$$ = make_str("for update");
|
|
}
|
|
| FOR READ ONLY
|
|
{
|
|
$$ = make_str("for read only");
|
|
}
|
|
| /* EMPTY */
|
|
{
|
|
$$ = EMPTY;
|
|
}
|
|
;
|
|
update_list: OF va_list
|
|
{
|
|
$$ = cat2_str(make_str("of"), $2);
|
|
}
|
|
| /* EMPTY */
|
|
{
|
|
$$ = EMPTY;
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* clauses common to all Optimizable Stmts:
|
|
* from_clause - allow list of both JOIN expressions and table names
|
|
* where_clause - qualifications for joins or restrictions
|
|
*
|
|
*****************************************************************************/
|
|
|
|
from_clause: FROM from_list { $$ = cat2_str(make_str("from"), $2); }
|
|
/***
|
|
#ifdef ENABLE_ORACLE_JOIN_SYNTAX
|
|
| FROM oracle_list { $$ = cat2_str(make_str("from"), $2); }
|
|
#endif
|
|
***/
|
|
| FROM from_expr { $$ = cat2_str(make_str("from"), $2); }
|
|
| /* EMPTY */ { $$ = EMPTY; }
|
|
;
|
|
|
|
from_list: from_list ',' table_expr { $$ = cat_str(3, $1, make_str(","), $3); }
|
|
| table_expr { $$ = $1; }
|
|
;
|
|
|
|
/***********
|
|
* This results in one shift/reduce conflict, presumably due to the trailing "(
|
|
* - Thomas 1999-09-20
|
|
*
|
|
#ifdef ENABLE_ORACLE_JOIN_SYNTAX
|
|
oracle_list: oracle_expr { $$ = $1; }
|
|
;
|
|
|
|
oracle_expr: ColId ',' ColId oracle_outer
|
|
{
|
|
mmerror(ET_ERROR, "Oracle OUTER JOIN not yet supported");
|
|
$$ = cat_str(3, $1, make_str(","), $3); }
|
|
}
|
|
| oracle_outer ColId ',' ColId
|
|
{
|
|
mmerror(ET_ERROR, "Oracle OUTER JOIN not yet supported");
|
|
$$ = cat_str(4, $1, $2, make_str(","), $3); }
|
|
}
|
|
;
|
|
|
|
oracle_outer: '(' '+' ')' { $$ = make_str("(+)"); }
|
|
;
|
|
#endif
|
|
*************/
|
|
|
|
from_expr: '(' join_clause_with_union ')' alias_clause
|
|
{ $$ = cat_str(4, make_str("("), $2, make_str(")"), $4); }
|
|
| join_clause
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
table_expr: relation_expr alias_clause
|
|
{
|
|
$$ = cat2_str($1, $2);
|
|
}
|
|
;
|
|
|
|
alias_clause: AS ColId '(' name_list ')'
|
|
{ $$ = cat_str(5, make_str("as"), $2, make_str("("), $4, make_str(")")); }
|
|
| AS ColId
|
|
{ $$ = cat2_str(make_str("as"), $2); }
|
|
| ColId '(' name_list ')'
|
|
{ $$ = cat_str(4, $1, make_str("("), $3, make_str(")")); }
|
|
| ColId
|
|
{ $$ = $1; }
|
|
| /*EMPTY*/
|
|
{ $$ = EMPTY; }
|
|
;
|
|
|
|
/* A UNION JOIN is the same as a FULL OUTER JOIN which *omits*
|
|
* all result rows which would have matched on an INNER JOIN.
|
|
* Syntactically, must enclose the UNION JOIN in parens to avoid
|
|
* conflicts with SELECT/UNION.
|
|
*/
|
|
join_clause: join_clause join_expr
|
|
{ $$ = cat2_str($1, $2); }
|
|
| table_expr join_expr
|
|
{ $$ = cat2_str($1, $2); }
|
|
;
|
|
|
|
/* This is everything but the left side of a join.
|
|
* Note that a CROSS JOIN is the same as an unqualified
|
|
* inner join, so just pass back the right-side table.
|
|
* A NATURAL JOIN implicitly matches column names between
|
|
* tables, and the shape is determined by which columns are
|
|
* in common. We'll collect columns during the later transformations.
|
|
*/
|
|
join_expr: join_type JOIN table_expr join_qual
|
|
{
|
|
$$ = cat_str(4, $1, make_str("join"), $3, $4);
|
|
}
|
|
| NATURAL join_type JOIN table_expr
|
|
{
|
|
$$ = cat_str(4, make_str("natural"), $2, make_str("join"), $4);
|
|
}
|
|
| CROSS JOIN table_expr
|
|
{ $$ = cat2_str(make_str("cross join"), $3); }
|
|
;
|
|
|
|
join_clause_with_union: join_clause_with_union join_expr_with_union
|
|
{ $$ = cat2_str($1, $2); }
|
|
| table_expr join_expr_with_union
|
|
{ $$ = cat2_str($1, $2); }
|
|
;
|
|
|
|
join_expr_with_union: join_expr
|
|
{ $$ = $1; }
|
|
| UNION JOIN table_expr
|
|
{ $$ = cat2_str(make_str("union join"), $3); }
|
|
;
|
|
|
|
/* OUTER is just noise... */
|
|
join_type: FULL join_outer { $$ = cat2_str(make_str("full"), $2); }
|
|
| LEFT join_outer { $$ = cat2_str(make_str("left"), $2); }
|
|
| RIGHT join_outer { $$ = cat2_str(make_str("right"), $2); }
|
|
| OUTER_P { $$ = make_str("outer"); }
|
|
| INNER_P { $$ = make_str("inner"); }
|
|
| /* EMPTY */ { $$ = EMPTY; }
|
|
;
|
|
|
|
join_outer: OUTER_P { $$ = make_str("outer"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; /* no qualifiers */ }
|
|
;
|
|
|
|
/* JOIN qualification clauses
|
|
* Possibilities are:
|
|
* USING ( column list ) allows only unqualified column names,
|
|
* which must match between tables.
|
|
* ON expr allows more general qualifications.
|
|
* - thomas 1999-01-07
|
|
*/
|
|
|
|
join_qual: USING '(' using_list ')' { $$ = cat_str(3, make_str("using ("), $3, make_str(")")); }
|
|
| ON a_expr { $$ = cat2_str(make_str("on"), $2); }
|
|
;
|
|
|
|
using_list: using_list ',' using_expr { $$ = cat_str(3, $1, make_str(","), $3); }
|
|
| using_expr { $$ = $1; }
|
|
;
|
|
|
|
using_expr: ColId
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
where_clause: WHERE a_expr { $$ = cat2_str(make_str("where"), $2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; /* no qualifiers */ }
|
|
;
|
|
|
|
relation_expr: relation_name
|
|
{
|
|
/* normal relations */
|
|
$$ = $1;
|
|
}
|
|
| relation_name '*' %prec '='
|
|
{
|
|
/* inheritance query */
|
|
$$ = cat2_str($1, make_str("*"));
|
|
}
|
|
|
|
opt_array_bounds: '[' ']' opt_array_bounds
|
|
{
|
|
$$.index1 = 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;
|
|
$$.index2 = $4.index1;
|
|
$$.str = cat_str(4, make_str("["), txt, make_str("]"), $4.str);
|
|
}
|
|
| /* EMPTY */
|
|
{
|
|
$$.index1 = -1;
|
|
$$.index2 = -1;
|
|
$$.str= EMPTY;
|
|
}
|
|
;
|
|
|
|
Iresult: Iconst { $$ = atol($1); }
|
|
| '(' Iresult ')' { $$ = $2; }
|
|
| Iresult '+' Iresult { $$ = $1 + $3; }
|
|
| Iresult '-' Iresult { $$ = $1 - $3; }
|
|
| Iresult '*' Iresult { $$ = $1 * $3; }
|
|
| Iresult '/' Iresult { $$ = $1 / $3; }
|
|
| Iresult '%' Iresult { $$ = $1 % $3; }
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Type syntax
|
|
* SQL92 introduces a large amount of type-specific syntax.
|
|
* Define individual clauses to handle these cases, and use
|
|
* the generic case to handle regular type-extensible Postgres syntax.
|
|
* - thomas 1997-10-10
|
|
*
|
|
*****************************************************************************/
|
|
|
|
Typename: SimpleTypename opt_array_bounds
|
|
{
|
|
$$ = cat2_str($1, $2.str);
|
|
}
|
|
| SETOF SimpleTypename
|
|
{
|
|
$$ = cat2_str(make_str("setof"), $2);
|
|
}
|
|
;
|
|
|
|
SimpleTypename: Generic { $$ = $1; }
|
|
| Datetime { $$ = $1; }
|
|
| Numeric { $$ = $1; }
|
|
| Character { $$ = $1; }
|
|
;
|
|
|
|
Generic: generic
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
generic: ident { $$ = $1; }
|
|
| TYPE_P { $$ = make_str("type"); }
|
|
| SQL_AT { $$ = make_str("at"); }
|
|
| SQL_AUTOCOMMIT { $$ = make_str("autocommit"); }
|
|
| SQL_BOOL { $$ = make_str("bool"); }
|
|
| SQL_BREAK { $$ = make_str("break"); }
|
|
| SQL_CALL { $$ = make_str("call"); }
|
|
| SQL_CONNECT { $$ = make_str("connect"); }
|
|
| SQL_CONNECTION { $$ = make_str("connection"); }
|
|
| SQL_CONTINUE { $$ = make_str("continue"); }
|
|
| SQL_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_INT { $$ = make_str("int"); }
|
|
| SQL_KEY_MEMBER { $$ = make_str("key_member"); }
|
|
| SQL_LENGTH { $$ = make_str("length"); }
|
|
| SQL_LONG { $$ = make_str("long"); }
|
|
| SQL_NAME { $$ = make_str("name"); }
|
|
| SQL_NULLABLE { $$ = make_str("nullable"); }
|
|
| SQL_OCTET_LENGTH { $$ = make_str("octet_length"); }
|
|
| SQL_OFF { $$ = make_str("off"); }
|
|
| SQL_OPEN { $$ = make_str("open"); }
|
|
| SQL_PREPARE { $$ = make_str("prepare"); }
|
|
| SQL_RELEASE { $$ = make_str("release"); }
|
|
| 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_SHORT { $$ = make_str("short"); }
|
|
| SQL_SIGNED { $$ = make_str("signed"); }
|
|
| SQL_SQLERROR { $$ = make_str("sqlerror"); }
|
|
| SQL_SQLPRINT { $$ = make_str("sqlprint"); }
|
|
| SQL_SQLWARNING { $$ = make_str("sqlwarning"); }
|
|
| SQL_STOP { $$ = make_str("stop"); }
|
|
| SQL_STRUCT { $$ = make_str("struct"); }
|
|
| SQL_UNSIGNED { $$ = make_str("unsigned"); }
|
|
| SQL_VAR { $$ = make_str("var"); }
|
|
| SQL_WHENEVER { $$ = make_str("whenever"); }
|
|
;
|
|
|
|
/* SQL92 numeric data types
|
|
* Check FLOAT() precision limits assuming IEEE floating types.
|
|
* Provide real DECIMAL() and NUMERIC() implementations now - Jan 1998-12-30
|
|
* - thomas 1997-09-18
|
|
*/
|
|
Numeric: FLOAT opt_float
|
|
{
|
|
$$ = cat2_str(make_str("float"), $2);
|
|
}
|
|
| DOUBLE PRECISION
|
|
{
|
|
$$ = make_str("double precision");
|
|
}
|
|
| DECIMAL opt_decimal
|
|
{
|
|
$$ = cat2_str(make_str("decimal"), $2);
|
|
}
|
|
| DEC opt_decimal
|
|
{
|
|
$$ = cat2_str(make_str("dec"), $2);
|
|
}
|
|
| NUMERIC opt_numeric
|
|
{
|
|
$$ = cat2_str(make_str("numeric"), $2);
|
|
}
|
|
;
|
|
|
|
numeric: FLOAT
|
|
{ $$ = make_str("float"); }
|
|
| DOUBLE PRECISION
|
|
{ $$ = make_str("double precision"); }
|
|
| DECIMAL
|
|
{ $$ = make_str("decimal"); }
|
|
| NUMERIC
|
|
{ $$ = make_str("numeric"); }
|
|
;
|
|
|
|
opt_float: '(' Iconst ')'
|
|
{
|
|
if (atol($2) < 1)
|
|
mmerror(ET_ERROR, "precision for FLOAT must be at least 1");
|
|
else if (atol($2) >= 16)
|
|
mmerror(ET_ERROR, "precision for FLOAT must be less than 16");
|
|
$$ = cat_str(3, make_str("("), $2, make_str(")"));
|
|
}
|
|
| /*EMPTY*/
|
|
{
|
|
$$ = EMPTY;
|
|
}
|
|
;
|
|
|
|
opt_numeric: '(' Iconst ',' Iconst ')'
|
|
{
|
|
if (atol($2) < 1 || atol($2) > NUMERIC_MAX_PRECISION) {
|
|
sprintf(errortext, "NUMERIC precision %s must be between 1 and %d", $2, NUMERIC_MAX_PRECISION);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
if (atol($4) < 0 || atol($4) > atol($2)) {
|
|
sprintf(errortext, "NUMERIC scale %s must be between 0 and precision %s", $4, $2);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
$$ = cat_str(5, make_str("("), $2, make_str(","), $4, make_str(")"));
|
|
}
|
|
| '(' Iconst ')'
|
|
{
|
|
if (atol($2) < 1 || atol($2) > NUMERIC_MAX_PRECISION) {
|
|
sprintf(errortext, "NUMERIC precision %s must be between 1 and %d", $2, NUMERIC_MAX_PRECISION);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
$$ = cat_str(3, make_str("("), $2, make_str(")"));
|
|
}
|
|
| /*EMPTY*/
|
|
{
|
|
$$ = EMPTY;
|
|
}
|
|
;
|
|
|
|
opt_decimal: '(' Iconst ',' Iconst ')'
|
|
{
|
|
if (atol($2) < 1 || atol($2) > NUMERIC_MAX_PRECISION) {
|
|
sprintf(errortext, "NUMERIC precision %s must be between 1 and %d", $2, NUMERIC_MAX_PRECISION);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
if (atol($4) < 0 || atol($4) > atol($2)) {
|
|
sprintf(errortext, "NUMERIC scale %s must be between 0 and precision %s", $4, $2);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
$$ = cat_str(5, make_str("("), $2, make_str(","), $4, make_str(")"));
|
|
}
|
|
| '(' Iconst ')'
|
|
{
|
|
if (atol($2) < 1 || atol($2) > NUMERIC_MAX_PRECISION) {
|
|
sprintf(errortext, "NUMERIC precision %s must be between 1 and %d", $2, NUMERIC_MAX_PRECISION);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
$$ = cat_str(3, make_str("("), $2, make_str(")"));
|
|
}
|
|
| /*EMPTY*/
|
|
{
|
|
$$ = EMPTY;
|
|
}
|
|
;
|
|
|
|
/*
|
|
* SQL92 character data types
|
|
* The following implements CHAR() and VARCHAR().
|
|
* - ay 6/95
|
|
*/
|
|
Character: character '(' Iconst ')'
|
|
{
|
|
if (atol($3) < 1)
|
|
{
|
|
sprintf(errortext, "length for type '%s' type must be at least 1",$1);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
else if (atol($3) > MaxAttrSize)
|
|
{
|
|
sprintf(errortext, "length for type '%s' cannot exceed %ld", $1, MaxAttrSize);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
|
|
$$ = cat_str(4, $1, make_str("("), $3, make_str(")"));
|
|
}
|
|
| character
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
character: CHARACTER opt_varying opt_charset
|
|
{
|
|
$$ = cat_str(3, make_str("character"), $2, $3);
|
|
}
|
|
| CHAR opt_varying { $$ = cat2_str(make_str("char"), $2); }
|
|
| VARCHAR { $$ = make_str("varchar"); }
|
|
| NATIONAL CHARACTER opt_varying { $$ = cat2_str(make_str("national character"), $3); }
|
|
| NATIONAL CHAR opt_varying { $$ = cat2_str(make_str("national char"), $3); }
|
|
| NCHAR opt_varying { $$ = cat2_str(make_str("nchar"), $2); }
|
|
;
|
|
|
|
opt_varying: VARYING { $$ = make_str("varying"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
opt_charset: CHARACTER SET ColId { $$ = cat2_str(make_str("character set"), $3); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
opt_collate: COLLATE ColId { $$ = cat2_str(make_str("collate"), $2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
Datetime: datetime
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| TIMESTAMP opt_timezone
|
|
{
|
|
$$ = cat2_str(make_str("timestamp"), $2);
|
|
}
|
|
| TIME opt_timezone
|
|
{
|
|
$$ = cat2_str(make_str("time"), $2);
|
|
}
|
|
| INTERVAL opt_interval
|
|
{
|
|
$$ = cat2_str(make_str("interval"), $2);
|
|
}
|
|
;
|
|
|
|
datetime: YEAR_P { $$ = make_str("year"); }
|
|
| MONTH_P { $$ = make_str("month"); }
|
|
| DAY_P { $$ = make_str("day"); }
|
|
| HOUR_P { $$ = make_str("hour"); }
|
|
| MINUTE_P { $$ = make_str("minute"); }
|
|
| SECOND_P { $$ = make_str("second"); }
|
|
;
|
|
|
|
opt_timezone: WITH TIME ZONE { $$ = make_str("with time zone"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
opt_interval: datetime { $$ = $1; }
|
|
| YEAR_P TO MONTH_P { $$ = make_str("year to #month"); }
|
|
| DAY_P TO HOUR_P { $$ = make_str("day to hour"); }
|
|
| DAY_P TO MINUTE_P { $$ = make_str("day to minute"); }
|
|
| DAY_P TO SECOND_P { $$ = make_str("day to second"); }
|
|
| HOUR_P TO MINUTE_P { $$ = make_str("hour to minute"); }
|
|
| MINUTE_P TO SECOND_P { $$ = make_str("minute to second"); }
|
|
| HOUR_P TO SECOND_P { $$ = make_str("hour to second"); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* expression grammar
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* Expressions using row descriptors
|
|
* Define row_descriptor to allow yacc to break the reduce/reduce conflict
|
|
* with singleton expressions.
|
|
*/
|
|
row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
|
|
{
|
|
$$ = cat_str(5, make_str("("), $2, make_str(") in ("), $6, make_str(")"));
|
|
}
|
|
| '(' row_descriptor ')' NOT IN '(' SubSelect ')'
|
|
{
|
|
$$ = cat_str(5, make_str("("), $2, make_str(") not in ("), $7, make_str(")"));
|
|
}
|
|
| '(' row_descriptor ')' all_Op sub_type '(' SubSelect ')'
|
|
{
|
|
$$ = cat_str(8, make_str("("), $2, make_str(")"), $4, $5, make_str("("), $7, make_str(")"));
|
|
}
|
|
| '(' row_descriptor ')' all_Op '(' SubSelect ')'
|
|
{
|
|
$$ = cat_str(7, make_str("("), $2, make_str(")"), $4, make_str("("), $6, make_str(")"));
|
|
}
|
|
| '(' 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"); }
|
|
| 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(">"); }
|
|
| '=' { $$ = make_str("="); }
|
|
;
|
|
|
|
/* General expressions
|
|
* This is the heart of the expression syntax.
|
|
*
|
|
* We have two expression types: a_expr is the unrestricted kind, and
|
|
* b_expr is a subset that must be used in some places to avoid shift/reduce
|
|
* conflicts. For example, we can't do BETWEEN as "BETWEEN a_expr AND a_expr"
|
|
* because that use of AND conflicts with AND as a boolean operator. So,
|
|
* b_expr is used in BETWEEN and we remove boolean keywords from b_expr.
|
|
*
|
|
* Note that '(' a_expr ')' is a b_expr, so an unrestricted expression can
|
|
* always be used by surrounding it with parens.
|
|
*
|
|
* c_expr is all the productions that are common to a_expr and b_expr;
|
|
* it's factored out just to eliminate redundant coding.
|
|
*/
|
|
|
|
a_expr: c_expr
|
|
{ $$ = $1; }
|
|
| a_expr TYPECAST Typename
|
|
{ $$ = cat_str(3, $1, make_str("::"), $3); }
|
|
/*
|
|
* These operators must be called out explicitly in order to make use
|
|
* of yacc/bison's automatic operator-precedence handling. All other
|
|
* operator names are handled by the generic productions using "Op",
|
|
* below; and all those operators will have the same precedence.
|
|
*
|
|
* If you add more explicitly-known operators, be sure to add them
|
|
* also to b_expr and to the MathOp list above.
|
|
*/
|
|
| '-' a_expr %prec UMINUS
|
|
{ $$ = cat2_str(make_str("-"), $2); }
|
|
| '%' a_expr
|
|
{ $$ = cat2_str(make_str("%"), $2); }
|
|
| '^' a_expr
|
|
{ $$ = cat2_str(make_str("^"), $2); }
|
|
| '|' a_expr
|
|
{ $$ = cat2_str(make_str("|"), $2); }
|
|
/* not possible in embedded sql | ':' a_expr
|
|
{ $$ = cat2_str(make_str(":"), $2); }
|
|
*/
|
|
| ';' a_expr
|
|
{ $$ = cat2_str(make_str(";"), $2); }
|
|
| a_expr '%'
|
|
{ $$ = cat2_str($1, make_str("%")); }
|
|
| 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
|
|
{ $$ = cat_str(3, $1, make_str("-"), $3); }
|
|
| a_expr '*' a_expr
|
|
{ $$ = cat_str(3, $1, make_str("*"), $3); }
|
|
| a_expr '/' a_expr
|
|
{ $$ = cat_str(3, $1, make_str("/"), $3); }
|
|
| a_expr '%' a_expr
|
|
{ $$ = cat_str(3, $1, make_str("%"), $3); }
|
|
| a_expr '^' a_expr
|
|
{ $$ = cat_str(3, $1, make_str("^"), $3); }
|
|
| a_expr '|' a_expr
|
|
{ $$ = cat_str(3, $1, make_str("|"), $3); }
|
|
| a_expr '<' a_expr
|
|
{ $$ = cat_str(3, $1, make_str("<"), $3); }
|
|
| a_expr '>' a_expr
|
|
{ $$ = cat_str(3, $1, make_str(">"), $3); }
|
|
| a_expr '=' a_expr
|
|
{ $$ = cat_str(3, $1, make_str("="), $3); }
|
|
| a_expr Op a_expr
|
|
{ $$ = cat_str(3, $1, $2, $3); }
|
|
| Op a_expr
|
|
{ $$ = cat2_str($1, $2); }
|
|
| a_expr Op
|
|
{ $$ = cat2_str($1, $2); }
|
|
| a_expr AND a_expr
|
|
{ $$ = cat_str(3, $1, make_str("and"), $3); }
|
|
| a_expr OR a_expr
|
|
{ $$ = cat_str(3, $1, make_str("or"), $3); }
|
|
| NOT a_expr
|
|
{ $$ = cat2_str(make_str("not"), $2); }
|
|
| a_expr LIKE a_expr
|
|
{ $$ = cat_str(3, $1, make_str("like"), $3); }
|
|
| a_expr NOT LIKE a_expr
|
|
{ $$ = cat_str(3, $1, make_str("not like"), $4); }
|
|
| a_expr ISNULL
|
|
{ $$ = cat2_str($1, make_str("isnull")); }
|
|
| a_expr IS NULL_P
|
|
{ $$ = cat2_str($1, make_str("is null")); }
|
|
| a_expr NOTNULL
|
|
{ $$ = cat2_str($1, make_str("notnull")); }
|
|
| a_expr IS NOT NULL_P
|
|
{ $$ = cat2_str($1, make_str("is not null")); }
|
|
/* IS TRUE, IS FALSE, etc used to be function calls
|
|
* but let's make them expressions to allow the optimizer
|
|
* a chance to eliminate them if a_expr is a constant string.
|
|
* - thomas 1997-12-22
|
|
*/
|
|
| a_expr IS TRUE_P
|
|
{ $$ = cat2_str($1, make_str("is true")); }
|
|
| a_expr IS NOT FALSE_P
|
|
{ $$ = cat2_str($1, make_str("is not false")); }
|
|
| a_expr IS FALSE_P
|
|
{ $$ = cat2_str($1, make_str("is false")); }
|
|
| a_expr IS NOT TRUE_P
|
|
{ $$ = cat2_str($1, make_str("is not true")); }
|
|
| a_expr BETWEEN b_expr AND b_expr
|
|
{
|
|
$$ = cat_str(5, $1, make_str("between"), $3, make_str("and"), $5);
|
|
}
|
|
| a_expr NOT BETWEEN b_expr AND b_expr
|
|
{
|
|
$$ = cat_str(5, $1, make_str("not between"), $4, make_str("and"), $6);
|
|
}
|
|
| a_expr IN '(' in_expr ')'
|
|
{
|
|
$$ = cat_str(4, $1, make_str(" in ("), $4, make_str(")"));
|
|
}
|
|
| a_expr NOT IN '(' in_expr ')'
|
|
{
|
|
$$ = cat_str(4, $1, make_str(" not in ("), $5, make_str(")"));
|
|
}
|
|
| a_expr all_Op sub_type '(' SubSelect ')'
|
|
{
|
|
$$ = cat_str(6, $1, $2, $3, make_str("("), $5, make_str(")"));
|
|
}
|
|
| row_expr
|
|
{ $$ = $1; }
|
|
| cinputvariable
|
|
{ $$ = make_str("?"); }
|
|
;
|
|
|
|
/* Restricted expressions
|
|
*
|
|
* b_expr is a subset of the complete expression syntax
|
|
*
|
|
* Presently, AND, NOT, IS and IN are the a_expr keywords that would
|
|
* cause trouble in the places where b_expr is used. For simplicity, we
|
|
* just eliminate all the boolean-keyword-operator productions from b_expr.
|
|
*/
|
|
b_expr: c_expr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| b_expr TYPECAST Typename
|
|
{
|
|
$$ = 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(make_str("|"), $2); }
|
|
/* not possible in embedded sql | ':' b_expr
|
|
{ $$ = cat2_str(make_str(":"), $2); }
|
|
*/
|
|
| ';' b_expr
|
|
{ $$ = cat2_str(make_str(";"), $2); }
|
|
| b_expr '%'
|
|
{ $$ = cat2_str($1, make_str("%")); }
|
|
| 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
|
|
{ $$ = cat_str(3, $1, make_str("-"), $3); }
|
|
| b_expr '*' b_expr
|
|
{ $$ = cat_str(3, $1, make_str("*"), $3); }
|
|
| b_expr '/' b_expr
|
|
{ $$ = cat_str(3, $1, make_str("/"), $3); }
|
|
| b_expr '%' b_expr
|
|
{ $$ = cat_str(3, $1, make_str("%"), $3); }
|
|
| b_expr '^' b_expr
|
|
{ $$ = cat_str(3, $1, make_str("^"), $3); }
|
|
| b_expr '|' b_expr
|
|
{ $$ = cat_str(3, $1, make_str("|"), $3); }
|
|
| b_expr '<' b_expr
|
|
{ $$ = cat_str(3, $1, make_str("<"), $3); }
|
|
| b_expr '>' b_expr
|
|
{ $$ = cat_str(3, $1, make_str(">"), $3); }
|
|
| b_expr '=' b_expr
|
|
{ $$ = cat_str(3, $1, make_str("="), $3); }
|
|
| b_expr Op b_expr
|
|
{ $$ = cat_str(3, $1, $2, $3); }
|
|
| Op b_expr
|
|
{ $$ = cat2_str($1, $2); }
|
|
| b_expr Op
|
|
{ $$ = cat2_str($1, $2); }
|
|
| civariableonly
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
/*
|
|
* Productions that can be used in both a_expr and b_expr.
|
|
*
|
|
* Note: productions that refer recursively to a_expr or b_expr mostly
|
|
* cannot appear here. However, it's OK to refer to a_exprs that occur
|
|
* inside parentheses, such as function arguments; that cannot introduce
|
|
* ambiguity to the b_expr syntax.
|
|
*/
|
|
c_expr: attr
|
|
{ $$ = $1; }
|
|
| ColId opt_indirection
|
|
{ $$ = cat2_str($1, $2); }
|
|
| AexprConst
|
|
{ $$ = $1; }
|
|
| '(' a_expr ')'
|
|
{ $$ = cat_str(3, make_str("("), $2, make_str(")")); }
|
|
| CAST '(' a_expr AS Typename ')'
|
|
{ $$ = cat_str(5, make_str("cast("), $3, make_str("as"), $5, make_str(")")); }
|
|
| case_expr
|
|
{ $$ = $1; }
|
|
| func_name '(' ')'
|
|
{ $$ = cat2_str($1, make_str("()")); }
|
|
| func_name '(' expr_list ')'
|
|
{ $$ = cat_str(4, $1, make_str("("), $3, make_str(")")); }
|
|
| func_name '(' ALL expr_list ')'
|
|
{ $$ = cat_str(4, $1, make_str("( all"), $4, make_str(")")); }
|
|
| func_name '(' DISTINCT expr_list ')'
|
|
{ $$ = cat_str(4, $1, make_str("( distinct"), $4, make_str(")")); }
|
|
| func_name '(' '*' ')'
|
|
{ $$ = cat2_str($1, make_str("(*)")); }
|
|
| CURRENT_DATE
|
|
{ $$ = make_str("current_date"); }
|
|
| CURRENT_TIME
|
|
{ $$ = make_str("current_time"); }
|
|
| CURRENT_TIME '(' Iconst ')'
|
|
{
|
|
if (atol($3) != 0)
|
|
{
|
|
sprintf(errortext, "CURRENT_TIME(%s) precision not implemented; backend will use zero instead", $3);
|
|
mmerror(ET_WARN, errortext);
|
|
}
|
|
|
|
$$ = make_str("current_time");
|
|
}
|
|
| CURRENT_TIMESTAMP
|
|
{ $$ = make_str("current_timestamp"); }
|
|
| CURRENT_TIMESTAMP '(' Iconst ')'
|
|
{
|
|
if (atol($3) != 0)
|
|
{
|
|
sprintf(errortext, "CURRENT_TIMESTAMP(%s) precision not implemented; backend will use zero instead", $3);
|
|
mmerror(ET_WARN, errortext);
|
|
}
|
|
|
|
$$ = make_str("current_timestamp");
|
|
}
|
|
| CURRENT_USER
|
|
{ $$ = make_str("current_user"); }
|
|
| SESSION_USER
|
|
{ $$ = make_str("session_user"); }
|
|
| USER
|
|
{ $$ = make_str("user"); }
|
|
| EXTRACT '(' extract_list ')'
|
|
{ $$ = cat_str(3, make_str("extract("), $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(")")); }
|
|
/* 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(")")); }
|
|
| TRIM '(' LEADING trim_list ')'
|
|
{ $$ = cat_str(3, make_str("trim(leading"), $4, make_str(")")); }
|
|
| TRIM '(' TRAILING trim_list ')'
|
|
{ $$ = cat_str(3, make_str("trim(trailing"), $4, make_str(")")); }
|
|
| TRIM '(' trim_list ')'
|
|
{ $$ = cat_str(3, make_str("trim("), $3, make_str(")")); }
|
|
| '(' SubSelect ')'
|
|
{ $$ = cat_str(3, make_str("("), $2, make_str(")")); }
|
|
| EXISTS '(' SubSelect ')'
|
|
{ $$ = cat_str(3, make_str("exists("), $3, make_str(")")); }
|
|
;
|
|
/*
|
|
* This used to use ecpg_expr, but since there is no shift/reduce conflict
|
|
* anymore, we can remove ecpg_expr. - MM
|
|
*/
|
|
opt_indirection: '[' a_expr ']' opt_indirection
|
|
{
|
|
$$ = 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; }
|
|
;
|
|
|
|
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); }
|
|
;
|
|
|
|
extract_list: extract_arg FROM a_expr
|
|
{
|
|
$$ = cat_str(3, $1, make_str("from"), $3);
|
|
}
|
|
| /* EMPTY */
|
|
{ $$ = EMPTY; }
|
|
| cinputvariable
|
|
{ $$ = make_str("?"); }
|
|
;
|
|
|
|
extract_arg: datetime { $$ = $1; }
|
|
| TIMEZONE_HOUR { $$ = make_str("timezone_hour"); }
|
|
| TIMEZONE_MINUTE { $$ = make_str("timezone_minute"); }
|
|
;
|
|
|
|
/* position_list uses b_expr not a_expr to avoid conflict with general IN */
|
|
position_list: b_expr IN b_expr
|
|
{ $$ = cat_str(3, $1, make_str("in"), $3); }
|
|
| /* EMPTY */
|
|
{ $$ = EMPTY; }
|
|
;
|
|
|
|
substr_list: expr_list substr_from substr_for
|
|
{
|
|
$$ = cat_str(3, $1, $2, $3);
|
|
}
|
|
| /* EMPTY */
|
|
{ $$ = EMPTY; }
|
|
;
|
|
|
|
substr_from: FROM expr_list
|
|
{ $$ = cat2_str(make_str("from"), $2); }
|
|
| /* EMPTY */
|
|
{
|
|
$$ = EMPTY;
|
|
}
|
|
;
|
|
|
|
substr_for: FOR expr_list
|
|
{ $$ = cat2_str(make_str("for"), $2); }
|
|
| /* EMPTY */
|
|
{ $$ = EMPTY; }
|
|
;
|
|
|
|
trim_list: a_expr FROM expr_list
|
|
{ $$ = cat_str(3, $1, make_str("from"), $3); }
|
|
| FROM expr_list
|
|
{ $$ = cat2_str(make_str("from"), $2); }
|
|
| expr_list
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
in_expr: SubSelect
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| in_expr_nodes
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
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
|
|
{ $$ = 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(")"));
|
|
|
|
mmerror(ET_WARN, "NULLIF() not yet fully implemented");
|
|
}
|
|
| COALESCE '(' expr_list ')'
|
|
{
|
|
$$ = cat_str(3, make_str("coalesce("), $3, make_str(")"));
|
|
}
|
|
;
|
|
|
|
when_clause_list: when_clause_list when_clause
|
|
{ $$ = cat2_str($1, $2); }
|
|
| when_clause
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
when_clause: WHEN a_expr THEN a_expr
|
|
{
|
|
$$ = cat_str(4, make_str("when"), $2, make_str("then"), $4);
|
|
}
|
|
;
|
|
|
|
case_default: ELSE a_expr { $$ = cat2_str(make_str("else"), $2); }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
case_arg: a_expr {
|
|
$$ = $1;
|
|
}
|
|
| /*EMPTY*/
|
|
{ $$ = EMPTY; }
|
|
;
|
|
|
|
attr: relation_name '.' attrs opt_indirection
|
|
{
|
|
$$ = cat_str(4, $1, make_str("."), $3, $4);
|
|
}
|
|
| ParamNo '.' attrs opt_indirection
|
|
{
|
|
$$ = cat_str(4, $1, make_str("."), $3, $4);
|
|
}
|
|
;
|
|
|
|
attrs: attr_name
|
|
{ $$ = $1; }
|
|
| attrs '.' attr_name
|
|
{ $$ = cat_str(3, $1, make_str("."), $3); }
|
|
| attrs '.' '*'
|
|
{ $$ = make2_str($1, make_str(".*")); }
|
|
;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* target lists
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* 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);
|
|
}
|
|
| a_expr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| relation_name '.' '*'
|
|
{
|
|
$$ = make2_str($1, make_str(".*"));
|
|
}
|
|
| '*'
|
|
{
|
|
$$ = 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("*"); }
|
|
;
|
|
|
|
update_target_el: ColId opt_indirection '=' a_expr
|
|
{
|
|
$$ = cat_str(4, $1, $2, make_str("="), $4);
|
|
}
|
|
;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Names and constants
|
|
*
|
|
*****************************************************************************/
|
|
|
|
relation_name: SpecialRuleRelation
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| ColId
|
|
{
|
|
/* disallow refs to variable system tables */
|
|
if (strcmp(LogRelationName, $1) == 0
|
|
|| strcmp(VariableRelationName, $1) == 0) {
|
|
sprintf(errortext, make_str("%s cannot be accessed by users"),$1);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
else
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
database_name: ColId { $$ = $1; };
|
|
access_method: ident { $$ = $1; };
|
|
attr_name: ColId { $$ = $1; };
|
|
class: ident { $$ = $1; };
|
|
index_name: ColId { $$ = $1; };
|
|
|
|
/* Functions
|
|
* Include date/time keywords as SQL92 extension.
|
|
* Include TYPE as a SQL92 unreserved keyword. - thomas 1997-10-05
|
|
*/
|
|
name: ColId { $$ = $1; };
|
|
func_name: ColId { $$ = $1; };
|
|
|
|
file_name: Sconst { $$ = $1; };
|
|
/* NOT USED recipe_name: ident { $$ = $1; };*/
|
|
|
|
/* Constants
|
|
* Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
|
|
*/
|
|
AexprConst: Iconst
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| Fconst
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| Sconst
|
|
{
|
|
$$ = $1;
|
|
}
|
|
/* this rule formerly used Typename, but that causes reduce conf licts
|
|
* with subscripted column names ...
|
|
*/
|
|
| SimpleTypename Sconst
|
|
{
|
|
$$ = cat2_str($1, $2);
|
|
}
|
|
| ParamNo
|
|
{ $$ = $1; }
|
|
| TRUE_P
|
|
{
|
|
$$ = make_str("true");
|
|
}
|
|
| FALSE_P
|
|
{
|
|
$$ = make_str("false");
|
|
}
|
|
| NULL_P
|
|
{
|
|
$$ = make_str("null");
|
|
}
|
|
;
|
|
|
|
ParamNo: PARAM opt_indirection
|
|
{
|
|
$$ = cat2_str(make_name(), $2);
|
|
}
|
|
;
|
|
|
|
Iconst: ICONST { $$ = make_name();};
|
|
Fconst: FCONST { $$ = make_name();};
|
|
Sconst: SCONST {
|
|
$$ = (char *)mm_alloc(strlen($1) + 3);
|
|
$$[0]='\'';
|
|
strcpy($$+1, $1);
|
|
$$[strlen($1)+2]='\0';
|
|
$$[strlen($1)+1]='\'';
|
|
free($1);
|
|
}
|
|
UserId: ident { $$ = $1;};
|
|
|
|
/* Column and type identifier
|
|
* Does not include explicit datetime types
|
|
* since these must be decoupled in Typename syntax.
|
|
* Use ColId for most identifiers. - thomas 1997-10-21
|
|
*/
|
|
TypeId: ColId
|
|
{ $$ = $1; }
|
|
| numeric
|
|
{ $$ = $1; }
|
|
| character
|
|
{ $$ = $1; }
|
|
;
|
|
/* Column identifier
|
|
* Include date/time keywords as SQL92 extension.
|
|
* Include TYPE as a SQL92 unreserved keyword. - thomas 1997-10-05
|
|
* Add other keywords. Note that as the syntax expands,
|
|
* some of these keywords will have to be removed from this
|
|
* list due to shift/reduce conflicts in yacc. If so, move
|
|
* down to the ColLabel entity. - thomas 1997-11-06
|
|
*/
|
|
ColId: ECPGColId { $$ = $1; }
|
|
| ECPGTypeName { $$ = $1; }
|
|
;
|
|
|
|
/* Column label
|
|
* Allowed labels in "AS" clauses.
|
|
* Include TRUE/FALSE SQL3 reserved words for Postgres backward
|
|
* compatibility. Cannot allow this for column names since the
|
|
* syntax would not distinguish between the constant value and
|
|
* a column name. - thomas 1997-10-24
|
|
* Add other keywords to this list. Note that they appear here
|
|
* rather than in ColId if there was a shift/reduce conflict
|
|
* when used as a full identifier. - thomas 1997-11-06
|
|
*/
|
|
ColLabel: ECPGLabelTypeName { $$ = $1; }
|
|
| ECPGColLabel { $$ = $1; }
|
|
;
|
|
|
|
SpecialRuleRelation: CURRENT
|
|
{
|
|
if (QueryIsRule)
|
|
$$ = make_str("current");
|
|
else
|
|
mmerror(ET_ERROR, "CURRENT used in non-rule query");
|
|
}
|
|
| NEW
|
|
{
|
|
if (QueryIsRule)
|
|
$$ = make_str("new");
|
|
else
|
|
mmerror(ET_ERROR, "NEW used in non-rule query");
|
|
}
|
|
;
|
|
|
|
/*
|
|
* and now special embedded SQL stuff
|
|
*/
|
|
|
|
/*
|
|
* the exec sql connect statement: connect to the given database
|
|
*/
|
|
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\"");
|
|
}
|
|
/* also allow ORACLE syntax */
|
|
| SQL_CONNECT ora_user
|
|
{
|
|
$$ = cat_str(3, make_str("NULL,"), $2, make_str(",NULL"));
|
|
}
|
|
|
|
connection_target: database_name opt_server opt_port
|
|
{
|
|
/* old style: dbname[@server][:port] */
|
|
if (strlen($2) > 0 && *($2) != '@')
|
|
{
|
|
sprintf(errortext, "parse error at or near '%s'", $2);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
|
|
$$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\""));
|
|
}
|
|
| db_prefix server opt_port '/' database_name opt_options
|
|
{
|
|
/* new style: <tcp|unix>:postgresql://server[:port][/dbname] */
|
|
if (strncmp($2, "://", strlen("://")) != 0)
|
|
{
|
|
sprintf(errortext, "parse error at or near '%s'", $2);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
|
|
if (strncmp($1, "unix", strlen("unix")) == 0 && strncmp($2 + strlen("://"), "localhost", strlen("localhost")) != 0)
|
|
{
|
|
sprintf(errortext, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $2);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
|
|
if (strncmp($1, "unix", strlen("unix")) != 0 && strncmp($1, "tcp", strlen("tcp")) != 0)
|
|
{
|
|
sprintf(errortext, "only protocols 'tcp' and 'unix' are supported");
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
|
|
$$ = make2_str(make3_str(make_str("\""), $1, $2), make3_str(make3_str($3, make_str("/"), $5), $6, make_str("\"")));
|
|
}
|
|
| char_variable
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| Sconst
|
|
{
|
|
$$ = mm_strdup($1);
|
|
$$[0] = '\"';
|
|
$$[strlen($$) - 1] = '\"';
|
|
free($1);
|
|
}
|
|
|
|
db_prefix: ident cvariable
|
|
{
|
|
if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
|
|
{
|
|
sprintf(errortext, "parse error at or near '%s'", $2);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
|
|
if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0)
|
|
{
|
|
sprintf(errortext, "Illegal connection type %s", $1);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
|
|
$$ = make3_str( $1, make_str(":"), $2);
|
|
}
|
|
|
|
server: Op server_name
|
|
{
|
|
if (strcmp($1, "@") != 0 && strcmp($1, "://") != 0)
|
|
{
|
|
sprintf(errortext, "parse error at or near '%s'", $1);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
|
|
$$ = make2_str($1, $2);
|
|
}
|
|
|
|
opt_server: server { $$ = $1; }
|
|
| /* empty */ { $$ = EMPTY; }
|
|
|
|
server_name: ColId { $$ = $1; }
|
|
| ColId '.' server_name { $$ = make3_str($1, make_str("."), $3); }
|
|
|
|
opt_port: ':' Iconst { $$ = make2_str(make_str(":"), $2); }
|
|
| /* empty */ { $$ = EMPTY; }
|
|
|
|
opt_connection_name: AS connection_target { $$ = $2; }
|
|
| /* empty */ { $$ = make_str("NULL"); }
|
|
|
|
opt_user: USER ora_user { $$ = $2; }
|
|
| /* empty */ { $$ = make_str("NULL,NULL"); }
|
|
|
|
ora_user: user_name
|
|
{
|
|
$$ = cat2_str($1, make_str(", NULL"));
|
|
}
|
|
| user_name '/' user_name
|
|
{
|
|
$$ = cat_str(3, $1, make_str(","), $3);
|
|
}
|
|
| user_name SQL_IDENTIFIED BY user_name
|
|
{
|
|
$$ = cat_str(3, $1, make_str(","), $4);
|
|
}
|
|
| user_name USING user_name
|
|
{
|
|
$$ = cat_str(3, $1, make_str(","), $3);
|
|
}
|
|
|
|
user_name: UserId { if ($1[0] == '\"')
|
|
$$ = $1;
|
|
else
|
|
$$ = make3_str(make_str("\""), $1, make_str("\""));
|
|
}
|
|
| char_variable { $$ = $1; }
|
|
| SCONST { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
|
|
|
|
char_variable: cvariable
|
|
{ /* check if we have a char variable */
|
|
struct variable *p = find_variable($1);
|
|
enum ECPGttype typ = p->type->typ;
|
|
|
|
/* if array see what's inside */
|
|
if (typ == ECPGt_array)
|
|
typ = p->type->u.element->typ;
|
|
|
|
switch (typ)
|
|
{
|
|
case ECPGt_char:
|
|
case ECPGt_unsigned_char:
|
|
$$ = $1;
|
|
break;
|
|
case ECPGt_varchar:
|
|
$$ = make2_str($1, make_str(".arr"));
|
|
break;
|
|
default:
|
|
mmerror(ET_ERROR, "invalid datatype");
|
|
break;
|
|
}
|
|
}
|
|
|
|
opt_options: Op ColId
|
|
{
|
|
if (strlen($1) == 0)
|
|
mmerror(ET_ERROR, "parse error");
|
|
|
|
if (strcmp($1, "?") != 0)
|
|
{
|
|
sprintf(errortext, "parse error at or near %s", $1);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
|
|
$$ = make2_str(make_str("?"), $2);
|
|
}
|
|
| /* empty */ { $$ = EMPTY; }
|
|
|
|
/*
|
|
* 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
|
|
{
|
|
struct cursor *ptr, *this;
|
|
struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
|
|
|
|
for (ptr = cur; ptr != NULL; ptr = ptr->next)
|
|
{
|
|
if (strcmp($2, ptr->name) == 0)
|
|
{
|
|
/* re-definition is a bug */
|
|
sprintf(errortext, "cursor %s already defined", $2);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
}
|
|
|
|
this = (struct cursor *) mm_alloc(sizeof(struct cursor));
|
|
|
|
/* initial definition */
|
|
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->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);
|
|
|
|
this->argsinsert = NULL;
|
|
add_variable(&(this->argsinsert), thisquery, &no_indicator);
|
|
|
|
cur = this;
|
|
|
|
$$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
|
|
}
|
|
;
|
|
|
|
/*
|
|
* the exec sql deallocate prepare command to deallocate a previously
|
|
* prepared statement
|
|
*/
|
|
ECPGDeallocate: SQL_DEALLOCATE SQL_PREPARE ident { $$ = cat_str(3, make_str("ECPGdeallocate(__LINE__, \""), $3, make_str("\");")); }
|
|
|
|
/*
|
|
* variable declaration inside the exec sql declare block
|
|
*/
|
|
ECPGDeclaration: sql_startdeclare
|
|
{
|
|
fputs("/* exec sql begin declare section */", yyout);
|
|
}
|
|
variable_declarations sql_enddeclare
|
|
{
|
|
fprintf(yyout, "%s/* exec sql end declare section */", $3);
|
|
free($3);
|
|
output_line_number();
|
|
}
|
|
|
|
sql_startdeclare : ecpgstart BEGIN_TRANS DECLARE SQL_SECTION ';' {}
|
|
|
|
sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION ';' {}
|
|
|
|
variable_declarations: /* empty */ { $$ = EMPTY; }
|
|
| declarations { $$ = $1; }
|
|
|
|
declarations: declaration { $$ = $1; }
|
|
| declarations declaration { $$ = cat2_str($1, $2); }
|
|
|
|
declaration: storage_clause storage_modifier
|
|
{
|
|
actual_storage[struct_level] = cat2_str(mm_strdup($1), mm_strdup($2));
|
|
actual_startline[struct_level] = hashline_number();
|
|
}
|
|
type
|
|
{
|
|
actual_type[struct_level].type_enum = $4.type_enum;
|
|
actual_type[struct_level].type_dimension = $4.type_dimension;
|
|
actual_type[struct_level].type_index = $4.type_index;
|
|
|
|
/* we do not need the string "varchar" for output */
|
|
/* so replace it with an empty string */
|
|
if ($4.type_enum == ECPGt_varchar)
|
|
{
|
|
free($4.type_str);
|
|
$4.type_str=EMPTY;
|
|
}
|
|
}
|
|
variable_list ';'
|
|
{
|
|
$$ = cat_str(6, actual_startline[struct_level], $1, $2, $4.type_str, $6, make_str(";\n"));
|
|
}
|
|
|
|
storage_clause : S_EXTERN { $$ = make_str("extern"); }
|
|
| S_STATIC { $$ = make_str("static"); }
|
|
| S_REGISTER { $$ = make_str("register"); }
|
|
| S_AUTO { $$ = make_str("auto"); }
|
|
| /* empty */ { $$ = EMPTY; }
|
|
|
|
storage_modifier : S_CONST { $$ = make_str("const"); }
|
|
| S_VOLATILE { $$ = make_str("volatile"); }
|
|
| /* empty */ { $$ = EMPTY; }
|
|
|
|
type: simple_type
|
|
{
|
|
$$.type_enum = $1;
|
|
$$.type_str = mm_strdup(ECPGtype_name($1));
|
|
$$.type_dimension = -1;
|
|
$$.type_index = -1;
|
|
}
|
|
| varchar_type
|
|
{
|
|
$$.type_enum = ECPGt_varchar;
|
|
$$.type_str = make_str("varchar");;
|
|
$$.type_dimension = -1;
|
|
$$.type_index = -1;
|
|
}
|
|
| struct_type
|
|
{
|
|
$$.type_enum = ECPGt_struct;
|
|
$$.type_str = $1;
|
|
$$.type_dimension = -1;
|
|
$$.type_index = -1;
|
|
}
|
|
| union_type
|
|
{
|
|
$$.type_enum = ECPGt_union;
|
|
$$.type_str = $1;
|
|
$$.type_dimension = -1;
|
|
$$.type_index = -1;
|
|
}
|
|
| enum_type
|
|
{
|
|
$$.type_str = $1;
|
|
$$.type_enum = ECPGt_int;
|
|
$$.type_dimension = -1;
|
|
$$.type_index = -1;
|
|
}
|
|
| ECPGColLabel
|
|
{
|
|
/* this is for typedef'ed types */
|
|
struct typedefs *this = get_typedef($1);
|
|
|
|
$$.type_str = (this->type->type_enum == ECPGt_varchar) ? EMPTY : mm_strdup(this->name);
|
|
$$.type_enum = this->type->type_enum;
|
|
$$.type_dimension = this->type->type_dimension;
|
|
$$.type_index = this->type->type_index;
|
|
struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
|
|
}
|
|
|
|
enum_type: SQL_ENUM opt_symbol enum_definition
|
|
{
|
|
$$ = cat_str(3, make_str("enum"), $2, $3);
|
|
}
|
|
| SQL_ENUM symbol
|
|
{
|
|
$$ = cat2_str(make_str("enum"), $2);
|
|
}
|
|
|
|
enum_definition: '{' c_list '}' { $$ = cat_str(3, make_str("{"), $2, make_str("}")); }
|
|
|
|
struct_type: s_struct '{' variable_declarations '}'
|
|
{
|
|
ECPGfree_struct_member(struct_member_list[struct_level]);
|
|
free(actual_storage[struct_level--]);
|
|
$$ = cat_str(4, $1, make_str("{"), $3, make_str("}"));
|
|
}
|
|
|
|
union_type: s_union '{' variable_declarations '}'
|
|
{
|
|
ECPGfree_struct_member(struct_member_list[struct_level]);
|
|
free(actual_storage[struct_level--]);
|
|
$$ = cat_str(4, $1, make_str("{"), $3, make_str("}"));
|
|
}
|
|
|
|
s_struct: SQL_STRUCT opt_symbol
|
|
{
|
|
struct_member_list[struct_level++] = NULL;
|
|
if (struct_level >= STRUCT_DEPTH)
|
|
mmerror(ET_ERROR, "Too many levels in nested structure definition");
|
|
|
|
/* reset this variable so we see if there was */
|
|
/* an initializer specified */
|
|
initializer = 0;
|
|
|
|
$$ = cat2_str(make_str("struct"), $2);
|
|
}
|
|
|
|
s_union: UNION opt_symbol
|
|
{
|
|
struct_member_list[struct_level++] = NULL;
|
|
if (struct_level >= STRUCT_DEPTH)
|
|
mmerror(ET_ERROR, "Too many levels in nested structure definition");
|
|
|
|
/* reset this variable so we see if there was */
|
|
/* an initializer specified */
|
|
initializer = 0;
|
|
|
|
$$ = cat2_str(make_str("union"), $2);
|
|
}
|
|
|
|
simple_type: unsigned_type { $$=$1; }
|
|
| opt_signed signed_type { $$=$2; }
|
|
;
|
|
|
|
unsigned_type: SQL_UNSIGNED SQL_SHORT { $$ = ECPGt_unsigned_short; }
|
|
| SQL_UNSIGNED SQL_SHORT SQL_INT { $$ = ECPGt_unsigned_short; }
|
|
| SQL_UNSIGNED { $$ = ECPGt_unsigned_int; }
|
|
| SQL_UNSIGNED SQL_INT { $$ = ECPGt_unsigned_int; }
|
|
| SQL_UNSIGNED SQL_LONG { $$ = ECPGt_unsigned_long; }
|
|
| SQL_UNSIGNED SQL_LONG SQL_INT { $$ = ECPGt_unsigned_long; }
|
|
| SQL_UNSIGNED CHAR { $$ = ECPGt_unsigned_char; }
|
|
;
|
|
|
|
signed_type: SQL_SHORT { $$ = ECPGt_short; }
|
|
| SQL_SHORT SQL_INT { $$ = ECPGt_short; }
|
|
| SQL_INT { $$ = ECPGt_int; }
|
|
| SQL_LONG { $$ = ECPGt_long; }
|
|
| SQL_LONG SQL_INT { $$ = ECPGt_long; }
|
|
| SQL_BOOL { $$ = ECPGt_bool; };
|
|
| FLOAT { $$ = ECPGt_float; }
|
|
| DOUBLE { $$ = ECPGt_double; }
|
|
| CHAR { $$ = ECPGt_char; }
|
|
;
|
|
|
|
opt_signed: SQL_SIGNED
|
|
| /* EMPTY */
|
|
;
|
|
|
|
varchar_type: VARCHAR { $$ = ECPGt_varchar; }
|
|
|
|
variable_list: variable
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| variable_list ',' variable
|
|
{
|
|
$$ = cat_str(3, $1, make_str(","), $3);
|
|
}
|
|
|
|
variable: opt_pointer ECPGColLabel opt_array_bounds 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];
|
|
|
|
adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1));
|
|
|
|
switch (actual_type[struct_level].type_enum)
|
|
{
|
|
case ECPGt_struct:
|
|
case ECPGt_union:
|
|
if (dimension < 0)
|
|
type = ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum);
|
|
else
|
|
type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum), dimension);
|
|
|
|
$$ = cat_str(4, $1, mm_strdup($2), $3.str, $4);
|
|
break;
|
|
case ECPGt_varchar:
|
|
if (dimension == -1)
|
|
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
|
|
else
|
|
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
|
|
|
|
switch(dimension)
|
|
{
|
|
case 0:
|
|
case -1:
|
|
case 1:
|
|
*dim = '\0';
|
|
break;
|
|
default:
|
|
sprintf(dim, "[%d]", dimension);
|
|
break;
|
|
}
|
|
sprintf(ascii_len, "%d", length);
|
|
|
|
if (length == 0)
|
|
mmerror(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);
|
|
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);
|
|
|
|
break;
|
|
case ECPGt_char:
|
|
case ECPGt_unsigned_char:
|
|
if (dimension == -1)
|
|
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
|
|
else
|
|
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
|
|
|
|
$$ = cat_str(4, $1, mm_strdup($2), $3.str, $4);
|
|
break;
|
|
default:
|
|
if (dimension < 0)
|
|
type = ECPGmake_simple_type(actual_type[struct_level].type_enum, 1);
|
|
else
|
|
type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension);
|
|
|
|
$$ = cat_str(4, $1, mm_strdup($2), $3.str, $4);
|
|
break;
|
|
}
|
|
|
|
if (struct_level == 0)
|
|
new_variable($2, type);
|
|
else
|
|
ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
|
|
|
|
free($2);
|
|
}
|
|
|
|
opt_initializer: /* empty */ { $$ = EMPTY; }
|
|
| '=' c_term {
|
|
initializer = 1;
|
|
$$ = cat2_str(make_str("="), $2);
|
|
}
|
|
|
|
opt_pointer: /* empty */ { $$ = EMPTY; }
|
|
| '*' { $$ = make_str("*"); }
|
|
|
|
/*
|
|
* As long as the prepare statement is not supported by the backend, we will
|
|
* try to simulate it here so we get dynamic SQL
|
|
*/
|
|
ECPGDeclare: DECLARE STATEMENT ident
|
|
{
|
|
/* this is only supported for compatibility */
|
|
$$ = cat_str(3, make_str("/* declare statement"), $3, make_str("*/"));
|
|
}
|
|
/*
|
|
* the exec sql disconnect statement: disconnect from the given database
|
|
*/
|
|
ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
|
|
|
|
dis_name: connection_object { $$ = $1; }
|
|
| CURRENT { $$ = make_str("\"CURRENT\""); }
|
|
| ALL { $$ = make_str("\"ALL\""); }
|
|
| /* empty */ { $$ = make_str("\"CURRENT\""); }
|
|
|
|
connection_object: connection_target { $$ = $1; }
|
|
| DEFAULT { $$ = make_str("\"DEFAULT\""); }
|
|
|
|
/*
|
|
* 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
|
|
{
|
|
$$ = make_str("?");
|
|
}
|
|
|
|
execstring: char_variable |
|
|
CSTRING { $$ = make3_str(make_str("\""), $1, make_str("\"")); };
|
|
|
|
/*
|
|
* the exec sql free command to deallocate a previously
|
|
* prepared statement
|
|
*/
|
|
ECPGFree: SQL_FREE ident { $$ = $2; }
|
|
|
|
/*
|
|
* open is an open cursor, at the moment this has to be removed
|
|
*/
|
|
ECPGOpen: SQL_OPEN name ecpg_using {
|
|
$$ = $2;
|
|
};
|
|
|
|
ecpg_using: /* empty */ { $$ = EMPTY; }
|
|
| USING variablelist {
|
|
/* mmerror ("open cursor with variables not implemented yet"); */
|
|
$$ = EMPTY;
|
|
}
|
|
|
|
variablelist: cinputvariable | cinputvariable ',' 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
|
|
*/
|
|
ECPGPrepare: SQL_PREPARE ident FROM execstring
|
|
{
|
|
$$ = cat2_str(make3_str(make_str("\""), $2, make_str("\",")), $4);
|
|
}
|
|
|
|
/*
|
|
* dynamic SQL: descriptor based access
|
|
* written by Christof Petig <christof.petig@wtal.de>
|
|
*/
|
|
|
|
/*
|
|
* deallocate a descriptor
|
|
*/
|
|
ECPGDeallocateDescr: SQL_DEALLOCATE SQL_DESCRIPTOR ident
|
|
{ drop_descriptor($3,connection);
|
|
$$ = $3;
|
|
}
|
|
|
|
/*
|
|
* allocate a descriptor
|
|
*/
|
|
ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR ident
|
|
{ add_descriptor($3,connection);
|
|
$$ = $3;
|
|
}
|
|
|
|
/*
|
|
* read from descriptor
|
|
*/
|
|
|
|
ECPGGetDescHeaderItem: cvariable '=' desc_header_item {
|
|
push_assignment($1, $3);
|
|
}
|
|
|
|
desc_header_item: SQL_COUNT { $$ = ECPGd_count; }
|
|
|
|
ECPGGetDescItem: cvariable '=' descriptor_item {
|
|
push_assignment($1, $3);
|
|
}
|
|
|
|
descriptor_item: SQL_DATA { $$ = ECPGd_data; }
|
|
| SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; }
|
|
| SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; }
|
|
| SQL_INDICATOR { $$ = ECPGd_indicator; }
|
|
| SQL_KEY_MEMBER { $$ = ECPGd_key_member; }
|
|
| SQL_LENGTH { $$ = ECPGd_length; }
|
|
| SQL_NAME { $$ = ECPGd_name; }
|
|
| SQL_NULLABLE { $$ = ECPGd_nullable; }
|
|
| SQL_OCTET_LENGTH { $$ = ECPGd_octet; }
|
|
| PRECISION { $$ = ECPGd_precision; }
|
|
| SQL_RETURNED_LENGTH { $$ = ECPGd_length; }
|
|
| SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; }
|
|
| SQL_SCALE { $$ = ECPGd_scale; }
|
|
| TYPE_P { $$ = ECPGd_type; }
|
|
;
|
|
|
|
ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
|
|
| ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem;
|
|
|
|
ECPGGetDescItems: ECPGGetDescItem
|
|
| ECPGGetDescItems ',' ECPGGetDescItem;
|
|
|
|
ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR ident ECPGGetDescHeaderItems
|
|
{ $$ = $3; }
|
|
|
|
ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR ident SQL_VALUE cvariable ECPGGetDescItems
|
|
{ $$.str = $5; $$.name = $3; }
|
|
| SQL_GET SQL_DESCRIPTOR ident SQL_VALUE Iconst ECPGGetDescItems
|
|
{ $$.str = $5; $$.name = $3; }
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* QUERY:
|
|
* fetch [forward | backward] [ # | all ] [ in <portalname> ]
|
|
* fetch [ forward | backward | absolute | relative ]
|
|
* [ # | all | next | prior ] [ [ in | from ] <portalname> ]
|
|
*
|
|
* Have to seperate the descriptor version since we have to
|
|
* call a different output function
|
|
*
|
|
*****************************************************************************/
|
|
|
|
ECPGFetchDescStmt: FETCH direction fetch_how_many from_in name INTO SQL_SQL SQL_DESCRIPTOR ident
|
|
{
|
|
$$.str = cat_str(5, make_str("fetch"), $2, $3, $4, $5);
|
|
$$.name=$9;
|
|
}
|
|
| FETCH fetch_how_many from_in name INTO SQL_SQL SQL_DESCRIPTOR ident
|
|
{
|
|
$$.str = cat_str(4, make_str("fetch"), $2, $3, $4);
|
|
$$.name=$8;
|
|
}
|
|
| FETCH direction from_in name INTO SQL_SQL SQL_DESCRIPTOR ident
|
|
{
|
|
$$.str = cat_str(4, make_str("fetch"), $2, $3, $4);
|
|
$$.name=$8;
|
|
}
|
|
| FETCH from_in name INTO SQL_SQL SQL_DESCRIPTOR ident
|
|
{
|
|
$$.str = cat_str(3, make_str("fetch"), $2, $3);
|
|
$$.name=$7;
|
|
}
|
|
| FETCH name INTO SQL_SQL SQL_DESCRIPTOR ident
|
|
{
|
|
$$.str = cat2_str(make_str("fetch"), $2);
|
|
$$.name=$6;
|
|
}
|
|
;
|
|
|
|
/*
|
|
* for compatibility with ORACLE we will also allow the keyword RELEASE
|
|
* after a transaction statement to disconnect from the database.
|
|
*/
|
|
|
|
ECPGRelease: TransactionStmt SQL_RELEASE
|
|
{
|
|
if (strcmp($1, "begin") == 0)
|
|
mmerror(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);
|
|
}
|
|
|
|
/*
|
|
* set/reset the automatic transaction mode, this needs a differnet handling
|
|
* as the other set commands
|
|
*/
|
|
ECPGSetAutocommit: SET SQL_AUTOCOMMIT to_equal on_off
|
|
{
|
|
$$ = $4;
|
|
}
|
|
|
|
on_off: ON { $$ = make_str("on"); }
|
|
| SQL_OFF { $$ = make_str("off"); }
|
|
|
|
to_equal: TO | '=';
|
|
|
|
/*
|
|
* set the actual connection, this needs a differnet handling as the other
|
|
* set commands
|
|
*/
|
|
ECPGSetConnection: SET SQL_CONNECTION to_equal connection_object
|
|
{
|
|
$$ = $4;
|
|
}
|
|
|
|
/*
|
|
* define a new type for embedded SQL
|
|
*/
|
|
ECPGTypedef: TYPE_P ECPGColLabel IS type opt_type_array_bounds opt_reference
|
|
{
|
|
/* add entry to list */
|
|
struct typedefs *ptr, *this;
|
|
int dimension = $5.index1;
|
|
int length = $5.index2;
|
|
|
|
if (($4.type_enum == ECPGt_struct ||
|
|
$4.type_enum == ECPGt_union) &&
|
|
initializer == 1)
|
|
mmerror(ET_ERROR, "Initializer not allowed in EXEC SQL VAR command");
|
|
|
|
for (ptr = types; ptr != NULL; ptr = ptr->next)
|
|
{
|
|
if (strcmp($2, ptr->name) == 0)
|
|
{
|
|
/* re-definition is a bug */
|
|
sprintf(errortext, "Type %s already defined", $2);
|
|
mmerror(ET_ERROR, errortext);
|
|
}
|
|
}
|
|
|
|
adjust_array($4.type_enum, &dimension, &length, $4.type_dimension, $4.type_index, strlen($6));
|
|
|
|
this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
|
|
|
|
/* initial definition */
|
|
this->next = types;
|
|
this->name = $2;
|
|
this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
|
|
this->type->type_enum = $4.type_enum;
|
|
this->type->type_str = mm_strdup($2);
|
|
this->type->type_dimension = dimension; /* dimension of array */
|
|
this->type->type_index = length; /* lenght of string */
|
|
this->struct_member_list = ($4.type_enum == ECPGt_struct || $4.type_enum == ECPGt_union) ?
|
|
struct_member_list[struct_level] : NULL;
|
|
|
|
if ($4.type_enum != ECPGt_varchar &&
|
|
$4.type_enum != ECPGt_char &&
|
|
$4.type_enum != ECPGt_unsigned_char &&
|
|
this->type->type_index >= 0)
|
|
mmerror(ET_ERROR, "No multi-dimensional array support for simple data types");
|
|
|
|
types = this;
|
|
|
|
$$ = cat_str(7, make_str("/* exec sql type"), mm_strdup($2), make_str("is"), mm_strdup($4.type_str), mm_strdup($5.str), $6, make_str("*/"));
|
|
}
|
|
|
|
opt_type_array_bounds: '[' ']' opt_type_array_bounds
|
|
{
|
|
$$.index1 = 0;
|
|
$$.index2 = $3.index1;
|
|
$$.str = cat2_str(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; }
|
|
|
|
/*
|
|
* define the type of one variable for embedded SQL
|
|
*/
|
|
ECPGVar: SQL_VAR ECPGColLabel IS type opt_type_array_bounds opt_reference
|
|
{
|
|
struct variable *p = find_variable($2);
|
|
int dimension = $5.index1;
|
|
int length = $5.index2;
|
|
struct ECPGtype * type;
|
|
|
|
if (($4.type_enum == ECPGt_struct ||
|
|
$4.type_enum == ECPGt_union) &&
|
|
initializer == 1)
|
|
mmerror(ET_ERROR, "Initializer not allowed in EXEC SQL VAR command");
|
|
|
|
adjust_array($4.type_enum, &dimension, &length, $4.type_dimension, $4.type_index, strlen($6));
|
|
|
|
switch ($4.type_enum)
|
|
{
|
|
case ECPGt_struct:
|
|
case ECPGt_union:
|
|
if (dimension < 0)
|
|
type = ECPGmake_struct_type(struct_member_list[struct_level], $4.type_enum);
|
|
else
|
|
type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $4.type_enum), dimension);
|
|
break;
|
|
case ECPGt_varchar:
|
|
if (dimension == -1)
|
|
type = ECPGmake_simple_type($4.type_enum, length);
|
|
else
|
|
type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, length), dimension);
|
|
|
|
break;
|
|
case ECPGt_char:
|
|
case ECPGt_unsigned_char:
|
|
if (dimension == -1)
|
|
type = ECPGmake_simple_type($4.type_enum, length);
|
|
else
|
|
type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, length), dimension);
|
|
|
|
break;
|
|
default:
|
|
if (length >= 0)
|
|
mmerror(ET_ERROR, "No multi-dimensional array support for simple data types");
|
|
|
|
if (dimension < 0)
|
|
type = ECPGmake_simple_type($4.type_enum, 1);
|
|
else
|
|
type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, 1), dimension);
|
|
|
|
break;
|
|
}
|
|
|
|
ECPGfree_type(p->type);
|
|
p->type = type;
|
|
|
|
$$ = cat_str(7, make_str("/* exec sql var"), mm_strdup($2), make_str("is"), mm_strdup($4.type_str), mm_strdup($5.str), $6, make_str("*/"));
|
|
}
|
|
|
|
/*
|
|
* whenever statement: decide what to do in case of error/no data found
|
|
* according to SQL standards we lack: SQLSTATE, CONSTRAINT and SQLEXCEPTION
|
|
*/
|
|
ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action {
|
|
when_error.code = $<action>3.code;
|
|
when_error.command = $<action>3.command;
|
|
$$ = cat_str(3, make_str("/* exec sql whenever sqlerror "), $3.str, make_str("; */\n"));
|
|
}
|
|
| SQL_WHENEVER NOT SQL_FOUND action {
|
|
when_nf.code = $<action>4.code;
|
|
when_nf.command = $<action>4.command;
|
|
$$ = cat_str(3, make_str("/* exec sql whenever not found "), $4.str, make_str("; */\n"));
|
|
}
|
|
| SQL_WHENEVER SQL_SQLWARNING action {
|
|
when_warn.code = $<action>3.code;
|
|
when_warn.command = $<action>3.command;
|
|
$$ = cat_str(3, make_str("/* exec sql whenever sql_warning "), $3.str, make_str("; */\n"));
|
|
}
|
|
|
|
action : SQL_CONTINUE {
|
|
$<action>$.code = W_NOTHING;
|
|
$<action>$.command = NULL;
|
|
$<action>$.str = make_str("continue");
|
|
}
|
|
| SQL_SQLPRINT {
|
|
$<action>$.code = W_SQLPRINT;
|
|
$<action>$.command = NULL;
|
|
$<action>$.str = make_str("sqlprint");
|
|
}
|
|
| SQL_STOP {
|
|
$<action>$.code = W_STOP;
|
|
$<action>$.command = NULL;
|
|
$<action>$.str = make_str("stop");
|
|
}
|
|
| SQL_GOTO name {
|
|
$<action>$.code = W_GOTO;
|
|
$<action>$.command = strdup($2);
|
|
$<action>$.str = cat2_str(make_str("goto "), $2);
|
|
}
|
|
| SQL_GO TO name {
|
|
$<action>$.code = W_GOTO;
|
|
$<action>$.command = strdup($3);
|
|
$<action>$.str = cat2_str(make_str("goto "), $3);
|
|
}
|
|
| DO name '(' c_args ')' {
|
|
$<action>$.code = W_DO;
|
|
$<action>$.command = cat_str(4, $2, make_str("("), $4, make_str(")"));
|
|
$<action>$.str = cat2_str(make_str("do"), mm_strdup($<action>$.command));
|
|
}
|
|
| DO SQL_BREAK {
|
|
$<action>$.code = W_BREAK;
|
|
$<action>$.command = NULL;
|
|
$<action>$.str = make_str("break");
|
|
}
|
|
| SQL_CALL name '(' c_args ')' {
|
|
$<action>$.code = W_DO;
|
|
$<action>$.command = cat_str(4, $2, make_str("("), $4, make_str(")"));
|
|
$<action>$.str = cat2_str(make_str("call"), mm_strdup($<action>$.command));
|
|
}
|
|
|
|
/* some other stuff for ecpg */
|
|
|
|
/* additional ColId entries */
|
|
ECPGKeywords: SQL_AT { $$ = make_str("at"); }
|
|
| SQL_BREAK { $$ = make_str("break"); }
|
|
| SQL_CALL { $$ = make_str("call"); }
|
|
| SQL_CONNECT { $$ = make_str("connect"); }
|
|
| SQL_CONTINUE { $$ = make_str("continue"); }
|
|
| 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_OFF { $$ = make_str("off"); }
|
|
| SQL_OPEN { $$ = make_str("open"); }
|
|
| SQL_PREPARE { $$ = make_str("prepare"); }
|
|
| SQL_RELEASE { $$ = make_str("release"); }
|
|
| 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"); }
|
|
;
|
|
|
|
ECPGTypeName: SQL_BOOL { $$ = make_str("bool"); }
|
|
| SQL_INT { $$ = make_str("int"); }
|
|
| 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"); }
|
|
| DOUBLE { $$ = make_str("double"); }
|
|
|
|
ECPGLabelTypeName: FLOAT { $$ = make_str("float"); }
|
|
| ECPGTypeName { $$ = $1; }
|
|
;
|
|
|
|
opt_symbol: symbol { $$ = $1; }
|
|
| /*EMPTY*/ { $$ = EMPTY; }
|
|
;
|
|
|
|
symbol: ColLabel { $$ = $1; }
|
|
|
|
ECPGColId: /* to be used instead of ColId */
|
|
ECPGKeywords { $$ = $1; }
|
|
| ident { $$ = $1; }
|
|
| datetime { $$ = $1; }
|
|
| ABSOLUTE { $$ = make_str("absolute"); }
|
|
| ACCESS { $$ = make_str("access"); }
|
|
| ACTION { $$ = make_str("action"); }
|
|
| AFTER { $$ = make_str("after"); }
|
|
| AGGREGATE { $$ = make_str("aggregate"); }
|
|
| BACKWARD { $$ = make_str("backward"); }
|
|
| BEFORE { $$ = make_str("before"); }
|
|
| CACHE { $$ = make_str("cache"); }
|
|
| COMMENT { $$ = make_str("comment"); }
|
|
| COMMITTED { $$ = make_str("committed"); }
|
|
| CONSTRAINTS { $$ = make_str("constraints"); }
|
|
| CREATEDB { $$ = make_str("createdb"); }
|
|
| CREATEUSER { $$ = make_str("createuser"); }
|
|
| CYCLE { $$ = make_str("cycle"); }
|
|
| DATABASE { $$ = make_str("database"); }
|
|
| DEFERRED { $$ = make_str("deferred"); }
|
|
| DELIMITERS { $$ = make_str("delimiters"); }
|
|
| EACH { $$ = make_str("each"); }
|
|
| ENCODING { $$ = make_str("encoding"); }
|
|
| EXCLUSIVE { $$ = make_str("exclusive"); }
|
|
| FORWARD { $$ = make_str("forward"); }
|
|
| FUNCTION { $$ = make_str("function"); }
|
|
| HANDLER { $$ = make_str("handler"); }
|
|
| IMMEDIATE { $$ = make_str("immediate"); }
|
|
| INCREMENT { $$ = make_str("increment"); }
|
|
| INDEX { $$ = make_str("index"); }
|
|
| INHERITS { $$ = make_str("inherits"); }
|
|
| INSENSITIVE { $$ = make_str("insensitive"); }
|
|
| INSTEAD { $$ = make_str("instead"); }
|
|
| INTERVAL { $$ = make_str("interval"); }
|
|
| ISNULL { $$ = make_str("isnull"); }
|
|
| ISOLATION { $$ = make_str("isolation"); }
|
|
| KEY { $$ = make_str("key"); }
|
|
| LANGUAGE { $$ = make_str("language"); }
|
|
| LANCOMPILER { $$ = make_str("lancompiler"); }
|
|
| LEVEL { $$ = make_str("level"); }
|
|
| LOCATION { $$ = make_str("location"); }
|
|
| MATCH { $$ = make_str("match"); }
|
|
| MAXVALUE { $$ = make_str("maxvalue"); }
|
|
| MINVALUE { $$ = make_str("minvalue"); }
|
|
| MODE { $$ = make_str("mode"); }
|
|
| NEXT { $$ = make_str("next"); }
|
|
| NOCREATEDB { $$ = make_str("nocreatedb"); }
|
|
| NOCREATEUSER { $$ = make_str("nocreateuser"); }
|
|
| NOTHING { $$ = make_str("nothing"); }
|
|
| NOTNULL { $$ = make_str("notnull"); }
|
|
| OF { $$ = make_str("of"); }
|
|
| OIDS { $$ = make_str("oids"); }
|
|
| ONLY { $$ = make_str("only"); }
|
|
| OPERATOR { $$ = make_str("operator"); }
|
|
| OPTION { $$ = make_str("option"); }
|
|
| OVERLAPS { $$ = make_str("overlaps"); }
|
|
| PASSWORD { $$ = make_str("password"); }
|
|
| PENDANT { $$ = make_str("pendant"); }
|
|
| PRIOR { $$ = make_str("prior"); }
|
|
| PRIVILEGES { $$ = make_str("privileges"); }
|
|
| PROCEDURAL { $$ = make_str("procedural"); }
|
|
| READ { $$ = make_str("read"); }
|
|
| RELATIVE { $$ = make_str("relative"); }
|
|
| RENAME { $$ = make_str("rename"); }
|
|
| RESTRICT { $$ = make_str("restrict"); }
|
|
| RETURNS { $$ = make_str("returns"); }
|
|
| ROW { $$ = make_str("row"); }
|
|
| RULE { $$ = make_str("rule"); }
|
|
| SCROLL { $$ = make_str("scroll"); }
|
|
| SEQUENCE { $$ = make_str("sequence"); }
|
|
| SERIAL { $$ = make_str("serial"); }
|
|
| SERIALIZABLE { $$ = make_str("serializable"); }
|
|
| SHARE { $$ = make_str("share"); }
|
|
| START { $$ = make_str("start"); }
|
|
| STATEMENT { $$ = make_str("statement"); }
|
|
| STDIN { $$ = make_str("stdin"); }
|
|
| STDOUT { $$ = make_str("stdout"); }
|
|
| SYSID { $$ = make_str("sysid"); }
|
|
| TEMP { $$ = make_str("temp"); }
|
|
| TEMPORARY { $$ = make_str("temporary"); }
|
|
| TIME { $$ = make_str("time"); }
|
|
| TIMESTAMP { $$ = make_str("timestamp"); }
|
|
| TIMEZONE_HOUR { $$ = make_str("timezone_hour"); }
|
|
| TIMEZONE_MINUTE { $$ = make_str("timezone_minute"); }
|
|
| TRIGGER { $$ = make_str("trigger"); }
|
|
| TRUNCATE { $$ = make_str("truncate"); }
|
|
| TRUSTED { $$ = make_str("trusted"); }
|
|
| TYPE_P { $$ = make_str("type"); }
|
|
| VALID { $$ = make_str("valid"); }
|
|
| VERSION { $$ = make_str("version"); }
|
|
| ZONE { $$ = make_str("zone"); }
|
|
;
|
|
|
|
ECPGColLabel: ECPGColId { $$ = $1; }
|
|
| ABORT_TRANS { $$ = make_str("abort"); }
|
|
| ANALYZE { $$ = make_str("analyze"); }
|
|
| BINARY { $$ = make_str("binary"); }
|
|
| CASE { $$ = make_str("case"); }
|
|
| CLUSTER { $$ = make_str("cluster"); }
|
|
| COALESCE { $$ = make_str("coalesce"); }
|
|
| CONSTRAINT { $$ = make_str("constraint"); }
|
|
| COPY { $$ = make_str("copy"); }
|
|
| CURRENT { $$ = make_str("current"); }
|
|
| CURRENT_USER { $$ = make_str("current_user"); }
|
|
| DEC { $$ = make_str("dec"); }
|
|
| DECIMAL { $$ = make_str("decimal"); }
|
|
| DEFERRABLE { $$ = make_str("deferrable"); }
|
|
| DO { $$ = make_str("do"); }
|
|
| ELSE { $$ = make_str("else"); }
|
|
| END_TRANS { $$ = make_str("end"); }
|
|
| EXPLAIN { $$ = make_str("explain"); }
|
|
| EXTEND { $$ = make_str("extend"); }
|
|
| FALSE_P { $$ = make_str("false"); }
|
|
| FOREIGN { $$ = make_str("foreign"); }
|
|
| GLOBAL { $$ = make_str("global"); }
|
|
| GROUP { $$ = make_str("group"); }
|
|
| INITIALLY { $$ = make_str("initially"); }
|
|
| LISTEN { $$ = make_str("listen"); }
|
|
| LOAD { $$ = make_str("load"); }
|
|
| LOCK_P { $$ = make_str("lock"); }
|
|
| MOVE { $$ = make_str("move"); }
|
|
| NEW { $$ = make_str("new"); }
|
|
| NONE { $$ = make_str("none"); }
|
|
| NULLIF { $$ = make_str("nullif"); }
|
|
| NUMERIC { $$ = make_str("numeric"); }
|
|
| ORDER { $$ = make_str("order"); }
|
|
| POSITION { $$ = make_str("position"); }
|
|
| PRECISION { $$ = make_str("precision"); }
|
|
| RESET { $$ = make_str("reset"); }
|
|
| SESSION_USER { $$ = make_str("session_user"); }
|
|
| SETOF { $$ = make_str("setof"); }
|
|
| SHOW { $$ = make_str("show"); }
|
|
| TABLE { $$ = make_str("table"); }
|
|
| THEN { $$ = make_str("then"); }
|
|
| TRANSACTION { $$ = make_str("transaction"); }
|
|
| TRUE_P { $$ = make_str("true"); }
|
|
| USER { $$ = make_str("user"); }
|
|
| VACUUM { $$ = make_str("vacuum"); }
|
|
| VERBOSE { $$ = make_str("verbose"); }
|
|
| WHEN { $$ = make_str("when"); }
|
|
;
|
|
|
|
into_list : coutputvariable | into_list ',' coutputvariable;
|
|
|
|
ecpgstart: SQL_START { reset_variables();}
|
|
|
|
c_args: /* empty */ { $$ = EMPTY; }
|
|
| c_list { $$ = $1; }
|
|
|
|
coutputvariable : cvariable indicator {
|
|
add_variable(&argsresult, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2));
|
|
}
|
|
|
|
cinputvariable : cvariable indicator {
|
|
if ($2 != NULL && (find_variable($2))->type->typ == ECPGt_array)
|
|
mmerror(ET_ERROR, "arrays of indicators are not allowed on input");
|
|
|
|
add_variable(&argsinsert, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2));
|
|
}
|
|
|
|
civariableonly : cvariable {
|
|
add_variable(&argsinsert, find_variable($1), &no_indicator);
|
|
$$ = make_str("?");
|
|
}
|
|
|
|
cvariable: CVARIABLE { $$ = $1; }
|
|
|
|
indicator: /* empty */ { $$ = NULL; }
|
|
| 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("\"")); };
|
|
|
|
/*
|
|
* C stuff
|
|
*/
|
|
|
|
cpp_line: CPP_LINE { $$ = $1; }
|
|
|
|
c_stuff: c_anything { $$ = $1; }
|
|
| c_stuff c_anything
|
|
{
|
|
$$ = cat2_str($1, $2);
|
|
}
|
|
| c_stuff '(' c_stuff ')'
|
|
{
|
|
$$ = cat_str(4, $1, make_str("("), $3, make_str(")"));
|
|
}
|
|
|
|
c_list: c_term { $$ = $1; }
|
|
| c_list ',' c_term { $$ = cat_str(3, $1, make_str(","), $3); }
|
|
|
|
c_term: c_stuff { $$ = $1; }
|
|
| '{' c_list '}' { $$ = cat_str(3, make_str("{"), $2, make_str("}")); }
|
|
|
|
c_thing: c_anything { $$ = $1; }
|
|
| '(' { $$ = make_str("("); }
|
|
| ')' { $$ = make_str(")"); }
|
|
| ',' { $$ = make_str(","); }
|
|
| ';' { $$ = make_str(";"); }
|
|
|
|
c_anything: IDENT { $$ = $1; }
|
|
| CSTRING { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
|
|
| Iconst { $$ = $1; }
|
|
| Fconst { $$ = $1; }
|
|
| Sconst { $$ = $1; }
|
|
| '*' { $$ = make_str("*"); }
|
|
| '+' { $$ = make_str("+"); }
|
|
| '-' { $$ = make_str("-"); }
|
|
| '/' { $$ = make_str("/"); }
|
|
| '%' { $$ = make_str("%"); }
|
|
| S_ANYTHING { $$ = make_name(); }
|
|
| S_AUTO { $$ = make_str("auto"); }
|
|
| S_CONST { $$ = make_str("const"); }
|
|
| S_EXTERN { $$ = make_str("extern"); }
|
|
| S_REGISTER { $$ = make_str("register"); }
|
|
| S_STATIC { $$ = make_str("static"); }
|
|
| SQL_BOOL { $$ = make_str("bool"); }
|
|
| SQL_ENUM { $$ = make_str("enum"); }
|
|
| SQL_INT { $$ = make_str("int"); }
|
|
| SQL_LONG { $$ = make_str("long"); }
|
|
| SQL_SHORT { $$ = make_str("short"); }
|
|
| SQL_SIGNED { $$ = make_str("signed"); }
|
|
| SQL_STRUCT { $$ = make_str("struct"); }
|
|
| SQL_UNSIGNED { $$ = make_str("unsigned"); }
|
|
| CHAR { $$ = make_str("char"); }
|
|
| DOUBLE { $$ = make_str("double"); }
|
|
| FLOAT { $$ = make_str("float"); }
|
|
| UNION { $$ = make_str("union"); }
|
|
| VARCHAR { $$ = make_str("varchar"); }
|
|
| '[' { $$ = make_str("["); }
|
|
| ']' { $$ = make_str("]"); }
|
|
| '=' { $$ = make_str("="); }
|
|
|
|
blockstart : '{' {
|
|
braces_open++;
|
|
$$ = make_str("{");
|
|
}
|
|
|
|
blockend : '}' {
|
|
remove_variables(braces_open--);
|
|
$$ = make_str("}");
|
|
}
|
|
|
|
%%
|
|
|
|
void yyerror(char * error)
|
|
{
|
|
mmerror(ET_ERROR, error);
|
|
}
|