1 | <?php |
||||
2 | /** |
||||
3 | * Class PostgreSQL |
||||
4 | * |
||||
5 | * @filesource PostgreSQL.php |
||||
6 | * @created 28.06.2017 |
||||
7 | * @package chillerlan\Database\Drivers |
||||
8 | * @author Smiley <[email protected]> |
||||
9 | * @copyright 2017 Smiley |
||||
10 | * @license MIT |
||||
11 | * |
||||
12 | * @noinspection PhpComposerExtensionStubsInspection |
||||
13 | */ |
||||
14 | |||||
15 | namespace chillerlan\Database\Drivers; |
||||
16 | |||||
17 | use chillerlan\Database\{ |
||||
18 | Dialects\Postgres, Result |
||||
19 | }; |
||||
20 | |||||
21 | /** |
||||
22 | * @property resource $db |
||||
23 | */ |
||||
24 | class PostgreSQL extends DriverAbstract{ |
||||
25 | |||||
26 | protected string $dialect = Postgres::class; |
||||
27 | |||||
28 | /** @inheritdoc */ |
||||
29 | public function connect():DriverInterface{ |
||||
30 | |||||
31 | if(gettype($this->db) === 'resource'){ |
||||
32 | return $this; |
||||
33 | } |
||||
34 | |||||
35 | // i am an ugly duckling. fix me please. |
||||
36 | |||||
37 | $options = [ |
||||
38 | '--client_encoding='.$this->options->pgsql_charset, |
||||
39 | ]; |
||||
40 | |||||
41 | $conn_str = [ |
||||
42 | 'host=\''.$this->options->host.'\'', |
||||
43 | 'port=\''.(int)$this->options->port.'\'', |
||||
44 | 'dbname=\''.$this->options->database.'\'', |
||||
45 | 'user=\''.$this->options->username.'\'', |
||||
46 | 'password=\''.$this->options->password.'\'', |
||||
47 | 'options=\''.implode(' ', $options).'\'', |
||||
48 | ]; |
||||
49 | |||||
50 | try{ |
||||
51 | $this->db = pg_connect(implode(' ', $conn_str)); |
||||
52 | |||||
53 | return $this; |
||||
54 | } |
||||
55 | catch(\Exception $e){ |
||||
56 | throw new DriverException('db error: [PostgreSQL]: '.$e->getMessage()); |
||||
57 | } |
||||
58 | |||||
59 | } |
||||
60 | |||||
61 | /** @inheritdoc */ |
||||
62 | public function disconnect():bool{ |
||||
63 | |||||
64 | if(gettype($this->db) === 'resource'){ |
||||
65 | return pg_close($this->db); |
||||
66 | } |
||||
67 | |||||
68 | return true; |
||||
69 | } |
||||
70 | |||||
71 | /** @inheritdoc */ |
||||
72 | public function getClientInfo():string{ |
||||
73 | $ver = pg_version($this->db); |
||||
74 | |||||
75 | return 'PostgreSQL '.$ver['client'].' ('.$ver['client_encoding'].')'; |
||||
76 | } |
||||
77 | |||||
78 | /** @inheritdoc */ |
||||
79 | public function getServerInfo():?string{ |
||||
80 | $ver = pg_version($this->db); |
||||
81 | |||||
82 | return 'PostgreSQL '.$ver['server'].' ('.$ver['server_encoding'].', date style: '.$ver['DateStyle'].', time zone: '.$ver['TimeZone'].')'; |
||||
83 | } |
||||
84 | |||||
85 | /** @inheritdoc */ |
||||
86 | protected function __escape(string $data):string{ |
||||
87 | return '\''.pg_escape_string($this->db, $data).'\''; // emulate PDO |
||||
88 | } |
||||
89 | |||||
90 | /** |
||||
91 | * @param $result |
||||
92 | * @param string|null $index |
||||
93 | * @param bool $assoc |
||||
94 | * |
||||
95 | * @return bool|\chillerlan\Database\Result |
||||
96 | */ |
||||
97 | protected function __getResult($result, string $index = null, bool $assoc = null){ |
||||
98 | |||||
99 | if(is_bool($result)){ |
||||
100 | return $result; // @codeCoverageIgnore |
||||
101 | } |
||||
102 | |||||
103 | $out = new Result(null, $this->convert_encoding_src, $this->convert_encoding_dest); |
||||
104 | $i = 0; |
||||
105 | |||||
106 | while($row = call_user_func_array($assoc === true ? 'pg_fetch_assoc' : 'pg_fetch_row', [$result])){ |
||||
107 | $key = $i; |
||||
108 | |||||
109 | $j = 0; |
||||
110 | foreach($row as $k => $item){ |
||||
111 | // https://gitter.im/arenanet/api-cdi?at=594326ba31f589c64fafe554 |
||||
112 | $fieldType = pg_field_type($result, $j); |
||||
113 | |||||
114 | if($fieldType === 'bool'){ |
||||
115 | $row[$k] = $item === 't'; |
||||
116 | } |
||||
117 | elseif(in_array($fieldType, ['int2', 'int4', 'int8'], true)){ |
||||
118 | $row[$k] = (int)$item; |
||||
119 | |||||
120 | } |
||||
121 | elseif(in_array($fieldType, ['float4', 'float8'], true)){ |
||||
122 | $row[$k] = (float)$item; // @codeCoverageIgnore |
||||
123 | } |
||||
124 | |||||
125 | $j++; |
||||
126 | } |
||||
127 | |||||
128 | if($assoc && !empty($index)){ |
||||
129 | $key = $row[$index]; |
||||
130 | } |
||||
131 | |||||
132 | $out[$key] = $row; |
||||
133 | $i++; |
||||
134 | } |
||||
135 | |||||
136 | pg_free_result($result); |
||||
137 | |||||
138 | return $i === 0 ? true : $out; |
||||
139 | } |
||||
140 | |||||
141 | /** @inheritdoc */ |
||||
142 | protected function raw_query(string $sql, string $index = null, bool $assoc = null){ |
||||
143 | return $this->__getResult(pg_query($sql), $index, $assoc); |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() The call to
pg_query() has too few arguments starting with query .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||
144 | } |
||||
145 | |||||
146 | /** @inheritdoc */ |
||||
147 | protected function prepared_query(string $sql, array $values = null, string $index = null, bool $assoc = null){ |
||||
148 | pg_prepare($this->db, '', $this->replaceParams($sql)); |
||||
149 | |||||
150 | return $this->__getResult(pg_execute($this->db, '', $values), $index, $assoc); |
||||
0 ignored issues
–
show
It seems like
$values can also be of type null ; however, parameter $params of pg_execute() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
151 | } |
||||
152 | |||||
153 | /** @inheritdoc */ |
||||
154 | protected function multi_query(string $sql, array $values){ |
||||
155 | pg_prepare($this->db, '', $this->replaceParams($sql)); |
||||
156 | |||||
157 | foreach($values as $row){ |
||||
158 | pg_execute($this->db, '', $row); |
||||
159 | } |
||||
160 | |||||
161 | return true; |
||||
162 | } |
||||
163 | |||||
164 | /** @inheritdoc */ |
||||
165 | protected function multi_callback_query(string $sql, iterable $data, $callback){ |
||||
166 | pg_prepare($this->db, '', $this->replaceParams($sql)); |
||||
167 | |||||
168 | foreach($data as $k => $row){ |
||||
169 | pg_execute($this->db, '', call_user_func_array($callback, [$row, $k])); |
||||
170 | } |
||||
171 | |||||
172 | return true; |
||||
173 | } |
||||
174 | |||||
175 | /** @inheritdoc */ |
||||
176 | protected function replaceParams(string $sql):string{ |
||||
177 | $i = 0; |
||||
178 | |||||
179 | return preg_replace_callback('/(\?)/', function() use (&$i){ |
||||
180 | return '$'.++$i; |
||||
181 | }, $sql); |
||||
182 | } |
||||
183 | |||||
184 | } |
||||
185 |