[SPIP] +2.1.12
[velocampus/web/www.git] / www / ecrire / req / sqlite_generique.php
diff --git a/www/ecrire/req/sqlite_generique.php b/www/ecrire/req/sqlite_generique.php
new file mode 100644 (file)
index 0000000..96116f9
--- /dev/null
@@ -0,0 +1,1905 @@
+<?php
+
+/***************************************************************************\
+ *  SPIP, Systeme de publication pour l'internet                           *
+ *                                                                         *
+ *  Copyright (c) 2001-2011                                                *
+ *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
+ *                                                                         *
+ *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
+ *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
+\***************************************************************************/
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+// infos :
+// il ne faut pas avoir de PDO::CONSTANTE dans ce fichier sinon php4 se tue !
+// idem, il ne faut pas de $obj->toto()->toto sinon php4 se tue !
+
+# todo : get/set_caracteres ?
+
+
+/*
+ * 
+ * regroupe le maximum de fonctions qui peuvent cohabiter
+ * D'abord les fonctions d'abstractions de SPIP
+ * 
+ */
+// http://doc.spip.org/@req_sqlite_dist
+function req_sqlite_dist($addr, $port, $login, $pass, $db='', $prefixe='', $sqlite_version=''){
+       static $last_connect = array();
+
+       // si provient de selectdb
+       // un code pour etre sur que l'on vient de select_db()
+       if (strpos($db, $code = '@selectdb@')!==false) {
+               foreach (array('addr','port','login','pass','prefixe') as $a){
+                       $$a = $last_connect[$a];
+               }
+               $db = str_replace($code, '', $db);
+       }
+
+       /*
+        * En sqlite, seule l'adresse du fichier est importante.
+        * Ce sera $db le nom, et le path _DIR_DB
+        */
+       _sqlite_init();
+
+       // un nom de base demande et impossible d'obtenir la base, on s'en va
+       if ($db && !is_file($f = _DIR_DB . $db . '.sqlite') && !is_writable(_DIR_DB))
+                       return false;
+
+       
+       // charger les modules sqlite au besoin
+       if (!_sqlite_charger_version($sqlite_version)) {
+               spip_log("Impossible de trouver/charger le module SQLite ($sqlite_version)!");
+               return false;
+       }
+
+       // chargement des constantes
+       // il ne faut pas definir les constantes avant d'avoir charge les modules sqlite
+       $define = "spip_sqlite".$sqlite_version."_constantes";
+       $define();
+       
+       $ok = false;
+       if (!$db){
+               // si installation -> base temporaire tant qu'on ne connait pas son vrai nom
+               if (defined('_ECRIRE_INSTALL') && _ECRIRE_INSTALL){
+                       // creation d'une base temporaire pour le debut d'install
+                       $db = "_sqlite".$sqlite_version."_install";     
+                       $tmp = _DIR_DB . $db . ".sqlite";
+                       if ($sqlite_version == 3) {
+                               $ok = $link = new PDO("sqlite:$tmp");
+                       } else {
+                               $ok = $link = sqlite_open($tmp, _SQLITE_CHMOD, $err);
+                       }
+               // sinon, on arrete finalement
+               } else {
+                       return false;
+               }
+       } else {
+               // Ouvrir (eventuellement creer la base)
+               // si pas de version fourni, on essaie la 3, sinon la 2
+               if ($sqlite_version == 3) {
+                       $ok = $link = new PDO("sqlite:$f");
+               } else {
+                       $ok = $link = sqlite_open($f, _SQLITE_CHMOD, $err);
+               }
+       }
+
+       if (!$ok){
+               spip_log("Impossible d'ouvrir la base de donnee SQLite ($sqlite_version) : $f ");
+               return false;
+       }
+       
+       if ($link) {
+               $last_connect = array (
+                       'addr' => $addr,
+                       'port' => $port,
+                       'login' => $login,
+                       'pass' => $pass,
+                       'db' => $db,
+                       'prefixe' => $prefixe,
+               );
+       }
+
+       return array(
+               'db' => $db,
+               'prefixe' => $prefixe ? $prefixe : $db,
+               'link' => $link,
+               );      
+}
+
+
+
+// Fonction de requete generale, munie d'une trace a la demande
+// http://doc.spip.org/@spip_sqlite_query
+function spip_sqlite_query($query, $serveur='',$requeter=true) {
+#spip_log("spip_sqlite_query() > $query");
+       _sqlite_init();
+       
+       $requete = new sqlite_traiter_requete($query, $serveur);
+       $requete->traduire_requete(); // mysql -> sqlite
+       if (!$requeter) return $requete->query;
+       return $requete->executer_requete();
+}
+
+
+/* ordre alphabetique pour les autres */
+
+// http://doc.spip.org/@spip_sqlite_alter
+function spip_sqlite_alter($query, $serveur='',$requeter=true){
+
+       $query = spip_sqlite_query("ALTER $query",$serveur,false);
+       
+       /* 
+        * la il faut faire les transformations
+        * si ALTER TABLE x (DROP|CHANGE) y
+        * 
+        * 1) recuperer "ALTER TABLE table "
+        * 2) spliter les sous requetes (,)
+        * 3) faire chaque requete independemment
+        */
+       
+       // 1
+       if (preg_match("/\s*(ALTER(\s*IGNORE)?\s*TABLE\s*([^\s]*))\s*(.*)?/is", $query, $regs)){
+               $debut = $regs[1];
+               $table = $regs[3];
+               $suite = $regs[4];
+       } else {
+               spip_log("SQLite : Probleme de ALTER TABLE mal forme dans $query", 'sqlite');
+               return false;
+       }
+
+       // 2
+       // il faudrait une regexp pour eviter de spliter ADD PRIMARY KEY (colA, colB)
+       // tout en cassant "ADD PRIMARY KEY (colA, colB), ADD INDEX (chose)"... en deux
+       // 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;
+               $o=(false!==strpos($do,"("));
+               $f=(false!==strpos($do,")"));
+               if ($o AND !$f) $ouverte=true;
+               elseif ($f) $ouverte=false;
+               if (!$ouverte) $i++;
+       }
+       
+       // 3    
+       $resultats = array();
+       foreach ($todo2 as $do){
+               $do = trim($do);
+               if (!preg_match('/(DROP PRIMARY KEY|DROP INDEX|DROP COLUMN|DROP'
+                               .'|CHANGE COLUMN|CHANGE|MODIFY|RENAME TO|RENAME'
+                               .'|ADD PRIMARY KEY|ADD INDEX|ADD COLUMN|ADD'
+                               .')\s*([^\s]*)\s*(.*)?/', $do, $matches)){
+                       spip_log("SQLite : Probleme de ALTER TABLE, utilisation non reconnue dans : $do \n(requete d'origine : $query)", 'sqlite');
+                       return false;
+               }
+
+               $cle = strtoupper($matches[1]);
+               $colonne_origine = $matches[2];
+               $colonne_destination = '';
+
+               $def = $matches[3];
+
+               // eluder une eventuelle clause before|after|first inutilisable
+               $defr = rtrim(preg_replace('/(BEFORE|AFTER|FIRST)(.*)$/is','', $def));
+               // remplacer les definitions venant de mysql
+               $defr = _sqlite_remplacements_definitions_table($defr);
+
+               // reinjecter dans le do
+               $do = str_replace($def,$defr,$do);
+               $def = $defr;
+               
+               switch($cle){
+                       // suppression d'un index
+                       case 'DROP INDEX':
+                               $nom_index = $colonne_origine;
+                               spip_sqlite_drop_index($nom_index, $table, $serveur);
+                               break;
+                       
+                       // suppression d'une pk
+                       case 'DROP PRIMARY KEY':
+                               if (!_sqlite_modifier_table(
+                                       $table, 
+                                       $colonne_origine, 
+                                       array('key'=>array('PRIMARY KEY'=>'')), 
+                                       $serveur)){
+                                               return false;
+                               }
+                               break;
+                       // suppression d'une colonne
+                       case 'DROP COLUMN':
+                       case 'DROP':
+                               if (!_sqlite_modifier_table(
+                                       $table, 
+                                       array($colonne_origine=>""), 
+                                       '', 
+                                       $serveur)){
+                                               return false;
+                               }
+                               break;
+                       
+                       case 'CHANGE COLUMN':
+                       case 'CHANGE':
+                               // recuperer le nom de la future colonne 
+                               $def = trim($def);
+                               $colonne_destination = substr($def, 0, strpos($def,' '));
+                               $def = substr($def, strlen($colonne_destination)+1);
+                               
+                               if (!_sqlite_modifier_table(
+                                       $table, 
+                                       array($colonne_origine=>$colonne_destination), 
+                                       array('field'=>array($colonne_destination=>$def)), 
+                                       $serveur)){
+                                               return false;
+                               }
+                               break;
+                               
+                       case 'MODIFY':
+                               if (!_sqlite_modifier_table(
+                                       $table, 
+                                       $colonne_origine, 
+                                       array('field'=>array($colonne_origine=>$def)), 
+                                       $serveur)){
+                                               return false;
+                               }
+                               break;
+                       
+                       // pas geres en sqlite2
+                       case 'RENAME':
+                                       $do = "RENAME TO" . substr($do,6);
+                       case 'RENAME TO':
+                               if (_sqlite_is_version(3, '', $serveur)){
+                                       $requete = new sqlite_traiter_requete("$debut $do", $serveur);
+                                       if (!$requete->executer_requete()){
+                                               spip_log("SQLite : Erreur ALTER TABLE / RENAME : $query", 'sqlite');
+                                               return false;
+                                       }
+                               // artillerie lourde pour sqlite2 !
+                               } else {
+                                       $table_dest = trim(substr($do, 9));
+                                       if (!_sqlite_modifier_table(array($table=>$table_dest), '', '', $serveur)){
+                                               spip_log("SQLite : Erreur ALTER TABLE / RENAME : $query", 'sqlite');
+                                               return false;
+                                       }
+                               }
+                               break;
+
+                       // ajout d'une pk
+                       case 'ADD PRIMARY KEY':
+                               $pk = trim(substr($do,16));
+                               $pk = ($pk[0]=='(') ? substr($pk,1,-1) : $pk;
+                               if (!_sqlite_modifier_table(
+                                       $table, 
+                                       $colonne_origine, 
+                                       array('key'=>array('PRIMARY KEY'=>$pk)), 
+                                       $serveur)){
+                                               return false;
+                               }
+                               break;                  
+                       // ajout d'un index
+                       case 'ADD INDEX':
+                               // peut etre "(colonne)" ou "nom_index (colonnes)"
+                               // bug potentiel si qqn met "(colonne, colonne)"
+                               //
+                               // nom_index (colonnes)
+                               if ($def) {
+                                       $colonnes = substr($def,1,-1);
+                                       $nom_index = $colonne_origine;
+                               }
+                               else {
+                                       // (colonne)
+                                       if ($colonne_origine[0] == "(") {
+                                               $colonnes = substr($colonne_origine,1,-1);
+                                               if (false!==strpos(",",$colonnes)) {
+                                                       spip_log("SQLite : Erreur, impossible de creer un index sur plusieurs colonnes"
+                                                               ." sans qu'il ait de nom ($table, ($colonnes))", 'sqlite');     
+                                                       break;
+                                               } else {
+                                                       $nom_index = $colonnes;
+                                               }
+                                       }
+                                       // nom_index
+                                       else {
+                                               $nom_index = $colonnes = $colonne_origine ;
+                                       }
+                               }
+                               spip_sqlite_create_index($nom_index, $table, $colonnes, $serveur);
+                               break;
+                               
+                       // pas geres en sqlite2
+                       case 'ADD COLUMN':
+                                       $do = "ADD".substr($do, 10);
+                       case 'ADD':
+                       default:
+                               if (_sqlite_is_version(3, '', $serveur)){
+                                       $requete = new sqlite_traiter_requete("$debut $do", $serveur);
+                                       if (!$requete->executer_requete()){
+                                               spip_log("SQLite : Erreur ALTER TABLE / ADD : $query", 'sqlite');
+                                               return false;
+                                       }
+                                       break;
+                               // artillerie lourde pour sqlite2 !
+                               } else {
+                                       $def = trim(substr($do, 3));
+                                       $colonne_ajoutee = substr($def, 0, strpos($def,' '));
+                                       $def = substr($def, strlen($colonne_ajoutee)+1);
+                                       if (!_sqlite_modifier_table($table, array($colonne_ajoutee), array('field'=>array($colonne_ajoutee=>$def)), $serveur)){
+                                               spip_log("SQLite : Erreur ALTER TABLE / ADD : $query", 'sqlite');
+                                               return false;
+                                       }
+                               }
+                               break;
+               }
+               // tout est bon, ouf !
+               spip_log("SQLite ($serveur) : Changements OK : $debut $do");
+       }
+
+       spip_log("SQLite ($serveur) : fin ALTER TABLE OK !");
+       return true;
+}
+
+
+// Fonction de creation d'une table SQL nommee $nom
+// http://doc.spip.org/@spip_sqlite_create
+function spip_sqlite_create($nom, $champs, $cles, $autoinc=false, $temporary=false, $serveur='',$requeter=true) {
+       $query = _sqlite_requete_create($nom, $champs, $cles, $autoinc, $temporary, $ifnotexists=true, $serveur, $requeter);
+       if (!$query) return false;
+       $res = spip_sqlite_query($query, $serveur, $requeter);
+       
+       // SQLite ne cree pas les KEY sur les requetes CREATE TABLE
+       // il faut donc les faire creer ensuite
+       if (!$requeter) return $res;
+
+       $ok = $res ? true : false;
+       if ($ok) {
+               foreach($cles as $k=>$v) {
+                       if (strpos($k, "KEY ") === 0) {
+                               $index = preg_replace("/KEY +/", '',$k);
+                               $ok &= $res = spip_sqlite_create_index($index, $nom, $v, $serveur);
+                       }
+               }
+       }
+       return $ok ? true : false;
+}
+
+/**
+ * Fonction pour creer une base de donnees SQLite
+ *
+ * @param string $nom le nom de la base (sans l'extension de fichier)
+ * @param string $serveur le nom de la connexion
+ * @param string $option options
+ * 
+ * @return bool true si la base est creee.
+**/
+function spip_sqlite_create_base($nom, $serveur='', $option=true) {
+       $f = _DIR_DB . $nom . '.sqlite';
+       if (_sqlite_is_version(2, '', $serveur)) {
+               $ok = sqlite_open($f, _SQLITE_CHMOD, $err);
+       } else {
+               $ok = new PDO("sqlite:$f");
+       }
+       if ($ok) {
+               unset($ok);
+               return true;
+       }
+       unset($ok);
+       return false;
+}
+
+
+// Fonction de creation d'une vue SQL nommee $nom
+// http://doc.spip.org/@spip_sqlite_create_view
+function spip_sqlite_create_view($nom, $query_select, $serveur='',$requeter=true) {
+       if (!$query_select) return false;
+       // vue deja presente
+       if (sql_showtable($nom, false, $serveur)) {
+               spip_log("Echec creation d'une vue sql ($nom) car celle-ci existe deja (serveur:$serveur)");
+               return false;
+       }
+       
+       $query = "CREATE VIEW $nom AS ". $query_select;
+       return spip_sqlite_query($query, $serveur, $requeter);
+}
+
+/**
+ * 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_sqlite_create_index($nom, $table, $champs, $serveur='', $requeter=true) {
+       if (!($nom OR $table OR $champs)) {
+               spip_log("Champ manquant pour creer un index sqlite ($nom, $table, (".join(',',$champs)."))");
+               return false;
+       }
+       
+       // SQLite ne differentie pas noms des index en fonction des tables
+       // il faut donc creer des noms uniques d'index pour une base sqlite
+       $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_sqlite_query($query, $serveur, $requeter);
+       if (!$requeter) return $res;
+       if ($res)
+               return true;
+       else
+               return false;
+}
+
+// en PDO/sqlite3, il faut calculer le count par une requete count(*)
+// pour les resultats de SELECT
+// cela est fait sans spip_sqlite_query()
+// http://doc.spip.org/@spip_sqlite_count
+function spip_sqlite_count($r, $serveur='',$requeter=true) {
+       if (!$r) return 0;
+               
+       if (_sqlite_is_version(3, '', $serveur)){
+               // select ou autre (insert, update,...) ?
+               if (isset($r->spipSqliteRowCount)) {
+                       // Ce compte est faux s'il y a des limit dans la requete :(
+                       // il retourne le nombre d'enregistrements sans le limit
+                       return $r->spipSqliteRowCount;
+               } else {
+                       return $r->rowCount();
+               }
+       } else {
+               return sqlite_num_rows($r);
+       }
+}
+
+
+// http://doc.spip.org/@spip_sqlite_countsel
+function spip_sqlite_countsel($from = array(), $where = array(), $groupby = '', $having = array(), $serveur='',$requeter=true) {
+       $c = !$groupby ? '*' : ('DISTINCT ' . (is_string($groupby) ? $groupby : join(',', $groupby)));
+       $r = spip_sqlite_select("COUNT($c)", $from, $where,'', '', '',$having, $serveur, $requeter);
+       if ((is_resource($r) or is_object($r)) && $requeter) { // ressource : sqlite2, object : sqlite3
+               if (_sqlite_is_version(3,'',$serveur)){
+                       list($n) = spip_sqlite_fetch($r, SPIP_SQLITE3_NUM, $serveur);
+               } else {
+                       list($n) = spip_sqlite_fetch($r, SPIP_SQLITE2_NUM, $serveur);
+               }
+               spip_sqlite_free($r,$serveur);
+       }
+       return $n;
+}
+
+
+
+// http://doc.spip.org/@spip_sqlite_delete
+function spip_sqlite_delete($table, $where='', $serveur='',$requeter=true) {
+       $res = spip_sqlite_query(
+                         _sqlite_calculer_expression('DELETE FROM', $table, ',')
+                       . _sqlite_calculer_expression('WHERE', $where),
+                       $serveur, $requeter);
+
+       // renvoyer la requete inerte si demandee
+       if (!$requeter) return $res;
+       
+  if ($res){
+         $link  = _sqlite_link($serveur);
+         if (_sqlite_is_version(3, $link)) {
+                 return $res->rowCount();
+         } else {
+                 return sqlite_changes($link);
+         }
+  }
+  else
+         return false;
+}
+
+
+// http://doc.spip.org/@spip_sqlite_drop_table
+function spip_sqlite_drop_table($table, $exist='', $serveur='',$requeter=true) {
+       if ($exist) $exist =" IF EXISTS";
+       
+       /* simuler le IF EXISTS - version 2 */
+       if ($exist && _sqlite_is_version(2, '', $serveur)){
+               $a = spip_sqlite_showtable($table, $serveur); 
+               if (!$a) return true;
+               $exist = '';
+       }
+       if (spip_sqlite_query("DROP TABLE$exist $table", $serveur, $requeter))
+               return true;
+       else 
+               return false;
+}
+
+// supprime une vue 
+// http://doc.spip.org/@spip_sqlite_drop_view
+function spip_sqlite_drop_view($view, $exist='', $serveur='',$requeter=true) {
+       if ($exist) $exist =" IF EXISTS";
+       
+       /* simuler le IF EXISTS - version 2 */
+       if ($exist && _sqlite_is_version(2, '', $serveur)){
+               $a = spip_sqlite_showtable($view, $serveur); 
+               if (!$a) return true;
+               $exist = '';
+       }
+       
+       return spip_sqlite_query("DROP VIEW$exist $view", $serveur, $requeter);
+}
+
+/**
+ * Fonction de suppression d'un INDEX
+ * 
+ * @param string $nom : nom de l'index
+ * @param string $table : table sql de 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_sqlite_drop_index($nom, $table, $serveur='', $requeter=true) {
+       if (!($nom OR $table)) {
+               spip_log("Champ manquant pour supprimer un index sqlite ($nom, $table)");
+               return false;
+       }
+       
+       // SQLite ne differentie pas noms des index en fonction des tables
+       // il faut donc creer des noms uniques d'index pour une base sqlite
+       $index = $table.'_'.$nom;
+       $exist =" IF EXISTS";
+       
+       /* simuler le IF EXISTS - version 2 */
+       if (_sqlite_is_version(2, '', $serveur)){
+               $a = spip_sqlite_showtable($table, $serveur); 
+               if (!isset($a['key']['KEY '.$nom])) return true;
+               $exist = '';
+       }
+       
+       $query = "DROP INDEX$exist $index";
+       return spip_sqlite_query($query, $serveur, $requeter);
+}
+
+/**
+ * Retourne la derniere erreur generee
+ *
+ * @param $serveur nom de la connexion
+ * @return string erreur eventuelle
+**/
+// http://doc.spip.org/@spip_sqlite_error
+function spip_sqlite_error($query='', $serveur='') {
+       $link  = _sqlite_link($serveur);
+       
+       if (_sqlite_is_version(3, $link)) {
+               $errs = $link->errorInfo();
+               $s = '';
+               foreach($errs as $n=>$e){
+                       $s .= "\n$n : $e";
+               }
+       } elseif ($link) {
+               $s = sqlite_error_string(sqlite_last_error($link));
+       } else {
+               $s = ": aucune ressource sqlite (link)";
+       }
+       if ($s) spip_log("$s - $query", 'sqlite');
+       return $s;
+}
+
+/**
+ * Retourne le numero de la derniere erreur SQL
+ * (sauf que SQLite semble ne connaitre que 0 ou 1)
+ *
+ * @param $serveur nom de la connexion
+ * @return int 0 pas d'erreur / 1 une erreur
+**/
+// http://doc.spip.org/@spip_sqlite_errno
+function spip_sqlite_errno($serveur='') {
+       $link  = _sqlite_link($serveur);
+       
+       if (_sqlite_is_version(3, $link)){
+               $t = $link->errorInfo();
+               $s = $t[1];
+       } elseif ($link) {
+               $s = sqlite_last_error($link);
+       } else {
+               $s = ": aucune ressource sqlite (link)";        
+       }
+               
+       if ($s) spip_log("Erreur sqlite $s");
+
+       return $s ? 1 : 0;
+}
+
+
+// http://doc.spip.org/@spip_sqlite_explain
+function spip_sqlite_explain($query, $serveur='',$requeter=true){
+       if (strpos(ltrim($query), 'SELECT') !== 0) return array();
+
+       $requete = new sqlite_traiter_requete("$query", $serveur);
+       $requete->traduire_requete(); // mysql -> sqlite
+       $requete->query = 'EXPLAIN ' . $requete->query;
+       if (!$requeter) return $requete;
+       // on ne trace pas ces requetes, sinon on obtient un tracage sans fin...
+       $requete->tracer = false; 
+       $r = $requete->executer_requete();
+
+       return $r ? spip_sqlite_fetch($r, null, $serveur) : false; // hum ? etrange ca... a verifier
+}
+
+
+// http://doc.spip.org/@spip_sqlite_fetch
+function spip_sqlite_fetch($r, $t='', $serveur='',$requeter=true) {
+
+       $link = _sqlite_link($serveur);
+       if (!$t) {
+               if (_sqlite_is_version(3, $link)) {
+                       $t = SPIP_SQLITE3_ASSOC;
+               } else {
+                       $t = SPIP_SQLITE2_ASSOC;
+               }
+       }
+
+
+       if (_sqlite_is_version(3, $link)){
+               if ($r) $retour = $r->fetch($t);
+       } elseif ($r) {
+               $retour = sqlite_fetch_array($r, $t);
+       }
+       
+       // les version 2 et 3 parfois renvoie des 'table.titre' au lieu de 'titre' tout court ! pff !
+       // suppression de 'table.' pour toutes les cles (c'est un peu violent !)
+       if ($retour){
+               $new = array();
+               foreach ($retour as $cle=>$val){
+                       if (($pos = strpos($cle, '.'))!==false){
+                               $cle = substr($cle,++$pos);
+                       }
+                       $new[$cle] = $val;
+               }
+               $retour = &$new;
+       }
+
+       return $retour;
+}
+
+
+function spip_sqlite_seek($r, $row_number, $serveur='',$requeter=true) {
+       if ($r){
+               $link = _sqlite_link($serveur);
+               if (_sqlite_is_version(3, $link)){
+                       // encore un truc de bien fichu : PDO ne PEUT PAS faire de seek ou de rewind...
+                       // je me demande si pour sqlite 3 il ne faudrait pas mieux utiliser
+                       // les nouvelles fonctions sqlite3_xx (mais encore moins presentes...)
+                       return false;
+               }
+               else {
+                       return sqlite_seek($r, $row_number);
+               }
+       }
+}
+
+
+// http://doc.spip.org/@spip_sqlite_free
+function spip_sqlite_free(&$r, $serveur='',$requeter=true) {
+       unset($r);
+       return true;
+       //return sqlite_free_result($r);
+}
+
+
+// http://doc.spip.org/@spip_sqlite_get_charset
+function spip_sqlite_get_charset($charset=array(), $serveur='',$requeter=true){
+       //$c = !$charset ? '' : (" LIKE "._q($charset['charset']));
+       //return spip_sqlite_fetch(sqlite_query(_sqlite_link($serveur), "SHOW CHARACTER SET$c"), NULL, $serveur);
+}
+
+
+// http://doc.spip.org/@spip_sqlite_hex
+function spip_sqlite_hex($v){
+       return hexdec($v);
+}
+
+
+// http://doc.spip.org/@spip_sqlite_in
+function spip_sqlite_in($val, $valeurs, $not='', $serveur='',$requeter=true) {
+       $n = $i = 0;
+       $in_sql ="";
+       while ($n = strpos($valeurs, ',', $n+1)) {
+         if ((++$i) >= 255) {
+                       $in_sql .= "($val $not IN (" .
+                         substr($valeurs, 0, $n) .
+                         "))\n" .
+                         ($not ? "AND\t" : "OR\t");
+                       $valeurs = substr($valeurs, $n+1);
+                       $i = $n = 0;
+               }
+       }
+       $in_sql .= "($val $not IN ($valeurs))";
+
+       return "($in_sql)";
+}
+
+
+// http://doc.spip.org/@spip_sqlite_insert
+function spip_sqlite_insert($table, $champs, $valeurs, $desc='', $serveur='',$requeter=true) {
+
+       $connexion = $GLOBALS['connexions'][$serveur ? $serveur : 0];
+       $prefixe = $connexion['prefixe'];
+       $sqlite = $connexion['link'];
+       $db = $connexion['db'];
+
+       if ($prefixe) $table = preg_replace('/^spip/', $prefixe, $table);
+
+
+       if (isset($_GET['var_profile'])) {
+               include_spip('public/tracer');
+               $t = trace_query_start();
+       } else $t = 0 ;
+       $query="INSERT INTO $table ".($champs?"$champs VALUES $valeurs":"DEFAULT VALUES");
+       
+       
+       if ($r = spip_sqlite_query($query, $serveur, $requeter)) {
+               if (!$requeter) return $r;
+               
+               if (_sqlite_is_version(3, $sqlite)) $nb = $sqlite->lastInsertId();
+               else $nb = sqlite_last_insert_rowid($sqlite);
+       } else $nb = 0;
+
+       $err = spip_sqlite_error($query, $serveur);
+       return $t ? trace_query_end($query, $t, $nb, $err, $serveur) : $nb;
+
+}
+
+
+// http://doc.spip.org/@spip_sqlite_insertq
+function spip_sqlite_insertq($table, $couples=array(), $desc=array(), $serveur='',$requeter=true) {
+       if (!$desc) $desc = description_table($table);
+       if (!$desc) die("$table insertion sans description");
+       $fields =  isset($desc['field'])?$desc['field']:array();
+
+       foreach ($couples as $champ => $val) {
+               $couples[$champ]= _sqlite_calculer_cite($val, $fields[$champ]);
+       }
+
+       // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
+       $couples = _sqlite_ajouter_champs_timestamp($table, $couples, $desc, $serveur);
+
+       // si aucun champ donne pour l'insertion, on en cherche un avec un DEFAULT
+       // sinon sqlite3 ne veut pas inserer
+       $cles = $valeurs = "";
+       if (count($couples)) {
+               $cles = "(".join(',',array_keys($couples)).")";
+               $valeurs = "(".join(',', $couples).")";
+       }
+       
+       return spip_sqlite_insert($table, $cles , $valeurs , $desc, $serveur, $requeter);
+}
+
+
+
+// http://doc.spip.org/@spip_sqlite_insertq_multi
+function spip_sqlite_insertq_multi($table, $tab_couples=array(), $desc=array(), $serveur='',$requeter=true) {
+       foreach ($tab_couples as $couples) {
+               $retour = spip_sqlite_insertq($table, $couples, $desc, $serveur, $requeter);
+       }
+       // renvoie le dernier id d'autoincrement ajoute
+       return $retour;
+}
+
+
+
+// http://doc.spip.org/@spip_sqlite_listdbs
+function spip_sqlite_listdbs($serveur='',$requeter=true) {
+       _sqlite_init();
+       
+       if (!is_dir($d = substr(_DIR_DB,0,-1))){
+               return array();
+       }
+       
+       include_spip('inc/flock');
+       $bases = preg_files($d, $pattern = '(.*)\.sqlite$');
+       $bds = array();
+
+       foreach($bases as $b){
+               // pas de bases commencant pas sqlite 
+               // (on s'en sert pour l'installation pour simuler la presence d'un serveur)
+               // les bases sont de la forme _sqliteX_tmp_spip_install.sqlite
+               if (strpos($b, '_sqlite')) continue;
+               $bds[] = preg_replace(";.*/$pattern;iS",'$1', $b);
+       }
+
+       return $bds;
+}
+
+
+// http://doc.spip.org/@spip_sqlite_multi
+function spip_sqlite_multi ($objet, $lang) {
+       $r = "PREG_REPLACE("
+         . $objet
+         . ",'<multi>.*[\[]"
+         . $lang
+         . "[\]]([^\[]*).*</multi>', '$1') AS multi";
+       return $r;
+}
+
+
+/**
+ * Optimise une table SQL
+ * Note: Sqlite optimise TOUTE un fichier sinon rien.
+ * On evite donc 2 traitements sur la meme base dans un hit.
+ * 
+ * @param $table nom de la table a optimiser
+ * @param $serveur nom de la connexion
+ * @param $requeter effectuer la requete ? sinon retourner son code
+ * @return bool|string true / false / requete
+**/
+// http://doc.spip.org/@spip_sqlite_optimize
+function spip_sqlite_optimize($table, $serveur='', $requeter=true) {
+       static $do = false;
+       if ($requeter and $do) {return true;}
+       if ($requeter) { $do = true; }
+       return spip_sqlite_query("VACUUM", $serveur, $requeter);
+}
+
+
+// avoir le meme comportement que _q()
+function spip_sqlite_quote($v, $type=''){
+       if (is_array($v)) return join(",", array_map('spip_sqlite_quote', $v));
+       if (is_int($v)) return strval($v);
+       if (strncmp($v,'0x',2)==0 AND ctype_xdigit(substr($v,2))) return hexdec(substr($v,2));
+       if ($type === 'int' AND !$v) return '0';
+
+       if (function_exists('sqlite_escape_string')) {
+               return "'" . sqlite_escape_string($v) . "'";
+       }
+       
+       // trouver un link sqlite3 pour faire l'echappement
+       foreach ($GLOBALS['connexions'] as $s) {
+               if (_sqlite_is_version(3, $l = $s['link'])){
+                       return  $l->quote($v);
+               }       
+       }
+}
+
+
+/**
+ * Tester si une date est proche de la valeur d'un champ
+ *
+ * @param string $champ le nom du champ a tester
+ * @param int $interval valeur de l'interval : -1, 4, ...
+ * @param string $unite utite utilisee (DAY, MONTH, YEAR, ...)
+ * @return string expression SQL
+**/
+function spip_sqlite_date_proche($champ, $interval, $unite)
+{
+       $op = $interval > 0 ? '>' : '<';
+       return "($champ $op datetime('" . date("Y-m-d H:i:s") . "', '$interval $unite'))";
+}
+
+
+// http://doc.spip.org/@spip_sqlite_replace
+function spip_sqlite_replace($table, $couples, $desc=array(), $serveur='',$requeter=true) {
+       if (!$desc) $desc = description_table($table);
+       if (!$desc) die("$table insertion sans description");
+       $fields =  isset($desc['field'])?$desc['field']:array();
+
+       foreach ($couples as $champ => $val) {
+               $couples[$champ]= _sqlite_calculer_cite($val, $fields[$champ]);
+       }
+       
+       // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
+       $couples = _sqlite_ajouter_champs_timestamp($table, $couples, $desc, $serveur);
+       
+       return spip_sqlite_query("REPLACE INTO $table (" . join(',',array_keys($couples)) . ') VALUES (' .join(',',$couples) . ')', $serveur);
+}
+
+
+
+// http://doc.spip.org/@spip_sqlite_replace_multi
+function spip_sqlite_replace_multi($table, $tab_couples, $desc=array(), $serveur='',$requeter=true) {
+       
+       // boucler pour trainter chaque requete independemment
+       foreach ($tab_couples as $couples){
+               $retour = spip_sqlite_replace($table, $couples, $desc, $serveur,$requeter);
+       }
+       // renvoie le dernier id        
+       return $retour; 
+}
+
+
+// http://doc.spip.org/@spip_sqlite_select
+function spip_sqlite_select($select, $from, $where='', $groupby='', $orderby='', $limit='', $having='', $serveur='',$requeter=true) {  
+
+       // version() n'est pas connu de sqlite
+       $select = str_replace('version()', 'sqlite_version()',$select);
+
+       // recomposer from
+       $from = (!is_array($from) ? $from : _sqlite_calculer_select_as($from));
+
+       $query = 
+                 _sqlite_calculer_expression('SELECT', $select, ', ')
+               . _sqlite_calculer_expression('FROM', $from, ', ')
+               . _sqlite_calculer_expression('WHERE', $where)
+               . _sqlite_calculer_expression('GROUP BY', $groupby, ',')
+               . _sqlite_calculer_expression('HAVING', $having)
+               . ($orderby ? ("\nORDER BY " . _sqlite_calculer_order($orderby)) :'')
+               . ($limit ? "\nLIMIT $limit" : '');
+
+       return spip_sqlite_query($query, $serveur, $requeter);
+}
+
+
+// http://doc.spip.org/@spip_sqlite_selectdb
+function spip_sqlite_selectdb($db, $serveur='',$requeter=true) {
+       _sqlite_init();
+
+       // interdire la creation d'une nouvelle base, 
+       // sauf si on est dans l'installation
+       if (!is_file($f = _DIR_DB . $db . '.sqlite')
+               && (!defined('_ECRIRE_INSTALL') || !_ECRIRE_INSTALL))
+               return false;
+
+       // se connecter a la base indiquee
+       // avec les identifiants connus
+       $index = $serveur ? $serveur : 0;
+
+       if ($link = spip_connect_db('', '', '', '', '@selectdb@' . $db , $serveur, '', '')){
+               if (($db==$link['db']) && $GLOBALS['connexions'][$index] = $link)
+                       return $db;                                     
+       } else {
+               spip_log("Impossible de selectionner la base $db", 'sqlite');
+               return false;
+       }
+
+}
+
+
+// http://doc.spip.org/@spip_sqlite_set_charset
+function spip_sqlite_set_charset($charset, $serveur='',$requeter=true){
+       #spip_log("changement de charset sql : "."SET NAMES "._q($charset));
+       # return spip_sqlite_query("SET NAMES ". spip_sqlite_quote($charset), $serveur); //<-- Passe pas !
+}
+
+
+// http://doc.spip.org/@spip_sqlite_showbase
+function spip_sqlite_showbase($match, $serveur='',$requeter=true){
+       // type est le type d'entrée : table / index / view
+       // on ne retourne que les tables (?) et non les vues...
+       # ESCAPE non supporte par les versions sqlite <3
+       #       return spip_sqlite_query("SELECT name FROM sqlite_master WHERE type='table' AND tbl_name LIKE "._q($match)." ESCAPE '\'", $serveur, $requeter);
+       $match = preg_quote($match);
+       $match = str_replace("\\\_","[[TIRETBAS]]",$match);
+       $match = str_replace("\\\%","[[POURCENT]]",$match);
+       $match = str_replace("_",".",$match);
+       $match = str_replace("%",".*",$match);
+       $match = str_replace("[[TIRETBAS]]","_",$match);
+       $match = str_replace("[[POURCENT]]","%",$match);
+       $match = "^$match$";
+       return spip_sqlite_query("SELECT name FROM sqlite_master WHERE type='table' AND tbl_name REGEXP "._q($match), $serveur, $requeter);
+}
+
+
+// http://doc.spip.org/@spip_sqlite_showtable
+function spip_sqlite_showtable($nom_table, $serveur='',$requeter=true){
+       
+       $query = 
+                       'SELECT sql, type FROM'
+                       . ' (SELECT * FROM sqlite_master UNION ALL'
+                       . ' SELECT * FROM sqlite_temp_master)'
+                       . " WHERE tbl_name LIKE '$nom_table'"
+                       . " AND type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%'"
+                       . ' ORDER BY substr(type,2,1), name';
+       
+       $a = spip_sqlite_query($query, $serveur, $requeter);
+       if (!$a) return "";
+       if (!$requeter) return $a;
+       if (!($a = spip_sqlite_fetch($a, null, $serveur))) return "";
+       $vue = ($a['type'] == 'view'); // table | vue
+
+       // c'est une table
+       // il faut parser le create
+       if (!$vue) {
+               if (!preg_match("/^[^(),]*\((([^()]*(\([^()]*\))?[^()]*)*)\)[^()]*$/", array_shift($a), $r))
+                       return "";
+               else {
+                       $dec = $r[1];
+                       if (preg_match("/^(.*?),([^,]*KEY.*)$/s", $dec, $r)) {
+                               $namedkeys = $r[2];
+                               $dec = $r[1];
+                       }
+                       else 
+                               $namedkeys = "";
+
+                       $fields = array();
+                       foreach (explode(",",$dec) as $v) {
+                               preg_match("/^\s*([^\s]+)\s+(.*)/",$v,$r);
+                               // trim car 'Sqlite Manager' (plugin Firefox) utilise des guillemets
+                               // lorsqu'on modifie une table avec cet outil.
+                               // possible que d'autres fassent de meme.
+                               $fields[ trim(strtolower($r[1]),'"') ] = $r[2];
+                       }
+                       // key inclues dans la requete
+                       $keys = array();
+                       foreach(preg_split('/\)\s*,?/',$namedkeys) as $v) {
+                               if (preg_match("/^\s*([^(]*)\((.*)$/",$v,$r)) {
+                                       $k = str_replace("`", '', trim($r[1]));
+                                       $t = trim(strtolower(str_replace("`", '', $r[2])), '"');
+                                       if ($k && !isset($keys[$k])) $keys[$k] = $t; else $keys[] = $t;
+                               }
+                       }
+                       // sinon ajouter les key index
+                       $query = 
+                               'SELECT name,sql FROM'
+                               . ' (SELECT * FROM sqlite_master UNION ALL'
+                               . ' SELECT * FROM sqlite_temp_master)'
+                               . " WHERE tbl_name LIKE '$nom_table'"
+                               . " AND type='index' AND name NOT LIKE 'sqlite_%'"
+                               . 'ORDER BY substr(type,2,1), name';
+                       $a = spip_sqlite_query($query, $serveur, $requeter);
+                       while ($r = spip_sqlite_fetch($a, null, $serveur)) {
+                               $key = str_replace($nom_table.'_','',$r['name']); // enlever le nom de la table ajoute a l'index
+                               $colonnes = preg_replace(',.*\((.*)\).*,','$1',$r['sql']);
+                               $keys['KEY '.$key] = $colonnes;
+                       }                       
+               }
+       // c'est une vue, on liste les champs disponibles simplement
+       } else {
+               if ($res = sql_fetsel('*',$nom_table,'','','','1','',$serveur)){ // limit 1
+                       $fields = array();
+                       foreach($res as $c=>$v) $fields[$c]='';
+                       $keys = array();                
+               } else {        
+                       return "";      
+               }
+       }
+       return array('field' => $fields, 'key' => $keys);
+       
+}
+
+
+// http://doc.spip.org/@spip_sqlite_update
+function spip_sqlite_update($table, $champs, $where='', $desc='', $serveur='',$requeter=true) {
+       // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
+       $champs = _sqlite_ajouter_champs_timestamp($table, $champs, $desc, $serveur);
+       
+       $set = array();
+       foreach ($champs as $champ => $val)
+               $set[] = $champ . "=$val";
+       if (!empty($set))
+               return spip_sqlite_query(
+                         _sqlite_calculer_expression('UPDATE', $table, ',')
+                       . _sqlite_calculer_expression('SET', $set, ',')
+                       . _sqlite_calculer_expression('WHERE', $where), 
+                       $serveur, $requeter);
+}
+
+
+// http://doc.spip.org/@spip_sqlite_updateq
+function spip_sqlite_updateq($table, $champs, $where='', $desc=array(), $serveur='',$requeter=true) {
+
+       if (!$champs) return;
+       if (!$desc) $desc = description_table($table);
+       if (!$desc) die("$table insertion sans description");
+       $fields =  $desc['field'];
+       
+       // recherche de champs 'timestamp' pour mise a jour auto de ceux-ci
+       $champs = _sqlite_ajouter_champs_timestamp($table, $champs, $desc, $serveur);
+       
+       $set = array();
+       foreach ($champs as $champ => $val) {
+               $set[] = $champ . '=' . _sqlite_calculer_cite($val, $fields[$champ]);
+       }
+       return spip_sqlite_query(
+                         _sqlite_calculer_expression('UPDATE', $table, ',')
+                       . _sqlite_calculer_expression('SET', $set, ',')
+                       . _sqlite_calculer_expression('WHERE', $where),
+                       $serveur, $requeter);
+}
+
+
+
+/*
+ * 
+ * Ensuite les fonctions non abstraites
+ * crees pour l'occasion de sqlite
+ * 
+ */
+
+
+// fonction pour la premiere connexion a un serveur SQLite
+// http://doc.spip.org/@_sqlite_init
+function _sqlite_init(){
+       if (!defined('_DIR_DB')) define('_DIR_DB', _DIR_ETC . 'bases/');
+       if (!defined('_SQLITE_CHMOD')) define('_SQLITE_CHMOD', _SPIP_CHMOD);
+       
+       if (!is_dir($d = _DIR_DB)){
+               include_spip('inc/flock');
+               sous_repertoire($d);
+       }
+}
+
+
+// teste la version sqlite du link en cours
+// http://doc.spip.org/@_sqlite_is_version
+function _sqlite_is_version($version='', $link='', $serveur='',$requeter=true){
+       if ($link==='') $link = _sqlite_link($serveur);
+       if (!$link) return false;
+       if (is_a($link, 'PDO')){
+               $v = 3; 
+       } else {
+               $v = 2; 
+       }
+       
+       if (!$version) return $v;
+       return ($version == $v);
+}
+
+
+// retrouver un link (et definir les fonctions externes sqlite->php)
+// $recharger devient inutile (a supprimer ?)
+// http://doc.spip.org/@_sqlite_link
+function _sqlite_link($serveur = '', $recharger = false){
+       static $charge = array();
+       if ($recharger) $charge[$serveur] = false;
+       
+       $link = &$GLOBALS['connexions'][$serveur ? $serveur : 0]['link'];
+
+       if ($link && !$charge[$serveur]){
+               include_spip('req/sqlite_fonctions');
+               _sqlite_init_functions($link);
+               $charge[$serveur] = true;
+       }
+       return $link;
+}
+
+
+/* ordre alphabetique pour les autres */
+
+
+// renvoie les bons echappements (pas sur les fonctions now())
+// http://doc.spip.org/@_sqlite_calculer_cite
+function _sqlite_calculer_cite($v, $type) {
+       if (sql_test_date($type) AND preg_match('/^\w+\(/', $v))
+               return $v;
+       if (sql_test_int($type)) {
+               if (is_numeric($v))
+                       return $v;
+               if (ctype_xdigit(substr($v,2)) AND strncmp($v,'0x',2)==0)
+                       return hexdec(substr($v,2));
+       }
+       //else return  ("'" . spip_sqlite_quote($v) . "'");
+       return  (spip_sqlite_quote($v));
+}
+
+
+// renvoie grosso modo "$expression join($join, $v)"
+// http://doc.spip.org/@_sqlite_calculer_expression
+function _sqlite_calculer_expression($expression, $v, $join = 'AND'){
+       if (empty($v))
+               return '';
+       
+       $exp = "\n$expression ";
+       
+       if (!is_array($v)) {
+               return $exp . $v;
+       } else {
+               if (strtoupper($join) === 'AND')
+                       return $exp . join("\n\t$join ", array_map('_sqlite_calculer_where', $v));
+               else
+                       return $exp . join($join, $v);
+       }
+}
+
+
+
+
+// pour conversion 0+x ? (pas la peine en sqlite)
+// http://doc.spip.org/@_sqlite_calculer_order
+function _sqlite_calculer_order($orderby) {
+       return (is_array($orderby)) ? join(", ", $orderby) :  $orderby;
+}
+
+
+// renvoie des 'nom AS alias' 
+// http://doc.spip.org/@_sqlite_calculer_select_as
+function _sqlite_calculer_select_as($args){
+       $res = '';
+       foreach($args as $k => $v) {
+               if (substr($k,-1)=='@') {
+                       // c'est une jointure qui se refere au from precedent
+                       // pas de virgule
+                 $res .= '  ' . $v ;
+               }
+               else {
+                       if (!is_numeric($k)) {
+                               $p = strpos($v, " ");
+                               if ($p)
+                               $v = substr($v,0,$p) . " AS '$k'" . substr($v,$p);
+                               else $v .= " AS '$k'";
+               }
+               $res .= ', ' . $v ;
+               }
+       }
+       return substr($res,2) . $join;
+}
+
+
+// renvoie les bonnes parentheses pour des where imbriquees
+// http://doc.spip.org/@_sqlite_calculer_where
+function _sqlite_calculer_where($v){
+       if (!is_array($v))
+         return $v ;
+
+       $op = array_shift($v);
+       if (!($n=count($v)))
+               return $op;
+       else {
+               $arg = _sqlite_calculer_where(array_shift($v));
+               if ($n==1) {
+                         return "$op($arg)";
+               } else {
+                       $arg2 = _sqlite_calculer_where(array_shift($v));
+                       if ($n==2) {
+                               return "($arg $op $arg2)";
+                       } else return "($arg $op ($arg2) : $v[0])";
+               }
+       }
+}
+
+
+
+/*
+ * Charger les modules sqlite (si possible) (juste la version demandee),
+ * ou, si aucune version, renvoie les versions sqlite dispo 
+ * sur ce serveur dans un array
+ */
+// http://doc.spip.org/@_sqlite_charger_version
+function _sqlite_charger_version($version=''){
+       $versions = array();
+       
+       // version 2
+       if (!$version || $version == 2){
+               if (charger_php_extension('sqlite')) {
+                       $versions[]=2;
+               }
+       }
+       
+       // version 3
+       if (!$version || $version == 3){
+               if (charger_php_extension('pdo') && charger_php_extension('pdo_sqlite')) {
+                       $versions[]=3;
+               }
+       }
+       if ($version) return in_array($version, $versions);
+       return $versions;
+}
+
+
+
+/**
+ * Gestion des requetes ALTER non reconnues de SQLite :
+ * ALTER TABLE table DROP column
+ * ALTER TABLE table CHANGE [COLUMN] columnA columnB definition
+ * ALTER TABLE table MODIFY column definition
+ * ALTER TABLE table ADD|DROP PRIMARY KEY
+ * 
+ * (MODIFY transforme en CHANGE columnA columnA) par spip_sqlite_alter()
+ * 
+ * 1) creer une table B avec le nouveau format souhaite
+ * 2) copier la table d'origine A vers B
+ * 3) supprimer la table A
+ * 4) renommer la table B en A
+ * 5) remettre les index (qui sont supprimes avec la table A)
+ * 
+ * @param string/array $table : nom_table, array(nom_table=>nom_futur)
+ * @param string/array $col : nom_colonne, array(nom_colonne=>nom_futur)
+ * @param array $opt : options comme les tables spip, qui sera merge a la table creee : array('field'=>array('nom'=>'syntaxe', ...), 'key'=>array('KEY nom'=>'colonne', ...))
+ * @param string $serveur : nom de la connexion sql en cours
+ * 
+ */
+// http://doc.spip.org/@_sqlite_modifier_table
+function _sqlite_modifier_table($table, $colonne, $opt=array(), $serveur=''){
+
+       if (is_array($table)) {
+               $table_origine = array_shift(array_keys($table));
+               $table_destination = array_shift($table);
+       } else {
+               $table_origine = $table_destination = $table;
+       }
+       // ne prend actuellement qu'un changement
+       // mais pourra etre adapte pour changer plus qu'une colonne a la fois
+       if (is_array($colonne)) {
+               $colonne_origine = array_shift(array_keys($colonne));
+               $colonne_destination = array_shift($colonne);
+       } else {
+               $colonne_origine = $colonne_destination = $colonne;
+       }       
+       if (!isset($opt['field'])) $opt['field'] = array();
+       if (!isset($opt['key'])) $opt['key'] = array();
+       
+       // si les noms de tables sont differents, pas besoin de table temporaire
+       // on prendra directement le nom de la future table
+       $meme_table = ($table_origine == $table_destination);
+       
+       $def_origine = sql_showtable($table_origine, false, $serveur);
+       $table_tmp = $table_origine . '_tmp';
+
+       // 1) creer une table temporaire avec les modifications 
+       // - DROP : suppression de la colonne
+       // - CHANGE : modification de la colonne
+       // (foreach pour conserver l'ordre des champs)
+       
+       // field 
+       $fields = array();
+       // pour le INSERT INTO plus loin
+       // stocker la correspondance nouvelles->anciennes colonnes
+       $fields_correspondances = array(); 
+       foreach ($def_origine['field'] as $c=>$d){
+
+               if ($colonne_origine && ($c == $colonne_origine)) {
+                       // si pas DROP
+                       if ($colonne_destination){
+                               $fields[$colonne_destination] = $opt['field'][$colonne_destination];
+                               $fields_correspondances[$colonne_destination] = $c;
+                       }       
+               } else {
+                       $fields[$c] = $d;
+                       $fields_correspondances[$c] = $c;
+               }
+       }
+       // cas de ADD sqlite2 (ajout du champ en fin de table):
+       if (!$colonne_origine && $colonne_destination){
+                       $fields[$colonne_destination] = $opt['field'][$colonne_destination];
+       }
+       
+       // key...
+       $keys = array();
+       foreach ($def_origine['key'] as $c=>$d){
+               $c = str_replace($colonne_origine,$colonne_destination,$c);
+               $d = str_replace($colonne_origine,$colonne_destination,$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';
+       
+       // copier dans destination (si differente de origine), sinon tmp
+       $table_copie = ($meme_table) ? $table_tmp : $table_destination;
+       
+       if ($q = _sqlite_requete_create(
+                       $table_copie, 
+                       $fields, 
+                       $keys, 
+                       $autoinc=false,
+                       $temporary=false, 
+                       $ifnotexists=true,
+                       $serveur)){
+               $queries[] = $q;                        
+       }
+
+       
+       // 2) y copier les champs qui vont bien
+       $champs_dest = join(', ', array_keys($fields_correspondances));
+       $champs_ori = join(', ', $fields_correspondances);
+       $queries[] = "INSERT INTO $table_copie ($champs_dest) SELECT $champs_ori FROM $table_origine";
+               
+       // 3) supprimer la table d'origine
+       $queries[] = "DROP TABLE $table_origine";
+       
+       // 4) renommer la table temporaire 
+       // avec le nom de la table destination
+       // si necessaire
+       if ($meme_table){
+               if (_sqlite_is_version(3, '', $serveur)){
+                       $queries[] = "ALTER TABLE $table_copie RENAME TO $table_destination";
+               } else {
+                       $queries[] = _sqlite_requete_create(
+                                       $table_destination, 
+                                       $fields, 
+                                       $keys, 
+                                       $autoinc=false,
+                                       $temporary=false, 
+                                       $ifnotexists=false, // la table existe puisqu'on est dans une transaction
+                                       $serveur);      
+                       $queries[] = "INSERT INTO $table_destination SELECT * FROM $table_copie";               
+                       $queries[] = "DROP TABLE $table_copie";
+               }
+       }
+       
+       // 5) remettre les index !
+       foreach ($keys as $k=>$v) {
+               if ($k=='PRIMARY KEY'){}
+               else {
+                       // enlever KEY
+                       $k = substr($k,4);
+                       $queries[] = "CREATE INDEX $table_destination"."_$k ON $table_destination ($v)";
+               }
+       }
+       
+       $queries[] = "COMMIT";
+       
+
+       // il faut les faire une par une car $query = join('; ', $queries).";"; ne fonctionne pas
+       foreach ($queries as $q){
+               $req = new sqlite_traiter_requete($q, $serveur);
+               if (!$req->executer_requete()){ 
+                       spip_log("SQLite : ALTER TABLE table :" 
+                       ." Erreur a l'execution de la requete : $q",'sqlite'); 
+                       return false;
+               }
+       }
+
+       return true;                                    
+}
+
+
+
+
+/*
+ * Nom des fonctions
+ */
+// http://doc.spip.org/@_sqlite_ref_fonctions
+function _sqlite_ref_fonctions(){
+       $fonctions = array(
+               'alter' => 'spip_sqlite_alter',
+               'count' => 'spip_sqlite_count',
+               'countsel' => 'spip_sqlite_countsel',
+               'create' => 'spip_sqlite_create',
+               'create_base' => 'spip_sqlite_create_base',
+               'create_view' => 'spip_sqlite_create_view',
+               'date_proche' => 'spip_sqlite_date_proche',
+               'delete' => 'spip_sqlite_delete',
+               'drop_table' => 'spip_sqlite_drop_table',
+               'drop_view' => 'spip_sqlite_drop_view',
+               'errno' => 'spip_sqlite_errno',
+               'error' => 'spip_sqlite_error',
+               'explain' => 'spip_sqlite_explain',
+               'fetch' => 'spip_sqlite_fetch',
+               'seek' => 'spip_sqlite_seek',
+               'free' => 'spip_sqlite_free',
+               'hex' => 'spip_sqlite_hex',
+               'in' => 'spip_sqlite_in', 
+               'insert' => 'spip_sqlite_insert',
+               'insertq' => 'spip_sqlite_insertq',
+               'insertq_multi' => 'spip_sqlite_insertq_multi',
+               'listdbs' => 'spip_sqlite_listdbs',
+               'multi' => 'spip_sqlite_multi',
+               'optimize' => 'spip_sqlite_optimize',
+               'query' => 'spip_sqlite_query',
+               'quote' => 'spip_sqlite_quote',
+               'replace' => 'spip_sqlite_replace',
+               'replace_multi' => 'spip_sqlite_replace_multi',
+               'select' => 'spip_sqlite_select',
+               'selectdb' => 'spip_sqlite_selectdb',
+               'set_charset' => 'spip_sqlite_set_charset',
+               'get_charset' => 'spip_sqlite_get_charset',
+               'showbase' => 'spip_sqlite_showbase',
+               'showtable' => 'spip_sqlite_showtable',
+               'update' => 'spip_sqlite_update',
+               'updateq' => 'spip_sqlite_updateq',
+       );
+       
+       // association de chaque nom http d'un charset aux couples sqlite 
+       // SQLite supporte utf-8 et utf-16 uniquement.
+       $charsets = array(
+               'utf-8'=>array('charset'=>'utf8','collation'=>'utf8_general_ci'), 
+               //'utf-16be'=>array('charset'=>'utf16be','collation'=>'UTF-16BE'),// aucune idee de quoi il faut remplir dans es champs la
+               //'utf-16le'=>array('charset'=>'utf16le','collation'=>'UTF-16LE')
+       );
+       
+       $fonctions['charsets'] = $charsets;
+       
+       return $fonctions;
+}
+
+
+
+// $query est une requete ou une liste de champs
+// http://doc.spip.org/@_sqlite_remplacements_definitions_table
+function _sqlite_remplacements_definitions_table($query,$autoinc=false){
+       // quelques remplacements
+       $num = "(\s*\([0-9]*\))?";
+       $enum = "(\s*\([^\)]*\))?";
+       
+       $remplace = array(
+               '/enum'.$enum.'/is' => 'VARCHAR',
+               '/binary/is' => '',
+               '/COLLATE \w+_bin/is' => '',
+               '/auto_increment/is' => '',
+               '/(timestamp .* )ON .*$/is' => '\\1',
+               '/character set \w+/is' => '',
+               '/((big|small|medium|tiny)?int(eger)?)'.$num.'\s*unsigned/is' => '\\1 UNSIGNED',
+               '/(text\s+not\s+null)\s*$/is' => "\\1 DEFAULT ''",
+       );
+
+       // pour l'autoincrement, il faut des INTEGER NOT NULL PRIMARY KEY
+       if ($autoinc)
+               $remplace['/(big|small|medium|tiny)?int(eger)?'.$num.'/is'] = 'INTEGER';
+
+       return preg_replace(array_keys($remplace), $remplace, $query);
+}
+
+
+/*
+ * Creer la requete pour la creation d'une table
+ * retourne la requete pour utilisation par sql_create() et sql_alter()
+ */
+// http://doc.spip.org/@_sqlite_requete_create
+function _sqlite_requete_create($nom, $champs, $cles, $autoinc=false, $temporary=false, $_ifnotexists=true, $serveur='',$requeter=true) {
+       $query = $keys = $s = $p = '';
+
+       // certains plugins declarent les tables  (permet leur inclusion dans le dump)
+       // sans les renseigner (laisse le compilo recuperer la description)
+       if (!is_array($champs) || !is_array($cles)) 
+               return;
+
+       // sqlite ne gere pas KEY tout court dans une requete CREATE TABLE
+       // il faut passer par des create index
+       // Il gere par contre primary key !
+       // Soit la PK est definie dans les cles, soit dans un champs
+       if (!$c = $cles[$pk = "PRIMARY KEY"]) {
+               foreach($champs as $k => $v) {
+                       if (false !== stripos($v,$pk)) {
+                               $c = $k;
+                               // on n'en a plus besoin dans field, vu que defini dans key
+                               $champs[$k] = preg_replace("/$pk/is", '', $champs[$k]); 
+                               break;  
+                       }
+               }
+       }
+       if ($c) $keys = "\n\t\t$pk ($c)";
+       
+       $champs = _sqlite_remplacements_definitions_table($champs, $autoinc);
+       foreach($champs as $k => $v) {
+               $query .= "$s\n\t\t$k $v";
+               $s = ",";
+       }
+
+       $ifnotexists = "";
+       if ($_ifnotexists) {
+               // simuler le IF NOT EXISTS - version 2 
+               if (_sqlite_is_version(2, '', $serveur)){
+                       $a = spip_sqlite_showtable($nom, $serveur);
+                       if ($a) return false;
+               } 
+               // sinon l'ajouter en version 3
+               else {
+                       $ifnotexists = ' IF NOT EXISTS';
+               }
+       }
+
+       $temporary = $temporary ? ' TEMPORARY':'';
+       $q = "CREATE$temporary TABLE$ifnotexists $nom ($query" . ($keys ? ",$keys" : '') . ")\n";
+
+       return $q;
+}
+       
+
+
+/*
+ * Retrouver les champs 'timestamp'
+ * pour les ajouter aux 'insert' ou 'replace'
+ * afin de simuler le fonctionnement de mysql 
+ * 
+ * stocke le resultat pour ne pas faire 
+ * de requetes showtable intempestives
+ */
+// http://doc.spip.org/@_sqlite_ajouter_champs_timestamp
+function _sqlite_ajouter_champs_timestamp($table, $couples, $desc='', $serveur=''){
+       static $tables = array();
+       
+       if (!isset($tables[$table])){
+               
+               if (!$desc){
+                       $f = charger_fonction('trouver_table', 'base');
+                       $desc = $f($table, $serveur);
+                       // si pas de description, on ne fait rien, ou on die() ?
+                       if (!$desc OR !$desc['field']) return $couples;
+               }
+               
+               // recherche des champs avec simplement 'TIMESTAMP'
+               // cependant, il faudra peut etre etendre
+               // avec la gestion de DEFAULT et ON UPDATE
+               // mais ceux-ci ne sont pas utilises dans le core
+               $tables[$table] = array();
+
+               foreach ($desc['field'] as $k=>$v){
+                       if (strpos(strtolower(ltrim($v)), 'timestamp')===0)
+                       $tables[$table][] = $k;
+               }
+       }
+       
+       // ajout des champs type 'timestamp' absents
+       foreach ($tables[$table] as $maj){
+               if (!array_key_exists($maj, $couples))
+                       $couples[$maj] = "datetime('now')";     
+       }
+       return $couples;
+}
+       
+       
+
+/*
+ * renvoyer la liste des versions sqlite disponibles
+ * sur le serveur 
+ */
+// http://doc.spip.org/@spip_versions_sqlite
+function spip_versions_sqlite(){
+       return  _sqlite_charger_version();
+}
+
+
+
+
+/*
+ * Classe pour partager les lancements de requete
+ * - peut corriger la syntaxe des requetes pour la conformite a sqlite
+ * - peut tracer les requetes
+ * 
+ * Cette classe est presente essentiellement pour un preg_replace_callback 
+ * avec des parametres dans la fonction appelee que l'on souhaite incrementer 
+ * (fonction pour proteger les textes)
+ * 
+ */
+class sqlite_traiter_requete{
+       var $query = ''; // la requete
+       var $queryCount = ''; // la requete pour compter
+       var $serveur = ''; // le serveur
+       var $link = ''; // le link (ressource) sqlite
+       var $prefixe = ''; // le prefixe des tables
+       var $db = ''; // le nom de la base 
+       var $tracer = false; // doit-on tracer les requetes (var_profile)
+       
+       var $sqlite_version = ''; // Version de sqlite (2 ou 3)
+       
+       // Pour les corrections a effectuer sur les requetes :
+       var $textes = array();  // array(code=>'texte') trouvé
+       var $codeEchappements = "%@##@%";
+       
+       
+       // constructeur
+// http://doc.spip.org/@sqlite_traiter_requete
+       function sqlite_traiter_requete($query, $serveur = ''){
+               $this->query = $query;
+               $this->serveur = strtolower($serveur);
+               
+               if (!($this->link = _sqlite_link($this->serveur)) && (!defined('_ECRIRE_INSTALL') || !_ECRIRE_INSTALL)){
+                       spip_log("Aucune connexion sqlite (link)");
+                       return false;   
+               }
+
+               $this->sqlite_version =_sqlite_is_version('', $this->link);
+               
+               $this->prefixe  = $GLOBALS['connexions'][$this->serveur ? $this->serveur : 0]['prefixe'];
+               $this->db               = $GLOBALS['connexions'][$this->serveur ? $this->serveur : 0]['db'];
+               
+               // tracage des requetes ?
+               $this->tracer = (isset($_GET['var_profile']) && $_GET['var_profile']);
+       }
+       
+       
+       // lancer la requete $this->query,
+       // faire le tracage si demande 
+// http://doc.spip.org/@executer_requete
+       function executer_requete(){
+               $err = "";
+               if ($this->tracer) {
+                       include_spip('public/tracer');
+                       $t = trace_query_start();
+               } else $t = 0 ;
+# spip_log("requete: $this->serveur >> $this->query",'query'); // boum ? pourquoi ?
+               if ($this->link){
+                       // memoriser la derniere erreur PHP vue
+                       $e = error_get_last();
+                       // sauver la derniere requete
+                       $GLOBALS['connexions'][$this->serveur ? $this->serveur : 0]['last'] = $this->query;
+                       
+                       if ($this->sqlite_version == 3) {
+                               $r = $this->link->query($this->query);
+                               // sauvegarde de la requete (elle y est deja dans $r->queryString)
+                               # $r->spipQueryString = $this->query;
+
+                               // comptage : oblige de compter le nombre d'entrees retournees 
+                               // par une requete SELECT
+                               // aucune autre solution ne donne le nombre attendu :( !
+                               // particulierement s'il y a des LIMIT dans la requete.
+                               if (strtoupper(substr(ltrim($this->query),0,6)) == 'SELECT'){
+                                       if ($r) {
+                                               $l = $this->link->query($this->query);
+                                               $r->spipSqliteRowCount =  count($l->fetchAll());
+                                               unset($l);
+                                       } elseif (is_a($r, 'PDOStatement')) {
+                                               $r->spipSqliteRowCount = 0;
+                                       }
+                               }
+                       } else {
+                               $r = sqlite_query($this->link, $this->query);
+                       }
+
+                       // loger les warnings/erreurs eventuels de sqlite remontant dans PHP
+                       if ($err = error_get_last() AND $err!=$e) {
+                               $err = strip_tags($err['message'])." in ".$err['file']." line ".$err['line'];
+                               spip_log("$err - ".$this->query, 'sqlite');
+                       }
+                 else $err="";
+
+               } else {
+                       $r = false;     
+               }
+
+               if (spip_sqlite_errno($serveur))
+                       $err .= spip_sqlite_error($this->query, $serveur);
+               return $t ? trace_query_end($this->query, $t, $r, $err, $serveur) : $r;
+       }
+               
+       // transformer la requete pour sqlite 
+       // enleve les textes, transforme la requete pour quelle soit
+       // bien interpretee par sqlite, puis remet les textes
+       // la fonction affecte $this->query
+// http://doc.spip.org/@traduire_requete
+       function traduire_requete(){
+               //
+               // 1) Protection des textes en les remplacant par des codes
+               //
+               // enlever les echappements ''
+               $this->query = str_replace("''", $this->codeEchappements, $this->query);
+               // enlever les 'textes'
+               $this->textes = array(); // vider 
+               $this->query = preg_replace_callback("/('[^']*')/", array(&$this, '_remplacerTexteParCode'), $this->query);
+               
+               //
+               // 2) Corrections de la requete
+               //
+               // Correction Create Database
+               // Create Database -> requete ignoree
+               if (strpos($this->query, 'CREATE DATABASE')===0){
+                       spip_log("Sqlite : requete non executee -> $this->query","sqlite");
+                       $this->query = "SELECT 1";      
+               }
+               
+               // Correction Insert Ignore
+               // INSERT IGNORE -> insert (tout court et pas 'insert or replace')
+               if (strpos($this->query, 'INSERT IGNORE')===0){
+                       #spip_log("Sqlite : requete transformee -> $this->query","sqlite");
+                       $this->query = 'INSERT ' . substr($this->query,'13');   
+               }
+               
+               // Correction des dates avec INTERVAL
+               // utiliser sql_date_proche() de preference
+               if (strpos($this->query, 'INTERVAL')!==false){
+                       $this->query = preg_replace_callback("/DATE_(ADD|SUB).*INTERVAL\s+(\d+)\s+([a-zA-Z]+)\)/U", 
+                                                       array(&$this, '_remplacerDateParTime'), 
+                                                       $this->query);
+               }
+               
+               // Correction Using
+               // USING (non reconnu en sqlite2)
+               // problematique car la jointure ne se fait pas du coup.
+               if (($this->sqlite_version == 2) && (strpos($this->query, "USING")!==false)) {
+                       spip_log("'USING (champ)' n'est pas reconnu en SQLite 2. Utilisez 'ON table1.champ = table2.champ', 'sqlite'");
+                       $this->query = preg_replace('/USING\s*\([^\)]*\)/', '', $this->query);
+               }
+               
+               // Correction Field
+               // remplace FIELD(table,i,j,k...) par CASE WHEN table=i THEN n ... ELSE 0 END
+               if (strpos($this->query, 'FIELD')!==false){
+                       $this->query = preg_replace_callback('/FIELD\s*\(([^\)]*)\)/', 
+                                                       array(&$this, '_remplacerFieldParCase'), 
+                                                       $this->query); 
+               }
+               
+               // Correction des noms de tables FROM
+               // mettre les bons noms de table dans from, update, insert, replace...
+               if (preg_match('/\s(SET|VALUES|WHERE|DATABASE)\s/i', $this->query, $regs)) {
+                       $suite = strstr($this->query, $regs[0]);
+                       $this->query = substr($this->query, 0, -strlen($suite));
+               } else $suite ='';
+               $pref = ($this->prefixe) ? $this->prefixe . "_": "";
+               $this->query = preg_replace('/([,\s])spip_/', '\1'.$pref, $this->query) . $suite;
+
+               // Correction zero AS x
+               // pg n'aime pas 0+x AS alias, sqlite, dans le meme style, 
+               // n'apprecie pas du tout SELECT 0 as x ... ORDER BY x
+               // il dit que x ne doit pas être un integer dans le order by !
+               // on remplace du coup x par vide() dans ce cas uniquement
+               //
+               // rien que pour public/vertebrer.php ?
+               if ((strpos($this->query, "0 AS")!==false)){
+                       // on ne remplace que dans ORDER BY ou GROUP BY
+                       if (preg_match('/\s(ORDER|GROUP) BY\s/i', $this->query, $regs)) {
+                               $suite = strstr($this->query, $regs[0]);
+                               $this->query = substr($this->query, 0, -strlen($suite));
+                       
+                               // on cherche les noms des x dans 0 AS x
+                               // on remplace dans $suite le nom par vide()
+                               preg_match_all('/\b0 AS\s*([^\s,]+)/', $this->query, $matches, PREG_PATTERN_ORDER);
+                               foreach ($matches[1] as $m){
+                                       $suite = str_replace($m, 'VIDE()', $suite);
+                               }
+                               $this->query .= $suite;
+                       }
+               }
+
+               // Correction possible des divisions entieres
+               // Le standard SQL (lequel? ou?) semble indiquer que
+               // a/b=c doit donner c entier si a et b sont entiers 4/3=1.
+               // C'est ce que retournent effectivement SQL Server et SQLite
+               // Ce n'est pas ce qu'applique MySQL qui retourne un reel : 4/3=1.333...
+               // 
+               // On peut forcer la conversion en multipliant par 1.0 avant la division
+               // /!\ SQLite 3.5.9 Debian/Ubuntu est victime d'un bug en plus ! 
+               // cf. https://bugs.launchpad.net/ubuntu/+source/sqlite3/+bug/254228
+               //     http://www.sqlite.org/cvstrac/tktview?tn=3202
+               // (4*1.0/3) n'est pas rendu dans ce cas !
+               # $this->query = str_replace('/','* 1.00 / ',$this->query);
+                       
+               // Correction Antiquotes
+               // ` => rien
+               $this->query = str_replace('`','',$this->query);
+               
+               // Correction critere REGEXP, non reconnu en sqlite2
+               if (($this->sqlite_version == 2) && (strpos($this->query, 'REGEXP')!==false)){
+                       $this->query = preg_replace('/([^\s\(]*)(\s*)REGEXP(\s*)([^\s\)]*)/', 'REGEXP($4, $1)', $this->query);
+               }
+               
+               
+               //
+               // 3) Remise en place des textes d'origine
+               //
+               // remettre les 'textes'
+               foreach ($this->textes as $cle=>$val){
+                       $this->query = str_replace($cle, $val, $this->query);
+               }
+               // remettre les echappements ''
+               $this->query = str_replace($this->codeEchappements,"''",$this->query);
+       }
+       
+
+
+       // les callbacks        
+       // remplacer DATE_ / INTERVAL par DATE...strtotime
+// http://doc.spip.org/@_remplacerDateParTime
+       function _remplacerDateParTime($matches){
+               $op = strtoupper($matches[1] == 'ADD')?'+':'-'; 
+               return "datetime('" . date("Y-m-d H:i:s") . "', '$op$matches[2] $matches[3]')";
+       }
+
+       // callback ou l'on remplace FIELD(table,i,j,k...) par CASE WHEN table=i THEN n ... ELSE 0 END
+// http://doc.spip.org/@_remplacerFieldParCase
+       function _remplacerFieldParCase($matches){
+               $fields = substr($matches[0],6,-1); // ne recuperer que l'interieur X de field(X)
+               $t = explode(',', $fields);
+               $index = array_shift($t);
+
+               $res = '';
+               $n=0;
+               foreach($t as $v) {
+                       $n++;
+                       $res .= "\nWHEN $index=$v THEN $n";
+               }
+               return "CASE $res ELSE 0 END ";                 
+       }
+
+       // callback ou l'on sauve le texte qui est cache dans un tableau $this->textes
+// http://doc.spip.org/@_remplacerTexteParCode
+       function _remplacerTexteParCode($matches){
+               $this->textes[$code = "%@##".count($this->textes)."##@%"] = $matches[1];
+               return $code;   
+       }
+
+}
+
+?>