xref: /reactos/dll/win32/msi/where.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * Implementation of the Microsoft Installer (msi.dll)
3*c2c66affSColin Finck  *
4*c2c66affSColin Finck  * Copyright 2002 Mike McCormack for CodeWeavers
5*c2c66affSColin Finck  * Copyright 2011 Bernhard Loos
6*c2c66affSColin Finck  *
7*c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
8*c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
9*c2c66affSColin Finck  * License as published by the Free Software Foundation; either
10*c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
11*c2c66affSColin Finck  *
12*c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
13*c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15*c2c66affSColin Finck  * Lesser General Public License for more details.
16*c2c66affSColin Finck  *
17*c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
18*c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
19*c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20*c2c66affSColin Finck  */
21*c2c66affSColin Finck 
22*c2c66affSColin Finck #include "msipriv.h"
23*c2c66affSColin Finck 
24*c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(msidb);
25*c2c66affSColin Finck 
26*c2c66affSColin Finck /* below is the query interface to a table */
27*c2c66affSColin Finck typedef struct tagMSIROWENTRY
28*c2c66affSColin Finck {
29*c2c66affSColin Finck     struct tagMSIWHEREVIEW *wv; /* used during sorting */
30*c2c66affSColin Finck     UINT values[1];
31*c2c66affSColin Finck } MSIROWENTRY;
32*c2c66affSColin Finck 
33*c2c66affSColin Finck typedef struct tagJOINTABLE
34*c2c66affSColin Finck {
35*c2c66affSColin Finck     struct tagJOINTABLE *next;
36*c2c66affSColin Finck     MSIVIEW *view;
37*c2c66affSColin Finck     UINT col_count;
38*c2c66affSColin Finck     UINT row_count;
39*c2c66affSColin Finck     UINT table_index;
40*c2c66affSColin Finck } JOINTABLE;
41*c2c66affSColin Finck 
42*c2c66affSColin Finck typedef struct tagMSIORDERINFO
43*c2c66affSColin Finck {
44*c2c66affSColin Finck     UINT col_count;
45*c2c66affSColin Finck     UINT error;
46*c2c66affSColin Finck     union ext_column columns[1];
47*c2c66affSColin Finck } MSIORDERINFO;
48*c2c66affSColin Finck 
49*c2c66affSColin Finck typedef struct tagMSIWHEREVIEW
50*c2c66affSColin Finck {
51*c2c66affSColin Finck     MSIVIEW        view;
52*c2c66affSColin Finck     MSIDATABASE   *db;
53*c2c66affSColin Finck     JOINTABLE     *tables;
54*c2c66affSColin Finck     UINT           row_count;
55*c2c66affSColin Finck     UINT           col_count;
56*c2c66affSColin Finck     UINT           table_count;
57*c2c66affSColin Finck     MSIROWENTRY  **reorder;
58*c2c66affSColin Finck     UINT           reorder_size; /* number of entries available in reorder */
59*c2c66affSColin Finck     struct expr   *cond;
60*c2c66affSColin Finck     UINT           rec_index;
61*c2c66affSColin Finck     MSIORDERINFO  *order_info;
62*c2c66affSColin Finck } MSIWHEREVIEW;
63*c2c66affSColin Finck 
64*c2c66affSColin Finck static UINT WHERE_evaluate( MSIWHEREVIEW *wv, const UINT rows[],
65*c2c66affSColin Finck                             struct expr *cond, INT *val, MSIRECORD *record );
66*c2c66affSColin Finck 
67*c2c66affSColin Finck #define INITIAL_REORDER_SIZE 16
68*c2c66affSColin Finck 
69*c2c66affSColin Finck #define INVALID_ROW_INDEX (-1)
70*c2c66affSColin Finck 
71*c2c66affSColin Finck static void free_reorder(MSIWHEREVIEW *wv)
72*c2c66affSColin Finck {
73*c2c66affSColin Finck     UINT i;
74*c2c66affSColin Finck 
75*c2c66affSColin Finck     if (!wv->reorder)
76*c2c66affSColin Finck         return;
77*c2c66affSColin Finck 
78*c2c66affSColin Finck     for (i = 0; i < wv->row_count; i++)
79*c2c66affSColin Finck         msi_free(wv->reorder[i]);
80*c2c66affSColin Finck 
81*c2c66affSColin Finck     msi_free( wv->reorder );
82*c2c66affSColin Finck     wv->reorder = NULL;
83*c2c66affSColin Finck     wv->reorder_size = 0;
84*c2c66affSColin Finck     wv->row_count = 0;
85*c2c66affSColin Finck }
86*c2c66affSColin Finck 
87*c2c66affSColin Finck static UINT init_reorder(MSIWHEREVIEW *wv)
88*c2c66affSColin Finck {
89*c2c66affSColin Finck     MSIROWENTRY **new = msi_alloc_zero(sizeof(MSIROWENTRY *) * INITIAL_REORDER_SIZE);
90*c2c66affSColin Finck     if (!new)
91*c2c66affSColin Finck         return ERROR_OUTOFMEMORY;
92*c2c66affSColin Finck 
93*c2c66affSColin Finck     free_reorder(wv);
94*c2c66affSColin Finck 
95*c2c66affSColin Finck     wv->reorder = new;
96*c2c66affSColin Finck     wv->reorder_size = INITIAL_REORDER_SIZE;
97*c2c66affSColin Finck 
98*c2c66affSColin Finck     return ERROR_SUCCESS;
99*c2c66affSColin Finck }
100*c2c66affSColin Finck 
101*c2c66affSColin Finck static inline UINT find_row(MSIWHEREVIEW *wv, UINT row, UINT *(values[]))
102*c2c66affSColin Finck {
103*c2c66affSColin Finck     if (row >= wv->row_count)
104*c2c66affSColin Finck         return ERROR_NO_MORE_ITEMS;
105*c2c66affSColin Finck 
106*c2c66affSColin Finck     *values = wv->reorder[row]->values;
107*c2c66affSColin Finck 
108*c2c66affSColin Finck     return ERROR_SUCCESS;
109*c2c66affSColin Finck }
110*c2c66affSColin Finck 
111*c2c66affSColin Finck static UINT add_row(MSIWHEREVIEW *wv, UINT vals[])
112*c2c66affSColin Finck {
113*c2c66affSColin Finck     MSIROWENTRY *new;
114*c2c66affSColin Finck 
115*c2c66affSColin Finck     if (wv->reorder_size <= wv->row_count)
116*c2c66affSColin Finck     {
117*c2c66affSColin Finck         MSIROWENTRY **new_reorder;
118*c2c66affSColin Finck         UINT newsize = wv->reorder_size * 2;
119*c2c66affSColin Finck 
120*c2c66affSColin Finck         new_reorder = msi_realloc_zero(wv->reorder, sizeof(MSIROWENTRY *) * newsize);
121*c2c66affSColin Finck         if (!new_reorder)
122*c2c66affSColin Finck             return ERROR_OUTOFMEMORY;
123*c2c66affSColin Finck 
124*c2c66affSColin Finck         wv->reorder = new_reorder;
125*c2c66affSColin Finck         wv->reorder_size = newsize;
126*c2c66affSColin Finck     }
127*c2c66affSColin Finck 
128*c2c66affSColin Finck     new = msi_alloc(FIELD_OFFSET( MSIROWENTRY, values[wv->table_count] ));
129*c2c66affSColin Finck 
130*c2c66affSColin Finck     if (!new)
131*c2c66affSColin Finck         return ERROR_OUTOFMEMORY;
132*c2c66affSColin Finck 
133*c2c66affSColin Finck     wv->reorder[wv->row_count++] = new;
134*c2c66affSColin Finck 
135*c2c66affSColin Finck     memcpy(new->values, vals, wv->table_count * sizeof(UINT));
136*c2c66affSColin Finck     new->wv = wv;
137*c2c66affSColin Finck 
138*c2c66affSColin Finck     return ERROR_SUCCESS;
139*c2c66affSColin Finck }
140*c2c66affSColin Finck 
141*c2c66affSColin Finck static JOINTABLE *find_table(MSIWHEREVIEW *wv, UINT col, UINT *table_col)
142*c2c66affSColin Finck {
143*c2c66affSColin Finck     JOINTABLE *table = wv->tables;
144*c2c66affSColin Finck 
145*c2c66affSColin Finck     if(col == 0 || col > wv->col_count)
146*c2c66affSColin Finck          return NULL;
147*c2c66affSColin Finck 
148*c2c66affSColin Finck     while (col > table->col_count)
149*c2c66affSColin Finck     {
150*c2c66affSColin Finck         col -= table->col_count;
151*c2c66affSColin Finck         table = table->next;
152*c2c66affSColin Finck         assert(table);
153*c2c66affSColin Finck     }
154*c2c66affSColin Finck 
155*c2c66affSColin Finck     *table_col = col;
156*c2c66affSColin Finck     return table;
157*c2c66affSColin Finck }
158*c2c66affSColin Finck 
159*c2c66affSColin Finck static UINT parse_column(MSIWHEREVIEW *wv, union ext_column *column,
160*c2c66affSColin Finck                          UINT *column_type)
161*c2c66affSColin Finck {
162*c2c66affSColin Finck     JOINTABLE *table = wv->tables;
163*c2c66affSColin Finck     UINT i, r;
164*c2c66affSColin Finck 
165*c2c66affSColin Finck     do
166*c2c66affSColin Finck     {
167*c2c66affSColin Finck         LPCWSTR table_name;
168*c2c66affSColin Finck 
169*c2c66affSColin Finck         if (column->unparsed.table)
170*c2c66affSColin Finck         {
171*c2c66affSColin Finck             r = table->view->ops->get_column_info(table->view, 1, NULL, NULL,
172*c2c66affSColin Finck                                                   NULL, &table_name);
173*c2c66affSColin Finck             if (r != ERROR_SUCCESS)
174*c2c66affSColin Finck                 return r;
175*c2c66affSColin Finck             if (strcmpW(table_name, column->unparsed.table) != 0)
176*c2c66affSColin Finck                 continue;
177*c2c66affSColin Finck         }
178*c2c66affSColin Finck 
179*c2c66affSColin Finck         for(i = 1; i <= table->col_count; i++)
180*c2c66affSColin Finck         {
181*c2c66affSColin Finck             LPCWSTR col_name;
182*c2c66affSColin Finck 
183*c2c66affSColin Finck             r = table->view->ops->get_column_info(table->view, i, &col_name, column_type,
184*c2c66affSColin Finck                                                   NULL, NULL);
185*c2c66affSColin Finck             if(r != ERROR_SUCCESS )
186*c2c66affSColin Finck                 return r;
187*c2c66affSColin Finck 
188*c2c66affSColin Finck             if(strcmpW(col_name, column->unparsed.column))
189*c2c66affSColin Finck                 continue;
190*c2c66affSColin Finck             column->parsed.column = i;
191*c2c66affSColin Finck             column->parsed.table = table;
192*c2c66affSColin Finck             return ERROR_SUCCESS;
193*c2c66affSColin Finck         }
194*c2c66affSColin Finck     }
195*c2c66affSColin Finck     while ((table = table->next));
196*c2c66affSColin Finck 
197*c2c66affSColin Finck     WARN("Couldn't find column %s.%s\n", debugstr_w( column->unparsed.table ), debugstr_w( column->unparsed.column ) );
198*c2c66affSColin Finck     return ERROR_BAD_QUERY_SYNTAX;
199*c2c66affSColin Finck }
200*c2c66affSColin Finck 
201*c2c66affSColin Finck static UINT WHERE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
202*c2c66affSColin Finck {
203*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
204*c2c66affSColin Finck     JOINTABLE *table;
205*c2c66affSColin Finck     UINT *rows;
206*c2c66affSColin Finck     UINT r;
207*c2c66affSColin Finck 
208*c2c66affSColin Finck     TRACE("%p %d %d %p\n", wv, row, col, val );
209*c2c66affSColin Finck 
210*c2c66affSColin Finck     if( !wv->tables )
211*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
212*c2c66affSColin Finck 
213*c2c66affSColin Finck     r = find_row(wv, row, &rows);
214*c2c66affSColin Finck     if (r != ERROR_SUCCESS)
215*c2c66affSColin Finck         return r;
216*c2c66affSColin Finck 
217*c2c66affSColin Finck     table = find_table(wv, col, &col);
218*c2c66affSColin Finck     if (!table)
219*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
220*c2c66affSColin Finck 
221*c2c66affSColin Finck     return table->view->ops->fetch_int(table->view, rows[table->table_index], col, val);
222*c2c66affSColin Finck }
223*c2c66affSColin Finck 
224*c2c66affSColin Finck static UINT WHERE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
225*c2c66affSColin Finck {
226*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
227*c2c66affSColin Finck     JOINTABLE *table;
228*c2c66affSColin Finck     UINT *rows;
229*c2c66affSColin Finck     UINT r;
230*c2c66affSColin Finck 
231*c2c66affSColin Finck     TRACE("%p %d %d %p\n", wv, row, col, stm );
232*c2c66affSColin Finck 
233*c2c66affSColin Finck     if( !wv->tables )
234*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
235*c2c66affSColin Finck 
236*c2c66affSColin Finck     r = find_row(wv, row, &rows);
237*c2c66affSColin Finck     if (r != ERROR_SUCCESS)
238*c2c66affSColin Finck         return r;
239*c2c66affSColin Finck 
240*c2c66affSColin Finck     table = find_table(wv, col, &col);
241*c2c66affSColin Finck     if (!table)
242*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
243*c2c66affSColin Finck 
244*c2c66affSColin Finck     return table->view->ops->fetch_stream( table->view, rows[table->table_index], col, stm );
245*c2c66affSColin Finck }
246*c2c66affSColin Finck 
247*c2c66affSColin Finck static UINT WHERE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
248*c2c66affSColin Finck {
249*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
250*c2c66affSColin Finck 
251*c2c66affSColin Finck     TRACE("%p %d %p\n", wv, row, rec );
252*c2c66affSColin Finck 
253*c2c66affSColin Finck     if (!wv->tables)
254*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
255*c2c66affSColin Finck 
256*c2c66affSColin Finck     return msi_view_get_row( wv->db, view, row, rec );
257*c2c66affSColin Finck }
258*c2c66affSColin Finck 
259*c2c66affSColin Finck static UINT WHERE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
260*c2c66affSColin Finck {
261*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
262*c2c66affSColin Finck     UINT i, r, offset = 0;
263*c2c66affSColin Finck     JOINTABLE *table = wv->tables;
264*c2c66affSColin Finck     UINT *rows;
265*c2c66affSColin Finck     UINT mask_copy = mask;
266*c2c66affSColin Finck 
267*c2c66affSColin Finck     TRACE("%p %d %p %08x\n", wv, row, rec, mask );
268*c2c66affSColin Finck 
269*c2c66affSColin Finck     if( !wv->tables )
270*c2c66affSColin Finck          return ERROR_FUNCTION_FAILED;
271*c2c66affSColin Finck 
272*c2c66affSColin Finck     r = find_row(wv, row, &rows);
273*c2c66affSColin Finck     if (r != ERROR_SUCCESS)
274*c2c66affSColin Finck         return r;
275*c2c66affSColin Finck 
276*c2c66affSColin Finck     if (mask >= 1 << wv->col_count)
277*c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
278*c2c66affSColin Finck 
279*c2c66affSColin Finck     do
280*c2c66affSColin Finck     {
281*c2c66affSColin Finck         for (i = 0; i < table->col_count; i++) {
282*c2c66affSColin Finck             UINT type;
283*c2c66affSColin Finck 
284*c2c66affSColin Finck             if (!(mask_copy & (1 << i)))
285*c2c66affSColin Finck                 continue;
286*c2c66affSColin Finck             r = table->view->ops->get_column_info(table->view, i + 1, NULL,
287*c2c66affSColin Finck                                             &type, NULL, NULL );
288*c2c66affSColin Finck             if (r != ERROR_SUCCESS)
289*c2c66affSColin Finck                 return r;
290*c2c66affSColin Finck             if (type & MSITYPE_KEY)
291*c2c66affSColin Finck                 return ERROR_FUNCTION_FAILED;
292*c2c66affSColin Finck         }
293*c2c66affSColin Finck         mask_copy >>= table->col_count;
294*c2c66affSColin Finck     }
295*c2c66affSColin Finck     while (mask_copy && (table = table->next));
296*c2c66affSColin Finck 
297*c2c66affSColin Finck     table = wv->tables;
298*c2c66affSColin Finck 
299*c2c66affSColin Finck     do
300*c2c66affSColin Finck     {
301*c2c66affSColin Finck         const UINT col_count = table->col_count;
302*c2c66affSColin Finck         UINT i;
303*c2c66affSColin Finck         MSIRECORD *reduced;
304*c2c66affSColin Finck         UINT reduced_mask = (mask >> offset) & ((1 << col_count) - 1);
305*c2c66affSColin Finck 
306*c2c66affSColin Finck         if (!reduced_mask)
307*c2c66affSColin Finck         {
308*c2c66affSColin Finck             offset += col_count;
309*c2c66affSColin Finck             continue;
310*c2c66affSColin Finck         }
311*c2c66affSColin Finck 
312*c2c66affSColin Finck         reduced = MSI_CreateRecord(col_count);
313*c2c66affSColin Finck         if (!reduced)
314*c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
315*c2c66affSColin Finck 
316*c2c66affSColin Finck         for (i = 1; i <= col_count; i++)
317*c2c66affSColin Finck         {
318*c2c66affSColin Finck             r = MSI_RecordCopyField(rec, i + offset, reduced, i);
319*c2c66affSColin Finck             if (r != ERROR_SUCCESS)
320*c2c66affSColin Finck                 break;
321*c2c66affSColin Finck         }
322*c2c66affSColin Finck 
323*c2c66affSColin Finck         offset += col_count;
324*c2c66affSColin Finck 
325*c2c66affSColin Finck         if (r == ERROR_SUCCESS)
326*c2c66affSColin Finck             r = table->view->ops->set_row(table->view, rows[table->table_index], reduced, reduced_mask);
327*c2c66affSColin Finck 
328*c2c66affSColin Finck         msiobj_release(&reduced->hdr);
329*c2c66affSColin Finck     }
330*c2c66affSColin Finck     while ((table = table->next));
331*c2c66affSColin Finck     return r;
332*c2c66affSColin Finck }
333*c2c66affSColin Finck 
334*c2c66affSColin Finck static UINT WHERE_delete_row(struct tagMSIVIEW *view, UINT row)
335*c2c66affSColin Finck {
336*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
337*c2c66affSColin Finck     UINT r;
338*c2c66affSColin Finck     UINT *rows;
339*c2c66affSColin Finck 
340*c2c66affSColin Finck     TRACE("(%p %d)\n", view, row);
341*c2c66affSColin Finck 
342*c2c66affSColin Finck     if (!wv->tables)
343*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
344*c2c66affSColin Finck 
345*c2c66affSColin Finck     r = find_row(wv, row, &rows);
346*c2c66affSColin Finck     if ( r != ERROR_SUCCESS )
347*c2c66affSColin Finck         return r;
348*c2c66affSColin Finck 
349*c2c66affSColin Finck     if (wv->table_count > 1)
350*c2c66affSColin Finck         return ERROR_CALL_NOT_IMPLEMENTED;
351*c2c66affSColin Finck 
352*c2c66affSColin Finck     return wv->tables->view->ops->delete_row(wv->tables->view, rows[0]);
353*c2c66affSColin Finck }
354*c2c66affSColin Finck 
355*c2c66affSColin Finck static INT INT_evaluate_binary( MSIWHEREVIEW *wv, const UINT rows[],
356*c2c66affSColin Finck                                 const struct complex_expr *expr, INT *val, MSIRECORD *record )
357*c2c66affSColin Finck {
358*c2c66affSColin Finck     UINT rl, rr;
359*c2c66affSColin Finck     INT lval, rval;
360*c2c66affSColin Finck 
361*c2c66affSColin Finck     rl = WHERE_evaluate(wv, rows, expr->left, &lval, record);
362*c2c66affSColin Finck     if (rl != ERROR_SUCCESS && rl != ERROR_CONTINUE)
363*c2c66affSColin Finck         return rl;
364*c2c66affSColin Finck     rr = WHERE_evaluate(wv, rows, expr->right, &rval, record);
365*c2c66affSColin Finck     if (rr != ERROR_SUCCESS && rr != ERROR_CONTINUE)
366*c2c66affSColin Finck         return rr;
367*c2c66affSColin Finck 
368*c2c66affSColin Finck     if (rl == ERROR_CONTINUE || rr == ERROR_CONTINUE)
369*c2c66affSColin Finck     {
370*c2c66affSColin Finck         if (rl == rr)
371*c2c66affSColin Finck         {
372*c2c66affSColin Finck             *val = TRUE;
373*c2c66affSColin Finck             return ERROR_CONTINUE;
374*c2c66affSColin Finck         }
375*c2c66affSColin Finck 
376*c2c66affSColin Finck         if (expr->op == OP_AND)
377*c2c66affSColin Finck         {
378*c2c66affSColin Finck             if ((rl == ERROR_CONTINUE && !rval) || (rr == ERROR_CONTINUE && !lval))
379*c2c66affSColin Finck             {
380*c2c66affSColin Finck                 *val = FALSE;
381*c2c66affSColin Finck                 return ERROR_SUCCESS;
382*c2c66affSColin Finck             }
383*c2c66affSColin Finck         }
384*c2c66affSColin Finck         else if (expr->op == OP_OR)
385*c2c66affSColin Finck         {
386*c2c66affSColin Finck             if ((rl == ERROR_CONTINUE && rval) || (rr == ERROR_CONTINUE && lval))
387*c2c66affSColin Finck             {
388*c2c66affSColin Finck                 *val = TRUE;
389*c2c66affSColin Finck                 return ERROR_SUCCESS;
390*c2c66affSColin Finck             }
391*c2c66affSColin Finck         }
392*c2c66affSColin Finck 
393*c2c66affSColin Finck         *val = TRUE;
394*c2c66affSColin Finck         return ERROR_CONTINUE;
395*c2c66affSColin Finck     }
396*c2c66affSColin Finck 
397*c2c66affSColin Finck     switch( expr->op )
398*c2c66affSColin Finck     {
399*c2c66affSColin Finck     case OP_EQ:
400*c2c66affSColin Finck         *val = ( lval == rval );
401*c2c66affSColin Finck         break;
402*c2c66affSColin Finck     case OP_AND:
403*c2c66affSColin Finck         *val = ( lval && rval );
404*c2c66affSColin Finck         break;
405*c2c66affSColin Finck     case OP_OR:
406*c2c66affSColin Finck         *val = ( lval || rval );
407*c2c66affSColin Finck         break;
408*c2c66affSColin Finck     case OP_GT:
409*c2c66affSColin Finck         *val = ( lval > rval );
410*c2c66affSColin Finck         break;
411*c2c66affSColin Finck     case OP_LT:
412*c2c66affSColin Finck         *val = ( lval < rval );
413*c2c66affSColin Finck         break;
414*c2c66affSColin Finck     case OP_LE:
415*c2c66affSColin Finck         *val = ( lval <= rval );
416*c2c66affSColin Finck         break;
417*c2c66affSColin Finck     case OP_GE:
418*c2c66affSColin Finck         *val = ( lval >= rval );
419*c2c66affSColin Finck         break;
420*c2c66affSColin Finck     case OP_NE:
421*c2c66affSColin Finck         *val = ( lval != rval );
422*c2c66affSColin Finck         break;
423*c2c66affSColin Finck     default:
424*c2c66affSColin Finck         ERR("Unknown operator %d\n", expr->op );
425*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
426*c2c66affSColin Finck     }
427*c2c66affSColin Finck 
428*c2c66affSColin Finck     return ERROR_SUCCESS;
429*c2c66affSColin Finck }
430*c2c66affSColin Finck 
431*c2c66affSColin Finck static inline UINT expr_fetch_value(const union ext_column *expr, const UINT rows[], UINT *val)
432*c2c66affSColin Finck {
433*c2c66affSColin Finck     JOINTABLE *table = expr->parsed.table;
434*c2c66affSColin Finck 
435*c2c66affSColin Finck     if( rows[table->table_index] == INVALID_ROW_INDEX )
436*c2c66affSColin Finck     {
437*c2c66affSColin Finck         *val = 1;
438*c2c66affSColin Finck         return ERROR_CONTINUE;
439*c2c66affSColin Finck     }
440*c2c66affSColin Finck     return table->view->ops->fetch_int(table->view, rows[table->table_index],
441*c2c66affSColin Finck                                         expr->parsed.column, val);
442*c2c66affSColin Finck }
443*c2c66affSColin Finck 
444*c2c66affSColin Finck 
445*c2c66affSColin Finck static UINT INT_evaluate_unary( MSIWHEREVIEW *wv, const UINT rows[],
446*c2c66affSColin Finck                                 const struct complex_expr *expr, INT *val, MSIRECORD *record )
447*c2c66affSColin Finck {
448*c2c66affSColin Finck     UINT r;
449*c2c66affSColin Finck     UINT lval;
450*c2c66affSColin Finck 
451*c2c66affSColin Finck     r = expr_fetch_value(&expr->left->u.column, rows, &lval);
452*c2c66affSColin Finck     if(r != ERROR_SUCCESS)
453*c2c66affSColin Finck         return r;
454*c2c66affSColin Finck 
455*c2c66affSColin Finck     switch( expr->op )
456*c2c66affSColin Finck     {
457*c2c66affSColin Finck     case OP_ISNULL:
458*c2c66affSColin Finck         *val = !lval;
459*c2c66affSColin Finck         break;
460*c2c66affSColin Finck     case OP_NOTNULL:
461*c2c66affSColin Finck         *val = lval;
462*c2c66affSColin Finck         break;
463*c2c66affSColin Finck     default:
464*c2c66affSColin Finck         ERR("Unknown operator %d\n", expr->op );
465*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
466*c2c66affSColin Finck     }
467*c2c66affSColin Finck     return ERROR_SUCCESS;
468*c2c66affSColin Finck }
469*c2c66affSColin Finck 
470*c2c66affSColin Finck static UINT STRING_evaluate( MSIWHEREVIEW *wv, const UINT rows[],
471*c2c66affSColin Finck                                      const struct expr *expr,
472*c2c66affSColin Finck                                      const MSIRECORD *record,
473*c2c66affSColin Finck                                      const WCHAR **str )
474*c2c66affSColin Finck {
475*c2c66affSColin Finck     UINT val = 0, r = ERROR_SUCCESS;
476*c2c66affSColin Finck 
477*c2c66affSColin Finck     switch( expr->type )
478*c2c66affSColin Finck     {
479*c2c66affSColin Finck     case EXPR_COL_NUMBER_STRING:
480*c2c66affSColin Finck         r = expr_fetch_value(&expr->u.column, rows, &val);
481*c2c66affSColin Finck         if (r == ERROR_SUCCESS)
482*c2c66affSColin Finck             *str =  msi_string_lookup(wv->db->strings, val, NULL);
483*c2c66affSColin Finck         else
484*c2c66affSColin Finck             *str = NULL;
485*c2c66affSColin Finck         break;
486*c2c66affSColin Finck 
487*c2c66affSColin Finck     case EXPR_SVAL:
488*c2c66affSColin Finck         *str = expr->u.sval;
489*c2c66affSColin Finck         break;
490*c2c66affSColin Finck 
491*c2c66affSColin Finck     case EXPR_WILDCARD:
492*c2c66affSColin Finck         *str = MSI_RecordGetString(record, ++wv->rec_index);
493*c2c66affSColin Finck         break;
494*c2c66affSColin Finck 
495*c2c66affSColin Finck     default:
496*c2c66affSColin Finck         ERR("Invalid expression type\n");
497*c2c66affSColin Finck         r = ERROR_FUNCTION_FAILED;
498*c2c66affSColin Finck         *str = NULL;
499*c2c66affSColin Finck         break;
500*c2c66affSColin Finck     }
501*c2c66affSColin Finck     return r;
502*c2c66affSColin Finck }
503*c2c66affSColin Finck 
504*c2c66affSColin Finck static UINT STRCMP_Evaluate( MSIWHEREVIEW *wv, const UINT rows[], const struct complex_expr *expr,
505*c2c66affSColin Finck                              INT *val, const MSIRECORD *record )
506*c2c66affSColin Finck {
507*c2c66affSColin Finck     int sr;
508*c2c66affSColin Finck     const WCHAR *l_str, *r_str;
509*c2c66affSColin Finck     UINT r;
510*c2c66affSColin Finck 
511*c2c66affSColin Finck     *val = TRUE;
512*c2c66affSColin Finck     r = STRING_evaluate(wv, rows, expr->left, record, &l_str);
513*c2c66affSColin Finck     if (r == ERROR_CONTINUE)
514*c2c66affSColin Finck         return r;
515*c2c66affSColin Finck     r = STRING_evaluate(wv, rows, expr->right, record, &r_str);
516*c2c66affSColin Finck     if (r == ERROR_CONTINUE)
517*c2c66affSColin Finck         return r;
518*c2c66affSColin Finck 
519*c2c66affSColin Finck     if( l_str == r_str ||
520*c2c66affSColin Finck         ((!l_str || !*l_str) && (!r_str || !*r_str)) )
521*c2c66affSColin Finck         sr = 0;
522*c2c66affSColin Finck     else if( l_str && ! r_str )
523*c2c66affSColin Finck         sr = 1;
524*c2c66affSColin Finck     else if( r_str && ! l_str )
525*c2c66affSColin Finck         sr = -1;
526*c2c66affSColin Finck     else
527*c2c66affSColin Finck         sr = strcmpW( l_str, r_str );
528*c2c66affSColin Finck 
529*c2c66affSColin Finck     *val = ( expr->op == OP_EQ && ( sr == 0 ) ) ||
530*c2c66affSColin Finck            ( expr->op == OP_NE && ( sr != 0 ) );
531*c2c66affSColin Finck 
532*c2c66affSColin Finck     return ERROR_SUCCESS;
533*c2c66affSColin Finck }
534*c2c66affSColin Finck 
535*c2c66affSColin Finck static UINT WHERE_evaluate( MSIWHEREVIEW *wv, const UINT rows[],
536*c2c66affSColin Finck                             struct expr *cond, INT *val, MSIRECORD *record )
537*c2c66affSColin Finck {
538*c2c66affSColin Finck     UINT r, tval;
539*c2c66affSColin Finck 
540*c2c66affSColin Finck     if( !cond )
541*c2c66affSColin Finck     {
542*c2c66affSColin Finck         *val = TRUE;
543*c2c66affSColin Finck         return ERROR_SUCCESS;
544*c2c66affSColin Finck     }
545*c2c66affSColin Finck 
546*c2c66affSColin Finck     switch( cond->type )
547*c2c66affSColin Finck     {
548*c2c66affSColin Finck     case EXPR_COL_NUMBER:
549*c2c66affSColin Finck         r = expr_fetch_value(&cond->u.column, rows, &tval);
550*c2c66affSColin Finck         if( r != ERROR_SUCCESS )
551*c2c66affSColin Finck             return r;
552*c2c66affSColin Finck         *val = tval - 0x8000;
553*c2c66affSColin Finck         return ERROR_SUCCESS;
554*c2c66affSColin Finck 
555*c2c66affSColin Finck     case EXPR_COL_NUMBER32:
556*c2c66affSColin Finck         r = expr_fetch_value(&cond->u.column, rows, &tval);
557*c2c66affSColin Finck         if( r != ERROR_SUCCESS )
558*c2c66affSColin Finck             return r;
559*c2c66affSColin Finck         *val = tval - 0x80000000;
560*c2c66affSColin Finck         return r;
561*c2c66affSColin Finck 
562*c2c66affSColin Finck     case EXPR_UVAL:
563*c2c66affSColin Finck         *val = cond->u.uval;
564*c2c66affSColin Finck         return ERROR_SUCCESS;
565*c2c66affSColin Finck 
566*c2c66affSColin Finck     case EXPR_COMPLEX:
567*c2c66affSColin Finck         return INT_evaluate_binary(wv, rows, &cond->u.expr, val, record);
568*c2c66affSColin Finck 
569*c2c66affSColin Finck     case EXPR_UNARY:
570*c2c66affSColin Finck         return INT_evaluate_unary( wv, rows, &cond->u.expr, val, record );
571*c2c66affSColin Finck 
572*c2c66affSColin Finck     case EXPR_STRCMP:
573*c2c66affSColin Finck         return STRCMP_Evaluate( wv, rows, &cond->u.expr, val, record );
574*c2c66affSColin Finck 
575*c2c66affSColin Finck     case EXPR_WILDCARD:
576*c2c66affSColin Finck         *val = MSI_RecordGetInteger( record, ++wv->rec_index );
577*c2c66affSColin Finck         return ERROR_SUCCESS;
578*c2c66affSColin Finck 
579*c2c66affSColin Finck     default:
580*c2c66affSColin Finck         ERR("Invalid expression type\n");
581*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
582*c2c66affSColin Finck     }
583*c2c66affSColin Finck 
584*c2c66affSColin Finck     return ERROR_SUCCESS;
585*c2c66affSColin Finck }
586*c2c66affSColin Finck 
587*c2c66affSColin Finck static UINT check_condition( MSIWHEREVIEW *wv, MSIRECORD *record, JOINTABLE **tables,
588*c2c66affSColin Finck                              UINT table_rows[] )
589*c2c66affSColin Finck {
590*c2c66affSColin Finck     UINT r = ERROR_FUNCTION_FAILED;
591*c2c66affSColin Finck     INT val;
592*c2c66affSColin Finck 
593*c2c66affSColin Finck     for (table_rows[(*tables)->table_index] = 0;
594*c2c66affSColin Finck          table_rows[(*tables)->table_index] < (*tables)->row_count;
595*c2c66affSColin Finck          table_rows[(*tables)->table_index]++)
596*c2c66affSColin Finck     {
597*c2c66affSColin Finck         val = 0;
598*c2c66affSColin Finck         wv->rec_index = 0;
599*c2c66affSColin Finck         r = WHERE_evaluate( wv, table_rows, wv->cond, &val, record );
600*c2c66affSColin Finck         if (r != ERROR_SUCCESS && r != ERROR_CONTINUE)
601*c2c66affSColin Finck             break;
602*c2c66affSColin Finck         if (val)
603*c2c66affSColin Finck         {
604*c2c66affSColin Finck             if (*(tables + 1))
605*c2c66affSColin Finck             {
606*c2c66affSColin Finck                 r = check_condition(wv, record, tables + 1, table_rows);
607*c2c66affSColin Finck                 if (r != ERROR_SUCCESS)
608*c2c66affSColin Finck                     break;
609*c2c66affSColin Finck             }
610*c2c66affSColin Finck             else
611*c2c66affSColin Finck             {
612*c2c66affSColin Finck                 if (r != ERROR_SUCCESS)
613*c2c66affSColin Finck                     break;
614*c2c66affSColin Finck                 add_row (wv, table_rows);
615*c2c66affSColin Finck             }
616*c2c66affSColin Finck         }
617*c2c66affSColin Finck     }
618*c2c66affSColin Finck     table_rows[(*tables)->table_index] = INVALID_ROW_INDEX;
619*c2c66affSColin Finck     return r;
620*c2c66affSColin Finck }
621*c2c66affSColin Finck 
622*c2c66affSColin Finck static int compare_entry( const void *left, const void *right )
623*c2c66affSColin Finck {
624*c2c66affSColin Finck     const MSIROWENTRY *le = *(const MSIROWENTRY**)left;
625*c2c66affSColin Finck     const MSIROWENTRY *re = *(const MSIROWENTRY**)right;
626*c2c66affSColin Finck     const MSIWHEREVIEW *wv = le->wv;
627*c2c66affSColin Finck     MSIORDERINFO *order = wv->order_info;
628*c2c66affSColin Finck     UINT i, j, r, l_val, r_val;
629*c2c66affSColin Finck 
630*c2c66affSColin Finck     assert(le->wv == re->wv);
631*c2c66affSColin Finck 
632*c2c66affSColin Finck     if (order)
633*c2c66affSColin Finck     {
634*c2c66affSColin Finck         for (i = 0; i < order->col_count; i++)
635*c2c66affSColin Finck         {
636*c2c66affSColin Finck             const union ext_column *column = &order->columns[i];
637*c2c66affSColin Finck 
638*c2c66affSColin Finck             r = column->parsed.table->view->ops->fetch_int(column->parsed.table->view,
639*c2c66affSColin Finck                           le->values[column->parsed.table->table_index],
640*c2c66affSColin Finck                           column->parsed.column, &l_val);
641*c2c66affSColin Finck             if (r != ERROR_SUCCESS)
642*c2c66affSColin Finck             {
643*c2c66affSColin Finck                 order->error = r;
644*c2c66affSColin Finck                 return 0;
645*c2c66affSColin Finck             }
646*c2c66affSColin Finck 
647*c2c66affSColin Finck             r = column->parsed.table->view->ops->fetch_int(column->parsed.table->view,
648*c2c66affSColin Finck                           re->values[column->parsed.table->table_index],
649*c2c66affSColin Finck                           column->parsed.column, &r_val);
650*c2c66affSColin Finck             if (r != ERROR_SUCCESS)
651*c2c66affSColin Finck             {
652*c2c66affSColin Finck                 order->error = r;
653*c2c66affSColin Finck                 return 0;
654*c2c66affSColin Finck             }
655*c2c66affSColin Finck 
656*c2c66affSColin Finck             if (l_val != r_val)
657*c2c66affSColin Finck                 return l_val < r_val ? -1 : 1;
658*c2c66affSColin Finck         }
659*c2c66affSColin Finck     }
660*c2c66affSColin Finck 
661*c2c66affSColin Finck     for (j = 0; j < wv->table_count; j++)
662*c2c66affSColin Finck     {
663*c2c66affSColin Finck         if (le->values[j] != re->values[j])
664*c2c66affSColin Finck             return le->values[j] < re->values[j] ? -1 : 1;
665*c2c66affSColin Finck     }
666*c2c66affSColin Finck     return 0;
667*c2c66affSColin Finck }
668*c2c66affSColin Finck 
669*c2c66affSColin Finck static void add_to_array( JOINTABLE **array, JOINTABLE *elem )
670*c2c66affSColin Finck {
671*c2c66affSColin Finck     while (*array && *array != elem)
672*c2c66affSColin Finck         array++;
673*c2c66affSColin Finck     if (!*array)
674*c2c66affSColin Finck         *array = elem;
675*c2c66affSColin Finck }
676*c2c66affSColin Finck 
677*c2c66affSColin Finck static BOOL in_array( JOINTABLE **array, JOINTABLE *elem )
678*c2c66affSColin Finck {
679*c2c66affSColin Finck     while (*array && *array != elem)
680*c2c66affSColin Finck         array++;
681*c2c66affSColin Finck     return *array != NULL;
682*c2c66affSColin Finck }
683*c2c66affSColin Finck 
684*c2c66affSColin Finck #define CONST_EXPR 1 /* comparison to a constant value */
685*c2c66affSColin Finck #define JOIN_TO_CONST_EXPR 0x10000 /* comparison to a table involved with
686*c2c66affSColin Finck                                       a CONST_EXPR comaprison */
687*c2c66affSColin Finck 
688*c2c66affSColin Finck static UINT reorder_check( const struct expr *expr, JOINTABLE **ordered_tables,
689*c2c66affSColin Finck                            BOOL process_joins, JOINTABLE **lastused )
690*c2c66affSColin Finck {
691*c2c66affSColin Finck     UINT res = 0;
692*c2c66affSColin Finck 
693*c2c66affSColin Finck     switch (expr->type)
694*c2c66affSColin Finck     {
695*c2c66affSColin Finck         case EXPR_WILDCARD:
696*c2c66affSColin Finck         case EXPR_SVAL:
697*c2c66affSColin Finck         case EXPR_UVAL:
698*c2c66affSColin Finck             return 0;
699*c2c66affSColin Finck         case EXPR_COL_NUMBER:
700*c2c66affSColin Finck         case EXPR_COL_NUMBER32:
701*c2c66affSColin Finck         case EXPR_COL_NUMBER_STRING:
702*c2c66affSColin Finck             if (in_array(ordered_tables, expr->u.column.parsed.table))
703*c2c66affSColin Finck                 return JOIN_TO_CONST_EXPR;
704*c2c66affSColin Finck             *lastused = expr->u.column.parsed.table;
705*c2c66affSColin Finck             return CONST_EXPR;
706*c2c66affSColin Finck         case EXPR_STRCMP:
707*c2c66affSColin Finck         case EXPR_COMPLEX:
708*c2c66affSColin Finck             res = reorder_check(expr->u.expr.right, ordered_tables, process_joins, lastused);
709*c2c66affSColin Finck             /* fall through */
710*c2c66affSColin Finck         case EXPR_UNARY:
711*c2c66affSColin Finck             res += reorder_check(expr->u.expr.left, ordered_tables, process_joins, lastused);
712*c2c66affSColin Finck             if (res == 0)
713*c2c66affSColin Finck                 return 0;
714*c2c66affSColin Finck             if (res == CONST_EXPR)
715*c2c66affSColin Finck                 add_to_array(ordered_tables, *lastused);
716*c2c66affSColin Finck             if (process_joins && res == JOIN_TO_CONST_EXPR + CONST_EXPR)
717*c2c66affSColin Finck                 add_to_array(ordered_tables, *lastused);
718*c2c66affSColin Finck             return res;
719*c2c66affSColin Finck         default:
720*c2c66affSColin Finck             ERR("Unknown expr type: %i\n", expr->type);
721*c2c66affSColin Finck             assert(0);
722*c2c66affSColin Finck             return 0x1000000;
723*c2c66affSColin Finck     }
724*c2c66affSColin Finck }
725*c2c66affSColin Finck 
726*c2c66affSColin Finck /* reorders the tablelist in a way to evaluate the condition as fast as possible */
727*c2c66affSColin Finck static JOINTABLE **ordertables( MSIWHEREVIEW *wv )
728*c2c66affSColin Finck {
729*c2c66affSColin Finck     JOINTABLE *table;
730*c2c66affSColin Finck     JOINTABLE **tables;
731*c2c66affSColin Finck 
732*c2c66affSColin Finck     tables = msi_alloc_zero( (wv->table_count + 1) * sizeof(*tables) );
733*c2c66affSColin Finck 
734*c2c66affSColin Finck     if (wv->cond)
735*c2c66affSColin Finck     {
736*c2c66affSColin Finck         table = NULL;
737*c2c66affSColin Finck         reorder_check(wv->cond, tables, FALSE, &table);
738*c2c66affSColin Finck         table = NULL;
739*c2c66affSColin Finck         reorder_check(wv->cond, tables, TRUE, &table);
740*c2c66affSColin Finck     }
741*c2c66affSColin Finck 
742*c2c66affSColin Finck     table = wv->tables;
743*c2c66affSColin Finck     while (table)
744*c2c66affSColin Finck     {
745*c2c66affSColin Finck         add_to_array(tables, table);
746*c2c66affSColin Finck         table = table->next;
747*c2c66affSColin Finck     }
748*c2c66affSColin Finck     return tables;
749*c2c66affSColin Finck }
750*c2c66affSColin Finck 
751*c2c66affSColin Finck static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
752*c2c66affSColin Finck {
753*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
754*c2c66affSColin Finck     UINT r;
755*c2c66affSColin Finck     JOINTABLE *table = wv->tables;
756*c2c66affSColin Finck     UINT *rows;
757*c2c66affSColin Finck     JOINTABLE **ordered_tables;
758*c2c66affSColin Finck     UINT i = 0;
759*c2c66affSColin Finck 
760*c2c66affSColin Finck     TRACE("%p %p\n", wv, record);
761*c2c66affSColin Finck 
762*c2c66affSColin Finck     if( !table )
763*c2c66affSColin Finck          return ERROR_FUNCTION_FAILED;
764*c2c66affSColin Finck 
765*c2c66affSColin Finck     r = init_reorder(wv);
766*c2c66affSColin Finck     if (r != ERROR_SUCCESS)
767*c2c66affSColin Finck         return r;
768*c2c66affSColin Finck 
769*c2c66affSColin Finck     do
770*c2c66affSColin Finck     {
771*c2c66affSColin Finck         table->view->ops->execute(table->view, NULL);
772*c2c66affSColin Finck 
773*c2c66affSColin Finck         r = table->view->ops->get_dimensions(table->view, &table->row_count, NULL);
774*c2c66affSColin Finck         if (r != ERROR_SUCCESS)
775*c2c66affSColin Finck         {
776*c2c66affSColin Finck             ERR("failed to get table dimensions\n");
777*c2c66affSColin Finck             return r;
778*c2c66affSColin Finck         }
779*c2c66affSColin Finck 
780*c2c66affSColin Finck         /* each table must have at least one row */
781*c2c66affSColin Finck         if (table->row_count == 0)
782*c2c66affSColin Finck             return ERROR_SUCCESS;
783*c2c66affSColin Finck     }
784*c2c66affSColin Finck     while ((table = table->next));
785*c2c66affSColin Finck 
786*c2c66affSColin Finck     ordered_tables = ordertables( wv );
787*c2c66affSColin Finck 
788*c2c66affSColin Finck     rows = msi_alloc( wv->table_count * sizeof(*rows) );
789*c2c66affSColin Finck     for (i = 0; i < wv->table_count; i++)
790*c2c66affSColin Finck         rows[i] = INVALID_ROW_INDEX;
791*c2c66affSColin Finck 
792*c2c66affSColin Finck     r =  check_condition(wv, record, ordered_tables, rows);
793*c2c66affSColin Finck 
794*c2c66affSColin Finck     if (wv->order_info)
795*c2c66affSColin Finck         wv->order_info->error = ERROR_SUCCESS;
796*c2c66affSColin Finck 
797*c2c66affSColin Finck     qsort(wv->reorder, wv->row_count, sizeof(MSIROWENTRY *), compare_entry);
798*c2c66affSColin Finck 
799*c2c66affSColin Finck     if (wv->order_info)
800*c2c66affSColin Finck         r = wv->order_info->error;
801*c2c66affSColin Finck 
802*c2c66affSColin Finck     msi_free( rows );
803*c2c66affSColin Finck     msi_free( ordered_tables );
804*c2c66affSColin Finck     return r;
805*c2c66affSColin Finck }
806*c2c66affSColin Finck 
807*c2c66affSColin Finck static UINT WHERE_close( struct tagMSIVIEW *view )
808*c2c66affSColin Finck {
809*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
810*c2c66affSColin Finck     JOINTABLE *table = wv->tables;
811*c2c66affSColin Finck 
812*c2c66affSColin Finck     TRACE("%p\n", wv );
813*c2c66affSColin Finck 
814*c2c66affSColin Finck     if (!table)
815*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
816*c2c66affSColin Finck 
817*c2c66affSColin Finck     do
818*c2c66affSColin Finck         table->view->ops->close(table->view);
819*c2c66affSColin Finck     while ((table = table->next));
820*c2c66affSColin Finck 
821*c2c66affSColin Finck     return ERROR_SUCCESS;
822*c2c66affSColin Finck }
823*c2c66affSColin Finck 
824*c2c66affSColin Finck static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
825*c2c66affSColin Finck {
826*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
827*c2c66affSColin Finck 
828*c2c66affSColin Finck     TRACE("%p %p %p\n", wv, rows, cols );
829*c2c66affSColin Finck 
830*c2c66affSColin Finck     if(!wv->tables)
831*c2c66affSColin Finck          return ERROR_FUNCTION_FAILED;
832*c2c66affSColin Finck 
833*c2c66affSColin Finck     if (rows)
834*c2c66affSColin Finck     {
835*c2c66affSColin Finck         if (!wv->reorder)
836*c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
837*c2c66affSColin Finck         *rows = wv->row_count;
838*c2c66affSColin Finck     }
839*c2c66affSColin Finck 
840*c2c66affSColin Finck     if (cols)
841*c2c66affSColin Finck         *cols = wv->col_count;
842*c2c66affSColin Finck 
843*c2c66affSColin Finck     return ERROR_SUCCESS;
844*c2c66affSColin Finck }
845*c2c66affSColin Finck 
846*c2c66affSColin Finck static UINT WHERE_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name,
847*c2c66affSColin Finck                                    UINT *type, BOOL *temporary, LPCWSTR *table_name )
848*c2c66affSColin Finck {
849*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
850*c2c66affSColin Finck     JOINTABLE *table;
851*c2c66affSColin Finck 
852*c2c66affSColin Finck     TRACE("%p %d %p %p %p %p\n", wv, n, name, type, temporary, table_name );
853*c2c66affSColin Finck 
854*c2c66affSColin Finck     if(!wv->tables)
855*c2c66affSColin Finck          return ERROR_FUNCTION_FAILED;
856*c2c66affSColin Finck 
857*c2c66affSColin Finck     table = find_table(wv, n, &n);
858*c2c66affSColin Finck     if (!table)
859*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
860*c2c66affSColin Finck 
861*c2c66affSColin Finck     return table->view->ops->get_column_info(table->view, n, name,
862*c2c66affSColin Finck                                             type, temporary, table_name);
863*c2c66affSColin Finck }
864*c2c66affSColin Finck 
865*c2c66affSColin Finck static UINT join_find_row( MSIWHEREVIEW *wv, MSIRECORD *rec, UINT *row )
866*c2c66affSColin Finck {
867*c2c66affSColin Finck     LPCWSTR str;
868*c2c66affSColin Finck     UINT r, i, id, data;
869*c2c66affSColin Finck 
870*c2c66affSColin Finck     str = MSI_RecordGetString( rec, 1 );
871*c2c66affSColin Finck     r = msi_string2id( wv->db->strings, str, -1, &id );
872*c2c66affSColin Finck     if (r != ERROR_SUCCESS)
873*c2c66affSColin Finck         return r;
874*c2c66affSColin Finck 
875*c2c66affSColin Finck     for (i = 0; i < wv->row_count; i++)
876*c2c66affSColin Finck     {
877*c2c66affSColin Finck         WHERE_fetch_int( &wv->view, i, 1, &data );
878*c2c66affSColin Finck 
879*c2c66affSColin Finck         if (data == id)
880*c2c66affSColin Finck         {
881*c2c66affSColin Finck             *row = i;
882*c2c66affSColin Finck             return ERROR_SUCCESS;
883*c2c66affSColin Finck         }
884*c2c66affSColin Finck     }
885*c2c66affSColin Finck 
886*c2c66affSColin Finck     return ERROR_FUNCTION_FAILED;
887*c2c66affSColin Finck }
888*c2c66affSColin Finck 
889*c2c66affSColin Finck static UINT join_modify_update( struct tagMSIVIEW *view, MSIRECORD *rec )
890*c2c66affSColin Finck {
891*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
892*c2c66affSColin Finck     UINT r, row, i, mask = 0;
893*c2c66affSColin Finck     MSIRECORD *current;
894*c2c66affSColin Finck 
895*c2c66affSColin Finck 
896*c2c66affSColin Finck     r = join_find_row( wv, rec, &row );
897*c2c66affSColin Finck     if (r != ERROR_SUCCESS)
898*c2c66affSColin Finck         return r;
899*c2c66affSColin Finck 
900*c2c66affSColin Finck     r = msi_view_get_row( wv->db, view, row, &current );
901*c2c66affSColin Finck     if (r != ERROR_SUCCESS)
902*c2c66affSColin Finck         return r;
903*c2c66affSColin Finck 
904*c2c66affSColin Finck     assert(MSI_RecordGetFieldCount(rec) == MSI_RecordGetFieldCount(current));
905*c2c66affSColin Finck 
906*c2c66affSColin Finck     for (i = MSI_RecordGetFieldCount(rec); i > 0; i--)
907*c2c66affSColin Finck     {
908*c2c66affSColin Finck         if (!MSI_RecordsAreFieldsEqual(rec, current, i))
909*c2c66affSColin Finck             mask |= 1 << (i - 1);
910*c2c66affSColin Finck     }
911*c2c66affSColin Finck      msiobj_release(&current->hdr);
912*c2c66affSColin Finck 
913*c2c66affSColin Finck     return WHERE_set_row( view, row, rec, mask );
914*c2c66affSColin Finck }
915*c2c66affSColin Finck 
916*c2c66affSColin Finck static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
917*c2c66affSColin Finck                           MSIRECORD *rec, UINT row )
918*c2c66affSColin Finck {
919*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
920*c2c66affSColin Finck     JOINTABLE *table = wv->tables;
921*c2c66affSColin Finck     UINT r;
922*c2c66affSColin Finck 
923*c2c66affSColin Finck     TRACE("%p %d %p\n", wv, eModifyMode, rec);
924*c2c66affSColin Finck 
925*c2c66affSColin Finck     if (!table)
926*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
927*c2c66affSColin Finck 
928*c2c66affSColin Finck     if (!table->next)
929*c2c66affSColin Finck     {
930*c2c66affSColin Finck         UINT *rows;
931*c2c66affSColin Finck 
932*c2c66affSColin Finck         if (find_row(wv, row - 1, &rows) == ERROR_SUCCESS)
933*c2c66affSColin Finck             row = rows[0] + 1;
934*c2c66affSColin Finck         else
935*c2c66affSColin Finck             row = -1;
936*c2c66affSColin Finck 
937*c2c66affSColin Finck         return table->view->ops->modify(table->view, eModifyMode, rec, row);
938*c2c66affSColin Finck     }
939*c2c66affSColin Finck 
940*c2c66affSColin Finck     switch (eModifyMode)
941*c2c66affSColin Finck     {
942*c2c66affSColin Finck     case MSIMODIFY_UPDATE:
943*c2c66affSColin Finck         return join_modify_update( view, rec );
944*c2c66affSColin Finck 
945*c2c66affSColin Finck     case MSIMODIFY_ASSIGN:
946*c2c66affSColin Finck     case MSIMODIFY_DELETE:
947*c2c66affSColin Finck     case MSIMODIFY_INSERT:
948*c2c66affSColin Finck     case MSIMODIFY_INSERT_TEMPORARY:
949*c2c66affSColin Finck     case MSIMODIFY_MERGE:
950*c2c66affSColin Finck     case MSIMODIFY_REPLACE:
951*c2c66affSColin Finck     case MSIMODIFY_SEEK:
952*c2c66affSColin Finck     case MSIMODIFY_VALIDATE:
953*c2c66affSColin Finck     case MSIMODIFY_VALIDATE_DELETE:
954*c2c66affSColin Finck     case MSIMODIFY_VALIDATE_FIELD:
955*c2c66affSColin Finck     case MSIMODIFY_VALIDATE_NEW:
956*c2c66affSColin Finck         r = ERROR_FUNCTION_FAILED;
957*c2c66affSColin Finck         break;
958*c2c66affSColin Finck 
959*c2c66affSColin Finck     case MSIMODIFY_REFRESH:
960*c2c66affSColin Finck         r = ERROR_CALL_NOT_IMPLEMENTED;
961*c2c66affSColin Finck         break;
962*c2c66affSColin Finck 
963*c2c66affSColin Finck     default:
964*c2c66affSColin Finck         WARN("%p %d %p %u - unknown mode\n", view, eModifyMode, rec, row );
965*c2c66affSColin Finck         r = ERROR_INVALID_PARAMETER;
966*c2c66affSColin Finck         break;
967*c2c66affSColin Finck     }
968*c2c66affSColin Finck 
969*c2c66affSColin Finck     return r;
970*c2c66affSColin Finck }
971*c2c66affSColin Finck 
972*c2c66affSColin Finck static UINT WHERE_delete( struct tagMSIVIEW *view )
973*c2c66affSColin Finck {
974*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
975*c2c66affSColin Finck     JOINTABLE *table = wv->tables;
976*c2c66affSColin Finck 
977*c2c66affSColin Finck     TRACE("%p\n", wv );
978*c2c66affSColin Finck 
979*c2c66affSColin Finck     while(table)
980*c2c66affSColin Finck     {
981*c2c66affSColin Finck         JOINTABLE *next;
982*c2c66affSColin Finck 
983*c2c66affSColin Finck         table->view->ops->delete(table->view);
984*c2c66affSColin Finck         table->view = NULL;
985*c2c66affSColin Finck         next = table->next;
986*c2c66affSColin Finck         msi_free(table);
987*c2c66affSColin Finck         table = next;
988*c2c66affSColin Finck     }
989*c2c66affSColin Finck     wv->tables = NULL;
990*c2c66affSColin Finck     wv->table_count = 0;
991*c2c66affSColin Finck 
992*c2c66affSColin Finck     free_reorder(wv);
993*c2c66affSColin Finck 
994*c2c66affSColin Finck     msi_free(wv->order_info);
995*c2c66affSColin Finck     wv->order_info = NULL;
996*c2c66affSColin Finck 
997*c2c66affSColin Finck     msiobj_release( &wv->db->hdr );
998*c2c66affSColin Finck     msi_free( wv );
999*c2c66affSColin Finck 
1000*c2c66affSColin Finck     return ERROR_SUCCESS;
1001*c2c66affSColin Finck }
1002*c2c66affSColin Finck 
1003*c2c66affSColin Finck static UINT WHERE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
1004*c2c66affSColin Finck     UINT val, UINT *row, MSIITERHANDLE *handle )
1005*c2c66affSColin Finck {
1006*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
1007*c2c66affSColin Finck     UINT i, row_value;
1008*c2c66affSColin Finck 
1009*c2c66affSColin Finck     TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
1010*c2c66affSColin Finck 
1011*c2c66affSColin Finck     if (!wv->tables)
1012*c2c66affSColin Finck          return ERROR_FUNCTION_FAILED;
1013*c2c66affSColin Finck 
1014*c2c66affSColin Finck     if (col == 0 || col > wv->col_count)
1015*c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
1016*c2c66affSColin Finck 
1017*c2c66affSColin Finck     for (i = PtrToUlong(*handle); i < wv->row_count; i++)
1018*c2c66affSColin Finck     {
1019*c2c66affSColin Finck         if (view->ops->fetch_int( view, i, col, &row_value ) != ERROR_SUCCESS)
1020*c2c66affSColin Finck             continue;
1021*c2c66affSColin Finck 
1022*c2c66affSColin Finck         if (row_value == val)
1023*c2c66affSColin Finck         {
1024*c2c66affSColin Finck             *row = i;
1025*c2c66affSColin Finck             *handle = UlongToPtr(i + 1);
1026*c2c66affSColin Finck             return ERROR_SUCCESS;
1027*c2c66affSColin Finck         }
1028*c2c66affSColin Finck     }
1029*c2c66affSColin Finck 
1030*c2c66affSColin Finck     return ERROR_NO_MORE_ITEMS;
1031*c2c66affSColin Finck }
1032*c2c66affSColin Finck 
1033*c2c66affSColin Finck static UINT WHERE_sort(struct tagMSIVIEW *view, column_info *columns)
1034*c2c66affSColin Finck {
1035*c2c66affSColin Finck     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
1036*c2c66affSColin Finck     JOINTABLE *table = wv->tables;
1037*c2c66affSColin Finck     column_info *column = columns;
1038*c2c66affSColin Finck     MSIORDERINFO *orderinfo;
1039*c2c66affSColin Finck     UINT r, count = 0;
1040*c2c66affSColin Finck     UINT i;
1041*c2c66affSColin Finck 
1042*c2c66affSColin Finck     TRACE("%p %p\n", view, columns);
1043*c2c66affSColin Finck 
1044*c2c66affSColin Finck     if (!table)
1045*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
1046*c2c66affSColin Finck 
1047*c2c66affSColin Finck     while (column)
1048*c2c66affSColin Finck     {
1049*c2c66affSColin Finck         count++;
1050*c2c66affSColin Finck         column = column->next;
1051*c2c66affSColin Finck     }
1052*c2c66affSColin Finck 
1053*c2c66affSColin Finck     if (count == 0)
1054*c2c66affSColin Finck         return ERROR_SUCCESS;
1055*c2c66affSColin Finck 
1056*c2c66affSColin Finck     orderinfo = msi_alloc(FIELD_OFFSET(MSIORDERINFO, columns[count]));
1057*c2c66affSColin Finck     if (!orderinfo)
1058*c2c66affSColin Finck         return ERROR_OUTOFMEMORY;
1059*c2c66affSColin Finck 
1060*c2c66affSColin Finck     orderinfo->col_count = count;
1061*c2c66affSColin Finck 
1062*c2c66affSColin Finck     column = columns;
1063*c2c66affSColin Finck 
1064*c2c66affSColin Finck     for (i = 0; i < count; i++)
1065*c2c66affSColin Finck     {
1066*c2c66affSColin Finck         orderinfo->columns[i].unparsed.column = column->column;
1067*c2c66affSColin Finck         orderinfo->columns[i].unparsed.table = column->table;
1068*c2c66affSColin Finck 
1069*c2c66affSColin Finck         r = parse_column(wv, &orderinfo->columns[i], NULL);
1070*c2c66affSColin Finck         if (r != ERROR_SUCCESS)
1071*c2c66affSColin Finck             goto error;
1072*c2c66affSColin Finck     }
1073*c2c66affSColin Finck 
1074*c2c66affSColin Finck     wv->order_info = orderinfo;
1075*c2c66affSColin Finck 
1076*c2c66affSColin Finck     return ERROR_SUCCESS;
1077*c2c66affSColin Finck error:
1078*c2c66affSColin Finck     msi_free(orderinfo);
1079*c2c66affSColin Finck     return r;
1080*c2c66affSColin Finck }
1081*c2c66affSColin Finck 
1082*c2c66affSColin Finck static const MSIVIEWOPS where_ops =
1083*c2c66affSColin Finck {
1084*c2c66affSColin Finck     WHERE_fetch_int,
1085*c2c66affSColin Finck     WHERE_fetch_stream,
1086*c2c66affSColin Finck     WHERE_get_row,
1087*c2c66affSColin Finck     WHERE_set_row,
1088*c2c66affSColin Finck     NULL,
1089*c2c66affSColin Finck     WHERE_delete_row,
1090*c2c66affSColin Finck     WHERE_execute,
1091*c2c66affSColin Finck     WHERE_close,
1092*c2c66affSColin Finck     WHERE_get_dimensions,
1093*c2c66affSColin Finck     WHERE_get_column_info,
1094*c2c66affSColin Finck     WHERE_modify,
1095*c2c66affSColin Finck     WHERE_delete,
1096*c2c66affSColin Finck     WHERE_find_matching_rows,
1097*c2c66affSColin Finck     NULL,
1098*c2c66affSColin Finck     NULL,
1099*c2c66affSColin Finck     NULL,
1100*c2c66affSColin Finck     NULL,
1101*c2c66affSColin Finck     WHERE_sort,
1102*c2c66affSColin Finck     NULL,
1103*c2c66affSColin Finck };
1104*c2c66affSColin Finck 
1105*c2c66affSColin Finck static UINT WHERE_VerifyCondition( MSIWHEREVIEW *wv, struct expr *cond,
1106*c2c66affSColin Finck                                    UINT *valid )
1107*c2c66affSColin Finck {
1108*c2c66affSColin Finck     UINT r;
1109*c2c66affSColin Finck 
1110*c2c66affSColin Finck     switch( cond->type )
1111*c2c66affSColin Finck     {
1112*c2c66affSColin Finck     case EXPR_COLUMN:
1113*c2c66affSColin Finck     {
1114*c2c66affSColin Finck         UINT type;
1115*c2c66affSColin Finck 
1116*c2c66affSColin Finck         *valid = FALSE;
1117*c2c66affSColin Finck 
1118*c2c66affSColin Finck         r = parse_column(wv, &cond->u.column, &type);
1119*c2c66affSColin Finck         if (r != ERROR_SUCCESS)
1120*c2c66affSColin Finck             break;
1121*c2c66affSColin Finck 
1122*c2c66affSColin Finck         if (type&MSITYPE_STRING)
1123*c2c66affSColin Finck             cond->type = EXPR_COL_NUMBER_STRING;
1124*c2c66affSColin Finck         else if ((type&0xff) == 4)
1125*c2c66affSColin Finck             cond->type = EXPR_COL_NUMBER32;
1126*c2c66affSColin Finck         else
1127*c2c66affSColin Finck             cond->type = EXPR_COL_NUMBER;
1128*c2c66affSColin Finck 
1129*c2c66affSColin Finck         *valid = TRUE;
1130*c2c66affSColin Finck         break;
1131*c2c66affSColin Finck     }
1132*c2c66affSColin Finck     case EXPR_COMPLEX:
1133*c2c66affSColin Finck         r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid );
1134*c2c66affSColin Finck         if( r != ERROR_SUCCESS )
1135*c2c66affSColin Finck             return r;
1136*c2c66affSColin Finck         if( !*valid )
1137*c2c66affSColin Finck             return ERROR_SUCCESS;
1138*c2c66affSColin Finck         r = WHERE_VerifyCondition( wv, cond->u.expr.right, valid );
1139*c2c66affSColin Finck         if( r != ERROR_SUCCESS )
1140*c2c66affSColin Finck             return r;
1141*c2c66affSColin Finck 
1142*c2c66affSColin Finck         /* check the type of the comparison */
1143*c2c66affSColin Finck         if( ( cond->u.expr.left->type == EXPR_SVAL ) ||
1144*c2c66affSColin Finck             ( cond->u.expr.left->type == EXPR_COL_NUMBER_STRING ) ||
1145*c2c66affSColin Finck             ( cond->u.expr.right->type == EXPR_SVAL ) ||
1146*c2c66affSColin Finck             ( cond->u.expr.right->type == EXPR_COL_NUMBER_STRING ) )
1147*c2c66affSColin Finck         {
1148*c2c66affSColin Finck             switch( cond->u.expr.op )
1149*c2c66affSColin Finck             {
1150*c2c66affSColin Finck             case OP_EQ:
1151*c2c66affSColin Finck             case OP_NE:
1152*c2c66affSColin Finck                 break;
1153*c2c66affSColin Finck             default:
1154*c2c66affSColin Finck                 *valid = FALSE;
1155*c2c66affSColin Finck                 return ERROR_INVALID_PARAMETER;
1156*c2c66affSColin Finck             }
1157*c2c66affSColin Finck 
1158*c2c66affSColin Finck             /* FIXME: check we're comparing a string to a column */
1159*c2c66affSColin Finck 
1160*c2c66affSColin Finck             cond->type = EXPR_STRCMP;
1161*c2c66affSColin Finck         }
1162*c2c66affSColin Finck 
1163*c2c66affSColin Finck         break;
1164*c2c66affSColin Finck     case EXPR_UNARY:
1165*c2c66affSColin Finck         if ( cond->u.expr.left->type != EXPR_COLUMN )
1166*c2c66affSColin Finck         {
1167*c2c66affSColin Finck             *valid = FALSE;
1168*c2c66affSColin Finck             return ERROR_INVALID_PARAMETER;
1169*c2c66affSColin Finck         }
1170*c2c66affSColin Finck         r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid );
1171*c2c66affSColin Finck         if( r != ERROR_SUCCESS )
1172*c2c66affSColin Finck             return r;
1173*c2c66affSColin Finck         break;
1174*c2c66affSColin Finck     case EXPR_IVAL:
1175*c2c66affSColin Finck         *valid = 1;
1176*c2c66affSColin Finck         cond->type = EXPR_UVAL;
1177*c2c66affSColin Finck         cond->u.uval = cond->u.ival;
1178*c2c66affSColin Finck         break;
1179*c2c66affSColin Finck     case EXPR_WILDCARD:
1180*c2c66affSColin Finck         *valid = 1;
1181*c2c66affSColin Finck         break;
1182*c2c66affSColin Finck     case EXPR_SVAL:
1183*c2c66affSColin Finck         *valid = 1;
1184*c2c66affSColin Finck         break;
1185*c2c66affSColin Finck     default:
1186*c2c66affSColin Finck         ERR("Invalid expression type\n");
1187*c2c66affSColin Finck         *valid = 0;
1188*c2c66affSColin Finck         break;
1189*c2c66affSColin Finck     }
1190*c2c66affSColin Finck 
1191*c2c66affSColin Finck     return ERROR_SUCCESS;
1192*c2c66affSColin Finck }
1193*c2c66affSColin Finck 
1194*c2c66affSColin Finck UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables,
1195*c2c66affSColin Finck                        struct expr *cond )
1196*c2c66affSColin Finck {
1197*c2c66affSColin Finck     MSIWHEREVIEW *wv = NULL;
1198*c2c66affSColin Finck     UINT r, valid = 0;
1199*c2c66affSColin Finck     WCHAR *ptr;
1200*c2c66affSColin Finck 
1201*c2c66affSColin Finck     TRACE("(%s)\n", debugstr_w(tables) );
1202*c2c66affSColin Finck 
1203*c2c66affSColin Finck     wv = msi_alloc_zero( sizeof *wv );
1204*c2c66affSColin Finck     if( !wv )
1205*c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
1206*c2c66affSColin Finck 
1207*c2c66affSColin Finck     /* fill the structure */
1208*c2c66affSColin Finck     wv->view.ops = &where_ops;
1209*c2c66affSColin Finck     msiobj_addref( &db->hdr );
1210*c2c66affSColin Finck     wv->db = db;
1211*c2c66affSColin Finck     wv->cond = cond;
1212*c2c66affSColin Finck 
1213*c2c66affSColin Finck     while (*tables)
1214*c2c66affSColin Finck     {
1215*c2c66affSColin Finck         JOINTABLE *table;
1216*c2c66affSColin Finck 
1217*c2c66affSColin Finck         if ((ptr = strchrW(tables, ' ')))
1218*c2c66affSColin Finck             *ptr = '\0';
1219*c2c66affSColin Finck 
1220*c2c66affSColin Finck         table = msi_alloc(sizeof(JOINTABLE));
1221*c2c66affSColin Finck         if (!table)
1222*c2c66affSColin Finck         {
1223*c2c66affSColin Finck             r = ERROR_OUTOFMEMORY;
1224*c2c66affSColin Finck             goto end;
1225*c2c66affSColin Finck         }
1226*c2c66affSColin Finck 
1227*c2c66affSColin Finck         r = TABLE_CreateView(db, tables, &table->view);
1228*c2c66affSColin Finck         if (r != ERROR_SUCCESS)
1229*c2c66affSColin Finck         {
1230*c2c66affSColin Finck             WARN("can't create table: %s\n", debugstr_w(tables));
1231*c2c66affSColin Finck             msi_free(table);
1232*c2c66affSColin Finck             r = ERROR_BAD_QUERY_SYNTAX;
1233*c2c66affSColin Finck             goto end;
1234*c2c66affSColin Finck         }
1235*c2c66affSColin Finck 
1236*c2c66affSColin Finck         r = table->view->ops->get_dimensions(table->view, NULL,
1237*c2c66affSColin Finck                                              &table->col_count);
1238*c2c66affSColin Finck         if (r != ERROR_SUCCESS)
1239*c2c66affSColin Finck         {
1240*c2c66affSColin Finck             ERR("can't get table dimensions\n");
1241*c2c66affSColin Finck             table->view->ops->delete(table->view);
1242*c2c66affSColin Finck             msi_free(table);
1243*c2c66affSColin Finck             goto end;
1244*c2c66affSColin Finck         }
1245*c2c66affSColin Finck 
1246*c2c66affSColin Finck         wv->col_count += table->col_count;
1247*c2c66affSColin Finck         table->table_index = wv->table_count++;
1248*c2c66affSColin Finck 
1249*c2c66affSColin Finck         table->next = wv->tables;
1250*c2c66affSColin Finck         wv->tables = table;
1251*c2c66affSColin Finck 
1252*c2c66affSColin Finck         if (!ptr)
1253*c2c66affSColin Finck             break;
1254*c2c66affSColin Finck 
1255*c2c66affSColin Finck         tables = ptr + 1;
1256*c2c66affSColin Finck     }
1257*c2c66affSColin Finck 
1258*c2c66affSColin Finck     if( cond )
1259*c2c66affSColin Finck     {
1260*c2c66affSColin Finck         r = WHERE_VerifyCondition( wv, cond, &valid );
1261*c2c66affSColin Finck         if( r != ERROR_SUCCESS )
1262*c2c66affSColin Finck             goto end;
1263*c2c66affSColin Finck         if( !valid ) {
1264*c2c66affSColin Finck             r = ERROR_FUNCTION_FAILED;
1265*c2c66affSColin Finck             goto end;
1266*c2c66affSColin Finck         }
1267*c2c66affSColin Finck     }
1268*c2c66affSColin Finck 
1269*c2c66affSColin Finck     *view = (MSIVIEW*) wv;
1270*c2c66affSColin Finck 
1271*c2c66affSColin Finck     return ERROR_SUCCESS;
1272*c2c66affSColin Finck end:
1273*c2c66affSColin Finck     WHERE_delete(&wv->view);
1274*c2c66affSColin Finck 
1275*c2c66affSColin Finck     return r;
1276*c2c66affSColin Finck }
1277