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