MSI: Implement queries by string value
Mike McCormack
mike at codeweavers.com
Fri Jun 25 15:01:48 CDT 2004
ChangeLog:
* Implement queries by string value
-------------- next part --------------
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.10
diff -u -r1.10 msipriv.h
--- dlls/msi/msipriv.h 30 Mar 2004 20:42:06 -0000 1.10
+++ dlls/msi/msipriv.h 25 Jun 2004 20:59:22 -0000
@@ -191,6 +191,9 @@
extern UINT msi_string_count( string_table *st );
extern UINT msi_id_refcount( string_table *st, UINT i );
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 );
Index: dlls/msi/query.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/query.h,v
retrieving revision 1.6
diff -u -r1.6 query.h
--- dlls/msi/query.h 20 Mar 2004 19:18:46 -0000 1.6
+++ dlls/msi/query.h 25 Jun 2004 20:59:22 -0000
@@ -48,6 +48,13 @@
#define EXPR_IVAL 4
#define EXPR_SVAL 5
#define EXPR_UVAL 6
+#define EXPR_STRCMP 7
+#define EXPR_UTF8 8
+
+struct sql_str {
+ LPCWSTR data;
+ INT len;
+};
typedef struct _string_list
{
@@ -73,6 +80,7 @@
LPWSTR sval;
LPWSTR column;
UINT col_number;
+ char *utf8;
} u;
};
Index: dlls/msi/sql.y
===================================================================
RCS file: /home/wine/wine/dlls/msi/sql.y,v
retrieving revision 1.8
diff -u -r1.8 sql.y
--- dlls/msi/sql.y 20 Mar 2004 19:18:46 -0000 1.8
+++ dlls/msi/sql.y 25 Jun 2004 20:59:22 -0000
@@ -48,9 +48,10 @@
MSIVIEW **view; /* view structure for the resulting query */
} 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_lex( void *SQL_lval, SQL_input *info);
+static LPWSTR SQL_strdup( struct sql_str *str);
static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
string_list *columns );
@@ -61,9 +62,9 @@
string_list *keys);
static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
-static struct expr * EXPR_column( LPWSTR column );
-static struct expr * EXPR_ival( INT ival );
-static struct expr * EXPR_sval( LPWSTR string );
+static struct expr * EXPR_column( LPWSTR );
+static struct expr * EXPR_ival( struct sql_str *);
+static struct expr * EXPR_sval( struct sql_str *);
%}
@@ -71,6 +72,7 @@
%union
{
+ struct sql_str str;
LPWSTR string;
string_list *column_list;
value_list *val_list;
@@ -92,8 +94,10 @@
%token TK_GE TK_GLOB TK_GROUP TK_GT
%token TK_HAVING TK_HOLD
%token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
-%token <string> TK_ID
-%token TK_INSERT TK_INSTEAD TK_INT TK_INTEGER TK_INTERSECT TK_INTO TK_IS
+%token <str> TK_ID
+%token TK_INSERT TK_INSTEAD TK_INT
+%token <str> TK_INTEGER
+%token TK_INTERSECT TK_INTO TK_IS
%token TK_ISNULL
%token TK_JOIN TK_JOIN_KW
%token TK_KEY
@@ -106,7 +110,7 @@
%token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
%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 <string> TK_STRING
+%token <str> TK_STRING
%token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
%token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
%token TK_UPDATE TK_UPLUS TK_USING
@@ -490,12 +494,11 @@
const_val:
TK_INTEGER
{
- SQL_input* sql = (SQL_input*) info;
- $$ = EXPR_ival( SQL_getint(sql) );
+ $$ = EXPR_ival( &$1 );
}
| TK_STRING
{
- $$ = EXPR_sval( $1 );
+ $$ = EXPR_sval( &$1 );
}
;
@@ -527,13 +530,11 @@
string_or_id:
TK_ID
{
- SQL_input* sql = (SQL_input*) info;
- $$ = SQL_getstring(sql);
+ $$ = SQL_getstring( &$1 );
}
| TK_STRING
{
- SQL_input* sql = (SQL_input*) info;
- $$ = SQL_getstring(sql);
+ $$ = SQL_getstring( &$1 );
}
;
@@ -542,6 +543,7 @@
int SQL_lex( void *SQL_lval, SQL_input *sql)
{
int token;
+ struct sql_str * str = SQL_lval;
do
{
@@ -553,6 +555,8 @@
sql->len = sqliteGetToken( &sql->command[sql->n], &token );
if( sql->len==0 )
break;
+ str->data = &sql->command[sql->n];
+ str->len = sql->len;
}
while( token == TK_SPACE );
@@ -561,11 +565,11 @@
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;
- UINT len = sql->len;
/* if there's quotes, remove them */
if( (p[0]=='`') && (p[len-1]=='`') )
@@ -637,6 +641,16 @@
return view;
}
+#if 0
+static LPWSTR SQL_strdup( struct sql_str *str)
+{
+ LPWSTR ret = HeapAlloc( GetProcessHeap(), 0, (str->len+1)*sizeof(WCHAR) );
+ strncpyW( ret, str->data, str->len );
+ ret[str->len]=0;
+ return ret;
+}
+#endif
+
static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
{
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
@@ -650,35 +664,35 @@
return e;
}
-static struct expr * EXPR_column( LPWSTR column )
+static struct expr * EXPR_column( LPWSTR str )
{
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e )
{
e->type = EXPR_COLUMN;
- e->u.column = column;
+ e->u.sval = str;
}
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 );
if( e )
{
e->type = EXPR_IVAL;
- e->u.ival = ival;
+ e->u.ival = atoiW( str->data );
}
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 );
if( e )
{
e->type = EXPR_SVAL;
- e->u.sval = string;
+ e->u.sval = SQL_getstring( str );
}
return e;
}
@@ -692,6 +706,10 @@
delete_expr( e->u.expr.left );
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 );
}
Index: dlls/msi/string.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/string.c,v
retrieving revision 1.5
diff -u -r1.5 string.c
--- dlls/msi/string.c 15 Jun 2004 20:26:45 -0000 1.5
+++ dlls/msi/string.c 25 Jun 2004 20:59:22 -0000
@@ -208,7 +208,7 @@
}
/* 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 )
return "";
@@ -241,7 +241,7 @@
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 )
return ERROR_FUNCTION_FAILED;
@@ -277,7 +277,7 @@
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 )
return ERROR_FUNCTION_FAILED;
@@ -353,6 +353,23 @@
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 )
{
Index: dlls/msi/where.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/where.c,v
retrieving revision 1.5
diff -u -r1.5 where.c
--- dlls/msi/where.c 20 Mar 2004 19:18:46 -0000 1.5
+++ dlls/msi/where.c 25 Jun 2004 20:59:22 -0000
@@ -95,7 +95,54 @@
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 )
{
UINT r, lval, rval;
@@ -117,15 +164,18 @@
return ERROR_SUCCESS;
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 )
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 )
return r;
*val = INT_evaluate( lval, cond->u.expr.op, rval );
return ERROR_SUCCESS;
+ case EXPR_STRCMP:
+ return STRCMP_Evaluate( db->strings, table, row, cond, val );
+
default:
ERR("Invalid expression type\n");
break;
@@ -161,7 +211,7 @@
for( i=0; i<count; i++ )
{
val = 0;
- r = WHERE_evaluate( table, i, wv->cond, &val );
+ r = WHERE_evaluate( wv->db, table, i, wv->cond, &val );
if( r != ERROR_SUCCESS )
return r;
if( val )
@@ -295,20 +345,21 @@
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 r, col = 0;
+ UINT r, val = 0, len;
+ char *str;
switch( cond->type )
{
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 )
{
*valid = 1;
cond->type = EXPR_COL_NUMBER;
- cond->u.col_number = col;
+ cond->u.col_number = val;
}
else
{
@@ -317,14 +368,35 @@
}
break;
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 )
return r;
if( !*valid )
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 )
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;
case EXPR_IVAL:
*valid = 1;
@@ -332,8 +404,18 @@
cond->u.uval = cond->u.ival + (1<<15);
break;
case EXPR_SVAL:
- *valid = 0;
- FIXME("can't deal with string values yet\n");
+ /* convert to UTF8 so we have the same format as the DB */
+ 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;
default:
ERR("Invalid expression type\n");
@@ -359,7 +441,7 @@
TRACE("Adding condition\n");
- r = WHERE_VerifyCondition( wv->table, cond, &valid );
+ r = WHERE_VerifyCondition( wv->db, wv->table, cond, &valid );
if( r != ERROR_SUCCESS )
ERR("condition evaluation failed\n");
More information about the wine-patches
mailing list