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