1: <?php
2:
3: /**
4: * This file contains the database driver handler class.
5: *
6: * @package Core
7: * @subpackage Database
8: * @author Dominik Ziegler
9: * @copyright four for business AG <www.4fb.de>
10: * @license http://www.contenido.org/license/LIZENZ.txt
11: * @link http://www.4fb.de
12: * @link http://www.contenido.org
13: */
14:
15: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
16:
17: /**
18: * This class contains functions for database driver handling in CONTENIDO.
19: *
20: * @package Core
21: * @subpackage Database
22: */
23: abstract class cDbDriverHandler {
24:
25: /**
26: *
27: * @var string
28: */
29: const HALT_YES = 'yes';
30:
31: /**
32: *
33: * @var string
34: */
35: const HALT_NO = 'no';
36:
37: /**
38: *
39: * @var string
40: */
41: const HALT_REPORT = 'report';
42:
43: /**
44: *
45: * @var string
46: */
47: const FETCH_NUMERIC = 'numeric';
48:
49: /**
50: *
51: * @var string
52: */
53: const FETCH_ASSOC = 'assoc';
54:
55: /**
56: *
57: * @var string
58: */
59: const FETCH_BOTH = 'both';
60:
61: /**
62: * Loader database driver.
63: *
64: * @var cDbDriverAbstract
65: */
66: protected $_driver = NULL;
67:
68: /**
69: * Driver type
70: *
71: * @var string
72: */
73: protected $_driverType = '';
74:
75: /**
76: * Default database connection for all instances
77: *
78: * @var array
79: */
80: protected static $_defaultDbCfg = array();
81:
82: /**
83: * Assoziative list of database connections
84: * @var array
85: */
86: protected static $_connectionCache = array();
87:
88: /**
89: * Assoziative list of database tables metadata
90: * @var array
91: */
92: protected static $_metaCache = array();
93:
94: /**
95: * Database connection configuration for current instance
96: *
97: * @var array
98: */
99: protected $_dbCfg = array();
100:
101: /**
102: * Halt status during occured errors.
103: * Feasible values are
104: * - "yes" (halt with message)
105: * - "no" (ignore errors quietly)
106: * - "report" (ignore errror, but spit a warning)
107: *
108: * @var string
109: */
110: protected $_haltBehaviour = 'no';
111:
112: /**
113: * Text to prepend to the halt message
114: *
115: * @var string
116: */
117: protected $_haltMsgPrefix = '';
118:
119: /**
120: * Profile data array
121: *
122: * @var array
123: */
124: protected static $_profileData = array();
125:
126: /**
127: * Constructor to create an instance of this class.
128: *
129: * Sets passed options and connects to the DBMS, if not done before.
130: *
131: * Uses default connection settings, passed $options['connection'] settings
132: * will overwrite connection settings for current instance.
133: *
134: * @param array $options [optional]
135: * Assoziative options as follows:
136: * - $options['haltBehavior'] (string) Optional, halt behavior on
137: * occured errors
138: * - $options['haltMsgPrefix'] (string) Optional, Text to prepend to
139: * the halt message
140: * - $options['enableProfiling'] (bool) Optional, flag to enable
141: * profiling
142: * - $options['connection'] (array) Optional, assoziative connection
143: * settings
144: * - $options['connection']['host'] (string) Hostname or ip
145: * - $options['connection']['database'] (string) Database name
146: * - $options['connection']['user'] (string) User name
147: * - $options['connection']['password'] (string) User password
148: * @throws cDbException
149: */
150: public function __construct($options = array()) {
151: // use default connection configuration, but overwrite it by passed
152: // options
153: $this->_dbCfg = array_merge(self::$_defaultDbCfg, $options);
154:
155: // in case we do not have any configuration for database, try to load it from configuration
156: if (count($this->_dbCfg) == 0) {
157: $cfg = cRegistry::getConfig();
158: if (isset($cfg['db']) && count($cfg['db']) > 0) {
159: $this->_dbCfg = $cfg['db'];
160: } else {
161: throw new cDbException("Unable to establish a database connection without options!");
162: }
163: }
164:
165: if (isset($this->_dbCfg['haltBehavior'])) {
166: switch ($this->_dbCfg['haltBehavior']) {
167: case self::HALT_YES:
168: $this->_haltBehaviour = self::HALT_YES;
169: break;
170: case self::HALT_NO:
171: $this->_haltBehaviour = self::HALT_NO;
172: break;
173: case self::HALT_REPORT:
174: $this->_haltBehaviour = self::HALT_REPORT;
175: break;
176: }
177: }
178:
179: if (isset($this->_dbCfg['haltMsgPrefix']) && is_string($this->_dbCfg['haltMsgPrefix'])) {
180: $this->_haltMsgPrefix = $this->_dbCfg['haltMsgPrefix'];
181: }
182:
183: $cfg = cRegistry::getConfig();
184: $this->_driverType = $cfg['database_extension'];
185:
186: $this->loadDriver();
187:
188: try {
189: if ($this->connect() == NULL) {
190: $this->setErrorNumber(1);
191: $this->setErrorMessage("Could not connect to database");
192:
193: throw new cDbException($this->getErrorMessage());
194: }
195: } catch (Exception $e) {
196: throw new cDbException($e->getMessage());
197: }
198: }
199:
200: /**
201: * Checks if profiling was enabled via configuration.
202: *
203: * @return bool
204: */
205: public function isProfilingEnabled() {
206: return (bool) $this->_dbCfg['enableProfiling'];
207: }
208:
209: /**
210: * Returns the halt behaviour setting.
211: *
212: * @return string
213: */
214: public function getHaltBehaviour() {
215: return $this->_haltBehaviour;
216: }
217:
218: /**
219: * Loads the database driver and checks its base functionality.
220: *
221: * @throws cDbException
222: */
223: public function loadDriver() {
224: if ($this->_driver != NULL) {
225: return;
226: }
227:
228: $classNameSuffix = ucfirst($this->_driverType);
229:
230: $driverName = 'cDbDriver' . $classNameSuffix;
231:
232: if (class_exists($driverName) === false) {
233: throw new cDbException("Database driver was not found.");
234: }
235:
236: $this->_driver = new $driverName($this->_dbCfg);
237:
238: if (($this->getDriver() instanceof cDbDriverAbstract) === false) {
239: $this->_driver = NULL;
240: throw new cDbException("Database driver must extend cDbDriverAbstract");
241: }
242:
243: $this->getDriver()->setHandler($this);
244:
245: if ($this->getDriver()->check() === false) {
246: throw new cDbException("Database driver check failed.");
247: }
248: }
249:
250: /**
251: * Returns the database driver instance.
252: *
253: * @return cDbDriverAbstract
254: */
255: public function getDriver() {
256: return $this->_driver;
257: }
258:
259: /**
260: * Setter for default database configuration, the connection values.
261: *
262: * @param array $defaultDbCfg
263: */
264: public static function setDefaultConfiguration(array $defaultDbCfg) {
265: self::$_defaultDbCfg = $defaultDbCfg;
266: }
267:
268: /**
269: * Returns connection from connection cache
270: *
271: * @param mixed $data
272: * Connection data array or variable
273: * @return mixed
274: * Either The connection (object, resource, integer) or NULL
275: */
276: protected function _getConnection($data) {
277: $hash = md5($this->_driverType . '-' . (is_array($data) ? implode('-', $data) : (string)$data));
278:
279: return (isset(self::$_connectionCache[$hash])) ? self::$_connectionCache[$hash] : NULL;
280: }
281:
282: /**
283: * Stores connection in connection cache
284: *
285: * @param mixed $data
286: * Connection data array
287: * @param mixed $connection
288: * The connection to store in cache
289: */
290: protected function _setConnection($data, $connection) {
291: $hash = md5($this->_driverType . '-' . (is_array($data) ? implode('-', $data) : (string)$data));
292: self::$_connectionCache[$hash] = $connection;
293: }
294:
295: /**
296: * Removes connection from cache
297: *
298: * @param mixed $connection
299: * The connection to remove in cache
300: */
301: protected function _removeConnection($connection) {
302: foreach (self::$_connectionCache as $hash => $res) {
303: if ($res == $connection) {
304: unset(self::$_connectionCache[$hash]);
305:
306: return;
307: }
308: }
309: }
310:
311: /**
312: * Adds a entry to the profile data.
313: *
314: * @param float $timeStart
315: * @param float $timeEnd
316: * @param string $statement
317: */
318: protected static function _addProfileData($timeStart, $timeEnd, $statement) {
319: self::$_profileData[] = array(
320: 'time' => $timeEnd - $timeStart, 'query' => $statement
321: );
322: }
323:
324: /**
325: * Returns collected profile data.
326: *
327: * @return array
328: * Profile data array like:
329: * - $arr[$i]['time'] (float) Elapsed time to execute the query
330: * - $arr[$i]['query'] (string) The query itself
331: */
332: public static function getProfileData() {
333: return self::$_profileData;
334: }
335:
336: /**
337: * Prepares the statement for execution and returns it back.
338: * Accepts multiple parameter, where the first parameter should be the query
339: * and any additional parameter should be the values to replace in format
340: * definitions.
341: * As an alternative the second parameter cound be also a indexed array with
342: * values to replace in format definitions.
343: *
344: * Other option is to call this function with the statement containing named
345: * parameter
346: * and the second parameter as a assoziative array with key/value pairs to
347: * set in statement.
348: *
349: * Examples:
350: * <pre>
351: * // multiple parameter
352: * $sql = $obj->prepare('SELECT * FROM `%s` WHERE id = %d', 'tablename',
353: * 123);
354: *
355: * // 2 parameter where the first is the statement with formatting signs and
356: * the second the entries array
357: * $sql = $obj->prepare('SELECT * FROM `%s` WHERE id = %d',
358: * array('tablename', 123));
359: *
360: * // 2 parameter where the first is the statement with named parameter and
361: * the second the assoziative entries array
362: * $sql = $obj->prepare('SELECT * FROM `:mytab` WHERE id = :myid',
363: * array('mytab' => 'tablename', 'myid' => 123));
364: * </pre>
365: *
366: * Accepts additional unlimited parameter, where the parameter will be
367: * replaced against formatting sign in query.
368: *
369: * @param string $statement
370: * The sql statement to prepare.
371: * @return string
372: * The prepared sql statement
373: * @throws cDbException
374: * If statement is empty or function is called with less than 2 parameters
375: */
376: public function prepare($statement) {
377: // No empty queries
378: if (empty($statement)) {
379: throw new cDbException('Empty statement!');
380: }
381:
382: $arguments = func_get_args();
383: if (count($arguments) <= 1) {
384: throw new cDbException('Wrong number of parameter!');
385: }
386:
387: array_shift($arguments);
388: $statement = $this->_prepareStatement($statement, $arguments);
389:
390: return $statement;
391: }
392:
393: /**
394: * Prepares the passed statement.
395: *
396: * @param string $statement
397: * @param array $arguments
398: *
399: * @return string
400: */
401: protected function _prepareStatement($statement, array $arguments) {
402: if (count($arguments) == 1 && is_array($arguments[0])) {
403: $arguments = $arguments[0];
404: if (count(array_filter(array_keys($arguments), 'is_string')) > 0) {
405: // we have at least one key being string, it is an assoc array
406: $statement = $this->_prepareStatementA($statement, $arguments);
407: } else {
408: // it is an indexed array
409: $statement = $this->_prepareStatementF($statement, $arguments);
410: }
411: } else {
412: $statement = $this->_prepareStatementF($statement, $arguments);
413: }
414:
415: return $statement;
416: }
417:
418: /**
419: * Prepares a statement with parameter for execution.
420: *
421: * Examples:
422: * <pre>
423: * $obj->_prepareStatementF('SELECT * FROM `%s` WHERE id = %d', 'tablename',
424: * 123);
425: * $obj->_prepareStatementF('SELECT * FROM `%s` WHERE id = %d AND user =
426: * %d', 'tablename', 123, 3);
427: * </pre>
428: *
429: * @param string $statement
430: * @param array $arguments
431: * Arguments array containing the query with formatting signs and
432: * the entries.
433: *
434: * @return string
435: */
436: protected function _prepareStatementF($statement, array $arguments) {
437: if (count($arguments) > 0) {
438: $arguments = array_map(array(
439: $this, 'escape'
440: ), $arguments);
441: array_unshift($arguments, $statement);
442: $statement = call_user_func_array('sprintf', $arguments);
443: }
444:
445: return $statement;
446: }
447:
448: /**
449: * Prepares a statement with named parameter for execution.
450: *
451: * Examples:
452: * <pre>
453: * // named parameter and assoziative entries array
454: * $sql = $obj->_prepareStatementA('SELECT * FROM `:mytab` WHERE id =
455: * :myid', array('mytab' => 'tablename', 'myid' => 123));
456: * $sql = $obj->_prepareStatementA('SELECT * FROM `:mytab` WHERE id = :myid
457: * AND user = :myuser', array('mytab' => 'tablename', 'myid' => 123,
458: * 'myuser' => 3));
459: * </pre>
460: *
461: * @param string $statement
462: * @param array $arguments
463: * Arguments array containing the query with named parameter and
464: * assoziative entries array
465: *
466: * @return string
467: */
468: protected function _prepareStatementA($statement, array $arguments) {
469: if (count($arguments) > 0) {
470: foreach ($arguments as $key => $value) {
471: $param = ':' . $key;
472: if (cSecurity::isInteger($value)) {
473: $statement = preg_replace('/' . $param . '/', cSecurity::toInteger($value), $statement);
474: $statement = preg_replace('/\'' . $param . '\'/', '\'' . cSecurity::toInteger($value) . '\'', $statement);
475: } else {
476: $param = cSecurity::toString($param);
477: $statement = preg_replace('/' . $param . '/', cSecurity::escapeString($value), $statement);
478: $statement = preg_replace('/\'' . $param . '\'/', '\'' . cSecurity::escapeString($value) . '\'', $statement);
479: $statement = preg_replace('/`' . $param . '`/', '`' . cSecurity::escapeString($value) . '`', $statement);
480: }
481: }
482: }
483:
484: return $statement;
485: }
486:
487: /**
488: * Establishes a connection to the database server.
489: *
490: * @return object|resource|int|NULL
491: * value depends on used driver and is NULL in case of an error.
492: */
493: public function connect() {
494: if (isset($this->_dbCfg['connection']) && $this->_linkId = $this->_getConnection($this->_dbCfg['connection'])) {
495: return $this->_linkId;
496: } else {
497: if ($this->_linkId = $this->getDriver()->connect()) {
498: $this->_setConnection($this->_dbCfg['connection'], $this->_linkId);
499:
500: return $this->_linkId;
501: }
502: }
503:
504: return NULL;
505: }
506:
507: /**
508: * Builds and executes a insert query.
509: * String values in passed aFields
510: * parameter will be escaped automatically.
511: *
512: * Example:
513: * <pre>
514: * $db = cRegistry::getDb();
515: * $fields = array(
516: * 'idcatart' => $idcatart,
517: * 'idlang' => $lang,
518: * 'idclient' => $client,
519: * 'code' => "<html>... code n' fun ...</html>",
520: * );
521: * $result = $db->insert($cfg['tab']['code'], $fields);
522: * </pre>
523: *
524: * @param string $tableName
525: * The table name
526: * @param array $fields
527: * Assoziative array of fields to insert
528: *
529: * @return bool
530: * @throws cDbException
531: */
532: public function insert($tableName, array $fields) {
533: $statement = $this->buildInsert($tableName, $fields);
534:
535: return $this->query($statement);
536: }
537:
538: /**
539: * Builds and returns a insert query.
540: * String values in passed fields
541: * parameter will be escaped automatically.
542: *
543: * Example:
544: * <pre>
545: * $db = cRegistry::getDb();
546: * $fields = array(
547: * 'idcode' => $idcode,
548: * 'idcatart' => $idcatart,
549: * 'idlang' => $lang,
550: * 'idclient' => $client,
551: * 'code' => "<html>... code n' fun ...</html>",
552: * );
553: * $statement = $db->buildInsert($cfg['tab']['code'], $fields);
554: * $db->query($statement);
555: * </pre>
556: *
557: * @param string $tableName
558: * The table name
559: * @param array $fields
560: * Assoziative array of fields to insert
561: *
562: * @return string
563: */
564: public function buildInsert($tableName, array $fields) {
565: return $this->getDriver()->buildInsert($tableName, $fields);
566: }
567:
568: /**
569: * Builds and executes a update query.
570: * String values in passed fields
571: * and whereClauses parameter will be escaped automatically.
572: *
573: * Example:
574: * <pre>
575: * $db = cRegistry::getDb();
576: * $fields = array('code' => "<html>... some new code n' fun ...</html>");
577: * $whereClauses = array('idcode' => 123);
578: * $result = $db->update($cfg['tab']['code'], $fields, $whereClauses);
579: * </pre>
580: *
581: * @param string $tableName
582: * The table name
583: * @param array $fields
584: * Assoziative array of fields to update
585: * @param array $whereClauses
586: * Assoziative array of field in where clause.
587: * Multiple entries will be concatenated with AND
588: * @return bool
589: * @throws cDbException
590: */
591: public function update($tableName, array $fields, array $whereClauses) {
592: $statement = $this->buildUpdate($tableName, $fields, $whereClauses);
593:
594: return $this->query($statement);
595: }
596:
597: /**
598: * Builds and returns a update query.
599: * String values in passed aFields
600: * and aWhere parameter will be escaped automatically.
601: *
602: * Example:
603: * <pre>
604: * $db = cRegistry::getDb();
605: * $fields = array('code' => "<html>... some new code n' fun ...</html>");
606: * $whereClauses = array('idcode' => 123);
607: * $statement = $db->buildUpdate($cfg['tab']['code'], $fields,
608: * $whereClauses);
609: * $db->query($statement);
610: * </pre>
611: *
612: * @param string $tableName
613: * The table name
614: * @param array $fields
615: * Assoziative array of fields to update
616: * @param array $whereClauses
617: * Assoziative array of field in where clause.
618: * Multiple entries will be concatenated with AND
619: * @return string
620: */
621: public function buildUpdate($tableName, array $fields, array $whereClauses) {
622: return $this->getDriver()->buildUpdate($tableName, $fields, $whereClauses);
623: }
624:
625: /**
626: * Executes the statement.
627: * If called with one parameter, it executes the statement directly.
628: *
629: * Accepts multiple parameter, where the first parameter should be the query
630: * and any additional parameter should be the values to replace in format
631: * definitions.
632: * As an alternative the second parameter cound be also a indexed array with
633: * values to replace in format definitions.
634: *
635: * Other option is to call this function with the statement containing named
636: * parameter
637: * and the second parameter as a assoziative array with key/value pairs to
638: * set in statement.
639: *
640: * Examples:
641: * <pre>
642: * // call with one parameter
643: * $obj->query('SELECT * FROM `tablename` WHERE id = 123');
644: *
645: * // call with multiple parameter
646: * $obj->query('SELECT * FROM `%s` WHERE id = %d', 'tablename', 123);
647: *
648: * // 2 parameter where the first is the statement with formatting signs and
649: * the second the entries array
650: * $obj->query('SELECT * FROM `%s` WHERE id = %d', array('tablename', 123));
651: *
652: * // 2 parameter where the first is the statement with named parameter and
653: * the second the assoziative entries array
654: * $obj->query('SELECT * FROM `:mytab` WHERE id = :myid', array('mytab' =>
655: * 'tablename', 'myid' => 123));
656: * </pre>
657: *
658: * Accepts additional unlimited parameter, where the parameter will be
659: * replaced against formatting sign in query.
660: *
661: * @param string $statement
662: * The SQL statement to execute.
663: *
664: * @return resource|int|object|bool
665: * database driver, false on error
666: * @throws cDbException
667: */
668: public function query($statement) {
669: // No empty queries, please, since PHP4 chokes on them
670: if ($statement == '') {
671: // The empty query string is passed on from the constructor, when
672: // calling
673: // the class without a query, e.g. in situations '$db = new
674: // DB_Sql_Subclass;'
675: return false;
676: }
677:
678: $arguments = func_get_args();
679: if (count($arguments) > 1) {
680: array_shift($arguments);
681: $statement = $this->_prepareStatement($statement, $arguments);
682: }
683:
684: if (!$this->connect()) {
685: return false;
686: }
687:
688: // new query, discard previous result
689: if ($this->getQueryId()) {
690: $this->free();
691: }
692:
693: if ($this->isProfilingEnabled() === true) {
694: $timeStart = microtime(true);
695: }
696:
697: $this->getDriver()->query($statement);
698:
699: if ($this->isProfilingEnabled() === true) {
700: $timeEnd = microtime(true);
701: $this->_addProfileData($timeStart, $timeEnd, $statement);
702: }
703:
704: if (!$this->getQueryId()) {
705: $this->halt($statement);
706: }
707:
708: // Will return nada if it fails. That's fine.
709: return $this->getQueryId();
710: }
711:
712: /**
713: * Fetches the next record set from result set
714: *
715: * @return bool
716: * @throws cDbException
717: */
718: public function nextRecord() {
719: if (!$this->getQueryId()) {
720: $currentModule = cRegistry::getCurrentModuleId();
721: if ($currentModule > 0) {
722: $this->halt('next_record called with no query pending in Module ID ' . $currentModule . '.');
723: } else {
724: $this->halt('next_record called with no query pending.');
725: }
726:
727: return false;
728: }
729:
730: return $this->getDriver()->nextRecord();
731: }
732:
733: /**
734: * This method returns the current result set as object or NULL if no result
735: * set is left.
736: * If optional param $className is set, the result object is an instance of
737: * class $className.
738: *
739: * @param string $className [optional]
740: * @return object
741: */
742: public function getResultObject($className = NULL) {
743: return $this->getDriver()->getResultObject($className);
744: }
745:
746: /**
747: * Returns number of affected rows from last executed query (update, delete)
748: *
749: * @return int
750: * Number of affected rows
751: */
752: public function affectedRows() {
753: return $this->getDriver()->affectedRows();
754: }
755:
756: /**
757: * Returns the number of rows from last executed select query.
758: *
759: * @return int
760: * The number of rows from last select query result
761: */
762: public function numRows() {
763: return $this->getDriver()->numRows();
764: }
765:
766: /**
767: * Returns the number of fields (columns) from current record set
768: *
769: * @return int
770: * Number of fields
771: */
772: public function numFields() {
773: return $this->getDriver()->numFields();
774: }
775:
776: /**
777: * Discard the query result
778: *
779: * @return int
780: */
781: public function free() {
782: return $this->getDriver()->free();
783: }
784:
785: /**
786: * Escape string for using in SQL-Statement.
787: *
788: * @param string $string
789: * The string to escape
790: * @return string
791: * Escaped string
792: */
793: public function escape($string) {
794: if (!$this->getLinkId()) {
795: $this->connect();
796: }
797:
798: return $this->getDriver()->escape($string);
799: }
800:
801: /**
802: * Moves the cursor (position inside current result sets).
803: *
804: * @param int $pos
805: * The positon to move to inside the current result set
806: * @return int
807: * @throws cDbException
808: */
809: public function seek($pos) {
810: $status = $this->getDriver()->seek($pos);
811: if ($status == 0) {
812: $this->halt("seek($pos) failed: result has " . $this->numRows() . " rows.");
813: }
814:
815: return $status;
816: }
817:
818: /**
819: * Get last inserted id of given table name
820: *
821: * @return int
822: * NULL id of table
823: * @throws cDbException
824: */
825: public function getLastInsertedId() {
826: $lastId = NULL;
827:
828: $this->query('SELECT LAST_INSERT_ID() as last_id');
829: if ($this->nextRecord()) {
830: $lastId = $this->f('last_id');
831: }
832:
833: return $lastId;
834: }
835:
836: /**
837: * Parses te table structure and generates a metadata from it.
838: *
839: * @param string $tableName [optional]
840: * The table to get metadata or empty string to retrieve metadata
841: * of all tables
842: * @param bool $full [optional]
843: * Flag to load full metadata
844: * @return array
845: * Depends on used database and on parameter $full
846: */
847: public function getMetaData($tableName = '', $full = false) {
848: $databaseName = '';
849: $key = (string)$databaseName . '_' . $tableName . '_' . (($full) ? '1' : '0');
850:
851: if (!isset(self::$_metaCache[$key])) {
852: // get meta data
853: self::$_metaCache[$key] = $this->getDriver()->getMetaData($tableName, $full);
854: }
855:
856: return self::$_metaCache[$key];
857: }
858:
859: /**
860: * Returns names of existing tables.
861: *
862: * @return array|NULL
863: * array containing assoziative table data as follows or NULL:
864: * - $info[$i]['table_name']
865: * - $info[$i]['tablespace_name']
866: * - $info[$i]['database']
867: */
868: public function getTableNames() {
869: if (!$this->connect()) {
870: return NULL;
871: }
872:
873: return $this->getDriver()->getTableNames();
874: }
875:
876: /**
877: * Returns information about DB server.
878: * The return value depends always on
879: * used DBMS.
880: *
881: * @return array|NULL
882: * array as follows or NULL:
883: * - $arr['description'] (string) Optional, server description
884: * - $arr['version'] (string) Optional, server version
885: */
886: public function getServerInfo() {
887: if (!$this->connect()) {
888: return NULL;
889: }
890:
891: return $this->getDriver()->getServerInfo();
892: }
893:
894: /**
895: * Closes the connection and frees the query id.
896: */
897: public function disconnect() {
898: $linkId = $this->getLinkId();
899:
900: if (is_resource($linkId)) {
901: $this->getDriver()->disconnect();
902: $this->_removeConnection($linkId);
903: }
904:
905: $this->setLinkId(0);
906: $this->setQueryId(0);
907: }
908:
909: /**
910: * Returns the desired field value from current record set.
911: *
912: * @param mixed $name
913: * The field name or index position
914: * @param mixed $default [optional]
915: * The default value to return
916: * @return mixed
917: * The value of field
918: */
919: public function f($name, $default = NULL) {
920: $record = $this->getRecord();
921:
922: return (isset($record[$name])) ? $record[$name] : $default;
923: }
924:
925: /**
926: * Returns current record set as a associative and/or indexed array.
927: *
928: * @param string $fetchMode [optional]
929: * One of cDbDriverHandler::FETCH_* constants
930: * @return array
931: */
932: public function toArray($fetchMode = self::FETCH_ASSOC) {
933: switch ($fetchMode) {
934: case self::FETCH_NUMERIC:
935: case self::FETCH_ASSOC:
936: case self::FETCH_BOTH:
937: // donut
938: break;
939: default:
940: $fetchMode = self::FETCH_ASSOC;
941: break;
942: }
943:
944: $result = array();
945: if (is_array($this->getRecord())) {
946: foreach ($this->getRecord() as $key => $value) {
947: if ($fetchMode == self::FETCH_ASSOC && !is_numeric($key)) {
948: $result[$key] = $value;
949: } elseif ($fetchMode == self::FETCH_NUMERIC && is_numeric($key)) {
950: $result[$key] = $value;
951: } elseif ($fetchMode == self::FETCH_BOTH) {
952: $result[$key] = $value;
953: }
954: }
955: }
956:
957: return $result;
958: }
959:
960: /**
961: * Returns current record set as a object
962: *
963: * @return stdClass
964: */
965: public function toObject() {
966: return (object) $this->toArray(self::FETCH_ASSOC);
967: }
968:
969: /**
970: * Error handling
971: *
972: * Error handler function, delegates passed message to the function
973: * reportHalt() if property
974: * $this->_haltBehaviour is not set to self::HALT_REPORT.
975: *
976: * Terminates further script execution if $this->_haltBehaviour is set to
977: * self::HALT_YES
978: *
979: * @param string $message
980: * The message to use for error handling
981: * @throws cDbException
982: */
983: public function halt($message) {
984: if ($this->_haltBehaviour == self::HALT_REPORT) {
985: $this->reportHalt($this->_haltMsgPrefix . $message);
986: }
987:
988: if ($this->_haltBehaviour == self::HALT_YES) {
989: throw new cDbException($message);
990: }
991: }
992:
993: /**
994: * Logs passed message, basically the last db error to the error log.
995: * Concatenates a detailed error message and invoke PHP's error_log()
996: * method.
997: *
998: * @param string $message
999: */
1000: public function reportHalt($message) {
1001: $errorNumber = $this->getErrorNumber();
1002: $errorMessage = $this->getErrorMessage();
1003:
1004: if (!$errorMessage) {
1005: $errorMessage = $this->getDriver()->getErrorMessage();
1006: }
1007:
1008: if (!$errorNumber) {
1009: $errorNumber = $this->getDriver()->getErrorNumber();
1010: }
1011:
1012: $message = sprintf("Database failure: %s (%s) - %s\n", $errorNumber, $errorMessage, $message);
1013: cWarning(__FILE__, __LINE__, $message);
1014: }
1015:
1016: /**
1017: * Returns the number of rows from last executed select query.
1018: *
1019: * @see cDbDriverHandler::numRows
1020: * @return int
1021: * The number of rows from last select query result
1022: */
1023: public function num_rows() {
1024: return $this->numRows();
1025: }
1026:
1027: /**
1028: * Returns number of affected rows from last executed query (update, delete)
1029: *
1030: * @see cDbDriverHandler::affectedRows
1031: * @return int
1032: * Number of affected rows
1033: */
1034: public function affected_rows() {
1035: return $this->affectedRows();
1036: }
1037:
1038: /**
1039: * Returns the number of fields (columns) from current record set
1040: *
1041: * @see cDbDriverHandler::numFields
1042: * @return int
1043: * Number of fields
1044: */
1045: public function num_fields() {
1046: return $this->numFields();
1047: }
1048:
1049: /**
1050: * Fetches the next record set from result set
1051: *
1052: * @see cDbDriverHandler::nextRecord
1053: * @return bool
1054: * @throws cDbException
1055: */
1056: public function next_record() {
1057: return $this->nextRecord();
1058: }
1059: }
1060: