1: <?php
2: /**
3: * AwlDatabase query/statement class and associated functions
4: *
5: * This subpackage provides some functions that are useful around database
6: * activity and a AwlDBDialect, AwlDatabase and AwlStatement classes to simplify
7: * handling of database queries and provide some access for a limited
8: * ability to handle varying database dialects.
9: *
10: * The class is intended to be a very lightweight wrapper with some features
11: * that have proved useful in developing and debugging web-based applications:
12: * - All queries are timed, and an expected time can be provided.
13: * - Parameters replaced into the SQL will be escaped correctly in order to
14: * minimise the chances of SQL injection errors.
15: * - Queries which fail, or which exceed their expected execution time, will
16: * be logged for potential further analysis.
17: * - Debug logging of queries may be enabled globally, or restricted to
18: * particular sets of queries.
19: * - Simple syntax for iterating through a result set.
20: *
21: * See http://wiki.davical.org/w/AwlDatabase for design and usage information.
22: *
23: * If not already connected, AwlDatabase will attempt to connect to the database,
24: * successively applying connection parameters from the array in $c->pdo_connect.
25: *
26: * We will die if the database is not currently connected and we fail to find
27: * a working connection.
28: *
29: * @package awl
30: * @subpackage AwlDatabase
31: * @author Andrew McMillan <andrew@morphoss.com>
32: * @copyright Morphoss Ltd
33: * @license http://gnu.org/copyleft/gpl.html GNU GPL v3 or later
34: * @compatibility Requires PHP 5.1 or later
35: */
36:
37: require_once('AwlDBDialect.php');
38:
39: if ( !defined('E_USER_ERROR') ) define('E_USER_ERROR',256);
40:
41:
42: /**
43: * Methods in the AwlDBDialect class which we inherit, include:
44: * __construct()
45: * SetSearchPath( $search_path )
46: * GetVersion()
47: * GetFields( $tablename_string )
48: * TranslateSQL( $sql_string )
49: * Quote( $value, $value_type = null )
50: * ReplaceParameters( $query_string [, param [, ...]] )
51: */
52:
53:
54: /**
55: * Typically there will only be a single instance of the database level class in an application.
56: * @package awl
57: */
58: class AwlDatabase extends AwlDBDialect {
59: /**#@+
60: * @access private
61: */
62:
63: /**
64: * Holds the state of the transaction 0 = not started, 1 = in progress, -1 = error pending rollback/commit
65: */
66: protected $txnstate = 0;
67:
68: /**
69: * Holds whether we are translating all statements.
70: */
71: protected $translate_all = false;
72:
73: /**#@-*/
74:
75: /**
76: * Returns a PDOStatement object created using this database, the supplied SQL string, and any parameters given.
77: * @param string $sql_query_string The SQL string containing optional variable replacements
78: * @param array $driver_options PDO driver options to the prepare statement, commonly to do with cursors
79: */
80: function prepare( $statement, $driver_options = array() ) {
81: if ( isset($this->translate_all) && $this->translate_all ) {
82: $statement = $this->TranslateSQL( $statement );
83: }
84: return $this->db->prepare( $statement, $driver_options );
85: }
86:
87:
88: /**
89: * Returns a PDOStatement object created using this database, the supplied SQL string, and any parameters given.
90: * @param string $sql_query_string The SQL string containing optional variable replacements
91: * @param mixed ... Subsequent arguments are positionally replaced into the $sql_query_string
92: */
93: function query( $statement ) {
94: return $this->db->query( $statement );
95: }
96:
97:
98: /**
99: * Begin a transaction.
100: */
101: function Begin() {
102: if ( $this->txnstate == 0 ) {
103: $this->db->beginTransaction();
104: $this->txnstate = 1;
105: }
106: else {
107: fatal("Cannot begin a transaction while a transaction is already active.");
108: }
109: return true;
110: }
111:
112:
113: /**
114: * Complete a transaction.
115: */
116: function Commit() {
117: if ( $this->txnstate != 0 ) {
118: $this->db->commit();
119: $this->txnstate = 0;
120: }
121: return true;
122: }
123:
124:
125: /**
126: * Cancel a transaction in progress.
127: */
128: function Rollback() {
129: if ( $this->txnstate != 0 ) {
130: $this->db->rollBack();
131: $this->txnstate = 0;
132: }
133: else {
134: throw new Exception("Cannot rollback unless a transaction is already active.");
135: }
136: return true;
137: }
138:
139:
140: /**
141: * Returns the current state of a transaction, indicating if we have begun a transaction, whether the transaction
142: * has failed, or if we are not in a transaction.
143: * @return int 0 = not started, 1 = in progress, -1 = error pending rollback/commit
144: */
145: function TransactionState() {
146: return $this->txnstate;
147: }
148:
149:
150: /**
151: * Operates identically to AwlDatabase::Prepare, except that $this->Translate() will be called on the query
152: * before any processing.
153: */
154: function PrepareTranslated( $statement, $driver_options = array() ) {
155: $statement = $this->TranslateSQL( $statement );
156: return $this->prepare( $statement, $driver_options );
157: }
158:
159:
160: /**
161: * Switches on or off the processing flag controlling whether subsequent calls to AwlDatabase::Prepare are translated
162: * as if PrepareTranslated() had been called.
163: */
164: function TranslateAll( $onoff_boolean ) {
165: $this->translate_all = $onoff_boolean;
166: return $onoff_boolean;
167: }
168:
169:
170: /**
171: *
172: */
173: function ErrorInfo() {
174: return $this->db->errorInfo();
175: }
176:
177: }
178:
179:
180: