extern int no_auto_trans;
-static PGconn *simple_connection = NULL;
+static struct connection
+{
+ char *name;
+ PGconn *connection;
+ struct connection *next;
+} *all_connections = NULL, *actual_connection = NULL;
+
static int simple_debug = 0;
static FILE *debugstream = NULL;
static int committed = true;
int i,
ri;
+ if (!res)
+ return(res);
+
for (i = 0, ri = 0; arg[i]; i++, ri++)
{
switch (arg[i])
}
+static void
+ECPGfinish(struct connection *act)
+{
+ if (act != NULL)
+ {
+ ECPGlog("ECPGfinish: finishing %s.\n", act->name);
+ PQfinish(act->connection);
+ /* remove act from the list */
+ if (act == all_connections)
+ {
+ all_connections = act->next;
+ free(act->name);
+ free(act);
+ }
+ else
+ {
+ struct connection *con;
+
+ for (con = all_connections; con->next && con->next != act; con = con->next);
+ if (con->next)
+ {
+ con->next = act->next;
+ free(act->name);
+ free(act);
+ }
+ }
+
+ if (actual_connection == act)
+ actual_connection = all_connections;
+ }
+ else
+ ECPGlog("ECPGfinish: called an extra time.\n");
+}
+
bool
ECPGdo(int lineno, char *query,...)
{
{
/* set slen to string length if type is char * */
int slen = (varcharsize == 0) ? strlen((char *) value) : varcharsize;
+ char * tmp;
newcopy = (char *) malloc(slen + 1);
+ if (!newcopy)
+ {
+ ECPGfinish(actual_connection);
+ ECPGlog("out of memory\n");
+ register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+ return false;
+ }
+
strncpy(newcopy, (char *) value, slen);
newcopy[slen] = '\0';
mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
+ if (!mallocedval)
+ {
+ ECPGfinish(actual_connection);
+ ECPGlog("out of memory\n");
+ register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+ return false;
+ }
+
strcpy(mallocedval, "'");
- strcat(mallocedval, quote_postgres(newcopy));
+ tmp = quote_postgres(newcopy);
+ if (!tmp)
+ {
+ ECPGfinish(actual_connection);
+ ECPGlog("out of memory\n");
+ register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+ return false;
+ }
+
+ strcat(mallocedval, tmp);
strcat(mallocedval, "'");
free(newcopy);
{
struct ECPGgeneric_varchar *var =
(struct ECPGgeneric_varchar *) value;
+ char *tmp;
newcopy = (char *) malloc(var->len + 1);
+ if (!newcopy)
+ {
+ ECPGfinish(actual_connection);
+ ECPGlog("out of memory\n");
+ register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+ return false;
+ }
+
strncpy(newcopy, var->arr, var->len);
newcopy[var->len] = '\0';
mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
+ if (!mallocedval)
+ {
+ ECPGfinish(actual_connection);
+ ECPGlog("out of memory\n");
+ register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+ return false;
+ }
+
strcpy(mallocedval, "'");
- strcat(mallocedval, quote_postgres(newcopy));
+ tmp = quote_postgres(newcopy);
+ if (!tmp)
+ {
+ ECPGfinish(actual_connection);
+ ECPGlog("out of memory\n");
+ register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+ return false;
+ }
+
+ strcat(mallocedval, tmp);
strcat(mallocedval, "'");
free(newcopy);
newcopy = (char *) malloc(strlen(copiedquery)
+ strlen(tobeinserted)
+ 1);
+ if (!newcopy)
+ {
+ ECPGfinish(actual_connection);
+ ECPGlog("out of memory\n");
+ register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+ return false;
+ }
+
strcpy(newcopy, copiedquery);
if ((p = strstr(newcopy, ";;")) == NULL)
{
if (committed && !no_auto_trans)
{
- if ((results = PQexec(simple_connection, "begin transaction")) == NULL)
+ if ((results = PQexec(actual_connection->connection, "begin transaction")) == NULL)
{
register_error(ECPG_TRANS, "Error starting transaction line %d.", lineno);
return false;
}
ECPGlog("ECPGdo line %d: QUERY: %s\n", lineno, copiedquery);
- results = PQexec(simple_connection, copiedquery);
+ results = PQexec(actual_connection->connection, copiedquery);
free(copiedquery);
if (results == NULL)
{
ECPGlog("ECPGdo line %d: error: %s", lineno,
- PQerrorMessage(simple_connection));
+ PQerrorMessage(actual_connection->connection));
register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
- PQerrorMessage(simple_connection), lineno);
+ PQerrorMessage(actual_connection->connection), lineno);
}
else
{
case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE:
ECPGlog("ECPGdo line %d: Error: %s",
- lineno, PQerrorMessage(simple_connection));
+ lineno, PQerrorMessage(actual_connection->connection));
register_error(ECPG_PGSQL, "Error: %s line %d.",
- PQerrorMessage(simple_connection), lineno);
+ PQerrorMessage(actual_connection->connection), lineno);
status = false;
break;
case PGRES_COPY_OUT:
}
/* check for asynchronous returns */
- notify = PQnotifies(simple_connection);
+ notify = PQnotifies(actual_connection->connection);
if (notify)
{
ECPGlog("ECPGdo line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
PGresult *res;
ECPGlog("ECPGtrans line %d action = %s\n", lineno, transaction);
- if ((res = PQexec(simple_connection, transaction)) == NULL)
+ if ((res = PQexec(actual_connection->connection, transaction)) == NULL)
{
register_error(ECPG_TRANS, "Error in transaction processing line %d.", lineno);
return (FALSE);
}
bool
-ECPGsetdb(PGconn *newcon)
+ECPGsetconn(int lineno, const char *connection_name)
{
- ECPGfinish();
- simple_connection = newcon;
- return true;
+ struct connection *con = all_connections;
+
+ for (; con && strcmp(connection_name, con->name) == 0; con=con->next);
+ if (con)
+ {
+ actual_connection = con;
+ return true;
+ }
+ else
+ {
+ register_error(ECPG_NO_CONN, "No such connection %s in line %d", connection_name, lineno);
+ return false;
+ }
}
bool
-ECPGconnect(const char *dbname)
+ECPGconnect(int lineno, const char *dbname, const char *user, const char *passwd, const char * connection_name)
{
- char *name = strdup(dbname);
-
- ECPGlog("ECPGconnect: opening database %s\n", name);
+ struct connection *this = malloc(sizeof(struct connection));
- sqlca.sqlcode = 0;
+ if (!this)
+ {
+ ECPGlog("out of memory\n");
+ register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+ return false;
+ }
+
+ if (dbname == NULL && connection_name == NULL)
+ connection_name = "DEFAULT";
+
+ /* add connection to our list */
+ if (connection_name != NULL)
+ this->name = strdup(connection_name);
+ else
+ this->name = strdup(dbname);
+
+ if (all_connections == NULL)
+ this->next = NULL;
+ else
+ this->next = all_connections;
- ECPGsetdb(PQsetdb(NULL, NULL, NULL, NULL, name));
+ actual_connection = all_connections = this;
+
+ ECPGlog("ECPGconnect: opening database %s %s%s\n", dbname ? dbname : "NULL", user ? "for user ": "", user ? user : "");
- free(name);
- name = NULL;
+ sqlca.sqlcode = 0;
- if (PQstatus(simple_connection) == CONNECTION_BAD)
+ this->connection = PQsetdbLogin(NULL, NULL, NULL, NULL, dbname, user, passwd);
+
+ if (PQstatus(this->connection) == CONNECTION_BAD)
{
- ECPGfinish();
- ECPGlog("connect: could not open database %s\n", dbname);
- register_error(ECPG_CONNECT, "connect: could not open database %s.", dbname);
+ ECPGfinish(this);
+ ECPGlog("connect: could not open database %s %s%s in line %d\n", dbname ? dbname : "NULL", user ? "for user ": "", user ? user : "", lineno);
+
+ register_error(ECPG_CONNECT, "connect: could not open database %s.", dbname ? dbname : "NULL");
return false;
}
+
return true;
}
bool
-ECPGdisconnect(const char *dbname)
+ECPGdisconnect(int lineno, const char *connection_name)
{
- if (strlen(dbname) > 0 && strcmp(PQdb(simple_connection), dbname) != 0)
+ struct connection *con;
+
+ if (strcmp(connection_name, "CURRENT") == 0)
+ ECPGfinish(actual_connection);
+ else if (strcmp(connection_name, "ALL") == 0)
{
- ECPGlog("disconnect: not connected to database %s\n", dbname);
- register_error(ECPG_DISCONNECT, "disconnect: not connected to database %s.", dbname);
- return false;
+ for (con = all_connections; con;)
+ {
+ struct connection *f = con;
+
+ con = con->next;
+ ECPGfinish(f);
+ }
}
- return ECPGfinish();
-}
-
-bool
-ECPGfinish(void)
-{
- if (simple_connection != NULL)
+ else
{
- ECPGlog("ECPGfinish: finishing.\n");
- PQfinish(simple_connection);
+ for (con = all_connections; con && strcmp(con->name, connection_name);con = con->next);
+ if (con == NULL)
+ {
+ ECPGlog("disconnect: not connected to connection %s\n", connection_name);
+ register_error(ECPG_NO_CONN, "No such connection %s in line %d", connection_name, lineno);
+ return false;
+ }
+ else
+ {
+ ECPGfinish(con);
+ }
}
- else
- ECPGlog("ECPGfinish: called an extra time.\n");
+
return true;
}
{
char *f = (char *) malloc(strlen(format) + 100);
+ if (!f)
+ return;
+
sprintf(f, "[%d]: %s", getpid(), format);
va_start(ap, format);
{
if (mode == 1 && when_nf.code != W_NOTHING)
{
+ output_line_number();
fprintf(yyout, "\nif (sqlca.sqlcode == ECPG_NOT_FOUND) ");
print_action(&when_nf);
}
if (when_error.code != W_NOTHING)
{
+ output_line_number();
fprintf(yyout, "\nif (sqlca.sqlcode < 0) ");
print_action(&when_error);
}
static struct variable *
find_struct_member(char *name, char *str, struct ECPGstruct_member *members)
{
- char *next = strpbrk(++str, ".-"), c = '\0';
+ char *next = strchr(++str, '.'), c = '\0';
if (next != NULL)
{
/* found the end */
switch (members->typ->typ)
{
+ case ECPGt_array:
+ return(new_variable(name, ECPGmake_array_type(members->typ->u.element, members->typ->size)));
case ECPGt_struct:
return(new_variable(name, ECPGmake_struct_type(members->typ->u.members)));
default:
else
{
*next = c;
- if (c == '-') next++;
- return(find_struct_member(name, next, members->typ->u.members));
+ if (c == '-')
+ {
+ next++;
+ return(find_struct_member(name, next, members->typ->u.element->u.members));
+ }
+ else return(find_struct_member(name, next, members->typ->u.members));
}
}
}
/* restore the name, we will need it later on */
*next = c;
- if (*next == '-') next++;
-
- return (find_struct_member(name, next, p->type->u.members));
+ if (c == '-')
+ {
+ next++;
+ return (find_struct_member(name, next, p->type->u.element->u.members));
+ }
+ else return (find_struct_member(name, next, p->type->u.members));
}
static struct variable *
return(NULL);
}
+/* Note that this function will end the program in case of an unknown */
+/* variable */
static struct variable *
find_variable(char * name)
{
char * next;
- struct variable * p =
- ((next = strpbrk(name, ".-")) != NULL) ? find_struct(name, next) : find_simple(name);
+ struct variable * p;
+
+ if ((next = strchr(name, '.')) != NULL)
+ p = find_struct(name, next);
+ else if ((next = strstr(name, "->")) != NULL)
+ p = find_struct(name, next);
+ else
+ p = find_simple(name);
if (p == NULL)
{
struct arguments * next;
};
-
static struct arguments * argsinsert = NULL;
static struct arguments * argsresult = NULL;
}
/* special embedded SQL token */
-%token SQL_BREAK SQL_CALL SQL_CONNECT SQL_CONTINUE SQL_DISCONNECT SQL_FOUND SQL_GO SQL_GOTO
-%token SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN SQL_RELEASE
+%token SQL_BREAK SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
+%token SQL_DISCONNECT SQL_FOUND SQL_GO SQL_GOTO
+%token SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN SQL_RELEASE
%token SQL_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START
%token SQL_STOP SQL_WHENEVER
PARTIAL, POSITION, PRECISION, PRIMARY, PRIVILEGES, PROCEDURE, PUBLIC,
REFERENCES, REVOKE, RIGHT, ROLLBACK,
SECOND_P, SELECT, SET, SUBSTRING,
- TABLE, TIME, TIMESTAMP, TO, TRAILING, TRANSACTION, TRIM,
- UNION, UNIQUE, UPDATE, USING,
+ TABLE, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE,
+ TO, TRAILING, TRANSACTION, TRIM,
+ UNION, UNIQUE, UPDATE, USER, USING,
VALUES, VARCHAR, VARYING, VIEW,
WHERE, WITH, WORK, YEAR_P, ZONE
*
* Todd A. Brandys
*/
-%token USER, PASSWORD, CREATEDB, NOCREATEDB, CREATEUSER, NOCREATEUSER, VALID, UNTIL
+%token PASSWORD, CREATEDB, NOCREATEDB, CREATEUSER, NOCREATEUSER, VALID, UNTIL
/* Special keywords, not in the query language - see the "lex" file */
%token <str> IDENT SCONST Op CSTRING CVARIABLE
%type <str> sortby OptUseOp opt_inh_star relation_name_list name_list
%type <str> group_clause groupby_list groupby having_clause from_clause
%type <str> from_list from_val join_expr join_outer join_spec join_list
-%type <str> join_using where_clause relation_expr
+%type <str> join_using where_clause relation_expr row_op sub_type
%type <str> opt_column_list insert_rest InsertStmt
%type <str> columnList DeleteStmt LockStmt UpdateStmt CursorStmt
%type <str> NotifyStmt columnElem copy_dirn OptimizableStmt
%type <str> DestroydbStmt ClusterStmt grantee RevokeStmt
%type <str> GrantStmt privileges operation_commalist operation
-%type <str> ECPGWhenever ECPGConnect db_name ECPGOpen open_opts
+%type <str> ECPGWhenever ECPGConnect connection_target ECPGOpen open_opts
%type <str> indicator ECPGExecute c_expr variable_list dotext
%type <str> storage_clause opt_initializer vartext c_anything blockstart
%type <str> blockend variable_list variable var_anything sql_anything
%type <str> opt_pointer ecpg_ident cvariable ECPGDisconnect dis_name
-%type <str> stmt symbol opt_symbol ECPGRelease execstring
+%type <str> stmt symbol opt_symbol ECPGRelease execstring server_name
+%type <str> connection_object opt_server opt_port
+%type <str> user_name opt_user char_variable ora_user ident
+%type <str> db_prefix server opt_options opt_connection_name
+%type <str> ECPGSetConnection
%type <type_enum> simple_type type struct_type
| VariableShowStmt { output_statement($1, 0); }
| VariableResetStmt { output_statement($1, 0); }
| ECPGConnect {
- fprintf(yyout, "ECPGconnect(\"%s\");", $1);
+ fprintf(yyout, "ECPGconnect(__LINE__, %s);", $1);
whenever_action(0);
free($1);
}
| ECPGDisconnect {
- fprintf(yyout, "ECPGdisconnect(\"%s\");", $1);
+ fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1);
whenever_action(0);
free($1);
}
}
| ECPGOpen { output_statement($1, 0); }
| ECPGRelease { /* output already done */ }
+ | ECPGSetConnection {
+ fprintf(yyout, "ECPGsetcon(__LINE__, %s);", $1);
+ whenever_action(0);
+ free($1);
+ }
| ECPGWhenever {
fputs($1, yyout);
output_line_number();
| /*EMPTY*/ { $$ = make1_str(""); }
;
-user_valid_clause: VALID UNTIL SCONST { $$ = cat2_str(make1_str("valid until"), $3);; }
+user_valid_clause: VALID UNTIL Sconst { $$ = cat2_str(make1_str("valid until"), $3);; }
| /*EMPTY*/ { $$ = make1_str(""); }
;
{
$$ = cat2_str(make1_str("set time zone"), $4);
}
+
;
var_value: Sconst { $$ = $1; }
$$ = "current_timestamp";
}
| CURRENT_USER
- { $$ = make1_str("current user"); }
+ { $$ = make1_str("current_user"); }
+ | USER
+ { $$ = make1_str("user"); }
;
/* ConstraintElem specifies constraint syntax which is not embedded into
$$ = make_name();
}
| Sconst { $$ = $1; }
- | ecpg_ident { $$ = $1; }
+ | ident { $$ = $1; }
;
DropTrigStmt: DROP TRIGGER name ON relation_name
having_clause: HAVING a_expr
{
+#if FALSE
yyerror("HAVING clause not yet implemented");
-/* $$ = cat2_str(make1_str("having"), $2); use this line instead to enable HAVING */
+#endif
+ $$ = cat2_str(make1_str("having"), $2);
}
| /*EMPTY*/ { $$ = make1_str(""); }
;
}
;
-generic: ecpg_ident { $$ = $1; }
+generic: ident { $$ = $1; }
| TYPE_P { $$ = make1_str("type"); }
;
Character: character '(' Iconst ')'
{
if (strncasecmp($1, "char", strlen("char")) && strncasecmp($1, "varchar", strlen("varchar")))
- yyerror("parse error");
+ yyerror("internal parsing error; unrecognized character type");
if (atol($3) < 1) {
sprintf(errortext, "length for '%s' type must be at least 1",$1);
yyerror(errortext);
character: CHARACTER opt_varying opt_charset opt_collate
{
- if (strlen($4) > 0) {
- sprintf(errortext, "COLLATE %s not yet implemented",$4);
- yyerror(errortext);
- }
+ if (strlen($4) > 0)
+ fprintf(stderr, "COLLATE %s not yet implemented",$4);
+
$$ = cat4_str(make1_str("character"), $2, $3, $4);
}
| CHAR opt_varying { $$ = cat2_str(make1_str("char"), $2); }
| DAY_P TO MINUTE_P { $$ = make1_str("day to minute"); }
| DAY_P TO SECOND_P { $$ = make1_str("day to second"); }
| HOUR_P TO MINUTE_P { $$ = make1_str("hour to minute"); }
+ | MINUTE_P TO SECOND_P { $$ = make1_str("minute to second"); }
| HOUR_P TO SECOND_P { $$ = make1_str("hour to second"); }
| /*EMPTY*/ { $$ = make1_str(""); }
;
/* Expressions using row descriptors
* Define row_descriptor to allow yacc to break the reduce/reduce conflict
* with singleton expressions.
+ * Eliminated lots of code by defining row_op and sub_type clauses.
+ * However, can not consolidate EXPR_LINK case with others subselects
+ * due to shift/reduce conflict with the non-subselect clause (the parser
+ * would have to look ahead more than one token to resolve the conflict).
+ * - thomas 1998-05-09
*/
row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
{
{
$$ = make5_str(make1_str("("), $2, make1_str(") not in ("), $7, make1_str(")"));
}
- | '(' row_descriptor ')' Op '(' SubSelect ')'
- {
- $$ = make3_str(make5_str(make1_str("("), $2, make1_str(")"), $4, make1_str("(")), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '+' '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")+("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '-' '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")-("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '/' '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")/("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '*' '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")*("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '<' '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")<("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '>' '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")>("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '=' '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")=("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' Op ANY '(' SubSelect ')'
- {
- $$ = cat3_str(make3_str(make1_str("("), $2, make1_str(")")), $4, make3_str(make1_str("any("), $7, make1_str(")")));
- }
- | '(' row_descriptor ')' '+' ANY '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")+any("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '-' ANY '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")-any("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '/' ANY '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")/any("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '*' ANY '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")*any("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '<' ANY '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")<any("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '>' ANY '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")>any("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '=' ANY '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")=any("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' Op ALL '(' SubSelect ')'
- {
- $$ = cat3_str(make3_str(make1_str("("), $2, make1_str(")")), $4, make3_str(make1_str("all("), $7, make1_str(")")));
- }
- | '(' row_descriptor ')' '+' ALL '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")+all("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '-' ALL '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")-all("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '/' ALL '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")/all("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '*' ALL '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")*all("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '<' ALL '(' SubSelect ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")<all("), $7, make1_str(")"));
- }
- | '(' row_descriptor ')' '>' ALL '(' SubSelect ')'
+ | '(' row_descriptor ')' row_op sub_type '(' SubSelect ')'
{
- $$ = make5_str(make1_str("("), $2, make1_str(")>all("), $7, make1_str(")"));
+ $$ = make4_str(make5_str(make1_str("("), $2, make1_str(")"), $4, $5), make1_str("("), $7, make1_str(")"));
}
- | '(' row_descriptor ')' '=' ALL '(' SubSelect ')'
+ | '(' row_descriptor ')' row_op '(' SubSelect ')'
{
- $$ = make5_str(make1_str("("), $2, make1_str(")=all("), $7, make1_str(")"));
+ $$ = make3_str(make5_str(make1_str("("), $2, make1_str(")"), $4, make1_str("(")), $6, make1_str(")"));
}
- | '(' row_descriptor ')' Op '(' row_descriptor ')'
+ | '(' row_descriptor ')' row_op '(' row_descriptor ')'
{
$$ = cat3_str(make3_str(make1_str("("), $2, make1_str(")")), $4, make3_str(make1_str("("), $6, make1_str(")")));
}
- | '(' row_descriptor ')' '+' '(' row_descriptor ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")+("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '-' '(' row_descriptor ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")-("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '/' '(' row_descriptor ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")/("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '*' '(' row_descriptor ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")*("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '<' '(' row_descriptor ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")<("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '>' '(' row_descriptor ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")>("), $6, make1_str(")"));
- }
- | '(' row_descriptor ')' '=' '(' row_descriptor ')'
- {
- $$ = make5_str(make1_str("("), $2, make1_str(")=("), $6, make1_str(")"));
- }
;
row_descriptor: row_list ',' a_expr
}
;
+row_op: Op { $$ = $1; }
+ | '<' { $$ = "<"; }
+ | '=' { $$ = "="; }
+ | '>' { $$ = ">"; }
+ | '+' { $$ = "+"; }
+ | '-' { $$ = "-"; }
+ | '*' { $$ = "*"; }
+ | '/' { $$ = "/"; }
+ ;
+
+sub_type: ANY { $$ = make1_str("ANY"); }
+ | ALL { $$ = make1_str("ALL"); }
+ ;
+
+
row_list: row_list ',' a_expr
{
$$ = cat3_str($1, make1_str(","), $3);
{
$$ = make1_str("current_user");
}
+ | USER
+ {
+ $$ = make1_str("user");
+ }
+
| EXISTS '(' SubSelect ')'
{
$$ = make3_str(make1_str("exists("), $3, make1_str(")"));
{
$$ = make1_str("current_user");
}
+ | USER
+ {
+ $$ = make1_str("user");
+ }
| POSITION '(' position_list ')'
{
$$ = make3_str(make1_str("position ("), $3, make1_str(")"));
{ $$ = make1_str(";;"); }
;
-/* Add in TIMEZONE_HOUR and TIMEZONE_MINUTE for SQL92 compliance
- * for next release. Just set up extract_arg for now...
- * - thomas 1998-04-08
- */
-extract_arg: datetime
- { $$ = $1; }
+extract_arg: datetime { $$ = $1; }
+ | TIMEZONE_HOUR { $$ = make1_str("timezone_hour"); }
+ | TIMEZONE_MINUTE { $$ = make1_str("timezone_minute"); }
;
position_list: position_expr IN position_expr
;
database_name: ColId { $$ = $1; };
-access_method: ecpg_ident { $$ = $1; };
+access_method: ident { $$ = $1; };
attr_name: ColId { $$ = $1; };
-class: ecpg_ident { $$ = $1; };
+class: ident { $$ = $1; };
index_name: ColId { $$ = $1; };
/* Functions
func_name: ColId { $$ = $1; };
file_name: Sconst { $$ = $1; };
-recipe_name: ecpg_ident { $$ = $1; };
+recipe_name: ident { $$ = $1; };
/* Constants
* Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
strcpy($$+1, $1);
$$[strlen($1)+2]='\0';
$$[strlen($1)+1]='\'';
+ free($1);
}
-UserId: ecpg_ident { $$ = $1;};
+UserId: ident { $$ = $1;};
/* Column and type identifier
* Does not include explicit datetime types
* list due to shift/reduce conflicts in yacc. If so, move
* down to the ColLabel entity. - thomas 1997-11-06
*/
-ColId: ecpg_ident { $$ = $1; }
+ColId: ident { $$ = $1; }
| datetime { $$ = $1; }
| ACTION { $$ = make1_str("action"); }
| CACHE { $$ = make1_str("cache"); }
| START { $$ = make1_str("start"); }
| STATEMENT { $$ = make1_str("statement"); }
| TIME { $$ = make1_str("time"); }
+ | TIMEZONE_HOUR { $$ = make1_str("timezone_hour"); }
+ | TIMEZONE_MINUTE { $$ = make1_str("timezone_minute"); }
| TRIGGER { $$ = make1_str("trigger"); }
| TYPE_P { $$ = make1_str("type"); }
- | USER { $$ = make1_str("user"); }
| VALID { $$ = make1_str("valid"); }
| VERSION { $$ = make1_str("version"); }
| ZONE { $$ = make1_str("zone"); }
if (struct_level == 0)
new_variable($2, type);
else
- ECPGmake_struct_member($2, type, &(struct_member_list[struct_level-1]));
-
+ ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]))->typ;
+
free($1);
free($2);
free($3.str);
/*
* the exec sql connect statement: connect to the given database
*/
-ECPGConnect: SQL_CONNECT db_name { $$ = $2; }
+ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user
+ {
+ $$ = make5_str($3, make1_str(","), $5, make1_str(","), $4);
+ }
+ | SQL_CONNECT TO DEFAULT
+ {
+ $$ = make1_str("NULL,NULL,NULL,\"DEFAULT\"");
+ }
+ /* also allow ORACLE syntax */
+ | SQL_CONNECT ora_user
+ {
+ $$ = make3_str(make1_str("NULL,"), $2, make1_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);
+ yyerror(errortext);
+ }
-db_name: database_name { $$ = $1; }
- | cvariable { /* check if we have a char variable */
+ $$ = make5_str(make1_str("\""), $1, $2, $3, make1_str("\""));
+ }
+ | db_prefix server opt_port '/' database_name opt_options
+ {
+ /* new style: esql:postgresql://server[:port][/dbname] */
+ if (strncmp($2, "://", 3) != 0)
+ {
+ sprintf(errortext, "parse error at or near '%s'", $2);
+ yyerror(errortext);
+ }
+
+ $$ = make4_str(make5_str(make1_str("\""), $1, $2, $3, make1_str("/")), $5, $6, make1_str("\""));
+ }
+ | char_variable
+ {
+ $$ = $1;
+ }
+
+db_prefix: ident cvariable
+ {
+ if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
+ {
+ sprintf(errortext, "parse error at or near '%s'", $2);
+ yyerror(errortext);
+ }
+
+ if (strcmp($1, "esql") != 0 && strcmp($1, "ecpg") != 0 && strcmp($1, "sql") != 0 && strcmp($1, "isql") != 0 && strcmp($1, "proc") != 0)
+ {
+ sprintf(errortext, "Illegal connection type %s", $1);
+ yyerror(errortext);
+ }
+
+ $$ = make3_str($1, make1_str(":"), $2);
+ }
+
+server: Op server_name
+ {
+ if (strcmp($1, "@") != 0 && strcmp($1, "://") != 0)
+ {
+ sprintf(errortext, "parse error at or near '%s'", $1);
+ yyerror(errortext);
+ }
+
+ $$ = make2_str($1, $2);
+ }
+
+opt_server: server { $$ = $1; }
+ | /* empty */ { $$ = make1_str(""); }
+
+server_name: ColId { $$ = $1; }
+ | ColId '.' server_name { $$ = make3_str($1, make1_str("."), $3); }
+
+opt_port: ':' Iconst { $$ = make2_str(make1_str(":"), $2); }
+ | /* empty */ { $$ = make1_str(""); }
+
+opt_connection_name: AS connection_target { $$ = $2; }
+ | /* empty */ { $$ = make1_str("NULL"); }
+
+opt_user: USER ora_user { $$ = $2; }
+ | /* empty */ { $$ = make1_str("NULL,NULL"); }
+
+ora_user: user_name
+ {
+ $$ = make2_str($1, make1_str(",NULL"));
+ }
+ | user_name '/' ColId
+ {
+ $$ = make3_str($1, make1_str(","), $3);
+ }
+ | user_name SQL_IDENTIFIED BY user_name
+ {
+ $$ = make3_str($1, make1_str(","), $4);
+ }
+ | user_name USING user_name
+ {
+ $$ = make3_str($1, make1_str(","), $3);
+ }
+
+user_name: UserId { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
+ | char_variable { $$ = $1; }
+ | CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
+ | SCONST { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
+
+char_variable: cvariable
+ { /* check if we have a char variable */
struct variable *p = find_variable($1);
enum ECPGttype typ = p->type->typ;
if (typ == ECPGt_array)
typ = p->type->u.element->typ;
- if (typ != ECPGt_char && typ != ECPGt_unsigned_char)
- yyerror("invalid datatype");
- $$ = $1;
- }
+ switch (typ)
+ {
+ case ECPGt_char:
+ case ECPGt_unsigned_char:
+ $$ = $1;
+ break;
+ case ECPGt_varchar:
+ $$ = make2_str($1, make1_str(".arr"));
+ break;
+ default:
+ yyerror("invalid datatype");
+ break;
+ }
+ }
+
+opt_options: Op ColId
+ {
+ if (strlen($1) == 0)
+ yyerror("parse error");
+
+ if (strcmp($1, "?") != 0)
+ {
+ sprintf(errortext, "parse error at or near %s", $1);
+ yyerror(errortext);
+ }
+
+ $$ = make2_str(make1_str("?"), $2);
+ }
+ | /* empty */ { $$ = make1_str(""); }
/*
* the exec sql disconnect statement: disconnect from the given database
*/
ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
-dis_name: database_name { $$ = $1; }
- | cvariable { /* check if we have a char variable */
- struct variable *p = find_variable($1);
- enum ECPGttype typ = p->type->typ;
+dis_name: connection_object { $$ = $1; }
+ | CURRENT { $$ = make1_str("CURRENT"); }
+ | ALL { $$ = make1_str("ALL"); }
+ | /* empty */ { $$ = make1_str("CURRENT"); }
- /* if array see what's inside */
- if (typ == ECPGt_array)
- typ = p->type->u.element->typ;
-
- if (typ != ECPGt_char && typ != ECPGt_unsigned_char)
- yyerror("invalid datatype");
- $$ = $1;
- }
- | CURRENT { $$ = make1_str(""); }
- | DEFAULT { $$ = make1_str(""); }
- | ALL { $$ = make1_str(""); }
- | /* empty */ { $$ = make1_str(""); }
+connection_object: connection_target { $$ = $1; }
+ | DEFAULT { $$ = make1_str("DEFAULT"); }
/*
* execute a given string as sql command
free($1);
}
+/*
+ * set the actual connection, this needs a differnet handling as the other
+ * set commands
+ */
+ECPGSetConnection: SET SQL_CONNECTION connection_object
+ {
+ $$ = $3;
+ }
/*
* whenever statement: decide what to do in case of error/no data found
* according to SQL standards we miss: SQLSTATE, CONSTRAINT, SQLEXCEPTION
| DO name '(' dotext ')' {
$<action>$.code = W_DO;
$<action>$.command = make4_str($2, make1_str("("), $4, make1_str(")"));
- $<action>$.str = cat2_str(make1_str("do"), $<action>$.command);
+ $<action>$.str = cat2_str(make1_str("do"), strdup($<action>$.command));
}
| DO SQL_BREAK {
$<action>$.code = W_BREAK;
| SQL_CALL name '(' dotext ')' {
$<action>$.code = W_DO;
$<action>$.command = make4_str($2, make1_str("("), $4, make1_str(")"));
- $<action>$.str = cat2_str(make1_str("call"), $<action>$.command);
+ $<action>$.str = cat2_str(make1_str("call"), strdup($<action>$.command));
}
/* some other stuff for ecpg */
add_variable(&argsinsert, find_variable($1), &no_indicator);
}
-cvariable: CVARIABLE { $$ = $1; }
+cvariable: CVARIABLE { $$ = make1_str($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; }
-ecpg_ident: IDENT { $$ = $1; }
+ident: IDENT { $$ = make1_str($1); }
+
+ecpg_ident: ident { $$ = $1; }
| CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
/*
* C stuff