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