xref: /reactos/dll/win32/msi/where.c (revision 0c2cdcae)
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 struct row_entry
42 {
43     struct tagMSIWHEREVIEW *wv; /* used during sorting */
44     UINT values[1];
45 };
46 
47 struct join_table
48 {
49     struct join_table *next;
50     MSIVIEW *view;
51     UINT col_count;
52     UINT row_count;
53     UINT table_index;
54 };
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     struct join_table *tables;
68     UINT           row_count;
69     UINT           col_count;
70     UINT           table_count;
71     struct row_entry **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         free(wv->reorder[i]);
94 
95     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     struct row_entry **new = calloc(INITIAL_REORDER_SIZE, sizeof(*new));
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     struct row_entry *new;
128 
129     if (wv->reorder_size <= wv->row_count)
130     {
131         struct row_entry **new_reorder;
132         UINT newsize = wv->reorder_size * 2;
133 
134         new_reorder = 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 = malloc(offsetof(struct row_entry, 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 struct join_table *find_table(MSIWHEREVIEW *wv, UINT col, UINT *table_col)
157 {
158     struct join_table *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     struct join_table *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     struct join_table *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     struct join_table *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     struct join_table *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     struct join_table *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     struct join_table *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     struct join_table *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     struct join_table *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, struct join_table **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 struct row_entry *le = *(const struct row_entry **)left;
688     const struct row_entry *re = *(const struct row_entry **)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( struct join_table **array, struct join_table *elem )
733 {
734     while (*array && *array != elem)
735         array++;
736     if (!*array)
737         *array = elem;
738 }
739 
740 static BOOL in_array( struct join_table **array, struct join_table *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, struct join_table **ordered_tables,
752                            BOOL process_joins, struct join_table **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 struct join_table **ordertables( MSIWHEREVIEW *wv )
791 {
792     struct join_table *table, **tables;
793 
794     tables = calloc(wv->table_count + 1, sizeof(*tables));
795 
796     if (wv->cond)
797     {
798         table = NULL;
799         reorder_check(wv->cond, tables, FALSE, &table);
800         table = NULL;
801         reorder_check(wv->cond, tables, TRUE, &table);
802     }
803 
804     table = wv->tables;
805     while (table)
806     {
807         add_to_array(tables, table);
808         table = table->next;
809     }
810     return tables;
811 }
812 
813 static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
814 {
815     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
816     UINT r;
817     struct join_table *table = wv->tables;
818     UINT *rows;
819     struct join_table **ordered_tables;
820     UINT i = 0;
821 
822     TRACE("%p %p\n", wv, record);
823 
824     if( !table )
825          return ERROR_FUNCTION_FAILED;
826 
827     r = init_reorder(wv);
828     if (r != ERROR_SUCCESS)
829         return r;
830 
831     do
832     {
833         table->view->ops->execute(table->view, NULL);
834 
835         r = table->view->ops->get_dimensions(table->view, &table->row_count, NULL);
836         if (r != ERROR_SUCCESS)
837         {
838             ERR("failed to get table dimensions\n");
839             return r;
840         }
841 
842         /* each table must have at least one row */
843         if (table->row_count == 0)
844             return ERROR_SUCCESS;
845     }
846     while ((table = table->next));
847 
848     ordered_tables = ordertables( wv );
849 
850     rows = malloc(wv->table_count * sizeof(*rows));
851     for (i = 0; i < wv->table_count; i++)
852         rows[i] = INVALID_ROW_INDEX;
853 
854     r =  check_condition(wv, record, ordered_tables, rows);
855 
856     if (wv->order_info)
857         wv->order_info->error = ERROR_SUCCESS;
858 
859     qsort(wv->reorder, wv->row_count, sizeof(struct row_entry *), compare_entry);
860 
861     if (wv->order_info)
862         r = wv->order_info->error;
863 
864     free(rows);
865     free(ordered_tables);
866     return r;
867 }
868 
869 static UINT WHERE_close( struct tagMSIVIEW *view )
870 {
871     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
872     struct join_table *table = wv->tables;
873 
874     TRACE("%p\n", wv );
875 
876     if (!table)
877         return ERROR_FUNCTION_FAILED;
878 
879     do
880         table->view->ops->close(table->view);
881     while ((table = table->next));
882 
883     return ERROR_SUCCESS;
884 }
885 
886 static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
887 {
888     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
889 
890     TRACE("%p %p %p\n", wv, rows, cols );
891 
892     if(!wv->tables)
893          return ERROR_FUNCTION_FAILED;
894 
895     if (rows)
896     {
897         if (!wv->reorder)
898             return ERROR_FUNCTION_FAILED;
899         *rows = wv->row_count;
900     }
901 
902     if (cols)
903         *cols = wv->col_count;
904 
905     return ERROR_SUCCESS;
906 }
907 
908 static UINT WHERE_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name,
909                                    UINT *type, BOOL *temporary, LPCWSTR *table_name )
910 {
911     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
912     struct join_table *table;
913 
914     TRACE("%p %d %p %p %p %p\n", wv, n, name, type, temporary, table_name );
915 
916     if(!wv->tables)
917          return ERROR_FUNCTION_FAILED;
918 
919     table = find_table(wv, n, &n);
920     if (!table)
921         return ERROR_FUNCTION_FAILED;
922 
923     return table->view->ops->get_column_info(table->view, n, name,
924                                             type, temporary, table_name);
925 }
926 
927 static UINT join_find_row( MSIWHEREVIEW *wv, MSIRECORD *rec, UINT *row )
928 {
929     LPCWSTR str;
930     UINT r, i, id, data;
931 
932     str = MSI_RecordGetString( rec, 1 );
933     r = msi_string2id( wv->db->strings, str, -1, &id );
934     if (r != ERROR_SUCCESS)
935         return r;
936 
937     for (i = 0; i < wv->row_count; i++)
938     {
939         WHERE_fetch_int( &wv->view, i, 1, &data );
940 
941         if (data == id)
942         {
943             *row = i;
944             return ERROR_SUCCESS;
945         }
946     }
947 
948     return ERROR_FUNCTION_FAILED;
949 }
950 
951 static UINT join_modify_update( struct tagMSIVIEW *view, MSIRECORD *rec )
952 {
953     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
954     UINT r, row, i, mask = 0;
955     MSIRECORD *current;
956 
957 
958     r = join_find_row( wv, rec, &row );
959     if (r != ERROR_SUCCESS)
960         return r;
961 
962     r = msi_view_get_row( wv->db, view, row, &current );
963     if (r != ERROR_SUCCESS)
964         return r;
965 
966     assert(MSI_RecordGetFieldCount(rec) == MSI_RecordGetFieldCount(current));
967 
968     for (i = MSI_RecordGetFieldCount(rec); i > 0; i--)
969     {
970         if (!MSI_RecordsAreFieldsEqual(rec, current, i))
971             mask |= 1 << (i - 1);
972     }
973      msiobj_release(&current->hdr);
974 
975     return WHERE_set_row( view, row, rec, mask );
976 }
977 
978 static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
979                           MSIRECORD *rec, UINT row )
980 {
981     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
982     struct join_table *table = wv->tables;
983     UINT r;
984 
985     TRACE("%p %d %p\n", wv, eModifyMode, rec);
986 
987     if (!table)
988         return ERROR_FUNCTION_FAILED;
989 
990     if (!table->next)
991     {
992         UINT *rows;
993 
994         if (find_row(wv, row, &rows) == ERROR_SUCCESS)
995             row = rows[0];
996         else
997             row = -1;
998 
999         return table->view->ops->modify(table->view, eModifyMode, rec, row);
1000     }
1001 
1002     switch (eModifyMode)
1003     {
1004     case MSIMODIFY_UPDATE:
1005         return join_modify_update( view, rec );
1006 
1007     case MSIMODIFY_ASSIGN:
1008     case MSIMODIFY_DELETE:
1009     case MSIMODIFY_INSERT:
1010     case MSIMODIFY_INSERT_TEMPORARY:
1011     case MSIMODIFY_MERGE:
1012     case MSIMODIFY_REPLACE:
1013     case MSIMODIFY_SEEK:
1014     case MSIMODIFY_VALIDATE:
1015     case MSIMODIFY_VALIDATE_DELETE:
1016     case MSIMODIFY_VALIDATE_FIELD:
1017     case MSIMODIFY_VALIDATE_NEW:
1018         r = ERROR_FUNCTION_FAILED;
1019         break;
1020 
1021     case MSIMODIFY_REFRESH:
1022         r = ERROR_CALL_NOT_IMPLEMENTED;
1023         break;
1024 
1025     default:
1026         WARN("%p %d %p %u - unknown mode\n", view, eModifyMode, rec, row );
1027         r = ERROR_INVALID_PARAMETER;
1028         break;
1029     }
1030 
1031     return r;
1032 }
1033 
1034 static UINT WHERE_delete( struct tagMSIVIEW *view )
1035 {
1036     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
1037     struct join_table *table = wv->tables;
1038 
1039     TRACE("%p\n", wv );
1040 
1041     while(table)
1042     {
1043         struct join_table *next;
1044 
1045         table->view->ops->delete(table->view);
1046         table->view = NULL;
1047         next = table->next;
1048         free(table);
1049         table = next;
1050     }
1051     wv->tables = NULL;
1052     wv->table_count = 0;
1053 
1054     free_reorder(wv);
1055 
1056     free(wv->order_info);
1057     wv->order_info = NULL;
1058 
1059     msiobj_release( &wv->db->hdr );
1060     free(wv);
1061 
1062     return ERROR_SUCCESS;
1063 }
1064 
1065 static UINT WHERE_sort(struct tagMSIVIEW *view, column_info *columns)
1066 {
1067     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
1068     struct join_table *table = wv->tables;
1069     column_info *column = columns;
1070     MSIORDERINFO *orderinfo;
1071     UINT r, count = 0;
1072     UINT i;
1073 
1074     TRACE("%p %p\n", view, columns);
1075 
1076     if (!table)
1077         return ERROR_FUNCTION_FAILED;
1078 
1079     while (column)
1080     {
1081         count++;
1082         column = column->next;
1083     }
1084 
1085     if (count == 0)
1086         return ERROR_SUCCESS;
1087 
1088     orderinfo = malloc(offsetof(MSIORDERINFO, columns[count]));
1089     if (!orderinfo)
1090         return ERROR_OUTOFMEMORY;
1091 
1092     orderinfo->col_count = count;
1093 
1094     column = columns;
1095 
1096     for (i = 0; i < count; i++)
1097     {
1098         orderinfo->columns[i].unparsed.column = column->column;
1099         orderinfo->columns[i].unparsed.table = column->table;
1100 
1101         r = parse_column(wv, &orderinfo->columns[i], NULL);
1102         if (r != ERROR_SUCCESS)
1103             goto error;
1104     }
1105 
1106     wv->order_info = orderinfo;
1107 
1108     return ERROR_SUCCESS;
1109 error:
1110     free(orderinfo);
1111     return r;
1112 }
1113 
1114 static const MSIVIEWOPS where_ops =
1115 {
1116     WHERE_fetch_int,
1117     WHERE_fetch_stream,
1118     WHERE_set_int,
1119     WHERE_set_string,
1120     WHERE_set_stream,
1121     WHERE_set_row,
1122     NULL,
1123     WHERE_delete_row,
1124     WHERE_execute,
1125     WHERE_close,
1126     WHERE_get_dimensions,
1127     WHERE_get_column_info,
1128     WHERE_modify,
1129     WHERE_delete,
1130     NULL,
1131     NULL,
1132     NULL,
1133     WHERE_sort,
1134     NULL,
1135 };
1136 
1137 static UINT WHERE_VerifyCondition( MSIWHEREVIEW *wv, struct expr *cond,
1138                                    UINT *valid )
1139 {
1140     UINT r;
1141 
1142     switch( cond->type )
1143     {
1144     case EXPR_COLUMN:
1145     {
1146         UINT type;
1147 
1148         *valid = FALSE;
1149 
1150         r = parse_column(wv, &cond->u.column, &type);
1151         if (r != ERROR_SUCCESS)
1152             break;
1153 
1154         if (type&MSITYPE_STRING)
1155             cond->type = EXPR_COL_NUMBER_STRING;
1156         else if ((type&0xff) == 4)
1157             cond->type = EXPR_COL_NUMBER32;
1158         else
1159             cond->type = EXPR_COL_NUMBER;
1160 
1161         *valid = TRUE;
1162         break;
1163     }
1164     case EXPR_COMPLEX:
1165         r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid );
1166         if( r != ERROR_SUCCESS )
1167             return r;
1168         if( !*valid )
1169             return ERROR_SUCCESS;
1170         r = WHERE_VerifyCondition( wv, cond->u.expr.right, valid );
1171         if( r != ERROR_SUCCESS )
1172             return r;
1173 
1174         /* check the type of the comparison */
1175         if( ( cond->u.expr.left->type == EXPR_SVAL ) ||
1176             ( cond->u.expr.left->type == EXPR_COL_NUMBER_STRING ) ||
1177             ( cond->u.expr.right->type == EXPR_SVAL ) ||
1178             ( cond->u.expr.right->type == EXPR_COL_NUMBER_STRING ) )
1179         {
1180             switch( cond->u.expr.op )
1181             {
1182             case OP_EQ:
1183             case OP_NE:
1184                 break;
1185             default:
1186                 *valid = FALSE;
1187                 return ERROR_INVALID_PARAMETER;
1188             }
1189 
1190             /* FIXME: check we're comparing a string to a column */
1191 
1192             cond->type = EXPR_STRCMP;
1193         }
1194 
1195         break;
1196     case EXPR_UNARY:
1197         if ( cond->u.expr.left->type != EXPR_COLUMN )
1198         {
1199             *valid = FALSE;
1200             return ERROR_INVALID_PARAMETER;
1201         }
1202         r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid );
1203         if( r != ERROR_SUCCESS )
1204             return r;
1205         break;
1206     case EXPR_IVAL:
1207         *valid = 1;
1208         cond->type = EXPR_UVAL;
1209         cond->u.uval = cond->u.ival;
1210         break;
1211     case EXPR_WILDCARD:
1212         *valid = 1;
1213         break;
1214     case EXPR_SVAL:
1215         *valid = 1;
1216         break;
1217     default:
1218         ERR("Invalid expression type\n");
1219         *valid = 0;
1220         break;
1221     }
1222 
1223     return ERROR_SUCCESS;
1224 }
1225 
1226 UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables,
1227                        struct expr *cond )
1228 {
1229     MSIWHEREVIEW *wv = NULL;
1230     UINT r, valid = 0;
1231     WCHAR *ptr;
1232 
1233     TRACE("(%s)\n", debugstr_w(tables) );
1234 
1235     wv = calloc(1, sizeof *wv);
1236     if( !wv )
1237         return ERROR_FUNCTION_FAILED;
1238 
1239     /* fill the structure */
1240     wv->view.ops = &where_ops;
1241     msiobj_addref( &db->hdr );
1242     wv->db = db;
1243     wv->cond = cond;
1244 
1245     while (*tables)
1246     {
1247         struct join_table *table;
1248 
1249         if ((ptr = wcschr(tables, ' ')))
1250             *ptr = '\0';
1251 
1252         table = malloc(sizeof(*table));
1253         if (!table)
1254         {
1255             r = ERROR_OUTOFMEMORY;
1256             goto end;
1257         }
1258 
1259         r = TABLE_CreateView(db, tables, &table->view);
1260         if (r != ERROR_SUCCESS)
1261         {
1262             WARN("can't create table: %s\n", debugstr_w(tables));
1263             free(table);
1264             r = ERROR_BAD_QUERY_SYNTAX;
1265             goto end;
1266         }
1267 
1268         r = table->view->ops->get_dimensions(table->view, NULL,
1269                                              &table->col_count);
1270         if (r != ERROR_SUCCESS)
1271         {
1272             ERR("can't get table dimensions\n");
1273             table->view->ops->delete(table->view);
1274             free(table);
1275             goto end;
1276         }
1277 
1278         wv->col_count += table->col_count;
1279         table->table_index = wv->table_count++;
1280 
1281         table->next = wv->tables;
1282         wv->tables = table;
1283 
1284         if (!ptr)
1285             break;
1286 
1287         tables = ptr + 1;
1288     }
1289 
1290     if( cond )
1291     {
1292         r = WHERE_VerifyCondition( wv, cond, &valid );
1293         if( r != ERROR_SUCCESS )
1294             goto end;
1295         if( !valid ) {
1296             r = ERROR_FUNCTION_FAILED;
1297             goto end;
1298         }
1299     }
1300 
1301     *view = (MSIVIEW*) wv;
1302 
1303     return ERROR_SUCCESS;
1304 end:
1305     WHERE_delete(&wv->view);
1306 
1307     return r;
1308 }
1309