PageRenderTime 682ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/spip/ecrire/req/pg.php

https://github.com/eyeswebcrea/espace-couture-sittler.fr
PHP | 1287 lines | 1113 code | 74 blank | 100 comment | 67 complexity | 31c58994c145c3f3dd3ef6a14587f7be MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2011 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. if (!defined('_ECRIRE_INC_VERSION')) return;
  12. define('_DEFAULT_DB', 'spip');
  13. // Se connecte et retourne le nom de la fonction a connexion persistante
  14. // A la premiere connexion de l'installation (BD pas precisee)
  15. // si on ne peut se connecter sans la preciser
  16. // on reessaye avec le login comme nom de BD
  17. // et si ca marche toujours pas, avec "spip" (constante ci-dessus)
  18. // si ca ne marche toujours pas, echec.
  19. // http://doc.spip.org/@req_pg_dist
  20. function req_pg_dist($addr, $port, $login, $pass, $db='', $prefixe='') {
  21. static $last_connect = array();
  22. if (!charger_php_extension('pgsql')) return false;
  23. // si provient de selectdb
  24. if (empty($addr) && empty($port) && empty($login) && empty($pass)){
  25. foreach (array('addr','port','login','pass','prefixe') as $a){
  26. $$a = $last_connect[$a];
  27. }
  28. }
  29. @list($host, $p) = explode(';', $addr);
  30. if ($p >0) $port = " port=$p" ; else $port = '';
  31. if ($db) {
  32. @$link = pg_connect("host=$host$port dbname=$db user=$login password=$pass", PGSQL_CONNECT_FORCE_NEW);
  33. } elseif (!@$link = pg_connect("host=$host$port user=$login password=$pass", PGSQL_CONNECT_FORCE_NEW)) {
  34. if (@$link = pg_connect("host=$host$port dbname=$login user=$login password=$pass", PGSQL_CONNECT_FORCE_NEW)) {
  35. $db = $login;
  36. } else {
  37. $db = _DEFAULT_DB;
  38. $link = pg_connect("host=$host$port dbname=$db user=$login password=$pass", PGSQL_CONNECT_FORCE_NEW);
  39. }
  40. }
  41. if ($link)
  42. $last_connect = array (
  43. 'addr' => $addr,
  44. 'port' => $port,
  45. 'login' => $login,
  46. 'pass' => $pass,
  47. 'db' => $db,
  48. 'prefixe' => $prefixe,
  49. );
  50. # spip_log("Connexion vers $host, base $db, prefixe $prefixe "
  51. # . ($link ? 'operationnelle' : 'impossible'));
  52. return !$link ? false : array(
  53. 'db' => $db,
  54. 'prefixe' => $prefixe ? $prefixe : $db,
  55. 'link' => $link,
  56. );
  57. }
  58. $GLOBALS['spip_pg_functions_1'] = array(
  59. 'alter' => 'spip_pg_alter',
  60. 'count' => 'spip_pg_count',
  61. 'countsel' => 'spip_pg_countsel',
  62. 'create' => 'spip_pg_create',
  63. 'create_base' => 'spip_pg_create_base',
  64. 'create_view' => 'spip_pg_create_view',
  65. 'date_proche' => 'spip_pg_date_proche',
  66. 'delete' => 'spip_pg_delete',
  67. 'drop_table' => 'spip_pg_drop_table',
  68. 'drop_view' => 'spip_pg_drop_view',
  69. 'errno' => 'spip_pg_errno',
  70. 'error' => 'spip_pg_error',
  71. 'explain' => 'spip_pg_explain',
  72. 'fetch' => 'spip_pg_fetch',
  73. 'seek' => 'spip_pg_seek',
  74. 'free' => 'spip_pg_free',
  75. 'hex' => 'spip_pg_hex',
  76. 'in' => 'spip_pg_in',
  77. 'insert' => 'spip_pg_insert',
  78. 'insertq' => 'spip_pg_insertq',
  79. 'insertq_multi' => 'spip_pg_insertq_multi',
  80. 'listdbs' => 'spip_pg_listdbs',
  81. 'multi' => 'spip_pg_multi',
  82. 'optimize' => 'spip_pg_optimize',
  83. 'query' => 'spip_pg_query',
  84. 'quote' => 'spip_pg_quote',
  85. 'replace' => 'spip_pg_replace',
  86. 'replace_multi' => 'spip_pg_replace_multi',
  87. 'select' => 'spip_pg_select',
  88. 'selectdb' => 'spip_pg_selectdb',
  89. 'set_connect_charset' => 'spip_pg_set_connect_charset',
  90. 'showbase' => 'spip_pg_showbase',
  91. 'showtable' => 'spip_pg_showtable',
  92. 'update' => 'spip_pg_update',
  93. 'updateq' => 'spip_pg_updateq',
  94. );
  95. // Par ou ca passe une fois les traductions faites
  96. // http://doc.spip.org/@spip_pg_trace_query
  97. function spip_pg_trace_query($query, $serveur='')
  98. {
  99. $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  100. $prefixe = $connexion['prefixe'];
  101. $link = $connexion['link'];
  102. $db = $connexion['db'];
  103. if (isset($_GET['var_profile'])) {
  104. include_spip('public/tracer');
  105. $t = trace_query_start();
  106. } else $t = 0 ;
  107. $connexion['last'] = $query;
  108. $r = spip_pg_query_simple($link, $query);
  109. if ($e = spip_pg_errno($serveur)) // Log de l'erreur eventuelle
  110. $e .= spip_pg_error($query, $serveur); // et du fautif
  111. return $t ? trace_query_end($query, $t, $r, $e, $serveur) : $r;
  112. }
  113. // Fonction de requete generale quand on est sur que c'est SQL standard.
  114. // Elle change juste le noms des tables ($table_prefix) dans le FROM etc
  115. // http://doc.spip.org/@spip_pg_query
  116. function spip_pg_query($query, $serveur='',$requeter=true)
  117. {
  118. $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  119. $prefixe = $connexion['prefixe'];
  120. $link = $connexion['link'];
  121. $db = $connexion['db'];
  122. if (preg_match('/\s(SET|VALUES|WHERE|DATABASE)\s/i', $query, $regs)) {
  123. $suite = strstr($query, $regs[0]);
  124. $query = substr($query, 0, -strlen($suite));
  125. } else $suite ='';
  126. $query = preg_replace('/([,\s])spip_/', '\1'.$prefixe.'_', $query) . $suite;
  127. // renvoyer la requete inerte si demandee
  128. if (!$requeter) return $query;
  129. return spip_pg_trace_query($query, $serveur);
  130. }
  131. function spip_pg_query_simple($link, $query){
  132. #spip_log(var_export($query,true), 'pg_queries');
  133. return pg_query($link, $query);
  134. }
  135. /*
  136. * Retrouver les champs 'timestamp'
  137. * pour les ajouter aux 'insert' ou 'replace'
  138. * afin de simuler le fonctionnement de mysql
  139. *
  140. * stocke le resultat pour ne pas faire
  141. * de requetes showtable intempestives
  142. */
  143. function spip_pg_ajouter_champs_timestamp($table, $couples, $desc='', $serveur=''){
  144. static $tables = array();
  145. if (!isset($tables[$table])){
  146. if (!$desc){
  147. $f = charger_fonction('trouver_table', 'base');
  148. $desc = $f($table, $serveur);
  149. // si pas de description, on ne fait rien, ou on die() ?
  150. if (!$desc) return $couples;
  151. }
  152. // recherche des champs avec simplement 'TIMESTAMP'
  153. // cependant, il faudra peut etre etendre
  154. // avec la gestion de DEFAULT et ON UPDATE
  155. // mais ceux-ci ne sont pas utilises dans le core
  156. $tables[$table] = array();
  157. foreach ($desc['field'] as $k=>$v){
  158. if (strpos(strtolower(ltrim($v)), 'timestamp')===0)
  159. $tables[$table][] = $k;
  160. }
  161. }
  162. // ajout des champs type 'timestamp' absents
  163. foreach ($tables[$table] as $maj){
  164. if (!array_key_exists($maj, $couples))
  165. $couples[$maj] = "NOW()";
  166. }
  167. return $couples;
  168. }
  169. // Alter en PG ne traite pas les index
  170. // http://doc.spip.org/@spip_pg_alter
  171. function spip_pg_alter($query, $serveur='',$requeter=true) {
  172. // il faudrait une regexp pour eviter de spliter ADD PRIMARY KEY (colA, colB)
  173. // tout en cassant en deux alter distincts "ADD PRIMARY KEY (colA, colB), ADD INDEX (chose)"...
  174. // ou revoir l'api de sql_alter en creant un
  175. // sql_alter_table($table,array($actions));
  176. if (!preg_match("/\s*((\s*IGNORE)?\s*TABLE\s*([^\s]*))\s*(.*)?/is", $query, $regs)){
  177. spip_log("$query mal comprise", 'pg');
  178. return false;
  179. }
  180. $debut = $regs[1];
  181. $table = $regs[3];
  182. $suite = $regs[4];
  183. $todo = explode(',', $suite);
  184. // on remet les morceaux dechires ensembles... que c'est laid !
  185. $todo2 = array(); $i=0;
  186. $ouverte = false;
  187. while ($do = array_shift($todo)) {
  188. $todo2[$i] = isset($todo2[$i]) ? $todo2[$i] . "," . $do : $do;
  189. $o=(false!==strpos($do,"("));
  190. $f=(false!==strpos($do,")"));
  191. if ($o AND !$f) $ouverte=true;
  192. elseif ($f) $ouverte=false;
  193. if (!$ouverte) $i++;
  194. }
  195. $todo=$todo2;
  196. $query = $debut.' '.array_shift($todo);
  197. if (!preg_match('/^\s*(IGNORE\s*)?TABLE\s+(\w+)\s+(ADD|DROP|CHANGE|MODIFY|RENAME)\s*(.*)$/is', $query, $r)) {
  198. spip_log("$query incompris", 'pg');
  199. } else {
  200. if ($r[1]) spip_log("j'ignore IGNORE dans $query", 'pg');
  201. $f = 'spip_pg_alter_' . strtolower($r[3]);
  202. if (function_exists($f))
  203. $f($r[2], $r[4], $serveur, $requeter);
  204. else spip_log("$query non prevu", 'pg');
  205. }
  206. // Alter a plusieurs args. Faudrait optimiser.
  207. if ($todo)
  208. spip_pg_alter("TABLE $table " . join(',',$todo));
  209. }
  210. // http://doc.spip.org/@spip_pg_alter_change
  211. function spip_pg_alter_change($table, $arg, $serveur='',$requeter=true)
  212. {
  213. if (!preg_match('/^`?(\w+)`?\s+`?(\w+)`?\s+(.*?)\s*(DEFAULT .*?)?(NOT\s+NULL)?\s*(DEFAULT .*?)?$/i',$arg, $r)) {
  214. spip_log("alter change: $arg incompris", 'pg');
  215. } else {
  216. list(,$old, $new, $type, $default, $null, $def2) = $r;
  217. $actions = array("ALTER $old TYPE " . mysql2pg_type($type));
  218. if ($null)
  219. $actions[]= "ALTER $old SET NOT NULL";
  220. else
  221. $actions[]= "ALTER $old DROP NOT NULL";
  222. if ($d = ($default ? $default : $def2))
  223. $actions[]= "ALTER $old SET $d";
  224. else
  225. $actions[]= "ALTER $old DROP DEFAULT";
  226. spip_pg_query("ALTER TABLE $table " . join(', ', $actions));
  227. if ($old != $new)
  228. spip_pg_query("ALTER TABLE $table RENAME $old TO $new", $serveur);
  229. }
  230. }
  231. // http://doc.spip.org/@spip_pg_alter_add
  232. function spip_pg_alter_add($table, $arg, $serveur='',$requeter=true) {
  233. if (!preg_match('/^(COLUMN|INDEX|KEY|PRIMARY\s+KEY|)\s*(.*)$/', $arg, $r)) {
  234. spip_log("alter add $arg incompris", 'pg');
  235. return NULL;
  236. }
  237. if (!$r[1] OR $r[1]=='COLUMN') {
  238. preg_match('/`?(\w+)`?(.*)/',$r[2], $m);
  239. if (preg_match('/^(.*)(BEFORE|AFTER|FIRST)(.*)$/is', $m[2], $n)) {
  240. $m[2]=$n[1];
  241. }
  242. return spip_pg_query("ALTER TABLE $table ADD " . $m[1] . ' ' . mysql2pg_type($m[2]), $serveur, $requeter);
  243. } elseif ($r[1][0] == 'P') {
  244. // la primary peut etre sur plusieurs champs
  245. $r[2] = trim(str_replace('`','',$r[2]));
  246. $m = ($r[2][0]=='(') ? substr($r[2],1,-1) : $r[2];
  247. return spip_pg_query("ALTER TABLE $table ADD CONSTRAINT $table" .'_pkey PRIMARY KEY (' . $m . ')', $serveur, $requeter);
  248. } else {
  249. preg_match('/([^\s,]*)\s*(.*)?/',$r[2], $m);
  250. // peut etre "(colonne)" ou "nom_index (colonnes)"
  251. // bug potentiel si qqn met "(colonne, colonne)"
  252. //
  253. // nom_index (colonnes)
  254. if ($m[2]) {
  255. $colonnes = substr($m[2],1,-1);
  256. $nom_index = $m[1];
  257. }
  258. else {
  259. // (colonne)
  260. if ($m[1][0] == "(") {
  261. $colonnes = substr($m[1],1,-1);
  262. if (false!==strpos(",",$colonnes)) {
  263. spip_log("PG : Erreur, impossible de creer un index sur plusieurs colonnes"
  264. ." sans qu'il ait de nom ($table, ($colonnes))", 'pg');
  265. break;
  266. } else {
  267. $nom_index = $colonnes;
  268. }
  269. }
  270. // nom_index
  271. else {
  272. $nom_index = $colonnes = $m[1];
  273. }
  274. }
  275. return spip_pg_create_index($nom_index, $table, $colonnes, $serveur, $requeter);
  276. }
  277. }
  278. // http://doc.spip.org/@spip_pg_alter_drop
  279. function spip_pg_alter_drop($table, $arg, $serveur='',$requeter=true) {
  280. if (!preg_match('/^(COLUMN|INDEX|KEY|PRIMARY\s+KEY|)\s*`?(\w*)`?/', $arg, $r))
  281. spip_log("alter drop: $arg incompris", 'pg');
  282. else {
  283. if (!$r[1] OR $r[1]=='COLUMN')
  284. return spip_pg_query("ALTER TABLE $table DROP " . $r[2], $serveur);
  285. elseif ($r[1][0] == 'P')
  286. return spip_pg_query("ALTER TABLE $table DROP CONSTRAINT $table" . '_pkey', $serveur);
  287. else {
  288. return spip_pg_query("DROP INDEX " . $table . '_' . $r[2], $serveur);
  289. }
  290. }
  291. }
  292. function spip_pg_alter_modify($table, $arg, $serveur='',$requeter=true) {
  293. if (!preg_match('/^`?(\w+)`?\s+(.*)$/',$arg, $r)) {
  294. spip_log("alter modify: $arg incompris", 'pg');
  295. } else {
  296. return spip_pg_alter_change($table, $r[1].' '.$arg, $serveur='',$requeter=true);
  297. }
  298. }
  299. // attention (en pg) :
  300. // - alter table A rename to X = changer le nom de la table
  301. // - alter table A rename X to Y = changer le nom de la colonne X en Y
  302. // pour l'instant, traiter simplement RENAME TO X
  303. function spip_pg_alter_rename($table, $arg, $serveur='',$requeter=true) {
  304. $rename="";
  305. // si TO, mais pas au debut
  306. if (!stripos($arg,'TO ')){
  307. $rename=$arg;
  308. }
  309. elseif (preg_match('/^(TO)\s*`?(\w*)`?/', $arg, $r)) {
  310. $rename=$r[2];
  311. } else {
  312. spip_log("alter rename: $arg incompris", 'pg');
  313. }
  314. return $rename?spip_pg_query("ALTER TABLE $table RENAME TO $rename"):false;
  315. }
  316. /**
  317. * Fonction de creation d'un INDEX
  318. *
  319. * @param string $nom : nom de l'index
  320. * @param string $table : table sql de l'index
  321. * @param string/array $champs : liste de champs sur lesquels s'applique l'index
  322. * @param string $serveur : nom de la connexion sql utilisee
  323. * @param bool $requeter : true pour executer la requete ou false pour retourner le texte de la requete
  324. *
  325. * @return bool ou requete
  326. */
  327. function spip_pg_create_index($nom, $table, $champs, $serveur='', $requeter=true) {
  328. if (!($nom OR $table OR $champs)) {
  329. spip_log("Champ manquant pour creer un index pg ($nom, $table, (".@join(',',$champs)."))","pg");
  330. return false;
  331. }
  332. $nom = str_replace("`","",$nom);
  333. $champs = str_replace("`","",$champs);
  334. // PG ne differentie pas noms des index en fonction des tables
  335. // il faut donc creer des noms uniques d'index pour une base pg
  336. $nom = $table.'_'.$nom;
  337. // enlever d'eventuelles parentheses deja presentes sur champs
  338. if (!is_array($champs)){
  339. if ($champs[0]=="(") $champs = substr($champs,1,-1);
  340. $champs = array($champs);
  341. }
  342. $query = "CREATE INDEX $nom ON $table (" . join(',',$champs) . ")";
  343. if (!$requeter) return $query;
  344. $res = spip_pg_query($query, $serveur, $requeter);
  345. return $res;
  346. }
  347. // http://doc.spip.org/@spip_pg_explain
  348. function spip_pg_explain($query, $serveur='',$requeter=true){
  349. if (strpos(ltrim($query), 'SELECT') !== 0) return array();
  350. $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  351. $prefixe = $connexion['prefixe'];
  352. $link = $connexion['link'];
  353. if (preg_match('/\s(SET|VALUES|WHERE)\s/i', $query, $regs)) {
  354. $suite = strstr($query, $regs[0]);
  355. $query = substr($query, 0, -strlen($suite));
  356. } else $suite ='';
  357. $query = 'EXPLAIN ' . preg_replace('/([,\s])spip_/', '\1'.$prefixe.'_', $query) . $suite;
  358. if (!$requeter) return $query;
  359. $r = spip_pg_query_simple($link,$query);
  360. return spip_pg_fetch($r, NULL, $serveur);
  361. }
  362. // http://doc.spip.org/@spip_pg_selectdb
  363. function spip_pg_selectdb($db, $serveur='',$requeter=true) {
  364. // se connecter a la base indiquee
  365. // avec les identifiants connus
  366. $index = $serveur ? strtolower($serveur) : 0;
  367. if ($link = spip_connect_db('', '', '', '', $db, 'pg', '', '')){
  368. if (($db==$link['db']) && $GLOBALS['connexions'][$index] = $link)
  369. return $db;
  370. } else
  371. return false;
  372. }
  373. // Qu'une seule base pour le moment
  374. // http://doc.spip.org/@spip_pg_listdbs
  375. function spip_pg_listdbs($serveur) {
  376. $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  377. $link = $connexion['link'];
  378. return spip_pg_query_simple($link, "select * From pg_database");
  379. }
  380. // http://doc.spip.org/@spip_pg_select
  381. function spip_pg_select($select, $from, $where='',
  382. $groupby=array(), $orderby='', $limit='',
  383. $having='', $serveur='',$requeter=true){
  384. $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  385. $prefixe = $connexion['prefixe'];
  386. $link = $connexion['link'];
  387. $db = $connexion['db'];
  388. $limit = preg_match("/^\s*(([0-9]+),)?\s*([0-9]+)\s*$/", $limit,$limatch);
  389. if ($limit) {
  390. $offset = $limatch[2];
  391. $count = $limatch[3];
  392. }
  393. $select = spip_pg_frommysql($select);
  394. // si pas de tri explicitement demande, le GROUP BY ne
  395. // contient que la clef primaire.
  396. // lui ajouter alors le champ de tri par defaut
  397. if (preg_match("/FIELD\(([a-z]+\.[a-z]+),/i", $orderby[0], $groupbyplus)) {
  398. $groupby[] = $groupbyplus[1];
  399. }
  400. $orderby = spip_pg_orderby($orderby, $select);
  401. if ($having) {
  402. if (is_array($having))
  403. $having = join("\n\tAND ", array_map('calculer_pg_where', $having));
  404. }
  405. $from = spip_pg_from($from, $prefixe);
  406. $query = "SELECT ". $select
  407. . (!$from ? '' : "\nFROM $from")
  408. . (!$where ? '' : ("\nWHERE " . (!is_array($where) ? calculer_pg_where($where) : (join("\n\tAND ", array_map('calculer_pg_where', $where))))))
  409. . spip_pg_groupby($groupby, $from, $select)
  410. . (!$having ? '' : "\nHAVING $having")
  411. . ($orderby ? ("\nORDER BY $orderby") :'')
  412. . (!$limit ? '' : (" LIMIT $count" . (!$offset ? '' : " OFFSET $offset")));
  413. // renvoyer la requete inerte si demandee
  414. if ($requeter === false) return $query;
  415. $r = spip_pg_trace_query($query, $serveur);
  416. return $r ? $r : $query;;
  417. }
  418. // Le traitement des prefixes de table dans un Select se limite au FROM
  419. // car le reste de la requete utilise les alias (AS) systematiquement
  420. // http://doc.spip.org/@spip_pg_from
  421. function spip_pg_from($from, $prefixe)
  422. {
  423. if (is_array($from)) $from = spip_pg_select_as($from);
  424. return !$prefixe ? $from : preg_replace('/(\b)spip_/','\1'.$prefixe.'_', $from);
  425. }
  426. // http://doc.spip.org/@spip_pg_orderby
  427. function spip_pg_orderby($order, $select)
  428. {
  429. $res = array();
  430. $arg = (is_array($order) ? $order : preg_split('/\s*,\s*/',$order));
  431. foreach($arg as $v) {
  432. if (preg_match('/(case\s+.*?else\s+0\s+end)\s*AS\s+' . $v .'/', $select, $m)) {
  433. $res[] = $m[1];
  434. } else $res[]=$v;
  435. }
  436. return spip_pg_frommysql(join(',',$res));
  437. }
  438. // Conversion a l'arrach' des jointures MySQL en jointures PG
  439. // A refaire pour tirer parti des possibilites de PG et de MySQL5
  440. // et pour enlever les repetitions (sans incidence de perf, mais ca fait sale)
  441. // http://doc.spip.org/@spip_pg_groupby
  442. function spip_pg_groupby($groupby, $from, $select)
  443. {
  444. $join = strpos($from, ",");
  445. if ($join OR $groupby) $join = !is_array($select) ? $select : join(", ", $select);
  446. if ($join) {
  447. $join = str_replace('DISTINCT ','',$join);
  448. // fct SQL sur colonne et constante apostrophee ==> la colonne
  449. $join = preg_replace('/\w+\(\s*([^(),\']*),\s*\'[^\']*\'[^)]*\)/','\\1', $join);
  450. $join = preg_replace('/CAST\(\s*([^(),\' ]*\s+)as\s*\w+\)/','\\1', $join);
  451. // resultat d'agregat ne sont pas a mettre dans le groupby
  452. $join = preg_replace('/(SUM|COUNT|MAX|MIN|UPPER)\([^)]+\)(\s*AS\s+\w+)\s*,?/i','', $join);
  453. // idem sans AS (fetch numerique)
  454. $join = preg_replace('/(SUM|COUNT|MAX|MIN|UPPER)\([^)]+\)\s*,?/i','', $join);
  455. // ne reste plus que les vrais colonnes, et parfois 1 virgule
  456. if (preg_match('/^(.*),\s*$/',$join,$m)) $join=$m[1];
  457. }
  458. if (is_array($groupby)) $groupby = join(',',$groupby);
  459. if ($join) $groupby = $groupby ? "$groupby, $join" : $join;
  460. if (!$groupby) return '';
  461. $groupby = spip_pg_frommysql($groupby);
  462. $groupby = preg_replace('/\s+AS\s+\w+\s*/i','', $groupby);
  463. return "\nGROUP BY $groupby";
  464. }
  465. // Conversion des operateurs MySQL en PG
  466. // IMPORTANT: "0+X" est vu comme conversion numerique du debut de X
  467. // Les expressions de date ne sont pas gerees au-dela de 3 ()
  468. // Le 'as' du 'CAST' est en minuscule pour echapper au dernier preg_replace
  469. // de spip_pg_groupby.
  470. // A ameliorer.
  471. // http://doc.spip.org/@spip_pg_frommysql
  472. function spip_pg_frommysql($arg)
  473. {
  474. if (is_array($arg)) $arg = join(", ", $arg);
  475. $res = spip_pg_fromfield($arg);
  476. $res = preg_replace('/\brand[(][)]/i','random()', $res);
  477. $res = preg_replace('/\b0\.0[+]([a-zA-Z0-9_.]+)\s*/',
  478. 'CAST(substring(\1, \'^ *[0-9.]+\') as float)',
  479. $res);
  480. $res = preg_replace('/\b0[+]([a-zA-Z0-9_.]+)\s*/',
  481. 'CAST(substring(\1, \'^ *[0-9]+\') as int)',
  482. $res);
  483. $res = preg_replace('/\bconv[(]([^,]*)[^)]*[)]/i',
  484. 'CAST(substring(\1, \'^ *[0-9]+\') as int)',
  485. $res);
  486. $res = preg_replace('/UNIX_TIMESTAMP\s*[(]\s*[)]/',
  487. ' EXTRACT(epoch FROM NOW())', $res);
  488. // la fonction md5(integer) n'est pas connu en pg
  489. // il faut donc forcer les types en text (cas de md5(id_article))
  490. $res = preg_replace('/md5\s*[(]([^)]*)[)]/i',
  491. 'MD5(CAST(\1 AS text))', $res);
  492. $res = preg_replace('/UNIX_TIMESTAMP\s*[(]([^)]*)[)]/',
  493. ' EXTRACT(epoch FROM \1)', $res);
  494. $res = preg_replace('/\bDAYOFMONTH\s*[(]([^()]*([(][^()]*[)][^()]*)*[^)]*)[)]/',
  495. ' EXTRACT(day FROM \1)',
  496. $res);
  497. $res = preg_replace('/\bMONTH\s*[(]([^()]*([(][^)]*[)][^()]*)*[^)]*)[)]/',
  498. ' EXTRACT(month FROM \1)',
  499. $res);
  500. $res = preg_replace('/\bYEAR\s*[(]([^()]*([(][^)]*[)][^()]*)*[^)]*)[)]/',
  501. ' EXTRACT(year FROM \1)',
  502. $res);
  503. $res = preg_replace('/TO_DAYS\s*[(]([^()]*([(][^)]*[)][()]*)*)[)]/',
  504. ' EXTRACT(day FROM \1 - \'0001-01-01\')',
  505. $res);
  506. $res = preg_replace("/(EXTRACT[(][^ ]* FROM *)\"([^\"]*)\"/", '\1\'\2\'', $res);
  507. $res = preg_replace('/DATE_FORMAT\s*[(]([^,]*),\s*\'%Y%m%d\'[)]/', 'to_char(\1, \'YYYYMMDD\')', $res);
  508. $res = preg_replace('/DATE_FORMAT\s*[(]([^,]*),\s*\'%Y%m\'[)]/', 'to_char(\1, \'YYYYMM\')', $res);
  509. $res = preg_replace('/DATE_SUB\s*[(]([^,]*),/', '(\1 -', $res);
  510. $res = preg_replace('/DATE_ADD\s*[(]([^,]*),/', '(\1 +', $res);
  511. $res = preg_replace('/INTERVAL\s+(\d+\s+\w+)/', 'INTERVAL \'\1\'', $res);
  512. $res = preg_replace('/([+<>-]=?)\s*(\'\d+-\d+-\d+\s+\d+:\d+(:\d+)\')/', '\1 timestamp \2', $res);
  513. $res = preg_replace('/(\'\d+-\d+-\d+\s+\d+:\d+:\d+\')\s*([+<>-]=?)/', 'timestamp \1 \2', $res);
  514. $res = preg_replace('/([+<>-]=?)\s*(\'\d+-\d+-\d+\')/', '\1 timestamp \2', $res);
  515. $res = preg_replace('/(\'\d+-\d+-\d+\')\s*([+<>-]=?)/', 'timestamp \1 \2', $res);
  516. $res = preg_replace('/(timestamp .\d+)-00-/','\1-01-', $res);
  517. $res = preg_replace('/(timestamp .\d+-\d+)-00/','\1-01',$res);
  518. # correct en theorie mais produit des debordements arithmetiques
  519. # $res = preg_replace("/(EXTRACT[(][^ ]* FROM *)(timestamp *'[^']*' *[+-] *timestamp *'[^']*') *[)]/", '\2', $res);
  520. $res = preg_replace("/(EXTRACT[(][^ ]* FROM *)('[^']*')/", '\1 timestamp \2', $res);
  521. $res = preg_replace("/\sLIKE\s+/", ' ILIKE ', $res);
  522. return str_replace('REGEXP', '~', $res);
  523. }
  524. // http://doc.spip.org/@spip_pg_fromfield
  525. function spip_pg_fromfield($arg)
  526. {
  527. while(preg_match('/^(.*?)FIELD\s*\(([^,]*)((,[^,)]*)*)\)/', $arg, $m)) {
  528. preg_match_all('/,([^,]*)/', $m[3], $r, PREG_PATTERN_ORDER);
  529. $res = '';
  530. $n=0;
  531. $index = $m[2];
  532. foreach($r[1] as $v) {
  533. $n++;
  534. $res .= "\nwhen $index=$v then $n";
  535. }
  536. $arg = $m[1] . "case $res else 0 end "
  537. . substr($arg,strlen($m[0]));
  538. }
  539. return $arg;
  540. }
  541. // http://doc.spip.org/@calculer_pg_where
  542. function calculer_pg_where($v)
  543. {
  544. if (!is_array($v))
  545. return spip_pg_frommysql($v);
  546. $op = str_replace('REGEXP', '~', array_shift($v));
  547. if (!($n=count($v)))
  548. return $op;
  549. else {
  550. $arg = calculer_pg_where(array_shift($v));
  551. if ($n==1) {
  552. return "$op($arg)";
  553. } else {
  554. $arg2 = calculer_pg_where(array_shift($v));
  555. if ($n==2) {
  556. return "($arg $op $arg2)";
  557. } else return "($arg $op ($arg2) : $v[0])";
  558. }
  559. }
  560. }
  561. // http://doc.spip.org/@calculer_pg_expression
  562. function calculer_pg_expression($expression, $v, $join = 'AND'){
  563. if (empty($v))
  564. return '';
  565. $exp = "\n$expression ";
  566. if (!is_array($v)) $v = array($v);
  567. if (strtoupper($join) === 'AND')
  568. return $exp . join("\n\t$join ", array_map('calculer_pg_where', $v));
  569. else
  570. return $exp . join($join, $v);
  571. }
  572. // http://doc.spip.org/@spip_pg_select_as
  573. function spip_pg_select_as($args)
  574. {
  575. $argsas = "";
  576. foreach($args as $k => $v) {
  577. if (substr($k,-1)=='@') {
  578. // c'est une jointure qui se refere au from precedent
  579. // pas de virgule
  580. $argsas .= ' ' . $v ;
  581. }
  582. else {
  583. $as = '';
  584. // spip_log("$k : $v");
  585. if (!is_numeric($k)) {
  586. if (preg_match('/\.(.*)$/', $k, $r))
  587. $v = $k;
  588. elseif ($v != $k) {
  589. $p = strpos($v, " ");
  590. if ($p)
  591. $v = substr($v,0,$p) . " AS $k" . substr($v,$p);
  592. else $as = " AS $k";
  593. }
  594. }
  595. // spip_log("subs $k : $v avec $as");
  596. // if (strpos($v, 'JOIN') === false) $argsas .= ', ';
  597. $argsas .= ', '. $v . $as;
  598. }
  599. }
  600. return substr($argsas,2) . $join;
  601. }
  602. // http://doc.spip.org/@spip_pg_fetch
  603. function spip_pg_fetch($res, $t='', $serveur='',$requeter=true) {
  604. if ($res) $res = pg_fetch_array($res, NULL, PGSQL_ASSOC);
  605. return $res;
  606. }
  607. function spip_pg_seek($r, $row_number, $serveur='',$requeter=true) {
  608. if ($r) return pg_result_seek($r,$row_number);
  609. }
  610. // http://doc.spip.org/@spip_pg_countsel
  611. function spip_pg_countsel($from = array(), $where = array(), $groupby=array(),
  612. $having = array(), $serveur='',$requeter=true)
  613. {
  614. $c = !$groupby ? '*' : ('DISTINCT ' . (is_string($groupby) ? $groupby : join(',', $groupby)));
  615. $r = spip_pg_select("COUNT($c)", $from, $where,'', '', '', $having, $serveur, $requeter);
  616. if (!$requeter) return $r;
  617. if (!is_resource($r)) return 0;
  618. list($c) = pg_fetch_array($r, NULL, PGSQL_NUM);
  619. return $c;
  620. }
  621. // http://doc.spip.org/@spip_pg_count
  622. function spip_pg_count($res, $serveur='',$requeter=true) {
  623. return !$res ? 0 : pg_numrows($res);
  624. }
  625. // http://doc.spip.org/@spip_pg_free
  626. function spip_pg_free($res, $serveur='',$requeter=true) {
  627. // rien a faire en postgres
  628. }
  629. // http://doc.spip.org/@spip_pg_delete
  630. function spip_pg_delete($table, $where='', $serveur='',$requeter=true) {
  631. $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  632. $prefixe = $connexion['prefixe'];
  633. $link = $connexion['link'];
  634. $db = $connexion['db'];
  635. if ($prefixe) $table = preg_replace('/^spip/', $prefixe, $table);
  636. $query = calculer_pg_expression('DELETE FROM', $table, ',')
  637. . calculer_pg_expression('WHERE', $where, 'AND');
  638. // renvoyer la requete inerte si demandee
  639. if (!$requeter) return $query;
  640. $res = spip_pg_trace_query($query, $serveur);
  641. if ($res)
  642. return pg_affected_rows($res);
  643. else
  644. return false;
  645. }
  646. // http://doc.spip.org/@spip_pg_insert
  647. function spip_pg_insert($table, $champs, $valeurs, $desc=array(), $serveur='',$requeter=true) {
  648. $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  649. $prefixe = $connexion['prefixe'];
  650. $link = $connexion['link'];
  651. $db = $connexion['db'];
  652. if (!$desc) $desc = description_table($table);
  653. $seq = spip_pg_sequence($table);
  654. if ($prefixe) {
  655. $table = preg_replace('/^spip/', $prefixe, $table);
  656. $seq = preg_replace('/^spip/', $prefixe, $seq);
  657. }
  658. $ret = !$seq ? '' : (" RETURNING currval('$seq')");
  659. $ins = (strlen($champs)<3)
  660. ? " DEFAULT VALUES"
  661. : "$champs VALUES $valeurs";
  662. $q ="INSERT INTO $table $ins $ret";
  663. if (!$requeter) return $q;
  664. $connexion['last'] = $q;
  665. $r = spip_pg_query_simple($link, $q);
  666. # spip_log($q);
  667. if ($r) {
  668. if (!$ret) return 0;
  669. if ($r2 = pg_fetch_array($r, NULL, PGSQL_NUM))
  670. return $r2[0];
  671. }
  672. return false;
  673. }
  674. // http://doc.spip.org/@spip_pg_insertq
  675. function spip_pg_insertq($table, $couples=array(), $desc=array(), $serveur='',$requeter=true) {
  676. if (!$desc) $desc = description_table($table);
  677. if (!$desc) die("$table insertion sans description");
  678. $fields = $desc['field'];
  679. foreach ($couples as $champ => $val) {
  680. $couples[$champ]= spip_pg_cite($val, $fields[$champ]);
  681. }
  682. // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
  683. $couples = spip_pg_ajouter_champs_timestamp($table, $couples, $desc, $serveur);
  684. return spip_pg_insert($table, "(".join(',',array_keys($couples)).")", "(".join(',', $couples).")", $desc, $serveur, $requeter);
  685. }
  686. // http://doc.spip.org/@spip_pg_insertq_multi
  687. function spip_pg_insertq_multi($table, $tab_couples=array(), $desc=array(), $serveur='',$requeter=true) {
  688. if (!$desc) $desc = description_table($table);
  689. if (!$desc) die("$table insertion sans description");
  690. $fields = isset($desc['field'])?$desc['field']:array();
  691. // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
  692. // une premiere fois pour ajouter maj dans les cles
  693. $les_cles = spip_pg_ajouter_champs_timestamp($table, $tab_couples[0], $desc, $serveur);
  694. $cles = "(" . join(',',array_keys($les_cles)). ')';
  695. $valeurs = array();
  696. foreach ($tab_couples as $couples) {
  697. foreach ($couples as $champ => $val){
  698. $couples[$champ]= spip_pg_cite($val, $fields[$champ]);
  699. }
  700. // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
  701. $couples = spip_pg_ajouter_champs_timestamp($table, $couples, $desc, $serveur);
  702. $valeurs[] = '(' .join(',', $couples) . ')';
  703. }
  704. $valeurs = implode(', ',$valeurs);
  705. return spip_pg_insert($table, $cles, $valeurs, $desc, $serveur, $requeter);
  706. }
  707. // http://doc.spip.org/@spip_pg_update
  708. function spip_pg_update($table, $couples, $where='', $desc='', $serveur='',$requeter=true) {
  709. if (!$couples) return;
  710. $connexion = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  711. $prefixe = $connexion['prefixe'];
  712. $link = $connexion['link'];
  713. $db = $connexion['db'];
  714. if ($prefixe) $table = preg_replace('/^spip/', $prefixe, $table);
  715. // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
  716. $couples = spip_pg_ajouter_champs_timestamp($table, $couples, $desc, $serveur);
  717. $set = array();
  718. foreach ($couples as $champ => $val) {
  719. $set[] = $champ . '=' . $val;
  720. }
  721. $query = calculer_pg_expression('UPDATE', $table, ',')
  722. . calculer_pg_expression('SET', $set, ',')
  723. . calculer_pg_expression('WHERE', $where, 'AND');
  724. // renvoyer la requete inerte si demandee
  725. if (!$requeter) return $query;
  726. return spip_pg_trace_query($query, $serveur);
  727. }
  728. // idem, mais les valeurs sont des constantes a mettre entre apostrophes
  729. // sauf les expressions de date lorsqu'il s'agit de fonctions SQL (NOW etc)
  730. // http://doc.spip.org/@spip_pg_updateq
  731. function spip_pg_updateq($table, $couples, $where='', $desc=array(), $serveur='',$requeter=true) {
  732. if (!$couples) return;
  733. if (!$desc) $desc = description_table($table);
  734. $fields = $desc['field'];
  735. foreach ($couples as $k => $val) {
  736. $couples[$k] = spip_pg_cite($val, $fields[$k]);
  737. }
  738. return spip_pg_update($table, $couples, $where, $desc, $serveur, $requeter);
  739. }
  740. // http://doc.spip.org/@spip_pg_replace
  741. function spip_pg_replace($table, $values, $desc, $serveur='',$requeter=true) {
  742. if (!$values) {spip_log("replace vide $table"); return 0;}
  743. $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  744. $prefixe = $connexion['prefixe'];
  745. $link = $connexion['link'];
  746. $db = $connexion['db'];
  747. if (!$desc) $desc = description_table($table);
  748. if (!$desc) die("$table insertion sans description");
  749. $prim = $desc['key']['PRIMARY KEY'];
  750. $ids = preg_split('/,\s*/', $prim);
  751. $noprims = $prims = array();
  752. foreach($values as $k=>$v) {
  753. $values[$k] = $v = spip_pg_cite($v, $desc['field'][$k]);
  754. if (!in_array($k, $ids))
  755. $noprims[$k]= "$k=$v";
  756. else $prims[$k]= "$k=$v";
  757. }
  758. // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
  759. $values = spip_pg_ajouter_champs_timestamp($table, $values, $desc, $serveur);
  760. $where = join(' AND ', $prims);
  761. if (!$where) {
  762. return spip_pg_insert($table, "(".join(',',array_keys($values)).")", "(".join(',', $values).")", $desc, $serveur);
  763. }
  764. $couples = join(',', $noprims);
  765. $seq = spip_pg_sequence($table);
  766. if ($prefixe) {
  767. $table = preg_replace('/^spip/', $prefixe, $table);
  768. $seq = preg_replace('/^spip/', $prefixe, $seq);
  769. }
  770. $connexion['last'] = $q = "UPDATE $table SET $couples WHERE $where";
  771. if ($couples) {
  772. $couples = spip_pg_query_simple($link, $q);
  773. # spip_log($q);
  774. if (!$couples) return false;
  775. $couples = pg_affected_rows($couples);
  776. }
  777. if (!$couples) {
  778. $ret = !$seq ? '' :
  779. (" RETURNING nextval('$seq') < $prim");
  780. $connexion['last'] = $q = "INSERT INTO $table (" . join(',',array_keys($values)) . ') VALUES (' .join(',', $values) . ")$ret";
  781. $couples = spip_pg_query_simple($link, $q);
  782. if (!$couples) {
  783. return false;
  784. } elseif ($ret) {
  785. $r = pg_fetch_array($couples, NULL, PGSQL_NUM);
  786. if ($r[0]) {
  787. $connexion['last'] = $q = "SELECT setval('$seq', $prim) from $table";
  788. // Le code de SPIP met parfois la sequence a 0 (dans l'import)
  789. // MySQL n'en dit rien, on fait pareil pour PG
  790. $r = @pg_query($link, $q);
  791. }
  792. }
  793. }
  794. return $couples;
  795. }
  796. // http://doc.spip.org/@spip_pg_replace_multi
  797. function spip_pg_replace_multi($table, $tab_couples, $desc=array(), $serveur='',$requeter=true) {
  798. // boucler pour traiter chaque requete independemment
  799. foreach ($tab_couples as $couples){
  800. $retour = spip_pg_replace($table, $couples, $desc, $serveur,$requeter);
  801. }
  802. // renvoie le dernier id
  803. return $retour;
  804. }
  805. // Donne la sequence eventuelle associee a une table
  806. // Pas extensible pour le moment,
  807. // http://doc.spip.org/@spip_pg_sequence
  808. function spip_pg_sequence($table)
  809. {
  810. global $tables_principales;
  811. include_spip('base/serial');
  812. if (!isset($tables_principales[$table])) return false;
  813. $desc = $tables_principales[$table];
  814. $prim = @$desc['key']['PRIMARY KEY'];
  815. if (!preg_match('/^\w+$/', $prim)
  816. OR strpos($desc['field'][$prim], 'int') === false)
  817. return '';
  818. else { return $table . '_' . $prim . "_seq";}
  819. }
  820. // Explicite les conversions de Mysql d'une valeur $v de type $t
  821. // Dans le cas d'un champ date, pas d'apostrophe, c'est une syntaxe ad hoc
  822. // http://doc.spip.org/@spip_pg_cite
  823. function spip_pg_cite($v, $t)
  824. {
  825. if (sql_test_date($t)) {
  826. if (strpos("0123456789", $v[0]) === false)
  827. return spip_pg_frommysql($v);
  828. else {
  829. if (strpos($v, "-00-00") <= 4) {
  830. $annee = substr($v,0,4);
  831. if (!intval($annee)) $annee = '0001';
  832. $v = $annee ."-01-01".substr($v,10);
  833. }
  834. return "timestamp '$v'";
  835. }
  836. }
  837. elseif (!sql_test_int($t))
  838. return ("'" . addslashes($v) . "'");
  839. elseif (is_numeric($v) OR (strpos($v, 'CAST(') === 0))
  840. return $v;
  841. elseif ($v[0]== '0' AND $v[1]!=='x' AND ctype_xdigit(substr($v,1)))
  842. return substr($v,1);
  843. else {
  844. spip_log("Warning: '$v' n'est pas de type $t", 'pg');
  845. return intval($v);
  846. }
  847. }
  848. // http://doc.spip.org/@spip_pg_hex
  849. function spip_pg_hex($v)
  850. {
  851. return "CAST(x'" . $v . "' as bigint)";
  852. }
  853. function spip_pg_quote($v, $type='')
  854. {
  855. return ($type === 'int' AND !$v) ? '0' : _q($v);
  856. }
  857. function spip_pg_date_proche($champ, $interval, $unite)
  858. {
  859. return '('
  860. . $champ
  861. . (($interval <= 0) ? '>' : '<')
  862. . (($interval <= 0) ? 'DATE_SUB' : 'DATE_ADD')
  863. . '('
  864. . sql_quote(date('Y-m-d H:i:s'))
  865. . ', INTERVAL '
  866. . (($interval > 0) ? $interval : (0-$interval))
  867. . ' '
  868. . $unite
  869. . '))';
  870. }
  871. // http://doc.spip.org/@spip_pg_in
  872. function spip_pg_in($val, $valeurs, $not='', $serveur) {
  873. //
  874. // IN (...) souvent limite a 255 elements, d'ou cette fonction assistante
  875. //
  876. if (strpos($valeurs, "CAST(x'") !== false)
  877. return "($val=" . join("OR $val=", explode(',',$valeurs)).')';
  878. $n = $i = 0;
  879. $in_sql ="";
  880. while ($n = strpos($valeurs, ',', $n+1)) {
  881. if ((++$i) >= 255) {
  882. $in_sql .= "($val $not IN (" .
  883. substr($valeurs, 0, $n) .
  884. "))\n" .
  885. ($not ? "AND\t" : "OR\t");
  886. $valeurs = substr($valeurs, $n+1);
  887. $i = $n = 0;
  888. }
  889. }
  890. $in_sql .= "($val $not IN ($valeurs))";
  891. return "($in_sql)";
  892. }
  893. // http://doc.spip.org/@spip_pg_error
  894. function spip_pg_error($query='', $serveur, $requeter=true) {
  895. $link = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0]['link'];
  896. $s = $link ? pg_last_error($link) : pg_last_error();
  897. if ($s) {
  898. $s = str_replace('ERROR', 'errcode: 1000 ', $s);
  899. spip_log("$s - $query", 'pg.'._LOG_ERREUR);
  900. }
  901. return $s;
  902. }
  903. // http://doc.spip.org/@spip_pg_errno
  904. function spip_pg_errno($serveur='') {
  905. // il faudrait avoir la derniere ressource retournee et utiliser
  906. // http://fr2.php.net/manual/fr/function.pg-result-error.php
  907. return 0;
  908. }
  909. // http://doc.spip.org/@spip_pg_drop_table
  910. function spip_pg_drop_table($table, $exist='', $serveur='',$requeter=true)
  911. {
  912. if ($exist) $exist =" IF EXISTS";
  913. if (spip_pg_query("DROP TABLE$exist $table", $serveur, $requeter))
  914. return true;
  915. else return false;
  916. }
  917. // supprime une vue
  918. // http://doc.spip.org/@spip_pg_drop_view
  919. function spip_pg_drop_view($view, $exist='', $serveur='',$requeter=true) {
  920. if ($exist) $exist =" IF EXISTS";
  921. return spip_pg_query("DROP VIEW$exist $view", $serveur, $requeter);
  922. }
  923. // http://doc.spip.org/@spip_pg_showbase
  924. function spip_pg_showbase($match, $serveur='',$requeter=true)
  925. {
  926. $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  927. $link = $connexion['link'];
  928. $connexion['last'] = $q = "SELECT tablename FROM pg_tables WHERE tablename ILIKE "._q($match);
  929. return spip_pg_query_simple($link, $q);
  930. }
  931. // http://doc.spip.org/@spip_pg_showtable
  932. function spip_pg_showtable($nom_table, $serveur='',$requeter=true)
  933. {
  934. $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  935. $link = $connexion['link'];
  936. $connexion['last'] = $q = "SELECT column_name, column_default, data_type FROM information_schema.columns WHERE table_name ILIKE " . _q($nom_table);
  937. $res = spip_pg_query_simple($link, $q);
  938. if (!$res) return false;
  939. // etrangement, $res peut ne rien contenir, mais arriver ici...
  940. // il faut en tenir compte dans le return
  941. $fields = array();
  942. while($field = pg_fetch_array($res, NULL, PGSQL_NUM)) {
  943. $fields[$field[0]] = $field[2] . (!$field[1] ? '' : (" DEFAULT " . $field[1]));
  944. }
  945. $connexion['last'] = $q = "SELECT indexdef FROM pg_indexes WHERE tablename ILIKE " . _q($nom_table);
  946. $res = spip_pg_query_simple($link, $q);
  947. $keys = array();
  948. while($index = pg_fetch_array($res, NULL, PGSQL_NUM)) {
  949. if (preg_match('/CREATE\s+(UNIQUE\s+)?INDEX\s([^\s]+).*\((.*)\)$/', $index[0],$r)) {
  950. $nom = str_replace($nom_table.'_','',$r[2]);
  951. $keys[($r[1] ? "PRIMARY KEY" : ("KEY " . $nom))] = $r[3];
  952. }
  953. }
  954. return count($fields) ? array('field' => $fields, 'key' => $keys) : false;
  955. }
  956. // Fonction de creation d'une table SQL nommee $nom
  957. // a partir de 2 tableaux PHP :
  958. // champs: champ => type
  959. // cles: type-de-cle => champ(s)
  960. // si $autoinc, c'est une auto-increment (i.e. serial) sur la Primary Key
  961. // Le nom des index est prefixe par celui de la table pour eviter les conflits
  962. // http://doc.spip.org/@spip_pg_create
  963. function spip_pg_create($nom, $champs, $cles, $autoinc=false, $temporary=false, $serveur='',$requeter=true) {
  964. $connexion = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0];
  965. $prefixe = $connexion['prefixe'];
  966. $link = $connexion['link'];
  967. $db = $connexion['db'];
  968. if ($prefixe) $nom = preg_replace('/^spip/', $prefixe, $nom);
  969. $query = $prim = $prim_name = $v = $s = $p='';
  970. $keys = array();
  971. // certains plugins declarent les tables (permet leur inclusion dans le dump)
  972. // sans les renseigner (laisse le compilo recuperer la description)
  973. if (!is_array($champs) || !is_array($cles))
  974. return;
  975. foreach($cles as $k => $v) {
  976. if (strpos($k, "KEY ") === 0) {
  977. $n = str_replace('`','',$k);
  978. $v = str_replace('`','"',$v);
  979. $i = $nom . preg_replace("/KEY +/", '_',$n);
  980. if ($k != $n) $i = "\"$i\"";
  981. $keys[] = "CREATE INDEX $i ON $nom ($v);";
  982. } else $prim .= "$s\n\t\t" . str_replace('`','"',$k) ." ($v)";
  983. if ($k == "PRIMARY KEY")
  984. $prim_name = $v;
  985. $s = ",";
  986. }
  987. $s = '';
  988. $character_set = "";
  989. if (@$GLOBALS['meta']['charset_sql_base'])
  990. $character_set .= " CHARACTER SET ".$GLOBALS['meta']['charset_sql_base'];
  991. if (@$GLOBALS['meta']['charset_collation_sql_base'])
  992. $character_set .= " COLLATE ".$GLOBALS['meta']['charset_collation_sql_base'];
  993. foreach($champs as $k => $v) {
  994. $k = str_replace('`','"',$k);
  995. if (preg_match(',([a-z]*\s*(\(\s*[0-9]*\s*\))?(\s*binary)?),i',$v,$defs)){
  996. if (preg_match(',(char|text),i',$defs[1]) AND !preg_match(',binary,i',$defs[1]) ){
  997. $v = $defs[1] . $character_set . ' ' . substr($v,strlen($defs[1]));
  998. }
  999. }
  1000. $query .= "$s\n\t\t$k "
  1001. . (($autoinc && ($prim_name == $k) && preg_match(',\b(big|small|medium|tiny)?int\b,i', $v))
  1002. ? " bigserial"
  1003. : mysql2pg_type($v)
  1004. );
  1005. $s = ",";
  1006. }
  1007. $temporary = $temporary ? 'TEMPORARY':'';
  1008. // En l'absence de "if not exists" en PG, on neutralise les erreurs
  1009. $q = "CREATE $temporary TABLE $nom ($query" . ($prim ? ",$prim" : '') . ")".
  1010. ($character_set?" DEFAULT $character_set":"")
  1011. ."\n";
  1012. if (!$requeter) return $q;
  1013. $connexion['last'] = $q;
  1014. $r = @pg_query($link, $q);
  1015. if (!$r)
  1016. spip_log("Impossible de creer cette table: $q");
  1017. else {
  1018. foreach($keys as $index) {pg_query($link, $index);}
  1019. }
  1020. return $r;
  1021. }
  1022. function spip_pg_create_base($nom, $serveur='',$requeter=true) {
  1023. return spip_pg_query("CREATE DATABASE $nom", $serveur, $requeter);
  1024. }
  1025. // Fonction de creation d'une vue SQL nommee $nom
  1026. // http://doc.spip.org/@spip_pg_create_view
  1027. function spip_pg_create_view($nom, $query_select, $serveur='',$requeter=true) {
  1028. if (!$query_select) return false;
  1029. // vue deja presente
  1030. if (sql_showtable($nom, false, $serveur)) {
  1031. if ($requeter) spip_log("Echec creation d'une vue sql ($nom) car celle-ci existe deja (serveur:$serveur)");
  1032. return false;
  1033. }
  1034. $query = "CREATE VIEW $nom AS ". $query_select;
  1035. return spip_pg_query($query, $serveur, $requeter);
  1036. }
  1037. // http://doc.spip.org/@spip_pg_set_connect_charset
  1038. function spip_pg_set_connect_charset($charset, $serveur='',$requeter=true){
  1039. spip_log("changement de charset sql a ecrire en PG");
  1040. }
  1041. /**
  1042. * Optimise une table SQL
  1043. *
  1044. * @param $table nom de la table a optimiser
  1045. * @param $serveur nom de la connexion
  1046. * @param $requeter effectuer la requete ? sinon retourner son code
  1047. * @return bool|string true / false / requete
  1048. **/
  1049. // http://doc.spip.org/@spip_sqlite_optimize
  1050. function spip_pg_optimize($table, $serveur='',$requeter=true){
  1051. return spip_pg_query("VACUUM ". $table, $serveur, $requeter);
  1052. }
  1053. // Selectionner la sous-chaine dans $objet
  1054. // correspondant a $lang. Cf balise Multi de Spip
  1055. // http://doc.spip.org/@spip_pg_multi
  1056. function spip_pg_multi ($objet, $lang) {
  1057. $r = "regexp_replace("
  1058. . $objet
  1059. . ",'<multi>.*[[]"
  1060. . $lang
  1061. . "[]]([^[]*).*</multi>', E'\\\\1') AS multi";
  1062. return $r;
  1063. }
  1064. // Palanquee d'idiosyncrasies MySQL dans les creations de table
  1065. // A completer par les autres, mais essayer de reduire en amont.
  1066. // http://doc.spip.org/@mysql2pg_type
  1067. function mysql2pg_type($v)
  1068. {
  1069. return
  1070. preg_replace('/auto_increment/i', '', // non reconnu
  1071. preg_replace('/bigint/i', 'bigint',
  1072. preg_replace('/mediumint/i', 'mediumint',
  1073. preg_replace('/smallint/i', 'smallint',
  1074. preg_replace("/tinyint/i", 'int',
  1075. preg_replace('/int\s*[(]\s*\d+\s*[)]/i', 'int',
  1076. preg_replace("/longtext/i", 'text',
  1077. str_replace("mediumtext", 'text',
  1078. preg_replace("/tinytext/i", 'text',
  1079. str_replace("longblob", 'text',
  1080. str_replace("0000-00-00",'0001-01-01',
  1081. preg_replace("/datetime/i", 'timestamp',
  1082. preg_replace("/unsigned/i", '',
  1083. preg_replace("/double/i", 'double precision',
  1084. preg_replace('/VARCHAR\((\d+)\)\s+BINARY/i', 'varchar(\1)',
  1085. preg_replace("/ENUM *[(][^)]*[)]/i", "varchar(255)",
  1086. $v
  1087. ))))))))))))))));
  1088. }
  1089. // Renvoie false si on n'a pas les fonctions pg (pour l'install)
  1090. // http://doc.spip.org/@spip_versions_pg
  1091. function spip_versions_pg(){
  1092. charger_php_extension('pgsql');
  1093. return function_exists('pg_connect');
  1094. }
  1095. ?>