diff --git a/ecrire/req/pg.php b/ecrire/req/pg.php index 1b2add593d26eb42d2a4b2e4af29675cc2b43313..dbfe96d6a51657805624c172e4e527f0c499d932 100644 --- a/ecrire/req/pg.php +++ b/ecrire/req/pg.php @@ -144,19 +144,46 @@ function spip_pg_query($query, $serveur='',$requeter=true) // Alter en PG ne traite pas les index // http://doc.spip.org/@spip_pg_alter function spip_pg_alter($query, $serveur='',$requeter=true) { + // il faudrait une regexp pour eviter de spliter ADD PRIMARY KEY (colA, colB) + // tout en cassant en deux alter distincts "ADD PRIMARY KEY (colA, colB), ADD INDEX (chose)"... + // ou revoir l'api de sql_alter en creant un + // sql_alter_table($table,array($actions)); + if (!preg_match("/\s*((\s*IGNORE)?\s*TABLE\s*([^\s]*))\s*(.*)?/is", $query, $regs)){ + spip_log("$query mal comprise", 'pg'); + return false; + } + $debut = $regs[1]; + $table = $regs[3]; + $suite = $regs[4]; + $todo = explode(',', $suite); + // on remet les morceaux dechires ensembles... que c'est laid ! + $todo2 = array(); $i=0; + $ouverte = false; + while ($do = array_shift($todo)) { + $todo2[$i] = isset($todo2[$i]) ? $todo2[$i] . "," . $do : $do; + $o=(false!==strpos($do,"(")); + $f=(false!==strpos($do,")")); + if ($o AND !$f) $ouverte=true; + elseif (!$o AND $f) $ouverte=false; + elseif ($o AND $f) $ouverte=false; + if (!$ouverte) $i++; + } + $todo=$todo2; + $query = $debut.' '.array_shift($todo); - if (!preg_match('/^\s*(IGNORE\s*)?TABLE\s+(\w+)\s+(ADD|DROP|CHANGE)\s*([^,]*)(.*)$/is', $query, $r)) { + if (!preg_match('/^\s*(IGNORE\s*)?TABLE\s+(\w+)\s+(ADD|DROP|CHANGE|MODIFY|RENAME)\s*(.*)$/is', $query, $r)) { spip_log("$query incompris", 'pg'); } else { if ($r[1]) spip_log("j'ignore IGNORE dans $query", 'pg'); $f = 'spip_pg_alter_' . strtolower($r[3]); if (function_exists($f)) - $f($r[2], $r[4], $serveur); + $f($r[2], $r[4], $serveur, $requeter); else spip_log("$query non prevu", 'pg'); } // Alter a plusieurs args. Faudrait optimiser. - if ($r[5]) - spip_pg_alter("TABLE " . $r[2] . substr($r[5],1)); + if ($todo) + spip_pg_alter("TABLE $table " . join(',',$todo)); + } // http://doc.spip.org/@spip_pg_alter_change @@ -186,28 +213,58 @@ function spip_pg_alter_change($table, $arg, $serveur='',$requeter=true) // http://doc.spip.org/@spip_pg_alter_add function spip_pg_alter_add($table, $arg, $serveur='',$requeter=true) { - if (!preg_match('/^(INDEX|KEY|PRIMARY\s+KEY|)\s*(.*)$/', $arg, $r)) { + if (!preg_match('/^(COLUMN|INDEX|KEY|PRIMARY\s+KEY|)\s*(.*)$/', $arg, $r)) { spip_log("alter add $arg incompris", 'pg'); return NULL; } - if (!$r[1]) { + if (!$r[1] OR $r[1]=='COLUMN') { preg_match('/`?(\w+)`?(.*)/',$r[2], $m); - return spip_pg_query("ALTER TABLE $table ADD " . $m[1] . ' ' . mysql2pg_type($m[2]), $serveur); + if (preg_match('/^(.*)(BEFORE|AFTER|FIRST)(.*)$/is', $m[2], $n)) { + $m[2]=$n[1]; + } + return spip_pg_query("ALTER TABLE $table ADD " . $m[1] . ' ' . mysql2pg_type($m[2]), $serveur, $requeter); } elseif ($r[1][0] == 'P') { - preg_match('/\(`?(\w+)`?\)/',$r[2], $m); - return spip_pg_query("ALTER TABLE $table ADD CONSTRAINT $table" .'_pkey PRIMARY KEY (' . $m[1] . ')', $serveur); + // la primary peut etre sur plusieurs champs + $r[2] = trim(str_replace('`','',$r[2])); + $m = ($r[2][0]=='(') ? substr($r[2],1,-1) : $r[2]; + return spip_pg_query("ALTER TABLE $table ADD CONSTRAINT $table" .'_pkey PRIMARY KEY (' . $m . ')', $serveur, $requeter); } else { - preg_match('/`?(\w+)`?\s*(\([^)]*\))/',$r[2], $m); - return spip_pg_query("CREATE INDEX " . $table . '_' . $m[1] . " ON $table " . str_replace("`","",$m[2]), $serveur); + preg_match('/([^\s,]*)\s*(.*)?/',$r[2], $m); + // peut etre "(colonne)" ou "nom_index (colonnes)" + // bug potentiel si qqn met "(colonne, colonne)" + // + // nom_index (colonnes) + if ($m[2]) { + $colonnes = substr($m[2],1,-1); + $nom_index = $m[1]; + } + else { + // (colonne) + if ($m[1][0] == "(") { + $colonnes = substr($m[1],1,-1); + if (false!==strpos(",",$colonnes)) { + spip_log("PG : Erreur, impossible de creer un index sur plusieurs colonnes" + ." sans qu'il ait de nom ($table, ($colonnes))", 'pg'); + break; + } else { + $nom_index = $colonnes; + } + } + // nom_index + else { + $nom_index = $colonnes = $m[1]; + } + } + return spip_pg_create_index($nom_index, $table, $colonnes, $serveur, $requeter); } } // http://doc.spip.org/@spip_pg_alter_drop function spip_pg_alter_drop($table, $arg, $serveur='',$requeter=true) { - if (!preg_match('/^(INDEX|KEY|PRIMARY\s+KEY|)\s*`?(\w*)`?/', $arg, $r)) + if (!preg_match('/^(COLUMN|INDEX|KEY|PRIMARY\s+KEY|)\s*`?(\w*)`?/', $arg, $r)) spip_log("alter drop: $arg incompris", 'pg'); else { - if (!$r[1]) + if (!$r[1] OR $r[1]=='COLUMN') return spip_pg_query("ALTER TABLE $table DROP " . $r[2], $serveur); elseif ($r[1][0] == 'P') return spip_pg_query("ALTER TABLE $table DROP CONSTRAINT $table" . '_pkey', $serveur); @@ -217,6 +274,68 @@ function spip_pg_alter_drop($table, $arg, $serveur='',$requeter=true) { } } +function spip_pg_alter_modify($table, $arg, $serveur='',$requeter=true) { + if (!preg_match('/^`?(\w+)`?\s+(.*)$/',$arg, $r)) { + spip_log("alter modify: $arg incompris", 'pg'); + } else { + return spip_pg_alter_change($table, $r[1].' '.$arg, $serveur='',$requeter=true); + } +} + +// attention (en pg) : +// - alter table A rename to X = changer le nom de la table +// - alter table A rename X to Y = changer le nom de la colonne X en Y +// pour l'instant, traiter simplement RENAME TO X +function spip_pg_alter_rename($table, $arg, $serveur='',$requeter=true) { + $rename=""; + // si TO, mais pas au debut + if (!stripos($arg,'TO ')){ + $rename=$arg; + } + elseif (preg_match('/^(TO)\s*`?(\w*)`?/', $arg, $r)) { + $rename=$r[2]; + } else { + spip_log("alter rename: $arg incompris", 'pg'); + } + return $rename?spip_pg_query("ALTER TABLE $table RENAME TO $rename"):false; +} + + +/** + * Fonction de creation d'un INDEX + * + * @param string $nom : nom de l'index + * @param string $table : table sql de l'index + * @param string/array $champs : liste de champs sur lesquels s'applique l'index + * @param string $serveur : nom de la connexion sql utilisee + * @param bool $requeter : true pour executer la requete ou false pour retourner le texte de la requete + * + * @return bool ou requete + */ +function spip_pg_create_index($nom, $table, $champs, $serveur='', $requeter=true) { + if (!($nom OR $table OR $champs)) { + spip_log("Champ manquant pour creer un index pg ($nom, $table, (".@join(',',$champs)."))","pg"); + return false; + } + + $nom = str_replace("`","",$nom); + $champs = str_replace("`","",$champs); + + // PG ne differentie pas noms des index en fonction des tables + // il faut donc creer des noms uniques d'index pour une base pg + $nom = $table.'_'.$nom; + // enlever d'eventuelles parentheses deja presentes sur champs + if (!is_array($champs)){ + if ($champs[0]=="(") $champs = substr($champs,1,-1); + $champs = array($champs); + } + $query = "CREATE INDEX $nom ON $table (" . join(',',$champs) . ")"; + $res = spip_pg_query($query, $serveur, $requeter); + if (!$requeter) return $query; + return $res; +} + + // http://doc.spip.org/@spip_pg_explain function spip_pg_explain($query, $serveur='',$requeter=true){ if (strpos(ltrim($query), 'SELECT') !== 0) return array(); @@ -861,7 +980,9 @@ function spip_pg_errno($serveur='',$requeter=true) { function spip_pg_drop_table($table, $exist='', $serveur='',$requeter=true) { if ($exist) $exist =" IF EXISTS"; - return spip_pg_query("DROP TABLE$exist $table", $serveur, $requeter); + if (spip_pg_query("DROP TABLE$exist $table", $serveur, $requeter)) + return true; + else return false; } // supprime une vue @@ -899,11 +1020,9 @@ function spip_pg_showtable($nom_table, $serveur='',$requeter=true) $res = pg_query($link, "SELECT indexdef FROM pg_indexes WHERE tablename ILIKE " . _q($nom_table)); $keys = array(); while($index = pg_fetch_array($res, NULL, PGSQL_NUM)) { - if (preg_match('/CREATE\s+(UNIQUE\s+)?INDEX.*\((.*)\)$/', - $index[0],$r)) { - $index = split(',', $r[2]); - $keys[($r[1] ? "PRIMARY KEY" : ("KEY " . $index[0]))] = - $r[2]; + if (preg_match('/CREATE\s+(UNIQUE\s+)?INDEX\s([^\s]+).*\((.*)\)$/', $index[0],$r)) { + $nom = str_replace($nom_table.'_','',$r[2]); + $keys[($r[1] ? "PRIMARY KEY" : ("KEY " . $nom))] = $r[3]; } } @@ -961,7 +1080,7 @@ function spip_pg_create($nom, $champs, $cles, $autoinc=false, $temporary=false, } $query .= "$s\n\t\t$k " - . (($autoinc && ($prim_name == $k) && preg_match(',\b(big|small|medium)?int\b,i', $v)) + . (($autoinc && ($prim_name == $k) && preg_match(',\b(big|small|medium|tiny)?int\b,i', $v)) ? " bigserial" : mysql2pg_type($v) ); @@ -975,6 +1094,7 @@ function spip_pg_create($nom, $champs, $cles, $autoinc=false, $temporary=false, ($character_set?" DEFAULT $character_set":"") ."\n"; + if (!$requeter) return $q; $r = @pg_query($link, $q); if (!$r) @@ -1026,7 +1146,12 @@ function spip_pg_multi ($objet, $lang) { // http://doc.spip.org/@mysql2pg_type function mysql2pg_type($v) { - return preg_replace('/bigint\s*[(]\s*\d+\s*[)]/i', 'bigint', + return + preg_replace('/auto_increment/i', '', // non reconnu + preg_replace('/bigint/i', 'bigint', + preg_replace('/mediumint/i', 'mediumint', + preg_replace('/smallint/i', 'smallint', + preg_replace("/tinyint/i", 'int', preg_replace('/int\s*[(]\s*\d+\s*[)]/i', 'int', preg_replace("/longtext/i", 'text', str_replace("mediumtext", 'text', @@ -1035,12 +1160,11 @@ function mysql2pg_type($v) str_replace("0000-00-00",'0000-01-01', preg_replace("/datetime/i", 'timestamp', preg_replace("/unsigned/i", '', - preg_replace("/double/i", 'double precision', - preg_replace("/tinyint/i", 'int', + preg_replace("/double/i", 'double precision', preg_replace('/VARCHAR\((\d+)\)\s+BINARY/i', 'varchar(\1)', preg_replace("/ENUM *[(][^)]*[)]/i", "varchar(255)", $v - ))))))))))))); + )))))))))))))))); } // Renvoie false si on n'a pas les fonctions pg (pour l'install) diff --git a/ecrire/req/sqlite_generique.php b/ecrire/req/sqlite_generique.php index 9e2f246c83a9e0d3d4042e8049fd20f24f8c8322..16881bfefa8617a7540e5dca274bbc9d136b9aed 100644 --- a/ecrire/req/sqlite_generique.php +++ b/ecrire/req/sqlite_generique.php @@ -156,14 +156,20 @@ function spip_sqlite_alter($query, $serveur='',$requeter=true){ // ou revoir l'api de sql_alter en creant un // sql_alter_table($table,array($actions)); $todo = explode(',', $suite); + // on remet les morceaux dechires ensembles... que c'est laid ! $todo2 = array(); $i=0; + $ouverte = false; while ($do = array_shift($todo)) { $todo2[$i] = isset($todo2[$i]) ? $todo2[$i] . "," . $do : $do; - if (false===strpos($do,"(") OR (false!==strpos($do,")"))) - $i++; + $o=(false!==strpos($do,"(")); + $f=(false!==strpos($do,")")); + if ($o AND !$f) $ouverte=true; + elseif (!$o AND $f) $ouverte=false; + elseif ($o AND $f) $ouverte=false; + if (!$ouverte) $i++; } - + // 3 $resultats = array(); foreach ($todo2 as $do){ @@ -181,7 +187,7 @@ function spip_sqlite_alter($query, $serveur='',$requeter=true){ $colonne_destination = ''; $def = $matches[3]; $def = _sqlite_remplacements_definitions_table($def); - + switch($cle){ // suppression d'un index case 'DROP INDEX': @@ -399,7 +405,9 @@ function spip_sqlite_create_index($nom, $table, $champs, $serveur='', $requeter= $champs = array($champs); } $query = "CREATE INDEX $nom ON $table (" . join(',',$champs) . ")"; - if (spip_sqlite_query($query, $serveur, $requeter)) + $res = spip_sqlite_query($query, $serveur, $requeter); + if (!$requeter) return $res; + if ($res) return true; else return false; @@ -1251,12 +1259,13 @@ function _sqlite_modifier_table($table, $colonne, $opt=array(), $serveur=''){ foreach ($def_origine['key'] as $c=>$d){ $c = str_replace($colonne_origine,$colonne_destination,$c); $d = str_replace($colonne_origine,$colonne_destination,$d); - $keys[$c] = $d; + // seulement si on ne supprime pas la colonne ! + if ($d) + $keys[$c] = $d; } // autres keys, on merge $keys = array_merge($keys,$opt['key']); - $queries = array(); $queries[] = 'BEGIN TRANSACTION';