Bernhard Loos : msi: Implement proper sorting in WHEREVIEW.

Alexandre Julliard julliard at winehq.org
Fri Aug 26 10:40:54 CDT 2011


Module: wine
Branch: master
Commit: f0a53a8f1bde9b8f1be096160f9664415835e29b
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=f0a53a8f1bde9b8f1be096160f9664415835e29b

Author: Bernhard Loos <bernhardloos at googlemail.com>
Date:   Fri Aug 26 04:53:44 2011 +0200

msi: Implement proper sorting in WHEREVIEW.

---

 dlls/msi/where.c |  118 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 106 insertions(+), 12 deletions(-)

diff --git a/dlls/msi/where.c b/dlls/msi/where.c
index 0742244..16b6c03 100644
--- a/dlls/msi/where.c
+++ b/dlls/msi/where.c
@@ -38,9 +38,9 @@
 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 /* below is the query interface to a table */
-
 typedef struct tagMSIROWENTRY
 {
+    struct tagMSIWHEREVIEW *wv; /* used during sorting */
     UINT values[1];
 } MSIROWENTRY;
 
@@ -53,6 +53,13 @@ typedef struct tagJOINTABLE
     UINT table_index;
 } JOINTABLE;
 
+typedef struct tagMSIORDERINFO
+{
+    UINT col_count;
+    UINT error;
+    union ext_column columns[1];
+} MSIORDERINFO;
+
 typedef struct tagMSIWHEREVIEW
 {
     MSIVIEW        view;
@@ -65,6 +72,7 @@ typedef struct tagMSIWHEREVIEW
     UINT           reorder_size; /* number of entries available in reorder */
     struct expr   *cond;
     UINT           rec_index;
+    MSIORDERINFO  *order_info;
 } MSIWHEREVIEW;
 
 #define INITIAL_REORDER_SIZE 16
@@ -136,6 +144,7 @@ static UINT add_row(MSIWHEREVIEW *wv, UINT vals[])
     wv->reorder[wv->row_count++] = new;
 
     memcpy(new->values, vals, wv->table_count * sizeof(UINT));
+    new->wv = wv;
 
     return ERROR_SUCCESS;
 }
@@ -549,6 +558,53 @@ static UINT check_condition( MSIWHEREVIEW *wv, MSIRECORD *record, JOINTABLE *tab
     return r;
 }
 
+static int compare_entry( const void *left, const void *right )
+{
+    const MSIROWENTRY *le = *(const MSIROWENTRY**)left;
+    const MSIROWENTRY *re = *(const MSIROWENTRY**)right;
+    const MSIWHEREVIEW *wv = le->wv;
+    MSIORDERINFO *order = wv->order_info;
+    UINT i, j, r, l_val, r_val;
+
+    assert(le->wv == re->wv);
+
+    if (order)
+    {
+        for (i = 0; i < order->col_count; i++)
+        {
+            const union ext_column *column = &order->columns[i];
+
+            r = column->parsed.table->view->ops->fetch_int(column->parsed.table->view,
+                          le->values[column->parsed.table->table_index],
+                          column->parsed.column, &l_val);
+            if (r != ERROR_SUCCESS)
+            {
+                order->error = r;
+                return 0;
+            }
+
+            r = column->parsed.table->view->ops->fetch_int(column->parsed.table->view,
+                          re->values[column->parsed.table->table_index],
+                          column->parsed.column, &r_val);
+            if (r != ERROR_SUCCESS)
+            {
+                order->error = r;
+                return 0;
+            }
+
+            if (l_val != r_val)
+                return l_val < r_val ? -1 : 1;
+        }
+    }
+
+    for (j = 0; j < wv->table_count; j++)
+    {
+        if (le->values[j] != re->values[j])
+            return le->values[j] < re->values[j] ? -1 : 1;
+    }
+    return 0;
+}
+
 static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
 {
     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
@@ -583,6 +639,15 @@ static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
     while ((table = table->next));
 
     r =  check_condition(wv, record, wv->tables, rows);
+
+    if (wv->order_info)
+        wv->order_info->error = ERROR_SUCCESS;
+
+    qsort(wv->reorder, wv->row_count, sizeof(MSIROWENTRY *), compare_entry);
+
+    if (wv->order_info)
+        r = wv->order_info->error;
+
     return r;
 }
 
@@ -773,6 +838,12 @@ static UINT WHERE_delete( struct tagMSIVIEW *view )
 
     free_reorder(wv);
 
+    if (wv->order_info)
+    {
+        msi_free(wv->order_info);
+        wv->order_info = NULL;
+    }
+
     msiobj_release( &wv->db->hdr );
     msi_free( wv );
 
@@ -813,22 +884,49 @@ static UINT WHERE_sort(struct tagMSIVIEW *view, column_info *columns)
 {
     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
     JOINTABLE *table = wv->tables;
-    UINT r;
+    column_info *column = columns;
+    MSIORDERINFO *orderinfo;
+    UINT r, count = 0;
+    int i;
 
     TRACE("%p %p\n", view, columns);
 
     if (!table)
         return ERROR_FUNCTION_FAILED;
 
-    do
+    while (column)
     {
-        r = table->view->ops->sort(table->view, columns);
+        count++;
+        column = column->next;
+    }
+
+    if (count == 0)
+        return ERROR_SUCCESS;
+
+    orderinfo = msi_alloc(sizeof(MSIORDERINFO) + (count - 1) * sizeof(union ext_column));
+    if (!orderinfo)
+        return ERROR_OUTOFMEMORY;
+
+    orderinfo->col_count = count;
+
+    column = columns;
+
+    for (i = 0; i < count; i++)
+    {
+        orderinfo->columns[i].unparsed.column = column->column;
+        orderinfo->columns[i].unparsed.table = column->table;
+
+        r = parse_column(wv, &orderinfo->columns[i], NULL);
         if (r != ERROR_SUCCESS)
-            return r;
+            goto error;
     }
-    while ((table = table->next));
+
+    wv->order_info = orderinfo;
 
     return ERROR_SUCCESS;
+error:
+    msi_free(orderinfo);
+    return r;
 }
 
 static const MSIVIEWOPS where_ops =
@@ -949,7 +1047,6 @@ UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables,
     MSIWHEREVIEW *wv = NULL;
     UINT r, valid = 0;
     WCHAR *ptr;
-    JOINTABLE **lastnext;
 
     TRACE("(%s)\n", debugstr_w(tables) );
 
@@ -963,8 +1060,6 @@ UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables,
     wv->db = db;
     wv->cond = cond;
 
-    lastnext = &wv->tables;
-
     while (*tables)
     {
         JOINTABLE *table;
@@ -998,10 +1093,9 @@ UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables,
 
         wv->col_count += table->col_count;
         table->table_index = wv->table_count++;
-        table->next = NULL;
 
-        *lastnext = table;
-        lastnext = &table->next;
+        table->next = wv->tables;
+        wv->tables = table;
 
         if (!ptr)
             break;




More information about the wine-cvs mailing list