]> granicus.if.org Git - postgresql/commitdiff
*** empty log message ***
authorMichael Meskes <meskes@postgresql.org>
Wed, 16 Feb 2000 16:18:29 +0000 (16:18 +0000)
committerMichael Meskes <meskes@postgresql.org>
Wed, 16 Feb 2000 16:18:29 +0000 (16:18 +0000)
16 files changed:
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/README.dynSQL [new file with mode: 0644]
src/interfaces/ecpg/TODO
src/interfaces/ecpg/include/Makefile
src/interfaces/ecpg/include/ecpgerrno.h
src/interfaces/ecpg/include/ecpglib.h
src/interfaces/ecpg/include/sql3types.h [new file with mode: 0644]
src/interfaces/ecpg/lib/Makefile.in
src/interfaces/ecpg/lib/dynamic.c [new file with mode: 0644]
src/interfaces/ecpg/lib/ecpglib.c
src/interfaces/ecpg/preproc/ecpg_keywords.c
src/interfaces/ecpg/preproc/extern.h
src/interfaces/ecpg/preproc/preproc.y
src/interfaces/ecpg/preproc/type.h
src/interfaces/ecpg/test/Makefile
src/interfaces/ecpg/test/dyntest.pgc [new file with mode: 0644]

index 3d5828f6ba6bb5f06d8e1b7ab899bee0ca94e351..157f219a303291fb0673e369e0de6aca4be11f2c 100644 (file)
@@ -809,5 +809,10 @@ Tue Feb 15 17:39:19 CET 2000
 Wed Feb 16 11:57:02 CET 2000
 
        - Fixed library to be able to input complete arrays.
+
+Wed Feb 16 17:04:41 CET 2000
+
+       - Apply patch by Christof Petig <christof.petig@wtal.de> that adds
+         descriptors.
        - Set library version to 3.1.0.
        - Set ecpg version to 2.7.0.
diff --git a/src/interfaces/ecpg/README.dynSQL b/src/interfaces/ecpg/README.dynSQL
new file mode 100644 (file)
index 0000000..fedcf80
--- /dev/null
@@ -0,0 +1,20 @@
+descriptor statements have the following shortcomings
+
+- up to now the only reasonable statement is
+       FETCH ... INTO SQL DESCRIPTOR <name>
+  no input variables allowed!
+  
+  Reason: to fully support dynamic SQL the frontend/backend communication
+       should change to recognize input parameters.
+       Since this is not likely to happen in the near future and you
+       can cover the same functionality with the existing infrastructure
+       I'll leave the work to someone else.
+
+- string buffer overflow does not always generate warnings 
+       (beware: terminating 0 may be missing because strncpy is used)
+       :var=data sets sqlwarn accordingly (but not indicator)
+
+- char variables pointing to NULL are not allocated on demand
+       
+- string truncation does not show up in indicator
+
index 542894945d18147d5780e0bd1e0734f40d3e1a14..747a87ac3f6fdbcf21d037e755fda501a27a2e3b 100644 (file)
@@ -18,8 +18,6 @@ cvariable for an array var
 
 How can one insert arrays from c variables?
 
-support for dynamic SQL with unknown number of variables with DESCRIPTORS
-
 What happens to the output variable during read if there was an
 indicator-error? 
 
index db0ea7954e5adbbafdc8db5742867cb0074cdc9b..6ab79fd856bb5d61a47a4620567311a22e28e3ac 100644 (file)
@@ -10,11 +10,13 @@ install::
        $(INSTALL) $(INSTLOPTS) ecpglib.h $(HEADERDIR)  
        $(INSTALL) $(INSTLOPTS) ecpgtype.h $(HEADERDIR) 
        $(INSTALL) $(INSTLOPTS) sqlca.h $(HEADERDIR)    
+       $(INSTALL) $(INSTLOPTS) sql3types.h $(HEADERDIR)        
 
 uninstall::
        rm -f $(HEADERDIR)/ecpgerrno.h
        rm -f $(HEADERDIR)/ecpglib.h
        rm -f $(HEADERDIR)/ecpgtype.h
        rm -f $(HEADERDIR)/sqlca.h
+       rm -f $(HEADERDIR)/sql3types.h
 
 dep depend:
index db2618f31d03c7c47d1c77a2e3725a5473dcde7b..429703a29ca461bc52d44b1cc3526bc99b2b783c 100644 (file)
 
 #define ECPG_INVALID_STMT      -230
 
+/* dynamic SQL related */
+#define ECPG_UNKNOWN_DESCRIPTOR        -240
+#define ECPG_INVALID_DESCRIPTOR_INDEX  -241
+
 /* finally the backend error messages, they start at 400 */
 #define ECPG_PGSQL             -400
 #define ECPG_TRANS             -401
index 9ceb6916954cfd36f1f9d749a4a0681d2becd4a0..f50a2bb09d81d8dee03cde186c84ae0806b86cf1 100644 (file)
@@ -1,4 +1,5 @@
 #include <postgres.h>
+#include <libpq-fe.h>
 
 #ifdef __cplusplus
 extern         "C"
@@ -49,6 +50,17 @@ extern               "C"
 
 #define                  SQLCODE        sqlca.sqlcode
 
+/* dynamic SQL */
+
+       unsigned int    ECPGDynamicType(Oid type);
+       unsigned int    ECPGDynamicType_DDT(Oid type);
+       PGresult *              ECPGresultByDescriptor(int line,const char *name);
+       bool                    ECPGdo_descriptor(int line,const char *connection,
+                                                       const char *descriptor,const char *query);
+       bool                    ECPGdeallocate_desc(int line,const char *name);
+       bool                    ECPGallocate_desc(int line,const char *name);
+       void                    ECPGraise(int line,int code);
+
 #ifdef __cplusplus
 }
 
diff --git a/src/interfaces/ecpg/include/sql3types.h b/src/interfaces/ecpg/include/sql3types.h
new file mode 100644 (file)
index 0000000..c844975
--- /dev/null
@@ -0,0 +1,38 @@
+/* SQL3 dynamic type codes
+ *
+ * Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
+ *
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/include/sql3types.h,v 1.1 2000/02/16 16:18:03 meskes Exp $
+ */
+
+/* chapter 13.1 table 2: Codes used for SQL data types in Dynamic SQL */
+
+enum {         SQL3_CHARACTER=1,
+       SQL3_NUMERIC,
+       SQL3_DECIMAL,
+       SQL3_INTEGER,
+       SQL3_SMALLINT,
+       SQL3_FLOAT,
+       SQL3_REAL,
+       SQL3_DOUBLE_PRECISION,
+       SQL3_DATE_TIME_TIMESTAMP,
+       SQL3_INTERVAL, //10
+       SQL3_CHARACTER_VARYING=12,
+       SQL3_ENUMERATED,
+       SQL3_BIT,
+       SQL3_BIT_VARYING,
+       SQL3_BOOLEAN,
+       SQL3_abstract
+       // the rest is xLOB stuff
+     };
+
+/* chapter 13.1 table 3: Codes associated with datetime data types in Dynamic SQL */
+
+enum { SQL3_DDT_DATE=1,
+       SQL3_DDT_TIME,
+       SQL3_DDT_TIMESTAMP,
+       SQL3_DDT_TIME_WITH_TIME_ZONE,
+       SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE,
+       
+       SQL3_DDT_ILLEGAL /* not a datetime data type (not part of standard) */
+     };
index 296c3c5a409ed2d28c784eeab1bdfc32dadc64c3..947f9fd1a9628c614dcc1b770f1b6788cac655ce 100644 (file)
@@ -6,7 +6,7 @@
 # Copyright (c) 1994, Regents of the University of California
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.57 2000/02/16 11:52:24 meskes Exp $
+#    $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.58 2000/02/16 16:18:05 meskes Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -36,7 +36,7 @@ include $(SRCDIR)/Makefile.shlib
 install: install-lib $(install-shlib-dep)
 
 # Handmade dependencies in case make depend not done
-ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
+ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h dynamic.c
 typename.o : typename.c ../include/ecpgtype.h
 
 
diff --git a/src/interfaces/ecpg/lib/dynamic.c b/src/interfaces/ecpg/lib/dynamic.c
new file mode 100644 (file)
index 0000000..ec8e927
--- /dev/null
@@ -0,0 +1,290 @@
+/* dynamic SQL support routines
+ *
+ * Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
+ *
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/dynamic.c,v 1.1 2000/02/16 16:18:12 meskes Exp $
+ */
+
+/* I borrowed the include files from ecpglib.c, maybe we don't need all of them */
+
+#if 0
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <locale.h>
+
+#include <libpq-fe.h>
+#include <libpq/pqcomm.h>
+#include <ecpgtype.h>
+#include <ecpglib.h>
+#include <sqlca.h>
+#endif
+#include <sql3types.h>
+
+static struct descriptor
+{      char *name;
+       PGresult *result;
+       struct descriptor *next;
+} *all_descriptors=NULL;
+
+PGconn *ECPG_internal_get_connection(char *name);
+
+unsigned int ECPGDynamicType(Oid type)
+{      switch(type)
+       {       case 16:        return SQL3_BOOLEAN;    /* bool */
+               case 21:        return SQL3_SMALLINT;   /* int2 */
+               case 23:        return SQL3_INTEGER;    /* int4 */
+               case 25:        return SQL3_CHARACTER;  /* text */
+               case 700:       return SQL3_REAL;               /* float4 */
+               case 701:       return SQL3_DOUBLE_PRECISION;   /* float8 */
+               case 1042:      return SQL3_CHARACTER;  /* bpchar */
+               case 1043:      return SQL3_CHARACTER_VARYING;  /* varchar */
+               case 1082:      return SQL3_DATE_TIME_TIMESTAMP;        /* date */
+               case 1083:      return SQL3_DATE_TIME_TIMESTAMP;        /* time */
+               case 1184:      return SQL3_DATE_TIME_TIMESTAMP;        /* datetime */
+               case 1296:      return SQL3_DATE_TIME_TIMESTAMP;        /* timestamp */
+               case 1700:      return SQL3_NUMERIC;    /* numeric */
+               default:
+                       return -type;
+       }
+}
+
+unsigned int ECPGDynamicType_DDT(Oid type)
+{      switch(type)
+       {       
+               case 1082:      return SQL3_DDT_DATE;   /* date */
+               case 1083:      return SQL3_DDT_TIME;   /* time */
+               case 1184:      return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;       /* datetime */
+               case 1296:      return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;       /* timestamp */
+               default:
+                       return SQL3_DDT_ILLEGAL;
+       }
+}
+
+// like ECPGexecute
+static bool execute_descriptor(int lineno,const char *query
+                                                       ,struct connection *con,PGresult **resultptr)
+{
+       bool    status = false;
+       PGresult   *results;
+       PGnotify   *notify;
+       
+       /* Now the request is built. */
+
+       if (con->committed && !con->autocommit)
+       {
+               if ((results = PQexec(con->connection, "begin transaction")) == NULL)
+               {
+                       register_error(ECPG_TRANS, "Error in transaction processing line %d.", lineno);
+                       return false;
+               }
+               PQclear(results);
+               con->committed = false;
+       }
+
+       ECPGlog("execute_descriptor line %d: QUERY: %s on connection %s\n", lineno, query, con->name);
+       results = PQexec(con->connection, query);
+
+       if (results == NULL)
+       {
+               ECPGlog("ECPGexecute line %d: error: %s", lineno,
+                               PQerrorMessage(con->connection));
+               register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
+                        PQerrorMessage(con->connection), lineno);
+       }
+       else
+       {       *resultptr=results;
+               switch (PQresultStatus(results))
+               {       int ntuples;
+                       case PGRES_TUPLES_OK:
+                               status = true;
+                               sqlca.sqlerrd[2] = ntuples = PQntuples(results);
+                               if (ntuples < 1)
+                               {
+                                       ECPGlog("execute_descriptor line %d: Incorrect number of matches: %d\n",
+                                                       lineno, ntuples);
+                                       register_error(ECPG_NOT_FOUND, "No data found line %d.", lineno);
+                                       status = false;
+                                       break;
+                               }
+                               break;
+#if 1 /* strictly these are not needed (yet) */
+                       case PGRES_EMPTY_QUERY:
+                               /* do nothing */
+                               register_error(ECPG_EMPTY, "Empty query line %d.", lineno);
+                               break;
+                       case PGRES_COMMAND_OK:
+                               status = true;
+                               sqlca.sqlerrd[1] = atol(PQoidStatus(results));
+                               sqlca.sqlerrd[2] = atol(PQcmdTuples(results));
+                               ECPGlog("ECPGexecute line %d Ok: %s\n", lineno, PQcmdStatus(results));
+                               break;
+                       case PGRES_COPY_OUT:
+                               ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", lineno);
+                               PQendcopy(con->connection);
+                               break;
+                       case PGRES_COPY_IN:
+                               ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", lineno);
+                               PQendcopy(con->connection);
+                               break;
+#else
+                       case PGRES_EMPTY_QUERY:
+                       case PGRES_COMMAND_OK:
+                       case PGRES_COPY_OUT:
+                       case PGRES_COPY_IN:
+                               break;
+#endif
+                       case PGRES_NONFATAL_ERROR:
+                       case PGRES_FATAL_ERROR:
+                       case PGRES_BAD_RESPONSE:
+                               ECPGlog("ECPGexecute line %d: Error: %s",
+                                               lineno, PQerrorMessage(con->connection));
+                               register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
+                                                          PQerrorMessage(con->connection), lineno);
+                               status = false;
+                               break;
+                       default:
+                               ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
+                                               lineno);
+                               register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
+                                                          PQerrorMessage(con->connection), lineno);
+                               status = false;
+                               break;
+               }
+       }
+
+       /* check for asynchronous returns */
+       notify = PQnotifies(con->connection);
+       if (notify)
+       {
+               ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
+                               lineno, notify->relname, notify->be_pid);
+               free(notify);
+       }
+       return status;
+}
+
+/* like ECPGdo */
+static bool do_descriptor2(int lineno,const char *connection_name,
+                                       PGresult **resultptr, const char *query)
+{
+       struct connection *con = get_connection(connection_name);
+       bool            status=true;
+       char *locale = setlocale(LC_NUMERIC, NULL);
+
+       /* Make sure we do NOT honor the locale for numeric input/output */
+       /* since the database wants teh standard decimal point */
+       setlocale(LC_NUMERIC, "C");
+
+       if (!ecpg_init(con, connection_name, lineno))
+       {       setlocale(LC_NUMERIC, locale);
+               return(false);
+       }
+
+       /* are we connected? */
+       if (con == NULL || con->connection == NULL)
+       {
+               ECPGlog("ECPGdo: not connected to %s\n", con->name);
+               register_error(ECPG_NOT_CONN, "Not connected in line %d.", lineno);
+               setlocale(LC_NUMERIC, locale);
+               return false;
+       }
+
+       status = execute_descriptor(lineno,query,con,resultptr);
+
+       /* and reset locale value so our application is not affected */
+       setlocale(LC_NUMERIC, locale);
+       return (status);
+}
+
+bool ECPGdo_descriptor(int line,const char *connection,
+                                                       const char *descriptor,const char *query)
+{
+       struct descriptor *i;
+       for (i=all_descriptors;i!=NULL;i=i->next)
+       {       if (!strcmp(descriptor,i->name)) 
+           {   
+                       bool status;
+
+                       /* free previous result */
+                       if (i->result) PQclear(i->result);
+               i->result=NULL;
+               
+                       status=do_descriptor2(line,connection,&i->result,query);
+                       
+                       if (!i->result) PQmakeEmptyPGresult(NULL, 0);
+                       return (status);
+           }
+       }
+       ECPGraise(line,ECPG_UNKNOWN_DESCRIPTOR);
+       return false;
+}
+                                                       
+PGresult *ECPGresultByDescriptor(int line,const char *name)
+{
+       struct descriptor *i;
+       for (i=all_descriptors;i!=NULL;i=i->next)
+       {       if (!strcmp(name,i->name)) return i->result;
+       }
+       ECPGraise(line,ECPG_UNKNOWN_DESCRIPTOR);
+       return 0;
+} 
+
+
+bool ECPGdeallocate_desc(int line,const char *name)
+{
+       struct descriptor *i;
+       struct descriptor **lastptr=&all_descriptors;
+       for (i=all_descriptors;i;lastptr=&i->next,i=i->next)
+       {       if (!strcmp(name,i->name))
+               {       *lastptr=i->next;
+                       free(i->name);
+                       PQclear(i->result);
+                       free(i);
+                       return true;
+               }
+       }
+       ECPGraise(line,ECPG_UNKNOWN_DESCRIPTOR);
+       return false;
+} 
+
+bool ECPGallocate_desc(int line,const char *name)
+{
+       struct descriptor *new=(struct descriptor *)malloc(sizeof(struct descriptor));
+       
+       new->next=all_descriptors;
+       new->name=malloc(strlen(name)+1);
+       new->result=PQmakeEmptyPGresult(NULL, 0);
+       strcpy(new->name,name);
+       all_descriptors=new;
+       return true;
+}
+
+void ECPGraise(int line,int code)
+{      sqlca.sqlcode=code;
+       switch (code)
+       {       case ECPG_NOT_FOUND: 
+                       snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+                               "No data found line %d.",line);
+                       break;
+               case ECPG_MISSING_INDICATOR: 
+                       snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+                               "NULL value without indicator, line %d.",line);
+                       break;
+               case ECPG_UNKNOWN_DESCRIPTOR: 
+                       snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+                               "descriptor not found, line %d.",line);
+                       break;
+               case ECPG_INVALID_DESCRIPTOR_INDEX: 
+                       snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+                               "descriptor index out of range, line %d.",line);
+                       break;
+           default:
+               snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+                               "SQL error #%d, line %d.",code,line);
+                       break;
+       }
+}
index 5074bc20e07a361f6ef580eb784d585e45c43eb8..a6e2b23e01b4802f413e1d844252a90ba9cae85f 100644 (file)
@@ -20,7 +20,6 @@
 #include <ctype.h>
 #include <locale.h>
 
-#include <libpq-fe.h>
 #include <libpq/pqcomm.h>
 #include <ecpgtype.h>
 #include <ecpglib.h>
@@ -753,7 +752,7 @@ ECPGexecute(struct statement * stmt)
                                {
                                        char       *pval;
                                        char       *scan_length;
-                                       char       *array_query;
+                                       char       *array_query;
                                        
                                        if (var == NULL)
                                        {
@@ -1127,36 +1126,44 @@ ECPGexecute(struct statement * stmt)
 bool
 ECPGdo(int lineno, const char *connection_name, char *query,...)
 {
-       va_list         args;
-       struct statement *stmt;
-       struct connection *con = get_connection(connection_name);
-       bool            status;
-       char *locale = setlocale(LC_NUMERIC, NULL);
+       va_list                 args;
+       struct statement        *stmt;
+       struct connection       *con = get_connection(connection_name);
+       bool                    status=true;
+       char                    *locale = setlocale(LC_NUMERIC, NULL);
 
        /* Make sure we do NOT honor the locale for numeric input/output */
        /* since the database wants teh standard decimal point */
        setlocale(LC_NUMERIC, "C");
 
        if (!ecpg_init(con, connection_name, lineno))
+       {
+               setlocale(LC_NUMERIC, locale);
                return(false);
+       }
 
        va_start(args, query);
        if (create_statement(lineno, con, &stmt, query, args) == false)
+       {
+               setlocale(LC_NUMERIC, locale);
                return (false);
+       }
        va_end(args);
 
        /* are we connected? */
        if (con == NULL || con->connection == NULL)
        {
+               free_statement(stmt);
                ECPGlog("ECPGdo: not connected to %s\n", con->name);
                register_error(ECPG_NOT_CONN, "Not connected in line %d.", lineno);
+               setlocale(LC_NUMERIC, locale);
                return false;
        }
 
        status = ECPGexecute(stmt);
        free_statement(stmt);
 
-       /* and reser value so our application is not affected */
+       /* and reset locale value so our application is not affected */
        setlocale(LC_NUMERIC, locale);
        return (status);
 }
@@ -1508,3 +1515,5 @@ ECPGprepared_statement(char *name)
        for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
        return (this) ? this->stmt->command : NULL;
 }
+
+#include "dynamic.c"
index 89676e7c34f33c0dc5a5cc06665c54ebfce43375..0cc7699a6dc3a26336b097193956f066cfd9be61 100644 (file)
@@ -19,6 +19,7 @@
  */
 static ScanKeyword ScanKeywords[] = {
        /* name                                 value                   */
+       {"allocate", SQL_ALLOCATE},
        {"at", SQL_AT},
        {"autocommit", SQL_AUTOCOMMIT},
        {"bool", SQL_BOOL},
@@ -28,10 +29,12 @@ static ScanKeyword ScanKeywords[] = {
        {"connection", SQL_CONNECTION},
        {"continue", SQL_CONTINUE},
        {"deallocate", SQL_DEALLOCATE},
+       {"descriptor", SQL_DESCRIPTOR},
        {"disconnect", SQL_DISCONNECT},
        {"enum", SQL_ENUM},
        {"found", SQL_FOUND},
        {"free", SQL_FREE},
+       {"get", SQL_GET},
        {"go", SQL_GO},
        {"goto", SQL_GOTO},
        {"identified", SQL_IDENTIFIED},
@@ -46,12 +49,14 @@ static ScanKeyword ScanKeywords[] = {
        {"section", SQL_SECTION},
        {"short", SQL_SHORT},
        {"signed", SQL_SIGNED},
+       {"sql",SQL_SQL}, // strange thing, used for into sql descriptor MYDESC;
        {"sqlerror", SQL_SQLERROR},
        {"sqlprint", SQL_SQLPRINT},
        {"sqlwarning", SQL_SQLWARNING},
        {"stop", SQL_STOP},
        {"struct", SQL_STRUCT},
        {"unsigned", SQL_UNSIGNED},
+       {"value", SQL_VALUE},
        {"var", SQL_VAR},
        {"whenever", SQL_WHENEVER},
 };
index 682ead43ec81b9154c66c2632833f16da61b7f80..2a1da562a7bd0a141b97bce00cae7b57d028b805 100644 (file)
@@ -29,6 +29,7 @@ extern struct arguments *argsinsert;
 extern struct arguments *argsresult;
 extern struct when when_error, when_nf, when_warn;
 extern struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH];
+extern struct descriptor *descriptors;
 
 /* functions */
 
index 8abcec55e57f67af51caa85dbed47d3e0d55d189..0c492febf015490705312f59f4ce8e30ebbdd78e 100644 (file)
@@ -23,6 +23,8 @@
 int    struct_level = 0;
 char   errortext[128];
 static char    *connection = NULL;
+static char *descriptor_name = NULL;
+static char *descriptor_index= NULL;
 static int      QueryIsRule = 0, ForUpdateNotAllowed = 0, FoundInto = 0;
 static int     FoundSort = 0;
 static int     initializer = 0;
@@ -38,6 +40,11 @@ struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
 
 struct ECPGtype ecpg_query = {ECPGt_char_variable, 0L, {NULL}};
 
+/* variable lookup */
+
+static struct variable * find_variable(char * name);
+static void whenever_action(int mode);
+
 /*
  * Handle parsing errors and warnings
  */
@@ -80,6 +87,275 @@ output_simple_statement(char *cmd)
         free(cmd);
 }
 
+/*
+ * assignment handling function (descriptor)
+ */
+static struct assignment *assignments;
+
+static void push_assignment(char *var,char *value)
+{
+       struct assignment *new=(struct assignment *)mm_alloc(sizeof(struct assignment));
+       
+       new->next=assignments;
+       new->variable=mm_alloc(strlen(var)+1);
+       strcpy(new->variable,var);
+       new->value=mm_alloc(strlen(value)+1);
+       strcpy(new->value,value);
+       assignments=new;
+}
+
+static void drop_assignments(void)
+{      while (assignments)
+       {       struct assignment *old_head=assignments;
+               assignments=old_head->next;
+               free(old_head->variable);
+               free(old_head->value);
+               free(old_head);
+       }
+}
+
+/* XXX: these should be more accurate (consider ECPGdump_a_* ) */
+static void ECPGnumeric_lvalue(FILE *f,char *name)
+{      const struct variable *v=find_variable(name);
+       switch(v->type->typ)
+       {       case ECPGt_short:
+               case ECPGt_int: 
+               case ECPGt_long:
+               case ECPGt_unsigned_short:
+               case ECPGt_unsigned_int:
+               case ECPGt_unsigned_long:
+                       fputs(name,yyout);
+                       break;
+               default:
+                       snprintf(errortext,sizeof errortext,"variable %s: numeric type needed"
+                                       ,name);
+                       mmerror(ET_ERROR,errortext);
+                       break;
+       }
+}
+
+static void ECPGstring_buffer(FILE *f,char *name)
+{   const struct variable *v=find_variable(name);
+       switch(v->type->typ)
+       {       case ECPGt_varchar:
+                       fprintf(yyout,"%s.arr",name);
+                       break;
+                       
+               case ECPGt_char:
+               case ECPGt_unsigned_char:
+                       fputs(name,yyout);
+                       break;
+                       
+               default:
+                       snprintf(errortext,sizeof errortext,"variable %s: character type needed"
+                                       ,name);
+                       mmerror(ET_ERROR,errortext);
+                       break;
+       }
+}
+
+static void ECPGstring_length(FILE *f,char *name)
+{   const struct variable *v=find_variable(name);
+       switch(v->type->typ)
+       {       case ECPGt_varchar:
+               case ECPGt_char:
+               case ECPGt_unsigned_char:
+                   if (!v->type->size) 
+                   {   snprintf(errortext,sizeof errortext,"zero length char variable %s for assignment",
+                                                                                       v->name);
+                       mmerror(ET_ERROR,errortext);
+                   }
+                       fprintf(yyout,"%ld",v->type->size);
+                       break;
+               default:
+                       snprintf(errortext,sizeof errortext,"variable %s: character type needed"
+                                       ,name);
+                       mmerror(ET_ERROR,errortext);
+                       break;
+       }
+}
+
+static void ECPGdata_assignment(char *variable,char *index_plus_1)
+{      const struct variable *v=find_variable(variable);
+       fprintf(yyout,"\t\t\tif (!PQgetisnull(ECPGresult,0,(%s)-1))\n",index_plus_1);
+       switch(v->type->typ)
+       {       case ECPGt_short:
+               case ECPGt_int: /* use the same conversion as ecpglib does */
+               case ECPGt_long:
+                       fprintf(yyout,"\t\t\t\t%s=strtol(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n"
+                                                                                       ,variable,index_plus_1);
+                       break;
+               case ECPGt_unsigned_short:
+               case ECPGt_unsigned_int:
+               case ECPGt_unsigned_long:
+                       fprintf(yyout,"\t\t\t\t%s=strtoul(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n"
+                                                                                       ,variable,index_plus_1);
+                       break;
+               case ECPGt_float:
+               case ECPGt_double:
+                       fprintf(yyout,"\t\t\t\t%s=strtod(PQgetvalue(ECPGresult,0,(%s)-1),NULL);\n"
+                                                                                       ,variable,index_plus_1);
+                       break;
+                       
+               case ECPGt_bool:
+                       fprintf(yyout,"\t\t\t\t%s=PQgetvalue(ECPGresult,0,(%s)-1)[0]=='t';\n"
+                                                                                       ,variable,index_plus_1);
+                       break;
+               
+               case ECPGt_varchar:
+                       fprintf(yyout,"\t\t\t{\tstrncpy(%s.arr,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n"
+                                                                                       ,variable,index_plus_1,v->type->size);
+                       fprintf(yyout,"\t\t\t\t%s.len=strlen(PQgetvalue(ECPGresult,0,(%s)-1)\n"
+                                                                                       ,variable,index_plus_1);
+                       fprintf(yyout,"\t\t\t\tif (%s.len>%ld) { %s.len=%ld; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n"
+                                                                                       ,variable,v->type->size,variable,v->type->size);
+                       fputs("\t\t\t}\n",yyout);                                                                                       
+                       break;
+                       
+               case ECPGt_char:
+               case ECPGt_unsigned_char:
+                   if (!v->type->size) 
+                   {   snprintf(errortext,sizeof errortext,"zero length char variable %s for DATA assignment",
+                                                                                       v->name);
+                       mmerror(ET_ERROR,errortext);
+                   }
+                       fprintf(yyout,"\t\t\t{\tstrncpy(%s,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n"
+                                                                                       ,variable,index_plus_1,v->type->size);
+                       fprintf(yyout,"\t\t\t\tif (strlen(PQgetvalue(ECPGresult,0,(%s)-1))>=%ld)\n"
+                               "\t\t\t\t{ %s[%ld]=0; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n"
+                                                                                       ,index_plus_1,v->type->size,variable,v->type->size-1);
+                       fputs("\t\t\t}\n",yyout);                                                                                       
+                       break;
+                       
+               default:
+                       snprintf(errortext,sizeof errortext,"unknown variable type %d for DATA assignment"
+                                       ,v->type->typ);
+                       mmerror(ET_ERROR,errortext);
+                       break;
+       }
+}
+
+static void
+output_get_descr_header(char *desc_name)
+{      struct assignment *results;
+       fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n"
+                                                                                                       ,yylineno,desc_name);
+       fputs("\tif (ECPGresult)\n\t{",yyout);
+       for (results=assignments;results!=NULL;results=results->next)
+       {       if (!strcasecmp(results->value,"count"))
+               {       fputs("\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fputs("=PQnfields(ECPGresult);\n",yyout);
+               }
+               else
+               {       snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value);
+                       mmerror(ET_WARN,errortext);
+               }
+       }
+       drop_assignments();
+       fputs("}",yyout);
+       
+       whenever_action(2|1);
+}
+
+static void
+output_get_descr(char *desc_name)
+{      struct assignment *results;
+       int flags=0;
+       const int DATA_SEEN=1;
+       const int INDICATOR_SEEN=2;
+       
+       fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n"
+                                                                                                       ,yylineno,desc_name);
+       fputs("\tif (ECPGresult)\n\t{",yyout);
+       fprintf(yyout,"\tif (PQntuples(ECPGresult)<1) ECPGraise(%d,ECPG_NOT_FOUND);\n",yylineno);
+       fprintf(yyout,"\t\telse if (%s<1 || %s>PQnfields(ECPGresult))\n"
+                       "\t\t\tECPGraise(%d,ECPG_INVALID_DESCRIPTOR_INDEX);\n"
+                               ,descriptor_index,descriptor_index,yylineno);
+       fputs("\t\telse\n\t\t{\n",yyout);
+       for (results=assignments;results!=NULL;results=results->next)
+       {       if (!strcasecmp(results->value,"type"))
+               {       fputs("\t\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fprintf(yyout,"=ECPGDynamicType(PQftype(ECPGresult,(%s)-1));\n",descriptor_index);
+               }
+               else if (!strcasecmp(results->value,"datetime_interval_code"))
+               {       fputs("\t\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fprintf(yyout,"=ECPGDynamicType_DDT(PQftype(ECPGresult,(%s)-1));\n",descriptor_index);
+               }
+               else if (!strcasecmp(results->value,"length"))
+               {       fputs("\t\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)-VARHDRSZ;\n",descriptor_index);
+               }
+               else if (!strcasecmp(results->value,"octet_length"))
+               {       fputs("\t\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fprintf(yyout,"=PQfsize(ECPGresult,(%s)-1);\n",descriptor_index);
+               }
+               else if (!strcasecmp(results->value,"returned_length")
+                       || !strcasecmp(results->value,"returned_octet_length"))
+               {       fputs("\t\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fprintf(yyout,"=PQgetlength(ECPGresult,0,(%s)-1);\n",descriptor_index);
+               }
+               else if (!strcasecmp(results->value,"precision"))
+               {       fputs("\t\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)>>16;\n",descriptor_index);
+               }
+               else if (!strcasecmp(results->value,"scale"))
+               {       fputs("\t\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fprintf(yyout,"=(PQfmod(ECPGresult,(%s)-1)-VARHDRSZ)&0xffff;\n",descriptor_index);
+               }
+               else if (!strcasecmp(results->value,"nullable"))
+               {       mmerror(ET_WARN,"nullable is always 1");
+                       fputs("\t\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fprintf(yyout,"=1;\n");
+               }
+               else if (!strcasecmp(results->value,"key_member"))
+               {       mmerror(ET_WARN,"key_member is always 0");
+                       fputs("\t\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fprintf(yyout,"=0;\n");
+               }
+               else if (!strcasecmp(results->value,"name"))
+               {       fputs("\t\t\tstrncpy(",yyout);
+                       ECPGstring_buffer(yyout,results->variable);
+                       fprintf(yyout,",PQfname(ECPGresult,(%s)-1),",descriptor_index);
+                       ECPGstring_length(yyout,results->variable);
+                       fputs(");\n",yyout);
+               }
+               else if (!strcasecmp(results->value,"indicator"))
+               {       flags|=INDICATOR_SEEN;
+                   fputs("\t\t\t",yyout);
+                       ECPGnumeric_lvalue(yyout,results->variable);
+                       fprintf(yyout,"=-PQgetisnull(ECPGresult,0,(%s)-1);\n",descriptor_index);
+               }
+               else if (!strcasecmp(results->value,"data"))
+               {       flags|=DATA_SEEN;
+                   ECPGdata_assignment(results->variable,descriptor_index);
+               }
+               else
+               {       snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value);
+                       mmerror(ET_WARN,errortext);
+               }
+       }
+       if (flags==DATA_SEEN) /* no indicator */
+       {       fprintf(yyout,"\t\t\tif (PQgetisnull(ECPGresult,0,(%s)-1))\n"
+                                       "\t\t\t\tECPGraise(%d,ECPG_MISSING_INDICATOR);\n"
+                               ,descriptor_index,yylineno);
+       }
+       drop_assignments();
+       fputs("\t\t}\n\t}\n",yyout);
+       
+       whenever_action(2|1);
+}
+
 /*
  * store the whenever action here
  */
@@ -157,8 +433,6 @@ new_variable(const char * name, struct ECPGtype * type)
     return(p);
 }
 
-static struct variable * find_variable(char * name);
-
 static struct variable *
 find_struct_member(char *name, char *str, struct ECPGstruct_member *members)
 {
@@ -401,6 +675,67 @@ check_indicator(struct ECPGtype *var)
        }
 }
 
+/*
+ * descriptor name lookup
+ */
+static struct descriptor *descriptors;
+
+static void add_descriptor(char *name,char *connection)
+{
+       struct descriptor *new=(struct descriptor *)mm_alloc(sizeof(struct descriptor));
+       
+       new->next=descriptors;
+       new->name=mm_alloc(strlen(name)+1);
+       strcpy(new->name,name);
+       if (connection) 
+       {       new->connection=mm_alloc(strlen(connection)+1);
+               strcpy(new->connection,connection);
+       }
+       else new->connection=connection;
+       descriptors=new;
+}
+
+static void drop_descriptor(char *name,char *connection)
+{      struct descriptor *i;
+       struct descriptor **lastptr=&descriptors;
+       for (i=descriptors;i;lastptr=&i->next,i=i->next)
+       {       if (!strcmp(name,i->name))
+               {       if ((!connection && !i->connection) 
+                               || (connection && i->connection 
+                                       && !strcmp(connection,i->connection)))
+                       {       *lastptr=i->next;
+                               if (i->connection) free(i->connection);
+                               free(i->name);
+                               free(i);
+                               return;
+                       }
+               }
+       }
+       snprintf(errortext,sizeof errortext,"unknown descriptor %s",name);
+       mmerror(ET_WARN,errortext);
+}
+
+static struct descriptor *lookup_descriptor(char *name,char *connection)
+{      struct descriptor *i;
+       for (i=descriptors;i;i=i->next)
+       {       if (!strcmp(name,i->name))
+               {       if ((!connection && !i->connection) 
+                               || (connection && i->connection 
+                                       && !strcmp(connection,i->connection)))
+                       {       return i;
+                       }
+               }
+       }
+       snprintf(errortext,sizeof errortext,"unknown descriptor %s",name);
+       mmerror(ET_WARN,errortext);
+       return NULL;
+}
+
+/*
+ * string concatenation
+ */
+
 static char *
 cat2_str(char *str1, char *str2)
 { 
@@ -522,6 +857,32 @@ output_statement(char * stmt, int mode)
                free(connection);
 }
 
+static void
+output_statement_desc(char * stmt, int mode)
+{
+       int i, j=strlen(stmt);
+
+       fprintf(yyout, "{ ECPGdo_descriptor(__LINE__, %s, \"%s\", \"", 
+               connection ? connection : "NULL", descriptor_name);
+
+       /* do this char by char as we have to filter '\"' */
+       for (i = 0;i < j; i++) {
+               if (stmt[i] != '\"')
+                       fputc(stmt[i], yyout);
+               else
+                       fputs("\\\"", yyout);
+       }
+
+       fputs("\");", yyout);
+
+       mode |= 2;
+       whenever_action(mode);
+       free(stmt);
+       if (connection != NULL)
+               free(connection);
+       free(descriptor_name);
+}
+
 static struct typedefs *
 get_typedef(char *name)
 {
@@ -632,15 +993,16 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
 }
 
 /* special embedded SQL token */
-%token         SQL_AT SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK 
+%token         SQL_ALLOCATE SQL_AT SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK 
 %token         SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
-%token         SQL_DEALLOCATE SQL_DISCONNECT SQL_ENUM 
-%token         SQL_FOUND SQL_FREE SQL_GO SQL_GOTO
+%token         SQL_DEALLOCATE SQL_DESCRIPTOR SQL_DISCONNECT SQL_ENUM 
+%token         SQL_FOUND SQL_FREE SQL_GET SQL_GO SQL_GOTO
 %token         SQL_IDENTIFIED SQL_INDICATOR SQL_INT SQL_LONG
 %token         SQL_OFF SQL_OPEN SQL_PREPARE SQL_RELEASE SQL_REFERENCE
-%token         SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQLERROR SQL_SQLPRINT
+%token         SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL 
+%token         SQL_SQLERROR SQL_SQLPRINT
 %token         SQL_SQLWARNING SQL_START SQL_STOP SQL_STRUCT SQL_UNSIGNED
-%token         SQL_VAR SQL_WHENEVER
+%token         SQL_VALUE SQL_VAR SQL_WHENEVER
 
 /* C token */
 %token         S_ANYTHING S_AUTO S_CONST S_EXTERN
@@ -829,6 +1191,9 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
 %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
+%type  <str>   ECPGGetDescriptor ECPGGetDescriptorHeader 
+%type  <str>   FetchDescriptorStmt
 
 %type  <type_enum> simple_type signed_type unsigned_type varchar_type
 
@@ -879,6 +1244,7 @@ stmt:  AlterTableStmt                      { output_statement($1, 0); }
                | ExtendStmt            { output_statement($1, 0); }
                | ExplainStmt           { output_statement($1, 0); }
                | FetchStmt             { output_statement($1, 1); }
+               | FetchDescriptorStmt           { output_statement_desc($1, 1); }
                | GrantStmt             { output_statement($1, 0); }
                | IndexStmt             { output_statement($1, 0); }
                | ListenStmt            { output_statement($1, 0); }
@@ -912,6 +1278,10 @@ stmt:  AlterTableStmt                     { output_statement($1, 0); }
                | VariableShowStmt      { output_statement($1, 0); }
                | VariableResetStmt     { output_statement($1, 0); }
                | ConstraintsSetStmt    { output_statement($1, 0); }
+               | ECPGAllocateDescr     {       fprintf(yyout,"ECPGallocate_desc(__LINE__, \"%s\");",$1);
+                                                               whenever_action(0);
+                                                               free($1);
+                                                       }
                | ECPGConnect           {
                                                if (connection)
                                                        mmerror(ET_ERROR, "no at option for connect statement.\n");
@@ -932,6 +1302,10 @@ stmt:  AlterTableStmt                     { output_statement($1, 0); }
                                                whenever_action(2);
                                                free($1);
                                        }
+               | ECPGDeallocateDescr   {       fprintf(yyout,"ECPGdeallocate_desc(__LINE__, \"%s\");",$1);
+                                                                       whenever_action(0);
+                                                                       free($1);
+                                                               }
                | ECPGDeclare           {
                                                output_simple_statement($1);
                                        }
@@ -952,6 +1326,14 @@ stmt:  AlterTableStmt                     { output_statement($1, 0); }
                                                whenever_action(2);
                                                free($1);
                                        }
+               | ECPGGetDescriptor     {       
+                                               lookup_descriptor($1,connection);
+                                               output_get_descr($1);
+                                       }
+               | ECPGGetDescriptorHeader       {       
+                                               lookup_descriptor($1,connection);
+                                               output_get_descr_header($1);
+                                       }
                | ECPGOpen              {       
                                                struct cursor *ptr;
                                                 
@@ -5014,6 +5396,78 @@ 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 '=' ident  {
+               push_assignment($1,$3);
+}
+
+ECPGGetDescItem: cvariable '=' ident  {
+               push_assignment($1,$3);
+}
+       | cvariable '=' TYPE_P {
+               push_assignment($1,"type");
+}
+       | cvariable '=' PRECISION {
+               push_assignment($1,"precision");
+}
+       | cvariable '=' SQL_INDICATOR {
+               push_assignment($1,"indicator");
+}
+
+ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
+       | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem;
+ECPGGetDescItems: ECPGGetDescItem
+       | ECPGGetDescItems ',' ECPGGetDescItem;
+ECPGGetDescriptorHeader:       SQL_GET SQL_DESCRIPTOR ident ECPGGetDescHeaderItems
+{  $$ = $3; }
+
+ECPGGetDescriptor:     SQL_GET SQL_DESCRIPTOR ident SQL_VALUE cvariable ECPGGetDescItems
+{  $$ = $3; descriptor_index=$5; }
+       |       SQL_GET SQL_DESCRIPTOR ident SQL_VALUE Iconst ECPGGetDescItems
+{  $$ = $3; descriptor_index=$5; }
+
+/*
+ *  fetch [ in | from ] <portalname> into sql descriptor <name>
+ */
+
+FetchDescriptorStmt:   FETCH from_in name INTO SQL_SQL SQL_DESCRIPTOR ident
+                               {
+                                       $$ = cat_str(3, make_str("fetch"), $2, $3);
+                                       descriptor_name=$7;
+                               }
+               |       FETCH name INTO SQL_SQL SQL_DESCRIPTOR ident
+                               {
+                                       $$ = cat2_str(make_str("fetch"), $2);
+                                       descriptor_name=$6;
+                               }
+               ;
+
 /*
  * for compatibility with ORACLE we will also allow the keyword RELEASE
  * after a transaction statement to disconnect from the database.
index efc8c6692382905f61b6a3ec827f3146567274d0..4a8814fcddd38f47340f30f3a3b537ad3f0151f6 100644 (file)
@@ -139,4 +139,18 @@ struct arguments
        struct arguments *next;
 };
 
+struct descriptor
+{
+       char    *name;
+       char    *connection;
+       struct descriptor *next;
+};
+
+struct assignment
+{      
+       char    *variable;
+       char    *value;
+       struct assignment *next;
+};
+
 enum errortype {ET_WARN, ET_ERROR, ET_FATAL};
index 03afc89b6d3a2ce1b1d7033d02f0cd772dc61596..9b945793e2253fa206bc27c1f5dd6e7a40e9f37e 100644 (file)
@@ -1,8 +1,8 @@
-all: stp.so test1 test2 test3 test4 test5 perftest
+all: stp.so test1 test2 test3 test4 test5 perftest dyntest
 
 #LDFLAGS=-g -I /usr/local/pgsql/include -L/usr/local/pgsql/lib -lecpg -lpq -lcrypt
-#LDFLAGS=-g -I../include -I/usr/include/postgresql  -L/usr/lib/postgresql -L../lib -lecpg -lpq -lcrypt
-LDFLAGS=-g -I/usr/include/postgresql -lecpg -lpq -lcrypt
+LDFLAGS=-g -I../include -I/usr/include/postgresql  -L/usr/lib/postgresql -L../lib -lecpg -lpq -lcrypt
+#LDFLAGS=-g -I/usr/include/postgresql -lecpg -lpq -lcrypt
 
 #ECPG=/usr/local/pgsql/bin/ecpg
 ECPG=../preproc/ecpg -I../include
@@ -16,6 +16,7 @@ test3: test3.c
 test4: test4.c
 test5: test5.c
 perftest: perftest.c
+dyntest: dyntest.c
 
 .pgc.c:
        $(ECPG) $? 
diff --git a/src/interfaces/ecpg/test/dyntest.pgc b/src/interfaces/ecpg/test/dyntest.pgc
new file mode 100644 (file)
index 0000000..451d82a
--- /dev/null
@@ -0,0 +1,127 @@
+/* dynamic SQL test program
+ *
+ * Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
+ *
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Attic/dyntest.pgc,v 1.1 2000/02/16 16:18:29 meskes Exp $
+ */
+
+#include <stdio.h>
+
+exec sql include sql3types;
+exec sql include sqlca;
+
+void error()
+{  printf("#%d:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
+   exit(1);
+}
+
+int main(int argc,char **argv)
+{ exec sql begin declare section;
+  int COUNT;
+  int INTVAR;
+  int INDEX;
+  int INDICATOR;
+  int TYPE,LENGTH,OCTET_LENGTH,PRECISION,SCALE,NULLABLE,RETURNED_OCTET_LENGTH;
+  int DATETIME_INTERVAL_CODE;
+  char NAME[120];
+  char STRINGVAR[1024];
+  float FLOATVAR;
+  double DOUBLEVAR;
+  char QUERY[1024];
+  exec sql end declare section;
+  int done=0;
+  
+  snprintf(QUERY,sizeof QUERY,"select * from %s",argc>1?argv[1]:"pg_tables");
+
+  exec sql whenever sqlerror do error();
+  
+  exec sql allocate descriptor MYDESC;
+  
+  exec sql connect to test;
+  
+  exec sql prepare MYQUERY from :QUERY;
+  exec sql declare MYCURS cursor for MYQUERY;
+  
+  exec sql open MYCURS;
+  
+  while (1)
+  {  exec sql fetch in MYCURS into sql descriptor MYDESC;
+     
+     if (sqlca.sqlcode) break;
+     
+     exec sql get descriptor MYDESC :COUNT = count;
+     if (!done) 
+     {  printf("Count %d\n",COUNT);
+        done=1;
+     } 
+     
+     for (INDEX=1;INDEX<=COUNT;++INDEX)
+     {  exec sql get descriptor MYDESC value :INDEX 
+               :TYPE = type,
+               :LENGTH = length, :OCTET_LENGTH=octet_length,
+               :RETURNED_OCTET_LENGTH=returned_octet_length,
+               :PRECISION = precision, :SCALE=scale,
+               :NULLABLE=nullable, :NAME=name,
+               :INDICATOR=indicator;
+       printf("%2d %s %d(%d)(%d,%d) %d,%d %d = "
+                       ,INDEX,NAME,TYPE,LENGTH,PRECISION,SCALE
+                       ,OCTET_LENGTH,RETURNED_OCTET_LENGTH,NULLABLE);
+       if (INDICATOR==-1) printf("NULL\n");
+        else switch (TYPE)
+       {  case SQL3_BOOLEAN: 
+               exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
+               printf("%s\n",INTVAR?"true":"false");
+               break;
+          case SQL3_NUMERIC:
+          case SQL3_DECIMAL:
+               if (SCALE==0) 
+               {  exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
+                  printf("%d\n",INTVAR);
+               }
+               else
+               {  exec sql get descriptor MYDESC value :INDEX :FLOATVAR=data;
+                  printf("%.*f\n",SCALE,FLOATVAR);
+               }
+               break;
+          case SQL3_INTEGER:
+          case SQL3_SMALLINT: 
+               exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
+               printf("%d\n",INTVAR);
+               break;
+          case SQL3_FLOAT:
+          case SQL3_REAL:
+               exec sql get descriptor MYDESC value :INDEX :FLOATVAR=data;
+               printf("%.*f\n",PRECISION,FLOATVAR);
+               break;
+          case SQL3_DOUBLE_PRECISION:
+               exec sql get descriptor MYDESC value :INDEX :DOUBLEVAR=data;
+               printf("%.*f\n",PRECISION,DOUBLEVAR);
+               break;
+          case SQL3_DATE_TIME_TIMESTAMP:
+               exec sql get descriptor MYDESC value :INDEX 
+                       :DATETIME_INTERVAL_CODE=datetime_interval_code,
+                       :STRINGVAR=data;
+               printf("%d \"%s\"\n",DATETIME_INTERVAL_CODE,STRINGVAR);
+               break;
+          case SQL3_INTERVAL:
+               exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
+               printf("\"%s\"\n",STRINGVAR);
+               break;
+          case SQL3_CHARACTER:
+          case SQL3_CHARACTER_VARYING:
+               exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
+               printf("\"%s\"\n",STRINGVAR);
+               break;
+          default:
+               exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
+               printf("<\"%s\">\n",STRINGVAR);
+               break;
+       }
+     }
+  }
+  
+  exec sql close MYCURS;
+  
+  exec sql deallocate descriptor MYDESC;
+  return 0;
+}