DbExtra-postgresql.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <?php
  2. /**
  3. * This file contains rarely used extended database functionality.
  4. *
  5. * Simple Machines Forum (SMF)
  6. *
  7. * @package SMF
  8. * @author Simple Machines http://www.simplemachines.org
  9. * @copyright 2011 Simple Machines
  10. * @license http://www.simplemachines.org/about/smf/license.php BSD
  11. *
  12. * @version 2.0
  13. */
  14. if (!defined('SMF'))
  15. die('Hacking attempt...');
  16. /**
  17. * Add the functions implemented in this file to the $smcFunc array.
  18. */
  19. function db_extra_init()
  20. {
  21. global $smcFunc;
  22. if (!isset($smcFunc['db_backup_table']) || $smcFunc['db_backup_table'] != 'smf_db_backup_table')
  23. $smcFunc += array(
  24. 'db_backup_table' => 'smf_db_backup_table',
  25. 'db_optimize_table' => 'smf_db_optimize_table',
  26. 'db_insert_sql' => 'smf_db_insert_sql',
  27. 'db_table_sql' => 'smf_db_table_sql',
  28. 'db_list_tables' => 'smf_db_list_tables',
  29. 'db_get_version' => 'smf_db_get_version',
  30. );
  31. }
  32. /**
  33. * Backup $table to $backup_table.
  34. * @param string $table
  35. * @param string $backup_table
  36. * @return resource -the request handle to the table creation query
  37. */
  38. function smf_db_backup_table($table, $backup_table)
  39. {
  40. global $smcFunc, $db_prefix;
  41. $table = str_replace('{db_prefix}', $db_prefix, $table);
  42. // Do we need to drop it first?
  43. $tables = smf_db_list_tables(false, $backup_table);
  44. if (!empty($tables))
  45. $smcFunc['db_query']('', '
  46. DROP TABLE {raw:backup_table}',
  47. array(
  48. 'backup_table' => $backup_table,
  49. )
  50. );
  51. //!!! Should we create backups of sequences as well?
  52. $smcFunc['db_query']('', '
  53. CREATE TABLE {raw:backup_table}
  54. (
  55. LIKE {raw:table}
  56. INCLUDING DEFAULTS
  57. )',
  58. array(
  59. 'backup_table' => $backup_table,
  60. 'table' => $table,
  61. )
  62. );
  63. $smcFunc['db_query']('', '
  64. INSERT INTO {raw:backup_table}
  65. SELECT * FROM {raw:table}',
  66. array(
  67. 'backup_table' => $backup_table,
  68. 'table' => $table,
  69. )
  70. );
  71. }
  72. /**
  73. * This function optimizes a table.
  74. * @param string $table - the table to be optimized
  75. * @return how much it was gained
  76. */
  77. function smf_db_optimize_table($table)
  78. {
  79. global $smcFunc, $db_prefix;
  80. $table = str_replace('{db_prefix}', $db_prefix, $table);
  81. $request = $smcFunc['db_query']('', '
  82. VACUUM ANALYZE {raw:table}',
  83. array(
  84. 'table' => $table,
  85. )
  86. );
  87. if (!$request)
  88. return -1;
  89. $row = $smcFunc['db_fetch_assoc']($request);
  90. $smcFunc['db_free_result']($request);
  91. if (isset($row['Data_free']))
  92. return $row['Data_free'] / 1024;
  93. else
  94. return 0;
  95. }
  96. /**
  97. * This function lists all tables in the database.
  98. * The listing could be filtered according to $filter.
  99. * @param mixed $db, string holding the table name, or false, default false
  100. * @param mixed $filter, string to filter by, or false, default false
  101. * @return array, an array of table names. (strings)
  102. */
  103. function smf_db_list_tables($db = false, $filter = false)
  104. {
  105. global $smcFunc;
  106. $request = $smcFunc['db_query']('', '
  107. SELECT tablename
  108. FROM pg_tables
  109. WHERE schemaname = {string:schema_public}' . ($filter == false ? '' : '
  110. AND tablename LIKE {string:filter}') . '
  111. ORDER BY tablename',
  112. array(
  113. 'schema_public' => 'public',
  114. 'filter' => $filter,
  115. )
  116. );
  117. $tables = array();
  118. while ($row = $smcFunc['db_fetch_row']($request))
  119. $tables[] = $row[0];
  120. $smcFunc['db_free_result']($request);
  121. return $tables;
  122. }
  123. /**
  124. * Gets all the necessary INSERTs for the table named table_name.
  125. * It goes in 250 row segments.
  126. * @param string $tableName - the table to create the inserts for.
  127. * @return string, the query to insert the data back in, or an empty
  128. * string if the table was empty.
  129. */
  130. function smf_db_insert_sql($tableName)
  131. {
  132. global $smcFunc, $db_prefix;
  133. $tableName = str_replace('{db_prefix}', $db_prefix, $tableName);
  134. // This will be handy...
  135. $crlf = "\r\n";
  136. // Get everything from the table.
  137. $result = $smcFunc['db_query']('', '
  138. SELECT *
  139. FROM {raw:table}',
  140. array(
  141. 'table' => $tableName,
  142. )
  143. );
  144. // The number of rows, just for record keeping and breaking INSERTs up.
  145. $num_rows = $smcFunc['db_num_rows']($result);
  146. if ($num_rows == 0)
  147. return '';
  148. $fields = array_keys($smcFunc['db_fetch_assoc']($result));
  149. $smcFunc['db_data_seek']($result, 0);
  150. // Start it off with the basic INSERT INTO.
  151. $data = '';
  152. $insert_msg = $crlf . 'INSERT INTO ' . $tableName . $crlf . "\t" . '(' . implode(', ', $fields) . ')' . $crlf . 'VALUES ' . $crlf . "\t";
  153. // Loop through each row.
  154. while ($row = $smcFunc['db_fetch_row']($result))
  155. {
  156. // Get the fields in this row...
  157. $field_list = array();
  158. for ($j = 0; $j < $smcFunc['db_num_fields']($result); $j++)
  159. {
  160. // Try to figure out the type of each field. (NULL, number, or 'string'.)
  161. if (!isset($row[$j]))
  162. $field_list[] = 'NULL';
  163. elseif (is_numeric($row[$j]) && (int) $row[$j] == $row[$j])
  164. $field_list[] = $row[$j];
  165. else
  166. $field_list[] = '\'' . $smcFunc['db_escape_string']($row[$j]) . '\'';
  167. }
  168. // 'Insert' the data.
  169. $data .= $insert_msg . '(' . implode(', ', $field_list) . ');';
  170. }
  171. $smcFunc['db_free_result']($result);
  172. // Return an empty string if there were no rows.
  173. return $num_rows == 0 ? '' : $data;
  174. }
  175. /**
  176. * Dumps the schema (CREATE) for a table.
  177. * @todo why is this needed for?
  178. * @param string $tableName - the table
  179. * @return string - the CREATE statement as string
  180. */
  181. function smf_db_table_sql($tableName)
  182. {
  183. global $smcFunc, $db_prefix;
  184. $tableName = str_replace('{db_prefix}', $db_prefix, $tableName);
  185. // This will be needed...
  186. $crlf = "\r\n";
  187. // Start the create table...
  188. $schema_create = 'CREATE TABLE ' . $tableName . ' (' . $crlf;
  189. $index_create = '';
  190. $seq_create = '';
  191. // Find all the fields.
  192. $result = $smcFunc['db_query']('', '
  193. SELECT column_name, column_default, is_nullable, data_type, character_maximum_length
  194. FROM information_schema.columns
  195. WHERE table_name = {string:table}
  196. ORDER BY ordinal_position',
  197. array(
  198. 'table' => $tableName,
  199. )
  200. );
  201. while ($row = $smcFunc['db_fetch_assoc']($result))
  202. {
  203. if ($row['data_type'] == 'character varying')
  204. $row['data_type'] = 'varchar';
  205. elseif ($row['data_type'] == 'character')
  206. $row['data_type'] = 'char';
  207. if ($row['character_maximum_length'])
  208. $row['data_type'] .= '(' . $row['character_maximum_length'] . ')';
  209. // Make the CREATE for this column.
  210. $schema_create .= ' "' . $row['column_name'] . '" ' . $row['data_type'] . ($row['is_nullable'] != 'YES' ? ' NOT NULL' : '');
  211. // Add a default...?
  212. if (trim($row['column_default']) != '')
  213. {
  214. $schema_create .= ' default ' . $row['column_default'] . '';
  215. // Auto increment?
  216. if (preg_match('~nextval\(\'(.+?)\'(.+?)*\)~i', $row['column_default'], $matches) != 0)
  217. {
  218. // Get to find the next variable first!
  219. $count_req = $smcFunc['db_query']('', '
  220. SELECT MAX("{raw:column}")
  221. FROM {raw:table}',
  222. array(
  223. 'column' => $row['column_name'],
  224. 'table' => $tableName,
  225. )
  226. );
  227. list ($max_ind) = $smcFunc['db_fetch_row']($count_req);
  228. $smcFunc['db_free_result']($count_req);
  229. // Get the right bloody start!
  230. $seq_create .= 'CREATE SEQUENCE ' . $matches[1] . ' START WITH ' . ($max_ind + 1) . ';' . $crlf . $crlf;
  231. }
  232. }
  233. $schema_create .= ',' . $crlf;
  234. }
  235. $smcFunc['db_free_result']($result);
  236. // Take off the last comma.
  237. $schema_create = substr($schema_create, 0, -strlen($crlf) - 1);
  238. $result = $smcFunc['db_query']('', '
  239. SELECT CASE WHEN i.indisprimary THEN 1 ELSE 0 END AS is_primary, pg_get_indexdef(i.indexrelid) AS inddef
  240. FROM pg_class AS c
  241. INNER JOIN pg_index AS i ON (i.indrelid = c.oid)
  242. INNER JOIN pg_class AS c2 ON (c2.oid = i.indexrelid)
  243. WHERE c.relname = {string:table}',
  244. array(
  245. 'table' => $tableName,
  246. )
  247. );
  248. $indexes = array();
  249. while ($row = $smcFunc['db_fetch_assoc']($result))
  250. {
  251. if ($row['is_primary'])
  252. {
  253. if (preg_match('~\(([^\)]+?)\)~i', $row['inddef'], $matches) == 0)
  254. continue;
  255. $index_create .= $crlf . 'ALTER TABLE ' . $tableName . ' ADD PRIMARY KEY ("' . $matches[1] . '");';
  256. }
  257. else
  258. $index_create .= $crlf . $row['inddef'] . ';';
  259. }
  260. $smcFunc['db_free_result']($result);
  261. // Finish it off!
  262. $schema_create .= $crlf . ');';
  263. return $seq_create . $schema_create . $index_create;
  264. }
  265. /**
  266. * Get the version number.
  267. * @return string - the version
  268. */
  269. function smf_db_get_version()
  270. {
  271. global $smcFunc;
  272. $request = $smcFunc['db_query']('', '
  273. SHOW server_version',
  274. array(
  275. )
  276. );
  277. list ($ver) = $smcFunc['db_fetch_row']($request);
  278. $smcFunc['db_free_result']($request);
  279. return $ver;
  280. }
  281. ?>