pg_con.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * $Id$
  3. *
  4. * Portions Copyright (C) 2001-2003 FhG FOKUS
  5. * Copyright (C) 2003 August.Net Services, LLC
  6. * Portions Copyright (C) 2005 iptelorg GmbH
  7. *
  8. * This file is part of ser, a free SIP server.
  9. *
  10. * ser is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version
  14. *
  15. * For a license to use the ser software under conditions
  16. * other than those described here, or to purchase support for this
  17. * software, please contact iptel.org by e-mail at the following addresses:
  18. * [email protected]
  19. *
  20. * ser is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program; if not, write to the Free Software
  27. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  28. */
  29. #include "pg_con.h"
  30. #include "../../mem/mem.h"
  31. #include "../../dprint.h"
  32. #include "../../ut.h"
  33. #include <string.h>
  34. #include <netinet/in.h>
  35. #include <time.h>
  36. /*
  37. * Override the default notice processor to output the messages
  38. * using SER's output subsystem.
  39. */
  40. static void notice_processor(void* arg, const char* message)
  41. {
  42. LOG(L_NOTICE, "postgres: %s\n", message);
  43. }
  44. /*
  45. * Determine the format used by the server to store timestamp data type
  46. * The function returns 1 if the server stores timestamps as int8 and 0
  47. * if it is stored as double
  48. */
  49. static int timestamp_format(PGconn* con)
  50. {
  51. unsigned long long offset;
  52. PGresult* res = 0;
  53. char* val;
  54. res = PQexecParams(con, "select timestamp '2000-01-01 00:00:00' + time '00:00:01'", 0, 0, 0, 0, 0, 1);
  55. if (PQfformat(res, 0) != 1) {
  56. ERR("Binary format expected but server sent text\n");
  57. goto err;
  58. }
  59. if (PQntuples(res) != 1) {
  60. ERR("1 column expected, %d received\n", PQntuples(res));
  61. goto err;
  62. }
  63. if (PQnfields(res) != 1) {
  64. ERR("1 Row expected, %d received\n", PQnfields(res));
  65. goto err;
  66. }
  67. val = PQgetvalue(res, 0, 0);
  68. offset = ((unsigned long long)ntohl(((unsigned int*)val)[0]) << 32)
  69. + ntohl(((unsigned int*)val)[1]);
  70. PQclear(res);
  71. /* Server using int8 timestamps would return 1000000, because it stores
  72. * timestamps in microsecond resolution across the whole range. Server using
  73. * double timestamps would return 1 (encoded as double) here because subsection
  74. * fraction is stored as fractional part in the IEEE representation.
  75. * 1 stored as double would result in 4607182418800017408 when the memory location
  76. * occupied by the variable is read as unsigned long long.
  77. */
  78. if (offset == 1000000) {
  79. DBG("Server uses int8 format for timestamps.\n");
  80. return 1;
  81. } else {
  82. DBG("Server uses double format for timestamps.\n");
  83. return 0;
  84. }
  85. err:
  86. PQclear(res);
  87. return -1;
  88. }
  89. /*
  90. * Create a new connection structure,
  91. * open the Postgres connection and set reference count to 1
  92. */
  93. struct pg_con* pg_new_connection(struct db_id* id)
  94. {
  95. struct pg_con* ptr;
  96. char* port_str;
  97. int ret;
  98. if (!id) {
  99. ERR("Invalid parameter value\n");
  100. return 0;
  101. }
  102. ptr = (struct pg_con*)pkg_malloc(sizeof(struct pg_con));
  103. if (!ptr) {
  104. ERR("No memory left\n");
  105. return 0;
  106. }
  107. memset(ptr, 0, sizeof(struct pg_con));
  108. ptr->ref = 1;
  109. if (id->port > 0) {
  110. port_str = int2str(id->port, 0);
  111. } else {
  112. port_str = NULL;
  113. }
  114. if (id->port) {
  115. DBG("Opening connection to: %s://%s:%s@%s:%d/%s\n",
  116. ZSW(id->scheme),
  117. ZSW(id->username),
  118. ZSW(id->password),
  119. ZSW(id->host),
  120. id->port,
  121. ZSW(id->database)
  122. );
  123. } else {
  124. DBG("Opening connection to: %s://%s:%s@%s/%s\n",
  125. ZSW(id->scheme),
  126. ZSW(id->username),
  127. ZSW(id->password),
  128. ZSW(id->host),
  129. ZSW(id->database)
  130. );
  131. }
  132. ptr->con = PQsetdbLogin(id->host, port_str,
  133. NULL, NULL, id->database,
  134. id->username, id->password);
  135. if (ptr->con == 0) {
  136. ERR("PQsetdbLogin ran out of memory\n");
  137. goto err;
  138. }
  139. if (PQstatus(ptr->con) != CONNECTION_OK) {
  140. ERR("postgres:new_connection: %s\n",
  141. PQerrorMessage(ptr->con));
  142. goto err;
  143. }
  144. /* Override default notice processor */
  145. PQsetNoticeProcessor(ptr->con, notice_processor, 0);
  146. DBG("Connected. Protocol version=%d, Server version=%d\n",
  147. PQprotocolVersion(ptr->con),
  148. #ifdef HAVE_PGSERVERVERSION
  149. PQserverVersion(ptr->con)
  150. #else
  151. 0
  152. #endif
  153. );
  154. ptr->timestamp = time(0);
  155. ptr->id = id;
  156. ret = timestamp_format(ptr->con);
  157. if (ret == 1 || ret == -1) {
  158. /* Assume INT8 representation if detection fails */
  159. ptr->flags |= PG_INT8_TIMESTAMP;
  160. }
  161. return ptr;
  162. err:
  163. if (ptr && ptr->con) PQfinish(ptr->con);
  164. if (ptr) pkg_free(ptr);
  165. return 0;
  166. }
  167. /*
  168. * Close the connection and release memory
  169. */
  170. void pg_free_connection(struct pg_con* con)
  171. {
  172. if (!con) return;
  173. if (con->id) free_db_id(con->id);
  174. if (con->con) PQfinish(con->con);
  175. pkg_free(con);
  176. }