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