Commit ef567413 authored by Marc G. Fournier's avatar Marc G. Fournier

From: Michael Meskes <meskes@topsystem.de>

+
+ Wed May  6 16:09:45 CEST 1998
+
+       - Some more cleanups in the library.
+
+ Thu May  7 12:34:28 CEST 1998
+
+       - Made CONNECT and DISCONNECT statement more SQL3 compliant.
+       - Changed the API for the ECPGconnect function to be able to handle
+         hostnames and ports
+
+ Fri May  8 13:54:45 CEST 1998
+       - More changes to the parser. The connect statement now allows
+         ORACLE style logins.
+       - db-name is accepted in two ways:
+               - <dbname>[@<server>][:<port>]
+               - esql:postgresql://<server>[:<port>][/<dbname>]
+
+ Mon May 11 10:28:37 CEST 1998
+
+       - Added '? options' to connect call.
+       - Also allow USING as keyword for the password
+
+ Thu May 14 15:09:58 CEST 1998
+
+       - Changed preproc.y and pgc.l according to the parser changes in the
+         backend.
+
+ Fri May 15 09:55:21 CEST 1998
+
+       - Added connection_name handling
+
+
+ Mon May 18 10:33:58 CEST 1998
+
+       - Fixed some more bugs
+       - Set version to 2.3.1
+       - Set library version to 2.2
parent d1c5021c
...@@ -189,3 +189,42 @@ Wed May 6 11:42:48 CEST 1998 ...@@ -189,3 +189,42 @@ Wed May 6 11:42:48 CEST 1998
an example) an example)
- Set version to 2.3.0 - Set version to 2.3.0
- Set library version to 2.1 - Set library version to 2.1
Wed May 6 16:09:45 CEST 1998
- Some more cleanups in the library.
Thu May 7 12:34:28 CEST 1998
- Made CONNECT and DISCONNECT statement more SQL3 compliant.
- Changed the API for the ECPGconnect function to be able to handle
hostnames and ports
Fri May 8 13:54:45 CEST 1998
- More changes to the parser. The connect statement now allows
ORACLE style logins.
- db-name is accepted in two ways:
- <dbname>[@<server>][:<port>]
- esql:postgresql://<server>[:<port>][/<dbname>]
Mon May 11 10:28:37 CEST 1998
- Added '? options' to connect call.
- Also allow USING as keyword for the password
Thu May 14 15:09:58 CEST 1998
- Changed preproc.y and pgc.l according to the parser changes in the
backend.
Fri May 15 09:55:21 CEST 1998
- Added connection_name handling
Mon May 18 10:33:58 CEST 1998
- Fixed some more bugs
- Set version to 2.3.1
- Set library version to 2.2
#ifndef _ECPG_ERROR_H #ifndef _ECPG_ERROR_H
#define _ECPG_ERROR_H #define _ECPG_ERROR_H
#include <errno.h>
/* This is a list of all error codes the embedded SQL program can return */ /* This is a list of all error codes the embedded SQL program can return */
#define ECPG_NO_ERROR 0 #define ECPG_NO_ERROR 0
#define ECPG_NOT_FOUND 100 #define ECPG_NOT_FOUND 100
#define ECPG_PGSQL -1 /* system error codes returned by ecpglib get the correct number,
#define ECPG_UNSUPPORTED -2 * but are made negative
#define ECPG_TOO_MANY_ARGUMENTS -3 */
#define ECPG_TOO_FEW_ARGUMENTS -4 #define ECPG_OUT_OF_MEMORY -ENOMEM
#define ECPG_TRANS -5
#define ECPG_TOO_MANY_MATCHES -6 /* first we have a set of ecpg messages, they start at 200 */
#define ECPG_INT_FORMAT -7 #define ECPG_UNSUPPORTED -200
#define ECPG_UINT_FORMAT -8 #define ECPG_TOO_MANY_ARGUMENTS -201
#define ECPG_FLOAT_FORMAT -9 #define ECPG_TOO_FEW_ARGUMENTS -202
#define ECPG_CONVERT_BOOL -10 #define ECPG_TOO_MANY_MATCHES -203
#define ECPG_EMPTY -11 #define ECPG_INT_FORMAT -204
#define ECPG_CONNECT -12 #define ECPG_UINT_FORMAT -205
#define ECPG_DISCONNECT -13 #define ECPG_FLOAT_FORMAT -206
#define ECPG_CONVERT_BOOL -207
#define ECPG_EMPTY -208
#define ECPG_NO_CONN -209
/* finally the backend error messages, they start at 300 */
#define ECPG_PGSQL -300
#define ECPG_TRANS -301
#define ECPG_CONNECT -302
#endif /* !_ECPG_ERROR_H */ #endif /* !_ECPG_ERROR_H */
...@@ -5,11 +5,11 @@ extern "C" { ...@@ -5,11 +5,11 @@ extern "C" {
#endif #endif
void ECPGdebug(int, FILE *); void ECPGdebug(int, FILE *);
bool ECPGconnect(const char *); bool ECPGsetconn(int, const char *);
bool ECPGconnect(int, const char *, const char *, const char *, const char *);
bool ECPGdo(int, char *,...); bool ECPGdo(int, char *,...);
bool ECPGtrans(int, const char *); bool ECPGtrans(int, const char *);
bool ECPGfinish(void); bool ECPGdisconnect(int, const char *);
bool ECPGdisconnect(const char *);
void ECPGlog(const char *format,...); void ECPGlog(const char *format,...);
......
...@@ -4,7 +4,7 @@ include $(SRCDIR)/Makefile.global ...@@ -4,7 +4,7 @@ include $(SRCDIR)/Makefile.global
PQ_INCLUDE=-I$(SRCDIR)/interfaces/libpq PQ_INCLUDE=-I$(SRCDIR)/interfaces/libpq
SO_MAJOR_VERSION=2 SO_MAJOR_VERSION=2
SO_MINOR_VERSION=1 SO_MINOR_VERSION=2
PORTNAME=@PORTNAME@ PORTNAME=@PORTNAME@
......
...@@ -26,7 +26,13 @@ ...@@ -26,7 +26,13 @@
extern int no_auto_trans; 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 int simple_debug = 0;
static FILE *debugstream = NULL; static FILE *debugstream = NULL;
static int committed = true; static int committed = true;
...@@ -54,6 +60,9 @@ quote_postgres(char *arg) ...@@ -54,6 +60,9 @@ quote_postgres(char *arg)
int i, int i,
ri; ri;
if (!res)
return(res);
for (i = 0, ri = 0; arg[i]; i++, ri++) for (i = 0, ri = 0; arg[i]; i++, ri++)
{ {
switch (arg[i]) switch (arg[i])
...@@ -73,6 +82,40 @@ quote_postgres(char *arg) ...@@ -73,6 +82,40 @@ quote_postgres(char *arg)
} }
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 bool
ECPGdo(int lineno, char *query,...) ECPGdo(int lineno, char *query,...)
{ {
...@@ -195,14 +238,40 @@ ECPGdo(int lineno, char *query,...) ...@@ -195,14 +238,40 @@ ECPGdo(int lineno, char *query,...)
{ {
/* set slen to string length if type is char * */ /* set slen to string length if type is char * */
int slen = (varcharsize == 0) ? strlen((char *) value) : varcharsize; int slen = (varcharsize == 0) ? strlen((char *) value) : varcharsize;
char * tmp;
newcopy = (char *) malloc(slen + 1); 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); strncpy(newcopy, (char *) value, slen);
newcopy[slen] = '\0'; newcopy[slen] = '\0';
mallocedval = (char *) malloc(2 * strlen(newcopy) + 3); 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, "'"); 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, "'"); strcat(mallocedval, "'");
free(newcopy); free(newcopy);
...@@ -215,14 +284,40 @@ ECPGdo(int lineno, char *query,...) ...@@ -215,14 +284,40 @@ ECPGdo(int lineno, char *query,...)
{ {
struct ECPGgeneric_varchar *var = struct ECPGgeneric_varchar *var =
(struct ECPGgeneric_varchar *) value; (struct ECPGgeneric_varchar *) value;
char *tmp;
newcopy = (char *) malloc(var->len + 1); 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); strncpy(newcopy, var->arr, var->len);
newcopy[var->len] = '\0'; newcopy[var->len] = '\0';
mallocedval = (char *) malloc(2 * strlen(newcopy) + 3); 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, "'"); 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, "'"); strcat(mallocedval, "'");
free(newcopy); free(newcopy);
...@@ -249,6 +344,14 @@ ECPGdo(int lineno, char *query,...) ...@@ -249,6 +344,14 @@ ECPGdo(int lineno, char *query,...)
newcopy = (char *) malloc(strlen(copiedquery) newcopy = (char *) malloc(strlen(copiedquery)
+ strlen(tobeinserted) + strlen(tobeinserted)
+ 1); + 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); strcpy(newcopy, copiedquery);
if ((p = strstr(newcopy, ";;")) == NULL) if ((p = strstr(newcopy, ";;")) == NULL)
{ {
...@@ -301,7 +404,7 @@ ECPGdo(int lineno, char *query,...) ...@@ -301,7 +404,7 @@ ECPGdo(int lineno, char *query,...)
if (committed && !no_auto_trans) 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); register_error(ECPG_TRANS, "Error starting transaction line %d.", lineno);
return false; return false;
...@@ -311,15 +414,15 @@ ECPGdo(int lineno, char *query,...) ...@@ -311,15 +414,15 @@ ECPGdo(int lineno, char *query,...)
} }
ECPGlog("ECPGdo line %d: QUERY: %s\n", lineno, copiedquery); ECPGlog("ECPGdo line %d: QUERY: %s\n", lineno, copiedquery);
results = PQexec(simple_connection, copiedquery); results = PQexec(actual_connection->connection, copiedquery);
free(copiedquery); free(copiedquery);
if (results == NULL) if (results == NULL)
{ {
ECPGlog("ECPGdo line %d: error: %s", lineno, ECPGlog("ECPGdo line %d: error: %s", lineno,
PQerrorMessage(simple_connection)); PQerrorMessage(actual_connection->connection));
register_error(ECPG_PGSQL, "Postgres error: %s line %d.", register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
PQerrorMessage(simple_connection), lineno); PQerrorMessage(actual_connection->connection), lineno);
} }
else else
{ {
...@@ -644,9 +747,9 @@ ECPGdo(int lineno, char *query,...) ...@@ -644,9 +747,9 @@ ECPGdo(int lineno, char *query,...)
case PGRES_FATAL_ERROR: case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE: case PGRES_BAD_RESPONSE:
ECPGlog("ECPGdo line %d: Error: %s", ECPGlog("ECPGdo line %d: Error: %s",
lineno, PQerrorMessage(simple_connection)); lineno, PQerrorMessage(actual_connection->connection));
register_error(ECPG_PGSQL, "Error: %s line %d.", register_error(ECPG_PGSQL, "Error: %s line %d.",
PQerrorMessage(simple_connection), lineno); PQerrorMessage(actual_connection->connection), lineno);
status = false; status = false;
break; break;
case PGRES_COPY_OUT: case PGRES_COPY_OUT:
...@@ -667,7 +770,7 @@ ECPGdo(int lineno, char *query,...) ...@@ -667,7 +770,7 @@ ECPGdo(int lineno, char *query,...)
} }
/* check for asynchronous returns */ /* check for asynchronous returns */
notify = PQnotifies(simple_connection); notify = PQnotifies(actual_connection->connection);
if (notify) if (notify)
{ {
ECPGlog("ECPGdo line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n", ECPGlog("ECPGdo line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
...@@ -686,7 +789,7 @@ ECPGtrans(int lineno, const char * transaction) ...@@ -686,7 +789,7 @@ ECPGtrans(int lineno, const char * transaction)
PGresult *res; PGresult *res;
ECPGlog("ECPGtrans line %d action = %s\n", lineno, transaction); 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); register_error(ECPG_TRANS, "Error in transaction processing line %d.", lineno);
return (FALSE); return (FALSE);
...@@ -698,59 +801,101 @@ ECPGtrans(int lineno, const char * transaction) ...@@ -698,59 +801,101 @@ ECPGtrans(int lineno, const char * transaction)
} }
bool bool
ECPGsetdb(PGconn *newcon) ECPGsetconn(int lineno, const char *connection_name)
{ {
ECPGfinish(); struct connection *con = all_connections;
simple_connection = newcon;
for (; con && strcmp(connection_name, con->name) == 0; con=con->next);
if (con)
{
actual_connection = con;
return true; return true;
}
else
{
register_error(ECPG_NO_CONN, "No such connection %s in line %d", connection_name, lineno);
return false;
}
} }
bool 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); struct connection *this = malloc(sizeof(struct connection));
ECPGlog("ECPGconnect: opening database %s\n", name); if (!this)
{
ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
return false;
}
sqlca.sqlcode = 0; if (dbname == NULL && connection_name == NULL)
connection_name = "DEFAULT";
ECPGsetdb(PQsetdb(NULL, NULL, NULL, NULL, name)); /* add connection to our list */
if (connection_name != NULL)
this->name = strdup(connection_name);
else
this->name = strdup(dbname);
free(name); if (all_connections == NULL)
name = NULL; this->next = NULL;
else
this->next = all_connections;
actual_connection = all_connections = this;
ECPGlog("ECPGconnect: opening database %s %s%s\n", dbname ? dbname : "NULL", user ? "for user ": "", user ? user : "");
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(); ECPGfinish(this);
ECPGlog("connect: could not open database %s\n", dbname); 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);
register_error(ECPG_CONNECT, "connect: could not open database %s.", dbname ? dbname : "NULL");
return false; return false;
} }
return true; return true;
} }
bool 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); for (con = all_connections; con;)
register_error(ECPG_DISCONNECT, "disconnect: not connected to database %s.", dbname); {
return false; struct connection *f = con;
}
return ECPGfinish();
}
bool con = con->next;
ECPGfinish(void) ECPGfinish(f);
{ }
if (simple_connection != NULL) }
else
{
for (con = all_connections; con && strcmp(con->name, connection_name);con = con->next);
if (con == NULL)
{ {
ECPGlog("ECPGfinish: finishing.\n"); ECPGlog("disconnect: not connected to connection %s\n", connection_name);
PQfinish(simple_connection); register_error(ECPG_NO_CONN, "No such connection %s in line %d", connection_name, lineno);
return false;
} }
else else
ECPGlog("ECPGfinish: called an extra time.\n"); {
ECPGfinish(con);
}
}
return true; return true;
} }
...@@ -771,6 +916,9 @@ ECPGlog(const char *format,...) ...@@ -771,6 +916,9 @@ ECPGlog(const char *format,...)
{ {
char *f = (char *) malloc(strlen(format) + 100); char *f = (char *) malloc(strlen(format) + 100);
if (!f)
return;
sprintf(f, "[%d]: %s", getpid(), format); sprintf(f, "[%d]: %s", getpid(), format);
va_start(ap, format); va_start(ap, format);
......
...@@ -3,7 +3,7 @@ include $(SRCDIR)/Makefile.global ...@@ -3,7 +3,7 @@ include $(SRCDIR)/Makefile.global
MAJOR_VERSION=2 MAJOR_VERSION=2
MINOR_VERSION=3 MINOR_VERSION=3
PATCHLEVEL=0 PATCHLEVEL=1
CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \ CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
-DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \ -DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \
......
...@@ -24,11 +24,13 @@ static ScanKeyword ScanKeywords[] = { ...@@ -24,11 +24,13 @@ static ScanKeyword ScanKeywords[] = {
{"break", SQL_BREAK}, {"break", SQL_BREAK},
{"call", SQL_CALL}, {"call", SQL_CALL},
{"connect", SQL_CONNECT}, {"connect", SQL_CONNECT},
{"connection", SQL_CONNECTION},
{"continue", SQL_CONTINUE}, {"continue", SQL_CONTINUE},
{"disconnect", SQL_DISCONNECT}, {"disconnect", SQL_DISCONNECT},
{"found", SQL_FOUND}, {"found", SQL_FOUND},
{"go", SQL_GO}, {"go", SQL_GO},
{"goto", SQL_GOTO}, {"goto", SQL_GOTO},
{"identified", SQL_IDENTIFIED},
{"immediate", SQL_IMMEDIATE}, {"immediate", SQL_IMMEDIATE},
{"indicator", SQL_INDICATOR}, {"indicator", SQL_INDICATOR},
{"open", SQL_OPEN}, {"open", SQL_OPEN},
......
#include "parser/keywords.h" #include "parser/keywords.h"
#include <errno.h>
/* variables */ /* variables */
...@@ -47,7 +48,8 @@ extern void yyerror(char *); ...@@ -47,7 +48,8 @@ extern void yyerror(char *);
/* return codes */ /* return codes */
#define OK 0 #define OK 0
#define NO_INCLUDE_FILE 1 #define PARSE_ERROR -1
#define PARSE_ERROR 2 #define ILLEGAL_OPTION -2
#define OUT_OF_MEMORY 3
#define ILLEGAL_OPTION 4 #define NO_INCLUDE_FILE ENOENT
#define OUT_OF_MEMORY ENOMEM
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.1 1998/04/21 13:23:06 scrappy Exp $ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.2 1998/05/18 16:05:00 scrappy Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -189,6 +189,8 @@ static ScanKeyword ScanKeywords[] = { ...@@ -189,6 +189,8 @@ static ScanKeyword ScanKeywords[] = {
{"substring", SUBSTRING}, {"substring", SUBSTRING},
{"table", TABLE}, {"table", TABLE},
{"time", TIME}, {"time", TIME},
{"timezone_hour", TIMEZONE_HOUR},
{"timezone_minute", TIMEZONE_MINUTE},
{"to", TO}, {"to", TO},
{"trailing", TRAILING}, {"trailing", TRAILING},
{"transaction", TRANSACTION}, {"transaction", TRANSACTION},
......
...@@ -139,12 +139,13 @@ self [,()\[\].$\:\+\-\*\/\<\>\=\|] ...@@ -139,12 +139,13 @@ self [,()\[\].$\:\+\-\*\/\<\>\=\|]
op_and_self [\~\!\@\#\%\^\&\|\`\?\$\:\+\-\*\/\<\>\=] op_and_self [\~\!\@\#\%\^\&\|\`\?\$\:\+\-\*\/\<\>\=]
operator {op_and_self}+ operator {op_and_self}+
xminteger {integer}/-
xmreal {real}/{space}*-{digit}
xmstop - xmstop -
integer -?{digit}+ integer [\-]?{digit}+
real -?{digit}+\.{digit}+([Ee][-+]?{digit}+)? /*
real [\-]?{digit}+\.{digit}+([Ee][-+]?{digit}+)?
*/
real [\-]?(((({digit}*\.{digit}+)|({digit}+\.{digit}*))([Ee][-+]?{digit}+)?)|({digit}+[Ee][-+]?{digit}+))
param \${integer} param \${integer}
...@@ -309,7 +310,8 @@ before_comment); ...@@ -309,7 +310,8 @@ before_comment);
<SQL>{typecast} { return TYPECAST; } <SQL>{typecast} { return TYPECAST; }
<SQL>{self}/-[\.0-9] { <SQL>{self}/{space}*-[\.0-9] {
BEGIN(xm);
return (yytext[0]); return (yytext[0]);
} }
<SQL>{self} { return (yytext[0]); } <SQL>{self} { return (yytext[0]); }
......
...@@ -70,11 +70,13 @@ whenever_action(int mode) ...@@ -70,11 +70,13 @@ whenever_action(int mode)
{ {
if (mode == 1 && when_nf.code != W_NOTHING) if (mode == 1 && when_nf.code != W_NOTHING)
{ {
output_line_number();
fprintf(yyout, "\nif (sqlca.sqlcode == ECPG_NOT_FOUND) "); fprintf(yyout, "\nif (sqlca.sqlcode == ECPG_NOT_FOUND) ");
print_action(&when_nf); print_action(&when_nf);
} }
if (when_error.code != W_NOTHING) if (when_error.code != W_NOTHING)
{ {
output_line_number();
fprintf(yyout, "\nif (sqlca.sqlcode < 0) "); fprintf(yyout, "\nif (sqlca.sqlcode < 0) ");
print_action(&when_error); print_action(&when_error);
} }
...@@ -112,7 +114,7 @@ static struct variable * find_variable(char * name); ...@@ -112,7 +114,7 @@ static struct variable * find_variable(char * name);
static struct variable * static struct variable *
find_struct_member(char *name, char *str, struct ECPGstruct_member *members) 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) if (next != NULL)
{ {
...@@ -129,6 +131,8 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member *members) ...@@ -129,6 +131,8 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member *members)
/* found the end */ /* found the end */
switch (members->typ->typ) switch (members->typ->typ)
{ {
case ECPGt_array:
return(new_variable(name, ECPGmake_array_type(members->typ->u.element, members->typ->size)));
case ECPGt_struct: case ECPGt_struct:
return(new_variable(name, ECPGmake_struct_type(members->typ->u.members))); return(new_variable(name, ECPGmake_struct_type(members->typ->u.members)));
default: default:
...@@ -138,8 +142,12 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member *members) ...@@ -138,8 +142,12 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member *members)
else else
{ {
*next = c; *next = c;
if (c == '-') next++; if (c == '-')
return(find_struct_member(name, next, members->typ->u.members)); {
next++;
return(find_struct_member(name, next, members->typ->u.element->u.members));
}
else return(find_struct_member(name, next, members->typ->u.members));
} }
} }
} }
...@@ -159,9 +167,12 @@ find_struct(char * name, char *next) ...@@ -159,9 +167,12 @@ find_struct(char * name, char *next)
/* restore the name, we will need it later on */ /* restore the name, we will need it later on */
*next = c; *next = c;
if (*next == '-') next++; if (c == '-')
{
return (find_struct_member(name, next, p->type->u.members)); 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 * static struct variable *
...@@ -178,12 +189,20 @@ find_simple(char * name) ...@@ -178,12 +189,20 @@ find_simple(char * name)
return(NULL); return(NULL);
} }
/* Note that this function will end the program in case of an unknown */
/* variable */
static struct variable * static struct variable *
find_variable(char * name) find_variable(char * name)
{ {
char * next; char * next;
struct variable * p = struct variable * p;
((next = strpbrk(name, ".-")) != NULL) ? find_struct(name, next) : find_simple(name);
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) if (p == NULL)
{ {
...@@ -231,7 +250,6 @@ struct arguments { ...@@ -231,7 +250,6 @@ struct arguments {
struct arguments * next; struct arguments * next;
}; };
static struct arguments * argsinsert = NULL; static struct arguments * argsinsert = NULL;
static struct arguments * argsresult = NULL; static struct arguments * argsresult = NULL;
...@@ -495,8 +513,9 @@ output_statement(char * stmt, int mode) ...@@ -495,8 +513,9 @@ output_statement(char * stmt, int mode)
} }
/* special embedded SQL token */ /* special embedded SQL token */
%token SQL_BREAK SQL_CALL SQL_CONNECT SQL_CONTINUE SQL_DISCONNECT SQL_FOUND SQL_GO SQL_GOTO %token SQL_BREAK SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
%token SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN SQL_RELEASE %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_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START
%token SQL_STOP SQL_WHENEVER %token SQL_STOP SQL_WHENEVER
...@@ -527,8 +546,9 @@ output_statement(char * stmt, int mode) ...@@ -527,8 +546,9 @@ output_statement(char * stmt, int mode)
PARTIAL, POSITION, PRECISION, PRIMARY, PRIVILEGES, PROCEDURE, PUBLIC, PARTIAL, POSITION, PRECISION, PRIMARY, PRIVILEGES, PROCEDURE, PUBLIC,
REFERENCES, REVOKE, RIGHT, ROLLBACK, REFERENCES, REVOKE, RIGHT, ROLLBACK,
SECOND_P, SELECT, SET, SUBSTRING, SECOND_P, SELECT, SET, SUBSTRING,
TABLE, TIME, TIMESTAMP, TO, TRAILING, TRANSACTION, TRIM, TABLE, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE,
UNION, UNIQUE, UPDATE, USING, TO, TRAILING, TRANSACTION, TRIM,
UNION, UNIQUE, UPDATE, USER, USING,
VALUES, VARCHAR, VARYING, VIEW, VALUES, VARCHAR, VARYING, VIEW,
WHERE, WITH, WORK, YEAR_P, ZONE WHERE, WITH, WORK, YEAR_P, ZONE
...@@ -559,7 +579,7 @@ output_statement(char * stmt, int mode) ...@@ -559,7 +579,7 @@ output_statement(char * stmt, int mode)
* *
* Todd A. Brandys * 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 */ /* Special keywords, not in the query language - see the "lex" file */
%token <str> IDENT SCONST Op CSTRING CVARIABLE %token <str> IDENT SCONST Op CSTRING CVARIABLE
...@@ -620,7 +640,7 @@ output_statement(char * stmt, int mode) ...@@ -620,7 +640,7 @@ output_statement(char * stmt, int mode)
%type <str> sortby OptUseOp opt_inh_star relation_name_list name_list %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> 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> 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> opt_column_list insert_rest InsertStmt
%type <str> columnList DeleteStmt LockStmt UpdateStmt CursorStmt %type <str> columnList DeleteStmt LockStmt UpdateStmt CursorStmt
%type <str> NotifyStmt columnElem copy_dirn OptimizableStmt %type <str> NotifyStmt columnElem copy_dirn OptimizableStmt
...@@ -650,12 +670,16 @@ output_statement(char * stmt, int mode) ...@@ -650,12 +670,16 @@ output_statement(char * stmt, int mode)
%type <str> DestroydbStmt ClusterStmt grantee RevokeStmt %type <str> DestroydbStmt ClusterStmt grantee RevokeStmt
%type <str> GrantStmt privileges operation_commalist operation %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> indicator ECPGExecute c_expr variable_list dotext
%type <str> storage_clause opt_initializer vartext c_anything blockstart %type <str> storage_clause opt_initializer vartext c_anything blockstart
%type <str> blockend variable_list variable var_anything sql_anything %type <str> blockend variable_list variable var_anything sql_anything
%type <str> opt_pointer ecpg_ident cvariable ECPGDisconnect dis_name %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 %type <type_enum> simple_type type struct_type
...@@ -721,12 +745,12 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -721,12 +745,12 @@ stmt: AddAttrStmt { output_statement($1, 0); }
| VariableShowStmt { output_statement($1, 0); } | VariableShowStmt { output_statement($1, 0); }
| VariableResetStmt { output_statement($1, 0); } | VariableResetStmt { output_statement($1, 0); }
| ECPGConnect { | ECPGConnect {
fprintf(yyout, "ECPGconnect(\"%s\");", $1); fprintf(yyout, "ECPGconnect(__LINE__, %s);", $1);
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
| ECPGDisconnect { | ECPGDisconnect {
fprintf(yyout, "ECPGdisconnect(\"%s\");", $1); fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1);
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
...@@ -737,6 +761,11 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -737,6 +761,11 @@ stmt: AddAttrStmt { output_statement($1, 0); }
} }
| ECPGOpen { output_statement($1, 0); } | ECPGOpen { output_statement($1, 0); }
| ECPGRelease { /* output already done */ } | ECPGRelease { /* output already done */ }
| ECPGSetConnection {
fprintf(yyout, "ECPGsetcon(__LINE__, %s);", $1);
whenever_action(0);
free($1);
}
| ECPGWhenever { | ECPGWhenever {
fputs($1, yyout); fputs($1, yyout);
output_line_number(); output_line_number();
...@@ -828,7 +857,7 @@ user_group_clause: IN GROUP user_group_list { $$ = cat2_str(make1_str("in group ...@@ -828,7 +857,7 @@ user_group_clause: IN GROUP user_group_list { $$ = cat2_str(make1_str("in group
| /*EMPTY*/ { $$ = make1_str(""); } | /*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(""); } | /*EMPTY*/ { $$ = make1_str(""); }
; ;
...@@ -853,6 +882,7 @@ VariableSetStmt: SET ColId TO var_value ...@@ -853,6 +882,7 @@ VariableSetStmt: SET ColId TO var_value
{ {
$$ = cat2_str(make1_str("set time zone"), $4); $$ = cat2_str(make1_str("set time zone"), $4);
} }
; ;
var_value: Sconst { $$ = $1; } var_value: Sconst { $$ = $1; }
...@@ -1136,7 +1166,9 @@ default_expr: AexprConst ...@@ -1136,7 +1166,9 @@ default_expr: AexprConst
$$ = "current_timestamp"; $$ = "current_timestamp";
} }
| CURRENT_USER | CURRENT_USER
{ $$ = make1_str("current user"); } { $$ = make1_str("current_user"); }
| USER
{ $$ = make1_str("user"); }
; ;
/* ConstraintElem specifies constraint syntax which is not embedded into /* ConstraintElem specifies constraint syntax which is not embedded into
...@@ -1459,7 +1491,7 @@ TriggerFuncArg: Iconst ...@@ -1459,7 +1491,7 @@ TriggerFuncArg: Iconst
$$ = make_name(); $$ = make_name();
} }
| Sconst { $$ = $1; } | Sconst { $$ = $1; }
| ecpg_ident { $$ = $1; } | ident { $$ = $1; }
; ;
DropTrigStmt: DROP TRIGGER name ON relation_name DropTrigStmt: DROP TRIGGER name ON relation_name
...@@ -2434,8 +2466,10 @@ groupby: ColId ...@@ -2434,8 +2466,10 @@ groupby: ColId
having_clause: HAVING a_expr having_clause: HAVING a_expr
{ {
#if FALSE
yyerror("HAVING clause not yet implemented"); 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(""); } | /*EMPTY*/ { $$ = make1_str(""); }
; ;
...@@ -2610,7 +2644,7 @@ Generic: generic ...@@ -2610,7 +2644,7 @@ Generic: generic
} }
; ;
generic: ecpg_ident { $$ = $1; } generic: ident { $$ = $1; }
| TYPE_P { $$ = make1_str("type"); } | TYPE_P { $$ = make1_str("type"); }
; ;
...@@ -2724,7 +2758,7 @@ opt_decimal: '(' Iconst ',' Iconst ')' ...@@ -2724,7 +2758,7 @@ opt_decimal: '(' Iconst ',' Iconst ')'
Character: character '(' Iconst ')' Character: character '(' Iconst ')'
{ {
if (strncasecmp($1, "char", strlen("char")) && strncasecmp($1, "varchar", strlen("varchar"))) 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) { if (atol($3) < 1) {
sprintf(errortext, "length for '%s' type must be at least 1",$1); sprintf(errortext, "length for '%s' type must be at least 1",$1);
yyerror(errortext); yyerror(errortext);
...@@ -2749,10 +2783,9 @@ Character: character '(' Iconst ')' ...@@ -2749,10 +2783,9 @@ Character: character '(' Iconst ')'
character: CHARACTER opt_varying opt_charset opt_collate character: CHARACTER opt_varying opt_charset opt_collate
{ {
if (strlen($4) > 0) { if (strlen($4) > 0)
sprintf(errortext, "COLLATE %s not yet implemented",$4); fprintf(stderr, "COLLATE %s not yet implemented",$4);
yyerror(errortext);
}
$$ = cat4_str(make1_str("character"), $2, $3, $4); $$ = cat4_str(make1_str("character"), $2, $3, $4);
} }
| CHAR opt_varying { $$ = cat2_str(make1_str("char"), $2); } | CHAR opt_varying { $$ = cat2_str(make1_str("char"), $2); }
...@@ -2809,6 +2842,7 @@ opt_interval: datetime { $$ = $1; } ...@@ -2809,6 +2842,7 @@ opt_interval: datetime { $$ = $1; }
| DAY_P TO MINUTE_P { $$ = make1_str("day to minute"); } | DAY_P TO MINUTE_P { $$ = make1_str("day to minute"); }
| DAY_P TO SECOND_P { $$ = make1_str("day to second"); } | DAY_P TO SECOND_P { $$ = make1_str("day to second"); }
| HOUR_P TO MINUTE_P { $$ = make1_str("hour to minute"); } | 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"); } | HOUR_P TO SECOND_P { $$ = make1_str("hour to second"); }
| /*EMPTY*/ { $$ = make1_str(""); } | /*EMPTY*/ { $$ = make1_str(""); }
; ;
...@@ -2831,6 +2865,11 @@ a_expr_or_null: a_expr ...@@ -2831,6 +2865,11 @@ a_expr_or_null: a_expr
/* Expressions using row descriptors /* Expressions using row descriptors
* Define row_descriptor to allow yacc to break the reduce/reduce conflict * Define row_descriptor to allow yacc to break the reduce/reduce conflict
* with singleton expressions. * 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 ')' row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
{ {
...@@ -2840,134 +2879,18 @@ row_expr: '(' row_descriptor ')' IN '(' SubSelect ')' ...@@ -2840,134 +2879,18 @@ row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
{ {
$$ = make5_str(make1_str("("), $2, make1_str(") not in ("), $7, make1_str(")")); $$ = make5_str(make1_str("("), $2, make1_str(") not in ("), $7, make1_str(")"));
} }
| '(' row_descriptor ')' Op '(' SubSelect ')' | '(' row_descriptor ')' row_op sub_type '(' 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(")")); $$ = make4_str(make5_str(make1_str("("), $2, make1_str(")"), $4, $5), make1_str("("), $7, make1_str(")"));
} }
| '(' row_descriptor ')' '<' ANY '(' SubSelect ')' | '(' row_descriptor ')' row_op '(' SubSelect ')'
{ {
$$ = make5_str(make1_str("("), $2, make1_str(")<any("), $7, make1_str(")")); $$ = make3_str(make5_str(make1_str("("), $2, make1_str(")"), $4, make1_str("(")), $6, 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 ')'
{
$$ = 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 ')' 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(")"))); $$ = 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_descriptor: row_list ',' a_expr
...@@ -2976,6 +2899,21 @@ row_descriptor: row_list ',' a_expr ...@@ -2976,6 +2899,21 @@ 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 row_list: row_list ',' a_expr
{ {
$$ = cat3_str($1, make1_str(","), $3); $$ = cat3_str($1, make1_str(","), $3);
...@@ -3089,6 +3027,11 @@ a_expr: attr opt_indirection ...@@ -3089,6 +3027,11 @@ a_expr: attr opt_indirection
{ {
$$ = make1_str("current_user"); $$ = make1_str("current_user");
} }
| USER
{
$$ = make1_str("user");
}
| EXISTS '(' SubSelect ')' | EXISTS '(' SubSelect ')'
{ {
$$ = make3_str(make1_str("exists("), $3, make1_str(")")); $$ = make3_str(make1_str("exists("), $3, make1_str(")"));
...@@ -3358,6 +3301,10 @@ b_expr: attr opt_indirection ...@@ -3358,6 +3301,10 @@ b_expr: attr opt_indirection
{ {
$$ = make1_str("current_user"); $$ = make1_str("current_user");
} }
| USER
{
$$ = make1_str("user");
}
| POSITION '(' position_list ')' | POSITION '(' position_list ')'
{ {
$$ = make3_str(make1_str("position ("), $3, make1_str(")")); $$ = make3_str(make1_str("position ("), $3, make1_str(")"));
...@@ -3417,12 +3364,9 @@ extract_list: extract_arg FROM a_expr ...@@ -3417,12 +3364,9 @@ extract_list: extract_arg FROM a_expr
{ $$ = make1_str(";;"); } { $$ = make1_str(";;"); }
; ;
/* Add in TIMEZONE_HOUR and TIMEZONE_MINUTE for SQL92 compliance extract_arg: datetime { $$ = $1; }
* for next release. Just set up extract_arg for now... | TIMEZONE_HOUR { $$ = make1_str("timezone_hour"); }
* - thomas 1998-04-08 | TIMEZONE_MINUTE { $$ = make1_str("timezone_minute"); }
*/
extract_arg: datetime
{ $$ = $1; }
; ;
position_list: position_expr IN position_expr position_list: position_expr IN position_expr
...@@ -3660,9 +3604,9 @@ relation_name: SpecialRuleRelation ...@@ -3660,9 +3604,9 @@ relation_name: SpecialRuleRelation
; ;
database_name: ColId { $$ = $1; }; database_name: ColId { $$ = $1; };
access_method: ecpg_ident { $$ = $1; }; access_method: ident { $$ = $1; };
attr_name: ColId { $$ = $1; }; attr_name: ColId { $$ = $1; };
class: ecpg_ident { $$ = $1; }; class: ident { $$ = $1; };
index_name: ColId { $$ = $1; }; index_name: ColId { $$ = $1; };
/* Functions /* Functions
...@@ -3673,7 +3617,7 @@ name: ColId { $$ = $1; }; ...@@ -3673,7 +3617,7 @@ name: ColId { $$ = $1; };
func_name: ColId { $$ = $1; }; func_name: ColId { $$ = $1; };
file_name: Sconst { $$ = $1; }; file_name: Sconst { $$ = $1; };
recipe_name: ecpg_ident { $$ = $1; }; recipe_name: ident { $$ = $1; };
/* Constants /* Constants
* Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24 * Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
...@@ -3723,8 +3667,9 @@ Sconst: SCONST { ...@@ -3723,8 +3667,9 @@ Sconst: SCONST {
strcpy($$+1, $1); strcpy($$+1, $1);
$$[strlen($1)+2]='\0'; $$[strlen($1)+2]='\0';
$$[strlen($1)+1]='\''; $$[strlen($1)+1]='\'';
free($1);
} }
UserId: ecpg_ident { $$ = $1;}; UserId: ident { $$ = $1;};
/* Column and type identifier /* Column and type identifier
* Does not include explicit datetime types * Does not include explicit datetime types
...@@ -3746,7 +3691,7 @@ TypeId: ColId ...@@ -3746,7 +3691,7 @@ TypeId: ColId
* list due to shift/reduce conflicts in yacc. If so, move * list due to shift/reduce conflicts in yacc. If so, move
* down to the ColLabel entity. - thomas 1997-11-06 * down to the ColLabel entity. - thomas 1997-11-06
*/ */
ColId: ecpg_ident { $$ = $1; } ColId: ident { $$ = $1; }
| datetime { $$ = $1; } | datetime { $$ = $1; }
| ACTION { $$ = make1_str("action"); } | ACTION { $$ = make1_str("action"); }
| CACHE { $$ = make1_str("cache"); } | CACHE { $$ = make1_str("cache"); }
...@@ -3773,9 +3718,10 @@ ColId: ecpg_ident { $$ = $1; } ...@@ -3773,9 +3718,10 @@ ColId: ecpg_ident { $$ = $1; }
| START { $$ = make1_str("start"); } | START { $$ = make1_str("start"); }
| STATEMENT { $$ = make1_str("statement"); } | STATEMENT { $$ = make1_str("statement"); }
| TIME { $$ = make1_str("time"); } | TIME { $$ = make1_str("time"); }
| TIMEZONE_HOUR { $$ = make1_str("timezone_hour"); }
| TIMEZONE_MINUTE { $$ = make1_str("timezone_minute"); }
| TRIGGER { $$ = make1_str("trigger"); } | TRIGGER { $$ = make1_str("trigger"); }
| TYPE_P { $$ = make1_str("type"); } | TYPE_P { $$ = make1_str("type"); }
| USER { $$ = make1_str("user"); }
| VALID { $$ = make1_str("valid"); } | VALID { $$ = make1_str("valid"); }
| VERSION { $$ = make1_str("version"); } | VERSION { $$ = make1_str("version"); }
| ZONE { $$ = make1_str("zone"); } | ZONE { $$ = make1_str("zone"); }
...@@ -4011,7 +3957,7 @@ variable: opt_pointer symbol opt_array_bounds opt_initializer ...@@ -4011,7 +3957,7 @@ variable: opt_pointer symbol opt_array_bounds opt_initializer
if (struct_level == 0) if (struct_level == 0)
new_variable($2, type); new_variable($2, type);
else 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($1);
free($2); free($2);
...@@ -4028,29 +3974,114 @@ opt_pointer: /* empty */ { $$ = make1_str(""); } ...@@ -4028,29 +3974,114 @@ opt_pointer: /* empty */ { $$ = make1_str(""); }
/* /*
* the exec sql connect statement: connect to the given database * 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"));
}
db_name: database_name { $$ = $1; } connection_target: database_name opt_server opt_port
| cvariable { /* check if we have a char variable */ {
struct variable *p = find_variable($1); /* old style: dbname[@server][:port] */
enum ECPGttype typ = p->type->typ; if (strlen($2) > 0 && *($2) != '@')
{
sprintf(errortext, "parse error at or near '%s'", $2);
yyerror(errortext);
}
/* if array see what's inside */ $$ = make5_str(make1_str("\""), $1, $2, $3, make1_str("\""));
if (typ == ECPGt_array) }
typ = p->type->u.element->typ; | 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);
}
if (typ != ECPGt_char && typ != ECPGt_unsigned_char) $$ = make4_str(make5_str(make1_str("\""), $1, $2, $3, make1_str("/")), $5, $6, make1_str("\""));
yyerror("invalid datatype"); }
| char_variable
{
$$ = $1; $$ = $1;
} }
/* db_prefix: ident cvariable
* the exec sql disconnect statement: disconnect from the given database {
*/ if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; } {
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(""); }
dis_name: database_name { $$ = $1; } opt_connection_name: AS connection_target { $$ = $2; }
| cvariable { /* check if we have a char variable */ | /* 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); struct variable *p = find_variable($1);
enum ECPGttype typ = p->type->typ; enum ECPGttype typ = p->type->typ;
...@@ -4058,15 +4089,49 @@ dis_name: database_name { $$ = $1; } ...@@ -4058,15 +4089,49 @@ dis_name: database_name { $$ = $1; }
if (typ == ECPGt_array) if (typ == ECPGt_array)
typ = p->type->u.element->typ; typ = p->type->u.element->typ;
if (typ != ECPGt_char && typ != ECPGt_unsigned_char) switch (typ)
yyerror("invalid datatype"); {
case ECPGt_char:
case ECPGt_unsigned_char:
$$ = $1; $$ = $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);
} }
| CURRENT { $$ = make1_str(""); }
| DEFAULT { $$ = make1_str(""); }
| ALL { $$ = make1_str(""); }
| /* empty */ { $$ = make1_str(""); } | /* empty */ { $$ = make1_str(""); }
/*
* the exec sql disconnect statement: disconnect from the given database
*/
ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
dis_name: connection_object { $$ = $1; }
| CURRENT { $$ = make1_str("CURRENT"); }
| ALL { $$ = make1_str("ALL"); }
| /* empty */ { $$ = make1_str("CURRENT"); }
connection_object: connection_target { $$ = $1; }
| DEFAULT { $$ = make1_str("DEFAULT"); }
/* /*
* execute a given string as sql command * execute a given string as sql command
*/ */
...@@ -4118,6 +4183,14 @@ ECPGRelease: TransactionStmt SQL_RELEASE ...@@ -4118,6 +4183,14 @@ ECPGRelease: TransactionStmt SQL_RELEASE
free($1); 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 * whenever statement: decide what to do in case of error/no data found
* according to SQL standards we miss: SQLSTATE, CONSTRAINT, SQLEXCEPTION * according to SQL standards we miss: SQLSTATE, CONSTRAINT, SQLEXCEPTION
...@@ -4163,7 +4236,7 @@ action : SQL_CONTINUE { ...@@ -4163,7 +4236,7 @@ action : SQL_CONTINUE {
| DO name '(' dotext ')' { | DO name '(' dotext ')' {
$<action>$.code = W_DO; $<action>$.code = W_DO;
$<action>$.command = make4_str($2, make1_str("("), $4, make1_str(")")); $<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 { | DO SQL_BREAK {
$<action>$.code = W_BREAK; $<action>$.code = W_BREAK;
...@@ -4173,7 +4246,7 @@ action : SQL_CONTINUE { ...@@ -4173,7 +4246,7 @@ action : SQL_CONTINUE {
| SQL_CALL name '(' dotext ')' { | SQL_CALL name '(' dotext ')' {
$<action>$.code = W_DO; $<action>$.code = W_DO;
$<action>$.command = make4_str($2, make1_str("("), $4, make1_str(")")); $<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 */ /* some other stuff for ecpg */
...@@ -4478,14 +4551,16 @@ civariableonly : cvariable name { ...@@ -4478,14 +4551,16 @@ civariableonly : cvariable name {
add_variable(&argsinsert, find_variable($1), &no_indicator); add_variable(&argsinsert, find_variable($1), &no_indicator);
} }
cvariable: CVARIABLE { $$ = $1; } cvariable: CVARIABLE { $$ = make1_str($1); }
indicator: /* empty */ { $$ = NULL; } indicator: /* empty */ { $$ = NULL; }
| cvariable { check_indicator((find_variable($1))->type); $$ = $1; } | cvariable { check_indicator((find_variable($1))->type); $$ = $1; }
| SQL_INDICATOR cvariable { check_indicator((find_variable($2))->type); $$ = $2; } | SQL_INDICATOR cvariable { check_indicator((find_variable($2))->type); $$ = $2; }
| SQL_INDICATOR name { 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("\"")); } | CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
/* /*
* C stuff * C stuff
......
...@@ -20,21 +20,6 @@ mm_alloc(size_t size) ...@@ -20,21 +20,6 @@ mm_alloc(size_t size)
return (ptr); return (ptr);
} }
/* realloc + error check */
void *
mm_realloc(void *ptr, size_t size)
{
ptr = realloc(ptr, size);
if (ptr == NULL)
{
fprintf(stderr, "Out of memory\n");
exit(OUT_OF_MEMORY);
}
return (ptr);
}
/* duplicate memberlist */ /* duplicate memberlist */
static struct ECPGstruct_member * static struct ECPGstruct_member *
struct_member_dup(struct ECPGstruct_member * rm) struct_member_dup(struct ECPGstruct_member * rm)
...@@ -43,7 +28,22 @@ struct_member_dup(struct ECPGstruct_member * rm) ...@@ -43,7 +28,22 @@ struct_member_dup(struct ECPGstruct_member * rm)
while (rm) while (rm)
{ {
ECPGmake_struct_member(rm->name, rm->typ, &new); struct ECPGtype *type;
switch(rm->typ->typ)
{
case ECPGt_struct:
type = ECPGmake_struct_type(rm->typ->u.members);
break;
case ECPGt_array:
type = ECPGmake_array_type(ECPGmake_simple_type(rm->typ->u.element->typ, rm->typ->u.element->size), rm->typ->size);
break;
default:
type = ECPGmake_simple_type(rm->typ->typ, rm->typ->size);
break;
}
ECPGmake_struct_member(rm->name, type, &new);
rm = rm->next; rm = rm->next;
} }
...@@ -165,11 +165,11 @@ static const char *get_type(enum ECPGttype typ) ...@@ -165,11 +165,11 @@ static const char *get_type(enum ECPGttype typ)
size is the maxsize in case it is a varchar. Otherwise it is the size of size is the maxsize in case it is a varchar. Otherwise it is the size of
the variable (required to do array fetches of structs). the variable (required to do array fetches of structs).
*/ */
void static void
ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ, ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
long varcharsize, long varcharsize,
long arrsiz, const char *siz, const char *prefix); long arrsiz, const char *siz, const char *prefix);
void static void
ECPGdump_a_struct(FILE *o, const char *name, const char *ind_name, long arrsiz, ECPGdump_a_struct(FILE *o, const char *name, const char *ind_name, long arrsiz,
struct ECPGtype * typ, struct ECPGtype * ind_typ, const char *offset, const char *prefix, const char * ind_prefix); struct ECPGtype * typ, struct ECPGtype * ind_typ, const char *offset, const char *prefix, const char * ind_prefix);
...@@ -223,7 +223,7 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in ...@@ -223,7 +223,7 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in
/* If siz is NULL, then the offset is 0, if not use siz as a /* If siz is NULL, then the offset is 0, if not use siz as a
string, it represents the offset needed if we are in an array of structs. */ string, it represents the offset needed if we are in an array of structs. */
void static void
ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ, ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
long varcharsize, long varcharsize,
long arrsize, long arrsize,
...@@ -272,7 +272,7 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ, ...@@ -272,7 +272,7 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
/* Penetrate a struct and dump the contents. */ /* Penetrate a struct and dump the contents. */
void static void
ECPGdump_a_struct(FILE *o, const char *name, const char * ind_name, long arrsiz, struct ECPGtype * typ, struct ECPGtype * ind_typ, const char *offsetarg, const char *prefix, const char *ind_prefix) ECPGdump_a_struct(FILE *o, const char *name, const char * ind_name, long arrsiz, struct ECPGtype * typ, struct ECPGtype * ind_typ, const char *offsetarg, const char *prefix, const char *ind_prefix)
{ {
...@@ -319,6 +319,7 @@ ECPGfree_struct_member(struct ECPGstruct_member * rm) ...@@ -319,6 +319,7 @@ ECPGfree_struct_member(struct ECPGstruct_member * rm)
rm = rm->next; rm = rm->next;
free(p->name); free(p->name);
free(p->typ);
free(p); free(p);
} }
} }
...@@ -337,7 +338,7 @@ ECPGfree_type(struct ECPGtype * typ) ...@@ -337,7 +338,7 @@ ECPGfree_type(struct ECPGtype * typ)
else if (typ->u.element->typ == ECPGt_struct) else if (typ->u.element->typ == ECPGt_struct)
{ {
/* Array of structs. */ /* Array of structs. */
ECPGfree_struct_member(typ->u.members); ECPGfree_struct_member(typ->u.element->u.members);
free(typ->u.members); free(typ->u.members);
} }
else else
......
...@@ -28,7 +28,7 @@ exec sql begin declare section; ...@@ -28,7 +28,7 @@ exec sql begin declare section;
exec sql end declare section; exec sql end declare section;
struct timeval tvs, tve; struct timeval tvs, tve;
exec sql connect mm; exec sql connect to mm;
exec sql create table perftest1(number int4, ascii char(16)); exec sql create table perftest1(number int4, ascii char(16));
......
...@@ -19,7 +19,7 @@ exec sql end declare section; ...@@ -19,7 +19,7 @@ exec sql end declare section;
ECPGdebug(1, dbgs); ECPGdebug(1, dbgs);
strcpy(msg, "connect"); strcpy(msg, "connect");
exec sql connect mm; exec sql connect to mm;
strcpy(msg, "create"); strcpy(msg, "create");
exec sql create table test(name char(8), amount int); exec sql create table test(name char(8), amount int);
......
...@@ -11,9 +11,9 @@ exec sql begin declare section; ...@@ -11,9 +11,9 @@ exec sql begin declare section;
short age; short age;
} birth; } birth;
} personal; } personal;
struct personal_indicator { short name; struct personal_indicator { short ind_name;
struct birth_indicator { short born; struct birth_indicator { short ind_born;
int age; int ind_age;
} ind_birth; } ind_birth;
} ind_personal; } ind_personal;
long ind_married; long ind_married;
...@@ -26,7 +26,7 @@ exec sql end declare section; ...@@ -26,7 +26,7 @@ exec sql end declare section;
ECPGdebug(1, dbgs); ECPGdebug(1, dbgs);
strcpy(msg, "connect"); strcpy(msg, "connect");
exec sql connect mm; exec sql connect to mm;
strcpy(msg, "create"); strcpy(msg, "create");
exec sql create table meskes(name char(8), born integer, age smallint, married char(8)); exec sql create table meskes(name char(8), born integer, age smallint, married char(8));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment