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