Newer
Older
// possible que d'autres fassent de meme.
$fields[ trim(strtolower($r[1]),'"') ] = $r[2];
$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);
cerdic
a validé
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),
cerdic
a validé
$serveur, $requeter);
cerdic
a validé
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),
cerdic
a validé
$serveur, $requeter);
}
/*
*
* Ensuite les fonctions non abstraites
* crees pour l'occasion de sqlite
*
*/
// fonction pour la premiere connexion a un serveur SQLite
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
cerdic
a validé
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 ?)
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())
function _sqlite_calculer_cite($v, $type) {
if (sql_test_date($type) AND preg_match('/^\w+\(/', $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)"
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)
function _sqlite_calculer_order($orderby) {
return (is_array($orderby)) ? join(", ", $orderby) : $orderby;
}
// renvoie des 'nom AS alias'
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 ;
}
}
// renvoie les bonnes parentheses pour des where imbriquees
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
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
*/
function _sqlite_charger_version($version=''){
$versions = array();
// version 2
if (!$version || $version == 2){
marcimat
a validé
if (charger_php_extension('sqlite')) {
$versions[]=2;
}
}
// version 3
if (!$version || $version == 3){
marcimat
a validé
if (charger_php_extension('pdo') && charger_php_extension('pdo_sqlite')) {
$versions[]=3;
}
}
if ($version) return in_array($version, $versions);
return $versions;
}
marcimat
a validé
/**
* 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
*
* (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
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];
$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']);
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
$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;
}
function _sqlite_ref_fonctions(){
$fonctions = array(
'alter' => 'spip_sqlite_alter',
'count' => 'spip_sqlite_count',
'countsel' => 'spip_sqlite_countsel',
'create' => 'spip_sqlite_create',
marcimat
a validé
'create_base' => 'spip_sqlite_create_base',
'create_view' => 'spip_sqlite_create_view',
marcimat
a validé
'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',
cerdic
a validé
'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
$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
function _sqlite_remplacements_definitions_table($query,$autoinc=false){
// quelques remplacements
$num = "(\s*\([0-9]*\))?";
$enum = "(\s*\([^\)]*\))?";
$remplace = array(
'/enum'.$enum.'/is' => 'VARCHAR',
);
// 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()
*/
cerdic
a validé
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;
}
}
}
marcimat
a validé
$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)){
if ($a) return false;
}
// sinon l'ajouter en version 3
else {
$ifnotexists = ' IF NOT EXISTS';
}
marcimat
a validé
}
$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
*/
function _sqlite_ajouter_champs_timestamp($table, $couples, $desc='', $serveur=''){
static $tables = array();
if (!isset($tables[$table])){
if (!$desc){
$trouver_table = charger_fonction('trouver_table', 'base');
$desc = $trouver_table($table, $serveur);
// si pas de description, on ne fait rien, ou on die() ?
if (!$desc) 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
*/
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
function sqlite_traiter_requete($query, $serveur = ''){
$this->query = $query;
$this->serveur = $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
function executer_requete(){
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();
marcimat
a validé
// sauver la derniere requete
$GLOBALS['connexions'][$this->serveur ? $this->serveur : 0]['last'] = $this->query;
$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 {
$r = false;
}
}
// 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
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
marcimat
a validé
// 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
function _remplacerDateParTime($matches){
$op = strtoupper($matches[1] == 'ADD')?'+':'-';
marcimat
a validé
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
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
function _remplacerTexteParCode($matches){
$this->textes[$code = "%@##".count($this->textes)."##@%"] = $matches[1];
return $code;
}