diff -rupN SemanticMediaWiki-30900/includes/SMW_QueryProcessor.php SemanticMediaWiki-30900-multsort/includes/SMW_QueryProcessor.php
--- SemanticMediaWiki-30900/includes/SMW_QueryProcessor.php	2008-02-13 10:38:35.000000000 +0300
+++ SemanticMediaWiki-30900-multsort/includes/SMW_QueryProcessor.php	2008-02-11 15:13:28.000000000 +0300
@@ -92,14 +92,24 @@ class SMWQueryProcessor {
 				$query->setLimit($smwgQDefaultLimit);
 			}
 		}
-		if (array_key_exists('sort', $params)) {
+		// next one works, sortkeys and ascendings are properly filled with data:
+		if ( array_key_exists('sort', $params) ) {
 			$query->sort = true;
-			$query->sortkey = smwfNormalTitleDBKey($params['sort']);
+			$query->sortkeys = Array();
+			foreach ( explode( ',', trim($params['sort']) ) as $sort ) {
+				$query->sortkeys[] = smwfNormalTitleDBKey( trim($sort) );
+			}
 		}
-		if (array_key_exists('order', $params)) {
-			$order = strtolower(trim($params['order']));
-			if (('descending'==$order)||('reverse'==$order)||('desc'==$order)) {
-				$query->ascending = false;
+		if ( array_key_exists('order', $params) ) {
+			$query->ascendings = Array();
+			foreach ( explode( ',', trim($params['order']) ) as $order ) {
+				$order = strtolower(trim($order));
+				$query->ascendings[] = ('descending'!=$order) && ('reverse'!=$order) && ('desc'!=$order);
+			}
+			// make sure all the ascendings filled with values, even if these aren't actually presented in query
+			foreach ( $query->sortkeys as $key => $val ) {
+				if ( !array_key_exists( $key, $query->ascendings ) )
+					$query->ascendings[$key] = true;
 			}
 		}
 		return $query;
diff -rupN SemanticMediaWiki-30900/includes/storage/SMW_Query.php SemanticMediaWiki-30900-multsort/includes/storage/SMW_Query.php
--- SemanticMediaWiki-30900/includes/storage/SMW_Query.php	2008-02-13 10:38:35.000000000 +0300
+++ SemanticMediaWiki-30900-multsort/includes/storage/SMW_Query.php	2008-02-11 14:28:10.000000000 +0300
@@ -26,8 +26,8 @@ class SMWQuery {
 	const MODE_NONE = 4;  // do nothing with the query
 
 	public $sort = false;
-	public $ascending = true;
-	public $sortkey = false;
+	public $ascendings = Array(true);
+	public $sortkeys = false;
 	public $querymode = SMWQuery::MODE_INSTANCES;
 
 	protected $m_limit;
diff -rupN SemanticMediaWiki-30900/includes/storage/SMW_QueryResult.php SemanticMediaWiki-30900-multsort/includes/storage/SMW_QueryResult.php
--- SemanticMediaWiki-30900/includes/storage/SMW_QueryResult.php	2008-02-13 10:38:35.000000000 +0300
+++ SemanticMediaWiki-30900-multsort/includes/storage/SMW_QueryResult.php	2008-02-13 10:45:46.000000000 +0300
@@ -137,13 +137,27 @@ class SMWQueryResult {
 		/// TODO implement (requires some way of generating/maintaining this URL as part of the query, and setting it when creating this result)
 		$title = Title::makeTitle(NS_SPECIAL, 'ask');
 		$params = 'query=' . urlencode($this->m_querystring);
-		if ($this->m_query->sortkey != false) {
-			$params .= '&sort=' . urlencode($this->m_query->sortkey);
-			if ($this->m_query->ascending) {
-				$params .= '&order=ASC';
-			} else {
-				$params .= '&order=DESC';
-			}
+		if ( is_array( $this->m_query->sortkeys ) ) {
+			$params .= '&sort=';
+			$first_elem = true;
+			foreach ( $this->m_query->sortkeys as $val ) {
+				if ( $first_elem )
+					$first_elem = false;
+				else
+					$params .= ',';
+  			$params .= urlencode($val);
+				if ( is_array( $this->m_query->ascendings ) ) {
+					$params .= '&order=';
+					$first_elem = true;
+					foreach ( $this->m_query->ascendings as $val ) {
+						if ( $first_elem )
+							$first_elem = false;
+						else
+							$params .= ',';
+						$params .= $val ? 'ASC' : 'DESC';
+				  }
+				}
+		  }
 		}
 		return $title->getFullURL($params);
 	}
@@ -164,16 +178,32 @@ class SMWQueryResult {
 		foreach ($this->m_extraprintouts as $printout) {
 			$params[] = $printout->getSerialisation();
 		}
-		if ($this->m_query->sortkey != false) {
-			$params[] = 'sort=' . $this->m_query->sortkey;
-			if ($this->m_query->ascending) {
-				$params[] = 'order=ASC';
-			} else {
-				$params[] = 'order=DESC';
+		if ( is_array( $this->m_query->sortkeys ) ) {
+			$first_elem = true;
+			$param = 'sort=';
+			foreach ( $this->m_query->sortkeys as $val ) {
+				if ( $first_elem )
+					$first_elem = false;
+				else
+					$param .= ',';
+  			$param .= $val;
+		  }
+			$params[] = $param;
+			if ( is_array( $this->m_query->ascendings ) ) {
+				$first_elem = true;
+				$param = 'order=';
+				foreach ( $this->m_query->ascendings as $val ) {
+					if ( $first_elem )
+						$first_elem = false;
+					else
+						$param .= ',';
+					$param .= $val ? 'ASC' : 'DESC';
+				}
+				$params[] = $param;
 			}
 		}
 		foreach ($params as $p) {
-			$p = str_replace(array('/','=','-','%'),array('-2F','-3D','-2D','-'), rawurlencode($p));
+			$p = str_replace(array('/','=','-',',','%'),array('-2F','-3D','-2D','-2C','-'), rawurlencode($p));
 			if ($titlestring != '') $titlestring .= '/';
 			$titlestring .= $p;
 		}
diff -rupN SemanticMediaWiki-30900/includes/storage/SMW_SQLStore.php SemanticMediaWiki-30900-multsort/includes/storage/SMW_SQLStore.php
--- SemanticMediaWiki-30900/includes/storage/SMW_SQLStore.php	2008-02-13 10:38:35.000000000 +0300
+++ SemanticMediaWiki-30900-multsort/includes/storage/SMW_SQLStore.php	2008-02-13 11:04:07.000000000 +0300
@@ -16,18 +16,18 @@ require_once( "$smwgIP/includes/SMW_Data
 class SMWSQLStore extends SMWStore {
 
 	/**
-	 * The (normalised) name of the property by which results during query
+	 * The array of (normalised) names of the properties by which results during query
 	 * processing should be ordered, if any. False otherwise (default from
 	 * SMWQuery). Needed during query processing (where this key is searched
 	 * while building the query conditions).
 	 */
-	protected $m_sortkey;
+	protected $m_sortkeys;
 	/**
-	 * The database field name by which results during query processing should
+	 * The database field names by which results during query processing should
 	 * be ordered, if any. False if no $m_sortkey was specified or if the key
 	 * did not match any condition.
 	 */
-	protected $m_sortfield;
+	protected $m_sortfields;
 	/**
 	 * Global counter to prevent clashes between table aliases.
 	 */
@@ -782,8 +782,8 @@ class SMWSQLStore extends SMWStore {
 
 		// Build main query
 		$this->m_usedtables = array();
-		$this->m_sortkey = $query->sortkey;
-		$this->m_sortfield = false;
+		$this->m_sortkeys = $query->sortkeys;
+		$this->m_sortfields = false;
 
 		$pagetable = $db->tableName('page');
 		$from = $pagetable;
@@ -796,22 +796,41 @@ class SMWSQLStore extends SMWStore {
 		$sql_options['LIMIT'] = $query->getLimit() + 1;
 		$sql_options['OFFSET'] = $query->getOffset();
 		if ( $smwgQSortingSupport ) {
-			$order = $query->ascending ? 'ASC' : 'DESC';
-			if ( ($this->m_sortfield == false) && ($this->m_sortkey == false) ) {
+			$order = $query->ascendings[0] ? 'ASC' : 'DESC';
+			if ( ($this->m_sortfields === false) && ($this->m_sortkeys === false) ) {
 				$sql_options['ORDER BY'] = "$pagetable.page_title $order "; // default
 			} else {
-				if ($this->m_sortfield == false) { // also query for sort property
+				if ( is_array( $this->m_sortkeys ) ) { // also query for sort property
+					reset( $this->m_sortkeys );
+					$m_sortkey = current( $this->m_sortkeys );
 					$extrawhere = '';
-					$this->createSQLQuery(new SMWSomeProperty(Title::newFromText($this->m_sortkey, SMW_NS_PROPERTY), new SMWThingDescription()), $from, $extrawhere, $db, $curtables);
+					$this->createSQLQuery(new SMWSomeProperty(Title::newFromText($m_sortkey, SMW_NS_PROPERTY), new SMWThingDescription()), $from, $extrawhere, $db, $curtables);
 					if ($extrawhere != '') {
 						if ($where != '') {
 							$where = "($where) AND ";
 						}
 						$where .= "($extrawhere)";
 					}
-				}
-				if ($this->m_sortfield != false) { // should always be the case, but who knows ...
-					$sql_options['ORDER BY'] = $this->m_sortfield . " $order ";
+					for ( $m_sortkey=next($this->m_sortkeys); $m_sortkey !== false; $m_sortkey=next($this->m_sortkeys) ) {
+						$this->setSQLSortOption(new SMWSomeProperty(Title::newFromText($m_sortkey, SMW_NS_PROPERTY), new SMWThingDescription()), key($this->m_sortkeys), $from, $extrawhere, $db, $curtables );
+						if ($extrawhere != '') {
+							if ($where != '') {
+								$where = "($where) AND ";
+							}
+							$where .= "($extrawhere)";
+						}
+					}
+					if ($this->m_sortfields !== false) { // should always be the case, but who knows ...
+  					$first_order = true;
+					  foreach ( $this->m_sortfields as $m_key => $m_sortfield ) {
+							$order = $query->ascendings[$m_key] ? 'ASC' : 'DESC';
+							if ( $first_order )
+								$first_order=false;
+							else
+								$sql_options['ORDER BY'] .= ", ";
+  						$sql_options['ORDER BY'] .= $m_sortfield . " $order ";
+					  }
+					}
 				}
 			}
 		}
@@ -1773,7 +1792,7 @@ class SMWSQLStore extends SMWStore {
 					$tablename = 'RELS';
 					$pcolumn = 'relation_title';
 					$sub = true;
-					if ($this->m_sortkey == $description->getProperty()->getDBkey()) {
+					if ($this->m_sortkeys[0] == $description->getProperty()->getDBkey()) {
 						$sort = 'object_title';
 					}
 				break;
@@ -1791,7 +1810,7 @@ class SMWSQLStore extends SMWStore {
 					$tablename = 'ATTS';
 					$pcolumn = 'attribute_title';
 					$sub = true;
-					if ($this->m_sortkey == $description->getProperty()->getDBkey()) {
+					if ($this->m_sortkeys[0] == $description->getProperty()->getDBkey()) {
 						if (SMWDataValueFactory::newTypeIDValue($id)->isNumeric()) {
 							$sort = 'value_num';
 						} else {
@@ -1814,7 +1833,7 @@ class SMWSQLStore extends SMWStore {
 					$nexttables['p' . $tablename] = $table; // keep only current table for reference
 					$this->createSQLQuery($description->getDescription(), $from, $subwhere, $db, $nexttables, $nary_pos);
 					if ($sort) {
-						$this->m_sortfield = "$table.$sort";
+						$this->m_sortfields[0] = "$table.$sort";
 					}
 					if ( $subwhere != '') {
 						$where .= ' AND (' . $subwhere . ')';
@@ -1826,6 +1845,71 @@ class SMWSQLStore extends SMWStore {
 	}
 
 	/**
+	 * Add orering option to an SQL query for a given property.
+	 *
+   */
+	protected function setSQLSortOption( SMWSomeProperty $property, $sortidx, &$from, &$where, &$db, &$curtables, $nary_pos = ''  ) {
+		$id = SMWDataValueFactory::getPropertyObjectTypeID($property->getProperty());
+		$sort = false;
+		switch ($id) {
+			case '_wpg':
+				$tablename = 'RELS';
+				$pcolumn = 'relation_title';
+				$sub = true;
+				if ($this->m_sortkeys[$sortidx] == $property->getProperty()->getDBkey()) {
+					$sort = 'object_title';
+				}
+			break;
+			case '_txt':
+				$tablename = 'TEXT';
+				$pcolumn = 'attribute_title';
+				$sub = false; //no recursion: we do not support further conditions on text-type values
+			break;
+			case '__nry':
+				$tablename = 'NARY';
+				$pcolumn = 'attribute_title';
+				$sub = true;
+			break;
+			default:
+				$tablename = 'ATTS';
+				$pcolumn = 'attribute_title';
+				$sub = true;
+				if ($this->m_sortkeys[$sortidx] == $property->getProperty()->getDBkey()) {
+					if (SMWDataValueFactory::newTypeIDValue($id)->isNumeric()) {
+						$sort = 'value_num';
+					} else {
+						$sort = 'value_xsd';
+					}
+				}
+		}
+		$pt = $this->getPropertyTable($property->getProperty()->getDBkey(), $db);
+		// in case don't unset, it would be all the same property, makes no sence here
+		unset($curtables[$tablename]);
+		if ($table = $this->addJoin($tablename, $from, $db, $curtables, $nary_pos)) {
+			global $smwgQSubpropertyDepth;
+			if ($smwgQSubpropertyDepth > 0) {
+				$pt = $this->getPropertyTable($property->getProperty()->getDBkey(), $db);
+				$from = '`' . $pt . '`, ' . $from;
+				$where = "$pt.title=" . $table . '.' . $pcolumn;
+			} else {
+				$where .= $table . '.' . $pcolumn . '=' .
+									$db->addQuotes($property->getProperty()->getDBkey());
+			}
+			if ($sub) {
+				$nexttables = array();
+				$nexttables['p' . $tablename] = $table; // keep only current table for reference
+				if ($sort) {
+					$this->m_sortfields[$sortidx] = "$table.$sort";
+				}
+				if ( $subwhere != '') {
+					$where .= ' AND (' . $subwhere . ')';
+				}
+			}
+		}
+	}
+
+
+	/**
 	 * Make sure the table of the given name has the given fields, provided
 	 * as an array with entries fieldname => typeparams. typeparams should be
 	 * in a normalised form and order to match to existing values.
