OSDN Git Service

8.4 pgindent run, with new combined Linux/FreeBSD/MinGW typedef list
[pg-rex/syncrep.git] / src / interfaces / ecpg / ecpglib / misc.c
1 /* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.49 2009/06/11 14:49:13 momjian 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 : ecpg_gettext("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         const char *intl_format;
246         int                     bufsize;
247         char       *fmt;
248
249         if (!simple_debug)
250                 return;
251
252         /* internationalize the error message string */
253         intl_format = ecpg_gettext(format);
254
255         /*
256          * Insert PID into the format, unless ecpg_internal_regression_mode is set
257          * (regression tests want unchanging output).
258          */
259         bufsize = strlen(intl_format) + 100;
260         fmt = (char *) malloc(bufsize);
261         if (fmt == NULL)
262                 return;
263
264         if (ecpg_internal_regression_mode)
265                 snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
266         else
267                 snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
268
269 #ifdef ENABLE_THREAD_SAFETY
270         pthread_mutex_lock(&debug_mutex);
271 #endif
272
273         va_start(ap, format);
274         vfprintf(debugstream, fmt, ap);
275         va_end(ap);
276
277         /* dump out internal sqlca variables */
278         if (ecpg_internal_regression_mode)
279                 fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
280                                 sqlca->sqlcode, sqlca->sqlstate);
281
282         fflush(debugstream);
283
284 #ifdef ENABLE_THREAD_SAFETY
285         pthread_mutex_unlock(&debug_mutex);
286 #endif
287
288         free(fmt);
289 }
290
291 void
292 ECPGset_noind_null(enum ECPGttype type, void *ptr)
293 {
294         switch (type)
295         {
296                 case ECPGt_char:
297                 case ECPGt_unsigned_char:
298                         *((char *) ptr) = '\0';
299                         break;
300                 case ECPGt_short:
301                 case ECPGt_unsigned_short:
302                         *((short int *) ptr) = SHRT_MIN;
303                         break;
304                 case ECPGt_int:
305                 case ECPGt_unsigned_int:
306                         *((int *) ptr) = INT_MIN;
307                         break;
308                 case ECPGt_long:
309                 case ECPGt_unsigned_long:
310                 case ECPGt_date:
311                         *((long *) ptr) = LONG_MIN;
312                         break;
313 #ifdef HAVE_LONG_LONG_INT_64
314                 case ECPGt_long_long:
315                 case ECPGt_unsigned_long_long:
316                         *((long long *) ptr) = LONG_LONG_MIN;
317                         break;
318 #endif   /* HAVE_LONG_LONG_INT_64 */
319                 case ECPGt_float:
320                         memset((char *) ptr, 0xff, sizeof(float));
321                         break;
322                 case ECPGt_double:
323                         memset((char *) ptr, 0xff, sizeof(double));
324                         break;
325                 case ECPGt_varchar:
326                         *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
327                         ((struct ECPGgeneric_varchar *) ptr)->len = 0;
328                         break;
329                 case ECPGt_decimal:
330                         memset((char *) ptr, 0, sizeof(decimal));
331                         ((decimal *) ptr)->sign = NUMERIC_NAN;
332                         break;
333                 case ECPGt_numeric:
334                         memset((char *) ptr, 0, sizeof(numeric));
335                         ((numeric *) ptr)->sign = NUMERIC_NAN;
336                         break;
337                 case ECPGt_interval:
338                         memset((char *) ptr, 0xff, sizeof(interval));
339                         break;
340                 case ECPGt_timestamp:
341                         memset((char *) ptr, 0xff, sizeof(timestamp));
342                         break;
343                 default:
344                         break;
345         }
346 }
347
348 static bool
349 _check(unsigned char *ptr, int length)
350 {
351         for (; length > 0 && ptr[--length] == 0xff;);
352         if (length <= 0)
353                 return true;
354         return false;
355 }
356
357 bool
358 ECPGis_noind_null(enum ECPGttype type, void *ptr)
359 {
360         switch (type)
361         {
362                 case ECPGt_char:
363                 case ECPGt_unsigned_char:
364                         if (*((char *) ptr) == '\0')
365                                 return true;
366                         break;
367                 case ECPGt_short:
368                 case ECPGt_unsigned_short:
369                         if (*((short int *) ptr) == SHRT_MIN)
370                                 return true;
371                         break;
372                 case ECPGt_int:
373                 case ECPGt_unsigned_int:
374                         if (*((int *) ptr) == INT_MIN)
375                                 return true;
376                         break;
377                 case ECPGt_long:
378                 case ECPGt_unsigned_long:
379                 case ECPGt_date:
380                         if (*((long *) ptr) == LONG_MIN)
381                                 return true;
382                         break;
383 #ifdef HAVE_LONG_LONG_INT_64
384                 case ECPGt_long_long:
385                 case ECPGt_unsigned_long_long:
386                         if (*((long long *) ptr) == LONG_LONG_MIN)
387                                 return true;
388                         break;
389 #endif   /* HAVE_LONG_LONG_INT_64 */
390                 case ECPGt_float:
391                         return (_check(ptr, sizeof(float)));
392                         break;
393                 case ECPGt_double:
394                         return (_check(ptr, sizeof(double)));
395                         break;
396                 case ECPGt_varchar:
397                         if (*(((struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
398                                 return true;
399                         break;
400                 case ECPGt_decimal:
401                         if (((decimal *) ptr)->sign == NUMERIC_NAN)
402                                 return true;
403                         break;
404                 case ECPGt_numeric:
405                         if (((numeric *) ptr)->sign == NUMERIC_NAN)
406                                 return true;
407                         break;
408                 case ECPGt_interval:
409                         return (_check(ptr, sizeof(interval)));
410                         break;
411                 case ECPGt_timestamp:
412                         return (_check(ptr, sizeof(timestamp)));
413                         break;
414                 default:
415                         break;
416         }
417
418         return false;
419 }
420
421 #ifdef WIN32
422 #ifdef ENABLE_THREAD_SAFETY
423
424 void
425 win32_pthread_mutex(volatile pthread_mutex_t *mutex)
426 {
427         if (mutex->handle == NULL)
428         {
429                 while (InterlockedExchange((LONG *) &mutex->initlock, 1) == 1)
430                         Sleep(0);
431                 if (mutex->handle == NULL)
432                         mutex->handle = CreateMutex(NULL, FALSE, NULL);
433                 InterlockedExchange((LONG *) &mutex->initlock, 0);
434         }
435 }
436
437 static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
438
439 void
440 win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
441 {
442         if (!*once)
443         {
444                 pthread_mutex_lock(&win32_pthread_once_lock);
445                 if (!*once)
446                 {
447                         *once = true;
448                         fn();
449                 }
450                 pthread_mutex_unlock(&win32_pthread_once_lock);
451         }
452 }
453 #endif   /* ENABLE_THREAD_SAFETY */
454 #endif   /* WIN32 */
455
456 #ifdef ENABLE_NLS
457
458 char *
459 ecpg_gettext(const char *msgid)
460 {
461         static bool already_bound = false;
462
463         if (!already_bound)
464         {
465                 /* dgettext() preserves errno, but bindtextdomain() doesn't */
466 #ifdef WIN32
467                 int                     save_errno = GetLastError();
468 #else
469                 int                     save_errno = errno;
470 #endif
471                 const char *ldir;
472
473                 already_bound = true;
474                 /* No relocatable lookup here because the binary could be anywhere */
475                 ldir = getenv("PGLOCALEDIR");
476                 if (!ldir)
477                         ldir = LOCALEDIR;
478                 bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
479 #ifdef WIN32
480                 SetLastError(save_errno);
481 #else
482                 errno = save_errno;
483 #endif
484         }
485
486         return dgettext(PG_TEXTDOMAIN("ecpg"), msgid);
487 }
488
489 #endif   /* ENABLE_NLS */