Skip to content
Extraits de code Groupes Projets
sqlite_generique.php 55,5 ko
Newer Older
<?php

/***************************************************************************\
 *  SPIP, Systeme de publication pour l'internet                           *
 *                                                                         *
cerdic's avatar
cerdic a validé
 *  Copyright (c) 2001-2010                                                *
 *  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.   *
\***************************************************************************/

// 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
 * 
 */
amemo's avatar
amemo a validé
// 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,
	 * le path est $addr
	 * (_DIR_DB si $addr est vide)
	 */
	_sqlite_init();

	// determiner le dossier de la base : $addr ou _DIR_DB
	$f = _DIR_DB;
	if ($addr AND strpos($addr,'/')!==false)
	// un nom de base demande et impossible d'obtenir la base, on s'en va
	if ($db AND !is_file($f .= $db . '.sqlite') AND !is_writable(dirname($f)))
			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)!");
	// 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
marcimat's avatar
marcimat a validé
			$db = "_sqlite".$sqlite_version."_install";	
			$tmp = _DIR_DB . $db . ".sqlite";
				$ok = $link = new PDO("sqlite:$tmp");
				$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
amemo's avatar
amemo a validé
// 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
	return $requete->executer_requete();
}
amemo's avatar
amemo a validé
// 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
	 */
	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;
marcimat's avatar
marcimat a validé
	// 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));
marcimat's avatar
marcimat a validé

marcimat's avatar
marcimat a validé
	// on remet les morceaux dechires ensembles... que c'est laid !
	$todo2 = array(); $i=0;
marcimat's avatar
marcimat a validé
	$ouverte = false;
marcimat's avatar
marcimat a validé
	while ($do = array_shift($todo)) {
		$todo2[$i] = isset($todo2[$i]) ? $todo2[$i] . "," . $do : $do;
marcimat's avatar
marcimat a validé
		$o=(false!==strpos($do,"("));
		$f=(false!==strpos($do,")"));
		if ($o AND !$f) $ouverte=true;
marcimat's avatar
marcimat a validé
		elseif ($f) $ouverte=false;
marcimat's avatar
marcimat a validé
		if (!$ouverte) $i++;
marcimat's avatar
marcimat a validé
	}
marcimat's avatar
marcimat a validé
	
marcimat's avatar
marcimat a validé
	foreach ($todo2 as $do){
marcimat's avatar
marcimat a validé
		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');
		$cle = strtoupper($matches[1]);
		$colonne_origine = $matches[2];
		$colonne_destination = '';
		$def = $matches[3];
marcimat's avatar
marcimat a validé
		$def = _sqlite_remplacements_definitions_table($def);
marcimat's avatar
marcimat a validé
		
marcimat's avatar
marcimat a validé
			// 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(
marcimat's avatar
marcimat a validé
					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=>""), 
				}
				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, 
marcimat's avatar
marcimat a validé
					array($colonne_origine=>$colonne_destination), 
					array('field'=>array($colonne_destination=>$def)), 
				if (!_sqlite_modifier_table(
					$table, 
					$colonne_origine, 
marcimat's avatar
marcimat a validé
					array('field'=>array($colonne_origine=>$def)), 
			// pas geres en sqlite2
			case 'RENAME':
					$do = "RENAME TO" . substr($do,6);
				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));
marcimat's avatar
marcimat a validé
					if (!_sqlite_modifier_table(array($table=>$table_dest), '', '', $serveur)){
						spip_log("SQLite : Erreur ALTER TABLE / RENAME : $query", 'sqlite');
marcimat's avatar
marcimat a validé

			// 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
					$do = "ADD".substr($do, 10);
marcimat's avatar
marcimat a validé
				if (preg_match('/^(.*)(BEFORE|AFTER|FIRST)(.*)$/is', $do, $matches)) {
				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);
marcimat's avatar
marcimat a validé
					if (!_sqlite_modifier_table($table, array($colonne_ajoutee), array('field'=>array($colonne_ajoutee=>$def)), $serveur)){
						spip_log("SQLite : Erreur ALTER TABLE / ADD : $query", 'sqlite');
		}
		// 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
amemo's avatar
amemo a validé
// 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;
marcimat's avatar
marcimat a validé
	$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;
marcimat's avatar
marcimat a validé
/**
 * 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 = $nom . '.sqlite';
	if (strpos($nom, "/")===false)
		$f = _DIR_DB . $f;
marcimat's avatar
marcimat a validé
	if (_sqlite_is_version(2, '', $serveur)) {
		$ok = new 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
amemo's avatar
amemo a validé
// 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);
}
marcimat's avatar
marcimat a validé
/**
 * 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) . ")";
marcimat's avatar
marcimat a validé
	$res = spip_sqlite_query($query, $serveur, $requeter);
	if (!$requeter) return $res;
	if ($res)
marcimat's avatar
marcimat a validé
		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()
amemo's avatar
amemo a validé
// 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);
	}
}


amemo's avatar
amemo a validé
// 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,'', '', $limit,
	if ((is_resource($r) or is_object($r)) && $requeter) { // ressource : sqlite2, object : sqlite3
		if (_sqlite_is_version(3,'',$serveur)){
			list($r) = spip_sqlite_fetch($r, SPIP_SQLITE3_NUM, $serveur);
		} else {
			list($r) = spip_sqlite_fetch($r, SPIP_SQLITE2_NUM, $serveur);
		}
		
	}
	return $r;
}



amemo's avatar
amemo a validé
// http://doc.spip.org/@spip_sqlite_delete
function spip_sqlite_delete($table, $where='', $serveur='',$requeter=true) {
	return spip_sqlite_query(
			  _sqlite_calculer_expression('DELETE FROM', $table, ',')
			. _sqlite_calculer_expression('WHERE', $where),
amemo's avatar
amemo a validé
// 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 = '';
	}
marcimat's avatar
marcimat a validé
	if (spip_sqlite_query("DROP TABLE$exist $table", $serveur, $requeter))
		return true;
	else 
		return false;
amemo's avatar
amemo a validé
// 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);
}

marcimat's avatar
marcimat a validé
/**
 * 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
**/
amemo's avatar
amemo a validé
// http://doc.spip.org/@spip_sqlite_error
function spip_sqlite_error($serveur='') {
	$link  = _sqlite_link($serveur);
	
		$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
**/
amemo's avatar
amemo a validé
// http://doc.spip.org/@spip_sqlite_errno
function spip_sqlite_errno($serveur='') {
	$link  = _sqlite_link($serveur);
	
	if (_sqlite_is_version(3, $link)){
	} elseif ($link) {
		$s = sqlite_last_error($link);
	} else {
		$s = ": aucune ressource sqlite (link)";	
	}
	if ($s) spip_log("Erreur sqlite $s");

amemo's avatar
amemo a validé
// 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;
	// 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
}


amemo's avatar
amemo a validé
// 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 !)
		$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 sqlite_seek($r, $row_number);
amemo's avatar
amemo a validé
// http://doc.spip.org/@spip_sqlite_free
marcimat's avatar
marcimat a validé
function spip_sqlite_free(&$r, $serveur='',$requeter=true) {
	unset($r);
	return true;
	//return sqlite_free_result($r);
}


amemo's avatar
amemo a validé
// 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);
}


amemo's avatar
amemo a validé
// http://doc.spip.org/@spip_sqlite_hex
function spip_sqlite_hex($v){
amemo's avatar
amemo a validé
// 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)";
}


amemo's avatar
amemo a validé
// 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 OR REPLACE INTO $table ".($champs?"$champs VALUES $valeurs":"DEFAULT VALUES");
marcimat's avatar
marcimat a validé
	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);
esj's avatar
esj a validé
	} else $nb = 0;
	return $t ? trace_query_end($query, $t, $nb, $serveur) : $nb;
amemo's avatar
amemo a validé
// 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);
amemo's avatar
amemo a validé
// 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;
}



amemo's avatar
amemo a validé
// 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;
}


amemo's avatar
amemo a validé
// http://doc.spip.org/@spip_sqlite_multi
function spip_sqlite_multi ($objet, $lang) {
	  . $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
**/
amemo's avatar
amemo a validé
// 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_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 (is_array($v)) return join(",", array_map('spip_sqlite_quote', $v));

	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'))";
amemo's avatar
amemo a validé
// 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);
}



amemo's avatar
amemo a validé
// 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; 
amemo's avatar
amemo a validé
// 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);
amemo's avatar
amemo a validé
// 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;
	}

}


amemo's avatar
amemo a validé
// 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 !
}


amemo's avatar
amemo a validé
// 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...
	return spip_sqlite_query("SELECT name FROM sqlite_master WHERE type='table' AND tbl_name LIKE '$match'", $serveur, $requeter);
amemo's avatar
amemo a validé
// 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_%'"
marcimat's avatar
marcimat a validé
			. ' ORDER BY substr(type,2,1), name';
	$a = spip_sqlite_query($query, $serveur, $requeter);
	if (!$a) return "";
	if (!($a = spip_sqlite_fetch($a, null, $serveur))) return "";
	$vue = ($a['type'] == 'view'); // table | vue
marcimat's avatar
marcimat a validé

	// 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);
marcimat's avatar
marcimat a validé
				// trim car 'Sqlite Manager' (plugin Firefox) utilise des guillemets
				// lorsqu'on modifie une table avec cet outil.