1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Database\Drivers;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17:
18: class PgSqlDriver extends Nette\Object implements Nette\Database\ISupplementalDriver
19: {
20:
21: private $connection;
22:
23:
24: public function __construct(Nette\Database\Connection $connection, array $options)
25: {
26: $this->connection = $connection;
27: }
28:
29:
30:
31:
32:
33: 34: 35:
36: public function delimite($name)
37: {
38:
39: return '"' . str_replace('"', '""', $name) . '"';
40: }
41:
42:
43: 44: 45:
46: public function formatBool($value)
47: {
48: return $value ? 'TRUE' : 'FALSE';
49: }
50:
51:
52: 53: 54:
55: public function formatDateTime( $value)
56: {
57: return $value->format("'Y-m-d H:i:s'");
58: }
59:
60:
61: 62: 63:
64: public function formatLike($value, $pos)
65: {
66: $bs = substr($this->connection->quote('\\', \PDO::PARAM_STR), 1, -1);
67: $value = substr($this->connection->quote($value, \PDO::PARAM_STR), 1, -1);
68: $value = strtr($value, array('%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\'));
69: return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
70: }
71:
72:
73: 74: 75:
76: public function applyLimit(& $sql, $limit, $offset)
77: {
78: if ($limit >= 0) {
79: $sql .= ' LIMIT ' . (int) $limit;
80: }
81: if ($offset > 0) {
82: $sql .= ' OFFSET ' . (int) $offset;
83: }
84: }
85:
86:
87: 88: 89:
90: public function normalizeRow($row)
91: {
92: return $row;
93: }
94:
95:
96:
97:
98:
99: 100: 101:
102: public function getTables()
103: {
104: $tables = array();
105: foreach ($this->connection->query("
106: SELECT
107: c.relname::varchar AS name,
108: c.relkind = 'v' AS view
109: FROM
110: pg_catalog.pg_class AS c
111: JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
112: WHERE
113: c.relkind IN ('r', 'v')
114: AND ARRAY[n.nspname] <@ pg_catalog.current_schemas(FALSE)
115: ORDER BY
116: c.relname
117: ") as $row) {
118: $tables[] = (array) $row;
119: }
120:
121: return $tables;
122: }
123:
124:
125: 126: 127:
128: public function getColumns($table)
129: {
130: $columns = array();
131: foreach ($this->connection->query("
132: SELECT
133: a.attname::varchar AS name,
134: c.relname::varchar AS table,
135: upper(t.typname) AS nativetype,
136: NULL AS size,
137: FALSE AS unsigned,
138: NOT (a.attnotnull OR t.typtype = 'd' AND t.typnotnull) AS nullable,
139: pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass)::varchar AS default,
140: coalesce(co.contype = 'p' AND strpos(ad.adsrc, 'nextval') = 1, FALSE) AS autoincrement,
141: coalesce(co.contype = 'p', FALSE) AS primary,
142: substring(pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass) from 'nextval[(]''\"?([^''\"]+)') AS sequence
143: FROM
144: pg_catalog.pg_attribute AS a
145: JOIN pg_catalog.pg_class AS c ON a.attrelid = c.oid
146: JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
147: JOIN pg_catalog.pg_type AS t ON a.atttypid = t.oid
148: LEFT JOIN pg_catalog.pg_attrdef AS ad ON ad.adrelid = c.oid AND ad.adnum = a.attnum
149: LEFT JOIN pg_catalog.pg_constraint AS co ON co.connamespace = n.oid AND contype = 'p' AND co.conrelid = c.oid AND a.attnum = ANY(co.conkey)
150: WHERE
151: c.relkind IN ('r', 'v')
152: AND c.relname::varchar = {$this->connection->quote($table)}
153: AND ARRAY[n.nspname] <@ pg_catalog.current_schemas(FALSE)
154: AND a.attnum > 0
155: AND NOT a.attisdropped
156: ORDER BY
157: a.attnum
158: ") as $row) {
159: $column = (array) $row;
160: $column['vendor'] = $column;
161: unset($column['sequence']);
162:
163: $columns[] = $column;
164: }
165:
166: return $columns;
167: }
168:
169:
170: 171: 172:
173: public function getIndexes($table)
174: {
175: $indexes = array();
176: foreach ($this->connection->query("
177: SELECT
178: c2.relname::varchar AS name,
179: i.indisunique AS unique,
180: i.indisprimary AS primary,
181: a.attname::varchar AS column
182: FROM
183: pg_catalog.pg_class AS c1
184: JOIN pg_catalog.pg_namespace AS n ON c1.relnamespace = n.oid
185: JOIN pg_catalog.pg_index AS i ON c1.oid = i.indrelid
186: JOIN pg_catalog.pg_class AS c2 ON i.indexrelid = c2.oid
187: LEFT JOIN pg_catalog.pg_attribute AS a ON c1.oid = a.attrelid AND a.attnum = ANY(i.indkey)
188: WHERE
189: ARRAY[n.nspname] <@ pg_catalog.current_schemas(FALSE)
190: AND c1.relkind = 'r'
191: AND c1.relname = {$this->connection->quote($table)}
192: ") as $row) {
193: $indexes[$row['name']]['name'] = $row['name'];
194: $indexes[$row['name']]['unique'] = $row['unique'];
195: $indexes[$row['name']]['primary'] = $row['primary'];
196: $indexes[$row['name']]['columns'][] = $row['column'];
197: }
198:
199: return array_values($indexes);
200: }
201:
202:
203: 204: 205:
206: public function getForeignKeys($table)
207: {
208:
209: return $this->connection->query("
210: SELECT
211: co.conname::varchar AS name,
212: al.attname::varchar AS local,
213: cf.relname::varchar AS table,
214: af.attname::varchar AS foreign
215: FROM
216: pg_catalog.pg_constraint AS co
217: JOIN pg_catalog.pg_namespace AS n ON co.connamespace = n.oid
218: JOIN pg_catalog.pg_class AS cl ON co.conrelid = cl.oid
219: JOIN pg_catalog.pg_class AS cf ON co.confrelid = cf.oid
220: JOIN pg_catalog.pg_attribute AS al ON al.attrelid = cl.oid AND al.attnum = co.conkey[1]
221: JOIN pg_catalog.pg_attribute AS af ON af.attrelid = cf.oid AND af.attnum = co.confkey[1]
222: WHERE
223: ARRAY[n.nspname] <@ pg_catalog.current_schemas(FALSE)
224: AND co.contype = 'f'
225: AND cl.relname = {$this->connection->quote($table)}
226: ")->fetchAll();
227: }
228:
229:
230: 231: 232:
233: public function getColumnTypes(\PDOStatement $statement)
234: {
235: return Nette\Database\Helpers::detectTypes($statement);
236: }
237:
238:
239: 240: 241:
242: public function isSupported($item)
243: {
244: return $item === self::SUPPORT_SEQUENCE || $item === self::SUPPORT_SUBSELECT;
245: }
246:
247: }
248: