msi: Implement proper sorting in WHEREVIEW.
[wine/multimedia.git] / dlls / msi / where.c
blob16b6c03dfc66e953e5da898cd7d3d851afbd9dbd
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002 Mike McCormack for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <assert.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "wine/debug.h"
28 #include "wine/unicode.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"
36 #include "query.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
40 /* below is the query interface to a table */
41 typedef struct tagMSIROWENTRY
43 struct tagMSIWHEREVIEW *wv; /* used during sorting */
44 UINT values[1];
45 } MSIROWENTRY;
47 typedef struct tagJOINTABLE
49 struct tagJOINTABLE *next;
50 MSIVIEW *view;
51 UINT col_count;
52 UINT row_count;
53 UINT table_index;
54 } JOINTABLE;
56 typedef struct tagMSIORDERINFO
58 UINT col_count;
59 UINT error;
60 union ext_column columns[1];
61 } MSIORDERINFO;
63 typedef struct tagMSIWHEREVIEW
65 MSIVIEW view;
66 MSIDATABASE *db;
67 JOINTABLE *tables;
68 UINT row_count;
69 UINT col_count;
70 UINT table_count;
71 MSIROWENTRY **reorder;
72 UINT reorder_size; /* number of entries available in reorder */
73 struct expr *cond;
74 UINT rec_index;
75 MSIORDERINFO *order_info;
76 } MSIWHEREVIEW;
78 #define INITIAL_REORDER_SIZE 16
80 static UINT init_reorder(MSIWHEREVIEW *wv)
82 MSIROWENTRY **new = msi_alloc_zero(sizeof(MSIROWENTRY *) * INITIAL_REORDER_SIZE);
83 if (!new)
84 return ERROR_OUTOFMEMORY;
86 if (wv->reorder)
87 msi_free(wv->reorder);
89 wv->reorder = new;
90 wv->reorder_size = INITIAL_REORDER_SIZE;
91 wv->row_count = 0;
93 return ERROR_SUCCESS;
96 static void free_reorder(MSIWHEREVIEW *wv)
98 UINT i;
100 if (!wv->reorder)
101 return;
103 for (i = 0; i < wv->row_count; i++)
104 msi_free(wv->reorder[i]);
106 msi_free( wv->reorder );
107 wv->reorder = NULL;
108 wv->reorder_size = 0;
109 wv->row_count = 0;
112 static inline UINT find_row(MSIWHEREVIEW *wv, UINT row, UINT *(values[]))
114 if (row >= wv->row_count)
115 return ERROR_NO_MORE_ITEMS;
117 *values = wv->reorder[row]->values;
119 return ERROR_SUCCESS;
122 static UINT add_row(MSIWHEREVIEW *wv, UINT vals[])
124 MSIROWENTRY *new;
126 if (wv->reorder_size <= wv->row_count)
128 MSIROWENTRY **new_reorder;
129 UINT newsize = wv->reorder_size * 2;
131 new_reorder = msi_realloc_zero(wv->reorder, sizeof(MSIROWENTRY *) * newsize);
132 if (!new_reorder)
133 return ERROR_OUTOFMEMORY;
135 wv->reorder = new_reorder;
136 wv->reorder_size = newsize;
139 new = msi_alloc(FIELD_OFFSET( MSIROWENTRY, values[wv->table_count] ));
141 if (!new)
142 return ERROR_OUTOFMEMORY;
144 wv->reorder[wv->row_count++] = new;
146 memcpy(new->values, vals, wv->table_count * sizeof(UINT));
147 new->wv = wv;
149 return ERROR_SUCCESS;
152 JOINTABLE *find_table(MSIWHEREVIEW *wv, UINT col, UINT *table_col)
154 JOINTABLE *table = wv->tables;
156 if(col == 0 || col > wv->col_count)
157 return NULL;
159 while (col > table->col_count)
161 col -= table->col_count;
162 table = table->next;
163 assert(table);
166 *table_col = col;
167 return table;
170 static UINT parse_column(MSIWHEREVIEW *wv, union ext_column *column,
171 UINT *column_type)
173 JOINTABLE *table = wv->tables;
174 UINT i, r;
178 LPCWSTR table_name;
180 if (column->unparsed.table)
182 r = table->view->ops->get_column_info(table->view, 1, NULL, NULL,
183 NULL, &table_name);
184 if (r != ERROR_SUCCESS)
185 return r;
186 if (strcmpW(table_name, column->unparsed.table) != 0)
187 continue;
190 for(i = 1; i <= table->col_count; i++)
192 LPCWSTR col_name;
194 r = table->view->ops->get_column_info(table->view, i, &col_name, column_type,
195 NULL, NULL);
196 if(r != ERROR_SUCCESS )
197 return r;
199 if(strcmpW(col_name, column->unparsed.column))
200 continue;
201 column->parsed.column = i;
202 column->parsed.table = table;
203 return ERROR_SUCCESS;
204 break;
207 while ((table = table->next));
209 WARN("Couldn't find column %s.%s\n", debugstr_w( column->unparsed.table ), debugstr_w( column->unparsed.column ) );
210 return ERROR_BAD_QUERY_SYNTAX;
213 static UINT WHERE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
215 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
216 JOINTABLE *table;
217 UINT *rows;
218 UINT r;
220 TRACE("%p %d %d %p\n", wv, row, col, val );
222 if( !wv->tables )
223 return ERROR_FUNCTION_FAILED;
225 r = find_row(wv, row, &rows);
226 if (r != ERROR_SUCCESS)
227 return r;
229 table = find_table(wv, col, &col);
230 if (!table)
231 return ERROR_FUNCTION_FAILED;
233 return table->view->ops->fetch_int(table->view, rows[table->table_index], col, val);
236 static UINT WHERE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
238 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
239 JOINTABLE *table;
240 UINT *rows;
241 UINT r;
243 TRACE("%p %d %d %p\n", wv, row, col, stm );
245 if( !wv->tables )
246 return ERROR_FUNCTION_FAILED;
248 r = find_row(wv, row, &rows);
249 if (r != ERROR_SUCCESS)
250 return r;
252 table = find_table(wv, col, &col);
253 if (!table)
254 return ERROR_FUNCTION_FAILED;
256 return table->view->ops->fetch_stream( table->view, rows[table->table_index], col, stm );
259 static UINT WHERE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
261 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
263 TRACE("%p %d %p\n", wv, row, rec );
265 if (!wv->tables)
266 return ERROR_FUNCTION_FAILED;
268 return msi_view_get_row( wv->db, view, row, rec );
271 static UINT WHERE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
273 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
274 UINT i, r, offset = 0;
275 JOINTABLE *table = wv->tables;
276 UINT *rows;
277 UINT mask_copy = mask;
279 TRACE("%p %d %p %08x\n", wv, row, rec, mask );
281 if( !wv->tables )
282 return ERROR_FUNCTION_FAILED;
284 r = find_row(wv, row, &rows);
285 if (r != ERROR_SUCCESS)
286 return r;
288 if (mask >= 1 << wv->col_count)
289 return ERROR_INVALID_PARAMETER;
293 for (i = 0; i < table->col_count; i++) {
294 UINT type;
296 if (!(mask_copy & (1 << i)))
297 continue;
298 r = table->view->ops->get_column_info(table->view, i + 1, NULL,
299 &type, NULL, NULL );
300 if (r != ERROR_SUCCESS)
301 return r;
302 if (type & MSITYPE_KEY)
303 return ERROR_FUNCTION_FAILED;
305 mask_copy >>= table->col_count;
307 while (mask_copy && (table = table->next));
309 table = wv->tables;
313 const UINT col_count = table->col_count;
314 UINT i;
315 MSIRECORD *reduced;
316 UINT reduced_mask = (mask >> offset) & ((1 << col_count) - 1);
318 if (!reduced_mask)
320 offset += col_count;
321 continue;
324 reduced = MSI_CreateRecord(col_count);
325 if (!reduced)
326 return ERROR_FUNCTION_FAILED;
328 for (i = 1; i <= col_count; i++)
330 r = MSI_RecordCopyField(rec, i + offset, reduced, i);
331 if (r != ERROR_SUCCESS)
332 break;
335 offset += col_count;
337 if (r == ERROR_SUCCESS)
338 r = table->view->ops->set_row(table->view, rows[table->table_index], reduced, reduced_mask);
340 msiobj_release(&reduced->hdr);
342 while ((table = table->next));
343 return r;
346 static UINT WHERE_delete_row(struct tagMSIVIEW *view, UINT row)
348 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
349 UINT r;
350 UINT *rows;
352 TRACE("(%p %d)\n", view, row);
354 if (!wv->tables)
355 return ERROR_FUNCTION_FAILED;
357 r = find_row(wv, row, &rows);
358 if ( r != ERROR_SUCCESS )
359 return r;
361 if (wv->table_count > 1)
362 return ERROR_CALL_NOT_IMPLEMENTED;
364 return wv->tables->view->ops->delete_row(wv->tables->view, rows[0]);
367 static INT INT_evaluate_binary( INT lval, UINT op, INT rval )
369 switch( op )
371 case OP_EQ:
372 return ( lval == rval );
373 case OP_AND:
374 return ( lval && rval );
375 case OP_OR:
376 return ( lval || rval );
377 case OP_GT:
378 return ( lval > rval );
379 case OP_LT:
380 return ( lval < rval );
381 case OP_LE:
382 return ( lval <= rval );
383 case OP_GE:
384 return ( lval >= rval );
385 case OP_NE:
386 return ( lval != rval );
387 default:
388 ERR("Unknown operator %d\n", op );
390 return 0;
393 static inline UINT expr_fetch_value(const union ext_column *expr, const UINT rows[], UINT *val)
395 JOINTABLE *table = expr->parsed.table;
397 return table->view->ops->fetch_int(table->view, rows[table->table_index],
398 expr->parsed.column, val);
402 static INT INT_evaluate_unary( INT lval, UINT op )
404 switch( op )
406 case OP_ISNULL:
407 return ( !lval );
408 case OP_NOTNULL:
409 return ( lval );
410 default:
411 ERR("Unknown operator %d\n", op );
413 return 0;
416 static const WCHAR *STRING_evaluate( MSIWHEREVIEW *wv, const UINT rows[],
417 const struct expr *expr,
418 const MSIRECORD *record )
420 UINT val = 0, r;
422 switch( expr->type )
424 case EXPR_COL_NUMBER_STRING:
425 r = expr_fetch_value(&expr->u.column, rows, &val);
426 if( r != ERROR_SUCCESS )
427 return NULL;
428 return msi_string_lookup_id( wv->db->strings, val );
430 case EXPR_SVAL:
431 return expr->u.sval;
433 case EXPR_WILDCARD:
434 return MSI_RecordGetString( record, ++wv->rec_index );
436 default:
437 ERR("Invalid expression type\n");
438 break;
440 return NULL;
443 static UINT STRCMP_Evaluate( MSIWHEREVIEW *wv, const UINT rows[], const struct expr *cond,
444 INT *val, const MSIRECORD *record )
446 int sr;
447 const WCHAR *l_str, *r_str;
449 l_str = STRING_evaluate( wv, rows, cond->u.expr.left, record );
450 r_str = STRING_evaluate( wv, rows, cond->u.expr.right, record );
451 if( l_str == r_str ||
452 ((!l_str || !*l_str) && (!r_str || !*r_str)) )
453 sr = 0;
454 else if( l_str && ! r_str )
455 sr = 1;
456 else if( r_str && ! l_str )
457 sr = -1;
458 else
459 sr = strcmpW( l_str, r_str );
461 *val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) ||
462 ( cond->u.expr.op == OP_NE && ( sr != 0 ) );
464 return ERROR_SUCCESS;
467 static UINT WHERE_evaluate( MSIWHEREVIEW *wv, const UINT rows[],
468 struct expr *cond, INT *val, MSIRECORD *record )
470 UINT r, tval;
471 INT lval, rval;
473 if( !cond )
475 *val = TRUE;
476 return ERROR_SUCCESS;
479 switch( cond->type )
481 case EXPR_COL_NUMBER:
482 r = expr_fetch_value(&cond->u.column, rows, &tval);
483 if( r != ERROR_SUCCESS )
484 return r;
485 *val = tval - 0x8000;
486 return ERROR_SUCCESS;
488 case EXPR_COL_NUMBER32:
489 r = expr_fetch_value(&cond->u.column, rows, &tval);
490 if( r != ERROR_SUCCESS )
491 return r;
492 *val = tval - 0x80000000;
493 return r;
495 case EXPR_UVAL:
496 *val = cond->u.uval;
497 return ERROR_SUCCESS;
499 case EXPR_COMPLEX:
500 r = WHERE_evaluate( wv, rows, cond->u.expr.left, &lval, record );
501 if( r != ERROR_SUCCESS )
502 return r;
503 r = WHERE_evaluate( wv, rows, cond->u.expr.right, &rval, record );
504 if( r != ERROR_SUCCESS )
505 return r;
506 *val = INT_evaluate_binary( lval, cond->u.expr.op, rval );
507 return ERROR_SUCCESS;
509 case EXPR_UNARY:
510 r = expr_fetch_value(&cond->u.expr.left->u.column, rows, &tval);
511 if( r != ERROR_SUCCESS )
512 return r;
513 *val = INT_evaluate_unary( tval, cond->u.expr.op );
514 return ERROR_SUCCESS;
516 case EXPR_STRCMP:
517 return STRCMP_Evaluate( wv, rows, cond, val, record );
519 case EXPR_WILDCARD:
520 *val = MSI_RecordGetInteger( record, ++wv->rec_index );
521 return ERROR_SUCCESS;
523 default:
524 ERR("Invalid expression type\n");
525 break;
528 return ERROR_SUCCESS;
531 static UINT check_condition( MSIWHEREVIEW *wv, MSIRECORD *record, JOINTABLE *table,
532 UINT table_rows[] )
534 UINT r = ERROR_FUNCTION_FAILED;
535 INT val;
537 for (table_rows[table->table_index] = 0; table_rows[table->table_index] < table->row_count;
538 table_rows[table->table_index]++)
540 if (table->next)
542 r = check_condition(wv, record, table->next, table_rows);
543 if(r != ERROR_SUCCESS)
544 break;
546 else
548 val = 0;
549 wv->rec_index = 0;
550 r = WHERE_evaluate (wv, table_rows, wv->cond, &val, record);
551 if(r != ERROR_SUCCESS)
552 break;
553 if (!val)
554 continue;
555 add_row(wv, table_rows);
558 return r;
561 static int compare_entry( const void *left, const void *right )
563 const MSIROWENTRY *le = *(const MSIROWENTRY**)left;
564 const MSIROWENTRY *re = *(const MSIROWENTRY**)right;
565 const MSIWHEREVIEW *wv = le->wv;
566 MSIORDERINFO *order = wv->order_info;
567 UINT i, j, r, l_val, r_val;
569 assert(le->wv == re->wv);
571 if (order)
573 for (i = 0; i < order->col_count; i++)
575 const union ext_column *column = &order->columns[i];
577 r = column->parsed.table->view->ops->fetch_int(column->parsed.table->view,
578 le->values[column->parsed.table->table_index],
579 column->parsed.column, &l_val);
580 if (r != ERROR_SUCCESS)
582 order->error = r;
583 return 0;
586 r = column->parsed.table->view->ops->fetch_int(column->parsed.table->view,
587 re->values[column->parsed.table->table_index],
588 column->parsed.column, &r_val);
589 if (r != ERROR_SUCCESS)
591 order->error = r;
592 return 0;
595 if (l_val != r_val)
596 return l_val < r_val ? -1 : 1;
600 for (j = 0; j < wv->table_count; j++)
602 if (le->values[j] != re->values[j])
603 return le->values[j] < re->values[j] ? -1 : 1;
605 return 0;
608 static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
610 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
611 UINT r;
612 JOINTABLE *table = wv->tables;
613 UINT rows[wv->table_count];
615 TRACE("%p %p\n", wv, record);
617 if( !table )
618 return ERROR_FUNCTION_FAILED;
620 r = init_reorder(wv);
621 if (r != ERROR_SUCCESS)
622 return r;
626 table->view->ops->execute(table->view, NULL);
628 r = table->view->ops->get_dimensions(table->view, &table->row_count, NULL);
629 if (r != ERROR_SUCCESS)
631 ERR("failed to get table dimensions\n");
632 return r;
635 /* each table must have at least one row */
636 if (table->row_count == 0)
637 return ERROR_SUCCESS;
639 while ((table = table->next));
641 r = check_condition(wv, record, wv->tables, rows);
643 if (wv->order_info)
644 wv->order_info->error = ERROR_SUCCESS;
646 qsort(wv->reorder, wv->row_count, sizeof(MSIROWENTRY *), compare_entry);
648 if (wv->order_info)
649 r = wv->order_info->error;
651 return r;
654 static UINT WHERE_close( struct tagMSIVIEW *view )
656 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
657 JOINTABLE *table = wv->tables;
659 TRACE("%p\n", wv );
661 if (!table)
662 return ERROR_FUNCTION_FAILED;
665 table->view->ops->close(table->view);
666 while ((table = table->next));
668 return ERROR_SUCCESS;
671 static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
673 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
675 TRACE("%p %p %p\n", wv, rows, cols );
677 if(!wv->tables)
678 return ERROR_FUNCTION_FAILED;
680 if (rows)
682 if (!wv->reorder)
683 return ERROR_FUNCTION_FAILED;
684 *rows = wv->row_count;
687 if (cols)
688 *cols = wv->col_count;
690 return ERROR_SUCCESS;
693 static UINT WHERE_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name,
694 UINT *type, BOOL *temporary, LPCWSTR *table_name )
696 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
697 JOINTABLE *table;
699 TRACE("%p %d %p %p %p %p\n", wv, n, name, type, temporary, table_name );
701 if(!wv->tables)
702 return ERROR_FUNCTION_FAILED;
704 table = find_table(wv, n, &n);
705 if (!table)
706 return ERROR_FUNCTION_FAILED;
708 return table->view->ops->get_column_info(table->view, n, name,
709 type, temporary, table_name);
712 static UINT join_find_row( MSIWHEREVIEW *wv, MSIRECORD *rec, UINT *row )
714 LPCWSTR str;
715 UINT r, i, id, data;
717 str = MSI_RecordGetString( rec, 1 );
718 r = msi_string2idW( wv->db->strings, str, &id );
719 if (r != ERROR_SUCCESS)
720 return r;
722 for (i = 0; i < wv->row_count; i++)
724 WHERE_fetch_int( &wv->view, i, 1, &data );
726 if (data == id)
728 *row = i;
729 return ERROR_SUCCESS;
733 return ERROR_FUNCTION_FAILED;
736 static UINT join_modify_update( struct tagMSIVIEW *view, MSIRECORD *rec )
738 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
739 UINT r, row, i, mask = 0;
740 MSIRECORD *current;
743 r = join_find_row( wv, rec, &row );
744 if (r != ERROR_SUCCESS)
745 return r;
747 r = msi_view_get_row( wv->db, view, row, &current );
748 if (r != ERROR_SUCCESS)
749 return r;
751 assert(MSI_RecordGetFieldCount(rec) == MSI_RecordGetFieldCount(current));
753 for (i = MSI_RecordGetFieldCount(rec); i > 0; i--)
755 if (!MSI_RecordsAreFieldsEqual(rec, current, i))
756 mask |= 1 << (i - 1);
758 msiobj_release(&current->hdr);
760 return WHERE_set_row( view, row, rec, mask );
763 static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
764 MSIRECORD *rec, UINT row )
766 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
767 JOINTABLE *table = wv->tables;
768 UINT r;
770 TRACE("%p %d %p\n", wv, eModifyMode, rec);
772 if (!table)
773 return ERROR_FUNCTION_FAILED;
775 if (!table->next)
777 UINT *rows;
779 if (find_row(wv, row - 1, &rows) == ERROR_SUCCESS)
780 row = rows[0] + 1;
781 else
782 row = -1;
784 return table->view->ops->modify(table->view, eModifyMode, rec, row);
787 switch (eModifyMode)
789 case MSIMODIFY_UPDATE:
790 return join_modify_update( view, rec );
792 case MSIMODIFY_ASSIGN:
793 case MSIMODIFY_DELETE:
794 case MSIMODIFY_INSERT:
795 case MSIMODIFY_INSERT_TEMPORARY:
796 case MSIMODIFY_MERGE:
797 case MSIMODIFY_REPLACE:
798 case MSIMODIFY_SEEK:
799 case MSIMODIFY_VALIDATE:
800 case MSIMODIFY_VALIDATE_DELETE:
801 case MSIMODIFY_VALIDATE_FIELD:
802 case MSIMODIFY_VALIDATE_NEW:
803 r = ERROR_FUNCTION_FAILED;
804 break;
806 case MSIMODIFY_REFRESH:
807 r = ERROR_CALL_NOT_IMPLEMENTED;
808 break;
810 default:
811 WARN("%p %d %p %u - unknown mode\n", view, eModifyMode, rec, row );
812 r = ERROR_INVALID_PARAMETER;
813 break;
816 return r;
819 static UINT WHERE_delete( struct tagMSIVIEW *view )
821 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
822 JOINTABLE *table = wv->tables;
824 TRACE("%p\n", wv );
826 while(table)
828 JOINTABLE *next;
830 table->view->ops->delete(table->view);
831 table->view = NULL;
832 next = table->next;
833 msi_free(table);
834 table = next;
836 wv->tables = NULL;
837 wv->table_count = 0;
839 free_reorder(wv);
841 if (wv->order_info)
843 msi_free(wv->order_info);
844 wv->order_info = NULL;
847 msiobj_release( &wv->db->hdr );
848 msi_free( wv );
850 return ERROR_SUCCESS;
853 static UINT WHERE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
854 UINT val, UINT *row, MSIITERHANDLE *handle )
856 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
857 UINT i, row_value;
859 TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
861 if (!wv->tables)
862 return ERROR_FUNCTION_FAILED;
864 if (col == 0 || col > wv->col_count)
865 return ERROR_INVALID_PARAMETER;
867 for (i = PtrToUlong(*handle); i < wv->row_count; i++)
869 if (view->ops->fetch_int( view, i, col, &row_value ) != ERROR_SUCCESS)
870 continue;
872 if (row_value == val)
874 *row = i;
875 *handle = UlongToPtr(i + 1);
876 return ERROR_SUCCESS;
880 return ERROR_NO_MORE_ITEMS;
883 static UINT WHERE_sort(struct tagMSIVIEW *view, column_info *columns)
885 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
886 JOINTABLE *table = wv->tables;
887 column_info *column = columns;
888 MSIORDERINFO *orderinfo;
889 UINT r, count = 0;
890 int i;
892 TRACE("%p %p\n", view, columns);
894 if (!table)
895 return ERROR_FUNCTION_FAILED;
897 while (column)
899 count++;
900 column = column->next;
903 if (count == 0)
904 return ERROR_SUCCESS;
906 orderinfo = msi_alloc(sizeof(MSIORDERINFO) + (count - 1) * sizeof(union ext_column));
907 if (!orderinfo)
908 return ERROR_OUTOFMEMORY;
910 orderinfo->col_count = count;
912 column = columns;
914 for (i = 0; i < count; i++)
916 orderinfo->columns[i].unparsed.column = column->column;
917 orderinfo->columns[i].unparsed.table = column->table;
919 r = parse_column(wv, &orderinfo->columns[i], NULL);
920 if (r != ERROR_SUCCESS)
921 goto error;
924 wv->order_info = orderinfo;
926 return ERROR_SUCCESS;
927 error:
928 msi_free(orderinfo);
929 return r;
932 static const MSIVIEWOPS where_ops =
934 WHERE_fetch_int,
935 WHERE_fetch_stream,
936 WHERE_get_row,
937 WHERE_set_row,
938 NULL,
939 WHERE_delete_row,
940 WHERE_execute,
941 WHERE_close,
942 WHERE_get_dimensions,
943 WHERE_get_column_info,
944 WHERE_modify,
945 WHERE_delete,
946 WHERE_find_matching_rows,
947 NULL,
948 NULL,
949 NULL,
950 NULL,
951 WHERE_sort,
952 NULL,
955 static UINT WHERE_VerifyCondition( MSIWHEREVIEW *wv, struct expr *cond,
956 UINT *valid )
958 UINT r;
960 switch( cond->type )
962 case EXPR_COLUMN:
964 UINT type;
966 *valid = FALSE;
968 r = parse_column(wv, &cond->u.column, &type);
969 if (r != ERROR_SUCCESS)
970 break;
972 if (type&MSITYPE_STRING)
973 cond->type = EXPR_COL_NUMBER_STRING;
974 else if ((type&0xff) == 4)
975 cond->type = EXPR_COL_NUMBER32;
976 else
977 cond->type = EXPR_COL_NUMBER;
979 *valid = TRUE;
980 break;
982 case EXPR_COMPLEX:
983 r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid );
984 if( r != ERROR_SUCCESS )
985 return r;
986 if( !*valid )
987 return ERROR_SUCCESS;
988 r = WHERE_VerifyCondition( wv, cond->u.expr.right, valid );
989 if( r != ERROR_SUCCESS )
990 return r;
992 /* check the type of the comparison */
993 if( ( cond->u.expr.left->type == EXPR_SVAL ) ||
994 ( cond->u.expr.left->type == EXPR_COL_NUMBER_STRING ) ||
995 ( cond->u.expr.right->type == EXPR_SVAL ) ||
996 ( cond->u.expr.right->type == EXPR_COL_NUMBER_STRING ) )
998 switch( cond->u.expr.op )
1000 case OP_EQ:
1001 case OP_NE:
1002 break;
1003 default:
1004 *valid = FALSE;
1005 return ERROR_INVALID_PARAMETER;
1008 /* FIXME: check we're comparing a string to a column */
1010 cond->type = EXPR_STRCMP;
1013 break;
1014 case EXPR_UNARY:
1015 if ( cond->u.expr.left->type != EXPR_COLUMN )
1017 *valid = FALSE;
1018 return ERROR_INVALID_PARAMETER;
1020 r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid );
1021 if( r != ERROR_SUCCESS )
1022 return r;
1023 break;
1024 case EXPR_IVAL:
1025 *valid = 1;
1026 cond->type = EXPR_UVAL;
1027 cond->u.uval = cond->u.ival;
1028 break;
1029 case EXPR_WILDCARD:
1030 *valid = 1;
1031 break;
1032 case EXPR_SVAL:
1033 *valid = 1;
1034 break;
1035 default:
1036 ERR("Invalid expression type\n");
1037 *valid = 0;
1038 break;
1041 return ERROR_SUCCESS;
1044 UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables,
1045 struct expr *cond )
1047 MSIWHEREVIEW *wv = NULL;
1048 UINT r, valid = 0;
1049 WCHAR *ptr;
1051 TRACE("(%s)\n", debugstr_w(tables) );
1053 wv = msi_alloc_zero( sizeof *wv );
1054 if( !wv )
1055 return ERROR_FUNCTION_FAILED;
1057 /* fill the structure */
1058 wv->view.ops = &where_ops;
1059 msiobj_addref( &db->hdr );
1060 wv->db = db;
1061 wv->cond = cond;
1063 while (*tables)
1065 JOINTABLE *table;
1067 if ((ptr = strchrW(tables, ' ')))
1068 *ptr = '\0';
1070 table = msi_alloc(sizeof(JOINTABLE));
1071 if (!table)
1073 r = ERROR_OUTOFMEMORY;
1074 goto end;
1077 r = TABLE_CreateView(db, tables, &table->view);
1078 if (r != ERROR_SUCCESS)
1080 WARN("can't create table: %s\n", debugstr_w(tables));
1081 msi_free(table);
1082 r = ERROR_BAD_QUERY_SYNTAX;
1083 goto end;
1086 r = table->view->ops->get_dimensions(table->view, NULL,
1087 &table->col_count);
1088 if (r != ERROR_SUCCESS)
1090 ERR("can't get table dimensions\n");
1091 goto end;
1094 wv->col_count += table->col_count;
1095 table->table_index = wv->table_count++;
1097 table->next = wv->tables;
1098 wv->tables = table;
1100 if (!ptr)
1101 break;
1103 tables = ptr + 1;
1106 if( cond )
1108 r = WHERE_VerifyCondition( wv, cond, &valid );
1109 if( r != ERROR_SUCCESS )
1110 goto end;
1111 if( !valid ) {
1112 r = ERROR_FUNCTION_FAILED;
1113 goto end;
1117 *view = (MSIVIEW*) wv;
1119 return ERROR_SUCCESS;
1120 end:
1121 WHERE_delete(&wv->view);
1123 return r;