wined3d: Use VBOs for index buffers.
[wine/wine-gecko.git] / dlls / msi / where.c
bloba30ebcb7c983b60cd7a802ec925053799227938c
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002 Mike McCormack for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winerror.h"
26 #include "wine/debug.h"
27 #include "msi.h"
28 #include "msiquery.h"
29 #include "objbase.h"
30 #include "objidl.h"
31 #include "msipriv.h"
32 #include "winnls.h"
34 #include "query.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
39 /* below is the query interface to a table */
41 typedef struct tagMSIWHEREVIEW
43 MSIVIEW view;
44 MSIDATABASE *db;
45 MSIVIEW *table;
46 UINT row_count;
47 UINT *reorder;
48 struct expr *cond;
49 } MSIWHEREVIEW;
51 static UINT WHERE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
53 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
55 TRACE("%p %d %d %p\n", wv, row, col, val );
57 if( !wv->table )
58 return ERROR_FUNCTION_FAILED;
60 if( row > wv->row_count )
61 return ERROR_NO_MORE_ITEMS;
63 row = wv->reorder[ row ];
65 return wv->table->ops->fetch_int( wv->table, row, col, val );
68 static UINT WHERE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
70 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
72 TRACE("%p %d %d %p\n", wv, row, col, stm );
74 if( !wv->table )
75 return ERROR_FUNCTION_FAILED;
77 if( row > wv->row_count )
78 return ERROR_NO_MORE_ITEMS;
80 row = wv->reorder[ row ];
82 return wv->table->ops->fetch_stream( wv->table, row, col, stm );
85 static UINT WHERE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
87 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
89 TRACE("%p %d %p %08x\n", wv, row, rec, mask );
91 if( !wv->table )
92 return ERROR_FUNCTION_FAILED;
94 if( row > wv->row_count )
95 return ERROR_NO_MORE_ITEMS;
97 row = wv->reorder[ row ];
99 return wv->table->ops->set_row( wv->table, row, rec, mask );
102 static INT INT_evaluate_binary( INT lval, UINT op, INT rval )
104 switch( op )
106 case OP_EQ:
107 return ( lval == rval );
108 case OP_AND:
109 return ( lval && rval );
110 case OP_OR:
111 return ( lval || rval );
112 case OP_GT:
113 return ( lval > rval );
114 case OP_LT:
115 return ( lval < rval );
116 case OP_LE:
117 return ( lval <= rval );
118 case OP_GE:
119 return ( lval >= rval );
120 case OP_NE:
121 return ( lval != rval );
122 default:
123 ERR("Unknown operator %d\n", op );
125 return 0;
128 static INT INT_evaluate_unary( INT lval, UINT op )
130 switch( op )
132 case OP_ISNULL:
133 return ( !lval );
134 case OP_NOTNULL:
135 return ( lval );
136 default:
137 ERR("Unknown operator %d\n", op );
139 return 0;
142 static const WCHAR *STRING_evaluate( string_table *st,
143 MSIVIEW *table, UINT row, struct expr *expr, MSIRECORD *record )
145 UINT val = 0, r;
147 switch( expr->type )
149 case EXPR_COL_NUMBER_STRING:
150 r = table->ops->fetch_int( table, row, expr->u.col_number, &val );
151 if( r != ERROR_SUCCESS )
152 return NULL;
153 return msi_string_lookup_id( st, val );
155 case EXPR_SVAL:
156 return expr->u.sval;
158 case EXPR_WILDCARD:
159 return MSI_RecordGetString( record, 1 );
161 default:
162 ERR("Invalid expression type\n");
163 break;
165 return NULL;
168 static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row,
169 struct expr *cond, INT *val, MSIRECORD *record )
171 int sr;
172 const WCHAR *l_str, *r_str;
174 l_str = STRING_evaluate( st, table, row, cond->u.expr.left, record );
175 r_str = STRING_evaluate( st, table, row, cond->u.expr.right, record );
176 if( l_str == r_str )
177 sr = 0;
178 else if( l_str && ! r_str )
179 sr = 1;
180 else if( r_str && ! l_str )
181 sr = -1;
182 else
183 sr = lstrcmpW( l_str, r_str );
185 *val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) ||
186 ( cond->u.expr.op == OP_LT && ( sr < 0 ) ) ||
187 ( cond->u.expr.op == OP_GT && ( sr > 0 ) );
189 return ERROR_SUCCESS;
192 static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row,
193 struct expr *cond, INT *val, MSIRECORD *record )
195 UINT r, tval;
196 INT lval, rval;
198 if( !cond )
199 return ERROR_SUCCESS;
201 switch( cond->type )
203 case EXPR_COL_NUMBER:
204 r = table->ops->fetch_int( table, row, cond->u.col_number, &tval );
205 *val = tval - 0x8000;
206 return ERROR_SUCCESS;
208 case EXPR_COL_NUMBER32:
209 r = table->ops->fetch_int( table, row, cond->u.col_number, &tval );
210 *val = tval - 0x80000000;
211 return r;
213 case EXPR_UVAL:
214 *val = cond->u.uval;
215 return ERROR_SUCCESS;
217 case EXPR_COMPLEX:
218 r = WHERE_evaluate( db, table, row, cond->u.expr.left, &lval, record );
219 if( r != ERROR_SUCCESS )
220 return r;
221 r = WHERE_evaluate( db, table, row, cond->u.expr.right, &rval, record );
222 if( r != ERROR_SUCCESS )
223 return r;
224 *val = INT_evaluate_binary( lval, cond->u.expr.op, rval );
225 return ERROR_SUCCESS;
227 case EXPR_UNARY:
228 r = table->ops->fetch_int( table, row, cond->u.expr.left->u.col_number, &tval );
229 if( r != ERROR_SUCCESS )
230 return r;
231 *val = INT_evaluate_unary( tval, cond->u.expr.op );
232 return ERROR_SUCCESS;
234 case EXPR_STRCMP:
235 return STRCMP_Evaluate( db->strings, table, row, cond, val, record );
237 case EXPR_WILDCARD:
238 *val = MSI_RecordGetInteger( record, 1 );
239 return ERROR_SUCCESS;
241 default:
242 ERR("Invalid expression type\n");
243 break;
246 return ERROR_SUCCESS;
250 static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
252 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
253 UINT count = 0, r, i;
254 INT val;
255 MSIVIEW *table = wv->table;
257 TRACE("%p %p\n", wv, record);
259 if( !table )
260 return ERROR_FUNCTION_FAILED;
262 r = table->ops->execute( table, record );
263 if( r != ERROR_SUCCESS )
264 return r;
266 r = table->ops->get_dimensions( table, &count, NULL );
267 if( r != ERROR_SUCCESS )
268 return r;
270 msi_free( wv->reorder );
271 wv->reorder = msi_alloc( count*sizeof(UINT) );
272 if( !wv->reorder )
273 return ERROR_FUNCTION_FAILED;
275 wv->row_count = 0;
276 if (wv->cond->type == EXPR_STRCMP)
278 MSIITERHANDLE handle = NULL;
279 UINT row, value, col;
280 struct expr *col_cond = wv->cond->u.expr.left;
281 struct expr *val_cond = wv->cond->u.expr.right;
283 /* swap conditionals */
284 if (col_cond->type != EXPR_COL_NUMBER_STRING)
286 val_cond = wv->cond->u.expr.left;
287 col_cond = wv->cond->u.expr.right;
290 if ((col_cond->type == EXPR_COL_NUMBER_STRING) && (val_cond->type == EXPR_SVAL))
292 col = col_cond->u.col_number;
293 /* special case for "" - translate it into nil */
294 if (!val_cond->u.sval[0])
295 value = 0;
296 else
298 r = msi_string2idW(wv->db->strings, val_cond->u.sval, &value);
299 if (r != ERROR_SUCCESS)
301 TRACE("no id for %s, assuming it doesn't exist in the table\n", debugstr_w(wv->cond->u.expr.right->u.sval));
302 return ERROR_SUCCESS;
308 r = table->ops->find_matching_rows(table, col, value, &row, &handle);
309 if (r == ERROR_SUCCESS)
310 wv->reorder[ wv->row_count ++ ] = row;
311 } while (r == ERROR_SUCCESS);
313 if (r == ERROR_NO_MORE_ITEMS)
314 return ERROR_SUCCESS;
315 else
316 return r;
318 /* else fallback to slow case */
321 for( i=0; i<count; i++ )
323 val = 0;
324 r = WHERE_evaluate( wv->db, table, i, wv->cond, &val, record );
325 if( r != ERROR_SUCCESS )
326 return r;
327 if( val )
328 wv->reorder[ wv->row_count ++ ] = i;
331 return ERROR_SUCCESS;
334 static UINT WHERE_close( struct tagMSIVIEW *view )
336 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
338 TRACE("%p\n", wv );
340 if( !wv->table )
341 return ERROR_FUNCTION_FAILED;
343 msi_free( wv->reorder );
344 wv->reorder = NULL;
346 return wv->table->ops->close( wv->table );
349 static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
351 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
353 TRACE("%p %p %p\n", wv, rows, cols );
355 if( !wv->table )
356 return ERROR_FUNCTION_FAILED;
358 if( rows )
360 if( !wv->reorder )
361 return ERROR_FUNCTION_FAILED;
362 *rows = wv->row_count;
365 return wv->table->ops->get_dimensions( wv->table, NULL, cols );
368 static UINT WHERE_get_column_info( struct tagMSIVIEW *view,
369 UINT n, LPWSTR *name, UINT *type )
371 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
373 TRACE("%p %d %p %p\n", wv, n, name, type );
375 if( !wv->table )
376 return ERROR_FUNCTION_FAILED;
378 return wv->table->ops->get_column_info( wv->table, n, name, type );
381 static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
382 MSIRECORD *rec )
384 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
386 TRACE("%p %d %p\n", wv, eModifyMode, rec );
388 if( !wv->table )
389 return ERROR_FUNCTION_FAILED;
391 return wv->table->ops->modify( wv->table, eModifyMode, rec );
394 static UINT WHERE_delete( struct tagMSIVIEW *view )
396 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
398 TRACE("%p\n", wv );
400 if( wv->table )
401 wv->table->ops->delete( wv->table );
402 wv->table = 0;
404 msi_free( wv->reorder );
405 wv->reorder = NULL;
406 wv->row_count = 0;
408 msiobj_release( &wv->db->hdr );
409 msi_free( wv );
411 return ERROR_SUCCESS;
414 static UINT WHERE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
415 UINT val, UINT *row, MSIITERHANDLE *handle )
417 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
418 UINT r;
420 TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
422 if( !wv->table )
423 return ERROR_FUNCTION_FAILED;
425 r = wv->table->ops->find_matching_rows( wv->table, col, val, row, handle );
427 if( *row > wv->row_count )
428 return ERROR_NO_MORE_ITEMS;
430 *row = wv->reorder[ *row ];
432 return r;
436 static const MSIVIEWOPS where_ops =
438 WHERE_fetch_int,
439 WHERE_fetch_stream,
440 WHERE_set_row,
441 NULL,
442 WHERE_execute,
443 WHERE_close,
444 WHERE_get_dimensions,
445 WHERE_get_column_info,
446 WHERE_modify,
447 WHERE_delete,
448 WHERE_find_matching_rows
451 static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
452 UINT *valid )
454 UINT r, val = 0;
456 switch( cond->type )
458 case EXPR_COLUMN:
459 r = VIEW_find_column( table, cond->u.column, &val );
460 if( r == ERROR_SUCCESS )
462 UINT type = 0;
463 r = table->ops->get_column_info( table, val, NULL, &type );
464 if( r == ERROR_SUCCESS )
466 if (type&MSITYPE_STRING)
467 cond->type = EXPR_COL_NUMBER_STRING;
468 else if ((type&0xff) == 4)
469 cond->type = EXPR_COL_NUMBER32;
470 else
471 cond->type = EXPR_COL_NUMBER;
472 cond->u.col_number = val;
473 *valid = 1;
475 else
476 *valid = 0;
478 else
480 *valid = 0;
481 ERR("Couldn't find column %s\n", debugstr_w( cond->u.column ) );
483 break;
484 case EXPR_COMPLEX:
485 r = WHERE_VerifyCondition( db, table, cond->u.expr.left, valid );
486 if( r != ERROR_SUCCESS )
487 return r;
488 if( !*valid )
489 return ERROR_SUCCESS;
490 r = WHERE_VerifyCondition( db, table, cond->u.expr.right, valid );
491 if( r != ERROR_SUCCESS )
492 return r;
494 /* check the type of the comparison */
495 if( ( cond->u.expr.left->type == EXPR_SVAL ) ||
496 ( cond->u.expr.left->type == EXPR_COL_NUMBER_STRING ) ||
497 ( cond->u.expr.right->type == EXPR_SVAL ) ||
498 ( cond->u.expr.right->type == EXPR_COL_NUMBER_STRING ) )
500 switch( cond->u.expr.op )
502 case OP_EQ:
503 case OP_GT:
504 case OP_LT:
505 break;
506 default:
507 *valid = FALSE;
508 return ERROR_INVALID_PARAMETER;
511 /* FIXME: check we're comparing a string to a column */
513 cond->type = EXPR_STRCMP;
516 break;
517 case EXPR_UNARY:
518 if ( cond->u.expr.left->type != EXPR_COLUMN )
520 *valid = FALSE;
521 return ERROR_INVALID_PARAMETER;
523 r = WHERE_VerifyCondition( db, table, cond->u.expr.left, valid );
524 if( r != ERROR_SUCCESS )
525 return r;
526 break;
527 case EXPR_IVAL:
528 *valid = 1;
529 cond->type = EXPR_UVAL;
530 cond->u.uval = cond->u.ival;
531 break;
532 case EXPR_WILDCARD:
533 *valid = 1;
534 break;
535 case EXPR_SVAL:
536 *valid = 1;
537 break;
538 default:
539 ERR("Invalid expression type\n");
540 *valid = 0;
541 break;
544 return ERROR_SUCCESS;
547 UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
548 struct expr *cond )
550 MSIWHEREVIEW *wv = NULL;
551 UINT count = 0, r, valid = 0;
553 TRACE("%p\n", table );
555 r = table->ops->get_dimensions( table, NULL, &count );
556 if( r != ERROR_SUCCESS )
558 ERR("can't get table dimensions\n");
559 return r;
562 if( cond )
564 r = WHERE_VerifyCondition( db, table, cond, &valid );
565 if( r != ERROR_SUCCESS )
566 return r;
567 if( !valid )
568 return ERROR_FUNCTION_FAILED;
571 wv = msi_alloc_zero( sizeof *wv );
572 if( !wv )
573 return ERROR_FUNCTION_FAILED;
575 /* fill the structure */
576 wv->view.ops = &where_ops;
577 msiobj_addref( &db->hdr );
578 wv->db = db;
579 wv->table = table;
580 wv->row_count = 0;
581 wv->reorder = NULL;
582 wv->cond = cond;
583 *view = (MSIVIEW*) wv;
585 return ERROR_SUCCESS;