59 var
$string_quoting = array(
'start' =>
"'",
'end' =>
"'",
'escape' =>
'\\',
'escape_pattern' =>
'\\');
64 array(
'start' =>
'-- ',
'end' =>
"\n",
'escape' =>
false),
65 array(
'start' =>
'#',
'end' =>
"\n",
'escape' =>
false),
66 array(
'start' =>
'/*',
'end' =>
'*/',
'escape' =>
false),
82 $this->phptype =
'mysql';
83 $this->dbsyntax =
'mysql';
85 $this->supported[
'sequences'] =
'emulated';
86 $this->supported[
'indexes'] =
true;
87 $this->supported[
'affected_rows'] =
true;
88 $this->supported[
'transactions'] =
false;
89 $this->supported[
'savepoints'] =
false;
90 $this->supported[
'summary_functions'] =
true;
91 $this->supported[
'order_by_text'] =
true;
92 $this->supported[
'current_id'] =
'emulated';
93 $this->supported[
'limit_queries'] =
true;
94 $this->supported[
'LOBs'] =
true;
95 $this->supported[
'replace'] =
true;
96 $this->supported[
'sub_selects'] =
'emulated';
97 $this->supported[
'auto_increment'] =
true;
98 $this->supported[
'primary_key'] =
true;
99 $this->supported[
'result_introspection'] =
true;
100 $this->supported[
'prepared_statements'] =
'emulated';
101 $this->supported[
'identifier_quoting'] =
true;
102 $this->supported[
'pattern_escaping'] =
true;
103 $this->supported[
'new_link'] =
true;
105 $this->options[
'default_table_type'] =
'';
120 if ($this->connection) {
121 $native_code = @mysql_errno($this->connection);
122 $native_msg = @mysql_error($this->connection);
124 $native_code = @mysql_errno();
125 $native_msg = @mysql_error();
127 if (is_null($error)) {
129 if (empty($ecode_map)) {
169 if (isset($ecode_map[$native_code])) {
170 $error = $ecode_map[$native_code];
173 return array($error, $native_code, $native_msg);
190 function escape($text, $escape_wildcards =
false)
192 if ($escape_wildcards) {
199 $text = @mysql_real_escape_string($text,
$connection);
216 $this->
debug(
'Starting transaction/savepoint', __FUNCTION__, array(
'is_manip' =>
true,
'savepoint' => $savepoint));
218 if (!is_null($savepoint)) {
219 if (!$this->
supports(
'savepoints')) {
221 'savepoints are not supported', __FUNCTION__);
223 if (!$this->in_transaction) {
225 'savepoint cannot be released when changes are auto committed', __FUNCTION__);
227 $query =
'SAVEPOINT '.$savepoint;
229 } elseif ($this->in_transaction) {
232 if (!$this->destructor_registered && $this->opened_persistent) {
233 $this->destructor_registered =
true;
234 register_shutdown_function(
'MDB2_closeOpenTransactions');
236 $query = $this->start_transaction ?
'START TRANSACTION' :
'SET AUTOCOMMIT = 1';
241 $this->in_transaction =
true;
261 $this->
debug(
'Committing transaction/savepoint', __FUNCTION__, array(
'is_manip' =>
true,
'savepoint' => $savepoint));
262 if (!$this->in_transaction) {
264 'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__);
266 if (!is_null($savepoint)) {
267 if (!$this->
supports(
'savepoints')) {
269 'savepoints are not supported', __FUNCTION__);
272 if (version_compare($server_info[
'major'].
'.'.$server_info[
'minor'].
'.'.$server_info[
'patch'],
'5.0.3',
'<')) {
275 $query =
'RELEASE SAVEPOINT '.$savepoint;
279 if (!$this->
supports(
'transactions')) {
281 'transactions are not supported', __FUNCTION__);
288 if (!$this->start_transaction) {
289 $query =
'SET AUTOCOMMIT = 0';
295 $this->in_transaction =
false;
315 $this->
debug(
'Rolling back transaction/savepoint', __FUNCTION__, array(
'is_manip' =>
true,
'savepoint' => $savepoint));
316 if (!$this->in_transaction) {
318 'rollback cannot be done changes are auto committed', __FUNCTION__);
320 if (!is_null($savepoint)) {
321 if (!$this->
supports(
'savepoints')) {
323 'savepoints are not supported', __FUNCTION__);
325 $query =
'ROLLBACK TO SAVEPOINT '.$savepoint;
334 if (!$this->start_transaction) {
335 $query =
'SET AUTOCOMMIT = 0';
341 $this->in_transaction =
false;
363 $this->
debug(
'Setting transaction isolation level', __FUNCTION__, array(
'is_manip' =>
true));
364 if (!$this->
supports(
'transactions')) {
366 'transactions are not supported', __FUNCTION__);
368 switch ($isolation) {
369 case 'READ UNCOMMITTED':
370 case 'READ COMMITTED':
371 case 'REPEATABLE READ':
376 'isolation level is not supported: '.$isolation, __FUNCTION__);
379 $query =
"SET SESSION TRANSACTION ISOLATION LEVEL $isolation";
393 if (is_resource($this->connection)) {
395 #if (count(array_diff($this->connected_dsn, $this->dsn)) == 0
396 if($this->connected_dsn == $this->dsn
397 && $this->opened_persistent == $this->options[
'persistent']
398 && $this->connected_database_name == $this->database_name
407 'extension '.$this->phptype.
' is not compiled into PHP', __FUNCTION__);
411 if ($this->dsn[
'protocol'] && $this->dsn[
'protocol'] ==
'unix') {
412 $params[0] =
':' . $this->dsn[
'socket'];
414 $params[0] = $this->dsn[
'hostspec'] ? $this->dsn[
'hostspec']
416 if ($this->dsn[
'port']) {
417 $params[0].=
':' . $this->dsn[
'port'];
420 $params[] = $this->dsn[
'username'] ? $this->dsn[
'username'] : null;
421 $params[] = $this->dsn[
'password'] ? $this->dsn[
'password'] : null;
422 if (!$this->options[
'persistent']) {
423 if (isset($this->dsn[
'new_link'])
424 && ($this->dsn[
'new_link'] ==
'true' || $this->dsn[
'new_link'] ===
true)
431 if (version_compare(phpversion(),
'4.3.0',
'>=')) {
432 $params[] = isset($this->dsn[
'client_flags'])
433 ? $this->dsn[
'client_flags'] : null;
435 $connect_function = $this->options[
'persistent'] ?
'mysql_pconnect' :
'mysql_connect';
437 $connection = @call_user_func_array($connect_function, $params);
439 if (($err = @mysql_error()) !=
'') {
444 'unable to establish a connection', __FUNCTION__);
448 if (!empty($this->dsn[
'charset'])) {
457 $this->connected_database_name =
'';
458 $this->opened_persistent = $this->options[
'persistent'];
459 $this->dbsyntax = $this->dsn[
'dbsyntax'] ? $this->dsn[
'dbsyntax'] :
$this->phptype;
461 if ($this->database_name) {
462 if ($this->database_name != $this->connected_database_name) {
463 if (!@mysql_select_db($this->database_name,
$connection)) {
465 'Could not select the database: '.$this->database_name, __FUNCTION__);
472 $this->supported[
'transactions'] = $this->options[
'use_transactions'];
473 if ($this->options[
'default_table_type']) {
474 switch (strtoupper($this->options[
'default_table_type'])) {
486 $this->supported[
'transactions'] =
false;
487 $this->warnings[] = $this->options[
'default_table_type'] .
488 ' is not a supported default table type';
535 if (is_resource($this->connection)) {
536 if ($this->in_transaction) {
539 $persistent = $this->options[
'persistent'];
546 $this->options[
'persistent'] = $persistent;
549 if (!$this->opened_persistent || $force) {
550 @mysql_close($this->connection);
570 $this->last_query =
$query;
571 $result = $this->
debug(
$query,
'query', array(
'is_manip' => $is_manip,
'when' =>
'pre'));
578 if ($this->options[
'disable_query']) {
579 $result = $is_manip ? 0 : null;
604 $function = $this->options[
'result_buffering']
605 ?
'mysql_query' :
'mysql_unbuffered_query';
609 'Could not execute statement', __FUNCTION__);
613 $this->
debug(
$query,
'query', array(
'is_manip' => $is_manip,
'when' =>
'post',
'result' =>
$result));
657 if (preg_match(
'/^\s*DELETE\s+FROM\s+(\S+)\s*$/i',
$query)) {
658 $query = preg_replace(
'/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
659 'DELETE FROM \1 WHERE 1=1',
$query);
663 && !preg_match(
'/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i',
$query)
666 if (substr(
$query, -1) ==
';') {
673 if (preg_match(
'/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims',
$query, $matches)) {
674 $after = $matches[0];
675 $query = preg_replace(
'/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims',
'',
$query);
676 } elseif (preg_match(
'/(\s+FOR\s+UPDATE\s*)$/i',
$query, $matches)) {
677 $after = $matches[0];
678 $query = preg_replace(
'/(\s+FOR\s+UPDATE\s*)$/im',
'',
$query);
679 } elseif (preg_match(
'/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im',
$query, $matches)) {
680 $after = $matches[0];
681 $query = preg_replace(
'/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im',
'',
$query);
685 return $query .
" LIMIT $limit" . $after;
687 return $query .
" LIMIT $offset, $limit" . $after;
709 if ($this->connected_server_info) {
712 $server_info = @mysql_get_server_info(
$connection);
716 'Could not get server information', __FUNCTION__);
719 $this->connected_server_info = $server_info;
721 $tmp = explode(
'.', $server_info, 3);
722 if (isset($tmp[2]) && strpos($tmp[2],
'-')) {
723 $tmp2 = explode(
'-', @$tmp[2], 2);
725 $tmp2[0] = isset($tmp[2]) ? $tmp[2] : null;
728 $server_info = array(
729 'major' => isset($tmp[0]) ? $tmp[0] : null,
730 'minor' => isset($tmp[1]) ? $tmp[1] : null,
733 'native' => $server_info,
750 static $already_checked =
false;
751 if (!$already_checked) {
752 $already_checked =
true;
755 $this->supported[
'sub_selects'] =
'emulated';
756 $this->supported[
'prepared_statements'] =
'emulated';
757 $this->start_transaction =
false;
758 $this->varchar_max_length = 255;
761 if (is_array($server_info)) {
762 if (!version_compare($server_info[
'major'].
'.'.$server_info[
'minor'].
'.'.$server_info[
'patch'],
'4.1.0',
'<')) {
763 $this->supported[
'sub_selects'] =
true;
764 $this->supported[
'prepared_statements'] =
true;
767 if (!version_compare($server_info[
'major'].
'.'.$server_info[
'minor'].
'.'.$server_info[
'patch'],
'4.0.14',
'<')
768 || !version_compare($server_info[
'major'].
'.'.$server_info[
'minor'].
'.'.$server_info[
'patch'],
'4.1.1',
'<')
770 $this->supported[
'savepoints'] =
true;
773 if (!version_compare($server_info[
'major'].
'.'.$server_info[
'minor'].
'.'.$server_info[
'patch'],
'4.0.11',
'<')) {
774 $this->start_transaction =
true;
777 if (!version_compare($server_info[
'major'].
'.'.$server_info[
'minor'].
'.'.$server_info[
'patch'],
'5.0.3',
'<')) {
778 $this->varchar_max_length = 65532;
801 $found = strpos(strrev(substr(
$query, 0, $position)),
'@');
802 if ($found ===
false) {
805 $pos = strlen(
$query) - strlen(substr(
$query, $position)) - $found - 1;
806 $substring = substr(
$query, $pos, $position - $pos + 2);
807 if (preg_match(
'/^@\w+:=$/', $substring)) {
808 return $position + 1;
836 function &
prepare(
$query, $types = null, $result_types = null, $lobs = array())
838 if ($this->options[
'emulate_prepared']
839 || $this->supported[
'prepared_statements'] !==
true
847 $this->offset = $this->limit = 0;
849 $result = $this->
debug(
$query, __FUNCTION__, array(
'is_manip' => $is_manip,
'when' =>
'pre'));
856 $placeholder_type_guess = $placeholder_type = null;
859 $positions = array();
861 while ($position < strlen(
$query)) {
862 $q_position = strpos(
$query, $question, $position);
863 $c_position = strpos(
$query, $colon, $position);
864 if ($q_position && $c_position) {
865 $p_position = min($q_position, $c_position);
866 } elseif ($q_position) {
867 $p_position = $q_position;
868 } elseif ($c_position) {
869 $p_position = $c_position;
873 if (is_null($placeholder_type)) {
874 $placeholder_type_guess =
$query[$p_position];
881 if ($new_pos != $position) {
882 $position = $new_pos;
886 if (
$query[$position] == $placeholder_type_guess) {
887 if (is_null($placeholder_type)) {
888 $placeholder_type =
$query[$p_position];
889 $question = $colon = $placeholder_type;
891 if ($placeholder_type ==
':') {
894 if ($new_pos != $position) {
895 $position = $new_pos;
898 $parameter = preg_replace(
'/^.{'.($position+1).
'}([a-z0-9_]+).*$/si',
'\\1',
$query);
899 if ($parameter ===
'') {
901 'named parameter with an empty name', __FUNCTION__);
904 $positions[$p_position] = $parameter;
905 $query = substr_replace(
$query,
'?', $position, strlen($parameter)+1);
907 $positions[$p_position] = count($positions);
909 $position = $p_position + 1;
911 $position = $p_position;
918 $statement_name = sprintf($this->options[
'statement_format'], $this->phptype, md5(time() + rand()));
919 $query =
"PREPARE $statement_name FROM ".$this->quote(
$query,
'text');
925 $class_name =
'MDB2_Statement_'.$this->phptype;
926 $obj =&
new $class_name($this, $statement_name, $positions,
$query, $types, $result_types, $is_manip,
$limit,
$offset);
927 $this->
debug(
$query, __FUNCTION__, array(
'is_manip' => $is_manip,
'when' =>
'post',
'result' => $obj));
1000 $count = count($fields);
1002 $keys = $colnum = 0;
1003 for (reset($fields); $colnum < $count; next($fields), $colnum++) {
1004 $name = key($fields);
1010 if (isset($fields[$name][
'null']) && $fields[$name][
'null']) {
1013 $type = isset($fields[$name][
'type']) ? $fields[$name][
'type'] : null;
1014 $value = $this->
quote($fields[$name][
'value'], $type);
1017 if (isset($fields[$name][
'key']) && $fields[$name][
'key']) {
1018 if ($value ===
'NULL') {
1020 'key value '.$name.
' may not be NULL', __FUNCTION__);
1027 'not specified which fields are keys', __FUNCTION__);
1035 $query =
"REPLACE INTO $table ($query) VALUES ($values)";
1060 $seqcol_name = $this->
quoteIdentifier($this->options[
'seqcol_name'],
true);
1061 $query =
"INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL)";
1068 $result = $this->manager->createSequence($seq_name);
1071 'on demand sequence '.$seq_name.
' could not be created', __FUNCTION__);
1073 return $this->
nextID($seq_name,
false);
1079 if (is_numeric($value)) {
1080 $query =
"DELETE FROM $sequence_name WHERE $seqcol_name < $value";
1083 $this->warnings[] =
'nextID: could not delete previous sequence table values from '.$seq_name;
1104 return $this->
queryOne(
'SELECT LAST_INSERT_ID()',
'integer');
1120 $seqcol_name = $this->
quoteIdentifier($this->options[
'seqcol_name'],
true);
1121 $query =
"SELECT MAX($seqcol_name) FROM $sequence_name";
1155 $fetchmode = $this->db->fetchmode;
1158 $row = @mysql_fetch_assoc($this->result);
1162 $row = array_change_key_case(
$row, $this->db->options[
'field_case']);
1165 $row = @mysql_fetch_row($this->result);
1169 if ($this->result ===
false) {
1171 'resultset has already been freed', __FUNCTION__);
1179 $this->db->_fixResultArrayValues(
$row, $mode);
1181 if (!empty($this->types)) {
1182 $row = $this->db->datatype->convertResultRow($this->types,
$row,
false);
1184 if (!empty($this->values)) {
1188 $object_class = $this->db->options[
'fetch_class'];
1189 if ($object_class ==
'stdClass') {
1218 for ($column = 0; $column < $numcols; $column++) {
1219 $column_name = @mysql_field_name($this->result, $column);
1223 $columns = array_change_key_case(
$columns, $this->db->options[
'field_case']);
1240 $cols = @mysql_num_fields($this->result);
1241 if (is_null($cols)) {
1242 if ($this->result ===
false) {
1244 'resultset has already been freed', __FUNCTION__);
1245 } elseif (is_null($this->result)) {
1246 return count($this->types);
1248 return $this->db->raiseError(null, null, null,
1249 'Could not get column count', __FUNCTION__);
1265 if (is_resource($this->result) && $this->db->connection) {
1266 $free = @mysql_free_result($this->result);
1267 if ($free ===
false) {
1268 return $this->db->raiseError(null, null, null,
1269 'Could not free result', __FUNCTION__);
1272 $this->result =
false;
1298 if ($this->rownum != (
$rownum - 1) && !@mysql_data_seek($this->result,
$rownum)) {
1299 if ($this->result ===
false) {
1301 'resultset has already been freed', __FUNCTION__);
1302 } elseif (is_null($this->result)) {
1306 'tried to seek to an invalid row number ('.
$rownum.
')', __FUNCTION__);
1327 return $this->rownum < ($numrows - 1);
1341 $rows = @mysql_num_rows($this->result);
1342 if (is_null($rows)) {
1343 if ($this->result ===
false) {
1345 'resultset has already been freed', __FUNCTION__);
1346 } elseif (is_null($this->result)) {
1349 return $this->db->raiseError(null, null, null,
1350 'Could not get row count', __FUNCTION__);
1375 function &
_execute($result_class =
true, $result_wrap_class =
false)
1377 if (is_null($this->statement)) {
1382 $this->db->debug($this->query,
'execute', array(
'is_manip' => $this->is_manip,
'when' =>
'pre',
'parameters' => $this->values));
1383 if ($this->db->getOption(
'disable_query')) {
1384 $result = $this->is_manip ? 0 : null;
1388 $connection = $this->db->getConnection();
1393 $query =
'EXECUTE '.$this->statement;
1394 if (!empty($this->positions)) {
1395 $parameters = array();
1396 foreach ($this->positions as $parameter) {
1397 if (!array_key_exists($parameter, $this->values)) {
1399 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
1401 $value = $this->values[$parameter];
1402 $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null;
1403 if (is_resource($value) || $type ==
'clob' || $type ==
'blob') {
1404 if (!is_resource($value) && preg_match(
'/^(\w+:\/\/)(.*)$/', $value, $match)) {
1405 if ($match[1] ==
'file://') {
1408 $value = @fopen($value,
'r');
1411 if (is_resource($value)) {
1413 while (!@feof($value)) {
1414 $data.= @fread($value, $this->db->options[
'lob_buffer_length']);
1422 $quoted = $this->db->quote($value, $type);
1426 $param_query =
'SET @'.$parameter.
' = '.$quoted;
1427 $result = $this->db->_doQuery($param_query,
true, $connection);
1432 $query.=
' USING @'.implode(
', @', array_values($this->positions));
1435 $result = $this->db->_doQuery(
$query, $this->is_manip, $connection);
1440 if ($this->is_manip) {
1441 $affected_rows = $this->db->_affectedRows($connection,
$result);
1442 return $affected_rows;
1446 $result_class, $result_wrap_class, $this->limit, $this->offset);
1447 $this->db->debug($this->query,
'execute', array(
'is_manip' => $this->is_manip,
'when' =>
'post',
'result' =>
$result));
1462 if (is_null($this->positions)) {
1463 return $this->db->raiseError(
MDB2_ERROR, null, null,
1464 'Prepared statement has already been freed', __FUNCTION__);
1468 if (!is_null($this->statement)) {
1469 $connection = $this->db->getConnection();
1473 $query =
'DEALLOCATE PREPARE '.$this->statement;