2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002 Mike McCormack for CodeWeavers
5 * Copyright 2011 Bernhard Loos
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.
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.
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
28 #include "wine/debug.h"
29 #include "wine/unicode.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msidb
);
41 /* below is the query interface to a table */
42 typedef struct tagMSIROWENTRY
44 struct tagMSIWHEREVIEW
*wv
; /* used during sorting */
48 typedef struct tagJOINTABLE
50 struct tagJOINTABLE
*next
;
57 typedef struct tagMSIORDERINFO
61 union ext_column columns
[1];
64 typedef struct tagMSIWHEREVIEW
72 MSIROWENTRY
**reorder
;
73 UINT reorder_size
; /* number of entries available in reorder */
76 MSIORDERINFO
*order_info
;
79 static UINT
WHERE_evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[],
80 struct expr
*cond
, INT
*val
, MSIRECORD
*record
);
82 #define INITIAL_REORDER_SIZE 16
84 #define INVALID_ROW_INDEX (-1)
86 static void free_reorder(MSIWHEREVIEW
*wv
)
93 for (i
= 0; i
< wv
->row_count
; i
++)
94 msi_free(wv
->reorder
[i
]);
96 msi_free( wv
->reorder
);
102 static UINT
init_reorder(MSIWHEREVIEW
*wv
)
104 MSIROWENTRY
**new = msi_alloc_zero(sizeof(MSIROWENTRY
*) * INITIAL_REORDER_SIZE
);
106 return ERROR_OUTOFMEMORY
;
111 wv
->reorder_size
= INITIAL_REORDER_SIZE
;
113 return ERROR_SUCCESS
;
116 static inline UINT
find_row(MSIWHEREVIEW
*wv
, UINT row
, UINT
*(values
[]))
118 if (row
>= wv
->row_count
)
119 return ERROR_NO_MORE_ITEMS
;
121 *values
= wv
->reorder
[row
]->values
;
123 return ERROR_SUCCESS
;
126 static UINT
add_row(MSIWHEREVIEW
*wv
, UINT vals
[])
130 if (wv
->reorder_size
<= wv
->row_count
)
132 MSIROWENTRY
**new_reorder
;
133 UINT newsize
= wv
->reorder_size
* 2;
135 new_reorder
= msi_realloc_zero(wv
->reorder
, sizeof(MSIROWENTRY
*) * newsize
);
137 return ERROR_OUTOFMEMORY
;
139 wv
->reorder
= new_reorder
;
140 wv
->reorder_size
= newsize
;
143 new = msi_alloc(FIELD_OFFSET( MSIROWENTRY
, values
[wv
->table_count
] ));
146 return ERROR_OUTOFMEMORY
;
148 wv
->reorder
[wv
->row_count
++] = new;
150 memcpy(new->values
, vals
, wv
->table_count
* sizeof(UINT
));
153 return ERROR_SUCCESS
;
156 static JOINTABLE
*find_table(MSIWHEREVIEW
*wv
, UINT col
, UINT
*table_col
)
158 JOINTABLE
*table
= wv
->tables
;
160 if(col
== 0 || col
> wv
->col_count
)
163 while (col
> table
->col_count
)
165 col
-= table
->col_count
;
174 static UINT
parse_column(MSIWHEREVIEW
*wv
, union ext_column
*column
,
177 JOINTABLE
*table
= wv
->tables
;
184 if (column
->unparsed
.table
)
186 r
= table
->view
->ops
->get_column_info(table
->view
, 1, NULL
, NULL
,
188 if (r
!= ERROR_SUCCESS
)
190 if (strcmpW(table_name
, column
->unparsed
.table
) != 0)
194 for(i
= 1; i
<= table
->col_count
; i
++)
198 r
= table
->view
->ops
->get_column_info(table
->view
, i
, &col_name
, column_type
,
200 if(r
!= ERROR_SUCCESS
)
203 if(strcmpW(col_name
, column
->unparsed
.column
))
205 column
->parsed
.column
= i
;
206 column
->parsed
.table
= table
;
207 return ERROR_SUCCESS
;
211 while ((table
= table
->next
));
213 WARN("Couldn't find column %s.%s\n", debugstr_w( column
->unparsed
.table
), debugstr_w( column
->unparsed
.column
) );
214 return ERROR_BAD_QUERY_SYNTAX
;
217 static UINT
WHERE_fetch_int( struct tagMSIVIEW
*view
, UINT row
, UINT col
, UINT
*val
)
219 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
224 TRACE("%p %d %d %p\n", wv
, row
, col
, val
);
227 return ERROR_FUNCTION_FAILED
;
229 r
= find_row(wv
, row
, &rows
);
230 if (r
!= ERROR_SUCCESS
)
233 table
= find_table(wv
, col
, &col
);
235 return ERROR_FUNCTION_FAILED
;
237 return table
->view
->ops
->fetch_int(table
->view
, rows
[table
->table_index
], col
, val
);
240 static UINT
WHERE_fetch_stream( struct tagMSIVIEW
*view
, UINT row
, UINT col
, IStream
**stm
)
242 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
247 TRACE("%p %d %d %p\n", wv
, row
, col
, stm
);
250 return ERROR_FUNCTION_FAILED
;
252 r
= find_row(wv
, row
, &rows
);
253 if (r
!= ERROR_SUCCESS
)
256 table
= find_table(wv
, col
, &col
);
258 return ERROR_FUNCTION_FAILED
;
260 return table
->view
->ops
->fetch_stream( table
->view
, rows
[table
->table_index
], col
, stm
);
263 static UINT
WHERE_get_row( struct tagMSIVIEW
*view
, UINT row
, MSIRECORD
**rec
)
265 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
267 TRACE("%p %d %p\n", wv
, row
, rec
);
270 return ERROR_FUNCTION_FAILED
;
272 return msi_view_get_row( wv
->db
, view
, row
, rec
);
275 static UINT
WHERE_set_row( struct tagMSIVIEW
*view
, UINT row
, MSIRECORD
*rec
, UINT mask
)
277 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
278 UINT i
, r
, offset
= 0;
279 JOINTABLE
*table
= wv
->tables
;
281 UINT mask_copy
= mask
;
283 TRACE("%p %d %p %08x\n", wv
, row
, rec
, mask
);
286 return ERROR_FUNCTION_FAILED
;
288 r
= find_row(wv
, row
, &rows
);
289 if (r
!= ERROR_SUCCESS
)
292 if (mask
>= 1 << wv
->col_count
)
293 return ERROR_INVALID_PARAMETER
;
297 for (i
= 0; i
< table
->col_count
; i
++) {
300 if (!(mask_copy
& (1 << i
)))
302 r
= table
->view
->ops
->get_column_info(table
->view
, i
+ 1, NULL
,
304 if (r
!= ERROR_SUCCESS
)
306 if (type
& MSITYPE_KEY
)
307 return ERROR_FUNCTION_FAILED
;
309 mask_copy
>>= table
->col_count
;
311 while (mask_copy
&& (table
= table
->next
));
317 const UINT col_count
= table
->col_count
;
320 UINT reduced_mask
= (mask
>> offset
) & ((1 << col_count
) - 1);
328 reduced
= MSI_CreateRecord(col_count
);
330 return ERROR_FUNCTION_FAILED
;
332 for (i
= 1; i
<= col_count
; i
++)
334 r
= MSI_RecordCopyField(rec
, i
+ offset
, reduced
, i
);
335 if (r
!= ERROR_SUCCESS
)
341 if (r
== ERROR_SUCCESS
)
342 r
= table
->view
->ops
->set_row(table
->view
, rows
[table
->table_index
], reduced
, reduced_mask
);
344 msiobj_release(&reduced
->hdr
);
346 while ((table
= table
->next
));
350 static UINT
WHERE_delete_row(struct tagMSIVIEW
*view
, UINT row
)
352 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
356 TRACE("(%p %d)\n", view
, row
);
359 return ERROR_FUNCTION_FAILED
;
361 r
= find_row(wv
, row
, &rows
);
362 if ( r
!= ERROR_SUCCESS
)
365 if (wv
->table_count
> 1)
366 return ERROR_CALL_NOT_IMPLEMENTED
;
368 return wv
->tables
->view
->ops
->delete_row(wv
->tables
->view
, rows
[0]);
371 static INT
INT_evaluate_binary( MSIWHEREVIEW
*wv
, const UINT rows
[],
372 const struct complex_expr
*expr
, INT
*val
, MSIRECORD
*record
)
377 rl
= WHERE_evaluate(wv
, rows
, expr
->left
, &lval
, record
);
378 if (rl
!= ERROR_SUCCESS
&& rl
!= ERROR_CONTINUE
)
380 rr
= WHERE_evaluate(wv
, rows
, expr
->right
, &rval
, record
);
381 if (rr
!= ERROR_SUCCESS
&& rr
!= ERROR_CONTINUE
)
384 if (rl
== ERROR_CONTINUE
|| rr
== ERROR_CONTINUE
)
389 return ERROR_CONTINUE
;
392 if (expr
->op
== OP_AND
)
394 if ((rl
== ERROR_CONTINUE
&& !rval
) || (rr
== ERROR_CONTINUE
&& !lval
))
397 return ERROR_SUCCESS
;
400 else if (expr
->op
== OP_OR
)
402 if ((rl
== ERROR_CONTINUE
&& rval
) || (rr
== ERROR_CONTINUE
&& lval
))
405 return ERROR_SUCCESS
;
410 return ERROR_CONTINUE
;
416 *val
= ( lval
== rval
);
419 *val
= ( lval
&& rval
);
422 *val
= ( lval
|| rval
);
425 *val
= ( lval
> rval
);
428 *val
= ( lval
< rval
);
431 *val
= ( lval
<= rval
);
434 *val
= ( lval
>= rval
);
437 *val
= ( lval
!= rval
);
440 ERR("Unknown operator %d\n", expr
->op
);
441 return ERROR_FUNCTION_FAILED
;
444 return ERROR_SUCCESS
;
447 static inline UINT
expr_fetch_value(const union ext_column
*expr
, const UINT rows
[], UINT
*val
)
449 JOINTABLE
*table
= expr
->parsed
.table
;
451 if( rows
[table
->table_index
] == INVALID_ROW_INDEX
)
454 return ERROR_CONTINUE
;
456 return table
->view
->ops
->fetch_int(table
->view
, rows
[table
->table_index
],
457 expr
->parsed
.column
, val
);
461 static UINT
INT_evaluate_unary( MSIWHEREVIEW
*wv
, const UINT rows
[],
462 const struct complex_expr
*expr
, INT
*val
, MSIRECORD
*record
)
467 r
= expr_fetch_value(&expr
->left
->u
.column
, rows
, &lval
);
468 if(r
!= ERROR_SUCCESS
)
480 ERR("Unknown operator %d\n", expr
->op
);
481 return ERROR_FUNCTION_FAILED
;
483 return ERROR_SUCCESS
;
486 static UINT
STRING_evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[],
487 const struct expr
*expr
,
488 const MSIRECORD
*record
,
491 UINT val
= 0, r
= ERROR_SUCCESS
;
495 case EXPR_COL_NUMBER_STRING
:
496 r
= expr_fetch_value(&expr
->u
.column
, rows
, &val
);
497 if (r
== ERROR_SUCCESS
)
498 *str
= msi_string_lookup_id(wv
->db
->strings
, val
);
508 *str
= MSI_RecordGetString(record
, ++wv
->rec_index
);
512 ERR("Invalid expression type\n");
513 r
= ERROR_FUNCTION_FAILED
;
520 static UINT
STRCMP_Evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[], const struct complex_expr
*expr
,
521 INT
*val
, const MSIRECORD
*record
)
524 const WCHAR
*l_str
, *r_str
;
528 r
= STRING_evaluate(wv
, rows
, expr
->left
, record
, &l_str
);
529 if (r
== ERROR_CONTINUE
)
531 r
= STRING_evaluate(wv
, rows
, expr
->right
, record
, &r_str
);
532 if (r
== ERROR_CONTINUE
)
535 if( l_str
== r_str
||
536 ((!l_str
|| !*l_str
) && (!r_str
|| !*r_str
)) )
538 else if( l_str
&& ! r_str
)
540 else if( r_str
&& ! l_str
)
543 sr
= strcmpW( l_str
, r_str
);
545 *val
= ( expr
->op
== OP_EQ
&& ( sr
== 0 ) ) ||
546 ( expr
->op
== OP_NE
&& ( sr
!= 0 ) );
548 return ERROR_SUCCESS
;
551 static UINT
WHERE_evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[],
552 struct expr
*cond
, INT
*val
, MSIRECORD
*record
)
559 return ERROR_SUCCESS
;
564 case EXPR_COL_NUMBER
:
565 r
= expr_fetch_value(&cond
->u
.column
, rows
, &tval
);
566 if( r
!= ERROR_SUCCESS
)
568 *val
= tval
- 0x8000;
569 return ERROR_SUCCESS
;
571 case EXPR_COL_NUMBER32
:
572 r
= expr_fetch_value(&cond
->u
.column
, rows
, &tval
);
573 if( r
!= ERROR_SUCCESS
)
575 *val
= tval
- 0x80000000;
580 return ERROR_SUCCESS
;
583 return INT_evaluate_binary(wv
, rows
, &cond
->u
.expr
, val
, record
);
586 return INT_evaluate_unary( wv
, rows
, &cond
->u
.expr
, val
, record
);
589 return STRCMP_Evaluate( wv
, rows
, &cond
->u
.expr
, val
, record
);
592 *val
= MSI_RecordGetInteger( record
, ++wv
->rec_index
);
593 return ERROR_SUCCESS
;
596 ERR("Invalid expression type\n");
600 return ERROR_SUCCESS
;
603 static UINT
check_condition( MSIWHEREVIEW
*wv
, MSIRECORD
*record
, JOINTABLE
*table
,
606 UINT r
= ERROR_FUNCTION_FAILED
;
609 for (table_rows
[table
->table_index
] = 0; table_rows
[table
->table_index
] < table
->row_count
;
610 table_rows
[table
->table_index
]++)
614 r
= WHERE_evaluate( wv
, table_rows
, wv
->cond
, &val
, record
);
615 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_CONTINUE
)
621 r
= check_condition(wv
, record
, table
->next
, table_rows
);
622 if (r
!= ERROR_SUCCESS
)
627 if (r
!= ERROR_SUCCESS
)
629 add_row (wv
, table_rows
);
633 table_rows
[table
->table_index
] = INVALID_ROW_INDEX
;
637 static int compare_entry( const void *left
, const void *right
)
639 const MSIROWENTRY
*le
= *(const MSIROWENTRY
**)left
;
640 const MSIROWENTRY
*re
= *(const MSIROWENTRY
**)right
;
641 const MSIWHEREVIEW
*wv
= le
->wv
;
642 MSIORDERINFO
*order
= wv
->order_info
;
643 UINT i
, j
, r
, l_val
, r_val
;
645 assert(le
->wv
== re
->wv
);
649 for (i
= 0; i
< order
->col_count
; i
++)
651 const union ext_column
*column
= &order
->columns
[i
];
653 r
= column
->parsed
.table
->view
->ops
->fetch_int(column
->parsed
.table
->view
,
654 le
->values
[column
->parsed
.table
->table_index
],
655 column
->parsed
.column
, &l_val
);
656 if (r
!= ERROR_SUCCESS
)
662 r
= column
->parsed
.table
->view
->ops
->fetch_int(column
->parsed
.table
->view
,
663 re
->values
[column
->parsed
.table
->table_index
],
664 column
->parsed
.column
, &r_val
);
665 if (r
!= ERROR_SUCCESS
)
672 return l_val
< r_val
? -1 : 1;
676 for (j
= 0; j
< wv
->table_count
; j
++)
678 if (le
->values
[j
] != re
->values
[j
])
679 return le
->values
[j
] < re
->values
[j
] ? -1 : 1;
684 static UINT
WHERE_execute( struct tagMSIVIEW
*view
, MSIRECORD
*record
)
686 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
688 JOINTABLE
*table
= wv
->tables
;
692 TRACE("%p %p\n", wv
, record
);
695 return ERROR_FUNCTION_FAILED
;
697 r
= init_reorder(wv
);
698 if (r
!= ERROR_SUCCESS
)
703 table
->view
->ops
->execute(table
->view
, NULL
);
705 r
= table
->view
->ops
->get_dimensions(table
->view
, &table
->row_count
, NULL
);
706 if (r
!= ERROR_SUCCESS
)
708 ERR("failed to get table dimensions\n");
712 /* each table must have at least one row */
713 if (table
->row_count
== 0)
714 return ERROR_SUCCESS
;
716 while ((table
= table
->next
));
718 rows
= msi_alloc( wv
->table_count
* sizeof(*rows
) );
719 for (i
= 0; i
< wv
->table_count
; i
++)
720 rows
[i
] = INVALID_ROW_INDEX
;
722 r
= check_condition(wv
, record
, wv
->tables
, rows
);
725 wv
->order_info
->error
= ERROR_SUCCESS
;
727 qsort(wv
->reorder
, wv
->row_count
, sizeof(MSIROWENTRY
*), compare_entry
);
730 r
= wv
->order_info
->error
;
736 static UINT
WHERE_close( struct tagMSIVIEW
*view
)
738 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
739 JOINTABLE
*table
= wv
->tables
;
744 return ERROR_FUNCTION_FAILED
;
747 table
->view
->ops
->close(table
->view
);
748 while ((table
= table
->next
));
750 return ERROR_SUCCESS
;
753 static UINT
WHERE_get_dimensions( struct tagMSIVIEW
*view
, UINT
*rows
, UINT
*cols
)
755 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
757 TRACE("%p %p %p\n", wv
, rows
, cols
);
760 return ERROR_FUNCTION_FAILED
;
765 return ERROR_FUNCTION_FAILED
;
766 *rows
= wv
->row_count
;
770 *cols
= wv
->col_count
;
772 return ERROR_SUCCESS
;
775 static UINT
WHERE_get_column_info( struct tagMSIVIEW
*view
, UINT n
, LPCWSTR
*name
,
776 UINT
*type
, BOOL
*temporary
, LPCWSTR
*table_name
)
778 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
781 TRACE("%p %d %p %p %p %p\n", wv
, n
, name
, type
, temporary
, table_name
);
784 return ERROR_FUNCTION_FAILED
;
786 table
= find_table(wv
, n
, &n
);
788 return ERROR_FUNCTION_FAILED
;
790 return table
->view
->ops
->get_column_info(table
->view
, n
, name
,
791 type
, temporary
, table_name
);
794 static UINT
join_find_row( MSIWHEREVIEW
*wv
, MSIRECORD
*rec
, UINT
*row
)
799 str
= MSI_RecordGetString( rec
, 1 );
800 r
= msi_string2idW( wv
->db
->strings
, str
, &id
);
801 if (r
!= ERROR_SUCCESS
)
804 for (i
= 0; i
< wv
->row_count
; i
++)
806 WHERE_fetch_int( &wv
->view
, i
, 1, &data
);
811 return ERROR_SUCCESS
;
815 return ERROR_FUNCTION_FAILED
;
818 static UINT
join_modify_update( struct tagMSIVIEW
*view
, MSIRECORD
*rec
)
820 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
821 UINT r
, row
, i
, mask
= 0;
825 r
= join_find_row( wv
, rec
, &row
);
826 if (r
!= ERROR_SUCCESS
)
829 r
= msi_view_get_row( wv
->db
, view
, row
, ¤t
);
830 if (r
!= ERROR_SUCCESS
)
833 assert(MSI_RecordGetFieldCount(rec
) == MSI_RecordGetFieldCount(current
));
835 for (i
= MSI_RecordGetFieldCount(rec
); i
> 0; i
--)
837 if (!MSI_RecordsAreFieldsEqual(rec
, current
, i
))
838 mask
|= 1 << (i
- 1);
840 msiobj_release(¤t
->hdr
);
842 return WHERE_set_row( view
, row
, rec
, mask
);
845 static UINT
WHERE_modify( struct tagMSIVIEW
*view
, MSIMODIFY eModifyMode
,
846 MSIRECORD
*rec
, UINT row
)
848 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
849 JOINTABLE
*table
= wv
->tables
;
852 TRACE("%p %d %p\n", wv
, eModifyMode
, rec
);
855 return ERROR_FUNCTION_FAILED
;
861 if (find_row(wv
, row
- 1, &rows
) == ERROR_SUCCESS
)
866 return table
->view
->ops
->modify(table
->view
, eModifyMode
, rec
, row
);
871 case MSIMODIFY_UPDATE
:
872 return join_modify_update( view
, rec
);
874 case MSIMODIFY_ASSIGN
:
875 case MSIMODIFY_DELETE
:
876 case MSIMODIFY_INSERT
:
877 case MSIMODIFY_INSERT_TEMPORARY
:
878 case MSIMODIFY_MERGE
:
879 case MSIMODIFY_REPLACE
:
881 case MSIMODIFY_VALIDATE
:
882 case MSIMODIFY_VALIDATE_DELETE
:
883 case MSIMODIFY_VALIDATE_FIELD
:
884 case MSIMODIFY_VALIDATE_NEW
:
885 r
= ERROR_FUNCTION_FAILED
;
888 case MSIMODIFY_REFRESH
:
889 r
= ERROR_CALL_NOT_IMPLEMENTED
;
893 WARN("%p %d %p %u - unknown mode\n", view
, eModifyMode
, rec
, row
);
894 r
= ERROR_INVALID_PARAMETER
;
901 static UINT
WHERE_delete( struct tagMSIVIEW
*view
)
903 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
904 JOINTABLE
*table
= wv
->tables
;
912 table
->view
->ops
->delete(table
->view
);
925 msi_free(wv
->order_info
);
926 wv
->order_info
= NULL
;
929 msiobj_release( &wv
->db
->hdr
);
932 return ERROR_SUCCESS
;
935 static UINT
WHERE_find_matching_rows( struct tagMSIVIEW
*view
, UINT col
,
936 UINT val
, UINT
*row
, MSIITERHANDLE
*handle
)
938 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
941 TRACE("%p, %d, %u, %p\n", view
, col
, val
, *handle
);
944 return ERROR_FUNCTION_FAILED
;
946 if (col
== 0 || col
> wv
->col_count
)
947 return ERROR_INVALID_PARAMETER
;
949 for (i
= PtrToUlong(*handle
); i
< wv
->row_count
; i
++)
951 if (view
->ops
->fetch_int( view
, i
, col
, &row_value
) != ERROR_SUCCESS
)
954 if (row_value
== val
)
957 *handle
= UlongToPtr(i
+ 1);
958 return ERROR_SUCCESS
;
962 return ERROR_NO_MORE_ITEMS
;
965 static UINT
WHERE_sort(struct tagMSIVIEW
*view
, column_info
*columns
)
967 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
968 JOINTABLE
*table
= wv
->tables
;
969 column_info
*column
= columns
;
970 MSIORDERINFO
*orderinfo
;
974 TRACE("%p %p\n", view
, columns
);
977 return ERROR_FUNCTION_FAILED
;
982 column
= column
->next
;
986 return ERROR_SUCCESS
;
988 orderinfo
= msi_alloc(sizeof(MSIORDERINFO
) + (count
- 1) * sizeof(union ext_column
));
990 return ERROR_OUTOFMEMORY
;
992 orderinfo
->col_count
= count
;
996 for (i
= 0; i
< count
; i
++)
998 orderinfo
->columns
[i
].unparsed
.column
= column
->column
;
999 orderinfo
->columns
[i
].unparsed
.table
= column
->table
;
1001 r
= parse_column(wv
, &orderinfo
->columns
[i
], NULL
);
1002 if (r
!= ERROR_SUCCESS
)
1006 wv
->order_info
= orderinfo
;
1008 return ERROR_SUCCESS
;
1010 msi_free(orderinfo
);
1014 static const MSIVIEWOPS where_ops
=
1024 WHERE_get_dimensions
,
1025 WHERE_get_column_info
,
1028 WHERE_find_matching_rows
,
1037 static UINT
WHERE_VerifyCondition( MSIWHEREVIEW
*wv
, struct expr
*cond
,
1042 switch( cond
->type
)
1050 r
= parse_column(wv
, &cond
->u
.column
, &type
);
1051 if (r
!= ERROR_SUCCESS
)
1054 if (type
&MSITYPE_STRING
)
1055 cond
->type
= EXPR_COL_NUMBER_STRING
;
1056 else if ((type
&0xff) == 4)
1057 cond
->type
= EXPR_COL_NUMBER32
;
1059 cond
->type
= EXPR_COL_NUMBER
;
1065 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.left
, valid
);
1066 if( r
!= ERROR_SUCCESS
)
1069 return ERROR_SUCCESS
;
1070 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.right
, valid
);
1071 if( r
!= ERROR_SUCCESS
)
1074 /* check the type of the comparison */
1075 if( ( cond
->u
.expr
.left
->type
== EXPR_SVAL
) ||
1076 ( cond
->u
.expr
.left
->type
== EXPR_COL_NUMBER_STRING
) ||
1077 ( cond
->u
.expr
.right
->type
== EXPR_SVAL
) ||
1078 ( cond
->u
.expr
.right
->type
== EXPR_COL_NUMBER_STRING
) )
1080 switch( cond
->u
.expr
.op
)
1087 return ERROR_INVALID_PARAMETER
;
1090 /* FIXME: check we're comparing a string to a column */
1092 cond
->type
= EXPR_STRCMP
;
1097 if ( cond
->u
.expr
.left
->type
!= EXPR_COLUMN
)
1100 return ERROR_INVALID_PARAMETER
;
1102 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.left
, valid
);
1103 if( r
!= ERROR_SUCCESS
)
1108 cond
->type
= EXPR_UVAL
;
1109 cond
->u
.uval
= cond
->u
.ival
;
1118 ERR("Invalid expression type\n");
1123 return ERROR_SUCCESS
;
1126 UINT
WHERE_CreateView( MSIDATABASE
*db
, MSIVIEW
**view
, LPWSTR tables
,
1129 MSIWHEREVIEW
*wv
= NULL
;
1133 TRACE("(%s)\n", debugstr_w(tables
) );
1135 wv
= msi_alloc_zero( sizeof *wv
);
1137 return ERROR_FUNCTION_FAILED
;
1139 /* fill the structure */
1140 wv
->view
.ops
= &where_ops
;
1141 msiobj_addref( &db
->hdr
);
1149 if ((ptr
= strchrW(tables
, ' ')))
1152 table
= msi_alloc(sizeof(JOINTABLE
));
1155 r
= ERROR_OUTOFMEMORY
;
1159 r
= TABLE_CreateView(db
, tables
, &table
->view
);
1160 if (r
!= ERROR_SUCCESS
)
1162 WARN("can't create table: %s\n", debugstr_w(tables
));
1164 r
= ERROR_BAD_QUERY_SYNTAX
;
1168 r
= table
->view
->ops
->get_dimensions(table
->view
, NULL
,
1170 if (r
!= ERROR_SUCCESS
)
1172 ERR("can't get table dimensions\n");
1176 wv
->col_count
+= table
->col_count
;
1177 table
->table_index
= wv
->table_count
++;
1179 table
->next
= wv
->tables
;
1190 r
= WHERE_VerifyCondition( wv
, cond
, &valid
);
1191 if( r
!= ERROR_SUCCESS
)
1194 r
= ERROR_FUNCTION_FAILED
;
1199 *view
= (MSIVIEW
*) wv
;
1201 return ERROR_SUCCESS
;
1203 WHERE_delete(&wv
->view
);