msi: Optimise WHERE operations.
Optimise WHERE operations on matching against strings by adding a new function find_matching_rows to the views, which eliminates the need to examine every record when executing a query. Implement this function in the table using a hash table on the ID stored in the data.
This commit is contained in:
parent
d62aa01ec0
commit
9f487ba1de
|
@ -182,6 +182,14 @@ static UINT DELETE_delete( struct tagMSIVIEW *view )
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT DELETE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
||||||
|
UINT val, UINT *row, MSIITERHANDLE *handle )
|
||||||
|
{
|
||||||
|
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
|
||||||
|
|
||||||
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MSIVIEWOPS delete_ops =
|
MSIVIEWOPS delete_ops =
|
||||||
{
|
{
|
||||||
|
@ -194,7 +202,8 @@ MSIVIEWOPS delete_ops =
|
||||||
DELETE_get_dimensions,
|
DELETE_get_dimensions,
|
||||||
DELETE_get_column_info,
|
DELETE_get_column_info,
|
||||||
DELETE_modify,
|
DELETE_modify,
|
||||||
DELETE_delete
|
DELETE_delete,
|
||||||
|
DELETE_find_matching_rows
|
||||||
};
|
};
|
||||||
|
|
||||||
UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
|
UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
|
||||||
|
|
|
@ -246,6 +246,27 @@ static UINT DISTINCT_delete( struct tagMSIVIEW *view )
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT DISTINCT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
||||||
|
UINT val, UINT *row, MSIITERHANDLE *handle )
|
||||||
|
{
|
||||||
|
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
|
||||||
|
UINT r;
|
||||||
|
|
||||||
|
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
|
||||||
|
|
||||||
|
if( !dv->table )
|
||||||
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
|
r = dv->table->ops->find_matching_rows( dv->table, col, val, row, handle );
|
||||||
|
|
||||||
|
if( *row > dv->row_count )
|
||||||
|
return ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
|
*row = dv->translation[ *row ];
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MSIVIEWOPS distinct_ops =
|
MSIVIEWOPS distinct_ops =
|
||||||
{
|
{
|
||||||
|
@ -258,7 +279,8 @@ MSIVIEWOPS distinct_ops =
|
||||||
DISTINCT_get_dimensions,
|
DISTINCT_get_dimensions,
|
||||||
DISTINCT_get_column_info,
|
DISTINCT_get_column_info,
|
||||||
DISTINCT_modify,
|
DISTINCT_modify,
|
||||||
DISTINCT_delete
|
DISTINCT_delete,
|
||||||
|
DISTINCT_find_matching_rows,
|
||||||
};
|
};
|
||||||
|
|
||||||
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
|
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
|
||||||
|
|
|
@ -214,6 +214,14 @@ static UINT INSERT_delete( struct tagMSIVIEW *view )
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT INSERT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
||||||
|
UINT val, UINT *row, MSIITERHANDLE *handle )
|
||||||
|
{
|
||||||
|
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
|
||||||
|
|
||||||
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MSIVIEWOPS insert_ops =
|
MSIVIEWOPS insert_ops =
|
||||||
{
|
{
|
||||||
|
@ -226,7 +234,8 @@ MSIVIEWOPS insert_ops =
|
||||||
INSERT_get_dimensions,
|
INSERT_get_dimensions,
|
||||||
INSERT_get_column_info,
|
INSERT_get_column_info,
|
||||||
INSERT_modify,
|
INSERT_modify,
|
||||||
INSERT_delete
|
INSERT_delete,
|
||||||
|
INSERT_find_matching_rows
|
||||||
};
|
};
|
||||||
|
|
||||||
UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
||||||
|
|
|
@ -100,6 +100,8 @@ typedef struct tagMSIRECORD
|
||||||
MSIFIELD fields[1]; /* nb. array size is count+1 */
|
MSIFIELD fields[1]; /* nb. array size is count+1 */
|
||||||
} MSIRECORD;
|
} MSIRECORD;
|
||||||
|
|
||||||
|
typedef void *MSIITERHANDLE;
|
||||||
|
|
||||||
typedef struct tagMSIVIEWOPS
|
typedef struct tagMSIVIEWOPS
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -114,7 +116,7 @@ typedef struct tagMSIVIEWOPS
|
||||||
UINT (*fetch_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT *val );
|
UINT (*fetch_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT *val );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fetch_int - reads one integer from {row,col} in the table
|
* fetch_stream - gets a stream from {row,col} in the table
|
||||||
*
|
*
|
||||||
* This function is similar to fetch_int, except fetches a
|
* This function is similar to fetch_int, except fetches a
|
||||||
* stream instead of an integer.
|
* stream instead of an integer.
|
||||||
|
@ -170,6 +172,18 @@ typedef struct tagMSIVIEWOPS
|
||||||
*/
|
*/
|
||||||
UINT (*delete)( struct tagMSIVIEW * );
|
UINT (*delete)( struct tagMSIVIEW * );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find_matching_rows - iterates through rows that match a value
|
||||||
|
*
|
||||||
|
* If the column type is a string then a string ID should be passed in.
|
||||||
|
* If the value to be looked up is an integer then no transformation of
|
||||||
|
* the input value is required, except if the column is a string, in which
|
||||||
|
* case a string ID should be passed in.
|
||||||
|
* The handle is an input/output parameter that keeps track of the current
|
||||||
|
* position in the iteration. It must be initialised to zero before the
|
||||||
|
* first call and continued to be passed in to subsequent calls.
|
||||||
|
*/
|
||||||
|
UINT (*find_matching_rows)( struct tagMSIVIEW *, UINT col, UINT val, UINT *row, MSIITERHANDLE *handle );
|
||||||
} MSIVIEWOPS;
|
} MSIVIEWOPS;
|
||||||
|
|
||||||
struct tagMSIVIEW
|
struct tagMSIVIEW
|
||||||
|
|
|
@ -249,6 +249,24 @@ static UINT ORDER_delete( struct tagMSIVIEW *view )
|
||||||
return ERROR_SUCCESS;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MSIVIEWOPS order_ops =
|
MSIVIEWOPS order_ops =
|
||||||
{
|
{
|
||||||
|
@ -261,7 +279,8 @@ MSIVIEWOPS order_ops =
|
||||||
ORDER_get_dimensions,
|
ORDER_get_dimensions,
|
||||||
ORDER_get_column_info,
|
ORDER_get_column_info,
|
||||||
ORDER_modify,
|
ORDER_modify,
|
||||||
ORDER_delete
|
ORDER_delete,
|
||||||
|
ORDER_find_matching_rows
|
||||||
};
|
};
|
||||||
|
|
||||||
static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name )
|
static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name )
|
||||||
|
|
|
@ -196,6 +196,24 @@ static UINT SELECT_delete( struct tagMSIVIEW *view )
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT SELECT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
||||||
|
UINT val, UINT *row, MSIITERHANDLE *handle )
|
||||||
|
{
|
||||||
|
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
|
||||||
|
|
||||||
|
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
|
||||||
|
|
||||||
|
if( !sv->table )
|
||||||
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
|
if( (col==0) || (col>sv->num_cols) )
|
||||||
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
|
col = sv->cols[ col - 1 ];
|
||||||
|
|
||||||
|
return sv->table->ops->find_matching_rows( sv->table, col, val, row, handle );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MSIVIEWOPS select_ops =
|
MSIVIEWOPS select_ops =
|
||||||
{
|
{
|
||||||
|
@ -208,7 +226,8 @@ MSIVIEWOPS select_ops =
|
||||||
SELECT_get_dimensions,
|
SELECT_get_dimensions,
|
||||||
SELECT_get_column_info,
|
SELECT_get_column_info,
|
||||||
SELECT_modify,
|
SELECT_modify,
|
||||||
SELECT_delete
|
SELECT_delete,
|
||||||
|
SELECT_find_matching_rows
|
||||||
};
|
};
|
||||||
|
|
||||||
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
|
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
|
||||||
|
|
109
dlls/msi/table.c
109
dlls/msi/table.c
|
@ -39,6 +39,15 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||||
|
|
||||||
|
#define MSITABLE_HASH_TABLE_SIZE 37
|
||||||
|
|
||||||
|
typedef struct tagMSICOLUMNHASHENTRY
|
||||||
|
{
|
||||||
|
struct tagMSICOLUMNHASHENTRY *next;
|
||||||
|
UINT value;
|
||||||
|
UINT row;
|
||||||
|
} MSICOLUMNHASHENTRY;
|
||||||
|
|
||||||
typedef struct tagMSICOLUMNINFO
|
typedef struct tagMSICOLUMNINFO
|
||||||
{
|
{
|
||||||
LPCWSTR tablename;
|
LPCWSTR tablename;
|
||||||
|
@ -46,6 +55,7 @@ typedef struct tagMSICOLUMNINFO
|
||||||
LPCWSTR colname;
|
LPCWSTR colname;
|
||||||
UINT type;
|
UINT type;
|
||||||
UINT offset;
|
UINT offset;
|
||||||
|
MSICOLUMNHASHENTRY **hash_table;
|
||||||
} MSICOLUMNINFO;
|
} MSICOLUMNINFO;
|
||||||
|
|
||||||
struct tagMSITABLE
|
struct tagMSITABLE
|
||||||
|
@ -884,6 +894,7 @@ static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count )
|
||||||
{
|
{
|
||||||
msi_free( (LPWSTR) colinfo[i].tablename );
|
msi_free( (LPWSTR) colinfo[i].tablename );
|
||||||
msi_free( (LPWSTR) colinfo[i].colname );
|
msi_free( (LPWSTR) colinfo[i].colname );
|
||||||
|
msi_free( colinfo[i].hash_table );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -931,7 +942,7 @@ static UINT get_tablecolumns( MSIDATABASE *db,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("Table id is %d\n", table_id);
|
TRACE("Table id is %d, row count is %d\n", table_id, table->row_count);
|
||||||
|
|
||||||
count = table->row_count;
|
count = table->row_count;
|
||||||
for( i=0; i<count; i++ )
|
for( i=0; i<count; i++ )
|
||||||
|
@ -945,6 +956,7 @@ static UINT get_tablecolumns( MSIDATABASE *db,
|
||||||
colinfo[n].number = table->data[ i ][ 1 ] - (1<<15);
|
colinfo[n].number = table->data[ i ][ 1 ] - (1<<15);
|
||||||
colinfo[n].colname = MSI_makestring( db, id );
|
colinfo[n].colname = MSI_makestring( db, id );
|
||||||
colinfo[n].type = table->data[ i ] [ 3 ] ^ 0x8000;
|
colinfo[n].type = table->data[ i ] [ 3 ] ^ 0x8000;
|
||||||
|
colinfo[n].hash_table = NULL;
|
||||||
/* this assumes that columns are in order in the table */
|
/* this assumes that columns are in order in the table */
|
||||||
if( n )
|
if( n )
|
||||||
colinfo[n].offset = colinfo[n-1].offset
|
colinfo[n].offset = colinfo[n-1].offset
|
||||||
|
@ -1389,6 +1401,98 @@ static UINT TABLE_delete( struct tagMSIVIEW *view )
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
||||||
|
UINT val, UINT *row, MSIITERHANDLE *handle )
|
||||||
|
{
|
||||||
|
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
|
||||||
|
const MSICOLUMNHASHENTRY *entry;
|
||||||
|
|
||||||
|
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
|
||||||
|
|
||||||
|
if( !tv->table )
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if( (col==0) || (col > tv->num_cols) )
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if( !tv->columns[col-1].hash_table )
|
||||||
|
{
|
||||||
|
UINT i;
|
||||||
|
UINT num_rows = tv->table->row_count;
|
||||||
|
MSICOLUMNHASHENTRY **hash_table;
|
||||||
|
MSICOLUMNHASHENTRY *new_entry;
|
||||||
|
|
||||||
|
if( tv->columns[col-1].offset >= tv->row_size )
|
||||||
|
{
|
||||||
|
ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
|
||||||
|
ERR("%p %p\n", tv, tv->columns );
|
||||||
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate contiguous memory for the table and its entries so we
|
||||||
|
* don't have to do an expensive cleanup */
|
||||||
|
hash_table = msi_alloc(MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*) +
|
||||||
|
num_rows * sizeof(MSICOLUMNHASHENTRY));
|
||||||
|
if (!hash_table)
|
||||||
|
return ERROR_OUTOFMEMORY;
|
||||||
|
|
||||||
|
memset(hash_table, 0, MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*));
|
||||||
|
tv->columns[col-1].hash_table = hash_table;
|
||||||
|
|
||||||
|
new_entry = (MSICOLUMNHASHENTRY *)(hash_table + MSITABLE_HASH_TABLE_SIZE);
|
||||||
|
|
||||||
|
for (i = 0; i < num_rows; i++, new_entry++)
|
||||||
|
{
|
||||||
|
UINT row_value, n;
|
||||||
|
UINT offset = i + (tv->columns[col-1].offset/2) * num_rows;
|
||||||
|
n = bytes_per_column( &tv->columns[col-1] );
|
||||||
|
switch( n )
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
offset = tv->columns[col-1].offset/2;
|
||||||
|
row_value = tv->table->data[i][offset] +
|
||||||
|
(tv->table->data[i][offset + 1] << 16);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
offset = tv->columns[col-1].offset/2;
|
||||||
|
row_value = tv->table->data[i][offset];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERR("oops! what is %d bytes per column?\n", n );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_entry->next = NULL;
|
||||||
|
new_entry->value = row_value;
|
||||||
|
new_entry->row = i;
|
||||||
|
if (hash_table[row_value % MSITABLE_HASH_TABLE_SIZE])
|
||||||
|
{
|
||||||
|
MSICOLUMNHASHENTRY *prev_entry = hash_table[row_value % MSITABLE_HASH_TABLE_SIZE];
|
||||||
|
while (prev_entry->next)
|
||||||
|
prev_entry = prev_entry->next;
|
||||||
|
prev_entry->next = new_entry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hash_table[row_value % MSITABLE_HASH_TABLE_SIZE] = new_entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !*handle )
|
||||||
|
entry = tv->columns[col-1].hash_table[val % MSITABLE_HASH_TABLE_SIZE];
|
||||||
|
else
|
||||||
|
entry = ((const MSICOLUMNHASHENTRY *)*handle)->next;
|
||||||
|
|
||||||
|
while (entry && entry->value != val)
|
||||||
|
entry = entry->next;
|
||||||
|
|
||||||
|
*handle = (MSIITERHANDLE)entry;
|
||||||
|
if (!entry)
|
||||||
|
return ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
|
*row = entry->row;
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MSIVIEWOPS table_ops =
|
MSIVIEWOPS table_ops =
|
||||||
{
|
{
|
||||||
|
@ -1401,7 +1505,8 @@ MSIVIEWOPS table_ops =
|
||||||
TABLE_get_dimensions,
|
TABLE_get_dimensions,
|
||||||
TABLE_get_column_info,
|
TABLE_get_column_info,
|
||||||
TABLE_modify,
|
TABLE_modify,
|
||||||
TABLE_delete
|
TABLE_delete,
|
||||||
|
TABLE_find_matching_rows
|
||||||
};
|
};
|
||||||
|
|
||||||
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
|
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
|
||||||
|
|
|
@ -177,6 +177,13 @@ static UINT UPDATE_delete( struct tagMSIVIEW *view )
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT UPDATE_find_matching_rows( struct tagMSIVIEW *view, UINT col, UINT val, UINT *row, MSIITERHANDLE *handle )
|
||||||
|
{
|
||||||
|
TRACE("%p %d %d %p\n", view, col, val, *handle );
|
||||||
|
|
||||||
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static MSIVIEWOPS update_ops =
|
static MSIVIEWOPS update_ops =
|
||||||
{
|
{
|
||||||
|
@ -189,7 +196,8 @@ static MSIVIEWOPS update_ops =
|
||||||
UPDATE_get_dimensions,
|
UPDATE_get_dimensions,
|
||||||
UPDATE_get_column_info,
|
UPDATE_get_column_info,
|
||||||
UPDATE_modify,
|
UPDATE_modify,
|
||||||
UPDATE_delete
|
UPDATE_delete,
|
||||||
|
UPDATE_find_matching_rows
|
||||||
};
|
};
|
||||||
|
|
||||||
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
||||||
|
|
|
@ -248,6 +248,45 @@ static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
wv->row_count = 0;
|
wv->row_count = 0;
|
||||||
|
if (wv->cond->type == EXPR_STRCMP)
|
||||||
|
{
|
||||||
|
MSIITERHANDLE handle = NULL;
|
||||||
|
UINT row, value, col;
|
||||||
|
struct expr *col_cond = wv->cond->u.expr.left;
|
||||||
|
struct expr *val_cond = wv->cond->u.expr.right;
|
||||||
|
|
||||||
|
/* swap conditionals */
|
||||||
|
if (col_cond->type != EXPR_COL_NUMBER_STRING)
|
||||||
|
{
|
||||||
|
val_cond = wv->cond->u.expr.left;
|
||||||
|
col_cond = wv->cond->u.expr.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((col_cond->type == EXPR_COL_NUMBER_STRING) && (val_cond->type == EXPR_SVAL))
|
||||||
|
{
|
||||||
|
col = col_cond->u.col_number;
|
||||||
|
r = msi_string2idW(wv->db->strings, val_cond->u.sval, &value);
|
||||||
|
if (r != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
TRACE("no id for %s, assuming it doesn't exist in the table\n", debugstr_w(wv->cond->u.expr.right->u.sval));
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
r = table->ops->find_matching_rows(table, col, value, &row, &handle);
|
||||||
|
if (r == ERROR_SUCCESS)
|
||||||
|
wv->reorder[ wv->row_count ++ ] = row;
|
||||||
|
} while (r == ERROR_SUCCESS);
|
||||||
|
|
||||||
|
if (r == ERROR_NO_MORE_ITEMS)
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
else
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
/* else fallback to slow case */
|
||||||
|
}
|
||||||
|
|
||||||
for( i=0; i<count; i++ )
|
for( i=0; i<count; i++ )
|
||||||
{
|
{
|
||||||
val = 0;
|
val = 0;
|
||||||
|
@ -341,6 +380,27 @@ static UINT WHERE_delete( struct tagMSIVIEW *view )
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT WHERE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
||||||
|
UINT val, UINT *row, MSIITERHANDLE *handle )
|
||||||
|
{
|
||||||
|
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
|
||||||
|
UINT r;
|
||||||
|
|
||||||
|
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
|
||||||
|
|
||||||
|
if( !wv->table )
|
||||||
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
|
r = wv->table->ops->find_matching_rows( wv->table, col, val, row, handle );
|
||||||
|
|
||||||
|
if( *row > wv->row_count )
|
||||||
|
return ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
|
*row = wv->reorder[ *row ];
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MSIVIEWOPS where_ops =
|
MSIVIEWOPS where_ops =
|
||||||
{
|
{
|
||||||
|
@ -353,7 +413,8 @@ MSIVIEWOPS where_ops =
|
||||||
WHERE_get_dimensions,
|
WHERE_get_dimensions,
|
||||||
WHERE_get_column_info,
|
WHERE_get_column_info,
|
||||||
WHERE_modify,
|
WHERE_modify,
|
||||||
WHERE_delete
|
WHERE_delete,
|
||||||
|
WHERE_find_matching_rows
|
||||||
};
|
};
|
||||||
|
|
||||||
static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
|
static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
|
||||||
|
|
Loading…
Reference in New Issue