|
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
|
|
|
if (!defined('_ECRIRE_INC_VERSION')) return; |
|
14
|
|
|
|
|
15
|
|
|
// infos : |
|
16
|
|
|
// il ne faut pas avoir de PDO::CONSTANTE dans ce fichier sinon php4 se tue ! |
|
17
|
|
|
// idem, il ne faut pas de $obj->toto()->toto sinon php4 se tue ! |
|
18
|
|
|
|
|
19
|
|
|
# todo : get/set_caracteres ? |
|
20
|
|
|
|
|
21
|
|
|
|
|
22
|
|
|
/* |
|
23
|
|
|
* |
|
24
|
|
|
* regroupe le maximum de fonctions qui peuvent cohabiter |
|
25
|
|
|
* D'abord les fonctions d'abstractions de SPIP |
|
26
|
|
|
* |
|
27
|
|
|
*/ |
|
28
|
|
|
// http://doc.spip.org/@req_sqlite_dist |
|
29
|
|
|
function req_sqlite_dist($addr, $port, $login, $pass, $db='', $prefixe='', $sqlite_version=''){ |
|
30
|
|
|
static $last_connect = array(); |
|
31
|
|
|
|
|
32
|
|
|
// si provient de selectdb |
|
33
|
|
|
// un code pour etre sur que l'on vient de select_db() |
|
34
|
|
|
if (strpos($db, $code = '@selectdb@')!==false) { |
|
35
|
|
View Code Duplication |
foreach (array('addr','port','login','pass','prefixe') as $a){ |
|
|
|
|
|
|
36
|
|
|
$$a = $last_connect[$a]; |
|
37
|
|
|
} |
|
38
|
|
|
$db = str_replace($code, '', $db); |
|
39
|
|
|
} |
|
40
|
|
|
|
|
41
|
|
|
/* |
|
42
|
|
|
* En sqlite, seule l'adresse du fichier est importante. |
|
43
|
|
|
* Ce sera $db le nom, et le path _DIR_DB |
|
44
|
|
|
*/ |
|
45
|
|
|
_sqlite_init(); |
|
46
|
|
|
|
|
47
|
|
|
// un nom de base demande et impossible d'obtenir la base, on s'en va |
|
48
|
|
|
if ($db && !is_file($f = _DIR_DB . $db . '.sqlite') && !is_writable(_DIR_DB)) |
|
49
|
|
|
return false; |
|
50
|
|
|
|
|
51
|
|
|
|
|
52
|
|
|
// charger les modules sqlite au besoin |
|
53
|
|
|
if (!_sqlite_charger_version($sqlite_version)) { |
|
54
|
|
|
spip_log("Impossible de trouver/charger le module SQLite ($sqlite_version)!"); |
|
55
|
|
|
return false; |
|
56
|
|
|
} |
|
57
|
|
|
|
|
58
|
|
|
// chargement des constantes |
|
59
|
|
|
// il ne faut pas definir les constantes avant d'avoir charge les modules sqlite |
|
60
|
|
|
$define = "spip_sqlite".$sqlite_version."_constantes"; |
|
61
|
|
|
$define(); |
|
62
|
|
|
|
|
63
|
|
|
$ok = false; |
|
|
|
|
|
|
64
|
|
|
if (!$db){ |
|
65
|
|
|
// si installation -> base temporaire tant qu'on ne connait pas son vrai nom |
|
66
|
|
|
if (defined('_ECRIRE_INSTALL') && _ECRIRE_INSTALL){ |
|
67
|
|
|
// creation d'une base temporaire pour le debut d'install |
|
68
|
|
|
$db = "_sqlite".$sqlite_version."_install"; |
|
69
|
|
|
$tmp = _DIR_DB . $db . ".sqlite"; |
|
70
|
|
View Code Duplication |
if ($sqlite_version == 3) { |
|
|
|
|
|
|
71
|
|
|
$ok = $link = new PDO("sqlite:$tmp"); |
|
72
|
|
|
} else { |
|
73
|
|
|
$ok = $link = sqlite_open($tmp, _SQLITE_CHMOD, $err); |
|
74
|
|
|
} |
|
75
|
|
|
// sinon, on arrete finalement |
|
76
|
|
|
} else { |
|
77
|
|
|
return false; |
|
78
|
|
|
} |
|
79
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
80
|
|
|
// Ouvrir (eventuellement creer la base) |
|
81
|
|
|
// si pas de version fourni, on essaie la 3, sinon la 2 |
|
82
|
|
|
if ($sqlite_version == 3) { |
|
83
|
|
|
$ok = $link = new PDO("sqlite:$f"); |
|
|
|
|
|
|
84
|
|
|
} else { |
|
85
|
|
|
$ok = $link = sqlite_open($f, _SQLITE_CHMOD, $err); |
|
86
|
|
|
} |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
|
|
if (!$ok){ |
|
90
|
|
|
spip_log("Impossible d'ouvrir la base de donnee SQLite ($sqlite_version) : $f "); |
|
91
|
|
|
return false; |
|
92
|
|
|
} |
|
93
|
|
|
|
|
94
|
|
View Code Duplication |
if ($link) { |
|
|
|
|
|
|
95
|
|
|
$last_connect = array ( |
|
96
|
|
|
'addr' => $addr, |
|
97
|
|
|
'port' => $port, |
|
98
|
|
|
'login' => $login, |
|
99
|
|
|
'pass' => $pass, |
|
100
|
|
|
'db' => $db, |
|
101
|
|
|
'prefixe' => $prefixe, |
|
102
|
|
|
); |
|
103
|
|
|
} |
|
104
|
|
|
|
|
105
|
|
|
return array( |
|
106
|
|
|
'db' => $db, |
|
107
|
|
|
'prefixe' => $prefixe ? $prefixe : $db, |
|
108
|
|
|
'link' => $link, |
|
109
|
|
|
); |
|
110
|
|
|
} |
|
111
|
|
|
|
|
112
|
|
|
|
|
113
|
|
|
|
|
114
|
|
|
// Fonction de requete generale, munie d'une trace a la demande |
|
115
|
|
|
// http://doc.spip.org/@spip_sqlite_query |
|
116
|
|
|
function spip_sqlite_query($query, $serveur='',$requeter=true) { |
|
117
|
|
|
#spip_log("spip_sqlite_query() > $query"); |
|
118
|
|
|
_sqlite_init(); |
|
119
|
|
|
|
|
120
|
|
|
$requete = new sqlite_traiter_requete($query, $serveur); |
|
121
|
|
|
$requete->traduire_requete(); // mysql -> sqlite |
|
122
|
|
|
if (!$requeter) return $requete->query; |
|
123
|
|
|
return $requete->executer_requete(); |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
|
|
127
|
|
|
/* ordre alphabetique pour les autres */ |
|
128
|
|
|
|
|
129
|
|
|
// http://doc.spip.org/@spip_sqlite_alter |
|
130
|
|
|
function spip_sqlite_alter($query, $serveur='',$requeter=true){ |
|
|
|
|
|
|
131
|
|
|
|
|
132
|
|
|
$query = spip_sqlite_query("ALTER $query",$serveur,false); |
|
133
|
|
|
|
|
134
|
|
|
/* |
|
135
|
|
|
* la il faut faire les transformations |
|
136
|
|
|
* si ALTER TABLE x (DROP|CHANGE) y |
|
137
|
|
|
* |
|
138
|
|
|
* 1) recuperer "ALTER TABLE table " |
|
139
|
|
|
* 2) spliter les sous requetes (,) |
|
140
|
|
|
* 3) faire chaque requete independemment |
|
141
|
|
|
*/ |
|
142
|
|
|
|
|
143
|
|
|
// 1 |
|
144
|
|
|
if (preg_match("/\s*(ALTER(\s*IGNORE)?\s*TABLE\s*([^\s]*))\s*(.*)?/is", $query, $regs)){ |
|
145
|
|
|
$debut = $regs[1]; |
|
146
|
|
|
$table = $regs[3]; |
|
147
|
|
|
$suite = $regs[4]; |
|
148
|
|
|
} else { |
|
149
|
|
|
spip_log("SQLite : Probleme de ALTER TABLE mal forme dans $query", 'sqlite'); |
|
150
|
|
|
return false; |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
// 2 |
|
154
|
|
|
// il faudrait une regexp pour eviter de spliter ADD PRIMARY KEY (colA, colB) |
|
155
|
|
|
// tout en cassant "ADD PRIMARY KEY (colA, colB), ADD INDEX (chose)"... en deux |
|
156
|
|
|
// ou revoir l'api de sql_alter en creant un |
|
157
|
|
|
// sql_alter_table($table,array($actions)); |
|
158
|
|
|
$todo = explode(',', $suite); |
|
159
|
|
|
|
|
160
|
|
|
// on remet les morceaux dechires ensembles... que c'est laid ! |
|
161
|
|
|
$todo2 = array(); $i=0; |
|
162
|
|
|
$ouverte = false; |
|
163
|
|
View Code Duplication |
while ($do = array_shift($todo)) { |
|
|
|
|
|
|
164
|
|
|
$todo2[$i] = isset($todo2[$i]) ? $todo2[$i] . "," . $do : $do; |
|
165
|
|
|
$o=(false!==strpos($do,"(")); |
|
166
|
|
|
$f=(false!==strpos($do,")")); |
|
167
|
|
|
if ($o AND !$f) $ouverte=true; |
|
168
|
|
|
elseif ($f) $ouverte=false; |
|
169
|
|
|
if (!$ouverte) $i++; |
|
170
|
|
|
} |
|
171
|
|
|
|
|
172
|
|
|
// 3 |
|
173
|
|
|
$resultats = array(); |
|
|
|
|
|
|
174
|
|
|
foreach ($todo2 as $do){ |
|
175
|
|
|
$do = trim($do); |
|
176
|
|
|
if (!preg_match('/(DROP PRIMARY KEY|DROP INDEX|DROP COLUMN|DROP' |
|
177
|
|
|
.'|CHANGE COLUMN|CHANGE|MODIFY|RENAME TO|RENAME' |
|
178
|
|
|
.'|ADD PRIMARY KEY|ADD INDEX|ADD COLUMN|ADD' |
|
179
|
|
|
.')\s*([^\s]*)\s*(.*)?/', $do, $matches)){ |
|
180
|
|
|
spip_log("SQLite : Probleme de ALTER TABLE, utilisation non reconnue dans : $do \n(requete d'origine : $query)", 'sqlite'); |
|
181
|
|
|
return false; |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
$cle = strtoupper($matches[1]); |
|
185
|
|
|
$colonne_origine = $matches[2]; |
|
186
|
|
|
$colonne_destination = ''; |
|
|
|
|
|
|
187
|
|
|
|
|
188
|
|
|
$def = $matches[3]; |
|
189
|
|
|
|
|
190
|
|
|
// eluder une eventuelle clause before|after|first inutilisable |
|
191
|
|
|
$defr = rtrim(preg_replace('/(BEFORE|AFTER|FIRST)(.*)$/is','', $def)); |
|
192
|
|
|
// remplacer les definitions venant de mysql |
|
193
|
|
|
$defr = _sqlite_remplacements_definitions_table($defr); |
|
194
|
|
|
|
|
195
|
|
|
// reinjecter dans le do |
|
196
|
|
|
$do = str_replace($def,$defr,$do); |
|
197
|
|
|
$def = $defr; |
|
198
|
|
|
|
|
199
|
|
|
switch($cle){ |
|
200
|
|
|
// suppression d'un index |
|
201
|
|
|
case 'DROP INDEX': |
|
202
|
|
|
$nom_index = $colonne_origine; |
|
203
|
|
|
spip_sqlite_drop_index($nom_index, $table, $serveur); |
|
204
|
|
|
break; |
|
205
|
|
|
|
|
206
|
|
|
// suppression d'une pk |
|
207
|
|
View Code Duplication |
case 'DROP PRIMARY KEY': |
|
|
|
|
|
|
208
|
|
|
if (!_sqlite_modifier_table( |
|
209
|
|
|
$table, |
|
210
|
|
|
$colonne_origine, |
|
211
|
|
|
array('key'=>array('PRIMARY KEY'=>'')), |
|
212
|
|
|
$serveur)){ |
|
213
|
|
|
return false; |
|
214
|
|
|
} |
|
215
|
|
|
break; |
|
216
|
|
|
// suppression d'une colonne |
|
217
|
|
|
case 'DROP COLUMN': |
|
218
|
|
View Code Duplication |
case 'DROP': |
|
|
|
|
|
|
219
|
|
|
if (!_sqlite_modifier_table( |
|
220
|
|
|
$table, |
|
221
|
|
|
array($colonne_origine=>""), |
|
222
|
|
|
'', |
|
223
|
|
|
$serveur)){ |
|
224
|
|
|
return false; |
|
225
|
|
|
} |
|
226
|
|
|
break; |
|
227
|
|
|
|
|
228
|
|
|
case 'CHANGE COLUMN': |
|
229
|
|
|
case 'CHANGE': |
|
230
|
|
|
// recuperer le nom de la future colonne |
|
231
|
|
|
$def = trim($def); |
|
232
|
|
|
$colonne_destination = substr($def, 0, strpos($def,' ')); |
|
233
|
|
|
$def = substr($def, strlen($colonne_destination)+1); |
|
234
|
|
|
|
|
235
|
|
|
if (!_sqlite_modifier_table( |
|
236
|
|
|
$table, |
|
237
|
|
|
array($colonne_origine=>$colonne_destination), |
|
238
|
|
|
array('field'=>array($colonne_destination=>$def)), |
|
239
|
|
|
$serveur)){ |
|
240
|
|
|
return false; |
|
241
|
|
|
} |
|
242
|
|
|
break; |
|
243
|
|
|
|
|
244
|
|
View Code Duplication |
case 'MODIFY': |
|
|
|
|
|
|
245
|
|
|
if (!_sqlite_modifier_table( |
|
246
|
|
|
$table, |
|
247
|
|
|
$colonne_origine, |
|
248
|
|
|
array('field'=>array($colonne_origine=>$def)), |
|
249
|
|
|
$serveur)){ |
|
250
|
|
|
return false; |
|
251
|
|
|
} |
|
252
|
|
|
break; |
|
253
|
|
|
|
|
254
|
|
|
// pas geres en sqlite2 |
|
255
|
|
|
case 'RENAME': |
|
256
|
|
|
$do = "RENAME TO" . substr($do,6); |
|
257
|
|
|
case 'RENAME TO': |
|
258
|
|
|
if (_sqlite_is_version(3, '', $serveur)){ |
|
259
|
|
|
$requete = new sqlite_traiter_requete("$debut $do", $serveur); |
|
260
|
|
|
if (!$requete->executer_requete()){ |
|
261
|
|
|
spip_log("SQLite : Erreur ALTER TABLE / RENAME : $query", 'sqlite'); |
|
262
|
|
|
return false; |
|
263
|
|
|
} |
|
264
|
|
|
// artillerie lourde pour sqlite2 ! |
|
265
|
|
|
} else { |
|
266
|
|
|
$table_dest = trim(substr($do, 9)); |
|
267
|
|
|
if (!_sqlite_modifier_table(array($table=>$table_dest), '', '', $serveur)){ |
|
268
|
|
|
spip_log("SQLite : Erreur ALTER TABLE / RENAME : $query", 'sqlite'); |
|
269
|
|
|
return false; |
|
270
|
|
|
} |
|
271
|
|
|
} |
|
272
|
|
|
break; |
|
273
|
|
|
|
|
274
|
|
|
// ajout d'une pk |
|
275
|
|
|
case 'ADD PRIMARY KEY': |
|
276
|
|
|
$pk = trim(substr($do,16)); |
|
277
|
|
|
$pk = ($pk[0]=='(') ? substr($pk,1,-1) : $pk; |
|
278
|
|
|
if (!_sqlite_modifier_table( |
|
279
|
|
|
$table, |
|
280
|
|
|
$colonne_origine, |
|
281
|
|
|
array('key'=>array('PRIMARY KEY'=>$pk)), |
|
282
|
|
|
$serveur)){ |
|
283
|
|
|
return false; |
|
284
|
|
|
} |
|
285
|
|
|
break; |
|
286
|
|
|
// ajout d'un index |
|
287
|
|
|
case 'ADD INDEX': |
|
288
|
|
|
// peut etre "(colonne)" ou "nom_index (colonnes)" |
|
289
|
|
|
// bug potentiel si qqn met "(colonne, colonne)" |
|
290
|
|
|
// |
|
291
|
|
|
// nom_index (colonnes) |
|
292
|
|
|
if ($def) { |
|
293
|
|
|
$colonnes = substr($def,1,-1); |
|
294
|
|
|
$nom_index = $colonne_origine; |
|
295
|
|
|
} |
|
296
|
|
|
else { |
|
297
|
|
|
// (colonne) |
|
298
|
|
|
if ($colonne_origine[0] == "(") { |
|
299
|
|
|
$colonnes = substr($colonne_origine,1,-1); |
|
300
|
|
View Code Duplication |
if (false!==strpos(",",$colonnes)) { |
|
|
|
|
|
|
301
|
|
|
spip_log("SQLite : Erreur, impossible de creer un index sur plusieurs colonnes" |
|
302
|
|
|
." sans qu'il ait de nom ($table, ($colonnes))", 'sqlite'); |
|
303
|
|
|
break; |
|
304
|
|
|
} else { |
|
305
|
|
|
$nom_index = $colonnes; |
|
306
|
|
|
} |
|
307
|
|
|
} |
|
308
|
|
|
// nom_index |
|
309
|
|
|
else { |
|
310
|
|
|
$nom_index = $colonnes = $colonne_origine ; |
|
311
|
|
|
} |
|
312
|
|
|
} |
|
313
|
|
|
spip_sqlite_create_index($nom_index, $table, $colonnes, $serveur); |
|
314
|
|
|
break; |
|
315
|
|
|
|
|
316
|
|
|
// pas geres en sqlite2 |
|
317
|
|
|
case 'ADD COLUMN': |
|
318
|
|
|
$do = "ADD".substr($do, 10); |
|
319
|
|
|
case 'ADD': |
|
320
|
|
|
default: |
|
321
|
|
|
if (_sqlite_is_version(3, '', $serveur)){ |
|
322
|
|
|
$requete = new sqlite_traiter_requete("$debut $do", $serveur); |
|
323
|
|
|
if (!$requete->executer_requete()){ |
|
324
|
|
|
spip_log("SQLite : Erreur ALTER TABLE / ADD : $query", 'sqlite'); |
|
325
|
|
|
return false; |
|
326
|
|
|
} |
|
327
|
|
|
break; |
|
328
|
|
|
// artillerie lourde pour sqlite2 ! |
|
329
|
|
|
} else { |
|
330
|
|
|
$def = trim(substr($do, 3)); |
|
331
|
|
|
$colonne_ajoutee = substr($def, 0, strpos($def,' ')); |
|
332
|
|
|
$def = substr($def, strlen($colonne_ajoutee)+1); |
|
333
|
|
|
if (!_sqlite_modifier_table($table, array($colonne_ajoutee), array('field'=>array($colonne_ajoutee=>$def)), $serveur)){ |
|
334
|
|
|
spip_log("SQLite : Erreur ALTER TABLE / ADD : $query", 'sqlite'); |
|
335
|
|
|
return false; |
|
336
|
|
|
} |
|
337
|
|
|
} |
|
338
|
|
|
break; |
|
339
|
|
|
} |
|
340
|
|
|
// tout est bon, ouf ! |
|
341
|
|
|
spip_log("SQLite ($serveur) : Changements OK : $debut $do"); |
|
342
|
|
|
} |
|
343
|
|
|
|
|
344
|
|
|
spip_log("SQLite ($serveur) : fin ALTER TABLE OK !"); |
|
345
|
|
|
return true; |
|
346
|
|
|
} |
|
347
|
|
|
|
|
348
|
|
|
|
|
349
|
|
|
// Fonction de creation d'une table SQL nommee $nom |
|
350
|
|
|
// http://doc.spip.org/@spip_sqlite_create |
|
351
|
|
|
function spip_sqlite_create($nom, $champs, $cles, $autoinc=false, $temporary=false, $serveur='',$requeter=true) { |
|
352
|
|
|
$query = _sqlite_requete_create($nom, $champs, $cles, $autoinc, $temporary, $ifnotexists=true, $serveur, $requeter); |
|
353
|
|
|
if (!$query) return false; |
|
354
|
|
|
$res = spip_sqlite_query($query, $serveur, $requeter); |
|
355
|
|
|
|
|
356
|
|
|
// SQLite ne cree pas les KEY sur les requetes CREATE TABLE |
|
357
|
|
|
// il faut donc les faire creer ensuite |
|
358
|
|
|
if (!$requeter) return $res; |
|
359
|
|
|
|
|
360
|
|
|
$ok = $res ? true : false; |
|
361
|
|
|
if ($ok) { |
|
362
|
|
|
foreach($cles as $k=>$v) { |
|
363
|
|
|
if (strpos($k, "KEY ") === 0) { |
|
364
|
|
|
$index = preg_replace("/KEY +/", '',$k); |
|
365
|
|
|
$ok &= $res = spip_sqlite_create_index($index, $nom, $v, $serveur); |
|
|
|
|
|
|
366
|
|
|
} |
|
367
|
|
|
} |
|
368
|
|
|
} |
|
369
|
|
|
return $ok ? true : false; |
|
370
|
|
|
} |
|
371
|
|
|
|
|
372
|
|
|
/** |
|
373
|
|
|
* Fonction pour creer une base de donnees SQLite |
|
374
|
|
|
* |
|
375
|
|
|
* @param string $nom le nom de la base (sans l'extension de fichier) |
|
376
|
|
|
* @param string $serveur le nom de la connexion |
|
377
|
|
|
* @param string $option options |
|
|
|
|
|
|
378
|
|
|
* |
|
379
|
|
|
* @return bool true si la base est creee. |
|
380
|
|
|
**/ |
|
381
|
|
|
function spip_sqlite_create_base($nom, $serveur='', $option=true) { |
|
|
|
|
|
|
382
|
|
|
$f = _DIR_DB . $nom . '.sqlite'; |
|
383
|
|
|
if (_sqlite_is_version(2, '', $serveur)) { |
|
384
|
|
|
$ok = sqlite_open($f, _SQLITE_CHMOD, $err); |
|
385
|
|
|
} else { |
|
386
|
|
|
$ok = new PDO("sqlite:$f"); |
|
387
|
|
|
} |
|
388
|
|
|
if ($ok) { |
|
389
|
|
|
unset($ok); |
|
390
|
|
|
return true; |
|
391
|
|
|
} |
|
392
|
|
|
unset($ok); |
|
393
|
|
|
return false; |
|
394
|
|
|
} |
|
395
|
|
|
|
|
396
|
|
|
|
|
397
|
|
|
// Fonction de creation d'une vue SQL nommee $nom |
|
398
|
|
|
// http://doc.spip.org/@spip_sqlite_create_view |
|
399
|
|
View Code Duplication |
function spip_sqlite_create_view($nom, $query_select, $serveur='',$requeter=true) { |
|
|
|
|
|
|
400
|
|
|
if (!$query_select) return false; |
|
401
|
|
|
// vue deja presente |
|
402
|
|
|
if (sql_showtable($nom, false, $serveur)) { |
|
403
|
|
|
spip_log("Echec creation d'une vue sql ($nom) car celle-ci existe deja (serveur:$serveur)"); |
|
404
|
|
|
return false; |
|
405
|
|
|
} |
|
406
|
|
|
|
|
407
|
|
|
$query = "CREATE VIEW $nom AS ". $query_select; |
|
408
|
|
|
return spip_sqlite_query($query, $serveur, $requeter); |
|
409
|
|
|
} |
|
410
|
|
|
|
|
411
|
|
|
/** |
|
412
|
|
|
* Fonction de creation d'un INDEX |
|
413
|
|
|
* |
|
414
|
|
|
* @param string $nom : nom de l'index |
|
415
|
|
|
* @param string $table : table sql de l'index |
|
416
|
|
|
* @param string/array $champs : liste de champs sur lesquels s'applique l'index |
|
|
|
|
|
|
417
|
|
|
* @param string $serveur : nom de la connexion sql utilisee |
|
418
|
|
|
* @param bool $requeter : true pour executer la requete ou false pour retourner le texte de la requete |
|
419
|
|
|
* |
|
420
|
|
|
* @return bool ou requete |
|
421
|
|
|
*/ |
|
422
|
|
|
function spip_sqlite_create_index($nom, $table, $champs, $serveur='', $requeter=true) { |
|
423
|
|
View Code Duplication |
if (!($nom OR $table OR $champs)) { |
|
|
|
|
|
|
424
|
|
|
spip_log("Champ manquant pour creer un index sqlite ($nom, $table, (".join(',',$champs)."))"); |
|
425
|
|
|
return false; |
|
426
|
|
|
} |
|
427
|
|
|
|
|
428
|
|
|
// SQLite ne differentie pas noms des index en fonction des tables |
|
429
|
|
|
// il faut donc creer des noms uniques d'index pour une base sqlite |
|
430
|
|
|
$nom = $table.'_'.$nom; |
|
431
|
|
|
// enlever d'eventuelles parentheses deja presentes sur champs |
|
432
|
|
View Code Duplication |
if (!is_array($champs)){ |
|
|
|
|
|
|
433
|
|
|
if ($champs[0]=="(") $champs = substr($champs,1,-1); |
|
434
|
|
|
$champs = array($champs); |
|
435
|
|
|
} |
|
436
|
|
|
$query = "CREATE INDEX $nom ON $table (" . join(',',$champs) . ")"; |
|
437
|
|
|
$res = spip_sqlite_query($query, $serveur, $requeter); |
|
438
|
|
|
if (!$requeter) return $res; |
|
439
|
|
|
if ($res) |
|
|
|
|
|
|
440
|
|
|
return true; |
|
441
|
|
|
else |
|
442
|
|
|
return false; |
|
443
|
|
|
} |
|
444
|
|
|
|
|
445
|
|
|
// en PDO/sqlite3, il faut calculer le count par une requete count(*) |
|
446
|
|
|
// pour les resultats de SELECT |
|
447
|
|
|
// cela est fait sans spip_sqlite_query() |
|
448
|
|
|
// http://doc.spip.org/@spip_sqlite_count |
|
449
|
|
|
function spip_sqlite_count($r, $serveur='',$requeter=true) { |
|
|
|
|
|
|
450
|
|
|
if (!$r) return 0; |
|
451
|
|
|
|
|
452
|
|
|
if (_sqlite_is_version(3, '', $serveur)){ |
|
453
|
|
|
// select ou autre (insert, update,...) ? |
|
454
|
|
|
if (isset($r->spipSqliteRowCount)) { |
|
455
|
|
|
// Ce compte est faux s'il y a des limit dans la requete :( |
|
456
|
|
|
// il retourne le nombre d'enregistrements sans le limit |
|
457
|
|
|
return $r->spipSqliteRowCount; |
|
458
|
|
|
} else { |
|
459
|
|
|
return $r->rowCount(); |
|
460
|
|
|
} |
|
461
|
|
|
} else { |
|
462
|
|
|
return sqlite_num_rows($r); |
|
463
|
|
|
} |
|
464
|
|
|
} |
|
465
|
|
|
|
|
466
|
|
|
|
|
467
|
|
|
// http://doc.spip.org/@spip_sqlite_countsel |
|
468
|
|
|
function spip_sqlite_countsel($from = array(), $where = array(), $groupby = '', $having = array(), $serveur='',$requeter=true) { |
|
469
|
|
|
$c = !$groupby ? '*' : ('DISTINCT ' . (is_string($groupby) ? $groupby : join(',', $groupby))); |
|
470
|
|
|
$r = spip_sqlite_select("COUNT($c)", $from, $where,'', '', '',$having, $serveur, $requeter); |
|
471
|
|
|
if ((is_resource($r) or is_object($r)) && $requeter) { // ressource : sqlite2, object : sqlite3 |
|
472
|
|
|
if (_sqlite_is_version(3,'',$serveur)){ |
|
473
|
|
|
list($n) = spip_sqlite_fetch($r, SPIP_SQLITE3_NUM, $serveur); |
|
474
|
|
|
} else { |
|
475
|
|
|
list($n) = spip_sqlite_fetch($r, SPIP_SQLITE2_NUM, $serveur); |
|
476
|
|
|
} |
|
477
|
|
|
spip_sqlite_free($r,$serveur); |
|
478
|
|
|
} |
|
479
|
|
|
return $n; |
|
|
|
|
|
|
480
|
|
|
} |
|
481
|
|
|
|
|
482
|
|
|
|
|
483
|
|
|
|
|
484
|
|
|
// http://doc.spip.org/@spip_sqlite_delete |
|
485
|
|
|
function spip_sqlite_delete($table, $where='', $serveur='',$requeter=true) { |
|
486
|
|
|
$res = spip_sqlite_query( |
|
487
|
|
|
_sqlite_calculer_expression('DELETE FROM', $table, ',') |
|
488
|
|
|
. _sqlite_calculer_expression('WHERE', $where), |
|
489
|
|
|
$serveur, $requeter); |
|
490
|
|
|
|
|
491
|
|
|
// renvoyer la requete inerte si demandee |
|
492
|
|
|
if (!$requeter) return $res; |
|
493
|
|
|
|
|
494
|
|
|
if ($res){ |
|
495
|
|
|
$link = _sqlite_link($serveur); |
|
496
|
|
|
if (_sqlite_is_version(3, $link)) { |
|
497
|
|
|
return $res->rowCount(); |
|
498
|
|
|
} else { |
|
499
|
|
|
return sqlite_changes($link); |
|
500
|
|
|
} |
|
501
|
|
|
} |
|
502
|
|
|
else |
|
503
|
|
|
return false; |
|
504
|
|
|
} |
|
505
|
|
|
|
|
506
|
|
|
|
|
507
|
|
|
// http://doc.spip.org/@spip_sqlite_drop_table |
|
508
|
|
|
function spip_sqlite_drop_table($table, $exist='', $serveur='',$requeter=true) { |
|
509
|
|
|
if ($exist) $exist =" IF EXISTS"; |
|
510
|
|
|
|
|
511
|
|
|
/* simuler le IF EXISTS - version 2 */ |
|
512
|
|
View Code Duplication |
if ($exist && _sqlite_is_version(2, '', $serveur)){ |
|
|
|
|
|
|
513
|
|
|
$a = spip_sqlite_showtable($table, $serveur); |
|
514
|
|
|
if (!$a) return true; |
|
515
|
|
|
$exist = ''; |
|
516
|
|
|
} |
|
517
|
|
|
if (spip_sqlite_query("DROP TABLE$exist $table", $serveur, $requeter)) |
|
|
|
|
|
|
518
|
|
|
return true; |
|
519
|
|
|
else |
|
520
|
|
|
return false; |
|
521
|
|
|
} |
|
522
|
|
|
|
|
523
|
|
|
// supprime une vue |
|
524
|
|
|
// http://doc.spip.org/@spip_sqlite_drop_view |
|
525
|
|
|
function spip_sqlite_drop_view($view, $exist='', $serveur='',$requeter=true) { |
|
526
|
|
|
if ($exist) $exist =" IF EXISTS"; |
|
527
|
|
|
|
|
528
|
|
|
/* simuler le IF EXISTS - version 2 */ |
|
529
|
|
View Code Duplication |
if ($exist && _sqlite_is_version(2, '', $serveur)){ |
|
|
|
|
|
|
530
|
|
|
$a = spip_sqlite_showtable($view, $serveur); |
|
531
|
|
|
if (!$a) return true; |
|
532
|
|
|
$exist = ''; |
|
533
|
|
|
} |
|
534
|
|
|
|
|
535
|
|
|
return spip_sqlite_query("DROP VIEW$exist $view", $serveur, $requeter); |
|
536
|
|
|
} |
|
537
|
|
|
|
|
538
|
|
|
/** |
|
539
|
|
|
* Fonction de suppression d'un INDEX |
|
540
|
|
|
* |
|
541
|
|
|
* @param string $nom : nom de l'index |
|
542
|
|
|
* @param string $table : table sql de l'index |
|
543
|
|
|
* @param string $serveur : nom de la connexion sql utilisee |
|
544
|
|
|
* @param bool $requeter : true pour executer la requete ou false pour retourner le texte de la requete |
|
545
|
|
|
* |
|
546
|
|
|
* @return bool ou requete |
|
547
|
|
|
*/ |
|
548
|
|
|
function spip_sqlite_drop_index($nom, $table, $serveur='', $requeter=true) { |
|
549
|
|
|
if (!($nom OR $table)) { |
|
550
|
|
|
spip_log("Champ manquant pour supprimer un index sqlite ($nom, $table)"); |
|
551
|
|
|
return false; |
|
552
|
|
|
} |
|
553
|
|
|
|
|
554
|
|
|
// SQLite ne differentie pas noms des index en fonction des tables |
|
555
|
|
|
// il faut donc creer des noms uniques d'index pour une base sqlite |
|
556
|
|
|
$index = $table.'_'.$nom; |
|
557
|
|
|
$exist =" IF EXISTS"; |
|
558
|
|
|
|
|
559
|
|
|
/* simuler le IF EXISTS - version 2 */ |
|
560
|
|
|
if (_sqlite_is_version(2, '', $serveur)){ |
|
561
|
|
|
$a = spip_sqlite_showtable($table, $serveur); |
|
562
|
|
|
if (!isset($a['key']['KEY '.$nom])) return true; |
|
563
|
|
|
$exist = ''; |
|
564
|
|
|
} |
|
565
|
|
|
|
|
566
|
|
|
$query = "DROP INDEX$exist $index"; |
|
567
|
|
|
return spip_sqlite_query($query, $serveur, $requeter); |
|
568
|
|
|
} |
|
569
|
|
|
|
|
570
|
|
|
/** |
|
571
|
|
|
* Retourne la derniere erreur generee |
|
572
|
|
|
* |
|
573
|
|
|
* @param $serveur nom de la connexion |
|
574
|
|
|
* @return string erreur eventuelle |
|
575
|
|
|
**/ |
|
576
|
|
|
// http://doc.spip.org/@spip_sqlite_error |
|
577
|
|
|
function spip_sqlite_error($query='', $serveur='') { |
|
578
|
|
|
$link = _sqlite_link($serveur); |
|
579
|
|
|
|
|
580
|
|
|
if (_sqlite_is_version(3, $link)) { |
|
581
|
|
|
$errs = $link->errorInfo(); |
|
582
|
|
|
$s = ''; |
|
583
|
|
|
foreach($errs as $n=>$e){ |
|
584
|
|
|
$s .= "\n$n : $e"; |
|
585
|
|
|
} |
|
586
|
|
|
} elseif ($link) { |
|
587
|
|
|
$s = sqlite_error_string(sqlite_last_error($link)); |
|
588
|
|
|
} else { |
|
589
|
|
|
$s = ": aucune ressource sqlite (link)"; |
|
590
|
|
|
} |
|
591
|
|
|
if ($s) spip_log("$s - $query", 'sqlite'); |
|
592
|
|
|
return $s; |
|
593
|
|
|
} |
|
594
|
|
|
|
|
595
|
|
|
/** |
|
596
|
|
|
* Retourne le numero de la derniere erreur SQL |
|
597
|
|
|
* (sauf que SQLite semble ne connaitre que 0 ou 1) |
|
598
|
|
|
* |
|
599
|
|
|
* @param $serveur nom de la connexion |
|
600
|
|
|
* @return int 0 pas d'erreur / 1 une erreur |
|
601
|
|
|
**/ |
|
602
|
|
|
// http://doc.spip.org/@spip_sqlite_errno |
|
603
|
|
|
function spip_sqlite_errno($serveur='') { |
|
604
|
|
|
$link = _sqlite_link($serveur); |
|
605
|
|
|
|
|
606
|
|
|
if (_sqlite_is_version(3, $link)){ |
|
607
|
|
|
$t = $link->errorInfo(); |
|
608
|
|
|
$s = $t[1]; |
|
609
|
|
|
} elseif ($link) { |
|
610
|
|
|
$s = sqlite_last_error($link); |
|
611
|
|
|
} else { |
|
612
|
|
|
$s = ": aucune ressource sqlite (link)"; |
|
613
|
|
|
} |
|
614
|
|
|
|
|
615
|
|
|
if ($s) spip_log("Erreur sqlite $s"); |
|
616
|
|
|
|
|
617
|
|
|
return $s ? 1 : 0; |
|
618
|
|
|
} |
|
619
|
|
|
|
|
620
|
|
|
|
|
621
|
|
|
// http://doc.spip.org/@spip_sqlite_explain |
|
622
|
|
|
function spip_sqlite_explain($query, $serveur='',$requeter=true){ |
|
623
|
|
|
if (strpos(ltrim($query), 'SELECT') !== 0) return array(); |
|
624
|
|
|
|
|
625
|
|
|
$requete = new sqlite_traiter_requete("$query", $serveur); |
|
626
|
|
|
$requete->traduire_requete(); // mysql -> sqlite |
|
627
|
|
|
$requete->query = 'EXPLAIN ' . $requete->query; |
|
628
|
|
|
if (!$requeter) return $requete; |
|
629
|
|
|
// on ne trace pas ces requetes, sinon on obtient un tracage sans fin... |
|
630
|
|
|
$requete->tracer = false; |
|
631
|
|
|
$r = $requete->executer_requete(); |
|
632
|
|
|
|
|
633
|
|
|
return $r ? spip_sqlite_fetch($r, null, $serveur) : false; // hum ? etrange ca... a verifier |
|
634
|
|
|
} |
|
635
|
|
|
|
|
636
|
|
|
|
|
637
|
|
|
// http://doc.spip.org/@spip_sqlite_fetch |
|
638
|
|
|
function spip_sqlite_fetch($r, $t='', $serveur='',$requeter=true) { |
|
|
|
|
|
|
639
|
|
|
|
|
640
|
|
|
$link = _sqlite_link($serveur); |
|
641
|
|
|
if (!$t) { |
|
642
|
|
|
if (_sqlite_is_version(3, $link)) { |
|
643
|
|
|
$t = SPIP_SQLITE3_ASSOC; |
|
644
|
|
|
} else { |
|
645
|
|
|
$t = SPIP_SQLITE2_ASSOC; |
|
646
|
|
|
} |
|
647
|
|
|
} |
|
648
|
|
|
|
|
649
|
|
|
|
|
650
|
|
|
if (_sqlite_is_version(3, $link)){ |
|
651
|
|
|
if ($r) $retour = $r->fetch($t); |
|
652
|
|
|
} elseif ($r) { |
|
653
|
|
|
$retour = sqlite_fetch_array($r, $t); |
|
654
|
|
|
} |
|
655
|
|
|
|
|
656
|
|
|
// les version 2 et 3 parfois renvoie des 'table.titre' au lieu de 'titre' tout court ! pff ! |
|
657
|
|
|
// suppression de 'table.' pour toutes les cles (c'est un peu violent !) |
|
658
|
|
|
if ($retour){ |
|
659
|
|
|
$new = array(); |
|
660
|
|
|
foreach ($retour as $cle=>$val){ |
|
|
|
|
|
|
661
|
|
|
if (($pos = strpos($cle, '.'))!==false){ |
|
662
|
|
|
$cle = substr($cle,++$pos); |
|
663
|
|
|
} |
|
664
|
|
|
$new[$cle] = $val; |
|
665
|
|
|
} |
|
666
|
|
|
$retour = &$new; |
|
667
|
|
|
} |
|
668
|
|
|
|
|
669
|
|
|
return $retour; |
|
670
|
|
|
} |
|
671
|
|
|
|
|
672
|
|
|
|
|
673
|
|
|
function spip_sqlite_seek($r, $row_number, $serveur='',$requeter=true) { |
|
|
|
|
|
|
674
|
|
|
if ($r){ |
|
675
|
|
|
$link = _sqlite_link($serveur); |
|
676
|
|
|
if (_sqlite_is_version(3, $link)){ |
|
677
|
|
|
// encore un truc de bien fichu : PDO ne PEUT PAS faire de seek ou de rewind... |
|
678
|
|
|
// je me demande si pour sqlite 3 il ne faudrait pas mieux utiliser |
|
679
|
|
|
// les nouvelles fonctions sqlite3_xx (mais encore moins presentes...) |
|
680
|
|
|
return false; |
|
681
|
|
|
} |
|
682
|
|
|
else { |
|
683
|
|
|
return sqlite_seek($r, $row_number); |
|
684
|
|
|
} |
|
685
|
|
|
} |
|
686
|
|
|
} |
|
687
|
|
|
|
|
688
|
|
|
|
|
689
|
|
|
// http://doc.spip.org/@spip_sqlite_free |
|
690
|
|
|
function spip_sqlite_free(&$r, $serveur='',$requeter=true) { |
|
|
|
|
|
|
691
|
|
|
unset($r); |
|
692
|
|
|
return true; |
|
693
|
|
|
//return sqlite_free_result($r); |
|
694
|
|
|
} |
|
695
|
|
|
|
|
696
|
|
|
|
|
697
|
|
|
// http://doc.spip.org/@spip_sqlite_get_charset |
|
698
|
|
|
function spip_sqlite_get_charset($charset=array(), $serveur='',$requeter=true){ |
|
|
|
|
|
|
699
|
|
|
//$c = !$charset ? '' : (" LIKE "._q($charset['charset'])); |
|
700
|
|
|
//return spip_sqlite_fetch(sqlite_query(_sqlite_link($serveur), "SHOW CHARACTER SET$c"), NULL, $serveur); |
|
701
|
|
|
} |
|
702
|
|
|
|
|
703
|
|
|
|
|
704
|
|
|
// http://doc.spip.org/@spip_sqlite_hex |
|
705
|
|
|
function spip_sqlite_hex($v){ |
|
706
|
|
|
return hexdec($v); |
|
707
|
|
|
} |
|
708
|
|
|
|
|
709
|
|
|
|
|
710
|
|
|
// http://doc.spip.org/@spip_sqlite_in |
|
711
|
|
View Code Duplication |
function spip_sqlite_in($val, $valeurs, $not='', $serveur='',$requeter=true) { |
|
|
|
|
|
|
712
|
|
|
$n = $i = 0; |
|
713
|
|
|
$in_sql =""; |
|
714
|
|
|
while ($n = strpos($valeurs, ',', $n+1)) { |
|
715
|
|
|
if ((++$i) >= 255) { |
|
716
|
|
|
$in_sql .= "($val $not IN (" . |
|
717
|
|
|
substr($valeurs, 0, $n) . |
|
718
|
|
|
"))\n" . |
|
719
|
|
|
($not ? "AND\t" : "OR\t"); |
|
720
|
|
|
$valeurs = substr($valeurs, $n+1); |
|
721
|
|
|
$i = $n = 0; |
|
722
|
|
|
} |
|
723
|
|
|
} |
|
724
|
|
|
$in_sql .= "($val $not IN ($valeurs))"; |
|
725
|
|
|
|
|
726
|
|
|
return "($in_sql)"; |
|
727
|
|
|
} |
|
728
|
|
|
|
|
729
|
|
|
|
|
730
|
|
|
// http://doc.spip.org/@spip_sqlite_insert |
|
731
|
|
|
function spip_sqlite_insert($table, $champs, $valeurs, $desc='', $serveur='',$requeter=true) { |
|
|
|
|
|
|
732
|
|
|
|
|
733
|
|
|
$connexion = $GLOBALS['connexions'][$serveur ? $serveur : 0]; |
|
734
|
|
|
$prefixe = $connexion['prefixe']; |
|
735
|
|
|
$sqlite = $connexion['link']; |
|
736
|
|
|
$db = $connexion['db']; |
|
|
|
|
|
|
737
|
|
|
|
|
738
|
|
|
if ($prefixe) $table = preg_replace('/^spip/', $prefixe, $table); |
|
739
|
|
|
|
|
740
|
|
|
|
|
741
|
|
View Code Duplication |
if (isset($_GET['var_profile'])) { |
|
|
|
|
|
|
742
|
|
|
include_spip('public/tracer'); |
|
743
|
|
|
$t = trace_query_start(); |
|
744
|
|
|
} else $t = 0 ; |
|
745
|
|
|
|
|
746
|
|
|
$query="INSERT INTO $table ".($champs?"$champs VALUES $valeurs":"DEFAULT VALUES"); |
|
747
|
|
|
|
|
748
|
|
|
|
|
749
|
|
|
if ($r = spip_sqlite_query($query, $serveur, $requeter)) { |
|
750
|
|
|
if (!$requeter) return $r; |
|
751
|
|
|
|
|
752
|
|
|
if (_sqlite_is_version(3, $sqlite)) $nb = $sqlite->lastInsertId(); |
|
753
|
|
|
else $nb = sqlite_last_insert_rowid($sqlite); |
|
754
|
|
|
} else $nb = 0; |
|
755
|
|
|
|
|
756
|
|
|
$err = spip_sqlite_error($query, $serveur); |
|
757
|
|
|
return $t ? trace_query_end($query, $t, $nb, $err, $serveur) : $nb; |
|
758
|
|
|
|
|
759
|
|
|
} |
|
760
|
|
|
|
|
761
|
|
|
|
|
762
|
|
|
// http://doc.spip.org/@spip_sqlite_insertq |
|
763
|
|
|
function spip_sqlite_insertq($table, $couples=array(), $desc=array(), $serveur='',$requeter=true) { |
|
764
|
|
|
if (!$desc) $desc = description_table($table); |
|
|
|
|
|
|
765
|
|
|
if (!$desc) die("$table insertion sans description"); |
|
|
|
|
|
|
766
|
|
|
$fields = isset($desc['field'])?$desc['field']:array(); |
|
767
|
|
|
|
|
768
|
|
|
foreach ($couples as $champ => $val) { |
|
769
|
|
|
$couples[$champ]= _sqlite_calculer_cite($val, $fields[$champ]); |
|
770
|
|
|
} |
|
771
|
|
|
|
|
772
|
|
|
// recherche de champs 'timestamp' pour mise a jour auto de ceux-ci |
|
773
|
|
|
$couples = _sqlite_ajouter_champs_timestamp($table, $couples, $desc, $serveur); |
|
774
|
|
|
|
|
775
|
|
|
// si aucun champ donne pour l'insertion, on en cherche un avec un DEFAULT |
|
776
|
|
|
// sinon sqlite3 ne veut pas inserer |
|
777
|
|
|
$cles = $valeurs = ""; |
|
778
|
|
|
if (count($couples)) { |
|
779
|
|
|
$cles = "(".join(',',array_keys($couples)).")"; |
|
780
|
|
|
$valeurs = "(".join(',', $couples).")"; |
|
781
|
|
|
} |
|
782
|
|
|
|
|
783
|
|
|
return spip_sqlite_insert($table, $cles , $valeurs , $desc, $serveur, $requeter); |
|
784
|
|
|
} |
|
785
|
|
|
|
|
786
|
|
|
|
|
787
|
|
|
|
|
788
|
|
|
// http://doc.spip.org/@spip_sqlite_insertq_multi |
|
789
|
|
|
function spip_sqlite_insertq_multi($table, $tab_couples=array(), $desc=array(), $serveur='',$requeter=true) { |
|
790
|
|
|
foreach ($tab_couples as $couples) { |
|
791
|
|
|
$retour = spip_sqlite_insertq($table, $couples, $desc, $serveur, $requeter); |
|
792
|
|
|
} |
|
793
|
|
|
// renvoie le dernier id d'autoincrement ajoute |
|
794
|
|
|
return $retour; |
|
|
|
|
|
|
795
|
|
|
} |
|
796
|
|
|
|
|
797
|
|
|
|
|
798
|
|
|
|
|
799
|
|
|
// http://doc.spip.org/@spip_sqlite_listdbs |
|
800
|
|
|
function spip_sqlite_listdbs($serveur='',$requeter=true) { |
|
|
|
|
|
|
801
|
|
|
_sqlite_init(); |
|
802
|
|
|
|
|
803
|
|
|
if (!is_dir($d = substr(_DIR_DB,0,-1))){ |
|
804
|
|
|
return array(); |
|
805
|
|
|
} |
|
806
|
|
|
|
|
807
|
|
|
include_spip('inc/flock'); |
|
808
|
|
|
$bases = preg_files($d, $pattern = '(.*)\.sqlite$'); |
|
809
|
|
|
$bds = array(); |
|
810
|
|
|
|
|
811
|
|
|
foreach($bases as $b){ |
|
812
|
|
|
// pas de bases commencant pas sqlite |
|
813
|
|
|
// (on s'en sert pour l'installation pour simuler la presence d'un serveur) |
|
814
|
|
|
// les bases sont de la forme _sqliteX_tmp_spip_install.sqlite |
|
815
|
|
|
if (strpos($b, '_sqlite')) continue; |
|
816
|
|
|
$bds[] = preg_replace(";.*/$pattern;iS",'$1', $b); |
|
817
|
|
|
} |
|
818
|
|
|
|
|
819
|
|
|
return $bds; |
|
820
|
|
|
} |
|
821
|
|
|
|
|
822
|
|
|
|
|
823
|
|
|
// http://doc.spip.org/@spip_sqlite_multi |
|
824
|
|
|
function spip_sqlite_multi ($objet, $lang) { |
|
825
|
|
|
$r = "PREG_REPLACE(" |
|
826
|
|
|
. $objet |
|
827
|
|
|
. ",'<multi>.*[\[]" |
|
828
|
|
|
. $lang |
|
829
|
|
|
. "[\]]([^\[]*).*</multi>', '$1') AS multi"; |
|
830
|
|
|
return $r; |
|
831
|
|
|
} |
|
832
|
|
|
|
|
833
|
|
|
|
|
834
|
|
|
/** |
|
835
|
|
|
* Optimise une table SQL |
|
836
|
|
|
* Note: Sqlite optimise TOUTE un fichier sinon rien. |
|
837
|
|
|
* On evite donc 2 traitements sur la meme base dans un hit. |
|
838
|
|
|
* |
|
839
|
|
|
* @param $table nom de la table a optimiser |
|
840
|
|
|
* @param $serveur nom de la connexion |
|
841
|
|
|
* @param $requeter effectuer la requete ? sinon retourner son code |
|
842
|
|
|
* @return bool|string true / false / requete |
|
843
|
|
|
**/ |
|
844
|
|
|
// http://doc.spip.org/@spip_sqlite_optimize |
|
845
|
|
|
function spip_sqlite_optimize($table, $serveur='', $requeter=true) { |
|
|
|
|
|
|
846
|
|
|
static $do = false; |
|
847
|
|
|
if ($requeter and $do) {return true;} |
|
848
|
|
|
if ($requeter) { $do = true; } |
|
849
|
|
|
return spip_sqlite_query("VACUUM", $serveur, $requeter); |
|
850
|
|
|
} |
|
851
|
|
|
|
|
852
|
|
|
|
|
853
|
|
|
// avoir le meme comportement que _q() |
|
854
|
|
|
function spip_sqlite_quote($v, $type=''){ |
|
855
|
|
|
if (is_array($v)) return join(",", array_map('spip_sqlite_quote', $v)); |
|
856
|
|
|
if (is_int($v)) return strval($v); |
|
857
|
|
View Code Duplication |
if (strncmp($v,'0x',2)==0 AND ctype_xdigit(substr($v,2))) return hexdec(substr($v,2)); |
|
|
|
|
|
|
858
|
|
|
if ($type === 'int' AND !$v) return '0'; |
|
859
|
|
|
|
|
860
|
|
|
if (function_exists('sqlite_escape_string')) { |
|
861
|
|
|
return "'" . sqlite_escape_string($v) . "'"; |
|
862
|
|
|
} |
|
863
|
|
|
|
|
864
|
|
|
// trouver un link sqlite3 pour faire l'echappement |
|
865
|
|
|
foreach ($GLOBALS['connexions'] as $s) { |
|
866
|
|
|
if (_sqlite_is_version(3, $l = $s['link'])){ |
|
867
|
|
|
return $l->quote($v); |
|
868
|
|
|
} |
|
869
|
|
|
} |
|
870
|
|
|
} |
|
871
|
|
|
|
|
872
|
|
|
|
|
873
|
|
|
/** |
|
874
|
|
|
* Tester si une date est proche de la valeur d'un champ |
|
875
|
|
|
* |
|
876
|
|
|
* @param string $champ le nom du champ a tester |
|
877
|
|
|
* @param int $interval valeur de l'interval : -1, 4, ... |
|
878
|
|
|
* @param string $unite utite utilisee (DAY, MONTH, YEAR, ...) |
|
879
|
|
|
* @return string expression SQL |
|
880
|
|
|
**/ |
|
881
|
|
|
function spip_sqlite_date_proche($champ, $interval, $unite) |
|
882
|
|
|
{ |
|
883
|
|
|
$op = $interval > 0 ? '>' : '<'; |
|
884
|
|
|
return "($champ $op datetime('" . date("Y-m-d H:i:s") . "', '$interval $unite'))"; |
|
885
|
|
|
} |
|
886
|
|
|
|
|
887
|
|
|
|
|
888
|
|
|
// http://doc.spip.org/@spip_sqlite_replace |
|
889
|
|
|
function spip_sqlite_replace($table, $couples, $desc=array(), $serveur='',$requeter=true) { |
|
|
|
|
|
|
890
|
|
|
if (!$desc) $desc = description_table($table); |
|
|
|
|
|
|
891
|
|
|
if (!$desc) die("$table insertion sans description"); |
|
|
|
|
|
|
892
|
|
|
$fields = isset($desc['field'])?$desc['field']:array(); |
|
893
|
|
|
|
|
894
|
|
|
foreach ($couples as $champ => $val) { |
|
895
|
|
|
$couples[$champ]= _sqlite_calculer_cite($val, $fields[$champ]); |
|
896
|
|
|
} |
|
897
|
|
|
|
|
898
|
|
|
// recherche de champs 'timestamp' pour mise a jour auto de ceux-ci |
|
899
|
|
|
$couples = _sqlite_ajouter_champs_timestamp($table, $couples, $desc, $serveur); |
|
900
|
|
|
|
|
901
|
|
|
return spip_sqlite_query("REPLACE INTO $table (" . join(',',array_keys($couples)) . ') VALUES (' .join(',',$couples) . ')', $serveur); |
|
902
|
|
|
} |
|
903
|
|
|
|
|
904
|
|
|
|
|
905
|
|
|
|
|
906
|
|
|
// http://doc.spip.org/@spip_sqlite_replace_multi |
|
907
|
|
|
function spip_sqlite_replace_multi($table, $tab_couples, $desc=array(), $serveur='',$requeter=true) { |
|
908
|
|
|
|
|
909
|
|
|
// boucler pour trainter chaque requete independemment |
|
910
|
|
|
foreach ($tab_couples as $couples){ |
|
911
|
|
|
$retour = spip_sqlite_replace($table, $couples, $desc, $serveur,$requeter); |
|
912
|
|
|
} |
|
913
|
|
|
// renvoie le dernier id |
|
914
|
|
|
return $retour; |
|
|
|
|
|
|
915
|
|
|
} |
|
916
|
|
|
|
|
917
|
|
|
|
|
918
|
|
|
// http://doc.spip.org/@spip_sqlite_select |
|
919
|
|
|
function spip_sqlite_select($select, $from, $where='', $groupby='', $orderby='', $limit='', $having='', $serveur='',$requeter=true) { |
|
920
|
|
|
|
|
921
|
|
|
// version() n'est pas connu de sqlite |
|
922
|
|
|
$select = str_replace('version()', 'sqlite_version()',$select); |
|
923
|
|
|
|
|
924
|
|
|
// recomposer from |
|
925
|
|
|
$from = (!is_array($from) ? $from : _sqlite_calculer_select_as($from)); |
|
926
|
|
|
|
|
927
|
|
|
$query = |
|
928
|
|
|
_sqlite_calculer_expression('SELECT', $select, ', ') |
|
929
|
|
|
. _sqlite_calculer_expression('FROM', $from, ', ') |
|
930
|
|
|
. _sqlite_calculer_expression('WHERE', $where) |
|
931
|
|
|
. _sqlite_calculer_expression('GROUP BY', $groupby, ',') |
|
932
|
|
|
. _sqlite_calculer_expression('HAVING', $having) |
|
933
|
|
|
. ($orderby ? ("\nORDER BY " . _sqlite_calculer_order($orderby)) :'') |
|
934
|
|
|
. ($limit ? "\nLIMIT $limit" : ''); |
|
935
|
|
|
|
|
936
|
|
|
return spip_sqlite_query($query, $serveur, $requeter); |
|
937
|
|
|
} |
|
938
|
|
|
|
|
939
|
|
|
|
|
940
|
|
|
// http://doc.spip.org/@spip_sqlite_selectdb |
|
941
|
|
|
function spip_sqlite_selectdb($db, $serveur='',$requeter=true) { |
|
|
|
|
|
|
942
|
|
|
_sqlite_init(); |
|
943
|
|
|
|
|
944
|
|
|
// interdire la creation d'une nouvelle base, |
|
945
|
|
|
// sauf si on est dans l'installation |
|
946
|
|
|
if (!is_file($f = _DIR_DB . $db . '.sqlite') |
|
947
|
|
|
&& (!defined('_ECRIRE_INSTALL') || !_ECRIRE_INSTALL)) |
|
948
|
|
|
return false; |
|
949
|
|
|
|
|
950
|
|
|
// se connecter a la base indiquee |
|
951
|
|
|
// avec les identifiants connus |
|
952
|
|
|
$index = $serveur ? $serveur : 0; |
|
953
|
|
|
|
|
954
|
|
|
if ($link = spip_connect_db('', '', '', '', '@selectdb@' . $db , $serveur, '', '')){ |
|
955
|
|
View Code Duplication |
if (($db==$link['db']) && $GLOBALS['connexions'][$index] = $link) |
|
|
|
|
|
|
956
|
|
|
return $db; |
|
957
|
|
|
} else { |
|
958
|
|
|
spip_log("Impossible de selectionner la base $db", 'sqlite'); |
|
959
|
|
|
return false; |
|
960
|
|
|
} |
|
961
|
|
|
|
|
962
|
|
|
} |
|
963
|
|
|
|
|
964
|
|
|
|
|
965
|
|
|
// http://doc.spip.org/@spip_sqlite_set_charset |
|
966
|
|
|
function spip_sqlite_set_charset($charset, $serveur='',$requeter=true){ |
|
|
|
|
|
|
967
|
|
|
#spip_log("changement de charset sql : "."SET NAMES "._q($charset)); |
|
968
|
|
|
# return spip_sqlite_query("SET NAMES ". spip_sqlite_quote($charset), $serveur); //<-- Passe pas ! |
|
969
|
|
|
} |
|
970
|
|
|
|
|
971
|
|
|
|
|
972
|
|
|
// http://doc.spip.org/@spip_sqlite_showbase |
|
973
|
|
|
function spip_sqlite_showbase($match, $serveur='',$requeter=true){ |
|
974
|
|
|
// type est le type d'entrée : table / index / view |
|
975
|
|
|
// on ne retourne que les tables (?) et non les vues... |
|
976
|
|
|
# ESCAPE non supporte par les versions sqlite <3 |
|
977
|
|
|
# return spip_sqlite_query("SELECT name FROM sqlite_master WHERE type='table' AND tbl_name LIKE "._q($match)." ESCAPE '\'", $serveur, $requeter); |
|
978
|
|
|
$match = preg_quote($match); |
|
979
|
|
|
$match = str_replace("\\\_","[[TIRETBAS]]",$match); |
|
980
|
|
|
$match = str_replace("\\\%","[[POURCENT]]",$match); |
|
981
|
|
|
$match = str_replace("_",".",$match); |
|
982
|
|
|
$match = str_replace("%",".*",$match); |
|
983
|
|
|
$match = str_replace("[[TIRETBAS]]","_",$match); |
|
984
|
|
|
$match = str_replace("[[POURCENT]]","%",$match); |
|
985
|
|
|
$match = "^$match$"; |
|
986
|
|
|
return spip_sqlite_query("SELECT name FROM sqlite_master WHERE type='table' AND tbl_name REGEXP "._q($match), $serveur, $requeter); |
|
987
|
|
|
} |
|
988
|
|
|
|
|
989
|
|
|
|
|
990
|
|
|
// http://doc.spip.org/@spip_sqlite_showtable |
|
991
|
|
|
function spip_sqlite_showtable($nom_table, $serveur='',$requeter=true){ |
|
992
|
|
|
|
|
993
|
|
|
$query = |
|
994
|
|
|
'SELECT sql, type FROM' |
|
995
|
|
|
. ' (SELECT * FROM sqlite_master UNION ALL' |
|
996
|
|
|
. ' SELECT * FROM sqlite_temp_master)' |
|
997
|
|
|
. " WHERE tbl_name LIKE '$nom_table'" |
|
998
|
|
|
. " AND type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%'" |
|
999
|
|
|
. ' ORDER BY substr(type,2,1), name'; |
|
1000
|
|
|
|
|
1001
|
|
|
$a = spip_sqlite_query($query, $serveur, $requeter); |
|
1002
|
|
|
if (!$a) return ""; |
|
1003
|
|
|
if (!$requeter) return $a; |
|
1004
|
|
|
if (!($a = spip_sqlite_fetch($a, null, $serveur))) return ""; |
|
1005
|
|
|
$vue = ($a['type'] == 'view'); // table | vue |
|
1006
|
|
|
|
|
1007
|
|
|
// c'est une table |
|
1008
|
|
|
// il faut parser le create |
|
1009
|
|
|
if (!$vue) { |
|
1010
|
|
|
if (!preg_match("/^[^(),]*\((([^()]*(\([^()]*\))?[^()]*)*)\)[^()]*$/", array_shift($a), $r)) |
|
1011
|
|
|
return ""; |
|
1012
|
|
|
else { |
|
1013
|
|
|
$dec = $r[1]; |
|
1014
|
|
View Code Duplication |
if (preg_match("/^(.*?),([^,]*KEY.*)$/s", $dec, $r)) { |
|
|
|
|
|
|
1015
|
|
|
$namedkeys = $r[2]; |
|
1016
|
|
|
$dec = $r[1]; |
|
1017
|
|
|
} |
|
1018
|
|
|
else |
|
1019
|
|
|
$namedkeys = ""; |
|
1020
|
|
|
|
|
1021
|
|
|
$fields = array(); |
|
1022
|
|
View Code Duplication |
foreach (explode(",",$dec) as $v) { |
|
|
|
|
|
|
1023
|
|
|
preg_match("/^\s*([^\s]+)\s+(.*)/",$v,$r); |
|
1024
|
|
|
// trim car 'Sqlite Manager' (plugin Firefox) utilise des guillemets |
|
1025
|
|
|
// lorsqu'on modifie une table avec cet outil. |
|
1026
|
|
|
// possible que d'autres fassent de meme. |
|
1027
|
|
|
$fields[ trim(strtolower($r[1]),'"') ] = $r[2]; |
|
1028
|
|
|
} |
|
1029
|
|
|
// key inclues dans la requete |
|
1030
|
|
|
$keys = array(); |
|
1031
|
|
View Code Duplication |
foreach(preg_split('/\)\s*,?/',$namedkeys) as $v) { |
|
|
|
|
|
|
1032
|
|
|
if (preg_match("/^\s*([^(]*)\((.*)$/",$v,$r)) { |
|
1033
|
|
|
$k = str_replace("`", '', trim($r[1])); |
|
1034
|
|
|
$t = trim(strtolower(str_replace("`", '', $r[2])), '"'); |
|
1035
|
|
|
if ($k && !isset($keys[$k])) $keys[$k] = $t; else $keys[] = $t; |
|
1036
|
|
|
} |
|
1037
|
|
|
} |
|
1038
|
|
|
// sinon ajouter les key index |
|
1039
|
|
|
$query = |
|
1040
|
|
|
'SELECT name,sql FROM' |
|
1041
|
|
|
. ' (SELECT * FROM sqlite_master UNION ALL' |
|
1042
|
|
|
. ' SELECT * FROM sqlite_temp_master)' |
|
1043
|
|
|
. " WHERE tbl_name LIKE '$nom_table'" |
|
1044
|
|
|
. " AND type='index' AND name NOT LIKE 'sqlite_%'" |
|
1045
|
|
|
. 'ORDER BY substr(type,2,1), name'; |
|
1046
|
|
|
$a = spip_sqlite_query($query, $serveur, $requeter); |
|
1047
|
|
|
while ($r = spip_sqlite_fetch($a, null, $serveur)) { |
|
1048
|
|
|
$key = str_replace($nom_table.'_','',$r['name']); // enlever le nom de la table ajoute a l'index |
|
1049
|
|
|
$colonnes = preg_replace(',.*\((.*)\).*,','$1',$r['sql']); |
|
1050
|
|
|
$keys['KEY '.$key] = $colonnes; |
|
1051
|
|
|
} |
|
1052
|
|
|
} |
|
1053
|
|
|
// c'est une vue, on liste les champs disponibles simplement |
|
1054
|
|
|
} else { |
|
1055
|
|
|
if ($res = sql_fetsel('*',$nom_table,'','','','1','',$serveur)){ // limit 1 |
|
1056
|
|
|
$fields = array(); |
|
1057
|
|
|
foreach($res as $c=>$v) $fields[$c]=''; |
|
1058
|
|
|
$keys = array(); |
|
1059
|
|
|
} else { |
|
1060
|
|
|
return ""; |
|
1061
|
|
|
} |
|
1062
|
|
|
} |
|
1063
|
|
|
return array('field' => $fields, 'key' => $keys); |
|
1064
|
|
|
|
|
1065
|
|
|
} |
|
1066
|
|
|
|
|
1067
|
|
|
|
|
1068
|
|
|
// http://doc.spip.org/@spip_sqlite_update |
|
1069
|
|
|
function spip_sqlite_update($table, $champs, $where='', $desc='', $serveur='',$requeter=true) { |
|
1070
|
|
|
// recherche de champs 'timestamp' pour mise a jour auto de ceux-ci |
|
1071
|
|
|
$champs = _sqlite_ajouter_champs_timestamp($table, $champs, $desc, $serveur); |
|
1072
|
|
|
|
|
1073
|
|
|
$set = array(); |
|
1074
|
|
|
foreach ($champs as $champ => $val) |
|
1075
|
|
|
$set[] = $champ . "=$val"; |
|
1076
|
|
View Code Duplication |
if (!empty($set)) |
|
|
|
|
|
|
1077
|
|
|
return spip_sqlite_query( |
|
1078
|
|
|
_sqlite_calculer_expression('UPDATE', $table, ',') |
|
1079
|
|
|
. _sqlite_calculer_expression('SET', $set, ',') |
|
1080
|
|
|
. _sqlite_calculer_expression('WHERE', $where), |
|
1081
|
|
|
$serveur, $requeter); |
|
1082
|
|
|
} |
|
1083
|
|
|
|
|
1084
|
|
|
|
|
1085
|
|
|
// http://doc.spip.org/@spip_sqlite_updateq |
|
1086
|
|
|
function spip_sqlite_updateq($table, $champs, $where='', $desc=array(), $serveur='',$requeter=true) { |
|
1087
|
|
|
|
|
1088
|
|
|
if (!$champs) return; |
|
1089
|
|
|
if (!$desc) $desc = description_table($table); |
|
|
|
|
|
|
1090
|
|
|
if (!$desc) die("$table insertion sans description"); |
|
|
|
|
|
|
1091
|
|
|
$fields = $desc['field']; |
|
1092
|
|
|
|
|
1093
|
|
|
// recherche de champs 'timestamp' pour mise a jour auto de ceux-ci |
|
1094
|
|
|
$champs = _sqlite_ajouter_champs_timestamp($table, $champs, $desc, $serveur); |
|
1095
|
|
|
|
|
1096
|
|
|
$set = array(); |
|
1097
|
|
|
foreach ($champs as $champ => $val) { |
|
1098
|
|
|
$set[] = $champ . '=' . _sqlite_calculer_cite($val, $fields[$champ]); |
|
1099
|
|
|
} |
|
1100
|
|
|
return spip_sqlite_query( |
|
1101
|
|
|
_sqlite_calculer_expression('UPDATE', $table, ',') |
|
1102
|
|
|
. _sqlite_calculer_expression('SET', $set, ',') |
|
1103
|
|
|
. _sqlite_calculer_expression('WHERE', $where), |
|
1104
|
|
|
$serveur, $requeter); |
|
1105
|
|
|
} |
|
1106
|
|
|
|
|
1107
|
|
|
|
|
1108
|
|
|
|
|
1109
|
|
|
/* |
|
1110
|
|
|
* |
|
1111
|
|
|
* Ensuite les fonctions non abstraites |
|
1112
|
|
|
* crees pour l'occasion de sqlite |
|
1113
|
|
|
* |
|
1114
|
|
|
*/ |
|
1115
|
|
|
|
|
1116
|
|
|
|
|
1117
|
|
|
// fonction pour la premiere connexion a un serveur SQLite |
|
1118
|
|
|
// http://doc.spip.org/@_sqlite_init |
|
1119
|
|
|
function _sqlite_init(){ |
|
1120
|
|
|
if (!defined('_DIR_DB')) define('_DIR_DB', _DIR_ETC . 'bases/'); |
|
1121
|
|
|
if (!defined('_SQLITE_CHMOD')) define('_SQLITE_CHMOD', _SPIP_CHMOD); |
|
1122
|
|
|
|
|
1123
|
|
|
if (!is_dir($d = _DIR_DB)){ |
|
1124
|
|
|
include_spip('inc/flock'); |
|
1125
|
|
|
sous_repertoire($d); |
|
1126
|
|
|
} |
|
1127
|
|
|
} |
|
1128
|
|
|
|
|
1129
|
|
|
|
|
1130
|
|
|
// teste la version sqlite du link en cours |
|
1131
|
|
|
// http://doc.spip.org/@_sqlite_is_version |
|
1132
|
|
|
function _sqlite_is_version($version='', $link='', $serveur='',$requeter=true){ |
|
|
|
|
|
|
1133
|
|
|
if ($link==='') $link = _sqlite_link($serveur); |
|
1134
|
|
|
if (!$link) return false; |
|
1135
|
|
|
if (is_a($link, 'PDO')){ |
|
1136
|
|
|
$v = 3; |
|
1137
|
|
|
} else { |
|
1138
|
|
|
$v = 2; |
|
1139
|
|
|
} |
|
1140
|
|
|
|
|
1141
|
|
|
if (!$version) return $v; |
|
1142
|
|
|
return ($version == $v); |
|
1143
|
|
|
} |
|
1144
|
|
|
|
|
1145
|
|
|
|
|
1146
|
|
|
// retrouver un link (et definir les fonctions externes sqlite->php) |
|
1147
|
|
|
// $recharger devient inutile (a supprimer ?) |
|
1148
|
|
|
// http://doc.spip.org/@_sqlite_link |
|
1149
|
|
|
function _sqlite_link($serveur = '', $recharger = false){ |
|
1150
|
|
|
static $charge = array(); |
|
1151
|
|
|
if ($recharger) $charge[$serveur] = false; |
|
1152
|
|
|
|
|
1153
|
|
|
$link = &$GLOBALS['connexions'][$serveur ? $serveur : 0]['link']; |
|
1154
|
|
|
|
|
1155
|
|
|
if ($link && !$charge[$serveur]){ |
|
1156
|
|
|
include_spip('req/sqlite_fonctions'); |
|
1157
|
|
|
_sqlite_init_functions($link); |
|
1158
|
|
|
$charge[$serveur] = true; |
|
1159
|
|
|
} |
|
1160
|
|
|
return $link; |
|
1161
|
|
|
} |
|
1162
|
|
|
|
|
1163
|
|
|
|
|
1164
|
|
|
/* ordre alphabetique pour les autres */ |
|
1165
|
|
|
|
|
1166
|
|
|
|
|
1167
|
|
|
// renvoie les bons echappements (pas sur les fonctions now()) |
|
1168
|
|
|
// http://doc.spip.org/@_sqlite_calculer_cite |
|
1169
|
|
|
function _sqlite_calculer_cite($v, $type) { |
|
1170
|
|
|
if (sql_test_date($type) AND preg_match('/^\w+\(/', $v)) |
|
1171
|
|
|
return $v; |
|
1172
|
|
|
if (sql_test_int($type)) { |
|
1173
|
|
|
if (is_numeric($v)) |
|
1174
|
|
|
return $v; |
|
1175
|
|
View Code Duplication |
if (ctype_xdigit(substr($v,2)) AND strncmp($v,'0x',2)==0) |
|
|
|
|
|
|
1176
|
|
|
return hexdec(substr($v,2)); |
|
1177
|
|
|
} |
|
1178
|
|
|
//else return ("'" . spip_sqlite_quote($v) . "'"); |
|
1179
|
|
|
return (spip_sqlite_quote($v)); |
|
1180
|
|
|
} |
|
1181
|
|
|
|
|
1182
|
|
|
|
|
1183
|
|
|
// renvoie grosso modo "$expression join($join, $v)" |
|
1184
|
|
|
// http://doc.spip.org/@_sqlite_calculer_expression |
|
1185
|
|
View Code Duplication |
function _sqlite_calculer_expression($expression, $v, $join = 'AND'){ |
|
|
|
|
|
|
1186
|
|
|
if (empty($v)) |
|
1187
|
|
|
return ''; |
|
1188
|
|
|
|
|
1189
|
|
|
$exp = "\n$expression "; |
|
1190
|
|
|
|
|
1191
|
|
|
if (!is_array($v)) { |
|
1192
|
|
|
return $exp . $v; |
|
1193
|
|
|
} else { |
|
1194
|
|
|
if (strtoupper($join) === 'AND') |
|
1195
|
|
|
return $exp . join("\n\t$join ", array_map('_sqlite_calculer_where', $v)); |
|
1196
|
|
|
else |
|
1197
|
|
|
return $exp . join($join, $v); |
|
1198
|
|
|
} |
|
1199
|
|
|
} |
|
1200
|
|
|
|
|
1201
|
|
|
|
|
1202
|
|
|
|
|
1203
|
|
|
|
|
1204
|
|
|
// pour conversion 0+x ? (pas la peine en sqlite) |
|
1205
|
|
|
// http://doc.spip.org/@_sqlite_calculer_order |
|
1206
|
|
|
function _sqlite_calculer_order($orderby) { |
|
1207
|
|
|
return (is_array($orderby)) ? join(", ", $orderby) : $orderby; |
|
1208
|
|
|
} |
|
1209
|
|
|
|
|
1210
|
|
|
|
|
1211
|
|
|
// renvoie des 'nom AS alias' |
|
1212
|
|
|
// http://doc.spip.org/@_sqlite_calculer_select_as |
|
1213
|
|
View Code Duplication |
function _sqlite_calculer_select_as($args){ |
|
|
|
|
|
|
1214
|
|
|
$res = ''; |
|
1215
|
|
|
foreach($args as $k => $v) { |
|
1216
|
|
|
if (substr($k,-1)=='@') { |
|
1217
|
|
|
// c'est une jointure qui se refere au from precedent |
|
1218
|
|
|
// pas de virgule |
|
1219
|
|
|
$res .= ' ' . $v ; |
|
1220
|
|
|
} |
|
1221
|
|
|
else { |
|
1222
|
|
|
if (!is_numeric($k)) { |
|
1223
|
|
|
$p = strpos($v, " "); |
|
1224
|
|
|
if ($p) |
|
1225
|
|
|
$v = substr($v,0,$p) . " AS '$k'" . substr($v,$p); |
|
1226
|
|
|
else $v .= " AS '$k'"; |
|
1227
|
|
|
} |
|
1228
|
|
|
$res .= ', ' . $v ; |
|
1229
|
|
|
} |
|
1230
|
|
|
} |
|
1231
|
|
|
return substr($res,2) . $join; |
|
|
|
|
|
|
1232
|
|
|
} |
|
1233
|
|
|
|
|
1234
|
|
|
|
|
1235
|
|
|
// renvoie les bonnes parentheses pour des where imbriquees |
|
1236
|
|
|
// http://doc.spip.org/@_sqlite_calculer_where |
|
1237
|
|
View Code Duplication |
function _sqlite_calculer_where($v){ |
|
|
|
|
|
|
1238
|
|
|
if (!is_array($v)) |
|
1239
|
|
|
return $v ; |
|
1240
|
|
|
|
|
1241
|
|
|
$op = array_shift($v); |
|
1242
|
|
|
if (!($n=count($v))) |
|
1243
|
|
|
return $op; |
|
1244
|
|
|
else { |
|
1245
|
|
|
$arg = _sqlite_calculer_where(array_shift($v)); |
|
1246
|
|
|
if ($n==1) { |
|
1247
|
|
|
return "$op($arg)"; |
|
1248
|
|
|
} else { |
|
1249
|
|
|
$arg2 = _sqlite_calculer_where(array_shift($v)); |
|
1250
|
|
|
if ($n==2) { |
|
1251
|
|
|
return "($arg $op $arg2)"; |
|
1252
|
|
|
} else return "($arg $op ($arg2) : $v[0])"; |
|
1253
|
|
|
} |
|
1254
|
|
|
} |
|
1255
|
|
|
} |
|
1256
|
|
|
|
|
1257
|
|
|
|
|
1258
|
|
|
|
|
1259
|
|
|
/* |
|
1260
|
|
|
* Charger les modules sqlite (si possible) (juste la version demandee), |
|
1261
|
|
|
* ou, si aucune version, renvoie les versions sqlite dispo |
|
1262
|
|
|
* sur ce serveur dans un array |
|
1263
|
|
|
*/ |
|
1264
|
|
|
// http://doc.spip.org/@_sqlite_charger_version |
|
1265
|
|
|
function _sqlite_charger_version($version=''){ |
|
1266
|
|
|
$versions = array(); |
|
1267
|
|
|
|
|
1268
|
|
|
// version 2 |
|
1269
|
|
|
if (!$version || $version == 2){ |
|
1270
|
|
|
if (charger_php_extension('sqlite')) { |
|
1271
|
|
|
$versions[]=2; |
|
1272
|
|
|
} |
|
1273
|
|
|
} |
|
1274
|
|
|
|
|
1275
|
|
|
// version 3 |
|
1276
|
|
|
if (!$version || $version == 3){ |
|
1277
|
|
|
if (charger_php_extension('pdo') && charger_php_extension('pdo_sqlite')) { |
|
1278
|
|
|
$versions[]=3; |
|
1279
|
|
|
} |
|
1280
|
|
|
} |
|
1281
|
|
|
if ($version) return in_array($version, $versions); |
|
1282
|
|
|
return $versions; |
|
1283
|
|
|
} |
|
1284
|
|
|
|
|
1285
|
|
|
|
|
1286
|
|
|
|
|
1287
|
|
|
/** |
|
1288
|
|
|
* Gestion des requetes ALTER non reconnues de SQLite : |
|
1289
|
|
|
* ALTER TABLE table DROP column |
|
1290
|
|
|
* ALTER TABLE table CHANGE [COLUMN] columnA columnB definition |
|
1291
|
|
|
* ALTER TABLE table MODIFY column definition |
|
1292
|
|
|
* ALTER TABLE table ADD|DROP PRIMARY KEY |
|
1293
|
|
|
* |
|
1294
|
|
|
* (MODIFY transforme en CHANGE columnA columnA) par spip_sqlite_alter() |
|
1295
|
|
|
* |
|
1296
|
|
|
* 1) creer une table B avec le nouveau format souhaite |
|
1297
|
|
|
* 2) copier la table d'origine A vers B |
|
1298
|
|
|
* 3) supprimer la table A |
|
1299
|
|
|
* 4) renommer la table B en A |
|
1300
|
|
|
* 5) remettre les index (qui sont supprimes avec la table A) |
|
1301
|
|
|
* |
|
1302
|
|
|
* @param string/array $table : nom_table, array(nom_table=>nom_futur) |
|
1303
|
|
|
* @param string/array $col : nom_colonne, array(nom_colonne=>nom_futur) |
|
1304
|
|
|
* @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', ...)) |
|
1305
|
|
|
* @param string $serveur : nom de la connexion sql en cours |
|
1306
|
|
|
* |
|
1307
|
|
|
*/ |
|
1308
|
|
|
// http://doc.spip.org/@_sqlite_modifier_table |
|
1309
|
|
|
function _sqlite_modifier_table($table, $colonne, $opt=array(), $serveur=''){ |
|
1310
|
|
|
|
|
1311
|
|
|
if (is_array($table)) { |
|
1312
|
|
|
reset($table); |
|
1313
|
|
|
list($table_origine,$table_destination) = each($table); |
|
1314
|
|
|
} else { |
|
1315
|
|
|
$table_origine = $table_destination = $table; |
|
1316
|
|
|
} |
|
1317
|
|
|
// ne prend actuellement qu'un changement |
|
1318
|
|
|
// mais pourra etre adapte pour changer plus qu'une colonne a la fois |
|
1319
|
|
|
if (is_array($colonne)) { |
|
1320
|
|
|
reset($colonne); |
|
1321
|
|
|
list($colonne_origine,$colonne_destination) = each($colonne); |
|
1322
|
|
|
} else { |
|
1323
|
|
|
$colonne_origine = $colonne_destination = $colonne; |
|
1324
|
|
|
} |
|
1325
|
|
|
if (!isset($opt['field'])) $opt['field'] = array(); |
|
1326
|
|
|
if (!isset($opt['key'])) $opt['key'] = array(); |
|
1327
|
|
|
|
|
1328
|
|
|
// si les noms de tables sont differents, pas besoin de table temporaire |
|
1329
|
|
|
// on prendra directement le nom de la future table |
|
1330
|
|
|
$meme_table = ($table_origine == $table_destination); |
|
1331
|
|
|
|
|
1332
|
|
|
$def_origine = sql_showtable($table_origine, false, $serveur); |
|
1333
|
|
|
$table_tmp = $table_origine . '_tmp'; |
|
1334
|
|
|
|
|
1335
|
|
|
// 1) creer une table temporaire avec les modifications |
|
1336
|
|
|
// - DROP : suppression de la colonne |
|
1337
|
|
|
// - CHANGE : modification de la colonne |
|
1338
|
|
|
// (foreach pour conserver l'ordre des champs) |
|
1339
|
|
|
|
|
1340
|
|
|
// field |
|
1341
|
|
|
$fields = array(); |
|
1342
|
|
|
// pour le INSERT INTO plus loin |
|
1343
|
|
|
// stocker la correspondance nouvelles->anciennes colonnes |
|
1344
|
|
|
$fields_correspondances = array(); |
|
1345
|
|
|
foreach ($def_origine['field'] as $c=>$d){ |
|
1346
|
|
|
|
|
1347
|
|
|
if ($colonne_origine && ($c == $colonne_origine)) { |
|
1348
|
|
|
// si pas DROP |
|
1349
|
|
|
if ($colonne_destination){ |
|
1350
|
|
|
$fields[$colonne_destination] = $opt['field'][$colonne_destination]; |
|
1351
|
|
|
$fields_correspondances[$colonne_destination] = $c; |
|
1352
|
|
|
} |
|
1353
|
|
|
} else { |
|
1354
|
|
|
$fields[$c] = $d; |
|
1355
|
|
|
$fields_correspondances[$c] = $c; |
|
1356
|
|
|
} |
|
1357
|
|
|
} |
|
1358
|
|
|
// cas de ADD sqlite2 (ajout du champ en fin de table): |
|
1359
|
|
|
if (!$colonne_origine && $colonne_destination){ |
|
1360
|
|
|
$fields[$colonne_destination] = $opt['field'][$colonne_destination]; |
|
1361
|
|
|
} |
|
1362
|
|
|
|
|
1363
|
|
|
// key... |
|
1364
|
|
|
$keys = array(); |
|
1365
|
|
|
foreach ($def_origine['key'] as $c=>$d){ |
|
1366
|
|
|
$c = str_replace($colonne_origine,$colonne_destination,$c); |
|
1367
|
|
|
$d = str_replace($colonne_origine,$colonne_destination,$d); |
|
1368
|
|
|
// seulement si on ne supprime pas la colonne ! |
|
1369
|
|
|
if ($d) |
|
1370
|
|
|
$keys[$c] = $d; |
|
1371
|
|
|
} |
|
1372
|
|
|
|
|
1373
|
|
|
// autres keys, on merge |
|
1374
|
|
|
$keys = array_merge($keys,$opt['key']); |
|
1375
|
|
|
$queries = array(); |
|
1376
|
|
|
$queries[] = 'BEGIN TRANSACTION'; |
|
1377
|
|
|
|
|
1378
|
|
|
// copier dans destination (si differente de origine), sinon tmp |
|
1379
|
|
|
$table_copie = ($meme_table) ? $table_tmp : $table_destination; |
|
1380
|
|
|
|
|
1381
|
|
|
if ($q = _sqlite_requete_create( |
|
1382
|
|
|
$table_copie, |
|
1383
|
|
|
$fields, |
|
1384
|
|
|
$keys, |
|
1385
|
|
|
$autoinc=false, |
|
1386
|
|
|
$temporary=false, |
|
1387
|
|
|
$ifnotexists=true, |
|
1388
|
|
|
$serveur)){ |
|
1389
|
|
|
$queries[] = $q; |
|
1390
|
|
|
} |
|
1391
|
|
|
|
|
1392
|
|
|
|
|
1393
|
|
|
// 2) y copier les champs qui vont bien |
|
1394
|
|
|
$champs_dest = join(', ', array_keys($fields_correspondances)); |
|
1395
|
|
|
$champs_ori = join(', ', $fields_correspondances); |
|
1396
|
|
|
$queries[] = "INSERT INTO $table_copie ($champs_dest) SELECT $champs_ori FROM $table_origine"; |
|
1397
|
|
|
|
|
1398
|
|
|
// 3) supprimer la table d'origine |
|
1399
|
|
|
$queries[] = "DROP TABLE $table_origine"; |
|
1400
|
|
|
|
|
1401
|
|
|
// 4) renommer la table temporaire |
|
1402
|
|
|
// avec le nom de la table destination |
|
1403
|
|
|
// si necessaire |
|
1404
|
|
|
if ($meme_table){ |
|
1405
|
|
|
if (_sqlite_is_version(3, '', $serveur)){ |
|
1406
|
|
|
$queries[] = "ALTER TABLE $table_copie RENAME TO $table_destination"; |
|
1407
|
|
|
} else { |
|
1408
|
|
|
$queries[] = _sqlite_requete_create( |
|
1409
|
|
|
$table_destination, |
|
1410
|
|
|
$fields, |
|
1411
|
|
|
$keys, |
|
1412
|
|
|
$autoinc=false, |
|
1413
|
|
|
$temporary=false, |
|
1414
|
|
|
$ifnotexists=false, // la table existe puisqu'on est dans une transaction |
|
1415
|
|
|
$serveur); |
|
1416
|
|
|
$queries[] = "INSERT INTO $table_destination SELECT * FROM $table_copie"; |
|
1417
|
|
|
$queries[] = "DROP TABLE $table_copie"; |
|
1418
|
|
|
} |
|
1419
|
|
|
} |
|
1420
|
|
|
|
|
1421
|
|
|
// 5) remettre les index ! |
|
1422
|
|
|
foreach ($keys as $k=>$v) { |
|
1423
|
|
View Code Duplication |
if ($k=='PRIMARY KEY'){} |
|
|
|
|
|
|
1424
|
|
|
else { |
|
1425
|
|
|
// enlever KEY |
|
1426
|
|
|
$k = substr($k,4); |
|
1427
|
|
|
$queries[] = "CREATE INDEX $table_destination"."_$k ON $table_destination ($v)"; |
|
1428
|
|
|
} |
|
1429
|
|
|
} |
|
1430
|
|
|
|
|
1431
|
|
|
$queries[] = "COMMIT"; |
|
1432
|
|
|
|
|
1433
|
|
|
|
|
1434
|
|
|
// il faut les faire une par une car $query = join('; ', $queries).";"; ne fonctionne pas |
|
1435
|
|
|
foreach ($queries as $q){ |
|
1436
|
|
|
$req = new sqlite_traiter_requete($q, $serveur); |
|
1437
|
|
|
if (!$req->executer_requete()){ |
|
1438
|
|
|
spip_log("SQLite : ALTER TABLE table :" |
|
1439
|
|
|
." Erreur a l'execution de la requete : $q",'sqlite'); |
|
1440
|
|
|
return false; |
|
1441
|
|
|
} |
|
1442
|
|
|
} |
|
1443
|
|
|
|
|
1444
|
|
|
return true; |
|
1445
|
|
|
} |
|
1446
|
|
|
|
|
1447
|
|
|
|
|
1448
|
|
|
|
|
1449
|
|
|
|
|
1450
|
|
|
/* |
|
1451
|
|
|
* Nom des fonctions |
|
1452
|
|
|
*/ |
|
1453
|
|
|
// http://doc.spip.org/@_sqlite_ref_fonctions |
|
1454
|
|
|
function _sqlite_ref_fonctions(){ |
|
1455
|
|
|
$fonctions = array( |
|
1456
|
|
|
'alter' => 'spip_sqlite_alter', |
|
1457
|
|
|
'count' => 'spip_sqlite_count', |
|
1458
|
|
|
'countsel' => 'spip_sqlite_countsel', |
|
1459
|
|
|
'create' => 'spip_sqlite_create', |
|
1460
|
|
|
'create_base' => 'spip_sqlite_create_base', |
|
1461
|
|
|
'create_view' => 'spip_sqlite_create_view', |
|
1462
|
|
|
'date_proche' => 'spip_sqlite_date_proche', |
|
1463
|
|
|
'delete' => 'spip_sqlite_delete', |
|
1464
|
|
|
'drop_table' => 'spip_sqlite_drop_table', |
|
1465
|
|
|
'drop_view' => 'spip_sqlite_drop_view', |
|
1466
|
|
|
'errno' => 'spip_sqlite_errno', |
|
1467
|
|
|
'error' => 'spip_sqlite_error', |
|
1468
|
|
|
'explain' => 'spip_sqlite_explain', |
|
1469
|
|
|
'fetch' => 'spip_sqlite_fetch', |
|
1470
|
|
|
'seek' => 'spip_sqlite_seek', |
|
1471
|
|
|
'free' => 'spip_sqlite_free', |
|
1472
|
|
|
'hex' => 'spip_sqlite_hex', |
|
1473
|
|
|
'in' => 'spip_sqlite_in', |
|
1474
|
|
|
'insert' => 'spip_sqlite_insert', |
|
1475
|
|
|
'insertq' => 'spip_sqlite_insertq', |
|
1476
|
|
|
'insertq_multi' => 'spip_sqlite_insertq_multi', |
|
1477
|
|
|
'listdbs' => 'spip_sqlite_listdbs', |
|
1478
|
|
|
'multi' => 'spip_sqlite_multi', |
|
1479
|
|
|
'optimize' => 'spip_sqlite_optimize', |
|
1480
|
|
|
'query' => 'spip_sqlite_query', |
|
1481
|
|
|
'quote' => 'spip_sqlite_quote', |
|
1482
|
|
|
'replace' => 'spip_sqlite_replace', |
|
1483
|
|
|
'replace_multi' => 'spip_sqlite_replace_multi', |
|
1484
|
|
|
'select' => 'spip_sqlite_select', |
|
1485
|
|
|
'selectdb' => 'spip_sqlite_selectdb', |
|
1486
|
|
|
'set_charset' => 'spip_sqlite_set_charset', |
|
1487
|
|
|
'get_charset' => 'spip_sqlite_get_charset', |
|
1488
|
|
|
'showbase' => 'spip_sqlite_showbase', |
|
1489
|
|
|
'showtable' => 'spip_sqlite_showtable', |
|
1490
|
|
|
'update' => 'spip_sqlite_update', |
|
1491
|
|
|
'updateq' => 'spip_sqlite_updateq', |
|
1492
|
|
|
); |
|
1493
|
|
|
|
|
1494
|
|
|
// association de chaque nom http d'un charset aux couples sqlite |
|
1495
|
|
|
// SQLite supporte utf-8 et utf-16 uniquement. |
|
1496
|
|
|
$charsets = array( |
|
1497
|
|
|
'utf-8'=>array('charset'=>'utf8','collation'=>'utf8_general_ci'), |
|
1498
|
|
|
//'utf-16be'=>array('charset'=>'utf16be','collation'=>'UTF-16BE'),// aucune idee de quoi il faut remplir dans es champs la |
|
1499
|
|
|
//'utf-16le'=>array('charset'=>'utf16le','collation'=>'UTF-16LE') |
|
1500
|
|
|
); |
|
1501
|
|
|
|
|
1502
|
|
|
$fonctions['charsets'] = $charsets; |
|
1503
|
|
|
|
|
1504
|
|
|
return $fonctions; |
|
1505
|
|
|
} |
|
1506
|
|
|
|
|
1507
|
|
|
|
|
1508
|
|
|
|
|
1509
|
|
|
// $query est une requete ou une liste de champs |
|
1510
|
|
|
// http://doc.spip.org/@_sqlite_remplacements_definitions_table |
|
1511
|
|
|
function _sqlite_remplacements_definitions_table($query,$autoinc=false){ |
|
1512
|
|
|
// quelques remplacements |
|
1513
|
|
|
$num = "(\s*\([0-9]*\))?"; |
|
1514
|
|
|
$enum = "(\s*\([^\)]*\))?"; |
|
1515
|
|
|
|
|
1516
|
|
|
$remplace = array( |
|
1517
|
|
|
'/enum'.$enum.'/is' => 'VARCHAR', |
|
1518
|
|
|
'/binary/is' => '', |
|
1519
|
|
|
'/COLLATE \w+_bin/is' => '', |
|
1520
|
|
|
'/auto_increment/is' => '', |
|
1521
|
|
|
'/(timestamp .* )ON .*$/is' => '\\1', |
|
1522
|
|
|
'/character set \w+/is' => '', |
|
1523
|
|
|
'/((big|small|medium|tiny)?int(eger)?)'.$num.'\s*unsigned/is' => '\\1 UNSIGNED', |
|
1524
|
|
|
'/(text\s+not\s+null)\s*$/is' => "\\1 DEFAULT ''", |
|
1525
|
|
|
); |
|
1526
|
|
|
|
|
1527
|
|
|
// pour l'autoincrement, il faut des INTEGER NOT NULL PRIMARY KEY |
|
1528
|
|
|
if ($autoinc) |
|
1529
|
|
|
$remplace['/(big|small|medium|tiny)?int(eger)?'.$num.'/is'] = 'INTEGER'; |
|
1530
|
|
|
|
|
1531
|
|
|
return preg_replace(array_keys($remplace), $remplace, $query); |
|
1532
|
|
|
} |
|
1533
|
|
|
|
|
1534
|
|
|
|
|
1535
|
|
|
/* |
|
1536
|
|
|
* Creer la requete pour la creation d'une table |
|
1537
|
|
|
* retourne la requete pour utilisation par sql_create() et sql_alter() |
|
1538
|
|
|
*/ |
|
1539
|
|
|
// http://doc.spip.org/@_sqlite_requete_create |
|
1540
|
|
|
function _sqlite_requete_create($nom, $champs, $cles, $autoinc=false, $temporary=false, $_ifnotexists=true, $serveur='',$requeter=true) { |
|
|
|
|
|
|
1541
|
|
|
$query = $keys = $s = $p = ''; |
|
|
|
|
|
|
1542
|
|
|
|
|
1543
|
|
|
// certains plugins declarent les tables (permet leur inclusion dans le dump) |
|
1544
|
|
|
// sans les renseigner (laisse le compilo recuperer la description) |
|
1545
|
|
|
if (!is_array($champs) || !is_array($cles)) |
|
1546
|
|
|
return; |
|
1547
|
|
|
|
|
1548
|
|
|
// sqlite ne gere pas KEY tout court dans une requete CREATE TABLE |
|
1549
|
|
|
// il faut passer par des create index |
|
1550
|
|
|
// Il gere par contre primary key ! |
|
1551
|
|
|
// Soit la PK est definie dans les cles, soit dans un champs |
|
1552
|
|
|
if (!$c = $cles[$pk = "PRIMARY KEY"]) { |
|
1553
|
|
|
foreach($champs as $k => $v) { |
|
1554
|
|
|
if (false !== stripos($v,$pk)) { |
|
1555
|
|
|
$c = $k; |
|
1556
|
|
|
// on n'en a plus besoin dans field, vu que defini dans key |
|
1557
|
|
|
$champs[$k] = preg_replace("/$pk/is", '', $champs[$k]); |
|
1558
|
|
|
break; |
|
1559
|
|
|
} |
|
1560
|
|
|
} |
|
1561
|
|
|
} |
|
1562
|
|
|
if ($c) $keys = "\n\t\t$pk ($c)"; |
|
1563
|
|
|
|
|
1564
|
|
|
$champs = _sqlite_remplacements_definitions_table($champs, $autoinc); |
|
1565
|
|
|
foreach($champs as $k => $v) { |
|
1566
|
|
|
$query .= "$s\n\t\t$k $v"; |
|
1567
|
|
|
$s = ","; |
|
1568
|
|
|
} |
|
1569
|
|
|
|
|
1570
|
|
|
$ifnotexists = ""; |
|
1571
|
|
View Code Duplication |
if ($_ifnotexists) { |
|
|
|
|
|
|
1572
|
|
|
// simuler le IF NOT EXISTS - version 2 |
|
1573
|
|
|
if (_sqlite_is_version(2, '', $serveur)){ |
|
1574
|
|
|
$a = spip_sqlite_showtable($nom, $serveur); |
|
1575
|
|
|
if ($a) return false; |
|
1576
|
|
|
} |
|
1577
|
|
|
// sinon l'ajouter en version 3 |
|
1578
|
|
|
else { |
|
1579
|
|
|
$ifnotexists = ' IF NOT EXISTS'; |
|
1580
|
|
|
} |
|
1581
|
|
|
} |
|
1582
|
|
|
|
|
1583
|
|
|
$temporary = $temporary ? ' TEMPORARY':''; |
|
1584
|
|
|
$q = "CREATE$temporary TABLE$ifnotexists $nom ($query" . ($keys ? ",$keys" : '') . ")\n"; |
|
1585
|
|
|
|
|
1586
|
|
|
return $q; |
|
1587
|
|
|
} |
|
1588
|
|
|
|
|
1589
|
|
|
|
|
1590
|
|
|
|
|
1591
|
|
|
/* |
|
1592
|
|
|
* Retrouver les champs 'timestamp' |
|
1593
|
|
|
* pour les ajouter aux 'insert' ou 'replace' |
|
1594
|
|
|
* afin de simuler le fonctionnement de mysql |
|
1595
|
|
|
* |
|
1596
|
|
|
* stocke le resultat pour ne pas faire |
|
1597
|
|
|
* de requetes showtable intempestives |
|
1598
|
|
|
*/ |
|
1599
|
|
|
// http://doc.spip.org/@_sqlite_ajouter_champs_timestamp |
|
1600
|
|
View Code Duplication |
function _sqlite_ajouter_champs_timestamp($table, $couples, $desc='', $serveur=''){ |
|
|
|
|
|
|
1601
|
|
|
static $tables = array(); |
|
1602
|
|
|
|
|
1603
|
|
|
if (!isset($tables[$table])){ |
|
1604
|
|
|
|
|
1605
|
|
|
if (!$desc){ |
|
1606
|
|
|
$f = charger_fonction('trouver_table', 'base'); |
|
1607
|
|
|
$desc = $f($table, $serveur); |
|
1608
|
|
|
// si pas de description, on ne fait rien, ou on die() ? |
|
1609
|
|
|
if (!$desc OR !$desc['field']) return $couples; |
|
1610
|
|
|
} |
|
1611
|
|
|
|
|
1612
|
|
|
// recherche des champs avec simplement 'TIMESTAMP' |
|
1613
|
|
|
// cependant, il faudra peut etre etendre |
|
1614
|
|
|
// avec la gestion de DEFAULT et ON UPDATE |
|
1615
|
|
|
// mais ceux-ci ne sont pas utilises dans le core |
|
1616
|
|
|
$tables[$table] = array(); |
|
1617
|
|
|
|
|
1618
|
|
|
foreach ($desc['field'] as $k=>$v){ |
|
1619
|
|
|
if (strpos(strtolower(ltrim($v)), 'timestamp')===0) |
|
1620
|
|
|
$tables[$table][] = $k; |
|
1621
|
|
|
} |
|
1622
|
|
|
} |
|
1623
|
|
|
|
|
1624
|
|
|
// ajout des champs type 'timestamp' absents |
|
1625
|
|
|
foreach ($tables[$table] as $maj){ |
|
1626
|
|
|
if (!array_key_exists($maj, $couples)) |
|
1627
|
|
|
$couples[$maj] = "datetime('now')"; |
|
1628
|
|
|
} |
|
1629
|
|
|
return $couples; |
|
1630
|
|
|
} |
|
1631
|
|
|
|
|
1632
|
|
|
|
|
1633
|
|
|
|
|
1634
|
|
|
/* |
|
1635
|
|
|
* renvoyer la liste des versions sqlite disponibles |
|
1636
|
|
|
* sur le serveur |
|
1637
|
|
|
*/ |
|
1638
|
|
|
// http://doc.spip.org/@spip_versions_sqlite |
|
1639
|
|
|
function spip_versions_sqlite(){ |
|
1640
|
|
|
return _sqlite_charger_version(); |
|
1641
|
|
|
} |
|
1642
|
|
|
|
|
1643
|
|
|
|
|
1644
|
|
|
|
|
1645
|
|
|
|
|
1646
|
|
|
/* |
|
1647
|
|
|
* Classe pour partager les lancements de requete |
|
1648
|
|
|
* - peut corriger la syntaxe des requetes pour la conformite a sqlite |
|
1649
|
|
|
* - peut tracer les requetes |
|
1650
|
|
|
* |
|
1651
|
|
|
* Cette classe est presente essentiellement pour un preg_replace_callback |
|
1652
|
|
|
* avec des parametres dans la fonction appelee que l'on souhaite incrementer |
|
1653
|
|
|
* (fonction pour proteger les textes) |
|
1654
|
|
|
* |
|
1655
|
|
|
*/ |
|
1656
|
|
|
class sqlite_traiter_requete{ |
|
1657
|
|
|
var $query = ''; // la requete |
|
1658
|
|
|
var $queryCount = ''; // la requete pour compter |
|
1659
|
|
|
var $serveur = ''; // le serveur |
|
1660
|
|
|
var $link = ''; // le link (ressource) sqlite |
|
1661
|
|
|
var $prefixe = ''; // le prefixe des tables |
|
1662
|
|
|
var $db = ''; // le nom de la base |
|
1663
|
|
|
var $tracer = false; // doit-on tracer les requetes (var_profile) |
|
1664
|
|
|
|
|
1665
|
|
|
var $sqlite_version = ''; // Version de sqlite (2 ou 3) |
|
1666
|
|
|
|
|
1667
|
|
|
// Pour les corrections a effectuer sur les requetes : |
|
1668
|
|
|
var $textes = array(); // array(code=>'texte') trouvé |
|
1669
|
|
|
|
|
1670
|
|
|
|
|
1671
|
|
|
// constructeur |
|
1672
|
|
|
// http://doc.spip.org/@sqlite_traiter_requete |
|
1673
|
|
|
function sqlite_traiter_requete($query, $serveur = ''){ |
|
|
|
|
|
|
1674
|
|
|
$this->query = $query; |
|
1675
|
|
|
$this->serveur = strtolower($serveur); |
|
1676
|
|
|
|
|
1677
|
|
|
if (!($this->link = _sqlite_link($this->serveur)) && (!defined('_ECRIRE_INSTALL') || !_ECRIRE_INSTALL)){ |
|
1678
|
|
|
spip_log("Aucune connexion sqlite (link)"); |
|
1679
|
|
|
return false; |
|
1680
|
|
|
} |
|
1681
|
|
|
|
|
1682
|
|
|
$this->sqlite_version =_sqlite_is_version('', $this->link); |
|
|
|
|
|
|
1683
|
|
|
|
|
1684
|
|
|
$this->prefixe = $GLOBALS['connexions'][$this->serveur ? $this->serveur : 0]['prefixe']; |
|
1685
|
|
|
$this->db = $GLOBALS['connexions'][$this->serveur ? $this->serveur : 0]['db']; |
|
1686
|
|
|
|
|
1687
|
|
|
// tracage des requetes ? |
|
1688
|
|
|
$this->tracer = (isset($_GET['var_profile']) && $_GET['var_profile']); |
|
1689
|
|
|
} |
|
1690
|
|
|
|
|
1691
|
|
|
|
|
1692
|
|
|
// lancer la requete $this->query, |
|
1693
|
|
|
// faire le tracage si demande |
|
1694
|
|
|
// http://doc.spip.org/@executer_requete |
|
1695
|
|
|
function executer_requete(){ |
|
|
|
|
|
|
1696
|
|
|
$err = ""; |
|
1697
|
|
|
if ($this->tracer) { |
|
1698
|
|
|
include_spip('public/tracer'); |
|
1699
|
|
|
$t = trace_query_start(); |
|
1700
|
|
|
} else $t = 0 ; |
|
1701
|
|
|
|
|
1702
|
|
|
# spip_log("requete: $this->serveur >> $this->query",'query'); // boum ? pourquoi ? |
|
1703
|
|
|
if ($this->link){ |
|
1704
|
|
|
// memoriser la derniere erreur PHP vue |
|
1705
|
|
|
$e = error_get_last(); |
|
1706
|
|
|
// sauver la derniere requete |
|
1707
|
|
|
$GLOBALS['connexions'][$this->serveur ? $this->serveur : 0]['last'] = $this->query; |
|
1708
|
|
|
|
|
1709
|
|
|
if ($this->sqlite_version == 3) { |
|
1710
|
|
|
$r = $this->link->query($this->query); |
|
|
|
|
|
|
1711
|
|
|
// sauvegarde de la requete (elle y est deja dans $r->queryString) |
|
1712
|
|
|
# $r->spipQueryString = $this->query; |
|
1713
|
|
|
|
|
1714
|
|
|
// comptage : oblige de compter le nombre d'entrees retournees |
|
1715
|
|
|
// par une requete SELECT |
|
1716
|
|
|
// aucune autre solution ne donne le nombre attendu :( ! |
|
1717
|
|
|
// particulierement s'il y a des LIMIT dans la requete. |
|
1718
|
|
|
if (strtoupper(substr(ltrim($this->query),0,6)) == 'SELECT'){ |
|
1719
|
|
|
if ($r) { |
|
1720
|
|
|
$l = $this->link->query($this->query); |
|
|
|
|
|
|
1721
|
|
|
$r->spipSqliteRowCount = count($l->fetchAll()); |
|
1722
|
|
|
unset($l); |
|
1723
|
|
|
} elseif (is_a($r, 'PDOStatement')) { |
|
1724
|
|
|
$r->spipSqliteRowCount = 0; |
|
1725
|
|
|
} |
|
1726
|
|
|
} |
|
1727
|
|
|
} else { |
|
1728
|
|
|
$r = sqlite_query($this->link, $this->query); |
|
1729
|
|
|
} |
|
1730
|
|
|
|
|
1731
|
|
|
// loger les warnings/erreurs eventuels de sqlite remontant dans PHP |
|
1732
|
|
|
if ($err = error_get_last() AND $err!=$e) { |
|
1733
|
|
|
$err = strip_tags($err['message'])." in ".$err['file']." line ".$err['line']; |
|
1734
|
|
|
spip_log("$err - ".$this->query, 'sqlite'); |
|
1735
|
|
|
} |
|
1736
|
|
|
else $err=""; |
|
1737
|
|
|
|
|
1738
|
|
|
} else { |
|
1739
|
|
|
$r = false; |
|
1740
|
|
|
} |
|
1741
|
|
|
|
|
1742
|
|
|
if (spip_sqlite_errno($serveur)) |
|
1743
|
|
|
$err .= spip_sqlite_error($this->query, $serveur); |
|
|
|
|
|
|
1744
|
|
|
return $t ? trace_query_end($this->query, $t, $r, $err, $serveur) : $r; |
|
1745
|
|
|
} |
|
1746
|
|
|
|
|
1747
|
|
|
// transformer la requete pour sqlite |
|
1748
|
|
|
// enleve les textes, transforme la requete pour quelle soit |
|
1749
|
|
|
// bien interpretee par sqlite, puis remet les textes |
|
1750
|
|
|
// la fonction affecte $this->query |
|
1751
|
|
|
// http://doc.spip.org/@traduire_requete |
|
1752
|
|
|
function traduire_requete(){ |
|
|
|
|
|
|
1753
|
|
|
// |
|
1754
|
|
|
// 1) Protection des textes en les remplacant par des codes |
|
1755
|
|
|
// |
|
1756
|
|
|
// enlever les 'textes' et initialiser avec |
|
1757
|
|
|
list($this->query, $textes) = query_echappe_textes($this->query); |
|
1758
|
|
|
|
|
1759
|
|
|
// |
|
1760
|
|
|
// 2) Corrections de la requete |
|
1761
|
|
|
// |
|
1762
|
|
|
// Correction Create Database |
|
1763
|
|
|
// Create Database -> requete ignoree |
|
1764
|
|
|
if (strpos($this->query, 'CREATE DATABASE')===0){ |
|
1765
|
|
|
spip_log("Sqlite : requete non executee -> $this->query","sqlite"); |
|
1766
|
|
|
$this->query = "SELECT 1"; |
|
1767
|
|
|
} |
|
1768
|
|
|
|
|
1769
|
|
|
// Correction Insert Ignore |
|
1770
|
|
|
// INSERT IGNORE -> insert (tout court et pas 'insert or replace') |
|
1771
|
|
|
if (strpos($this->query, 'INSERT IGNORE')===0){ |
|
1772
|
|
|
#spip_log("Sqlite : requete transformee -> $this->query","sqlite"); |
|
1773
|
|
|
$this->query = 'INSERT ' . substr($this->query,'13'); |
|
1774
|
|
|
} |
|
1775
|
|
|
|
|
1776
|
|
|
// Correction des dates avec INTERVAL |
|
1777
|
|
|
// utiliser sql_date_proche() de preference |
|
1778
|
|
View Code Duplication |
if (strpos($this->query, 'INTERVAL')!==false){ |
|
|
|
|
|
|
1779
|
|
|
$this->query = preg_replace_callback("/DATE_(ADD|SUB).*INTERVAL\s+(\d+)\s+([a-zA-Z]+)\)/U", |
|
1780
|
|
|
array(&$this, '_remplacerDateParTime'), |
|
1781
|
|
|
$this->query); |
|
1782
|
|
|
} |
|
1783
|
|
|
|
|
1784
|
|
|
// Correction Using |
|
1785
|
|
|
// USING (non reconnu en sqlite2) |
|
1786
|
|
|
// problematique car la jointure ne se fait pas du coup. |
|
1787
|
|
View Code Duplication |
if (($this->sqlite_version == 2) && (strpos($this->query, "USING")!==false)) { |
|
|
|
|
|
|
1788
|
|
|
spip_log("'USING (champ)' n'est pas reconnu en SQLite 2. Utilisez 'ON table1.champ = table2.champ', 'sqlite'"); |
|
1789
|
|
|
$this->query = preg_replace('/USING\s*\([^\)]*\)/', '', $this->query); |
|
1790
|
|
|
} |
|
1791
|
|
|
|
|
1792
|
|
|
// Correction Field |
|
1793
|
|
|
// remplace FIELD(table,i,j,k...) par CASE WHEN table=i THEN n ... ELSE 0 END |
|
1794
|
|
View Code Duplication |
if (strpos($this->query, 'FIELD')!==false){ |
|
|
|
|
|
|
1795
|
|
|
$this->query = preg_replace_callback('/FIELD\s*\(([^\)]*)\)/', |
|
1796
|
|
|
array(&$this, '_remplacerFieldParCase'), |
|
1797
|
|
|
$this->query); |
|
1798
|
|
|
} |
|
1799
|
|
|
|
|
1800
|
|
|
// Correction des noms de tables FROM |
|
1801
|
|
|
// mettre les bons noms de table dans from, update, insert, replace... |
|
1802
|
|
|
if (preg_match('/\s(SET|VALUES|WHERE|DATABASE)\s/i', $this->query, $regs)) { |
|
1803
|
|
|
$suite = strstr($this->query, $regs[0]); |
|
1804
|
|
|
$this->query = substr($this->query, 0, -strlen($suite)); |
|
1805
|
|
|
} else $suite =''; |
|
1806
|
|
|
$pref = ($this->prefixe) ? $this->prefixe . "_": ""; |
|
1807
|
|
|
$this->query = preg_replace('/([,\s])spip_/', '\1'.$pref, $this->query) . $suite; |
|
1808
|
|
|
|
|
1809
|
|
|
// Correction zero AS x |
|
1810
|
|
|
// pg n'aime pas 0+x AS alias, sqlite, dans le meme style, |
|
1811
|
|
|
// n'apprecie pas du tout SELECT 0 as x ... ORDER BY x |
|
1812
|
|
|
// il dit que x ne doit pas être un integer dans le order by ! |
|
1813
|
|
|
// on remplace du coup x par vide() dans ce cas uniquement |
|
1814
|
|
|
// |
|
1815
|
|
|
// rien que pour public/vertebrer.php ? |
|
1816
|
|
|
if ((strpos($this->query, "0 AS")!==false)){ |
|
1817
|
|
|
// on ne remplace que dans ORDER BY ou GROUP BY |
|
1818
|
|
|
if (preg_match('/\s(ORDER|GROUP) BY\s/i', $this->query, $regs)) { |
|
1819
|
|
|
$suite = strstr($this->query, $regs[0]); |
|
1820
|
|
|
$this->query = substr($this->query, 0, -strlen($suite)); |
|
1821
|
|
|
|
|
1822
|
|
|
// on cherche les noms des x dans 0 AS x |
|
1823
|
|
|
// on remplace dans $suite le nom par vide() |
|
1824
|
|
|
preg_match_all('/\b0 AS\s*([^\s,]+)/', $this->query, $matches, PREG_PATTERN_ORDER); |
|
1825
|
|
|
foreach ($matches[1] as $m){ |
|
1826
|
|
|
$suite = str_replace($m, 'VIDE()', $suite); |
|
1827
|
|
|
} |
|
1828
|
|
|
$this->query .= $suite; |
|
1829
|
|
|
} |
|
1830
|
|
|
} |
|
1831
|
|
|
|
|
1832
|
|
|
// Correction possible des divisions entieres |
|
1833
|
|
|
// Le standard SQL (lequel? ou?) semble indiquer que |
|
1834
|
|
|
// a/b=c doit donner c entier si a et b sont entiers 4/3=1. |
|
1835
|
|
|
// C'est ce que retournent effectivement SQL Server et SQLite |
|
1836
|
|
|
// Ce n'est pas ce qu'applique MySQL qui retourne un reel : 4/3=1.333... |
|
1837
|
|
|
// |
|
1838
|
|
|
// On peut forcer la conversion en multipliant par 1.0 avant la division |
|
1839
|
|
|
// /!\ SQLite 3.5.9 Debian/Ubuntu est victime d'un bug en plus ! |
|
1840
|
|
|
// cf. https://bugs.launchpad.net/ubuntu/+source/sqlite3/+bug/254228 |
|
1841
|
|
|
// http://www.sqlite.org/cvstrac/tktview?tn=3202 |
|
1842
|
|
|
// (4*1.0/3) n'est pas rendu dans ce cas ! |
|
1843
|
|
|
# $this->query = str_replace('/','* 1.00 / ',$this->query); |
|
1844
|
|
|
|
|
1845
|
|
|
// Correction Antiquotes |
|
1846
|
|
|
// ` => rien |
|
1847
|
|
|
$this->query = str_replace('`','',$this->query); |
|
1848
|
|
|
|
|
1849
|
|
|
// Correction critere REGEXP, non reconnu en sqlite2 |
|
1850
|
|
View Code Duplication |
if (($this->sqlite_version == 2) && (strpos($this->query, 'REGEXP')!==false)){ |
|
|
|
|
|
|
1851
|
|
|
$this->query = preg_replace('/([^\s\(]*)(\s*)REGEXP(\s*)([^\s\)]*)/', 'REGEXP($4, $1)', $this->query); |
|
1852
|
|
|
} |
|
1853
|
|
|
|
|
1854
|
|
|
|
|
1855
|
|
|
// |
|
1856
|
|
|
// 3) Remise en place des textes d'origine |
|
1857
|
|
|
// |
|
1858
|
|
|
// Correction Antiquotes et echappements |
|
1859
|
|
|
// ` => rien |
|
1860
|
|
|
if (strpos($this->query,'`')!==false) |
|
1861
|
|
|
$this->query = str_replace('`','', $this->query); |
|
1862
|
|
|
|
|
1863
|
|
|
$this->query = query_reinjecte_textes($this->query, $textes); |
|
|
|
|
|
|
1864
|
|
|
} |
|
1865
|
|
|
|
|
1866
|
|
|
|
|
1867
|
|
|
|
|
1868
|
|
|
// les callbacks |
|
1869
|
|
|
// remplacer DATE_ / INTERVAL par DATE...strtotime |
|
1870
|
|
|
// http://doc.spip.org/@_remplacerDateParTime |
|
1871
|
|
|
function _remplacerDateParTime($matches){ |
|
|
|
|
|
|
1872
|
|
|
$op = strtoupper($matches[1] == 'ADD')?'+':'-'; |
|
1873
|
|
|
return "datetime('" . date("Y-m-d H:i:s") . "', '$op$matches[2] $matches[3]')"; |
|
1874
|
|
|
} |
|
1875
|
|
|
|
|
1876
|
|
|
// callback ou l'on remplace FIELD(table,i,j,k...) par CASE WHEN table=i THEN n ... ELSE 0 END |
|
1877
|
|
|
// http://doc.spip.org/@_remplacerFieldParCase |
|
1878
|
|
|
function _remplacerFieldParCase($matches){ |
|
|
|
|
|
|
1879
|
|
|
$fields = substr($matches[0],6,-1); // ne recuperer que l'interieur X de field(X) |
|
1880
|
|
|
$t = explode(',', $fields); |
|
1881
|
|
|
$index = array_shift($t); |
|
1882
|
|
|
|
|
1883
|
|
|
$res = ''; |
|
1884
|
|
|
$n=0; |
|
1885
|
|
|
foreach($t as $v) { |
|
1886
|
|
|
$n++; |
|
1887
|
|
|
$res .= "\nWHEN $index=$v THEN $n"; |
|
1888
|
|
|
} |
|
1889
|
|
|
return "CASE $res ELSE 0 END "; |
|
1890
|
|
|
} |
|
1891
|
|
|
|
|
1892
|
|
|
// callback ou l'on sauve le texte qui est cache dans un tableau $this->textes |
|
1893
|
|
|
// http://doc.spip.org/@_remplacerTexteParCode |
|
1894
|
|
|
function _remplacerTexteParCode($matches){ |
|
|
|
|
|
|
1895
|
|
|
$this->textes[$code = "%@##".count($this->textes)."##@%"] = $matches[1]; |
|
1896
|
|
|
return $code; |
|
1897
|
|
|
} |
|
1898
|
|
|
|
|
1899
|
|
|
} |
|
1900
|
|
|
|
|
1901
|
|
|
?> |
|
|
|
|
|
|
1902
|
|
|
|
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.