PluginProbe
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.0.6
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.0.6
5.13.0 5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 All 83 releases
matomo / app / libs / Zend / Db / Adapter / Abstract.php
Abstract.php
1,162 lines 45.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace {
4 /**
5 * Zend Framework
6 *
7 * LICENSE
8 *
9 * This source file is subject to the new BSD license that is bundled
10 * with this package in the file LICENSE.txt.
11 * It is also available through the world-wide-web at this URL:
12 * http://framework.zend.com/license/new-bsd
13 * If you did not receive a copy of the license and are unable to
14 * obtain it through the world-wide-web, please send an email
15 * to license@zend.com so we can send you a copy immediately.
16 *
17 * @category Zend
18 * @package Zend_Db
19 * @subpackage Adapter
20 * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
21 * @license http://framework.zend.com/license/new-bsd New BSD License
22 * @version $Id: Abstract.php 24148 2011-06-21 15:14:00Z yoshida@zend.co.jp $
23 */
24 /**
25 * @see Zend_Db
26 */
27 // require_once 'Zend/Db.php';
28 /**
29 * @see Zend_Db_Select
30 */
31 // require_once 'Zend/Db/Select.php';
32 /**
33 * Class for connecting to SQL databases and performing common operations.
34 *
35 * @category Zend
36 * @package Zend_Db
37 * @subpackage Adapter
38 * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
39 * @license http://framework.zend.com/license/new-bsd New BSD License
40 */
41 abstract class Zend_Db_Adapter_Abstract
42 {
43 /**
44 * User-provided configuration
45 *
46 * @var array
47 */
48 protected $_config = array();
49 /**
50 * Fetch mode
51 *
52 * @var integer
53 */
54 protected $_fetchMode = \Zend_Db::FETCH_ASSOC;
55 /**
56 * Query profiler object, of type Zend_Db_Profiler
57 * or a subclass of that.
58 *
59 * @var Zend_Db_Profiler
60 */
61 protected $_profiler;
62 /**
63 * Default class name for a DB statement.
64 *
65 * @var string
66 */
67 protected $_defaultStmtClass = 'Zend_Db_Statement';
68 /**
69 * Default class name for the profiler object.
70 *
71 * @var string
72 */
73 protected $_defaultProfilerClass = 'Zend_Db_Profiler';
74 /**
75 * Database connection
76 *
77 * @var object|resource|null
78 */
79 protected $_connection = null;
80 /**
81 * Specifies the case of column names retrieved in queries
82 * Options
83 * Zend_Db::CASE_NATURAL (default)
84 * Zend_Db::CASE_LOWER
85 * Zend_Db::CASE_UPPER
86 *
87 * @var integer
88 */
89 protected $_caseFolding = \Zend_Db::CASE_NATURAL;
90 /**
91 * Specifies whether the adapter automatically quotes identifiers.
92 * If true, most SQL generated by Zend_Db classes applies
93 * identifier quoting automatically.
94 * If false, developer must quote identifiers themselves
95 * by calling quoteIdentifier().
96 *
97 * @var bool
98 */
99 protected $_autoQuoteIdentifiers = \true;
100 /**
101 * Keys are UPPERCASE SQL datatypes or the constants
102 * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
103 *
104 * Values are:
105 * 0 = 32-bit integer
106 * 1 = 64-bit integer
107 * 2 = float or decimal
108 *
109 * @var array Associative array of datatypes to values 0, 1, or 2.
110 */
111 protected $_numericDataTypes = array(\Zend_Db::INT_TYPE => \Zend_Db::INT_TYPE, \Zend_Db::BIGINT_TYPE => \Zend_Db::BIGINT_TYPE, \Zend_Db::FLOAT_TYPE => \Zend_Db::FLOAT_TYPE);
112 /** Weither or not that object can get serialized
113 *
114 * @var bool
115 */
116 protected $_allowSerialization = \true;
117 /**
118 * Weither or not the database should be reconnected
119 * to that adapter when waking up
120 *
121 * @var bool
122 */
123 protected $_autoReconnectOnUnserialize = \false;
124 /**
125 * Constructor.
126 *
127 * $config is an array of key/value pairs or an instance of Zend_Config
128 * containing configuration options. These options are common to most adapters:
129 *
130 * dbname => (string) The name of the database to user
131 * username => (string) Connect to the database as this username.
132 * password => (string) Password associated with the username.
133 * host => (string) What host to connect to, defaults to localhost
134 *
135 * Some options are used on a case-by-case basis by adapters:
136 *
137 * port => (string) The port of the database
138 * persistent => (boolean) Whether to use a persistent connection or not, defaults to false
139 * protocol => (string) The network protocol, defaults to TCPIP
140 * caseFolding => (int) style of case-alteration used for identifiers
141 *
142 * @param array|Zend_Config $config An array or instance of Zend_Config having configuration data
143 * @throws Zend_Db_Adapter_Exception
144 */
145 public function __construct($config)
146 {
147 /*
148 * Verify that adapter parameters are in an array.
149 */
150 if (!\is_array($config)) {
151 /*
152 * Convert Zend_Config argument to a plain array.
153 */
154 if ($config instanceof \Zend_Config) {
155 $config = $config->toArray();
156 } else {
157 /**
158 * @see Zend_Db_Adapter_Exception
159 */
160 // require_once 'Zend/Db/Adapter/Exception.php';
161 throw new \Zend_Db_Adapter_Exception('Adapter parameters must be in an array or a Zend_Config object');
162 }
163 }
164 $this->_checkRequiredOptions($config);
165 $options = array(\Zend_Db::CASE_FOLDING => $this->_caseFolding, \Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers, \Zend_Db::FETCH_MODE => $this->_fetchMode);
166 $driverOptions = array();
167 /*
168 * normalize the config and merge it with the defaults
169 */
170 if (\array_key_exists('options', $config)) {
171 // can't use array_merge() because keys might be integers
172 foreach ((array) $config['options'] as $key => $value) {
173 $options[$key] = $value;
174 }
175 }
176 if (\array_key_exists('driver_options', $config)) {
177 if (!empty($config['driver_options'])) {
178 // can't use array_merge() because keys might be integers
179 foreach ((array) $config['driver_options'] as $key => $value) {
180 $driverOptions[$key] = $value;
181 }
182 }
183 }
184 if (!isset($config['charset'])) {
185 $config['charset'] = null;
186 }
187 if (!isset($config['persistent'])) {
188 $config['persistent'] = \false;
189 }
190 $this->_config = \array_merge($this->_config, $config);
191 $this->_config['options'] = $options;
192 $this->_config['driver_options'] = $driverOptions;
193 // obtain the case setting, if there is one
194 if (\array_key_exists(\Zend_Db::CASE_FOLDING, $options)) {
195 $case = (int) $options[\Zend_Db::CASE_FOLDING];
196 switch ($case) {
197 case \Zend_Db::CASE_LOWER:
198 case \Zend_Db::CASE_UPPER:
199 case \Zend_Db::CASE_NATURAL:
200 $this->_caseFolding = $case;
201 break;
202 default:
203 /** @see Zend_Db_Adapter_Exception */
204 // require_once 'Zend/Db/Adapter/Exception.php';
205 throw new \Zend_Db_Adapter_Exception('Case must be one of the following constants: ' . 'Zend_Db::CASE_NATURAL, Zend_Db::CASE_LOWER, Zend_Db::CASE_UPPER');
206 }
207 }
208 if (\array_key_exists(\Zend_Db::FETCH_MODE, $options)) {
209 if (\is_string($options[\Zend_Db::FETCH_MODE])) {
210 $constant = 'Zend_Db::FETCH_' . \strtoupper($options[\Zend_Db::FETCH_MODE]);
211 if (\defined($constant)) {
212 $options[\Zend_Db::FETCH_MODE] = \constant($constant);
213 }
214 }
215 $this->setFetchMode((int) $options[\Zend_Db::FETCH_MODE]);
216 }
217 // obtain quoting property if there is one
218 if (\array_key_exists(\Zend_Db::AUTO_QUOTE_IDENTIFIERS, $options)) {
219 $this->_autoQuoteIdentifiers = (bool) $options[\Zend_Db::AUTO_QUOTE_IDENTIFIERS];
220 }
221 // obtain allow serialization property if there is one
222 if (\array_key_exists(\Zend_Db::ALLOW_SERIALIZATION, $options)) {
223 $this->_allowSerialization = (bool) $options[\Zend_Db::ALLOW_SERIALIZATION];
224 }
225 // obtain auto reconnect on unserialize property if there is one
226 if (\array_key_exists(\Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE, $options)) {
227 $this->_autoReconnectOnUnserialize = (bool) $options[\Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE];
228 }
229 // create a profiler object
230 $profiler = \false;
231 if (\array_key_exists(\Zend_Db::PROFILER, $this->_config)) {
232 $profiler = $this->_config[\Zend_Db::PROFILER];
233 unset($this->_config[\Zend_Db::PROFILER]);
234 }
235 $this->setProfiler($profiler);
236 }
237 /**
238 * Check for config options that are mandatory.
239 * Throw exceptions if any are missing.
240 *
241 * @param array $config
242 * @throws Zend_Db_Adapter_Exception
243 */
244 protected function _checkRequiredOptions(array $config)
245 {
246 // we need at least a dbname
247 if (!\array_key_exists('dbname', $config)) {
248 /** @see Zend_Db_Adapter_Exception */
249 // require_once 'Zend/Db/Adapter/Exception.php';
250 throw new \Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance");
251 }
252 if (!\array_key_exists('password', $config)) {
253 /**
254 * @see Zend_Db_Adapter_Exception
255 */
256 // require_once 'Zend/Db/Adapter/Exception.php';
257 throw new \Zend_Db_Adapter_Exception("Configuration array must have a key for 'password' for login credentials");
258 }
259 if (!\array_key_exists('username', $config)) {
260 /**
261 * @see Zend_Db_Adapter_Exception
262 */
263 // require_once 'Zend/Db/Adapter/Exception.php';
264 throw new \Zend_Db_Adapter_Exception("Configuration array must have a key for 'username' for login credentials");
265 }
266 }
267 /**
268 * Returns the underlying database connection object or resource.
269 * If not presently connected, this initiates the connection.
270 *
271 * @return object|resource|null
272 */
273 public function getConnection()
274 {
275 $this->_connect();
276 return $this->_connection;
277 }
278 /**
279 * Returns the configuration variables in this adapter.
280 *
281 * @return array
282 */
283 public function getConfig()
284 {
285 return $this->_config;
286 }
287 /**
288 * Set the adapter's profiler object.
289 *
290 * The argument may be a boolean, an associative array, an instance of
291 * Zend_Db_Profiler, or an instance of Zend_Config.
292 *
293 * A boolean argument sets the profiler to enabled if true, or disabled if
294 * false. The profiler class is the adapter's default profiler class,
295 * Zend_Db_Profiler.
296 *
297 * An instance of Zend_Db_Profiler sets the adapter's instance to that
298 * object. The profiler is enabled and disabled separately.
299 *
300 * An associative array argument may contain any of the keys 'enabled',
301 * 'class', and 'instance'. The 'enabled' and 'instance' keys correspond to the
302 * boolean and object types documented above. The 'class' key is used to name a
303 * class to use for a custom profiler. The class must be Zend_Db_Profiler or a
304 * subclass. The class is instantiated with no constructor arguments. The 'class'
305 * option is ignored when the 'instance' option is supplied.
306 *
307 * An object of type Zend_Config may contain the properties 'enabled', 'class', and
308 * 'instance', just as if an associative array had been passed instead.
309 *
310 * @param Zend_Db_Profiler|Zend_Config|array|boolean $profiler
311 * @return Zend_Db_Adapter_Abstract Provides a fluent interface
312 * @throws Zend_Db_Profiler_Exception if the object instance or class specified
313 * is not Zend_Db_Profiler or an extension of that class.
314 */
315 public function setProfiler($profiler)
316 {
317 $enabled = null;
318 $profilerClass = $this->_defaultProfilerClass;
319 $profilerInstance = null;
320 if ($profilerIsObject = \is_object($profiler)) {
321 if ($profiler instanceof \Zend_Db_Profiler) {
322 $profilerInstance = $profiler;
323 } else {
324 if ($profiler instanceof \Zend_Config) {
325 $profiler = $profiler->toArray();
326 } else {
327 /**
328 * @see Zend_Db_Profiler_Exception
329 */
330 // require_once 'Zend/Db/Profiler/Exception.php';
331 throw new \Zend_Db_Profiler_Exception('Profiler argument must be an instance of either Zend_Db_Profiler' . ' or Zend_Config when provided as an object');
332 }
333 }
334 }
335 if (\is_array($profiler)) {
336 if (isset($profiler['enabled'])) {
337 $enabled = (bool) $profiler['enabled'];
338 }
339 if (isset($profiler['class'])) {
340 $profilerClass = $profiler['class'];
341 }
342 if (isset($profiler['instance'])) {
343 $profilerInstance = $profiler['instance'];
344 }
345 } else {
346 if (!$profilerIsObject) {
347 $enabled = (bool) $profiler;
348 }
349 }
350 if ($profilerInstance === null) {
351 if (!\class_exists($profilerClass)) {
352 // require_once 'Zend/Loader.php';
353 \Zend_Loader::loadClass($profilerClass);
354 }
355 $profilerInstance = new $profilerClass();
356 }
357 if (!$profilerInstance instanceof \Zend_Db_Profiler) {
358 /** @see Zend_Db_Profiler_Exception */
359 // require_once 'Zend/Db/Profiler/Exception.php';
360 throw new \Zend_Db_Profiler_Exception('Class ' . \get_class($profilerInstance) . ' does not extend ' . 'Zend_Db_Profiler');
361 }
362 if (null !== $enabled) {
363 $profilerInstance->setEnabled($enabled);
364 }
365 $this->_profiler = $profilerInstance;
366 return $this;
367 }
368 /**
369 * Returns the profiler for this adapter.
370 *
371 * @return Zend_Db_Profiler
372 */
373 public function getProfiler()
374 {
375 return $this->_profiler;
376 }
377 /**
378 * Get the default statement class.
379 *
380 * @return string
381 */
382 public function getStatementClass()
383 {
384 return $this->_defaultStmtClass;
385 }
386 /**
387 * Set the default statement class.
388 *
389 * @return Zend_Db_Adapter_Abstract Fluent interface
390 */
391 public function setStatementClass($class)
392 {
393 $this->_defaultStmtClass = $class;
394 return $this;
395 }
396 /**
397 * Prepares and executes an SQL statement with bound data.
398 *
399 * @param mixed $sql The SQL statement with placeholders.
400 * May be a string or Zend_Db_Select.
401 * @param mixed $bind An array of data to bind to the placeholders.
402 * @return Zend_Db_Statement_Interface
403 */
404 public function query($sql, $bind = array())
405 {
406 // connect to the database if needed
407 $this->_connect();
408 // is the $sql a Zend_Db_Select object?
409 if ($sql instanceof \Zend_Db_Select) {
410 if (empty($bind)) {
411 $bind = $sql->getBind();
412 }
413 $sql = $sql->assemble();
414 }
415 // make sure $bind to an array;
416 // don't use (array) typecasting because
417 // because $bind may be a Zend_Db_Expr object
418 if (!\is_array($bind)) {
419 $bind = array($bind);
420 }
421 // prepare and execute the statement with profiling
422 $stmt = $this->prepare($sql);
423 $stmt->execute($bind);
424 // return the results embedded in the prepared statement object
425 $stmt->setFetchMode($this->_fetchMode);
426 return $stmt;
427 }
428 /**
429 * Leave autocommit mode and begin a transaction.
430 *
431 * @return Zend_Db_Adapter_Abstract
432 */
433 public function beginTransaction()
434 {
435 $this->_connect();
436 $q = $this->_profiler->queryStart('begin', \Zend_Db_Profiler::TRANSACTION);
437 $this->_beginTransaction();
438 $this->_profiler->queryEnd($q);
439 return $this;
440 }
441 /**
442 * Commit a transaction and return to autocommit mode.
443 *
444 * @return Zend_Db_Adapter_Abstract
445 */
446 public function commit()
447 {
448 $this->_connect();
449 $q = $this->_profiler->queryStart('commit', \Zend_Db_Profiler::TRANSACTION);
450 $this->_commit();
451 $this->_profiler->queryEnd($q);
452 return $this;
453 }
454 /**
455 * Roll back a transaction and return to autocommit mode.
456 *
457 * @return Zend_Db_Adapter_Abstract
458 */
459 public function rollBack()
460 {
461 $this->_connect();
462 $q = $this->_profiler->queryStart('rollback', \Zend_Db_Profiler::TRANSACTION);
463 $this->_rollBack();
464 $this->_profiler->queryEnd($q);
465 return $this;
466 }
467 /**
468 * Inserts a table row with specified data.
469 *
470 * @param mixed $table The table to insert data into.
471 * @param array $bind Column-value pairs.
472 * @return int The number of affected rows.
473 * @throws Zend_Db_Adapter_Exception
474 */
475 public function insert($table, array $bind)
476 {
477 // extract and quote col names from the array keys
478 $cols = array();
479 $vals = array();
480 $i = 0;
481 foreach ($bind as $col => $val) {
482 $cols[] = $this->quoteIdentifier($col, \true);
483 if ($val instanceof \Zend_Db_Expr) {
484 $vals[] = $val->__toString();
485 unset($bind[$col]);
486 } else {
487 if ($this->supportsParameters('positional')) {
488 $vals[] = '?';
489 } else {
490 if ($this->supportsParameters('named')) {
491 unset($bind[$col]);
492 $bind[':col' . $i] = $val;
493 $vals[] = ':col' . $i;
494 $i++;
495 } else {
496 /** @see Zend_Db_Adapter_Exception */
497 // require_once 'Zend/Db/Adapter/Exception.php';
498 throw new \Zend_Db_Adapter_Exception(\get_class($this) . " doesn't support positional or named binding");
499 }
500 }
501 }
502 }
503 // build the statement
504 $sql = "INSERT INTO " . $this->quoteIdentifier($table, \true) . ' (' . \implode(', ', $cols) . ') ' . 'VALUES (' . \implode(', ', $vals) . ')';
505 // execute the statement and return the number of affected rows
506 if ($this->supportsParameters('positional')) {
507 $bind = \array_values($bind);
508 }
509 $stmt = $this->query($sql, $bind);
510 $result = $stmt->rowCount();
511 return $result;
512 }
513 /**
514 * Updates table rows with specified data based on a WHERE clause.
515 *
516 * @param mixed $table The table to update.
517 * @param array $bind Column-value pairs.
518 * @param mixed $where UPDATE WHERE clause(s).
519 * @return int The number of affected rows.
520 * @throws Zend_Db_Adapter_Exception
521 */
522 public function update($table, array $bind, $where = '')
523 {
524 /**
525 * Build "col = ?" pairs for the statement,
526 * except for Zend_Db_Expr which is treated literally.
527 */
528 $set = array();
529 $i = 0;
530 foreach ($bind as $col => $val) {
531 if ($val instanceof \Zend_Db_Expr) {
532 $val = $val->__toString();
533 unset($bind[$col]);
534 } else {
535 if ($this->supportsParameters('positional')) {
536 $val = '?';
537 } else {
538 if ($this->supportsParameters('named')) {
539 unset($bind[$col]);
540 $bind[':col' . $i] = $val;
541 $val = ':col' . $i;
542 $i++;
543 } else {
544 /** @see Zend_Db_Adapter_Exception */
545 // require_once 'Zend/Db/Adapter/Exception.php';
546 throw new \Zend_Db_Adapter_Exception(\get_class($this) . " doesn't support positional or named binding");
547 }
548 }
549 }
550 $set[] = $this->quoteIdentifier($col, \true) . ' = ' . $val;
551 }
552 $where = $this->_whereExpr($where);
553 /**
554 * Build the UPDATE statement
555 */
556 $sql = "UPDATE " . $this->quoteIdentifier($table, \true) . ' SET ' . \implode(', ', $set) . ($where ? " WHERE {$where}" : '');
557 /**
558 * Execute the statement and return the number of affected rows
559 */
560 if ($this->supportsParameters('positional')) {
561 $stmt = $this->query($sql, \array_values($bind));
562 } else {
563 $stmt = $this->query($sql, $bind);
564 }
565 $result = $stmt->rowCount();
566 return $result;
567 }
568 /**
569 * Deletes table rows based on a WHERE clause.
570 *
571 * @param mixed $table The table to update.
572 * @param mixed $where DELETE WHERE clause(s).
573 * @return int The number of affected rows.
574 */
575 public function delete($table, $where = '')
576 {
577 $where = $this->_whereExpr($where);
578 /**
579 * Build the DELETE statement
580 */
581 $sql = "DELETE FROM " . $this->quoteIdentifier($table, \true) . ($where ? " WHERE {$where}" : '');
582 /**
583 * Execute the statement and return the number of affected rows
584 */
585 $stmt = $this->query($sql);
586 $result = $stmt->rowCount();
587 return $result;
588 }
589 /**
590 * Convert an array, string, or Zend_Db_Expr object
591 * into a string to put in a WHERE clause.
592 *
593 * @param mixed $where
594 * @return string
595 */
596 protected function _whereExpr($where)
597 {
598 if (empty($where)) {
599 return $where;
600 }
601 if (!\is_array($where)) {
602 $where = array($where);
603 }
604 foreach ($where as $cond => &$term) {
605 // is $cond an int? (i.e. Not a condition)
606 if (\is_int($cond)) {
607 // $term is the full condition
608 if ($term instanceof \Zend_Db_Expr) {
609 $term = $term->__toString();
610 }
611 } else {
612 // $cond is the condition with placeholder,
613 // and $term is quoted into the condition
614 $term = $this->quoteInto($cond, $term);
615 }
616 $term = '(' . $term . ')';
617 }
618 $where = \implode(' AND ', $where);
619 return $where;
620 }
621 /**
622 * Creates and returns a new Zend_Db_Select object for this adapter.
623 *
624 * @return Zend_Db_Select
625 */
626 public function select()
627 {
628 return new \Zend_Db_Select($this);
629 }
630 /**
631 * Get the fetch mode.
632 *
633 * @return int
634 */
635 public function getFetchMode()
636 {
637 return $this->_fetchMode;
638 }
639 /**
640 * Fetches all SQL result rows as a sequential array.
641 * Uses the current fetchMode for the adapter.
642 *
643 * @param string|Zend_Db_Select $sql An SQL SELECT statement.
644 * @param mixed $bind Data to bind into SELECT placeholders.
645 * @param mixed $fetchMode Override current fetch mode.
646 * @return array
647 */
648 public function fetchAll($sql, $bind = array(), $fetchMode = null)
649 {
650 if ($fetchMode === null) {
651 $fetchMode = $this->_fetchMode;
652 }
653 $stmt = $this->query($sql, $bind);
654 $result = $stmt->fetchAll($fetchMode);
655 return $result;
656 }
657 /**
658 * Fetches the first row of the SQL result.
659 * Uses the current fetchMode for the adapter.
660 *
661 * @param string|Zend_Db_Select $sql An SQL SELECT statement.
662 * @param mixed $bind Data to bind into SELECT placeholders.
663 * @param mixed $fetchMode Override current fetch mode.
664 * @return array
665 */
666 public function fetchRow($sql, $bind = array(), $fetchMode = null)
667 {
668 if ($fetchMode === null) {
669 $fetchMode = $this->_fetchMode;
670 }
671 $stmt = $this->query($sql, $bind);
672 $result = $stmt->fetch($fetchMode);
673 return $result;
674 }
675 /**
676 * Fetches all SQL result rows as an associative array.
677 *
678 * The first column is the key, the entire row array is the
679 * value. You should construct the query to be sure that
680 * the first column contains unique values, or else
681 * rows with duplicate values in the first column will
682 * overwrite previous data.
683 *
684 * @param string|Zend_Db_Select $sql An SQL SELECT statement.
685 * @param mixed $bind Data to bind into SELECT placeholders.
686 * @return array
687 */
688 public function fetchAssoc($sql, $bind = array())
689 {
690 $stmt = $this->query($sql, $bind);
691 $data = array();
692 while ($row = $stmt->fetch(\Zend_Db::FETCH_ASSOC)) {
693 $tmp = \array_values(\array_slice($row, 0, 1));
694 $data[$tmp[0]] = $row;
695 }
696 return $data;
697 }
698 /**
699 * Fetches the first column of all SQL result rows as an array.
700 *
701 * @param string|Zend_Db_Select $sql An SQL SELECT statement.
702 * @param mixed $bind Data to bind into SELECT placeholders.
703 * @return array
704 */
705 public function fetchCol($sql, $bind = array())
706 {
707 $stmt = $this->query($sql, $bind);
708 $result = $stmt->fetchAll(\Zend_Db::FETCH_COLUMN, 0);
709 return $result;
710 }
711 /**
712 * Fetches all SQL result rows as an array of key-value pairs.
713 *
714 * The first column is the key, the second column is the
715 * value.
716 *
717 * @param string|Zend_Db_Select $sql An SQL SELECT statement.
718 * @param mixed $bind Data to bind into SELECT placeholders.
719 * @return array
720 */
721 public function fetchPairs($sql, $bind = array())
722 {
723 $stmt = $this->query($sql, $bind);
724 $data = array();
725 while ($row = $stmt->fetch(\Zend_Db::FETCH_NUM)) {
726 $data[$row[0]] = $row[1];
727 }
728 return $data;
729 }
730 /**
731 * Fetches the first column of the first row of the SQL result.
732 *
733 * @param string|Zend_Db_Select $sql An SQL SELECT statement.
734 * @param mixed $bind Data to bind into SELECT placeholders.
735 * @return string
736 */
737 public function fetchOne($sql, $bind = array())
738 {
739 $stmt = $this->query($sql, $bind);
740 $result = $stmt->fetchColumn(0);
741 return $result;
742 }
743 /**
744 * Quote a raw string.
745 *
746 * @param string $value Raw string
747 * @return string Quoted string
748 */
749 protected function _quote($value)
750 {
751 if (\is_int($value)) {
752 return $value;
753 } elseif (\is_float($value)) {
754 return \sprintf('%F', $value);
755 }
756 return "'" . \addcslashes($value, "\x00\n\r\\'\"\x1a") . "'";
757 }
758 /**
759 * Safely quotes a value for an SQL statement.
760 *
761 * If an array is passed as the value, the array values are quoted
762 * and then returned as a comma-separated string.
763 *
764 * @param mixed $value The value to quote.
765 * @param mixed $type OPTIONAL the SQL datatype name, or constant, or null.
766 * @return mixed An SQL-safe quoted value (or string of separated values).
767 */
768 public function quote($value, $type = null)
769 {
770 $this->_connect();
771 if ($value instanceof \Zend_Db_Select) {
772 return '(' . $value->assemble() . ')';
773 }
774 if ($value instanceof \Zend_Db_Expr) {
775 return $value->__toString();
776 }
777 if (\is_array($value)) {
778 foreach ($value as &$val) {
779 $val = $this->quote($val, $type);
780 }
781 return \implode(', ', $value);
782 }
783 if ($type !== null && \array_key_exists($type = \strtoupper($type), $this->_numericDataTypes)) {
784 $quotedValue = '0';
785 switch ($this->_numericDataTypes[$type]) {
786 case \Zend_Db::INT_TYPE:
787 // 32-bit integer
788 $quotedValue = (string) \intval($value);
789 break;
790 case \Zend_Db::BIGINT_TYPE:
791 // 64-bit integer
792 // ANSI SQL-style hex literals (e.g. x'[\dA-F]+')
793 // are not supported here, because these are string
794 // literals, not numeric literals.
795 if (\preg_match('/^(
796 [+-]? # optional sign
797 (?:
798 0[Xx][\\da-fA-F]+ # ODBC-style hexadecimal
799 |\\d+ # decimal or octal, or MySQL ZEROFILL decimal
800 (?:[eE][+-]?\\d+)? # optional exponent on decimals or octals
801 )
802 )/x', (string) $value, $matches)) {
803 $quotedValue = $matches[1];
804 }
805 break;
806 case \Zend_Db::FLOAT_TYPE:
807 // float or decimal
808 $quotedValue = \sprintf('%F', $value);
809 }
810 return $quotedValue;
811 }
812 return $this->_quote($value);
813 }
814 /**
815 * Quotes a value and places into a piece of text at a placeholder.
816 *
817 * The placeholder is a question-mark; all placeholders will be replaced
818 * with the quoted value. For example:
819 *
820 * <code>
821 * $text = "WHERE date < ?";
822 * $date = "2005-01-02";
823 * $safe = $sql->quoteInto($text, $date);
824 * // $safe = "WHERE date < '2005-01-02'"
825 * </code>
826 *
827 * @param string $text The text with a placeholder.
828 * @param mixed $value The value to quote.
829 * @param string $type OPTIONAL SQL datatype
830 * @param integer $count OPTIONAL count of placeholders to replace
831 * @return string An SQL-safe quoted value placed into the original text.
832 */
833 public function quoteInto($text, $value, $type = null, $count = null)
834 {
835 if ($count === null) {
836 return \str_replace('?', $this->quote($value, $type), $text);
837 } else {
838 while ($count > 0) {
839 if (\strpos($text, '?') !== \false) {
840 $text = \substr_replace($text, $this->quote($value, $type), \strpos($text, '?'), 1);
841 }
842 --$count;
843 }
844 return $text;
845 }
846 }
847 /**
848 * Quotes an identifier.
849 *
850 * Accepts a string representing a qualified indentifier. For Example:
851 * <code>
852 * $adapter->quoteIdentifier('myschema.mytable')
853 * </code>
854 * Returns: "myschema"."mytable"
855 *
856 * Or, an array of one or more identifiers that may form a qualified identifier:
857 * <code>
858 * $adapter->quoteIdentifier(array('myschema','my.table'))
859 * </code>
860 * Returns: "myschema"."my.table"
861 *
862 * The actual quote character surrounding the identifiers may vary depending on
863 * the adapter.
864 *
865 * @param string|array|Zend_Db_Expr $ident The identifier.
866 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
867 * @return string The quoted identifier.
868 */
869 public function quoteIdentifier($ident, $auto = \false)
870 {
871 return $this->_quoteIdentifierAs($ident, null, $auto);
872 }
873 /**
874 * Quote a column identifier and alias.
875 *
876 * @param string|array|Zend_Db_Expr $ident The identifier or expression.
877 * @param string $alias An alias for the column.
878 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
879 * @return string The quoted identifier and alias.
880 */
881 public function quoteColumnAs($ident, $alias, $auto = \false)
882 {
883 return $this->_quoteIdentifierAs($ident, $alias, $auto);
884 }
885 /**
886 * Quote a table identifier and alias.
887 *
888 * @param string|array|Zend_Db_Expr $ident The identifier or expression.
889 * @param string $alias An alias for the table.
890 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
891 * @return string The quoted identifier and alias.
892 */
893 public function quoteTableAs($ident, $alias = null, $auto = \false)
894 {
895 return $this->_quoteIdentifierAs($ident, $alias, $auto);
896 }
897 /**
898 * Quote an identifier and an optional alias.
899 *
900 * @param string|array|Zend_Db_Expr $ident The identifier or expression.
901 * @param string $alias An optional alias.
902 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
903 * @param string $as The string to add between the identifier/expression and the alias.
904 * @return string The quoted identifier and alias.
905 */
906 protected function _quoteIdentifierAs($ident, $alias = null, $auto = \false, $as = ' AS ')
907 {
908 if ($ident instanceof \Zend_Db_Expr) {
909 $quoted = $ident->__toString();
910 } elseif ($ident instanceof \Zend_Db_Select) {
911 $quoted = '(' . $ident->assemble() . ')';
912 } else {
913 if (\is_string($ident)) {
914 $ident = \explode('.', $ident);
915 }
916 if (\is_array($ident)) {
917 $segments = array();
918 foreach ($ident as $segment) {
919 if ($segment instanceof \Zend_Db_Expr) {
920 $segments[] = $segment->__toString();
921 } else {
922 $segments[] = $this->_quoteIdentifier($segment, $auto);
923 }
924 }
925 if ($alias !== null && \end($ident) == $alias) {
926 $alias = null;
927 }
928 $quoted = \implode('.', $segments);
929 } else {
930 $quoted = $this->_quoteIdentifier($ident, $auto);
931 }
932 }
933 if ($alias !== null) {
934 $quoted .= $as . $this->_quoteIdentifier($alias, $auto);
935 }
936 return $quoted;
937 }
938 /**
939 * Quote an identifier.
940 *
941 * @param string $value The identifier or expression.
942 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
943 * @return string The quoted identifier and alias.
944 */
945 protected function _quoteIdentifier($value, $auto = \false)
946 {
947 if ($auto === \false || $this->_autoQuoteIdentifiers === \true) {
948 $q = $this->getQuoteIdentifierSymbol();
949 return $q . \str_replace("{$q}", "{$q}{$q}", $value) . $q;
950 }
951 return $value;
952 }
953 /**
954 * Returns the symbol the adapter uses for delimited identifiers.
955 *
956 * @return string
957 */
958 public function getQuoteIdentifierSymbol()
959 {
960 return '"';
961 }
962 /**
963 * Return the most recent value from the specified sequence in the database.
964 * This is supported only on RDBMS brands that support sequences
965 * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null.
966 *
967 * @param string $sequenceName
968 * @return string
969 */
970 public function lastSequenceId($sequenceName)
971 {
972 return null;
973 }
974 /**
975 * Generate a new value from the specified sequence in the database, and return it.
976 * This is supported only on RDBMS brands that support sequences
977 * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null.
978 *
979 * @param string $sequenceName
980 * @return string
981 */
982 public function nextSequenceId($sequenceName)
983 {
984 return null;
985 }
986 /**
987 * Helper method to change the case of the strings used
988 * when returning result sets in FETCH_ASSOC and FETCH_BOTH
989 * modes.
990 *
991 * This is not intended to be used by application code,
992 * but the method must be public so the Statement class
993 * can invoke it.
994 *
995 * @param string $key
996 * @return string
997 */
998 public function foldCase($key)
999 {
1000 switch ($this->_caseFolding) {
1001 case \Zend_Db::CASE_LOWER:
1002 $value = \strtolower((string) $key);
1003 break;
1004 case \Zend_Db::CASE_UPPER:
1005 $value = \strtoupper((string) $key);
1006 break;
1007 case \Zend_Db::CASE_NATURAL:
1008 default:
1009 $value = (string) $key;
1010 }
1011 return $value;
1012 }
1013 /**
1014 * called when object is getting serialized
1015 * This disconnects the DB object that cant be serialized
1016 *
1017 * @throws Zend_Db_Adapter_Exception
1018 * @return array
1019 */
1020 public function __sleep()
1021 {
1022 if ($this->_allowSerialization == \false) {
1023 /** @see Zend_Db_Adapter_Exception */
1024 // require_once 'Zend/Db/Adapter/Exception.php';
1025 throw new \Zend_Db_Adapter_Exception(\get_class($this) . " is not allowed to be serialized");
1026 }
1027 $this->_connection = \false;
1028 return \array_keys(\array_diff_key(\get_object_vars($this), array('_connection' => \false)));
1029 }
1030 /**
1031 * called when object is getting unserialized
1032 *
1033 * @return void
1034 */
1035 public function __wakeup()
1036 {
1037 if ($this->_autoReconnectOnUnserialize == \true) {
1038 $this->getConnection();
1039 }
1040 }
1041 /**
1042 * Abstract Methods
1043 */
1044 /**
1045 * Returns a list of the tables in the database.
1046 *
1047 * @return array
1048 */
1049 public abstract function listTables();
1050 /**
1051 * Returns the column descriptions for a table.
1052 *
1053 * The return value is an associative array keyed by the column name,
1054 * as returned by the RDBMS.
1055 *
1056 * The value of each array element is an associative array
1057 * with the following keys:
1058 *
1059 * SCHEMA_NAME => string; name of database or schema
1060 * TABLE_NAME => string;
1061 * COLUMN_NAME => string; column name
1062 * COLUMN_POSITION => number; ordinal position of column in table
1063 * DATA_TYPE => string; SQL datatype name of column
1064 * DEFAULT => string; default expression of column, null if none
1065 * NULLABLE => boolean; true if column can have nulls
1066 * LENGTH => number; length of CHAR/VARCHAR
1067 * SCALE => number; scale of NUMERIC/DECIMAL
1068 * PRECISION => number; precision of NUMERIC/DECIMAL
1069 * UNSIGNED => boolean; unsigned property of an integer type
1070 * PRIMARY => boolean; true if column is part of the primary key
1071 * PRIMARY_POSITION => integer; position of column in primary key
1072 *
1073 * @param string $tableName
1074 * @param string $schemaName OPTIONAL
1075 * @return array
1076 */
1077 public abstract function describeTable($tableName, $schemaName = null);
1078 /**
1079 * Creates a connection to the database.
1080 *
1081 * @return void
1082 */
1083 protected abstract function _connect();
1084 /**
1085 * Test if a connection is active
1086 *
1087 * @return boolean
1088 */
1089 public abstract function isConnected();
1090 /**
1091 * Force the connection to close.
1092 *
1093 * @return void
1094 */
1095 public abstract function closeConnection();
1096 /**
1097 * Prepare a statement and return a PDOStatement-like object.
1098 *
1099 * @param string|Zend_Db_Select $sql SQL query
1100 * @return Zend_Db_Statement|PDOStatement
1101 */
1102 public abstract function prepare($sql);
1103 /**
1104 * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
1105 *
1106 * As a convention, on RDBMS brands that support sequences
1107 * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
1108 * from the arguments and returns the last id generated by that sequence.
1109 * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
1110 * returns the last value generated for such a column, and the table name
1111 * argument is disregarded.
1112 *
1113 * @param string $tableName OPTIONAL Name of table.
1114 * @param string $primaryKey OPTIONAL Name of primary key column.
1115 * @return string
1116 */
1117 public abstract function lastInsertId($tableName = null, $primaryKey = null);
1118 /**
1119 * Begin a transaction.
1120 */
1121 protected abstract function _beginTransaction();
1122 /**
1123 * Commit a transaction.
1124 */
1125 protected abstract function _commit();
1126 /**
1127 * Roll-back a transaction.
1128 */
1129 protected abstract function _rollBack();
1130 /**
1131 * Set the fetch mode.
1132 *
1133 * @param integer $mode
1134 * @return void
1135 * @throws Zend_Db_Adapter_Exception
1136 */
1137 public abstract function setFetchMode($mode);
1138 /**
1139 * Adds an adapter-specific LIMIT clause to the SELECT statement.
1140 *
1141 * @param mixed $sql
1142 * @param integer $count
1143 * @param integer $offset
1144 * @return string
1145 */
1146 public abstract function limit($sql, $count, $offset = 0);
1147 /**
1148 * Check if the adapter supports real SQL parameters.
1149 *
1150 * @param string $type 'positional' or 'named'
1151 * @return bool
1152 */
1153 public abstract function supportsParameters($type);
1154 /**
1155 * Retrieve server version in PHP style
1156 *
1157 * @return string
1158 */
1159 public abstract function getServerVersion();
1160 }
1161 }
1162