gdi32: Implement SelectFont as a standard driver entry point.
[wine] / dlls / msi / where.c
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 "wine/unicode.h"
30 #include "msi.h"
31 #include "msiquery.h"
32 #include "objbase.h"
33 #include "objidl.h"
34 #include "msipriv.h"
35 #include "winnls.h"
36
37 #include "query.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
40
41 /* below is the query interface to a table */
42 typedef struct tagMSIROWENTRY
43 {
44     struct tagMSIWHEREVIEW *wv; /* used during sorting */
45     UINT values[1];
46 } MSIROWENTRY;
47
48 typedef struct tagJOINTABLE
49 {
50     struct tagJOINTABLE *next;
51     MSIVIEW *view;
52     UINT col_count;
53     UINT row_count;
54     UINT table_index;
55 } JOINTABLE;
56
57 typedef struct tagMSIORDERINFO
58 {
59     UINT col_count;
60     UINT error;
61     union ext_column columns[1];
62 } MSIORDERINFO;
63
64 typedef struct tagMSIWHEREVIEW
65 {
66     MSIVIEW        view;
67     MSIDATABASE   *db;
68     JOINTABLE     *tables;
69     UINT           row_count;
70     UINT           col_count;
71     UINT           table_count;
72     MSIROWENTRY  **reorder;
73     UINT           reorder_size; /* number of entries available in reorder */
74     struct expr   *cond;
75     UINT           rec_index;
76     MSIORDERINFO  *order_info;
77 } MSIWHEREVIEW;
78
79 static UINT WHERE_evaluate( MSIWHEREVIEW *wv, const UINT rows[],
80                             struct expr *cond, INT *val, MSIRECORD *record );
81
82 #define INITIAL_REORDER_SIZE 16
83
84 #define INVALID_ROW_INDEX (-1)
85
86 static void free_reorder(MSIWHEREVIEW *wv)
87 {
88     UINT i;
89
90     if (!wv->reorder)
91         return;
92
93     for (i = 0; i < wv->row_count; i++)
94         msi_free(wv->reorder[i]);
95
96     msi_free( wv->reorder );
97     wv->reorder = NULL;
98     wv->reorder_size = 0;
99     wv->row_count = 0;
100 }
101
102 static UINT init_reorder(MSIWHEREVIEW *wv)
103 {
104     MSIROWENTRY **new = msi_alloc_zero(sizeof(MSIROWENTRY *) * INITIAL_REORDER_SIZE);
105     if (!new)
106         return ERROR_OUTOFMEMORY;
107
108     free_reorder(wv);
109
110     wv->reorder = new;
111     wv->reorder_size = INITIAL_REORDER_SIZE;
112
113     return ERROR_SUCCESS;
114 }
115
116 static inline UINT find_row(MSIWHEREVIEW *wv, UINT row, UINT *(values[]))
117 {
118     if (row >= wv->row_count)
119         return ERROR_NO_MORE_ITEMS;
120
121     *values = wv->reorder[row]->values;
122
123     return ERROR_SUCCESS;
124 }
125
126 static UINT add_row(MSIWHEREVIEW *wv, UINT vals[])
127 {
128     MSIROWENTRY *new;
129
130     if (wv->reorder_size <= wv->row_count)
131     {
132         MSIROWENTRY **new_reorder;
133         UINT newsize = wv->reorder_size * 2;
134
135         new_reorder = msi_realloc_zero(wv->reorder, sizeof(MSIROWENTRY *) * newsize);
136         if (!new_reorder)
137             return ERROR_OUTOFMEMORY;
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 (strcmpW(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(strcmpW(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_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
263 {
264     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
265
266     TRACE("%p %d %p\n", wv, row, rec );
267
268     if (!wv->tables)
269         return ERROR_FUNCTION_FAILED;
270
271     return msi_view_get_row( wv->db, view, row, rec );
272 }
273
274 static UINT WHERE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
275 {
276     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
277     UINT i, r, offset = 0;
278     JOINTABLE *table = wv->tables;
279     UINT *rows;
280     UINT mask_copy = mask;
281
282     TRACE("%p %d %p %08x\n", wv, row, rec, mask );
283
284     if( !wv->tables )
285          return ERROR_FUNCTION_FAILED;
286
287     r = find_row(wv, row, &rows);
288     if (r != ERROR_SUCCESS)
289         return r;
290
291     if (mask >= 1 << wv->col_count)
292         return ERROR_INVALID_PARAMETER;
293
294     do
295     {
296         for (i = 0; i < table->col_count; i++) {
297             UINT type;
298
299             if (!(mask_copy & (1 << i)))
300                 continue;
301             r = table->view->ops->get_column_info(table->view, i + 1, NULL,
302                                             &type, NULL, NULL );
303             if (r != ERROR_SUCCESS)
304                 return r;
305             if (type & MSITYPE_KEY)
306                 return ERROR_FUNCTION_FAILED;
307         }
308         mask_copy >>= table->col_count;
309     }
310     while (mask_copy && (table = table->next));
311
312     table = wv->tables;
313
314     do
315     {
316         const UINT col_count = table->col_count;
317         UINT i;
318         MSIRECORD *reduced;
319         UINT reduced_mask = (mask >> offset) & ((1 << col_count) - 1);
320
321         if (!reduced_mask)
322         {
323             offset += col_count;
324             continue;
325         }
326
327         reduced = MSI_CreateRecord(col_count);
328         if (!reduced)
329             return ERROR_FUNCTION_FAILED;
330
331         for (i = 1; i <= col_count; i++)
332         {
333             r = MSI_RecordCopyField(rec, i + offset, reduced, i);
334             if (r != ERROR_SUCCESS)
335                 break;
336         }
337
338         offset += col_count;
339
340         if (r == ERROR_SUCCESS)
341             r = table->view->ops->set_row(table->view, rows[table->table_index], reduced, reduced_mask);
342
343         msiobj_release(&reduced->hdr);
344     }
345     while ((table = table->next));
346     return r;
347 }
348
349 static UINT WHERE_delete_row(struct tagMSIVIEW *view, UINT row)
350 {
351     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
352     UINT r;
353     UINT *rows;
354
355     TRACE("(%p %d)\n", view, row);
356
357     if (!wv->tables)
358         return ERROR_FUNCTION_FAILED;
359
360     r = find_row(wv, row, &rows);
361     if ( r != ERROR_SUCCESS )
362         return r;
363
364     if (wv->table_count > 1)
365         return ERROR_CALL_NOT_IMPLEMENTED;
366
367     return wv->tables->view->ops->delete_row(wv->tables->view, rows[0]);
368 }
369
370 static INT INT_evaluate_binary( MSIWHEREVIEW *wv, const UINT rows[],
371                                 const struct complex_expr *expr, INT *val, MSIRECORD *record )
372 {
373     UINT rl, rr;
374     INT lval, rval;
375
376     rl = WHERE_evaluate(wv, rows, expr->left, &lval, record);
377     if (rl != ERROR_SUCCESS && rl != ERROR_CONTINUE)
378         return rl;
379     rr = WHERE_evaluate(wv, rows, expr->right, &rval, record);
380     if (rr != ERROR_SUCCESS && rr != ERROR_CONTINUE)
381         return rr;
382
383     if (rl == ERROR_CONTINUE || rr == ERROR_CONTINUE)
384     {
385         if (rl == rr)
386         {
387             *val = TRUE;
388             return ERROR_CONTINUE;
389         }
390
391         if (expr->op == OP_AND)
392         {
393             if ((rl == ERROR_CONTINUE && !rval) || (rr == ERROR_CONTINUE && !lval))
394             {
395                 *val = FALSE;
396                 return ERROR_SUCCESS;
397             }
398         }
399         else if (expr->op == OP_OR)
400         {
401             if ((rl == ERROR_CONTINUE && rval) || (rr == ERROR_CONTINUE && lval))
402             {
403                 *val = TRUE;
404                 return ERROR_SUCCESS;
405             }
406         }
407
408         *val = TRUE;
409         return ERROR_CONTINUE;
410     }
411
412     switch( expr->op )
413     {
414     case OP_EQ:
415         *val = ( lval == rval );
416         break;
417     case OP_AND:
418         *val = ( lval && rval );
419         break;
420     case OP_OR:
421         *val = ( lval || rval );
422         break;
423     case OP_GT:
424         *val = ( lval > rval );
425         break;
426     case OP_LT:
427         *val = ( lval < rval );
428         break;
429     case OP_LE:
430         *val = ( lval <= rval );
431         break;
432     case OP_GE:
433         *val = ( lval >= rval );
434         break;
435     case OP_NE:
436         *val = ( lval != rval );
437         break;
438     default:
439         ERR("Unknown operator %d\n", expr->op );
440         return ERROR_FUNCTION_FAILED;
441     }
442
443     return ERROR_SUCCESS;
444 }
445
446 static inline UINT expr_fetch_value(const union ext_column *expr, const UINT rows[], UINT *val)
447 {
448     JOINTABLE *table = expr->parsed.table;
449
450     if( rows[table->table_index] == INVALID_ROW_INDEX )
451     {
452         *val = 1;
453         return ERROR_CONTINUE;
454     }
455     return table->view->ops->fetch_int(table->view, rows[table->table_index],
456                                         expr->parsed.column, val);
457 }
458
459
460 static UINT INT_evaluate_unary( MSIWHEREVIEW *wv, const UINT rows[],
461                                 const struct complex_expr *expr, INT *val, MSIRECORD *record )
462 {
463     UINT r;
464     UINT lval;
465
466     r = expr_fetch_value(&expr->left->u.column, rows, &lval);
467     if(r != ERROR_SUCCESS)
468         return r;
469
470     switch( expr->op )
471     {
472     case OP_ISNULL:
473         *val = !lval;
474         break;
475     case OP_NOTNULL:
476         *val = lval;
477         break;
478     default:
479         ERR("Unknown operator %d\n", expr->op );
480         return ERROR_FUNCTION_FAILED;
481     }
482     return ERROR_SUCCESS;
483 }
484
485 static UINT STRING_evaluate( MSIWHEREVIEW *wv, const UINT rows[],
486                                      const struct expr *expr,
487                                      const MSIRECORD *record,
488                                      const WCHAR **str )
489 {
490     UINT val = 0, r = ERROR_SUCCESS;
491
492     switch( expr->type )
493     {
494     case EXPR_COL_NUMBER_STRING:
495         r = expr_fetch_value(&expr->u.column, rows, &val);
496         if (r == ERROR_SUCCESS)
497             *str =  msi_string_lookup_id(wv->db->strings, val);
498         else
499             *str = NULL;
500         break;
501
502     case EXPR_SVAL:
503         *str = expr->u.sval;
504         break;
505
506     case EXPR_WILDCARD:
507         *str = MSI_RecordGetString(record, ++wv->rec_index);
508         break;
509
510     default:
511         ERR("Invalid expression type\n");
512         r = ERROR_FUNCTION_FAILED;
513         *str = NULL;
514         break;
515     }
516     return r;
517 }
518
519 static UINT STRCMP_Evaluate( MSIWHEREVIEW *wv, const UINT rows[], const struct complex_expr *expr,
520                              INT *val, const MSIRECORD *record )
521 {
522     int sr;
523     const WCHAR *l_str, *r_str;
524     UINT r;
525
526     *val = TRUE;
527     r = STRING_evaluate(wv, rows, expr->left, record, &l_str);
528     if (r == ERROR_CONTINUE)
529         return r;
530     r = STRING_evaluate(wv, rows, expr->right, record, &r_str);
531     if (r == ERROR_CONTINUE)
532         return r;
533
534     if( l_str == r_str ||
535         ((!l_str || !*l_str) && (!r_str || !*r_str)) )
536         sr = 0;
537     else if( l_str && ! r_str )
538         sr = 1;
539     else if( r_str && ! l_str )
540         sr = -1;
541     else
542         sr = strcmpW( l_str, r_str );
543
544     *val = ( expr->op == OP_EQ && ( sr == 0 ) ) ||
545            ( expr->op == OP_NE && ( sr != 0 ) );
546
547     return ERROR_SUCCESS;
548 }
549
550 static UINT WHERE_evaluate( MSIWHEREVIEW *wv, const UINT rows[],
551                             struct expr *cond, INT *val, MSIRECORD *record )
552 {
553     UINT r, tval;
554
555     if( !cond )
556     {
557         *val = TRUE;
558         return ERROR_SUCCESS;
559     }
560
561     switch( cond->type )
562     {
563     case EXPR_COL_NUMBER:
564         r = expr_fetch_value(&cond->u.column, rows, &tval);
565         if( r != ERROR_SUCCESS )
566             return r;
567         *val = tval - 0x8000;
568         return ERROR_SUCCESS;
569
570     case EXPR_COL_NUMBER32:
571         r = expr_fetch_value(&cond->u.column, rows, &tval);
572         if( r != ERROR_SUCCESS )
573             return r;
574         *val = tval - 0x80000000;
575         return r;
576
577     case EXPR_UVAL:
578         *val = cond->u.uval;
579         return ERROR_SUCCESS;
580
581     case EXPR_COMPLEX:
582         return INT_evaluate_binary(wv, rows, &cond->u.expr, val, record);
583
584     case EXPR_UNARY:
585         return INT_evaluate_unary( wv, rows, &cond->u.expr, val, record );
586
587     case EXPR_STRCMP:
588         return STRCMP_Evaluate( wv, rows, &cond->u.expr, val, record );
589
590     case EXPR_WILDCARD:
591         *val = MSI_RecordGetInteger( record, ++wv->rec_index );
592         return ERROR_SUCCESS;
593
594     default:
595         ERR("Invalid expression type\n");
596         break;
597     }
598
599     return ERROR_SUCCESS;
600 }
601
602 static UINT check_condition( MSIWHEREVIEW *wv, MSIRECORD *record, JOINTABLE *table,
603                              UINT table_rows[] )
604 {
605     UINT r = ERROR_FUNCTION_FAILED;
606     INT val;
607
608     for (table_rows[table->table_index] = 0; table_rows[table->table_index] < table->row_count;
609          table_rows[table->table_index]++)
610     {
611         val = 0;
612         wv->rec_index = 0;
613         r = WHERE_evaluate( wv, table_rows, wv->cond, &val, record );
614         if (r != ERROR_SUCCESS && r != ERROR_CONTINUE)
615             break;
616         if (val)
617         {
618             if (table->next)
619             {
620                 r = check_condition(wv, record, table->next, table_rows);
621                 if (r != ERROR_SUCCESS)
622                     break;
623             }
624             else
625             {
626                 if (r != ERROR_SUCCESS)
627                     break;
628                 add_row (wv, table_rows);
629             }
630         }
631     }
632     table_rows[table->table_index] = INVALID_ROW_INDEX;
633     return r;
634 }
635
636 static int compare_entry( const void *left, const void *right )
637 {
638     const MSIROWENTRY *le = *(const MSIROWENTRY**)left;
639     const MSIROWENTRY *re = *(const MSIROWENTRY**)right;
640     const MSIWHEREVIEW *wv = le->wv;
641     MSIORDERINFO *order = wv->order_info;
642     UINT i, j, r, l_val, r_val;
643
644     assert(le->wv == re->wv);
645
646     if (order)
647     {
648         for (i = 0; i < order->col_count; i++)
649         {
650             const union ext_column *column = &order->columns[i];
651
652             r = column->parsed.table->view->ops->fetch_int(column->parsed.table->view,
653                           le->values[column->parsed.table->table_index],
654                           column->parsed.column, &l_val);
655             if (r != ERROR_SUCCESS)
656             {
657                 order->error = r;
658                 return 0;
659             }
660
661             r = column->parsed.table->view->ops->fetch_int(column->parsed.table->view,
662                           re->values[column->parsed.table->table_index],
663                           column->parsed.column, &r_val);
664             if (r != ERROR_SUCCESS)
665             {
666                 order->error = r;
667                 return 0;
668             }
669
670             if (l_val != r_val)
671                 return l_val < r_val ? -1 : 1;
672         }
673     }
674
675     for (j = 0; j < wv->table_count; j++)
676     {
677         if (le->values[j] != re->values[j])
678             return le->values[j] < re->values[j] ? -1 : 1;
679     }
680     return 0;
681 }
682
683 static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
684 {
685     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
686     UINT r;
687     JOINTABLE *table = wv->tables;
688     UINT *rows;
689     int i;
690
691     TRACE("%p %p\n", wv, record);
692
693     if( !table )
694          return ERROR_FUNCTION_FAILED;
695
696     r = init_reorder(wv);
697     if (r != ERROR_SUCCESS)
698         return r;
699
700     do
701     {
702         table->view->ops->execute(table->view, NULL);
703
704         r = table->view->ops->get_dimensions(table->view, &table->row_count, NULL);
705         if (r != ERROR_SUCCESS)
706         {
707             ERR("failed to get table dimensions\n");
708             return r;
709         }
710
711         /* each table must have at least one row */
712         if (table->row_count == 0)
713             return ERROR_SUCCESS;
714     }
715     while ((table = table->next));
716
717     rows = msi_alloc( wv->table_count * sizeof(*rows) );
718     for (i = 0; i < wv->table_count; i++)
719         rows[i] = INVALID_ROW_INDEX;
720
721     r =  check_condition(wv, record, wv->tables, rows);
722
723     if (wv->order_info)
724         wv->order_info->error = ERROR_SUCCESS;
725
726     qsort(wv->reorder, wv->row_count, sizeof(MSIROWENTRY *), compare_entry);
727
728     if (wv->order_info)
729         r = wv->order_info->error;
730
731     msi_free( rows );
732     return r;
733 }
734
735 static UINT WHERE_close( struct tagMSIVIEW *view )
736 {
737     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
738     JOINTABLE *table = wv->tables;
739
740     TRACE("%p\n", wv );
741
742     if (!table)
743         return ERROR_FUNCTION_FAILED;
744
745     do
746         table->view->ops->close(table->view);
747     while ((table = table->next));
748
749     return ERROR_SUCCESS;
750 }
751
752 static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
753 {
754     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
755
756     TRACE("%p %p %p\n", wv, rows, cols );
757
758     if(!wv->tables)
759          return ERROR_FUNCTION_FAILED;
760
761     if (rows)
762     {
763         if (!wv->reorder)
764             return ERROR_FUNCTION_FAILED;
765         *rows = wv->row_count;
766     }
767
768     if (cols)
769         *cols = wv->col_count;
770
771     return ERROR_SUCCESS;
772 }
773
774 static UINT WHERE_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name,
775                                    UINT *type, BOOL *temporary, LPCWSTR *table_name )
776 {
777     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
778     JOINTABLE *table;
779
780     TRACE("%p %d %p %p %p %p\n", wv, n, name, type, temporary, table_name );
781
782     if(!wv->tables)
783          return ERROR_FUNCTION_FAILED;
784
785     table = find_table(wv, n, &n);
786     if (!table)
787         return ERROR_FUNCTION_FAILED;
788
789     return table->view->ops->get_column_info(table->view, n, name,
790                                             type, temporary, table_name);
791 }
792
793 static UINT join_find_row( MSIWHEREVIEW *wv, MSIRECORD *rec, UINT *row )
794 {
795     LPCWSTR str;
796     UINT r, i, id, data;
797
798     str = MSI_RecordGetString( rec, 1 );
799     r = msi_string2idW( wv->db->strings, str, &id );
800     if (r != ERROR_SUCCESS)
801         return r;
802
803     for (i = 0; i < wv->row_count; i++)
804     {
805         WHERE_fetch_int( &wv->view, i, 1, &data );
806
807         if (data == id)
808         {
809             *row = i;
810             return ERROR_SUCCESS;
811         }
812     }
813
814     return ERROR_FUNCTION_FAILED;
815 }
816
817 static UINT join_modify_update( struct tagMSIVIEW *view, MSIRECORD *rec )
818 {
819     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
820     UINT r, row, i, mask = 0;
821     MSIRECORD *current;
822
823
824     r = join_find_row( wv, rec, &row );
825     if (r != ERROR_SUCCESS)
826         return r;
827
828     r = msi_view_get_row( wv->db, view, row, &current );
829     if (r != ERROR_SUCCESS)
830         return r;
831
832     assert(MSI_RecordGetFieldCount(rec) == MSI_RecordGetFieldCount(current));
833
834     for (i = MSI_RecordGetFieldCount(rec); i > 0; i--)
835     {
836         if (!MSI_RecordsAreFieldsEqual(rec, current, i))
837             mask |= 1 << (i - 1);
838     }
839      msiobj_release(&current->hdr);
840
841     return WHERE_set_row( view, row, rec, mask );
842 }
843
844 static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
845                           MSIRECORD *rec, UINT row )
846 {
847     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
848     JOINTABLE *table = wv->tables;
849     UINT r;
850
851     TRACE("%p %d %p\n", wv, eModifyMode, rec);
852
853     if (!table)
854         return ERROR_FUNCTION_FAILED;
855
856     if (!table->next)
857     {
858         UINT *rows;
859
860         if (find_row(wv, row - 1, &rows) == ERROR_SUCCESS)
861             row = rows[0] + 1;
862         else
863             row = -1;
864
865         return table->view->ops->modify(table->view, eModifyMode, rec, row);
866     }
867
868     switch (eModifyMode)
869     {
870     case MSIMODIFY_UPDATE:
871         return join_modify_update( view, rec );
872
873     case MSIMODIFY_ASSIGN:
874     case MSIMODIFY_DELETE:
875     case MSIMODIFY_INSERT:
876     case MSIMODIFY_INSERT_TEMPORARY:
877     case MSIMODIFY_MERGE:
878     case MSIMODIFY_REPLACE:
879     case MSIMODIFY_SEEK:
880     case MSIMODIFY_VALIDATE:
881     case MSIMODIFY_VALIDATE_DELETE:
882     case MSIMODIFY_VALIDATE_FIELD:
883     case MSIMODIFY_VALIDATE_NEW:
884         r = ERROR_FUNCTION_FAILED;
885         break;
886
887     case MSIMODIFY_REFRESH:
888         r = ERROR_CALL_NOT_IMPLEMENTED;
889         break;
890
891     default:
892         WARN("%p %d %p %u - unknown mode\n", view, eModifyMode, rec, row );
893         r = ERROR_INVALID_PARAMETER;
894         break;
895     }
896
897     return r;
898 }
899
900 static UINT WHERE_delete( struct tagMSIVIEW *view )
901 {
902     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
903     JOINTABLE *table = wv->tables;
904
905     TRACE("%p\n", wv );
906
907     while(table)
908     {
909         JOINTABLE *next;
910
911         table->view->ops->delete(table->view);
912         table->view = NULL;
913         next = table->next;
914         msi_free(table);
915         table = next;
916     }
917     wv->tables = NULL;
918     wv->table_count = 0;
919
920     free_reorder(wv);
921
922     msi_free(wv->order_info);
923     wv->order_info = NULL;
924
925     msiobj_release( &wv->db->hdr );
926     msi_free( wv );
927
928     return ERROR_SUCCESS;
929 }
930
931 static UINT WHERE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
932     UINT val, UINT *row, MSIITERHANDLE *handle )
933 {
934     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
935     UINT i, row_value;
936
937     TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
938
939     if (!wv->tables)
940          return ERROR_FUNCTION_FAILED;
941
942     if (col == 0 || col > wv->col_count)
943         return ERROR_INVALID_PARAMETER;
944
945     for (i = PtrToUlong(*handle); i < wv->row_count; i++)
946     {
947         if (view->ops->fetch_int( view, i, col, &row_value ) != ERROR_SUCCESS)
948             continue;
949
950         if (row_value == val)
951         {
952             *row = i;
953             *handle = UlongToPtr(i + 1);
954             return ERROR_SUCCESS;
955         }
956     }
957
958     return ERROR_NO_MORE_ITEMS;
959 }
960
961 static UINT WHERE_sort(struct tagMSIVIEW *view, column_info *columns)
962 {
963     MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
964     JOINTABLE *table = wv->tables;
965     column_info *column = columns;
966     MSIORDERINFO *orderinfo;
967     UINT r, count = 0;
968     int i;
969
970     TRACE("%p %p\n", view, columns);
971
972     if (!table)
973         return ERROR_FUNCTION_FAILED;
974
975     while (column)
976     {
977         count++;
978         column = column->next;
979     }
980
981     if (count == 0)
982         return ERROR_SUCCESS;
983
984     orderinfo = msi_alloc(sizeof(MSIORDERINFO) + (count - 1) * sizeof(union ext_column));
985     if (!orderinfo)
986         return ERROR_OUTOFMEMORY;
987
988     orderinfo->col_count = count;
989
990     column = columns;
991
992     for (i = 0; i < count; i++)
993     {
994         orderinfo->columns[i].unparsed.column = column->column;
995         orderinfo->columns[i].unparsed.table = column->table;
996
997         r = parse_column(wv, &orderinfo->columns[i], NULL);
998         if (r != ERROR_SUCCESS)
999             goto error;
1000     }
1001
1002     wv->order_info = orderinfo;
1003
1004     return ERROR_SUCCESS;
1005 error:
1006     msi_free(orderinfo);
1007     return r;
1008 }
1009
1010 static const MSIVIEWOPS where_ops =
1011 {
1012     WHERE_fetch_int,
1013     WHERE_fetch_stream,
1014     WHERE_get_row,
1015     WHERE_set_row,
1016     NULL,
1017     WHERE_delete_row,
1018     WHERE_execute,
1019     WHERE_close,
1020     WHERE_get_dimensions,
1021     WHERE_get_column_info,
1022     WHERE_modify,
1023     WHERE_delete,
1024     WHERE_find_matching_rows,
1025     NULL,
1026     NULL,
1027     NULL,
1028     NULL,
1029     WHERE_sort,
1030     NULL,
1031 };
1032
1033 static UINT WHERE_VerifyCondition( MSIWHEREVIEW *wv, struct expr *cond,
1034                                    UINT *valid )
1035 {
1036     UINT r;
1037
1038     switch( cond->type )
1039     {
1040     case EXPR_COLUMN:
1041     {
1042         UINT type;
1043
1044         *valid = FALSE;
1045
1046         r = parse_column(wv, &cond->u.column, &type);
1047         if (r != ERROR_SUCCESS)
1048             break;
1049
1050         if (type&MSITYPE_STRING)
1051             cond->type = EXPR_COL_NUMBER_STRING;
1052         else if ((type&0xff) == 4)
1053             cond->type = EXPR_COL_NUMBER32;
1054         else
1055             cond->type = EXPR_COL_NUMBER;
1056
1057         *valid = TRUE;
1058         break;
1059     }
1060     case EXPR_COMPLEX:
1061         r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid );
1062         if( r != ERROR_SUCCESS )
1063             return r;
1064         if( !*valid )
1065             return ERROR_SUCCESS;
1066         r = WHERE_VerifyCondition( wv, cond->u.expr.right, valid );
1067         if( r != ERROR_SUCCESS )
1068             return r;
1069
1070         /* check the type of the comparison */
1071         if( ( cond->u.expr.left->type == EXPR_SVAL ) ||
1072             ( cond->u.expr.left->type == EXPR_COL_NUMBER_STRING ) ||
1073             ( cond->u.expr.right->type == EXPR_SVAL ) ||
1074             ( cond->u.expr.right->type == EXPR_COL_NUMBER_STRING ) )
1075         {
1076             switch( cond->u.expr.op )
1077             {
1078             case OP_EQ:
1079             case OP_NE:
1080                 break;
1081             default:
1082                 *valid = FALSE;
1083                 return ERROR_INVALID_PARAMETER;
1084             }
1085
1086             /* FIXME: check we're comparing a string to a column */
1087
1088             cond->type = EXPR_STRCMP;
1089         }
1090
1091         break;
1092     case EXPR_UNARY:
1093         if ( cond->u.expr.left->type != EXPR_COLUMN )
1094         {
1095             *valid = FALSE;
1096             return ERROR_INVALID_PARAMETER;
1097         }
1098         r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid );
1099         if( r != ERROR_SUCCESS )
1100             return r;
1101         break;
1102     case EXPR_IVAL:
1103         *valid = 1;
1104         cond->type = EXPR_UVAL;
1105         cond->u.uval = cond->u.ival;
1106         break;
1107     case EXPR_WILDCARD:
1108         *valid = 1;
1109         break;
1110     case EXPR_SVAL:
1111         *valid = 1;
1112         break;
1113     default:
1114         ERR("Invalid expression type\n");
1115         *valid = 0;
1116         break;
1117     }
1118
1119     return ERROR_SUCCESS;
1120 }
1121
1122 UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables,
1123                        struct expr *cond )
1124 {
1125     MSIWHEREVIEW *wv = NULL;
1126     UINT r, valid = 0;
1127     WCHAR *ptr;
1128
1129     TRACE("(%s)\n", debugstr_w(tables) );
1130
1131     wv = msi_alloc_zero( sizeof *wv );
1132     if( !wv )
1133         return ERROR_FUNCTION_FAILED;
1134     
1135     /* fill the structure */
1136     wv->view.ops = &where_ops;
1137     msiobj_addref( &db->hdr );
1138     wv->db = db;
1139     wv->cond = cond;
1140
1141     while (*tables)
1142     {
1143         JOINTABLE *table;
1144
1145         if ((ptr = strchrW(tables, ' ')))
1146             *ptr = '\0';
1147
1148         table = msi_alloc(sizeof(JOINTABLE));
1149         if (!table)
1150         {
1151             r = ERROR_OUTOFMEMORY;
1152             goto end;
1153         }
1154
1155         r = TABLE_CreateView(db, tables, &table->view);
1156         if (r != ERROR_SUCCESS)
1157         {
1158             WARN("can't create table: %s\n", debugstr_w(tables));
1159             msi_free(table);
1160             r = ERROR_BAD_QUERY_SYNTAX;
1161             goto end;
1162         }
1163
1164         r = table->view->ops->get_dimensions(table->view, NULL,
1165                                              &table->col_count);
1166         if (r != ERROR_SUCCESS)
1167         {
1168             ERR("can't get table dimensions\n");
1169             goto end;
1170         }
1171
1172         wv->col_count += table->col_count;
1173         table->table_index = wv->table_count++;
1174
1175         table->next = wv->tables;
1176         wv->tables = table;
1177
1178         if (!ptr)
1179             break;
1180
1181         tables = ptr + 1;
1182     }
1183
1184     if( cond )
1185     {
1186         r = WHERE_VerifyCondition( wv, cond, &valid );
1187         if( r != ERROR_SUCCESS )
1188             goto end;
1189         if( !valid ) {
1190             r = ERROR_FUNCTION_FAILED;
1191             goto end;
1192         }
1193     }
1194
1195     *view = (MSIVIEW*) wv;
1196
1197     return ERROR_SUCCESS;
1198 end:
1199     WHERE_delete(&wv->view);
1200
1201     return r;
1202 }