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