1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* KumbiaPHP web & app Framework |
4
|
|
|
* |
5
|
|
|
* LICENSE |
6
|
|
|
* |
7
|
|
|
* This source file is subject to the new BSD license that is bundled |
8
|
|
|
* with this package in the file LICENSE.txt. |
9
|
|
|
* It is also available through the world-wide-web at this URL: |
10
|
|
|
* http://wiki.kumbiaphp.com/Licencia |
11
|
|
|
* If you did not receive a copy of the license and are unable to |
12
|
|
|
* obtain it through the world-wide-web, please send an email |
13
|
|
|
* to [email protected] so we can send you a copy immediately. |
14
|
|
|
* |
15
|
|
|
* @category Kumbia |
16
|
|
|
* @package Db |
17
|
|
|
* @subpackage Adapters |
18
|
|
|
* @copyright Copyright (c) 2005 - 2017 Kumbia Team (http://www.kumbiaphp.com) |
19
|
|
|
* @license http://wiki.kumbiaphp.com/Licencia New BSD License |
20
|
|
|
*/ |
21
|
|
|
/** |
22
|
|
|
* @see DbPdo Padre de Drivers Pdo |
23
|
|
|
*/ |
24
|
|
|
require_once CORE_PATH . 'libs/db/adapters/pdo.php'; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* PDO PostgreSQL Database Support |
28
|
|
|
* |
29
|
|
|
* @category Kumbia |
30
|
|
|
* @package Db |
31
|
|
|
* @subpackage Adapters |
32
|
|
|
*/ |
33
|
|
|
class DbPdoPgSQL extends DbPDO |
34
|
|
|
{ |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Nombre de RBDM |
38
|
|
|
*/ |
39
|
|
|
protected $db_rbdm = "pgsql"; |
40
|
|
|
/** |
41
|
|
|
* Puerto de Conexión a PostgreSQL |
42
|
|
|
* |
43
|
|
|
* @var integer |
44
|
|
|
*/ |
45
|
|
|
protected $db_port = 5432; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Tipo de Dato Integer |
49
|
|
|
* |
50
|
|
|
*/ |
51
|
|
|
const TYPE_INTEGER = "INTEGER"; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Tipo de Dato Date |
55
|
|
|
* |
56
|
|
|
*/ |
57
|
|
|
const TYPE_DATE = "DATE"; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Tipo de Dato Varchar |
61
|
|
|
* |
62
|
|
|
*/ |
63
|
|
|
const TYPE_VARCHAR = "VARCHAR"; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Tipo de Dato Decimal |
67
|
|
|
* |
68
|
|
|
*/ |
69
|
|
|
const TYPE_DECIMAL = "DECIMAL"; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Tipo de Dato Datetime |
73
|
|
|
* |
74
|
|
|
*/ |
75
|
|
|
const TYPE_DATETIME = "DATETIME"; |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Tipo de Dato Char |
79
|
|
|
* |
80
|
|
|
*/ |
81
|
|
|
const TYPE_CHAR = "CHAR"; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Ejecuta acciones de incializacion del driver |
85
|
|
|
* |
86
|
|
|
*/ |
87
|
|
|
public function initialize() |
88
|
|
|
{ |
89
|
|
|
|
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Devuelve el ultimo id autonumerico generado en la BD |
94
|
|
|
* |
95
|
|
|
* @return integer |
96
|
|
|
*/ |
97
|
|
|
public function last_insert_id($table='', $primary_key='') |
98
|
|
|
{ |
99
|
|
|
return $this->pdo->lastInsertId("{$table}_{$primary_key}_seq"); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Verifica si una tabla existe o no |
104
|
|
|
* |
105
|
|
|
* @param string $table |
106
|
|
|
* @return boolean |
107
|
|
|
*/ |
108
|
|
|
function table_exists($table, $schema='') |
109
|
|
|
{ |
110
|
|
|
$table = addslashes(strtolower($table)); |
111
|
|
|
if (strpos($table, ".")) { |
112
|
|
|
list($schema, $table) = explode(".", $table); |
113
|
|
|
} |
114
|
|
|
if ($schema == '') { |
115
|
|
|
$num = $this->fetch_one("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME ='$table'"); |
116
|
|
|
} else { |
117
|
|
|
$schema = addslashes(strtolower($schema)); |
118
|
|
|
$num = $this->fetch_one("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '$schema' AND TABLE_NAME ='$table'"); |
119
|
|
|
} |
120
|
|
|
return $num[0]; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Devuelve un LIMIT valido para un SELECT del RBDM |
125
|
|
|
* |
126
|
|
|
* @param string $sql consulta sql |
127
|
|
|
* @return string |
128
|
|
|
*/ |
129
|
|
|
public function limit($sql) |
130
|
|
|
{ |
131
|
|
|
$params = Util::getParams(func_get_args()); |
132
|
|
|
$sql_new = $sql; |
133
|
|
|
|
134
|
|
|
if (isset($params['limit']) && is_numeric($params['limit'])) { |
135
|
|
|
$sql_new.=" LIMIT $params[limit]"; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
if (isset($params['offset']) && is_numeric($params['offset'])) { |
139
|
|
|
$sql_new.=" OFFSET $params[offset]"; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
return $sql_new; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Borra una tabla de la base de datos |
147
|
|
|
* |
148
|
|
|
* @param string $table |
149
|
|
|
* @return boolean |
150
|
|
|
*/ |
151
|
|
|
public function drop_table($table, $if_exists=true) |
152
|
|
|
{ |
153
|
|
|
if ($if_exists) { |
154
|
|
|
if ($this->table_exists($table)) { |
155
|
|
|
return $this->query("DROP TABLE $table"); |
156
|
|
|
} else { |
157
|
|
|
return true; |
158
|
|
|
} |
159
|
|
|
} |
160
|
|
|
return $this->query("DROP TABLE $table"); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Crea una tabla utilizando SQL nativo del RDBM |
165
|
|
|
* |
166
|
|
|
* TODO: |
167
|
|
|
* - Falta que el parametro index funcione. Este debe listar indices compuestos multipes y unicos |
168
|
|
|
* - Agregar el tipo de tabla que debe usarse (PostgreSQL) |
169
|
|
|
* - Soporte para campos autonumericos |
170
|
|
|
* - Soporte para llaves foraneas |
171
|
|
|
* |
172
|
|
|
* @param string $table |
173
|
|
|
* @param array $definition |
174
|
|
|
* @return boolean |
175
|
|
|
*/ |
176
|
|
|
public function create_table($table, $definition, $index=array()) |
177
|
|
|
{ |
178
|
|
|
$create_sql = "CREATE TABLE $table ("; |
179
|
|
|
if (!is_array($definition)) { |
180
|
|
|
throw new KumbiaException("Definición inválida para crear la tabla '$table'"); |
181
|
|
|
} |
182
|
|
|
$create_lines = array(); |
183
|
|
|
$index = array(); |
184
|
|
|
$unique_index = array(); |
185
|
|
|
$primary = array(); |
186
|
|
|
//$not_null = ""; |
187
|
|
|
//$size = ""; |
188
|
|
|
foreach ($definition as $field => $field_def) { |
189
|
|
|
if (isset($field_def['not_null'])) { |
190
|
|
|
$not_null = $field_def['not_null'] ? 'NOT NULL' : ''; |
191
|
|
|
} else { |
192
|
|
|
$not_null = ""; |
193
|
|
|
} |
194
|
|
|
if (isset($field_def['size'])) { |
195
|
|
|
$size = $field_def['size'] ? '(' . $field_def['size'] . ')' : ''; |
196
|
|
|
} else { |
197
|
|
|
$size = ""; |
198
|
|
|
} |
199
|
|
|
if (isset($field_def['index'])) { |
200
|
|
|
if ($field_def['index']) { |
201
|
|
|
$index[] = "INDEX($field)"; |
202
|
|
|
} |
203
|
|
|
} |
204
|
|
|
if (isset($field_def['unique_index'])) { |
205
|
|
|
if ($field_def['unique_index']) { |
206
|
|
|
$index[] = "UNIQUE($field)"; |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
if (isset($field_def['primary'])) { |
210
|
|
|
if ($field_def['primary']) { |
211
|
|
|
$primary[] = "$field"; |
212
|
|
|
} |
213
|
|
|
} |
214
|
|
|
if (isset($field_def['auto'])) { |
215
|
|
|
if ($field_def['auto']) { |
216
|
|
|
$field_def['type'] = "SERIAL"; |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
if (isset($field_def['extra'])) { |
220
|
|
|
$extra = $field_def['extra']; |
221
|
|
|
} else { |
222
|
|
|
$extra = ""; |
223
|
|
|
} |
224
|
|
|
$create_lines[] = "$field " . $field_def['type'] . $size . ' ' . $not_null . ' ' . $extra; |
225
|
|
|
} |
226
|
|
|
$create_sql.= join(',', $create_lines); |
227
|
|
|
$last_lines = array(); |
228
|
|
|
if (count($primary)) { |
229
|
|
|
$last_lines[] = 'PRIMARY KEY(' . join(",", $primary) . ')'; |
230
|
|
|
} |
231
|
|
|
if (count($index)) { |
232
|
|
|
$last_lines[] = join(',', $index); |
233
|
|
|
} |
234
|
|
|
if (count($unique_index)) { |
235
|
|
|
$last_lines[] = join(',', $unique_index); |
236
|
|
|
} |
237
|
|
|
if (count($last_lines)) { |
238
|
|
|
$create_sql.= ',' . join(',', $last_lines) . ')'; |
239
|
|
|
} |
240
|
|
|
return $this->query($create_sql); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Listar las tablas en la base de datos |
245
|
|
|
* |
246
|
|
|
* @return array |
247
|
|
|
*/ |
248
|
|
|
public function list_tables() |
249
|
|
|
{ |
250
|
|
|
return $this->fetch_all("SELECT c.relname AS table_name FROM pg_class c, pg_user u " |
251
|
|
|
. "WHERE c.relowner = u.usesysid AND c.relkind = 'r' " |
252
|
|
|
. "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) " |
253
|
|
|
. "AND c.relname !~ '^(pg_|sql_)' UNION " |
254
|
|
|
. "SELECT c.relname AS table_name FROM pg_class c " |
255
|
|
|
. "WHERE c.relkind = 'r' " |
256
|
|
|
. "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) " |
257
|
|
|
. "AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner) " |
258
|
|
|
. "AND c.relname !~ '^pg_'"); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* Listar los campos de una tabla |
263
|
|
|
* |
264
|
|
|
* @param string $table |
265
|
|
|
* @return array |
266
|
|
|
*/ |
267
|
|
|
public function describe_table($table, $schema='') |
268
|
|
|
{ |
269
|
|
|
$describe = $this->fetch_all("SELECT a.attname AS Field, t.typname AS Type, |
270
|
|
|
CASE WHEN attnotnull=false THEN 'YES' ELSE 'NO' END AS Null, |
271
|
|
|
CASE WHEN (select cc.contype FROM pg_catalog.pg_constraint cc WHERE |
272
|
|
|
cc.conrelid = c.oid AND cc.conkey[1] = a.attnum)='p' THEN 'PRI' ELSE '' |
273
|
|
|
END AS Key, CASE WHEN atthasdef=true THEN TRUE ELSE NULL END AS Default |
274
|
|
|
FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a, |
275
|
|
|
pg_catalog.pg_type t WHERE c.relname = '$table' AND c.oid = a.attrelid |
276
|
|
|
AND a.attnum > 0 AND t.oid = a.atttypid order by a.attnum"); |
277
|
|
|
$final_describe = array(); |
278
|
|
|
foreach ($describe as $key => $value) { |
279
|
|
|
$final_describe[] = array( |
280
|
|
|
"Field" => $value["field"], |
281
|
|
|
"Type" => $value["type"], |
282
|
|
|
"Null" => $value["null"], |
283
|
|
|
"Key" => $value["key"], |
284
|
|
|
"Default" => $value["default"] |
285
|
|
|
); |
286
|
|
|
} |
287
|
|
|
return $final_describe; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
} |
291
|
|
|
|