aboutsummaryrefslogtreecommitdiffstats
path: root/lib/db.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/db.php')
-rw-r--r--lib/db.php266
1 files changed, 150 insertions, 116 deletions
diff --git a/lib/db.php b/lib/db.php
index a6b81aaba69..a93b9eccbdf 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -180,28 +180,18 @@ class OC_DB {
$dsn = 'oci:dbname=//' . $host . '/' . $name;
}
break;
- case 'mssql':
+ case 'mssql':
if ($port) {
$dsn='sqlsrv:Server='.$host.','.$port.';Database='.$name;
} else {
$dsn='sqlsrv:Server='.$host.';Database='.$name;
}
- break;
+ break;
default:
return false;
}
- try{
- self::$PDO=new PDO($dsn, $user, $pass, $opts);
- }catch(PDOException $e) {
- OC_Log::write('core', $e->getMessage(), OC_Log::FATAL);
- OC_User::setUserId(null);
-
- // send http status 503
- header('HTTP/1.1 503 Service Temporarily Unavailable');
- header('Status: 503 Service Temporarily Unavailable');
- OC_Template::printErrorPage('Failed to connect to database');
- die();
- }
+ self::$PDO=new PDO($dsn, $user, $pass, $opts);
+
// We always, really always want associative arrays
self::$PDO->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
self::$PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
@@ -299,19 +289,8 @@ class OC_DB {
// Try to establish connection
self::$MDB2 = MDB2::factory( $dsn, $options );
-
- // Die if we could not connect
- if( PEAR::isError( self::$MDB2 )) {
- OC_Log::write('core', self::$MDB2->getUserInfo(), OC_Log::FATAL);
- OC_Log::write('core', self::$MDB2->getMessage(), OC_Log::FATAL);
- OC_User::setUserId(null);
-
- // send http status 503
- header('HTTP/1.1 503 Service Temporarily Unavailable');
- header('Status: 503 Service Temporarily Unavailable');
- OC_Template::printErrorPage('Failed to connect to database');
- die();
- }
+
+ self::raiseExceptionOnError( self::$MDB2 );
// We always, really always want associative arrays
self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC);
@@ -326,11 +305,12 @@ class OC_DB {
* @param string $query Query string
* @param int $limit
* @param int $offset
+ * @param bool $isManipulation
* @return MDB2_Statement_Common prepared SQL query
*
* SQL query via MDB2 prepare(), needs to be execute()'d!
*/
- static public function prepare( $query , $limit=null, $offset=null ) {
+ static public function prepare( $query , $limit = null, $offset = null, $isManipulation = null) {
if (!is_null($limit) && $limit != -1) {
if (self::$backend == self::BACKEND_MDB2) {
@@ -367,12 +347,23 @@ class OC_DB {
OC_Log::write('core', 'DB prepare : '.$query, OC_Log::DEBUG);
}
self::connect();
+
+ if ($isManipulation === null) {
+ //try to guess, so we return the number of rows on manipulations
+ $isManipulation = self::isManipulation($query);
+ }
+
// return the result
if(self::$backend==self::BACKEND_MDB2) {
- $result = self::$connection->prepare( $query );
+ // differentiate between query and manipulation
+ if ($isManipulation) {
+ $result = self::$connection->prepare( $query, null, MDB2_PREPARE_MANIP );
+ } else {
+ $result = self::$connection->prepare( $query, null, MDB2_PREPARE_RESULT );
+ }
// Die if we have an error (error means: bad query, not 0 results!)
- if( PEAR::isError($result)) {
+ if( self::isError($result)) {
throw new DatabaseException($result->getMessage(), $query);
}
}else{
@@ -381,7 +372,8 @@ class OC_DB {
}catch(PDOException $e) {
throw new DatabaseException($e->getMessage(), $query);
}
- $result=new PDOStatementWrapper($result);
+ // differentiate between query and manipulation
+ $result = new PDOStatementWrapper($result, $isManipulation);
}
if ((is_null($limit) || $limit == -1) and self::$cachingEnabled ) {
$type = OC_Config::getValue( "dbtype", "sqlite" );
@@ -391,7 +383,33 @@ class OC_DB {
}
return $result;
}
-
+
+ /**
+ * tries to guess the type of statement based on the first 10 characters
+ * the current check allows some whitespace but does not work with IF EXISTS or other more complex statements
+ *
+ * @param string $sql
+ */
+ static public function isManipulation( $sql ) {
+ $selectOccurence = stripos ($sql, "SELECT");
+ if ($selectOccurence !== false && $selectOccurence < 10) {
+ return false;
+ }
+ $insertOccurence = stripos ($sql, "INSERT");
+ if ($insertOccurence !== false && $insertOccurence < 10) {
+ return true;
+ }
+ $updateOccurence = stripos ($sql, "UPDATE");
+ if ($updateOccurence !== false && $updateOccurence < 10) {
+ return true;
+ }
+ $deleteOccurance = stripos ($sql, "DELETE");
+ if ($deleteOccurance !== false && $deleteOccurance < 10) {
+ return true;
+ }
+ return false;
+ }
+
/**
* @brief execute a prepared statement, on error write log and throw exception
* @param mixed $stmt PDOStatementWrapper | MDB2_Statement_Common ,
@@ -718,6 +736,9 @@ class OC_DB {
} catch(PDOException $e) {
OC_Template::printExceptionErrorPage( $e );
}
+ if ($result === 0) {
+ return true;
+ }
return $result;
}
@@ -754,15 +775,16 @@ class OC_DB {
}elseif( $type == 'oci' ) {
$query = str_replace( '`', '"', $query );
$query = str_ireplace( 'NOW()', 'CURRENT_TIMESTAMP', $query );
+ $query = str_ireplace( 'UNIX_TIMESTAMP()', '((CAST(SYS_EXTRACT_UTC(systimestamp) AS DATE))-TO_DATE(\'1970101000000\',\'YYYYMMDDHH24MiSS\'))*24*3600', $query );
}elseif( $type == 'mssql' ) {
$query = preg_replace( "/\`(.*?)`/", "[$1]", $query );
$query = str_replace( 'NOW()', 'CURRENT_TIMESTAMP', $query );
$query = str_replace( 'now()', 'CURRENT_TIMESTAMP', $query );
$query = str_replace( 'LENGTH(', 'LEN(', $query );
$query = str_replace( 'SUBSTR(', 'SUBSTRING(', $query );
-
- $query = self::fixLimitClauseForMSSQL($query);
- }
+
+ $query = self::fixLimitClauseForMSSQL($query);
+ }
// replace table name prefix
$query = str_replace( '*PREFIX*', $prefix, $query );
@@ -770,60 +792,60 @@ class OC_DB {
return $query;
}
- private static function fixLimitClauseForMSSQL($query) {
- $limitLocation = stripos ($query, "LIMIT");
-
- if ( $limitLocation === false ) {
- return $query;
- }
-
- // total == 0 means all results - not zero results
- //
- // First number is either total or offset, locate it by first space
- //
- $offset = substr ($query, $limitLocation + 5);
- $offset = substr ($offset, 0, stripos ($offset, ' '));
- $offset = trim ($offset);
-
- // check for another parameter
- if (stripos ($offset, ',') === false) {
- // no more parameters
- $offset = 0;
- $total = intval ($offset);
- } else {
- // found another parameter
- $offset = intval ($offset);
-
- $total = substr ($query, $limitLocation + 5);
- $total = substr ($total, stripos ($total, ','));
-
- $total = substr ($total, 0, stripos ($total, ' '));
- $total = intval ($total);
- }
-
- $query = trim (substr ($query, 0, $limitLocation));
-
- if ($offset == 0 && $total !== 0) {
- if (strpos($query, "SELECT") === false) {
- $query = "TOP {$total} " . $query;
- } else {
- $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query);
- }
- } else if ($offset > 0) {
- $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query);
- $query = 'SELECT *
- FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3
- FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3';
-
- if ($total > 0) {
- $query .= ' WHERE line3 BETWEEN ' . ($offset + 1) . ' AND ' . ($offset + $total);
- } else {
- $query .= ' WHERE line3 > ' . $offset;
- }
- }
- return $query;
- }
-
+ private static function fixLimitClauseForMSSQL($query) {
+ $limitLocation = stripos ($query, "LIMIT");
+
+ if ( $limitLocation === false ) {
+ return $query;
+ }
+
+ // total == 0 means all results - not zero results
+ //
+ // First number is either total or offset, locate it by first space
+ //
+ $offset = substr ($query, $limitLocation + 5);
+ $offset = substr ($offset, 0, stripos ($offset, ' '));
+ $offset = trim ($offset);
+
+ // check for another parameter
+ if (stripos ($offset, ',') === false) {
+ // no more parameters
+ $offset = 0;
+ $total = intval ($offset);
+ } else {
+ // found another parameter
+ $offset = intval ($offset);
+
+ $total = substr ($query, $limitLocation + 5);
+ $total = substr ($total, stripos ($total, ','));
+
+ $total = substr ($total, 0, stripos ($total, ' '));
+ $total = intval ($total);
+ }
+
+ $query = trim (substr ($query, 0, $limitLocation));
+
+ if ($offset == 0 && $total !== 0) {
+ if (strpos($query, "SELECT") === false) {
+ $query = "TOP {$total} " . $query;
+ } else {
+ $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query);
+ }
+ } else if ($offset > 0) {
+ $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query);
+ $query = 'SELECT *
+ FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3
+ FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3';
+
+ if ($total > 0) {
+ $query .= ' WHERE line3 BETWEEN ' . ($offset + 1) . ' AND ' . ($offset + $total);
+ } else {
+ $query .= ' WHERE line3 > ' . $offset;
+ }
+ }
+ return $query;
+ }
+
/**
* @brief drop a table
* @param string $tableName the table to drop
@@ -919,18 +941,21 @@ class OC_DB {
* @return bool
*/
public static function isError($result) {
- if(!$result) {
+ //MDB2 returns an MDB2_Error object
+ if (class_exists('PEAR') === true && PEAR::isError($result)) {
return true;
- }elseif(self::$backend==self::BACKEND_MDB2 and PEAR::isError($result)) {
+ }
+ //PDO returns false on error (and throws an exception)
+ if (self::$backend===self::BACKEND_PDO and $result === false) {
return true;
- }else{
- return false;
}
+
+ return false;
}
/**
* check if a result is an error and throws an exception, works with MDB2 and PDOException
* @param mixed $result
- * @param string message
+ * @param string $message
* @return void
* @throws DatabaseException
*/
@@ -946,12 +971,15 @@ class OC_DB {
}
public static function getErrorCode($error) {
- if ( self::$backend==self::BACKEND_MDB2 and PEAR::isError($error) ) {
- $code = $error->getCode();
- } elseif ( self::$backend==self::BACKEND_PDO and self::$PDO ) {
- $code = self::$PDO->errorCode();
+ if ( class_exists('PEAR') === true && PEAR::isError($error) ) {
+ /** @var $error PEAR_Error */
+ return $error->getCode();
+ }
+ if ( self::$backend==self::BACKEND_PDO and self::$PDO ) {
+ return self::$PDO->errorCode();
}
- return $code;
+
+ return -1;
}
/**
* returns the error code and message as a string for logging
@@ -960,23 +988,24 @@ class OC_DB {
* @return string
*/
public static function getErrorMessage($error) {
- if ( self::$backend==self::BACKEND_MDB2 and PEAR::isError($error) ) {
+ if ( class_exists('PEAR') === true && PEAR::isError($error) ) {
$msg = $error->getCode() . ': ' . $error->getMessage();
$msg .= ' (' . $error->getDebugInfo() . ')';
- } elseif (self::$backend==self::BACKEND_PDO and self::$PDO) {
+
+ return $msg;
+ }
+ if (self::$backend==self::BACKEND_PDO and self::$PDO) {
$msg = self::$PDO->errorCode() . ': ';
$errorInfo = self::$PDO->errorInfo();
if (is_array($errorInfo)) {
$msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
$msg .= 'Driver Code = '.$errorInfo[1] . ', ';
$msg .= 'Driver Message = '.$errorInfo[2];
- }else{
- $msg = '';
}
- }else{
- $msg = '';
+ return $msg;
}
- return $msg;
+
+ return '';
}
/**
@@ -997,11 +1026,13 @@ class PDOStatementWrapper{
/**
* @var PDOStatement
*/
- private $statement=null;
- private $lastArguments=array();
+ private $statement = null;
+ private $isManipulation = false;
+ private $lastArguments = array();
- public function __construct($statement) {
- $this->statement=$statement;
+ public function __construct($statement, $isManipulation = false) {
+ $this->statement = $statement;
+ $this->isManipulation = $isManipulation;
}
/**
@@ -1023,16 +1054,19 @@ class PDOStatementWrapper{
$input = $this->tryFixSubstringLastArgumentDataForMSSQL($input);
}
- $result=$this->statement->execute($input);
+ $result = $this->statement->execute($input);
} else {
- $result=$this->statement->execute();
+ $result = $this->statement->execute();
}
- if ($result) {
- return $this;
- } else {
+ if ($result === false) {
return false;
}
+ if ($this->isManipulation) {
+ return $this->statement->rowCount();
+ } else {
+ return $this;
+ }
}
private function tryFixSubstringLastArgumentDataForMSSQL($input) {
@@ -1124,7 +1158,7 @@ class PDOStatementWrapper{
die ($entry);
}
}
-
+
/**
* provide numRows
*/