If using the default values, also set dwType to REG_SZ as our default
[wine] / dlls / msi / where.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002 Mike McCormack for CodeWeavers
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
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"
33
34 #include "query.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(msi);
37
38
39 /* below is the query interface to a table */
40
41 typedef struct tagMSIWHEREVIEW
42 {
43     MSIVIEW        view;
44     MSIDATABASE   *db;
45     MSIVIEW       *table;
46     UINT           row_count;
47     UINT          *reorder;
48     struct expr   *cond;
49 } MSIWHEREVIEW;
50
51 static UINT WHERE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
52 {
53     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
54
55     TRACE("%p %d %d %p\n", wv, row, col, val );
56
57     if( !wv->table )
58         return ERROR_FUNCTION_FAILED;
59
60     if( row > wv->row_count )
61         return ERROR_NO_MORE_ITEMS;
62
63     row = wv->reorder[ row ];
64
65     return wv->table->ops->fetch_int( wv->table, row, col, val );
66 }
67
68 static UINT INT_evaluate( UINT lval, UINT op, UINT rval )
69 {
70     switch( op )
71     {
72     case OP_EQ:
73         return ( lval == rval );
74     case OP_AND:
75         return ( lval && rval );
76     case OP_OR:
77         return ( lval || rval );
78     case OP_GT:
79         return ( lval > rval );
80     case OP_LT:
81         return ( lval < rval );
82     case OP_LE:
83         return ( lval <= rval );
84     case OP_GE:
85         return ( lval >= rval );
86     case OP_NE:
87         return ( lval != rval );
88     case OP_ISNULL:
89         return ( !lval );
90     case OP_NOTNULL:
91         return ( lval );
92     default:
93         ERR("Unknown operator %d\n", op );
94     }
95     return 0;
96 }
97
98 static UINT WHERE_evaluate( MSIVIEW *table, UINT row, 
99                              struct expr *cond, UINT *val )
100 {
101     UINT r, lval, rval;
102
103     if( !cond )
104         return ERROR_SUCCESS;
105
106     switch( cond->type )
107     {
108     case EXPR_COL_NUMBER:
109         return table->ops->fetch_int( table, row, cond->u.col_number, val );
110
111     /* case EXPR_IVAL:
112         *val = cond->u.ival;
113         return ERROR_SUCCESS; */
114
115     case EXPR_UVAL:
116         *val = cond->u.uval;
117         return ERROR_SUCCESS;
118
119     case EXPR_COMPLEX:
120         r = WHERE_evaluate( table, row, cond->u.expr.left, &lval );
121         if( r != ERROR_SUCCESS )
122             return r;
123         r = WHERE_evaluate( table, row, cond->u.expr.right, &rval );
124         if( r != ERROR_SUCCESS )
125             return r;
126         *val = INT_evaluate( lval, cond->u.expr.op, rval );
127         return ERROR_SUCCESS;
128
129     default:
130         ERR("Invalid expression type\n");
131         break;
132     } 
133
134     return ERROR_SUCCESS;
135
136 }
137
138 static UINT WHERE_execute( struct tagMSIVIEW *view, MSIHANDLE record )
139 {
140     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
141     UINT count = 0, r, val, i;
142     MSIVIEW *table = wv->table;
143
144     TRACE("%p %ld\n", wv, record);
145
146     if( !table )
147          return ERROR_FUNCTION_FAILED;
148
149     r = table->ops->execute( table, record );
150     if( r != ERROR_SUCCESS )
151         return r;
152
153     r = table->ops->get_dimensions( table, &count, NULL );
154     if( r != ERROR_SUCCESS )
155         return r;
156
157     wv->reorder = HeapAlloc( GetProcessHeap(), 0, count*sizeof(UINT) );
158     if( !wv->reorder )
159         return ERROR_FUNCTION_FAILED;
160
161     for( i=0; i<count; i++ )
162     {
163         val = 0;
164         r = WHERE_evaluate( table, i, wv->cond, &val );
165         if( r != ERROR_SUCCESS )
166             return r;
167         if( val )
168             wv->reorder[ wv->row_count ++ ] = i;
169     }
170
171     return ERROR_SUCCESS;
172 }
173
174 static UINT WHERE_close( struct tagMSIVIEW *view )
175 {
176     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
177
178     TRACE("%p\n", wv );
179
180     if( !wv->table )
181          return ERROR_FUNCTION_FAILED;
182
183     if( wv->reorder )
184         HeapFree( GetProcessHeap(), 0, wv->reorder );
185     wv->reorder = NULL;
186
187     return wv->table->ops->close( wv->table );
188 }
189
190 static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
191 {
192     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
193
194     TRACE("%p %p %p\n", wv, rows, cols );
195
196     if( !wv->table )
197          return ERROR_FUNCTION_FAILED;
198
199     if( rows )
200     {
201         if( !wv->reorder )
202             return ERROR_FUNCTION_FAILED;
203         *rows = wv->row_count;
204     }
205
206     return wv->table->ops->get_dimensions( wv->table, NULL, cols );
207 }
208
209 static UINT WHERE_get_column_info( struct tagMSIVIEW *view,
210                 UINT n, LPWSTR *name, UINT *type )
211 {
212     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
213
214     TRACE("%p %d %p %p\n", wv, n, name, type );
215
216     if( !wv->table )
217          return ERROR_FUNCTION_FAILED;
218
219     return wv->table->ops->get_column_info( wv->table, n, name, type );
220 }
221
222 static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
223 {
224     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
225
226     TRACE("%p %d %ld\n", wv, eModifyMode, hrec );
227
228     if( !wv->table )
229          return ERROR_FUNCTION_FAILED;
230
231     return wv->table->ops->modify( wv->table, eModifyMode, hrec );
232 }
233
234 static void WHERE_delete_expr( struct expr *e )
235 {
236     if( !e )
237         return;
238     if( e->type == EXPR_COMPLEX )
239     {
240         WHERE_delete_expr( e->u.expr.left );
241         WHERE_delete_expr( e->u.expr.right );
242     }
243     HeapFree( GetProcessHeap(), 0, e );
244 }
245
246 static UINT WHERE_delete( struct tagMSIVIEW *view )
247 {
248     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
249
250     TRACE("%p\n", wv );
251
252     if( wv->table )
253         wv->table->ops->delete( wv->table );
254
255     if( wv->reorder )
256         HeapFree( GetProcessHeap(), 0, wv->reorder );
257     wv->reorder = NULL;
258     wv->row_count = 0;
259
260     WHERE_delete_expr( wv->cond );
261
262     HeapFree( GetProcessHeap(), 0, wv );
263
264     return ERROR_SUCCESS;
265 }
266
267
268 MSIVIEWOPS where_ops =
269 {
270     WHERE_fetch_int,
271     WHERE_execute,
272     WHERE_close,
273     WHERE_get_dimensions,
274     WHERE_get_column_info,
275     WHERE_modify,
276     WHERE_delete
277 };
278
279 UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
280 {
281     MSIWHEREVIEW *wv = NULL;
282     UINT count = 0, r;
283
284     TRACE("%p\n", wv );
285
286     r = table->ops->get_dimensions( table, NULL, &count );
287     if( r != ERROR_SUCCESS )
288     {
289         ERR("can't get table dimensions\n");
290         return r;
291     }
292
293     wv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *wv );
294     if( !wv )
295         return ERROR_FUNCTION_FAILED;
296     
297     /* fill the structure */
298     wv->view.ops = &where_ops;
299     wv->db = db;
300     wv->table = table;
301     wv->row_count = 0;
302     wv->reorder = NULL;
303     *view = (MSIVIEW*) wv;
304
305     return ERROR_SUCCESS;
306 }
307
308 static UINT WHERE_VerifyCondition( MSIVIEW *table, struct expr *cond,
309                                    UINT *valid )
310 {
311     UINT r, col = 0;
312
313     switch( cond->type )
314     {
315     case EXPR_COLUMN:
316         r = VIEW_find_column( table, cond->u.column, &col );
317         if( r == ERROR_SUCCESS )
318         {
319             *valid = 1;
320             cond->type = EXPR_COL_NUMBER;
321             cond->u.col_number = col;
322         }
323         else
324         {
325             *valid = 0;
326             ERR("Couldn't find column %s\n", debugstr_w( cond->u.column ) );
327         }
328         break;
329     case EXPR_COMPLEX:
330         r = WHERE_VerifyCondition( table, cond->u.expr.left, valid );
331         if( r != ERROR_SUCCESS )
332             return r;
333         if( !*valid )
334             return ERROR_SUCCESS;
335         r = WHERE_VerifyCondition( table, cond->u.expr.right, valid );
336         if( r != ERROR_SUCCESS )
337             return r;
338         break;
339     case EXPR_IVAL:
340         *valid = 1;
341         cond->type = EXPR_UVAL;
342         cond->u.uval = cond->u.ival + (1<<15);
343         break;
344     case EXPR_SVAL:
345         *valid = 0;
346         FIXME("can't deal with string values yet\n");
347         break;
348     default:
349         ERR("Invalid expression type\n");
350         *valid = 0;
351         break;
352     } 
353
354     return ERROR_SUCCESS;
355 }
356
357 UINT WHERE_AddCondition( MSIVIEW *view, struct expr *cond )
358 {
359     MSIWHEREVIEW *wv = (MSIWHEREVIEW *) view;
360     UINT r, valid = 0;
361
362     if( wv->view.ops != &where_ops )
363         return ERROR_FUNCTION_FAILED;
364     if( !wv->table )
365         return ERROR_INVALID_PARAMETER;
366     
367     if( !cond )
368         return ERROR_SUCCESS;
369
370     TRACE("Adding condition\n");
371
372     r = WHERE_VerifyCondition( wv->table, cond, &valid );
373     if( r != ERROR_SUCCESS )
374         ERR("condition evaluation failed\n");
375
376     TRACE("condition is %s\n", valid ? "valid" : "invalid" );
377     if( !valid )
378     {
379         WHERE_delete_expr( cond );
380         return ERROR_FUNCTION_FAILED;
381     }
382
383     wv->cond = cond;
384
385     return ERROR_SUCCESS;
386 }