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 */
41 typedef struct tagMSIROWENTRY
43 struct tagMSIWHEREVIEW
*wv
; /* used during sorting */
47 typedef struct tagJOINTABLE
49 struct tagJOINTABLE
*next
;
56 typedef struct tagMSIORDERINFO
60 union ext_column columns
[1];
63 typedef struct tagMSIWHEREVIEW
71 MSIROWENTRY
**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
++)
93 msi_free(wv
->reorder
[i
]);
95 msi_free( wv
->reorder
);
101 static UINT
init_reorder(MSIWHEREVIEW
*wv
)
103 MSIROWENTRY
**new = msi_alloc_zero(sizeof(MSIROWENTRY
*) * INITIAL_REORDER_SIZE
);
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
[])
129 if (wv
->reorder_size
<= wv
->row_count
)
131 MSIROWENTRY
**new_reorder
;
132 UINT newsize
= wv
->reorder_size
* 2;
134 new_reorder
= msi_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 = 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 (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
;
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
;
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
;
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
;
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
;
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 JOINTABLE
*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 JOINTABLE
*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
, JOINTABLE
**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 MSIROWENTRY
*le
= *(const MSIROWENTRY
**)left
;
688 const MSIROWENTRY
*re
= *(const MSIROWENTRY
**)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( JOINTABLE
**array
, JOINTABLE
*elem
)
734 while (*array
&& *array
!= elem
)
740 static BOOL
in_array( JOINTABLE
**array
, JOINTABLE
*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
, JOINTABLE
**ordered_tables
,
752 BOOL process_joins
, JOINTABLE
**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 JOINTABLE
**ordertables( MSIWHEREVIEW
*wv
)
795 tables
= msi_alloc_zero( (wv
->table_count
+ 1) * sizeof(*tables
) );
800 reorder_check(wv
->cond
, tables
, FALSE
, &table
);
802 reorder_check(wv
->cond
, tables
, TRUE
, &table
);
808 add_to_array(tables
, table
);
814 static UINT
WHERE_execute( struct tagMSIVIEW
*view
, MSIRECORD
*record
)
816 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
818 JOINTABLE
*table
= wv
->tables
;
820 JOINTABLE
**ordered_tables
;
823 TRACE("%p %p\n", wv
, record
);
826 return ERROR_FUNCTION_FAILED
;
828 r
= init_reorder(wv
);
829 if (r
!= ERROR_SUCCESS
)
834 table
->view
->ops
->execute(table
->view
, NULL
);
836 r
= table
->view
->ops
->get_dimensions(table
->view
, &table
->row_count
, NULL
);
837 if (r
!= ERROR_SUCCESS
)
839 ERR("failed to get table dimensions\n");
843 /* each table must have at least one row */
844 if (table
->row_count
== 0)
845 return ERROR_SUCCESS
;
847 while ((table
= table
->next
));
849 ordered_tables
= ordertables( wv
);
851 rows
= msi_alloc( wv
->table_count
* sizeof(*rows
) );
852 for (i
= 0; i
< wv
->table_count
; i
++)
853 rows
[i
] = INVALID_ROW_INDEX
;
855 r
= check_condition(wv
, record
, ordered_tables
, rows
);
858 wv
->order_info
->error
= ERROR_SUCCESS
;
860 qsort(wv
->reorder
, wv
->row_count
, sizeof(MSIROWENTRY
*), compare_entry
);
863 r
= wv
->order_info
->error
;
866 msi_free( ordered_tables
);
870 static UINT
WHERE_close( struct tagMSIVIEW
*view
)
872 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
873 JOINTABLE
*table
= wv
->tables
;
878 return ERROR_FUNCTION_FAILED
;
881 table
->view
->ops
->close(table
->view
);
882 while ((table
= table
->next
));
884 return ERROR_SUCCESS
;
887 static UINT
WHERE_get_dimensions( struct tagMSIVIEW
*view
, UINT
*rows
, UINT
*cols
)
889 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
891 TRACE("%p %p %p\n", wv
, rows
, cols
);
894 return ERROR_FUNCTION_FAILED
;
899 return ERROR_FUNCTION_FAILED
;
900 *rows
= wv
->row_count
;
904 *cols
= wv
->col_count
;
906 return ERROR_SUCCESS
;
909 static UINT
WHERE_get_column_info( struct tagMSIVIEW
*view
, UINT n
, LPCWSTR
*name
,
910 UINT
*type
, BOOL
*temporary
, LPCWSTR
*table_name
)
912 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
915 TRACE("%p %d %p %p %p %p\n", wv
, n
, name
, type
, temporary
, table_name
);
918 return ERROR_FUNCTION_FAILED
;
920 table
= find_table(wv
, n
, &n
);
922 return ERROR_FUNCTION_FAILED
;
924 return table
->view
->ops
->get_column_info(table
->view
, n
, name
,
925 type
, temporary
, table_name
);
928 static UINT
join_find_row( MSIWHEREVIEW
*wv
, MSIRECORD
*rec
, UINT
*row
)
933 str
= MSI_RecordGetString( rec
, 1 );
934 r
= msi_string2id( wv
->db
->strings
, str
, -1, &id
);
935 if (r
!= ERROR_SUCCESS
)
938 for (i
= 0; i
< wv
->row_count
; i
++)
940 WHERE_fetch_int( &wv
->view
, i
, 1, &data
);
945 return ERROR_SUCCESS
;
949 return ERROR_FUNCTION_FAILED
;
952 static UINT
join_modify_update( struct tagMSIVIEW
*view
, MSIRECORD
*rec
)
954 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
955 UINT r
, row
, i
, mask
= 0;
959 r
= join_find_row( wv
, rec
, &row
);
960 if (r
!= ERROR_SUCCESS
)
963 r
= msi_view_get_row( wv
->db
, view
, row
, ¤t
);
964 if (r
!= ERROR_SUCCESS
)
967 assert(MSI_RecordGetFieldCount(rec
) == MSI_RecordGetFieldCount(current
));
969 for (i
= MSI_RecordGetFieldCount(rec
); i
> 0; i
--)
971 if (!MSI_RecordsAreFieldsEqual(rec
, current
, i
))
972 mask
|= 1 << (i
- 1);
974 msiobj_release(¤t
->hdr
);
976 return WHERE_set_row( view
, row
, rec
, mask
);
979 static UINT
WHERE_modify( struct tagMSIVIEW
*view
, MSIMODIFY eModifyMode
,
980 MSIRECORD
*rec
, UINT row
)
982 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
983 JOINTABLE
*table
= wv
->tables
;
986 TRACE("%p %d %p\n", wv
, eModifyMode
, rec
);
989 return ERROR_FUNCTION_FAILED
;
995 if (find_row(wv
, row
, &rows
) == ERROR_SUCCESS
)
1000 return table
->view
->ops
->modify(table
->view
, eModifyMode
, rec
, row
);
1003 switch (eModifyMode
)
1005 case MSIMODIFY_UPDATE
:
1006 return join_modify_update( view
, rec
);
1008 case MSIMODIFY_ASSIGN
:
1009 case MSIMODIFY_DELETE
:
1010 case MSIMODIFY_INSERT
:
1011 case MSIMODIFY_INSERT_TEMPORARY
:
1012 case MSIMODIFY_MERGE
:
1013 case MSIMODIFY_REPLACE
:
1014 case MSIMODIFY_SEEK
:
1015 case MSIMODIFY_VALIDATE
:
1016 case MSIMODIFY_VALIDATE_DELETE
:
1017 case MSIMODIFY_VALIDATE_FIELD
:
1018 case MSIMODIFY_VALIDATE_NEW
:
1019 r
= ERROR_FUNCTION_FAILED
;
1022 case MSIMODIFY_REFRESH
:
1023 r
= ERROR_CALL_NOT_IMPLEMENTED
;
1027 WARN("%p %d %p %u - unknown mode\n", view
, eModifyMode
, rec
, row
);
1028 r
= ERROR_INVALID_PARAMETER
;
1035 static UINT
WHERE_delete( struct tagMSIVIEW
*view
)
1037 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
1038 JOINTABLE
*table
= wv
->tables
;
1046 table
->view
->ops
->delete(table
->view
);
1053 wv
->table_count
= 0;
1057 msi_free(wv
->order_info
);
1058 wv
->order_info
= NULL
;
1060 msiobj_release( &wv
->db
->hdr
);
1063 return ERROR_SUCCESS
;
1066 static UINT
WHERE_sort(struct tagMSIVIEW
*view
, column_info
*columns
)
1068 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
1069 JOINTABLE
*table
= wv
->tables
;
1070 column_info
*column
= columns
;
1071 MSIORDERINFO
*orderinfo
;
1075 TRACE("%p %p\n", view
, columns
);
1078 return ERROR_FUNCTION_FAILED
;
1083 column
= column
->next
;
1087 return ERROR_SUCCESS
;
1089 orderinfo
= msi_alloc(FIELD_OFFSET(MSIORDERINFO
, columns
[count
]));
1091 return ERROR_OUTOFMEMORY
;
1093 orderinfo
->col_count
= count
;
1097 for (i
= 0; i
< count
; i
++)
1099 orderinfo
->columns
[i
].unparsed
.column
= column
->column
;
1100 orderinfo
->columns
[i
].unparsed
.table
= column
->table
;
1102 r
= parse_column(wv
, &orderinfo
->columns
[i
], NULL
);
1103 if (r
!= ERROR_SUCCESS
)
1107 wv
->order_info
= orderinfo
;
1109 return ERROR_SUCCESS
;
1111 msi_free(orderinfo
);
1115 static const MSIVIEWOPS where_ops
=
1127 WHERE_get_dimensions
,
1128 WHERE_get_column_info
,
1138 static UINT
WHERE_VerifyCondition( MSIWHEREVIEW
*wv
, struct expr
*cond
,
1143 switch( cond
->type
)
1151 r
= parse_column(wv
, &cond
->u
.column
, &type
);
1152 if (r
!= ERROR_SUCCESS
)
1155 if (type
&MSITYPE_STRING
)
1156 cond
->type
= EXPR_COL_NUMBER_STRING
;
1157 else if ((type
&0xff) == 4)
1158 cond
->type
= EXPR_COL_NUMBER32
;
1160 cond
->type
= EXPR_COL_NUMBER
;
1166 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.left
, valid
);
1167 if( r
!= ERROR_SUCCESS
)
1170 return ERROR_SUCCESS
;
1171 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.right
, valid
);
1172 if( r
!= ERROR_SUCCESS
)
1175 /* check the type of the comparison */
1176 if( ( cond
->u
.expr
.left
->type
== EXPR_SVAL
) ||
1177 ( cond
->u
.expr
.left
->type
== EXPR_COL_NUMBER_STRING
) ||
1178 ( cond
->u
.expr
.right
->type
== EXPR_SVAL
) ||
1179 ( cond
->u
.expr
.right
->type
== EXPR_COL_NUMBER_STRING
) )
1181 switch( cond
->u
.expr
.op
)
1188 return ERROR_INVALID_PARAMETER
;
1191 /* FIXME: check we're comparing a string to a column */
1193 cond
->type
= EXPR_STRCMP
;
1198 if ( cond
->u
.expr
.left
->type
!= EXPR_COLUMN
)
1201 return ERROR_INVALID_PARAMETER
;
1203 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.left
, valid
);
1204 if( r
!= ERROR_SUCCESS
)
1209 cond
->type
= EXPR_UVAL
;
1210 cond
->u
.uval
= cond
->u
.ival
;
1219 ERR("Invalid expression type\n");
1224 return ERROR_SUCCESS
;
1227 UINT
WHERE_CreateView( MSIDATABASE
*db
, MSIVIEW
**view
, LPWSTR tables
,
1230 MSIWHEREVIEW
*wv
= NULL
;
1234 TRACE("(%s)\n", debugstr_w(tables
) );
1236 wv
= msi_alloc_zero( sizeof *wv
);
1238 return ERROR_FUNCTION_FAILED
;
1240 /* fill the structure */
1241 wv
->view
.ops
= &where_ops
;
1242 msiobj_addref( &db
->hdr
);
1250 if ((ptr
= wcschr(tables
, ' ')))
1253 table
= msi_alloc(sizeof(JOINTABLE
));
1256 r
= ERROR_OUTOFMEMORY
;
1260 r
= TABLE_CreateView(db
, tables
, &table
->view
);
1261 if (r
!= ERROR_SUCCESS
)
1263 WARN("can't create table: %s\n", debugstr_w(tables
));
1265 r
= ERROR_BAD_QUERY_SYNTAX
;
1269 r
= table
->view
->ops
->get_dimensions(table
->view
, NULL
,
1271 if (r
!= ERROR_SUCCESS
)
1273 ERR("can't get table dimensions\n");
1274 table
->view
->ops
->delete(table
->view
);
1279 wv
->col_count
+= table
->col_count
;
1280 table
->table_index
= wv
->table_count
++;
1282 table
->next
= wv
->tables
;
1293 r
= WHERE_VerifyCondition( wv
, cond
, &valid
);
1294 if( r
!= ERROR_SUCCESS
)
1297 r
= ERROR_FUNCTION_FAILED
;
1302 *view
= (MSIVIEW
*) wv
;
1304 return ERROR_SUCCESS
;
1306 WHERE_delete(&wv
->view
);