3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
6 * The PEAR DB driver for PHP's mysql extension
7 * for interacting with MySQL databases
11 * LICENSE: This source file is subject to version 3.0 of the PHP license
12 * that is available through the world-wide-web at the following URI:
13 * http://www.php.net/license/3_0.txt. If you did not receive a copy of
14 * the PHP License and are unable to obtain it through the web, please
15 * send a note to license@php.net so we can mail you a copy immediately.
19 * @author Stig Bakken <ssb@php.net>
20 * @author Daniel Convissor <danielc@php.net>
21 * @copyright 1997-2007 The PHP Group
22 * @license http://www.php.net/license/3_0.txt PHP License 3.0
23 * @version CVS: $Id: mysql.php,v 1.126 2007/09/21 13:32:52 aharvey Exp $
24 * @link http://pear.php.net/package/DB
28 * Obtain the DB_common class so it can be extended from
30 require_once 'DB/common.php';
33 * The methods PEAR DB uses to interact with PHP's mysql extension
34 * for interacting with MySQL databases
36 * These methods overload the ones declared in DB_common.
40 * @author Stig Bakken <ssb@php.net>
41 * @author Daniel Convissor <danielc@php.net>
42 * @copyright 1997-2007 The PHP Group
43 * @license http://www.php.net/license/3_0.txt PHP License 3.0
44 * @version Release: 1.7.13
45 * @link http://pear.php.net/package/DB
47 class DB_mysql
extends DB_common
52 * The DB driver type (mysql, oci8, odbc, etc.)
55 var $phptype = 'mysql';
58 * The database syntax variant to be used (db2, access, etc.), if any
61 var $dbsyntax = 'mysql';
64 * The capabilities of this DB implementation
66 * The 'new_link' element contains the PHP version that first provided
67 * new_link support for this DBMS. Contains false if it's unsupported.
69 * Meaning of the 'limit' element:
70 * + 'emulate' = emulate with fetch row by number
71 * + 'alter' = alter the query
76 var $features = array(
78 'new_link' => '4.2.0',
83 'transactions' => true,
87 * A mapping of native error codes to DB error codes
90 var $errorcode_map = array(
91 1004 => DB_ERROR_CANNOT_CREATE
,
92 1005 => DB_ERROR_CANNOT_CREATE
,
93 1006 => DB_ERROR_CANNOT_CREATE
,
94 1007 => DB_ERROR_ALREADY_EXISTS
,
95 1008 => DB_ERROR_CANNOT_DROP
,
96 1022 => DB_ERROR_ALREADY_EXISTS
,
97 1044 => DB_ERROR_ACCESS_VIOLATION
,
98 1046 => DB_ERROR_NODBSELECTED
,
99 1048 => DB_ERROR_CONSTRAINT
,
100 1049 => DB_ERROR_NOSUCHDB
,
101 1050 => DB_ERROR_ALREADY_EXISTS
,
102 1051 => DB_ERROR_NOSUCHTABLE
,
103 1054 => DB_ERROR_NOSUCHFIELD
,
104 1061 => DB_ERROR_ALREADY_EXISTS
,
105 1062 => DB_ERROR_ALREADY_EXISTS
,
106 1064 => DB_ERROR_SYNTAX
,
107 1091 => DB_ERROR_NOT_FOUND
,
108 1100 => DB_ERROR_NOT_LOCKED
,
109 1136 => DB_ERROR_VALUE_COUNT_ON_ROW
,
110 1142 => DB_ERROR_ACCESS_VIOLATION
,
111 1146 => DB_ERROR_NOSUCHTABLE
,
112 1216 => DB_ERROR_CONSTRAINT
,
113 1217 => DB_ERROR_CONSTRAINT
,
114 1356 => DB_ERROR_INVALID_VIEW
,
115 1365 => DB_ERROR_DIVZERO
,
116 1451 => DB_ERROR_CONSTRAINT
,
117 1452 => DB_ERROR_CONSTRAINT
,
121 * The raw database connection created by PHP
127 * The DSN information for connecting to a database
134 * Should data manipulation queries be committed automatically?
138 var $autocommit = true;
141 * The quantity of transactions begun
143 * {@internal While this is private, it can't actually be designated
144 * private in PHP 5 because it is directly accessed in the test suite.}}
149 var $transaction_opcount = 0;
152 * The database specified in the DSN
154 * It's a fix to allow calls to different databases in the same script.
166 * This constructor calls <kbd>$this->DB_common()</kbd>
179 * Connect to the database server, log in and open the database
181 * Don't call this method directly. Use DB::connect() instead.
183 * PEAR DB's mysql driver supports the following extra DSN options:
184 * + new_link If set to true, causes subsequent calls to connect()
185 * to return a new connection link instead of the
186 * existing one. WARNING: this is not portable to
187 * other DBMS's. Available since PEAR DB 1.7.0.
188 * + client_flags Any combination of MYSQL_CLIENT_* constants.
189 * Only used if PHP is at version 4.3.0 or greater.
190 * Available since PEAR DB 1.7.0.
192 * @param array $dsn the data source name
193 * @param bool $persistent should the connection be persistent?
195 * @return int DB_OK on success. A DB_Error object on failure.
197 function connect($dsn, $persistent = false)
199 if (!PEAR
::loadExtension('mysql')) {
200 return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND
);
204 if ($dsn['dbsyntax']) {
205 $this->dbsyntax
= $dsn['dbsyntax'];
209 if ($dsn['protocol'] && $dsn['protocol'] == 'unix') {
210 $params[0] = ':' . $dsn['socket'];
212 $params[0] = $dsn['hostspec'] ?
$dsn['hostspec']
215 $params[0] .= ':' . $dsn['port'];
218 $params[] = $dsn['username'] ?
$dsn['username'] : null;
219 $params[] = $dsn['password'] ?
$dsn['password'] : null;
222 if (isset($dsn['new_link'])
223 && ($dsn['new_link'] == 'true' ||
$dsn['new_link'] === true))
230 if (version_compare(phpversion(), '4.3.0', '>=')) {
231 $params[] = isset($dsn['client_flags'])
232 ?
$dsn['client_flags'] : null;
235 $connect_function = $persistent ?
'mysql_pconnect' : 'mysql_connect';
237 $ini = ini_get('track_errors');
240 $this->connection
= @call_user_func_array
($connect_function,
243 @ini_set
('track_errors', 1);
244 $this->connection
= @call_user_func_array
($connect_function,
246 @ini_set
('track_errors', $ini);
249 if (!$this->connection
) {
250 if (($err = @mysql_error
()) != '') {
251 return $this->raiseError(DB_ERROR_CONNECT_FAILED
,
255 return $this->raiseError(DB_ERROR_CONNECT_FAILED
,
261 if ($dsn['database']) {
262 if (!@mysql_select_db
($dsn['database'], $this->connection
)) {
263 return $this->mysqlRaiseError();
265 $this->_db
= $dsn['database'];
275 * Disconnects from the database server
277 * @return bool TRUE on success, FALSE on failure
279 function disconnect()
281 $ret = @mysql_close
($this->connection
);
282 $this->connection
= null;
290 * Sends a query to the database server
292 * Generally uses mysql_query(). If you want to use
293 * mysql_unbuffered_query() set the "result_buffering" option to 0 using
294 * setOptions(). This option was added in Release 1.7.0.
296 * @param string the SQL query string
298 * @return mixed + a PHP result resrouce for successful SELECT queries
299 * + the DB_OK constant for other successful queries
300 * + a DB_Error object on failure
302 function simpleQuery($query)
304 $ismanip = $this->_checkManip($query);
305 $this->last_query
= $query;
306 $query = $this->modifyQuery($query);
308 if (!@mysql_select_db
($this->_db
, $this->connection
)) {
309 return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED
);
312 if (!$this->autocommit
&& $ismanip) {
313 if ($this->transaction_opcount
== 0) {
314 $result = @mysql_query
('SET AUTOCOMMIT=0', $this->connection
);
315 $result = @mysql_query
('BEGIN', $this->connection
);
317 return $this->mysqlRaiseError();
320 $this->transaction_opcount++
;
322 if (!$this->options
['result_buffering']) {
323 $result = @mysql_unbuffered_query
($query, $this->connection
);
325 $result = @mysql_query
($query, $this->connection
);
328 return $this->mysqlRaiseError();
330 if (is_resource($result)) {
340 * Move the internal mysql result pointer to the next available result
342 * This method has not been implemented yet.
344 * @param a valid sql result resource
348 function nextResult($result)
357 * Places a row from the result set into the given array
359 * Formating of the array and the data therein are configurable.
360 * See DB_result::fetchInto() for more information.
362 * This method is not meant to be called directly. Use
363 * DB_result::fetchInto() instead. It can't be declared "protected"
364 * because DB_result is a separate object.
366 * @param resource $result the query result resource
367 * @param array $arr the referenced array to put the data in
368 * @param int $fetchmode how the resulting array should be indexed
369 * @param int $rownum the row number to fetch (0 = first row)
371 * @return mixed DB_OK on success, NULL when the end of a result set is
372 * reached or on failure
374 * @see DB_result::fetchInto()
376 function fetchInto($result, &$arr, $fetchmode, $rownum = null)
378 if ($rownum !== null) {
379 if (!@mysql_data_seek
($result, $rownum)) {
383 if ($fetchmode & DB_FETCHMODE_ASSOC
) {
384 $arr = @mysql_fetch_array
($result, MYSQL_ASSOC
);
385 if ($this->options
['portability'] & DB_PORTABILITY_LOWERCASE
&& $arr) {
386 $arr = array_change_key_case($arr, CASE_LOWER
);
389 $arr = @mysql_fetch_row
($result);
394 if ($this->options
['portability'] & DB_PORTABILITY_RTRIM
) {
396 * Even though this DBMS already trims output, we do this because
397 * a field might have intentional whitespace at the end that
398 * gets removed by DB_PORTABILITY_RTRIM under another driver.
400 $this->_rtrimArrayValues($arr);
402 if ($this->options
['portability'] & DB_PORTABILITY_NULL_TO_EMPTY
) {
403 $this->_convertNullArrayValuesToEmpty($arr);
412 * Deletes the result set and frees the memory occupied by the result set
414 * This method is not meant to be called directly. Use
415 * DB_result::free() instead. It can't be declared "protected"
416 * because DB_result is a separate object.
418 * @param resource $result PHP's query result resource
420 * @return bool TRUE on success, FALSE if $result is invalid
422 * @see DB_result::free()
424 function freeResult($result)
426 return is_resource($result) ?
mysql_free_result($result) : false;
433 * Gets the number of columns in a result set
435 * This method is not meant to be called directly. Use
436 * DB_result::numCols() instead. It can't be declared "protected"
437 * because DB_result is a separate object.
439 * @param resource $result PHP's query result resource
441 * @return int the number of columns. A DB_Error object on failure.
443 * @see DB_result::numCols()
445 function numCols($result)
447 $cols = @mysql_num_fields
($result);
449 return $this->mysqlRaiseError();
458 * Gets the number of rows in a result set
460 * This method is not meant to be called directly. Use
461 * DB_result::numRows() instead. It can't be declared "protected"
462 * because DB_result is a separate object.
464 * @param resource $result PHP's query result resource
466 * @return int the number of rows. A DB_Error object on failure.
468 * @see DB_result::numRows()
470 function numRows($result)
472 $rows = @mysql_num_rows
($result);
473 if ($rows === null) {
474 return $this->mysqlRaiseError();
483 * Enables or disables automatic commits
485 * @param bool $onoff true turns it on, false turns it off
487 * @return int DB_OK on success. A DB_Error object if the driver
488 * doesn't support auto-committing transactions.
490 function autoCommit($onoff = false)
492 // XXX if $this->transaction_opcount > 0, we should probably
493 // issue a warning here.
494 $this->autocommit
= $onoff ?
true : false;
502 * Commits the current transaction
504 * @return int DB_OK on success. A DB_Error object on failure.
508 if ($this->transaction_opcount
> 0) {
510 if (!@mysql_select_db
($this->_db
, $this->connection
)) {
511 return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED
);
514 $result = @mysql_query
('COMMIT', $this->connection
);
515 $result = @mysql_query
('SET AUTOCOMMIT=1', $this->connection
);
516 $this->transaction_opcount
= 0;
518 return $this->mysqlRaiseError();
528 * Reverts the current transaction
530 * @return int DB_OK on success. A DB_Error object on failure.
534 if ($this->transaction_opcount
> 0) {
536 if (!@mysql_select_db
($this->_db
, $this->connection
)) {
537 return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED
);
540 $result = @mysql_query
('ROLLBACK', $this->connection
);
541 $result = @mysql_query
('SET AUTOCOMMIT=1', $this->connection
);
542 $this->transaction_opcount
= 0;
544 return $this->mysqlRaiseError();
551 // {{{ affectedRows()
554 * Determines the number of rows affected by a data maniuplation query
556 * 0 is returned for queries that don't manipulate data.
558 * @return int the number of rows. A DB_Error object on failure.
560 function affectedRows()
562 if ($this->_last_query_manip
) {
563 return @mysql_affected_rows
($this->connection
);
573 * Returns the next free id in a sequence
575 * @param string $seq_name name of the sequence
576 * @param boolean $ondemand when true, the seqence is automatically
577 * created if it does not exist
579 * @return int the next id number in the sequence.
580 * A DB_Error object on failure.
582 * @see DB_common::nextID(), DB_common::getSequenceName(),
583 * DB_mysql::createSequence(), DB_mysql::dropSequence()
585 function nextId($seq_name, $ondemand = true)
587 $seqname = $this->getSequenceName($seq_name);
590 $this->pushErrorHandling(PEAR_ERROR_RETURN
);
591 $result = $this->query("UPDATE ${seqname} ".
592 'SET id=LAST_INSERT_ID(id+1)');
593 $this->popErrorHandling();
594 if ($result === DB_OK
) {
596 $id = @mysql_insert_id
($this->connection
);
601 // Sequence table must be empty for some reason, so fill
602 // it and return 1 and obtain a user-level lock
603 $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)");
604 if (DB
::isError($result)) {
605 return $this->raiseError($result);
608 // Failed to get the lock
609 return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED
);
612 // add the default value
613 $result = $this->query("REPLACE INTO ${seqname} (id) VALUES (0)");
614 if (DB
::isError($result)) {
615 return $this->raiseError($result);
619 $result = $this->getOne('SELECT RELEASE_LOCK('
620 . "'${seqname}_lock')");
621 if (DB
::isError($result)) {
622 return $this->raiseError($result);
624 // We know what the result will be, so no need to try again
627 } elseif ($ondemand && DB
::isError($result) &&
628 $result->getCode() == DB_ERROR_NOSUCHTABLE
)
630 // ONDEMAND TABLE CREATION
631 $result = $this->createSequence($seq_name);
632 if (DB
::isError($result)) {
633 return $this->raiseError($result);
638 } elseif (DB
::isError($result) &&
639 $result->getCode() == DB_ERROR_ALREADY_EXISTS
)
642 // see _BCsequence() comment
643 $result = $this->_BCsequence($seqname);
644 if (DB
::isError($result)) {
645 return $this->raiseError($result);
651 return $this->raiseError($result);
655 // {{{ createSequence()
658 * Creates a new sequence
660 * @param string $seq_name name of the new sequence
662 * @return int DB_OK on success. A DB_Error object on failure.
664 * @see DB_common::createSequence(), DB_common::getSequenceName(),
665 * DB_mysql::nextID(), DB_mysql::dropSequence()
667 function createSequence($seq_name)
669 $seqname = $this->getSequenceName($seq_name);
670 $res = $this->query('CREATE TABLE ' . $seqname
671 . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'
672 . ' PRIMARY KEY(id))');
673 if (DB
::isError($res)) {
676 // insert yields value 1, nextId call will generate ID 2
677 $res = $this->query("INSERT INTO ${seqname} (id) VALUES (0)");
678 if (DB
::isError($res)) {
682 return $this->query("UPDATE ${seqname} SET id = 0");
686 // {{{ dropSequence()
691 * @param string $seq_name name of the sequence to be deleted
693 * @return int DB_OK on success. A DB_Error object on failure.
695 * @see DB_common::dropSequence(), DB_common::getSequenceName(),
696 * DB_mysql::nextID(), DB_mysql::createSequence()
698 function dropSequence($seq_name)
700 return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
707 * Backwards compatibility with old sequence emulation implementation
708 * (clean up the dupes)
710 * @param string $seqname the sequence name to clean up
712 * @return bool true on success. A DB_Error object on failure.
716 function _BCsequence($seqname)
718 // Obtain a user-level lock... this will release any previous
719 // application locks, but unlike LOCK TABLES, it does not abort
720 // the current transaction and is much less frequently used.
721 $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)");
722 if (DB
::isError($result)) {
726 // Failed to get the lock, can't do the conversion, bail
727 // with a DB_ERROR_NOT_LOCKED error
728 return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED
);
731 $highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}");
732 if (DB
::isError($highest_id)) {
735 // This should kill all rows except the highest
736 // We should probably do something if $highest_id isn't
737 // numeric, but I'm at a loss as how to handle that...
738 $result = $this->query('DELETE FROM ' . $seqname
739 . " WHERE id <> $highest_id");
740 if (DB
::isError($result)) {
744 // If another thread has been waiting for this lock,
745 // it will go thru the above procedure, but will have no
747 $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')");
748 if (DB
::isError($result)) {
755 // {{{ quoteIdentifier()
758 * Quotes a string so it can be safely used as a table or column name
759 * (WARNING: using names that require this is a REALLY BAD IDEA)
761 * WARNING: Older versions of MySQL can't handle the backtick
762 * character (<kbd>`</kbd>) in table or column names.
764 * @param string $str identifier name to be quoted
766 * @return string quoted identifier string
768 * @see DB_common::quoteIdentifier()
769 * @since Method available since Release 1.6.0
771 function quoteIdentifier($str)
773 return '`' . str_replace('`', '``', $str) . '`';
780 * @deprecated Deprecated in release 1.6.0
782 function quote($str = null)
784 return $this->quoteSmart($str);
788 // {{{ escapeSimple()
791 * Escapes a string according to the current DBMS's standards
793 * @param string $str the string to be escaped
795 * @return string the escaped string
797 * @see DB_common::quoteSmart()
798 * @since Method available since Release 1.6.0
800 function escapeSimple($str)
802 return @mysql_real_escape_string
($str, $this->connection
);
809 * Changes a query string for various DBMS specific reasons
811 * This little hack lets you know how many rows were deleted
812 * when running a "DELETE FROM table" query. Only implemented
813 * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
815 * @param string $query the query string to modify
817 * @return string the modified query string
820 * @see DB_common::setOption()
822 function modifyQuery($query)
824 if ($this->options
['portability'] & DB_PORTABILITY_DELETE_COUNT
) {
825 // "DELETE FROM table" gives 0 affected rows in MySQL.
826 // This little hack lets you know how many rows were deleted.
827 if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
828 $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
829 'DELETE FROM \1 WHERE 1=1', $query);
836 // {{{ modifyLimitQuery()
839 * Adds LIMIT clauses to a query string according to current DBMS standards
841 * @param string $query the query to modify
842 * @param int $from the row to start to fetching (0 = the first row)
843 * @param int $count the numbers of rows to fetch
844 * @param mixed $params array, string or numeric data to be used in
845 * execution of the statement. Quantity of items
846 * passed must match quantity of placeholders in
847 * query: meaning 1 placeholder for non-array
848 * parameters or 1 placeholder per array element.
850 * @return string the query string with LIMIT clauses added
854 function modifyLimitQuery($query, $from, $count, $params = array())
856 if (DB
::isManip($query) ||
$this->_next_query_manip
) {
857 return $query . " LIMIT $count";
859 return $query . " LIMIT $from, $count";
864 // {{{ mysqlRaiseError()
867 * Produces a DB_Error object regarding the current problem
869 * @param int $errno if the error is being manually raised pass a
870 * DB_ERROR* constant here. If this isn't passed
871 * the error information gathered from the DBMS.
873 * @return object the DB_Error object
875 * @see DB_common::raiseError(),
876 * DB_mysql::errorNative(), DB_common::errorCode()
878 function mysqlRaiseError($errno = null)
880 if ($errno === null) {
881 if ($this->options
['portability'] & DB_PORTABILITY_ERRORS
) {
882 $this->errorcode_map
[1022] = DB_ERROR_CONSTRAINT
;
883 $this->errorcode_map
[1048] = DB_ERROR_CONSTRAINT_NOT_NULL
;
884 $this->errorcode_map
[1062] = DB_ERROR_CONSTRAINT
;
886 // Doing this in case mode changes during runtime.
887 $this->errorcode_map
[1022] = DB_ERROR_ALREADY_EXISTS
;
888 $this->errorcode_map
[1048] = DB_ERROR_CONSTRAINT
;
889 $this->errorcode_map
[1062] = DB_ERROR_ALREADY_EXISTS
;
891 $errno = $this->errorCode(mysql_errno($this->connection
));
893 return $this->raiseError($errno, null, null, null,
894 @mysql_errno
($this->connection
) . ' ** ' .
895 @mysql_error
($this->connection
));
902 * Gets the DBMS' native error code produced by the last query
904 * @return int the DBMS' error code
906 function errorNative()
908 return @mysql_errno
($this->connection
);
915 * Returns information about a table or a result set
917 * @param object|string $result DB_result object from a query or a
918 * string containing the name of a table.
919 * While this also accepts a query result
920 * resource identifier, this behavior is
922 * @param int $mode a valid tableInfo mode
924 * @return array an associative array with the information requested.
925 * A DB_Error object on failure.
927 * @see DB_common::tableInfo()
929 function tableInfo($result, $mode = null)
931 if (is_string($result)) {
932 // Fix for bug #11580.
934 if (!@mysql_select_db
($this->_db
, $this->connection
)) {
935 return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED
);
940 * Probably received a table name.
941 * Create a result resource identifier.
943 $id = @mysql_query
("SELECT * FROM $result LIMIT 0",
946 } elseif (isset($result->result
)) {
948 * Probably received a result object.
949 * Extract the result resource identifier.
951 $id = $result->result
;
955 * Probably received a result resource identifier.
957 * Deprecated. Here for compatibility only.
963 if (!is_resource($id)) {
964 return $this->mysqlRaiseError(DB_ERROR_NEED_MORE_DATA
);
967 if ($this->options
['portability'] & DB_PORTABILITY_LOWERCASE
) {
968 $case_func = 'strtolower';
970 $case_func = 'strval';
973 $count = @mysql_num_fields
($id);
977 $res['num_fields'] = $count;
980 for ($i = 0; $i < $count; $i++
) {
982 'table' => $case_func(@mysql_field_table
($id, $i)),
983 'name' => $case_func(@mysql_field_name
($id, $i)),
984 'type' => @mysql_field_type
($id, $i),
985 'len' => @mysql_field_len
($id, $i),
986 'flags' => @mysql_field_flags
($id, $i),
988 if ($mode & DB_TABLEINFO_ORDER
) {
989 $res['order'][$res[$i]['name']] = $i;
991 if ($mode & DB_TABLEINFO_ORDERTABLE
) {
992 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
996 // free the result only if we were called on a table
998 @mysql_free_result
($id);
1004 // {{{ getSpecialQuery()
1007 * Obtains the query string needed for listing a given type of objects
1009 * @param string $type the kind of objects you want to retrieve
1011 * @return string the SQL query string or null if the driver doesn't
1012 * support the object type requested
1015 * @see DB_common::getListOf()
1017 function getSpecialQuery($type)
1021 return 'SHOW TABLES';
1023 return 'SELECT DISTINCT User FROM mysql.user';
1025 return 'SHOW DATABASES';