[+BUGFIX] Extbase (Persistence): Fixed typo in Exception class.
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Storage / Typo3DbBackend.php
index 212b7da..6aecfd7 100644 (file)
@@ -29,7 +29,7 @@
  * A Storage backend
  *
  * @package Extbase
- * @subpackage Persistence
+ * @subpackage Persistence\Storage
  * @version $Id: $
  */
 class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persistence_Storage_BackendInterface, t3lib_Singleton {
@@ -45,18 +45,16 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
        protected $databaseHandle;
 
        /**
-        * The TYPO3 page select object. Used for language and workspace overlay
-        *
-        * @var t3lib_pageSelect
+        * @var Tx_Extbase_Persistence_DataMapper
         */
-       protected $pageSelectObject;
+       protected $dataMapper;
 
        /**
-        * TRUE if automatic cache clearing in TCEMAIN should be done on insert/update/delete, FALSE otherwise.
+        * The TYPO3 page select object. Used for language and workspace overlay
         *
-        * @var boolean
+        * @var t3lib_pageSelect
         */
-       protected $automaticCacheClearing = FALSE;
+       protected $pageSelectObject;
 
        /**
         * Constructs this Storage Backend instance
@@ -68,15 +66,13 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
        }
 
        /**
-        * Set the automatic cache clearing flag.
-        * If TRUE, then inserted/updated/deleted records trigger a TCEMAIN cache clearing.
+        * Injects the DataMapper to map nodes to objects
         *
-        * @param $automaticCacheClearing boolean if TRUE, enables automatic cache clearing
+        * @param Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper
         * @return void
-        * @internal
         */
-       public function setAutomaticCacheClearing($automaticCacheClearing) {
-               $this->automaticCacheClearing = (boolean)$automaticCacheClearing;
+       public function injectDataMapper(Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper) {
+               $this->dataMapper = $dataMapper;
        }
 
        /**
@@ -91,7 +87,9 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                $fields = array();
                $values = array();
                $parameters = array();
-               unset($row['uid']); // TODO Check if the offset exists
+               if (isset($row['uid'])) {
+                       unset($row['uid']);
+               }
                foreach ($row as $columnName => $value) {
                        $fields[] = $columnName;
                        $values[] = '?';
@@ -144,17 +142,24 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         * Deletes a row in the storage
         *
         * @param string $tableName The database table name
-        * @param array $uid The uid of the row to be deleted
+        * @param array $identifyer An array of identifyer array('fieldname' => value). This array will be transformed to a WHERE clause
         * @param boolean $isRelation TRUE if we are currently inserting into a relation table, FALSE by default
         * @return void
         */
-       public function removeRow($tableName, $uid, $isRelation = FALSE) {
-               $sqlString = 'DELETE FROM ' . $tableName . ' WHERE uid=?';
-               $this->replacePlaceholders($sqlString, array((int)$uid));
+       public function removeRow($tableName, array $identifyer, $isRelation = FALSE) {
+               $fieldNames = array_keys($identifyer);
+               $suffixedFieldNames = array();
+               foreach ($fieldNames as $fieldName) {
+                       $suffixedFieldNames[] = $fieldName . '=?';
+               }
+               $parameters = array_values($identifyer);
+               $statement = 'DELETE FROM ' . $tableName;
+               $statement .= ' WHERE ' . implode(' AND ', $suffixedFieldNames);
+               $this->replacePlaceholders($statement, $parameters);
                if (!$isRelation) {
                        $this->clearPageCache($tableName, $uid, $isRelation);
                }
-               $returnValue = $this->databaseHandle->sql_query($sqlString);
+               $returnValue = $this->databaseHandle->sql_query($statement);
                $this->checkSqlErrors();
                return $returnValue;
        }
@@ -167,6 +172,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         */
        public function getRows(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query) {
                $statement = $this->parseQuery($query);
+               // debug($statement, -2); // FIXME remove debug code
                $result = $this->databaseHandle->sql_query($statement);
                $this->checkSqlErrors();
                if ($result) {
@@ -184,10 +190,12 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         */
        public function parseQuery(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query) {
                $statement = '';
+               $parameters = array();
                $constraint = $query->getConstraint();
                if($constraint instanceof Tx_Extbase_Persistence_QOM_StatementInterface) {
                        if ($constraint->getLanguage() === Tx_Extbase_Persistence_QOM_QueryObjectModelInterface::TYPO3_SQL_MYSQL) {
                                $statement = $constraint->getStatement();
+                               $parameters= $query->getBoundVariableValues();
                        } else {
                                throw new Tx_Extbase_Persistence_Exception('Unsupported query language.', 1248701951);
                        }
@@ -196,40 +204,38 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                        $sql['tables'] = array();
                        $sql['fields'] = array();
                        $sql['where'] = array();
-                       $sql['enableFields'] = array();
+                       $sql['additionalWhereClause'] = array();
                        $sql['orderings'] = array();
                        $sql['limit'] = array();
-                       $parameters = array();
                        $tuples = array();
 
-                       $this->parseSource($query, $sql, $parameters);
+                       $source = $query->getSource();
+                       $this->parseSource($query, $source, $sql, $parameters);
+
                        $statement = 'SELECT ' . implode(',', $sql['fields']) . ' FROM ' . implode(' ', $sql['tables']);
 
-                       $this->parseConstraint($query->getConstraint(), $sql, $parameters, $query->getBoundVariableValues());
+                       $this->parseConstraint($constraint, $source, $sql, $parameters, $query->getBoundVariableValues());
 
                        if (!empty($sql['where'])) {
                                $statement .= ' WHERE ' . implode('', $sql['where']);
-                               if (!empty($sql['enableFields'])) {
-                                       $statement .= ' AND ' . implode(' AND ', $sql['enableFields']);
+                               if (!empty($sql['additionalWhereClause'])) {
+                                       $statement .= ' AND ' . implode(' AND ', $sql['additionalWhereClause']);
                                }
-                       } elseif (!empty($sql['enableFields'])) {
-                               $statement .= ' WHERE ' . implode(' AND ', $sql['enableFields']);
+                       } elseif (!empty($sql['additionalWhereClause'])) {
+                               $statement .= ' WHERE ' . implode(' AND ', $sql['additionalWhereClause']);
                        }
 
-                       $this->parseOrderings($query->getOrderings(), $sql, $parameters, $query->getBoundVariableValues());
+                       $this->parseOrderings($query->getOrderings(), $source, $sql);
                        if (!empty($sql['orderings'])) {
                                $statement .= ' ORDER BY ' . implode(', ', $sql['orderings']);
                        }
 
-                       $this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $sql, $parameters, $query->getBoundVariableValues());
+                       $this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $sql);
                        if (!empty($sql['limit'])) {
                                $statement .= ' LIMIT ' . $sql['limit'];
                        }
-
-                       $this->replacePlaceholders($statement, $parameters);
-
                }
-
+               $this->replacePlaceholders($statement, $parameters);
                return $statement;
        }
 
@@ -238,21 +244,31 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         *
         * @param array $properties The properties of the Value Object
         * @param Tx_Extbase_Persistence_Mapper_DataMap $dataMap The Data Map
-        * @return array The matching tuples
+        * @return array The matching uid
         */
        public function hasValueObject(array $properties, Tx_Extbase_Persistence_Mapper_DataMap $dataMap) {
                $fields = array();
                $parameters = array();
                foreach ($properties as $propertyName => $propertyValue) {
-                       if ($dataMap->isPersistableProperty($propertyName) && ($propertyName !== 'uid')) {
+                       // FIXME We couple the Backend to the Entity implementation (uid, isClone); changes there breaks this method
+                       if ($dataMap->isPersistableProperty($propertyName) && ($propertyName !== 'uid')  && ($propertyName !== 'pid') && ($propertyName !== 'isClone')) {
                                $fields[] = $dataMap->getColumnMap($propertyName)->getColumnName() . '=?';
                                $parameters[] = $dataMap->convertPropertyValueToFieldValue($propertyValue);
                        }
                }
+               $sql = array();
+               $sql['additionalWhereClause'] = array();
 
-               $sqlString = 'SELECT * FROM ' . $dataMap->getTableName() .  ' WHERE ' . implode(' AND ', $fields);
-               $this->replacePlaceholders($sqlString, $parameters);
-               $res = $this->databaseHandle->sql_query($sqlString);
+               $tableName = $dataMap->getTableName();
+               $this->addEnableFieldsStatement($tableName, $sql);
+
+               $statement = 'SELECT * FROM ' . $tableName;
+               $statement .= ' WHERE ' . implode(' AND ', $fields);
+               if (!empty($sql['additionalWhereClause'])) {
+                       $statement .= ' AND ' . implode(' AND ', $sql['additionalWhereClause']);
+               }
+               $this->replacePlaceholders($statement, $parameters);
+               $res = $this->databaseHandle->sql_query($statement);
                $this->checkSqlErrors();
                $row = $this->databaseHandle->sql_fetch_assoc($res);
                if ($row !== FALSE) {
@@ -266,65 +282,69 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         * Transforms a Query Source into SQL and parameter arrays
         *
         * @param Tx_Extbase_Persistence_QOM_QueryObjectModel $query
+        * @param Tx_Extbase_Persistence_QOM_SourceInterface $source The source
         * @param array &$sql
         * @param array &$parameters
         * @return void
         */
-       protected function parseSource(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query, array &$sql, array &$parameters) {
-               $source = $query->getSource();
+       protected function parseSource(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query, Tx_Extbase_Persistence_QOM_SourceInterface $source, array &$sql, array &$parameters) {
                if ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
-                       $selectorName = $source->getSelectorName();
-                       $sql['fields'][] = $selectorName . '.*';
-                       $sql['tables'][] = $selectorName;
+                       $tableName = $source->getSelectorName();
+                       $sql['fields'][] = $tableName . '.*';
+                       $sql['tables'][] = $tableName;
                        $querySettings = $query->getQuerySettings();
                        if ($querySettings instanceof Tx_Extbase_Persistence_Typo3QuerySettingsInterface) {
                                if ($querySettings->getRespectEnableFields()) {
-                                       $this->addEnableFieldsStatement($selectorName, $sql);
+                                       $this->addEnableFieldsStatement($tableName, $sql);
                                }
                                if ($querySettings->getRespectStoragePage()) {
-                                       $this->addPageIdStatement($selectorName, $sql);
+                                       $this->addPageIdStatement($tableName, $sql);
                                }
                        }
                } elseif ($source instanceof Tx_Extbase_Persistence_QOM_JoinInterface) {
-                       $this->parseJoin($query, $source, $sql, $parameters);
+                       $this->parseJoin($query, $source, $sql);
                }
        }
 
        /**
         * Transforms a Join into SQL and parameter arrays
         *
-        * @param Tx_Extbase_Persistence_QOM_QueryObjectModel $query
-        * @param Tx_Extbase_Persistence_QOM_JoinInterface $join
-        * @param array &$sql
-        * @param array &$parameters
+        * @param Tx_Extbase_Persistence_QOM_QueryObjectModel $query The Query Object Model
+        * @param Tx_Extbase_Persistence_QOM_JoinInterface $join The join
+        * @param array &$sql The query parts
         * @return void
         */
-       protected function parseJoin(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query, Tx_Extbase_Persistence_QOM_JoinInterface $join, array &$sql, array &$parameters) {
-               $leftSelectorName = $join->getLeft()->getSelectorName();
-               $rightSelectorName = $join->getRight()->getSelectorName();
+       protected function parseJoin(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query, Tx_Extbase_Persistence_QOM_JoinInterface $join, array &$sql) {
+               $leftSource = $join->getLeft();
+               $leftTableName = $leftSource->getSelectorName();
+               $rightSource = $join->getRight();
+               $rightTableName = $rightSource->getSelectorName();
 
-               $sql['fields'][] = $leftSelectorName . '.*';
-               $sql['fields'][] = $rightSelectorName . '.*';
+               $sql['fields'][] = $leftTableName . '.*';
+               $sql['fields'][] = $rightTableName . '.*';
 
                // TODO Implement support for different join types and nested joins
-               $sql['tables'][] = $leftSelectorName . ' LEFT JOIN ' . $rightSelectorName;
+               $sql['tables'][] = $leftTableName . ' LEFT JOIN ' . $rightTableName;
 
                $joinCondition = $join->getJoinCondition();
                // TODO Check the parsing of the join
                if ($joinCondition instanceof Tx_Extbase_Persistence_QOM_EquiJoinCondition) {
-                       $sql['tables'][] = 'ON ' . $joinCondition->getSelector1Name() . '.' . $joinCondition->getProperty1Name() . ' = ' . $joinCondition->getSelector2Name() . '.' . $joinCondition->getProperty2Name();
+                       // TODO Discuss, if we should use $leftSource instead of $selector1Name
+                       $column1Name = $this->dataMapper->convertPropertyNameToColumnName($joinCondition->getProperty1Name(), $leftSource->getNodeTypeName());
+                       $column2Name = $this->dataMapper->convertPropertyNameToColumnName($joinCondition->getProperty2Name(), $rightSource->getNodeTypeName());
+                       $sql['tables'][] = 'ON ' . $joinCondition->getSelector1Name() . '.' . $column1Name . ' = ' . $joinCondition->getSelector2Name() . '.' . $column2Name;
                }
                // TODO Implement childtableWhere
 
                $querySettings = $query->getQuerySettings();
                if ($querySettings instanceof Tx_Extbase_Persistence_Typo3QuerySettingsInterface) {
                        if ($querySettings->getRespectEnableFields()) {
-                               $this->addEnableFieldsStatement($leftSelectorName, $sql);
-                               $this->addEnableFieldsStatement($rightSelectorName, $sql);
+                               $this->addEnableFieldsStatement($leftTableName, $sql);
+                               $this->addEnableFieldsStatement($rightTableName, $sql);
                        }
                        if ($querySettings->getRespectStoragePage()) {
-                               $this->addPageIdStatement($leftSelectorName, $sql);
-                               $this->addPageIdStatement($rightSelectorName, $sql);
+                               $this->addPageIdStatement($leftTableName, $sql);
+                               $this->addPageIdStatement($rightTableName, $sql);
                        }
                }
        }
@@ -332,31 +352,33 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
        /**
         * Transforms a constraint into SQL and parameter arrays
         *
-        * @param Tx_Extbase_Persistence_QOM_ConstraintInterface $constraint
-        * @param array &$sql
-        * @param array &$parameters
-        * @param array $boundVariableValues
+        * @param Tx_Extbase_Persistence_QOM_ConstraintInterface $constraint The constraint
+        * @param Tx_Extbase_Persistence_QOM_SourceInterface $source The source
+        * @param array &$sql The query parts
+        * @param array &$parameters The parameters that will replace the markers
+        * @param array $boundVariableValues The bound variables in the query (key) and their values (value)
         * @return void
         */
-       protected function parseConstraint(Tx_Extbase_Persistence_QOM_ConstraintInterface $constraint = NULL, array &$sql, array &$parameters, array $boundVariableValues) {
+       protected function parseConstraint(Tx_Extbase_Persistence_QOM_ConstraintInterface $constraint = NULL, Tx_Extbase_Persistence_QOM_SourceInterface $source, array &$sql, array &$parameters, array $boundVariableValues) {
+               if ($constraint === NULL) return;
                if ($constraint instanceof Tx_Extbase_Persistence_QOM_AndInterface) {
                        $sql['where'][] = '(';
-                       $this->parseConstraint($constraint->getConstraint1(), $sql, $parameters, $boundVariableValues);
+                       $this->parseConstraint($constraint->getConstraint1(), $source, $sql, $parameters, $boundVariableValues);
                        $sql['where'][] = ' AND ';
-                       $this->parseConstraint($constraint->getConstraint2(), $sql, $parameters, $boundVariableValues);
+                       $this->parseConstraint($constraint->getConstraint2(), $source, $sql, $parameters, $boundVariableValues);
                        $sql['where'][] = ')';
                } elseif ($constraint instanceof Tx_Extbase_Persistence_QOM_OrInterface) {
                        $sql['where'][] = '(';
-                       $this->parseConstraint($constraint->getConstraint1(), $sql, $parameters, $boundVariableValues);
+                       $this->parseConstraint($constraint->getConstraint1(), $source, $sql, $parameters, $boundVariableValues);
                        $sql['where'][] = ' OR ';
-                       $this->parseConstraint($constraint->getConstraint2(), $sql, $parameters, $boundVariableValues);
+                       $this->parseConstraint($constraint->getConstraint2(), $source, $sql, $parameters, $boundVariableValues);
                        $sql['where'][] = ')';
                } elseif ($constraint instanceof Tx_Extbase_Persistence_QOM_NotInterface) {
                        $sql['where'][] = 'NOT (';
-                       $this->parseConstraint($constraint->getConstraint(), $sql, $parameters, $boundVariableValues);
+                       $this->parseConstraint($constraint->getConstraint(), $source, $sql, $parameters, $boundVariableValues);
                        $sql['where'][] = ')';
                } elseif ($constraint instanceof Tx_Extbase_Persistence_QOM_ComparisonInterface) {
-                       $this->parseComparison($constraint, $sql, $parameters, $boundVariableValues);
+                       $this->parseComparison($constraint, $source, $sql, $parameters, $boundVariableValues);
                } elseif ($constraint instanceof Tx_Extbase_Persistence_QOM_RelatedInterface) {
                        $this->parseRelated($constraint, $sql, $parameters, $boundVariableValues);
                }
@@ -366,12 +388,13 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         * Parse a Comparison into SQL and parameter arrays.
         *
         * @param Tx_Extbase_Persistence_QOM_ComparisonInterface $comparison The comparison to parse
+        * @param Tx_Extbase_Persistence_QOM_SourceInterface $source The source
         * @param array &$sql SQL query parts to add to
         * @param array &$parameters Parameters to bind to the SQL
         * @param array $boundVariableValues The bound variables in the query and their values
         * @return void
         */
-       protected function parseComparison(Tx_Extbase_Persistence_QOM_ComparisonInterface $comparison, array &$sql, array &$parameters, array $boundVariableValues) {
+       protected function parseComparison(Tx_Extbase_Persistence_QOM_ComparisonInterface $comparison, Tx_Extbase_Persistence_QOM_SourceInterface $source, array &$sql, array &$parameters, array $boundVariableValues) {
                if (!($comparison->getOperand2() instanceof Tx_Extbase_Persistence_QOM_BindVariableValueInterface)) throw new Tx_Extbase_Persistence_Exception('Type of operand is not supported', 1247581135);
 
                $value = $boundVariableValues[$comparison->getOperand2()->getBindVariableName()];
@@ -387,7 +410,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                }
                $parameters[] = $value;
 
-               $this->parseDynamicOperand($comparison->getOperand1(), $operator, $sql, $parameters);
+               $this->parseDynamicOperand($comparison->getOperand1(), $operator, $source, $sql, $parameters);
        }
 
        /**
@@ -395,24 +418,32 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         *
         * @param Tx_Extbase_Persistence_QOM_DynamicOperandInterface $operand
         * @param string $operator One of the JCR_OPERATOR_* constants
-        * @param array $boundVariableValues
-        * @param array &$parameters
-        * @param string $valueFunction an aoptional SQL function to apply to the operand value
+        * @param Tx_Extbase_Persistence_QOM_SourceInterface $source The source
+        * @param array &$sql The query parts
+        * @param array &$parameters The parameters that will replace the markers
+        * @param string $valueFunction an optional SQL function to apply to the operand value
         * @return void
         */
-       protected function parseDynamicOperand(Tx_Extbase_Persistence_QOM_DynamicOperandInterface $operand, $operator, array &$sql, array &$parameters, $valueFunction = NULL) {
+       protected function parseDynamicOperand(Tx_Extbase_Persistence_QOM_DynamicOperandInterface $operand, $operator, Tx_Extbase_Persistence_QOM_SourceInterface $source, array &$sql, array &$parameters, $valueFunction = NULL) {
                if ($operand instanceof Tx_Extbase_Persistence_QOM_LowerCaseInterface) {
-                       $this->parseDynamicOperand($operand->getOperand(), $operator, $sql, $parameters, 'LOWER');
+                       $this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'LOWER');
                } elseif ($operand instanceof Tx_Extbase_Persistence_QOM_UpperCaseInterface) {
-                       $this->parseDynamicOperand($operand->getOperand(), $operator, $sql, $parameters, 'UPPER');
+                       $this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'UPPER');
                } elseif ($operand instanceof Tx_Extbase_Persistence_QOM_PropertyValueInterface) {
-                       $selectorName = $operand->getSelectorName();
+                       $tableName = $operand->getSelectorName();
+                       // FIXME Discuss the translation from propertyName to columnName
+                       if ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
+                               $className = $source->getNodeTypeName();
+                       } else {
+                               $className = '';
+                       }
+                       $columnName = $this->dataMapper->convertPropertyNameToColumnName($operand->getPropertyName(), $className);
                        $operator = $this->resolveOperator($operator);
 
                        if ($valueFunction === NULL) {
-                               $constraintSQL .= (!empty($selectorName) ? $selectorName . '.' : '') . $operand->getPropertyName() .  ' ' . $operator . ' ?';
+                               $constraintSQL .= (!empty($tableName) ? $tableName . '.' : '') . $columnName .  ' ' . $operator . ' ?';
                        } else {
-                               $constraintSQL .= $valueFunction . '(' . (!empty($selectorName) ? $selectorName . '.' : '') . $operand->getPropertyName() .  ' ' . $operator . ' ?';
+                               $constraintSQL .= $valueFunction . '(' . (!empty($tableName) ? $tableName . '.' : '') . $columnName .  ' ' . $operator . ' ?';
                        }
 
                        $sql['where'][] = $constraintSQL;
@@ -465,7 +496,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         * Replace query placeholders in a query part by the given
         * parameters.
         *
-        * @param string $queryPart The query part with placeholders
+        * @param string $sqlString The query part with placeholders
         * @param array $parameters The parameters
         * @return string The query part with replaced placeholders
         */
@@ -478,7 +509,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                                if ($parameter === NULL) {
                                        $parameter = 'NULL';
                                } else {
-                                       $parameter = "'" . $parameter . "'"; // TODO Discuss: Do we need quotation?
+                                       $parameter = $this->databaseHandle->fullQuoteStr($parameter, 'foo'); // FIXME This may not work with DBAL; check this
                                }
                                $sqlString = substr($sqlString, 0, $markPosition) . $parameter . substr($sqlString, $markPosition + 1);
                        }
@@ -489,19 +520,21 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
        /**
         * Builds the enable fields statement
         *
-        * @param string $selectorName The selector name (= database table name)
+        * @param string $tableName The database table name
         * @param array &$sql The query parts
         * @return void
         */
-       protected function addEnableFieldsStatement($selectorName, array &$sql) {
-               if (is_array($GLOBALS['TCA'][$selectorName]['ctrl'])) {
+       protected function addEnableFieldsStatement($tableName, array &$sql) {
+               if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
                        if (TYPO3_MODE === 'FE') {
-                               $statement = substr($GLOBALS['TSFE']->sys_page->enableFields($selectorName), 5);
+                               $statement = $GLOBALS['TSFE']->sys_page->enableFields($tableName);
                        } else { // TYPO3_MODE === 'BE'
-                               $statement = substr(t3lib_BEfunc::BEenableFields($selectorName), 5);
+                               $statement = t3lib_BEfunc::deleteClause($tableName);
+                               $statement .= t3lib_BEfunc::BEenableFields($tableName);
                        }
                        if(!empty($statement)) {
-                               $sql['enableFields'][] = $statement;
+                               $statement = substr($statement, 5);
+                               $sql['additionalWhereClause'][] = $statement;
                        }
                }
        }
@@ -509,28 +542,27 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
        /**
         * Builds the page ID checking statement
         *
-        * @param string $selectorName The selector name (= database table name)
+        * @param string $tableName The database table name
         * @param array &$sql The query parts
         * @return void
         */
-       protected function addPageIdStatement($selectorName, array &$sql) {
-               // TODO We have to call the appropriate API method if we are in TYPO3BE mode
-               if (is_array($GLOBALS['TCA'][$selectorName]['ctrl'])) {
-                       $extbaseSettings = Tx_Extbase_Dispatcher::getSettings();
-                       $sql['enableFields'][] = $selectorName . '.pid IN (' . implode(', ', t3lib_div::intExplode(',', $extbaseSettings['storagePid'])) . ')';
+       protected function addPageIdStatement($tableName, array &$sql) {
+               $columns = $this->databaseHandle->admin_get_fields($tableName);         
+               if (is_array($GLOBALS['TCA'][$tableName]['ctrl']) && array_key_exists('pid', $columns)) {
+                       $extbaseFrameworkConfiguration = Tx_Extbase_Dispatcher::getExtbaseFrameworkConfiguration();
+                       $sql['additionalWhereClause'][] = $tableName . '.pid IN (' . implode(', ', t3lib_div::intExplode(',', $extbaseFrameworkConfiguration['persistence']['storagePid'])) . ')';
                }
        }
 
        /**
-        * Transforms orderings into SQL
+        * Transforms orderings into SQL.
         *
-        * @param array $orderings
-        * @param array &$sql
-        * @param array &$parameters
-        * @param array $boundVariableValues
+        * @param array $orderings Ann array of orderings (Tx_Extbase_Persistence_QOM_Ordering)
+        * @param Tx_Extbase_Persistence_QOM_SourceInterface $source The source
+        * @param array &$sql The query parts
         * @return void
         */
-       protected function parseOrderings(array $orderings, array &$sql, array &$parameters, array $boundVariableValues) {
+       protected function parseOrderings(array $orderings, Tx_Extbase_Persistence_QOM_SourceInterface $source, array &$sql) {
                foreach ($orderings as $ordering) {
                        $operand = $ordering->getOperand();
                        $order = $ordering->getOrder();
@@ -543,10 +575,19 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                                                $order = 'DESC';
                                                break;
                                        default:
-                                               throw new Tx_Extbase_Persistence_Exception('Unsupported order encountered.', 1242816074);
+                                               throw new Tx_Extbase_Persistence_Exception_UnsupportedOrder('Unsupported order encountered.', 1242816074);
+                               }
+                               $tableName = $operand->getSelectorName();
+                               $className = '';
+                               if ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
+                                       $className = $source->getNodeTypeName();
+                               }
+                               $columnName = $this->dataMapper->convertPropertyNameToColumnName($operand->getPropertyName(), $className);
+                               if (strlen($tableName) > 0) {
+                                       $sql['orderings'][] = $tableName . '.' . $columnName . ' ' . $order;
+                               } else {
+                                       $sql['orderings'][] = $columnName . ' ' . $order;
                                }
-
-                               $sql['orderings'][] = $ordering->getOperand()->getPropertyName() . ' ' . $order;
                        }
                }
        }
@@ -572,14 +613,15 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         * workspace overlay before.
         *
         * @param Tx_Extbase_Persistence_QOM_SourceInterface $source The source (selector od join)
-        *
+        * @param resource &$sql The resource
         * @return array The result as an array of rows (tuples)
         */
        protected function getRowsFromResult(Tx_Extbase_Persistence_QOM_SourceInterface $source, $res) {
                $rows = array();
                while ($row = $this->databaseHandle->sql_fetch_assoc($res)) {
                        if      ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
-                       $row = $this->doLanguageAndWorkspaceOverlay($source->getSelectorName(), $row);
+                               // FIXME The overlay is only performed if we query a single table; no joins
+                               $row = $this->doLanguageAndWorkspaceOverlay($source->getSelectorName(), $row);
                        }
                        if (is_array($row)) {
                                // TODO Check if this is necessary, maybe the last line is enough
@@ -622,7 +664,6 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                        } else {
                                require_once(PATH_t3lib . 'class.t3lib_page.php');
                                $this->pageSelectObject = t3lib_div::makeInstance( 't3lib_pageSelect' );
-                               //$this->pageSelectObject->versioningPreview =  TRUE;
                                if ($workspaceUid === NULL) {
                                        $workspaceUid = $GLOBALS['BE_USER']->workspace;
                                }
@@ -651,6 +692,9 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
 
        /**
         * Clear the TYPO3 page cache for the given record.
+        * If the record lies on a page, then we clear the cache of this page.
+        * If the record has no PID column, we clear the cache of the current page as best-effort.
+        *
         * Much of this functionality is taken from t3lib_tcemain::clear_cache() which unfortunately only works with logged-in BE user.
         *
         * @param $tableName Table name of the record
@@ -658,19 +702,31 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         * @return void
         */
        protected function clearPageCache($tableName, $uid) {
-               if ($this->automaticCacheClearing !== TRUE) return;
-
-               $pageCache = $GLOBALS['typo3CacheManager']->getCache('cache_pages');
-               $pageSectionCache = $GLOBALS['typo3CacheManager']->getCache('cache_pagesection');
-
-               $result = $this->databaseHandle->exec_SELECTquery('pid', $tableName, 'uid='.intval($uid));
+               $extbaseSettings = Tx_Extbase_Dispatcher::getExtbaseFrameworkConfiguration();
+               if (isset($extbaseSettings['persistence']['enableAutomaticCacheClearing']) && $extbaseSettings['persistence']['enableAutomaticCacheClearing'] === '1') {
+               } else {
+                       // if disabled, return
+                       return;
+               }
 
                $pageIdsToClear = array();
-               if ($row = $this->databaseHandle->sql_fetch_assoc($result))     {
-                       $storagePage = $row['pid'];
+               $storagePage = NULL;
+
+               $columns = $this->databaseHandle->admin_get_fields($tableName);
+               if (array_key_exists('pid', $columns)) {
+                       $result = $this->databaseHandle->exec_SELECTquery('pid', $tableName, 'uid='.intval($uid));
+                       if ($row = $this->databaseHandle->sql_fetch_assoc($result))     {
+                               $storagePage = $row['pid'];
+                               $pageIdsToClear[] = $storagePage;
+                       }
+               } elseif (isset($GLOBALS['TSFE'])) {
+                       // No PID column - we can do a best-effort to clear the cache of the current page if in FE
+                       $storagePage = $GLOBALS['TSFE']->id;
                        $pageIdsToClear[] = $storagePage;
                }
-               if (!$storagePage) {
+
+
+               if ($storagePage === NULL) {
                        return;
                }
 
@@ -685,10 +741,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                        }
                }
 
-               foreach ($pageIdsToClear as $pageIdToClear) {
-                       $pageCache->flushByTag('pageId_' . $pageIdToClear);
-                       $pageSectionCache->flushByTag('pageId_' . $pageIdToClear);
-               }
+               Tx_Extbase_Utility_Cache::clearPageCache($pageIdsToClear);
        }
 }