diff -r 87d13544b4d5 nuxeo-core-storage-sql/nuxeo-core-storage-sql-test/src/test/java/org/nuxeo/ecm/core/storage/sql/TestSQLRepositoryQuery.java
--- a/nuxeo-core-storage-sql/nuxeo-core-storage-sql-test/src/test/java/org/nuxeo/ecm/core/storage/sql/TestSQLRepositoryQuery.java	Wed Aug 12 19:06:28 2009 +0200
+++ b/nuxeo-core-storage-sql/nuxeo-core-storage-sql-test/src/test/java/org/nuxeo/ecm/core/storage/sql/TestSQLRepositoryQuery.java	Mon Aug 17 13:24:37 2009 +0200
@@ -17,6 +17,7 @@
 
 package org.nuxeo.ecm.core.storage.sql;
 
+import org.nuxeo.ecm.core.api.DocumentModelList;
 import org.nuxeo.ecm.core.query.test.QueryTestCase;
 
 /**
@@ -52,4 +53,27 @@
         super.testFulltextBlob();
     }
 
+    public void testMultiSortQuery() throws Exception {
+        DocumentModelList dml;
+        createDocs();
+
+        dml = session.query("SELECT * FROM Document ORDER BY ecm:primaryType ASC, ecm:name ASC");
+        assertEquals("testfile1_Title", dml.get(0).getPropertyValue(
+        "dc:title")); // first File
+        assertEquals("testfolder1_Title", dml.get(3).getPropertyValue(
+        "dc:title")); // first Folder
+
+        dml = session.query("SELECT * FROM Document ORDER BY ecm:primaryType DESC, ecm:name ASC");
+        assertEquals("testfile3_Title", dml.get(0).getPropertyValue(
+        "dc:title")); // a Note
+        assertEquals("testfile1_Title", dml.get(4).getPropertyValue(
+        "dc:title")); // first File
+
+        dml = session.query("SELECT * FROM Document ORDER BY ecm:primaryType ASC, ecm:name DESC");
+        assertEquals("testfile4_Title", dml.get(0).getPropertyValue(
+        "dc:title"));
+        assertEquals("testfolder1_Title", dml.get(5).getPropertyValue(
+        "dc:title"));
+    }
+
 }
diff -r 87d13544b4d5 nuxeo-core-storage-sql/nuxeo-core-storage-sql/src/main/java/org/nuxeo/ecm/core/storage/sql/NXQLQueryMaker.java
--- a/nuxeo-core-storage-sql/nuxeo-core-storage-sql/src/main/java/org/nuxeo/ecm/core/storage/sql/NXQLQueryMaker.java	Wed Aug 12 19:06:28 2009 +0200
+++ b/nuxeo-core-storage-sql/nuxeo-core-storage-sql/src/main/java/org/nuxeo/ecm/core/storage/sql/NXQLQueryMaker.java	Mon Aug 17 13:24:37 2009 +0200
@@ -309,8 +309,7 @@
         if (considerProxies) {
             // complex case where we have to add a left joins to link to the
             // proxies table and another join to select both proxies targets and
-            // direct documents
-            // hier
+            // direct documents hier
             String alias = dialect.storesUpperCaseIdentifiers() ? "_NXHIER"
                     : "_nxhier";
             hierTable = new TableAlias(hier, alias);
@@ -448,26 +447,6 @@
         }
 
         /*
-         * Security check.
-         */
-
-        if (queryFilter.getPrincipals() != null) {
-            whereClauses.add(dialect.getSecurityCheckSql(hierId));
-            Serializable principals;
-            Serializable permissions;
-            if (dialect.supportsArrays()) {
-                principals = queryFilter.getPrincipals();
-                permissions = queryFilter.getPermissions();
-            } else {
-                principals = StringUtils.join(queryFilter.getPrincipals(), '|');
-                permissions = StringUtils.join(queryFilter.getPermissions(),
-                        '|');
-            }
-            q.selectParams.add(principals);
-            q.selectParams.add(permissions);
-        }
-
-        /*
          * Order by.
          */
 
@@ -489,30 +468,92 @@
             // For proxies we do a LEFT JOIN with a non equi-join
             // condition that can return two rows.
             what = "DISTINCT " + what;
-            // Some dialects need any ORDER BY expressions to appear in the
-            // SELECT list when using DISTINCT.
-            if (dialect.needsOrderByKeysAfterDistinct()) {
-                for (String key : info.orderKeys) {
-                    Column column = findColumn(key, false, true);
-                    String qname = column.getFullQuotedName();
-                    what += ", " + qname;
-                }
-            }
         }
         // else no DISTINCT needed as all impacted tables have unique keys
 
+
         /*
-         * Create the whole select.
+         * Create the sub-select.
          */
         Select select = new Select(null);
         select.setWhat(what);
         select.setFrom(StringUtils.join(joins, " LEFT JOIN "));
         select.setWhere(StringUtils.join(whereClauses, " AND "));
-        select.setOrderBy(orderBy);
 
         List<Column> whatColumns = Collections.singletonList(hierTable.getColumn(model.MAIN_KEY));
-        q.selectInfo = new SQLInfoSelect(select.getStatement(), whatColumns,
-                null, null);
+
+        // MANAGE MAIN QUERY INCLUDING SUBQUERY "select"
+        Select mainSelect = new Select(null);
+        List<String> mainJoins = new ArrayList<String>();
+        List<String> mainWhereClauses = new ArrayList<String>();
+        String mainWhat = what;
+
+        /*
+         * Create the FROM for the main select.
+         */
+
+        boolean useAlias = false;
+        if (considerProxies) {
+            useAlias = true;
+            String alias = dialect.storesUpperCaseIdentifiers() ? "_NXHIER"
+                    : "_nxhier";
+            hierTable = new TableAlias(hier, alias);
+            mainJoins.add(hier.getQuotedName() + " " + hierTable.getQuotedName()); // TODO dialect
+        } else {
+            // simple case where we directly refer to the hierarchy table
+            mainJoins.add(hierTable.getQuotedName());
+        }
+
+
+        /*
+         * Security check.
+         */
+        mainWhereClauses.add(hierId + " IN (" + select.getStatement() + ")");
+        if (queryFilter.getPrincipals() != null) {
+            mainWhereClauses.add(dialect.getSecurityCheckSql(hierId));
+            Serializable principals;
+            Serializable permissions;
+            if (dialect.supportsArrays()) {
+                principals = queryFilter.getPrincipals();
+                permissions = queryFilter.getPermissions();
+            } else {
+                principals = StringUtils.join(queryFilter.getPrincipals(), '|');
+                permissions = StringUtils.join(queryFilter.getPermissions(),
+                        '|');
+            }
+            q.selectParams.add(principals);
+            q.selectParams.add(permissions);
+        }
+
+        // Some dialects need any ORDER BY expressions to appear in the
+        // SELECT list when using DISTINCT.
+        Set<Column> columns = new HashSet<Column>();
+        if (dialect.needsOrderByKeysAfterDistinct()) {
+            for (String key : info.orderKeys) {
+                Column column = findColumn(key, false, true);
+                String qname = column.getFullQuotedName();
+                mainWhat += ", " + qname;
+                if (!hierTable.getName().equals(column.getTable().getName())) {
+                    columns.add(column);
+                }
+            }
+            for (Column column : columns) {
+                mainJoins.add(String.format("%s ON %s = %s",
+                        column.getTable().getQuotedName(), useAlias ? hierId
+                                : joinedHierId, column.getTable().getColumn(
+                                model.MAIN_KEY).getFullQuotedName()));
+            }
+        }
+
+        mainSelect.setWhat(mainWhat);
+        mainSelect.setFrom(StringUtils.join(mainJoins, " LEFT JOIN "));
+        mainSelect.setWhere("(" + StringUtils.join(mainWhereClauses, " AND ")
+                + ")");
+        mainSelect.setOrderBy(orderBy);
+
+        q.selectInfo = new SQLInfoSelect(mainSelect.getStatement(),
+                whatColumns, null, null);
+
         return q;
     }
 
