/**
* This class manages the access to the database. It basically is a wrapper for
- * MDB2 with some adaptions.
+ * Doctrine with some adaptions.
*/
class OC_DB {
- const BACKEND_PDO=0;
- const BACKEND_MDB2=1;
+ const BACKEND_DOCTRINE=2;
static private $preparedQueries = array();
+ static private $cachingEnabled = true;
/**
- * @var MDB2_Driver_Common
+ * @var \Doctrine\DBAL\Connection
*/
- static private $connection; //the prefered connection to use, either PDO or MDB2
+ static private $connection; //the prefered connection to use, only Doctrine
static private $backend=null;
/**
- * @var MDB2_Driver_Common
- */
- static private $MDB2=null;
- /**
- * @var PDO
+ * @var Doctrine
*/
- static private $PDO=null;
- /**
- * @var MDB2_Schema
- */
- static private $schema=null;
+ static private $DOCTRINE=null;
+
static private $inTransaction=false;
static private $prefix=null;
static private $type=null;
);
break;
case 'oci':
- $dsn = array(
- 'phptype' => 'oci8',
- 'username' => $user,
+ $connectionParams = array(
+ 'user' => $user,
'password' => $pass,
+ 'host' => $host,
+ 'port' => $port,
+ 'dbname' => $name,
'charset' => 'AL32UTF8',
+ 'driver' => 'oci8',
);
- if ($host != '') {
- $dsn['hostspec'] = $host;
- $dsn['database'] = $name;
- } else { // use dbname for hostspec
- $dsn['hostspec'] = $name;
- $dsn['database'] = $user;
- }
break;
+ case 'mssql':
+ $dsn = array(
+ 'phptype' => 'sqlsrv',
+ 'username' => $user,
+ 'password' => $pass,
+ 'hostspec' => $host,
+ 'database' => $name
+ );
+ break;
default:
return false;
}
static public function prepare( $query , $limit=null, $offset=null ) {
if (!is_null($limit) && $limit != -1) {
- if (self::$backend == self::BACKEND_MDB2) {
- //MDB2 uses or emulates limits & offset internally
- self::$MDB2->setLimit($limit, $offset);
+ //Doctrine does not handle limit and offset.
+ //FIXME: check limit notation for other dbs
+ //the following sql thus might needs to take into account db ways of representing it
+ //(oracle has no LIMIT / OFFSET)
+ $limit = (int)$limit;
+ $limitsql = ' LIMIT ' . $limit;
+ if (!is_null($offset)) {
+ $offset = (int)$offset;
+ $limitsql .= ' OFFSET ' . $offset;
+ }
+ //insert limitsql
+ if (substr($query, -1) == ';') { //if query ends with ;
+ $query = substr($query, 0, -1) . $limitsql . ';';
} else {
- //PDO does not handle limit and offset.
- //FIXME: check limit notation for other dbs
- //the following sql thus might needs to take into account db ways of representing it
- //(oracle has no LIMIT / OFFSET)
- $limit = (int)$limit;
- $limitsql = ' LIMIT ' . $limit;
- if (!is_null($offset)) {
- $offset = (int)$offset;
- $limitsql .= ' OFFSET ' . $offset;
- }
- //insert limitsql
- if (substr($query, -1) == ';') { //if query ends with ;
- $query = substr($query, 0, -1) . $limitsql . ';';
- } else {
- $query.=$limitsql;
- }
+ $query.=$limitsql;
}
} else {
- if (isset(self::$preparedQueries[$query])) {
+ if (isset(self::$preparedQueries[$query]) and self::$cachingEnabled) {
return self::$preparedQueries[$query];
}
}
self::connect();
// return the result
- if(self::$backend==self::BACKEND_MDB2) {
- $result = self::$connection->prepare( $query );
-
- // Die if we have an error (error means: bad query, not 0 results!)
- if( PEAR::isError($result)) {
- throw new DatabaseException($result->getMessage(), $query);
- }
- }else{
- try{
+ if (self::$backend == self::BACKEND_DOCTRINE) {
+ try {
$result=self::$connection->prepare($query);
- }catch(PDOException $e) {
+ } catch(\Doctrine\DBAL\DBALException $e) {
throw new DatabaseException($e->getMessage(), $query);
}
- $result=new PDOStatementWrapper($result);
+ $result=new DoctrineStatementWrapper($result);
}
- if (is_null($limit) || $limit == -1) {
- self::$preparedQueries[$rawQuery] = $result;
+ if ((is_null($limit) || $limit == -1) and self::$cachingEnabled ) {
+ $type = OC_Config::getValue( "dbtype", "sqlite" );
+ if( $type != 'sqlite' && $type != 'sqlite3' ) {
+ self::$preparedQueries[$rawQuery] = $result;
+ }
}
return $result;
}
$query = self::prepare('SELECT lastval() AS id');
$row = $query->execute()->fetchRow();
return $row['id'];
- }else{
+ }
+ if( $type == 'mssql' ) {
+ if($table !== null) {
+ $prefix = OC_Config::getValue( "dbtableprefix", "oc_" );
+ $table = str_replace( '*PREFIX*', $prefix, $table );
+ }
+ return self::$connection->lastInsertId($table);
+ } else {
if($table !== null) {
$prefix = OC_Config::getValue( "dbtableprefix", "oc_" );
$suffix = OC_Config::getValue( "dbsequencesuffix", "_id_seq" );
return true;
}
-- /**
++ /** else {
* @brief saves database scheme to xml file
* @param string $file name of file
* @param int $mode
$query = str_replace( '`', '"', $query );
$query = str_ireplace( 'UNIX_TIMESTAMP()', 'cast(extract(epoch from current_timestamp) as integer)',
$query );
- }elseif( $type == 'oci' ) {
+ } elseif( $type == 'oci' ) {
$query = str_replace( '`', '"', $query );
$query = str_ireplace( 'NOW()', 'CURRENT_TIMESTAMP', $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);
+ }
// replace table name prefix
$query = str_replace( '*PREFIX*', $prefix, $query );
}
}
- /**
- * provide numRows
- */
- public function numRows() {
- $regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/i';
- if (preg_match($regex, $this->statement->queryString, $output) > 0) {
- $query = OC_DB::prepare("SELECT COUNT(*) FROM {$output[1]}", PDO::FETCH_NUM);
- return $query->execute($this->lastArguments)->fetchColumn();
- }else{
- return $this->statement->rowCount();
- }
- }
-
+ private function tryFixSubstringLastArgumentDataForMSSQL($input) {
+ $query = $this->statement->queryString;
+ $pos = stripos ($query, 'SUBSTRING');
+
+ if ( $pos === false) {
+ return;
+ }
+
+ try {
+ $newQuery = '';
+
+ $cArg = 0;
+
+ $inSubstring = false;
+
+ // Create new query
+ for ($i = 0; $i < strlen ($query); $i++) {
+ if ($inSubstring == false) {
+ // Defines when we should start inserting values
+ if (substr ($query, $i, 9) == 'SUBSTRING') {
+ $inSubstring = true;
+ }
+ } else {
+ // Defines when we should stop inserting values
+ if (substr ($query, $i, 1) == ')') {
+ $inSubstring = false;
+ }
+ }
+
+ if (substr ($query, $i, 1) == '?') {
+ // We found a question mark
+ if ($inSubstring) {
+ $newQuery .= $input[$cArg];
+
+ //
+ // Remove from input array
+ //
+ array_splice ($input, $cArg, 1);
+ } else {
+ $newQuery .= substr ($query, $i, 1);
+ $cArg++;
+ }
+ } else {
+ $newQuery .= substr ($query, $i, 1);
+ }
+ }
+
+ // The global data we need
+ $name = OC_Config::getValue( "dbname", "owncloud" );
+ $host = OC_Config::getValue( "dbhost", "" );
+ $user = OC_Config::getValue( "dbuser", "" );
+ $pass = OC_Config::getValue( "dbpassword", "" );
+ if (strpos($host,':')) {
+ list($host, $port) = explode(':', $host, 2);
+ } else {
+ $port = false;
+ }
+ $opts = array();
+
+ if ($port) {
+ $dsn = 'sqlsrv:Server='.$host.','.$port.';Database='.$name;
+ } else {
+ $dsn = 'sqlsrv:Server='.$host.';Database='.$name;
+ }
+
+ $PDO = new PDO($dsn, $user, $pass, $opts);
+ $PDO->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
+ $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ $this->statement = $PDO->prepare($newQuery);
+
+ $this->lastArguments = $input;
+
+ return $input;
+ } catch (PDOException $e){
+ $entry = 'PDO DB Error: "'.$e->getMessage().'"<br />';
+ $entry .= 'Offending command was: '.$this->statement->queryString .'<br />';
+ $entry .= 'Input parameters: ' .print_r($input, true).'<br />';
+ $entry .= 'Stack trace: ' .$e->getTraceAsString().'<br />';
+ OC_Log::write('core', $entry, 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 ($entry);
+ }
+ }
+
/**
* provide an alias for fetch
*/