msi: Sort each table of the join separately.

This commit is contained in:
James Hawkins 2007-12-17 19:35:31 -06:00 committed by Alexandre Julliard
parent f93ee6f420
commit 91c205e8c0
15 changed files with 258 additions and 454 deletions

View File

@ -32,7 +32,6 @@ C_SRCS = \
msi.c \
msi_main.c \
msiquery.c \
order.c \
package.c \
preview.c \
record.c \

View File

@ -241,6 +241,7 @@ static const MSIVIEWOPS alter_ops =
NULL,
NULL,
NULL,
NULL,
};
UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_info *colinfo, int hold )

View File

@ -136,6 +136,7 @@ static const MSIVIEWOPS create_ops =
NULL,
NULL,
NULL,
NULL,
};
static UINT check_columns( column_info *col_info )

View File

@ -267,6 +267,14 @@ static UINT DISTINCT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
return r;
}
static UINT DISTINCT_sort(struct tagMSIVIEW *view, column_info *columns)
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW *)view;
TRACE("%p %p\n", view, columns);
return dv->table->ops->sort( dv->table, columns );
}
static const MSIVIEWOPS distinct_ops =
{
@ -287,6 +295,7 @@ static const MSIVIEWOPS distinct_ops =
NULL,
NULL,
NULL,
DISTINCT_sort,
};
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )

View File

@ -238,6 +238,7 @@ static const MSIVIEWOPS insert_ops =
NULL,
NULL,
NULL,
NULL,
};
static UINT count_column_info( const column_info *ci )

View File

@ -268,6 +268,24 @@ static UINT JOIN_find_matching_rows( struct tagMSIVIEW *view, UINT col,
return ERROR_NO_MORE_ITEMS;
}
static UINT JOIN_sort(struct tagMSIVIEW *view, column_info *columns)
{
MSIJOINVIEW *jv = (MSIJOINVIEW *)view;
JOINTABLE *table;
UINT r;
TRACE("%p %p\n", view, columns);
LIST_FOR_EACH_ENTRY(table, &jv->tables, JOINTABLE, entry)
{
r = table->view->ops->sort(table->view, columns);
if (r != ERROR_SUCCESS)
return r;
}
return ERROR_SUCCESS;
}
static const MSIVIEWOPS join_ops =
{
JOIN_fetch_int,
@ -287,6 +305,7 @@ static const MSIVIEWOPS join_ops =
NULL,
NULL,
NULL,
JOIN_sort,
};
UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables )

View File

@ -133,6 +133,16 @@ typedef struct tagMSIMEDIADISK
LPWSTR disk_prompt;
} MSIMEDIADISK;
typedef struct _column_info
{
LPCWSTR table;
LPCWSTR column;
INT type;
BOOL temporary;
struct expr *val;
struct _column_info *next;
} column_info;
typedef const struct tagMSICOLUMNHASHENTRY *MSIITERHANDLE;
typedef struct tagMSIVIEWOPS
@ -248,6 +258,11 @@ typedef struct tagMSIVIEWOPS
* remove_column - removes the column represented by table name and column number from the table
*/
UINT (*remove_column)( struct tagMSIVIEW *view, LPCWSTR table, UINT number );
/*
* sort - orders the table by columns
*/
UINT (*sort)( struct tagMSIVIEW *view, column_info *columns );
} MSIVIEWOPS;
struct tagMSIVIEW

View File

@ -1,376 +0,0 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 Mike McCormack for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
#include "objidl.h"
#include "msipriv.h"
#include "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
/* below is the query interface to a table */
typedef struct tagMSIORDERVIEW
{
MSIVIEW view;
MSIDATABASE *db;
MSIVIEW *table;
UINT *reorder;
UINT num_cols;
UINT cols[1];
} MSIORDERVIEW;
static UINT ORDER_compare( MSIORDERVIEW *ov, UINT a, UINT b, UINT *swap )
{
UINT r, i, a_val = 0, b_val = 0;
*swap = 0;
for( i=0; i<ov->num_cols; i++ )
{
r = ov->table->ops->fetch_int( ov->table, a, ov->cols[i], &a_val );
if( r != ERROR_SUCCESS )
return r;
r = ov->table->ops->fetch_int( ov->table, b, ov->cols[i], &b_val );
if( r != ERROR_SUCCESS )
return r;
if( a_val != b_val )
{
if( a_val > b_val )
*swap = 1;
break;
}
}
return ERROR_SUCCESS;
}
static UINT ORDER_mergesort( MSIORDERVIEW *ov, UINT left, UINT right )
{
UINT r, centre = (left + right)/2, temp, swap = 0, i, j;
UINT *array = ov->reorder;
if( left == right )
return ERROR_SUCCESS;
/* sort the left half */
r = ORDER_mergesort( ov, left, centre );
if( r != ERROR_SUCCESS )
return r;
/* sort the right half */
r = ORDER_mergesort( ov, centre+1, right );
if( r != ERROR_SUCCESS )
return r;
for( i=left, j=centre+1; (i<=centre) && (j<=right); i++ )
{
r = ORDER_compare( ov, array[i], array[j], &swap );
if( r != ERROR_SUCCESS )
return r;
if( swap )
{
temp = array[j];
memmove( &array[i+1], &array[i], (j-i)*sizeof (UINT) );
array[i] = temp;
j++;
centre++;
}
}
return ERROR_SUCCESS;
}
static UINT ORDER_verify( MSIORDERVIEW *ov, UINT num_rows )
{
UINT i, swap, r;
for( i=1; i<num_rows; i++ )
{
r = ORDER_compare( ov, ov->reorder[i-1], ov->reorder[i], &swap );
if( r != ERROR_SUCCESS )
return r;
if( !swap )
continue;
ERR("Bad order! %d\n", i);
return ERROR_FUNCTION_FAILED;
}
return ERROR_SUCCESS;
}
static UINT ORDER_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p %d %d %p\n", ov, row, col, val );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
row = ov->reorder[ row ];
return ov->table->ops->fetch_int( ov->table, row, col, val );
}
static UINT ORDER_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
{
MSIORDERVIEW *ov = (MSIORDERVIEW *)view;
TRACE("%p %d %p\n", ov, row, rec );
if (!ov->table)
return ERROR_FUNCTION_FAILED;
row = ov->reorder[row];
return ov->table->ops->get_row(ov->table, row, rec);
}
static UINT ORDER_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
UINT r, num_rows = 0, i;
TRACE("%p %p\n", ov, record);
if( !ov->table )
return ERROR_FUNCTION_FAILED;
r = ov->table->ops->execute( ov->table, record );
if( r != ERROR_SUCCESS )
return r;
r = ov->table->ops->get_dimensions( ov->table, &num_rows, NULL );
if( r != ERROR_SUCCESS )
return r;
ov->reorder = msi_alloc( num_rows*sizeof(UINT) );
if( !ov->reorder )
return ERROR_FUNCTION_FAILED;
for( i=0; i<num_rows; i++ )
ov->reorder[i] = i;
r = ORDER_mergesort( ov, 0, num_rows - 1 );
if( r != ERROR_SUCCESS )
return r;
r = ORDER_verify( ov, num_rows );
if( r != ERROR_SUCCESS )
return r;
return ERROR_SUCCESS;
}
static UINT ORDER_close( struct tagMSIVIEW *view )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p\n", ov );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
msi_free( ov->reorder );
ov->reorder = NULL;
return ov->table->ops->close( ov->table );
}
static UINT ORDER_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p %p %p\n", ov, rows, cols );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
return ov->table->ops->get_dimensions( ov->table, rows, cols );
}
static UINT ORDER_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p %d %p %p\n", ov, n, name, type );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
return ov->table->ops->get_column_info( ov->table, n, name, type );
}
static UINT ORDER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec, UINT row )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p %d %p\n", ov, eModifyMode, rec );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
return ov->table->ops->modify( ov->table, eModifyMode, rec, row );
}
static UINT ORDER_delete( struct tagMSIVIEW *view )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p\n", ov );
if( ov->table )
ov->table->ops->delete( ov->table );
msi_free( ov->reorder );
ov->reorder = NULL;
msiobj_release( &ov->db->hdr );
msi_free( ov );
return ERROR_SUCCESS;
}
static UINT ORDER_find_matching_rows( struct tagMSIVIEW *view, UINT col,
UINT val, UINT *row, MSIITERHANDLE *handle )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
UINT r;
TRACE("%p, %d, %u, %p\n", ov, col, val, *handle);
if( !ov->table )
return ERROR_FUNCTION_FAILED;
r = ov->table->ops->find_matching_rows( ov->table, col, val, row, handle );
*row = ov->reorder[ *row ];
return r;
}
static const MSIVIEWOPS order_ops =
{
ORDER_fetch_int,
NULL,
ORDER_get_row,
NULL,
NULL,
NULL,
ORDER_execute,
ORDER_close,
ORDER_get_dimensions,
ORDER_get_column_info,
ORDER_modify,
ORDER_delete,
ORDER_find_matching_rows,
NULL,
NULL,
NULL,
NULL,
};
static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name )
{
UINT n, count, r;
MSIVIEW *table;
TRACE("%p adding %s\n", ov, debugstr_w( name ) );
if( ov->view.ops != &order_ops )
return ERROR_FUNCTION_FAILED;
table = ov->table;
if( !table )
return ERROR_FUNCTION_FAILED;
if( !table->ops->get_dimensions )
return ERROR_FUNCTION_FAILED;
if( !table->ops->get_column_info )
return ERROR_FUNCTION_FAILED;
r = table->ops->get_dimensions( table, NULL, &count );
if( r != ERROR_SUCCESS )
return r;
if( ov->num_cols >= count )
return ERROR_FUNCTION_FAILED;
r = VIEW_find_column( table, name, &n );
if( r != ERROR_SUCCESS )
return r;
ov->cols[ov->num_cols] = n;
TRACE("Ordering by column %s (%d)\n", debugstr_w( name ), n);
ov->num_cols++;
return ERROR_SUCCESS;
}
UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
column_info *columns )
{
MSIORDERVIEW *ov = NULL;
UINT count = 0, r;
column_info *x;
TRACE("%p\n", ov );
r = table->ops->get_dimensions( table, NULL, &count );
if( r != ERROR_SUCCESS )
{
ERR("can't get table dimensions\n");
return r;
}
ov = msi_alloc_zero( sizeof *ov + sizeof (UINT) * count );
if( !ov )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
ov->view.ops = &order_ops;
msiobj_addref( &db->hdr );
ov->db = db;
ov->table = table;
ov->reorder = NULL;
ov->num_cols = 0;
*view = (MSIVIEW*) ov;
for( x = columns; x ; x = x->next )
ORDER_AddColumn( ov, x->column );
return ERROR_SUCCESS;
}

View File

@ -61,16 +61,6 @@ struct sql_str {
INT len;
};
typedef struct _column_info
{
LPCWSTR table;
LPCWSTR column;
UINT type;
BOOL temporary;
struct expr *val;
struct _column_info *next;
} column_info;
struct complex_expr
{
UINT op;

View File

@ -334,6 +334,14 @@ static UINT SELECT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
return sv->table->ops->find_matching_rows( sv->table, col, val, row, handle );
}
static UINT SELECT_sort(struct tagMSIVIEW *view, column_info *columns)
{
MSISELECTVIEW *sv = (MSISELECTVIEW *)view;
TRACE("%p %p\n", view, columns);
return sv->table->ops->sort( sv->table, columns );
}
static const MSIVIEWOPS select_ops =
{
@ -354,6 +362,7 @@ static const MSIVIEWOPS select_ops =
NULL,
NULL,
NULL,
SELECT_sort,
};
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )

View File

@ -373,16 +373,17 @@ data_count:
oneselect:
unorderedsel TK_ORDER TK_BY selcollist
{
SQL_input* sql = (SQL_input*) info;
UINT r;
$$ = NULL;
if( $4 )
ORDER_CreateView( sql->db, &$$, $1, $4 );
else
$$ = $1;
if( !$$ )
{
r = $1->ops->sort( $1, $4 );
if ( r != ERROR_SUCCESS)
YYABORT;
}
$$ = $1;
}
| unorderedsel
;

View File

@ -379,6 +379,7 @@ static const MSIVIEWOPS streams_ops =
NULL,
NULL,
NULL,
NULL,
};
static UINT add_streams_to_table(MSISTREAMSVIEW *sv)

View File

@ -62,6 +62,13 @@ typedef struct tagMSICOLUMNINFO
MSICOLUMNHASHENTRY **hash_table;
} MSICOLUMNINFO;
typedef struct tagMSIORDERINFO
{
UINT *reorder;
UINT num_cols;
UINT cols[1];
} MSIORDERINFO;
struct tagMSITABLE
{
BYTE **data;
@ -1114,6 +1121,7 @@ typedef struct tagMSITABLEVIEW
MSIDATABASE *db;
MSITABLE *table;
MSICOLUMNINFO *columns;
MSIORDERINFO *order;
UINT num_cols;
UINT row_size;
WCHAR name[1];
@ -1142,6 +1150,9 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
return ERROR_FUNCTION_FAILED;
}
if (tv->order)
row = tv->order->reorder[row];
if (row >= tv->table->row_count)
{
row -= tv->table->row_count;
@ -1286,6 +1297,9 @@ static UINT TABLE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
if (!tv->table)
return ERROR_INVALID_PARAMETER;
if (tv->order)
row = tv->order->reorder[row];
return msi_view_get_row(tv->db, view, row, rec);
}
@ -1728,6 +1742,10 @@ static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
return ERROR_NO_MORE_ITEMS;
*row = entry->row;
if (tv->order)
*row = tv->order->reorder[*row];
return ERROR_SUCCESS;
}
@ -1860,6 +1878,157 @@ done:
return r;
}
static UINT order_add_column(struct tagMSIVIEW *view, MSIORDERINFO *order, LPCWSTR name)
{
UINT n, r, count;
r = TABLE_get_dimensions(view, NULL, &count);
if (r != ERROR_SUCCESS)
return r;
if (order->num_cols >= count)
return ERROR_FUNCTION_FAILED;
r = VIEW_find_column(view, name, &n);
if (r != ERROR_SUCCESS)
return r;
order->cols[order->num_cols] = n;
TRACE("Ordering by column %s (%d)\n", debugstr_w(name), n);
order->num_cols++;
return ERROR_SUCCESS;
}
static UINT order_compare(struct tagMSIVIEW *view, MSIORDERINFO *order,
UINT a, UINT b, UINT *swap)
{
UINT r, i, a_val = 0, b_val = 0;
*swap = 0;
for (i = 0; i < order->num_cols; i++)
{
r = TABLE_fetch_int(view, a, order->cols[i], &a_val);
if (r != ERROR_SUCCESS)
return r;
r = TABLE_fetch_int(view, b, order->cols[i], &b_val);
if (r != ERROR_SUCCESS)
return r;
if (a_val != b_val)
{
if (a_val > b_val)
*swap = 1;
break;
}
}
return ERROR_SUCCESS;
}
static UINT order_mergesort(struct tagMSIVIEW *view, MSIORDERINFO *order,
UINT left, UINT right)
{
UINT r, i, j, temp;
UINT swap = 0, center = (left + right) / 2;
UINT *array = order->reorder;
if (left == right)
return ERROR_SUCCESS;
/* sort the left half */
r = order_mergesort(view, order, left, center);
if (r != ERROR_SUCCESS)
return r;
/* sort the right half */
r = order_mergesort(view, order, center + 1, right);
if (r != ERROR_SUCCESS)
return r;
for (i = left, j = center + 1; (i <= center) && (j <= right); i++)
{
r = order_compare(view, order, array[i], array[j], &swap);
if (r != ERROR_SUCCESS)
return r;
if (swap)
{
temp = array[j];
memmove(&array[i + 1], &array[i], (j - i) * sizeof(UINT));
array[i] = temp;
j++;
center++;
}
}
return ERROR_SUCCESS;
}
static UINT order_verify(struct tagMSIVIEW *view, MSIORDERINFO *order, UINT num_rows)
{
UINT i, swap, r;
for (i = 1; i < num_rows; i++)
{
r = order_compare(view, order, order->reorder[i - 1],
order->reorder[i], &swap);
if (r != ERROR_SUCCESS)
return r;
if (!swap)
continue;
ERR("Bad order! %d\n", i);
return ERROR_FUNCTION_FAILED;
}
return ERROR_SUCCESS;
}
static UINT TABLE_sort(struct tagMSIVIEW *view, column_info *columns)
{
MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
MSIORDERINFO *order;
column_info *ptr;
UINT r, i;
UINT rows, cols;
TRACE("sorting table %s\n", debugstr_w(tv->name));
r = TABLE_get_dimensions(view, &rows, &cols);
if (r != ERROR_SUCCESS)
return r;
order = msi_alloc_zero(sizeof(MSIORDERINFO) + sizeof(UINT) * cols);
if (!order)
return ERROR_OUTOFMEMORY;
for (ptr = columns; ptr; ptr = ptr->next)
order_add_column(view, order, ptr->column);
order->reorder = msi_alloc(rows * sizeof(UINT));
if (!order->reorder)
return ERROR_OUTOFMEMORY;
for (i = 0; i < rows; i++)
order->reorder[i] = i;
r = order_mergesort(view, order, 0, rows - 1);
if (r != ERROR_SUCCESS)
return r;
r = order_verify(view, order, rows);
if (r != ERROR_SUCCESS)
return r;
tv->order = order;
return ERROR_SUCCESS;
}
static const MSIVIEWOPS table_ops =
{
TABLE_fetch_int,
@ -1879,6 +2048,7 @@ static const MSIVIEWOPS table_ops =
TABLE_release,
TABLE_add_column,
TABLE_remove_column,
TABLE_sort,
};
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )

View File

@ -4610,16 +4610,10 @@ static void test_order(void)
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
val = MsiRecordGetInteger(hrec, 1);
todo_wine
{
ok(val == 3, "Expected 3, got %d\n", val);
}
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 4, "Expected 3, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4627,16 +4621,10 @@ static void test_order(void)
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
val = MsiRecordGetInteger(hrec, 1);
todo_wine
{
ok(val == 5, "Expected 5, got %d\n", val);
}
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 6, "Expected 6, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4644,16 +4632,10 @@ static void test_order(void)
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
val = MsiRecordGetInteger(hrec, 1);
todo_wine
{
ok(val == 1, "Expected 1, got %d\n", val);
}
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 2, "Expected 2, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4673,10 +4655,7 @@ static void test_order(void)
ok(val == 1, "Expected 1, got %d\n", val);
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 12, "Expected 12, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4687,10 +4666,7 @@ static void test_order(void)
ok(val == 3, "Expected 3, got %d\n", val);
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 12, "Expected 12, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4701,10 +4677,7 @@ static void test_order(void)
ok(val == 5, "Expected 5, got %d\n", val);
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 12, "Expected 12, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4715,10 +4688,7 @@ static void test_order(void)
ok(val == 1, "Expected 1, got %d\n", val);
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 14, "Expected 14, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4729,10 +4699,7 @@ static void test_order(void)
ok(val == 3, "Expected 3, got %d\n", val);
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 14, "Expected 14, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4743,10 +4710,7 @@ static void test_order(void)
ok(val == 5, "Expected 5, got %d\n", val);
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 14, "Expected 14, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4757,10 +4721,7 @@ static void test_order(void)
ok(val == 1, "Expected 1, got %d\n", val);
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 10, "Expected 10, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4771,10 +4732,7 @@ static void test_order(void)
ok(val == 3, "Expected 3, got %d\n", val);
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 10, "Expected 10, got %d\n", val);
}
MsiCloseHandle(hrec);
@ -4785,10 +4743,7 @@ static void test_order(void)
ok(val == 5, "Expected 5, got %d\n", val);
val = MsiRecordGetInteger(hrec, 2);
todo_wine
{
ok(val == 10, "Expected 10, got %d\n", val);
}
MsiCloseHandle(hrec);

View File

@ -532,6 +532,14 @@ static UINT WHERE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
return find_entry_in_hash(wv->reorder, *row, row);
}
static UINT WHERE_sort(struct tagMSIVIEW *view, column_info *columns)
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
TRACE("%p %p\n", view, columns);
return wv->table->ops->sort(wv->table, columns);
}
static const MSIVIEWOPS where_ops =
{
@ -552,6 +560,7 @@ static const MSIVIEWOPS where_ops =
NULL,
NULL,
NULL,
WHERE_sort,
};
static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,