Index: class.ux_t3lib_db.php
===================================================================
--- class.ux_t3lib_db.php	(revision 25171)
+++ class.ux_t3lib_db.php	(working copy)
@@ -969,12 +969,14 @@
 				$from_table[$k]['as'] = $this->quoteName($from_table[$k]['as']);
 			}
 			if (is_array($v['JOIN']))	{
-				$from_table[$k]['JOIN']['withTable'] = $this->quoteName($from_table[$k]['JOIN']['withTable']);
-				$from_table[$k]['JOIN']['as'] = ($from_table[$k]['JOIN']['as']) ? $this->quoteName($from_table[$k]['JOIN']['as']) : '';
-				$from_table[$k]['JOIN']['ON'][0]['table'] = ($from_table[$k]['JOIN']['ON'][0]['table']) ? $this->quoteName($from_table[$k]['JOIN']['ON'][0]['table']) : '';
-				$from_table[$k]['JOIN']['ON'][0]['field'] = $this->quoteName($from_table[$k]['JOIN']['ON'][0]['field']);
-				$from_table[$k]['JOIN']['ON'][1]['table'] = ($from_table[$k]['JOIN']['ON'][1]['table']) ? $this->quoteName($from_table[$k]['JOIN']['ON'][1]['table']) : '';
-				$from_table[$k]['JOIN']['ON'][1]['field'] = $this->quoteName($from_table[$k]['JOIN']['ON'][1]['field']);
+				foreach($v['JOIN'] as $key => $join) {
+					$from_table[$k]['JOIN'][$key]['withTable'] = $this->quoteName($join['withTable']);
+					$from_table[$k]['JOIN'][$key]['as'] = ($join['as']) ? $this->quoteName($join['as']) : '';
+					$from_table[$k]['JOIN'][$key]['ON'][0]['table'] = ($join['ON'][0]['table']) ? $this->quoteName($join['ON'][0]['table']) : '';
+					$from_table[$k]['JOIN'][$key]['ON'][0]['field'] = $this->quoteName($join['ON'][0]['field']);
+					$from_table[$k]['JOIN'][$key]['ON'][1]['table'] = ($join['ON'][1]['table']) ? $this->quoteName($join['ON'][1]['table']) : '';
+					$from_table[$k]['JOIN'][$key]['ON'][1]['field'] = $this->quoteName($join['ON'][1]['field']);
+				}
 			}
 		}
 		return $this->SQLparser->compileFromTables($from_table);
@@ -2286,6 +2288,16 @@
 					} else {
 						if (is_array($this->mapping[$tableCfg['table']]))	{
 							$this->cache_mappingFromTableList[$key] = $tables;
+						} elseif(is_array($tableCfg['JOIN'])) {
+							$mapping = false;
+							foreach($tableCfg['JOIN'] as $join) {
+								if(is_array($this->mapping[$join['withTable']])) {
+									$mapping = true;
+								}								
+							}
+							if($mapping) {
+								$this->cache_mappingFromTableList[$key] = $tables;
+							}
 						}
 					}
 				}
@@ -2360,13 +2372,36 @@
 			// Tables:
 		$tables = $this->SQLparser->parseFromTables($from_table);
 		$defaultTable = $tables[0]['table'];
-		foreach($tables as $k => $v)	{
-			if ($this->mapping[$v['table']]['mapTableName'])	{
+		foreach($tables as $k => $v) {
+				// Mapping JOINS
+			if(is_array($v['JOIN'])) {	
+				foreach($v['JOIN'] as $key => $join){			
+					// Mapping withTable of the join
+				if ($this->mapping[$join['withTable']]['mapTableName']) {
+					$tables[$k]['JOIN'][$key]['withTable'] = $this->mapping[$join['withTable']]['mapTableName'];					
+				}
+				$onPartsArray = array();
+					//Mapping ON parts of the JOIN
+				if(is_array($join['ON'])) {
+					foreach($join['ON'] as $onParts) {
+						if(isset($this->mapping[$onParts['table']]['mapFieldNames'][$onParts['field']])) {
+							$onParts['field'] = $this->mapping[$onParts['table']]['mapFieldNames'][$onParts['field']];
+						}
+						
+						if (isset($this->mapping[$onParts['table']]['mapTableName'])) {
+							$onParts['table'] = $this->mapping[$onParts['table']]['mapTableName'];
+						}
+						$onPartsArray[]	=$onParts;					
+					}
+					$tables[$k]['JOIN'][$key]['ON'] = $onPartsArray;
+				}
+				}				
+			}
+			if ($this->mapping[$v['table']]['mapTableName']) {
 				$tables[$k]['table'] = $this->mapping[$v['table']]['mapTableName'];
 			}
 		}
 		$from_table = $this->SQLparser->compileFromTables($tables);
-
 			// Where clause:
 		$whereParts = $this->SQLparser->parseWhereClause($where_clause);
 		$this->map_sqlParts($whereParts,$defaultTable);

Index: class.ux_t3lib_sqlparser.php
===================================================================
--- class.ux_t3lib_sqlparser.php	(revision 24017)
+++ class.ux_t3lib_sqlparser.php	(working copy)
@@ -390,6 +390,145 @@
 
 		return $output;
 	}
+	
+	
+	/**
+	 * Compiles a "FROM [output] WHERE..:" table list based on input array (made with ->parseFromTables())
+	 *
+	 * @param	array		Array of table names, (made with ->parseFromTables())
+	 * @return	string		Table name string
+	 * @see parseFromTables()
+	 */
+	function compileFromTables($tablesArray)	{
+
+			// Prepare buffer variable:
+		$outputParts = array();
+
+			// Traverse the table names:
+		if (is_array($tablesArray))	{
+			foreach($tablesArray as $k => $v)	{
+
+					// Set table name:
+				$outputParts[$k] = $v['table'];
+
+					// Add alias AS if there:
+				if ($v['as'])	{
+					$outputParts[$k] .= ' ' . $v['as_keyword'] . ' ' . $v['as'];
+				}
+
+				if (is_array($v['JOIN']))	{
+					foreach($v['JOIN'] as $join) {
+					$outputParts[$k] .= ' ' . $join['type'] . ' ' . $join['withTable'] . ' ON ';
+					$outputParts[$k] .= ($join['ON'][0]['table']) ? $join['ON'][0]['table'] . '.' : '';
+					$outputParts[$k] .= $join['ON'][0]['field'];
+					$outputParts[$k] .= '=';
+					$outputParts[$k] .= ($join['ON'][1]['table']) ? $join['ON'][1]['table'] . '.' : '';
+					$outputParts[$k] .= $join['ON'][1]['field'];
+					}
+				}
+			}
+		}
+
+			// Return imploded buffer:
+		return implode(', ', $outputParts);
+	}
+	
+	
+	/**
+	 * Parsing the tablenames in the "FROM [$parseString] WHERE" part of a query into an array.
+	 * The success of this parsing determines if that part of the query is supported by TYPO3.
+	 *
+	 * @param	string		list of tables, eg. "pages, tt_content" or "pages A, pages B". NOTICE: passed by reference!
+	 * @param	string		Regular expressing to STOP parsing, eg. '^(WHERE)([[:space:]]*)'
+	 * @return	array		If successful parsing, returns an array, otherwise an error string.
+	 * @see compileFromTables()
+	 */
+	function parseFromTables(&$parseString, $stopRegex='')	{
+
+			// Prepare variables:
+		$parseString = $this->trimSQL($parseString);
+		$this->lastStopKeyWord = '';
+		$this->parse_error = '';
+
+		$stack = array();	// Contains the parsed content
+		$pnt = 0;			// Pointer to positions in $stack
+		$loopExit = 0;		// Recursivity brake.
+
+			// $parseString is continously shortend by the process and we keep parsing it till it is zero:
+		while (strlen($parseString)) {
+				// Looking for the table:
+			if ($stack[$pnt]['table'] = $this->nextPart($parseString, '^([[:alnum:]_]+)(,|[[:space:]]+)'))	{
+					// Looking for stop-keywords before fetching potential table alias:
+				if ($stopRegex && ($this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex)))	{
+					$this->lastStopKeyWord = strtoupper(str_replace(array(' ', "\t", "\r", "\n"), '', $this->lastStopKeyWord));
+					return $stack;
+				}
+				if(!preg_match('/^(LEFT|JOIN)[[:space:]]+/i', $parseString)) {
+					$stack[$pnt]['as_keyword'] = $this->nextPart($parseString, '^(AS[[:space:]]+)');
+					$stack[$pnt]['as'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]*');
+				}
+			} else return $this->parseError('No table name found as expected in parseFromTables()!', $parseString);
+			$joinCpt = 0;
+				// Looking for JOIN
+			while ($join = $this->nextPart($parseString, '^(LEFT[[:space:]]+JOIN|INNER[[:space:]]+JOIN|LEFT[[:space:]]+OUTER[[:space:]]+JOIN|JOIN)[[:space:]]+'))	{
+				$stack[$pnt]['JOIN'][$joinCpt]['type'] = $join;
+				if ($stack[$pnt]['JOIN'][$joinCpt]['withTable'] = $this->nextPart($parseString, '^([[:alnum:]_]+)[[:space:]]+ON[[:space:]]+', 1))	{
+					$field1 = $this->nextPart($parseString, '^([[:alnum:]_.]+)[[:space:]]*=[[:space:]]*', 1);
+					$field2 = $this->nextPart($parseString, '^([[:alnum:]_.]+)[[:space:]]+');
+					if ($field1 && $field2)	{
+
+						// Explode fields into field and table:
+						$tableField = explode('.', $field1, 2);
+						$field1 = array();
+						if (count($tableField) != 2)	{
+							$field1['table'] = '';
+							$field1['field'] = $tableField[0];
+						} else {
+							$field1['table'] = $tableField[0];
+							$field1['field'] = $tableField[1];
+						}
+						$tableField = explode('.', $field2, 2);
+						$field2 = array();
+						if (count($tableField) != 2)	{
+							$field2['table'] = '';
+							$field2['field'] = $tableField[0];
+						} else {
+							$field2['table'] = $tableField[0];
+							$field2['field'] = $tableField[1];
+						}
+						$stack[$pnt]['JOIN'][$joinCpt]['ON'] = array($field1, $field2);
+						$joinCpt++;			
+					} else return $this->parseError('No join fields found in parseFromTables()!', $parseString);
+				} else  return $this->parseError('No join table found in parseFromTables()!', $parseString);
+			}
+
+				// Looking for stop-keywords:
+			if ($stopRegex && $this->lastStopKeyWord = $this->nextPart($parseString, $stopRegex))	{
+				$this->lastStopKeyWord = strtoupper(str_replace(array(' ',"\t","\r","\n"), '', $this->lastStopKeyWord));
+				return $stack;
+			}
+
+				// Looking for comma:
+			if (strlen($parseString) && !$this->nextPart($parseString, '^(,)'))	{
+				//return $this->parseError('No comma found as expected in parseFromTables()',$parseString);
+			}
+
+				// Increasing pointer:
+			$pnt++;
+
+				// Check recursivity brake:
+			$loopExit++;
+			if ($loopExit > 500)	{
+				return $this->parseError('More than 500 loops, exiting prematurely in parseFromTables()...', $parseString);
+			}
+		}
+
+			// Return result array:
+		return $stack;
+	}
+	
+	
+	
 }
 
