Commit 9d66d947 authored by Mike McCormack's avatar Mike McCormack Committed by Alexandre Julliard

Implement queries by string value.

parent 495e0c94
...@@ -191,6 +191,9 @@ extern VOID msi_destroy_stringtable( string_table *st ); ...@@ -191,6 +191,9 @@ extern VOID msi_destroy_stringtable( string_table *st );
extern UINT msi_string_count( string_table *st ); extern UINT msi_string_count( string_table *st );
extern UINT msi_id_refcount( string_table *st, UINT i ); extern UINT msi_id_refcount( string_table *st, UINT i );
extern UINT msi_string_totalsize( string_table *st ); extern UINT msi_string_totalsize( string_table *st );
extern UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res );
extern const char *msi_string_lookup_id( string_table *st, UINT id );
UINT VIEW_find_column( MSIVIEW *view, LPWSTR name, UINT *n ); UINT VIEW_find_column( MSIVIEW *view, LPWSTR name, UINT *n );
......
...@@ -48,6 +48,13 @@ ...@@ -48,6 +48,13 @@
#define EXPR_IVAL 4 #define EXPR_IVAL 4
#define EXPR_SVAL 5 #define EXPR_SVAL 5
#define EXPR_UVAL 6 #define EXPR_UVAL 6
#define EXPR_STRCMP 7
#define EXPR_UTF8 8
struct sql_str {
LPCWSTR data;
INT len;
};
typedef struct _string_list typedef struct _string_list
{ {
...@@ -73,6 +80,7 @@ struct expr ...@@ -73,6 +80,7 @@ struct expr
LPWSTR sval; LPWSTR sval;
LPWSTR column; LPWSTR column;
UINT col_number; UINT col_number;
char *utf8;
} u; } u;
}; };
......
...@@ -48,7 +48,7 @@ typedef struct tag_SQL_input ...@@ -48,7 +48,7 @@ typedef struct tag_SQL_input
MSIVIEW **view; /* view structure for the resulting query */ MSIVIEW **view; /* view structure for the resulting query */
} SQL_input; } SQL_input;
static LPWSTR SQL_getstring( SQL_input *info ); static LPWSTR SQL_getstring( struct sql_str *str );
static INT SQL_getint( SQL_input *sql ); static INT SQL_getint( SQL_input *sql );
static int SQL_lex( void *SQL_lval, SQL_input *info); static int SQL_lex( void *SQL_lval, SQL_input *info);
...@@ -61,9 +61,9 @@ static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, ...@@ -61,9 +61,9 @@ static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
string_list *keys); string_list *keys);
static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ); static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
static struct expr * EXPR_column( LPWSTR column ); static struct expr * EXPR_column( LPWSTR );
static struct expr * EXPR_ival( INT ival ); static struct expr * EXPR_ival( struct sql_str *);
static struct expr * EXPR_sval( LPWSTR string ); static struct expr * EXPR_sval( struct sql_str *);
%} %}
...@@ -71,6 +71,7 @@ static struct expr * EXPR_sval( LPWSTR string ); ...@@ -71,6 +71,7 @@ static struct expr * EXPR_sval( LPWSTR string );
%union %union
{ {
struct sql_str str;
LPWSTR string; LPWSTR string;
string_list *column_list; string_list *column_list;
value_list *val_list; value_list *val_list;
...@@ -92,8 +93,10 @@ static struct expr * EXPR_sval( LPWSTR string ); ...@@ -92,8 +93,10 @@ static struct expr * EXPR_sval( LPWSTR string );
%token TK_GE TK_GLOB TK_GROUP TK_GT %token TK_GE TK_GLOB TK_GROUP TK_GT
%token TK_HAVING TK_HOLD %token TK_HAVING TK_HOLD
%token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY %token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
%token <string> TK_ID %token <str> TK_ID
%token TK_INSERT TK_INSTEAD TK_INT TK_INTEGER TK_INTERSECT TK_INTO TK_IS %token TK_INSERT TK_INSTEAD TK_INT
%token <str> TK_INTEGER
%token TK_INTERSECT TK_INTO TK_IS
%token TK_ISNULL %token TK_ISNULL
%token TK_JOIN TK_JOIN_KW %token TK_JOIN TK_JOIN_KW
%token TK_KEY %token TK_KEY
...@@ -106,7 +109,7 @@ static struct expr * EXPR_sval( LPWSTR string ); ...@@ -106,7 +109,7 @@ static struct expr * EXPR_sval( LPWSTR string );
%token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK %token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
%token TK_ROW TK_RP TK_RSHIFT %token TK_ROW TK_RP TK_RSHIFT
%token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT %token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
%token <string> TK_STRING %token <str> TK_STRING
%token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER %token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
%token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE %token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
%token TK_UPDATE TK_UPLUS TK_USING %token TK_UPDATE TK_UPLUS TK_USING
...@@ -490,12 +493,11 @@ constlist: ...@@ -490,12 +493,11 @@ constlist:
const_val: const_val:
TK_INTEGER TK_INTEGER
{ {
SQL_input* sql = (SQL_input*) info; $$ = EXPR_ival( &$1 );
$$ = EXPR_ival( SQL_getint(sql) );
} }
| TK_STRING | TK_STRING
{ {
$$ = EXPR_sval( $1 ); $$ = EXPR_sval( &$1 );
} }
; ;
...@@ -527,13 +529,11 @@ table: ...@@ -527,13 +529,11 @@ table:
string_or_id: string_or_id:
TK_ID TK_ID
{ {
SQL_input* sql = (SQL_input*) info; $$ = SQL_getstring( &$1 );
$$ = SQL_getstring(sql);
} }
| TK_STRING | TK_STRING
{ {
SQL_input* sql = (SQL_input*) info; $$ = SQL_getstring( &$1 );
$$ = SQL_getstring(sql);
} }
; ;
...@@ -542,6 +542,7 @@ string_or_id: ...@@ -542,6 +542,7 @@ string_or_id:
int SQL_lex( void *SQL_lval, SQL_input *sql) int SQL_lex( void *SQL_lval, SQL_input *sql)
{ {
int token; int token;
struct sql_str * str = SQL_lval;
do do
{ {
...@@ -553,6 +554,8 @@ int SQL_lex( void *SQL_lval, SQL_input *sql) ...@@ -553,6 +554,8 @@ int SQL_lex( void *SQL_lval, SQL_input *sql)
sql->len = sqliteGetToken( &sql->command[sql->n], &token ); sql->len = sqliteGetToken( &sql->command[sql->n], &token );
if( sql->len==0 ) if( sql->len==0 )
break; break;
str->data = &sql->command[sql->n];
str->len = sql->len;
} }
while( token == TK_SPACE ); while( token == TK_SPACE );
...@@ -561,11 +564,11 @@ int SQL_lex( void *SQL_lval, SQL_input *sql) ...@@ -561,11 +564,11 @@ int SQL_lex( void *SQL_lval, SQL_input *sql)
return token; return token;
} }
LPWSTR SQL_getstring( SQL_input *sql ) LPWSTR SQL_getstring( struct sql_str *strdata)
{ {
LPCWSTR p = &sql->command[sql->n]; LPCWSTR p = strdata->data;
UINT len = strdata->len;
LPWSTR str; LPWSTR str;
UINT len = sql->len;
/* if there's quotes, remove them */ /* if there's quotes, remove them */
if( (p[0]=='`') && (p[len-1]=='`') ) if( (p[0]=='`') && (p[len-1]=='`') )
...@@ -650,35 +653,35 @@ static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ) ...@@ -650,35 +653,35 @@ static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
return e; return e;
} }
static struct expr * EXPR_column( LPWSTR column ) static struct expr * EXPR_column( LPWSTR str )
{ {
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e ) if( e )
{ {
e->type = EXPR_COLUMN; e->type = EXPR_COLUMN;
e->u.column = column; e->u.sval = str;
} }
return e; return e;
} }
static struct expr * EXPR_ival( INT ival ) static struct expr * EXPR_ival( struct sql_str *str )
{ {
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e ) if( e )
{ {
e->type = EXPR_IVAL; e->type = EXPR_IVAL;
e->u.ival = ival; e->u.ival = atoiW( str->data );
} }
return e; return e;
} }
static struct expr * EXPR_sval( LPWSTR string ) static struct expr * EXPR_sval( struct sql_str *str )
{ {
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e ) if( e )
{ {
e->type = EXPR_SVAL; e->type = EXPR_SVAL;
e->u.sval = string; e->u.sval = SQL_getstring( str );
} }
return e; return e;
} }
...@@ -692,6 +695,10 @@ void delete_expr( struct expr *e ) ...@@ -692,6 +695,10 @@ void delete_expr( struct expr *e )
delete_expr( e->u.expr.left ); delete_expr( e->u.expr.left );
delete_expr( e->u.expr.right ); delete_expr( e->u.expr.right );
} }
else if( e->type == EXPR_UTF8 )
HeapFree( GetProcessHeap(), 0, e->u.utf8 );
else if( e->type == EXPR_SVAL )
HeapFree( GetProcessHeap(), 0, e->u.sval );
HeapFree( GetProcessHeap(), 0, e ); HeapFree( GetProcessHeap(), 0, e );
} }
......
...@@ -208,7 +208,7 @@ int msi_addstringW( string_table *st, UINT n, const WCHAR *data, UINT len, UINT ...@@ -208,7 +208,7 @@ int msi_addstringW( string_table *st, UINT n, const WCHAR *data, UINT len, UINT
} }
/* find the string identified by an id - return null if there's none */ /* find the string identified by an id - return null if there's none */
static const char *string_lookup_id( string_table *st, UINT id ) const char *msi_string_lookup_id( string_table *st, UINT id )
{ {
if( id == 0 ) if( id == 0 )
return ""; return "";
...@@ -241,7 +241,7 @@ UINT msi_id2stringW( string_table *st, UINT id, LPWSTR buffer, UINT *sz ) ...@@ -241,7 +241,7 @@ UINT msi_id2stringW( string_table *st, UINT id, LPWSTR buffer, UINT *sz )
TRACE("Finding string %d of %d\n", id, st->count); TRACE("Finding string %d of %d\n", id, st->count);
str = string_lookup_id( st, id ); str = msi_string_lookup_id( st, id );
if( !str ) if( !str )
return ERROR_FUNCTION_FAILED; return ERROR_FUNCTION_FAILED;
...@@ -277,7 +277,7 @@ UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz ) ...@@ -277,7 +277,7 @@ UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz )
TRACE("Finding string %d of %d\n", id, st->count); TRACE("Finding string %d of %d\n", id, st->count);
str = string_lookup_id( st, id ); str = msi_string_lookup_id( st, id );
if( !str ) if( !str )
return ERROR_FUNCTION_FAILED; return ERROR_FUNCTION_FAILED;
...@@ -353,6 +353,23 @@ UINT msi_string2id( string_table *st, LPCWSTR buffer, UINT *id ) ...@@ -353,6 +353,23 @@ UINT msi_string2id( string_table *st, LPCWSTR buffer, UINT *id )
return r; return r;
} }
UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res )
{
const char *l_str, *r_str; /* utf8 */
l_str = msi_string_lookup_id( st, lval );
if( !l_str )
return ERROR_INVALID_PARAMETER;
r_str = msi_string_lookup_id( st, rval );
if( !r_str )
return ERROR_INVALID_PARAMETER;
/* does this do the right thing for all UTF-8 strings? */
*res = strcmp( l_str, r_str );
return ERROR_SUCCESS;
}
UINT msi_string_count( string_table *st ) UINT msi_string_count( string_table *st )
{ {
......
...@@ -95,7 +95,54 @@ static UINT INT_evaluate( UINT lval, UINT op, UINT rval ) ...@@ -95,7 +95,54 @@ static UINT INT_evaluate( UINT lval, UINT op, UINT rval )
return 0; return 0;
} }
static UINT WHERE_evaluate( MSIVIEW *table, UINT row, static const char *STRING_evaluate( string_table *st,
MSIVIEW *table, UINT row, struct expr *expr )
{
UINT val = 0, r;
switch( expr->type )
{
case EXPR_COL_NUMBER:
r = table->ops->fetch_int( table, row, expr->u.col_number, &val );
if( r != ERROR_SUCCESS )
return NULL;
return msi_string_lookup_id( st, val );
case EXPR_UTF8:
return expr->u.utf8;
default:
ERR("Invalid expression type\n");
break;
}
return NULL;
}
static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row,
struct expr *cond, UINT *val )
{
int sr;
const char *l_str, *r_str;
l_str = STRING_evaluate( st, table, row, cond->u.expr.left );
r_str = STRING_evaluate( st, table, row, cond->u.expr.right );
if( l_str == r_str )
sr = 0;
else if( l_str && ! r_str )
sr = 1;
else if( r_str && ! l_str )
sr = -1;
else
sr = strcmp( l_str, r_str );
*val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) ||
( cond->u.expr.op == OP_LT && ( sr < 0 ) ) ||
( cond->u.expr.op == OP_GT && ( sr > 0 ) );
return ERROR_SUCCESS;
}
static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row,
struct expr *cond, UINT *val ) struct expr *cond, UINT *val )
{ {
UINT r, lval, rval; UINT r, lval, rval;
...@@ -117,15 +164,18 @@ static UINT WHERE_evaluate( MSIVIEW *table, UINT row, ...@@ -117,15 +164,18 @@ static UINT WHERE_evaluate( MSIVIEW *table, UINT row,
return ERROR_SUCCESS; return ERROR_SUCCESS;
case EXPR_COMPLEX: case EXPR_COMPLEX:
r = WHERE_evaluate( table, row, cond->u.expr.left, &lval ); r = WHERE_evaluate( db, table, row, cond->u.expr.left, &lval );
if( r != ERROR_SUCCESS ) if( r != ERROR_SUCCESS )
return r; return r;
r = WHERE_evaluate( table, row, cond->u.expr.right, &rval ); r = WHERE_evaluate( db, table, row, cond->u.expr.right, &rval );
if( r != ERROR_SUCCESS ) if( r != ERROR_SUCCESS )
return r; return r;
*val = INT_evaluate( lval, cond->u.expr.op, rval ); *val = INT_evaluate( lval, cond->u.expr.op, rval );
return ERROR_SUCCESS; return ERROR_SUCCESS;
case EXPR_STRCMP:
return STRCMP_Evaluate( db->strings, table, row, cond, val );
default: default:
ERR("Invalid expression type\n"); ERR("Invalid expression type\n");
break; break;
...@@ -161,7 +211,7 @@ static UINT WHERE_execute( struct tagMSIVIEW *view, MSIHANDLE record ) ...@@ -161,7 +211,7 @@ static UINT WHERE_execute( struct tagMSIVIEW *view, MSIHANDLE record )
for( i=0; i<count; i++ ) for( i=0; i<count; i++ )
{ {
val = 0; val = 0;
r = WHERE_evaluate( table, i, wv->cond, &val ); r = WHERE_evaluate( wv->db, table, i, wv->cond, &val );
if( r != ERROR_SUCCESS ) if( r != ERROR_SUCCESS )
return r; return r;
if( val ) if( val )
...@@ -295,20 +345,21 @@ UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ) ...@@ -295,20 +345,21 @@ UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
static UINT WHERE_VerifyCondition( MSIVIEW *table, struct expr *cond, static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
UINT *valid ) UINT *valid )
{ {
UINT r, col = 0; UINT r, val = 0, len;
char *str;
switch( cond->type ) switch( cond->type )
{ {
case EXPR_COLUMN: case EXPR_COLUMN:
r = VIEW_find_column( table, cond->u.column, &col ); r = VIEW_find_column( table, cond->u.column, &val );
if( r == ERROR_SUCCESS ) if( r == ERROR_SUCCESS )
{ {
*valid = 1; *valid = 1;
cond->type = EXPR_COL_NUMBER; cond->type = EXPR_COL_NUMBER;
cond->u.col_number = col; cond->u.col_number = val;
} }
else else
{ {
...@@ -317,14 +368,35 @@ static UINT WHERE_VerifyCondition( MSIVIEW *table, struct expr *cond, ...@@ -317,14 +368,35 @@ static UINT WHERE_VerifyCondition( MSIVIEW *table, struct expr *cond,
} }
break; break;
case EXPR_COMPLEX: case EXPR_COMPLEX:
r = WHERE_VerifyCondition( table, cond->u.expr.left, valid ); r = WHERE_VerifyCondition( db, table, cond->u.expr.left, valid );
if( r != ERROR_SUCCESS ) if( r != ERROR_SUCCESS )
return r; return r;
if( !*valid ) if( !*valid )
return ERROR_SUCCESS; return ERROR_SUCCESS;
r = WHERE_VerifyCondition( table, cond->u.expr.right, valid ); r = WHERE_VerifyCondition( db, table, cond->u.expr.right, valid );
if( r != ERROR_SUCCESS ) if( r != ERROR_SUCCESS )
return r; return r;
/* check the type of the comparison */
if( ( cond->u.expr.left->type == EXPR_UTF8 ) ||
( cond->u.expr.right->type == EXPR_UTF8 ) )
{
switch( cond->u.expr.op )
{
case OP_EQ:
case OP_GT:
case OP_LT:
break;
default:
*valid = FALSE;
return ERROR_INVALID_PARAMETER;
}
/* FIXME: check we're comparing a string to a column */
cond->type = EXPR_STRCMP;
}
break; break;
case EXPR_IVAL: case EXPR_IVAL:
*valid = 1; *valid = 1;
...@@ -332,8 +404,18 @@ static UINT WHERE_VerifyCondition( MSIVIEW *table, struct expr *cond, ...@@ -332,8 +404,18 @@ static UINT WHERE_VerifyCondition( MSIVIEW *table, struct expr *cond,
cond->u.uval = cond->u.ival + (1<<15); cond->u.uval = cond->u.ival + (1<<15);
break; break;
case EXPR_SVAL: case EXPR_SVAL:
*valid = 0; /* convert to UTF8 so we have the same format as the DB */
FIXME("can't deal with string values yet\n"); len = WideCharToMultiByte( CP_UTF8, 0,
cond->u.sval, -1, NULL, 0, NULL, NULL);
str = HeapAlloc( GetProcessHeap(), 0, len );
if( !str )
return ERROR_OUTOFMEMORY;
WideCharToMultiByte( CP_UTF8, 0,
cond->u.sval, -1, str, len, NULL, NULL);
HeapFree( GetProcessHeap(), 0, cond->u.sval );
cond->type = EXPR_UTF8;
cond->u.utf8 = str;
*valid = 1;
break; break;
default: default:
ERR("Invalid expression type\n"); ERR("Invalid expression type\n");
...@@ -359,7 +441,7 @@ UINT WHERE_AddCondition( MSIVIEW *view, struct expr *cond ) ...@@ -359,7 +441,7 @@ UINT WHERE_AddCondition( MSIVIEW *view, struct expr *cond )
TRACE("Adding condition\n"); TRACE("Adding condition\n");
r = WHERE_VerifyCondition( wv->table, cond, &valid ); r = WHERE_VerifyCondition( wv->db, wv->table, cond, &valid );
if( r != ERROR_SUCCESS ) if( r != ERROR_SUCCESS )
ERR("condition evaluation failed\n"); ERR("condition evaluation failed\n");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment