From: Michael Meskes Date: Sun, 14 Mar 2004 12:16:30 +0000 (+0000) Subject: - Fixed Informix compat math functions to cope with the situations X-Git-Tag: REL8_0_0BETA1~1002 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=757fb0e5a9a61ac8d3a67e334faeea6dc0084b3f;p=postgresql - Fixed Informix compat math functions to cope with the situations where one argument takes the result. - Applied thread patches by Lee Kindness --- diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog index 922def7031..44cdbc1418 100644 --- a/src/interfaces/ecpg/ChangeLog +++ b/src/interfaces/ecpg/ChangeLog @@ -1724,9 +1724,9 @@ Wed Dec 17 16:11:16 CET 2003 variable listing for output variables in cursor definitions - Fixed incorrect if call in long=>numeric conversion. - Set ecpg version to 3.1.0 - - Set ecpg library to 4.1.0 - - Set pgtypes library to 1.1.0 - - Set compat library to 1.1.0 + - Set ecpg library to 4.1 + - Set pgtypes library to 1.1 + - Set compat library to 1.1 Mon Jan 26 21:57:14 CET 2004 @@ -1759,6 +1759,14 @@ Thu Mar 4 08:29:02 CET 2004 - Fixed segfault due to missing check for variable declaration. - Added check for multidimensional array usage. - - Set pgtypeslib version to 1.2. + +Sun Mar 14 12:59:15 CET 2004 + + - Fixed Informix compat math functions to cope with the situations + where one argument takes the result. + - Applied thread patches by Lee Kindness + - Set pgtypes library version to 1.2. - Set ecpg version to 3.2.0. + - Set compat library version to 1.2. + - Set ecpg library version to 4.2. diff --git a/src/interfaces/ecpg/compatlib/informix.c b/src/interfaces/ecpg/compatlib/informix.c index 5773c45abe..973d7a8547 100644 --- a/src/interfaces/ecpg/compatlib/informix.c +++ b/src/interfaces/ecpg/compatlib/informix.c @@ -60,8 +60,7 @@ deccall3(decimal * arg1, decimal * arg2, decimal * result, int (*ptr) (numeric * *nres; int i; - /* set it to null in case it errors out later */ - rsetnull(CDECIMALTYPE, (char *) result); + /* we must NOT set the result to NULL here because it may be the same variable as one of the arguments */ if (risnull(CDECIMALTYPE, (char *) arg1) || risnull(CDECIMALTYPE, (char *) arg2)) return 0; @@ -100,8 +99,13 @@ deccall3(decimal * arg1, decimal * arg2, decimal * result, int (*ptr) (numeric * i = (*ptr) (a1, a2, nres); if (i == 0) /* No error */ + { + + /* set the result to null in case it errors out later */ + rsetnull(CDECIMALTYPE, (char *) result); PGTYPESnumeric_to_decimal(nres, result); - + } + PGTYPESnumeric_free(nres); PGTYPESnumeric_free(a1); PGTYPESnumeric_free(a2); @@ -268,7 +272,6 @@ decdiv(decimal * n1, decimal * n2, decimal * result) int i; - rsetnull(CDECIMALTYPE, (char *) result); i = deccall3(n1, n2, result, PGTYPESnumeric_div); if (i != 0) @@ -293,7 +296,6 @@ decmul(decimal * n1, decimal * n2, decimal * result) { int i; - rsetnull(CDECIMALTYPE, (char *) result); i = deccall3(n1, n2, result, PGTYPESnumeric_mul); if (i != 0) @@ -315,7 +317,6 @@ decsub(decimal * n1, decimal * n2, decimal * result) { int i; - rsetnull(CDECIMALTYPE, (char *) result); i = deccall3(n1, n2, result, PGTYPESnumeric_sub); if (i != 0) diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ecpglib/Makefile index c40c6a95d4..58b13af19a 100644 --- a/src/interfaces/ecpg/ecpglib/Makefile +++ b/src/interfaces/ecpg/ecpglib/Makefile @@ -4,7 +4,7 @@ # # Copyright (c) 1994, Regents of the University of California # -# $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/Makefile,v 1.13 2004/02/10 07:26:25 tgl Exp $ +# $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/Makefile,v 1.14 2004/03/14 12:16:29 meskes Exp $ # #------------------------------------------------------------------------- @@ -14,7 +14,7 @@ include $(top_builddir)/src/Makefile.global NAME= ecpg SO_MAJOR_VERSION= 4 -SO_MINOR_VERSION= 1 +SO_MINOR_VERSION= 2 override CPPFLAGS := -I$(top_srcdir)/src/interfaces/ecpg/include -I$(libpq_srcdir) $(CPPFLAGS) $(THREAD_CPPFLAGS) diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c index 075f774bf7..a4a02c3914 100644 --- a/src/interfaces/ecpg/ecpglib/connect.c +++ b/src/interfaces/ecpg/ecpglib/connect.c @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.19 2003/11/29 19:52:08 pgsql Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.20 2004/03/14 12:16:29 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" @@ -14,9 +14,20 @@ #ifdef ENABLE_THREAD_SAFETY static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_key_t actual_connection_key; +static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT; +#else +static struct connection *actual_connection = NULL; #endif static struct connection *all_connections = NULL; -static struct connection *actual_connection = NULL; + +#ifdef ENABLE_THREAD_SAFETY +static void +ecpg_actual_connection_init(void) +{ + pthread_key_create(&actual_connection_key, NULL); +} +#endif static struct connection * ecpg_get_connection_nr(const char *connection_name) @@ -24,7 +35,13 @@ ecpg_get_connection_nr(const char *connection_name) struct connection *ret = NULL; if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0)) + { +#ifdef ENABLE_THREAD_SAFETY + ret = pthread_getspecific(actual_connection_key); +#else ret = actual_connection; +#endif + } else { struct connection *con; @@ -86,8 +103,13 @@ ecpg_finish(struct connection * act) con->next = act->next; } +#ifdef ENABLE_THREAD_SAFETY + if( pthread_getspecific(actual_connection_key) == act ) + pthread_setspecific(actual_connection_key, all_connections); +#else if (actual_connection == act) actual_connection = all_connections; +#endif ECPGlog("ecpg_finish: Connection %s closed.\n", act->name); @@ -150,7 +172,11 @@ ECPGsetconn(int lineno, const char *connection_name) if (!ECPGinit(con, connection_name, lineno)) return (false); +#ifdef ENABLE_THREAD_SAFETY + pthread_setspecific(actual_connection_key, con); +#else actual_connection = con; +#endif return true; } @@ -370,7 +396,13 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p else this->next = all_connections; - actual_connection = all_connections = this; + all_connections = this; +#ifdef ENABLE_THREAD_SAFETY + pthread_once(&actual_connection_key_once, ecpg_actual_connection_init); + pthread_setspecific(actual_connection_key, all_connections); +#else + actual_connection = all_connections; +#endif ECPGlog("ECPGconnect: opening database %s on %s port %s %s%s%s%s\n", realname ? realname : "", diff --git a/src/interfaces/ecpg/ecpglib/misc.c b/src/interfaces/ecpg/ecpglib/misc.c index a388e70aaf..c912c5d0b4 100644 --- a/src/interfaces/ecpg/ecpglib/misc.c +++ b/src/interfaces/ecpg/ecpglib/misc.c @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.18 2003/11/29 19:52:08 pgsql Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.19 2004/03/14 12:16:30 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" @@ -118,10 +118,15 @@ ECPGinit(const struct connection * con, const char *connection_name, const int l } #ifdef ENABLE_THREAD_SAFETY -static void -ecpg_sqlca_key_init(void) +static void *ecpg_sqlca_key_destructor(void *arg) { - pthread_key_create(&sqlca_key, NULL); + if( arg != NULL ) + free(arg); /* sqlca structure allocated in ECPGget_sqlca */ +} + +static void ecpg_sqlca_key_init(void) +{ + pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor); } #endif diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile index 896f590f12..8abbb6fada 100644 --- a/src/interfaces/ecpg/test/Makefile +++ b/src/interfaces/ecpg/test/Makefile @@ -1,4 +1,4 @@ -# $PostgreSQL: pgsql/src/interfaces/ecpg/test/Makefile,v 1.43 2003/12/19 23:29:15 momjian Exp $ +# $PostgreSQL: pgsql/src/interfaces/ecpg/test/Makefile,v 1.44 2004/03/14 12:16:30 meskes Exp $ subdir = src/interfaces/ecpg/test top_builddir = ../../../.. @@ -10,7 +10,7 @@ ECPG = ../preproc/ecpg -I$(srcdir)/../include TESTS = test1 test2 test3 test4 perftest dyntest dyntest2 test_notice test_code100 test_init testdynalloc num_test dt_test test_informix ifeq ($(enable_thread_safety), yes) -TESTS += test_thread +TESTS += test_thread test_thread_implicit endif all: $(TESTS) diff --git a/src/interfaces/ecpg/test/test_thread.pgc b/src/interfaces/ecpg/test/test_thread.pgc index 44769f6812..a545942f9a 100644 --- a/src/interfaces/ecpg/test/test_thread.pgc +++ b/src/interfaces/ecpg/test/test_thread.pgc @@ -1,107 +1,140 @@ /* * Thread test program - * by Philip Yarra + * by Philip Yarra & Lee Kindness. */ +/* #define ECPGDEBUG */ #include #include -void ins1(void); -void ins2(void); +void *test_thread(void *arg); EXEC SQL BEGIN DECLARE SECTION; -char *dbname; -int iterations = 10; +char *l_dbname; EXEC SQL END DECLARE SECTION; +int nthreads = 2; +int iterations = 10; -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { - pthread_t thread1, - thread2; -EXEC SQL BEGIN DECLARE SECTION; - int rows; -EXEC SQL END DECLARE SECTION; - - if (argc < 2 || argc > 3) - { - fprintf(stderr, "Usage: %s dbname [iterations]\n", argv[0]); - return 1; - } - dbname = argv[1]; - - if (argc == 3) - iterations = atoi(argv[2]); - if (iterations % 2 != 0) - { - fprintf(stderr, "iterations must be an even number\n"); - return 1; - } - - EXEC SQL CONNECT TO:dbname AS test0; - - /* DROP might fail */ - EXEC SQL AT test0 DROP TABLE test_thread; - EXEC SQL AT test0 COMMIT WORK; - EXEC SQL AT test0 CREATE TABLE test_thread(message TEXT); - EXEC SQL AT test0 COMMIT WORK; - EXEC SQL DISCONNECT test0; - - pthread_create(&thread1, NULL, (void * (*)(void *)) ins1, NULL); - pthread_create(&thread2, NULL, (void * (*)(void *)) ins2, NULL); - pthread_join(thread1, NULL); - pthread_join(thread2, NULL); - - EXEC SQL CONNECT TO:dbname AS test3; - EXEC SQL AT test3 SELECT COUNT(*) INTO :rows FROM test_thread; - EXEC SQL AT test3 COMMIT WORK; - EXEC SQL DISCONNECT test3; - - if (rows == iterations) - printf("\nSuccess.\n"); - else - printf("\nFailure.\n"); - return 0; +#ifdef ECPGDEBUG + char debugfilename[] = "thread_test.log"; + FILE *debugfile; +#endif + pthread_t *threads; + int n; + EXEC SQL BEGIN DECLARE SECTION; + int l_rows; + EXEC SQL END DECLARE SECTION; + + /* parse command line arguments */ + if( (argc < 2) || (argc > 4) ) + { + fprintf(stderr, "Usage: %s dbname [threads] [iterations_per_thread]\n", argv[0]); + return( 1 ); + } + l_dbname = argv[1]; + if( argc >= 3 ) + nthreads = atoi(argv[2]); + if( argc == 4 ) + iterations = atoi(argv[3]); + + /* open ECPG debug log? */ +#ifdef ECPGDEBUG + debugfile = fopen(debugfilename, "w"); + if( debugfile != NULL ) + ECPGdebug(1, debugfile); + else + fprintf(stderr, "Cannot open ECPG debug log: %s\n", debugfilename); +#endif + + /* setup test_thread table */ + EXEC SQL CONNECT TO:l_dbname; + EXEC SQL DROP TABLE test_thread; /* DROP might fail */ + EXEC SQL COMMIT; + EXEC SQL CREATE TABLE + test_thread(tstamp TIMESTAMP NOT NULL DEFAULT CAST(timeofday() AS TIMESTAMP), + thread TEXT NOT NULL, + iteration INTEGER NOT NULL, + PRIMARY KEY(thread, iteration)); + EXEC SQL COMMIT; + EXEC SQL DISCONNECT; + + /* create, and start, threads */ + threads = calloc(nthreads, sizeof(pthread_t)); + if( threads == NULL ) + { + fprintf(stderr, "Cannot alloc memory\n"); + return( 1 ); + } + for( n = 0; n < nthreads; n++ ) + { + pthread_create(&threads[n], NULL, test_thread, (void *)n + 1); + } + + /* wait for thread completion */ + for( n = 0; n < nthreads; n++ ) + { + pthread_join(threads[n], NULL); + } + free(threads); + + /* and check results */ + EXEC SQL CONNECT TO :l_dbname; + EXEC SQL SELECT COUNT(*) INTO :l_rows FROM test_thread; + EXEC SQL COMMIT; + EXEC SQL DISCONNECT; + if( l_rows == (nthreads * iterations) ) + printf("\nSuccess.\n"); + else + printf("\nERROR: Failure - expecting %d rows, got %d.\n", nthreads * iterations, l_rows); + + /* close ECPG debug log? */ +#ifdef ECPGDEBUG + if( debugfile != NULL ) + { + ECPGdebug(0, debugfile); + fclose(debugfile); + } +#endif + + return( 0 ); } -void -ins1(void) +void *test_thread(void *arg) { - int i; - EXEC SQL WHENEVER sqlerror sqlprint; - EXEC SQL CONNECT TO:dbname AS test1; - - for (i = 0; i < iterations / 2; i++) - { - printf("thread 1 : inserting\n"); - EXEC SQL AT test1 INSERT INTO test_thread VALUES('thread1'); - - printf("thread 1 : insert done\n"); - } - EXEC SQL AT test1 COMMIT WORK; - EXEC SQL DISCONNECT test1; - - printf("thread 1 : done!\n"); -} - - -void -ins2(void) -{ - int i; - EXEC SQL WHENEVER sqlerror sqlprint; - EXEC SQL CONNECT TO:dbname AS test2; - - for (i = 0; i < iterations / 2; i++) - { - printf("thread 2: inserting\n"); - EXEC SQL AT test2 INSERT INTO test_thread VALUES('thread2'); - - printf("thread 2: insert done\n"); - } - EXEC SQL AT test2 COMMIT WORK; - EXEC SQL DISCONNECT test2; - - printf("thread 2: done!\n"); + long threadnum = (long)arg; + EXEC SQL BEGIN DECLARE SECTION; + int l_i; + char l_connection[128]; + EXEC SQL END DECLARE SECTION; + + /* build up connection name, and connect to database */ + snprintf(l_connection, sizeof(l_connection), "thread_%03ld", threadnum); + EXEC SQL WHENEVER sqlerror sqlprint; + EXEC SQL CONNECT TO :l_dbname AS :l_connection; + if( sqlca.sqlcode != 0 ) + { + printf("%s: ERROR: cannot connect to database!\n", l_connection); + return( NULL ); + } + EXEC SQL AT :l_connection BEGIN; + + /* insert into test_thread table */ + for( l_i = 1; l_i <= iterations; l_i++ ) + { + printf("%s: inserting %d\n", l_connection, l_i); + EXEC SQL AT :l_connection INSERT INTO test_thread(thread, iteration) VALUES(:l_connection, :l_i); + if( sqlca.sqlcode == 0 ) + printf("%s: insert done\n", l_connection); + else + printf("%s: ERROR: insert failed!\n", l_connection); + } + + /* all done */ + EXEC SQL AT :l_connection COMMIT; + EXEC SQL DISCONNECT :l_connection; + printf("%s: done!\n", l_connection); + return( NULL ); }