Fixed bug #15580: Add calls to logDeprecatedFunction() for more deprecated functions...
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_db.php
old mode 100755 (executable)
new mode 100644 (file)
index 09d3f23..00b1bdf
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2004-2007 Kasper Skaarhoj (kasperYYYY@typo3.com)
+*  (c) 2004-2010 Kasper Skårhøj (kasperYYYY@typo3.com)
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
 /**
- * Contains the class "t3lib_db" containing functions for building SQL queries and mysql wrappers, thus providing a foundational API to all database interaction.
+ * Contains the class "t3lib_db" containing functions for building SQL queries
+ * and mysql wrappers, thus providing a foundational API to all database
+ * interaction.
  * This class is instantiated globally as $TYPO3_DB in TYPO3 scripts.
  *
  * $Id$
  *
- * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
+ * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
  */
 /**
  * [CLASS/FUNCTION INDEX of SCRIPT]
  * In all TYPO3 scripts the global variable $TYPO3_DB is an instance of this class. Use that.
  * Eg.                 $GLOBALS['TYPO3_DB']->sql_fetch_assoc()
  *
- * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
+ * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
  * @package TYPO3
  * @subpackage t3lib
  */
@@ -142,10 +144,14 @@ class t3lib_DB {
        var $debugOutput = FALSE;               // Set "TRUE" if you want database errors outputted.
        var $debug_lastBuiltQuery = '';         // Internally: Set to last built query (not necessarily executed...)
        var $store_lastBuiltQuery = FALSE;      // Set "TRUE" if you want the last built query to be stored in $debug_lastBuiltQuery independent of $this->debugOutput
+       var $explainOutput = 0;                 // Set this to 1 to get queries explained (devIPmask must match). Set the value to 2 to the same but disregarding the devIPmask. There is an alternative option to enable explain output in the admin panel under "TypoScript", which will produce much nicer output, but only works in FE.
 
                // Default link identifier:
        var $link = FALSE;
 
+               // Default character set, applies unless character set or collation are explicitely set
+       var $default_charset = 'utf8';
+
 
 
 
@@ -172,9 +178,28 @@ class t3lib_DB {
         * @param       string/array            See fullQuoteArray()
         * @return      pointer         MySQL result pointer / DBAL object
         */
-       function exec_INSERTquery($table,$fields_values,$no_quote_fields=FALSE) {
-               $res = mysql_query($this->INSERTquery($table,$fields_values,$no_quote_fields), $this->link);
-               if ($this->debugOutput) $this->debug('exec_INSERTquery');
+       function exec_INSERTquery($table, $fields_values, $no_quote_fields = FALSE) {
+               $res = mysql_query($this->INSERTquery($table, $fields_values, $no_quote_fields), $this->link);
+               if ($this->debugOutput) {
+                       $this->debug('exec_INSERTquery');
+               }
+               return $res;
+       }
+
+       /**
+        * Creates and executes an INSERT SQL-statement for $table with multiple rows.
+        *
+        * @param       string          Table name
+        * @param       array           Field names
+        * @param       array           Table rows. Each row should be an array with field values mapping to $fields
+        * @param       string/array            See fullQuoteArray()
+        * @return      pointer         MySQL result pointer / DBAL object
+        */
+       public function exec_INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) {
+               $res = mysql_query($this->INSERTmultipleRows($table, $fields, $rows, $no_quote_fields), $this->link);
+               if ($this->debugOutput) {
+                       $this->debug('exec_INSERTmultipleRows');
+               }
                return $res;
        }
 
@@ -189,9 +214,11 @@ class t3lib_DB {
         * @param       string/array            See fullQuoteArray()
         * @return      pointer         MySQL result pointer / DBAL object
         */
-       function exec_UPDATEquery($table,$where,$fields_values,$no_quote_fields=FALSE)  {
-               $res = mysql_query($this->UPDATEquery($table,$where,$fields_values,$no_quote_fields), $this->link);
-               if ($this->debugOutput) $this->debug('exec_UPDATEquery');
+       function exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields = FALSE) {
+               $res = mysql_query($this->UPDATEquery($table, $where, $fields_values, $no_quote_fields), $this->link);
+               if ($this->debugOutput) {
+                       $this->debug('exec_UPDATEquery');
+               }
                return $res;
        }
 
@@ -203,9 +230,11 @@ class t3lib_DB {
         * @param       string          WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
         * @return      pointer         MySQL result pointer / DBAL object
         */
-       function exec_DELETEquery($table,$where)        {
-               $res = mysql_query($this->DELETEquery($table,$where), $this->link);
-               if ($this->debugOutput) $this->debug('exec_DELETEquery');
+       function exec_DELETEquery($table, $where) {
+               $res = mysql_query($this->DELETEquery($table, $where), $this->link);
+               if ($this->debugOutput) {
+                       $this->debug('exec_DELETEquery');
+               }
                return $res;
        }
 
@@ -222,9 +251,17 @@ class t3lib_DB {
         * @param       string          Optional LIMIT value ([begin,]max), if none, supply blank string.
         * @return      pointer         MySQL result pointer / DBAL object
         */
-       function exec_SELECTquery($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='',$limit='')   {
-               $res = mysql_query($this->SELECTquery($select_fields,$from_table,$where_clause,$groupBy,$orderBy,$limit), $this->link);
-               if ($this->debugOutput) $this->debug('exec_SELECTquery');
+       function exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') {
+               $query = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
+               $res = mysql_query($query, $this->link);
+
+               if ($this->debugOutput) {
+                       $this->debug('exec_SELECTquery');
+               }
+               if ($this->explainOutput) {
+                       $this->explain($query, $from_table, $this->sql_num_rows($res));
+               }
+
                return $res;
        }
 
@@ -247,19 +284,26 @@ class t3lib_DB {
         * @return      pointer         MySQL result pointer / DBAL object
         * @see exec_SELECTquery()
         */
-       function exec_SELECT_mm_query($select,$local_table,$mm_table,$foreign_table,$whereClause='',$groupBy='',$orderBy='',$limit='')  {
-               if($foreign_table == $local_table) {
-                       $foreign_table_as = $foreign_table.uniqid('_join');
+       function exec_SELECT_mm_query($select, $local_table, $mm_table, $foreign_table, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '') {
+               if ($foreign_table == $local_table) {
+                       $foreign_table_as = $foreign_table . uniqid('_join');
                }
 
-               $mmWhere = $local_table ? $local_table.'.uid='.$mm_table.'.uid_local' : '';
-               $mmWhere.= ($local_table AND $foreign_table) ? ' AND ' : '';
-               $mmWhere.= $foreign_table ? ($foreign_table_as ? $foreign_table_as : $foreign_table).'.uid='.$mm_table.'.uid_foreign' : '';
+               $mmWhere = $local_table ? $local_table . '.uid=' . $mm_table . '.uid_local' : '';
+               $mmWhere .= ($local_table AND $foreign_table) ? ' AND ' : '';
+
+               $tables = ($local_table ? $local_table . ',' : '') . $mm_table;
+
+               if ($foreign_table) {
+                       $mmWhere .= ($foreign_table_as ? $foreign_table_as : $foreign_table) . '.uid=' . $mm_table . '.uid_foreign';
+                       $tables .= ',' . $foreign_table . ($foreign_table_as ? ' AS ' . $foreign_table_as : '');
+               }
 
-               return $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+               return $this->exec_SELECTquery(
                                        $select,
-                                       ($local_table ? $local_table.',' : '').$mm_table.($foreign_table ? ','. $foreign_table.($foreign_table_as ? ' AS '.$foreign_table_as : '') : ''),
-                                       $mmWhere.' '.$whereClause,              // whereClauseMightContainGroupOrderBy
+                                       $tables,
+                                               // whereClauseMightContainGroupOrderBy
+                                       $mmWhere . ' ' . $whereClause,
                                        $groupBy,
                                        $orderBy,
                                        $limit
@@ -275,15 +319,15 @@ class t3lib_DB {
         * @return      pointer         MySQL select result pointer / DBAL object
         * @see exec_SELECTquery()
         */
-       function exec_SELECT_queryArray($queryParts)    {
+       function exec_SELECT_queryArray($queryParts) {
                return $this->exec_SELECTquery(
-                                       $queryParts['SELECT'],
-                                       $queryParts['FROM'],
-                                       $queryParts['WHERE'],
-                                       $queryParts['GROUPBY'],
-                                       $queryParts['ORDERBY'],
-                                       $queryParts['LIMIT']
-                               );
+                       $queryParts['SELECT'],
+                       $queryParts['FROM'],
+                       $queryParts['WHERE'],
+                       $queryParts['GROUPBY'],
+                       $queryParts['ORDERBY'],
+                       $queryParts['LIMIT']
+               );
        }
 
        /**
@@ -298,19 +342,21 @@ class t3lib_DB {
         * @param       string          If set, the result array will carry this field names value as index. Requires that field to be selected of course!
         * @return      array           Array of rows.
         */
-       function exec_SELECTgetRows($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='',$limit='',$uidIndexField='')       {
-               $res = $this->exec_SELECTquery($select_fields,$from_table,$where_clause,$groupBy,$orderBy,$limit);
-               if ($this->debugOutput) $this->debug('exec_SELECTquery');
+       function exec_SELECTgetRows($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', $uidIndexField = '') {
+               $res = $this->exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
+               if ($this->debugOutput) {
+                       $this->debug('exec_SELECTquery');
+               }
 
-               if (!$this->sql_error())        {
+               if (!$this->sql_error()) {
                        $output = array();
 
-                       if ($uidIndexField)     {
-                               while($tempRow = $this->sql_fetch_assoc($res))  {
+                       if ($uidIndexField) {
+                               while ($tempRow = $this->sql_fetch_assoc($res)) {
                                        $output[$tempRow[$uidIndexField]] = $tempRow;
                                }
                        } else {
-                               while($output[] = $this->sql_fetch_assoc($res));
+                               while ($output[] = $this->sql_fetch_assoc($res));
                                array_pop($output);
                        }
                        $this->sql_free_result($res);
@@ -318,6 +364,38 @@ class t3lib_DB {
                return $output;
        }
 
+       /**
+        * Counts the number of rows in a table.
+        *
+        * @param       string          $field: Name of the field to use in the COUNT() expression (e.g. '*')
+        * @param       string          $table: Name of the table to count rows for
+        * @param       string          $where: (optional) WHERE statement of the query
+        * @return      mixed           Number of rows counter (integer) or false if something went wrong (boolean)
+        */
+       public function exec_SELECTcountRows($field, $table, $where = '') {
+               $count = false;
+               $resultSet = $this->exec_SELECTquery('COUNT(' . $field . ')', $table, $where);
+               if ($resultSet !== false) {
+                       list($count) = $this->sql_fetch_row($resultSet);
+                       $this->sql_free_result($resultSet);
+               }
+               return $count;
+       }
+
+       /**
+        * Truncates a table.
+        *
+        * @param       string          Database tablename
+        * @return      mixed           Result from handler
+        */
+       public function exec_TRUNCATEquery($table) {
+               $res = mysql_query($this->TRUNCATEquery($table), $this->link);
+               if ($this->debugOutput) {
+                       $this->debug('exec_TRUNCATEquery');
+               }
+               return $res;
+       }
+
 
 
 
@@ -342,28 +420,60 @@ class t3lib_DB {
         * @param       array           See exec_INSERTquery()
         * @param       string/array            See fullQuoteArray()
         * @return      string          Full SQL query for INSERT (unless $fields_values does not contain any elements in which case it will be false)
-        * @deprecated                  use exec_INSERTquery() instead if possible!
         */
-       function INSERTquery($table,$fields_values,$no_quote_fields=FALSE)      {
+       function INSERTquery($table, $fields_values, $no_quote_fields = FALSE) {
 
-                       // Table and fieldnames should be "SQL-injection-safe" when supplied to this function (contrary to values in the arrays which may be insecure).
-               if (is_array($fields_values) && count($fields_values))  {
+                       // Table and fieldnames should be "SQL-injection-safe" when supplied to this
+                       // function (contrary to values in the arrays which may be insecure).
+               if (is_array($fields_values) && count($fields_values)) {
 
                                // quote and escape values
-                       $fields_values = $this->fullQuoteArray($fields_values,$table,$no_quote_fields);
+                       $fields_values = $this->fullQuoteArray($fields_values, $table, $no_quote_fields);
 
                                // Build query:
-                       $query = 'INSERT INTO '.$table.'
-                               (
-                                       '.implode(',
-                                       ',array_keys($fields_values)).'
-                               ) VALUES (
-                                       '.implode(',
-                                       ',$fields_values).'
-                               )';
+                       $query = 'INSERT INTO ' . $table .
+                               '(' . implode(',', array_keys($fields_values)) . ') VALUES ' .
+                               '(' . implode(',', $fields_values) . ')';
 
                                // Return query:
-                       if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
+                       if ($this->debugOutput || $this->store_lastBuiltQuery) {
+                               $this->debug_lastBuiltQuery = $query;
+                       }
+                       return $query;
+               }
+       }
+
+       /**
+        * Creates an INSERT SQL-statement for $table with multiple rows.
+        *
+        * @param       string          Table name
+        * @param       array           Field names
+        * @param       array           Table rows. Each row should be an array with field values mapping to $fields
+        * @param       string/array            See fullQuoteArray()
+        * @return      string          Full SQL query for INSERT (unless $rows does not contain any elements in which case it will be false)
+        */
+       public function INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) {
+                       // Table and fieldnames should be "SQL-injection-safe" when supplied to this
+                       // function (contrary to values in the arrays which may be insecure).
+               if (count($rows)) {
+                               // Build query:
+                       $query = 'INSERT INTO ' . $table .
+                               ' (' . implode(', ', $fields) . ') VALUES ';
+
+                       $rowSQL = array();
+                       foreach ($rows as $row) {
+                                       // quote and escape values
+                               $row = $this->fullQuoteArray($row, $table, $no_quote_fields);
+                               $rowSQL[] = '(' . implode(', ', $row) . ')';
+                       }
+
+                       $query .= implode(', ', $rowSQL);
+
+                               // Return query:
+                       if ($this->debugOutput || $this->store_lastBuiltQuery) {
+                               $this->debug_lastBuiltQuery = $query;
+                       }
+
                        return $query;
                }
        }
@@ -376,38 +486,36 @@ class t3lib_DB {
         * @param       string          See exec_UPDATEquery()
         * @param       array           See exec_UPDATEquery()
         * @param       array           See fullQuoteArray()
-        * @return      string          Full SQL query for UPDATE (unless $fields_values does not contain any elements in which case it will be false)
-        * @deprecated                  use exec_UPDATEquery() instead if possible!
+        * @return      string          Full SQL query for UPDATE
         */
-       function UPDATEquery($table,$where,$fields_values,$no_quote_fields=FALSE)       {
-
-                       // Table and fieldnames should be "SQL-injection-safe" when supplied to this function (contrary to values in the arrays which may be insecure).
-               if (is_string($where))  {
-                       if (is_array($fields_values) && count($fields_values))  {
+       function UPDATEquery($table, $where, $fields_values, $no_quote_fields = FALSE) {
+                       // Table and fieldnames should be "SQL-injection-safe" when supplied to this
+                       // function (contrary to values in the arrays which may be insecure).
+               if (is_string($where)) {
+                       $fields = array();
+                       if (is_array($fields_values) && count($fields_values)) {
 
                                        // quote and escape values
-                               $nArr = $this->fullQuoteArray($fields_values,$table,$no_quote_fields);
+                               $nArr = $this->fullQuoteArray($fields_values, $table, $no_quote_fields);
 
-                               $fields = array();
                                foreach ($nArr as $k => $v) {
                                        $fields[] = $k.'='.$v;
                                }
+                       }
+
+                               // Build query:
+                       $query = 'UPDATE ' . $table . ' SET ' . implode(',', $fields) .
+                               (strlen($where) > 0 ? ' WHERE ' . $where : '');
 
-                                       // Build query:
-                               $query = 'UPDATE '.$table.'
-                                       SET
-                                               '.implode(',
-                                               ',$fields).
-                                       (strlen($where)>0 ? '
-                                       WHERE
-                                               '.$where : '');
-
-                                       // Return query:
-                               if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
-                               return $query;
+                       if ($this->debugOutput || $this->store_lastBuiltQuery) {
+                               $this->debug_lastBuiltQuery = $query;
                        }
+                       return $query;
                } else {
-                       die('<strong>TYPO3 Fatal Error:</strong> "Where" clause argument for UPDATE query was not a string in $this->UPDATEquery() !');
+                       throw new InvalidArgumentException(
+                               'TYPO3 Fatal Error: "Where" clause argument for UPDATE query was not a string in $this->UPDATEquery() !',
+                               1270853880
+                       );
                }
        }
 
@@ -418,21 +526,23 @@ class t3lib_DB {
         * @param       string          See exec_DELETEquery()
         * @param       string          See exec_DELETEquery()
         * @return      string          Full SQL query for DELETE
-        * @deprecated                  use exec_DELETEquery() instead if possible!
         */
-       function DELETEquery($table,$where)     {
-               if (is_string($where))  {
+       function DELETEquery($table, $where) {
+               if (is_string($where)) {
 
                                // Table and fieldnames should be "SQL-injection-safe" when supplied to this function
-                       $query = 'DELETE FROM '.$table.
-                               (strlen($where)>0 ? '
-                               WHERE
-                                       '.$where : '');
+                       $query = 'DELETE FROM ' . $table .
+                               (strlen($where) > 0 ? ' WHERE ' . $where : '');
 
-                       if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
+                       if ($this->debugOutput || $this->store_lastBuiltQuery) {
+                               $this->debug_lastBuiltQuery = $query;
+                       }
                        return $query;
                } else {
-                       die('<strong>TYPO3 Fatal Error:</strong> "Where" clause argument for DELETE query was not a string in $this->DELETEquery() !');
+                       throw new InvalidArgumentException(
+                               'TYPO3 Fatal Error: "Where" clause argument for DELETE query was not a string in $this->DELETEquery() !',
+                               1270853881
+                       );
                }
        }
 
@@ -447,42 +557,79 @@ class t3lib_DB {
         * @param       string          See exec_SELECTquery()
         * @param       string          See exec_SELECTquery()
         * @return      string          Full SQL query for SELECT
-        * @deprecated                  use exec_SELECTquery() instead if possible!
         */
-       function SELECTquery($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='',$limit='')        {
+       function SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') {
 
                        // Table and fieldnames should be "SQL-injection-safe" when supplied to this function
                        // Build basic query:
-               $query = 'SELECT '.$select_fields.'
-                       FROM '.$from_table.
-                       (strlen($where_clause)>0 ? '
-                       WHERE
-                               '.$where_clause : '');
+               $query = 'SELECT ' . $select_fields . ' FROM ' . $from_table .
+                       (strlen($where_clause) > 0 ? ' WHERE ' . $where_clause : '');
 
                        // Group by:
-               if (strlen($groupBy)>0) {
-                       $query.= '
-                       GROUP BY '.$groupBy;
-               }
+               $query .= (strlen($groupBy) > 0 ? ' GROUP BY ' . $groupBy : '');
+
                        // Order by:
-               if (strlen($orderBy)>0) {
-                       $query.= '
-                       ORDER BY '.$orderBy;
-               }
+               $query .= (strlen($orderBy) > 0 ? ' ORDER BY ' . $orderBy : '');
+
                        // Group by:
-               if (strlen($limit)>0)   {
-                       $query.= '
-                       LIMIT '.$limit;
+               $query .= (strlen($limit) > 0 ? ' LIMIT ' . $limit : '');
+
+                       // Return query:
+               if ($this->debugOutput || $this->store_lastBuiltQuery) {
+                       $this->debug_lastBuiltQuery = $query;
                }
+               return $query;
+       }
+
+       /**
+        * Creates a SELECT SQL-statement to be used as subquery within another query.
+        * BEWARE: This method should not be overriden within DBAL to prevent quoting from happening.
+        *
+        * @param       string          $select_fields: List of fields to select from the table.
+        * @param       string          $from_table: Table from which to select.
+        * @param       string          $where_clause: Conditional WHERE statement
+        * @return      string          Full SQL query for SELECT
+        */
+       public function SELECTsubquery($select_fields, $from_table, $where_clause) {
+                       // Table and fieldnames should be "SQL-injection-safe" when supplied to this function
+                       // Build basic query:
+               $query = 'SELECT ' . $select_fields . ' FROM ' . $from_table .
+                       (strlen($where_clause) > 0 ? ' WHERE ' . $where_clause : '');
 
                        // Return query:
-               if ($this->debugOutput || $this->store_lastBuiltQuery) $this->debug_lastBuiltQuery = $query;
+               if ($this->debugOutput || $this->store_lastBuiltQuery) {
+                       $this->debug_lastBuiltQuery = $query;
+               }
+
+               return $query;
+       }
+
+       /**
+        * Creates a TRUNCATE TABLE SQL-statement
+        *
+        * @param       string          See exec_TRUNCATEquery()
+        * @return      string          Full SQL query for TRUNCATE TABLE
+        */
+       public function TRUNCATEquery($table) {
+                       // Table should be "SQL-injection-safe" when supplied to this function
+                       // Build basic query:
+               $query = 'TRUNCATE TABLE ' . $table;
+
+                       // Return query:
+               if ($this->debugOutput || $this->store_lastBuiltQuery) {
+                       $this->debug_lastBuiltQuery = $query;
+               }
+
                return $query;
        }
 
        /**
         * Returns a WHERE clause that can find a value ($value) in a list field ($field)
-        * For instance a record in the database might contain a list of numbers, "34,234,5" (with no spaces between). This query would be able to select that record based on the value "34", "234" or "5" regardless of their positioni in the list (left, middle or right).
+        * For instance a record in the database might contain a list of numbers,
+        * "34,234,5" (with no spaces between). This query would be able to select that
+        * record based on the value "34", "234" or "5" regardless of their position in
+        * the list (left, middle or right).
+        * The value must not contain a comma (,)
         * Is nice to look up list-relations to records or files in TYPO3 database tables.
         *
         * @param       string          Field name
@@ -490,9 +637,13 @@ class t3lib_DB {
         * @param       string          Table in which we are searching (for DBAL detection of quoteStr() method)
         * @return      string          WHERE clause for a query
         */
-       function listQuery($field, $value, $table)      {
-               $command = $this->quoteStr($value, $table);
-               $where = '('.$field.' LIKE \'%,'.$command.',%\' OR '.$field.' LIKE \''.$command.',%\' OR '.$field.' LIKE \'%,'.$command.'\' OR '.$field.'=\''.$command.'\')';
+       public function listQuery($field, $value, $table) {
+               $value = (string)$value;
+               if (strpos(',', $value) !== FALSE) {
+                       throw new InvalidArgumentException('$value must not contain a comma (,) in $this->listQuery() !');
+               }
+               $pattern = $this->quoteStr($value, $table);
+               $where = 'FIND_IN_SET(\'' . $pattern . '\',' . $field . ')';
                return $where;
        }
 
@@ -504,14 +655,14 @@ class t3lib_DB {
         * @param       string          Table in which we are searching (for DBAL detection of quoteStr() method)
         * @return      string          WHERE clause for search
         */
-       function searchQuery($searchWords,$fields,$table)       {
+       function searchQuery($searchWords, $fields, $table) {
                $queryParts = array();
 
-               foreach($searchWords as $sw)    {
-                       $like=' LIKE \'%'.$this->quoteStr($sw, $table).'%\'';
-                       $queryParts[] = $table.'.'.implode($like.' OR '.$table.'.',$fields).$like;
+               foreach($searchWords as $sw) {
+                       $like = ' LIKE \'%' . $this->quoteStr($sw, $table) . '%\'';
+                       $queryParts[] = $table . '.' . implode($like . ' OR ' . $table . '.', $fields) . $like;
                }
-               $query = '('.implode(') AND (',$queryParts).')';
+               $query = '(' . implode(') AND (', $queryParts) . ')';
                return $query ;
        }
 
@@ -525,6 +676,79 @@ class t3lib_DB {
 
 
 
+       /**************************************
+        *
+        * Prepared Query Support
+        *
+        **************************************/
+
+       /**
+        * Creates a SELECT prepared SQL statement.
+        *
+        * @param string See exec_SELECTquery()
+        * @param string See exec_SELECTquery()
+        * @param string See exec_SELECTquery()
+        * @param string See exec_SELECTquery()
+        * @param string See exec_SELECTquery()
+        * @param string See exec_SELECTquery()
+        * @param array $input_parameters An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as t3lib_db_PreparedStatement::PARAM_AUTOTYPE.
+        * @return t3lib_db_PreparedStatement Prepared statement
+        */
+       public function prepare_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', array $input_parameters = array()) {
+               $query = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
+               $preparedStatement = t3lib_div::makeInstance('t3lib_db_PreparedStatement', $query, $from_table, array());
+               /* @var $preparedStatement t3lib_db_PreparedStatement */
+
+                       // Bind values to parameters
+               foreach ($input_parameters as $key => $value) {
+                       $preparedStatement->bindValue($key, $value, t3lib_db_PreparedStatement::PARAM_AUTOTYPE);
+               }
+
+                       // Return prepared statement
+               return $preparedStatement;
+       }
+
+       /**
+        * Creates a SELECT prepared SQL statement based on input query parts array
+        *
+        * @param array Query parts array
+        * @param array $input_parameters An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as t3lib_db_PreparedStatement::PARAM_AUTOTYPE.
+        * @return t3lib_db_PreparedStatement Prepared statement
+        */
+       public function prepare_SELECTqueryArray(array $queryParts, array $input_parameters = array()) {
+               return $this->prepare_SELECTquery(
+                       $queryParts['SELECT'],
+                       $queryParts['FROM'],
+                       $queryParts['WHERE'],
+                       $queryParts['GROUPBY'],
+                       $queryParts['ORDERBY'],
+                       $queryParts['LIMIT'],
+                       $input_parameters
+               );
+       }
+
+       /**
+        * Executes a prepared query.
+        * This method may only be called by t3lib_db_PreparedStatement.
+        *
+        * @param string $query The query to execute
+        * @param array $queryComponents The components of the query to execute
+        * @return pointer MySQL result pointer / DBAL object
+        * @access private
+        */
+       public function exec_PREPAREDquery($query, array $queryComponents) {
+               $res = mysql_query($query, $this->link);
+               if ($this->debugOutput) {
+                       $this->debug('stmt_execute', $query);
+               }
+               return $res;
+       }
+
+
+
+
+
+
 
 
 
@@ -550,8 +774,8 @@ class t3lib_DB {
         * @return      string          Output string; Wrapped in single quotes and quotes in the string (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
         * @see quoteStr()
         */
-       function fullQuoteStr($str, $table)     {
-               return '\''.mysql_real_escape_string($str, $this->link).'\'';
+       function fullQuoteStr($str, $table) {
+               return '\'' . mysql_real_escape_string($str, $this->link) . '\'';
        }
 
        /**
@@ -563,15 +787,16 @@ class t3lib_DB {
         * @return      array           The input array with the values quoted
         * @see cleanIntArray()
         */
-       function fullQuoteArray($arr, $table, $noQuote=FALSE)   {
-               if (is_string($noQuote))        {
-                       $noQuote = explode(',',$noQuote);
-               } elseif (!is_array($noQuote))  {       // sanity check
+       function fullQuoteArray($arr, $table, $noQuote = FALSE) {
+               if (is_string($noQuote)) {
+                       $noQuote = explode(',', $noQuote);
+                       // sanity check
+               } elseif (!is_array($noQuote)) {
                        $noQuote = FALSE;
                }
 
-               foreach($arr as $k => $v)       {
-                       if ($noQuote===FALSE || !in_array($k,$noQuote))     {
+               foreach($arr as $k => $v) {
+                       if ($noQuote === FALSE || !in_array($k, $noQuote)) {
                                $arr[$k] = $this->fullQuoteStr($v, $table);
                        }
                }
@@ -590,7 +815,7 @@ class t3lib_DB {
         * @return      string          Output string; Quotes (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
         * @see quoteStr()
         */
-       function quoteStr($str, $table) {
+       function quoteStr($str, $table) {
                return mysql_real_escape_string($str, $this->link);
        }
 
@@ -602,8 +827,8 @@ class t3lib_DB {
         * @return      string          Output string; % and _ will be escaped with \ (or otherwise based on DBAL handler)
         * @see quoteStr()
         */
-       function escapeStrForLike($str, $table) {
-               return preg_replace('/[_%]/','\\\$0',$str);
+       function escapeStrForLike($str, $table) {
+               return addcslashes($str, '_%');
        }
 
        /**
@@ -615,8 +840,8 @@ class t3lib_DB {
         * @return      array           The input array with all values passed through intval()
         * @see cleanIntList()
         */
-       function cleanIntArray($arr)    {
-               foreach($arr as $k => $v)       {
+       function cleanIntArray($arr) {
+               foreach($arr as $k => $v) {
                        $arr[$k] = intval($arr[$k]);
                }
                return $arr;
@@ -631,8 +856,8 @@ class t3lib_DB {
         * @return      string          The input list but with every value passed through intval()
         * @see cleanIntArray()
         */
-       function cleanIntList($list)    {
-               return implode(',',t3lib_div::intExplode(',',$list));
+       function cleanIntList($list) {
+               return implode(',', t3lib_div::intExplode(',', $list));
        }
 
        /**
@@ -645,8 +870,8 @@ class t3lib_DB {
         * @return      string          eg. "title, uid"
         * @see exec_SELECTquery(), stripGroupBy()
         */
-       function stripOrderBy($str)     {
-               return preg_replace('/^ORDER[[:space:]]+BY[[:space:]]+/i','',trim($str));
+       function stripOrderBy($str) {
+               return preg_replace('/^ORDER[[:space:]]+BY[[:space:]]+/i', '', trim($str));
        }
 
        /**
@@ -659,8 +884,8 @@ class t3lib_DB {
         * @return      string          eg. "title, uid"
         * @see exec_SELECTquery(), stripOrderBy()
         */
-       function stripGroupBy($str)     {
-               return preg_replace('/^GROUP[[:space:]]+BY[[:space:]]+/i','',trim($str));
+       function stripGroupBy($str) {
+               return preg_replace('/^GROUP[[:space:]]+BY[[:space:]]+/i', '', trim($str));
        }
 
        /**
@@ -671,33 +896,35 @@ class t3lib_DB {
         * @param       string          Input string
         * @return      array
         */
-       function splitGroupOrderLimit($str)     {
-               $str = ' '.$str;        // Prepending a space to make sure "[[:space:]]+" will find a space there for the first element.
+       function splitGroupOrderLimit($str) {
+                       // Prepending a space to make sure "[[:space:]]+" will find a space there
+                       // for the first element.
+               $str = ' ' . $str;
                        // Init output array:
                $wgolParts = array(
                        'WHERE' => '',
                        'GROUPBY' => '',
                        'ORDERBY' => '',
-                       'LIMIT' => ''
+                       'LIMIT' => '',
                );
 
                        // Find LIMIT:
                $reg = array();
-               if (preg_match('/^(.*)[[:space:]]+LIMIT[[:space:]]+([[:alnum:][:space:],._]+)$/i',$str,$reg))   {
+               if (preg_match('/^(.*)[[:space:]]+LIMIT[[:space:]]+([[:alnum:][:space:],._]+)$/i', $str, $reg)) {
                        $wgolParts['LIMIT'] = trim($reg[2]);
                        $str = $reg[1];
                }
 
                        // Find ORDER BY:
                $reg = array();
-               if (preg_match('/^(.*)[[:space:]]+ORDER[[:space:]]+BY[[:space:]]+([[:alnum:][:space:],._]+)$/i',$str,$reg))     {
+               if (preg_match('/^(.*)[[:space:]]+ORDER[[:space:]]+BY[[:space:]]+([[:alnum:][:space:],._]+)$/i', $str, $reg)) {
                        $wgolParts['ORDERBY'] = trim($reg[2]);
                        $str = $reg[1];
                }
 
                        // Find GROUP BY:
                $reg = array();
-               if (preg_match('/^(.*)[[:space:]]+GROUP[[:space:]]+BY[[:space:]]+([[:alnum:][:space:],._]+)$/i',$str,$reg))     {
+               if (preg_match('/^(.*)[[:space:]]+GROUP[[:space:]]+BY[[:space:]]+([[:alnum:][:space:],._]+)$/i', $str, $reg)) {
                        $wgolParts['GROUPBY'] = trim($reg[2]);
                        $str = $reg[1];
                }
@@ -732,16 +959,21 @@ class t3lib_DB {
        /**
         * Executes query
         * mysql() wrapper function
-        * DEPRECATED - use exec_* functions from this class instead!
-        * Usage count/core: 9
+        * Usage count/core: 0
         *
         * @param       string          Database name
         * @param       string          Query to execute
         * @return      pointer         Result pointer / DBAL object
+        * @deprecated since TYPO3 3.6, will be removed in TYPO3 4.6
+        * @see sql_query()
         */
-       function sql($db,$query)        {
+       function sql($db, $query) {
+               t3lib_div::logDeprecatedFunction();
+
                $res = mysql_query($query, $this->link);
-               if ($this->debugOutput) $this->debug('sql',$query);
+               if ($this->debugOutput) {
+                       $this->debug('sql', $query);
+               }
                return $res;
        }
 
@@ -753,9 +985,11 @@ class t3lib_DB {
         * @param       string          Query to execute
         * @return      pointer         Result pointer / DBAL object
         */
-       function sql_query($query)      {
+       function sql_query($query) {
                $res = mysql_query($query, $this->link);
-               if ($this->debugOutput) $this->debug('sql_query',$query);
+               if ($this->debugOutput) {
+                       $this->debug('sql_query', $query);
+               }
                return $res;
        }
 
@@ -766,21 +1000,34 @@ class t3lib_DB {
         *
         * @return      string          MySQL error string.
         */
-       function sql_error()    {
+       function sql_error() {
                return mysql_error($this->link);
        }
 
        /**
+        * Returns the error number on the last sql() execution
+        * mysql_errno() wrapper function
+        *
+        * @return      int             MySQL error number.
+        */
+       function sql_errno() {
+               return mysql_errno($this->link);
+       }
+
+       /**
         * Returns the number of selected rows.
         * mysql_num_rows() wrapper function
         * Usage count/core: 85
         *
         * @param       pointer         MySQL result pointer (of SELECT query) / DBAL object
-        * @return      integer         Number of resulting rows.
+        * @return      integer         Number of resulting rows
         */
-       function sql_num_rows($res)     {
-               $this->debug_check_recordset($res);
-               return mysql_num_rows($res);
+       function sql_num_rows($res) {
+               if ($this->debug_check_recordset($res)) {
+                       return mysql_num_rows($res);
+               } else {
+                       return FALSE;
+               }
        }
 
        /**
@@ -791,9 +1038,12 @@ class t3lib_DB {
         * @param       pointer         MySQL result pointer (of SELECT query) / DBAL object
         * @return      array           Associative array of result row.
         */
-       function sql_fetch_assoc($res)  {
-               $this->debug_check_recordset($res);
-               return mysql_fetch_assoc($res);
+       function sql_fetch_assoc($res) {
+               if ($this->debug_check_recordset($res)) {
+                       return mysql_fetch_assoc($res);
+               } else {
+                       return FALSE;
+               }
        }
 
        /**
@@ -805,9 +1055,12 @@ class t3lib_DB {
         * @param       pointer         MySQL result pointer (of SELECT query) / DBAL object
         * @return      array           Array with result rows.
         */
-       function sql_fetch_row($res)    {
-               $this->debug_check_recordset($res);
-               return mysql_fetch_row($res);
+       function sql_fetch_row($res) {
+               if ($this->debug_check_recordset($res)) {
+                       return mysql_fetch_row($res);
+               } else {
+                       return FALSE;
+               }
        }
 
        /**
@@ -818,9 +1071,12 @@ class t3lib_DB {
         * @param       pointer         MySQL result pointer to free / DBAL object
         * @return      boolean         Returns TRUE on success or FALSE on failure.
         */
-       function sql_free_result($res)  {
-               $this->debug_check_recordset($res);
-               return mysql_free_result($res);
+       function sql_free_result($res) {
+               if ($this->debug_check_recordset($res)) {
+                       return mysql_free_result($res);
+               } else {
+                       return FALSE;
+               }
        }
 
        /**
@@ -830,7 +1086,7 @@ class t3lib_DB {
         *
         * @return      integer         The uid of the last inserted record.
         */
-       function sql_insert_id()        {
+       function sql_insert_id() {
                return mysql_insert_id($this->link);
        }
 
@@ -841,7 +1097,7 @@ class t3lib_DB {
         *
         * @return      integer         Number of rows affected by last query
         */
-       function sql_affected_rows()    {
+       function sql_affected_rows() {
                return mysql_affected_rows($this->link);
        }
 
@@ -854,9 +1110,12 @@ class t3lib_DB {
         * @param       integer         Seek result number.
         * @return      boolean         Returns TRUE on success or FALSE on failure.
         */
-       function sql_data_seek($res,$seek)      {
-               $this->debug_check_recordset($res);
-               return mysql_data_seek($res,$seek);
+       function sql_data_seek($res, $seek) {
+               if ($this->debug_check_recordset($res)) {
+                       return mysql_data_seek($res, $seek);
+               } else {
+                       return FALSE;
+               }
        }
 
        /**
@@ -868,9 +1127,12 @@ class t3lib_DB {
         * @param       integer         Field index.
         * @return      string          Returns the name of the specified field index
         */
-       function sql_field_type($res,$pointer)  {
-               $this->debug_check_recordset($res);
-               return mysql_field_type($res,$pointer);
+       function sql_field_type($res, $pointer) {
+               if ($this->debug_check_recordset($res)) {
+                       return mysql_field_type($res, $pointer);
+               } else {
+                       return FALSE;
+               }
        }
 
        /**
@@ -886,24 +1148,54 @@ class t3lib_DB {
        function sql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password)   {
                        // mysql_error() is tied to an established connection
                        // if the connection fails we need a different method to get the error message
-               ini_set('track_errors', 1);
-               ini_set('html_errors', 0);
-               if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect'])  {
-                       $this->link = @mysql_connect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password);
+               @ini_set('track_errors', 1);
+               @ini_set('html_errors', 0);
+
+                       // check if MySQL extension is loaded
+               if (!extension_loaded('mysql')) {
+                       $message = 'Database Error: It seems that MySQL support for PHP is not installed!';
+                       throw new RuntimeException($message, 1271492606);
+               }
+
+                       // Check for client compression
+               $isLocalhost = ($TYPO3_db_host == 'localhost' || $TYPO3_db_host == '127.0.0.1');
+               if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']) {
+                       if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['dbClientCompress'] && !$isLocalhost) {
+                                       // We use PHP's default value for 4th parameter (new_link), which is false.
+                                       // See PHP sources, for example: file php-5.2.5/ext/mysql/php_mysql.c,
+                                       // function php_mysql_do_connect(), near line 525
+                               $this->link = @mysql_connect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password, false, MYSQL_CLIENT_COMPRESS);
+                       } else {
+                               $this->link = @mysql_connect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password);
+                       }
                } else {
-                       $this->link = @mysql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password);
+                       if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['dbClientCompress'] && !$isLocalhost) {
+                                       // See comment about 4th parameter in block above
+                               $this->link = @mysql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password, MYSQL_CLIENT_COMPRESS);
+                       } else {
+                               $this->link = @mysql_pconnect($TYPO3_db_host, $TYPO3_db_username, $TYPO3_db_password);
+                       }
                }
+
                $error_msg = $php_errormsg;
-               ini_restore('track_errors');
-               ini_restore('html_errors');
+               @ini_restore('track_errors');
+               @ini_restore('html_errors');
 
                if (!$this->link) {
-                       t3lib_div::sysLog('Could not connect to Mysql server '.$TYPO3_db_host.' with user '.$TYPO3_db_username.': '.$error_msg,'Core',4);
+                       t3lib_div::sysLog('Could not connect to MySQL server ' . $TYPO3_db_host .
+                               ' with user ' . $TYPO3_db_username . ': ' . $error_msg,
+                               'Core',
+                               4
+                       );
                } else {
-                       $setDBinit = t3lib_div::trimExplode(chr(10), $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit'],TRUE);
-                       foreach ($setDBinit as $v)      {
-                               if (mysql_query($v, $this->link) === FALSE)     {
-                                       t3lib_div::sysLog('Could not initialize DB connection with query "'.$v.'": '.mysql_error($this->link),'Core',3);
+                       $setDBinit = t3lib_div::trimExplode(LF, str_replace("' . LF . '", LF, $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit']), TRUE);
+                       foreach ($setDBinit as $v) {
+                               if (mysql_query($v, $this->link) === FALSE) {
+                                       t3lib_div::sysLog('Could not initialize DB connection with query "' . $v .
+                                               '": ' . mysql_error($this->link),
+                                               'Core',
+                                               3
+                                       );
                                }
                        }
                }
@@ -919,11 +1211,15 @@ class t3lib_DB {
         * @param       string          Database to connect to.
         * @return      boolean         Returns TRUE on success or FALSE on failure.
         */
-       function sql_select_db($TYPO3_db)       {
+       function sql_select_db($TYPO3_db) {
                $ret = @mysql_select_db($TYPO3_db, $this->link);
                if (!$ret) {
-                       t3lib_div::sysLog('Could not select Mysql database '.$TYPO3_db.': '.mysql_error(),'Core',4);
-       }
+                       t3lib_div::sysLog('Could not select MySQL database ' . $TYPO3_db . ': ' .
+                               mysql_error(),
+                               'Core',
+                               4
+                       );
+               }
                return $ret;
        }
 
@@ -945,17 +1241,18 @@ class t3lib_DB {
 
        /**
         * Listing databases from current MySQL connection. NOTICE: It WILL try to select those databases and thus break selection of current database.
-        * This is only used as a service function in the (1-2-3 process) of the Install Tool. In any case a lookup should be done in the _DEFAULT handler DBMS then.
+        * This is only used as a service function in the (1-2-3 process) of the Install Tool.
+        * In any case a lookup should be done in the _DEFAULT handler DBMS then.
         * Use in Install Tool only!
         * Usage count/core: 1
         *
         * @return      array           Each entry represents a database name
         */
-       function admin_get_dbs()        {
+       function admin_get_dbs() {
                $dbArr = array();
                $db_list = mysql_list_dbs($this->link);
                while ($row = mysql_fetch_object($db_list)) {
-                       if ($this->sql_select_db($row->Database))       {
+                       if ($this->sql_select_db($row->Database)) {
                                $dbArr[] = $row->Database;
                        }
                }
@@ -964,38 +1261,48 @@ class t3lib_DB {
 
        /**
         * Returns the list of tables from the default database, TYPO3_db (quering the DBMS)
-        * In a DBAL this method should 1) look up all tables from the DBMS  of the _DEFAULT handler and then 2) add all tables *configured* to be managed by other handlers
+        * In a DBAL this method should 1) look up all tables from the DBMS  of
+        * the _DEFAULT handler and then 2) add all tables *configured* to be managed by other handlers
         * Usage count/core: 2
         *
-        * @return      array           Tables in an array (tablename is in both key and value)
+        * @return      array           Array with tablenames as key and arrays with status information as value
         */
-       function admin_get_tables()     {
+       function admin_get_tables() {
                $whichTables = array();
-               $tables_result = mysql_list_tables(TYPO3_db, $this->link);
-               if (!mysql_error())     {
+
+               $tables_result = mysql_query('SHOW TABLE STATUS FROM `' . TYPO3_db . '`', $this->link);
+               if (!mysql_error()) {
                        while ($theTable = mysql_fetch_assoc($tables_result)) {
-                               $whichTables[current($theTable)] = current($theTable);
+                               $whichTables[$theTable['Name']] = $theTable;
                        }
+
+                       $this->sql_free_result($tables_result);
                }
+
                return $whichTables;
        }
 
        /**
         * Returns information about each field in the $table (quering the DBMS)
         * In a DBAL this should look up the right handler for the table and return compatible information
-        * This function is important not only for the Install Tool but probably for DBALs as well since they might need to look up table specific information in order to construct correct queries. In such cases this information should probably be cached for quick delivery.
+        * This function is important not only for the Install Tool but probably for
+        * DBALs as well since they might need to look up table specific information
+        * in order to construct correct queries. In such cases this information should
+        * probably be cached for quick delivery.
         *
         * @param       string          Table name
         * @return      array           Field information in an associative array with fieldname => field row
         */
-       function admin_get_fields($tableName)   {
+       function admin_get_fields($tableName) {
                $output = array();
 
-               $columns_res = mysql_query('SHOW columns FROM `'.$tableName.'`', $this->link);
-               while($fieldRow = mysql_fetch_assoc($columns_res))      {
+               $columns_res = mysql_query('SHOW COLUMNS FROM `' . $tableName . '`', $this->link);
+               while ($fieldRow = mysql_fetch_assoc($columns_res)) {
                        $output[$fieldRow['Field']] = $fieldRow;
                }
 
+               $this->sql_free_result($columns_res);
+
                return $output;
        }
 
@@ -1006,14 +1313,43 @@ class t3lib_DB {
         * @param       string          Table name
         * @return      array           Key information in a numeric array
         */
-       function admin_get_keys($tableName)     {
+       function admin_get_keys($tableName) {
                $output = array();
 
-               $keyRes = mysql_query('SHOW keys FROM `'.$tableName.'`', $this->link);
-               while($keyRow = mysql_fetch_assoc($keyRes))     {
+               $keyRes = mysql_query('SHOW KEYS FROM `' . $tableName . '`', $this->link);
+               while ($keyRow = mysql_fetch_assoc($keyRes)) {
                        $output[] = $keyRow;
                }
 
+               $this->sql_free_result($keyRes);
+
+               return $output;
+       }
+
+       /**
+        * Returns information about the character sets supported by the current DBM
+        * This function is important not only for the Install Tool but probably for
+        * DBALs as well since they might need to look up table specific information
+        * in order to construct correct queries. In such cases this information should
+        * probably be cached for quick delivery.
+        *
+        * This is used by the Install Tool to convert tables tables with non-UTF8 charsets
+        * Use in Install Tool only!
+        *
+        * @return      array           Array with Charset as key and an array of "Charset", "Description", "Default collation", "Maxlen" as values
+        */
+       function admin_get_charsets() {
+               $output = array();
+
+               $columns_res = mysql_query('SHOW CHARACTER SET', $this->link);
+               if ($columns_res) {
+                       while (($row = mysql_fetch_assoc($columns_res))) {
+                               $output[$row['Charset']] = $row;
+                       }
+
+                       $this->sql_free_result($columns_res);
+               }
+
                return $output;
        }
 
@@ -1024,9 +1360,11 @@ class t3lib_DB {
         * @param       string          Query to execute
         * @return      pointer         Result pointer
         */
-       function admin_query($query)    {
+       function admin_query($query) {
                $res = mysql_query($query, $this->link);
-               if ($this->debugOutput) $this->debug('admin_query',$query);
+               if ($this->debugOutput) {
+                       $this->debug('admin_query', $query);
+               }
                return $res;
        }
 
@@ -1050,31 +1388,41 @@ class t3lib_DB {
        /**
         * Connects to database for TYPO3 sites:
         *
+        * @param string $host
+        * @param string $user
+        * @param string $password
+        * @param string $db
         * @return      void
         */
-       function connectDB()    {
-               if ($this->sql_pconnect(TYPO3_db_host, TYPO3_db_username, TYPO3_db_password))   {
-                       if (!TYPO3_db)  {
-                               die('No database selected');
-                               exit;
-                       } elseif (!$this->sql_select_db(TYPO3_db))      {
-                               die('Cannot connect to the current database, "'.TYPO3_db.'"');
-                               exit;
+       function connectDB($host = TYPO3_db_host, $user = TYPO3_db_username, $password = TYPO3_db_password, $db = TYPO3_db) {
+               if ($this->sql_pconnect($host, $user, $password)) {
+                       if (!$db) {
+                               throw new RuntimeException(
+                                       'TYPO3 Fatal Error: No database selected!',
+                                       1270853882
+                               );
+                       } elseif (!$this->sql_select_db($db)) {
+                               throw new RuntimeException(
+                                       'TYPO3 Fatal Error: Cannot connect to the current database, "' . $db . '"!',
+                                       1270853883
+                               );
                        }
                } else {
-                       die('The current username, password or host was not accepted when the connection to the database was attempted to be established!');
-                       exit;
+                       throw new RuntimeException(
+                               'TYPO3 Fatal Error: The current username, password or host was not accepted when the connection to the database was attempted to be established!',
+                               1270853884
+                       );
                }
        }
 
-
-
-
-
-
-
-
-
+       /**
+        * Checks if database is connected
+        *
+        * @return boolean
+        */
+       public function isConnected() {
+               return is_resource($this->link);
+       }
 
 
 
@@ -1091,22 +1439,26 @@ class t3lib_DB {
         * @param       string          Last query if not last built query
         * @return      void
         */
-       function debug($func, $query='')        {
+       function debug($func, $query='') {
 
                $error = $this->sql_error();
-               if ($error)     {
-                       echo t3lib_div::view_array(array(
-                               'caller' => 't3lib_DB::'.$func,
-                               'ERROR' => $error,
-                               'lastBuiltQuery' => ($query ? $query : $this->debug_lastBuiltQuery),
-                               'debug_backtrace' => t3lib_div::debug_trail()
-                       ));
+               if ($error || $this->debugOutput == 2) {
+                       debug(
+                               array(
+                                       'caller' => 't3lib_DB::' . $func,
+                                       'ERROR' => $error,
+                                       'lastBuiltQuery' => ($query ? $query : $this->debug_lastBuiltQuery),
+                                       'debug_backtrace' => t3lib_utility_Debug::debugTrail(),
+                               ),
+                               $func,
+                               is_object($GLOBALS['error']) && @is_callable(array($GLOBALS['error'], 'debug')) ? '' : 'DB Error'
+                       );
                }
        }
 
        /**
         * Checks if recordset is valid and writes debugging inormation into devLog if not.
-        * 
+        *
         * @param       resource        $res    Recordset
         * @return      boolean <code>false</code> if recordset is not valid
         */
@@ -1114,26 +1466,134 @@ class t3lib_DB {
                if (!$res) {
                        $trace = FALSE;
                        $msg = 'Invalid database result resource detected';
-                       $trace = debug_backtrace();
+                       $trace = debug_backtrace();
                        array_shift($trace);
                        $cnt = count($trace);
-                       for ($i=0; $i<$cnt; $i++)       {
+                       for ($i = 0; $i < $cnt; $i++) {
                                        // complete objects are too large for the log
-                               if (isset($trace['object']))    unset($trace['object']);
+                               if (isset($trace['object'])) {
+                                       unset($trace['object']);
+                               }
                        }
-                       $msg .= ': function t3lib_DB->' . $trace[0]['function'] . ' called from file ' . substr($trace[0]['file'],strlen(PATH_site)+2) . ' in line ' . $trace[0]['line'];
+                       $msg .= ': function t3lib_DB->' . $trace[0]['function'] . ' called from file ' .
+                               substr($trace[0]['file'], strlen(PATH_site) + 2) . ' in line ' .
+                               $trace[0]['line'];
                        t3lib_div::sysLog($msg.'. Use a devLog extension to get more details.', 'Core/t3lib_db', 3);
-                       t3lib_div::devLog($msg.'.', 'Core/t3lib_db', 3, $trace);
+                               // Send to devLog if enabled
+                       if (TYPO3_DLOG) {
+                               $debugLogData = array(
+                                       'SQL Error' => $this->sql_error(),
+                                       'Backtrace' => $trace,
+                               );
+                               if ($this->debug_lastBuiltQuery) {
+                                       $debugLogData = array('SQL Query' => $this->debug_lastBuiltQuery) + $debugLogData;
+                               }
+                               t3lib_div::devLog($msg . '.', 'Core/t3lib_db', 3, $debugLogData);
+                       }
 
                        return FALSE;
                }
                return TRUE;
        }
 
+       /**
+        * Explain select queries
+        * If $this->explainOutput is set, SELECT queries will be explained here. Only queries with more than one possible result row will be displayed.
+        * The output is either printed as raw HTML output or embedded into the TS admin panel (checkbox must be enabled!)
+        *
+        * TODO: Feature is not DBAL-compliant
+        *
+        * @param       string          SQL query
+        * @param       string          Table(s) from which to select. This is what comes right after "FROM ...". Required value.
+        * @param       integer         Number of resulting rows
+        * @return      boolean         True if explain was run, false otherwise
+        */
+       protected function explain($query, $from_table, $row_count) {
+
+               if ((int)$this->explainOutput == 1 || ((int)$this->explainOutput == 2 &&
+                       t3lib_div::cmpIP(t3lib_div::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']))
+                       ) {
+                               // raw HTML output
+                       $explainMode = 1;
+               } elseif ((int)$this->explainOutput == 3 && is_object($GLOBALS['TT'])) {
+                               // embed the output into the TS admin panel
+                       $explainMode = 2;
+               } else {
+                       return false;
+               }
+
+               $error = $this->sql_error();
+               $trail = t3lib_utility_Debug::debugTrail();
+
+               $explain_tables = array();
+               $explain_output = array();
+               $res = $this->sql_query('EXPLAIN ' . $query, $this->link);
+               if (is_resource($res)) {
+                       while ($tempRow = $this->sql_fetch_assoc($res)) {
+                               $explain_output[] = $tempRow;
+                               $explain_tables[] = $tempRow['table'];
+                       }
+                       $this->sql_free_result($res);
+               }
+
+               $indices_output = array();
+                       // Notice: Rows are skipped if there is only one result, or if no conditions are set
+               if ($explain_output[0]['rows'] > 1 || t3lib_div::inList('ALL', $explain_output[0]['type'])) {
+                               // only enable output if it's really useful
+                       $debug = true;
+
+                       foreach ($explain_tables as $table) {
+                               $tableRes = $this->sql_query('SHOW TABLE STATUS LIKE \'' . $table . '\'');
+                               $isTable = $this->sql_num_rows($tableRes);
+                               if ($isTable) {
+                                       $res = $this->sql_query('SHOW INDEX FROM ' . $table, $this->link);
+                                       if (is_resource($res)) {
+                                               while ($tempRow = $this->sql_fetch_assoc($res)) {
+                                                       $indices_output[] = $tempRow;
+                                               }
+                                               $this->sql_free_result($res);
+                                       }
+                               }
+                               $this->sql_free_result($tableRes);
+                       }
+               } else {
+                       $debug = false;
+               }
+
+               if ($debug) {
+                       if ($explainMode) {
+                               $data = array();
+                               $data['query'] = $query;
+                               $data['trail'] = $trail;
+                               $data['row_count'] = $row_count;
+
+                               if ($error) {
+                                       $data['error'] = $error;
+                               }
+                               if (count($explain_output)) {
+                                       $data['explain'] = $explain_output;
+                               }
+                               if (count($indices_output)) {
+                                       $data['indices'] = $indices_output;
+                               }
+
+                               if ($explainMode == 1) {
+                                       t3lib_utility_Debug::debug($data, 'Tables: ' . $from_table, 'DB SQL EXPLAIN');
+                               } elseif ($explainMode == 2) {
+                                       $GLOBALS['TT']->setTSselectQuery($data);
+                               }
+                       }
+                       return true;
+               }
+
+               return false;
+       }
+
 }
 
 
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_db.php'])       {
        include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_db.php']);
 }
-?>
+
+?>
\ No newline at end of file