summaryrefslogtreecommitdiffstats
path: root/lib/private/legacy/db.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/legacy/db.php')
-rw-r--r--lib/private/legacy/db.php258
1 files changed, 258 insertions, 0 deletions
diff --git a/lib/private/legacy/db.php b/lib/private/legacy/db.php
new file mode 100644
index 00000000000..5d612312919
--- /dev/null
+++ b/lib/private/legacy/db.php
@@ -0,0 +1,258 @@
+<?php
+/**
+ * @author Andreas Fischer <bantu@owncloud.com>
+ * @author Bart Visscher <bartv@thisnet.nl>
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/**
+ * This class manages the access to the database. It basically is a wrapper for
+ * Doctrine with some adaptions.
+ */
+class OC_DB {
+
+ /**
+ * get MDB2 schema manager
+ *
+ * @return \OC\DB\MDB2SchemaManager
+ */
+ private static function getMDB2SchemaManager() {
+ return new \OC\DB\MDB2SchemaManager(\OC::$server->getDatabaseConnection());
+ }
+
+ /**
+ * Prepare a SQL query
+ * @param string $query Query string
+ * @param int $limit
+ * @param int $offset
+ * @param bool $isManipulation
+ * @throws \OC\DatabaseException
+ * @return OC_DB_StatementWrapper prepared SQL query
+ *
+ * SQL query via Doctrine prepare(), needs to be execute()'d!
+ */
+ static public function prepare( $query , $limit = null, $offset = null, $isManipulation = null) {
+ $connection = \OC::$server->getDatabaseConnection();
+
+ if ($isManipulation === null) {
+ //try to guess, so we return the number of rows on manipulations
+ $isManipulation = self::isManipulation($query);
+ }
+
+ // return the result
+ try {
+ $result =$connection->prepare($query, $limit, $offset);
+ } catch (\Doctrine\DBAL\DBALException $e) {
+ throw new \OC\DatabaseException($e->getMessage(), $query);
+ }
+ // differentiate between query and manipulation
+ $result = new OC_DB_StatementWrapper($result, $isManipulation);
+ 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
+ * @return bool
+ */
+ static public function isManipulation( $sql ) {
+ $selectOccurrence = stripos($sql, 'SELECT');
+ if ($selectOccurrence !== false && $selectOccurrence < 10) {
+ return false;
+ }
+ $insertOccurrence = stripos($sql, 'INSERT');
+ if ($insertOccurrence !== false && $insertOccurrence < 10) {
+ return true;
+ }
+ $updateOccurrence = stripos($sql, 'UPDATE');
+ if ($updateOccurrence !== false && $updateOccurrence < 10) {
+ return true;
+ }
+ $deleteOccurrence = stripos($sql, 'DELETE');
+ if ($deleteOccurrence !== false && $deleteOccurrence < 10) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * execute a prepared statement, on error write log and throw exception
+ * @param mixed $stmt OC_DB_StatementWrapper,
+ * an array with 'sql' and optionally 'limit' and 'offset' keys
+ * .. or a simple sql query string
+ * @param array $parameters
+ * @return OC_DB_StatementWrapper
+ * @throws \OC\DatabaseException
+ */
+ static public function executeAudited( $stmt, array $parameters = null) {
+ if (is_string($stmt)) {
+ // convert to an array with 'sql'
+ if (stripos($stmt, 'LIMIT') !== false) { //OFFSET requires LIMIT, so we only need to check for LIMIT
+ // TODO try to convert LIMIT OFFSET notation to parameters
+ $message = 'LIMIT and OFFSET are forbidden for portability reasons,'
+ . ' pass an array with \'limit\' and \'offset\' instead';
+ throw new \OC\DatabaseException($message);
+ }
+ $stmt = array('sql' => $stmt, 'limit' => null, 'offset' => null);
+ }
+ if (is_array($stmt)) {
+ // convert to prepared statement
+ if ( ! array_key_exists('sql', $stmt) ) {
+ $message = 'statement array must at least contain key \'sql\'';
+ throw new \OC\DatabaseException($message);
+ }
+ if ( ! array_key_exists('limit', $stmt) ) {
+ $stmt['limit'] = null;
+ }
+ if ( ! array_key_exists('limit', $stmt) ) {
+ $stmt['offset'] = null;
+ }
+ $stmt = self::prepare($stmt['sql'], $stmt['limit'], $stmt['offset']);
+ }
+ self::raiseExceptionOnError($stmt, 'Could not prepare statement');
+ if ($stmt instanceof OC_DB_StatementWrapper) {
+ $result = $stmt->execute($parameters);
+ self::raiseExceptionOnError($result, 'Could not execute statement');
+ } else {
+ if (is_object($stmt)) {
+ $message = 'Expected a prepared statement or array got ' . get_class($stmt);
+ } else {
+ $message = 'Expected a prepared statement or array got ' . gettype($stmt);
+ }
+ throw new \OC\DatabaseException($message);
+ }
+ return $result;
+ }
+
+ /**
+ * saves database schema to xml file
+ * @param string $file name of file
+ * @param int $mode
+ * @return bool
+ *
+ * TODO: write more documentation
+ */
+ public static function getDbStructure($file) {
+ $schemaManager = self::getMDB2SchemaManager();
+ return $schemaManager->getDbStructure($file);
+ }
+
+ /**
+ * Creates tables from XML file
+ * @param string $file file to read structure from
+ * @return bool
+ *
+ * TODO: write more documentation
+ */
+ public static function createDbFromStructure( $file ) {
+ $schemaManager = self::getMDB2SchemaManager();
+ $result = $schemaManager->createDbFromStructure($file);
+ return $result;
+ }
+
+ /**
+ * update the database schema
+ * @param string $file file to read structure from
+ * @throws Exception
+ * @return string|boolean
+ */
+ public static function updateDbFromStructure($file) {
+ $schemaManager = self::getMDB2SchemaManager();
+ try {
+ $result = $schemaManager->updateDbFromStructure($file);
+ } catch (Exception $e) {
+ \OCP\Util::writeLog('core', 'Failed to update database structure ('.$e.')', \OCP\Util::FATAL);
+ throw $e;
+ }
+ return $result;
+ }
+
+ /**
+ * simulate the database schema update
+ * @param string $file file to read structure from
+ * @throws Exception
+ * @return string|boolean
+ */
+ public static function simulateUpdateDbFromStructure($file) {
+ $schemaManager = self::getMDB2SchemaManager();
+ try {
+ $result = $schemaManager->simulateUpdateDbFromStructure($file);
+ } catch (Exception $e) {
+ \OCP\Util::writeLog('core', 'Simulated database structure update failed ('.$e.')', \OCP\Util::FATAL);
+ throw $e;
+ }
+ return $result;
+ }
+
+ /**
+ * remove all tables defined in a database structure xml file
+ * @param string $file the xml file describing the tables
+ */
+ public static function removeDBStructure($file) {
+ $schemaManager = self::getMDB2SchemaManager();
+ $schemaManager->removeDBStructure($file);
+ }
+
+ /**
+ * check if a result is an error and throws an exception, works with \Doctrine\DBAL\DBALException
+ * @param mixed $result
+ * @param string $message
+ * @return void
+ * @throws \OC\DatabaseException
+ */
+ public static function raiseExceptionOnError($result, $message = null) {
+ if($result === false) {
+ if ($message === null) {
+ $message = self::getErrorMessage();
+ } else {
+ $message .= ', Root cause:' . self::getErrorMessage();
+ }
+ throw new \OC\DatabaseException($message, \OC::$server->getDatabaseConnection()->errorCode());
+ }
+ }
+
+ /**
+ * returns the error code and message as a string for logging
+ * works with DoctrineException
+ * @return string
+ */
+ public static function getErrorMessage() {
+ $connection = \OC::$server->getDatabaseConnection();
+ return $connection->getError();
+ }
+
+ /**
+ * Checks if a table exists in the database - the database prefix will be prepended
+ *
+ * @param string $table
+ * @return bool
+ * @throws \OC\DatabaseException
+ */
+ public static function tableExists($table) {
+ $connection = \OC::$server->getDatabaseConnection();
+ return $connection->tableExists($table);
+ }
+}