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_zero(wv
->reorder
, sizeof(MSIROWENTRY
*) * newsize
);
136 return ERROR_OUTOFMEMORY
;
138 wv
->reorder
= new_reorder
;
139 wv
->reorder_size
= newsize
;
142 new = msi_alloc(FIELD_OFFSET( MSIROWENTRY
, values
[wv
->table_count
] ));
145 return ERROR_OUTOFMEMORY
;
147 wv
->reorder
[wv
->row_count
++] = new;
149 memcpy(new->values
, vals
, wv
->table_count
* sizeof(UINT
));
152 return ERROR_SUCCESS
;
155 static JOINTABLE
*find_table(MSIWHEREVIEW
*wv
, UINT col
, UINT
*table_col
)
157 JOINTABLE
*table
= wv
->tables
;
159 if(col
== 0 || col
> wv
->col_count
)
162 while (col
> table
->col_count
)
164 col
-= table
->col_count
;
173 static UINT
parse_column(MSIWHEREVIEW
*wv
, union ext_column
*column
,
176 JOINTABLE
*table
= wv
->tables
;
183 if (column
->unparsed
.table
)
185 r
= table
->view
->ops
->get_column_info(table
->view
, 1, NULL
, NULL
,
187 if (r
!= ERROR_SUCCESS
)
189 if (wcscmp(table_name
, column
->unparsed
.table
) != 0)
193 for(i
= 1; i
<= table
->col_count
; i
++)
197 r
= table
->view
->ops
->get_column_info(table
->view
, i
, &col_name
, column_type
,
199 if(r
!= ERROR_SUCCESS
)
202 if(wcscmp(col_name
, column
->unparsed
.column
))
204 column
->parsed
.column
= i
;
205 column
->parsed
.table
= table
;
206 return ERROR_SUCCESS
;
209 while ((table
= table
->next
));
211 WARN("Couldn't find column %s.%s\n", debugstr_w( column
->unparsed
.table
), debugstr_w( column
->unparsed
.column
) );
212 return ERROR_BAD_QUERY_SYNTAX
;
215 static UINT
WHERE_fetch_int( struct tagMSIVIEW
*view
, UINT row
, UINT col
, UINT
*val
)
217 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
222 TRACE("%p %d %d %p\n", wv
, row
, col
, val
);
225 return ERROR_FUNCTION_FAILED
;
227 r
= find_row(wv
, row
, &rows
);
228 if (r
!= ERROR_SUCCESS
)
231 table
= find_table(wv
, col
, &col
);
233 return ERROR_FUNCTION_FAILED
;
235 return table
->view
->ops
->fetch_int(table
->view
, rows
[table
->table_index
], col
, val
);
238 static UINT
WHERE_fetch_stream( struct tagMSIVIEW
*view
, UINT row
, UINT col
, IStream
**stm
)
240 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
245 TRACE("%p %d %d %p\n", wv
, row
, col
, stm
);
248 return ERROR_FUNCTION_FAILED
;
250 r
= find_row(wv
, row
, &rows
);
251 if (r
!= ERROR_SUCCESS
)
254 table
= find_table(wv
, col
, &col
);
256 return ERROR_FUNCTION_FAILED
;
258 return table
->view
->ops
->fetch_stream( table
->view
, rows
[table
->table_index
], col
, stm
);
261 static UINT
WHERE_set_int(struct tagMSIVIEW
*view
, UINT row
, UINT col
, int val
)
263 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
268 TRACE("view %p, row %u, col %u, val %d.\n", wv
, row
, col
, val
);
270 r
= find_row(wv
, row
, &rows
);
271 if (r
!= ERROR_SUCCESS
)
274 table
= find_table(wv
, col
, &col
);
276 return ERROR_FUNCTION_FAILED
;
278 return table
->view
->ops
->set_int(table
->view
, rows
[table
->table_index
], col
, val
);
281 static UINT
WHERE_set_string(struct tagMSIVIEW
*view
, UINT row
, UINT col
, const WCHAR
*val
, int len
)
283 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
288 TRACE("view %p, row %u, col %u, val %s.\n", wv
, row
, col
, debugstr_wn(val
, len
));
290 r
= find_row(wv
, row
, &rows
);
291 if (r
!= ERROR_SUCCESS
)
294 table
= find_table(wv
, col
, &col
);
296 return ERROR_FUNCTION_FAILED
;
298 return table
->view
->ops
->set_string(table
->view
, rows
[table
->table_index
], col
, val
, len
);
301 static UINT
WHERE_set_stream(MSIVIEW
*view
, UINT row
, UINT col
, IStream
*stream
)
303 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
308 TRACE("view %p, row %u, col %u, stream %p.\n", wv
, row
, col
, stream
);
310 r
= find_row(wv
, row
, &rows
);
311 if (r
!= ERROR_SUCCESS
)
314 table
= find_table(wv
, col
, &col
);
316 return ERROR_FUNCTION_FAILED
;
318 return table
->view
->ops
->set_stream(table
->view
, rows
[table
->table_index
], col
, stream
);
321 static UINT
WHERE_set_row( struct tagMSIVIEW
*view
, UINT row
, MSIRECORD
*rec
, UINT mask
)
323 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
324 UINT i
, r
, offset
= 0;
325 JOINTABLE
*table
= wv
->tables
;
327 UINT mask_copy
= mask
;
329 TRACE("%p %d %p %08x\n", wv
, row
, rec
, mask
);
332 return ERROR_FUNCTION_FAILED
;
334 r
= find_row(wv
, row
, &rows
);
335 if (r
!= ERROR_SUCCESS
)
338 if (mask
>= 1 << wv
->col_count
)
339 return ERROR_INVALID_PARAMETER
;
343 for (i
= 0; i
< table
->col_count
; i
++) {
346 if (!(mask_copy
& (1 << i
)))
348 r
= table
->view
->ops
->get_column_info(table
->view
, i
+ 1, NULL
,
350 if (r
!= ERROR_SUCCESS
)
352 if (type
& MSITYPE_KEY
)
353 return ERROR_FUNCTION_FAILED
;
355 mask_copy
>>= table
->col_count
;
357 while (mask_copy
&& (table
= table
->next
));
363 const UINT col_count
= table
->col_count
;
366 UINT reduced_mask
= (mask
>> offset
) & ((1 << col_count
) - 1);
374 reduced
= MSI_CreateRecord(col_count
);
376 return ERROR_FUNCTION_FAILED
;
378 for (i
= 1; i
<= col_count
; i
++)
380 r
= MSI_RecordCopyField(rec
, i
+ offset
, reduced
, i
);
381 if (r
!= ERROR_SUCCESS
)
387 if (r
== ERROR_SUCCESS
)
388 r
= table
->view
->ops
->set_row(table
->view
, rows
[table
->table_index
], reduced
, reduced_mask
);
390 msiobj_release(&reduced
->hdr
);
392 while ((table
= table
->next
));
396 static UINT
WHERE_delete_row(struct tagMSIVIEW
*view
, UINT row
)
398 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
402 TRACE("(%p %d)\n", view
, row
);
405 return ERROR_FUNCTION_FAILED
;
407 r
= find_row(wv
, row
, &rows
);
408 if ( r
!= ERROR_SUCCESS
)
411 if (wv
->table_count
> 1)
412 return ERROR_CALL_NOT_IMPLEMENTED
;
414 return wv
->tables
->view
->ops
->delete_row(wv
->tables
->view
, rows
[0]);
417 static INT
INT_evaluate_binary( MSIWHEREVIEW
*wv
, const UINT rows
[],
418 const struct complex_expr
*expr
, INT
*val
, MSIRECORD
*record
)
423 rl
= WHERE_evaluate(wv
, rows
, expr
->left
, &lval
, record
);
424 if (rl
!= ERROR_SUCCESS
&& rl
!= ERROR_CONTINUE
)
426 rr
= WHERE_evaluate(wv
, rows
, expr
->right
, &rval
, record
);
427 if (rr
!= ERROR_SUCCESS
&& rr
!= ERROR_CONTINUE
)
430 if (rl
== ERROR_CONTINUE
|| rr
== ERROR_CONTINUE
)
435 return ERROR_CONTINUE
;
438 if (expr
->op
== OP_AND
)
440 if ((rl
== ERROR_CONTINUE
&& !rval
) || (rr
== ERROR_CONTINUE
&& !lval
))
443 return ERROR_SUCCESS
;
446 else if (expr
->op
== OP_OR
)
448 if ((rl
== ERROR_CONTINUE
&& rval
) || (rr
== ERROR_CONTINUE
&& lval
))
451 return ERROR_SUCCESS
;
456 return ERROR_CONTINUE
;
462 *val
= ( lval
== rval
);
465 *val
= ( lval
&& rval
);
468 *val
= ( lval
|| rval
);
471 *val
= ( lval
> rval
);
474 *val
= ( lval
< rval
);
477 *val
= ( lval
<= rval
);
480 *val
= ( lval
>= rval
);
483 *val
= ( lval
!= rval
);
486 ERR("Unknown operator %d\n", expr
->op
);
487 return ERROR_FUNCTION_FAILED
;
490 return ERROR_SUCCESS
;
493 static inline UINT
expr_fetch_value(const union ext_column
*expr
, const UINT rows
[], UINT
*val
)
495 JOINTABLE
*table
= expr
->parsed
.table
;
497 if( rows
[table
->table_index
] == INVALID_ROW_INDEX
)
500 return ERROR_CONTINUE
;
502 return table
->view
->ops
->fetch_int(table
->view
, rows
[table
->table_index
],
503 expr
->parsed
.column
, val
);
507 static UINT
INT_evaluate_unary( MSIWHEREVIEW
*wv
, const UINT rows
[],
508 const struct complex_expr
*expr
, INT
*val
, MSIRECORD
*record
)
513 r
= expr_fetch_value(&expr
->left
->u
.column
, rows
, &lval
);
514 if(r
!= ERROR_SUCCESS
)
526 ERR("Unknown operator %d\n", expr
->op
);
527 return ERROR_FUNCTION_FAILED
;
529 return ERROR_SUCCESS
;
532 static UINT
STRING_evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[],
533 const struct expr
*expr
,
534 const MSIRECORD
*record
,
537 UINT val
= 0, r
= ERROR_SUCCESS
;
541 case EXPR_COL_NUMBER_STRING
:
542 r
= expr_fetch_value(&expr
->u
.column
, rows
, &val
);
543 if (r
== ERROR_SUCCESS
)
544 *str
= msi_string_lookup(wv
->db
->strings
, val
, NULL
);
554 *str
= MSI_RecordGetString(record
, ++wv
->rec_index
);
558 ERR("Invalid expression type\n");
559 r
= ERROR_FUNCTION_FAILED
;
566 static UINT
STRCMP_Evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[], const struct complex_expr
*expr
,
567 INT
*val
, const MSIRECORD
*record
)
570 const WCHAR
*l_str
, *r_str
;
574 r
= STRING_evaluate(wv
, rows
, expr
->left
, record
, &l_str
);
575 if (r
== ERROR_CONTINUE
)
577 r
= STRING_evaluate(wv
, rows
, expr
->right
, record
, &r_str
);
578 if (r
== ERROR_CONTINUE
)
581 if( l_str
== r_str
||
582 ((!l_str
|| !*l_str
) && (!r_str
|| !*r_str
)) )
584 else if( l_str
&& ! r_str
)
586 else if( r_str
&& ! l_str
)
589 sr
= wcscmp( l_str
, r_str
);
591 *val
= ( expr
->op
== OP_EQ
&& ( sr
== 0 ) ) ||
592 ( expr
->op
== OP_NE
&& ( sr
!= 0 ) );
594 return ERROR_SUCCESS
;
597 static UINT
WHERE_evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[],
598 struct expr
*cond
, INT
*val
, MSIRECORD
*record
)
605 return ERROR_SUCCESS
;
610 case EXPR_COL_NUMBER
:
611 r
= expr_fetch_value(&cond
->u
.column
, rows
, &tval
);
612 if( r
!= ERROR_SUCCESS
)
614 *val
= tval
- 0x8000;
615 return ERROR_SUCCESS
;
617 case EXPR_COL_NUMBER32
:
618 r
= expr_fetch_value(&cond
->u
.column
, rows
, &tval
);
619 if( r
!= ERROR_SUCCESS
)
621 *val
= tval
- 0x80000000;
626 return ERROR_SUCCESS
;
629 return INT_evaluate_binary(wv
, rows
, &cond
->u
.expr
, val
, record
);
632 return INT_evaluate_unary( wv
, rows
, &cond
->u
.expr
, val
, record
);
635 return STRCMP_Evaluate( wv
, rows
, &cond
->u
.expr
, val
, record
);
638 *val
= MSI_RecordGetInteger( record
, ++wv
->rec_index
);
639 return ERROR_SUCCESS
;
642 ERR("Invalid expression type\n");
643 return ERROR_FUNCTION_FAILED
;
646 return ERROR_SUCCESS
;
649 static UINT
check_condition( MSIWHEREVIEW
*wv
, MSIRECORD
*record
, JOINTABLE
**tables
,
652 UINT r
= ERROR_FUNCTION_FAILED
;
655 for (table_rows
[(*tables
)->table_index
] = 0;
656 table_rows
[(*tables
)->table_index
] < (*tables
)->row_count
;
657 table_rows
[(*tables
)->table_index
]++)
661 r
= WHERE_evaluate( wv
, table_rows
, wv
->cond
, &val
, record
);
662 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_CONTINUE
)
668 r
= check_condition(wv
, record
, tables
+ 1, table_rows
);
669 if (r
!= ERROR_SUCCESS
)
674 if (r
!= ERROR_SUCCESS
)
676 add_row (wv
, table_rows
);
680 table_rows
[(*tables
)->table_index
] = INVALID_ROW_INDEX
;
684 static int __cdecl
compare_entry( const void *left
, const void *right
)
686 const MSIROWENTRY
*le
= *(const MSIROWENTRY
**)left
;
687 const MSIROWENTRY
*re
= *(const MSIROWENTRY
**)right
;
688 const MSIWHEREVIEW
*wv
= le
->wv
;
689 MSIORDERINFO
*order
= wv
->order_info
;
690 UINT i
, j
, r
, l_val
, r_val
;
692 assert(le
->wv
== re
->wv
);
696 for (i
= 0; i
< order
->col_count
; i
++)
698 const union ext_column
*column
= &order
->columns
[i
];
700 r
= column
->parsed
.table
->view
->ops
->fetch_int(column
->parsed
.table
->view
,
701 le
->values
[column
->parsed
.table
->table_index
],
702 column
->parsed
.column
, &l_val
);
703 if (r
!= ERROR_SUCCESS
)
709 r
= column
->parsed
.table
->view
->ops
->fetch_int(column
->parsed
.table
->view
,
710 re
->values
[column
->parsed
.table
->table_index
],
711 column
->parsed
.column
, &r_val
);
712 if (r
!= ERROR_SUCCESS
)
719 return l_val
< r_val
? -1 : 1;
723 for (j
= 0; j
< wv
->table_count
; j
++)
725 if (le
->values
[j
] != re
->values
[j
])
726 return le
->values
[j
] < re
->values
[j
] ? -1 : 1;
731 static void add_to_array( JOINTABLE
**array
, JOINTABLE
*elem
)
733 while (*array
&& *array
!= elem
)
739 static BOOL
in_array( JOINTABLE
**array
, JOINTABLE
*elem
)
741 while (*array
&& *array
!= elem
)
743 return *array
!= NULL
;
746 #define CONST_EXPR 1 /* comparison to a constant value */
747 #define JOIN_TO_CONST_EXPR 0x10000 /* comparison to a table involved with
748 a CONST_EXPR comaprison */
750 static UINT
reorder_check( const struct expr
*expr
, JOINTABLE
**ordered_tables
,
751 BOOL process_joins
, JOINTABLE
**lastused
)
761 case EXPR_COL_NUMBER
:
762 case EXPR_COL_NUMBER32
:
763 case EXPR_COL_NUMBER_STRING
:
764 if (in_array(ordered_tables
, expr
->u
.column
.parsed
.table
))
765 return JOIN_TO_CONST_EXPR
;
766 *lastused
= expr
->u
.column
.parsed
.table
;
770 res
= reorder_check(expr
->u
.expr
.right
, ordered_tables
, process_joins
, lastused
);
773 res
+= reorder_check(expr
->u
.expr
.left
, ordered_tables
, process_joins
, lastused
);
776 if (res
== CONST_EXPR
)
777 add_to_array(ordered_tables
, *lastused
);
778 if (process_joins
&& res
== JOIN_TO_CONST_EXPR
+ CONST_EXPR
)
779 add_to_array(ordered_tables
, *lastused
);
782 ERR("Unknown expr type: %i\n", expr
->type
);
788 /* reorders the tablelist in a way to evaluate the condition as fast as possible */
789 static JOINTABLE
**ordertables( MSIWHEREVIEW
*wv
)
794 tables
= msi_alloc_zero( (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 JOINTABLE
*table
= wv
->tables
;
819 JOINTABLE
**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
= msi_alloc( 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(MSIROWENTRY
*), compare_entry
);
862 r
= wv
->order_info
->error
;
865 msi_free( ordered_tables
);
869 static UINT
WHERE_close( struct tagMSIVIEW
*view
)
871 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
872 JOINTABLE
*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
;
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 JOINTABLE
*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 JOINTABLE
*table
= wv
->tables
;
1045 table
->view
->ops
->delete(table
->view
);
1052 wv
->table_count
= 0;
1056 msi_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 JOINTABLE
*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
= msi_alloc(FIELD_OFFSET(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
;
1110 msi_free(orderinfo
);
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
= msi_alloc_zero( sizeof *wv
);
1237 return ERROR_FUNCTION_FAILED
;
1239 /* fill the structure */
1240 wv
->view
.ops
= &where_ops
;
1241 msiobj_addref( &db
->hdr
);
1249 if ((ptr
= wcschr(tables
, ' ')))
1252 table
= msi_alloc(sizeof(JOINTABLE
));
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
);