PageRenderTime 62ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/interfaces/ecpg/ecpglib/misc.c

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