Implement queries by string value.

This commit is contained in:
Mike McCormack 2004-06-26 00:11:08 +00:00 committed by Alexandre Julliard
parent 495e0c9498
commit 9d66d94780
5 changed files with 156 additions and 39 deletions

View File

@ -191,6 +191,9 @@ extern VOID msi_destroy_stringtable( string_table *st );
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 );

View File

@ -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 @@ struct expr
LPWSTR sval;
LPWSTR column;
UINT col_number;
char *utf8;
} u;
};

View File

@ -48,7 +48,7 @@ typedef struct tag_SQL_input
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);
@ -61,9 +61,9 @@ static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
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 +71,7 @@ static struct expr * EXPR_sval( LPWSTR string );
%union
{
struct sql_str str;
LPWSTR string;
string_list *column_list;
value_list *val_list;
@ -92,8 +93,10 @@ static struct expr * EXPR_sval( LPWSTR string );
%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 +109,7 @@ static struct expr * EXPR_sval( LPWSTR string );
%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 +493,11 @@ constlist:
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 +529,11 @@ table:
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 +542,7 @@ string_or_id:
int SQL_lex( void *SQL_lval, SQL_input *sql)
{
int token;
struct sql_str * str = SQL_lval;
do
{
@ -553,6 +554,8 @@ int SQL_lex( void *SQL_lval, SQL_input *sql)
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 +564,11 @@ int SQL_lex( void *SQL_lval, SQL_input *sql)
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]=='`') )
@ -650,35 +653,35 @@ static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
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 +695,10 @@ void delete_expr( struct expr *e )
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 );
}

View File

@ -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 */
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 @@ UINT msi_id2stringW( string_table *st, UINT id, LPWSTR buffer, UINT *sz )
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 @@ UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz )
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 @@ UINT msi_string2id( string_table *st, LPCWSTR buffer, UINT *id )
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 )
{

View File

@ -95,7 +95,54 @@ static UINT INT_evaluate( UINT lval, UINT op, UINT rval )
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 @@ static UINT WHERE_evaluate( MSIVIEW *table, UINT row,
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 @@ static UINT WHERE_execute( struct tagMSIVIEW *view, MSIHANDLE record )
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 @@ UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
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 @@ static UINT WHERE_VerifyCondition( MSIVIEW *table, struct expr *cond,
}
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 @@ static UINT WHERE_VerifyCondition( MSIVIEW *table, struct expr *cond,
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 @@ UINT WHERE_AddCondition( MSIVIEW *view, struct expr *cond )
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");