58 var
$string_quoting = array(
'start' =>
"'",
'end' =>
"'",
'escape' =>
"'",
'escape_pattern' =>
'@');
73 $this->phptype =
'oci8';
74 $this->dbsyntax =
'oci8';
76 $this->supported[
'sequences'] =
true;
77 $this->supported[
'indexes'] =
true;
78 $this->supported[
'summary_functions'] =
true;
79 $this->supported[
'order_by_text'] =
true;
80 $this->supported[
'current_id'] =
true;
81 $this->supported[
'affected_rows'] =
true;
82 $this->supported[
'transactions'] =
true;
83 $this->supported[
'savepoints'] =
true;
84 $this->supported[
'limit_queries'] =
true;
85 $this->supported[
'LOBs'] =
true;
86 $this->supported[
'replace'] =
'emulated';
87 $this->supported[
'sub_selects'] =
true;
88 $this->supported[
'auto_increment'] =
false;
89 $this->supported[
'primary_key'] =
true;
90 $this->supported[
'result_introspection'] =
true;
91 $this->supported[
'prepared_statements'] =
true;
92 $this->supported[
'identifier_quoting'] =
true;
93 $this->supported[
'pattern_escaping'] =
true;
94 $this->supported[
'new_link'] =
true;
96 $this->options[
'DBA_username'] =
false;
97 $this->options[
'DBA_password'] =
false;
98 $this->options[
'database_name_prefix'] =
false;
99 $this->options[
'emulate_database'] =
true;
100 $this->options[
'default_tablespace'] =
false;
101 $this->options[
'default_text_field_length'] = 2000;
102 $this->options[
'result_prefetching'] =
false;
117 if (is_resource($error)) {
118 $error_data = @OCIError($error);
120 } elseif ($this->connection) {
121 $error_data = @OCIError($this->connection);
123 $error_data = @OCIError();
125 $native_code = $error_data[
'code'];
126 $native_msg = $error_data[
'message'];
127 if (is_null($error)) {
129 if (empty($ecode_map)) {
153 if (isset($ecode_map[$native_code])) {
154 $error = $ecode_map[$native_code];
157 return array($error, $native_code, $native_msg);
173 $this->
debug(
'Starting transaction/savepoint', __FUNCTION__, array(
'is_manip' =>
true,
'savepoint' => $savepoint));
174 if (!is_null($savepoint)) {
175 if (!$this->in_transaction) {
177 'savepoint cannot be released when changes are auto committed', __FUNCTION__);
179 $query =
'SAVEPOINT '.$savepoint;
181 } elseif ($this->in_transaction) {
184 if (!$this->destructor_registered && $this->opened_persistent) {
185 $this->destructor_registered =
true;
186 register_shutdown_function(
'MDB2_closeOpenTransactions');
188 $this->in_transaction =
true;
209 $this->
debug(
'Committing transaction/savepoint', __FUNCTION__, array(
'is_manip' =>
true,
'savepoint' => $savepoint));
210 if (!$this->in_transaction) {
212 'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__);
214 if (!is_null($savepoint)) {
218 if ($this->uncommitedqueries) {
225 'Unable to commit transaction', __FUNCTION__);
227 $this->uncommitedqueries = 0;
229 $this->in_transaction =
false;
249 $this->
debug(
'Rolling back transaction/savepoint', __FUNCTION__, array(
'is_manip' =>
true,
'savepoint' => $savepoint));
250 if (!$this->in_transaction) {
252 'rollback cannot be done changes are auto committed', __FUNCTION__);
254 if (!is_null($savepoint)) {
255 $query =
'ROLLBACK TO SAVEPOINT '.$savepoint;
259 if ($this->uncommitedqueries) {
266 'Unable to rollback transaction', __FUNCTION__);
268 $this->uncommitedqueries = 0;
270 $this->in_transaction =
false;
292 $this->
debug(
'Setting transaction isolation level', __FUNCTION__, array(
'is_manip' =>
true));
293 switch ($isolation) {
294 case 'READ UNCOMMITTED':
295 $isolation =
'READ COMMITTED';
296 case 'READ COMMITTED':
297 case 'REPEATABLE READ':
298 $isolation =
'SERIALIZABLE';
303 'isolation level is not supported: '.$isolation, __FUNCTION__);
306 $query =
"ALTER SESSION ISOLATION LEVEL $isolation";
319 function _doConnect($username, $password, $persistent =
false)
323 'extension '.$this->phptype.
' is not compiled into PHP', __FUNCTION__);
328 if (!empty($this->dsn[
'service']) && $this->dsn[
'hostspec']) {
332 $port = $this->dsn[
'port'] ? $this->dsn[
'port'] : 1521;
333 $sid = sprintf(
"(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)
334 (HOST=%s) (PORT=%s)))
335 (CONNECT_DATA=(SERVICE_NAME=%s)))",
336 $this->dsn[
'hostspec'],
338 $this->dsn[
'service']
340 } elseif ($this->dsn[
'hostspec']) {
344 $sid = $this->dsn[
'hostspec'];
349 if (!$this->options[
'emulate_database'] && $this->database_name) {
351 } elseif (getenv(
'ORACLE_SID')) {
352 $sid = getenv(
'ORACLE_SID');
353 } elseif ($sid = getenv(
'TWO_TASK')) {
354 $sid = getenv(
'TWO_TASK');
357 'not a valid connection string or environment variable [ORACLE_SID|TWO_TASK] not set',
362 if (function_exists(
'oci_connect')) {
363 if (isset($this->dsn[
'new_link'])
364 && ($this->dsn[
'new_link'] ==
'true' || $this->dsn[
'new_link'] ===
true)
366 $connect_function =
'oci_new_connect';
368 $connect_function = $persistent ?
'oci_pconnect' :
'oci_connect';
371 $charset = empty($this->dsn[
'charset']) ? null : $this->dsn[
'charset'];
372 $connection = @$connect_function($username, $password, $sid, $charset);
373 $error = @OCIError();
374 if (isset($error[
'code']) && $error[
'code'] == 12541) {
376 $connection = @$connect_function($username, $password, null, $charset);
379 $connect_function = $persistent ?
'OCIPLogon' :
'OCILogon';
380 $connection = @$connect_function($username, $password, $sid);
382 if (!empty($this->dsn[
'charset'])) {
392 'unable to establish a connection', __FUNCTION__);
395 if (empty($this->dsn[
'disable_iso_date'])) {
396 $query =
"ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'";
404 $query =
"ALTER SESSION SET NLS_NUMERIC_CHARACTERS='. '";
425 if ($this->database_name && $this->options[
'emulate_database']) {
426 $this->dsn[
'username'] = $this->options[
'database_name_prefix'].$this->database_name;
428 if (is_resource($this->connection)) {
429 if (count(array_diff($this->connected_dsn, $this->dsn)) == 0
430 && $this->connected_database_name == $this->database_name
431 && $this->opened_persistent == $this->options[
'persistent']
439 $this->dsn[
'username'],
440 $this->dsn[
'password'],
441 $this->options[
'persistent']
449 $this->opened_persistent = $this->options[
'persistent'];
450 $this->dbsyntax = $this->dsn[
'dbsyntax'] ? $this->dsn[
'dbsyntax'] :
$this->phptype;
452 $this->as_keyword =
' ';
454 if (is_array($server_info)) {
455 if ($server_info[
'major'] >=
'10') {
456 $this->as_keyword =
' AS ';
476 if (is_resource($this->connection)) {
477 if ($this->in_transaction) {
480 $persistent = $this->options[
'persistent'];
487 $this->options[
'persistent'] = $persistent;
490 if (!$this->opened_persistent || $force) {
491 if (function_exists(
'oci_close')) {
492 @oci_close($this->connection);
494 @OCILogOff($this->connection);
497 $this->uncommitedqueries = 0;
515 $this->options[
'DBA_username'],
516 $this->options[
'DBA_password'],
517 $this->options[
'persistent']
525 $this->offset = $this->limit = 0;
555 $this->options[
'DBA_username'],
556 $this->options[
'DBA_password'],
557 $this->options[
'persistent']
565 $this->offset = $this->limit = 0;
576 return $affected_rows;
597 if (preg_match(
'/^\s*SELECT/i',
$query)) {
598 if (!preg_match(
'/\sFROM\s/i',
$query)) {
606 $query =
"SELECT * FROM (SELECT a.*, ROWNUM mdb2rn FROM ($query) a WHERE ROWNUM <= $max) WHERE mdb2rn >= $min";
608 $query =
"SELECT a.* FROM ($query) a WHERE ROWNUM <= $max";
629 $this->last_query =
$query;
630 $result = $this->
debug(
$query,
'query', array(
'is_manip' => $is_manip,
'when' =>
'pre'));
654 'Could not create statement', __FUNCTION__);
658 $mode = $this->in_transaction ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS;
659 if (!@OCIExecute(
$result, $mode)) {
661 'Could not execute statement', __FUNCTION__);
665 if (is_numeric($this->options[
'result_prefetching'])) {
666 @ocisetprefetch(
$result, $this->options[
'result_prefetching']);
669 $this->
debug(
$query,
'query', array(
'is_manip' => $is_manip,
'when' =>
'post',
'result' =>
$result));
711 if ($this->connected_server_info) {
718 'Could not get server information', __FUNCTION__);
721 $this->connected_server_info = $server_info;
723 if (!preg_match(
'/ (\d+)\.(\d+)\.(\d+)\.([\d\.]+) /', $server_info, $tmp)) {
725 'Could not parse version information:'.$server_info, __FUNCTION__);
727 $server_info = array(
732 'native' => $server_info,
761 function &
prepare(
$query, $types = null, $result_types = null, $lobs = array())
763 if ($this->options[
'emulate_prepared']) {
770 $this->offset = $this->limit = 0;
771 $result = $this->
debug(
$query, __FUNCTION__, array(
'is_manip' => $is_manip,
'when' =>
'pre'));
779 $placeholder_type_guess = $placeholder_type = null;
782 $positions = array();
785 while ($position < strlen(
$query)) {
786 $q_position = strpos(
$query, $question, $position);
787 $c_position = strpos(
$query, $colon, $position);
788 if ($q_position && $c_position) {
789 $p_position = min($q_position, $c_position);
790 } elseif ($q_position) {
791 $p_position = $q_position;
792 } elseif ($c_position) {
793 $p_position = $c_position;
797 if (is_null($placeholder_type)) {
798 $placeholder_type_guess =
$query[$p_position];
805 if ($new_pos != $position) {
806 $position = $new_pos;
810 if (
$query[$position] == $placeholder_type_guess) {
811 if (is_null($placeholder_type)) {
812 $placeholder_type =
$query[$p_position];
813 $question = $colon = $placeholder_type;
814 if (!empty($types) && is_array($types)) {
815 if ($placeholder_type ==
':') {
816 if (is_int(key($types))) {
822 $types = array_values($types);
826 if ($placeholder_type ==
':') {
827 $parameter = preg_replace(
'/^.{'.($position+1).
'}([a-z0-9_]+).*$/si',
'\\1',
$query);
828 if ($parameter ===
'') {
830 'named parameter with an empty name', __FUNCTION__);
834 if (isset($count) && isset($types_tmp[++$count])) {
835 $types[$parameter] = $types_tmp[$count];
837 $length = strlen($parameter) + 1;
840 $length = strlen($parameter);
842 if (!in_array($parameter, $positions)) {
843 $positions[] = $parameter;
845 if (isset($types[$parameter])
846 && ($types[$parameter] ==
'clob' || $types[$parameter] ==
'blob')
848 if (!isset($lobs[$parameter])) {
849 $lobs[$parameter] = $parameter;
851 $value = $this->
quote(
true, $types[$parameter]);
852 $query = substr_replace(
$query, $value, $p_position, $length);
853 $position = $p_position + strlen($value) - 1;
854 } elseif ($placeholder_type ==
'?') {
855 $query = substr_replace(
$query,
':'.$parameter, $p_position, 1);
856 $position = $p_position + $length;
858 $position = $p_position + 1;
861 $position = $p_position;
864 if (is_array($lobs)) {
866 foreach ($lobs as $parameter => $field) {
868 $variables.= ($variables ?
', ' :
' INTO ').
':'.$parameter;
879 'Could not create statement', __FUNCTION__);
883 $class_name =
'MDB2_Statement_'.$this->phptype;
884 $obj =&
new $class_name($this, $statement, $positions,
$query, $types, $result_types, $is_manip,
$limit,
$offset);
885 $this->
debug(
$query, __FUNCTION__, array(
'is_manip' => $is_manip,
'when' =>
'post',
'result' => $obj));
902 function nextID($seq_name, $ondemand =
true)
905 $query =
"SELECT $sequence_name.nextval FROM DUAL";
912 $result = $this->manager->createSequence($seq_name);
916 return $this->nextId($seq_name,
false);
936 $seq = $table.(empty($field) ?
'' :
'_'.$field);
938 return $this->
queryOne(
"SELECT $sequence_name.currval",
'integer');
954 $query =
'SELECT (last_number-1) FROM user_sequences';
955 $query.=
' WHERE sequence_name='.$this->quote($sequence_name,
'text');
956 $query.=
' OR sequence_name='.$this->quote(strtoupper($sequence_name),
'text');
990 $fetchmode = $this->db->fetchmode;
993 @OCIFetchInto($this->result,
$row, OCI_ASSOC+OCI_RETURN_NULLS);
997 $row = array_change_key_case(
$row, $this->db->options[
'field_case']);
1000 @OCIFetchInto($this->result,
$row, OCI_RETURN_NULLS);
1003 if ($this->result ===
false) {
1005 'resultset has already been freed', __FUNCTION__);
1012 if ($this->offset > 0) {
1018 if (empty($this->types)) {
1025 $this->db->_fixResultArrayValues(
$row, $mode);
1027 if (!empty($this->types)) {
1028 $row = $this->db->datatype->convertResultRow($this->types,
$row, $rtrim);
1030 if (!empty($this->values)) {
1034 $object_class = $this->db->options[
'fetch_class'];
1035 if ($object_class ==
'stdClass') {
1064 for ($column = 0; $column < $numcols; $column++) {
1065 $column_name = @OCIColumnName($this->result, $column + 1);
1069 $columns = array_change_key_case(
$columns, $this->db->options[
'field_case']);
1086 $cols = @OCINumCols($this->result);
1087 if (is_null($cols)) {
1088 if ($this->result ===
false) {
1090 'resultset has already been freed', __FUNCTION__);
1091 } elseif (is_null($this->result)) {
1092 return count($this->types);
1094 return $this->db->raiseError(null, null, null,
1095 'Could not get column count', __FUNCTION__);
1097 if ($this->offset > 0) {
1114 if (is_resource($this->result) && $this->db->connection) {
1115 $free = @OCIFreeCursor($this->result);
1116 if ($free ===
false) {
1117 return $this->db->raiseError(null, null, null,
1118 'Could not free result', __FUNCTION__);
1121 $this->result =
false;
1151 if (isset($this->buffer) && is_array($this->buffer)) {
1153 if (!end($this->buffer)) {
1156 } elseif (isset($this->buffer[
$rownum])) {
1157 return (
bool)$this->buffer[
$rownum];
1163 && (
$row = @OCIFetchInto($this->result,
$buffer, OCI_RETURN_NULLS))
1167 if ($this->offset > 0) {
1170 if (empty($this->types)) {
1171 foreach (array_keys(
$buffer) as $key) {
1172 if (is_a(
$buffer[$key],
'oci-lob')) {
1201 if ($this->result ===
false) {
1203 'resultset has already been freed', __FUNCTION__);
1205 } elseif (is_null($this->result)) {
1214 $target_rownum = $this->rownum + 1;
1216 $fetchmode = $this->db->fetchmode;
1222 $row = $this->buffer[$target_rownum];
1233 if (empty($this->types)) {
1240 $this->db->_fixResultArrayValues(
$row, $mode);
1242 if (!empty($this->types)) {
1243 $row = $this->db->datatype->convertResultRow($this->types,
$row, $rtrim);
1245 if (!empty($this->values)) {
1249 $object_class = $this->db->options[
'fetch_class'];
1250 if ($object_class ==
'stdClass') {
1272 if ($this->result ===
false) {
1274 'resultset has already been freed', __FUNCTION__);
1291 if ($this->result ===
false) {
1293 'resultset has already been freed', __FUNCTION__);
1294 } elseif (is_null($this->result)) {
1314 if ($this->result ===
false) {
1316 'resultset has already been freed', __FUNCTION__);
1317 } elseif (is_null($this->result)) {
1335 $this->buffer = null;
1336 $this->buffer_rownum = null;
1361 function &
_execute($result_class =
true, $result_wrap_class =
false)
1363 if (is_null($this->statement)) {
1368 $this->db->debug($this->query,
'execute', array(
'is_manip' => $this->is_manip,
'when' =>
'pre',
'parameters' => $this->values));
1369 if ($this->db->getOption(
'disable_query')) {
1370 $result = $this->is_manip ? 0 : null;
1374 $connection = $this->db->getConnection();
1380 $lobs = $quoted_values = array();
1382 foreach ($this->positions as $parameter) {
1383 if (!array_key_exists($parameter, $this->values)) {
1385 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
1387 $value = $this->values[$parameter];
1388 $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null;
1389 if ($type ==
'clob' || $type ==
'blob') {
1390 $lobs[$i][
'file'] =
false;
1391 if (is_resource($value)) {
1394 while (!feof($fp)) {
1395 $value.= fread($fp, 8192);
1397 } elseif (preg_match(
'/^(\w+:\/\/)(.*)$/', $value, $match)) {
1405 $lobs[$i][
'value'] = $value;
1406 $lobs[$i][
'descriptor'] = @OCINewDescriptor($connection, OCI_D_LOB);
1407 if (!is_object($lobs[$i][
'descriptor'])) {
1408 $result = $this->db->raiseError(null, null, null,
1409 'Unable to create descriptor for LOB in parameter: '.$parameter, __FUNCTION__);
1412 $lob_type = ($type ==
'blob' ? OCI_B_BLOB : OCI_B_CLOB);
1413 if (!@OCIBindByName($this->statement,
':'.$parameter, $lobs[$i][
'descriptor'], -1, $lob_type)) {
1414 $result = $this->db->raiseError($this->statement, null, null,
1415 'could not bind LOB parameter', __FUNCTION__);
1419 $quoted_values[$i] = $this->db->quote($value, $type,
false);
1421 return $quoted_values[$i];
1423 if (!@OCIBindByName($this->statement,
':'.$parameter, $quoted_values[$i])) {
1424 $result = $this->db->raiseError($this->statement, null, null,
1425 'could not bind non LOB parameter', __FUNCTION__);
1432 $lob_keys = array_keys($lobs);
1434 $mode = (!empty($lobs) || $this->db->in_transaction) ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS;
1435 if (!@OCIExecute($this->statement, $mode)) {
1436 $err =& $this->db->raiseError($this->statement, null, null,
1437 'could not execute statement', __FUNCTION__);
1441 if (!empty($lobs)) {
1442 foreach ($lob_keys as $i) {
1443 if (!is_null($lobs[$i][
'value']) && $lobs[$i][
'value'] !==
'') {
1444 if ($lobs[$i][
'file']) {
1445 $result = $lobs[$i][
'descriptor']->savefile($lobs[$i][
'value']);
1447 $result = $lobs[$i][
'descriptor']->save($lobs[$i][
'value']);
1450 $result = $this->db->raiseError(null, null, null,
1451 'Unable to save descriptor contents', __FUNCTION__);
1458 if (!$this->db->in_transaction) {
1459 if (!@OCICommit($connection)) {
1460 $result = $this->db->raiseError(null, null, null,
1461 'Unable to commit transaction', __FUNCTION__);
1464 ++$this->db->uncommitedqueries;
1470 $lob_keys = array_keys($lobs);
1471 foreach ($lob_keys as $i) {
1472 $lobs[$i][
'descriptor']->free();
1479 if ($this->is_manip) {
1480 $affected_rows = $this->db->_affectedRows($connection, $this->statement);
1481 return $affected_rows;
1484 $result =& $this->db->_wrapResult($this->statement, $this->result_types,
1485 $result_class, $result_wrap_class, $this->limit, $this->offset);
1486 $this->db->debug($this->query,
'execute', array(
'is_manip' => $this->is_manip,
'when' =>
'post',
'result' =>
$result));
1501 if (is_null($this->positions)) {
1502 return $this->db->raiseError(
MDB2_ERROR, null, null,
1503 'Prepared statement has already been freed', __FUNCTION__);
1507 if (!is_null($this->statement) && !@OCIFreeStatement($this->statement)) {
1508 $result = $this->db->raiseError(null, null, null,
1509 'Could not free statement', __FUNCTION__);