private $nrows;
private $unique;
-
+ private function array_unique_md($array_in) {
+ $array_out = array();
+ $array_hashes = array();
+
+ foreach($array_in as $key => $item) {
+ $hash = md5(serialize($item));
+ if (!isset($array_hashes[$hash])) {
+ $array_hashes[$hash] = $hash;
+ $array_out[] = $item;
+ }
+ }
+
+ return $array_out;
+ }
+
function __construct(&$db, $stmt, $unique = false) {
$this->db =& $db;
}
if ($unique) {
- $this->rows = array_unique($this->rows);
+ $this->rows = $this->array_unique_md($this->rows);
$this->nrows = count($this->rows);
}
var $mAffectedRows;
var $ignore_DUP_VAL_ON_INDEX = false;
+ var $sequenceData = null;
function DatabaseOracle($server = false, $user = false, $password = false, $dbName = false,
$failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
return true;
}
- static function newFromParams( $server = false, $user = false, $password = false, $dbName = false,
- $failFunction = false, $flags = 0)
+ static function newFromParams( $server, $user, $password, $dbName, $failFunction = false, $flags = 0 )
{
return new DatabaseOracle( $server, $user, $password, $dbName, $failFunction, $flags );
}
$union_unique = (preg_match('/\/\* UNION_UNIQUE \*\/ /', $sql) != 0);
//EXPLAIN syntax in Oracle is EXPLAIN PLAN FOR and it return nothing
//you have to select data from plan table after explain
+ $olderr = error_reporting(E_ERROR);
$explain_id = date('dmYHis');
+ error_reporting($olderr);
$sql = preg_replace('/^EXPLAIN /', 'EXPLAIN PLAN SET STATEMENT_ID = \''.$explain_id.'\' FOR', $sql, 1, $explain_count);
$first = true;
foreach ($row as $col => $val) {
if ($first)
- $sql .= ':'.$col;
+ $sql .= $val !== NULL ? ':'.$col : 'NULL';
else
- $sql.= ', :'.$col;
+ $sql .= $val !== NULL ? ', :'.$col : ', NULL';
$first = false;
}
$sql .= ')';
- $stmt = oci_parse($this->mConn, $sql);
- foreach ($row as $col => $val) {
- if (!is_object($val)) {
- if (oci_bind_by_name($stmt, ":$col", $row[$col]) === false)
- $this->reportQueryError($this->lastErrno(), $this->lastError(), $sql, __METHOD__);
- }
- }
$stmt = oci_parse($this->mConn, $sql);
- foreach ($row as $col => $val) {
+ foreach ($row as $col => &$val) {
$col_type=$this->fieldInfo($this->tableName($table), $col)->type();
- if ($col_type != 'BLOB' && $col_type != 'CLOB') {
+
+ if ($val === NULL) {
+ // do nothing ... null was inserted in statement creation
+ } elseif ($col_type != 'BLOB' && $col_type != 'CLOB') {
if (is_object($val))
$val = $val->getData();
-
+
if (preg_match('/^timestamp.*/i', $col_type) == 1 && strtolower($val) == 'infinity')
$val = '31-12-2030 12:00:00.000000';
- if (oci_bind_by_name($stmt, ":$col", $wgLang->checkTitleEncoding($val)) === false)
+ $val = $wgLang->checkTitleEncoding($val);
+ if (oci_bind_by_name($stmt, ":$col", $val) === false)
$this->reportQueryError($this->lastErrno(), $this->lastError(), $sql, __METHOD__);
} else {
if (($lob[$col] = oci_new_descriptor($this->mConn, OCI_D_LOB)) === false) {
}
}
}
-
+
$olderr = error_reporting(E_ERROR);
if (oci_execute($stmt, OCI_DEFAULT) === false) {
$e = oci_error($stmt);
} else {
$srcTable = $this->tableName( $srcTable );
}
+
+ if (($sequenceData = $this->getSequenceData($destTable)) !== false &&
+ !isset($varMap[$sequenceData['column']]))
+ $varMap[$sequenceData['column']] = 'GET_SEQUENCE_VALUE(\''.$sequenceData['sequence'].'\')';
+
+ // count-alias subselect fields to avoid abigious definition errors
+ $i=0;
+ foreach($varMap as $key=>&$val)
+ $val=$val.' field'.($i++);
+
$sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' .
" SELECT $startOpts " . implode( ',', $varMap ) .
" FROM $srcTable $useIndex ";
$sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
}
$sql .= " $tailOpts";
-
+
if (in_array('IGNORE', $insertOptions))
$this->ignore_DUP_VAL_ON_INDEX = true;
-
+
$retval = $this->query( $sql, $fname );
-
+
if (in_array('IGNORE', $insertOptions))
$this->ignore_DUP_VAL_ON_INDEX = false;
}
/**
- * Oracle does not have a "USE INDEX" clause, so return an empty string
+ * Return sequence_name if table has a sequence
*/
- function useIndexClause($index) {
- return '';
+ function getSequenceData($table) {
+ if ($this->sequenceData == NULL) {
+ $result = $this->query("SELECT lower(us.sequence_name), lower(utc.table_name), lower(utc.column_name) from user_sequences us, user_tab_columns utc where us.sequence_name = utc.table_name||'_'||utc.column_name||'_SEQ'");
+
+ while(($row = $result->fetchRow()) !== false)
+ $this->sequenceData[$this->tableName($row[1])] = array('sequence' => $row[0], 'column' => $row[2]);
+ }
+
+ return (isset($this->sequenceData[$table])) ? $this->sequenceData[$table] : false;
}
+
# REPLACE query wrapper
# Oracle simulates this with a DELETE followed by INSERT
return $size;
}
- function lowPriorityOption() {
- return '';
- }
-
- function limitResult($sql, $limit, $offset) {
+ function limitResult( $sql, $limit, $offset=false ) {
if ($offset === false)
$offset = 0;
return "SELECT * FROM ($sql) WHERE rownum >= (1 + $offset) AND rownum < (1 + $limit + $offset)";
}
- function unionQueries($sqls, $all = false) {
+ function unionQueries($sqls, $all) {
$glue = ' UNION ALL ';
return 'SELECT * '.($all?'':'/* UNION_UNIQUE */ ').'FROM ('.implode( $glue, $sqls ).')' ;
}
- /**
- * Returns an SQL expression for a simple conditional.
- * Uses CASE on Oracle
- *
- * @param $cond String: SQL expression which will result in a boolean value
- * @param $trueVal String: SQL expression to return if true
- * @param $falseVal String: SQL expression to return if false
- * @return String: SQL fragment
- */
- function conditional( $cond, $trueVal, $falseVal ) {
- return " (CASE WHEN $cond THEN $trueVal ELSE $falseVal END) ";
- }
-
function wasDeadlock() {
return $this->lastErrno() == 'OCI-00060';
}
* Query whether a given column exists in the mediawiki schema
* based on prebuilt table to simulate MySQL field info and keep query speed minimal
*/
- function fieldExists( $table, $field ) {
+ function fieldExists( $table, $field, $fname = 'DatabaseOracle::fieldExists' ) {
if (!isset($this->fieldInfo_stmt))
$this->fieldInfo_stmt = oci_parse($this->mConn, 'SELECT * FROM wiki_field_info_full WHERE table_name = upper(:tab) and column_name = UPPER(:col)');
if (!isset($this->fieldInfo_stmt))
$this->fieldInfo_stmt = oci_parse($this->mConn, 'SELECT * FROM wiki_field_info_full WHERE table_name = upper(:tab) and column_name = UPPER(:col)');
- oci_bind_by_name($this->fieldInfo_stmt, ':tab', trim($table, '"'));
+ $table = trim($table, '"');
+ oci_bind_by_name($this->fieldInfo_stmt, ':tab', $table);
oci_bind_by_name($this->fieldInfo_stmt, ':col', $field);
if (oci_execute($this->fieldInfo_stmt, OCI_DEFAULT) === false) {
global $wgVersion, $wgDBmwschema, $wgDBts2schema, $wgDBport, $wgDBuser;
echo "<li>Creating DB objects</li>\n";
- $res = dbsource( "../maintenance/ora/tables.sql", $this);
+ $res = $this->sourceFile( "../maintenance/ora/tables.sql" );
// Avoid the non-standard "REPLACE INTO" syntax
echo "<li>Populating table interwiki</li>\n";
return $s;
}
- /* For now, does nothing */
- function selectDB( $db ) {
- return true;
- }
-
function selectRow( $table, $vars, $conds, $fname = 'DatabaseOracle::selectRow', $options = array(), $join_conds = array() ) {
if (is_array($table))
foreach ($table as $tab)
return array( $startOpts, $useIndex, $preLimitTail, $postLimitTail );
}
- /* redundand ... will remove after confirming bitwise operations functionality
- public function makeList( $a, $mode = LIST_COMMA ) {
- if ( !is_array( $a ) ) {
- throw new DBUnexpectedError( $this, 'DatabaseOracle::makeList called with incorrect parameters' );
- }
- $a2 = array();
- foreach ($a as $key => $value) {
- if (strpos($key, ' & ') !== FALSE)
- $a2[preg_replace('/(.*)\s&\s(.*)/', 'BITAND($1, $2)', $key)] = $value;
- elseif (strpos($key, ' | ') !== FALSE)
- $a2[preg_replace('/(.*)\s|\s(.*)/', 'BITOR($1, $2)', $key)] = $value;
- elseif (!is_array($value)) {
- if (strpos($value, ' = ') !== FALSE) {
- if (strpos($value, ' & ') !== FALSE)
- $a2[$key] = preg_replace('/(.*)\s&\s(.*?)\s=\s(.*)/', 'BITAND($1, $2) = $3', $value);
- elseif (strpos($value, ' | ') !== FALSE)
- $a2[$key] = preg_replace('/(.*)\s|\s(.*?)\s=\s(.*)/', 'BITOR($1, $2) = $3', $value);
- else $a2[$key] = $value;
- }
- elseif (strpos($value, ' & ') !== FALSE)
- $a2[$key] = preg_replace('/(.*)\s&\s(.*)/', 'BITAND($1, $2)', $value);
- elseif (strpos($value, ' | ') !== FALSE)
- $a2[$key] = preg_replace('/(.*)\s|\s(.*)/', 'BITOR($1, $2)', $value);
- else
- $a2[$key] = $value;
- }
+ public function delete( $table, $conds, $fname = 'DatabaseOracle::delete' ) {
+
+ $conds2 = array();
+ foreach($conds as $col=>$val) {
+ $col_type=$this->fieldInfo($this->tableName($table), $col)->type();
+ if ($col_type == 'CLOB')
+ $conds2['TO_CHAR('.$col.')'] = $val;
else
- $a2[$key] = $value;
+ $conds2[$col] = $val;
}
- return parent::makeList($a2, $mode);
+ return parent::delete( $table, $conds2, $fname );
}
- */
function bitNot($field) {
//expecting bit-fields smaller than 4bytes
return 'BITOR('.$fieldLeft.', '.$fieldRight.')';
}
- public function setTimeout( $timeout ) {
- // @todo fixme no-op
- }
-
- function ping() {
- wfDebug( "Function ping() not written for DatabaseOracle.php yet");
- return true;
- }
-
/**
* How lagged is this slave?
*
return parent::replaceVars($ins);
}
- /**
- * No-op lock functions
- */
- public function lock( $lockName, $method ) {
- return true;
- }
- public function unlock( $lockName, $method ) {
- return true;
- }
-
public function getSearchEngine() {
return "SearchOracle";
}
-
- /** No-op */
- public function setBigSelects( $value = true ) {}
-
} // end DatabaseOracle class