DbExtra-postgresql.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <?php
  2. /**
  3. * Simple Machines Forum (SMF)
  4. *
  5. * @package SMF
  6. * @author Simple Machines http://www.simplemachines.org
  7. * @copyright 2011 Simple Machines
  8. * @license http://www.simplemachines.org/about/smf/license.php BSD
  9. *
  10. * @version 2.0
  11. */
  12. if (!defined('SMF'))
  13. die('Hacking attempt...');
  14. /* This file contains rarely used extended database functionality.
  15. void db_extra_init()
  16. - add this file's functions to the $smcFunc array.
  17. resource smf_db_backup_table($table, $backup_table)
  18. - backup $table to $backup_table.
  19. - returns the request handle to the table creation query
  20. string function smf_db_get_version()
  21. - get the version number.
  22. string db_insert_sql(string table_name)
  23. - gets all the necessary INSERTs for the table named table_name.
  24. - goes in 250 row segments.
  25. - returns the query to insert the data back in.
  26. - returns an empty string if the table was empty.
  27. array smf_db_list_tables($db = false, $filter = false)
  28. - lists all tables in the database
  29. - could be filtered according to $filter
  30. - returns an array of table names. (strings)
  31. float smf_db_optimize_table($table)
  32. - optimize a table
  33. - $table - the table to be optimized
  34. - returns how much it was gained
  35. string db_table_sql(string table_name)
  36. - dumps the CREATE for the specified table. (by table_name.)
  37. - returns the CREATE statement.
  38. */
  39. // Add the file functions to the $smcFunc array.
  40. function db_extra_init()
  41. {
  42. global $smcFunc;
  43. if (!isset($smcFunc['db_backup_table']) || $smcFunc['db_backup_table'] != 'smf_db_backup_table')
  44. $smcFunc += array(
  45. 'db_backup_table' => 'smf_db_backup_table',
  46. 'db_optimize_table' => 'smf_db_optimize_table',
  47. 'db_insert_sql' => 'smf_db_insert_sql',
  48. 'db_table_sql' => 'smf_db_table_sql',
  49. 'db_list_tables' => 'smf_db_list_tables',
  50. 'db_get_version' => 'smf_db_get_version',
  51. );
  52. }
  53. // Backup $table to $backup_table.
  54. function smf_db_backup_table($table, $backup_table)
  55. {
  56. global $smcFunc, $db_prefix;
  57. $table = str_replace('{db_prefix}', $db_prefix, $table);
  58. // Do we need to drop it first?
  59. $tables = smf_db_list_tables(false, $backup_table);
  60. if (!empty($tables))
  61. $smcFunc['db_query']('', '
  62. DROP TABLE {raw:backup_table}',
  63. array(
  64. 'backup_table' => $backup_table,
  65. )
  66. );
  67. //!!! Should we create backups of sequences as well?
  68. $smcFunc['db_query']('', '
  69. CREATE TABLE {raw:backup_table}
  70. (
  71. LIKE {raw:table}
  72. INCLUDING DEFAULTS
  73. )',
  74. array(
  75. 'backup_table' => $backup_table,
  76. 'table' => $table,
  77. )
  78. );
  79. $smcFunc['db_query']('', '
  80. INSERT INTO {raw:backup_table}
  81. SELECT * FROM {raw:table}',
  82. array(
  83. 'backup_table' => $backup_table,
  84. 'table' => $table,
  85. )
  86. );
  87. }
  88. // Optimize a table - return data freed!
  89. function smf_db_optimize_table($table)
  90. {
  91. global $smcFunc, $db_prefix;
  92. $table = str_replace('{db_prefix}', $db_prefix, $table);
  93. $request = $smcFunc['db_query']('', '
  94. VACUUM ANALYZE {raw:table}',
  95. array(
  96. 'table' => $table,
  97. )
  98. );
  99. if (!$request)
  100. return -1;
  101. $row = $smcFunc['db_fetch_assoc']($request);
  102. $smcFunc['db_free_result']($request);
  103. if (isset($row['Data_free']))
  104. return $row['Data_free'] / 1024;
  105. else
  106. return 0;
  107. }
  108. // List all the tables in the database.
  109. function smf_db_list_tables($db = false, $filter = false)
  110. {
  111. global $smcFunc;
  112. $request = $smcFunc['db_query']('', '
  113. SELECT tablename
  114. FROM pg_tables
  115. WHERE schemaname = {string:schema_public}' . ($filter == false ? '' : '
  116. AND tablename LIKE {string:filter}') . '
  117. ORDER BY tablename',
  118. array(
  119. 'schema_public' => 'public',
  120. 'filter' => $filter,
  121. )
  122. );
  123. $tables = array();
  124. while ($row = $smcFunc['db_fetch_row']($request))
  125. $tables[] = $row[0];
  126. $smcFunc['db_free_result']($request);
  127. return $tables;
  128. }
  129. // Get the content (INSERTs) for a table.
  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. // Get the schema (CREATE) for a table.
  176. function smf_db_table_sql($tableName)
  177. {
  178. global $smcFunc, $db_prefix;
  179. $tableName = str_replace('{db_prefix}', $db_prefix, $tableName);
  180. // This will be needed...
  181. $crlf = "\r\n";
  182. // Start the create table...
  183. $schema_create = 'CREATE TABLE ' . $tableName . ' (' . $crlf;
  184. $index_create = '';
  185. $seq_create = '';
  186. // Find all the fields.
  187. $result = $smcFunc['db_query']('', '
  188. SELECT column_name, column_default, is_nullable, data_type, character_maximum_length
  189. FROM information_schema.columns
  190. WHERE table_name = {string:table}
  191. ORDER BY ordinal_position',
  192. array(
  193. 'table' => $tableName,
  194. )
  195. );
  196. while ($row = $smcFunc['db_fetch_assoc']($result))
  197. {
  198. if ($row['data_type'] == 'character varying')
  199. $row['data_type'] = 'varchar';
  200. elseif ($row['data_type'] == 'character')
  201. $row['data_type'] = 'char';
  202. if ($row['character_maximum_length'])
  203. $row['data_type'] .= '(' . $row['character_maximum_length'] . ')';
  204. // Make the CREATE for this column.
  205. $schema_create .= ' "' . $row['column_name'] . '" ' . $row['data_type'] . ($row['is_nullable'] != 'YES' ? ' NOT NULL' : '');
  206. // Add a default...?
  207. if (trim($row['column_default']) != '')
  208. {
  209. $schema_create .= ' default ' . $row['column_default'] . '';
  210. // Auto increment?
  211. if (preg_match('~nextval\(\'(.+?)\'(.+?)*\)~i', $row['column_default'], $matches) != 0)
  212. {
  213. // Get to find the next variable first!
  214. $count_req = $smcFunc['db_query']('', '
  215. SELECT MAX("{raw:column}")
  216. FROM {raw:table}',
  217. array(
  218. 'column' => $row['column_name'],
  219. 'table' => $tableName,
  220. )
  221. );
  222. list ($max_ind) = $smcFunc['db_fetch_row']($count_req);
  223. $smcFunc['db_free_result']($count_req);
  224. // Get the right bloody start!
  225. $seq_create .= 'CREATE SEQUENCE ' . $matches[1] . ' START WITH ' . ($max_ind + 1) . ';' . $crlf . $crlf;
  226. }
  227. }
  228. $schema_create .= ',' . $crlf;
  229. }
  230. $smcFunc['db_free_result']($result);
  231. // Take off the last comma.
  232. $schema_create = substr($schema_create, 0, -strlen($crlf) - 1);
  233. $result = $smcFunc['db_query']('', '
  234. SELECT CASE WHEN i.indisprimary THEN 1 ELSE 0 END AS is_primary, pg_get_indexdef(i.indexrelid) AS inddef
  235. FROM pg_class AS c
  236. INNER JOIN pg_index AS i ON (i.indrelid = c.oid)
  237. INNER JOIN pg_class AS c2 ON (c2.oid = i.indexrelid)
  238. WHERE c.relname = {string:table}',
  239. array(
  240. 'table' => $tableName,
  241. )
  242. );
  243. $indexes = array();
  244. while ($row = $smcFunc['db_fetch_assoc']($result))
  245. {
  246. if ($row['is_primary'])
  247. {
  248. if (preg_match('~\(([^\)]+?)\)~i', $row['inddef'], $matches) == 0)
  249. continue;
  250. $index_create .= $crlf . 'ALTER TABLE ' . $tableName . ' ADD PRIMARY KEY ("' . $matches[1] . '");';
  251. }
  252. else
  253. $index_create .= $crlf . $row['inddef'] . ';';
  254. }
  255. $smcFunc['db_free_result']($result);
  256. // Finish it off!
  257. $schema_create .= $crlf . ');';
  258. return $seq_create . $schema_create . $index_create;
  259. }
  260. // Get the version number.
  261. function smf_db_get_version()
  262. {
  263. global $smcFunc;
  264. $request = $smcFunc['db_query']('', '
  265. SHOW server_version',
  266. array(
  267. )
  268. );
  269. list ($ver) = $smcFunc['db_fetch_row']($request);
  270. $smcFunc['db_free_result']($request);
  271. return $ver;
  272. }
  273. ?>