Joomla Platform  13.1
Documentation des API du framework Joomla Platform
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
oracle.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @package Joomla.Platform
4  * @subpackage Database
5  *
6  * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
7  * @license GNU General Public License version 2 or later; see LICENSE
8  */
9 
10 defined('JPATH_PLATFORM') or die;
11 
12 /**
13  * Oracle database driver
14  *
15  * @package Joomla.Platform
16  * @subpackage Database
17  * @see http://php.net/pdo
18  * @since 12.1
19  */
21 {
22  /**
23  * The name of the database driver.
24  *
25  * @var string
26  * @since 12.1
27  */
28  public $name = 'oracle';
29 
30  /**
31  * The character(s) used to quote SQL statement names such as table names or field names,
32  * etc. The child classes should define this as necessary. If a single character string the
33  * same character is used for both sides of the quoted name, else the first character will be
34  * used for the opening quote and the second for the closing quote.
35  *
36  * @var string
37  * @since 12.1
38  */
39  protected $nameQuote = '"';
40 
41  /**
42  * Returns the current dateformat
43  *
44  * @var string
45  * @since 12.1
46  */
47  protected $dateformat;
48 
49  /**
50  * Returns the current character set
51  *
52  * @var string
53  * @since 12.1
54  */
55  protected $charset;
56 
57  /**
58  * Constructor.
59  *
60  * @param array $options List of options used to configure the connection
61  *
62  * @since 12.1
63  */
64  public function __construct($options)
65  {
66  $options['driver'] = 'oci';
67  $options['charset'] = (isset($options['charset'])) ? $options['charset'] : 'AL32UTF8';
68  $options['dateformat'] = (isset($options['dateformat'])) ? $options['dateformat'] : 'RRRR-MM-DD HH24:MI:SS';
69 
70  $this->charset = $options['charset'];
71  $this->dateformat = $options['dateformat'];
72 
73  // Finalize initialisation
74  parent::__construct($options);
75  }
76 
77  /**
78  * Destructor.
79  *
80  * @since 12.1
81  */
82  public function __destruct()
83  {
84  $this->freeResult();
85  unset($this->connection);
86  }
87 
88  /**
89  * Connects to the database if needed.
90  *
91  * @return void Returns void if the database connected successfully.
92  *
93  * @since 12.1
94  * @throws RuntimeException
95  */
96  public function connect()
97  {
98  if ($this->connection)
99  {
100  return;
101  }
102 
103  parent::connect();
104 
105  if (isset($this->options['schema']))
106  {
107  $this->setQuery('ALTER SESSION SET CURRENT_SCHEMA = ' . $this->quoteName($this->options['schema']))->execute();
108  }
109 
110  $this->setDateFormat($this->dateformat);
111  }
112 
113  /**
114  * Disconnects the database.
115  *
116  * @return void
117  *
118  * @since 12.1
119  */
120  public function disconnect()
121  {
122  // Close the connection.
123  $this->freeResult();
124  unset($this->connection);
125  }
126 
127  /**
128  * Drops a table from the database.
129  *
130  * Note: The IF EXISTS flag is unused in the Oracle driver.
131  *
132  * @param string $tableName The name of the database table to drop.
133  * @param boolean $ifExists Optionally specify that the table must exist before it is dropped.
134  *
135  * @return JDatabaseDriverOracle Returns this object to support chaining.
136  *
137  * @since 12.1
138  */
139  public function dropTable($tableName, $ifExists = true)
140  {
141  $this->connect();
142 
143  $query = $this->getQuery(true)
144  ->setQuery('DROP TABLE :tableName');
145  $query->bind(':tableName', $tableName);
146 
147  $this->setQuery($query);
148 
149  $this->execute();
150 
151  return $this;
152  }
153 
154  /**
155  * Method to get the database collation in use by sampling a text field of a table in the database.
156  *
157  * @return mixed The collation in use by the database or boolean false if not supported.
158  *
159  * @since 12.1
160  */
161  public function getCollation()
162  {
163  return $this->charset;
164  }
165 
166  /**
167  * Get a query to run and verify the database is operational.
168  *
169  * @return string The query to check the health of the DB.
170  *
171  * @since 12.2
172  */
173  public function getConnectedQuery()
174  {
175  return 'SELECT 1 FROM dual';
176  }
177 
178  /**
179  * Returns the current date format
180  * This method should be useful in the case that
181  * somebody actually wants to use a different
182  * date format and needs to check what the current
183  * one is to see if it needs to be changed.
184  *
185  * @return string The current date format
186  *
187  * @since 12.1
188  */
189  public function getDateFormat()
190  {
191  return $this->dateformat;
192  }
193 
194  /**
195  * Shows the table CREATE statement that creates the given tables.
196  *
197  * Note: You must have the correct privileges before this method
198  * will return usable results!
199  *
200  * @param mixed $tables A table name or a list of table names.
201  *
202  * @return array A list of the create SQL for the tables.
203  *
204  * @since 12.1
205  * @throws RuntimeException
206  */
207  public function getTableCreate($tables)
208  {
209  $this->connect();
210 
211  $result = array();
212  $query = $this->getQuery(true)
213  ->select('dbms_metadata.get_ddl(:type, :tableName)')
214  ->from('dual')
215  ->bind(':type', 'TABLE');
216 
217  // Sanitize input to an array and iterate over the list.
218  settype($tables, 'array');
219  foreach ($tables as $table)
220  {
221  $query->bind(':tableName', $table);
222  $this->setQuery($query);
223  $statement = (string) $this->loadResult();
224  $result[$table] = $statement;
225  }
226 
227  return $result;
228  }
229 
230  /**
231  * Retrieves field information about a given table.
232  *
233  * @param string $table The name of the database table.
234  * @param boolean $typeOnly True to only return field types.
235  *
236  * @return array An array of fields for the database table.
237  *
238  * @since 12.1
239  * @throws RuntimeException
240  */
241  public function getTableColumns($table, $typeOnly = true)
242  {
243  $this->connect();
244 
245  $columns = array();
246  $query = $this->getQuery(true);
247 
248  $fieldCasing = $this->getOption(PDO::ATTR_CASE);
249 
250  $this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
251 
252  $table = strtoupper($table);
253 
254  $query->select('*');
255  $query->from('ALL_TAB_COLUMNS');
256  $query->where('table_name = :tableName');
257 
258  $prefixedTable = str_replace('#__', strtoupper($this->tablePrefix), $table);
259  $query->bind(':tableName', $prefixedTable);
260  $this->setQuery($query);
261  $fields = $this->loadObjectList();
262 
263  if ($typeOnly)
264  {
265  foreach ($fields as $field)
266  {
267  $columns[$field->COLUMN_NAME] = $field->DATA_TYPE;
268  }
269  }
270  else
271  {
272  foreach ($fields as $field)
273  {
274  $columns[$field->COLUMN_NAME] = $field;
275  $columns[$field->COLUMN_NAME]->Default = null;
276  }
277  }
278 
279  $this->setOption(PDO::ATTR_CASE, $fieldCasing);
280 
281  return $columns;
282  }
283 
284  /**
285  * Get the details list of keys for a table.
286  *
287  * @param string $table The name of the table.
288  *
289  * @return array An array of the column specification for the table.
290  *
291  * @since 12.1
292  * @throws RuntimeException
293  */
294  public function getTableKeys($table)
295  {
296  $this->connect();
297 
298  $query = $this->getQuery(true);
299 
300  $fieldCasing = $this->getOption(PDO::ATTR_CASE);
301 
302  $this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
303 
304  $table = strtoupper($table);
305  $query->select('*')
306  ->from('ALL_CONSTRAINTS')
307  ->where('table_name = :tableName')
308  ->bind(':tableName', $table);
309 
310  $this->setQuery($query);
311  $keys = $this->loadObjectList();
312 
313  $this->setOption(PDO::ATTR_CASE, $fieldCasing);
314 
315  return $keys;
316  }
317 
318  /**
319  * Method to get an array of all tables in the database (schema).
320  *
321  * @param string $databaseName The database (schema) name
322  * @param boolean $includeDatabaseName Whether to include the schema name in the results
323  *
324  * @return array An array of all the tables in the database.
325  *
326  * @since 12.1
327  * @throws RuntimeException
328  */
329  public function getTableList($databaseName = null, $includeDatabaseName = false)
330  {
331  $this->connect();
332 
333  $query = $this->getQuery(true);
334 
335  if ($includeDatabaseName)
336  {
337  $query->select('owner, table_name');
338  }
339  else
340  {
341  $query->select('table_name');
342  }
343 
344  $query->from('all_tables');
345  if ($databaseName)
346  {
347  $query->where('owner = :database')
348  ->bind(':database', $databaseName);
349  }
350 
351  $query->order('table_name');
352 
353  $this->setQuery($query);
354 
355  if ($includeDatabaseName)
356  {
357  $tables = $this->loadAssocList();
358  }
359  else
360  {
361  $tables = $this->loadColumn();
362  }
363 
364  return $tables;
365  }
366 
367  /**
368  * Get the version of the database connector.
369  *
370  * @return string The database connector version.
371  *
372  * @since 12.1
373  */
374  public function getVersion()
375  {
376  $this->connect();
377 
378  $this->setQuery("select value from nls_database_parameters where parameter = 'NLS_RDBMS_VERSION'");
379 
380  return $this->loadResult();
381  }
382 
383  /**
384  * Select a database for use.
385  *
386  * @param string $database The name of the database to select for use.
387  *
388  * @return boolean True if the database was successfully selected.
389  *
390  * @since 12.1
391  * @throws RuntimeException
392  */
393  public function select($database)
394  {
395  $this->connect();
396 
397  return true;
398  }
399 
400  /**
401  * Sets the Oracle Date Format for the session
402  * Default date format for Oracle is = DD-MON-RR
403  * The default date format for this driver is:
404  * 'RRRR-MM-DD HH24:MI:SS' since it is the format
405  * that matches the MySQL one used within most Joomla
406  * tables.
407  *
408  * @param string $dateFormat Oracle Date Format String
409  *
410  * @return boolean
411  *
412  * @since 12.1
413  */
414  public function setDateFormat($dateFormat = 'DD-MON-RR')
415  {
416  $this->connect();
417 
418  $this->setQuery("ALTER SESSION SET NLS_DATE_FORMAT = '$dateFormat'");
419 
420  if (!$this->execute())
421  {
422  return false;
423  }
424 
425  $this->setQuery("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = '$dateFormat'");
426  if (!$this->execute())
427  {
428  return false;
429  }
430 
431  $this->dateformat = $dateFormat;
432 
433  return true;
434  }
435 
436  /**
437  * Set the connection to use UTF-8 character encoding.
438  *
439  * Returns false automatically for the Oracle driver since
440  * you can only set the character set when the connection
441  * is created.
442  *
443  * @return boolean True on success.
444  *
445  * @since 12.1
446  */
447  public function setUTF()
448  {
449  return false;
450  }
451 
452  /**
453  * Locks a table in the database.
454  *
455  * @param string $table The name of the table to unlock.
456  *
457  * @return JDatabaseDriverOracle Returns this object to support chaining.
458  *
459  * @since 12.1
460  * @throws RuntimeException
461  */
462  public function lockTable($table)
463  {
464  $this->setQuery('LOCK TABLE ' . $this->quoteName($table) . ' IN EXCLUSIVE MODE')->execute();
465 
466  return $this;
467  }
468 
469  /**
470  * Renames a table in the database.
471  *
472  * @param string $oldTable The name of the table to be renamed
473  * @param string $newTable The new name for the table.
474  * @param string $backup Not used by Oracle.
475  * @param string $prefix Not used by Oracle.
476  *
477  * @return JDatabaseDriverOracle Returns this object to support chaining.
478  *
479  * @since 12.1
480  * @throws RuntimeException
481  */
482  public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
483  {
484  $this->setQuery('RENAME ' . $oldTable . ' TO ' . $newTable)->execute();
485 
486  return $this;
487  }
488 
489  /**
490  * Unlocks tables in the database.
491  *
492  * @return JDatabaseDriverOracle Returns this object to support chaining.
493  *
494  * @since 12.1
495  * @throws RuntimeException
496  */
497  public function unlockTables()
498  {
499  $this->setQuery('COMMIT')->execute();
500 
501  return $this;
502  }
503 
504  /**
505  * Test to see if the PDO ODBC connector is available.
506  *
507  * @return boolean True on success, false otherwise.
508  *
509  * @since 12.1
510  */
511  public static function isSupported()
512  {
513  return class_exists('PDO') && in_array('oci', PDO::getAvailableDrivers());
514  }
515 
516  /**
517  * This function replaces a string identifier <var>$prefix</var> with the string held is the
518  * <var>tablePrefix</var> class variable.
519  *
520  * @param string $query The SQL statement to prepare.
521  * @param string $prefix The common table prefix.
522  *
523  * @return string The processed SQL statement.
524  *
525  * @since 11.1
526  */
527  public function replacePrefix($query, $prefix = '#__')
528  {
529  $startPos = 0;
530  $quoteChar = "'";
531  $literal = '';
532 
533  $query = trim($query);
534  $n = strlen($query);
535 
536  while ($startPos < $n)
537  {
538  $ip = strpos($query, $prefix, $startPos);
539  if ($ip === false)
540  {
541  break;
542  }
543 
544  $j = strpos($query, "'", $startPos);
545 
546  if ($j === false)
547  {
548  $j = $n;
549  }
550 
551  $literal .= str_replace($prefix, $this->tablePrefix, substr($query, $startPos, $j - $startPos));
552  $startPos = $j;
553 
554  $j = $startPos + 1;
555 
556  if ($j >= $n)
557  {
558  break;
559  }
560 
561  // Quote comes first, find end of quote
562  while (true)
563  {
564  $k = strpos($query, $quoteChar, $j);
565  $escaped = false;
566  if ($k === false)
567  {
568  break;
569  }
570  $l = $k - 1;
571  while ($l >= 0 && $query{$l} == '\\')
572  {
573  $l--;
574  $escaped = !$escaped;
575  }
576  if ($escaped)
577  {
578  $j = $k + 1;
579  continue;
580  }
581  break;
582  }
583  if ($k === false)
584  {
585  // Error in the query - no end quote; ignore it
586  break;
587  }
588  $literal .= substr($query, $startPos, $k - $startPos + 1);
589  $startPos = $k + 1;
590  }
591  if ($startPos < $n)
592  {
593  $literal .= substr($query, $startPos, $n - $startPos);
594  }
595 
596  return $literal;
597  }
598 
599  /**
600  * Method to commit a transaction.
601  *
602  * @param boolean $toSavepoint If true, commit to the last savepoint.
603  *
604  * @return void
605  *
606  * @since 12.3
607  * @throws RuntimeException
608  */
609  public function transactionCommit($toSavepoint = false)
610  {
611  $this->connect();
612 
613  if (!$toSavepoint || $this->transactionDepth <= 1)
614  {
615  parent::transactionCommit($toSavepoint);
616  }
617  else
618  {
619  $this->transactionDepth--;
620  }
621  }
622 
623  /**
624  * Method to roll back a transaction.
625  *
626  * @param boolean $toSavepoint If true, rollback to the last savepoint.
627  *
628  * @return void
629  *
630  * @since 12.3
631  * @throws RuntimeException
632  */
633  public function transactionRollback($toSavepoint = false)
634  {
635  $this->connect();
636 
637  if (!$toSavepoint || $this->transactionDepth <= 1)
638  {
639  parent::transactionRollback($toSavepoint);
640  }
641  else
642  {
643  $savepoint = 'SP_' . ($this->transactionDepth - 1);
644  $this->setQuery('ROLLBACK TO SAVEPOINT ' . $this->quoteName($savepoint));
645 
646  if ($this->execute())
647  {
648  $this->transactionDepth--;
649  }
650  }
651  }
652 
653  /**
654  * Method to initialize a transaction.
655  *
656  * @param boolean $asSavepoint If true and a transaction is already active, a savepoint will be created.
657  *
658  * @return void
659  *
660  * @since 12.3
661  * @throws RuntimeException
662  */
663  public function transactionStart($asSavepoint = false)
664  {
665  $this->connect();
666 
667  if (!$asSavepoint || !$this->transactionDepth)
668  {
669  return parent::transactionStart($asSavepoint);
670  }
671 
672  $savepoint = 'SP_' . $this->transactionDepth;
673  $this->setQuery('SAVEPOINT ' . $this->quoteName($savepoint));
674 
675  if ($this->execute())
676  {
677  $this->transactionDepth++;
678  }
679  }
680 }