# Coverage for Doctrine_DataDict_Pgsql

Back to coverage report

1 | <?php
2 | /*
3 | * $Id: Pgsql.php 2963 2007-10-21 06:23:59Z Jonathan.Wage $
4 | *
5 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 | *
17 | * This software consists of voluntary contributions made by many individuals
18 | * and is licensed under the LGPL. For more information, see
19 | * <http://www.phpdoctrine.org>.
20 | */
21 | Doctrine::autoload('Doctrine_DataDict');
22 | /**
23 | * @package Doctrine
24 | * @subpackage DataDict
25 | * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
26 | * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
27 | * @author Paul Cooper <pgc@ucecom.com>
28 | * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
29 | * @version $Revision: 2963 $
30 | * @link www.phpdoctrine.org
31 | * @since 1.0
32 | */
33 | class Doctrine_DataDict_Pgsql extends Doctrine_DataDict
34 | {
35 | /**
36 | * @param array $reservedKeyWords an array of reserved keywords by pgsql
37 | */
38 | protected static $reservedKeyWords = array(
39 | 'abort',
40 | 'absolute',
41 | 'access',
42 | 'action',
43 | 'add',
44 | 'after',
45 | 'aggregate',
46 | 'all',
47 | 'alter',
48 | 'analyse',
49 | 'analyze',
50 | 'and',
51 | 'any',
52 | 'as',
53 | 'asc',
54 | 'assertion',
55 | 'assignment',
56 | 'at',
57 | 'authorization',
58 | 'backward',
59 | 'before',
60 | 'begin',
61 | 'between',
62 | 'bigint',
63 | 'binary',
64 | 'bit',
65 | 'boolean',
66 | 'both',
67 | 'by',
68 | 'cache',
69 | 'called',
70 | 'cascade',
71 | 'case',
72 | 'cast',
73 | 'chain',
74 | 'char',
75 | 'character',
76 | 'characteristics',
77 | 'check',
78 | 'checkpoint',
79 | 'class',
80 | 'close',
81 | 'cluster',
82 | 'coalesce',
83 | 'collate',
84 | 'column',
85 | 'comment',
86 | 'commit',
87 | 'committed',
88 | 'constraint',
89 | 'constraints',
90 | 'conversion',
91 | 'convert',
92 | 'copy',
93 | 'create',
94 | 'createdb',
95 | 'createuser',
96 | 'cross',
97 | 'current_date',
98 | 'current_time',
99 | 'current_timestamp',
100 | 'current_user',
101 | 'cursor',
102 | 'cycle',
103 | 'database',
104 | 'day',
105 | 'deallocate',
106 | 'dec',
107 | 'decimal',
108 | 'declare',
109 | 'default',
110 | 'deferrable',
111 | 'deferred',
112 | 'definer',
113 | 'delete',
114 | 'delimiter',
115 | 'delimiters',
116 | 'desc',
117 | 'distinct',
118 | 'do',
119 | 'domain',
120 | 'double',
121 | 'drop',
122 | 'each',
123 | 'else',
124 | 'encoding',
125 | 'encrypted',
126 | 'end',
127 | 'escape',
128 | 'except',
129 | 'exclusive',
130 | 'execute',
131 | 'exists',
132 | 'explain',
133 | 'external',
134 | 'extract',
135 | 'false',
136 | 'fetch',
137 | 'float',
138 | 'for',
139 | 'force',
140 | 'foreign',
141 | 'forward',
142 | 'freeze',
143 | 'from',
144 | 'full',
145 | 'function',
146 | 'get',
147 | 'global',
148 | 'grant',
149 | 'group',
150 | 'handler',
151 | 'having',
152 | 'hour',
153 | 'ilike',
154 | 'immediate',
155 | 'immutable',
156 | 'implicit',
157 | 'in',
158 | 'increment',
159 | 'index',
160 | 'inherits',
161 | 'initially',
162 | 'inner',
163 | 'inout',
164 | 'input',
165 | 'insensitive',
166 | 'insert',
167 | 'instead',
168 | 'int',
169 | 'integer',
170 | 'intersect',
171 | 'interval',
172 | 'into',
173 | 'invoker',
174 | 'is',
175 | 'isnull',
176 | 'isolation',
177 | 'join',
178 | 'key',
179 | 'lancompiler',
180 | 'language',
181 | 'leading',
182 | 'left',
183 | 'level',
184 | 'like',
185 | 'limit',
186 | 'listen',
187 | 'load',
188 | 'local',
189 | 'localtime',
190 | 'localtimestamp',
191 | 'location',
192 | 'lock',
193 | 'match',
194 | 'maxvalue',
195 | 'minute',
196 | 'minvalue',
197 | 'mode',
198 | 'month',
199 | 'move',
200 | 'names',
201 | 'national',
202 | 'natural',
203 | 'nchar',
204 | 'new',
205 | 'next',
206 | 'no',
207 | 'nocreatedb',
208 | 'nocreateuser',
209 | 'none',
210 | 'not',
211 | 'nothing',
212 | 'notify',
213 | 'notnull',
214 | 'null',
215 | 'nullif',
216 | 'numeric',
217 | 'of',
218 | 'off',
219 | 'offset',
220 | 'oids',
221 | 'old',
222 | 'on',
223 | 'only',
224 | 'operator',
225 | 'option',
226 | 'or',
227 | 'order',
228 | 'out',
229 | 'outer',
230 | 'overlaps',
231 | 'overlay',
232 | 'owner',
233 | 'partial',
234 | 'password',
235 | 'path',
236 | 'pendant',
237 | 'placing',
238 | 'position',
239 | 'precision',
240 | 'prepare',
241 | 'primary',
242 | 'prior',
243 | 'privileges',
244 | 'procedural',
245 | 'procedure',
246 | 'read',
247 | 'real',
248 | 'recheck',
249 | 'references',
250 | 'reindex',
251 | 'relative',
252 | 'rename',
253 | 'replace',
254 | 'reset',
255 | 'restrict',
256 | 'returns',
257 | 'revoke',
258 | 'right',
259 | 'rollback',
260 | 'row',
261 | 'rule',
262 | 'schema',
263 | 'scroll',
264 | 'second',
265 | 'security',
266 | 'select',
267 | 'sequence',
268 | 'serializable',
269 | 'session',
270 | 'session_user',
271 | 'set',
272 | 'setof',
273 | 'share',
274 | 'show',
275 | 'similar',
276 | 'simple',
277 | 'smallint',
278 | 'some',
279 | 'stable',
280 | 'start',
281 | 'statement',
282 | 'statistics',
283 | 'stdin',
284 | 'stdout',
285 | 'storage',
286 | 'strict',
287 | 'substring',
288 | 'sysid',
289 | 'table',
290 | 'temp',
291 | 'template',
292 | 'temporary',
293 | 'then',
294 | 'time',
295 | 'timestamp',
296 | 'to',
297 | 'toast',
298 | 'trailing',
299 | 'transaction',
300 | 'treat',
301 | 'trigger',
302 | 'trim',
303 | 'true',
304 | 'truncate',
305 | 'trusted',
306 | 'type',
307 | 'unencrypted',
308 | 'union',
309 | 'unique',
310 | 'unknown',
311 | 'unlisten',
312 | 'until',
313 | 'update',
314 | 'usage',
315 | 'user',
316 | 'using',
317 | 'vacuum',
318 | 'valid',
319 | 'validator',
320 | 'values',
321 | 'varchar',
322 | 'varying',
323 | 'verbose',
324 | 'version',
325 | 'view',
326 | 'volatile',
327 | 'when',
328 | 'where',
329 | 'with',
330 | 'without',
331 | 'work',
332 | 'write',
333 | 'year',
334 | 'zone'
335 | );
336 |
337 | /**
338 | * Obtain DBMS specific SQL code portion needed to declare an text type
339 | * field to be used in statements like CREATE TABLE.
340 | *
341 | * @param array $field associative array with the name of the properties
342 | * of the field being declared as array indexes. Currently, the types
343 | * of supported field properties are as follows:
344 | *
345 | * length
346 | * Integer value that determines the maximum length of the text
347 | * field. If this argument is missing the field should be
348 | * declared to have the longest length allowed by the DBMS.
349 | *
350 | * default
351 | * Text value to be used as default for this field.
352 | *
353 | * notnull
354 | * Boolean flag that indicates whether this field is constrained
355 | * to not be set to null.
356 | *
357 | * @return string DBMS specific SQL code portion that should be used to
358 | * declare the specified field.
359 | */
360 | public function getNativeDeclaration(array $field)
361 | {
362 | if ( ! isset($field['type'])) {
363 | throw new Doctrine_DataDict_Exception('Missing column type.');
364 | }
365 | switch ($field['type']) {
366 | case 'char':
367 | case 'string':
368 | case 'array':
369 | case 'object':
370 | case 'varchar':
371 | case 'gzip':
372 | // TODO: what is the maximum VARCHAR length in pgsql ?
373 | $length = (isset($field['length']) && $field['length'] && $field['length'] < 10000) ? $field['length'] : null;
374 |
375 | $fixed = ((isset($field['fixed']) && $field['fixed']) || $field['type'] == 'char') ? true : false;
376 |
377 | return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR('.$this->conn->options['default_text_field_length'].')')
378 | : ($length ? 'VARCHAR(' .$length . ')' : 'TEXT');
379 |
380 | case 'clob':
381 | return 'TEXT';
382 | case 'blob':
383 | return 'BYTEA';
384 | case 'enum':
385 | case 'integer':
386 | case 'int':
387 | if ( ! empty($field['autoincrement'])) {
388 | if ( ! empty($field['length'])) {
389 | $length = $field['length'];
390 | if ($length > 4) {
391 | return 'BIGSERIAL';
392 | }
393 | }
394 | return 'SERIAL';
395 | }
396 | if ( ! empty($field['length'])) {
397 | $length = $field['length'];
398 | if ($length <= 2) {
399 | return 'SMALLINT';
400 | } elseif ($length == 3 || $length == 4) {
401 | return 'INT';
402 | } elseif ($length > 4) {
403 | return 'BIGINT';
404 | }
405 | }
406 | return 'INT';
407 | case 'boolean':
408 | return 'BOOLEAN';
409 | case 'date':
410 | return 'DATE';
411 | case 'time':
412 | return 'TIME without time zone';
413 | case 'timestamp':
414 | return 'TIMESTAMP without time zone';
415 | case 'float':
416 | case 'double':
417 | return 'FLOAT8';
418 | case 'decimal':
419 | $length = !empty($field['length']) ? $field['length'] : 18;
420 | $scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
421 | return 'NUMERIC('.$length.','.$scale.')';
422 | }
423 | throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] . '\'.');
424 | }
425 |
426 | /**
427 | * Maps a native array description of a field to a portable Doctrine datatype and length
428 | *
429 | * @param array $field native field description
430 | *
431 | * @return array containing the various possible types, length, sign, fixed
432 | */
433 | public function getPortableDeclaration(array $field)
434 | {
435 |
436 | $length = (isset($field['length'])) ? $field['length'] : null;
437 | if ($length == '-1' && isset($field['atttypmod'])) {
438 | $length = $field['atttypmod'] - 4;
439 | }
440 | if ((int)$length <= 0) {
441 | $length = null;
442 | }
443 | $type = array();
444 | $unsigned = $fixed = null;
445 |
446 | if ( ! isset($field['name'])) {
447 | $field['name'] = '';
448 | }
449 |
450 | $dbType = strtolower($field['type']);
451 |
452 | switch ($dbType) {
453 | case 'smallint':
454 | case 'int2':
455 | $type[] = 'integer';
456 | $unsigned = false;
457 | $length = 2;
458 | if ($length == '2') {
459 | $type[] = 'boolean';
460 | if (preg_match('/^(is|has)/', $field['name'])) {
461 | $type = array_reverse($type);
462 | }
463 | }
464 | break;
465 | case 'int':
466 | case 'int4':
467 | case 'integer':
468 | case 'serial':
469 | case 'serial4':
470 | $type[] = 'integer';
471 | $unsigned = false;
472 | $length = 4;
473 | break;
474 | case 'bigint':
475 | case 'int8':
476 | case 'bigserial':
477 | case 'serial8':
478 | $type[] = 'integer';
479 | $unsigned = false;
480 | $length = 8;
481 | break;
482 | case 'bool':
483 | case 'boolean':
484 | $type[] = 'boolean';
485 | $length = 1;
486 | break;
487 | case 'text':
488 | case 'varchar':
489 | $fixed = false;
490 | case 'unknown':
491 | case 'char':
492 | case 'bpchar':
493 | $type[] = 'string';
494 | if ($length == '1') {
495 | $type[] = 'boolean';
496 | if (preg_match('/^(is|has)/', $field['name'])) {
497 | $type = array_reverse($type);
498 | }
499 | } elseif (strstr($dbType, 'text')) {
500 | $type[] = 'clob';
501 | }
502 | if ($fixed !== false) {
503 | $fixed = true;
504 | }
505 | break;
506 | case 'date':
507 | $type[] = 'date';
508 | $length = null;
509 | break;
510 | case 'datetime':
511 | case 'timestamp':
512 | $type[] = 'timestamp';
513 | $length = null;
514 | break;
515 | case 'time':
516 | $type[] = 'time';
517 | $length = null;
518 | break;
519 | case 'float':
520 | case 'float4':
521 | case 'double':
522 | case 'real':
523 | $type[] = 'float';
524 | break;
525 | case 'decimal':
526 | case 'money':
527 | case 'numeric':
528 | $type[] = 'decimal';
529 | break;
530 | case 'tinyblob':
531 | case 'mediumblob':
532 | case 'longblob':
533 | case 'blob':
534 | case 'bytea':
535 | $type[] = 'blob';
536 | $length = null;
537 | break;
538 | case 'oid':
539 | $type[] = 'blob';
540 | $type[] = 'clob';
541 | $length = null;
542 | break;
543 | case 'year':
544 | $type[] = 'integer';
545 | $type[] = 'date';
546 | $length = null;
547 | break;
548 | default:
549 | throw new Doctrine_DataDict_Exception('unknown database attribute type: '.$dbType);
550 | }
551 |
552 | return array('type' => $type,
553 | 'length' => $length,
554 | 'unsigned' => $unsigned,
555 | 'fixed' => $fixed);
556 | }
557 |
558 | /**
559 | * Obtain DBMS specific SQL code portion needed to declare an integer type
560 | * field to be used in statements like CREATE TABLE.
561 | *
562 | * @param string $name name the field to be declared.
563 | * @param array $field associative array with the name of the properties
564 | * of the field being declared as array indexes. Currently, the types
565 | * of supported field properties are as follows:
566 | *
567 | * unsigned
568 | * Boolean flag that indicates whether the field should be
569 | * declared as unsigned integer if possible.
570 | *
571 | * default
572 | * Integer value to be used as default for this field.
573 | *
574 | * notnull
575 | * Boolean flag that indicates whether this field is constrained
576 | * to not be set to null.
577 | * @return string DBMS specific SQL code portion that should be used to
578 | * declare the specified field.
579 | */
580 | public function getIntegerDeclaration($name, $field)
581 | {
582 | /**
583 | if ( ! empty($field['unsigned'])) {
584 | $this->conn->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
585 | }
586 | */
587 |
588 | if ( ! empty($field['autoincrement'])) {
589 | $name = $this->conn->quoteIdentifier($name, true);
590 | return $name . ' ' . $this->getNativeDeclaration($field);
591 | }
592 |
593 | $default = '';
594 | if (array_key_exists('default', $field)) {
595 | if ($field['default'] === '') {
596 | $field['default'] = empty($field['notnull']) ? null : 0;
597 | }
598 | $default = ' DEFAULT '.$this->conn->quote($field['default'], $field['type']);
599 | }
600 | /**
601 | TODO: is this needed ?
602 | elseif (empty($field['notnull'])) {
603 | $default = ' DEFAULT NULL';
604 | }
605 | */
606 |
607 | $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
608 | $name = $this->conn->quoteIdentifier($name, true);
609 | return $name . ' ' . $this->getNativeDeclaration($field) . $default . $notnull;
610 | }
611 |
612 | /**
613 | * parseBoolean
614 | * parses a literal boolean value and returns
615 | * proper sql equivalent
616 | *
617 | * @param string $value boolean value to be parsed
618 | * @return string parsed boolean value
619 | */
620 | public function parseBoolean($value)
621 | {
622 | return $value;
623 | }
624 | }