|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* *************************************************************************\ |
|
4
|
|
|
* SPIP, Systeme de publication pour l'internet * |
|
5
|
|
|
* * |
|
6
|
|
|
* Copyright (c) 2001-2016 * |
|
7
|
|
|
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * |
|
8
|
|
|
* * |
|
9
|
|
|
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. * |
|
10
|
|
|
* Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * |
|
11
|
|
|
\***************************************************************************/ |
|
12
|
|
|
|
|
13
|
|
|
/** |
|
14
|
|
|
* Ce fichier contient les fonctions gerant |
|
15
|
|
|
* les instructions SQL pour Sqlite |
|
16
|
|
|
* |
|
17
|
|
|
* @package SPIP\SQL\SQLite |
|
18
|
|
|
*/ |
|
19
|
|
|
|
|
20
|
|
|
if (!defined('_ECRIRE_INC_VERSION')) return; |
|
21
|
|
|
|
|
22
|
|
|
// TODO: get/set_caracteres ? |
|
23
|
|
|
|
|
24
|
|
|
|
|
25
|
|
|
/* |
|
26
|
|
|
* |
|
27
|
|
|
* regroupe le maximum de fonctions qui peuvent cohabiter |
|
28
|
|
|
* D'abord les fonctions d'abstractions de SPIP |
|
29
|
|
|
* |
|
30
|
|
|
*/ |
|
31
|
|
|
// http://doc.spip.org/@req_sqlite_dist |
|
32
|
|
|
function req_sqlite_dist($addr, $port, $login, $pass, $db = '', $prefixe = '', $sqlite_version = ''){ |
|
33
|
|
|
static $last_connect = array(); |
|
34
|
|
|
|
|
35
|
|
|
// si provient de selectdb |
|
36
|
|
|
// un code pour etre sur que l'on vient de select_db() |
|
37
|
|
|
if (strpos($db, $code = '@selectdb@')!==false){ |
|
38
|
|
View Code Duplication |
foreach (array('addr', 'port', 'login', 'pass', 'prefixe') as $a){ |
|
|
|
|
|
|
39
|
|
|
$$a = $last_connect[$a]; |
|
40
|
|
|
} |
|
41
|
|
|
$db = str_replace($code, '', $db); |
|
42
|
|
|
} |
|
43
|
|
|
|
|
44
|
|
|
/* |
|
45
|
|
|
* En sqlite, seule l'adresse du fichier est importante. |
|
46
|
|
|
* Ce sera $db le nom, |
|
47
|
|
|
* le path est $addr |
|
48
|
|
|
* (_DIR_DB si $addr est vide) |
|
49
|
|
|
*/ |
|
50
|
|
|
_sqlite_init(); |
|
51
|
|
|
|
|
52
|
|
|
// determiner le dossier de la base : $addr ou _DIR_DB |
|
53
|
|
|
$f = _DIR_DB; |
|
54
|
|
|
if ($addr AND strpos($addr, '/')!==false) |
|
55
|
|
|
$f = rtrim($addr, '/').'/'; |
|
56
|
|
|
|
|
57
|
|
|
// un nom de base demande et impossible d'obtenir la base, on s'en va : |
|
58
|
|
|
// il faut que la base existe ou que le repertoire parent soit writable |
|
59
|
|
|
if ($db AND !is_file($f .= $db.'.sqlite') AND !is_writable(dirname($f))){ |
|
60
|
|
|
spip_log("base $f non trouvee ou droits en ecriture manquants", 'sqlite.'._LOG_HS); |
|
61
|
|
|
return false; |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
// charger les modules sqlite au besoin |
|
65
|
|
|
if (!_sqlite_charger_version($sqlite_version)){ |
|
66
|
|
|
spip_log("Impossible de trouver/charger le module SQLite ($sqlite_version)!", 'sqlite.'._LOG_HS); |
|
67
|
|
|
return false; |
|
68
|
|
|
} |
|
69
|
|
|
|
|
70
|
|
|
// chargement des constantes |
|
71
|
|
|
// il ne faut pas definir les constantes avant d'avoir charge les modules sqlite |
|
72
|
|
|
$define = "spip_sqlite".$sqlite_version."_constantes"; |
|
73
|
|
|
$define(); |
|
74
|
|
|
|
|
75
|
|
|
$ok = false; |
|
|
|
|
|
|
76
|
|
|
if (!$db){ |
|
77
|
|
|
// si pas de db -> |
|
78
|
|
|
// base temporaire tant qu'on ne connait pas son vrai nom |
|
79
|
|
|
// pour tester la connexion |
|
80
|
|
|
$db = "_sqlite".$sqlite_version."_install"; |
|
81
|
|
|
$tmp = _DIR_DB.$db.".sqlite"; |
|
82
|
|
View Code Duplication |
if ($sqlite_version==3){ |
|
|
|
|
|
|
83
|
|
|
$ok = $link = new PDO("sqlite:$tmp"); |
|
84
|
|
|
} else { |
|
85
|
|
|
$ok = $link = sqlite_open($tmp, _SQLITE_CHMOD, $err); |
|
86
|
|
|
} |
|
87
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
88
|
|
|
// Ouvrir (eventuellement creer la base) |
|
89
|
|
|
// si pas de version fourni, on essaie la 3, sinon la 2 |
|
90
|
|
|
if ($sqlite_version==3){ |
|
91
|
|
|
$ok = $link = new PDO("sqlite:$f"); |
|
92
|
|
|
} else { |
|
93
|
|
|
$ok = $link = sqlite_open($f, _SQLITE_CHMOD, $err); |
|
94
|
|
|
} |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
if (!$ok){ |
|
98
|
|
|
$e = sqlite_last_error($db); |
|
99
|
|
|
spip_log("Impossible d'ouvrir la base SQLite($sqlite_version) $f : $e", 'sqlite.'._LOG_HS); |
|
100
|
|
|
return false; |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
if ($link){ |
|
104
|
|
|
$last_connect = array( |
|
105
|
|
|
'addr' => $addr, |
|
106
|
|
|
'port' => $port, |
|
107
|
|
|
'login' => $login, |
|
108
|
|
|
'pass' => $pass, |
|
109
|
|
|
'db' => $db, |
|
110
|
|
|
'prefixe' => $prefixe, |
|
111
|
|
|
); |
|
112
|
|
|
// etre sur qu'on definit bien les fonctions a chaque nouvelle connexion |
|
113
|
|
|
include_spip('req/sqlite_fonctions'); |
|
114
|
|
|
_sqlite_init_functions($link); |
|
115
|
|
|
} |
|
116
|
|
|
|
|
117
|
|
|
return array( |
|
118
|
|
|
'db' => $db, |
|
119
|
|
|
'prefixe' => $prefixe ? $prefixe : $db, |
|
120
|
|
|
'link' => $link, |
|
121
|
|
|
); |
|
122
|
|
|
} |
|
123
|
|
|
|
|
124
|
|
|
|
|
125
|
|
|
/** |
|
126
|
|
|
* Fonction de requete generale, munie d'une trace a la demande |
|
127
|
|
|
* |
|
128
|
|
|
* @param string $query |
|
129
|
|
|
* Requete a executer |
|
130
|
|
|
* @param string $serveur |
|
131
|
|
|
* Nom du connecteur |
|
132
|
|
|
* @param bool $requeter |
|
133
|
|
|
* Effectuer la requete ? |
|
134
|
|
|
* - true pour executer |
|
135
|
|
|
* - false pour retourner le texte de la requete |
|
136
|
|
|
* @return bool|SQLiteResult|string |
|
137
|
|
|
* Resultat de la requete |
|
138
|
|
|
*/ |
|
139
|
|
|
function spip_sqlite_query($query, $serveur = '', $requeter = true){ |
|
140
|
|
|
#spip_log("spip_sqlite_query() > $query",'sqlite.'._LOG_DEBUG); |
|
141
|
|
|
#_sqlite_init(); // fait la premiere fois dans spip_sqlite |
|
142
|
|
|
$query = spip_sqlite::traduire_requete($query, $serveur); |
|
143
|
|
|
if (!$requeter) return $query; |
|
144
|
|
|
return spip_sqlite::executer_requete($query, $serveur); |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
|
|
|
|
148
|
|
|
/* ordre alphabetique pour les autres */ |
|
149
|
|
|
|
|
150
|
|
|
// http://doc.spip.org/@spip_sqlite_alter |
|
151
|
|
|
function spip_sqlite_alter($query, $serveur = '', $requeter = true){ |
|
|
|
|
|
|
152
|
|
|
|
|
153
|
|
|
$query = spip_sqlite_query("ALTER $query", $serveur, false); |
|
154
|
|
|
// traduire la requete pour recuperer les bons noms de table |
|
155
|
|
|
$query = spip_sqlite::traduire_requete($query, $serveur); |
|
156
|
|
|
|
|
157
|
|
|
/* |
|
158
|
|
|
* la il faut faire les transformations |
|
159
|
|
|
* si ALTER TABLE x (DROP|CHANGE) y |
|
160
|
|
|
* |
|
161
|
|
|
* 1) recuperer "ALTER TABLE table " |
|
162
|
|
|
* 2) spliter les sous requetes (,) |
|
163
|
|
|
* 3) faire chaque requete independemment |
|
164
|
|
|
*/ |
|
165
|
|
|
|
|
166
|
|
|
// 1 |
|
167
|
|
|
if (preg_match("/\s*(ALTER(\s*IGNORE)?\s*TABLE\s*([^\s]*))\s*(.*)?/is", $query, $regs)){ |
|
168
|
|
|
$debut = $regs[1]; |
|
169
|
|
|
$table = $regs[3]; |
|
170
|
|
|
$suite = $regs[4]; |
|
171
|
|
|
} else { |
|
172
|
|
|
spip_log("SQLite : Probleme de ALTER TABLE mal forme dans $query", 'sqlite.'._LOG_ERREUR); |
|
173
|
|
|
return false; |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
// 2 |
|
177
|
|
|
// il faudrait une regexp pour eviter de spliter ADD PRIMARY KEY (colA, colB) |
|
178
|
|
|
// tout en cassant "ADD PRIMARY KEY (colA, colB), ADD INDEX (chose)"... en deux |
|
179
|
|
|
// ou revoir l'api de sql_alter en creant un |
|
180
|
|
|
// sql_alter_table($table,array($actions)); |
|
181
|
|
|
$todo = explode(',', $suite); |
|
182
|
|
|
|
|
183
|
|
|
// on remet les morceaux dechires ensembles... que c'est laid ! |
|
184
|
|
|
$todo2 = array(); |
|
185
|
|
|
$i = 0; |
|
186
|
|
|
$ouverte = false; |
|
187
|
|
View Code Duplication |
while ($do = array_shift($todo)){ |
|
|
|
|
|
|
188
|
|
|
$todo2[$i] = isset($todo2[$i]) ? $todo2[$i].",".$do : $do; |
|
189
|
|
|
$o = (false!==strpos($do, "(")); |
|
190
|
|
|
$f = (false!==strpos($do, ")")); |
|
191
|
|
|
if ($o AND !$f) $ouverte = true; |
|
192
|
|
|
elseif ($f) $ouverte = false; |
|
193
|
|
|
if (!$ouverte) $i++; |
|
194
|
|
|
} |
|
195
|
|
|
|
|
196
|
|
|
// 3 |
|
197
|
|
|
$resultats = array(); |
|
|
|
|
|
|
198
|
|
|
foreach ($todo2 as $do){ |
|
199
|
|
|
$do = trim($do); |
|
200
|
|
|
if (!preg_match('/(DROP PRIMARY KEY|DROP KEY|DROP INDEX|DROP COLUMN|DROP' |
|
201
|
|
|
.'|CHANGE COLUMN|CHANGE|MODIFY|RENAME TO|RENAME' |
|
202
|
|
|
.'|ADD PRIMARY KEY|ADD KEY|ADD INDEX|ADD UNIQUE KEY|ADD UNIQUE' |
|
203
|
|
|
.'|ADD COLUMN|ADD' |
|
204
|
|
|
.')\s*([^\s]*)\s*(.*)?/i', $do, $matches)){ |
|
205
|
|
|
spip_log("SQLite : Probleme de ALTER TABLE, utilisation non reconnue dans : $do \n(requete d'origine : $query)", 'sqlite.'._LOG_ERREUR); |
|
206
|
|
|
return false; |
|
207
|
|
|
} |
|
208
|
|
|
|
|
209
|
|
|
$cle = strtoupper($matches[1]); |
|
210
|
|
|
$colonne_origine = $matches[2]; |
|
211
|
|
|
$colonne_destination = ''; |
|
|
|
|
|
|
212
|
|
|
|
|
213
|
|
|
$def = $matches[3]; |
|
214
|
|
|
|
|
215
|
|
|
// eluder une eventuelle clause before|after|first inutilisable |
|
216
|
|
|
$defr = rtrim(preg_replace('/(BEFORE|AFTER|FIRST)(.*)$/is', '', $def)); |
|
217
|
|
|
$defo = $defr; // garder la def d'origine pour certains cas |
|
218
|
|
|
// remplacer les definitions venant de mysql |
|
219
|
|
|
$defr = _sqlite_remplacements_definitions_table($defr); |
|
220
|
|
|
|
|
221
|
|
|
// reinjecter dans le do |
|
222
|
|
|
$do = str_replace($def, $defr, $do); |
|
223
|
|
|
$def = $defr; |
|
224
|
|
|
|
|
225
|
|
|
switch ($cle) { |
|
226
|
|
|
// suppression d'un index |
|
227
|
|
|
case 'DROP KEY': |
|
228
|
|
|
case 'DROP INDEX': |
|
229
|
|
|
$nom_index = $colonne_origine; |
|
230
|
|
|
spip_sqlite_drop_index($nom_index, $table, $serveur); |
|
231
|
|
|
break; |
|
232
|
|
|
|
|
233
|
|
|
// suppression d'une pk |
|
234
|
|
View Code Duplication |
case 'DROP PRIMARY KEY': |
|
|
|
|
|
|
235
|
|
|
if (!_sqlite_modifier_table( |
|
236
|
|
|
$table, |
|
237
|
|
|
$colonne_origine, |
|
238
|
|
|
array('key' => array('PRIMARY KEY' => '')), |
|
239
|
|
|
$serveur)){ |
|
240
|
|
|
return false; |
|
241
|
|
|
} |
|
242
|
|
|
break; |
|
243
|
|
|
// suppression d'une colonne |
|
244
|
|
|
case 'DROP COLUMN': |
|
245
|
|
View Code Duplication |
case 'DROP': |
|
|
|
|
|
|
246
|
|
|
if (!_sqlite_modifier_table( |
|
247
|
|
|
$table, |
|
248
|
|
|
array($colonne_origine => ""), |
|
249
|
|
|
'', |
|
250
|
|
|
$serveur)){ |
|
251
|
|
|
return false; |
|
252
|
|
|
} |
|
253
|
|
|
break; |
|
254
|
|
|
|
|
255
|
|
|
case 'CHANGE COLUMN': |
|
256
|
|
|
case 'CHANGE': |
|
257
|
|
|
// recuperer le nom de la future colonne |
|
258
|
|
|
// on reprend la def d'origine car _sqlite_modifier_table va refaire la translation |
|
259
|
|
|
// en tenant compte de la cle primaire (ce qui est mieux) |
|
260
|
|
|
$def = trim($defo); |
|
261
|
|
|
$colonne_destination = substr($def, 0, strpos($def, ' ')); |
|
262
|
|
|
$def = substr($def, strlen($colonne_destination)+1); |
|
263
|
|
|
|
|
264
|
|
|
if (!_sqlite_modifier_table( |
|
265
|
|
|
$table, |
|
266
|
|
|
array($colonne_origine => $colonne_destination), |
|
267
|
|
|
array('field' => array($colonne_destination => $def)), |
|
268
|
|
|
$serveur)){ |
|
269
|
|
|
return false; |
|
270
|
|
|
} |
|
271
|
|
|
break; |
|
272
|
|
|
|
|
273
|
|
View Code Duplication |
case 'MODIFY': |
|
|
|
|
|
|
274
|
|
|
// on reprend la def d'origine car _sqlite_modifier_table va refaire la translation |
|
275
|
|
|
// en tenant compte de la cle primaire (ce qui est mieux) |
|
276
|
|
|
if (!_sqlite_modifier_table( |
|
277
|
|
|
$table, |
|
278
|
|
|
$colonne_origine, |
|
279
|
|
|
array('field' => array($colonne_origine => $defo)), |
|
280
|
|
|
$serveur)){ |
|
281
|
|
|
return false; |
|
282
|
|
|
} |
|
283
|
|
|
break; |
|
284
|
|
|
|
|
285
|
|
|
// pas geres en sqlite2 |
|
286
|
|
|
case 'RENAME': |
|
287
|
|
|
$do = "RENAME TO".substr($do, 6); |
|
288
|
|
|
case 'RENAME TO': |
|
289
|
|
|
if (_sqlite_is_version(3, '', $serveur)){ |
|
290
|
|
View Code Duplication |
if (!spip_sqlite::executer_requete("$debut $do", $serveur)){ |
|
|
|
|
|
|
291
|
|
|
spip_log("SQLite : Erreur ALTER TABLE / RENAME : $query", 'sqlite.'._LOG_ERREUR); |
|
292
|
|
|
return false; |
|
293
|
|
|
} |
|
294
|
|
|
// artillerie lourde pour sqlite2 ! |
|
295
|
|
|
} else { |
|
296
|
|
|
$table_dest = trim(substr($do, 9)); |
|
297
|
|
View Code Duplication |
if (!_sqlite_modifier_table(array($table => $table_dest), '', '', $serveur)){ |
|
|
|
|
|
|
298
|
|
|
spip_log("SQLite : Erreur ALTER TABLE / RENAME : $query", 'sqlite.'._LOG_ERREUR); |
|
299
|
|
|
return false; |
|
300
|
|
|
} |
|
301
|
|
|
} |
|
302
|
|
|
break; |
|
303
|
|
|
|
|
304
|
|
|
// ajout d'une pk |
|
305
|
|
|
case 'ADD PRIMARY KEY': |
|
306
|
|
|
$pk = trim(substr($do, 16)); |
|
307
|
|
|
$pk = ($pk[0]=='(') ? substr($pk, 1, -1) : $pk; |
|
308
|
|
|
if (!_sqlite_modifier_table( |
|
309
|
|
|
$table, |
|
310
|
|
|
$colonne_origine, |
|
311
|
|
|
array('key' => array('PRIMARY KEY' => $pk)), |
|
312
|
|
|
$serveur)){ |
|
313
|
|
|
return false; |
|
314
|
|
|
} |
|
315
|
|
|
break; |
|
316
|
|
|
// ajout d'un index |
|
317
|
|
|
case 'ADD UNIQUE KEY': |
|
318
|
|
|
case 'ADD UNIQUE': |
|
319
|
|
|
$unique=true; |
|
320
|
|
|
case 'ADD INDEX': |
|
321
|
|
|
case 'ADD KEY': |
|
322
|
|
|
// peut etre "(colonne)" ou "nom_index (colonnes)" |
|
323
|
|
|
// bug potentiel si qqn met "(colonne, colonne)" |
|
324
|
|
|
// |
|
325
|
|
|
// nom_index (colonnes) |
|
326
|
|
|
if ($def){ |
|
327
|
|
|
$colonnes = substr($def, 1, -1); |
|
328
|
|
|
$nom_index = $colonne_origine; |
|
329
|
|
|
} |
|
330
|
|
|
else { |
|
331
|
|
|
// (colonne) |
|
332
|
|
|
if ($colonne_origine[0]=="("){ |
|
333
|
|
|
$colonnes = substr($colonne_origine, 1, -1); |
|
334
|
|
View Code Duplication |
if (false!==strpos(",", $colonnes)){ |
|
|
|
|
|
|
335
|
|
|
spip_log(_LOG_GRAVITE_ERREUR, "SQLite : Erreur, impossible de creer un index sur plusieurs colonnes" |
|
336
|
|
|
." sans qu'il ait de nom ($table, ($colonnes))", 'sqlite'); |
|
|
|
|
|
|
337
|
|
|
break; |
|
338
|
|
|
} else { |
|
339
|
|
|
$nom_index = $colonnes; |
|
340
|
|
|
} |
|
341
|
|
|
} |
|
342
|
|
|
// nom_index |
|
343
|
|
|
else { |
|
344
|
|
|
$nom_index = $colonnes = $colonne_origine; |
|
345
|
|
|
} |
|
346
|
|
|
} |
|
347
|
|
|
spip_sqlite_create_index($nom_index, $table, $colonnes, $unique, $serveur); |
|
|
|
|
|
|
348
|
|
|
break; |
|
349
|
|
|
|
|
350
|
|
|
// pas geres en sqlite2 |
|
351
|
|
|
case 'ADD COLUMN': |
|
352
|
|
|
$do = "ADD".substr($do, 10); |
|
353
|
|
|
case 'ADD': |
|
354
|
|
|
default: |
|
355
|
|
|
if (_sqlite_is_version(3, '', $serveur) AND !preg_match(',primary\s+key,i',$do)){ |
|
356
|
|
View Code Duplication |
if (!spip_sqlite::executer_requete("$debut $do", $serveur)){ |
|
|
|
|
|
|
357
|
|
|
spip_log("SQLite : Erreur ALTER TABLE / ADD : $query", 'sqlite.'._LOG_ERREUR); |
|
358
|
|
|
return false; |
|
359
|
|
|
} |
|
360
|
|
|
break; |
|
361
|
|
|
|
|
362
|
|
|
} |
|
363
|
|
|
// artillerie lourde pour sqlite2 ! |
|
364
|
|
|
// ou si la colonne est aussi primary key |
|
365
|
|
|
// cas du add id_truc int primary key |
|
366
|
|
|
// ajout d'une colonne qui passe en primary key directe |
|
367
|
|
|
else { |
|
368
|
|
|
$def = trim(substr($do, 3)); |
|
369
|
|
|
$colonne_ajoutee = substr($def, 0, strpos($def, ' ')); |
|
370
|
|
|
$def = substr($def, strlen($colonne_ajoutee)+1); |
|
371
|
|
|
$opts = array(); |
|
372
|
|
|
if (preg_match(',primary\s+key,i',$def)){ |
|
373
|
|
|
$opts['key'] = array('PRIMARY KEY' => $colonne_ajoutee); |
|
374
|
|
|
$def = preg_replace(',primary\s+key,i','',$def); |
|
375
|
|
|
} |
|
376
|
|
|
$opts['field'] = array($colonne_ajoutee => $def); |
|
377
|
|
View Code Duplication |
if (!_sqlite_modifier_table($table, array($colonne_ajoutee), $opts, $serveur)){ |
|
|
|
|
|
|
378
|
|
|
spip_log("SQLite : Erreur ALTER TABLE / ADD : $query", 'sqlite.'._LOG_ERREUR); |
|
379
|
|
|
return false; |
|
380
|
|
|
} |
|
381
|
|
|
} |
|
382
|
|
|
break; |
|
383
|
|
|
} |
|
384
|
|
|
// tout est bon, ouf ! |
|
385
|
|
|
spip_log("SQLite ($serveur) : Changements OK : $debut $do", 'sqlite.'._LOG_INFO); |
|
386
|
|
|
} |
|
387
|
|
|
|
|
388
|
|
|
spip_log("SQLite ($serveur) : fin ALTER TABLE OK !", 'sqlite.'._LOG_INFO); |
|
389
|
|
|
return true; |
|
390
|
|
|
} |
|
391
|
|
|
|
|
392
|
|
|
|
|
393
|
|
|
/** |
|
394
|
|
|
* Fonction de creation d'une table SQL nommee $nom |
|
395
|
|
|
* http://doc.spip.org/@spip_sqlite_create |
|
396
|
|
|
* |
|
397
|
|
|
* @param string $nom |
|
398
|
|
|
* @param array $champs |
|
399
|
|
|
* @param array $cles |
|
400
|
|
|
* @param bool $autoinc |
|
401
|
|
|
* @param bool $temporary |
|
402
|
|
|
* @param string $serveur |
|
403
|
|
|
* @param bool $requeter |
|
404
|
|
|
* @return bool|SQLiteResult|string |
|
405
|
|
|
*/ |
|
406
|
|
|
function spip_sqlite_create($nom, $champs, $cles, $autoinc = false, $temporary = false, $serveur = '', $requeter = true){ |
|
407
|
|
|
$query = _sqlite_requete_create($nom, $champs, $cles, $autoinc, $temporary, $ifnotexists = true, $serveur, $requeter); |
|
408
|
|
|
if (!$query) return false; |
|
409
|
|
|
$res = spip_sqlite_query($query, $serveur, $requeter); |
|
|
|
|
|
|
410
|
|
|
|
|
411
|
|
|
// SQLite ne cree pas les KEY sur les requetes CREATE TABLE |
|
412
|
|
|
// il faut donc les faire creer ensuite |
|
413
|
|
|
if (!$requeter) return $res; |
|
414
|
|
|
|
|
415
|
|
|
$ok = $res ? true : false; |
|
416
|
|
|
if ($ok){ |
|
417
|
|
|
foreach ($cles as $k => $v){ |
|
418
|
|
|
if (preg_match(',^(KEY|UNIQUE)\s,i',$k,$m)){ |
|
419
|
|
|
$index = trim(substr($k,strlen($m[1]))); |
|
420
|
|
|
$unique = (strlen($m[1])>3); |
|
421
|
|
|
$ok &= spip_sqlite_create_index($index, $nom, $v, $unique, $serveur); |
|
422
|
|
|
} |
|
423
|
|
|
} |
|
424
|
|
|
} |
|
425
|
|
|
return $ok ? true : false; |
|
426
|
|
|
} |
|
427
|
|
|
|
|
428
|
|
|
/** |
|
429
|
|
|
* Fonction pour creer une base de donnees SQLite |
|
430
|
|
|
* |
|
431
|
|
|
* @param string $nom le nom de la base (sans l'extension de fichier) |
|
432
|
|
|
* @param string $serveur le nom de la connexion |
|
433
|
|
|
* @param string $option options |
|
|
|
|
|
|
434
|
|
|
* |
|
435
|
|
|
* @return bool true si la base est creee. |
|
436
|
|
|
**/ |
|
437
|
|
|
function spip_sqlite_create_base($nom, $serveur = '', $option = true){ |
|
|
|
|
|
|
438
|
|
|
$f = $nom.'.sqlite'; |
|
439
|
|
|
if (strpos($nom, "/")===false) |
|
440
|
|
|
$f = _DIR_DB.$f; |
|
441
|
|
|
if (_sqlite_is_version(2, '', $serveur)){ |
|
442
|
|
|
$ok = sqlite_open($f, _SQLITE_CHMOD, $err); |
|
443
|
|
|
} else { |
|
444
|
|
|
$ok = new PDO("sqlite:$f"); |
|
445
|
|
|
} |
|
446
|
|
|
if ($ok){ |
|
447
|
|
|
unset($ok); |
|
448
|
|
|
return true; |
|
449
|
|
|
} |
|
450
|
|
|
unset($ok); |
|
451
|
|
|
return false; |
|
452
|
|
|
} |
|
453
|
|
|
|
|
454
|
|
|
|
|
455
|
|
|
/** |
|
456
|
|
|
* Fonction de creation d'une vue SQL nommee $nom |
|
457
|
|
|
* http://doc.spip.org/@spip_sqlite_create_view |
|
458
|
|
|
* |
|
459
|
|
|
* @param string $nom |
|
460
|
|
|
* Nom de la vue a creer |
|
461
|
|
|
* @param string $query_select |
|
462
|
|
|
* Texte de la requete de selection servant de base a la vue |
|
463
|
|
|
* @param string $serveur |
|
464
|
|
|
* Nom du connecteur |
|
465
|
|
|
* @param bool $requeter |
|
466
|
|
|
* Effectuer la requete ? |
|
467
|
|
|
* - true pour executer |
|
468
|
|
|
* - false pour retourner le texte de la requete |
|
469
|
|
|
* @return bool|SQLiteResult|string |
|
470
|
|
|
* Resultat de la requete ou |
|
471
|
|
|
* - false si erreur ou si la vue existe deja |
|
472
|
|
|
* - string texte de la requete si $requeter vaut false |
|
473
|
|
|
*/ |
|
474
|
|
View Code Duplication |
function spip_sqlite_create_view($nom, $query_select, $serveur = '', $requeter = true){ |
|
|
|
|
|
|
475
|
|
|
if (!$query_select) return false; |
|
476
|
|
|
// vue deja presente |
|
477
|
|
|
if (sql_showtable($nom, false, $serveur)){ |
|
478
|
|
|
spip_log("Echec creation d'une vue sql ($nom) car celle-ci existe deja (serveur:$serveur)", 'sqlite.'._LOG_ERREUR); |
|
479
|
|
|
return false; |
|
480
|
|
|
} |
|
481
|
|
|
|
|
482
|
|
|
$query = "CREATE VIEW $nom AS ".$query_select; |
|
483
|
|
|
return spip_sqlite_query($query, $serveur, $requeter); |
|
484
|
|
|
} |
|
485
|
|
|
|
|
486
|
|
|
/** |
|
487
|
|
|
* Fonction de creation d'un INDEX |
|
488
|
|
|
* |
|
489
|
|
|
* @param string $nom : nom de l'index |
|
490
|
|
|
* @param string $table : table sql de l'index |
|
491
|
|
|
* @param string/array $champs : liste de champs sur lesquels s'applique l'index |
|
|
|
|
|
|
492
|
|
|
* @param string $serveur : nom de la connexion sql utilisee |
|
493
|
|
|
* @param bool $requeter : true pour executer la requete ou false pour retourner le texte de la requete |
|
494
|
|
|
* |
|
495
|
|
|
* @return bool ou requete |
|
|
|
|
|
|
496
|
|
|
*/ |
|
497
|
|
|
function spip_sqlite_create_index($nom, $table, $champs, $unique='', $serveur = '', $requeter = true){ |
|
498
|
|
View Code Duplication |
if (!($nom OR $table OR $champs)){ |
|
|
|
|
|
|
499
|
|
|
spip_log("Champ manquant pour creer un index sqlite ($nom, $table, (".join(',', $champs)."))", 'sqlite.'._LOG_ERREUR); |
|
500
|
|
|
return false; |
|
501
|
|
|
} |
|
502
|
|
|
|
|
503
|
|
|
// SQLite ne differentie pas noms des index en fonction des tables |
|
504
|
|
|
// il faut donc creer des noms uniques d'index pour une base sqlite |
|
505
|
|
|
$nom = $table.'_'.$nom; |
|
506
|
|
|
// enlever d'eventuelles parentheses deja presentes sur champs |
|
507
|
|
|
if (!is_array($champs)){ |
|
508
|
|
|
if ($champs[0]=="(") $champs = substr($champs, 1, -1); |
|
509
|
|
|
$champs = array($champs); |
|
510
|
|
|
// supprimer l'info de longueur d'index mysql en fin de champ |
|
511
|
|
|
$champs = preg_replace(",\(\d+\)$,","",$champs); |
|
512
|
|
|
} |
|
513
|
|
|
|
|
514
|
|
|
$ifnotexists = ""; |
|
515
|
|
|
$version = spip_sqlite_fetch(spip_sqlite_query("select sqlite_version() AS sqlite_version",$serveur),'',$serveur); |
|
516
|
|
|
if (!function_exists('spip_version_compare')) include_spip('plugins/installer'); |
|
517
|
|
|
|
|
518
|
|
View Code Duplication |
if ($version AND spip_version_compare($version['sqlite_version'],'3.3.0','>=')) { |
|
|
|
|
|
|
519
|
|
|
$ifnotexists = ' IF NOT EXISTS'; |
|
520
|
|
|
} else { |
|
521
|
|
|
/* simuler le IF EXISTS - version 2 et sqlite < 3.3a */ |
|
522
|
|
|
$a = spip_sqlite_showtable($table, $serveur); |
|
523
|
|
|
if (isset($a['key']['KEY '.$nom])) return true; |
|
524
|
|
|
} |
|
525
|
|
|
|
|
526
|
|
|
$query = "CREATE ".($unique?"UNIQUE ":"")."INDEX$ifnotexists $nom ON $table (".join(',', $champs).")"; |
|
527
|
|
|
$res = spip_sqlite_query($query, $serveur, $requeter); |
|
528
|
|
|
if (!$requeter) return $res; |
|
529
|
|
|
if ($res) |
|
|
|
|
|
|
530
|
|
|
return true; |
|
531
|
|
|
else |
|
532
|
|
|
return false; |
|
533
|
|
|
} |
|
534
|
|
|
|
|
535
|
|
|
/** |
|
536
|
|
|
* en PDO/sqlite3, il faut calculer le count par une requete count(*) |
|
537
|
|
|
* pour les resultats de SELECT |
|
538
|
|
|
* cela est fait sans spip_sqlite_query() |
|
539
|
|
|
* http://doc.spip.org/@spip_sqlite_count |
|
540
|
|
|
* |
|
541
|
|
|
* @param $r |
|
542
|
|
|
* @param string $serveur |
|
543
|
|
|
* @param bool $requeter |
|
544
|
|
|
* @return int |
|
545
|
|
|
*/ |
|
546
|
|
|
function spip_sqlite_count($r, $serveur = '', $requeter = true){ |
|
|
|
|
|
|
547
|
|
|
if (!$r) return 0; |
|
548
|
|
|
|
|
549
|
|
|
if (_sqlite_is_version(3, '', $serveur)){ |
|
550
|
|
|
// select ou autre (insert, update,...) ? |
|
551
|
|
|
|
|
552
|
|
|
// (link,requete) a compter |
|
553
|
|
|
if (is_array($r->spipSqliteRowCount)){ |
|
554
|
|
|
list($link,$query) = $r->spipSqliteRowCount; |
|
555
|
|
|
// amelioration possible a tester intensivement : pas de order by pour compter ! |
|
556
|
|
|
// $query = preg_replace(",ORDER BY .+(LIMIT\s|HAVING\s|GROUP BY\s|$),Uims","\\1",$query); |
|
557
|
|
|
$query = "SELECT count(*) as zzzzsqlitecount FROM ($query)"; |
|
558
|
|
|
$l = $link->query($query); |
|
559
|
|
|
$i = 0; |
|
560
|
|
|
if ($l AND $z = $l->fetch()) |
|
561
|
|
|
$i = $z['zzzzsqlitecount']; |
|
562
|
|
|
$r->spipSqliteRowCount = $i; |
|
563
|
|
|
} |
|
564
|
|
|
if (isset($r->spipSqliteRowCount)){ |
|
565
|
|
|
// Ce compte est faux s'il y a des limit dans la requete :( |
|
566
|
|
|
// il retourne le nombre d'enregistrements sans le limit |
|
567
|
|
|
return $r->spipSqliteRowCount; |
|
568
|
|
|
} else { |
|
569
|
|
|
return $r->rowCount(); |
|
570
|
|
|
} |
|
571
|
|
|
} else { |
|
572
|
|
|
return sqlite_num_rows($r); |
|
573
|
|
|
} |
|
574
|
|
|
} |
|
575
|
|
|
|
|
576
|
|
|
|
|
577
|
|
|
// http://doc.spip.org/@spip_sqlite_countsel |
|
578
|
|
|
function spip_sqlite_countsel($from = array(), $where = array(), $groupby = '', $having = array(), $serveur = '', $requeter = true){ |
|
579
|
|
|
$c = !$groupby ? '*' : ('DISTINCT '.(is_string($groupby) ? $groupby : join(',', $groupby))); |
|
580
|
|
|
$r = spip_sqlite_select("COUNT($c)", $from, $where, '', '', '', |
|
581
|
|
|
$having, $serveur, $requeter); |
|
582
|
|
|
if ((is_resource($r) or is_object($r)) && $requeter){ // ressource : sqlite2, object : sqlite3 |
|
583
|
|
|
if (_sqlite_is_version(3, '', $serveur)){ |
|
584
|
|
|
list($r) = spip_sqlite_fetch($r, SPIP_SQLITE3_NUM, $serveur); |
|
585
|
|
|
} else { |
|
586
|
|
|
list($r) = spip_sqlite_fetch($r, SPIP_SQLITE2_NUM, $serveur); |
|
587
|
|
|
} |
|
588
|
|
|
|
|
589
|
|
|
} |
|
590
|
|
|
return $r; |
|
591
|
|
|
} |
|
592
|
|
|
|
|
593
|
|
|
|
|
594
|
|
|
// http://doc.spip.org/@spip_sqlite_delete |
|
595
|
|
|
function spip_sqlite_delete($table, $where = '', $serveur = '', $requeter = true){ |
|
596
|
|
|
$res = spip_sqlite_query( |
|
597
|
|
|
_sqlite_calculer_expression('DELETE FROM', $table, ',') |
|
598
|
|
|
._sqlite_calculer_expression('WHERE', $where), |
|
599
|
|
|
$serveur, $requeter); |
|
600
|
|
|
|
|
601
|
|
|
// renvoyer la requete inerte si demandee |
|
602
|
|
|
if (!$requeter) return $res; |
|
603
|
|
|
|
|
604
|
|
|
if ($res){ |
|
605
|
|
|
$link = _sqlite_link($serveur); |
|
606
|
|
|
if (_sqlite_is_version(3, $link)){ |
|
607
|
|
|
return $res->rowCount(); |
|
608
|
|
|
} else { |
|
609
|
|
|
return sqlite_changes($link); |
|
610
|
|
|
} |
|
611
|
|
|
} |
|
612
|
|
|
else |
|
613
|
|
|
return false; |
|
614
|
|
|
} |
|
615
|
|
|
|
|
616
|
|
|
|
|
617
|
|
|
// http://doc.spip.org/@spip_sqlite_drop_table |
|
618
|
|
|
function spip_sqlite_drop_table($table, $exist = '', $serveur = '', $requeter = true){ |
|
619
|
|
|
if ($exist) $exist = " IF EXISTS"; |
|
620
|
|
|
|
|
621
|
|
|
/* simuler le IF EXISTS - version 2 */ |
|
622
|
|
View Code Duplication |
if ($exist && _sqlite_is_version(2, '', $serveur)){ |
|
|
|
|
|
|
623
|
|
|
$a = spip_sqlite_showtable($table, $serveur); |
|
624
|
|
|
if (!$a) return true; |
|
625
|
|
|
$exist = ''; |
|
626
|
|
|
} |
|
627
|
|
|
if (spip_sqlite_query("DROP TABLE$exist $table", $serveur, $requeter)) |
|
|
|
|
|
|
628
|
|
|
return true; |
|
629
|
|
|
else |
|
630
|
|
|
return false; |
|
631
|
|
|
} |
|
632
|
|
|
|
|
633
|
|
|
/** |
|
634
|
|
|
* supprime une vue |
|
635
|
|
|
* http://doc.spip.org/@spip_sqlite_drop_view |
|
636
|
|
|
* |
|
637
|
|
|
* @param $view |
|
638
|
|
|
* @param string $exist |
|
639
|
|
|
* @param string $serveur |
|
640
|
|
|
* @param bool $requeter |
|
641
|
|
|
* @return bool|SQLiteResult|string |
|
642
|
|
|
*/ |
|
643
|
|
|
function spip_sqlite_drop_view($view, $exist = '', $serveur = '', $requeter = true){ |
|
644
|
|
|
if ($exist) $exist = " IF EXISTS"; |
|
645
|
|
|
|
|
646
|
|
|
/* simuler le IF EXISTS - version 2 */ |
|
647
|
|
View Code Duplication |
if ($exist && _sqlite_is_version(2, '', $serveur)){ |
|
|
|
|
|
|
648
|
|
|
$a = spip_sqlite_showtable($view, $serveur); |
|
649
|
|
|
if (!$a) return true; |
|
650
|
|
|
$exist = ''; |
|
651
|
|
|
} |
|
652
|
|
|
|
|
653
|
|
|
return spip_sqlite_query("DROP VIEW$exist $view", $serveur, $requeter); |
|
654
|
|
|
} |
|
655
|
|
|
|
|
656
|
|
|
/** |
|
657
|
|
|
* Fonction de suppression d'un INDEX |
|
658
|
|
|
* |
|
659
|
|
|
* @param string $nom : nom de l'index |
|
660
|
|
|
* @param string $table : table sql de l'index |
|
661
|
|
|
* @param string $serveur : nom de la connexion sql utilisee |
|
662
|
|
|
* @param bool $requeter : true pour executer la requete ou false pour retourner le texte de la requete |
|
663
|
|
|
* |
|
664
|
|
|
* @return bool ou requete |
|
|
|
|
|
|
665
|
|
|
*/ |
|
666
|
|
|
function spip_sqlite_drop_index($nom, $table, $serveur = '', $requeter = true){ |
|
667
|
|
|
if (!($nom OR $table)){ |
|
668
|
|
|
spip_log("Champ manquant pour supprimer un index sqlite ($nom, $table)", 'sqlite.'._LOG_ERREUR); |
|
669
|
|
|
return false; |
|
670
|
|
|
} |
|
671
|
|
|
|
|
672
|
|
|
// SQLite ne differentie pas noms des index en fonction des tables |
|
673
|
|
|
// il faut donc creer des noms uniques d'index pour une base sqlite |
|
674
|
|
|
$index = $table.'_'.$nom; |
|
675
|
|
|
$exist = " IF EXISTS"; |
|
676
|
|
|
|
|
677
|
|
|
/* simuler le IF EXISTS - version 2 */ |
|
678
|
|
|
if (_sqlite_is_version(2, '', $serveur)){ |
|
679
|
|
|
$a = spip_sqlite_showtable($table, $serveur); |
|
680
|
|
|
if (!isset($a['key']['KEY '.$nom])) return true; |
|
681
|
|
|
$exist = ''; |
|
682
|
|
|
} |
|
683
|
|
|
|
|
684
|
|
|
$query = "DROP INDEX$exist $index"; |
|
685
|
|
|
return spip_sqlite_query($query, $serveur, $requeter); |
|
686
|
|
|
} |
|
687
|
|
|
|
|
688
|
|
|
/** |
|
689
|
|
|
* Retourne la dernière erreur generée |
|
690
|
|
|
* |
|
691
|
|
|
* @param $serveur |
|
692
|
|
|
* nom de la connexion |
|
693
|
|
|
* @return string |
|
694
|
|
|
* erreur eventuelle |
|
695
|
|
|
**/ |
|
696
|
|
View Code Duplication |
function spip_sqlite_error($query = '', $serveur = ''){ |
|
|
|
|
|
|
697
|
|
|
$link = _sqlite_link($serveur); |
|
698
|
|
|
|
|
699
|
|
|
if (_sqlite_is_version(3, $link)){ |
|
700
|
|
|
$errs = $link->errorInfo(); |
|
701
|
|
|
/* |
|
702
|
|
|
$errs[0] |
|
703
|
|
|
numero SQLState ('HY000' souvent lors d'une erreur) |
|
704
|
|
|
http://www.easysoft.com/developer/interfaces/odbc/sqlstate_status_return_codes.html |
|
705
|
|
|
$errs[1] |
|
706
|
|
|
numéro d'erreur SQLite (souvent 1 lors d'une erreur) |
|
707
|
|
|
http://www.sqlite.org/c3ref/c_abort.html |
|
708
|
|
|
$errs[2] |
|
709
|
|
|
Le texte du message d'erreur |
|
710
|
|
|
*/ |
|
711
|
|
|
$s = ''; |
|
712
|
|
|
if (ltrim($errs[0],'0')) { // 00000 si pas d'erreur |
|
713
|
|
|
$s = "$errs[2]"; |
|
714
|
|
|
} |
|
715
|
|
|
} elseif ($link) { |
|
716
|
|
|
$s = sqlite_error_string(sqlite_last_error($link)); |
|
717
|
|
|
} else { |
|
718
|
|
|
$s = ": aucune ressource sqlite (link)"; |
|
719
|
|
|
} |
|
720
|
|
|
if ($s) spip_log("$s - $query", 'sqlite.'._LOG_ERREUR); |
|
721
|
|
|
return $s; |
|
722
|
|
|
} |
|
723
|
|
|
|
|
724
|
|
|
/** |
|
725
|
|
|
* Retourne le numero de la dernière erreur SQL |
|
726
|
|
|
* |
|
727
|
|
|
* Le numéro (en sqlite3/pdo) est un retour ODBC tel que (très souvent) HY000 |
|
728
|
|
|
* http://www.easysoft.com/developer/interfaces/odbc/sqlstate_status_return_codes.html |
|
729
|
|
|
* |
|
730
|
|
|
* @param string $serveur |
|
731
|
|
|
* nom de la connexion |
|
732
|
|
|
* @return int|string |
|
733
|
|
|
* 0 pas d'erreur |
|
734
|
|
|
* 1 ou autre erreur (en sqlite 2) |
|
735
|
|
|
* 'HY000/1' : numéro de l'erreur SQLState / numéro d'erreur interne SQLite (en sqlite 3) |
|
736
|
|
|
**/ |
|
737
|
|
View Code Duplication |
function spip_sqlite_errno($serveur = ''){ |
|
|
|
|
|
|
738
|
|
|
$link = _sqlite_link($serveur); |
|
739
|
|
|
|
|
740
|
|
|
if (_sqlite_is_version(3, $link)){ |
|
741
|
|
|
$t = $link->errorInfo(); |
|
742
|
|
|
$s = ltrim($t[0],'0'); // 00000 si pas d'erreur |
|
743
|
|
|
if ($s) $s .= ' / ' . $t[1]; // ajoute l'erreur du moteur SQLite |
|
744
|
|
|
} elseif ($link) { |
|
745
|
|
|
$s = sqlite_last_error($link); |
|
746
|
|
|
} else { |
|
747
|
|
|
$s = ": aucune ressource sqlite (link)"; |
|
748
|
|
|
} |
|
749
|
|
|
|
|
750
|
|
|
if ($s) spip_log("Erreur sqlite $s", 'sqlite.'._LOG_ERREUR); |
|
751
|
|
|
|
|
752
|
|
|
return $s ? $s : 0; |
|
753
|
|
|
} |
|
754
|
|
|
|
|
755
|
|
|
|
|
756
|
|
|
// http://doc.spip.org/@spip_sqlite_explain |
|
757
|
|
|
function spip_sqlite_explain($query, $serveur = '', $requeter = true){ |
|
758
|
|
|
if (strpos(ltrim($query), 'SELECT')!==0) return array(); |
|
759
|
|
|
|
|
760
|
|
|
$query = spip_sqlite::traduire_requete($query, $serveur); |
|
761
|
|
|
$query = 'EXPLAIN '.$query; |
|
762
|
|
|
if (!$requeter) return $query; |
|
763
|
|
|
// on ne trace pas ces requetes, sinon on obtient un tracage sans fin... |
|
764
|
|
|
$r = spip_sqlite::executer_requete($query, $serveur, false); |
|
765
|
|
|
|
|
766
|
|
|
return $r ? spip_sqlite_fetch($r, null, $serveur) : false; // hum ? etrange ca... a verifier |
|
767
|
|
|
} |
|
768
|
|
|
|
|
769
|
|
|
|
|
770
|
|
|
// http://doc.spip.org/@spip_sqlite_fetch |
|
771
|
|
|
function spip_sqlite_fetch($r, $t = '', $serveur = '', $requeter = true){ |
|
|
|
|
|
|
772
|
|
|
|
|
773
|
|
|
$link = _sqlite_link($serveur); |
|
774
|
|
|
$is_v3 = _sqlite_is_version(3, $link); |
|
775
|
|
|
if (!$t) |
|
776
|
|
|
$t = ($is_v3 ? SPIP_SQLITE3_ASSOC : SPIP_SQLITE2_ASSOC); |
|
777
|
|
|
|
|
778
|
|
|
$retour = false; |
|
779
|
|
|
if ($r) |
|
780
|
|
|
$retour = ($is_v3 ? $r->fetch($t) : sqlite_fetch_array($r, $t)); |
|
781
|
|
|
|
|
782
|
|
|
// les version 2 et 3 parfois renvoie des 'table.titre' au lieu de 'titre' tout court ! pff ! |
|
783
|
|
|
// suppression de 'table.' pour toutes les cles (c'est un peu violent !) |
|
784
|
|
|
// c'est couteux : on ne verifie que la premiere ligne pour voir si on le fait ou non |
|
785
|
|
|
if ($retour |
|
786
|
|
|
AND strpos(implode('',array_keys($retour)),'.')!==false){ |
|
787
|
|
|
foreach ($retour as $cle => $val){ |
|
788
|
|
|
if (($pos = strpos($cle, '.'))!==false){ |
|
789
|
|
|
$retour[substr($cle, $pos+1)] = &$retour[$cle]; |
|
790
|
|
|
unset($retour[$cle]); |
|
791
|
|
|
} |
|
792
|
|
|
} |
|
793
|
|
|
} |
|
794
|
|
|
|
|
795
|
|
|
return $retour; |
|
796
|
|
|
} |
|
797
|
|
|
|
|
798
|
|
|
|
|
799
|
|
|
function spip_sqlite_seek($r, $row_number, $serveur = '', $requeter = true){ |
|
|
|
|
|
|
800
|
|
|
if ($r){ |
|
801
|
|
|
$link = _sqlite_link($serveur); |
|
802
|
|
|
if (_sqlite_is_version(3, $link)){ |
|
803
|
|
|
// encore un truc de bien fichu : PDO ne PEUT PAS faire de seek ou de rewind... |
|
804
|
|
|
// je me demande si pour sqlite 3 il ne faudrait pas mieux utiliser |
|
805
|
|
|
// les nouvelles fonctions sqlite3_xx (mais encore moins presentes...) |
|
806
|
|
|
return false; |
|
807
|
|
|
} |
|
808
|
|
|
else { |
|
809
|
|
|
return sqlite_seek($r, $row_number); |
|
810
|
|
|
} |
|
811
|
|
|
} |
|
812
|
|
|
} |
|
813
|
|
|
|
|
814
|
|
|
|
|
815
|
|
|
// http://doc.spip.org/@spip_sqlite_free |
|
816
|
|
|
function spip_sqlite_free(&$r, $serveur = '', $requeter = true){ |
|
|
|
|
|
|
817
|
|
|
unset($r); |
|
818
|
|
|
return true; |
|
819
|
|
|
//return sqlite_free_result($r); |
|
820
|
|
|
} |
|
821
|
|
|
|
|
822
|
|
|
|
|
823
|
|
|
// http://doc.spip.org/@spip_sqlite_get_charset |
|
824
|
|
|
function spip_sqlite_get_charset($charset = array(), $serveur = '', $requeter = true){ |
|
|
|
|
|
|
825
|
|
|
//$c = !$charset ? '' : (" LIKE "._q($charset['charset'])); |
|
826
|
|
|
//return spip_sqlite_fetch(sqlite_query(_sqlite_link($serveur), "SHOW CHARACTER SET$c"), NULL, $serveur); |
|
827
|
|
|
} |
|
828
|
|
|
|
|
829
|
|
|
|
|
830
|
|
|
// http://doc.spip.org/@spip_sqlite_hex |
|
831
|
|
|
function spip_sqlite_hex($v){ |
|
832
|
|
|
return hexdec($v); |
|
833
|
|
|
} |
|
834
|
|
|
|
|
835
|
|
|
|
|
836
|
|
|
// http://doc.spip.org/@spip_sqlite_in |
|
837
|
|
View Code Duplication |
function spip_sqlite_in($val, $valeurs, $not = '', $serveur = '', $requeter = true){ |
|
|
|
|
|
|
838
|
|
|
$n = $i = 0; |
|
839
|
|
|
$in_sql = ""; |
|
840
|
|
|
while ($n = strpos($valeurs, ',', $n+1)){ |
|
841
|
|
|
if ((++$i)>=255){ |
|
842
|
|
|
$in_sql .= "($val $not IN (". |
|
843
|
|
|
substr($valeurs, 0, $n). |
|
844
|
|
|
"))\n". |
|
845
|
|
|
($not ? "AND\t" : "OR\t"); |
|
846
|
|
|
$valeurs = substr($valeurs, $n+1); |
|
847
|
|
|
$i = $n = 0; |
|
848
|
|
|
} |
|
849
|
|
|
} |
|
850
|
|
|
$in_sql .= "($val $not IN ($valeurs))"; |
|
851
|
|
|
|
|
852
|
|
|
return "($in_sql)"; |
|
853
|
|
|
} |
|
854
|
|
|
|
|
855
|
|
|
|
|
856
|
|
|
// http://doc.spip.org/@spip_sqlite_insert |
|
857
|
|
|
function spip_sqlite_insert($table, $champs, $valeurs, $desc = '', $serveur = '', $requeter = true){ |
|
|
|
|
|
|
858
|
|
|
|
|
859
|
|
|
$query = "INSERT INTO $table ".($champs ? "$champs VALUES $valeurs" : "DEFAULT VALUES"); |
|
860
|
|
|
if ($r = spip_sqlite_query($query, $serveur, $requeter)){ |
|
861
|
|
|
if (!$requeter) return $r; |
|
862
|
|
|
$nb = spip_sqlite::last_insert_id($serveur); |
|
863
|
|
|
} |
|
864
|
|
|
else |
|
865
|
|
|
$nb = 0; |
|
866
|
|
|
|
|
867
|
|
|
$err = spip_sqlite_error($query, $serveur); |
|
|
|
|
|
|
868
|
|
|
// cas particulier : ne pas substituer la reponse spip_sqlite_query si on est en profilage |
|
869
|
|
|
return isset($_GET['var_profile']) ? $r : $nb; |
|
870
|
|
|
|
|
871
|
|
|
} |
|
872
|
|
|
|
|
873
|
|
|
|
|
874
|
|
|
// http://doc.spip.org/@spip_sqlite_insertq |
|
875
|
|
|
function spip_sqlite_insertq($table, $couples = array(), $desc = array(), $serveur = '', $requeter = true){ |
|
876
|
|
|
if (!$desc) $desc = description_table($table, $serveur); |
|
|
|
|
|
|
877
|
|
|
if (!$desc) die("$table insertion sans description"); |
|
|
|
|
|
|
878
|
|
|
$fields = isset($desc['field']) ? $desc['field'] : array(); |
|
879
|
|
|
|
|
880
|
|
|
foreach ($couples as $champ => $val){ |
|
881
|
|
|
$couples[$champ] = _sqlite_calculer_cite($val, $fields[$champ]); |
|
882
|
|
|
} |
|
883
|
|
|
|
|
884
|
|
|
// recherche de champs 'timestamp' pour mise a jour auto de ceux-ci |
|
885
|
|
|
$couples = _sqlite_ajouter_champs_timestamp($table, $couples, $desc, $serveur); |
|
886
|
|
|
|
|
887
|
|
|
$cles = $valeurs = ""; |
|
888
|
|
|
if (count($couples)){ |
|
889
|
|
|
$cles = "(".join(',', array_keys($couples)).")"; |
|
890
|
|
|
$valeurs = "(".join(',', $couples).")"; |
|
891
|
|
|
} |
|
892
|
|
|
|
|
893
|
|
|
return spip_sqlite_insert($table, $cles, $valeurs, $desc, $serveur, $requeter); |
|
894
|
|
|
} |
|
895
|
|
|
|
|
896
|
|
|
|
|
897
|
|
|
// http://doc.spip.org/@spip_sqlite_insertq_multi |
|
898
|
|
|
function spip_sqlite_insertq_multi($table, $tab_couples = array(), $desc = array(), $serveur = '', $requeter = true){ |
|
899
|
|
|
if (!$desc) $desc = description_table($table, $serveur); |
|
|
|
|
|
|
900
|
|
|
if (!$desc) die("$table insertion sans description"); |
|
|
|
|
|
|
901
|
|
|
if (!isset($desc['field'])) |
|
902
|
|
|
$desc['field'] = array(); |
|
903
|
|
|
|
|
904
|
|
|
// recuperer les champs 'timestamp' pour mise a jour auto de ceux-ci |
|
905
|
|
|
$maj = _sqlite_ajouter_champs_timestamp($table, array(), $desc, $serveur); |
|
906
|
|
|
|
|
907
|
|
|
// seul le nom de la table est a traduire ici : |
|
908
|
|
|
// le faire une seule fois au debut |
|
909
|
|
|
$query_start = "INSERT INTO $table "; |
|
910
|
|
|
$query_start = spip_sqlite::traduire_requete($query_start,$serveur); |
|
911
|
|
|
|
|
912
|
|
|
// ouvrir une transaction |
|
913
|
|
|
if ($requeter) |
|
914
|
|
|
spip_sqlite::demarrer_transaction($serveur); |
|
915
|
|
|
|
|
916
|
|
|
while ($couples = array_shift($tab_couples)){ |
|
917
|
|
|
foreach ($couples as $champ => $val){ |
|
918
|
|
|
$couples[$champ] = _sqlite_calculer_cite($val, $desc['field'][$champ]); |
|
919
|
|
|
} |
|
920
|
|
|
|
|
921
|
|
|
// inserer les champs timestamp par defaut |
|
922
|
|
|
$couples = array_merge($maj,$couples); |
|
923
|
|
|
|
|
924
|
|
|
$champs = $valeurs = ""; |
|
|
|
|
|
|
925
|
|
|
if (count($couples)){ |
|
926
|
|
|
$champs = "(".join(',', array_keys($couples)).")"; |
|
927
|
|
|
$valeurs = "(".join(',', $couples).")"; |
|
928
|
|
|
$query = $query_start."$champs VALUES $valeurs"; |
|
929
|
|
|
} |
|
930
|
|
|
else |
|
931
|
|
|
$query = $query_start."DEFAULT VALUES"; |
|
932
|
|
|
|
|
933
|
|
|
if ($requeter) |
|
934
|
|
|
$retour = spip_sqlite::executer_requete($query,$serveur); |
|
935
|
|
|
|
|
936
|
|
|
// sur le dernier couple uniquement |
|
937
|
|
|
if (!count($tab_couples)){ |
|
938
|
|
|
$nb = 0; |
|
|
|
|
|
|
939
|
|
|
if ($requeter) |
|
940
|
|
|
$nb = spip_sqlite::last_insert_id($serveur); |
|
941
|
|
|
else |
|
942
|
|
|
return $query; |
|
943
|
|
|
} |
|
944
|
|
|
|
|
945
|
|
|
$err = spip_sqlite_error($query, $serveur); |
|
|
|
|
|
|
946
|
|
|
} |
|
947
|
|
|
|
|
948
|
|
|
if ($requeter) |
|
949
|
|
|
spip_sqlite::finir_transaction($serveur); |
|
950
|
|
|
|
|
951
|
|
|
// renvoie le dernier id d'autoincrement ajoute |
|
952
|
|
|
// cas particulier : ne pas substituer la reponse spip_sqlite_query si on est en profilage |
|
953
|
|
|
return isset($_GET['var_profile']) ? $retour : $nb; |
|
|
|
|
|
|
954
|
|
|
} |
|
955
|
|
|
|
|
956
|
|
|
|
|
957
|
|
|
/** |
|
958
|
|
|
* Retourne si le moteur SQL prefere utiliser des transactions. |
|
959
|
|
|
* |
|
960
|
|
|
* @param |
|
961
|
|
|
* @return bool true / false |
|
962
|
|
|
**/ |
|
963
|
|
|
function spip_sqlite_preferer_transaction($serveur = '', $requeter = true) { |
|
|
|
|
|
|
964
|
|
|
return true; |
|
965
|
|
|
} |
|
966
|
|
|
|
|
967
|
|
|
/** |
|
968
|
|
|
* Demarre une transaction. |
|
969
|
|
|
* Pratique pour des sql_updateq() dans un foreach, |
|
970
|
|
|
* parfois 100* plus rapide s'ils sont nombreux en sqlite ! |
|
971
|
|
|
* |
|
972
|
|
|
**/ |
|
973
|
|
|
function spip_sqlite_demarrer_transaction($serveur = '', $requeter = true) { |
|
974
|
|
|
if (!$requeter) return "BEGIN TRANSACTION"; |
|
975
|
|
|
spip_sqlite::demarrer_transaction($serveur); |
|
976
|
|
|
return true; |
|
977
|
|
|
} |
|
978
|
|
|
|
|
979
|
|
|
/** |
|
980
|
|
|
* Cloture une transaction. |
|
981
|
|
|
* |
|
982
|
|
|
**/ |
|
983
|
|
|
function spip_sqlite_terminer_transaction($serveur = '', $requeter = true) { |
|
984
|
|
|
if (!$requeter) return "COMMIT"; |
|
985
|
|
|
spip_sqlite::finir_transaction($serveur); |
|
986
|
|
|
return true; |
|
987
|
|
|
} |
|
988
|
|
|
|
|
989
|
|
|
|
|
990
|
|
|
// http://doc.spip.org/@spip_sqlite_listdbs |
|
991
|
|
|
function spip_sqlite_listdbs($serveur = '', $requeter = true){ |
|
|
|
|
|
|
992
|
|
|
_sqlite_init(); |
|
993
|
|
|
|
|
994
|
|
|
if (!is_dir($d = substr(_DIR_DB, 0, -1))){ |
|
995
|
|
|
return array(); |
|
996
|
|
|
} |
|
997
|
|
|
|
|
998
|
|
|
include_spip('inc/flock'); |
|
999
|
|
|
$bases = preg_files($d, $pattern = '(.*)\.sqlite$'); |
|
1000
|
|
|
$bds = array(); |
|
1001
|
|
|
|
|
1002
|
|
|
foreach ($bases as $b){ |
|
1003
|
|
|
// pas de bases commencant pas sqlite |
|
1004
|
|
|
// (on s'en sert pour l'installation pour simuler la presence d'un serveur) |
|
1005
|
|
|
// les bases sont de la forme _sqliteX_tmp_spip_install.sqlite |
|
1006
|
|
|
if (strpos($b, '_sqlite')) continue; |
|
1007
|
|
|
$bds[] = preg_replace(";.*/$pattern;iS", '$1', $b); |
|
1008
|
|
|
} |
|
1009
|
|
|
|
|
1010
|
|
|
return $bds; |
|
1011
|
|
|
} |
|
1012
|
|
|
|
|
1013
|
|
|
|
|
1014
|
|
|
// http://doc.spip.org/@spip_sqlite_multi |
|
1015
|
|
|
function spip_sqlite_multi($objet, $lang){ |
|
1016
|
|
|
$r = "EXTRAIRE_MULTI(" . $objet . ", '" . $lang . "') AS multi"; |
|
1017
|
|
|
return $r; |
|
1018
|
|
|
} |
|
1019
|
|
|
|
|
1020
|
|
|
|
|
1021
|
|
|
/** |
|
1022
|
|
|
* Optimise une table SQL |
|
1023
|
|
|
* Note: Sqlite optimise TOUTE un fichier sinon rien. |
|
1024
|
|
|
* On evite donc 2 traitements sur la meme base dans un hit. |
|
1025
|
|
|
* |
|
1026
|
|
|
* @param $table nom de la table a optimiser |
|
1027
|
|
|
* @param $serveur nom de la connexion |
|
1028
|
|
|
* @param $requeter effectuer la requete ? sinon retourner son code |
|
1029
|
|
|
* @return bool|string true / false / requete |
|
1030
|
|
|
**/ |
|
1031
|
|
|
// http://doc.spip.org/@spip_sqlite_optimize |
|
1032
|
|
|
function spip_sqlite_optimize($table, $serveur = '', $requeter = true){ |
|
|
|
|
|
|
1033
|
|
|
static $do = false; |
|
1034
|
|
|
if ($requeter and $do){ |
|
1035
|
|
|
return true; |
|
1036
|
|
|
} |
|
1037
|
|
|
if ($requeter){ |
|
1038
|
|
|
$do = true; |
|
1039
|
|
|
} |
|
1040
|
|
|
return spip_sqlite_query("VACUUM", $serveur, $requeter); |
|
1041
|
|
|
} |
|
1042
|
|
|
|
|
1043
|
|
|
|
|
1044
|
|
|
// |
|
1045
|
|
|
/** |
|
1046
|
|
|
* echapper une valeur selon son type ou au mieux |
|
1047
|
|
|
* comme le fait _q() mais pour sqlite avec ses specificites |
|
1048
|
|
|
* |
|
1049
|
|
|
* @param string|array|number $v |
|
1050
|
|
|
* @param string $type |
|
1051
|
|
|
* @return string|number |
|
1052
|
|
|
*/ |
|
1053
|
|
View Code Duplication |
function spip_sqlite_quote($v, $type = ''){ |
|
|
|
|
|
|
1054
|
|
|
if (!is_array($v)) |
|
1055
|
|
|
return _sqlite_calculer_cite($v,$type); |
|
1056
|
|
|
// si c'est un tableau, le parcourir en propageant le type |
|
1057
|
|
|
foreach($v as $k=>$r) |
|
1058
|
|
|
$v[$k] = spip_sqlite_quote($r, $type); |
|
1059
|
|
|
return join(",", $v); |
|
1060
|
|
|
} |
|
1061
|
|
|
|
|
1062
|
|
|
|
|
1063
|
|
|
/** |
|
1064
|
|
|
* Tester si une date est proche de la valeur d'un champ |
|
1065
|
|
|
* |
|
1066
|
|
|
* @param string $champ le nom du champ a tester |
|
1067
|
|
|
* @param int $interval valeur de l'interval : -1, 4, ... |
|
1068
|
|
|
* @param string $unite utite utilisee (DAY, MONTH, YEAR, ...) |
|
1069
|
|
|
* @return string expression SQL |
|
1070
|
|
|
**/ |
|
1071
|
|
|
function spip_sqlite_date_proche($champ, $interval, $unite){ |
|
1072
|
|
|
$op = (($interval <= 0) ? '>' : '<'); |
|
1073
|
|
|
return "($champ $op datetime('".date("Y-m-d H:i:s")."', '$interval $unite'))"; |
|
1074
|
|
|
} |
|
1075
|
|
|
|
|
1076
|
|
|
|
|
1077
|
|
|
// http://doc.spip.org/@spip_sqlite_replace |
|
1078
|
|
|
function spip_sqlite_replace($table, $couples, $desc = array(), $serveur = '', $requeter = true){ |
|
|
|
|
|
|
1079
|
|
|
if (!$desc) $desc = description_table($table, $serveur); |
|
|
|
|
|
|
1080
|
|
|
if (!$desc) die("$table insertion sans description"); |
|
|
|
|
|
|
1081
|
|
|
$fields = isset($desc['field']) ? $desc['field'] : array(); |
|
1082
|
|
|
|
|
1083
|
|
|
foreach ($couples as $champ => $val){ |
|
1084
|
|
|
$couples[$champ] = _sqlite_calculer_cite($val, $fields[$champ]); |
|
1085
|
|
|
} |
|
1086
|
|
|
|
|
1087
|
|
|
// recherche de champs 'timestamp' pour mise a jour auto de ceux-ci |
|
1088
|
|
|
$couples = _sqlite_ajouter_champs_timestamp($table, $couples, $desc, $serveur); |
|
1089
|
|
|
|
|
1090
|
|
|
return spip_sqlite_query("REPLACE INTO $table (".join(',', array_keys($couples)).') VALUES ('.join(',', $couples).')', $serveur); |
|
1091
|
|
|
} |
|
1092
|
|
|
|
|
1093
|
|
|
|
|
1094
|
|
|
// http://doc.spip.org/@spip_sqlite_replace_multi |
|
1095
|
|
|
function spip_sqlite_replace_multi($table, $tab_couples, $desc = array(), $serveur = '', $requeter = true){ |
|
1096
|
|
|
|
|
1097
|
|
|
// boucler pour trainter chaque requete independemment |
|
1098
|
|
|
foreach ($tab_couples as $couples){ |
|
1099
|
|
|
$retour = spip_sqlite_replace($table, $couples, $desc, $serveur, $requeter); |
|
1100
|
|
|
} |
|
1101
|
|
|
// renvoie le dernier id |
|
1102
|
|
|
return $retour; |
|
|
|
|
|
|
1103
|
|
|
} |
|
1104
|
|
|
|
|
1105
|
|
|
|
|
1106
|
|
|
// http://doc.spip.org/@spip_sqlite_select |
|
1107
|
|
|
function spip_sqlite_select($select, $from, $where = '', $groupby = '', $orderby = '', $limit = '', $having = '', $serveur = '', $requeter = true){ |
|
1108
|
|
|
|
|
1109
|
|
|
// version() n'est pas connu de sqlite |
|
1110
|
|
|
$select = str_replace('version()', 'sqlite_version()', $select); |
|
1111
|
|
|
|
|
1112
|
|
|
// recomposer from |
|
1113
|
|
|
$from = (!is_array($from) ? $from : _sqlite_calculer_select_as($from)); |
|
1114
|
|
|
|
|
1115
|
|
|
$query = |
|
1116
|
|
|
_sqlite_calculer_expression('SELECT', $select, ', ') |
|
1117
|
|
|
._sqlite_calculer_expression('FROM', $from, ', ') |
|
1118
|
|
|
._sqlite_calculer_expression('WHERE', $where) |
|
1119
|
|
|
._sqlite_calculer_expression('GROUP BY', $groupby, ',') |
|
1120
|
|
|
._sqlite_calculer_expression('HAVING', $having) |
|
1121
|
|
|
.($orderby ? ("\nORDER BY "._sqlite_calculer_order($orderby)) : '') |
|
1122
|
|
|
.($limit ? "\nLIMIT $limit" : ''); |
|
1123
|
|
|
|
|
1124
|
|
|
// dans un select, on doit renvoyer la requête en cas d'erreur |
|
1125
|
|
|
$res = spip_sqlite_query($query, $serveur, $requeter); |
|
1126
|
|
|
// texte de la requete demande ? |
|
1127
|
|
|
if (!$requeter) return $res; |
|
1128
|
|
|
// erreur survenue ? |
|
1129
|
|
|
if ($res === false) { |
|
1130
|
|
|
return spip_sqlite::traduire_requete($query, $serveur); |
|
1131
|
|
|
} |
|
1132
|
|
|
return $res; |
|
1133
|
|
|
} |
|
1134
|
|
|
|
|
1135
|
|
|
|
|
1136
|
|
|
/** |
|
1137
|
|
|
* Selectionne un fichier de base de donnees |
|
1138
|
|
|
* |
|
1139
|
|
|
* @param string $nom |
|
|
|
|
|
|
1140
|
|
|
* Nom de la base a utiliser |
|
1141
|
|
|
* @param string $serveur |
|
1142
|
|
|
* Nom du connecteur |
|
1143
|
|
|
* @param bool $requeter |
|
1144
|
|
|
* Inutilise |
|
1145
|
|
|
* |
|
1146
|
|
|
* @return bool|string |
|
1147
|
|
|
* Nom de la base en cas de success. |
|
1148
|
|
|
* False en cas d'erreur. |
|
1149
|
|
|
**/ |
|
1150
|
|
|
function spip_sqlite_selectdb($db, $serveur = '', $requeter = true){ |
|
|
|
|
|
|
1151
|
|
|
_sqlite_init(); |
|
1152
|
|
|
|
|
1153
|
|
|
// interdire la creation d'une nouvelle base, |
|
1154
|
|
|
// sauf si on est dans l'installation |
|
1155
|
|
|
if (!is_file($f = _DIR_DB.$db.'.sqlite') |
|
1156
|
|
|
&& (!defined('_ECRIRE_INSTALL') || !_ECRIRE_INSTALL)){ |
|
1157
|
|
|
spip_log("Il est interdit de creer la base $db", 'sqlite.'._LOG_HS); |
|
1158
|
|
|
return false; |
|
1159
|
|
|
} |
|
1160
|
|
|
|
|
1161
|
|
|
// se connecter a la base indiquee |
|
1162
|
|
|
// avec les identifiants connus |
|
1163
|
|
|
$index = $serveur ? $serveur : 0; |
|
1164
|
|
|
|
|
1165
|
|
|
if ($link = spip_connect_db('', '', '', '', '@selectdb@'.$db, $serveur, '', '')){ |
|
1166
|
|
View Code Duplication |
if (($db==$link['db']) && $GLOBALS['connexions'][$index] = $link) |
|
|
|
|
|
|
1167
|
|
|
return $db; |
|
1168
|
|
|
} else { |
|
1169
|
|
|
spip_log("Impossible de selectionner la base $db", 'sqlite.'._LOG_HS); |
|
1170
|
|
|
return false; |
|
1171
|
|
|
} |
|
1172
|
|
|
|
|
1173
|
|
|
} |
|
1174
|
|
|
|
|
1175
|
|
|
|
|
1176
|
|
|
// http://doc.spip.org/@spip_sqlite_set_charset |
|
1177
|
|
|
function spip_sqlite_set_charset($charset, $serveur = '', $requeter = true){ |
|
|
|
|
|
|
1178
|
|
|
# spip_log("Gestion charset sql a ecrire : "."SET NAMES "._q($charset), 'sqlite.'._LOG_ERREUR); |
|
1179
|
|
|
# return spip_sqlite_query("SET NAMES ". spip_sqlite_quote($charset), $serveur); //<-- Passe pas ! |
|
1180
|
|
|
} |
|
1181
|
|
|
|
|
1182
|
|
|
|
|
1183
|
|
|
/** |
|
1184
|
|
|
* Retourne une ressource de la liste des tables de la base de données |
|
1185
|
|
|
* |
|
1186
|
|
|
* @param string $match |
|
1187
|
|
|
* Filtre sur tables à récupérer |
|
1188
|
|
|
* @param string $serveur |
|
1189
|
|
|
* Connecteur de la base |
|
1190
|
|
|
* @param bool $requeter |
|
1191
|
|
|
* true pour éxecuter la requête |
|
1192
|
|
|
* false pour retourner le texte de la requête. |
|
1193
|
|
|
* @return ressource |
|
|
|
|
|
|
1194
|
|
|
* Ressource à utiliser avec sql_fetch() |
|
1195
|
|
|
**/ |
|
1196
|
|
|
function spip_sqlite_showbase($match, $serveur = '', $requeter = true){ |
|
1197
|
|
|
// type est le type d'entrée : table / index / view |
|
1198
|
|
|
// on ne retourne que les tables (?) et non les vues... |
|
1199
|
|
|
# ESCAPE non supporte par les versions sqlite <3 |
|
1200
|
|
|
# return spip_sqlite_query("SELECT name FROM sqlite_master WHERE type='table' AND tbl_name LIKE "._q($match)." ESCAPE '\'", $serveur, $requeter); |
|
1201
|
|
|
$match = preg_quote($match); |
|
1202
|
|
|
$match = str_replace("\\\_", "[[TIRETBAS]]", $match); |
|
1203
|
|
|
$match = str_replace("\\\%", "[[POURCENT]]", $match); |
|
1204
|
|
|
$match = str_replace("_", ".", $match); |
|
1205
|
|
|
$match = str_replace("%", ".*", $match); |
|
1206
|
|
|
$match = str_replace("[[TIRETBAS]]", "_", $match); |
|
1207
|
|
|
$match = str_replace("[[POURCENT]]", "%", $match); |
|
1208
|
|
|
$match = "^$match$"; |
|
1209
|
|
|
return spip_sqlite_query("SELECT name FROM sqlite_master WHERE type='table' AND tbl_name REGEXP "._q($match), $serveur, $requeter); |
|
1210
|
|
|
} |
|
1211
|
|
|
|
|
1212
|
|
|
define('_SQLITE_RE_SHOW_TABLE', '/^[^(),]*\(((?:[^()]*\((?:[^()]*\([^()]*\))?[^()]*\)[^()]*)*[^()]*)\)[^()]*$/'); |
|
1213
|
|
|
// http://doc.spip.org/@spip_sqlite_showtable |
|
1214
|
|
|
function spip_sqlite_showtable($nom_table, $serveur = '', $requeter = true){ |
|
1215
|
|
|
$query = |
|
1216
|
|
|
'SELECT sql, type FROM' |
|
1217
|
|
|
.' (SELECT * FROM sqlite_master UNION ALL' |
|
1218
|
|
|
.' SELECT * FROM sqlite_temp_master)' |
|
1219
|
|
|
." WHERE tbl_name LIKE '$nom_table'" |
|
1220
|
|
|
." AND type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%'" |
|
1221
|
|
|
.' ORDER BY substr(type,2,1), name'; |
|
1222
|
|
|
|
|
1223
|
|
|
$a = spip_sqlite_query($query, $serveur, $requeter); |
|
1224
|
|
|
if (!$a) return ""; |
|
1225
|
|
|
if (!$requeter) return $a; |
|
1226
|
|
|
if (!($a = spip_sqlite_fetch($a, null, $serveur))) return ""; |
|
1227
|
|
|
$vue = ($a['type']=='view'); // table | vue |
|
1228
|
|
|
|
|
1229
|
|
|
// c'est une table |
|
1230
|
|
|
// il faut parser le create |
|
1231
|
|
|
if (!$vue){ |
|
1232
|
|
|
if (!preg_match(_SQLITE_RE_SHOW_TABLE, array_shift($a), $r)){ |
|
1233
|
|
|
return ""; |
|
1234
|
|
|
} else { |
|
1235
|
|
|
$desc = $r[1]; |
|
1236
|
|
|
// extraction d'une KEY éventuelle en prenant garde de ne pas |
|
1237
|
|
|
// relever un champ dont le nom contient KEY (ex. ID_WHISKEY) |
|
1238
|
|
View Code Duplication |
if (preg_match("/^(.*?),([^,]*\sKEY[ (].*)$/s", $desc, $r)){ |
|
|
|
|
|
|
1239
|
|
|
$namedkeys = $r[2]; |
|
1240
|
|
|
$desc = $r[1]; |
|
1241
|
|
|
} |
|
1242
|
|
|
else |
|
1243
|
|
|
$namedkeys = ""; |
|
1244
|
|
|
|
|
1245
|
|
|
$fields = array(); |
|
1246
|
|
|
$keys = array(); |
|
1247
|
|
|
|
|
1248
|
|
|
// enlever les contenus des valeurs DEFAULT 'xxx' qui pourraient perturber |
|
1249
|
|
|
// par exemple s'il contiennent une virgule. |
|
1250
|
|
|
// /!\ cela peut aussi echapper le nom des champs si la table a eu des operations avec SQLite Manager ! |
|
1251
|
|
|
list($desc, $echaps) = query_echappe_textes($desc); |
|
1252
|
|
|
|
|
1253
|
|
|
// separer toutes les descriptions de champs, separes par des virgules |
|
1254
|
|
|
# /!\ explode peut exploser aussi DECIMAL(10,2) ! |
|
1255
|
|
|
$k_precedent = null; |
|
1256
|
|
|
foreach (explode(",", $desc) as $v){ |
|
1257
|
|
|
|
|
1258
|
|
|
preg_match("/^\s*([^\s]+)\s+(.*)/", $v, $r); |
|
1259
|
|
|
// Les cles de champs peuvent etre entourees |
|
1260
|
|
|
// de guillements doubles " , simples ', graves ` ou de crochets [ ], ou rien. |
|
1261
|
|
|
// http://www.sqlite.org/lang_keywords.html |
|
1262
|
|
|
$k = strtolower(query_reinjecte_textes($r[1], $echaps)); // champ, "champ", [champ]... |
|
|
|
|
|
|
1263
|
|
|
if ($char = strpbrk($k[0], '\'"[`')) { |
|
1264
|
|
|
$k = trim($k, $char); |
|
1265
|
|
|
if ($char == '[') $k = rtrim($k, ']'); |
|
1266
|
|
|
} |
|
1267
|
|
|
$def = query_reinjecte_textes($r[2], $echaps); // valeur du champ |
|
|
|
|
|
|
1268
|
|
|
|
|
1269
|
|
|
# rustine pour DECIMAL(10,2) |
|
1270
|
|
|
if (false !== strpos($k, ')')) { |
|
1271
|
|
|
$fields[$k_precedent] .= ',' . $k . ' ' . $def; |
|
1272
|
|
|
continue; |
|
1273
|
|
|
} |
|
1274
|
|
|
|
|
1275
|
|
|
$fields[$k] = $def; |
|
1276
|
|
|
$k_precedent = $k; |
|
1277
|
|
|
|
|
1278
|
|
|
// la primary key peut etre dans une des descriptions de champs |
|
1279
|
|
|
// et non en fin de table, cas encore decouvert avec Sqlite Manager |
|
1280
|
|
|
if (stripos($r[2], 'PRIMARY KEY') !== false) { |
|
1281
|
|
|
$keys['PRIMARY KEY'] = $k; |
|
1282
|
|
|
} |
|
1283
|
|
|
} |
|
1284
|
|
|
// key inclues dans la requete |
|
1285
|
|
View Code Duplication |
foreach(preg_split('/\)\s*(,|$)/',$namedkeys) as $v) { |
|
|
|
|
|
|
1286
|
|
|
if (preg_match("/^\s*([^(]*)\(([^(]*(\(\d+\))?)$/",$v,$r)) { |
|
1287
|
|
|
$k = str_replace("`", '', trim($r[1])); |
|
1288
|
|
|
$t = trim(strtolower(str_replace("`", '', $r[2])), '"'); |
|
1289
|
|
|
if ($k && !isset($keys[$k])) $keys[$k] = $t; else $keys[] = $t; |
|
1290
|
|
|
} |
|
1291
|
|
|
} |
|
1292
|
|
|
// sinon ajouter les key index |
|
1293
|
|
|
$query = |
|
1294
|
|
|
'SELECT name,sql FROM' |
|
1295
|
|
|
.' (SELECT * FROM sqlite_master UNION ALL' |
|
1296
|
|
|
.' SELECT * FROM sqlite_temp_master)' |
|
1297
|
|
|
." WHERE tbl_name LIKE '$nom_table'" |
|
1298
|
|
|
." AND type='index' AND name NOT LIKE 'sqlite_%'" |
|
1299
|
|
|
.'ORDER BY substr(type,2,1), name'; |
|
1300
|
|
|
$a = spip_sqlite_query($query, $serveur, $requeter); |
|
1301
|
|
|
while ($r = spip_sqlite_fetch($a, null, $serveur)){ |
|
1302
|
|
|
$key = str_replace($nom_table.'_', '', $r['name']); // enlever le nom de la table ajoute a l'index |
|
1303
|
|
|
$colonnes = preg_replace(',.*\((.*)\).*,', '$1', $r['sql']); |
|
1304
|
|
|
$keys['KEY '.$key] = $colonnes; |
|
1305
|
|
|
} |
|
1306
|
|
|
} |
|
1307
|
|
|
} |
|
1308
|
|
|
// c'est une vue, on liste les champs disponibles simplement |
|
1309
|
|
|
else { |
|
1310
|
|
|
if ($res = sql_fetsel('*', $nom_table, '', '', '', '1', '', $serveur)){ // limit 1 |
|
1311
|
|
|
$fields = array(); |
|
1312
|
|
|
foreach ($res as $c => $v) $fields[$c] = ''; |
|
1313
|
|
|
$keys = array(); |
|
1314
|
|
|
} else { |
|
1315
|
|
|
return ""; |
|
1316
|
|
|
} |
|
1317
|
|
|
} |
|
1318
|
|
|
return array('field' => $fields, 'key' => $keys); |
|
1319
|
|
|
|
|
1320
|
|
|
} |
|
1321
|
|
|
|
|
1322
|
|
|
|
|
1323
|
|
|
// http://doc.spip.org/@spip_sqlite_update |
|
1324
|
|
|
function spip_sqlite_update($table, $champs, $where = '', $desc = '', $serveur = '', $requeter = true){ |
|
1325
|
|
|
// recherche de champs 'timestamp' pour mise a jour auto de ceux-ci |
|
1326
|
|
|
$champs = _sqlite_ajouter_champs_timestamp($table, $champs, $desc, $serveur); |
|
1327
|
|
|
|
|
1328
|
|
|
$set = array(); |
|
1329
|
|
|
foreach ($champs as $champ => $val) |
|
1330
|
|
|
$set[] = $champ."=$val"; |
|
1331
|
|
View Code Duplication |
if (!empty($set)) |
|
|
|
|
|
|
1332
|
|
|
return spip_sqlite_query( |
|
1333
|
|
|
_sqlite_calculer_expression('UPDATE', $table, ',') |
|
1334
|
|
|
._sqlite_calculer_expression('SET', $set, ',') |
|
1335
|
|
|
._sqlite_calculer_expression('WHERE', $where), |
|
1336
|
|
|
$serveur, $requeter); |
|
1337
|
|
|
} |
|
1338
|
|
|
|
|
1339
|
|
|
|
|
1340
|
|
|
// http://doc.spip.org/@spip_sqlite_updateq |
|
1341
|
|
|
function spip_sqlite_updateq($table, $champs, $where = '', $desc = array(), $serveur = '', $requeter = true){ |
|
1342
|
|
|
|
|
1343
|
|
|
if (!$champs) return; |
|
1344
|
|
|
if (!$desc) $desc = description_table($table, $serveur); |
|
|
|
|
|
|
1345
|
|
|
if (!$desc) die("$table insertion sans description"); |
|
|
|
|
|
|
1346
|
|
|
$fields = $desc['field']; |
|
1347
|
|
|
|
|
1348
|
|
|
// recherche de champs 'timestamp' pour mise a jour auto de ceux-ci |
|
1349
|
|
|
$champs = _sqlite_ajouter_champs_timestamp($table, $champs, $desc, $serveur); |
|
1350
|
|
|
|
|
1351
|
|
|
$set = array(); |
|
1352
|
|
|
foreach ($champs as $champ => $val){ |
|
1353
|
|
|
$set[] = $champ.'='._sqlite_calculer_cite($val, $fields[$champ]); |
|
1354
|
|
|
} |
|
1355
|
|
|
return spip_sqlite_query( |
|
1356
|
|
|
_sqlite_calculer_expression('UPDATE', $table, ',') |
|
1357
|
|
|
._sqlite_calculer_expression('SET', $set, ',') |
|
1358
|
|
|
._sqlite_calculer_expression('WHERE', $where), |
|
1359
|
|
|
$serveur, $requeter); |
|
1360
|
|
|
} |
|
1361
|
|
|
|
|
1362
|
|
|
|
|
1363
|
|
|
/* |
|
1364
|
|
|
* |
|
1365
|
|
|
* Ensuite les fonctions non abstraites |
|
1366
|
|
|
* crees pour l'occasion de sqlite |
|
1367
|
|
|
* |
|
1368
|
|
|
*/ |
|
1369
|
|
|
|
|
1370
|
|
|
|
|
1371
|
|
|
/** |
|
1372
|
|
|
* fonction pour la premiere connexion a un serveur SQLite |
|
1373
|
|
|
* http://doc.spip.org/@_sqlite_init |
|
1374
|
|
|
* |
|
1375
|
|
|
* @return void |
|
1376
|
|
|
*/ |
|
1377
|
|
|
function _sqlite_init(){ |
|
1378
|
|
|
if (!defined('_DIR_DB')) define('_DIR_DB', _DIR_ETC.'bases/'); |
|
1379
|
|
|
if (!defined('_SQLITE_CHMOD')) define('_SQLITE_CHMOD', _SPIP_CHMOD); |
|
1380
|
|
|
|
|
1381
|
|
|
if (!is_dir($d = _DIR_DB)){ |
|
1382
|
|
|
include_spip('inc/flock'); |
|
1383
|
|
|
sous_repertoire($d); |
|
1384
|
|
|
} |
|
1385
|
|
|
} |
|
1386
|
|
|
|
|
1387
|
|
|
|
|
1388
|
|
|
/** |
|
1389
|
|
|
* teste la version sqlite du link en cours |
|
1390
|
|
|
* http://doc.spip.org/@_sqlite_is_version |
|
1391
|
|
|
* |
|
1392
|
|
|
* @param string $version |
|
1393
|
|
|
* @param string $link |
|
1394
|
|
|
* @param string $serveur |
|
1395
|
|
|
* @param bool $requeter |
|
1396
|
|
|
* @return bool|int |
|
1397
|
|
|
*/ |
|
1398
|
|
|
function _sqlite_is_version($version = '', $link = '', $serveur = '', $requeter = true){ |
|
|
|
|
|
|
1399
|
|
|
if ($link==='') $link = _sqlite_link($serveur); |
|
1400
|
|
|
if (!$link) return false; |
|
1401
|
|
|
if ($link instanceof PDO){ |
|
1402
|
|
|
$v = 3; |
|
1403
|
|
|
} else { |
|
1404
|
|
|
$v = 2; |
|
1405
|
|
|
} |
|
1406
|
|
|
|
|
1407
|
|
|
if (!$version) return $v; |
|
1408
|
|
|
return ($version==$v); |
|
1409
|
|
|
} |
|
1410
|
|
|
|
|
1411
|
|
|
|
|
1412
|
|
|
/** |
|
1413
|
|
|
* retrouver un link |
|
1414
|
|
|
* http://doc.spip.org/@_sqlite_link |
|
1415
|
|
|
* |
|
1416
|
|
|
* @param string $serveur |
|
1417
|
|
|
* @return |
|
1418
|
|
|
*/ |
|
1419
|
|
|
function _sqlite_link($serveur = ''){ |
|
1420
|
|
|
$link = &$GLOBALS['connexions'][$serveur ? $serveur : 0]['link']; |
|
1421
|
|
|
return $link; |
|
1422
|
|
|
} |
|
1423
|
|
|
|
|
1424
|
|
|
|
|
1425
|
|
|
/* ordre alphabetique pour les autres */ |
|
1426
|
|
|
|
|
1427
|
|
|
|
|
1428
|
|
|
/** |
|
1429
|
|
|
* renvoie les bons echappements (pas sur les fonctions now()) |
|
1430
|
|
|
* http://doc.spip.org/@_sqlite_calculer_cite |
|
1431
|
|
|
* |
|
1432
|
|
|
* @param string|array|number $v |
|
1433
|
|
|
* @param string $type |
|
1434
|
|
|
* @return string|array|number |
|
1435
|
|
|
*/ |
|
1436
|
|
|
function _sqlite_calculer_cite($v, $type){ |
|
1437
|
|
|
if ($type){ |
|
1438
|
|
|
if(is_null($v) |
|
1439
|
|
|
AND stripos($type,"NOT NULL")===false) return 'NULL'; // null php se traduit en NULL SQL |
|
1440
|
|
|
|
|
1441
|
|
|
if (sql_test_date($type) AND preg_match('/^\w+\(/', $v)) |
|
1442
|
|
|
return $v; |
|
1443
|
|
|
if (sql_test_int($type)){ |
|
1444
|
|
|
if (is_numeric($v)) |
|
1445
|
|
|
return $v; |
|
1446
|
|
|
elseif (ctype_xdigit(substr($v, 2)) AND strncmp($v, '0x', 2)==0) |
|
1447
|
|
|
return hexdec(substr($v, 2)); |
|
1448
|
|
|
else |
|
1449
|
|
|
return intval($v); |
|
1450
|
|
|
} |
|
1451
|
|
|
} |
|
1452
|
|
|
else { |
|
1453
|
|
|
// si on ne connait pas le type on le deduit de $v autant que possible |
|
1454
|
|
|
if (is_numeric($v)) |
|
1455
|
|
|
return strval($v); |
|
1456
|
|
|
} |
|
1457
|
|
|
|
|
1458
|
|
|
if (function_exists('sqlite_escape_string')){ |
|
1459
|
|
|
return "'".sqlite_escape_string($v)."'"; |
|
1460
|
|
|
} |
|
1461
|
|
|
|
|
1462
|
|
|
// trouver un link sqlite3 pour faire l'echappement |
|
1463
|
|
|
foreach ($GLOBALS['connexions'] as $s){ |
|
1464
|
|
|
if (_sqlite_is_version(3, $l = $s['link'])){ |
|
1465
|
|
|
return $l->quote($v); |
|
1466
|
|
|
} |
|
1467
|
|
|
} |
|
1468
|
|
|
|
|
1469
|
|
|
// echapper les ' en '' |
|
1470
|
|
|
spip_log("Pas de methode sqlite_escape_string ni ->quote pour echapper","sqlite."._LOG_INFO_IMPORTANTE); |
|
1471
|
|
|
return ("'" . str_replace("'","''",$v) . "'"); |
|
1472
|
|
|
} |
|
1473
|
|
|
|
|
1474
|
|
|
|
|
1475
|
|
|
/** |
|
1476
|
|
|
* renvoie grosso modo "$expression join($join, $v)" |
|
1477
|
|
|
* http://doc.spip.org/@_sqlite_calculer_expression |
|
1478
|
|
|
* |
|
1479
|
|
|
* @param $expression |
|
1480
|
|
|
* @param $v |
|
1481
|
|
|
* @param string $join |
|
1482
|
|
|
* @return string |
|
1483
|
|
|
*/ |
|
1484
|
|
View Code Duplication |
function _sqlite_calculer_expression($expression, $v, $join = 'AND'){ |
|
|
|
|
|
|
1485
|
|
|
if (empty($v)) |
|
1486
|
|
|
return ''; |
|
1487
|
|
|
|
|
1488
|
|
|
$exp = "\n$expression "; |
|
1489
|
|
|
|
|
1490
|
|
|
if (!is_array($v)){ |
|
1491
|
|
|
return $exp.$v; |
|
1492
|
|
|
} else { |
|
1493
|
|
|
if (strtoupper($join)==='AND') |
|
1494
|
|
|
return $exp.join("\n\t$join ", array_map('_sqlite_calculer_where', $v)); |
|
1495
|
|
|
else |
|
1496
|
|
|
return $exp.join($join, $v); |
|
1497
|
|
|
} |
|
1498
|
|
|
} |
|
1499
|
|
|
|
|
1500
|
|
|
|
|
1501
|
|
|
/** |
|
1502
|
|
|
* pour conversion 0+x ? (pas la peine en sqlite) |
|
1503
|
|
|
* http://doc.spip.org/@_sqlite_calculer_order |
|
1504
|
|
|
* |
|
1505
|
|
|
* @param $orderby |
|
1506
|
|
|
* @return string |
|
1507
|
|
|
*/ |
|
1508
|
|
|
function _sqlite_calculer_order($orderby){ |
|
1509
|
|
|
return (is_array($orderby)) ? join(", ", $orderby) : $orderby; |
|
1510
|
|
|
} |
|
1511
|
|
|
|
|
1512
|
|
|
|
|
1513
|
|
|
// renvoie des 'nom AS alias' |
|
1514
|
|
|
// http://doc.spip.org/@_sqlite_calculer_select_as |
|
1515
|
|
View Code Duplication |
function _sqlite_calculer_select_as($args){ |
|
|
|
|
|
|
1516
|
|
|
$res = ''; |
|
1517
|
|
|
foreach ($args as $k => $v){ |
|
1518
|
|
|
if (substr($k, -1)=='@'){ |
|
1519
|
|
|
// c'est une jointure qui se refere au from precedent |
|
1520
|
|
|
// pas de virgule |
|
1521
|
|
|
$res .= ' '.$v; |
|
1522
|
|
|
} |
|
1523
|
|
|
else { |
|
1524
|
|
|
if (!is_numeric($k)){ |
|
1525
|
|
|
$p = strpos($v, " "); |
|
1526
|
|
|
if ($p) |
|
1527
|
|
|
$v = substr($v, 0, $p)." AS '$k'".substr($v, $p); |
|
1528
|
|
|
else $v .= " AS '$k'"; |
|
1529
|
|
|
} |
|
1530
|
|
|
$res .= ', '.$v; |
|
1531
|
|
|
} |
|
1532
|
|
|
} |
|
1533
|
|
|
return substr($res, 2); |
|
1534
|
|
|
} |
|
1535
|
|
|
|
|
1536
|
|
|
|
|
1537
|
|
|
/** |
|
1538
|
|
|
* renvoie les bonnes parentheses pour des where imbriquees |
|
1539
|
|
|
* http://doc.spip.org/@_sqlite_calculer_where |
|
1540
|
|
|
* |
|
1541
|
|
|
* @param $v |
|
1542
|
|
|
* @return array|mixed|string |
|
1543
|
|
|
*/ |
|
1544
|
|
View Code Duplication |
function _sqlite_calculer_where($v){ |
|
|
|
|
|
|
1545
|
|
|
if (!is_array($v)) |
|
1546
|
|
|
return $v; |
|
1547
|
|
|
|
|
1548
|
|
|
$op = array_shift($v); |
|
1549
|
|
|
if (!($n = count($v))) |
|
1550
|
|
|
return $op; |
|
1551
|
|
|
else { |
|
1552
|
|
|
$arg = _sqlite_calculer_where(array_shift($v)); |
|
1553
|
|
|
if ($n==1){ |
|
1554
|
|
|
return "$op($arg)"; |
|
1555
|
|
|
} else { |
|
1556
|
|
|
$arg2 = _sqlite_calculer_where(array_shift($v)); |
|
1557
|
|
|
if ($n==2){ |
|
1558
|
|
|
return "($arg $op $arg2)"; |
|
1559
|
|
|
} else return "($arg $op ($arg2) : $v[0])"; |
|
1560
|
|
|
} |
|
1561
|
|
|
} |
|
1562
|
|
|
} |
|
1563
|
|
|
|
|
1564
|
|
|
|
|
1565
|
|
|
/** |
|
1566
|
|
|
* Charger les modules sqlite (si possible) (juste la version demandee), |
|
1567
|
|
|
* ou, si aucune version, renvoie les versions sqlite dispo |
|
1568
|
|
|
* sur ce serveur dans un array |
|
1569
|
|
|
* |
|
1570
|
|
|
* http://doc.spip.org/@_sqlite_charger_version |
|
1571
|
|
|
* |
|
1572
|
|
|
* @param string $version |
|
1573
|
|
|
* @return array|bool |
|
1574
|
|
|
*/ |
|
1575
|
|
|
function _sqlite_charger_version($version = ''){ |
|
1576
|
|
|
$versions = array(); |
|
1577
|
|
|
|
|
1578
|
|
|
// version 2 |
|
1579
|
|
|
if (!$version || $version==2){ |
|
1580
|
|
|
if (charger_php_extension('sqlite')){ |
|
1581
|
|
|
$versions[] = 2; |
|
1582
|
|
|
} |
|
1583
|
|
|
} |
|
1584
|
|
|
|
|
1585
|
|
|
// version 3 |
|
1586
|
|
|
if (!$version || $version==3){ |
|
1587
|
|
|
if (charger_php_extension('pdo') && charger_php_extension('pdo_sqlite')){ |
|
1588
|
|
|
$versions[] = 3; |
|
1589
|
|
|
} |
|
1590
|
|
|
} |
|
1591
|
|
|
if ($version) return in_array($version, $versions); |
|
1592
|
|
|
return $versions; |
|
1593
|
|
|
} |
|
1594
|
|
|
|
|
1595
|
|
|
|
|
1596
|
|
|
/** |
|
1597
|
|
|
* Gestion des requetes ALTER non reconnues de SQLite : |
|
1598
|
|
|
* ALTER TABLE table DROP column |
|
1599
|
|
|
* ALTER TABLE table CHANGE [COLUMN] columnA columnB definition |
|
1600
|
|
|
* ALTER TABLE table MODIFY column definition |
|
1601
|
|
|
* ALTER TABLE table ADD|DROP PRIMARY KEY |
|
1602
|
|
|
* |
|
1603
|
|
|
* (MODIFY transforme en CHANGE columnA columnA) par spip_sqlite_alter() |
|
1604
|
|
|
* |
|
1605
|
|
|
* 1) creer une table B avec le nouveau format souhaite |
|
1606
|
|
|
* 2) copier la table d'origine A vers B |
|
1607
|
|
|
* 3) supprimer la table A |
|
1608
|
|
|
* 4) renommer la table B en A |
|
1609
|
|
|
* 5) remettre les index (qui sont supprimes avec la table A) |
|
1610
|
|
|
* |
|
1611
|
|
|
* http://doc.spip.org/@_sqlite_modifier_table |
|
1612
|
|
|
* |
|
1613
|
|
|
* @param string/array $table : nom_table, array(nom_table=>nom_futur) |
|
|
|
|
|
|
1614
|
|
|
* @param string/array $col : nom_colonne, array(nom_colonne=>nom_futur) |
|
|
|
|
|
|
1615
|
|
|
* @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', ...)) |
|
1616
|
|
|
* @param string $serveur : nom de la connexion sql en cours |
|
1617
|
|
|
* |
|
1618
|
|
|
*/ |
|
1619
|
|
|
function _sqlite_modifier_table($table, $colonne, $opt = array(), $serveur = ''){ |
|
1620
|
|
|
|
|
1621
|
|
|
if (is_array($table)){ |
|
1622
|
|
|
reset($table); |
|
1623
|
|
|
list($table_origine,$table_destination) = each($table); |
|
1624
|
|
|
} else { |
|
1625
|
|
|
$table_origine = $table_destination = $table; |
|
1626
|
|
|
} |
|
1627
|
|
|
// ne prend actuellement qu'un changement |
|
1628
|
|
|
// mais pourra etre adapte pour changer plus qu'une colonne a la fois |
|
1629
|
|
|
if (is_array($colonne)){ |
|
1630
|
|
|
reset($colonne); |
|
1631
|
|
|
list($colonne_origine,$colonne_destination) = each($colonne); |
|
1632
|
|
|
} else { |
|
1633
|
|
|
$colonne_origine = $colonne_destination = $colonne; |
|
1634
|
|
|
} |
|
1635
|
|
|
if (!isset($opt['field'])) $opt['field'] = array(); |
|
1636
|
|
|
if (!isset($opt['key'])) $opt['key'] = array(); |
|
1637
|
|
|
|
|
1638
|
|
|
// si les noms de tables sont differents, pas besoin de table temporaire |
|
1639
|
|
|
// on prendra directement le nom de la future table |
|
1640
|
|
|
$meme_table = ($table_origine==$table_destination); |
|
1641
|
|
|
|
|
1642
|
|
|
$def_origine = sql_showtable($table_origine, false, $serveur); |
|
1643
|
|
View Code Duplication |
if (!$def_origine OR !isset($def_origine['field'])){ |
|
|
|
|
|
|
1644
|
|
|
spip_log("Alter table impossible sur $table_origine : table non trouvee",'sqlite'._LOG_ERREUR); |
|
1645
|
|
|
return false; |
|
1646
|
|
|
} |
|
1647
|
|
|
|
|
1648
|
|
|
|
|
1649
|
|
|
$table_tmp = $table_origine.'_tmp'; |
|
1650
|
|
|
|
|
1651
|
|
|
// 1) creer une table temporaire avec les modifications |
|
1652
|
|
|
// - DROP : suppression de la colonne |
|
1653
|
|
|
// - CHANGE : modification de la colonne |
|
1654
|
|
|
// (foreach pour conserver l'ordre des champs) |
|
1655
|
|
|
|
|
1656
|
|
|
// field |
|
1657
|
|
|
$fields = array(); |
|
1658
|
|
|
// pour le INSERT INTO plus loin |
|
1659
|
|
|
// stocker la correspondance nouvelles->anciennes colonnes |
|
1660
|
|
|
$fields_correspondances = array(); |
|
1661
|
|
|
foreach ($def_origine['field'] as $c => $d){ |
|
1662
|
|
|
|
|
1663
|
|
|
if ($colonne_origine && ($c==$colonne_origine)){ |
|
1664
|
|
|
// si pas DROP |
|
1665
|
|
|
if ($colonne_destination){ |
|
1666
|
|
|
$fields[$colonne_destination] = $opt['field'][$colonne_destination]; |
|
1667
|
|
|
$fields_correspondances[$colonne_destination] = $c; |
|
1668
|
|
|
} |
|
1669
|
|
|
} else { |
|
1670
|
|
|
$fields[$c] = $d; |
|
1671
|
|
|
$fields_correspondances[$c] = $c; |
|
1672
|
|
|
} |
|
1673
|
|
|
} |
|
1674
|
|
|
// cas de ADD sqlite2 (ajout du champ en fin de table): |
|
1675
|
|
|
if (!$colonne_origine && $colonne_destination){ |
|
1676
|
|
|
$fields[$colonne_destination] = $opt['field'][$colonne_destination]; |
|
1677
|
|
|
} |
|
1678
|
|
|
|
|
1679
|
|
|
// key... |
|
1680
|
|
|
$keys = array(); |
|
1681
|
|
|
foreach ($def_origine['key'] as $c => $d){ |
|
1682
|
|
|
$c = str_replace($colonne_origine, $colonne_destination, $c); |
|
1683
|
|
|
$d = str_replace($colonne_origine, $colonne_destination, $d); |
|
1684
|
|
|
// seulement si on ne supprime pas la colonne ! |
|
1685
|
|
|
if ($d) |
|
1686
|
|
|
$keys[$c] = $d; |
|
1687
|
|
|
} |
|
1688
|
|
|
|
|
1689
|
|
|
// autres keys, on merge |
|
1690
|
|
|
$keys = array_merge($keys, $opt['key']); |
|
1691
|
|
|
$queries = array(); |
|
1692
|
|
|
|
|
1693
|
|
|
// copier dans destination (si differente de origine), sinon tmp |
|
1694
|
|
|
$table_copie = ($meme_table) ? $table_tmp : $table_destination; |
|
1695
|
|
|
$autoinc = (isset($keys['PRIMARY KEY']) |
|
1696
|
|
|
AND stripos($keys['PRIMARY KEY'],',')===false |
|
1697
|
|
|
AND stripos($fields[$keys['PRIMARY KEY']],'default')===false); |
|
1698
|
|
|
|
|
1699
|
|
|
if ($q = _sqlite_requete_create( |
|
1700
|
|
|
$table_copie, |
|
1701
|
|
|
$fields, |
|
1702
|
|
|
$keys, |
|
1703
|
|
|
$autoinc, |
|
1704
|
|
|
$temporary = false, |
|
1705
|
|
|
$ifnotexists = true, |
|
1706
|
|
|
$serveur)){ |
|
1707
|
|
|
$queries[] = $q; |
|
1708
|
|
|
} |
|
1709
|
|
|
|
|
1710
|
|
|
|
|
1711
|
|
|
// 2) y copier les champs qui vont bien |
|
1712
|
|
|
$champs_dest = join(', ', array_keys($fields_correspondances)); |
|
1713
|
|
|
$champs_ori = join(', ', $fields_correspondances); |
|
1714
|
|
|
$queries[] = "INSERT INTO $table_copie ($champs_dest) SELECT $champs_ori FROM $table_origine"; |
|
1715
|
|
|
|
|
1716
|
|
|
// 3) supprimer la table d'origine |
|
1717
|
|
|
$queries[] = "DROP TABLE $table_origine"; |
|
1718
|
|
|
|
|
1719
|
|
|
// 4) renommer la table temporaire |
|
1720
|
|
|
// avec le nom de la table destination |
|
1721
|
|
|
// si necessaire |
|
1722
|
|
|
if ($meme_table){ |
|
1723
|
|
|
if (_sqlite_is_version(3, '', $serveur)){ |
|
1724
|
|
|
$queries[] = "ALTER TABLE $table_copie RENAME TO $table_destination"; |
|
1725
|
|
|
} else { |
|
1726
|
|
|
$queries[] = _sqlite_requete_create( |
|
1727
|
|
|
$table_destination, |
|
1728
|
|
|
$fields, |
|
1729
|
|
|
$keys, |
|
1730
|
|
|
$autoinc, |
|
1731
|
|
|
$temporary = false, |
|
1732
|
|
|
$ifnotexists = false, // la table existe puisqu'on est dans une transaction |
|
1733
|
|
|
$serveur); |
|
1734
|
|
|
$queries[] = "INSERT INTO $table_destination SELECT * FROM $table_copie"; |
|
1735
|
|
|
$queries[] = "DROP TABLE $table_copie"; |
|
1736
|
|
|
} |
|
1737
|
|
|
} |
|
1738
|
|
|
|
|
1739
|
|
|
// 5) remettre les index ! |
|
1740
|
|
|
foreach ($keys as $k => $v){ |
|
1741
|
|
View Code Duplication |
if ($k=='PRIMARY KEY'){ |
|
|
|
|
|
|
1742
|
|
|
} |
|
1743
|
|
|
else { |
|
1744
|
|
|
// enlever KEY |
|
1745
|
|
|
$k = substr($k, 4); |
|
1746
|
|
|
$queries[] = "CREATE INDEX $table_destination"."_$k ON $table_destination ($v)"; |
|
1747
|
|
|
} |
|
1748
|
|
|
} |
|
1749
|
|
|
|
|
1750
|
|
|
|
|
1751
|
|
|
if (count($queries)){ |
|
1752
|
|
|
spip_sqlite::demarrer_transaction($serveur); |
|
1753
|
|
|
// il faut les faire une par une car $query = join('; ', $queries).";"; ne fonctionne pas |
|
1754
|
|
|
foreach ($queries as $q){ |
|
1755
|
|
|
if (!spip_sqlite::executer_requete($q, $serveur)){ |
|
1756
|
|
|
spip_log(_LOG_GRAVITE_ERREUR, "SQLite : ALTER TABLE table :" |
|
1757
|
|
|
." Erreur a l'execution de la requete : $q", 'sqlite'); |
|
|
|
|
|
|
1758
|
|
|
spip_sqlite::annuler_transaction($serveur); |
|
1759
|
|
|
return false; |
|
1760
|
|
|
} |
|
1761
|
|
|
} |
|
1762
|
|
|
spip_sqlite::finir_transaction($serveur); |
|
1763
|
|
|
} |
|
1764
|
|
|
|
|
1765
|
|
|
return true; |
|
1766
|
|
|
} |
|
1767
|
|
|
|
|
1768
|
|
|
|
|
1769
|
|
|
/** |
|
1770
|
|
|
* Nom des fonctions |
|
1771
|
|
|
* http://doc.spip.org/@_sqlite_ref_fonctions |
|
1772
|
|
|
* |
|
1773
|
|
|
* @return array |
|
|
|
|
|
|
1774
|
|
|
*/ |
|
1775
|
|
|
function _sqlite_ref_fonctions(){ |
|
1776
|
|
|
$fonctions = array( |
|
1777
|
|
|
'alter' => 'spip_sqlite_alter', |
|
1778
|
|
|
'count' => 'spip_sqlite_count', |
|
1779
|
|
|
'countsel' => 'spip_sqlite_countsel', |
|
1780
|
|
|
'create' => 'spip_sqlite_create', |
|
1781
|
|
|
'create_base' => 'spip_sqlite_create_base', |
|
1782
|
|
|
'create_view' => 'spip_sqlite_create_view', |
|
1783
|
|
|
'date_proche' => 'spip_sqlite_date_proche', |
|
1784
|
|
|
'delete' => 'spip_sqlite_delete', |
|
1785
|
|
|
'drop_table' => 'spip_sqlite_drop_table', |
|
1786
|
|
|
'drop_view' => 'spip_sqlite_drop_view', |
|
1787
|
|
|
'errno' => 'spip_sqlite_errno', |
|
1788
|
|
|
'error' => 'spip_sqlite_error', |
|
1789
|
|
|
'explain' => 'spip_sqlite_explain', |
|
1790
|
|
|
'fetch' => 'spip_sqlite_fetch', |
|
1791
|
|
|
'seek' => 'spip_sqlite_seek', |
|
1792
|
|
|
'free' => 'spip_sqlite_free', |
|
1793
|
|
|
'hex' => 'spip_sqlite_hex', |
|
1794
|
|
|
'in' => 'spip_sqlite_in', |
|
1795
|
|
|
'insert' => 'spip_sqlite_insert', |
|
1796
|
|
|
'insertq' => 'spip_sqlite_insertq', |
|
1797
|
|
|
'insertq_multi' => 'spip_sqlite_insertq_multi', |
|
1798
|
|
|
'listdbs' => 'spip_sqlite_listdbs', |
|
1799
|
|
|
'multi' => 'spip_sqlite_multi', |
|
1800
|
|
|
'optimize' => 'spip_sqlite_optimize', |
|
1801
|
|
|
'query' => 'spip_sqlite_query', |
|
1802
|
|
|
'quote' => 'spip_sqlite_quote', |
|
1803
|
|
|
'replace' => 'spip_sqlite_replace', |
|
1804
|
|
|
'replace_multi' => 'spip_sqlite_replace_multi', |
|
1805
|
|
|
'select' => 'spip_sqlite_select', |
|
1806
|
|
|
'selectdb' => 'spip_sqlite_selectdb', |
|
1807
|
|
|
'set_charset' => 'spip_sqlite_set_charset', |
|
1808
|
|
|
'get_charset' => 'spip_sqlite_get_charset', |
|
1809
|
|
|
'showbase' => 'spip_sqlite_showbase', |
|
1810
|
|
|
'showtable' => 'spip_sqlite_showtable', |
|
1811
|
|
|
'update' => 'spip_sqlite_update', |
|
1812
|
|
|
'updateq' => 'spip_sqlite_updateq', |
|
1813
|
|
|
'preferer_transaction' => 'spip_sqlite_preferer_transaction', |
|
1814
|
|
|
'demarrer_transaction' => 'spip_sqlite_demarrer_transaction', |
|
1815
|
|
|
'terminer_transaction' => 'spip_sqlite_terminer_transaction', |
|
1816
|
|
|
); |
|
1817
|
|
|
|
|
1818
|
|
|
// association de chaque nom http d'un charset aux couples sqlite |
|
1819
|
|
|
// SQLite supporte utf-8 et utf-16 uniquement. |
|
1820
|
|
|
$charsets = array( |
|
1821
|
|
|
'utf-8' => array('charset' => 'utf8', 'collation' => 'utf8_general_ci'), |
|
1822
|
|
|
//'utf-16be'=>array('charset'=>'utf16be','collation'=>'UTF-16BE'),// aucune idee de quoi il faut remplir dans es champs la |
|
1823
|
|
|
//'utf-16le'=>array('charset'=>'utf16le','collation'=>'UTF-16LE') |
|
1824
|
|
|
); |
|
1825
|
|
|
|
|
1826
|
|
|
$fonctions['charsets'] = $charsets; |
|
1827
|
|
|
|
|
1828
|
|
|
return $fonctions; |
|
1829
|
|
|
} |
|
1830
|
|
|
|
|
1831
|
|
|
|
|
1832
|
|
|
/** |
|
1833
|
|
|
* $query est une requete ou une liste de champs |
|
1834
|
|
|
* http://doc.spip.org/@_sqlite_remplacements_definitions_table |
|
1835
|
|
|
* |
|
1836
|
|
|
* @param $query |
|
1837
|
|
|
* @param bool $autoinc |
|
1838
|
|
|
* @return mixed |
|
1839
|
|
|
*/ |
|
1840
|
|
|
function _sqlite_remplacements_definitions_table($query, $autoinc = false){ |
|
1841
|
|
|
// quelques remplacements |
|
1842
|
|
|
$num = "(\s*\([0-9]*\))?"; |
|
1843
|
|
|
$enum = "(\s*\([^\)]*\))?"; |
|
1844
|
|
|
|
|
1845
|
|
|
$remplace = array( |
|
1846
|
|
|
'/enum'.$enum.'/is' => 'VARCHAR(255)', |
|
1847
|
|
|
'/COLLATE \w+_bin/is' => 'COLLATE BINARY', |
|
1848
|
|
|
'/COLLATE \w+_ci/is' => 'COLLATE NOCASE', |
|
1849
|
|
|
'/auto_increment/is' => '', |
|
1850
|
|
|
'/(timestamp .* )ON .*$/is' => '\\1', |
|
1851
|
|
|
'/character set \w+/is' => '', |
|
1852
|
|
|
'/((big|small|medium|tiny)?int(eger)?)'.$num.'\s*unsigned/is' => '\\1 UNSIGNED', |
|
1853
|
|
|
'/(text\s+not\s+null(\s+collate\s+\w+)?)\s*$/is' => "\\1 DEFAULT ''", |
|
1854
|
|
|
'/((char|varchar)'.$num.'\s+not\s+null(\s+collate\s+\w+)?)\s*$/is' => "\\1 DEFAULT ''", |
|
1855
|
|
|
'/(datetime\s+not\s+null)\s*$/is' => "\\1 DEFAULT '0000-00-00 00:00:00'", |
|
1856
|
|
|
'/(date\s+not\s+null)\s*$/is' => "\\1 DEFAULT '0000-00-00'", |
|
1857
|
|
|
); |
|
1858
|
|
|
|
|
1859
|
|
|
// pour l'autoincrement, il faut des INTEGER NOT NULL PRIMARY KEY |
|
1860
|
|
|
$remplace_autocinc = array( |
|
1861
|
|
|
'/(big|small|medium|tiny)?int(eger)?'.$num.'/is' => 'INTEGER' |
|
1862
|
|
|
); |
|
1863
|
|
|
// pour les int non autoincrement, il faut un DEFAULT |
|
1864
|
|
|
$remplace_nonautocinc = array( |
|
1865
|
|
|
'/((big|small|medium|tiny)?int(eger)?'.$num.'\s+not\s+null)\s*$/is' => "\\1 DEFAULT 0", |
|
1866
|
|
|
); |
|
1867
|
|
|
|
|
1868
|
|
|
if (is_string($query)){ |
|
1869
|
|
|
$query = preg_replace(array_keys($remplace), $remplace, $query); |
|
1870
|
|
|
if ($autoinc OR preg_match(',AUTO_INCREMENT,is',$query)) |
|
1871
|
|
|
$query = preg_replace(array_keys($remplace_autocinc), $remplace_autocinc, $query); |
|
1872
|
|
|
else{ |
|
1873
|
|
|
$query = preg_replace(array_keys($remplace_nonautocinc), $remplace_nonautocinc, $query); |
|
1874
|
|
|
$query = _sqlite_collate_ci($query); |
|
1875
|
|
|
} |
|
1876
|
|
|
} |
|
1877
|
|
|
elseif(is_array($query)){ |
|
1878
|
|
|
foreach($query as $k=>$q) { |
|
1879
|
|
|
$ai = ($autoinc?$k==$autoinc:preg_match(',AUTO_INCREMENT,is',$q)); |
|
1880
|
|
|
$query[$k] = preg_replace(array_keys($remplace), $remplace, $query[$k]); |
|
1881
|
|
|
if ($ai) |
|
1882
|
|
|
$query[$k] = preg_replace(array_keys($remplace_autocinc), $remplace_autocinc, $query[$k]); |
|
1883
|
|
|
else{ |
|
1884
|
|
|
$query[$k] = preg_replace(array_keys($remplace_nonautocinc), $remplace_nonautocinc, $query[$k]); |
|
1885
|
|
|
$query[$k] = _sqlite_collate_ci($query[$k]); |
|
1886
|
|
|
} |
|
1887
|
|
|
} |
|
1888
|
|
|
} |
|
1889
|
|
|
return $query; |
|
1890
|
|
|
} |
|
1891
|
|
|
|
|
1892
|
|
|
/** |
|
1893
|
|
|
* Definir la collation d'un champ en fonction de si une collation est deja explicite |
|
1894
|
|
|
* et du par defaut que l'on veut NOCASE |
|
1895
|
|
|
* @param string $champ |
|
1896
|
|
|
* @return string |
|
1897
|
|
|
*/ |
|
1898
|
|
|
function _sqlite_collate_ci($champ){ |
|
1899
|
|
|
if (stripos($champ,"COLLATE")!==false) |
|
1900
|
|
|
return $champ; |
|
1901
|
|
|
if (stripos($champ,"BINARY")!==false) |
|
1902
|
|
|
return str_ireplace("BINARY","COLLATE BINARY",$champ); |
|
1903
|
|
|
if (preg_match(",^(char|varchar|(long|small|medium|tiny)?text),i",$champ)) |
|
1904
|
|
|
return $champ . " COLLATE NOCASE"; |
|
1905
|
|
|
|
|
1906
|
|
|
return $champ; |
|
1907
|
|
|
} |
|
1908
|
|
|
|
|
1909
|
|
|
|
|
1910
|
|
|
/** |
|
1911
|
|
|
* Creer la requete pour la creation d'une table |
|
1912
|
|
|
* retourne la requete pour utilisation par sql_create() et sql_alter() |
|
1913
|
|
|
* |
|
1914
|
|
|
* http://doc.spip.org/@_sqlite_requete_create |
|
1915
|
|
|
* |
|
1916
|
|
|
* @param $nom |
|
1917
|
|
|
* @param $champs |
|
1918
|
|
|
* @param $cles |
|
1919
|
|
|
* @param bool $autoinc |
|
1920
|
|
|
* @param bool $temporary |
|
1921
|
|
|
* @param bool $_ifnotexists |
|
1922
|
|
|
* @param string $serveur |
|
1923
|
|
|
* @param bool $requeter |
|
1924
|
|
|
* @return bool|string |
|
1925
|
|
|
*/ |
|
1926
|
|
|
function _sqlite_requete_create($nom, $champs, $cles, $autoinc = false, $temporary = false, $_ifnotexists = true, $serveur = '', $requeter = true){ |
|
|
|
|
|
|
1927
|
|
|
$query = $keys = $s = $p = ''; |
|
|
|
|
|
|
1928
|
|
|
|
|
1929
|
|
|
// certains plugins declarent les tables (permet leur inclusion dans le dump) |
|
1930
|
|
|
// sans les renseigner (laisse le compilo recuperer la description) |
|
1931
|
|
|
if (!is_array($champs) || !is_array($cles)) |
|
1932
|
|
|
return; |
|
1933
|
|
|
|
|
1934
|
|
|
// sqlite ne gere pas KEY tout court dans une requete CREATE TABLE |
|
1935
|
|
|
// il faut passer par des create index |
|
1936
|
|
|
// Il gere par contre primary key ! |
|
1937
|
|
|
// Soit la PK est definie dans les cles, soit dans un champs |
|
1938
|
|
|
$c = ""; // le champ de cle primaire |
|
|
|
|
|
|
1939
|
|
|
if (!isset($cles[$pk = "PRIMARY KEY"]) OR !$c = $cles[$pk]){ |
|
1940
|
|
|
foreach ($champs as $k => $v){ |
|
1941
|
|
|
if (false!==stripos($v, $pk)){ |
|
1942
|
|
|
$c = $k; |
|
1943
|
|
|
// on n'en a plus besoin dans field, vu que defini dans key |
|
1944
|
|
|
$champs[$k] = preg_replace("/$pk/is", '', $champs[$k]); |
|
1945
|
|
|
break; |
|
1946
|
|
|
} |
|
1947
|
|
|
} |
|
1948
|
|
|
} |
|
1949
|
|
|
if ($c) $keys = "\n\t\t$pk ($c)"; |
|
1950
|
|
|
// Pas de DEFAULT 0 sur les cles primaires en auto-increment |
|
1951
|
|
|
if (isset($champs[$c]) |
|
1952
|
|
|
AND stripos($champs[$c],"default 0")!==false){ |
|
1953
|
|
|
$champs[$c] = trim(str_ireplace("default 0","",$champs[$c])); |
|
1954
|
|
|
} |
|
1955
|
|
|
|
|
1956
|
|
|
$champs = _sqlite_remplacements_definitions_table($champs, $autoinc?$c:false); |
|
1957
|
|
|
foreach ($champs as $k => $v){ |
|
1958
|
|
|
$query .= "$s\n\t\t$k $v"; |
|
1959
|
|
|
$s = ","; |
|
1960
|
|
|
} |
|
1961
|
|
|
|
|
1962
|
|
|
$ifnotexists = ""; |
|
1963
|
|
|
if ($_ifnotexists){ |
|
1964
|
|
|
|
|
1965
|
|
|
$version = spip_sqlite_fetch(spip_sqlite_query("select sqlite_version() AS sqlite_version",$serveur),'',$serveur); |
|
1966
|
|
|
if (!function_exists('spip_version_compare')) include_spip('plugins/installer'); |
|
1967
|
|
|
|
|
1968
|
|
View Code Duplication |
if ($version AND spip_version_compare($version['sqlite_version'],'3.3.0','>=')) { |
|
|
|
|
|
|
1969
|
|
|
$ifnotexists = ' IF NOT EXISTS'; |
|
1970
|
|
|
} else { |
|
1971
|
|
|
/* simuler le IF EXISTS - version 2 et sqlite < 3.3a */ |
|
1972
|
|
|
$a = spip_sqlite_showtable($table, $serveur); |
|
|
|
|
|
|
1973
|
|
|
if (isset($a['key']['KEY '.$nom])) return true; |
|
1974
|
|
|
} |
|
1975
|
|
|
|
|
1976
|
|
|
} |
|
1977
|
|
|
|
|
1978
|
|
|
$temporary = $temporary ? ' TEMPORARY' : ''; |
|
1979
|
|
|
$q = "CREATE$temporary TABLE$ifnotexists $nom ($query".($keys ? ",$keys" : '').")\n"; |
|
1980
|
|
|
|
|
1981
|
|
|
return $q; |
|
1982
|
|
|
} |
|
1983
|
|
|
|
|
1984
|
|
|
|
|
1985
|
|
|
/** |
|
1986
|
|
|
* Retrouver les champs 'timestamp' |
|
1987
|
|
|
* pour les ajouter aux 'insert' ou 'replace' |
|
1988
|
|
|
* afin de simuler le fonctionnement de mysql |
|
1989
|
|
|
* |
|
1990
|
|
|
* stocke le resultat pour ne pas faire |
|
1991
|
|
|
* de requetes showtable intempestives |
|
1992
|
|
|
* |
|
1993
|
|
|
* http://doc.spip.org/@_sqlite_ajouter_champs_timestamp |
|
1994
|
|
|
* |
|
1995
|
|
|
* @param $table |
|
1996
|
|
|
* @param $couples |
|
1997
|
|
|
* @param string $desc |
|
1998
|
|
|
* @param string $serveur |
|
1999
|
|
|
* @return |
|
2000
|
|
|
*/ |
|
2001
|
|
|
function _sqlite_ajouter_champs_timestamp($table, $couples, $desc = '', $serveur = ''){ |
|
2002
|
|
|
static $tables = array(); |
|
2003
|
|
|
|
|
2004
|
|
|
if (!isset($tables[$table])){ |
|
2005
|
|
|
|
|
2006
|
|
View Code Duplication |
if (!$desc){ |
|
|
|
|
|
|
2007
|
|
|
$trouver_table = charger_fonction('trouver_table', 'base'); |
|
2008
|
|
|
$desc = $trouver_table($table, $serveur); |
|
2009
|
|
|
// si pas de description, on ne fait rien, ou on die() ? |
|
2010
|
|
|
if (!$desc) return $couples; |
|
2011
|
|
|
} |
|
2012
|
|
|
|
|
2013
|
|
|
// recherche des champs avec simplement 'TIMESTAMP' |
|
2014
|
|
|
// cependant, il faudra peut etre etendre |
|
2015
|
|
|
// avec la gestion de DEFAULT et ON UPDATE |
|
2016
|
|
|
// mais ceux-ci ne sont pas utilises dans le core |
|
2017
|
|
|
$tables[$table] = array(); |
|
2018
|
|
|
|
|
2019
|
|
|
foreach ($desc['field'] as $k => $v){ |
|
2020
|
|
View Code Duplication |
if (strpos(strtolower(ltrim($v)), 'timestamp')===0) |
|
|
|
|
|
|
2021
|
|
|
$tables[$table][$k] = "datetime('now')"; |
|
2022
|
|
|
} |
|
2023
|
|
|
} |
|
2024
|
|
|
|
|
2025
|
|
|
// ajout des champs type 'timestamp' absents |
|
2026
|
|
|
return array_merge($tables[$table],$couples); |
|
2027
|
|
|
} |
|
2028
|
|
|
|
|
2029
|
|
|
|
|
2030
|
|
|
/** |
|
2031
|
|
|
* renvoyer la liste des versions sqlite disponibles |
|
2032
|
|
|
* sur le serveur |
|
2033
|
|
|
* http://doc.spip.org/@spip_versions_sqlite |
|
2034
|
|
|
* |
|
2035
|
|
|
* @return array|bool |
|
2036
|
|
|
*/ |
|
2037
|
|
|
function spip_versions_sqlite(){ |
|
2038
|
|
|
return _sqlite_charger_version(); |
|
2039
|
|
|
} |
|
2040
|
|
|
|
|
2041
|
|
|
|
|
2042
|
|
|
class spip_sqlite { |
|
2043
|
|
|
static $requeteurs = array(); |
|
2044
|
|
|
static $transaction_en_cours = array(); |
|
2045
|
|
|
|
|
2046
|
|
|
function spip_sqlite(){} |
|
|
|
|
|
|
2047
|
|
|
|
|
2048
|
|
|
/** |
|
2049
|
|
|
* Retourne une unique instance du requêteur |
|
2050
|
|
|
* |
|
2051
|
|
|
* Retourne une instance unique du requêteur pour une connexion SQLite |
|
2052
|
|
|
* donnée |
|
2053
|
|
|
* |
|
2054
|
|
|
* @param string $serveur |
|
2055
|
|
|
* Nom du connecteur |
|
2056
|
|
|
* @return sqlite_requeteur |
|
2057
|
|
|
* Instance unique du requêteur |
|
2058
|
|
|
**/ |
|
2059
|
|
|
static function requeteur($serveur){ |
|
|
|
|
|
|
2060
|
|
|
if (!isset(spip_sqlite::$requeteurs[$serveur])) |
|
2061
|
|
|
spip_sqlite::$requeteurs[$serveur] = new sqlite_requeteur($serveur); |
|
2062
|
|
|
return spip_sqlite::$requeteurs[$serveur]; |
|
2063
|
|
|
} |
|
2064
|
|
|
|
|
2065
|
|
|
static function traduire_requete($query, $serveur){ |
|
|
|
|
|
|
2066
|
|
|
$requeteur = spip_sqlite::requeteur($serveur); |
|
2067
|
|
|
$traducteur = new sqlite_traducteur($query, $requeteur->prefixe,$requeteur->sqlite_version); |
|
2068
|
|
|
return $traducteur->traduire_requete(); |
|
2069
|
|
|
} |
|
2070
|
|
|
|
|
2071
|
|
|
static function demarrer_transaction($serveur){ |
|
|
|
|
|
|
2072
|
|
|
spip_sqlite::executer_requete("BEGIN TRANSACTION",$serveur); |
|
2073
|
|
|
spip_sqlite::$transaction_en_cours[$serveur] = true; |
|
2074
|
|
|
} |
|
2075
|
|
|
|
|
2076
|
|
|
static function executer_requete($query, $serveur, $tracer=null){ |
|
|
|
|
|
|
2077
|
|
|
$requeteur = spip_sqlite::requeteur($serveur); |
|
2078
|
|
|
return $requeteur->executer_requete($query, $tracer); |
|
2079
|
|
|
} |
|
2080
|
|
|
|
|
2081
|
|
|
static function last_insert_id($serveur){ |
|
|
|
|
|
|
2082
|
|
|
$requeteur = spip_sqlite::requeteur($serveur); |
|
2083
|
|
|
return $requeteur->last_insert_id($serveur); |
|
|
|
|
|
|
2084
|
|
|
} |
|
2085
|
|
|
|
|
2086
|
|
|
static function annuler_transaction($serveur){ |
|
|
|
|
|
|
2087
|
|
|
spip_sqlite::executer_requete("ROLLBACK",$serveur); |
|
2088
|
|
|
spip_sqlite::$transaction_en_cours[$serveur] = false; |
|
2089
|
|
|
} |
|
2090
|
|
|
|
|
2091
|
|
|
static function finir_transaction($serveur){ |
|
|
|
|
|
|
2092
|
|
|
// si pas de transaction en cours, ne rien faire et le dire |
|
2093
|
|
|
if (!isset (spip_sqlite::$transaction_en_cours[$serveur]) |
|
2094
|
|
|
OR spip_sqlite::$transaction_en_cours[$serveur]==false) |
|
2095
|
|
|
return false; |
|
2096
|
|
|
// sinon fermer la transaction et retourner true |
|
2097
|
|
|
spip_sqlite::executer_requete("COMMIT",$serveur); |
|
2098
|
|
|
spip_sqlite::$transaction_en_cours[$serveur] = false; |
|
2099
|
|
|
return true; |
|
2100
|
|
|
} |
|
2101
|
|
|
} |
|
2102
|
|
|
|
|
2103
|
|
|
/* |
|
2104
|
|
|
* Classe pour partager les lancements de requete |
|
2105
|
|
|
* instanciee une fois par $serveur |
|
2106
|
|
|
* - peut corriger la syntaxe des requetes pour la conformite a sqlite |
|
2107
|
|
|
* - peut tracer les requetes |
|
2108
|
|
|
* |
|
2109
|
|
|
*/ |
|
2110
|
|
|
class sqlite_requeteur { |
|
2111
|
|
|
var $query = ''; // la requete |
|
2112
|
|
|
var $serveur = ''; // le serveur |
|
2113
|
|
|
var $link = ''; // le link (ressource) sqlite |
|
2114
|
|
|
var $prefixe = ''; // le prefixe des tables |
|
2115
|
|
|
var $db = ''; // le nom de la base |
|
2116
|
|
|
var $tracer = false; // doit-on tracer les requetes (var_profile) |
|
2117
|
|
|
|
|
2118
|
|
|
var $sqlite_version = ''; // Version de sqlite (2 ou 3) |
|
2119
|
|
|
|
|
2120
|
|
|
/** |
|
2121
|
|
|
* constructeur |
|
2122
|
|
|
* http://doc.spip.org/@sqlite_traiter_requete |
|
2123
|
|
|
* |
|
2124
|
|
|
* @param $query |
|
2125
|
|
|
* @param string $serveur |
|
2126
|
|
|
* @return bool |
|
|
|
|
|
|
2127
|
|
|
*/ |
|
2128
|
|
|
function sqlite_requeteur($serveur = ''){ |
|
|
|
|
|
|
2129
|
|
|
_sqlite_init(); |
|
2130
|
|
|
$this->serveur = strtolower($serveur); |
|
2131
|
|
|
|
|
2132
|
|
|
if (!($this->link = _sqlite_link($this->serveur)) && (!defined('_ECRIRE_INSTALL') || !_ECRIRE_INSTALL)){ |
|
2133
|
|
|
spip_log("Aucune connexion sqlite (link)", 'sqlite.'._LOG_ERREUR); |
|
2134
|
|
|
return false; |
|
2135
|
|
|
} |
|
2136
|
|
|
|
|
2137
|
|
|
$this->sqlite_version = _sqlite_is_version('', $this->link); |
|
|
|
|
|
|
2138
|
|
|
|
|
2139
|
|
|
$this->prefixe = $GLOBALS['connexions'][$this->serveur ? $this->serveur : 0]['prefixe']; |
|
2140
|
|
|
$this->db = $GLOBALS['connexions'][$this->serveur ? $this->serveur : 0]['db']; |
|
2141
|
|
|
|
|
2142
|
|
|
// tracage des requetes ? |
|
2143
|
|
|
$this->tracer = (isset($_GET['var_profile']) && $_GET['var_profile']); |
|
2144
|
|
|
} |
|
2145
|
|
|
|
|
2146
|
|
|
/** |
|
2147
|
|
|
* lancer la requete $query, |
|
2148
|
|
|
* faire le tracage si demande |
|
2149
|
|
|
* http://doc.spip.org/@executer_requete |
|
2150
|
|
|
* |
|
2151
|
|
|
* @return bool|SQLiteResult |
|
2152
|
|
|
*/ |
|
2153
|
|
|
function executer_requete($query, $tracer=null){ |
|
|
|
|
|
|
2154
|
|
|
if (is_null($tracer)) |
|
2155
|
|
|
$tracer = $this->tracer; |
|
2156
|
|
|
$err = ""; |
|
2157
|
|
|
$t = 0; |
|
2158
|
|
|
if ($tracer){ |
|
2159
|
|
|
include_spip('public/tracer'); |
|
2160
|
|
|
$t = trace_query_start(); |
|
2161
|
|
|
} |
|
2162
|
|
|
|
|
2163
|
|
|
# spip_log("requete: $this->serveur >> $query",'sqlite.'._LOG_DEBUG); // boum ? pourquoi ? |
|
2164
|
|
|
if ($this->link){ |
|
2165
|
|
|
// memoriser la derniere erreur PHP vue |
|
2166
|
|
|
$e = (function_exists('error_get_last')?error_get_last():""); |
|
2167
|
|
|
// sauver la derniere requete |
|
2168
|
|
|
$GLOBALS['connexions'][$this->serveur ? $this->serveur : 0]['last'] = $query; |
|
2169
|
|
|
|
|
2170
|
|
|
if ($this->sqlite_version==3){ |
|
2171
|
|
|
$r = $this->link->query($query); |
|
|
|
|
|
|
2172
|
|
|
// sauvegarde de la requete (elle y est deja dans $r->queryString) |
|
2173
|
|
|
# $r->spipQueryString = $query; |
|
2174
|
|
|
|
|
2175
|
|
|
// comptage : oblige de compter le nombre d'entrees retournees |
|
2176
|
|
|
// par une requete SELECT |
|
2177
|
|
|
// aucune autre solution ne donne le nombre attendu :( ! |
|
2178
|
|
|
// particulierement s'il y a des LIMIT dans la requete. |
|
2179
|
|
|
if (strtoupper(substr(ltrim($query), 0, 6))=='SELECT'){ |
|
2180
|
|
|
if ($r){ |
|
2181
|
|
|
// noter le link et la query pour faire le comptage *si* on en a besoin |
|
2182
|
|
|
$r->spipSqliteRowCount = array($this->link,$query); |
|
2183
|
|
|
} |
|
2184
|
|
|
elseif ($r instanceof PDOStatement) { |
|
2185
|
|
|
$r->spipSqliteRowCount = 0; |
|
|
|
|
|
|
2186
|
|
|
} |
|
2187
|
|
|
} |
|
2188
|
|
|
} |
|
2189
|
|
|
else { |
|
2190
|
|
|
$r = sqlite_query($this->link, $query); |
|
2191
|
|
|
} |
|
2192
|
|
|
|
|
2193
|
|
|
// loger les warnings/erreurs eventuels de sqlite remontant dans PHP |
|
2194
|
|
|
if ($err = (function_exists('error_get_last')?error_get_last():"") AND $err!=$e){ |
|
2195
|
|
|
$err = strip_tags($err['message'])." in ".$err['file']." line ".$err['line']; |
|
2196
|
|
|
spip_log("$err - ".$query, 'sqlite.'._LOG_ERREUR); |
|
2197
|
|
|
} |
|
2198
|
|
|
else $err = ""; |
|
2199
|
|
|
|
|
2200
|
|
|
} |
|
2201
|
|
|
else { |
|
2202
|
|
|
$r = false; |
|
2203
|
|
|
} |
|
2204
|
|
|
|
|
2205
|
|
|
if (spip_sqlite_errno($this->serveur)) |
|
2206
|
|
|
$err .= spip_sqlite_error($query, $this->serveur); |
|
2207
|
|
|
return $t ? trace_query_end($query, $t, $r, $err, $this->serveur) : $r; |
|
2208
|
|
|
} |
|
2209
|
|
|
|
|
2210
|
|
|
function last_insert_id(){ |
|
|
|
|
|
|
2211
|
|
|
if ($this->sqlite_version==3) |
|
2212
|
|
|
return $this->link->lastInsertId(); |
|
|
|
|
|
|
2213
|
|
|
else |
|
2214
|
|
|
return sqlite_last_insert_rowid($this->link); |
|
2215
|
|
|
} |
|
2216
|
|
|
} |
|
2217
|
|
|
|
|
2218
|
|
|
|
|
2219
|
|
|
/** |
|
2220
|
|
|
* Cette classe est presente essentiellement pour un preg_replace_callback |
|
2221
|
|
|
* avec des parametres dans la fonction appelee que l'on souhaite incrementer |
|
2222
|
|
|
* (fonction pour proteger les textes) |
|
2223
|
|
|
*/ |
|
2224
|
|
|
class sqlite_traducteur { |
|
2225
|
|
|
var $query = ''; |
|
2226
|
|
|
var $prefixe = ''; // le prefixe des tables |
|
2227
|
|
|
var $sqlite_version = ''; // Version de sqlite (2 ou 3) |
|
2228
|
|
|
|
|
2229
|
|
|
// Pour les corrections a effectuer sur les requetes : |
|
2230
|
|
|
var $textes = array(); // array(code=>'texte') trouvé |
|
2231
|
|
|
|
|
2232
|
|
|
function sqlite_traducteur($query, $prefixe, $sqlite_version){ |
|
|
|
|
|
|
2233
|
|
|
$this->query = $query; |
|
2234
|
|
|
$this->prefixe = $prefixe; |
|
2235
|
|
|
$this->sqlite_version = $sqlite_version; |
|
2236
|
|
|
} |
|
2237
|
|
|
|
|
2238
|
|
|
/** |
|
2239
|
|
|
* transformer la requete pour sqlite |
|
2240
|
|
|
* enleve les textes, transforme la requete pour quelle soit |
|
2241
|
|
|
* bien interpretee par sqlite, puis remet les textes |
|
2242
|
|
|
* la fonction affecte $this->query |
|
2243
|
|
|
* http://doc.spip.org/@traduire_requete |
|
2244
|
|
|
* |
|
2245
|
|
|
* @return void |
|
|
|
|
|
|
2246
|
|
|
*/ |
|
2247
|
|
|
function traduire_requete(){ |
|
|
|
|
|
|
2248
|
|
|
// |
|
2249
|
|
|
// 1) Protection des textes en les remplacant par des codes |
|
2250
|
|
|
// |
|
2251
|
|
|
// enlever les 'textes' et initialiser avec |
|
2252
|
|
|
list($this->query, $textes) = query_echappe_textes($this->query); |
|
2253
|
|
|
|
|
2254
|
|
|
// |
|
2255
|
|
|
// 2) Corrections de la requete |
|
2256
|
|
|
// |
|
2257
|
|
|
// Correction Create Database |
|
2258
|
|
|
// Create Database -> requete ignoree |
|
2259
|
|
View Code Duplication |
if (strpos($this->query, 'CREATE DATABASE')===0){ |
|
|
|
|
|
|
2260
|
|
|
spip_log("Sqlite : requete non executee -> $this->query", 'sqlite.'._LOG_AVERTISSEMENT); |
|
2261
|
|
|
$this->query = "SELECT 1"; |
|
2262
|
|
|
} |
|
2263
|
|
|
|
|
2264
|
|
|
// Correction Insert Ignore |
|
2265
|
|
|
// INSERT IGNORE -> insert (tout court et pas 'insert or replace') |
|
2266
|
|
View Code Duplication |
if (strpos($this->query, 'INSERT IGNORE')===0){ |
|
|
|
|
|
|
2267
|
|
|
spip_log("Sqlite : requete transformee -> $this->query", 'sqlite.'._LOG_DEBUG); |
|
2268
|
|
|
$this->query = 'INSERT '.substr($this->query, '13'); |
|
2269
|
|
|
} |
|
2270
|
|
|
|
|
2271
|
|
|
// Correction des dates avec INTERVAL |
|
2272
|
|
|
// utiliser sql_date_proche() de preference |
|
2273
|
|
View Code Duplication |
if (strpos($this->query, 'INTERVAL')!==false){ |
|
|
|
|
|
|
2274
|
|
|
$this->query = preg_replace_callback("/DATE_(ADD|SUB)(.*)INTERVAL\s+(\d+)\s+([a-zA-Z]+)\)/U", |
|
2275
|
|
|
array(&$this, '_remplacerDateParTime'), |
|
2276
|
|
|
$this->query); |
|
2277
|
|
|
} |
|
2278
|
|
|
|
|
2279
|
|
View Code Duplication |
if (strpos($this->query, 'LEFT(')!==false){ |
|
|
|
|
|
|
2280
|
|
|
$this->query = str_replace('LEFT(','_LEFT(',$this->query); |
|
2281
|
|
|
} |
|
2282
|
|
|
|
|
2283
|
|
|
if (strpos($this->query, 'TIMESTAMPDIFF(')!==false){ |
|
2284
|
|
|
$this->query = preg_replace('/TIMESTAMPDIFF\(\s*([^,]*)\s*,/Uims',"TIMESTAMPDIFF('\\1',",$this->query); |
|
2285
|
|
|
} |
|
2286
|
|
|
|
|
2287
|
|
|
|
|
2288
|
|
|
// Correction Using |
|
2289
|
|
|
// USING (non reconnu en sqlite2) |
|
2290
|
|
|
// problematique car la jointure ne se fait pas du coup. |
|
2291
|
|
|
if (($this->sqlite_version==2) && (strpos($this->query, "USING")!==false)){ |
|
2292
|
|
|
spip_log("'USING (champ)' n'est pas reconnu en SQLite 2. Utilisez 'ON table1.champ = table2.champ'", 'sqlite.'._LOG_ERREUR); |
|
2293
|
|
|
$this->query = preg_replace('/USING\s*\([^\)]*\)/', '', $this->query); |
|
2294
|
|
|
} |
|
2295
|
|
|
|
|
2296
|
|
|
// Correction Field |
|
2297
|
|
|
// remplace FIELD(table,i,j,k...) par CASE WHEN table=i THEN n ... ELSE 0 END |
|
2298
|
|
View Code Duplication |
if (strpos($this->query, 'FIELD')!==false){ |
|
|
|
|
|
|
2299
|
|
|
$this->query = preg_replace_callback('/FIELD\s*\(([^\)]*)\)/', |
|
2300
|
|
|
array(&$this, '_remplacerFieldParCase'), |
|
2301
|
|
|
$this->query); |
|
2302
|
|
|
} |
|
2303
|
|
|
|
|
2304
|
|
|
// Correction des noms de tables FROM |
|
2305
|
|
|
// mettre les bons noms de table dans from, update, insert, replace... |
|
2306
|
|
|
if (preg_match('/\s(SET|VALUES|WHERE|DATABASE)\s/iS', $this->query, $regs)){ |
|
2307
|
|
|
$suite = strstr($this->query, $regs[0]); |
|
2308
|
|
|
$this->query = substr($this->query, 0, -strlen($suite)); |
|
2309
|
|
|
} |
|
2310
|
|
|
else |
|
2311
|
|
|
$suite = ''; |
|
2312
|
|
|
$pref = ($this->prefixe) ? $this->prefixe."_" : ""; |
|
2313
|
|
|
$this->query = preg_replace('/([,\s])spip_/S', '\1'.$pref, $this->query).$suite; |
|
2314
|
|
|
|
|
2315
|
|
|
// Correction zero AS x |
|
2316
|
|
|
// pg n'aime pas 0+x AS alias, sqlite, dans le meme style, |
|
2317
|
|
|
// n'apprecie pas du tout SELECT 0 as x ... ORDER BY x |
|
2318
|
|
|
// il dit que x ne doit pas être un integer dans le order by ! |
|
2319
|
|
|
// on remplace du coup x par vide() dans ce cas uniquement |
|
2320
|
|
|
// |
|
2321
|
|
|
// rien que pour public/vertebrer.php ? |
|
2322
|
|
|
if ((strpos($this->query, "0 AS")!==false)){ |
|
2323
|
|
|
// on ne remplace que dans ORDER BY ou GROUP BY |
|
2324
|
|
|
if (preg_match('/\s(ORDER|GROUP) BY\s/i', $this->query, $regs)){ |
|
2325
|
|
|
$suite = strstr($this->query, $regs[0]); |
|
2326
|
|
|
$this->query = substr($this->query, 0, -strlen($suite)); |
|
2327
|
|
|
|
|
2328
|
|
|
// on cherche les noms des x dans 0 AS x |
|
2329
|
|
|
// on remplace dans $suite le nom par vide() |
|
2330
|
|
|
preg_match_all('/\b0 AS\s*([^\s,]+)/', $this->query, $matches, PREG_PATTERN_ORDER); |
|
2331
|
|
|
foreach ($matches[1] as $m){ |
|
2332
|
|
|
$suite = str_replace($m, 'VIDE()', $suite); |
|
2333
|
|
|
} |
|
2334
|
|
|
$this->query .= $suite; |
|
2335
|
|
|
} |
|
2336
|
|
|
} |
|
2337
|
|
|
|
|
2338
|
|
|
// Correction possible des divisions entieres |
|
2339
|
|
|
// Le standard SQL (lequel? ou?) semble indiquer que |
|
2340
|
|
|
// a/b=c doit donner c entier si a et b sont entiers 4/3=1. |
|
2341
|
|
|
// C'est ce que retournent effectivement SQL Server et SQLite |
|
2342
|
|
|
// Ce n'est pas ce qu'applique MySQL qui retourne un reel : 4/3=1.333... |
|
2343
|
|
|
// |
|
2344
|
|
|
// On peut forcer la conversion en multipliant par 1.0 avant la division |
|
2345
|
|
|
// /!\ SQLite 3.5.9 Debian/Ubuntu est victime d'un bug en plus ! |
|
2346
|
|
|
// cf. https://bugs.launchpad.net/ubuntu/+source/sqlite3/+bug/254228 |
|
2347
|
|
|
// http://www.sqlite.org/cvstrac/tktview?tn=3202 |
|
2348
|
|
|
// (4*1.0/3) n'est pas rendu dans ce cas ! |
|
2349
|
|
|
# $this->query = str_replace('/','* 1.00 / ',$this->query); |
|
2350
|
|
|
|
|
2351
|
|
|
|
|
2352
|
|
|
// Correction critere REGEXP, non reconnu en sqlite2 |
|
2353
|
|
|
if (($this->sqlite_version==2) && (strpos($this->query, 'REGEXP')!==false)){ |
|
2354
|
|
|
$this->query = preg_replace('/([^\s\(]*)(\s*)REGEXP(\s*)([^\s\)]*)/', 'REGEXP($4, $1)', $this->query); |
|
2355
|
|
|
} |
|
2356
|
|
|
|
|
2357
|
|
|
// |
|
2358
|
|
|
// 3) Remise en place des textes d'origine |
|
2359
|
|
|
// |
|
2360
|
|
|
// Correction Antiquotes et echappements |
|
2361
|
|
|
// ` => rien |
|
2362
|
|
View Code Duplication |
if (strpos($this->query,'`')!==false) |
|
|
|
|
|
|
2363
|
|
|
$this->query = str_replace('`','', $this->query); |
|
2364
|
|
|
|
|
2365
|
|
|
$this->query = query_reinjecte_textes($this->query, $textes); |
|
|
|
|
|
|
2366
|
|
|
|
|
2367
|
|
|
return $this->query; |
|
2368
|
|
|
} |
|
2369
|
|
|
|
|
2370
|
|
|
|
|
2371
|
|
|
/** |
|
2372
|
|
|
* les callbacks |
|
2373
|
|
|
* remplacer DATE_ / INTERVAL par DATE...strtotime |
|
2374
|
|
|
* http://doc.spip.org/@_remplacerDateParTime |
|
2375
|
|
|
* |
|
2376
|
|
|
* @param $matches |
|
2377
|
|
|
* @return string |
|
2378
|
|
|
*/ |
|
2379
|
|
|
function _remplacerDateParTime($matches){ |
|
|
|
|
|
|
2380
|
|
|
$op = strtoupper($matches[1]=='ADD') ? '+' : '-'; |
|
2381
|
|
|
return "datetime$matches[2] '$op$matches[3] $matches[4]')"; |
|
2382
|
|
|
} |
|
2383
|
|
|
|
|
2384
|
|
|
/** |
|
2385
|
|
|
* callback ou l'on remplace FIELD(table,i,j,k...) par CASE WHEN table=i THEN n ... ELSE 0 END |
|
2386
|
|
|
* http://doc.spip.org/@_remplacerFieldParCase |
|
2387
|
|
|
* |
|
2388
|
|
|
* @param $matches |
|
2389
|
|
|
* @return string |
|
2390
|
|
|
*/ |
|
2391
|
|
|
function _remplacerFieldParCase($matches){ |
|
|
|
|
|
|
2392
|
|
|
$fields = substr($matches[0], 6, -1); // ne recuperer que l'interieur X de field(X) |
|
2393
|
|
|
$t = explode(',', $fields); |
|
2394
|
|
|
$index = array_shift($t); |
|
2395
|
|
|
|
|
2396
|
|
|
$res = ''; |
|
2397
|
|
|
$n = 0; |
|
2398
|
|
|
foreach ($t as $v){ |
|
2399
|
|
|
$n++; |
|
2400
|
|
|
$res .= "\nWHEN $index=$v THEN $n"; |
|
2401
|
|
|
} |
|
2402
|
|
|
return "CASE $res ELSE 0 END "; |
|
2403
|
|
|
} |
|
2404
|
|
|
|
|
2405
|
|
|
} |
|
2406
|
|
|
|
|
2407
|
|
|
?> |
|
|
|
|
|
|
2408
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.