*** src/interfaces/ecpg/ecpglib/execute.c.orig	2007-04-26 23:56:11.000000000 -0700
--- src/interfaces/ecpg/ecpglib/execute.c	2007-05-10 14:14:16.000000000 -0700
***************
*** 31,36 ****
--- 31,70 ----
  #include "pgtypes_timestamp.h"
  #include "pgtypes_interval.h"
  
+ #include <time.h>
+ #include <sys/time.h>
+ 
+ void     ECPGdispCacheStats(void);
+ void     ECPGdispCache(void);
+ 
+ typedef struct 
+ {   char        id[8];
+     int         lineno;
+     char        stmtID[32];
+     char        *ecpgQuery;
+     char        *pqQuery;
+     long        execs;                  /* # of executions      */
+     double      execTime;               /* time to execute prepared statement   */
+     PGconn      *connection;            /* connection for the statement     */
+ } stmtCacheEntry;
+ 
+ static int             nextStmtID               = 1;
+ static int             stmtCacheNBuckets        = 2039;     /* # buckets - a prime # */
+ static int             stmtCacheEntPerBucket    = 8;        /* # entries/bucket     */
+ static stmtCacheEntry  stmtCacheEntries[16384] = {{{0},0,{0},0,0}};
+ 
+ static long long       stmtCacheExecs          = 0;
+ static long long       stmtCachePrepares       = 0;
+ static long long       stmtCacheFrees          = 0;
+ static long long       stmtCacheInserts        = 0;
+ 
+ static double          totalPrepareTime    = 0.0;
+ static double          totalExecTime       = 0.0;
+ static double          totalSearchTime     = 0.0;
+ static double          totalHashTime       = 0.0;
+ static double          totalInsertTime     = 0.0;
+ static double          totalFreeTime       = 0.0;
+ 
  /*
   *	This function returns a newly malloced string that has ' and \
   *	escaped.
***************
*** 1381,1386 ****
--- 1415,2104 ----
  	return status;
  }
  
+ /*
+  * display SQL cache
+  */
+ void
+ ECPGdispCache(void)
+ {
+     int             bucketNo, ix, entNo;
+     stmtCacheEntry  *entry;
+ 
+     for(bucketNo = 1; bucketNo < stmtCacheNBuckets + 1; ++bucketNo)
+     {   printf("-- bucket # %5.5d\n", bucketNo);
+         for(ix = 0; ix < stmtCacheEntPerBucket; ++ix)
+         {   entNo = bucketNo * stmtCacheEntPerBucket + ix;
+             entry = &stmtCacheEntries[entNo];
+             if(entry->stmtID[0])
+                 printf("      entry # %d: %s\n", entNo, entry->ecpgQuery);
+         }
+     }
+     fflush(stdout);
+ }
+ 
+ /*
+  * display SQL cache statistics
+  */
+ void
+ ECPGdispCacheStats(void)
+ {
+     int     bucketNo, ix, entNo, fillCount, fillMax, noCacheEntries, leng, histo[80];
+     char    timeStr[50];
+     time_t  clock;
+     FILE    *otFile;
+ 
+     otFile = stdout;
+ 
+ /* display title line with date/time                                                    */
+     clock = time(0);
+     strcpy(timeStr, ctime(&clock));
+     leng = strlen(timeStr);
+     if(leng && timeStr[leng - 1] < ' ')
+         timeStr[leng - 1] = '\0';
+     fprintf(otFile, "\n");
+     fprintf(otFile, "---- %s ----------------------------\n", timeStr);
+ 
+ /* gather statistics to display     */
+     noCacheEntries = 0;
+     fillMax        = 0;
+     memset(histo, 0, sizeof(histo));
+     for(bucketNo = 1; bucketNo < stmtCacheNBuckets + 1; ++bucketNo)
+     {   fillCount = 0;
+         for(ix = 0; ix < stmtCacheEntPerBucket; ++ix)
+         {   entNo = bucketNo * stmtCacheEntPerBucket + ix;
+             if(stmtCacheEntries[entNo].stmtID[0])
+                 ++fillCount;
+         }
+         ++histo[fillCount];             /* incr count of buckets w/ this many entries   */
+         noCacheEntries += fillCount;    /* incr total # of entries used     */
+         if(fillCount > fillMax)         /* get value of max cache fill      */
+             fillMax = fillCount;
+     }
+ 
+ /* display the statistics   */
+     fprintf(otFile, "-- # of cache buckets           - %d\n", stmtCacheNBuckets);
+     fprintf(otFile, "-- # of entries per bucket      - %d\n", stmtCacheEntPerBucket);
+     fprintf(otFile, "-- # of SQL statements in cache - %d\n", noCacheEntries);
+     fprintf(otFile, "-- # 'insert cache entry' execs - %lld\n", stmtCacheInserts);
+     fprintf(otFile, "-- # 'free cache entry' execs   - %lld\n", stmtCacheFrees);
+     fprintf(otFile, "--\n");
+     for(ix = 0; ix <= fillMax; ++ix)
+         fprintf(otFile, "    %6d buckets contain %d entries\n", histo[ix], ix);
+ 
+     fprintf(otFile, "-- total # of statements executed     - %lld\n", stmtCacheExecs);
+     fprintf(otFile, "-- # of statements prepared           - %lld\n", stmtCachePrepares);
+ 
+     fprintf(otFile, "-- total 'prepare statement' time   %16.6f seconds\n", totalPrepareTime);
+     fprintf(otFile, "-- total 'execute statement' time   %16.6f seconds\n", totalExecTime);
+     fprintf(otFile, "-- total 'hash statement' time      %16.6f seconds\n", totalHashTime);
+     fprintf(otFile, "-- total 'search cache' time        %16.6f seconds\n", totalSearchTime);
+     fprintf(otFile, "-- total 'insert cache entry' time  %16.6f seconds\n", totalInsertTime);
+     fprintf(otFile, "-- total 'free cache entry' time    %16.6f seconds\n", totalFreeTime);
+ }
+ 
+ /*
+  * Build a SQL statement for the server  -   replace '?' variable placeholders in
+  *      a query from ECPG with '$n' placeholders required by the postgres server.
+  * Returns # of host variables replaced  OR  negative error code
+  */
+ static int
+ ECPGbuildPQstmt(int     lineno,
+                 char    *ecpgQuery,     /* input ECPG format query      */
+                 char    **retQuery)     /* returned new PQ format query */
+ {   int     varNo, varNameLeng;
+     char    *pqQuery, *hv, varName[20];
+ 
+     if(!(pqQuery = (char *) ECPGalloc(strlen(ecpgQuery) + 1000, lineno)))
+ 		return(-1);
+     strcpy(pqQuery, ecpgQuery);
+ 
+     for(varNo = 0; varNo < 10000; ++varNo)
+     {
+         if((hv = next_insert(pqQuery)) == 0)
+             break;
+         sprintf(varName, "$%d", varNo + 1);
+         varNameLeng = strlen(varName);
+         memmove(hv + varNameLeng, hv + 1, strlen(hv + 1));
+         memcpy(hv, varName, varNameLeng);
+     }
+     *retQuery = pqQuery;
+ 
+     return(varNo);
+ }
+ 
+ /*
+  * hash a SQL statement -  returns entry # of first entry in the bucket
+  */
+ static int
+ ECPGhashStmt(char    *ecpgQuery,        /* statement to hash                */
+              int     *retBucketNo)      /* returned bucket #                */
+ {
+     int             stmtIx, bucketNo, entryNo, hashLeng, stmtLeng;
+     long long       hashVal, rotVal;
+     double          lapseHashTime;
+     struct timeval  startHashTime, endHashTime;
+ 
+     gettimeofday(&startHashTime, (struct timezone *)0);
+ 
+     stmtLeng = strlen(ecpgQuery);
+     hashLeng = 50;                          /* use 1st 50 characters of statement       */
+     if(hashLeng > stmtLeng)                 /* if the statement isn't that long         */
+         hashLeng = stmtLeng;                /*      use its actual length               */
+ 
+     hashVal = 0;
+     for(stmtIx = 0; stmtIx < hashLeng; ++stmtIx)
+     {
+         hashVal = hashVal +  (int) ecpgQuery[stmtIx];
+         hashVal = hashVal << 13;
+         rotVal  = (hashVal & 0x1fff00000000LL) >> 32;
+         hashVal = (hashVal & 0xffffffffLL) | rotVal;
+     }
+ 
+     bucketNo  = hashVal % stmtCacheNBuckets;
+     bucketNo += 1;                                      /* don't use bucket # 0         */
+     entryNo   = bucketNo * stmtCacheEntPerBucket;       /* get entry #                  */
+ 
+     gettimeofday(&endHashTime, (struct timezone *)0);
+     lapseHashTime = (((double) endHashTime.tv_sec)  + (((double) endHashTime.tv_usec) / 1000000))
+                     - (((double) startHashTime.tv_sec)  + (((double) startHashTime.tv_usec) / 1000000));
+     totalHashTime += lapseHashTime;
+ 
+     *retBucketNo = bucketNo;
+     return(entryNo);
+ }
+ 
+ /*
+  * search the statement cache - search for entry with matching ECPG-format query
+  * Returns entry # in cache if found
+  *   OR  zero if not present (zero'th entry isn't used)
+  */
+ static int
+ ECPGsearchStmtCache(char    *ecpgQuery,         /* stmt to search for       */
+                     int     *retBucketNo)       /* returned bucket #        */
+ {
+     int             entNo, entIx, bucketNo;
+     double          lapseSearchTime;
+     struct timeval  startSearchTime, endSearchTime;
+ 
+     gettimeofday(&startSearchTime, (struct timezone *)0);
+ 
+ /* hash the statement           */
+     entNo = ECPGhashStmt(ecpgQuery, &bucketNo);
+ 
+ /* search the cache     */
+     for(entIx = 0; entIx < stmtCacheEntPerBucket; ++entIx)
+     {
+         if(stmtCacheEntries[entNo].stmtID[0])   /* check if entry is in use     */
+         {   if(!strcmp(ecpgQuery, stmtCacheEntries[entNo].ecpgQuery))
+                 break;                          /* found it     */
+         }
+         ++entNo;                                /* incr entry #     */
+     }
+ 
+ /* if entry wasn't found - set entry # to zero  */
+     if(entIx >= stmtCacheEntPerBucket)
+         entNo = 0;
+ 
+ /* done - accumulate statistics and return      */
+     gettimeofday(&endSearchTime, (struct timezone *)0);
+     lapseSearchTime = (((double) endSearchTime.tv_sec)  + (((double) endSearchTime.tv_usec) / 1000000))
+                     - (((double) startSearchTime.tv_sec)  + (((double) startSearchTime.tv_usec) / 1000000));
+     totalSearchTime += lapseSearchTime;
+ 
+     *retBucketNo = bucketNo;
+     return(entNo);
+ }
+ 
+ /*
+  * free an entry in the statement cache
+  * Returns entry # in cache used
+  *   OR  negative error code
+  */
+ static int
+ ECPGfreeStmtCacheEntry(int      entNo)          /* entry # to free          */
+ {
+     stmtCacheEntry  *entry;
+     long            resultSts;
+ 	PGresult        *results;
+     double          lapseFreeTime;
+     struct timeval  startFreeTime, endFreeTime;
+     char            deallocText[100];
+ 
+     entry = &stmtCacheEntries[entNo];
+     if(!entry->stmtID[0])                       /* return if the entry isn't in use     */
+         return(0);
+ 
+     gettimeofday(&startFreeTime, (struct timezone *) 0);
+     ++stmtCacheFrees;                           /* incr # of cache free's   */
+ 
+ /* free the server resources for the statement                                          */
+     ECPGlog("ECPGfreeStmtCacheEntry line %d: freeing cache entry #%d\n", entry->lineno, entNo);
+     sprintf(deallocText, "DEALLOCATE PREPARE %s", entry->stmtID);
+  	if((results = PQexec(entry->connection, deallocText)) == NULL)
+     {
+         ECPGlog("ECPGfreeStmtCacheEntry line %d: deallocate stmt, cache entry #%d\n", entry->lineno, entNo);
+         ECPGlog("ECPGfreeStmtCacheEntry results NULL\n");
+           /* continue  */
+     }
+     else
+     {
+         resultSts = PQresultStatus(results);
+         if(resultSts != PGRES_COMMAND_OK)
+         {   ECPGlog("ECPGfreeStmtCacheEntry line %d: deallocate stmt, cache entry #%d\n", entry->lineno, entNo);
+             ECPGlog("resultSts = %ld\n", resultSts);
+             ECPGlog("message =  '%s'\n", PQerrorMessage(entry->connection));
+               /* continue  */
+         }
+     }
+     PQclear(results);
+     entry->stmtID[0] = '\0';
+ 
+ /* free the memory used by the cache entry      */
+     if(entry->ecpgQuery)
+     {
+ 	    ECPGfree(entry->ecpgQuery);
+         entry->ecpgQuery = 0;
+     }
+     if(entry->pqQuery)
+ 	{   ECPGfree(entry->pqQuery);
+         entry->pqQuery = 0;
+     }
+ 
+ /* done - accumulate statistics and return     */
+     gettimeofday(&endFreeTime, (struct timezone *)0);
+     lapseFreeTime  = (((double) endFreeTime.tv_sec)  + (((double) endFreeTime.tv_usec) / 1000000))
+                       - (((double) startFreeTime.tv_sec)  + (((double) startFreeTime.tv_usec) / 1000000));
+     totalFreeTime += lapseFreeTime;
+ 
+     return(entNo);
+ }
+ 
+ 
+ /*
+  * add an entry to the statement cache
+  * returns entry # in cache used  OR  negative error code
+  */
+ static int
+ ECPGaddStmtToCache(int      lineno,         /* line # of statement      */
+                    char     *stmtID,        /* statement ID             */
+                    PGconn   *connection,    /* connection               */
+                    char     *ecpgQuery,     /* query with '?' for vars  */
+                    char     *pqQuery)       /* query with '$n' for vars */
+ {
+     int             ix, initEntNo, luEntNo, entNo, bucketNo;
+     stmtCacheEntry  *entry;
+     double          lapseInsertTime;
+     struct timeval  startInsertTime, endInsertTime;
+ 
+     gettimeofday(&startInsertTime, (struct timezone *)0);
+     ++stmtCacheInserts;                             /* incr # of cache insert's         */
+ 
+ /* hash the statement                                                                   */
+     initEntNo = ECPGhashStmt(ecpgQuery, &bucketNo);
+ 
+ /* search for an unused entry                                                           */
+     entNo   = initEntNo;            /* start with the initial entry # for the bucket    */
+     luEntNo = initEntNo;            /* use it as the initial 'least used' entry         */
+     for(ix = 0; ix < stmtCacheEntPerBucket; ++ix)
+     {
+         entry = &stmtCacheEntries[entNo];
+         if(!entry->stmtID[0])                       /* unused entry  -  use it          */
+             break;
+         if(entry->execs < stmtCacheEntries[luEntNo].execs)
+             luEntNo = entNo;                        /* save new 'least used' entry      */
+         ++entNo;                                    /* increment entry #                */
+     }
+ 
+ /* if no unused entries were found - use the 'least used' entry found in the bucket     */
+     if(ix >= stmtCacheEntPerBucket)                 /* if no unused entries were found  */
+         entNo = luEntNo;                            /* re-use the 'least used' entry    */
+ 
+ /* 'entNo' is the entry to use - make sure its free                                     */
+     ECPGfreeStmtCacheEntry(entNo);
+ 
+ /* add the query to the entry                                                           */
+     ECPGlog("ECPGaddStmtToCache, line %d: adding stmt to cache, stmt ID: %s\n", lineno, stmtID);
+     entry = &stmtCacheEntries[entNo];
+     memcpy(entry->id, "ECPGSTMT", 8);
+     entry->lineno     = lineno;
+     entry->ecpgQuery  = ecpgQuery;
+     entry->pqQuery    = pqQuery;
+     entry->connection = connection;
+     entry->execs      = 0;
+     entry->execTime   = 0.0;
+     memset(entry->stmtID, 0, sizeof(entry->stmtID));
+     strncpy(entry->stmtID, stmtID, sizeof(entry->stmtID) - 1);
+ 
+     gettimeofday(&endInsertTime, (struct timezone *)0);
+     lapseInsertTime = (((double) endInsertTime.tv_sec)  + (((double) endInsertTime.tv_usec) / 1000000))
+                     - (((double) startInsertTime.tv_sec)  + (((double) startInsertTime.tv_usec) / 1000000));
+     totalInsertTime += lapseInsertTime;
+ 
+     return(entNo);
+ }
+ 
+ static bool
+ ECPGexecuteWithPrepare(struct statement *stmt)
+ {
+     int         noParams, paramNo, entNo, bucketNo;
+     long        resultSts;
+ 	bool		status = false;
+ 	char	   *ecpgQuery;
+ 	char	   *cmdstat;
+ 	PGresult   *results;
+ 	PGnotify   *notify;
+ 	struct variable *var;
+ 	int			desc_counter = 0;
+     stmtCacheEntry  *entry;
+     double          lapsePrepareTime, lapseExecTime;
+     struct timeval  startPrepareTime, endPrepareTime, startExecTime, endExecTime;
+     char            *pqQuery = 0;
+     char            stmtID[40];
+     bool            paramMalloced[1000];
+     const char      *paramValues[1000];
+ 
+ /* build an array of host variable values  */
+ 	var = stmt->inlist;
+     noParams = 0;
+ 	while (var)
+ 	{
+ 		const char *tobeinserted;
+ 		bool		malloced = FALSE;
+ 
+ 		tobeinserted = NULL;
+ 
+ 		/*
+ 		 * A descriptor is a special case since it contains many variables but
+ 		 * is listed only once.
+ 		 */
+ 		if (var->type == ECPGt_descriptor)
+ 		{
+ 			/*
+ 			 * We create an additional variable list here, so the same logic
+ 			 * applies.
+ 			 */
+ 			struct variable desc_inlist;
+ 			struct descriptor *desc;
+ 			struct descriptor_item *desc_item;
+ 
+ 			for (desc = all_descriptors; desc; desc = desc->next)
+ 			{
+ 				if (strcmp(var->pointer, desc->name) == 0)
+ 					break;
+ 			}
+ 
+ 			if (desc == NULL)
+ 			{
+ 				ECPGraise(stmt->lineno, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, var->pointer);
+ 				return false;
+ 			}
+ 
+ 			desc_counter++;
+ 			if (desc->count < 0 || desc->count >= desc_counter)
+ 			{
+ 				for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
+ 				{
+ 					if (desc_item->num == desc_counter)
+ 					{
+ 						desc_inlist.type = ECPGt_char;
+ 						desc_inlist.value = desc_item->data;
+ 						desc_inlist.pointer = &(desc_item->data);
+ 						desc_inlist.varcharsize = strlen(desc_item->data);
+ 						desc_inlist.arrsize = 1;
+ 						desc_inlist.offset = 0;
+ 						if (!desc_item->indicator)
+ 						{
+ 							desc_inlist.ind_type = ECPGt_NO_INDICATOR;
+ 							desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
+ 							desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
+ 						}
+ 						else
+ 						{
+ 							desc_inlist.ind_type = ECPGt_int;
+ 							desc_inlist.ind_value = &(desc_item->indicator);
+ 							desc_inlist.ind_pointer = &(desc_inlist.ind_value);
+ 							desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1;
+ 							desc_inlist.ind_offset = 0;
+ 						}
+ 						if (!ECPGstore_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, &malloced, false))
+ 						{
+ 							return false;
+ 						}
+ 
+ 						break;
+ 					}
+ 				}
+ 
+ 				if (!desc_item) /* no more entries found in descriptor */
+ 					desc_counter = 0;
+ 			}
+ 			else
+ 				desc_counter = 0;
+ 		}
+ 		else
+ 		{
+ 			if (!ECPGstore_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, &malloced, false))
+ 				return false;
+ 		}
+ 
+     /* at this point, 'tobeinserted' points to memory that contains the value of the */
+     /* current parameter; it has been converted from the caller's type to a string. */
+         if (tobeinserted)
+         {
+             paramValues[noParams] = tobeinserted;
+ 
+         /* 'malloced' indicates that the memory identified by 'tobeinserted' must be */
+         /* free'd after the query is executed.                                       */
+  	        if (malloced)
+                 paramMalloced[noParams] = true;
+             else
+                 paramMalloced[noParams] = false;
+ 
+         /* increment the # of parameters to pass to the server  */
+             ++noParams;
+         }
+ 
+ 		if (desc_counter == 0)
+ 			var = var->next;
+     }
+ 
+ /* search the statement cache for this statement    */
+     entNo = ECPGsearchStmtCache(stmt->command, &bucketNo);
+ 
+ /* if not found - add the statement to the cache    */
+     if(entNo)
+         ECPGlog("ECPGexecute, line %d: stmt found in cache, entry %d\n", stmt->lineno, entNo);
+     else
+     {
+         ECPGlog("ECPGexecute, line %d: stmt not in cache; inserting\n", stmt->lineno);
+ 
+     /* convert the SQL statement to '$nnn' vars instead of the '?' vars from ECPG  */
+         ECPGbuildPQstmt(stmt->lineno, stmt->command, &pqQuery);
+ 
+     /* generate a statement ID --  name must be lower-case; "deallocate <stmt-id>"  */
+     /* converts to lower-case and won't find the name, if it is created as upper case */
+         sprintf(stmtID, "ecpg%d", nextStmtID++);
+ 
+     /* prepare the statement    */
+         gettimeofday(&startPrepareTime, (struct timezone *)0);
+         ++stmtCachePrepares;
+ 
+         ECPGlog("ECPGexecute line %d: PREPARE: %s on connection %s\n", stmt->lineno, stmt->command, stmt->connection->name);
+         results = PQprepare(stmt->connection->connection, stmtID, pqQuery, 0, 0);
+         resultSts = PQresultStatus(results);
+         if(resultSts != PGRES_COMMAND_OK)
+         {   ECPGlog("ECPGexecute line %d: preparing stmt, cache entry #%d\n", stmt->lineno, entNo);
+             ECPGlog("SQL = '%s'\n", stmt->command);
+             ECPGlog("resultSts = %ld\n", PQresultStatus(results));
+             ECPGlog("message =  '%s'\n", PQerrorMessage(stmt->connection->connection));
+             PQclear(results);
+             return(false);
+         }
+         PQclear(results);
+ 
+         gettimeofday(&endPrepareTime, (struct timezone *)0);
+         lapsePrepareTime = (((double) endPrepareTime.tv_sec)  + (((double) endPrepareTime.tv_usec) / 1000000))
+                     - (((double) startPrepareTime.tv_sec)  + (((double) startPrepareTime.tv_usec) / 1000000));
+         totalPrepareTime += lapsePrepareTime;
+ 
+     /* add the statement to the statement cache         */
+ 	    ecpgQuery = ECPGstrdup(stmt->command, stmt->lineno);
+         entNo = ECPGaddStmtToCache(stmt->lineno, stmtID, stmt->connection->connection, ecpgQuery, pqQuery);
+         ECPGlog("ECPGexecute line %d: stmt inserted into cache entry %d\n", stmt->lineno, entNo);
+     }
+ 
+ /* The query was either found in the cache or was prepared and put into the cache   */
+ /* In either case, it is now in the cache: 'entNo' is its entry #                   */
+     entry = &stmtCacheEntries[entNo];
+ 
+ /* execute a "BEGIN TRANSACTION" if we've just committed and this isn't autocommit mode */
+ 	if (stmt->connection->committed && !stmt->connection->autocommit)
+ 	{
+         if ((results = PQexec(stmt->connection->connection, "begin transaction")) == NULL)
+ 		{
+             ECPGraise(stmt->lineno, ECPG_TRANS,
+ 					  ECPG_SQLSTATE_TRANSACTION_RESOLUTION_UNKNOWN, NULL);
+ 			return false;
+ 		}
+ 		PQclear(results);
+ 		stmt->connection->committed = false;
+ 	}
+ 
+ /* execute the query            */
+     gettimeofday(&startExecTime, (struct timezone *)0);
+     ++stmtCacheExecs;
+     ++entry->execs;
+     ECPGlog("ECPGexecute line %d: EXEC-PREP: %s on connection %s\n", stmt->lineno, stmt->command, stmt->connection->name);
+     results = PQexecPrepared(stmt->connection->connection, entry->stmtID,
+                     noParams, paramValues,      /* parameters       */
+                     NULL,        /* don't need param lengths since text     */
+                     NULL,        /* default to all text params      */
+                     0);          /* ask for text results        */
+     gettimeofday(&endExecTime, (struct timezone *)0);
+     lapseExecTime = (((double) endExecTime.tv_sec)  + (((double) endExecTime.tv_usec) / 1000000))
+                     - (((double) startExecTime.tv_sec)  + (((double) startExecTime.tv_usec) / 1000000));
+     totalExecTime  += lapseExecTime;
+     entry->execTime = lapseExecTime;
+ 
+ /* free any memory allocated to contain parameter values    */
+     for (paramNo = 0; paramNo < noParams; ++paramNo)
+     {
+         if (paramMalloced[paramNo])
+             ECPGfree((char *) paramValues[paramNo]);
+     }
+ 
+ /* check the results            */
+ 	if(results == NULL)
+ 	{
+ 		ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno, PQerrorMessage(stmt->connection->connection));
+ 		ECPGraise_backend(stmt->lineno, NULL, stmt->connection->connection, stmt->compat);
+ 	}
+ 	else
+ 
+ 		/*
+ 		 * note: since some of the following code is duplicated in
+ 		 * descriptor.c it should go into a separate function
+ 		 */
+ 	{
+ 		bool		clear_result = TRUE;
+ 		struct sqlca_t *sqlca = ECPGget_sqlca();
+ 
+ 		var = stmt->outlist;
+ 		switch (PQresultStatus(results))
+ 		{
+ 				int			nfields,
+ 							ntuples,
+ 							act_field;
+ 
+ 			case PGRES_TUPLES_OK:
+ 				nfields = PQnfields(results);
+ 				sqlca->sqlerrd[2] = ntuples = PQntuples(results);
+ 				ECPGlog("ECPGexecute line %d: Correctly got %d tuples with %d fields\n", stmt->lineno, ntuples, nfields);
+ 				status = true;
+ 
+ 				if (ntuples < 1)
+ 				{
+ 					if (ntuples)
+ 						ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d\n",
+ 								stmt->lineno, ntuples);
+ 					ECPGraise(stmt->lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
+ 					status = false;
+ 					break;
+ 				}
+ 
+ 				if (var != NULL && var->type == ECPGt_descriptor)
+ 				{
+ 					PGresult  **resultpp = ECPGdescriptor_lvalue(stmt->lineno, (const char *) var->pointer);
+ 
+ 					if (resultpp == NULL)
+ 						status = false;
+ 					else
+ 					{
+ 						if (*resultpp)
+ 							PQclear(*resultpp);
+ 						*resultpp = results;
+ 						clear_result = FALSE;
+ 						ECPGlog("ECPGexecute putting result (%d tuples) into descriptor '%s'\n", PQntuples(results), (const char *) var->pointer);
+ 					}
+ 					var = var->next;
+ 				}
+ 				else
+ 					for (act_field = 0; act_field < nfields && status; act_field++)
+ 					{
+ 						if (var != NULL)
+ 						{
+ 							status = ECPGstore_result(results, act_field, stmt, var);
+ 							var = var->next;
+ 						}
+ 						else if (!INFORMIX_MODE(stmt->compat))
+ 						{
+ 							ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_TARGETS, NULL);
+ 							return (false);
+ 						}
+ 					}
+ 
+ 				if (status && var != NULL)
+ 				{
+ 					ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_TARGETS, NULL);
+ 					status = false;
+ 				}
+ 
+ 				break;
+ 			case PGRES_EMPTY_QUERY:
+ 				/* do nothing */
+ 				ECPGraise(stmt->lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
+ 				break;
+ 			case PGRES_COMMAND_OK:
+ 				status = true;
+ 				cmdstat = PQcmdStatus(results);
+ 				sqlca->sqlerrd[1] = PQoidValue(results);
+ 				sqlca->sqlerrd[2] = atol(PQcmdTuples(results));
+ 				ECPGlog("ECPGexecute line %d Ok: %s\n", stmt->lineno, cmdstat);
+ 				if (stmt->compat != ECPG_COMPAT_INFORMIX_SE &&
+ 					!sqlca->sqlerrd[2] &&
+ 					(!strncmp(cmdstat, "UPDATE", 6)
+ 					 || !strncmp(cmdstat, "INSERT", 6)
+ 					 || !strncmp(cmdstat, "DELETE", 6)))
+ 					ECPGraise(stmt->lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
+ 				break;
+ 			case PGRES_NONFATAL_ERROR:
+ 			case PGRES_FATAL_ERROR:
+ 			case PGRES_BAD_RESPONSE:
+ 				ECPGlog("ECPGexecute line %d: Error: %s", stmt->lineno, PQresultErrorMessage(results));
+ 				ECPGraise_backend(stmt->lineno, results, stmt->connection->connection, stmt->compat);
+ 				status = false;
+ 				break;
+ 			case PGRES_COPY_OUT:
+ 				{
+ 					char	   *buffer;
+ 					int			res;
+ 
+ 					ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT\n", stmt->lineno);
+ 					while ((res = PQgetCopyData(stmt->connection->connection,
+ 												&buffer, 0)) > 0)
+ 					{
+ 						printf("%s", buffer);
+ 						PQfreemem(buffer);
+ 					}
+ 					if (res == -1)
+ 					{
+ 						/* COPY done */
+ 						PQclear(results);
+ 						results = PQgetResult(stmt->connection->connection);
+ 						if (PQresultStatus(results) == PGRES_COMMAND_OK)
+ 							ECPGlog("ECPGexecute line %d: Got PGRES_COMMAND_OK after PGRES_COPY_OUT\n", stmt->lineno);
+ 						else
+ 							ECPGlog("ECPGexecute line %d: Got error after PGRES_COPY_OUT: %s", PQresultErrorMessage(results));
+ 					}
+ 					break;
+ 				}
+ 			case PGRES_COPY_IN:
+ 				ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno);
+ 				PQendcopy(stmt->connection->connection);
+ 				break;
+ 			default:
+ 				ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
+ 						stmt->lineno);
+ 				ECPGraise_backend(stmt->lineno, results, stmt->connection->connection, stmt->compat);
+ 				status = false;
+ 				break;
+ 		}
+ 		if (clear_result)
+ 			PQclear(results);
+ 	}
+ 
+ /* check for asynchronous returns */
+ 	notify = PQnotifies(stmt->connection->connection);
+ 	if (notify)
+ 	{
+ 		ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
+ 				stmt->lineno, notify->relname, notify->be_pid);
+ 		PQfreemem(notify);
+ 	}
+ 
+ 	return status;
+ }
+ 
  bool
  ECPGdo(int lineno, int compat, int force_indicator, const char *connection_name, const char *query,...)
  {
***************
*** 1389,1397 ****
--- 2107,2119 ----
  	struct connection *con;
  	bool		status;
  	char	   *oldlocale;
+     char       *prep;
  	enum ECPGttype type;
  	struct variable **list;
  
+ 	static int	firstTime = 1;
+     static int  usePrepare = 0;
+ 
  	/* Make sure we do NOT honor the locale for numeric input/output */
  	/* since the database wants the standard decimal point */
  	oldlocale = ECPGstrdup(setlocale(LC_NUMERIC, NULL), lineno);
***************
*** 1549,1555 ****
  	/* initialize auto_mem struct */
  	ECPGclear_auto_mem();
  
! 	status = ECPGexecute(stmt);
  	free_statement(stmt);
  
  	/* and reset locale value so our application is not affected */
--- 2271,2288 ----
  	/* initialize auto_mem struct */
  	ECPGclear_auto_mem();
  
!     if(firstTime)
!     {
!         firstTime = 0;
!         prep = getenv("ECPGUSEPREPARE");
!         if(prep  &&  (!strcasecmp(prep, "yes")  ||  !strcasecmp(prep, "y")))
!             usePrepare = 1;
!         ECPGlog("ECPGdo line %d: usePrepare=%d\n", stmt->lineno, usePrepare);
!     }
!     if(usePrepare)
!         status = ECPGexecuteWithPrepare(stmt);
!     else
!         status = ECPGexecute(stmt);
  	free_statement(stmt);
  
  	/* and reset locale value so our application is not affected */
