danielebarchiesi@0
|
1 <?php
|
danielebarchiesi@0
|
2
|
danielebarchiesi@0
|
3 /**
|
danielebarchiesi@0
|
4 * @file
|
danielebarchiesi@0
|
5 * Core systems for the database layer.
|
danielebarchiesi@0
|
6 *
|
danielebarchiesi@0
|
7 * Classes required for basic functioning of the database system should be
|
danielebarchiesi@0
|
8 * placed in this file. All utility functions should also be placed in this
|
danielebarchiesi@0
|
9 * file only, as they cannot auto-load the way classes can.
|
danielebarchiesi@0
|
10 */
|
danielebarchiesi@0
|
11
|
danielebarchiesi@0
|
12 /**
|
danielebarchiesi@0
|
13 * @defgroup database Database abstraction layer
|
danielebarchiesi@0
|
14 * @{
|
danielebarchiesi@0
|
15 * Allow the use of different database servers using the same code base.
|
danielebarchiesi@0
|
16 *
|
danielebarchiesi@0
|
17 * Drupal provides a database abstraction layer to provide developers with
|
danielebarchiesi@0
|
18 * the ability to support multiple database servers easily. The intent of
|
danielebarchiesi@0
|
19 * this layer is to preserve the syntax and power of SQL as much as possible,
|
danielebarchiesi@0
|
20 * but also allow developers a way to leverage more complex functionality in
|
danielebarchiesi@0
|
21 * a unified way. It also provides a structured interface for dynamically
|
danielebarchiesi@0
|
22 * constructing queries when appropriate, and enforcing security checks and
|
danielebarchiesi@0
|
23 * similar good practices.
|
danielebarchiesi@0
|
24 *
|
danielebarchiesi@0
|
25 * The system is built atop PHP's PDO (PHP Data Objects) database API and
|
danielebarchiesi@0
|
26 * inherits much of its syntax and semantics.
|
danielebarchiesi@0
|
27 *
|
danielebarchiesi@0
|
28 * Most Drupal database SELECT queries are performed by a call to db_query() or
|
danielebarchiesi@0
|
29 * db_query_range(). Module authors should also consider using the PagerDefault
|
danielebarchiesi@0
|
30 * Extender for queries that return results that need to be presented on
|
danielebarchiesi@0
|
31 * multiple pages, and the Tablesort Extender for generating appropriate queries
|
danielebarchiesi@0
|
32 * for sortable tables.
|
danielebarchiesi@0
|
33 *
|
danielebarchiesi@0
|
34 * For example, one might wish to return a list of the most recent 10 nodes
|
danielebarchiesi@0
|
35 * authored by a given user. Instead of directly issuing the SQL query
|
danielebarchiesi@0
|
36 * @code
|
danielebarchiesi@0
|
37 * SELECT n.nid, n.title, n.created FROM node n WHERE n.uid = $uid LIMIT 0, 10;
|
danielebarchiesi@0
|
38 * @endcode
|
danielebarchiesi@0
|
39 * one would instead call the Drupal functions:
|
danielebarchiesi@0
|
40 * @code
|
danielebarchiesi@0
|
41 * $result = db_query_range('SELECT n.nid, n.title, n.created
|
danielebarchiesi@0
|
42 * FROM {node} n WHERE n.uid = :uid', 0, 10, array(':uid' => $uid));
|
danielebarchiesi@0
|
43 * foreach ($result as $record) {
|
danielebarchiesi@0
|
44 * // Perform operations on $record->title, etc. here.
|
danielebarchiesi@0
|
45 * }
|
danielebarchiesi@0
|
46 * @endcode
|
danielebarchiesi@0
|
47 * Curly braces are used around "node" to provide table prefixing via
|
danielebarchiesi@0
|
48 * DatabaseConnection::prefixTables(). The explicit use of a user ID is pulled
|
danielebarchiesi@0
|
49 * out into an argument passed to db_query() so that SQL injection attacks
|
danielebarchiesi@0
|
50 * from user input can be caught and nullified. The LIMIT syntax varies between
|
danielebarchiesi@0
|
51 * database servers, so that is abstracted into db_query_range() arguments.
|
danielebarchiesi@0
|
52 * Finally, note the PDO-based ability to iterate over the result set using
|
danielebarchiesi@0
|
53 * foreach ().
|
danielebarchiesi@0
|
54 *
|
danielebarchiesi@0
|
55 * All queries are passed as a prepared statement string. A
|
danielebarchiesi@0
|
56 * prepared statement is a "template" of a query that omits literal or variable
|
danielebarchiesi@0
|
57 * values in favor of placeholders. The values to place into those
|
danielebarchiesi@0
|
58 * placeholders are passed separately, and the database driver handles
|
danielebarchiesi@0
|
59 * inserting the values into the query in a secure fashion. That means you
|
danielebarchiesi@0
|
60 * should never quote or string-escape a value to be inserted into the query.
|
danielebarchiesi@0
|
61 *
|
danielebarchiesi@0
|
62 * There are two formats for placeholders: named and unnamed. Named placeholders
|
danielebarchiesi@0
|
63 * are strongly preferred in all cases as they are more flexible and
|
danielebarchiesi@0
|
64 * self-documenting. Named placeholders should start with a colon ":" and can be
|
danielebarchiesi@0
|
65 * followed by one or more letters, numbers or underscores.
|
danielebarchiesi@0
|
66 *
|
danielebarchiesi@0
|
67 * Named placeholders begin with a colon followed by a unique string. Example:
|
danielebarchiesi@0
|
68 * @code
|
danielebarchiesi@0
|
69 * SELECT nid, title FROM {node} WHERE uid=:uid;
|
danielebarchiesi@0
|
70 * @endcode
|
danielebarchiesi@0
|
71 *
|
danielebarchiesi@0
|
72 * ":uid" is a placeholder that will be replaced with a literal value when
|
danielebarchiesi@0
|
73 * the query is executed. A given placeholder label cannot be repeated in a
|
danielebarchiesi@0
|
74 * given query, even if the value should be the same. When using named
|
danielebarchiesi@0
|
75 * placeholders, the array of arguments to the query must be an associative
|
danielebarchiesi@0
|
76 * array where keys are a placeholder label (e.g., :uid) and the value is the
|
danielebarchiesi@0
|
77 * corresponding value to use. The array may be in any order.
|
danielebarchiesi@0
|
78 *
|
danielebarchiesi@0
|
79 * Unnamed placeholders are simply a question mark. Example:
|
danielebarchiesi@0
|
80 * @code
|
danielebarchiesi@0
|
81 * SELECT nid, title FROM {node} WHERE uid=?;
|
danielebarchiesi@0
|
82 * @endcode
|
danielebarchiesi@0
|
83 *
|
danielebarchiesi@0
|
84 * In this case, the array of arguments must be an indexed array of values to
|
danielebarchiesi@0
|
85 * use in the exact same order as the placeholders in the query.
|
danielebarchiesi@0
|
86 *
|
danielebarchiesi@0
|
87 * Note that placeholders should be a "complete" value. For example, when
|
danielebarchiesi@0
|
88 * running a LIKE query the SQL wildcard character, %, should be part of the
|
danielebarchiesi@0
|
89 * value, not the query itself. Thus, the following is incorrect:
|
danielebarchiesi@0
|
90 * @code
|
danielebarchiesi@0
|
91 * SELECT nid, title FROM {node} WHERE title LIKE :title%;
|
danielebarchiesi@0
|
92 * @endcode
|
danielebarchiesi@0
|
93 * It should instead read:
|
danielebarchiesi@0
|
94 * @code
|
danielebarchiesi@0
|
95 * SELECT nid, title FROM {node} WHERE title LIKE :title;
|
danielebarchiesi@0
|
96 * @endcode
|
danielebarchiesi@0
|
97 * and the value for :title should include a % as appropriate. Again, note the
|
danielebarchiesi@0
|
98 * lack of quotation marks around :title. Because the value is not inserted
|
danielebarchiesi@0
|
99 * into the query as one big string but as an explicitly separate value, the
|
danielebarchiesi@0
|
100 * database server knows where the query ends and a value begins. That is
|
danielebarchiesi@0
|
101 * considerably more secure against SQL injection than trying to remember
|
danielebarchiesi@0
|
102 * which values need quotation marks and string escaping and which don't.
|
danielebarchiesi@0
|
103 *
|
danielebarchiesi@0
|
104 * INSERT, UPDATE, and DELETE queries need special care in order to behave
|
danielebarchiesi@0
|
105 * consistently across all different databases. Therefore, they use a special
|
danielebarchiesi@0
|
106 * object-oriented API for defining a query structurally. For example, rather
|
danielebarchiesi@0
|
107 * than:
|
danielebarchiesi@0
|
108 * @code
|
danielebarchiesi@0
|
109 * INSERT INTO node (nid, title, body) VALUES (1, 'my title', 'my body');
|
danielebarchiesi@0
|
110 * @endcode
|
danielebarchiesi@0
|
111 * one would instead write:
|
danielebarchiesi@0
|
112 * @code
|
danielebarchiesi@0
|
113 * $fields = array('nid' => 1, 'title' => 'my title', 'body' => 'my body');
|
danielebarchiesi@0
|
114 * db_insert('node')->fields($fields)->execute();
|
danielebarchiesi@0
|
115 * @endcode
|
danielebarchiesi@0
|
116 * This method allows databases that need special data type handling to do so,
|
danielebarchiesi@0
|
117 * while also allowing optimizations such as multi-insert queries. UPDATE and
|
danielebarchiesi@0
|
118 * DELETE queries have a similar pattern.
|
danielebarchiesi@0
|
119 *
|
danielebarchiesi@0
|
120 * Drupal also supports transactions, including a transparent fallback for
|
danielebarchiesi@0
|
121 * databases that do not support transactions. To start a new transaction,
|
danielebarchiesi@0
|
122 * simply call $txn = db_transaction(); in your own code. The transaction will
|
danielebarchiesi@0
|
123 * remain open for as long as the variable $txn remains in scope. When $txn is
|
danielebarchiesi@0
|
124 * destroyed, the transaction will be committed. If your transaction is nested
|
danielebarchiesi@0
|
125 * inside of another then Drupal will track each transaction and only commit
|
danielebarchiesi@0
|
126 * the outer-most transaction when the last transaction object goes out out of
|
danielebarchiesi@0
|
127 * scope, that is, all relevant queries completed successfully.
|
danielebarchiesi@0
|
128 *
|
danielebarchiesi@0
|
129 * Example:
|
danielebarchiesi@0
|
130 * @code
|
danielebarchiesi@0
|
131 * function my_transaction_function() {
|
danielebarchiesi@0
|
132 * // The transaction opens here.
|
danielebarchiesi@0
|
133 * $txn = db_transaction();
|
danielebarchiesi@0
|
134 *
|
danielebarchiesi@0
|
135 * try {
|
danielebarchiesi@0
|
136 * $id = db_insert('example')
|
danielebarchiesi@0
|
137 * ->fields(array(
|
danielebarchiesi@0
|
138 * 'field1' => 'mystring',
|
danielebarchiesi@0
|
139 * 'field2' => 5,
|
danielebarchiesi@0
|
140 * ))
|
danielebarchiesi@0
|
141 * ->execute();
|
danielebarchiesi@0
|
142 *
|
danielebarchiesi@0
|
143 * my_other_function($id);
|
danielebarchiesi@0
|
144 *
|
danielebarchiesi@0
|
145 * return $id;
|
danielebarchiesi@0
|
146 * }
|
danielebarchiesi@0
|
147 * catch (Exception $e) {
|
danielebarchiesi@0
|
148 * // Something went wrong somewhere, so roll back now.
|
danielebarchiesi@0
|
149 * $txn->rollback();
|
danielebarchiesi@0
|
150 * // Log the exception to watchdog.
|
danielebarchiesi@0
|
151 * watchdog_exception('type', $e);
|
danielebarchiesi@0
|
152 * }
|
danielebarchiesi@0
|
153 *
|
danielebarchiesi@0
|
154 * // $txn goes out of scope here. Unless the transaction was rolled back, it
|
danielebarchiesi@0
|
155 * // gets automatically committed here.
|
danielebarchiesi@0
|
156 * }
|
danielebarchiesi@0
|
157 *
|
danielebarchiesi@0
|
158 * function my_other_function($id) {
|
danielebarchiesi@0
|
159 * // The transaction is still open here.
|
danielebarchiesi@0
|
160 *
|
danielebarchiesi@0
|
161 * if ($id % 2 == 0) {
|
danielebarchiesi@0
|
162 * db_update('example')
|
danielebarchiesi@0
|
163 * ->condition('id', $id)
|
danielebarchiesi@0
|
164 * ->fields(array('field2' => 10))
|
danielebarchiesi@0
|
165 * ->execute();
|
danielebarchiesi@0
|
166 * }
|
danielebarchiesi@0
|
167 * }
|
danielebarchiesi@0
|
168 * @endcode
|
danielebarchiesi@0
|
169 *
|
danielebarchiesi@0
|
170 * @see http://drupal.org/developing/api/database
|
danielebarchiesi@0
|
171 */
|
danielebarchiesi@0
|
172
|
danielebarchiesi@0
|
173
|
danielebarchiesi@0
|
174 /**
|
danielebarchiesi@0
|
175 * Base Database API class.
|
danielebarchiesi@0
|
176 *
|
danielebarchiesi@0
|
177 * This class provides a Drupal-specific extension of the PDO database
|
danielebarchiesi@0
|
178 * abstraction class in PHP. Every database driver implementation must provide a
|
danielebarchiesi@0
|
179 * concrete implementation of it to support special handling required by that
|
danielebarchiesi@0
|
180 * database.
|
danielebarchiesi@0
|
181 *
|
danielebarchiesi@0
|
182 * @see http://php.net/manual/en/book.pdo.php
|
danielebarchiesi@0
|
183 */
|
danielebarchiesi@0
|
184 abstract class DatabaseConnection extends PDO {
|
danielebarchiesi@0
|
185
|
danielebarchiesi@0
|
186 /**
|
danielebarchiesi@0
|
187 * The database target this connection is for.
|
danielebarchiesi@0
|
188 *
|
danielebarchiesi@0
|
189 * We need this information for later auditing and logging.
|
danielebarchiesi@0
|
190 *
|
danielebarchiesi@0
|
191 * @var string
|
danielebarchiesi@0
|
192 */
|
danielebarchiesi@0
|
193 protected $target = NULL;
|
danielebarchiesi@0
|
194
|
danielebarchiesi@0
|
195 /**
|
danielebarchiesi@0
|
196 * The key representing this connection.
|
danielebarchiesi@0
|
197 *
|
danielebarchiesi@0
|
198 * The key is a unique string which identifies a database connection. A
|
danielebarchiesi@0
|
199 * connection can be a single server or a cluster of master and slaves (use
|
danielebarchiesi@0
|
200 * target to pick between master and slave).
|
danielebarchiesi@0
|
201 *
|
danielebarchiesi@0
|
202 * @var string
|
danielebarchiesi@0
|
203 */
|
danielebarchiesi@0
|
204 protected $key = NULL;
|
danielebarchiesi@0
|
205
|
danielebarchiesi@0
|
206 /**
|
danielebarchiesi@0
|
207 * The current database logging object for this connection.
|
danielebarchiesi@0
|
208 *
|
danielebarchiesi@0
|
209 * @var DatabaseLog
|
danielebarchiesi@0
|
210 */
|
danielebarchiesi@0
|
211 protected $logger = NULL;
|
danielebarchiesi@0
|
212
|
danielebarchiesi@0
|
213 /**
|
danielebarchiesi@0
|
214 * Tracks the number of "layers" of transactions currently active.
|
danielebarchiesi@0
|
215 *
|
danielebarchiesi@0
|
216 * On many databases transactions cannot nest. Instead, we track
|
danielebarchiesi@0
|
217 * nested calls to transactions and collapse them into a single
|
danielebarchiesi@0
|
218 * transaction.
|
danielebarchiesi@0
|
219 *
|
danielebarchiesi@0
|
220 * @var array
|
danielebarchiesi@0
|
221 */
|
danielebarchiesi@0
|
222 protected $transactionLayers = array();
|
danielebarchiesi@0
|
223
|
danielebarchiesi@0
|
224 /**
|
danielebarchiesi@0
|
225 * Index of what driver-specific class to use for various operations.
|
danielebarchiesi@0
|
226 *
|
danielebarchiesi@0
|
227 * @var array
|
danielebarchiesi@0
|
228 */
|
danielebarchiesi@0
|
229 protected $driverClasses = array();
|
danielebarchiesi@0
|
230
|
danielebarchiesi@0
|
231 /**
|
danielebarchiesi@0
|
232 * The name of the Statement class for this connection.
|
danielebarchiesi@0
|
233 *
|
danielebarchiesi@0
|
234 * @var string
|
danielebarchiesi@0
|
235 */
|
danielebarchiesi@0
|
236 protected $statementClass = 'DatabaseStatementBase';
|
danielebarchiesi@0
|
237
|
danielebarchiesi@0
|
238 /**
|
danielebarchiesi@0
|
239 * Whether this database connection supports transactions.
|
danielebarchiesi@0
|
240 *
|
danielebarchiesi@0
|
241 * @var bool
|
danielebarchiesi@0
|
242 */
|
danielebarchiesi@0
|
243 protected $transactionSupport = TRUE;
|
danielebarchiesi@0
|
244
|
danielebarchiesi@0
|
245 /**
|
danielebarchiesi@0
|
246 * Whether this database connection supports transactional DDL.
|
danielebarchiesi@0
|
247 *
|
danielebarchiesi@0
|
248 * Set to FALSE by default because few databases support this feature.
|
danielebarchiesi@0
|
249 *
|
danielebarchiesi@0
|
250 * @var bool
|
danielebarchiesi@0
|
251 */
|
danielebarchiesi@0
|
252 protected $transactionalDDLSupport = FALSE;
|
danielebarchiesi@0
|
253
|
danielebarchiesi@0
|
254 /**
|
danielebarchiesi@0
|
255 * An index used to generate unique temporary table names.
|
danielebarchiesi@0
|
256 *
|
danielebarchiesi@0
|
257 * @var integer
|
danielebarchiesi@0
|
258 */
|
danielebarchiesi@0
|
259 protected $temporaryNameIndex = 0;
|
danielebarchiesi@0
|
260
|
danielebarchiesi@0
|
261 /**
|
danielebarchiesi@0
|
262 * The connection information for this connection object.
|
danielebarchiesi@0
|
263 *
|
danielebarchiesi@0
|
264 * @var array
|
danielebarchiesi@0
|
265 */
|
danielebarchiesi@0
|
266 protected $connectionOptions = array();
|
danielebarchiesi@0
|
267
|
danielebarchiesi@0
|
268 /**
|
danielebarchiesi@0
|
269 * The schema object for this connection.
|
danielebarchiesi@0
|
270 *
|
danielebarchiesi@0
|
271 * @var object
|
danielebarchiesi@0
|
272 */
|
danielebarchiesi@0
|
273 protected $schema = NULL;
|
danielebarchiesi@0
|
274
|
danielebarchiesi@0
|
275 /**
|
danielebarchiesi@0
|
276 * The prefixes used by this database connection.
|
danielebarchiesi@0
|
277 *
|
danielebarchiesi@0
|
278 * @var array
|
danielebarchiesi@0
|
279 */
|
danielebarchiesi@0
|
280 protected $prefixes = array();
|
danielebarchiesi@0
|
281
|
danielebarchiesi@0
|
282 /**
|
danielebarchiesi@0
|
283 * List of search values for use in prefixTables().
|
danielebarchiesi@0
|
284 *
|
danielebarchiesi@0
|
285 * @var array
|
danielebarchiesi@0
|
286 */
|
danielebarchiesi@0
|
287 protected $prefixSearch = array();
|
danielebarchiesi@0
|
288
|
danielebarchiesi@0
|
289 /**
|
danielebarchiesi@0
|
290 * List of replacement values for use in prefixTables().
|
danielebarchiesi@0
|
291 *
|
danielebarchiesi@0
|
292 * @var array
|
danielebarchiesi@0
|
293 */
|
danielebarchiesi@0
|
294 protected $prefixReplace = array();
|
danielebarchiesi@0
|
295
|
danielebarchiesi@0
|
296 function __construct($dsn, $username, $password, $driver_options = array()) {
|
danielebarchiesi@0
|
297 // Initialize and prepare the connection prefix.
|
danielebarchiesi@0
|
298 $this->setPrefix(isset($this->connectionOptions['prefix']) ? $this->connectionOptions['prefix'] : '');
|
danielebarchiesi@0
|
299
|
danielebarchiesi@0
|
300 // Because the other methods don't seem to work right.
|
danielebarchiesi@0
|
301 $driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
|
danielebarchiesi@0
|
302
|
danielebarchiesi@0
|
303 // Call PDO::__construct and PDO::setAttribute.
|
danielebarchiesi@0
|
304 parent::__construct($dsn, $username, $password, $driver_options);
|
danielebarchiesi@0
|
305
|
danielebarchiesi@0
|
306 // Set a Statement class, unless the driver opted out.
|
danielebarchiesi@0
|
307 if (!empty($this->statementClass)) {
|
danielebarchiesi@0
|
308 $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array($this->statementClass, array($this)));
|
danielebarchiesi@0
|
309 }
|
danielebarchiesi@0
|
310 }
|
danielebarchiesi@0
|
311
|
danielebarchiesi@0
|
312 /**
|
danielebarchiesi@0
|
313 * Destroys this Connection object.
|
danielebarchiesi@0
|
314 *
|
danielebarchiesi@0
|
315 * PHP does not destruct an object if it is still referenced in other
|
danielebarchiesi@0
|
316 * variables. In case of PDO database connection objects, PHP only closes the
|
danielebarchiesi@0
|
317 * connection when the PDO object is destructed, so any references to this
|
danielebarchiesi@0
|
318 * object may cause the number of maximum allowed connections to be exceeded.
|
danielebarchiesi@0
|
319 */
|
danielebarchiesi@0
|
320 public function destroy() {
|
danielebarchiesi@0
|
321 // Destroy all references to this connection by setting them to NULL.
|
danielebarchiesi@0
|
322 // The Statement class attribute only accepts a new value that presents a
|
danielebarchiesi@0
|
323 // proper callable, so we reset it to PDOStatement.
|
danielebarchiesi@0
|
324 $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array()));
|
danielebarchiesi@0
|
325 $this->schema = NULL;
|
danielebarchiesi@0
|
326 }
|
danielebarchiesi@0
|
327
|
danielebarchiesi@0
|
328 /**
|
danielebarchiesi@0
|
329 * Returns the default query options for any given query.
|
danielebarchiesi@0
|
330 *
|
danielebarchiesi@0
|
331 * A given query can be customized with a number of option flags in an
|
danielebarchiesi@0
|
332 * associative array:
|
danielebarchiesi@0
|
333 * - target: The database "target" against which to execute a query. Valid
|
danielebarchiesi@0
|
334 * values are "default" or "slave". The system will first try to open a
|
danielebarchiesi@0
|
335 * connection to a database specified with the user-supplied key. If one
|
danielebarchiesi@0
|
336 * is not available, it will silently fall back to the "default" target.
|
danielebarchiesi@0
|
337 * If multiple databases connections are specified with the same target,
|
danielebarchiesi@0
|
338 * one will be selected at random for the duration of the request.
|
danielebarchiesi@0
|
339 * - fetch: This element controls how rows from a result set will be
|
danielebarchiesi@0
|
340 * returned. Legal values include PDO::FETCH_ASSOC, PDO::FETCH_BOTH,
|
danielebarchiesi@0
|
341 * PDO::FETCH_OBJ, PDO::FETCH_NUM, or a string representing the name of a
|
danielebarchiesi@0
|
342 * class. If a string is specified, each record will be fetched into a new
|
danielebarchiesi@0
|
343 * object of that class. The behavior of all other values is defined by PDO.
|
danielebarchiesi@0
|
344 * See http://php.net/manual/pdostatement.fetch.php
|
danielebarchiesi@0
|
345 * - return: Depending on the type of query, different return values may be
|
danielebarchiesi@0
|
346 * meaningful. This directive instructs the system which type of return
|
danielebarchiesi@0
|
347 * value is desired. The system will generally set the correct value
|
danielebarchiesi@0
|
348 * automatically, so it is extremely rare that a module developer will ever
|
danielebarchiesi@0
|
349 * need to specify this value. Setting it incorrectly will likely lead to
|
danielebarchiesi@0
|
350 * unpredictable results or fatal errors. Legal values include:
|
danielebarchiesi@0
|
351 * - Database::RETURN_STATEMENT: Return the prepared statement object for
|
danielebarchiesi@0
|
352 * the query. This is usually only meaningful for SELECT queries, where
|
danielebarchiesi@0
|
353 * the statement object is how one accesses the result set returned by the
|
danielebarchiesi@0
|
354 * query.
|
danielebarchiesi@0
|
355 * - Database::RETURN_AFFECTED: Return the number of rows affected by an
|
danielebarchiesi@0
|
356 * UPDATE or DELETE query. Be aware that means the number of rows actually
|
danielebarchiesi@0
|
357 * changed, not the number of rows matched by the WHERE clause.
|
danielebarchiesi@0
|
358 * - Database::RETURN_INSERT_ID: Return the sequence ID (primary key)
|
danielebarchiesi@0
|
359 * created by an INSERT statement on a table that contains a serial
|
danielebarchiesi@0
|
360 * column.
|
danielebarchiesi@0
|
361 * - Database::RETURN_NULL: Do not return anything, as there is no
|
danielebarchiesi@0
|
362 * meaningful value to return. That is the case for INSERT queries on
|
danielebarchiesi@0
|
363 * tables that do not contain a serial column.
|
danielebarchiesi@0
|
364 * - throw_exception: By default, the database system will catch any errors
|
danielebarchiesi@0
|
365 * on a query as an Exception, log it, and then rethrow it so that code
|
danielebarchiesi@0
|
366 * further up the call chain can take an appropriate action. To suppress
|
danielebarchiesi@0
|
367 * that behavior and simply return NULL on failure, set this option to
|
danielebarchiesi@0
|
368 * FALSE.
|
danielebarchiesi@0
|
369 *
|
danielebarchiesi@0
|
370 * @return
|
danielebarchiesi@0
|
371 * An array of default query options.
|
danielebarchiesi@0
|
372 */
|
danielebarchiesi@0
|
373 protected function defaultOptions() {
|
danielebarchiesi@0
|
374 return array(
|
danielebarchiesi@0
|
375 'target' => 'default',
|
danielebarchiesi@0
|
376 'fetch' => PDO::FETCH_OBJ,
|
danielebarchiesi@0
|
377 'return' => Database::RETURN_STATEMENT,
|
danielebarchiesi@0
|
378 'throw_exception' => TRUE,
|
danielebarchiesi@0
|
379 );
|
danielebarchiesi@0
|
380 }
|
danielebarchiesi@0
|
381
|
danielebarchiesi@0
|
382 /**
|
danielebarchiesi@0
|
383 * Returns the connection information for this connection object.
|
danielebarchiesi@0
|
384 *
|
danielebarchiesi@0
|
385 * Note that Database::getConnectionInfo() is for requesting information
|
danielebarchiesi@0
|
386 * about an arbitrary database connection that is defined. This method
|
danielebarchiesi@0
|
387 * is for requesting the connection information of this specific
|
danielebarchiesi@0
|
388 * open connection object.
|
danielebarchiesi@0
|
389 *
|
danielebarchiesi@0
|
390 * @return
|
danielebarchiesi@0
|
391 * An array of the connection information. The exact list of
|
danielebarchiesi@0
|
392 * properties is driver-dependent.
|
danielebarchiesi@0
|
393 */
|
danielebarchiesi@0
|
394 public function getConnectionOptions() {
|
danielebarchiesi@0
|
395 return $this->connectionOptions;
|
danielebarchiesi@0
|
396 }
|
danielebarchiesi@0
|
397
|
danielebarchiesi@0
|
398 /**
|
danielebarchiesi@0
|
399 * Set the list of prefixes used by this database connection.
|
danielebarchiesi@0
|
400 *
|
danielebarchiesi@0
|
401 * @param $prefix
|
danielebarchiesi@0
|
402 * The prefixes, in any of the multiple forms documented in
|
danielebarchiesi@0
|
403 * default.settings.php.
|
danielebarchiesi@0
|
404 */
|
danielebarchiesi@0
|
405 protected function setPrefix($prefix) {
|
danielebarchiesi@0
|
406 if (is_array($prefix)) {
|
danielebarchiesi@0
|
407 $this->prefixes = $prefix + array('default' => '');
|
danielebarchiesi@0
|
408 }
|
danielebarchiesi@0
|
409 else {
|
danielebarchiesi@0
|
410 $this->prefixes = array('default' => $prefix);
|
danielebarchiesi@0
|
411 }
|
danielebarchiesi@0
|
412
|
danielebarchiesi@0
|
413 // Set up variables for use in prefixTables(). Replace table-specific
|
danielebarchiesi@0
|
414 // prefixes first.
|
danielebarchiesi@0
|
415 $this->prefixSearch = array();
|
danielebarchiesi@0
|
416 $this->prefixReplace = array();
|
danielebarchiesi@0
|
417 foreach ($this->prefixes as $key => $val) {
|
danielebarchiesi@0
|
418 if ($key != 'default') {
|
danielebarchiesi@0
|
419 $this->prefixSearch[] = '{' . $key . '}';
|
danielebarchiesi@0
|
420 $this->prefixReplace[] = $val . $key;
|
danielebarchiesi@0
|
421 }
|
danielebarchiesi@0
|
422 }
|
danielebarchiesi@0
|
423 // Then replace remaining tables with the default prefix.
|
danielebarchiesi@0
|
424 $this->prefixSearch[] = '{';
|
danielebarchiesi@0
|
425 $this->prefixReplace[] = $this->prefixes['default'];
|
danielebarchiesi@0
|
426 $this->prefixSearch[] = '}';
|
danielebarchiesi@0
|
427 $this->prefixReplace[] = '';
|
danielebarchiesi@0
|
428 }
|
danielebarchiesi@0
|
429
|
danielebarchiesi@0
|
430 /**
|
danielebarchiesi@0
|
431 * Appends a database prefix to all tables in a query.
|
danielebarchiesi@0
|
432 *
|
danielebarchiesi@0
|
433 * Queries sent to Drupal should wrap all table names in curly brackets. This
|
danielebarchiesi@0
|
434 * function searches for this syntax and adds Drupal's table prefix to all
|
danielebarchiesi@0
|
435 * tables, allowing Drupal to coexist with other systems in the same database
|
danielebarchiesi@0
|
436 * and/or schema if necessary.
|
danielebarchiesi@0
|
437 *
|
danielebarchiesi@0
|
438 * @param $sql
|
danielebarchiesi@0
|
439 * A string containing a partial or entire SQL query.
|
danielebarchiesi@0
|
440 *
|
danielebarchiesi@0
|
441 * @return
|
danielebarchiesi@0
|
442 * The properly-prefixed string.
|
danielebarchiesi@0
|
443 */
|
danielebarchiesi@0
|
444 public function prefixTables($sql) {
|
danielebarchiesi@0
|
445 return str_replace($this->prefixSearch, $this->prefixReplace, $sql);
|
danielebarchiesi@0
|
446 }
|
danielebarchiesi@0
|
447
|
danielebarchiesi@0
|
448 /**
|
danielebarchiesi@0
|
449 * Find the prefix for a table.
|
danielebarchiesi@0
|
450 *
|
danielebarchiesi@0
|
451 * This function is for when you want to know the prefix of a table. This
|
danielebarchiesi@0
|
452 * is not used in prefixTables due to performance reasons.
|
danielebarchiesi@0
|
453 */
|
danielebarchiesi@0
|
454 public function tablePrefix($table = 'default') {
|
danielebarchiesi@0
|
455 if (isset($this->prefixes[$table])) {
|
danielebarchiesi@0
|
456 return $this->prefixes[$table];
|
danielebarchiesi@0
|
457 }
|
danielebarchiesi@0
|
458 else {
|
danielebarchiesi@0
|
459 return $this->prefixes['default'];
|
danielebarchiesi@0
|
460 }
|
danielebarchiesi@0
|
461 }
|
danielebarchiesi@0
|
462
|
danielebarchiesi@0
|
463 /**
|
danielebarchiesi@0
|
464 * Prepares a query string and returns the prepared statement.
|
danielebarchiesi@0
|
465 *
|
danielebarchiesi@0
|
466 * This method caches prepared statements, reusing them when
|
danielebarchiesi@0
|
467 * possible. It also prefixes tables names enclosed in curly-braces.
|
danielebarchiesi@0
|
468 *
|
danielebarchiesi@0
|
469 * @param $query
|
danielebarchiesi@0
|
470 * The query string as SQL, with curly-braces surrounding the
|
danielebarchiesi@0
|
471 * table names.
|
danielebarchiesi@0
|
472 *
|
danielebarchiesi@0
|
473 * @return DatabaseStatementInterface
|
danielebarchiesi@0
|
474 * A PDO prepared statement ready for its execute() method.
|
danielebarchiesi@0
|
475 */
|
danielebarchiesi@0
|
476 public function prepareQuery($query) {
|
danielebarchiesi@0
|
477 $query = $this->prefixTables($query);
|
danielebarchiesi@0
|
478
|
danielebarchiesi@0
|
479 // Call PDO::prepare.
|
danielebarchiesi@0
|
480 return parent::prepare($query);
|
danielebarchiesi@0
|
481 }
|
danielebarchiesi@0
|
482
|
danielebarchiesi@0
|
483 /**
|
danielebarchiesi@0
|
484 * Tells this connection object what its target value is.
|
danielebarchiesi@0
|
485 *
|
danielebarchiesi@0
|
486 * This is needed for logging and auditing. It's sloppy to do in the
|
danielebarchiesi@0
|
487 * constructor because the constructor for child classes has a different
|
danielebarchiesi@0
|
488 * signature. We therefore also ensure that this function is only ever
|
danielebarchiesi@0
|
489 * called once.
|
danielebarchiesi@0
|
490 *
|
danielebarchiesi@0
|
491 * @param $target
|
danielebarchiesi@0
|
492 * The target this connection is for. Set to NULL (default) to disable
|
danielebarchiesi@0
|
493 * logging entirely.
|
danielebarchiesi@0
|
494 */
|
danielebarchiesi@0
|
495 public function setTarget($target = NULL) {
|
danielebarchiesi@0
|
496 if (!isset($this->target)) {
|
danielebarchiesi@0
|
497 $this->target = $target;
|
danielebarchiesi@0
|
498 }
|
danielebarchiesi@0
|
499 }
|
danielebarchiesi@0
|
500
|
danielebarchiesi@0
|
501 /**
|
danielebarchiesi@0
|
502 * Returns the target this connection is associated with.
|
danielebarchiesi@0
|
503 *
|
danielebarchiesi@0
|
504 * @return
|
danielebarchiesi@0
|
505 * The target string of this connection.
|
danielebarchiesi@0
|
506 */
|
danielebarchiesi@0
|
507 public function getTarget() {
|
danielebarchiesi@0
|
508 return $this->target;
|
danielebarchiesi@0
|
509 }
|
danielebarchiesi@0
|
510
|
danielebarchiesi@0
|
511 /**
|
danielebarchiesi@0
|
512 * Tells this connection object what its key is.
|
danielebarchiesi@0
|
513 *
|
danielebarchiesi@0
|
514 * @param $target
|
danielebarchiesi@0
|
515 * The key this connection is for.
|
danielebarchiesi@0
|
516 */
|
danielebarchiesi@0
|
517 public function setKey($key) {
|
danielebarchiesi@0
|
518 if (!isset($this->key)) {
|
danielebarchiesi@0
|
519 $this->key = $key;
|
danielebarchiesi@0
|
520 }
|
danielebarchiesi@0
|
521 }
|
danielebarchiesi@0
|
522
|
danielebarchiesi@0
|
523 /**
|
danielebarchiesi@0
|
524 * Returns the key this connection is associated with.
|
danielebarchiesi@0
|
525 *
|
danielebarchiesi@0
|
526 * @return
|
danielebarchiesi@0
|
527 * The key of this connection.
|
danielebarchiesi@0
|
528 */
|
danielebarchiesi@0
|
529 public function getKey() {
|
danielebarchiesi@0
|
530 return $this->key;
|
danielebarchiesi@0
|
531 }
|
danielebarchiesi@0
|
532
|
danielebarchiesi@0
|
533 /**
|
danielebarchiesi@0
|
534 * Associates a logging object with this connection.
|
danielebarchiesi@0
|
535 *
|
danielebarchiesi@0
|
536 * @param $logger
|
danielebarchiesi@0
|
537 * The logging object we want to use.
|
danielebarchiesi@0
|
538 */
|
danielebarchiesi@0
|
539 public function setLogger(DatabaseLog $logger) {
|
danielebarchiesi@0
|
540 $this->logger = $logger;
|
danielebarchiesi@0
|
541 }
|
danielebarchiesi@0
|
542
|
danielebarchiesi@0
|
543 /**
|
danielebarchiesi@0
|
544 * Gets the current logging object for this connection.
|
danielebarchiesi@0
|
545 *
|
danielebarchiesi@0
|
546 * @return DatabaseLog
|
danielebarchiesi@0
|
547 * The current logging object for this connection. If there isn't one,
|
danielebarchiesi@0
|
548 * NULL is returned.
|
danielebarchiesi@0
|
549 */
|
danielebarchiesi@0
|
550 public function getLogger() {
|
danielebarchiesi@0
|
551 return $this->logger;
|
danielebarchiesi@0
|
552 }
|
danielebarchiesi@0
|
553
|
danielebarchiesi@0
|
554 /**
|
danielebarchiesi@0
|
555 * Creates the appropriate sequence name for a given table and serial field.
|
danielebarchiesi@0
|
556 *
|
danielebarchiesi@0
|
557 * This information is exposed to all database drivers, although it is only
|
danielebarchiesi@0
|
558 * useful on some of them. This method is table prefix-aware.
|
danielebarchiesi@0
|
559 *
|
danielebarchiesi@0
|
560 * @param $table
|
danielebarchiesi@0
|
561 * The table name to use for the sequence.
|
danielebarchiesi@0
|
562 * @param $field
|
danielebarchiesi@0
|
563 * The field name to use for the sequence.
|
danielebarchiesi@0
|
564 *
|
danielebarchiesi@0
|
565 * @return
|
danielebarchiesi@0
|
566 * A table prefix-parsed string for the sequence name.
|
danielebarchiesi@0
|
567 */
|
danielebarchiesi@0
|
568 public function makeSequenceName($table, $field) {
|
danielebarchiesi@0
|
569 return $this->prefixTables('{' . $table . '}_' . $field . '_seq');
|
danielebarchiesi@0
|
570 }
|
danielebarchiesi@0
|
571
|
danielebarchiesi@0
|
572 /**
|
danielebarchiesi@0
|
573 * Flatten an array of query comments into a single comment string.
|
danielebarchiesi@0
|
574 *
|
danielebarchiesi@0
|
575 * The comment string will be sanitized to avoid SQL injection attacks.
|
danielebarchiesi@0
|
576 *
|
danielebarchiesi@0
|
577 * @param $comments
|
danielebarchiesi@0
|
578 * An array of query comment strings.
|
danielebarchiesi@0
|
579 *
|
danielebarchiesi@0
|
580 * @return
|
danielebarchiesi@0
|
581 * A sanitized comment string.
|
danielebarchiesi@0
|
582 */
|
danielebarchiesi@0
|
583 public function makeComment($comments) {
|
danielebarchiesi@0
|
584 if (empty($comments))
|
danielebarchiesi@0
|
585 return '';
|
danielebarchiesi@0
|
586
|
danielebarchiesi@0
|
587 // Flatten the array of comments.
|
danielebarchiesi@0
|
588 $comment = implode('; ', $comments);
|
danielebarchiesi@0
|
589
|
danielebarchiesi@0
|
590 // Sanitize the comment string so as to avoid SQL injection attacks.
|
danielebarchiesi@0
|
591 return '/* ' . $this->filterComment($comment) . ' */ ';
|
danielebarchiesi@0
|
592 }
|
danielebarchiesi@0
|
593
|
danielebarchiesi@0
|
594 /**
|
danielebarchiesi@0
|
595 * Sanitize a query comment string.
|
danielebarchiesi@0
|
596 *
|
danielebarchiesi@0
|
597 * Ensure a query comment does not include strings such as "* /" that might
|
danielebarchiesi@0
|
598 * terminate the comment early. This avoids SQL injection attacks via the
|
danielebarchiesi@0
|
599 * query comment. The comment strings in this example are separated by a
|
danielebarchiesi@0
|
600 * space to avoid PHP parse errors.
|
danielebarchiesi@0
|
601 *
|
danielebarchiesi@0
|
602 * For example, the comment:
|
danielebarchiesi@0
|
603 * @code
|
danielebarchiesi@0
|
604 * db_update('example')
|
danielebarchiesi@0
|
605 * ->condition('id', $id)
|
danielebarchiesi@0
|
606 * ->fields(array('field2' => 10))
|
danielebarchiesi@0
|
607 * ->comment('Exploit * / DROP TABLE node; --')
|
danielebarchiesi@0
|
608 * ->execute()
|
danielebarchiesi@0
|
609 * @endcode
|
danielebarchiesi@0
|
610 *
|
danielebarchiesi@0
|
611 * Would result in the following SQL statement being generated:
|
danielebarchiesi@0
|
612 * @code
|
danielebarchiesi@0
|
613 * "/ * Exploit * / DROP TABLE node; -- * / UPDATE example SET field2=..."
|
danielebarchiesi@0
|
614 * @endcode
|
danielebarchiesi@0
|
615 *
|
danielebarchiesi@0
|
616 * Unless the comment is sanitised first, the SQL server would drop the
|
danielebarchiesi@0
|
617 * node table and ignore the rest of the SQL statement.
|
danielebarchiesi@0
|
618 *
|
danielebarchiesi@0
|
619 * @param $comment
|
danielebarchiesi@0
|
620 * A query comment string.
|
danielebarchiesi@0
|
621 *
|
danielebarchiesi@0
|
622 * @return
|
danielebarchiesi@0
|
623 * A sanitized version of the query comment string.
|
danielebarchiesi@0
|
624 */
|
danielebarchiesi@0
|
625 protected function filterComment($comment = '') {
|
danielebarchiesi@0
|
626 return preg_replace('/(\/\*\s*)|(\s*\*\/)/', '', $comment);
|
danielebarchiesi@0
|
627 }
|
danielebarchiesi@0
|
628
|
danielebarchiesi@0
|
629 /**
|
danielebarchiesi@0
|
630 * Executes a query string against the database.
|
danielebarchiesi@0
|
631 *
|
danielebarchiesi@0
|
632 * This method provides a central handler for the actual execution of every
|
danielebarchiesi@0
|
633 * query. All queries executed by Drupal are executed as PDO prepared
|
danielebarchiesi@0
|
634 * statements.
|
danielebarchiesi@0
|
635 *
|
danielebarchiesi@0
|
636 * @param $query
|
danielebarchiesi@0
|
637 * The query to execute. In most cases this will be a string containing
|
danielebarchiesi@0
|
638 * an SQL query with placeholders. An already-prepared instance of
|
danielebarchiesi@0
|
639 * DatabaseStatementInterface may also be passed in order to allow calling
|
danielebarchiesi@0
|
640 * code to manually bind variables to a query. If a
|
danielebarchiesi@0
|
641 * DatabaseStatementInterface is passed, the $args array will be ignored.
|
danielebarchiesi@0
|
642 * It is extremely rare that module code will need to pass a statement
|
danielebarchiesi@0
|
643 * object to this method. It is used primarily for database drivers for
|
danielebarchiesi@0
|
644 * databases that require special LOB field handling.
|
danielebarchiesi@0
|
645 * @param $args
|
danielebarchiesi@0
|
646 * An array of arguments for the prepared statement. If the prepared
|
danielebarchiesi@0
|
647 * statement uses ? placeholders, this array must be an indexed array.
|
danielebarchiesi@0
|
648 * If it contains named placeholders, it must be an associative array.
|
danielebarchiesi@0
|
649 * @param $options
|
danielebarchiesi@0
|
650 * An associative array of options to control how the query is run. See
|
danielebarchiesi@0
|
651 * the documentation for DatabaseConnection::defaultOptions() for details.
|
danielebarchiesi@0
|
652 *
|
danielebarchiesi@0
|
653 * @return DatabaseStatementInterface
|
danielebarchiesi@0
|
654 * This method will return one of: the executed statement, the number of
|
danielebarchiesi@0
|
655 * rows affected by the query (not the number matched), or the generated
|
danielebarchiesi@0
|
656 * insert IT of the last query, depending on the value of
|
danielebarchiesi@0
|
657 * $options['return']. Typically that value will be set by default or a
|
danielebarchiesi@0
|
658 * query builder and should not be set by a user. If there is an error,
|
danielebarchiesi@0
|
659 * this method will return NULL and may throw an exception if
|
danielebarchiesi@0
|
660 * $options['throw_exception'] is TRUE.
|
danielebarchiesi@0
|
661 *
|
danielebarchiesi@0
|
662 * @throws PDOException
|
danielebarchiesi@0
|
663 */
|
danielebarchiesi@0
|
664 public function query($query, array $args = array(), $options = array()) {
|
danielebarchiesi@0
|
665
|
danielebarchiesi@0
|
666 // Use default values if not already set.
|
danielebarchiesi@0
|
667 $options += $this->defaultOptions();
|
danielebarchiesi@0
|
668
|
danielebarchiesi@0
|
669 try {
|
danielebarchiesi@0
|
670 // We allow either a pre-bound statement object or a literal string.
|
danielebarchiesi@0
|
671 // In either case, we want to end up with an executed statement object,
|
danielebarchiesi@0
|
672 // which we pass to PDOStatement::execute.
|
danielebarchiesi@0
|
673 if ($query instanceof DatabaseStatementInterface) {
|
danielebarchiesi@0
|
674 $stmt = $query;
|
danielebarchiesi@0
|
675 $stmt->execute(NULL, $options);
|
danielebarchiesi@0
|
676 }
|
danielebarchiesi@0
|
677 else {
|
danielebarchiesi@0
|
678 $this->expandArguments($query, $args);
|
danielebarchiesi@0
|
679 $stmt = $this->prepareQuery($query);
|
danielebarchiesi@0
|
680 $stmt->execute($args, $options);
|
danielebarchiesi@0
|
681 }
|
danielebarchiesi@0
|
682
|
danielebarchiesi@0
|
683 // Depending on the type of query we may need to return a different value.
|
danielebarchiesi@0
|
684 // See DatabaseConnection::defaultOptions() for a description of each
|
danielebarchiesi@0
|
685 // value.
|
danielebarchiesi@0
|
686 switch ($options['return']) {
|
danielebarchiesi@0
|
687 case Database::RETURN_STATEMENT:
|
danielebarchiesi@0
|
688 return $stmt;
|
danielebarchiesi@0
|
689 case Database::RETURN_AFFECTED:
|
danielebarchiesi@0
|
690 return $stmt->rowCount();
|
danielebarchiesi@0
|
691 case Database::RETURN_INSERT_ID:
|
danielebarchiesi@0
|
692 return $this->lastInsertId();
|
danielebarchiesi@0
|
693 case Database::RETURN_NULL:
|
danielebarchiesi@0
|
694 return;
|
danielebarchiesi@0
|
695 default:
|
danielebarchiesi@0
|
696 throw new PDOException('Invalid return directive: ' . $options['return']);
|
danielebarchiesi@0
|
697 }
|
danielebarchiesi@0
|
698 }
|
danielebarchiesi@0
|
699 catch (PDOException $e) {
|
danielebarchiesi@0
|
700 if ($options['throw_exception']) {
|
danielebarchiesi@0
|
701 // Add additional debug information.
|
danielebarchiesi@0
|
702 if ($query instanceof DatabaseStatementInterface) {
|
danielebarchiesi@0
|
703 $e->query_string = $stmt->getQueryString();
|
danielebarchiesi@0
|
704 }
|
danielebarchiesi@0
|
705 else {
|
danielebarchiesi@0
|
706 $e->query_string = $query;
|
danielebarchiesi@0
|
707 }
|
danielebarchiesi@0
|
708 $e->args = $args;
|
danielebarchiesi@0
|
709 throw $e;
|
danielebarchiesi@0
|
710 }
|
danielebarchiesi@0
|
711 return NULL;
|
danielebarchiesi@0
|
712 }
|
danielebarchiesi@0
|
713 }
|
danielebarchiesi@0
|
714
|
danielebarchiesi@0
|
715 /**
|
danielebarchiesi@0
|
716 * Expands out shorthand placeholders.
|
danielebarchiesi@0
|
717 *
|
danielebarchiesi@0
|
718 * Drupal supports an alternate syntax for doing arrays of values. We
|
danielebarchiesi@0
|
719 * therefore need to expand them out into a full, executable query string.
|
danielebarchiesi@0
|
720 *
|
danielebarchiesi@0
|
721 * @param $query
|
danielebarchiesi@0
|
722 * The query string to modify.
|
danielebarchiesi@0
|
723 * @param $args
|
danielebarchiesi@0
|
724 * The arguments for the query.
|
danielebarchiesi@0
|
725 *
|
danielebarchiesi@0
|
726 * @return
|
danielebarchiesi@0
|
727 * TRUE if the query was modified, FALSE otherwise.
|
danielebarchiesi@0
|
728 */
|
danielebarchiesi@0
|
729 protected function expandArguments(&$query, &$args) {
|
danielebarchiesi@0
|
730 $modified = FALSE;
|
danielebarchiesi@0
|
731
|
danielebarchiesi@0
|
732 // If the placeholder value to insert is an array, assume that we need
|
danielebarchiesi@0
|
733 // to expand it out into a comma-delimited set of placeholders.
|
danielebarchiesi@0
|
734 foreach (array_filter($args, 'is_array') as $key => $data) {
|
danielebarchiesi@0
|
735 $new_keys = array();
|
danielebarchiesi@0
|
736 foreach ($data as $i => $value) {
|
danielebarchiesi@0
|
737 // This assumes that there are no other placeholders that use the same
|
danielebarchiesi@0
|
738 // name. For example, if the array placeholder is defined as :example
|
danielebarchiesi@0
|
739 // and there is already an :example_2 placeholder, this will generate
|
danielebarchiesi@0
|
740 // a duplicate key. We do not account for that as the calling code
|
danielebarchiesi@0
|
741 // is already broken if that happens.
|
danielebarchiesi@0
|
742 $new_keys[$key . '_' . $i] = $value;
|
danielebarchiesi@0
|
743 }
|
danielebarchiesi@0
|
744
|
danielebarchiesi@0
|
745 // Update the query with the new placeholders.
|
danielebarchiesi@0
|
746 // preg_replace is necessary to ensure the replacement does not affect
|
danielebarchiesi@0
|
747 // placeholders that start with the same exact text. For example, if the
|
danielebarchiesi@0
|
748 // query contains the placeholders :foo and :foobar, and :foo has an
|
danielebarchiesi@0
|
749 // array of values, using str_replace would affect both placeholders,
|
danielebarchiesi@0
|
750 // but using the following preg_replace would only affect :foo because
|
danielebarchiesi@0
|
751 // it is followed by a non-word character.
|
danielebarchiesi@0
|
752 $query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);
|
danielebarchiesi@0
|
753
|
danielebarchiesi@0
|
754 // Update the args array with the new placeholders.
|
danielebarchiesi@0
|
755 unset($args[$key]);
|
danielebarchiesi@0
|
756 $args += $new_keys;
|
danielebarchiesi@0
|
757
|
danielebarchiesi@0
|
758 $modified = TRUE;
|
danielebarchiesi@0
|
759 }
|
danielebarchiesi@0
|
760
|
danielebarchiesi@0
|
761 return $modified;
|
danielebarchiesi@0
|
762 }
|
danielebarchiesi@0
|
763
|
danielebarchiesi@0
|
764 /**
|
danielebarchiesi@0
|
765 * Gets the driver-specific override class if any for the specified class.
|
danielebarchiesi@0
|
766 *
|
danielebarchiesi@0
|
767 * @param string $class
|
danielebarchiesi@0
|
768 * The class for which we want the potentially driver-specific class.
|
danielebarchiesi@0
|
769 * @param array $files
|
danielebarchiesi@0
|
770 * The name of the files in which the driver-specific class can be.
|
danielebarchiesi@0
|
771 * @param $use_autoload
|
danielebarchiesi@0
|
772 * If TRUE, attempt to load classes using PHP's autoload capability
|
danielebarchiesi@0
|
773 * as well as the manual approach here.
|
danielebarchiesi@0
|
774 * @return string
|
danielebarchiesi@0
|
775 * The name of the class that should be used for this driver.
|
danielebarchiesi@0
|
776 */
|
danielebarchiesi@0
|
777 public function getDriverClass($class, array $files = array(), $use_autoload = FALSE) {
|
danielebarchiesi@0
|
778 if (empty($this->driverClasses[$class])) {
|
danielebarchiesi@0
|
779 $driver = $this->driver();
|
danielebarchiesi@0
|
780 $this->driverClasses[$class] = $class . '_' . $driver;
|
danielebarchiesi@0
|
781 Database::loadDriverFile($driver, $files);
|
danielebarchiesi@0
|
782 if (!class_exists($this->driverClasses[$class], $use_autoload)) {
|
danielebarchiesi@0
|
783 $this->driverClasses[$class] = $class;
|
danielebarchiesi@0
|
784 }
|
danielebarchiesi@0
|
785 }
|
danielebarchiesi@0
|
786 return $this->driverClasses[$class];
|
danielebarchiesi@0
|
787 }
|
danielebarchiesi@0
|
788
|
danielebarchiesi@0
|
789 /**
|
danielebarchiesi@0
|
790 * Prepares and returns a SELECT query object.
|
danielebarchiesi@0
|
791 *
|
danielebarchiesi@0
|
792 * @param $table
|
danielebarchiesi@0
|
793 * The base table for this query, that is, the first table in the FROM
|
danielebarchiesi@0
|
794 * clause. This table will also be used as the "base" table for query_alter
|
danielebarchiesi@0
|
795 * hook implementations.
|
danielebarchiesi@0
|
796 * @param $alias
|
danielebarchiesi@0
|
797 * The alias of the base table of this query.
|
danielebarchiesi@0
|
798 * @param $options
|
danielebarchiesi@0
|
799 * An array of options on the query.
|
danielebarchiesi@0
|
800 *
|
danielebarchiesi@0
|
801 * @return SelectQueryInterface
|
danielebarchiesi@0
|
802 * An appropriate SelectQuery object for this database connection. Note that
|
danielebarchiesi@0
|
803 * it may be a driver-specific subclass of SelectQuery, depending on the
|
danielebarchiesi@0
|
804 * driver.
|
danielebarchiesi@0
|
805 *
|
danielebarchiesi@0
|
806 * @see SelectQuery
|
danielebarchiesi@0
|
807 */
|
danielebarchiesi@0
|
808 public function select($table, $alias = NULL, array $options = array()) {
|
danielebarchiesi@0
|
809 $class = $this->getDriverClass('SelectQuery', array('query.inc', 'select.inc'));
|
danielebarchiesi@0
|
810 return new $class($table, $alias, $this, $options);
|
danielebarchiesi@0
|
811 }
|
danielebarchiesi@0
|
812
|
danielebarchiesi@0
|
813 /**
|
danielebarchiesi@0
|
814 * Prepares and returns an INSERT query object.
|
danielebarchiesi@0
|
815 *
|
danielebarchiesi@0
|
816 * @param $options
|
danielebarchiesi@0
|
817 * An array of options on the query.
|
danielebarchiesi@0
|
818 *
|
danielebarchiesi@0
|
819 * @return InsertQuery
|
danielebarchiesi@0
|
820 * A new InsertQuery object.
|
danielebarchiesi@0
|
821 *
|
danielebarchiesi@0
|
822 * @see InsertQuery
|
danielebarchiesi@0
|
823 */
|
danielebarchiesi@0
|
824 public function insert($table, array $options = array()) {
|
danielebarchiesi@0
|
825 $class = $this->getDriverClass('InsertQuery', array('query.inc'));
|
danielebarchiesi@0
|
826 return new $class($this, $table, $options);
|
danielebarchiesi@0
|
827 }
|
danielebarchiesi@0
|
828
|
danielebarchiesi@0
|
829 /**
|
danielebarchiesi@0
|
830 * Prepares and returns a MERGE query object.
|
danielebarchiesi@0
|
831 *
|
danielebarchiesi@0
|
832 * @param $options
|
danielebarchiesi@0
|
833 * An array of options on the query.
|
danielebarchiesi@0
|
834 *
|
danielebarchiesi@0
|
835 * @return MergeQuery
|
danielebarchiesi@0
|
836 * A new MergeQuery object.
|
danielebarchiesi@0
|
837 *
|
danielebarchiesi@0
|
838 * @see MergeQuery
|
danielebarchiesi@0
|
839 */
|
danielebarchiesi@0
|
840 public function merge($table, array $options = array()) {
|
danielebarchiesi@0
|
841 $class = $this->getDriverClass('MergeQuery', array('query.inc'));
|
danielebarchiesi@0
|
842 return new $class($this, $table, $options);
|
danielebarchiesi@0
|
843 }
|
danielebarchiesi@0
|
844
|
danielebarchiesi@0
|
845
|
danielebarchiesi@0
|
846 /**
|
danielebarchiesi@0
|
847 * Prepares and returns an UPDATE query object.
|
danielebarchiesi@0
|
848 *
|
danielebarchiesi@0
|
849 * @param $options
|
danielebarchiesi@0
|
850 * An array of options on the query.
|
danielebarchiesi@0
|
851 *
|
danielebarchiesi@0
|
852 * @return UpdateQuery
|
danielebarchiesi@0
|
853 * A new UpdateQuery object.
|
danielebarchiesi@0
|
854 *
|
danielebarchiesi@0
|
855 * @see UpdateQuery
|
danielebarchiesi@0
|
856 */
|
danielebarchiesi@0
|
857 public function update($table, array $options = array()) {
|
danielebarchiesi@0
|
858 $class = $this->getDriverClass('UpdateQuery', array('query.inc'));
|
danielebarchiesi@0
|
859 return new $class($this, $table, $options);
|
danielebarchiesi@0
|
860 }
|
danielebarchiesi@0
|
861
|
danielebarchiesi@0
|
862 /**
|
danielebarchiesi@0
|
863 * Prepares and returns a DELETE query object.
|
danielebarchiesi@0
|
864 *
|
danielebarchiesi@0
|
865 * @param $options
|
danielebarchiesi@0
|
866 * An array of options on the query.
|
danielebarchiesi@0
|
867 *
|
danielebarchiesi@0
|
868 * @return DeleteQuery
|
danielebarchiesi@0
|
869 * A new DeleteQuery object.
|
danielebarchiesi@0
|
870 *
|
danielebarchiesi@0
|
871 * @see DeleteQuery
|
danielebarchiesi@0
|
872 */
|
danielebarchiesi@0
|
873 public function delete($table, array $options = array()) {
|
danielebarchiesi@0
|
874 $class = $this->getDriverClass('DeleteQuery', array('query.inc'));
|
danielebarchiesi@0
|
875 return new $class($this, $table, $options);
|
danielebarchiesi@0
|
876 }
|
danielebarchiesi@0
|
877
|
danielebarchiesi@0
|
878 /**
|
danielebarchiesi@0
|
879 * Prepares and returns a TRUNCATE query object.
|
danielebarchiesi@0
|
880 *
|
danielebarchiesi@0
|
881 * @param $options
|
danielebarchiesi@0
|
882 * An array of options on the query.
|
danielebarchiesi@0
|
883 *
|
danielebarchiesi@0
|
884 * @return TruncateQuery
|
danielebarchiesi@0
|
885 * A new TruncateQuery object.
|
danielebarchiesi@0
|
886 *
|
danielebarchiesi@0
|
887 * @see TruncateQuery
|
danielebarchiesi@0
|
888 */
|
danielebarchiesi@0
|
889 public function truncate($table, array $options = array()) {
|
danielebarchiesi@0
|
890 $class = $this->getDriverClass('TruncateQuery', array('query.inc'));
|
danielebarchiesi@0
|
891 return new $class($this, $table, $options);
|
danielebarchiesi@0
|
892 }
|
danielebarchiesi@0
|
893
|
danielebarchiesi@0
|
894 /**
|
danielebarchiesi@0
|
895 * Returns a DatabaseSchema object for manipulating the schema.
|
danielebarchiesi@0
|
896 *
|
danielebarchiesi@0
|
897 * This method will lazy-load the appropriate schema library file.
|
danielebarchiesi@0
|
898 *
|
danielebarchiesi@0
|
899 * @return DatabaseSchema
|
danielebarchiesi@0
|
900 * The DatabaseSchema object for this connection.
|
danielebarchiesi@0
|
901 */
|
danielebarchiesi@0
|
902 public function schema() {
|
danielebarchiesi@0
|
903 if (empty($this->schema)) {
|
danielebarchiesi@0
|
904 $class = $this->getDriverClass('DatabaseSchema', array('schema.inc'));
|
danielebarchiesi@0
|
905 if (class_exists($class)) {
|
danielebarchiesi@0
|
906 $this->schema = new $class($this);
|
danielebarchiesi@0
|
907 }
|
danielebarchiesi@0
|
908 }
|
danielebarchiesi@0
|
909 return $this->schema;
|
danielebarchiesi@0
|
910 }
|
danielebarchiesi@0
|
911
|
danielebarchiesi@0
|
912 /**
|
danielebarchiesi@0
|
913 * Escapes a table name string.
|
danielebarchiesi@0
|
914 *
|
danielebarchiesi@0
|
915 * Force all table names to be strictly alphanumeric-plus-underscore.
|
danielebarchiesi@0
|
916 * For some database drivers, it may also wrap the table name in
|
danielebarchiesi@0
|
917 * database-specific escape characters.
|
danielebarchiesi@0
|
918 *
|
danielebarchiesi@0
|
919 * @return
|
danielebarchiesi@0
|
920 * The sanitized table name string.
|
danielebarchiesi@0
|
921 */
|
danielebarchiesi@0
|
922 public function escapeTable($table) {
|
danielebarchiesi@0
|
923 return preg_replace('/[^A-Za-z0-9_.]+/', '', $table);
|
danielebarchiesi@0
|
924 }
|
danielebarchiesi@0
|
925
|
danielebarchiesi@0
|
926 /**
|
danielebarchiesi@0
|
927 * Escapes a field name string.
|
danielebarchiesi@0
|
928 *
|
danielebarchiesi@0
|
929 * Force all field names to be strictly alphanumeric-plus-underscore.
|
danielebarchiesi@0
|
930 * For some database drivers, it may also wrap the field name in
|
danielebarchiesi@0
|
931 * database-specific escape characters.
|
danielebarchiesi@0
|
932 *
|
danielebarchiesi@0
|
933 * @return
|
danielebarchiesi@0
|
934 * The sanitized field name string.
|
danielebarchiesi@0
|
935 */
|
danielebarchiesi@0
|
936 public function escapeField($field) {
|
danielebarchiesi@0
|
937 return preg_replace('/[^A-Za-z0-9_.]+/', '', $field);
|
danielebarchiesi@0
|
938 }
|
danielebarchiesi@0
|
939
|
danielebarchiesi@0
|
940 /**
|
danielebarchiesi@0
|
941 * Escapes an alias name string.
|
danielebarchiesi@0
|
942 *
|
danielebarchiesi@0
|
943 * Force all alias names to be strictly alphanumeric-plus-underscore. In
|
danielebarchiesi@0
|
944 * contrast to DatabaseConnection::escapeField() /
|
danielebarchiesi@0
|
945 * DatabaseConnection::escapeTable(), this doesn't allow the period (".")
|
danielebarchiesi@0
|
946 * because that is not allowed in aliases.
|
danielebarchiesi@0
|
947 *
|
danielebarchiesi@0
|
948 * @return
|
danielebarchiesi@0
|
949 * The sanitized field name string.
|
danielebarchiesi@0
|
950 */
|
danielebarchiesi@0
|
951 public function escapeAlias($field) {
|
danielebarchiesi@0
|
952 return preg_replace('/[^A-Za-z0-9_]+/', '', $field);
|
danielebarchiesi@0
|
953 }
|
danielebarchiesi@0
|
954
|
danielebarchiesi@0
|
955 /**
|
danielebarchiesi@0
|
956 * Escapes characters that work as wildcard characters in a LIKE pattern.
|
danielebarchiesi@0
|
957 *
|
danielebarchiesi@0
|
958 * The wildcard characters "%" and "_" as well as backslash are prefixed with
|
danielebarchiesi@0
|
959 * a backslash. Use this to do a search for a verbatim string without any
|
danielebarchiesi@0
|
960 * wildcard behavior.
|
danielebarchiesi@0
|
961 *
|
danielebarchiesi@0
|
962 * For example, the following does a case-insensitive query for all rows whose
|
danielebarchiesi@0
|
963 * name starts with $prefix:
|
danielebarchiesi@0
|
964 * @code
|
danielebarchiesi@0
|
965 * $result = db_query(
|
danielebarchiesi@0
|
966 * 'SELECT * FROM person WHERE name LIKE :pattern',
|
danielebarchiesi@0
|
967 * array(':pattern' => db_like($prefix) . '%')
|
danielebarchiesi@0
|
968 * );
|
danielebarchiesi@0
|
969 * @endcode
|
danielebarchiesi@0
|
970 *
|
danielebarchiesi@0
|
971 * Backslash is defined as escape character for LIKE patterns in
|
danielebarchiesi@0
|
972 * DatabaseCondition::mapConditionOperator().
|
danielebarchiesi@0
|
973 *
|
danielebarchiesi@0
|
974 * @param $string
|
danielebarchiesi@0
|
975 * The string to escape.
|
danielebarchiesi@0
|
976 *
|
danielebarchiesi@0
|
977 * @return
|
danielebarchiesi@0
|
978 * The escaped string.
|
danielebarchiesi@0
|
979 */
|
danielebarchiesi@0
|
980 public function escapeLike($string) {
|
danielebarchiesi@0
|
981 return addcslashes($string, '\%_');
|
danielebarchiesi@0
|
982 }
|
danielebarchiesi@0
|
983
|
danielebarchiesi@0
|
984 /**
|
danielebarchiesi@0
|
985 * Determines if there is an active transaction open.
|
danielebarchiesi@0
|
986 *
|
danielebarchiesi@0
|
987 * @return
|
danielebarchiesi@0
|
988 * TRUE if we're currently in a transaction, FALSE otherwise.
|
danielebarchiesi@0
|
989 */
|
danielebarchiesi@0
|
990 public function inTransaction() {
|
danielebarchiesi@0
|
991 return ($this->transactionDepth() > 0);
|
danielebarchiesi@0
|
992 }
|
danielebarchiesi@0
|
993
|
danielebarchiesi@0
|
994 /**
|
danielebarchiesi@0
|
995 * Determines current transaction depth.
|
danielebarchiesi@0
|
996 */
|
danielebarchiesi@0
|
997 public function transactionDepth() {
|
danielebarchiesi@0
|
998 return count($this->transactionLayers);
|
danielebarchiesi@0
|
999 }
|
danielebarchiesi@0
|
1000
|
danielebarchiesi@0
|
1001 /**
|
danielebarchiesi@0
|
1002 * Returns a new DatabaseTransaction object on this connection.
|
danielebarchiesi@0
|
1003 *
|
danielebarchiesi@0
|
1004 * @param $name
|
danielebarchiesi@0
|
1005 * Optional name of the savepoint.
|
danielebarchiesi@0
|
1006 *
|
danielebarchiesi@0
|
1007 * @return DatabaseTransaction
|
danielebarchiesi@0
|
1008 * A DatabaseTransaction object.
|
danielebarchiesi@0
|
1009 *
|
danielebarchiesi@0
|
1010 * @see DatabaseTransaction
|
danielebarchiesi@0
|
1011 */
|
danielebarchiesi@0
|
1012 public function startTransaction($name = '') {
|
danielebarchiesi@0
|
1013 $class = $this->getDriverClass('DatabaseTransaction');
|
danielebarchiesi@0
|
1014 return new $class($this, $name);
|
danielebarchiesi@0
|
1015 }
|
danielebarchiesi@0
|
1016
|
danielebarchiesi@0
|
1017 /**
|
danielebarchiesi@0
|
1018 * Rolls back the transaction entirely or to a named savepoint.
|
danielebarchiesi@0
|
1019 *
|
danielebarchiesi@0
|
1020 * This method throws an exception if no transaction is active.
|
danielebarchiesi@0
|
1021 *
|
danielebarchiesi@0
|
1022 * @param $savepoint_name
|
danielebarchiesi@0
|
1023 * The name of the savepoint. The default, 'drupal_transaction', will roll
|
danielebarchiesi@0
|
1024 * the entire transaction back.
|
danielebarchiesi@0
|
1025 *
|
danielebarchiesi@0
|
1026 * @throws DatabaseTransactionNoActiveException
|
danielebarchiesi@0
|
1027 *
|
danielebarchiesi@0
|
1028 * @see DatabaseTransaction::rollback()
|
danielebarchiesi@0
|
1029 */
|
danielebarchiesi@0
|
1030 public function rollback($savepoint_name = 'drupal_transaction') {
|
danielebarchiesi@0
|
1031 if (!$this->supportsTransactions()) {
|
danielebarchiesi@0
|
1032 return;
|
danielebarchiesi@0
|
1033 }
|
danielebarchiesi@0
|
1034 if (!$this->inTransaction()) {
|
danielebarchiesi@0
|
1035 throw new DatabaseTransactionNoActiveException();
|
danielebarchiesi@0
|
1036 }
|
danielebarchiesi@0
|
1037 // A previous rollback to an earlier savepoint may mean that the savepoint
|
danielebarchiesi@0
|
1038 // in question has already been accidentally committed.
|
danielebarchiesi@0
|
1039 if (!isset($this->transactionLayers[$savepoint_name])) {
|
danielebarchiesi@0
|
1040 throw new DatabaseTransactionNoActiveException();
|
danielebarchiesi@0
|
1041 }
|
danielebarchiesi@0
|
1042
|
danielebarchiesi@0
|
1043 // We need to find the point we're rolling back to, all other savepoints
|
danielebarchiesi@0
|
1044 // before are no longer needed. If we rolled back other active savepoints,
|
danielebarchiesi@0
|
1045 // we need to throw an exception.
|
danielebarchiesi@0
|
1046 $rolled_back_other_active_savepoints = FALSE;
|
danielebarchiesi@0
|
1047 while ($savepoint = array_pop($this->transactionLayers)) {
|
danielebarchiesi@0
|
1048 if ($savepoint == $savepoint_name) {
|
danielebarchiesi@0
|
1049 // If it is the last the transaction in the stack, then it is not a
|
danielebarchiesi@0
|
1050 // savepoint, it is the transaction itself so we will need to roll back
|
danielebarchiesi@0
|
1051 // the transaction rather than a savepoint.
|
danielebarchiesi@0
|
1052 if (empty($this->transactionLayers)) {
|
danielebarchiesi@0
|
1053 break;
|
danielebarchiesi@0
|
1054 }
|
danielebarchiesi@0
|
1055 $this->query('ROLLBACK TO SAVEPOINT ' . $savepoint);
|
danielebarchiesi@0
|
1056 $this->popCommittableTransactions();
|
danielebarchiesi@0
|
1057 if ($rolled_back_other_active_savepoints) {
|
danielebarchiesi@0
|
1058 throw new DatabaseTransactionOutOfOrderException();
|
danielebarchiesi@0
|
1059 }
|
danielebarchiesi@0
|
1060 return;
|
danielebarchiesi@0
|
1061 }
|
danielebarchiesi@0
|
1062 else {
|
danielebarchiesi@0
|
1063 $rolled_back_other_active_savepoints = TRUE;
|
danielebarchiesi@0
|
1064 }
|
danielebarchiesi@0
|
1065 }
|
danielebarchiesi@0
|
1066 parent::rollBack();
|
danielebarchiesi@0
|
1067 if ($rolled_back_other_active_savepoints) {
|
danielebarchiesi@0
|
1068 throw new DatabaseTransactionOutOfOrderException();
|
danielebarchiesi@0
|
1069 }
|
danielebarchiesi@0
|
1070 }
|
danielebarchiesi@0
|
1071
|
danielebarchiesi@0
|
1072 /**
|
danielebarchiesi@0
|
1073 * Increases the depth of transaction nesting.
|
danielebarchiesi@0
|
1074 *
|
danielebarchiesi@0
|
1075 * If no transaction is already active, we begin a new transaction.
|
danielebarchiesi@0
|
1076 *
|
danielebarchiesi@0
|
1077 * @throws DatabaseTransactionNameNonUniqueException
|
danielebarchiesi@0
|
1078 *
|
danielebarchiesi@0
|
1079 * @see DatabaseTransaction
|
danielebarchiesi@0
|
1080 */
|
danielebarchiesi@0
|
1081 public function pushTransaction($name) {
|
danielebarchiesi@0
|
1082 if (!$this->supportsTransactions()) {
|
danielebarchiesi@0
|
1083 return;
|
danielebarchiesi@0
|
1084 }
|
danielebarchiesi@0
|
1085 if (isset($this->transactionLayers[$name])) {
|
danielebarchiesi@0
|
1086 throw new DatabaseTransactionNameNonUniqueException($name . " is already in use.");
|
danielebarchiesi@0
|
1087 }
|
danielebarchiesi@0
|
1088 // If we're already in a transaction then we want to create a savepoint
|
danielebarchiesi@0
|
1089 // rather than try to create another transaction.
|
danielebarchiesi@0
|
1090 if ($this->inTransaction()) {
|
danielebarchiesi@0
|
1091 $this->query('SAVEPOINT ' . $name);
|
danielebarchiesi@0
|
1092 }
|
danielebarchiesi@0
|
1093 else {
|
danielebarchiesi@0
|
1094 parent::beginTransaction();
|
danielebarchiesi@0
|
1095 }
|
danielebarchiesi@0
|
1096 $this->transactionLayers[$name] = $name;
|
danielebarchiesi@0
|
1097 }
|
danielebarchiesi@0
|
1098
|
danielebarchiesi@0
|
1099 /**
|
danielebarchiesi@0
|
1100 * Decreases the depth of transaction nesting.
|
danielebarchiesi@0
|
1101 *
|
danielebarchiesi@0
|
1102 * If we pop off the last transaction layer, then we either commit or roll
|
danielebarchiesi@0
|
1103 * back the transaction as necessary. If no transaction is active, we return
|
danielebarchiesi@0
|
1104 * because the transaction may have manually been rolled back.
|
danielebarchiesi@0
|
1105 *
|
danielebarchiesi@0
|
1106 * @param $name
|
danielebarchiesi@0
|
1107 * The name of the savepoint
|
danielebarchiesi@0
|
1108 *
|
danielebarchiesi@0
|
1109 * @throws DatabaseTransactionNoActiveException
|
danielebarchiesi@0
|
1110 * @throws DatabaseTransactionCommitFailedException
|
danielebarchiesi@0
|
1111 *
|
danielebarchiesi@0
|
1112 * @see DatabaseTransaction
|
danielebarchiesi@0
|
1113 */
|
danielebarchiesi@0
|
1114 public function popTransaction($name) {
|
danielebarchiesi@0
|
1115 if (!$this->supportsTransactions()) {
|
danielebarchiesi@0
|
1116 return;
|
danielebarchiesi@0
|
1117 }
|
danielebarchiesi@0
|
1118 // The transaction has already been committed earlier. There is nothing we
|
danielebarchiesi@0
|
1119 // need to do. If this transaction was part of an earlier out-of-order
|
danielebarchiesi@0
|
1120 // rollback, an exception would already have been thrown by
|
danielebarchiesi@0
|
1121 // Database::rollback().
|
danielebarchiesi@0
|
1122 if (!isset($this->transactionLayers[$name])) {
|
danielebarchiesi@0
|
1123 return;
|
danielebarchiesi@0
|
1124 }
|
danielebarchiesi@0
|
1125
|
danielebarchiesi@0
|
1126 // Mark this layer as committable.
|
danielebarchiesi@0
|
1127 $this->transactionLayers[$name] = FALSE;
|
danielebarchiesi@0
|
1128 $this->popCommittableTransactions();
|
danielebarchiesi@0
|
1129 }
|
danielebarchiesi@0
|
1130
|
danielebarchiesi@0
|
1131 /**
|
danielebarchiesi@0
|
1132 * Internal function: commit all the transaction layers that can commit.
|
danielebarchiesi@0
|
1133 */
|
danielebarchiesi@0
|
1134 protected function popCommittableTransactions() {
|
danielebarchiesi@0
|
1135 // Commit all the committable layers.
|
danielebarchiesi@0
|
1136 foreach (array_reverse($this->transactionLayers) as $name => $active) {
|
danielebarchiesi@0
|
1137 // Stop once we found an active transaction.
|
danielebarchiesi@0
|
1138 if ($active) {
|
danielebarchiesi@0
|
1139 break;
|
danielebarchiesi@0
|
1140 }
|
danielebarchiesi@0
|
1141
|
danielebarchiesi@0
|
1142 // If there are no more layers left then we should commit.
|
danielebarchiesi@0
|
1143 unset($this->transactionLayers[$name]);
|
danielebarchiesi@0
|
1144 if (empty($this->transactionLayers)) {
|
danielebarchiesi@0
|
1145 if (!parent::commit()) {
|
danielebarchiesi@0
|
1146 throw new DatabaseTransactionCommitFailedException();
|
danielebarchiesi@0
|
1147 }
|
danielebarchiesi@0
|
1148 }
|
danielebarchiesi@0
|
1149 else {
|
danielebarchiesi@0
|
1150 $this->query('RELEASE SAVEPOINT ' . $name);
|
danielebarchiesi@0
|
1151 }
|
danielebarchiesi@0
|
1152 }
|
danielebarchiesi@0
|
1153 }
|
danielebarchiesi@0
|
1154
|
danielebarchiesi@0
|
1155 /**
|
danielebarchiesi@0
|
1156 * Runs a limited-range query on this database object.
|
danielebarchiesi@0
|
1157 *
|
danielebarchiesi@0
|
1158 * Use this as a substitute for ->query() when a subset of the query is to be
|
danielebarchiesi@0
|
1159 * returned. User-supplied arguments to the query should be passed in as
|
danielebarchiesi@0
|
1160 * separate parameters so that they can be properly escaped to avoid SQL
|
danielebarchiesi@0
|
1161 * injection attacks.
|
danielebarchiesi@0
|
1162 *
|
danielebarchiesi@0
|
1163 * @param $query
|
danielebarchiesi@0
|
1164 * A string containing an SQL query.
|
danielebarchiesi@0
|
1165 * @param $args
|
danielebarchiesi@0
|
1166 * An array of values to substitute into the query at placeholder markers.
|
danielebarchiesi@0
|
1167 * @param $from
|
danielebarchiesi@0
|
1168 * The first result row to return.
|
danielebarchiesi@0
|
1169 * @param $count
|
danielebarchiesi@0
|
1170 * The maximum number of result rows to return.
|
danielebarchiesi@0
|
1171 * @param $options
|
danielebarchiesi@0
|
1172 * An array of options on the query.
|
danielebarchiesi@0
|
1173 *
|
danielebarchiesi@0
|
1174 * @return DatabaseStatementInterface
|
danielebarchiesi@0
|
1175 * A database query result resource, or NULL if the query was not executed
|
danielebarchiesi@0
|
1176 * correctly.
|
danielebarchiesi@0
|
1177 */
|
danielebarchiesi@0
|
1178 abstract public function queryRange($query, $from, $count, array $args = array(), array $options = array());
|
danielebarchiesi@0
|
1179
|
danielebarchiesi@0
|
1180 /**
|
danielebarchiesi@0
|
1181 * Generates a temporary table name.
|
danielebarchiesi@0
|
1182 *
|
danielebarchiesi@0
|
1183 * @return
|
danielebarchiesi@0
|
1184 * A table name.
|
danielebarchiesi@0
|
1185 */
|
danielebarchiesi@0
|
1186 protected function generateTemporaryTableName() {
|
danielebarchiesi@0
|
1187 return "db_temporary_" . $this->temporaryNameIndex++;
|
danielebarchiesi@0
|
1188 }
|
danielebarchiesi@0
|
1189
|
danielebarchiesi@0
|
1190 /**
|
danielebarchiesi@0
|
1191 * Runs a SELECT query and stores its results in a temporary table.
|
danielebarchiesi@0
|
1192 *
|
danielebarchiesi@0
|
1193 * Use this as a substitute for ->query() when the results need to stored
|
danielebarchiesi@0
|
1194 * in a temporary table. Temporary tables exist for the duration of the page
|
danielebarchiesi@0
|
1195 * request. User-supplied arguments to the query should be passed in as
|
danielebarchiesi@0
|
1196 * separate parameters so that they can be properly escaped to avoid SQL
|
danielebarchiesi@0
|
1197 * injection attacks.
|
danielebarchiesi@0
|
1198 *
|
danielebarchiesi@0
|
1199 * Note that if you need to know how many results were returned, you should do
|
danielebarchiesi@0
|
1200 * a SELECT COUNT(*) on the temporary table afterwards.
|
danielebarchiesi@0
|
1201 *
|
danielebarchiesi@0
|
1202 * @param $query
|
danielebarchiesi@0
|
1203 * A string containing a normal SELECT SQL query.
|
danielebarchiesi@0
|
1204 * @param $args
|
danielebarchiesi@0
|
1205 * An array of values to substitute into the query at placeholder markers.
|
danielebarchiesi@0
|
1206 * @param $options
|
danielebarchiesi@0
|
1207 * An associative array of options to control how the query is run. See
|
danielebarchiesi@0
|
1208 * the documentation for DatabaseConnection::defaultOptions() for details.
|
danielebarchiesi@0
|
1209 *
|
danielebarchiesi@0
|
1210 * @return
|
danielebarchiesi@0
|
1211 * The name of the temporary table.
|
danielebarchiesi@0
|
1212 */
|
danielebarchiesi@0
|
1213 abstract function queryTemporary($query, array $args = array(), array $options = array());
|
danielebarchiesi@0
|
1214
|
danielebarchiesi@0
|
1215 /**
|
danielebarchiesi@0
|
1216 * Returns the type of database driver.
|
danielebarchiesi@0
|
1217 *
|
danielebarchiesi@0
|
1218 * This is not necessarily the same as the type of the database itself. For
|
danielebarchiesi@0
|
1219 * instance, there could be two MySQL drivers, mysql and mysql_mock. This
|
danielebarchiesi@0
|
1220 * function would return different values for each, but both would return
|
danielebarchiesi@0
|
1221 * "mysql" for databaseType().
|
danielebarchiesi@0
|
1222 */
|
danielebarchiesi@0
|
1223 abstract public function driver();
|
danielebarchiesi@0
|
1224
|
danielebarchiesi@0
|
1225 /**
|
danielebarchiesi@0
|
1226 * Returns the version of the database server.
|
danielebarchiesi@0
|
1227 */
|
danielebarchiesi@0
|
1228 public function version() {
|
danielebarchiesi@0
|
1229 return $this->getAttribute(PDO::ATTR_SERVER_VERSION);
|
danielebarchiesi@0
|
1230 }
|
danielebarchiesi@0
|
1231
|
danielebarchiesi@0
|
1232 /**
|
danielebarchiesi@0
|
1233 * Determines if this driver supports transactions.
|
danielebarchiesi@0
|
1234 *
|
danielebarchiesi@0
|
1235 * @return
|
danielebarchiesi@0
|
1236 * TRUE if this connection supports transactions, FALSE otherwise.
|
danielebarchiesi@0
|
1237 */
|
danielebarchiesi@0
|
1238 public function supportsTransactions() {
|
danielebarchiesi@0
|
1239 return $this->transactionSupport;
|
danielebarchiesi@0
|
1240 }
|
danielebarchiesi@0
|
1241
|
danielebarchiesi@0
|
1242 /**
|
danielebarchiesi@0
|
1243 * Determines if this driver supports transactional DDL.
|
danielebarchiesi@0
|
1244 *
|
danielebarchiesi@0
|
1245 * DDL queries are those that change the schema, such as ALTER queries.
|
danielebarchiesi@0
|
1246 *
|
danielebarchiesi@0
|
1247 * @return
|
danielebarchiesi@0
|
1248 * TRUE if this connection supports transactions for DDL queries, FALSE
|
danielebarchiesi@0
|
1249 * otherwise.
|
danielebarchiesi@0
|
1250 */
|
danielebarchiesi@0
|
1251 public function supportsTransactionalDDL() {
|
danielebarchiesi@0
|
1252 return $this->transactionalDDLSupport;
|
danielebarchiesi@0
|
1253 }
|
danielebarchiesi@0
|
1254
|
danielebarchiesi@0
|
1255 /**
|
danielebarchiesi@0
|
1256 * Returns the name of the PDO driver for this connection.
|
danielebarchiesi@0
|
1257 */
|
danielebarchiesi@0
|
1258 abstract public function databaseType();
|
danielebarchiesi@0
|
1259
|
danielebarchiesi@0
|
1260
|
danielebarchiesi@0
|
1261 /**
|
danielebarchiesi@0
|
1262 * Gets any special processing requirements for the condition operator.
|
danielebarchiesi@0
|
1263 *
|
danielebarchiesi@0
|
1264 * Some condition types require special processing, such as IN, because
|
danielebarchiesi@0
|
1265 * the value data they pass in is not a simple value. This is a simple
|
danielebarchiesi@0
|
1266 * overridable lookup function. Database connections should define only
|
danielebarchiesi@0
|
1267 * those operators they wish to be handled differently than the default.
|
danielebarchiesi@0
|
1268 *
|
danielebarchiesi@0
|
1269 * @param $operator
|
danielebarchiesi@0
|
1270 * The condition operator, such as "IN", "BETWEEN", etc. Case-sensitive.
|
danielebarchiesi@0
|
1271 *
|
danielebarchiesi@0
|
1272 * @return
|
danielebarchiesi@0
|
1273 * The extra handling directives for the specified operator, or NULL.
|
danielebarchiesi@0
|
1274 *
|
danielebarchiesi@0
|
1275 * @see DatabaseCondition::compile()
|
danielebarchiesi@0
|
1276 */
|
danielebarchiesi@0
|
1277 abstract public function mapConditionOperator($operator);
|
danielebarchiesi@0
|
1278
|
danielebarchiesi@0
|
1279 /**
|
danielebarchiesi@0
|
1280 * Throws an exception to deny direct access to transaction commits.
|
danielebarchiesi@0
|
1281 *
|
danielebarchiesi@0
|
1282 * We do not want to allow users to commit transactions at any time, only
|
danielebarchiesi@0
|
1283 * by destroying the transaction object or allowing it to go out of scope.
|
danielebarchiesi@0
|
1284 * A direct commit bypasses all of the safety checks we've built on top of
|
danielebarchiesi@0
|
1285 * PDO's transaction routines.
|
danielebarchiesi@0
|
1286 *
|
danielebarchiesi@0
|
1287 * @throws DatabaseTransactionExplicitCommitNotAllowedException
|
danielebarchiesi@0
|
1288 *
|
danielebarchiesi@0
|
1289 * @see DatabaseTransaction
|
danielebarchiesi@0
|
1290 */
|
danielebarchiesi@0
|
1291 public function commit() {
|
danielebarchiesi@0
|
1292 throw new DatabaseTransactionExplicitCommitNotAllowedException();
|
danielebarchiesi@0
|
1293 }
|
danielebarchiesi@0
|
1294
|
danielebarchiesi@0
|
1295 /**
|
danielebarchiesi@0
|
1296 * Retrieves an unique id from a given sequence.
|
danielebarchiesi@0
|
1297 *
|
danielebarchiesi@0
|
1298 * Use this function if for some reason you can't use a serial field. For
|
danielebarchiesi@0
|
1299 * example, MySQL has no ways of reading of the current value of a sequence
|
danielebarchiesi@0
|
1300 * and PostgreSQL can not advance the sequence to be larger than a given
|
danielebarchiesi@0
|
1301 * value. Or sometimes you just need a unique integer.
|
danielebarchiesi@0
|
1302 *
|
danielebarchiesi@0
|
1303 * @param $existing_id
|
danielebarchiesi@0
|
1304 * After a database import, it might be that the sequences table is behind,
|
danielebarchiesi@0
|
1305 * so by passing in the maximum existing id, it can be assured that we
|
danielebarchiesi@0
|
1306 * never issue the same id.
|
danielebarchiesi@0
|
1307 *
|
danielebarchiesi@0
|
1308 * @return
|
danielebarchiesi@0
|
1309 * An integer number larger than any number returned by earlier calls and
|
danielebarchiesi@0
|
1310 * also larger than the $existing_id if one was passed in.
|
danielebarchiesi@0
|
1311 */
|
danielebarchiesi@0
|
1312 abstract public function nextId($existing_id = 0);
|
danielebarchiesi@0
|
1313 }
|
danielebarchiesi@0
|
1314
|
danielebarchiesi@0
|
1315 /**
|
danielebarchiesi@0
|
1316 * Primary front-controller for the database system.
|
danielebarchiesi@0
|
1317 *
|
danielebarchiesi@0
|
1318 * This class is uninstantiatable and un-extendable. It acts to encapsulate
|
danielebarchiesi@0
|
1319 * all control and shepherding of database connections into a single location
|
danielebarchiesi@0
|
1320 * without the use of globals.
|
danielebarchiesi@0
|
1321 */
|
danielebarchiesi@0
|
1322 abstract class Database {
|
danielebarchiesi@0
|
1323
|
danielebarchiesi@0
|
1324 /**
|
danielebarchiesi@0
|
1325 * Flag to indicate a query call should simply return NULL.
|
danielebarchiesi@0
|
1326 *
|
danielebarchiesi@0
|
1327 * This is used for queries that have no reasonable return value anyway, such
|
danielebarchiesi@0
|
1328 * as INSERT statements to a table without a serial primary key.
|
danielebarchiesi@0
|
1329 */
|
danielebarchiesi@0
|
1330 const RETURN_NULL = 0;
|
danielebarchiesi@0
|
1331
|
danielebarchiesi@0
|
1332 /**
|
danielebarchiesi@0
|
1333 * Flag to indicate a query call should return the prepared statement.
|
danielebarchiesi@0
|
1334 */
|
danielebarchiesi@0
|
1335 const RETURN_STATEMENT = 1;
|
danielebarchiesi@0
|
1336
|
danielebarchiesi@0
|
1337 /**
|
danielebarchiesi@0
|
1338 * Flag to indicate a query call should return the number of affected rows.
|
danielebarchiesi@0
|
1339 */
|
danielebarchiesi@0
|
1340 const RETURN_AFFECTED = 2;
|
danielebarchiesi@0
|
1341
|
danielebarchiesi@0
|
1342 /**
|
danielebarchiesi@0
|
1343 * Flag to indicate a query call should return the "last insert id".
|
danielebarchiesi@0
|
1344 */
|
danielebarchiesi@0
|
1345 const RETURN_INSERT_ID = 3;
|
danielebarchiesi@0
|
1346
|
danielebarchiesi@0
|
1347 /**
|
danielebarchiesi@0
|
1348 * An nested array of all active connections. It is keyed by database name
|
danielebarchiesi@0
|
1349 * and target.
|
danielebarchiesi@0
|
1350 *
|
danielebarchiesi@0
|
1351 * @var array
|
danielebarchiesi@0
|
1352 */
|
danielebarchiesi@0
|
1353 static protected $connections = array();
|
danielebarchiesi@0
|
1354
|
danielebarchiesi@0
|
1355 /**
|
danielebarchiesi@0
|
1356 * A processed copy of the database connection information from settings.php.
|
danielebarchiesi@0
|
1357 *
|
danielebarchiesi@0
|
1358 * @var array
|
danielebarchiesi@0
|
1359 */
|
danielebarchiesi@0
|
1360 static protected $databaseInfo = NULL;
|
danielebarchiesi@0
|
1361
|
danielebarchiesi@0
|
1362 /**
|
danielebarchiesi@0
|
1363 * A list of key/target credentials to simply ignore.
|
danielebarchiesi@0
|
1364 *
|
danielebarchiesi@0
|
1365 * @var array
|
danielebarchiesi@0
|
1366 */
|
danielebarchiesi@0
|
1367 static protected $ignoreTargets = array();
|
danielebarchiesi@0
|
1368
|
danielebarchiesi@0
|
1369 /**
|
danielebarchiesi@0
|
1370 * The key of the currently active database connection.
|
danielebarchiesi@0
|
1371 *
|
danielebarchiesi@0
|
1372 * @var string
|
danielebarchiesi@0
|
1373 */
|
danielebarchiesi@0
|
1374 static protected $activeKey = 'default';
|
danielebarchiesi@0
|
1375
|
danielebarchiesi@0
|
1376 /**
|
danielebarchiesi@0
|
1377 * An array of active query log objects.
|
danielebarchiesi@0
|
1378 *
|
danielebarchiesi@0
|
1379 * Every connection has one and only one logger object for all targets and
|
danielebarchiesi@0
|
1380 * logging keys.
|
danielebarchiesi@0
|
1381 *
|
danielebarchiesi@0
|
1382 * array(
|
danielebarchiesi@0
|
1383 * '$db_key' => DatabaseLog object.
|
danielebarchiesi@0
|
1384 * );
|
danielebarchiesi@0
|
1385 *
|
danielebarchiesi@0
|
1386 * @var array
|
danielebarchiesi@0
|
1387 */
|
danielebarchiesi@0
|
1388 static protected $logs = array();
|
danielebarchiesi@0
|
1389
|
danielebarchiesi@0
|
1390 /**
|
danielebarchiesi@0
|
1391 * Starts logging a given logging key on the specified connection.
|
danielebarchiesi@0
|
1392 *
|
danielebarchiesi@0
|
1393 * @param $logging_key
|
danielebarchiesi@0
|
1394 * The logging key to log.
|
danielebarchiesi@0
|
1395 * @param $key
|
danielebarchiesi@0
|
1396 * The database connection key for which we want to log.
|
danielebarchiesi@0
|
1397 *
|
danielebarchiesi@0
|
1398 * @return DatabaseLog
|
danielebarchiesi@0
|
1399 * The query log object. Note that the log object does support richer
|
danielebarchiesi@0
|
1400 * methods than the few exposed through the Database class, so in some
|
danielebarchiesi@0
|
1401 * cases it may be desirable to access it directly.
|
danielebarchiesi@0
|
1402 *
|
danielebarchiesi@0
|
1403 * @see DatabaseLog
|
danielebarchiesi@0
|
1404 */
|
danielebarchiesi@0
|
1405 final public static function startLog($logging_key, $key = 'default') {
|
danielebarchiesi@0
|
1406 if (empty(self::$logs[$key])) {
|
danielebarchiesi@0
|
1407 self::$logs[$key] = new DatabaseLog($key);
|
danielebarchiesi@0
|
1408
|
danielebarchiesi@0
|
1409 // Every target already active for this connection key needs to have the
|
danielebarchiesi@0
|
1410 // logging object associated with it.
|
danielebarchiesi@0
|
1411 if (!empty(self::$connections[$key])) {
|
danielebarchiesi@0
|
1412 foreach (self::$connections[$key] as $connection) {
|
danielebarchiesi@0
|
1413 $connection->setLogger(self::$logs[$key]);
|
danielebarchiesi@0
|
1414 }
|
danielebarchiesi@0
|
1415 }
|
danielebarchiesi@0
|
1416 }
|
danielebarchiesi@0
|
1417
|
danielebarchiesi@0
|
1418 self::$logs[$key]->start($logging_key);
|
danielebarchiesi@0
|
1419 return self::$logs[$key];
|
danielebarchiesi@0
|
1420 }
|
danielebarchiesi@0
|
1421
|
danielebarchiesi@0
|
1422 /**
|
danielebarchiesi@0
|
1423 * Retrieves the queries logged on for given logging key.
|
danielebarchiesi@0
|
1424 *
|
danielebarchiesi@0
|
1425 * This method also ends logging for the specified key. To get the query log
|
danielebarchiesi@0
|
1426 * to date without ending the logger request the logging object by starting
|
danielebarchiesi@0
|
1427 * it again (which does nothing to an open log key) and call methods on it as
|
danielebarchiesi@0
|
1428 * desired.
|
danielebarchiesi@0
|
1429 *
|
danielebarchiesi@0
|
1430 * @param $logging_key
|
danielebarchiesi@0
|
1431 * The logging key to log.
|
danielebarchiesi@0
|
1432 * @param $key
|
danielebarchiesi@0
|
1433 * The database connection key for which we want to log.
|
danielebarchiesi@0
|
1434 *
|
danielebarchiesi@0
|
1435 * @return array
|
danielebarchiesi@0
|
1436 * The query log for the specified logging key and connection.
|
danielebarchiesi@0
|
1437 *
|
danielebarchiesi@0
|
1438 * @see DatabaseLog
|
danielebarchiesi@0
|
1439 */
|
danielebarchiesi@0
|
1440 final public static function getLog($logging_key, $key = 'default') {
|
danielebarchiesi@0
|
1441 if (empty(self::$logs[$key])) {
|
danielebarchiesi@0
|
1442 return NULL;
|
danielebarchiesi@0
|
1443 }
|
danielebarchiesi@0
|
1444 $queries = self::$logs[$key]->get($logging_key);
|
danielebarchiesi@0
|
1445 self::$logs[$key]->end($logging_key);
|
danielebarchiesi@0
|
1446 return $queries;
|
danielebarchiesi@0
|
1447 }
|
danielebarchiesi@0
|
1448
|
danielebarchiesi@0
|
1449 /**
|
danielebarchiesi@0
|
1450 * Gets the connection object for the specified database key and target.
|
danielebarchiesi@0
|
1451 *
|
danielebarchiesi@0
|
1452 * @param $target
|
danielebarchiesi@0
|
1453 * The database target name.
|
danielebarchiesi@0
|
1454 * @param $key
|
danielebarchiesi@0
|
1455 * The database connection key. Defaults to NULL which means the active key.
|
danielebarchiesi@0
|
1456 *
|
danielebarchiesi@0
|
1457 * @return DatabaseConnection
|
danielebarchiesi@0
|
1458 * The corresponding connection object.
|
danielebarchiesi@0
|
1459 */
|
danielebarchiesi@0
|
1460 final public static function getConnection($target = 'default', $key = NULL) {
|
danielebarchiesi@0
|
1461 if (!isset($key)) {
|
danielebarchiesi@0
|
1462 // By default, we want the active connection, set in setActiveConnection.
|
danielebarchiesi@0
|
1463 $key = self::$activeKey;
|
danielebarchiesi@0
|
1464 }
|
danielebarchiesi@0
|
1465 // If the requested target does not exist, or if it is ignored, we fall back
|
danielebarchiesi@0
|
1466 // to the default target. The target is typically either "default" or
|
danielebarchiesi@0
|
1467 // "slave", indicating to use a slave SQL server if one is available. If
|
danielebarchiesi@0
|
1468 // it's not available, then the default/master server is the correct server
|
danielebarchiesi@0
|
1469 // to use.
|
danielebarchiesi@0
|
1470 if (!empty(self::$ignoreTargets[$key][$target]) || !isset(self::$databaseInfo[$key][$target])) {
|
danielebarchiesi@0
|
1471 $target = 'default';
|
danielebarchiesi@0
|
1472 }
|
danielebarchiesi@0
|
1473
|
danielebarchiesi@0
|
1474 if (!isset(self::$connections[$key][$target])) {
|
danielebarchiesi@0
|
1475 // If necessary, a new connection is opened.
|
danielebarchiesi@0
|
1476 self::$connections[$key][$target] = self::openConnection($key, $target);
|
danielebarchiesi@0
|
1477 }
|
danielebarchiesi@0
|
1478 return self::$connections[$key][$target];
|
danielebarchiesi@0
|
1479 }
|
danielebarchiesi@0
|
1480
|
danielebarchiesi@0
|
1481 /**
|
danielebarchiesi@0
|
1482 * Determines if there is an active connection.
|
danielebarchiesi@0
|
1483 *
|
danielebarchiesi@0
|
1484 * Note that this method will return FALSE if no connection has been
|
danielebarchiesi@0
|
1485 * established yet, even if one could be.
|
danielebarchiesi@0
|
1486 *
|
danielebarchiesi@0
|
1487 * @return
|
danielebarchiesi@0
|
1488 * TRUE if there is at least one database connection established, FALSE
|
danielebarchiesi@0
|
1489 * otherwise.
|
danielebarchiesi@0
|
1490 */
|
danielebarchiesi@0
|
1491 final public static function isActiveConnection() {
|
danielebarchiesi@0
|
1492 return !empty(self::$activeKey) && !empty(self::$connections) && !empty(self::$connections[self::$activeKey]);
|
danielebarchiesi@0
|
1493 }
|
danielebarchiesi@0
|
1494
|
danielebarchiesi@0
|
1495 /**
|
danielebarchiesi@0
|
1496 * Sets the active connection to the specified key.
|
danielebarchiesi@0
|
1497 *
|
danielebarchiesi@0
|
1498 * @return
|
danielebarchiesi@0
|
1499 * The previous database connection key.
|
danielebarchiesi@0
|
1500 */
|
danielebarchiesi@0
|
1501 final public static function setActiveConnection($key = 'default') {
|
danielebarchiesi@0
|
1502 if (empty(self::$databaseInfo)) {
|
danielebarchiesi@0
|
1503 self::parseConnectionInfo();
|
danielebarchiesi@0
|
1504 }
|
danielebarchiesi@0
|
1505
|
danielebarchiesi@0
|
1506 if (!empty(self::$databaseInfo[$key])) {
|
danielebarchiesi@0
|
1507 $old_key = self::$activeKey;
|
danielebarchiesi@0
|
1508 self::$activeKey = $key;
|
danielebarchiesi@0
|
1509 return $old_key;
|
danielebarchiesi@0
|
1510 }
|
danielebarchiesi@0
|
1511 }
|
danielebarchiesi@0
|
1512
|
danielebarchiesi@0
|
1513 /**
|
danielebarchiesi@0
|
1514 * Process the configuration file for database information.
|
danielebarchiesi@0
|
1515 */
|
danielebarchiesi@0
|
1516 final public static function parseConnectionInfo() {
|
danielebarchiesi@0
|
1517 global $databases;
|
danielebarchiesi@0
|
1518
|
danielebarchiesi@0
|
1519 $database_info = is_array($databases) ? $databases : array();
|
danielebarchiesi@0
|
1520 foreach ($database_info as $index => $info) {
|
danielebarchiesi@0
|
1521 foreach ($database_info[$index] as $target => $value) {
|
danielebarchiesi@0
|
1522 // If there is no "driver" property, then we assume it's an array of
|
danielebarchiesi@0
|
1523 // possible connections for this target. Pick one at random. That allows
|
danielebarchiesi@0
|
1524 // us to have, for example, multiple slave servers.
|
danielebarchiesi@0
|
1525 if (empty($value['driver'])) {
|
danielebarchiesi@0
|
1526 $database_info[$index][$target] = $database_info[$index][$target][mt_rand(0, count($database_info[$index][$target]) - 1)];
|
danielebarchiesi@0
|
1527 }
|
danielebarchiesi@0
|
1528
|
danielebarchiesi@0
|
1529 // Parse the prefix information.
|
danielebarchiesi@0
|
1530 if (!isset($database_info[$index][$target]['prefix'])) {
|
danielebarchiesi@0
|
1531 // Default to an empty prefix.
|
danielebarchiesi@0
|
1532 $database_info[$index][$target]['prefix'] = array(
|
danielebarchiesi@0
|
1533 'default' => '',
|
danielebarchiesi@0
|
1534 );
|
danielebarchiesi@0
|
1535 }
|
danielebarchiesi@0
|
1536 elseif (!is_array($database_info[$index][$target]['prefix'])) {
|
danielebarchiesi@0
|
1537 // Transform the flat form into an array form.
|
danielebarchiesi@0
|
1538 $database_info[$index][$target]['prefix'] = array(
|
danielebarchiesi@0
|
1539 'default' => $database_info[$index][$target]['prefix'],
|
danielebarchiesi@0
|
1540 );
|
danielebarchiesi@0
|
1541 }
|
danielebarchiesi@0
|
1542 }
|
danielebarchiesi@0
|
1543 }
|
danielebarchiesi@0
|
1544
|
danielebarchiesi@0
|
1545 if (!is_array(self::$databaseInfo)) {
|
danielebarchiesi@0
|
1546 self::$databaseInfo = $database_info;
|
danielebarchiesi@0
|
1547 }
|
danielebarchiesi@0
|
1548
|
danielebarchiesi@0
|
1549 // Merge the new $database_info into the existing.
|
danielebarchiesi@0
|
1550 // array_merge_recursive() cannot be used, as it would make multiple
|
danielebarchiesi@0
|
1551 // database, user, and password keys in the same database array.
|
danielebarchiesi@0
|
1552 else {
|
danielebarchiesi@0
|
1553 foreach ($database_info as $database_key => $database_values) {
|
danielebarchiesi@0
|
1554 foreach ($database_values as $target => $target_values) {
|
danielebarchiesi@0
|
1555 self::$databaseInfo[$database_key][$target] = $target_values;
|
danielebarchiesi@0
|
1556 }
|
danielebarchiesi@0
|
1557 }
|
danielebarchiesi@0
|
1558 }
|
danielebarchiesi@0
|
1559 }
|
danielebarchiesi@0
|
1560
|
danielebarchiesi@0
|
1561 /**
|
danielebarchiesi@0
|
1562 * Adds database connection information for a given key/target.
|
danielebarchiesi@0
|
1563 *
|
danielebarchiesi@0
|
1564 * This method allows the addition of new connection credentials at runtime.
|
danielebarchiesi@0
|
1565 * Under normal circumstances the preferred way to specify database
|
danielebarchiesi@0
|
1566 * credentials is via settings.php. However, this method allows them to be
|
danielebarchiesi@0
|
1567 * added at arbitrary times, such as during unit tests, when connecting to
|
danielebarchiesi@0
|
1568 * admin-defined third party databases, etc.
|
danielebarchiesi@0
|
1569 *
|
danielebarchiesi@0
|
1570 * If the given key/target pair already exists, this method will be ignored.
|
danielebarchiesi@0
|
1571 *
|
danielebarchiesi@0
|
1572 * @param $key
|
danielebarchiesi@0
|
1573 * The database key.
|
danielebarchiesi@0
|
1574 * @param $target
|
danielebarchiesi@0
|
1575 * The database target name.
|
danielebarchiesi@0
|
1576 * @param $info
|
danielebarchiesi@0
|
1577 * The database connection information, as it would be defined in
|
danielebarchiesi@0
|
1578 * settings.php. Note that the structure of this array will depend on the
|
danielebarchiesi@0
|
1579 * database driver it is connecting to.
|
danielebarchiesi@0
|
1580 */
|
danielebarchiesi@0
|
1581 public static function addConnectionInfo($key, $target, $info) {
|
danielebarchiesi@0
|
1582 if (empty(self::$databaseInfo[$key][$target])) {
|
danielebarchiesi@0
|
1583 self::$databaseInfo[$key][$target] = $info;
|
danielebarchiesi@0
|
1584 }
|
danielebarchiesi@0
|
1585 }
|
danielebarchiesi@0
|
1586
|
danielebarchiesi@0
|
1587 /**
|
danielebarchiesi@0
|
1588 * Gets information on the specified database connection.
|
danielebarchiesi@0
|
1589 *
|
danielebarchiesi@0
|
1590 * @param $connection
|
danielebarchiesi@0
|
1591 * The connection key for which we want information.
|
danielebarchiesi@0
|
1592 */
|
danielebarchiesi@0
|
1593 final public static function getConnectionInfo($key = 'default') {
|
danielebarchiesi@0
|
1594 if (empty(self::$databaseInfo)) {
|
danielebarchiesi@0
|
1595 self::parseConnectionInfo();
|
danielebarchiesi@0
|
1596 }
|
danielebarchiesi@0
|
1597
|
danielebarchiesi@0
|
1598 if (!empty(self::$databaseInfo[$key])) {
|
danielebarchiesi@0
|
1599 return self::$databaseInfo[$key];
|
danielebarchiesi@0
|
1600 }
|
danielebarchiesi@0
|
1601 }
|
danielebarchiesi@0
|
1602
|
danielebarchiesi@0
|
1603 /**
|
danielebarchiesi@0
|
1604 * Rename a connection and its corresponding connection information.
|
danielebarchiesi@0
|
1605 *
|
danielebarchiesi@0
|
1606 * @param $old_key
|
danielebarchiesi@0
|
1607 * The old connection key.
|
danielebarchiesi@0
|
1608 * @param $new_key
|
danielebarchiesi@0
|
1609 * The new connection key.
|
danielebarchiesi@0
|
1610 * @return
|
danielebarchiesi@0
|
1611 * TRUE in case of success, FALSE otherwise.
|
danielebarchiesi@0
|
1612 */
|
danielebarchiesi@0
|
1613 final public static function renameConnection($old_key, $new_key) {
|
danielebarchiesi@0
|
1614 if (empty(self::$databaseInfo)) {
|
danielebarchiesi@0
|
1615 self::parseConnectionInfo();
|
danielebarchiesi@0
|
1616 }
|
danielebarchiesi@0
|
1617
|
danielebarchiesi@0
|
1618 if (!empty(self::$databaseInfo[$old_key]) && empty(self::$databaseInfo[$new_key])) {
|
danielebarchiesi@0
|
1619 // Migrate the database connection information.
|
danielebarchiesi@0
|
1620 self::$databaseInfo[$new_key] = self::$databaseInfo[$old_key];
|
danielebarchiesi@0
|
1621 unset(self::$databaseInfo[$old_key]);
|
danielebarchiesi@0
|
1622
|
danielebarchiesi@0
|
1623 // Migrate over the DatabaseConnection object if it exists.
|
danielebarchiesi@0
|
1624 if (isset(self::$connections[$old_key])) {
|
danielebarchiesi@0
|
1625 self::$connections[$new_key] = self::$connections[$old_key];
|
danielebarchiesi@0
|
1626 unset(self::$connections[$old_key]);
|
danielebarchiesi@0
|
1627 }
|
danielebarchiesi@0
|
1628
|
danielebarchiesi@0
|
1629 return TRUE;
|
danielebarchiesi@0
|
1630 }
|
danielebarchiesi@0
|
1631 else {
|
danielebarchiesi@0
|
1632 return FALSE;
|
danielebarchiesi@0
|
1633 }
|
danielebarchiesi@0
|
1634 }
|
danielebarchiesi@0
|
1635
|
danielebarchiesi@0
|
1636 /**
|
danielebarchiesi@0
|
1637 * Remove a connection and its corresponding connection information.
|
danielebarchiesi@0
|
1638 *
|
danielebarchiesi@0
|
1639 * @param $key
|
danielebarchiesi@0
|
1640 * The connection key.
|
danielebarchiesi@0
|
1641 * @return
|
danielebarchiesi@0
|
1642 * TRUE in case of success, FALSE otherwise.
|
danielebarchiesi@0
|
1643 */
|
danielebarchiesi@0
|
1644 final public static function removeConnection($key) {
|
danielebarchiesi@0
|
1645 if (isset(self::$databaseInfo[$key])) {
|
danielebarchiesi@0
|
1646 self::closeConnection(NULL, $key);
|
danielebarchiesi@0
|
1647 unset(self::$databaseInfo[$key]);
|
danielebarchiesi@0
|
1648 return TRUE;
|
danielebarchiesi@0
|
1649 }
|
danielebarchiesi@0
|
1650 else {
|
danielebarchiesi@0
|
1651 return FALSE;
|
danielebarchiesi@0
|
1652 }
|
danielebarchiesi@0
|
1653 }
|
danielebarchiesi@0
|
1654
|
danielebarchiesi@0
|
1655 /**
|
danielebarchiesi@0
|
1656 * Opens a connection to the server specified by the given key and target.
|
danielebarchiesi@0
|
1657 *
|
danielebarchiesi@0
|
1658 * @param $key
|
danielebarchiesi@0
|
1659 * The database connection key, as specified in settings.php. The default is
|
danielebarchiesi@0
|
1660 * "default".
|
danielebarchiesi@0
|
1661 * @param $target
|
danielebarchiesi@0
|
1662 * The database target to open.
|
danielebarchiesi@0
|
1663 *
|
danielebarchiesi@0
|
1664 * @throws DatabaseConnectionNotDefinedException
|
danielebarchiesi@0
|
1665 * @throws DatabaseDriverNotSpecifiedException
|
danielebarchiesi@0
|
1666 */
|
danielebarchiesi@0
|
1667 final protected static function openConnection($key, $target) {
|
danielebarchiesi@0
|
1668 if (empty(self::$databaseInfo)) {
|
danielebarchiesi@0
|
1669 self::parseConnectionInfo();
|
danielebarchiesi@0
|
1670 }
|
danielebarchiesi@0
|
1671
|
danielebarchiesi@0
|
1672 // If the requested database does not exist then it is an unrecoverable
|
danielebarchiesi@0
|
1673 // error.
|
danielebarchiesi@0
|
1674 if (!isset(self::$databaseInfo[$key])) {
|
danielebarchiesi@0
|
1675 throw new DatabaseConnectionNotDefinedException('The specified database connection is not defined: ' . $key);
|
danielebarchiesi@0
|
1676 }
|
danielebarchiesi@0
|
1677
|
danielebarchiesi@0
|
1678 if (!$driver = self::$databaseInfo[$key][$target]['driver']) {
|
danielebarchiesi@0
|
1679 throw new DatabaseDriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
|
danielebarchiesi@0
|
1680 }
|
danielebarchiesi@0
|
1681
|
danielebarchiesi@0
|
1682 // We cannot rely on the registry yet, because the registry requires an
|
danielebarchiesi@0
|
1683 // open database connection.
|
danielebarchiesi@0
|
1684 $driver_class = 'DatabaseConnection_' . $driver;
|
danielebarchiesi@0
|
1685 require_once DRUPAL_ROOT . '/includes/database/' . $driver . '/database.inc';
|
danielebarchiesi@0
|
1686 $new_connection = new $driver_class(self::$databaseInfo[$key][$target]);
|
danielebarchiesi@0
|
1687 $new_connection->setTarget($target);
|
danielebarchiesi@0
|
1688 $new_connection->setKey($key);
|
danielebarchiesi@0
|
1689
|
danielebarchiesi@0
|
1690 // If we have any active logging objects for this connection key, we need
|
danielebarchiesi@0
|
1691 // to associate them with the connection we just opened.
|
danielebarchiesi@0
|
1692 if (!empty(self::$logs[$key])) {
|
danielebarchiesi@0
|
1693 $new_connection->setLogger(self::$logs[$key]);
|
danielebarchiesi@0
|
1694 }
|
danielebarchiesi@0
|
1695
|
danielebarchiesi@0
|
1696 return $new_connection;
|
danielebarchiesi@0
|
1697 }
|
danielebarchiesi@0
|
1698
|
danielebarchiesi@0
|
1699 /**
|
danielebarchiesi@0
|
1700 * Closes a connection to the server specified by the given key and target.
|
danielebarchiesi@0
|
1701 *
|
danielebarchiesi@0
|
1702 * @param $target
|
danielebarchiesi@0
|
1703 * The database target name. Defaults to NULL meaning that all target
|
danielebarchiesi@0
|
1704 * connections will be closed.
|
danielebarchiesi@0
|
1705 * @param $key
|
danielebarchiesi@0
|
1706 * The database connection key. Defaults to NULL which means the active key.
|
danielebarchiesi@0
|
1707 */
|
danielebarchiesi@0
|
1708 public static function closeConnection($target = NULL, $key = NULL) {
|
danielebarchiesi@0
|
1709 // Gets the active connection by default.
|
danielebarchiesi@0
|
1710 if (!isset($key)) {
|
danielebarchiesi@0
|
1711 $key = self::$activeKey;
|
danielebarchiesi@0
|
1712 }
|
danielebarchiesi@0
|
1713 // To close a connection, it needs to be set to NULL and removed from the
|
danielebarchiesi@0
|
1714 // static variable. In all cases, closeConnection() might be called for a
|
danielebarchiesi@0
|
1715 // connection that was not opened yet, in which case the key is not defined
|
danielebarchiesi@0
|
1716 // yet and we just ensure that the connection key is undefined.
|
danielebarchiesi@0
|
1717 if (isset($target)) {
|
danielebarchiesi@0
|
1718 if (isset(self::$connections[$key][$target])) {
|
danielebarchiesi@0
|
1719 self::$connections[$key][$target]->destroy();
|
danielebarchiesi@0
|
1720 self::$connections[$key][$target] = NULL;
|
danielebarchiesi@0
|
1721 }
|
danielebarchiesi@0
|
1722 unset(self::$connections[$key][$target]);
|
danielebarchiesi@0
|
1723 }
|
danielebarchiesi@0
|
1724 else {
|
danielebarchiesi@0
|
1725 if (isset(self::$connections[$key])) {
|
danielebarchiesi@0
|
1726 foreach (self::$connections[$key] as $target => $connection) {
|
danielebarchiesi@0
|
1727 self::$connections[$key][$target]->destroy();
|
danielebarchiesi@0
|
1728 self::$connections[$key][$target] = NULL;
|
danielebarchiesi@0
|
1729 }
|
danielebarchiesi@0
|
1730 }
|
danielebarchiesi@0
|
1731 unset(self::$connections[$key]);
|
danielebarchiesi@0
|
1732 }
|
danielebarchiesi@0
|
1733 }
|
danielebarchiesi@0
|
1734
|
danielebarchiesi@0
|
1735 /**
|
danielebarchiesi@0
|
1736 * Instructs the system to temporarily ignore a given key/target.
|
danielebarchiesi@0
|
1737 *
|
danielebarchiesi@0
|
1738 * At times we need to temporarily disable slave queries. To do so, call this
|
danielebarchiesi@0
|
1739 * method with the database key and the target to disable. That database key
|
danielebarchiesi@0
|
1740 * will then always fall back to 'default' for that key, even if it's defined.
|
danielebarchiesi@0
|
1741 *
|
danielebarchiesi@0
|
1742 * @param $key
|
danielebarchiesi@0
|
1743 * The database connection key.
|
danielebarchiesi@0
|
1744 * @param $target
|
danielebarchiesi@0
|
1745 * The target of the specified key to ignore.
|
danielebarchiesi@0
|
1746 */
|
danielebarchiesi@0
|
1747 public static function ignoreTarget($key, $target) {
|
danielebarchiesi@0
|
1748 self::$ignoreTargets[$key][$target] = TRUE;
|
danielebarchiesi@0
|
1749 }
|
danielebarchiesi@0
|
1750
|
danielebarchiesi@0
|
1751 /**
|
danielebarchiesi@0
|
1752 * Load a file for the database that might hold a class.
|
danielebarchiesi@0
|
1753 *
|
danielebarchiesi@0
|
1754 * @param $driver
|
danielebarchiesi@0
|
1755 * The name of the driver.
|
danielebarchiesi@0
|
1756 * @param array $files
|
danielebarchiesi@0
|
1757 * The name of the files the driver specific class can be.
|
danielebarchiesi@0
|
1758 */
|
danielebarchiesi@0
|
1759 public static function loadDriverFile($driver, array $files = array()) {
|
danielebarchiesi@0
|
1760 static $base_path;
|
danielebarchiesi@0
|
1761
|
danielebarchiesi@0
|
1762 if (empty($base_path)) {
|
danielebarchiesi@0
|
1763 $base_path = dirname(realpath(__FILE__));
|
danielebarchiesi@0
|
1764 }
|
danielebarchiesi@0
|
1765
|
danielebarchiesi@0
|
1766 $driver_base_path = "$base_path/$driver";
|
danielebarchiesi@0
|
1767 foreach ($files as $file) {
|
danielebarchiesi@0
|
1768 // Load the base file first so that classes extending base classes will
|
danielebarchiesi@0
|
1769 // have the base class loaded.
|
danielebarchiesi@0
|
1770 foreach (array("$base_path/$file", "$driver_base_path/$file") as $filename) {
|
danielebarchiesi@0
|
1771 // The OS caches file_exists() and PHP caches require_once(), so
|
danielebarchiesi@0
|
1772 // we'll let both of those take care of performance here.
|
danielebarchiesi@0
|
1773 if (file_exists($filename)) {
|
danielebarchiesi@0
|
1774 require_once $filename;
|
danielebarchiesi@0
|
1775 }
|
danielebarchiesi@0
|
1776 }
|
danielebarchiesi@0
|
1777 }
|
danielebarchiesi@0
|
1778 }
|
danielebarchiesi@0
|
1779 }
|
danielebarchiesi@0
|
1780
|
danielebarchiesi@0
|
1781 /**
|
danielebarchiesi@0
|
1782 * Exception for when popTransaction() is called with no active transaction.
|
danielebarchiesi@0
|
1783 */
|
danielebarchiesi@0
|
1784 class DatabaseTransactionNoActiveException extends Exception { }
|
danielebarchiesi@0
|
1785
|
danielebarchiesi@0
|
1786 /**
|
danielebarchiesi@0
|
1787 * Exception thrown when a savepoint or transaction name occurs twice.
|
danielebarchiesi@0
|
1788 */
|
danielebarchiesi@0
|
1789 class DatabaseTransactionNameNonUniqueException extends Exception { }
|
danielebarchiesi@0
|
1790
|
danielebarchiesi@0
|
1791 /**
|
danielebarchiesi@0
|
1792 * Exception thrown when a commit() function fails.
|
danielebarchiesi@0
|
1793 */
|
danielebarchiesi@0
|
1794 class DatabaseTransactionCommitFailedException extends Exception { }
|
danielebarchiesi@0
|
1795
|
danielebarchiesi@0
|
1796 /**
|
danielebarchiesi@0
|
1797 * Exception to deny attempts to explicitly manage transactions.
|
danielebarchiesi@0
|
1798 *
|
danielebarchiesi@0
|
1799 * This exception will be thrown when the PDO connection commit() is called.
|
danielebarchiesi@0
|
1800 * Code should never call this method directly.
|
danielebarchiesi@0
|
1801 */
|
danielebarchiesi@0
|
1802 class DatabaseTransactionExplicitCommitNotAllowedException extends Exception { }
|
danielebarchiesi@0
|
1803
|
danielebarchiesi@0
|
1804 /**
|
danielebarchiesi@0
|
1805 * Exception thrown when a rollback() resulted in other active transactions being rolled-back.
|
danielebarchiesi@0
|
1806 */
|
danielebarchiesi@0
|
1807 class DatabaseTransactionOutOfOrderException extends Exception { }
|
danielebarchiesi@0
|
1808
|
danielebarchiesi@0
|
1809 /**
|
danielebarchiesi@0
|
1810 * Exception thrown for merge queries that do not make semantic sense.
|
danielebarchiesi@0
|
1811 *
|
danielebarchiesi@0
|
1812 * There are many ways that a merge query could be malformed. They should all
|
danielebarchiesi@0
|
1813 * throw this exception and set an appropriately descriptive message.
|
danielebarchiesi@0
|
1814 */
|
danielebarchiesi@0
|
1815 class InvalidMergeQueryException extends Exception {}
|
danielebarchiesi@0
|
1816
|
danielebarchiesi@0
|
1817 /**
|
danielebarchiesi@0
|
1818 * Exception thrown if an insert query specifies a field twice.
|
danielebarchiesi@0
|
1819 *
|
danielebarchiesi@0
|
1820 * It is not allowed to specify a field as default and insert field, this
|
danielebarchiesi@0
|
1821 * exception is thrown if that is the case.
|
danielebarchiesi@0
|
1822 */
|
danielebarchiesi@0
|
1823 class FieldsOverlapException extends Exception {}
|
danielebarchiesi@0
|
1824
|
danielebarchiesi@0
|
1825 /**
|
danielebarchiesi@0
|
1826 * Exception thrown if an insert query doesn't specify insert or default fields.
|
danielebarchiesi@0
|
1827 */
|
danielebarchiesi@0
|
1828 class NoFieldsException extends Exception {}
|
danielebarchiesi@0
|
1829
|
danielebarchiesi@0
|
1830 /**
|
danielebarchiesi@0
|
1831 * Exception thrown if an undefined database connection is requested.
|
danielebarchiesi@0
|
1832 */
|
danielebarchiesi@0
|
1833 class DatabaseConnectionNotDefinedException extends Exception {}
|
danielebarchiesi@0
|
1834
|
danielebarchiesi@0
|
1835 /**
|
danielebarchiesi@0
|
1836 * Exception thrown if no driver is specified for a database connection.
|
danielebarchiesi@0
|
1837 */
|
danielebarchiesi@0
|
1838 class DatabaseDriverNotSpecifiedException extends Exception {}
|
danielebarchiesi@0
|
1839
|
danielebarchiesi@0
|
1840
|
danielebarchiesi@0
|
1841 /**
|
danielebarchiesi@0
|
1842 * A wrapper class for creating and managing database transactions.
|
danielebarchiesi@0
|
1843 *
|
danielebarchiesi@0
|
1844 * Not all databases or database configurations support transactions. For
|
danielebarchiesi@0
|
1845 * example, MySQL MyISAM tables do not. It is also easy to begin a transaction
|
danielebarchiesi@0
|
1846 * and then forget to commit it, which can lead to connection errors when
|
danielebarchiesi@0
|
1847 * another transaction is started.
|
danielebarchiesi@0
|
1848 *
|
danielebarchiesi@0
|
1849 * This class acts as a wrapper for transactions. To begin a transaction,
|
danielebarchiesi@0
|
1850 * simply instantiate it. When the object goes out of scope and is destroyed
|
danielebarchiesi@0
|
1851 * it will automatically commit. It also will check to see if the specified
|
danielebarchiesi@0
|
1852 * connection supports transactions. If not, it will simply skip any transaction
|
danielebarchiesi@0
|
1853 * commands, allowing user-space code to proceed normally. The only difference
|
danielebarchiesi@0
|
1854 * is that rollbacks won't actually do anything.
|
danielebarchiesi@0
|
1855 *
|
danielebarchiesi@0
|
1856 * In the vast majority of cases, you should not instantiate this class
|
danielebarchiesi@0
|
1857 * directly. Instead, call ->startTransaction(), from the appropriate connection
|
danielebarchiesi@0
|
1858 * object.
|
danielebarchiesi@0
|
1859 */
|
danielebarchiesi@0
|
1860 class DatabaseTransaction {
|
danielebarchiesi@0
|
1861
|
danielebarchiesi@0
|
1862 /**
|
danielebarchiesi@0
|
1863 * The connection object for this transaction.
|
danielebarchiesi@0
|
1864 *
|
danielebarchiesi@0
|
1865 * @var DatabaseConnection
|
danielebarchiesi@0
|
1866 */
|
danielebarchiesi@0
|
1867 protected $connection;
|
danielebarchiesi@0
|
1868
|
danielebarchiesi@0
|
1869 /**
|
danielebarchiesi@0
|
1870 * A boolean value to indicate whether this transaction has been rolled back.
|
danielebarchiesi@0
|
1871 *
|
danielebarchiesi@0
|
1872 * @var Boolean
|
danielebarchiesi@0
|
1873 */
|
danielebarchiesi@0
|
1874 protected $rolledBack = FALSE;
|
danielebarchiesi@0
|
1875
|
danielebarchiesi@0
|
1876 /**
|
danielebarchiesi@0
|
1877 * The name of the transaction.
|
danielebarchiesi@0
|
1878 *
|
danielebarchiesi@0
|
1879 * This is used to label the transaction savepoint. It will be overridden to
|
danielebarchiesi@0
|
1880 * 'drupal_transaction' if there is no transaction depth.
|
danielebarchiesi@0
|
1881 */
|
danielebarchiesi@0
|
1882 protected $name;
|
danielebarchiesi@0
|
1883
|
danielebarchiesi@0
|
1884 public function __construct(DatabaseConnection $connection, $name = NULL) {
|
danielebarchiesi@0
|
1885 $this->connection = $connection;
|
danielebarchiesi@0
|
1886 // If there is no transaction depth, then no transaction has started. Name
|
danielebarchiesi@0
|
1887 // the transaction 'drupal_transaction'.
|
danielebarchiesi@0
|
1888 if (!$depth = $connection->transactionDepth()) {
|
danielebarchiesi@0
|
1889 $this->name = 'drupal_transaction';
|
danielebarchiesi@0
|
1890 }
|
danielebarchiesi@0
|
1891 // Within transactions, savepoints are used. Each savepoint requires a
|
danielebarchiesi@0
|
1892 // name. So if no name is present we need to create one.
|
danielebarchiesi@0
|
1893 elseif (!$name) {
|
danielebarchiesi@0
|
1894 $this->name = 'savepoint_' . $depth;
|
danielebarchiesi@0
|
1895 }
|
danielebarchiesi@0
|
1896 else {
|
danielebarchiesi@0
|
1897 $this->name = $name;
|
danielebarchiesi@0
|
1898 }
|
danielebarchiesi@0
|
1899 $this->connection->pushTransaction($this->name);
|
danielebarchiesi@0
|
1900 }
|
danielebarchiesi@0
|
1901
|
danielebarchiesi@0
|
1902 public function __destruct() {
|
danielebarchiesi@0
|
1903 // If we rolled back then the transaction would have already been popped.
|
danielebarchiesi@0
|
1904 if (!$this->rolledBack) {
|
danielebarchiesi@0
|
1905 $this->connection->popTransaction($this->name);
|
danielebarchiesi@0
|
1906 }
|
danielebarchiesi@0
|
1907 }
|
danielebarchiesi@0
|
1908
|
danielebarchiesi@0
|
1909 /**
|
danielebarchiesi@0
|
1910 * Retrieves the name of the transaction or savepoint.
|
danielebarchiesi@0
|
1911 */
|
danielebarchiesi@0
|
1912 public function name() {
|
danielebarchiesi@0
|
1913 return $this->name;
|
danielebarchiesi@0
|
1914 }
|
danielebarchiesi@0
|
1915
|
danielebarchiesi@0
|
1916 /**
|
danielebarchiesi@0
|
1917 * Rolls back the current transaction.
|
danielebarchiesi@0
|
1918 *
|
danielebarchiesi@0
|
1919 * This is just a wrapper method to rollback whatever transaction stack we are
|
danielebarchiesi@0
|
1920 * currently in, which is managed by the connection object itself. Note that
|
danielebarchiesi@0
|
1921 * logging (preferable with watchdog_exception()) needs to happen after a
|
danielebarchiesi@0
|
1922 * transaction has been rolled back or the log messages will be rolled back
|
danielebarchiesi@0
|
1923 * too.
|
danielebarchiesi@0
|
1924 *
|
danielebarchiesi@0
|
1925 * @see DatabaseConnection::rollback()
|
danielebarchiesi@0
|
1926 * @see watchdog_exception()
|
danielebarchiesi@0
|
1927 */
|
danielebarchiesi@0
|
1928 public function rollback() {
|
danielebarchiesi@0
|
1929 $this->rolledBack = TRUE;
|
danielebarchiesi@0
|
1930 $this->connection->rollback($this->name);
|
danielebarchiesi@0
|
1931 }
|
danielebarchiesi@0
|
1932 }
|
danielebarchiesi@0
|
1933
|
danielebarchiesi@0
|
1934 /**
|
danielebarchiesi@0
|
1935 * Represents a prepared statement.
|
danielebarchiesi@0
|
1936 *
|
danielebarchiesi@0
|
1937 * Some methods in that class are purposefully commented out. Due to a change in
|
danielebarchiesi@0
|
1938 * how PHP defines PDOStatement, we can't define a signature for those methods
|
danielebarchiesi@0
|
1939 * that will work the same way between versions older than 5.2.6 and later
|
danielebarchiesi@0
|
1940 * versions. See http://bugs.php.net/bug.php?id=42452 for more details.
|
danielebarchiesi@0
|
1941 *
|
danielebarchiesi@0
|
1942 * Child implementations should either extend PDOStatement:
|
danielebarchiesi@0
|
1943 * @code
|
danielebarchiesi@0
|
1944 * class DatabaseStatement_oracle extends PDOStatement implements DatabaseStatementInterface {}
|
danielebarchiesi@0
|
1945 * @endcode
|
danielebarchiesi@0
|
1946 * or define their own class. If defining their own class, they will also have
|
danielebarchiesi@0
|
1947 * to implement either the Iterator or IteratorAggregate interface before
|
danielebarchiesi@0
|
1948 * DatabaseStatementInterface:
|
danielebarchiesi@0
|
1949 * @code
|
danielebarchiesi@0
|
1950 * class DatabaseStatement_oracle implements Iterator, DatabaseStatementInterface {}
|
danielebarchiesi@0
|
1951 * @endcode
|
danielebarchiesi@0
|
1952 */
|
danielebarchiesi@0
|
1953 interface DatabaseStatementInterface extends Traversable {
|
danielebarchiesi@0
|
1954
|
danielebarchiesi@0
|
1955 /**
|
danielebarchiesi@0
|
1956 * Executes a prepared statement
|
danielebarchiesi@0
|
1957 *
|
danielebarchiesi@0
|
1958 * @param $args
|
danielebarchiesi@0
|
1959 * An array of values with as many elements as there are bound parameters in
|
danielebarchiesi@0
|
1960 * the SQL statement being executed.
|
danielebarchiesi@0
|
1961 * @param $options
|
danielebarchiesi@0
|
1962 * An array of options for this query.
|
danielebarchiesi@0
|
1963 *
|
danielebarchiesi@0
|
1964 * @return
|
danielebarchiesi@0
|
1965 * TRUE on success, or FALSE on failure.
|
danielebarchiesi@0
|
1966 */
|
danielebarchiesi@0
|
1967 public function execute($args = array(), $options = array());
|
danielebarchiesi@0
|
1968
|
danielebarchiesi@0
|
1969 /**
|
danielebarchiesi@0
|
1970 * Gets the query string of this statement.
|
danielebarchiesi@0
|
1971 *
|
danielebarchiesi@0
|
1972 * @return
|
danielebarchiesi@0
|
1973 * The query string, in its form with placeholders.
|
danielebarchiesi@0
|
1974 */
|
danielebarchiesi@0
|
1975 public function getQueryString();
|
danielebarchiesi@0
|
1976
|
danielebarchiesi@0
|
1977 /**
|
danielebarchiesi@0
|
1978 * Returns the number of rows affected by the last SQL statement.
|
danielebarchiesi@0
|
1979 *
|
danielebarchiesi@0
|
1980 * @return
|
danielebarchiesi@0
|
1981 * The number of rows affected by the last DELETE, INSERT, or UPDATE
|
danielebarchiesi@0
|
1982 * statement executed.
|
danielebarchiesi@0
|
1983 */
|
danielebarchiesi@0
|
1984 public function rowCount();
|
danielebarchiesi@0
|
1985
|
danielebarchiesi@0
|
1986 /**
|
danielebarchiesi@0
|
1987 * Sets the default fetch mode for this statement.
|
danielebarchiesi@0
|
1988 *
|
danielebarchiesi@0
|
1989 * See http://php.net/manual/en/pdo.constants.php for the definition of the
|
danielebarchiesi@0
|
1990 * constants used.
|
danielebarchiesi@0
|
1991 *
|
danielebarchiesi@0
|
1992 * @param $mode
|
danielebarchiesi@0
|
1993 * One of the PDO::FETCH_* constants.
|
danielebarchiesi@0
|
1994 * @param $a1
|
danielebarchiesi@0
|
1995 * An option depending of the fetch mode specified by $mode:
|
danielebarchiesi@0
|
1996 * - for PDO::FETCH_COLUMN, the index of the column to fetch
|
danielebarchiesi@0
|
1997 * - for PDO::FETCH_CLASS, the name of the class to create
|
danielebarchiesi@0
|
1998 * - for PDO::FETCH_INTO, the object to add the data to
|
danielebarchiesi@0
|
1999 * @param $a2
|
danielebarchiesi@0
|
2000 * If $mode is PDO::FETCH_CLASS, the optional arguments to pass to the
|
danielebarchiesi@0
|
2001 * constructor.
|
danielebarchiesi@0
|
2002 */
|
danielebarchiesi@0
|
2003 // public function setFetchMode($mode, $a1 = NULL, $a2 = array());
|
danielebarchiesi@0
|
2004
|
danielebarchiesi@0
|
2005 /**
|
danielebarchiesi@0
|
2006 * Fetches the next row from a result set.
|
danielebarchiesi@0
|
2007 *
|
danielebarchiesi@0
|
2008 * See http://php.net/manual/en/pdo.constants.php for the definition of the
|
danielebarchiesi@0
|
2009 * constants used.
|
danielebarchiesi@0
|
2010 *
|
danielebarchiesi@0
|
2011 * @param $mode
|
danielebarchiesi@0
|
2012 * One of the PDO::FETCH_* constants.
|
danielebarchiesi@0
|
2013 * Default to what was specified by setFetchMode().
|
danielebarchiesi@0
|
2014 * @param $cursor_orientation
|
danielebarchiesi@0
|
2015 * Not implemented in all database drivers, don't use.
|
danielebarchiesi@0
|
2016 * @param $cursor_offset
|
danielebarchiesi@0
|
2017 * Not implemented in all database drivers, don't use.
|
danielebarchiesi@0
|
2018 *
|
danielebarchiesi@0
|
2019 * @return
|
danielebarchiesi@0
|
2020 * A result, formatted according to $mode.
|
danielebarchiesi@0
|
2021 */
|
danielebarchiesi@0
|
2022 // public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset = NULL);
|
danielebarchiesi@0
|
2023
|
danielebarchiesi@0
|
2024 /**
|
danielebarchiesi@0
|
2025 * Returns a single field from the next record of a result set.
|
danielebarchiesi@0
|
2026 *
|
danielebarchiesi@0
|
2027 * @param $index
|
danielebarchiesi@0
|
2028 * The numeric index of the field to return. Defaults to the first field.
|
danielebarchiesi@0
|
2029 *
|
danielebarchiesi@0
|
2030 * @return
|
danielebarchiesi@0
|
2031 * A single field from the next record, or FALSE if there is no next record.
|
danielebarchiesi@0
|
2032 */
|
danielebarchiesi@0
|
2033 public function fetchField($index = 0);
|
danielebarchiesi@0
|
2034
|
danielebarchiesi@0
|
2035 /**
|
danielebarchiesi@0
|
2036 * Fetches the next row and returns it as an object.
|
danielebarchiesi@0
|
2037 *
|
danielebarchiesi@0
|
2038 * The object will be of the class specified by DatabaseStatementInterface::setFetchMode()
|
danielebarchiesi@0
|
2039 * or stdClass if not specified.
|
danielebarchiesi@0
|
2040 */
|
danielebarchiesi@0
|
2041 // public function fetchObject();
|
danielebarchiesi@0
|
2042
|
danielebarchiesi@0
|
2043 /**
|
danielebarchiesi@0
|
2044 * Fetches the next row and returns it as an associative array.
|
danielebarchiesi@0
|
2045 *
|
danielebarchiesi@0
|
2046 * This method corresponds to PDOStatement::fetchObject(), but for associative
|
danielebarchiesi@0
|
2047 * arrays. For some reason PDOStatement does not have a corresponding array
|
danielebarchiesi@0
|
2048 * helper method, so one is added.
|
danielebarchiesi@0
|
2049 *
|
danielebarchiesi@0
|
2050 * @return
|
danielebarchiesi@0
|
2051 * An associative array, or FALSE if there is no next row.
|
danielebarchiesi@0
|
2052 */
|
danielebarchiesi@0
|
2053 public function fetchAssoc();
|
danielebarchiesi@0
|
2054
|
danielebarchiesi@0
|
2055 /**
|
danielebarchiesi@0
|
2056 * Returns an array containing all of the result set rows.
|
danielebarchiesi@0
|
2057 *
|
danielebarchiesi@0
|
2058 * @param $mode
|
danielebarchiesi@0
|
2059 * One of the PDO::FETCH_* constants.
|
danielebarchiesi@0
|
2060 * @param $column_index
|
danielebarchiesi@0
|
2061 * If $mode is PDO::FETCH_COLUMN, the index of the column to fetch.
|
danielebarchiesi@0
|
2062 * @param $constructor_arguments
|
danielebarchiesi@0
|
2063 * If $mode is PDO::FETCH_CLASS, the arguments to pass to the constructor.
|
danielebarchiesi@0
|
2064 *
|
danielebarchiesi@0
|
2065 * @return
|
danielebarchiesi@0
|
2066 * An array of results.
|
danielebarchiesi@0
|
2067 */
|
danielebarchiesi@0
|
2068 // function fetchAll($mode = NULL, $column_index = NULL, array $constructor_arguments);
|
danielebarchiesi@0
|
2069
|
danielebarchiesi@0
|
2070 /**
|
danielebarchiesi@0
|
2071 * Returns an entire single column of a result set as an indexed array.
|
danielebarchiesi@0
|
2072 *
|
danielebarchiesi@0
|
2073 * Note that this method will run the result set to the end.
|
danielebarchiesi@0
|
2074 *
|
danielebarchiesi@0
|
2075 * @param $index
|
danielebarchiesi@0
|
2076 * The index of the column number to fetch.
|
danielebarchiesi@0
|
2077 *
|
danielebarchiesi@0
|
2078 * @return
|
danielebarchiesi@0
|
2079 * An indexed array, or an empty array if there is no result set.
|
danielebarchiesi@0
|
2080 */
|
danielebarchiesi@0
|
2081 public function fetchCol($index = 0);
|
danielebarchiesi@0
|
2082
|
danielebarchiesi@0
|
2083 /**
|
danielebarchiesi@0
|
2084 * Returns the entire result set as a single associative array.
|
danielebarchiesi@0
|
2085 *
|
danielebarchiesi@0
|
2086 * This method is only useful for two-column result sets. It will return an
|
danielebarchiesi@0
|
2087 * associative array where the key is one column from the result set and the
|
danielebarchiesi@0
|
2088 * value is another field. In most cases, the default of the first two columns
|
danielebarchiesi@0
|
2089 * is appropriate.
|
danielebarchiesi@0
|
2090 *
|
danielebarchiesi@0
|
2091 * Note that this method will run the result set to the end.
|
danielebarchiesi@0
|
2092 *
|
danielebarchiesi@0
|
2093 * @param $key_index
|
danielebarchiesi@0
|
2094 * The numeric index of the field to use as the array key.
|
danielebarchiesi@0
|
2095 * @param $value_index
|
danielebarchiesi@0
|
2096 * The numeric index of the field to use as the array value.
|
danielebarchiesi@0
|
2097 *
|
danielebarchiesi@0
|
2098 * @return
|
danielebarchiesi@0
|
2099 * An associative array, or an empty array if there is no result set.
|
danielebarchiesi@0
|
2100 */
|
danielebarchiesi@0
|
2101 public function fetchAllKeyed($key_index = 0, $value_index = 1);
|
danielebarchiesi@0
|
2102
|
danielebarchiesi@0
|
2103 /**
|
danielebarchiesi@0
|
2104 * Returns the result set as an associative array keyed by the given field.
|
danielebarchiesi@0
|
2105 *
|
danielebarchiesi@0
|
2106 * If the given key appears multiple times, later records will overwrite
|
danielebarchiesi@0
|
2107 * earlier ones.
|
danielebarchiesi@0
|
2108 *
|
danielebarchiesi@0
|
2109 * @param $key
|
danielebarchiesi@0
|
2110 * The name of the field on which to index the array.
|
danielebarchiesi@0
|
2111 * @param $fetch
|
danielebarchiesi@0
|
2112 * The fetchmode to use. If set to PDO::FETCH_ASSOC, PDO::FETCH_NUM, or
|
danielebarchiesi@0
|
2113 * PDO::FETCH_BOTH the returned value with be an array of arrays. For any
|
danielebarchiesi@0
|
2114 * other value it will be an array of objects. By default, the fetch mode
|
danielebarchiesi@0
|
2115 * set for the query will be used.
|
danielebarchiesi@0
|
2116 *
|
danielebarchiesi@0
|
2117 * @return
|
danielebarchiesi@0
|
2118 * An associative array, or an empty array if there is no result set.
|
danielebarchiesi@0
|
2119 */
|
danielebarchiesi@0
|
2120 public function fetchAllAssoc($key, $fetch = NULL);
|
danielebarchiesi@0
|
2121 }
|
danielebarchiesi@0
|
2122
|
danielebarchiesi@0
|
2123 /**
|
danielebarchiesi@0
|
2124 * Default implementation of DatabaseStatementInterface.
|
danielebarchiesi@0
|
2125 *
|
danielebarchiesi@0
|
2126 * PDO allows us to extend the PDOStatement class to provide additional
|
danielebarchiesi@0
|
2127 * functionality beyond that offered by default. We do need extra
|
danielebarchiesi@0
|
2128 * functionality. By default, this class is not driver-specific. If a given
|
danielebarchiesi@0
|
2129 * driver needs to set a custom statement class, it may do so in its
|
danielebarchiesi@0
|
2130 * constructor.
|
danielebarchiesi@0
|
2131 *
|
danielebarchiesi@0
|
2132 * @see http://us.php.net/pdostatement
|
danielebarchiesi@0
|
2133 */
|
danielebarchiesi@0
|
2134 class DatabaseStatementBase extends PDOStatement implements DatabaseStatementInterface {
|
danielebarchiesi@0
|
2135
|
danielebarchiesi@0
|
2136 /**
|
danielebarchiesi@0
|
2137 * Reference to the database connection object for this statement.
|
danielebarchiesi@0
|
2138 *
|
danielebarchiesi@0
|
2139 * The name $dbh is inherited from PDOStatement.
|
danielebarchiesi@0
|
2140 *
|
danielebarchiesi@0
|
2141 * @var DatabaseConnection
|
danielebarchiesi@0
|
2142 */
|
danielebarchiesi@0
|
2143 public $dbh;
|
danielebarchiesi@0
|
2144
|
danielebarchiesi@0
|
2145 protected function __construct($dbh) {
|
danielebarchiesi@0
|
2146 $this->dbh = $dbh;
|
danielebarchiesi@0
|
2147 $this->setFetchMode(PDO::FETCH_OBJ);
|
danielebarchiesi@0
|
2148 }
|
danielebarchiesi@0
|
2149
|
danielebarchiesi@0
|
2150 public function execute($args = array(), $options = array()) {
|
danielebarchiesi@0
|
2151 if (isset($options['fetch'])) {
|
danielebarchiesi@0
|
2152 if (is_string($options['fetch'])) {
|
danielebarchiesi@0
|
2153 // Default to an object. Note: db fields will be added to the object
|
danielebarchiesi@0
|
2154 // before the constructor is run. If you need to assign fields after
|
danielebarchiesi@0
|
2155 // the constructor is run, see http://drupal.org/node/315092.
|
danielebarchiesi@0
|
2156 $this->setFetchMode(PDO::FETCH_CLASS, $options['fetch']);
|
danielebarchiesi@0
|
2157 }
|
danielebarchiesi@0
|
2158 else {
|
danielebarchiesi@0
|
2159 $this->setFetchMode($options['fetch']);
|
danielebarchiesi@0
|
2160 }
|
danielebarchiesi@0
|
2161 }
|
danielebarchiesi@0
|
2162
|
danielebarchiesi@0
|
2163 $logger = $this->dbh->getLogger();
|
danielebarchiesi@0
|
2164 if (!empty($logger)) {
|
danielebarchiesi@0
|
2165 $query_start = microtime(TRUE);
|
danielebarchiesi@0
|
2166 }
|
danielebarchiesi@0
|
2167
|
danielebarchiesi@0
|
2168 $return = parent::execute($args);
|
danielebarchiesi@0
|
2169
|
danielebarchiesi@0
|
2170 if (!empty($logger)) {
|
danielebarchiesi@0
|
2171 $query_end = microtime(TRUE);
|
danielebarchiesi@0
|
2172 $logger->log($this, $args, $query_end - $query_start);
|
danielebarchiesi@0
|
2173 }
|
danielebarchiesi@0
|
2174
|
danielebarchiesi@0
|
2175 return $return;
|
danielebarchiesi@0
|
2176 }
|
danielebarchiesi@0
|
2177
|
danielebarchiesi@0
|
2178 public function getQueryString() {
|
danielebarchiesi@0
|
2179 return $this->queryString;
|
danielebarchiesi@0
|
2180 }
|
danielebarchiesi@0
|
2181
|
danielebarchiesi@0
|
2182 public function fetchCol($index = 0) {
|
danielebarchiesi@0
|
2183 return $this->fetchAll(PDO::FETCH_COLUMN, $index);
|
danielebarchiesi@0
|
2184 }
|
danielebarchiesi@0
|
2185
|
danielebarchiesi@0
|
2186 public function fetchAllAssoc($key, $fetch = NULL) {
|
danielebarchiesi@0
|
2187 $return = array();
|
danielebarchiesi@0
|
2188 if (isset($fetch)) {
|
danielebarchiesi@0
|
2189 if (is_string($fetch)) {
|
danielebarchiesi@0
|
2190 $this->setFetchMode(PDO::FETCH_CLASS, $fetch);
|
danielebarchiesi@0
|
2191 }
|
danielebarchiesi@0
|
2192 else {
|
danielebarchiesi@0
|
2193 $this->setFetchMode($fetch);
|
danielebarchiesi@0
|
2194 }
|
danielebarchiesi@0
|
2195 }
|
danielebarchiesi@0
|
2196
|
danielebarchiesi@0
|
2197 foreach ($this as $record) {
|
danielebarchiesi@0
|
2198 $record_key = is_object($record) ? $record->$key : $record[$key];
|
danielebarchiesi@0
|
2199 $return[$record_key] = $record;
|
danielebarchiesi@0
|
2200 }
|
danielebarchiesi@0
|
2201
|
danielebarchiesi@0
|
2202 return $return;
|
danielebarchiesi@0
|
2203 }
|
danielebarchiesi@0
|
2204
|
danielebarchiesi@0
|
2205 public function fetchAllKeyed($key_index = 0, $value_index = 1) {
|
danielebarchiesi@0
|
2206 $return = array();
|
danielebarchiesi@0
|
2207 $this->setFetchMode(PDO::FETCH_NUM);
|
danielebarchiesi@0
|
2208 foreach ($this as $record) {
|
danielebarchiesi@0
|
2209 $return[$record[$key_index]] = $record[$value_index];
|
danielebarchiesi@0
|
2210 }
|
danielebarchiesi@0
|
2211 return $return;
|
danielebarchiesi@0
|
2212 }
|
danielebarchiesi@0
|
2213
|
danielebarchiesi@0
|
2214 public function fetchField($index = 0) {
|
danielebarchiesi@0
|
2215 // Call PDOStatement::fetchColumn to fetch the field.
|
danielebarchiesi@0
|
2216 return $this->fetchColumn($index);
|
danielebarchiesi@0
|
2217 }
|
danielebarchiesi@0
|
2218
|
danielebarchiesi@0
|
2219 public function fetchAssoc() {
|
danielebarchiesi@0
|
2220 // Call PDOStatement::fetch to fetch the row.
|
danielebarchiesi@0
|
2221 return $this->fetch(PDO::FETCH_ASSOC);
|
danielebarchiesi@0
|
2222 }
|
danielebarchiesi@0
|
2223 }
|
danielebarchiesi@0
|
2224
|
danielebarchiesi@0
|
2225 /**
|
danielebarchiesi@0
|
2226 * Empty implementation of a database statement.
|
danielebarchiesi@0
|
2227 *
|
danielebarchiesi@0
|
2228 * This class satisfies the requirements of being a database statement/result
|
danielebarchiesi@0
|
2229 * object, but does not actually contain data. It is useful when developers
|
danielebarchiesi@0
|
2230 * need to safely return an "empty" result set without connecting to an actual
|
danielebarchiesi@0
|
2231 * database. Calling code can then treat it the same as if it were an actual
|
danielebarchiesi@0
|
2232 * result set that happens to contain no records.
|
danielebarchiesi@0
|
2233 *
|
danielebarchiesi@0
|
2234 * @see SearchQuery
|
danielebarchiesi@0
|
2235 */
|
danielebarchiesi@0
|
2236 class DatabaseStatementEmpty implements Iterator, DatabaseStatementInterface {
|
danielebarchiesi@0
|
2237
|
danielebarchiesi@0
|
2238 public function execute($args = array(), $options = array()) {
|
danielebarchiesi@0
|
2239 return FALSE;
|
danielebarchiesi@0
|
2240 }
|
danielebarchiesi@0
|
2241
|
danielebarchiesi@0
|
2242 public function getQueryString() {
|
danielebarchiesi@0
|
2243 return '';
|
danielebarchiesi@0
|
2244 }
|
danielebarchiesi@0
|
2245
|
danielebarchiesi@0
|
2246 public function rowCount() {
|
danielebarchiesi@0
|
2247 return 0;
|
danielebarchiesi@0
|
2248 }
|
danielebarchiesi@0
|
2249
|
danielebarchiesi@0
|
2250 public function setFetchMode($mode, $a1 = NULL, $a2 = array()) {
|
danielebarchiesi@0
|
2251 return;
|
danielebarchiesi@0
|
2252 }
|
danielebarchiesi@0
|
2253
|
danielebarchiesi@0
|
2254 public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset = NULL) {
|
danielebarchiesi@0
|
2255 return NULL;
|
danielebarchiesi@0
|
2256 }
|
danielebarchiesi@0
|
2257
|
danielebarchiesi@0
|
2258 public function fetchField($index = 0) {
|
danielebarchiesi@0
|
2259 return NULL;
|
danielebarchiesi@0
|
2260 }
|
danielebarchiesi@0
|
2261
|
danielebarchiesi@0
|
2262 public function fetchObject() {
|
danielebarchiesi@0
|
2263 return NULL;
|
danielebarchiesi@0
|
2264 }
|
danielebarchiesi@0
|
2265
|
danielebarchiesi@0
|
2266 public function fetchAssoc() {
|
danielebarchiesi@0
|
2267 return NULL;
|
danielebarchiesi@0
|
2268 }
|
danielebarchiesi@0
|
2269
|
danielebarchiesi@0
|
2270 function fetchAll($mode = NULL, $column_index = NULL, array $constructor_arguments = array()) {
|
danielebarchiesi@0
|
2271 return array();
|
danielebarchiesi@0
|
2272 }
|
danielebarchiesi@0
|
2273
|
danielebarchiesi@0
|
2274 public function fetchCol($index = 0) {
|
danielebarchiesi@0
|
2275 return array();
|
danielebarchiesi@0
|
2276 }
|
danielebarchiesi@0
|
2277
|
danielebarchiesi@0
|
2278 public function fetchAllKeyed($key_index = 0, $value_index = 1) {
|
danielebarchiesi@0
|
2279 return array();
|
danielebarchiesi@0
|
2280 }
|
danielebarchiesi@0
|
2281
|
danielebarchiesi@0
|
2282 public function fetchAllAssoc($key, $fetch = NULL) {
|
danielebarchiesi@0
|
2283 return array();
|
danielebarchiesi@0
|
2284 }
|
danielebarchiesi@0
|
2285
|
danielebarchiesi@0
|
2286 /* Implementations of Iterator. */
|
danielebarchiesi@0
|
2287
|
danielebarchiesi@0
|
2288 public function current() {
|
danielebarchiesi@0
|
2289 return NULL;
|
danielebarchiesi@0
|
2290 }
|
danielebarchiesi@0
|
2291
|
danielebarchiesi@0
|
2292 public function key() {
|
danielebarchiesi@0
|
2293 return NULL;
|
danielebarchiesi@0
|
2294 }
|
danielebarchiesi@0
|
2295
|
danielebarchiesi@0
|
2296 public function rewind() {
|
danielebarchiesi@0
|
2297 // Nothing to do: our DatabaseStatement can't be rewound.
|
danielebarchiesi@0
|
2298 }
|
danielebarchiesi@0
|
2299
|
danielebarchiesi@0
|
2300 public function next() {
|
danielebarchiesi@0
|
2301 // Do nothing, since this is an always-empty implementation.
|
danielebarchiesi@0
|
2302 }
|
danielebarchiesi@0
|
2303
|
danielebarchiesi@0
|
2304 public function valid() {
|
danielebarchiesi@0
|
2305 return FALSE;
|
danielebarchiesi@0
|
2306 }
|
danielebarchiesi@0
|
2307 }
|
danielebarchiesi@0
|
2308
|
danielebarchiesi@0
|
2309 /**
|
danielebarchiesi@0
|
2310 * The following utility functions are simply convenience wrappers.
|
danielebarchiesi@0
|
2311 *
|
danielebarchiesi@0
|
2312 * They should never, ever have any database-specific code in them.
|
danielebarchiesi@0
|
2313 */
|
danielebarchiesi@0
|
2314
|
danielebarchiesi@0
|
2315 /**
|
danielebarchiesi@0
|
2316 * Executes an arbitrary query string against the active database.
|
danielebarchiesi@0
|
2317 *
|
danielebarchiesi@0
|
2318 * Use this function for SELECT queries if it is just a simple query string.
|
danielebarchiesi@0
|
2319 * If the caller or other modules need to change the query, use db_select()
|
danielebarchiesi@0
|
2320 * instead.
|
danielebarchiesi@0
|
2321 *
|
danielebarchiesi@0
|
2322 * Do not use this function for INSERT, UPDATE, or DELETE queries. Those should
|
danielebarchiesi@0
|
2323 * be handled via db_insert(), db_update() and db_delete() respectively.
|
danielebarchiesi@0
|
2324 *
|
danielebarchiesi@0
|
2325 * @param $query
|
danielebarchiesi@0
|
2326 * The prepared statement query to run. Although it will accept both named and
|
danielebarchiesi@0
|
2327 * unnamed placeholders, named placeholders are strongly preferred as they are
|
danielebarchiesi@0
|
2328 * more self-documenting.
|
danielebarchiesi@0
|
2329 * @param $args
|
danielebarchiesi@0
|
2330 * An array of values to substitute into the query. If the query uses named
|
danielebarchiesi@0
|
2331 * placeholders, this is an associative array in any order. If the query uses
|
danielebarchiesi@0
|
2332 * unnamed placeholders (?), this is an indexed array and the order must match
|
danielebarchiesi@0
|
2333 * the order of placeholders in the query string.
|
danielebarchiesi@0
|
2334 * @param $options
|
danielebarchiesi@0
|
2335 * An array of options to control how the query operates.
|
danielebarchiesi@0
|
2336 *
|
danielebarchiesi@0
|
2337 * @return DatabaseStatementInterface
|
danielebarchiesi@0
|
2338 * A prepared statement object, already executed.
|
danielebarchiesi@0
|
2339 *
|
danielebarchiesi@0
|
2340 * @see DatabaseConnection::defaultOptions()
|
danielebarchiesi@0
|
2341 */
|
danielebarchiesi@0
|
2342 function db_query($query, array $args = array(), array $options = array()) {
|
danielebarchiesi@0
|
2343 if (empty($options['target'])) {
|
danielebarchiesi@0
|
2344 $options['target'] = 'default';
|
danielebarchiesi@0
|
2345 }
|
danielebarchiesi@0
|
2346
|
danielebarchiesi@0
|
2347 return Database::getConnection($options['target'])->query($query, $args, $options);
|
danielebarchiesi@0
|
2348 }
|
danielebarchiesi@0
|
2349
|
danielebarchiesi@0
|
2350 /**
|
danielebarchiesi@0
|
2351 * Executes a query against the active database, restricted to a range.
|
danielebarchiesi@0
|
2352 *
|
danielebarchiesi@0
|
2353 * @param $query
|
danielebarchiesi@0
|
2354 * The prepared statement query to run. Although it will accept both named and
|
danielebarchiesi@0
|
2355 * unnamed placeholders, named placeholders are strongly preferred as they are
|
danielebarchiesi@0
|
2356 * more self-documenting.
|
danielebarchiesi@0
|
2357 * @param $from
|
danielebarchiesi@0
|
2358 * The first record from the result set to return.
|
danielebarchiesi@0
|
2359 * @param $count
|
danielebarchiesi@0
|
2360 * The number of records to return from the result set.
|
danielebarchiesi@0
|
2361 * @param $args
|
danielebarchiesi@0
|
2362 * An array of values to substitute into the query. If the query uses named
|
danielebarchiesi@0
|
2363 * placeholders, this is an associative array in any order. If the query uses
|
danielebarchiesi@0
|
2364 * unnamed placeholders (?), this is an indexed array and the order must match
|
danielebarchiesi@0
|
2365 * the order of placeholders in the query string.
|
danielebarchiesi@0
|
2366 * @param $options
|
danielebarchiesi@0
|
2367 * An array of options to control how the query operates.
|
danielebarchiesi@0
|
2368 *
|
danielebarchiesi@0
|
2369 * @return DatabaseStatementInterface
|
danielebarchiesi@0
|
2370 * A prepared statement object, already executed.
|
danielebarchiesi@0
|
2371 *
|
danielebarchiesi@0
|
2372 * @see DatabaseConnection::defaultOptions()
|
danielebarchiesi@0
|
2373 */
|
danielebarchiesi@0
|
2374 function db_query_range($query, $from, $count, array $args = array(), array $options = array()) {
|
danielebarchiesi@0
|
2375 if (empty($options['target'])) {
|
danielebarchiesi@0
|
2376 $options['target'] = 'default';
|
danielebarchiesi@0
|
2377 }
|
danielebarchiesi@0
|
2378
|
danielebarchiesi@0
|
2379 return Database::getConnection($options['target'])->queryRange($query, $from, $count, $args, $options);
|
danielebarchiesi@0
|
2380 }
|
danielebarchiesi@0
|
2381
|
danielebarchiesi@0
|
2382 /**
|
danielebarchiesi@0
|
2383 * Executes a query string and saves the result set to a temporary table.
|
danielebarchiesi@0
|
2384 *
|
danielebarchiesi@0
|
2385 * The execution of the query string happens against the active database.
|
danielebarchiesi@0
|
2386 *
|
danielebarchiesi@0
|
2387 * @param $query
|
danielebarchiesi@0
|
2388 * The prepared statement query to run. Although it will accept both named and
|
danielebarchiesi@0
|
2389 * unnamed placeholders, named placeholders are strongly preferred as they are
|
danielebarchiesi@0
|
2390 * more self-documenting.
|
danielebarchiesi@0
|
2391 * @param $args
|
danielebarchiesi@0
|
2392 * An array of values to substitute into the query. If the query uses named
|
danielebarchiesi@0
|
2393 * placeholders, this is an associative array in any order. If the query uses
|
danielebarchiesi@0
|
2394 * unnamed placeholders (?), this is an indexed array and the order must match
|
danielebarchiesi@0
|
2395 * the order of placeholders in the query string.
|
danielebarchiesi@0
|
2396 * @param $options
|
danielebarchiesi@0
|
2397 * An array of options to control how the query operates.
|
danielebarchiesi@0
|
2398 *
|
danielebarchiesi@0
|
2399 * @return
|
danielebarchiesi@0
|
2400 * The name of the temporary table.
|
danielebarchiesi@0
|
2401 *
|
danielebarchiesi@0
|
2402 * @see DatabaseConnection::defaultOptions()
|
danielebarchiesi@0
|
2403 */
|
danielebarchiesi@0
|
2404 function db_query_temporary($query, array $args = array(), array $options = array()) {
|
danielebarchiesi@0
|
2405 if (empty($options['target'])) {
|
danielebarchiesi@0
|
2406 $options['target'] = 'default';
|
danielebarchiesi@0
|
2407 }
|
danielebarchiesi@0
|
2408
|
danielebarchiesi@0
|
2409 return Database::getConnection($options['target'])->queryTemporary($query, $args, $options);
|
danielebarchiesi@0
|
2410 }
|
danielebarchiesi@0
|
2411
|
danielebarchiesi@0
|
2412 /**
|
danielebarchiesi@0
|
2413 * Returns a new InsertQuery object for the active database.
|
danielebarchiesi@0
|
2414 *
|
danielebarchiesi@0
|
2415 * @param $table
|
danielebarchiesi@0
|
2416 * The table into which to insert.
|
danielebarchiesi@0
|
2417 * @param $options
|
danielebarchiesi@0
|
2418 * An array of options to control how the query operates.
|
danielebarchiesi@0
|
2419 *
|
danielebarchiesi@0
|
2420 * @return InsertQuery
|
danielebarchiesi@0
|
2421 * A new InsertQuery object for this connection.
|
danielebarchiesi@0
|
2422 */
|
danielebarchiesi@0
|
2423 function db_insert($table, array $options = array()) {
|
danielebarchiesi@0
|
2424 if (empty($options['target']) || $options['target'] == 'slave') {
|
danielebarchiesi@0
|
2425 $options['target'] = 'default';
|
danielebarchiesi@0
|
2426 }
|
danielebarchiesi@0
|
2427 return Database::getConnection($options['target'])->insert($table, $options);
|
danielebarchiesi@0
|
2428 }
|
danielebarchiesi@0
|
2429
|
danielebarchiesi@0
|
2430 /**
|
danielebarchiesi@0
|
2431 * Returns a new MergeQuery object for the active database.
|
danielebarchiesi@0
|
2432 *
|
danielebarchiesi@0
|
2433 * @param $table
|
danielebarchiesi@0
|
2434 * The table into which to merge.
|
danielebarchiesi@0
|
2435 * @param $options
|
danielebarchiesi@0
|
2436 * An array of options to control how the query operates.
|
danielebarchiesi@0
|
2437 *
|
danielebarchiesi@0
|
2438 * @return MergeQuery
|
danielebarchiesi@0
|
2439 * A new MergeQuery object for this connection.
|
danielebarchiesi@0
|
2440 */
|
danielebarchiesi@0
|
2441 function db_merge($table, array $options = array()) {
|
danielebarchiesi@0
|
2442 if (empty($options['target']) || $options['target'] == 'slave') {
|
danielebarchiesi@0
|
2443 $options['target'] = 'default';
|
danielebarchiesi@0
|
2444 }
|
danielebarchiesi@0
|
2445 return Database::getConnection($options['target'])->merge($table, $options);
|
danielebarchiesi@0
|
2446 }
|
danielebarchiesi@0
|
2447
|
danielebarchiesi@0
|
2448 /**
|
danielebarchiesi@0
|
2449 * Returns a new UpdateQuery object for the active database.
|
danielebarchiesi@0
|
2450 *
|
danielebarchiesi@0
|
2451 * @param $table
|
danielebarchiesi@0
|
2452 * The table to update.
|
danielebarchiesi@0
|
2453 * @param $options
|
danielebarchiesi@0
|
2454 * An array of options to control how the query operates.
|
danielebarchiesi@0
|
2455 *
|
danielebarchiesi@0
|
2456 * @return UpdateQuery
|
danielebarchiesi@0
|
2457 * A new UpdateQuery object for this connection.
|
danielebarchiesi@0
|
2458 */
|
danielebarchiesi@0
|
2459 function db_update($table, array $options = array()) {
|
danielebarchiesi@0
|
2460 if (empty($options['target']) || $options['target'] == 'slave') {
|
danielebarchiesi@0
|
2461 $options['target'] = 'default';
|
danielebarchiesi@0
|
2462 }
|
danielebarchiesi@0
|
2463 return Database::getConnection($options['target'])->update($table, $options);
|
danielebarchiesi@0
|
2464 }
|
danielebarchiesi@0
|
2465
|
danielebarchiesi@0
|
2466 /**
|
danielebarchiesi@0
|
2467 * Returns a new DeleteQuery object for the active database.
|
danielebarchiesi@0
|
2468 *
|
danielebarchiesi@0
|
2469 * @param $table
|
danielebarchiesi@0
|
2470 * The table from which to delete.
|
danielebarchiesi@0
|
2471 * @param $options
|
danielebarchiesi@0
|
2472 * An array of options to control how the query operates.
|
danielebarchiesi@0
|
2473 *
|
danielebarchiesi@0
|
2474 * @return DeleteQuery
|
danielebarchiesi@0
|
2475 * A new DeleteQuery object for this connection.
|
danielebarchiesi@0
|
2476 */
|
danielebarchiesi@0
|
2477 function db_delete($table, array $options = array()) {
|
danielebarchiesi@0
|
2478 if (empty($options['target']) || $options['target'] == 'slave') {
|
danielebarchiesi@0
|
2479 $options['target'] = 'default';
|
danielebarchiesi@0
|
2480 }
|
danielebarchiesi@0
|
2481 return Database::getConnection($options['target'])->delete($table, $options);
|
danielebarchiesi@0
|
2482 }
|
danielebarchiesi@0
|
2483
|
danielebarchiesi@0
|
2484 /**
|
danielebarchiesi@0
|
2485 * Returns a new TruncateQuery object for the active database.
|
danielebarchiesi@0
|
2486 *
|
danielebarchiesi@0
|
2487 * @param $table
|
danielebarchiesi@0
|
2488 * The table from which to delete.
|
danielebarchiesi@0
|
2489 * @param $options
|
danielebarchiesi@0
|
2490 * An array of options to control how the query operates.
|
danielebarchiesi@0
|
2491 *
|
danielebarchiesi@0
|
2492 * @return TruncateQuery
|
danielebarchiesi@0
|
2493 * A new TruncateQuery object for this connection.
|
danielebarchiesi@0
|
2494 */
|
danielebarchiesi@0
|
2495 function db_truncate($table, array $options = array()) {
|
danielebarchiesi@0
|
2496 if (empty($options['target']) || $options['target'] == 'slave') {
|
danielebarchiesi@0
|
2497 $options['target'] = 'default';
|
danielebarchiesi@0
|
2498 }
|
danielebarchiesi@0
|
2499 return Database::getConnection($options['target'])->truncate($table, $options);
|
danielebarchiesi@0
|
2500 }
|
danielebarchiesi@0
|
2501
|
danielebarchiesi@0
|
2502 /**
|
danielebarchiesi@0
|
2503 * Returns a new SelectQuery object for the active database.
|
danielebarchiesi@0
|
2504 *
|
danielebarchiesi@0
|
2505 * @param $table
|
danielebarchiesi@0
|
2506 * The base table for this query. May be a string or another SelectQuery
|
danielebarchiesi@0
|
2507 * object. If a query object is passed, it will be used as a subselect.
|
danielebarchiesi@0
|
2508 * @param $alias
|
danielebarchiesi@0
|
2509 * The alias for the base table of this query.
|
danielebarchiesi@0
|
2510 * @param $options
|
danielebarchiesi@0
|
2511 * An array of options to control how the query operates.
|
danielebarchiesi@0
|
2512 *
|
danielebarchiesi@0
|
2513 * @return SelectQuery
|
danielebarchiesi@0
|
2514 * A new SelectQuery object for this connection.
|
danielebarchiesi@0
|
2515 */
|
danielebarchiesi@0
|
2516 function db_select($table, $alias = NULL, array $options = array()) {
|
danielebarchiesi@0
|
2517 if (empty($options['target'])) {
|
danielebarchiesi@0
|
2518 $options['target'] = 'default';
|
danielebarchiesi@0
|
2519 }
|
danielebarchiesi@0
|
2520 return Database::getConnection($options['target'])->select($table, $alias, $options);
|
danielebarchiesi@0
|
2521 }
|
danielebarchiesi@0
|
2522
|
danielebarchiesi@0
|
2523 /**
|
danielebarchiesi@0
|
2524 * Returns a new transaction object for the active database.
|
danielebarchiesi@0
|
2525 *
|
danielebarchiesi@0
|
2526 * @param string $name
|
danielebarchiesi@0
|
2527 * Optional name of the transaction.
|
danielebarchiesi@0
|
2528 * @param array $options
|
danielebarchiesi@0
|
2529 * An array of options to control how the transaction operates:
|
danielebarchiesi@0
|
2530 * - target: The database target name.
|
danielebarchiesi@0
|
2531 *
|
danielebarchiesi@0
|
2532 * @return DatabaseTransaction
|
danielebarchiesi@0
|
2533 * A new DatabaseTransaction object for this connection.
|
danielebarchiesi@0
|
2534 */
|
danielebarchiesi@0
|
2535 function db_transaction($name = NULL, array $options = array()) {
|
danielebarchiesi@0
|
2536 if (empty($options['target'])) {
|
danielebarchiesi@0
|
2537 $options['target'] = 'default';
|
danielebarchiesi@0
|
2538 }
|
danielebarchiesi@0
|
2539 return Database::getConnection($options['target'])->startTransaction($name);
|
danielebarchiesi@0
|
2540 }
|
danielebarchiesi@0
|
2541
|
danielebarchiesi@0
|
2542 /**
|
danielebarchiesi@0
|
2543 * Sets a new active database.
|
danielebarchiesi@0
|
2544 *
|
danielebarchiesi@0
|
2545 * @param $key
|
danielebarchiesi@0
|
2546 * The key in the $databases array to set as the default database.
|
danielebarchiesi@0
|
2547 *
|
danielebarchiesi@0
|
2548 * @return
|
danielebarchiesi@0
|
2549 * The key of the formerly active database.
|
danielebarchiesi@0
|
2550 */
|
danielebarchiesi@0
|
2551 function db_set_active($key = 'default') {
|
danielebarchiesi@0
|
2552 return Database::setActiveConnection($key);
|
danielebarchiesi@0
|
2553 }
|
danielebarchiesi@0
|
2554
|
danielebarchiesi@0
|
2555 /**
|
danielebarchiesi@0
|
2556 * Restricts a dynamic table name to safe characters.
|
danielebarchiesi@0
|
2557 *
|
danielebarchiesi@0
|
2558 * Only keeps alphanumeric and underscores.
|
danielebarchiesi@0
|
2559 *
|
danielebarchiesi@0
|
2560 * @param $table
|
danielebarchiesi@0
|
2561 * The table name to escape.
|
danielebarchiesi@0
|
2562 *
|
danielebarchiesi@0
|
2563 * @return
|
danielebarchiesi@0
|
2564 * The escaped table name as a string.
|
danielebarchiesi@0
|
2565 */
|
danielebarchiesi@0
|
2566 function db_escape_table($table) {
|
danielebarchiesi@0
|
2567 return Database::getConnection()->escapeTable($table);
|
danielebarchiesi@0
|
2568 }
|
danielebarchiesi@0
|
2569
|
danielebarchiesi@0
|
2570 /**
|
danielebarchiesi@0
|
2571 * Restricts a dynamic column or constraint name to safe characters.
|
danielebarchiesi@0
|
2572 *
|
danielebarchiesi@0
|
2573 * Only keeps alphanumeric and underscores.
|
danielebarchiesi@0
|
2574 *
|
danielebarchiesi@0
|
2575 * @param $field
|
danielebarchiesi@0
|
2576 * The field name to escape.
|
danielebarchiesi@0
|
2577 *
|
danielebarchiesi@0
|
2578 * @return
|
danielebarchiesi@0
|
2579 * The escaped field name as a string.
|
danielebarchiesi@0
|
2580 */
|
danielebarchiesi@0
|
2581 function db_escape_field($field) {
|
danielebarchiesi@0
|
2582 return Database::getConnection()->escapeField($field);
|
danielebarchiesi@0
|
2583 }
|
danielebarchiesi@0
|
2584
|
danielebarchiesi@0
|
2585 /**
|
danielebarchiesi@0
|
2586 * Escapes characters that work as wildcard characters in a LIKE pattern.
|
danielebarchiesi@0
|
2587 *
|
danielebarchiesi@0
|
2588 * The wildcard characters "%" and "_" as well as backslash are prefixed with
|
danielebarchiesi@0
|
2589 * a backslash. Use this to do a search for a verbatim string without any
|
danielebarchiesi@0
|
2590 * wildcard behavior.
|
danielebarchiesi@0
|
2591 *
|
danielebarchiesi@0
|
2592 * For example, the following does a case-insensitive query for all rows whose
|
danielebarchiesi@0
|
2593 * name starts with $prefix:
|
danielebarchiesi@0
|
2594 * @code
|
danielebarchiesi@0
|
2595 * $result = db_query(
|
danielebarchiesi@0
|
2596 * 'SELECT * FROM person WHERE name LIKE :pattern',
|
danielebarchiesi@0
|
2597 * array(':pattern' => db_like($prefix) . '%')
|
danielebarchiesi@0
|
2598 * );
|
danielebarchiesi@0
|
2599 * @endcode
|
danielebarchiesi@0
|
2600 *
|
danielebarchiesi@0
|
2601 * Backslash is defined as escape character for LIKE patterns in
|
danielebarchiesi@0
|
2602 * DatabaseCondition::mapConditionOperator().
|
danielebarchiesi@0
|
2603 *
|
danielebarchiesi@0
|
2604 * @param $string
|
danielebarchiesi@0
|
2605 * The string to escape.
|
danielebarchiesi@0
|
2606 *
|
danielebarchiesi@0
|
2607 * @return
|
danielebarchiesi@0
|
2608 * The escaped string.
|
danielebarchiesi@0
|
2609 */
|
danielebarchiesi@0
|
2610 function db_like($string) {
|
danielebarchiesi@0
|
2611 return Database::getConnection()->escapeLike($string);
|
danielebarchiesi@0
|
2612 }
|
danielebarchiesi@0
|
2613
|
danielebarchiesi@0
|
2614 /**
|
danielebarchiesi@0
|
2615 * Retrieves the name of the currently active database driver.
|
danielebarchiesi@0
|
2616 *
|
danielebarchiesi@0
|
2617 * @return
|
danielebarchiesi@0
|
2618 * The name of the currently active database driver.
|
danielebarchiesi@0
|
2619 */
|
danielebarchiesi@0
|
2620 function db_driver() {
|
danielebarchiesi@0
|
2621 return Database::getConnection()->driver();
|
danielebarchiesi@0
|
2622 }
|
danielebarchiesi@0
|
2623
|
danielebarchiesi@0
|
2624 /**
|
danielebarchiesi@0
|
2625 * Closes the active database connection.
|
danielebarchiesi@0
|
2626 *
|
danielebarchiesi@0
|
2627 * @param $options
|
danielebarchiesi@0
|
2628 * An array of options to control which connection is closed. Only the target
|
danielebarchiesi@0
|
2629 * key has any meaning in this case.
|
danielebarchiesi@0
|
2630 */
|
danielebarchiesi@0
|
2631 function db_close(array $options = array()) {
|
danielebarchiesi@0
|
2632 if (empty($options['target'])) {
|
danielebarchiesi@0
|
2633 $options['target'] = NULL;
|
danielebarchiesi@0
|
2634 }
|
danielebarchiesi@0
|
2635 Database::closeConnection($options['target']);
|
danielebarchiesi@0
|
2636 }
|
danielebarchiesi@0
|
2637
|
danielebarchiesi@0
|
2638 /**
|
danielebarchiesi@0
|
2639 * Retrieves a unique id.
|
danielebarchiesi@0
|
2640 *
|
danielebarchiesi@0
|
2641 * Use this function if for some reason you can't use a serial field. Using a
|
danielebarchiesi@0
|
2642 * serial field is preferred, and InsertQuery::execute() returns the value of
|
danielebarchiesi@0
|
2643 * the last ID inserted.
|
danielebarchiesi@0
|
2644 *
|
danielebarchiesi@0
|
2645 * @param $existing_id
|
danielebarchiesi@0
|
2646 * After a database import, it might be that the sequences table is behind, so
|
danielebarchiesi@0
|
2647 * by passing in a minimum ID, it can be assured that we never issue the same
|
danielebarchiesi@0
|
2648 * ID.
|
danielebarchiesi@0
|
2649 *
|
danielebarchiesi@0
|
2650 * @return
|
danielebarchiesi@0
|
2651 * An integer number larger than any number returned before for this sequence.
|
danielebarchiesi@0
|
2652 */
|
danielebarchiesi@0
|
2653 function db_next_id($existing_id = 0) {
|
danielebarchiesi@0
|
2654 return Database::getConnection()->nextId($existing_id);
|
danielebarchiesi@0
|
2655 }
|
danielebarchiesi@0
|
2656
|
danielebarchiesi@0
|
2657 /**
|
danielebarchiesi@0
|
2658 * Returns a new DatabaseCondition, set to "OR" all conditions together.
|
danielebarchiesi@0
|
2659 *
|
danielebarchiesi@0
|
2660 * @return DatabaseCondition
|
danielebarchiesi@0
|
2661 */
|
danielebarchiesi@0
|
2662 function db_or() {
|
danielebarchiesi@0
|
2663 return new DatabaseCondition('OR');
|
danielebarchiesi@0
|
2664 }
|
danielebarchiesi@0
|
2665
|
danielebarchiesi@0
|
2666 /**
|
danielebarchiesi@0
|
2667 * Returns a new DatabaseCondition, set to "AND" all conditions together.
|
danielebarchiesi@0
|
2668 *
|
danielebarchiesi@0
|
2669 * @return DatabaseCondition
|
danielebarchiesi@0
|
2670 */
|
danielebarchiesi@0
|
2671 function db_and() {
|
danielebarchiesi@0
|
2672 return new DatabaseCondition('AND');
|
danielebarchiesi@0
|
2673 }
|
danielebarchiesi@0
|
2674
|
danielebarchiesi@0
|
2675 /**
|
danielebarchiesi@0
|
2676 * Returns a new DatabaseCondition, set to "XOR" all conditions together.
|
danielebarchiesi@0
|
2677 *
|
danielebarchiesi@0
|
2678 * @return DatabaseCondition
|
danielebarchiesi@0
|
2679 */
|
danielebarchiesi@0
|
2680 function db_xor() {
|
danielebarchiesi@0
|
2681 return new DatabaseCondition('XOR');
|
danielebarchiesi@0
|
2682 }
|
danielebarchiesi@0
|
2683
|
danielebarchiesi@0
|
2684 /**
|
danielebarchiesi@0
|
2685 * Returns a new DatabaseCondition, set to the specified conjunction.
|
danielebarchiesi@0
|
2686 *
|
danielebarchiesi@0
|
2687 * Internal API function call. The db_and(), db_or(), and db_xor()
|
danielebarchiesi@0
|
2688 * functions are preferred.
|
danielebarchiesi@0
|
2689 *
|
danielebarchiesi@0
|
2690 * @param $conjunction
|
danielebarchiesi@0
|
2691 * The conjunction to use for query conditions (AND, OR or XOR).
|
danielebarchiesi@0
|
2692 * @return DatabaseCondition
|
danielebarchiesi@0
|
2693 */
|
danielebarchiesi@0
|
2694 function db_condition($conjunction) {
|
danielebarchiesi@0
|
2695 return new DatabaseCondition($conjunction);
|
danielebarchiesi@0
|
2696 }
|
danielebarchiesi@0
|
2697
|
danielebarchiesi@0
|
2698 /**
|
danielebarchiesi@0
|
2699 * @} End of "defgroup database".
|
danielebarchiesi@0
|
2700 */
|
danielebarchiesi@0
|
2701
|
danielebarchiesi@0
|
2702
|
danielebarchiesi@0
|
2703 /**
|
danielebarchiesi@0
|
2704 * @addtogroup schemaapi
|
danielebarchiesi@0
|
2705 * @{
|
danielebarchiesi@0
|
2706 */
|
danielebarchiesi@0
|
2707
|
danielebarchiesi@0
|
2708 /**
|
danielebarchiesi@0
|
2709 * Creates a new table from a Drupal table definition.
|
danielebarchiesi@0
|
2710 *
|
danielebarchiesi@0
|
2711 * @param $name
|
danielebarchiesi@0
|
2712 * The name of the table to create.
|
danielebarchiesi@0
|
2713 * @param $table
|
danielebarchiesi@0
|
2714 * A Schema API table definition array.
|
danielebarchiesi@0
|
2715 */
|
danielebarchiesi@0
|
2716 function db_create_table($name, $table) {
|
danielebarchiesi@0
|
2717 return Database::getConnection()->schema()->createTable($name, $table);
|
danielebarchiesi@0
|
2718 }
|
danielebarchiesi@0
|
2719
|
danielebarchiesi@0
|
2720 /**
|
danielebarchiesi@0
|
2721 * Returns an array of field names from an array of key/index column specifiers.
|
danielebarchiesi@0
|
2722 *
|
danielebarchiesi@0
|
2723 * This is usually an identity function but if a key/index uses a column prefix
|
danielebarchiesi@0
|
2724 * specification, this function extracts just the name.
|
danielebarchiesi@0
|
2725 *
|
danielebarchiesi@0
|
2726 * @param $fields
|
danielebarchiesi@0
|
2727 * An array of key/index column specifiers.
|
danielebarchiesi@0
|
2728 *
|
danielebarchiesi@0
|
2729 * @return
|
danielebarchiesi@0
|
2730 * An array of field names.
|
danielebarchiesi@0
|
2731 */
|
danielebarchiesi@0
|
2732 function db_field_names($fields) {
|
danielebarchiesi@0
|
2733 return Database::getConnection()->schema()->fieldNames($fields);
|
danielebarchiesi@0
|
2734 }
|
danielebarchiesi@0
|
2735
|
danielebarchiesi@0
|
2736 /**
|
danielebarchiesi@0
|
2737 * Checks if an index exists in the given table.
|
danielebarchiesi@0
|
2738 *
|
danielebarchiesi@0
|
2739 * @param $table
|
danielebarchiesi@0
|
2740 * The name of the table in drupal (no prefixing).
|
danielebarchiesi@0
|
2741 * @param $name
|
danielebarchiesi@0
|
2742 * The name of the index in drupal (no prefixing).
|
danielebarchiesi@0
|
2743 *
|
danielebarchiesi@0
|
2744 * @return
|
danielebarchiesi@0
|
2745 * TRUE if the given index exists, otherwise FALSE.
|
danielebarchiesi@0
|
2746 */
|
danielebarchiesi@0
|
2747 function db_index_exists($table, $name) {
|
danielebarchiesi@0
|
2748 return Database::getConnection()->schema()->indexExists($table, $name);
|
danielebarchiesi@0
|
2749 }
|
danielebarchiesi@0
|
2750
|
danielebarchiesi@0
|
2751 /**
|
danielebarchiesi@0
|
2752 * Checks if a table exists.
|
danielebarchiesi@0
|
2753 *
|
danielebarchiesi@0
|
2754 * @param $table
|
danielebarchiesi@0
|
2755 * The name of the table in drupal (no prefixing).
|
danielebarchiesi@0
|
2756 *
|
danielebarchiesi@0
|
2757 * @return
|
danielebarchiesi@0
|
2758 * TRUE if the given table exists, otherwise FALSE.
|
danielebarchiesi@0
|
2759 */
|
danielebarchiesi@0
|
2760 function db_table_exists($table) {
|
danielebarchiesi@0
|
2761 return Database::getConnection()->schema()->tableExists($table);
|
danielebarchiesi@0
|
2762 }
|
danielebarchiesi@0
|
2763
|
danielebarchiesi@0
|
2764 /**
|
danielebarchiesi@0
|
2765 * Checks if a column exists in the given table.
|
danielebarchiesi@0
|
2766 *
|
danielebarchiesi@0
|
2767 * @param $table
|
danielebarchiesi@0
|
2768 * The name of the table in drupal (no prefixing).
|
danielebarchiesi@0
|
2769 * @param $field
|
danielebarchiesi@0
|
2770 * The name of the field.
|
danielebarchiesi@0
|
2771 *
|
danielebarchiesi@0
|
2772 * @return
|
danielebarchiesi@0
|
2773 * TRUE if the given column exists, otherwise FALSE.
|
danielebarchiesi@0
|
2774 */
|
danielebarchiesi@0
|
2775 function db_field_exists($table, $field) {
|
danielebarchiesi@0
|
2776 return Database::getConnection()->schema()->fieldExists($table, $field);
|
danielebarchiesi@0
|
2777 }
|
danielebarchiesi@0
|
2778
|
danielebarchiesi@0
|
2779 /**
|
danielebarchiesi@0
|
2780 * Finds all tables that are like the specified base table name.
|
danielebarchiesi@0
|
2781 *
|
danielebarchiesi@0
|
2782 * @param $table_expression
|
danielebarchiesi@0
|
2783 * An SQL expression, for example "simpletest%" (without the quotes).
|
danielebarchiesi@0
|
2784 * BEWARE: this is not prefixed, the caller should take care of that.
|
danielebarchiesi@0
|
2785 *
|
danielebarchiesi@0
|
2786 * @return
|
danielebarchiesi@0
|
2787 * Array, both the keys and the values are the matching tables.
|
danielebarchiesi@0
|
2788 */
|
danielebarchiesi@0
|
2789 function db_find_tables($table_expression) {
|
danielebarchiesi@0
|
2790 return Database::getConnection()->schema()->findTables($table_expression);
|
danielebarchiesi@0
|
2791 }
|
danielebarchiesi@0
|
2792
|
danielebarchiesi@0
|
2793 function _db_create_keys_sql($spec) {
|
danielebarchiesi@0
|
2794 return Database::getConnection()->schema()->createKeysSql($spec);
|
danielebarchiesi@0
|
2795 }
|
danielebarchiesi@0
|
2796
|
danielebarchiesi@0
|
2797 /**
|
danielebarchiesi@0
|
2798 * Renames a table.
|
danielebarchiesi@0
|
2799 *
|
danielebarchiesi@0
|
2800 * @param $table
|
danielebarchiesi@0
|
2801 * The current name of the table to be renamed.
|
danielebarchiesi@0
|
2802 * @param $new_name
|
danielebarchiesi@0
|
2803 * The new name for the table.
|
danielebarchiesi@0
|
2804 */
|
danielebarchiesi@0
|
2805 function db_rename_table($table, $new_name) {
|
danielebarchiesi@0
|
2806 return Database::getConnection()->schema()->renameTable($table, $new_name);
|
danielebarchiesi@0
|
2807 }
|
danielebarchiesi@0
|
2808
|
danielebarchiesi@0
|
2809 /**
|
danielebarchiesi@0
|
2810 * Drops a table.
|
danielebarchiesi@0
|
2811 *
|
danielebarchiesi@0
|
2812 * @param $table
|
danielebarchiesi@0
|
2813 * The table to be dropped.
|
danielebarchiesi@0
|
2814 */
|
danielebarchiesi@0
|
2815 function db_drop_table($table) {
|
danielebarchiesi@0
|
2816 return Database::getConnection()->schema()->dropTable($table);
|
danielebarchiesi@0
|
2817 }
|
danielebarchiesi@0
|
2818
|
danielebarchiesi@0
|
2819 /**
|
danielebarchiesi@0
|
2820 * Adds a new field to a table.
|
danielebarchiesi@0
|
2821 *
|
danielebarchiesi@0
|
2822 * @param $table
|
danielebarchiesi@0
|
2823 * Name of the table to be altered.
|
danielebarchiesi@0
|
2824 * @param $field
|
danielebarchiesi@0
|
2825 * Name of the field to be added.
|
danielebarchiesi@0
|
2826 * @param $spec
|
danielebarchiesi@0
|
2827 * The field specification array, as taken from a schema definition. The
|
danielebarchiesi@0
|
2828 * specification may also contain the key 'initial'; the newly-created field
|
danielebarchiesi@0
|
2829 * will be set to the value of the key in all rows. This is most useful for
|
danielebarchiesi@0
|
2830 * creating NOT NULL columns with no default value in existing tables.
|
danielebarchiesi@0
|
2831 * @param $keys_new
|
danielebarchiesi@0
|
2832 * Optional keys and indexes specification to be created on the table along
|
danielebarchiesi@0
|
2833 * with adding the field. The format is the same as a table specification, but
|
danielebarchiesi@0
|
2834 * without the 'fields' element. If you are adding a type 'serial' field, you
|
danielebarchiesi@0
|
2835 * MUST specify at least one key or index including it in this array. See
|
danielebarchiesi@0
|
2836 * db_change_field() for more explanation why.
|
danielebarchiesi@0
|
2837 *
|
danielebarchiesi@0
|
2838 * @see db_change_field()
|
danielebarchiesi@0
|
2839 */
|
danielebarchiesi@0
|
2840 function db_add_field($table, $field, $spec, $keys_new = array()) {
|
danielebarchiesi@0
|
2841 return Database::getConnection()->schema()->addField($table, $field, $spec, $keys_new);
|
danielebarchiesi@0
|
2842 }
|
danielebarchiesi@0
|
2843
|
danielebarchiesi@0
|
2844 /**
|
danielebarchiesi@0
|
2845 * Drops a field.
|
danielebarchiesi@0
|
2846 *
|
danielebarchiesi@0
|
2847 * @param $table
|
danielebarchiesi@0
|
2848 * The table to be altered.
|
danielebarchiesi@0
|
2849 * @param $field
|
danielebarchiesi@0
|
2850 * The field to be dropped.
|
danielebarchiesi@0
|
2851 */
|
danielebarchiesi@0
|
2852 function db_drop_field($table, $field) {
|
danielebarchiesi@0
|
2853 return Database::getConnection()->schema()->dropField($table, $field);
|
danielebarchiesi@0
|
2854 }
|
danielebarchiesi@0
|
2855
|
danielebarchiesi@0
|
2856 /**
|
danielebarchiesi@0
|
2857 * Sets the default value for a field.
|
danielebarchiesi@0
|
2858 *
|
danielebarchiesi@0
|
2859 * @param $table
|
danielebarchiesi@0
|
2860 * The table to be altered.
|
danielebarchiesi@0
|
2861 * @param $field
|
danielebarchiesi@0
|
2862 * The field to be altered.
|
danielebarchiesi@0
|
2863 * @param $default
|
danielebarchiesi@0
|
2864 * Default value to be set. NULL for 'default NULL'.
|
danielebarchiesi@0
|
2865 */
|
danielebarchiesi@0
|
2866 function db_field_set_default($table, $field, $default) {
|
danielebarchiesi@0
|
2867 return Database::getConnection()->schema()->fieldSetDefault($table, $field, $default);
|
danielebarchiesi@0
|
2868 }
|
danielebarchiesi@0
|
2869
|
danielebarchiesi@0
|
2870 /**
|
danielebarchiesi@0
|
2871 * Sets a field to have no default value.
|
danielebarchiesi@0
|
2872 *
|
danielebarchiesi@0
|
2873 * @param $table
|
danielebarchiesi@0
|
2874 * The table to be altered.
|
danielebarchiesi@0
|
2875 * @param $field
|
danielebarchiesi@0
|
2876 * The field to be altered.
|
danielebarchiesi@0
|
2877 */
|
danielebarchiesi@0
|
2878 function db_field_set_no_default($table, $field) {
|
danielebarchiesi@0
|
2879 return Database::getConnection()->schema()->fieldSetNoDefault($table, $field);
|
danielebarchiesi@0
|
2880 }
|
danielebarchiesi@0
|
2881
|
danielebarchiesi@0
|
2882 /**
|
danielebarchiesi@0
|
2883 * Adds a primary key to a database table.
|
danielebarchiesi@0
|
2884 *
|
danielebarchiesi@0
|
2885 * @param $table
|
danielebarchiesi@0
|
2886 * Name of the table to be altered.
|
danielebarchiesi@0
|
2887 * @param $fields
|
danielebarchiesi@0
|
2888 * Array of fields for the primary key.
|
danielebarchiesi@0
|
2889 */
|
danielebarchiesi@0
|
2890 function db_add_primary_key($table, $fields) {
|
danielebarchiesi@0
|
2891 return Database::getConnection()->schema()->addPrimaryKey($table, $fields);
|
danielebarchiesi@0
|
2892 }
|
danielebarchiesi@0
|
2893
|
danielebarchiesi@0
|
2894 /**
|
danielebarchiesi@0
|
2895 * Drops the primary key of a database table.
|
danielebarchiesi@0
|
2896 *
|
danielebarchiesi@0
|
2897 * @param $table
|
danielebarchiesi@0
|
2898 * Name of the table to be altered.
|
danielebarchiesi@0
|
2899 */
|
danielebarchiesi@0
|
2900 function db_drop_primary_key($table) {
|
danielebarchiesi@0
|
2901 return Database::getConnection()->schema()->dropPrimaryKey($table);
|
danielebarchiesi@0
|
2902 }
|
danielebarchiesi@0
|
2903
|
danielebarchiesi@0
|
2904 /**
|
danielebarchiesi@0
|
2905 * Adds a unique key.
|
danielebarchiesi@0
|
2906 *
|
danielebarchiesi@0
|
2907 * @param $table
|
danielebarchiesi@0
|
2908 * The table to be altered.
|
danielebarchiesi@0
|
2909 * @param $name
|
danielebarchiesi@0
|
2910 * The name of the key.
|
danielebarchiesi@0
|
2911 * @param $fields
|
danielebarchiesi@0
|
2912 * An array of field names.
|
danielebarchiesi@0
|
2913 */
|
danielebarchiesi@0
|
2914 function db_add_unique_key($table, $name, $fields) {
|
danielebarchiesi@0
|
2915 return Database::getConnection()->schema()->addUniqueKey($table, $name, $fields);
|
danielebarchiesi@0
|
2916 }
|
danielebarchiesi@0
|
2917
|
danielebarchiesi@0
|
2918 /**
|
danielebarchiesi@0
|
2919 * Drops a unique key.
|
danielebarchiesi@0
|
2920 *
|
danielebarchiesi@0
|
2921 * @param $table
|
danielebarchiesi@0
|
2922 * The table to be altered.
|
danielebarchiesi@0
|
2923 * @param $name
|
danielebarchiesi@0
|
2924 * The name of the key.
|
danielebarchiesi@0
|
2925 */
|
danielebarchiesi@0
|
2926 function db_drop_unique_key($table, $name) {
|
danielebarchiesi@0
|
2927 return Database::getConnection()->schema()->dropUniqueKey($table, $name);
|
danielebarchiesi@0
|
2928 }
|
danielebarchiesi@0
|
2929
|
danielebarchiesi@0
|
2930 /**
|
danielebarchiesi@0
|
2931 * Adds an index.
|
danielebarchiesi@0
|
2932 *
|
danielebarchiesi@0
|
2933 * @param $table
|
danielebarchiesi@0
|
2934 * The table to be altered.
|
danielebarchiesi@0
|
2935 * @param $name
|
danielebarchiesi@0
|
2936 * The name of the index.
|
danielebarchiesi@0
|
2937 * @param $fields
|
danielebarchiesi@0
|
2938 * An array of field names.
|
danielebarchiesi@0
|
2939 */
|
danielebarchiesi@0
|
2940 function db_add_index($table, $name, $fields) {
|
danielebarchiesi@0
|
2941 return Database::getConnection()->schema()->addIndex($table, $name, $fields);
|
danielebarchiesi@0
|
2942 }
|
danielebarchiesi@0
|
2943
|
danielebarchiesi@0
|
2944 /**
|
danielebarchiesi@0
|
2945 * Drops an index.
|
danielebarchiesi@0
|
2946 *
|
danielebarchiesi@0
|
2947 * @param $table
|
danielebarchiesi@0
|
2948 * The table to be altered.
|
danielebarchiesi@0
|
2949 * @param $name
|
danielebarchiesi@0
|
2950 * The name of the index.
|
danielebarchiesi@0
|
2951 */
|
danielebarchiesi@0
|
2952 function db_drop_index($table, $name) {
|
danielebarchiesi@0
|
2953 return Database::getConnection()->schema()->dropIndex($table, $name);
|
danielebarchiesi@0
|
2954 }
|
danielebarchiesi@0
|
2955
|
danielebarchiesi@0
|
2956 /**
|
danielebarchiesi@0
|
2957 * Changes a field definition.
|
danielebarchiesi@0
|
2958 *
|
danielebarchiesi@0
|
2959 * IMPORTANT NOTE: To maintain database portability, you have to explicitly
|
danielebarchiesi@0
|
2960 * recreate all indices and primary keys that are using the changed field.
|
danielebarchiesi@0
|
2961 *
|
danielebarchiesi@0
|
2962 * That means that you have to drop all affected keys and indexes with
|
danielebarchiesi@0
|
2963 * db_drop_{primary_key,unique_key,index}() before calling db_change_field().
|
danielebarchiesi@0
|
2964 * To recreate the keys and indices, pass the key definitions as the optional
|
danielebarchiesi@0
|
2965 * $keys_new argument directly to db_change_field().
|
danielebarchiesi@0
|
2966 *
|
danielebarchiesi@0
|
2967 * For example, suppose you have:
|
danielebarchiesi@0
|
2968 * @code
|
danielebarchiesi@0
|
2969 * $schema['foo'] = array(
|
danielebarchiesi@0
|
2970 * 'fields' => array(
|
danielebarchiesi@0
|
2971 * 'bar' => array('type' => 'int', 'not null' => TRUE)
|
danielebarchiesi@0
|
2972 * ),
|
danielebarchiesi@0
|
2973 * 'primary key' => array('bar')
|
danielebarchiesi@0
|
2974 * );
|
danielebarchiesi@0
|
2975 * @endcode
|
danielebarchiesi@0
|
2976 * and you want to change foo.bar to be type serial, leaving it as the primary
|
danielebarchiesi@0
|
2977 * key. The correct sequence is:
|
danielebarchiesi@0
|
2978 * @code
|
danielebarchiesi@0
|
2979 * db_drop_primary_key('foo');
|
danielebarchiesi@0
|
2980 * db_change_field('foo', 'bar', 'bar',
|
danielebarchiesi@0
|
2981 * array('type' => 'serial', 'not null' => TRUE),
|
danielebarchiesi@0
|
2982 * array('primary key' => array('bar')));
|
danielebarchiesi@0
|
2983 * @endcode
|
danielebarchiesi@0
|
2984 *
|
danielebarchiesi@0
|
2985 * The reasons for this are due to the different database engines:
|
danielebarchiesi@0
|
2986 *
|
danielebarchiesi@0
|
2987 * On PostgreSQL, changing a field definition involves adding a new field and
|
danielebarchiesi@0
|
2988 * dropping an old one which causes any indices, primary keys and sequences
|
danielebarchiesi@0
|
2989 * (from serial-type fields) that use the changed field to be dropped.
|
danielebarchiesi@0
|
2990 *
|
danielebarchiesi@0
|
2991 * On MySQL, all type 'serial' fields must be part of at least one key or index
|
danielebarchiesi@0
|
2992 * as soon as they are created. You cannot use
|
danielebarchiesi@0
|
2993 * db_add_{primary_key,unique_key,index}() for this purpose because the ALTER
|
danielebarchiesi@0
|
2994 * TABLE command will fail to add the column without a key or index
|
danielebarchiesi@0
|
2995 * specification. The solution is to use the optional $keys_new argument to
|
danielebarchiesi@0
|
2996 * create the key or index at the same time as field.
|
danielebarchiesi@0
|
2997 *
|
danielebarchiesi@0
|
2998 * You could use db_add_{primary_key,unique_key,index}() in all cases unless you
|
danielebarchiesi@0
|
2999 * are converting a field to be type serial. You can use the $keys_new argument
|
danielebarchiesi@0
|
3000 * in all cases.
|
danielebarchiesi@0
|
3001 *
|
danielebarchiesi@0
|
3002 * @param $table
|
danielebarchiesi@0
|
3003 * Name of the table.
|
danielebarchiesi@0
|
3004 * @param $field
|
danielebarchiesi@0
|
3005 * Name of the field to change.
|
danielebarchiesi@0
|
3006 * @param $field_new
|
danielebarchiesi@0
|
3007 * New name for the field (set to the same as $field if you don't want to
|
danielebarchiesi@0
|
3008 * change the name).
|
danielebarchiesi@0
|
3009 * @param $spec
|
danielebarchiesi@0
|
3010 * The field specification for the new field.
|
danielebarchiesi@0
|
3011 * @param $keys_new
|
danielebarchiesi@0
|
3012 * Optional keys and indexes specification to be created on the table along
|
danielebarchiesi@0
|
3013 * with changing the field. The format is the same as a table specification
|
danielebarchiesi@0
|
3014 * but without the 'fields' element.
|
danielebarchiesi@0
|
3015 */
|
danielebarchiesi@0
|
3016 function db_change_field($table, $field, $field_new, $spec, $keys_new = array()) {
|
danielebarchiesi@0
|
3017 return Database::getConnection()->schema()->changeField($table, $field, $field_new, $spec, $keys_new);
|
danielebarchiesi@0
|
3018 }
|
danielebarchiesi@0
|
3019
|
danielebarchiesi@0
|
3020 /**
|
danielebarchiesi@0
|
3021 * @} End of "addtogroup schemaapi".
|
danielebarchiesi@0
|
3022 */
|
danielebarchiesi@0
|
3023
|
danielebarchiesi@0
|
3024 /**
|
danielebarchiesi@0
|
3025 * Sets a session variable specifying the lag time for ignoring a slave server.
|
danielebarchiesi@0
|
3026 */
|
danielebarchiesi@0
|
3027 function db_ignore_slave() {
|
danielebarchiesi@0
|
3028 $connection_info = Database::getConnectionInfo();
|
danielebarchiesi@0
|
3029 // Only set ignore_slave_server if there are slave servers being used, which
|
danielebarchiesi@0
|
3030 // is assumed if there are more than one.
|
danielebarchiesi@0
|
3031 if (count($connection_info) > 1) {
|
danielebarchiesi@0
|
3032 // Five minutes is long enough to allow the slave to break and resume
|
danielebarchiesi@0
|
3033 // interrupted replication without causing problems on the Drupal site from
|
danielebarchiesi@0
|
3034 // the old data.
|
danielebarchiesi@0
|
3035 $duration = variable_get('maximum_replication_lag', 300);
|
danielebarchiesi@0
|
3036 // Set session variable with amount of time to delay before using slave.
|
danielebarchiesi@0
|
3037 $_SESSION['ignore_slave_server'] = REQUEST_TIME + $duration;
|
danielebarchiesi@0
|
3038 }
|
danielebarchiesi@0
|
3039 }
|