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"
38 WINE_DEFAULT_DEBUG_CHANNEL(msidb
);
40 /* below is the query interface to a table */
43 struct tagMSIWHEREVIEW
*wv
; /* used during sorting */
49 struct join_table
*next
;
56 typedef struct tagMSIORDERINFO
60 union ext_column columns
[1];
63 typedef struct tagMSIWHEREVIEW
67 struct join_table
*tables
;
71 struct row_entry
**reorder
;
72 UINT reorder_size
; /* number of entries available in reorder */
75 MSIORDERINFO
*order_info
;
78 static UINT
WHERE_evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[],
79 struct expr
*cond
, INT
*val
, MSIRECORD
*record
);
81 #define INITIAL_REORDER_SIZE 16
83 #define INVALID_ROW_INDEX (-1)
85 static void free_reorder(MSIWHEREVIEW
*wv
)
92 for (i
= 0; i
< wv
->row_count
; i
++)
101 static UINT
init_reorder(MSIWHEREVIEW
*wv
)
103 struct row_entry
**new = calloc(INITIAL_REORDER_SIZE
, sizeof(*new));
105 return ERROR_OUTOFMEMORY
;
110 wv
->reorder_size
= INITIAL_REORDER_SIZE
;
112 return ERROR_SUCCESS
;
115 static inline UINT
find_row(MSIWHEREVIEW
*wv
, UINT row
, UINT
*(values
[]))
117 if (row
>= wv
->row_count
)
118 return ERROR_NO_MORE_ITEMS
;
120 *values
= wv
->reorder
[row
]->values
;
122 return ERROR_SUCCESS
;
125 static UINT
add_row(MSIWHEREVIEW
*wv
, UINT vals
[])
127 struct row_entry
*new;
129 if (wv
->reorder_size
<= wv
->row_count
)
131 struct row_entry
**new_reorder
;
132 UINT newsize
= wv
->reorder_size
* 2;
134 new_reorder
= realloc(wv
->reorder
, newsize
* sizeof(*new_reorder
));
136 return ERROR_OUTOFMEMORY
;
137 memset(new_reorder
+ wv
->reorder_size
, 0, (newsize
- wv
->reorder_size
) * sizeof(*new_reorder
));
139 wv
->reorder
= new_reorder
;
140 wv
->reorder_size
= newsize
;
143 new = malloc(offsetof(struct row_entry
, 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 struct join_table
*find_table(MSIWHEREVIEW
*wv
, UINT col
, UINT
*table_col
)
158 struct join_table
*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 struct join_table
*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 (wcscmp(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(wcscmp(col_name
, column
->unparsed
.column
))
205 column
->parsed
.column
= i
;
206 column
->parsed
.table
= table
;
207 return ERROR_SUCCESS
;
210 while ((table
= table
->next
));
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
;
216 static UINT
WHERE_fetch_int( struct tagMSIVIEW
*view
, UINT row
, UINT col
, UINT
*val
)
218 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
219 struct join_table
*table
;
223 TRACE("%p %d %d %p\n", wv
, row
, col
, val
);
226 return ERROR_FUNCTION_FAILED
;
228 r
= find_row(wv
, row
, &rows
);
229 if (r
!= ERROR_SUCCESS
)
232 table
= find_table(wv
, col
, &col
);
234 return ERROR_FUNCTION_FAILED
;
236 return table
->view
->ops
->fetch_int(table
->view
, rows
[table
->table_index
], col
, val
);
239 static UINT
WHERE_fetch_stream( struct tagMSIVIEW
*view
, UINT row
, UINT col
, IStream
**stm
)
241 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
242 struct join_table
*table
;
246 TRACE("%p %d %d %p\n", wv
, row
, col
, stm
);
249 return ERROR_FUNCTION_FAILED
;
251 r
= find_row(wv
, row
, &rows
);
252 if (r
!= ERROR_SUCCESS
)
255 table
= find_table(wv
, col
, &col
);
257 return ERROR_FUNCTION_FAILED
;
259 return table
->view
->ops
->fetch_stream( table
->view
, rows
[table
->table_index
], col
, stm
);
262 static UINT
WHERE_set_int(struct tagMSIVIEW
*view
, UINT row
, UINT col
, int val
)
264 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
265 struct join_table
*table
;
269 TRACE("view %p, row %u, col %u, val %d.\n", wv
, row
, col
, val
);
271 r
= find_row(wv
, row
, &rows
);
272 if (r
!= ERROR_SUCCESS
)
275 table
= find_table(wv
, col
, &col
);
277 return ERROR_FUNCTION_FAILED
;
279 return table
->view
->ops
->set_int(table
->view
, rows
[table
->table_index
], col
, val
);
282 static UINT
WHERE_set_string(struct tagMSIVIEW
*view
, UINT row
, UINT col
, const WCHAR
*val
, int len
)
284 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
285 struct join_table
*table
;
289 TRACE("view %p, row %u, col %u, val %s.\n", wv
, row
, col
, debugstr_wn(val
, len
));
291 r
= find_row(wv
, row
, &rows
);
292 if (r
!= ERROR_SUCCESS
)
295 table
= find_table(wv
, col
, &col
);
297 return ERROR_FUNCTION_FAILED
;
299 return table
->view
->ops
->set_string(table
->view
, rows
[table
->table_index
], col
, val
, len
);
302 static UINT
WHERE_set_stream(MSIVIEW
*view
, UINT row
, UINT col
, IStream
*stream
)
304 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
305 struct join_table
*table
;
309 TRACE("view %p, row %u, col %u, stream %p.\n", wv
, row
, col
, stream
);
311 r
= find_row(wv
, row
, &rows
);
312 if (r
!= ERROR_SUCCESS
)
315 table
= find_table(wv
, col
, &col
);
317 return ERROR_FUNCTION_FAILED
;
319 return table
->view
->ops
->set_stream(table
->view
, rows
[table
->table_index
], col
, stream
);
322 static UINT
WHERE_set_row( struct tagMSIVIEW
*view
, UINT row
, MSIRECORD
*rec
, UINT mask
)
324 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
325 UINT i
, r
, offset
= 0;
326 struct join_table
*table
= wv
->tables
;
328 UINT mask_copy
= mask
;
330 TRACE("%p %d %p %08x\n", wv
, row
, rec
, mask
);
333 return ERROR_FUNCTION_FAILED
;
335 r
= find_row(wv
, row
, &rows
);
336 if (r
!= ERROR_SUCCESS
)
339 if (mask
>= 1 << wv
->col_count
)
340 return ERROR_INVALID_PARAMETER
;
344 for (i
= 0; i
< table
->col_count
; i
++) {
347 if (!(mask_copy
& (1 << i
)))
349 r
= table
->view
->ops
->get_column_info(table
->view
, i
+ 1, NULL
,
351 if (r
!= ERROR_SUCCESS
)
353 if (type
& MSITYPE_KEY
)
354 return ERROR_FUNCTION_FAILED
;
356 mask_copy
>>= table
->col_count
;
358 while (mask_copy
&& (table
= table
->next
));
364 const UINT col_count
= table
->col_count
;
367 UINT reduced_mask
= (mask
>> offset
) & ((1 << col_count
) - 1);
375 reduced
= MSI_CreateRecord(col_count
);
377 return ERROR_FUNCTION_FAILED
;
379 for (i
= 1; i
<= col_count
; i
++)
381 r
= MSI_RecordCopyField(rec
, i
+ offset
, reduced
, i
);
382 if (r
!= ERROR_SUCCESS
)
388 if (r
== ERROR_SUCCESS
)
389 r
= table
->view
->ops
->set_row(table
->view
, rows
[table
->table_index
], reduced
, reduced_mask
);
391 msiobj_release(&reduced
->hdr
);
393 while ((table
= table
->next
));
397 static UINT
WHERE_delete_row(struct tagMSIVIEW
*view
, UINT row
)
399 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
403 TRACE("(%p %d)\n", view
, row
);
406 return ERROR_FUNCTION_FAILED
;
408 r
= find_row(wv
, row
, &rows
);
409 if ( r
!= ERROR_SUCCESS
)
412 if (wv
->table_count
> 1)
413 return ERROR_CALL_NOT_IMPLEMENTED
;
415 return wv
->tables
->view
->ops
->delete_row(wv
->tables
->view
, rows
[0]);
418 static INT
INT_evaluate_binary( MSIWHEREVIEW
*wv
, const UINT rows
[],
419 const struct complex_expr
*expr
, INT
*val
, MSIRECORD
*record
)
424 rl
= WHERE_evaluate(wv
, rows
, expr
->left
, &lval
, record
);
425 if (rl
!= ERROR_SUCCESS
&& rl
!= ERROR_CONTINUE
)
427 rr
= WHERE_evaluate(wv
, rows
, expr
->right
, &rval
, record
);
428 if (rr
!= ERROR_SUCCESS
&& rr
!= ERROR_CONTINUE
)
431 if (rl
== ERROR_CONTINUE
|| rr
== ERROR_CONTINUE
)
436 return ERROR_CONTINUE
;
439 if (expr
->op
== OP_AND
)
441 if ((rl
== ERROR_CONTINUE
&& !rval
) || (rr
== ERROR_CONTINUE
&& !lval
))
444 return ERROR_SUCCESS
;
447 else if (expr
->op
== OP_OR
)
449 if ((rl
== ERROR_CONTINUE
&& rval
) || (rr
== ERROR_CONTINUE
&& lval
))
452 return ERROR_SUCCESS
;
457 return ERROR_CONTINUE
;
463 *val
= ( lval
== rval
);
466 *val
= ( lval
&& rval
);
469 *val
= ( lval
|| rval
);
472 *val
= ( lval
> rval
);
475 *val
= ( lval
< rval
);
478 *val
= ( lval
<= rval
);
481 *val
= ( lval
>= rval
);
484 *val
= ( lval
!= rval
);
487 ERR("Unknown operator %d\n", expr
->op
);
488 return ERROR_FUNCTION_FAILED
;
491 return ERROR_SUCCESS
;
494 static inline UINT
expr_fetch_value(const union ext_column
*expr
, const UINT rows
[], UINT
*val
)
496 struct join_table
*table
= expr
->parsed
.table
;
498 if( rows
[table
->table_index
] == INVALID_ROW_INDEX
)
501 return ERROR_CONTINUE
;
503 return table
->view
->ops
->fetch_int(table
->view
, rows
[table
->table_index
],
504 expr
->parsed
.column
, val
);
508 static UINT
INT_evaluate_unary( MSIWHEREVIEW
*wv
, const UINT rows
[],
509 const struct complex_expr
*expr
, INT
*val
, MSIRECORD
*record
)
514 r
= expr_fetch_value(&expr
->left
->u
.column
, rows
, &lval
);
515 if(r
!= ERROR_SUCCESS
)
527 ERR("Unknown operator %d\n", expr
->op
);
528 return ERROR_FUNCTION_FAILED
;
530 return ERROR_SUCCESS
;
533 static UINT
STRING_evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[],
534 const struct expr
*expr
,
535 const MSIRECORD
*record
,
538 UINT val
= 0, r
= ERROR_SUCCESS
;
542 case EXPR_COL_NUMBER_STRING
:
543 r
= expr_fetch_value(&expr
->u
.column
, rows
, &val
);
544 if (r
== ERROR_SUCCESS
)
545 *str
= msi_string_lookup(wv
->db
->strings
, val
, NULL
);
555 *str
= MSI_RecordGetString(record
, ++wv
->rec_index
);
559 ERR("Invalid expression type\n");
560 r
= ERROR_FUNCTION_FAILED
;
567 static UINT
STRCMP_Evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[], const struct complex_expr
*expr
,
568 INT
*val
, const MSIRECORD
*record
)
571 const WCHAR
*l_str
, *r_str
;
575 r
= STRING_evaluate(wv
, rows
, expr
->left
, record
, &l_str
);
576 if (r
== ERROR_CONTINUE
)
578 r
= STRING_evaluate(wv
, rows
, expr
->right
, record
, &r_str
);
579 if (r
== ERROR_CONTINUE
)
582 if( l_str
== r_str
||
583 ((!l_str
|| !*l_str
) && (!r_str
|| !*r_str
)) )
585 else if( l_str
&& ! r_str
)
587 else if( r_str
&& ! l_str
)
590 sr
= wcscmp( l_str
, r_str
);
592 *val
= ( expr
->op
== OP_EQ
&& ( sr
== 0 ) ) ||
593 ( expr
->op
== OP_NE
&& ( sr
!= 0 ) );
595 return ERROR_SUCCESS
;
598 static UINT
WHERE_evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[],
599 struct expr
*cond
, INT
*val
, MSIRECORD
*record
)
606 return ERROR_SUCCESS
;
611 case EXPR_COL_NUMBER
:
612 r
= expr_fetch_value(&cond
->u
.column
, rows
, &tval
);
613 if( r
!= ERROR_SUCCESS
)
615 *val
= tval
- 0x8000;
616 return ERROR_SUCCESS
;
618 case EXPR_COL_NUMBER32
:
619 r
= expr_fetch_value(&cond
->u
.column
, rows
, &tval
);
620 if( r
!= ERROR_SUCCESS
)
622 *val
= tval
- 0x80000000;
627 return ERROR_SUCCESS
;
630 return INT_evaluate_binary(wv
, rows
, &cond
->u
.expr
, val
, record
);
633 return INT_evaluate_unary( wv
, rows
, &cond
->u
.expr
, val
, record
);
636 return STRCMP_Evaluate( wv
, rows
, &cond
->u
.expr
, val
, record
);
639 *val
= MSI_RecordGetInteger( record
, ++wv
->rec_index
);
640 return ERROR_SUCCESS
;
643 ERR("Invalid expression type\n");
644 return ERROR_FUNCTION_FAILED
;
647 return ERROR_SUCCESS
;
650 static UINT
check_condition( MSIWHEREVIEW
*wv
, MSIRECORD
*record
, struct join_table
**tables
,
653 UINT r
= ERROR_FUNCTION_FAILED
;
656 for (table_rows
[(*tables
)->table_index
] = 0;
657 table_rows
[(*tables
)->table_index
] < (*tables
)->row_count
;
658 table_rows
[(*tables
)->table_index
]++)
662 r
= WHERE_evaluate( wv
, table_rows
, wv
->cond
, &val
, record
);
663 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_CONTINUE
)
669 r
= check_condition(wv
, record
, tables
+ 1, table_rows
);
670 if (r
!= ERROR_SUCCESS
)
675 if (r
!= ERROR_SUCCESS
)
677 add_row (wv
, table_rows
);
681 table_rows
[(*tables
)->table_index
] = INVALID_ROW_INDEX
;
685 static int __cdecl
compare_entry( const void *left
, const void *right
)
687 const struct row_entry
*le
= *(const struct row_entry
**)left
;
688 const struct row_entry
*re
= *(const struct row_entry
**)right
;
689 const MSIWHEREVIEW
*wv
= le
->wv
;
690 MSIORDERINFO
*order
= wv
->order_info
;
691 UINT i
, j
, r
, l_val
, r_val
;
693 assert(le
->wv
== re
->wv
);
697 for (i
= 0; i
< order
->col_count
; i
++)
699 const union ext_column
*column
= &order
->columns
[i
];
701 r
= column
->parsed
.table
->view
->ops
->fetch_int(column
->parsed
.table
->view
,
702 le
->values
[column
->parsed
.table
->table_index
],
703 column
->parsed
.column
, &l_val
);
704 if (r
!= ERROR_SUCCESS
)
710 r
= column
->parsed
.table
->view
->ops
->fetch_int(column
->parsed
.table
->view
,
711 re
->values
[column
->parsed
.table
->table_index
],
712 column
->parsed
.column
, &r_val
);
713 if (r
!= ERROR_SUCCESS
)
720 return l_val
< r_val
? -1 : 1;
724 for (j
= 0; j
< wv
->table_count
; j
++)
726 if (le
->values
[j
] != re
->values
[j
])
727 return le
->values
[j
] < re
->values
[j
] ? -1 : 1;
732 static void add_to_array( struct join_table
**array
, struct join_table
*elem
)
734 while (*array
&& *array
!= elem
)
740 static BOOL
in_array( struct join_table
**array
, struct join_table
*elem
)
742 while (*array
&& *array
!= elem
)
744 return *array
!= NULL
;
747 #define CONST_EXPR 1 /* comparison to a constant value */
748 #define JOIN_TO_CONST_EXPR 0x10000 /* comparison to a table involved with
749 a CONST_EXPR comaprison */
751 static UINT
reorder_check( const struct expr
*expr
, struct join_table
**ordered_tables
,
752 BOOL process_joins
, struct join_table
**lastused
)
762 case EXPR_COL_NUMBER
:
763 case EXPR_COL_NUMBER32
:
764 case EXPR_COL_NUMBER_STRING
:
765 if (in_array(ordered_tables
, expr
->u
.column
.parsed
.table
))
766 return JOIN_TO_CONST_EXPR
;
767 *lastused
= expr
->u
.column
.parsed
.table
;
771 res
= reorder_check(expr
->u
.expr
.right
, ordered_tables
, process_joins
, lastused
);
774 res
+= reorder_check(expr
->u
.expr
.left
, ordered_tables
, process_joins
, lastused
);
777 if (res
== CONST_EXPR
)
778 add_to_array(ordered_tables
, *lastused
);
779 if (process_joins
&& res
== JOIN_TO_CONST_EXPR
+ CONST_EXPR
)
780 add_to_array(ordered_tables
, *lastused
);
783 ERR("Unknown expr type: %i\n", expr
->type
);
789 /* reorders the tablelist in a way to evaluate the condition as fast as possible */
790 static struct join_table
**ordertables( MSIWHEREVIEW
*wv
)
792 struct join_table
*table
, **tables
;
794 tables
= calloc(wv
->table_count
+ 1, sizeof(*tables
));
799 reorder_check(wv
->cond
, tables
, FALSE
, &table
);
801 reorder_check(wv
->cond
, tables
, TRUE
, &table
);
807 add_to_array(tables
, table
);
813 static UINT
WHERE_execute( struct tagMSIVIEW
*view
, MSIRECORD
*record
)
815 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
817 struct join_table
*table
= wv
->tables
;
819 struct join_table
**ordered_tables
;
822 TRACE("%p %p\n", wv
, record
);
825 return ERROR_FUNCTION_FAILED
;
827 r
= init_reorder(wv
);
828 if (r
!= ERROR_SUCCESS
)
833 table
->view
->ops
->execute(table
->view
, NULL
);
835 r
= table
->view
->ops
->get_dimensions(table
->view
, &table
->row_count
, NULL
);
836 if (r
!= ERROR_SUCCESS
)
838 ERR("failed to get table dimensions\n");
842 /* each table must have at least one row */
843 if (table
->row_count
== 0)
844 return ERROR_SUCCESS
;
846 while ((table
= table
->next
));
848 ordered_tables
= ordertables( wv
);
850 rows
= malloc(wv
->table_count
* sizeof(*rows
));
851 for (i
= 0; i
< wv
->table_count
; i
++)
852 rows
[i
] = INVALID_ROW_INDEX
;
854 r
= check_condition(wv
, record
, ordered_tables
, rows
);
857 wv
->order_info
->error
= ERROR_SUCCESS
;
859 qsort(wv
->reorder
, wv
->row_count
, sizeof(struct row_entry
*), compare_entry
);
862 r
= wv
->order_info
->error
;
865 free(ordered_tables
);
869 static UINT
WHERE_close( struct tagMSIVIEW
*view
)
871 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
872 struct join_table
*table
= wv
->tables
;
877 return ERROR_FUNCTION_FAILED
;
880 table
->view
->ops
->close(table
->view
);
881 while ((table
= table
->next
));
883 return ERROR_SUCCESS
;
886 static UINT
WHERE_get_dimensions( struct tagMSIVIEW
*view
, UINT
*rows
, UINT
*cols
)
888 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
890 TRACE("%p %p %p\n", wv
, rows
, cols
);
893 return ERROR_FUNCTION_FAILED
;
898 return ERROR_FUNCTION_FAILED
;
899 *rows
= wv
->row_count
;
903 *cols
= wv
->col_count
;
905 return ERROR_SUCCESS
;
908 static UINT
WHERE_get_column_info( struct tagMSIVIEW
*view
, UINT n
, LPCWSTR
*name
,
909 UINT
*type
, BOOL
*temporary
, LPCWSTR
*table_name
)
911 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
912 struct join_table
*table
;
914 TRACE("%p %d %p %p %p %p\n", wv
, n
, name
, type
, temporary
, table_name
);
917 return ERROR_FUNCTION_FAILED
;
919 table
= find_table(wv
, n
, &n
);
921 return ERROR_FUNCTION_FAILED
;
923 return table
->view
->ops
->get_column_info(table
->view
, n
, name
,
924 type
, temporary
, table_name
);
927 static UINT
join_find_row( MSIWHEREVIEW
*wv
, MSIRECORD
*rec
, UINT
*row
)
932 str
= MSI_RecordGetString( rec
, 1 );
933 r
= msi_string2id( wv
->db
->strings
, str
, -1, &id
);
934 if (r
!= ERROR_SUCCESS
)
937 for (i
= 0; i
< wv
->row_count
; i
++)
939 WHERE_fetch_int( &wv
->view
, i
, 1, &data
);
944 return ERROR_SUCCESS
;
948 return ERROR_FUNCTION_FAILED
;
951 static UINT
join_modify_update( struct tagMSIVIEW
*view
, MSIRECORD
*rec
)
953 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
954 UINT r
, row
, i
, mask
= 0;
958 r
= join_find_row( wv
, rec
, &row
);
959 if (r
!= ERROR_SUCCESS
)
962 r
= msi_view_get_row( wv
->db
, view
, row
, ¤t
);
963 if (r
!= ERROR_SUCCESS
)
966 assert(MSI_RecordGetFieldCount(rec
) == MSI_RecordGetFieldCount(current
));
968 for (i
= MSI_RecordGetFieldCount(rec
); i
> 0; i
--)
970 if (!MSI_RecordsAreFieldsEqual(rec
, current
, i
))
971 mask
|= 1 << (i
- 1);
973 msiobj_release(¤t
->hdr
);
975 return WHERE_set_row( view
, row
, rec
, mask
);
978 static UINT
WHERE_modify( struct tagMSIVIEW
*view
, MSIMODIFY eModifyMode
,
979 MSIRECORD
*rec
, UINT row
)
981 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
982 struct join_table
*table
= wv
->tables
;
985 TRACE("%p %d %p\n", wv
, eModifyMode
, rec
);
988 return ERROR_FUNCTION_FAILED
;
994 if (find_row(wv
, row
, &rows
) == ERROR_SUCCESS
)
999 return table
->view
->ops
->modify(table
->view
, eModifyMode
, rec
, row
);
1002 switch (eModifyMode
)
1004 case MSIMODIFY_UPDATE
:
1005 return join_modify_update( view
, rec
);
1007 case MSIMODIFY_ASSIGN
:
1008 case MSIMODIFY_DELETE
:
1009 case MSIMODIFY_INSERT
:
1010 case MSIMODIFY_INSERT_TEMPORARY
:
1011 case MSIMODIFY_MERGE
:
1012 case MSIMODIFY_REPLACE
:
1013 case MSIMODIFY_SEEK
:
1014 case MSIMODIFY_VALIDATE
:
1015 case MSIMODIFY_VALIDATE_DELETE
:
1016 case MSIMODIFY_VALIDATE_FIELD
:
1017 case MSIMODIFY_VALIDATE_NEW
:
1018 r
= ERROR_FUNCTION_FAILED
;
1021 case MSIMODIFY_REFRESH
:
1022 r
= ERROR_CALL_NOT_IMPLEMENTED
;
1026 WARN("%p %d %p %u - unknown mode\n", view
, eModifyMode
, rec
, row
);
1027 r
= ERROR_INVALID_PARAMETER
;
1034 static UINT
WHERE_delete( struct tagMSIVIEW
*view
)
1036 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
1037 struct join_table
*table
= wv
->tables
;
1043 struct join_table
*next
;
1045 table
->view
->ops
->delete(table
->view
);
1052 wv
->table_count
= 0;
1056 free(wv
->order_info
);
1057 wv
->order_info
= NULL
;
1059 msiobj_release( &wv
->db
->hdr
);
1062 return ERROR_SUCCESS
;
1065 static UINT
WHERE_sort(struct tagMSIVIEW
*view
, column_info
*columns
)
1067 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
1068 struct join_table
*table
= wv
->tables
;
1069 column_info
*column
= columns
;
1070 MSIORDERINFO
*orderinfo
;
1074 TRACE("%p %p\n", view
, columns
);
1077 return ERROR_FUNCTION_FAILED
;
1082 column
= column
->next
;
1086 return ERROR_SUCCESS
;
1088 orderinfo
= malloc(offsetof(MSIORDERINFO
, columns
[count
]));
1090 return ERROR_OUTOFMEMORY
;
1092 orderinfo
->col_count
= count
;
1096 for (i
= 0; i
< count
; i
++)
1098 orderinfo
->columns
[i
].unparsed
.column
= column
->column
;
1099 orderinfo
->columns
[i
].unparsed
.table
= column
->table
;
1101 r
= parse_column(wv
, &orderinfo
->columns
[i
], NULL
);
1102 if (r
!= ERROR_SUCCESS
)
1106 wv
->order_info
= orderinfo
;
1108 return ERROR_SUCCESS
;
1114 static const MSIVIEWOPS where_ops
=
1126 WHERE_get_dimensions
,
1127 WHERE_get_column_info
,
1137 static UINT
WHERE_VerifyCondition( MSIWHEREVIEW
*wv
, struct expr
*cond
,
1142 switch( cond
->type
)
1150 r
= parse_column(wv
, &cond
->u
.column
, &type
);
1151 if (r
!= ERROR_SUCCESS
)
1154 if (type
&MSITYPE_STRING
)
1155 cond
->type
= EXPR_COL_NUMBER_STRING
;
1156 else if ((type
&0xff) == 4)
1157 cond
->type
= EXPR_COL_NUMBER32
;
1159 cond
->type
= EXPR_COL_NUMBER
;
1165 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.left
, valid
);
1166 if( r
!= ERROR_SUCCESS
)
1169 return ERROR_SUCCESS
;
1170 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.right
, valid
);
1171 if( r
!= ERROR_SUCCESS
)
1174 /* check the type of the comparison */
1175 if( ( cond
->u
.expr
.left
->type
== EXPR_SVAL
) ||
1176 ( cond
->u
.expr
.left
->type
== EXPR_COL_NUMBER_STRING
) ||
1177 ( cond
->u
.expr
.right
->type
== EXPR_SVAL
) ||
1178 ( cond
->u
.expr
.right
->type
== EXPR_COL_NUMBER_STRING
) )
1180 switch( cond
->u
.expr
.op
)
1187 return ERROR_INVALID_PARAMETER
;
1190 /* FIXME: check we're comparing a string to a column */
1192 cond
->type
= EXPR_STRCMP
;
1197 if ( cond
->u
.expr
.left
->type
!= EXPR_COLUMN
)
1200 return ERROR_INVALID_PARAMETER
;
1202 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.left
, valid
);
1203 if( r
!= ERROR_SUCCESS
)
1208 cond
->type
= EXPR_UVAL
;
1209 cond
->u
.uval
= cond
->u
.ival
;
1218 ERR("Invalid expression type\n");
1223 return ERROR_SUCCESS
;
1226 UINT
WHERE_CreateView( MSIDATABASE
*db
, MSIVIEW
**view
, LPWSTR tables
,
1229 MSIWHEREVIEW
*wv
= NULL
;
1233 TRACE("(%s)\n", debugstr_w(tables
) );
1235 wv
= calloc(1, sizeof *wv
);
1237 return ERROR_FUNCTION_FAILED
;
1239 /* fill the structure */
1240 wv
->view
.ops
= &where_ops
;
1241 msiobj_addref( &db
->hdr
);
1247 struct join_table
*table
;
1249 if ((ptr
= wcschr(tables
, ' ')))
1252 table
= malloc(sizeof(*table
));
1255 r
= ERROR_OUTOFMEMORY
;
1259 r
= TABLE_CreateView(db
, tables
, &table
->view
);
1260 if (r
!= ERROR_SUCCESS
)
1262 WARN("can't create table: %s\n", debugstr_w(tables
));
1264 r
= ERROR_BAD_QUERY_SYNTAX
;
1268 r
= table
->view
->ops
->get_dimensions(table
->view
, NULL
,
1270 if (r
!= ERROR_SUCCESS
)
1272 ERR("can't get table dimensions\n");
1273 table
->view
->ops
->delete(table
->view
);
1278 wv
->col_count
+= table
->col_count
;
1279 table
->table_index
= wv
->table_count
++;
1281 table
->next
= wv
->tables
;
1292 r
= WHERE_VerifyCondition( wv
, cond
, &valid
);
1293 if( r
!= ERROR_SUCCESS
)
1296 r
= ERROR_FUNCTION_FAILED
;
1301 *view
= (MSIVIEW
*) wv
;
1303 return ERROR_SUCCESS
;
1305 WHERE_delete(&wv
->view
);