Rev 1086 | Rev 1130 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1086 | Rev 1116 | ||
---|---|---|---|
Line 27... | Line 27... | ||
27 | protected /*bool*/ $connected = false; |
27 | protected /*bool*/ $connected = false; |
28 | protected /*?bool*/ $html = null; |
28 | protected /*?bool*/ $html = null; |
29 | protected /*?string*/ $last_query = null; |
29 | protected /*?string*/ $last_query = null; |
30 | protected /*bool*/ $slangDetectionDone = false; |
30 | protected /*bool*/ $slangDetectionDone = false; |
31 | 31 | ||
- | 32 | /** |
|
- | 33 | * @param string $sql |
|
- | 34 | * @param array|null $prepared_args |
|
- | 35 | * @return OIDplusQueryResult |
|
- | 36 | * @throws OIDplusException |
|
- | 37 | */ |
|
32 | protected abstract function doQuery(string $sql, /*?array*/ $prepared_args=null): OIDplusQueryResult; |
38 | protected abstract function doQuery(string $sql, array $prepared_args=null): OIDplusQueryResult; |
- | 39 | ||
- | 40 | /** |
|
- | 41 | * @return string |
|
- | 42 | */ |
|
33 | public abstract function error(): string; |
43 | public abstract function error(): string; |
- | 44 | ||
- | 45 | /** |
|
- | 46 | * @return void |
|
- | 47 | */ |
|
34 | public abstract function transaction_begin()/*: void*/; |
48 | public abstract function transaction_begin()/*: void*/; |
- | 49 | ||
- | 50 | /** |
|
- | 51 | * @return void |
|
- | 52 | */ |
|
35 | public abstract function transaction_commit()/*: void*/; |
53 | public abstract function transaction_commit()/*: void*/; |
- | 54 | ||
- | 55 | /** |
|
- | 56 | * @return void |
|
- | 57 | */ |
|
36 | public abstract function transaction_rollback()/*: void*/; |
58 | public abstract function transaction_rollback()/*: void*/; |
- | 59 | ||
- | 60 | /** |
|
- | 61 | * @return bool |
|
- | 62 | */ |
|
37 | public abstract function transaction_supported(): bool; |
63 | public abstract function transaction_supported(): bool; |
- | 64 | ||
- | 65 | /** |
|
- | 66 | * @return int |
|
- | 67 | */ |
|
38 | public abstract function transaction_level(): int; |
68 | public abstract function transaction_level(): int; |
- | 69 | ||
- | 70 | /** |
|
- | 71 | * @return void |
|
- | 72 | */ |
|
39 | protected abstract function doConnect()/*: void*/; |
73 | protected abstract function doConnect()/*: void*/; |
- | 74 | ||
- | 75 | /** |
|
- | 76 | * @return void |
|
- | 77 | */ |
|
40 | protected abstract function doDisconnect()/*: void*/; |
78 | protected abstract function doDisconnect()/*: void*/; |
41 | 79 | ||
- | 80 | /** |
|
- | 81 | * @return OIDplusDatabasePlugin|null |
|
- | 82 | */ |
|
42 | public function getPlugin()/*: ?OIDplusDatabasePlugin*/ { |
83 | public function getPlugin()/*: ?OIDplusDatabasePlugin*/ { |
43 | $res = null; |
84 | $res = null; |
44 | $plugins = OIDplus::getDatabasePlugins(); |
85 | $plugins = OIDplus::getDatabasePlugins(); |
45 | foreach ($plugins as $plugin) { |
86 | foreach ($plugins as $plugin) { |
46 | if (get_class($this) == get_class($plugin::newConnection($this))) { |
87 | if (get_class($this) == get_class($plugin::newConnection())) { |
47 | return $plugin; |
88 | return $plugin; |
48 | } |
89 | } |
49 | } |
90 | } |
50 | return $res; |
91 | return $res; |
51 | } |
92 | } |
52 | 93 | ||
- | 94 | /** |
|
- | 95 | * @return int |
|
- | 96 | * @throws OIDplusException |
|
- | 97 | */ |
|
53 | public function insert_id(): int { |
98 | public function insert_id(): int { |
54 | // This is the "fallback" variant. If your database provider (e.g. PDO) supports |
99 | // This is the "fallback" variant. If your database provider (e.g. PDO) supports |
55 | // a function to detect the last inserted id, please override this |
100 | // a function to detect the last inserted id, please override this |
56 | // function in order to use that specialized function (since it is usually |
101 | // function in order to use that specialized function (since it is usually |
57 | // more reliable). |
102 | // more reliable). |
58 | return $this->getSlang()->insert_id($this); |
103 | return $this->getSlang()->insert_id($this); |
59 | } |
104 | } |
60 | 105 | ||
- | 106 | /** |
|
- | 107 | * @param string $sql |
|
- | 108 | * @return array[] |
|
- | 109 | * @throws OIDplusException |
|
- | 110 | */ |
|
61 | public final function getTable(string $sql) { |
111 | public final function getTable(string $sql): array { |
62 | $out = array(); |
112 | $out = array(); |
63 | $res = $this->query($sql); |
113 | $res = $this->query($sql); |
64 | while ($row = $res->fetch_array()) { |
114 | while ($row = $res->fetch_array()) { |
65 | $out[] = $row; |
115 | $out[] = $row; |
66 | } |
116 | } |
67 | return $out; |
117 | return $out; |
68 | } |
118 | } |
69 | 119 | ||
- | 120 | /** |
|
- | 121 | * @param string $sql |
|
- | 122 | * @return mixed|null |
|
- | 123 | * @throws OIDplusException |
|
- | 124 | */ |
|
70 | public final function getScalar(string $sql) { |
125 | public final function getScalar(string $sql) { |
71 | $res = $this->query($sql); |
126 | $res = $this->query($sql); |
72 | $row = $res->fetch_array(); |
127 | $row = $res->fetch_array(); |
73 | return $row ? reset($row) : null; |
128 | return $row ? reset($row) : null; |
74 | } |
129 | } |
75 | 130 | ||
- | 131 | /** |
|
- | 132 | * @param string $sql |
|
- | 133 | * @param array|null $prepared_args |
|
- | 134 | * @return OIDplusQueryResult |
|
- | 135 | * @throws OIDplusException |
|
- | 136 | */ |
|
76 | public final function query(string $sql, /*?array*/ $prepared_args=null): OIDplusQueryResult { |
137 | public final function query(string $sql, /*?array*/ $prepared_args=null): OIDplusQueryResult { |
77 | 138 | ||
78 | $query_logfile = OIDplus::baseConfig()->getValue('QUERY_LOGFILE', ''); |
139 | $query_logfile = OIDplus::baseConfig()->getValue('QUERY_LOGFILE', ''); |
79 | if (!empty($query_logfile)) { |
140 | if (!empty($query_logfile)) { |
80 | $ts = explode(" ",microtime()); |
141 | $ts = explode(" ",microtime()); |
Line 98... | Line 159... | ||
98 | } |
159 | } |
99 | 160 | ||
100 | return $this->doQuery($sql, $prepared_args); |
161 | return $this->doQuery($sql, $prepared_args); |
101 | } |
162 | } |
102 | 163 | ||
- | 164 | /** |
|
- | 165 | * @return void |
|
- | 166 | * @throws OIDplusException |
|
- | 167 | */ |
|
103 | public final function connect()/*: void*/ { |
168 | public final function connect()/*: void*/ { |
104 | if ($this->connected) return; |
169 | if ($this->connected) return; |
105 | $this->beforeConnect(); |
170 | $this->beforeConnect(); |
106 | $this->doConnect(); |
171 | $this->doConnect(); |
107 | $this->connected = true; |
172 | $this->connected = true; |
108 | OIDplus::register_shutdown_function(array($this, 'disconnect')); |
173 | OIDplus::register_shutdown_function(array($this, 'disconnect')); |
109 | $this->afterConnectMandatory(); |
174 | $this->afterConnectMandatory(); |
110 | $this->afterConnect(); |
175 | $this->afterConnect(); |
111 | } |
176 | } |
112 | 177 | ||
- | 178 | /** |
|
- | 179 | * @return void |
|
- | 180 | */ |
|
113 | public final function disconnect()/*: void*/ { |
181 | public final function disconnect()/*: void*/ { |
114 | if (!$this->connected) return; |
182 | if (!$this->connected) return; |
115 | $this->beforeDisconnect(); |
183 | $this->beforeDisconnect(); |
116 | $this->doDisconnect(); |
184 | $this->doDisconnect(); |
117 | $this->connected = false; |
185 | $this->connected = false; |
118 | $this->afterDisconnect(); |
186 | $this->afterDisconnect(); |
119 | } |
187 | } |
120 | 188 | ||
- | 189 | /** |
|
- | 190 | * @param string $fieldname |
|
- | 191 | * @param string $order |
|
- | 192 | * @return string |
|
- | 193 | * @throws OIDplusException |
|
- | 194 | */ |
|
121 | public function natOrder($fieldname, $order='asc'): string { |
195 | public function natOrder(string $fieldname, string $order='asc'): string { |
122 | $slang = $this->getSlang(); |
196 | $slang = $this->getSlang(); |
123 | if (!is_null($slang)) { |
197 | if (!is_null($slang)) { |
124 | return $slang->natOrder($fieldname, $order); |
198 | return $slang->natOrder($fieldname, $order); |
125 | } else { |
199 | } else { |
126 | $order = strtolower($order); |
200 | $order = strtolower($order); |
Line 131... | Line 205... | ||
131 | // For (yet) unsupported DBMS, we do not offer natural sort |
205 | // For (yet) unsupported DBMS, we do not offer natural sort |
132 | return "$fieldname $order"; |
206 | return "$fieldname $order"; |
133 | } |
207 | } |
134 | } |
208 | } |
135 | 209 | ||
- | 210 | /** |
|
- | 211 | * @return void |
|
- | 212 | */ |
|
136 | protected function beforeDisconnect()/*: void*/ {} |
213 | protected function beforeDisconnect()/*: void*/ {} |
137 | 214 | ||
- | 215 | /** |
|
- | 216 | * @return void |
|
- | 217 | */ |
|
138 | protected function afterDisconnect()/*: void*/ {} |
218 | protected function afterDisconnect()/*: void*/ {} |
139 | 219 | ||
- | 220 | /** |
|
- | 221 | * @return void |
|
- | 222 | */ |
|
140 | protected function beforeConnect()/*: void*/ {} |
223 | protected function beforeConnect()/*: void*/ {} |
141 | 224 | ||
- | 225 | /** |
|
- | 226 | * @return void |
|
- | 227 | */ |
|
142 | protected function afterConnect()/*: void*/ {} |
228 | protected function afterConnect()/*: void*/ {} |
143 | 229 | ||
- | 230 | /** |
|
- | 231 | * @return void |
|
- | 232 | * @throws OIDplusConfigInitializationException |
|
- | 233 | * @throws OIDplusException |
|
- | 234 | */ |
|
144 | private function afterConnectMandatory()/*: void*/ { |
235 | private function afterConnectMandatory()/*: void*/ { |
145 | // Check if the config table exists. This is important because the database version is stored in it |
236 | // Check if the config table exists. This is important because the database version is stored in it |
146 | $this->initRequireTables(array('config')); |
237 | $this->initRequireTables(array('config')); |
147 | 238 | ||
148 | // Do the database tables need an update? |
239 | // Do the database tables need an update? |
Line 161... | Line 252... | ||
161 | // PDO would automatically roll-back. Therefore, we detect the slang right at the beginning, |
252 | // PDO would automatically roll-back. Therefore, we detect the slang right at the beginning, |
162 | // before any transaction is used. |
253 | // before any transaction is used. |
163 | $this->getSlang(); |
254 | $this->getSlang(); |
164 | } |
255 | } |
165 | 256 | ||
- | 257 | /** |
|
- | 258 | * @param string[] $tableNames |
|
- | 259 | * @return void |
|
- | 260 | * @throws OIDplusConfigInitializationException |
|
- | 261 | * @throws OIDplusException |
|
- | 262 | */ |
|
166 | private function initRequireTables($tableNames)/*: void*/ { |
263 | private function initRequireTables(array $tableNames)/*: void*/ { |
167 | $msgs = array(); |
264 | $msgs = array(); |
168 | foreach ($tableNames as $tableName) { |
265 | foreach ($tableNames as $tableName) { |
169 | $prefix = OIDplus::baseConfig()->getValue('TABLENAME_PREFIX', ''); |
266 | $prefix = OIDplus::baseConfig()->getValue('TABLENAME_PREFIX', ''); |
170 | if (!$this->tableExists($prefix.$tableName)) { |
267 | if (!$this->tableExists($prefix.$tableName)) { |
171 | $msgs[] = _L('Table %1 is missing!',$prefix.$tableName); |
268 | $msgs[] = _L('Table %1 is missing!',$prefix.$tableName); |
Line 174... | Line 271... | ||
174 | if (count($msgs) > 0) { |
271 | if (count($msgs) > 0) { |
175 | throw new OIDplusConfigInitializationException(implode("\n\n",$msgs)); |
272 | throw new OIDplusConfigInitializationException(implode("\n\n",$msgs)); |
176 | } |
273 | } |
177 | } |
274 | } |
178 | 275 | ||
- | 276 | /** |
|
- | 277 | * @param string $tableName |
|
- | 278 | * @return bool |
|
- | 279 | */ |
|
179 | public function tableExists($tableName): bool { |
280 | public function tableExists(string $tableName): bool { |
180 | try { |
281 | try { |
181 | // Attention: This query could interrupt transactions if Rollback-On-Error is enabled |
282 | // Attention: This query could interrupt transactions if Rollback-On-Error is enabled |
182 | $this->query("select 0 from ".$tableName." where 1=0"); |
283 | $this->query("select 0 from ".$tableName." where 1=0"); |
183 | return true; |
284 | return true; |
184 | } catch (\Exception $e) { |
285 | } catch (\Exception $e) { |
185 | return false; |
286 | return false; |
186 | } |
287 | } |
187 | } |
288 | } |
188 | 289 | ||
- | 290 | /** |
|
- | 291 | * @return bool |
|
- | 292 | */ |
|
189 | public function isConnected(): bool { |
293 | public function isConnected(): bool { |
190 | return $this->connected; |
294 | return $this->connected; |
191 | } |
295 | } |
192 | 296 | ||
- | 297 | /** |
|
- | 298 | * @param bool $html |
|
- | 299 | * @return void |
|
- | 300 | */ |
|
193 | public function init($html = true)/*: void*/ { |
301 | public function init(bool $html = true)/*: void*/ { |
194 | $this->html = $html; |
302 | $this->html = $html; |
195 | } |
303 | } |
196 | 304 | ||
- | 305 | /** |
|
- | 306 | * @return string |
|
- | 307 | * @throws OIDplusException |
|
- | 308 | */ |
|
197 | public function sqlDate(): string { |
309 | public function sqlDate(): string { |
198 | $slang = $this->getSlang(); |
310 | $slang = $this->getSlang(); |
199 | if (!is_null($slang)) { |
311 | if (!is_null($slang)) { |
200 | return $slang->sqlDate(); |
312 | return $slang->sqlDate(); |
201 | } else { |
313 | } else { |
202 | return "'" . date('Y-m-d H:i:s') . "'"; |
314 | return "'" . date('Y-m-d H:i:s') . "'"; |
203 | } |
315 | } |
204 | } |
316 | } |
205 | 317 | ||
- | 318 | /** |
|
- | 319 | * @param bool $mustExist |
|
- | 320 | * @return OIDplusSqlSlangPlugin|null |
|
- | 321 | * @throws OIDplusConfigInitializationException |
|
- | 322 | * @throws OIDplusException |
|
- | 323 | */ |
|
206 | protected function doGetSlang(bool $mustExist=true)/*: ?OIDplusSqlSlangPlugin*/ { |
324 | protected function doGetSlang(bool $mustExist=true)/*: ?OIDplusSqlSlangPlugin*/ { |
207 | $res = null; |
325 | $res = null; |
208 | 326 | ||
209 | if (OIDplus::baseConfig()->exists('FORCE_DBMS_SLANG')) { |
327 | if (OIDplus::baseConfig()->exists('FORCE_DBMS_SLANG')) { |
210 | $name = OIDplus::baseConfig()->getValue('FORCE_DBMS_SLANG', ''); |
328 | $name = OIDplus::baseConfig()->getValue('FORCE_DBMS_SLANG', ''); |
Line 232... | Line 350... | ||
232 | } |
350 | } |
233 | 351 | ||
234 | return $res; |
352 | return $res; |
235 | } |
353 | } |
236 | 354 | ||
- | 355 | /** |
|
- | 356 | * @param bool $mustExist |
|
- | 357 | * @return OIDplusSqlSlangPlugin|null |
|
- | 358 | * @throws OIDplusConfigInitializationException |
|
- | 359 | * @throws OIDplusException |
|
- | 360 | */ |
|
237 | public final function getSlang(bool $mustExist=true)/*: ?OIDplusSqlSlangPlugin*/ { |
361 | public final function getSlang(bool $mustExist=true)/*: ?OIDplusSqlSlangPlugin*/ { |
238 | static /*?OIDplusSqlSlangPlugin*/ $slangCache = null; |
362 | static /*?OIDplusSqlSlangPlugin*/ $slangCache = null; |
239 | 363 | ||
240 | if ($this->slangDetectionDone) { |
364 | if ($this->slangDetectionDone) { |
241 | return $slangCache; |
365 | return $slangCache; |