]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/ecpglib/misc.c
dbeb448f213c6a333c1cef4fa1f6db60f8927926
[postgresql] / src / interfaces / ecpg / ecpglib / misc.c
1 /* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.43 2008/11/01 19:53:35 meskes Exp $ */
2
3 #define POSTGRES_ECPG_INTERNAL
4 #include "postgres_fe.h"
5
6 #include <limits.h>
7 #include <unistd.h>
8 #include "ecpg-pthread-win32.h"
9 #include "ecpgtype.h"
10 #include "ecpglib.h"
11 #include "ecpgerrno.h"
12 #include "extern.h"
13 #include "sqlca.h"
14 #include "pgtypes_numeric.h"
15 #include "pgtypes_date.h"
16 #include "pgtypes_timestamp.h"
17 #include "pgtypes_interval.h"
18 #include "pg_config_paths.h"
19
20 #ifdef HAVE_LONG_LONG_INT_64
21 #ifndef LONG_LONG_MIN
22 #ifdef LLONG_MIN
23 #define LONG_LONG_MIN LLONG_MIN
24 #else
25 #define LONG_LONG_MIN LONGLONG_MIN
26 #endif
27 #endif
28 #endif
29
30 bool            ecpg_internal_regression_mode = false;
31
32 static struct sqlca_t sqlca_init =
33 {
34         {
35                 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
36         },
37         sizeof(struct sqlca_t),
38         0,
39         {
40                 0,
41                 {
42                         0
43                 }
44         },
45         {
46                 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
47         },
48         {
49                 0, 0, 0, 0, 0, 0
50         },
51         {
52                 0, 0, 0, 0, 0, 0, 0, 0
53         },
54         {
55                 '0', '0', '0', '0', '0'
56         }
57 };
58
59 #ifdef ENABLE_THREAD_SAFETY
60 static pthread_key_t sqlca_key;
61 static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
62 #else
63 static struct sqlca_t sqlca =
64 {
65         {
66                 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
67         },
68         sizeof(struct sqlca_t),
69         0,
70         {
71                 0,
72                 {
73                         0
74                 }
75         },
76         {
77                 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
78         },
79         {
80                 0, 0, 0, 0, 0, 0
81         },
82         {
83                 0, 0, 0, 0, 0, 0, 0, 0
84         },
85         {
86                 '0', '0', '0', '0', '0'
87         }
88 };
89 #endif
90
91 #ifdef ENABLE_THREAD_SAFETY
92 static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
93 static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER;
94 #endif
95 static int      simple_debug = 0;
96 static FILE *debugstream = NULL;
97
98 void
99 ecpg_init_sqlca(struct sqlca_t * sqlca)
100 {
101         memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
102 }
103
104 bool
105 ecpg_init(const struct connection * con, const char *connection_name, const int lineno)
106 {
107         struct sqlca_t *sqlca = ECPGget_sqlca();
108
109         ecpg_init_sqlca(sqlca);
110         if (con == NULL)
111         {
112                 ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
113                                    connection_name ? connection_name : _("NULL"));
114                 return (false);
115         }
116
117         return (true);
118 }
119
120 #ifdef ENABLE_THREAD_SAFETY
121 static void
122 ecpg_sqlca_key_destructor(void *arg)
123 {
124         free(arg);                                      /* sqlca structure allocated in ECPGget_sqlca */
125 }
126
127 static void
128 ecpg_sqlca_key_init(void)
129 {
130         pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
131 }
132 #endif
133
134 struct sqlca_t *
135 ECPGget_sqlca(void)
136 {
137 #ifdef ENABLE_THREAD_SAFETY
138         struct sqlca_t *sqlca;
139
140         pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
141
142         sqlca = pthread_getspecific(sqlca_key);
143         if (sqlca == NULL)
144         {
145                 sqlca = malloc(sizeof(struct sqlca_t));
146                 ecpg_init_sqlca(sqlca);
147                 pthread_setspecific(sqlca_key, sqlca);
148         }
149         return (sqlca);
150 #else
151         return (&sqlca);
152 #endif
153 }
154
155 bool
156 ECPGstatus(int lineno, const char *connection_name)
157 {
158         struct connection *con = ecpg_get_connection(connection_name);
159
160         if (!ecpg_init(con, connection_name, lineno))
161                 return (false);
162
163         /* are we connected? */
164         if (con->connection == NULL)
165         {
166                 ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, con->name);
167                 return false;
168         }
169
170         return (true);
171 }
172
173 bool
174 ECPGtrans(int lineno, const char *connection_name, const char *transaction)
175 {
176         PGresult   *res;
177         struct connection *con = ecpg_get_connection(connection_name);
178
179         if (!ecpg_init(con, connection_name, lineno))
180                 return (false);
181
182         ecpg_log("ECPGtrans on line %d: action \"%s\"; connection \"%s\"\n", lineno, transaction, con ? con->name : _("null"));
183
184         /* if we have no connection we just simulate the command */
185         if (con && con->connection)
186         {
187                 /*
188                  * If we got a transaction command but have no open transaction, we
189                  * have to start one, unless we are in autocommit, where the
190                  * developers have to take care themselves. However, if the command is
191                  * a begin statement, we just execute it once.
192                  */
193                 if (con->committed && !con->autocommit && strncmp(transaction, "begin", 5) != 0 && strncmp(transaction, "start", 5) != 0)
194                 {
195                         res = PQexec(con->connection, "begin transaction");
196                         if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
197                                 return FALSE;
198                         PQclear(res);
199                 }
200
201                 res = PQexec(con->connection, transaction);
202                 if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
203                         return FALSE;
204                 PQclear(res);
205         }
206
207         if (strncmp(transaction, "commit", 6) == 0 || strncmp(transaction, "rollback", 8) == 0)
208                 con->committed = true;
209         else
210                 con->committed = false;
211
212         return true;
213 }
214
215
216 void
217 ECPGdebug(int n, FILE *dbgs)
218 {
219 #ifdef ENABLE_THREAD_SAFETY
220         pthread_mutex_lock(&debug_init_mutex);
221 #endif
222
223         if (n > 100)
224         {
225                 ecpg_internal_regression_mode = true;
226                 simple_debug = n - 100;
227         }
228         else
229                 simple_debug = n;
230
231         debugstream = dbgs;
232
233         ecpg_log("ECPGdebug: set to %d\n", simple_debug);
234
235 #ifdef ENABLE_THREAD_SAFETY
236         pthread_mutex_unlock(&debug_init_mutex);
237 #endif
238 }
239
240 void
241 ecpg_log(const char *format,...)
242 {
243         va_list         ap;
244         struct sqlca_t *sqlca = ECPGget_sqlca();
245
246         /* internationalize the error message string */
247         format = ecpg_gettext(format);
248
249         if (simple_debug)
250         {
251                 int                     bufsize = strlen(format) + 100;
252                 char       *f = (char *) malloc(bufsize);
253
254                 if (f == NULL)
255                         return;
256
257                 /*
258                  * regression tests set this environment variable to get the same
259                  * output for every run.
260                  */
261                 if (ecpg_internal_regression_mode)
262                         snprintf(f, bufsize, "[NO_PID]: %s", format);
263                 else
264                         snprintf(f, bufsize, "[%d]: %s", (int) getpid(), format);
265
266 #ifdef ENABLE_THREAD_SAFETY
267                 pthread_mutex_lock(&debug_mutex);
268 #endif
269
270                 va_start(ap, format);
271                 vfprintf(debugstream, f, ap);
272                 va_end(ap);
273
274                 /* dump out internal sqlca variables */
275                 if (ecpg_internal_regression_mode)
276                         fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
277                                         sqlca->sqlcode, sqlca->sqlstate);
278
279                 fflush(debugstream);
280
281 #ifdef ENABLE_THREAD_SAFETY
282                 pthread_mutex_unlock(&debug_mutex);
283 #endif
284
285                 free(f);
286         }
287 }
288
289 void
290 ECPGset_noind_null(enum ECPGttype type, void *ptr)
291 {
292         switch (type)
293         {
294                 case ECPGt_char:
295                 case ECPGt_unsigned_char:
296                         *((char *) ptr) = '\0';
297                         break;
298                 case ECPGt_short:
299                 case ECPGt_unsigned_short:
300                         *((short int *) ptr) = SHRT_MIN;
301                         break;
302                 case ECPGt_int:
303                 case ECPGt_unsigned_int:
304                         *((int *) ptr) = INT_MIN;
305                         break;
306                 case ECPGt_long:
307                 case ECPGt_unsigned_long:
308                 case ECPGt_date:
309                         *((long *) ptr) = LONG_MIN;
310                         break;
311 #ifdef HAVE_LONG_LONG_INT_64
312                 case ECPGt_long_long:
313                 case ECPGt_unsigned_long_long:
314                         *((long long *) ptr) = LONG_LONG_MIN;
315                         break;
316 #endif   /* HAVE_LONG_LONG_INT_64 */
317                 case ECPGt_float:
318                         memset((char *) ptr, 0xff, sizeof(float));
319                         break;
320                 case ECPGt_double:
321                         memset((char *) ptr, 0xff, sizeof(double));
322                         break;
323                 case ECPGt_varchar:
324                         *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
325                         ((struct ECPGgeneric_varchar *) ptr)->len = 0;
326                         break;
327                 case ECPGt_decimal:
328                         memset((char *) ptr, 0, sizeof(decimal));
329                         ((decimal *) ptr)->sign = NUMERIC_NAN;
330                         break;
331                 case ECPGt_numeric:
332                         memset((char *) ptr, 0, sizeof(numeric));
333                         ((numeric *) ptr)->sign = NUMERIC_NAN;
334                         break;
335                 case ECPGt_interval:
336                         memset((char *) ptr, 0xff, sizeof(interval));
337                         break;
338                 case ECPGt_timestamp:
339                         memset((char *) ptr, 0xff, sizeof(timestamp));
340                         break;
341                 default:
342                         break;
343         }
344 }
345
346 static bool
347 _check(unsigned char *ptr, int length)
348 {
349         for (; length > 0 && ptr[--length] == 0xff;);
350         if (length <= 0)
351                 return true;
352         return false;
353 }
354
355 bool
356 ECPGis_noind_null(enum ECPGttype type, void *ptr)
357 {
358         switch (type)
359         {
360                 case ECPGt_char:
361                 case ECPGt_unsigned_char:
362                         if (*((char *) ptr) == '\0')
363                                 return true;
364                         break;
365                 case ECPGt_short:
366                 case ECPGt_unsigned_short:
367                         if (*((short int *) ptr) == SHRT_MIN)
368                                 return true;
369                         break;
370                 case ECPGt_int:
371                 case ECPGt_unsigned_int:
372                         if (*((int *) ptr) == INT_MIN)
373                                 return true;
374                         break;
375                 case ECPGt_long:
376                 case ECPGt_unsigned_long:
377                 case ECPGt_date:
378                         if (*((long *) ptr) == LONG_MIN)
379                                 return true;
380                         break;
381 #ifdef HAVE_LONG_LONG_INT_64
382                 case ECPGt_long_long:
383                 case ECPGt_unsigned_long_long:
384                         if (*((long long *) ptr) == LONG_LONG_MIN)
385                                 return true;
386                         break;
387 #endif   /* HAVE_LONG_LONG_INT_64 */
388                 case ECPGt_float:
389                         return (_check(ptr, sizeof(float)));
390                         break;
391                 case ECPGt_double:
392                         return (_check(ptr, sizeof(double)));
393                         break;
394                 case ECPGt_varchar:
395                         if (*(((struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
396                                 return true;
397                         break;
398                 case ECPGt_decimal:
399                         if (((decimal *) ptr)->sign == NUMERIC_NAN)
400                                 return true;
401                         break;
402                 case ECPGt_numeric:
403                         if (((numeric *) ptr)->sign == NUMERIC_NAN)
404                                 return true;
405                         break;
406                 case ECPGt_interval:
407                         return (_check(ptr, sizeof(interval)));
408                         break;
409                 case ECPGt_timestamp:
410                         return (_check(ptr, sizeof(timestamp)));
411                         break;
412                 default:
413                         break;
414         }
415
416         return false;
417 }
418
419 #ifdef WIN32
420 #ifdef ENABLE_THREAD_SAFETY
421
422 void
423 win32_pthread_mutex(volatile pthread_mutex_t *mutex)
424 {
425         if (mutex->handle == NULL)
426         {
427                 while (InterlockedExchange((LONG *) & mutex->initlock, 1) == 1)
428                         Sleep(0);
429                 if (mutex->handle == NULL)
430                         mutex->handle = CreateMutex(NULL, FALSE, NULL);
431                 InterlockedExchange((LONG *) & mutex->initlock, 0);
432         }
433 }
434
435 static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
436
437 void
438 win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
439 {
440         if (!*once)
441         {
442                 pthread_mutex_lock(&win32_pthread_once_lock);
443                 if (!*once)
444                 {
445                         *once = true;
446                         fn();
447                 }
448                 pthread_mutex_unlock(&win32_pthread_once_lock);
449         }
450 }
451 #endif   /* ENABLE_THREAD_SAFETY */
452
453 #endif   /* WIN32 */
454
455 #ifdef ENABLE_NLS
456
457 char *
458 ecpg_gettext(const char *msgid)
459 {
460         static bool already_bound = false;
461
462         if (!already_bound)
463         {
464                 /* dgettext() preserves errno, but bindtextdomain() doesn't */
465 #ifdef WIN32
466                 int                     save_errno = GetLastError();
467 #else
468                 int                     save_errno = errno;
469 #endif
470                 const char *ldir;
471
472                 already_bound = true;
473                 /* No relocatable lookup here because the binary could be anywhere */
474                 ldir = getenv("PGLOCALEDIR");
475                 if (!ldir)
476                         ldir = LOCALEDIR;
477                 bindtextdomain("ecpg", ldir);
478 #ifdef WIN32
479                 SetLastError(save_errno);
480 #else
481                 errno = save_errno;
482 #endif
483         }
484
485         return dgettext("ecpg", msgid);
486 }
487
488 #endif   /* ENABLE_NLS */