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
;
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_get_row( struct tagMSIVIEW
*view
, UINT row
, MSIRECORD
**rec
)
264 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
266 TRACE("%p %d %p\n", wv
, row
, rec
);
269 return ERROR_FUNCTION_FAILED
;
271 return msi_view_get_row( wv
->db
, view
, row
, rec
);
274 static UINT
WHERE_set_row( struct tagMSIVIEW
*view
, UINT row
, MSIRECORD
*rec
, UINT mask
)
276 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
277 UINT i
, r
, offset
= 0;
278 JOINTABLE
*table
= wv
->tables
;
280 UINT mask_copy
= mask
;
282 TRACE("%p %d %p %08x\n", wv
, row
, rec
, mask
);
285 return ERROR_FUNCTION_FAILED
;
287 r
= find_row(wv
, row
, &rows
);
288 if (r
!= ERROR_SUCCESS
)
291 if (mask
>= 1 << wv
->col_count
)
292 return ERROR_INVALID_PARAMETER
;
296 for (i
= 0; i
< table
->col_count
; i
++) {
299 if (!(mask_copy
& (1 << i
)))
301 r
= table
->view
->ops
->get_column_info(table
->view
, i
+ 1, NULL
,
303 if (r
!= ERROR_SUCCESS
)
305 if (type
& MSITYPE_KEY
)
306 return ERROR_FUNCTION_FAILED
;
308 mask_copy
>>= table
->col_count
;
310 while (mask_copy
&& (table
= table
->next
));
316 const UINT col_count
= table
->col_count
;
319 UINT reduced_mask
= (mask
>> offset
) & ((1 << col_count
) - 1);
327 reduced
= MSI_CreateRecord(col_count
);
329 return ERROR_FUNCTION_FAILED
;
331 for (i
= 1; i
<= col_count
; i
++)
333 r
= MSI_RecordCopyField(rec
, i
+ offset
, reduced
, i
);
334 if (r
!= ERROR_SUCCESS
)
340 if (r
== ERROR_SUCCESS
)
341 r
= table
->view
->ops
->set_row(table
->view
, rows
[table
->table_index
], reduced
, reduced_mask
);
343 msiobj_release(&reduced
->hdr
);
345 while ((table
= table
->next
));
349 static UINT
WHERE_delete_row(struct tagMSIVIEW
*view
, UINT row
)
351 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
355 TRACE("(%p %d)\n", view
, row
);
358 return ERROR_FUNCTION_FAILED
;
360 r
= find_row(wv
, row
, &rows
);
361 if ( r
!= ERROR_SUCCESS
)
364 if (wv
->table_count
> 1)
365 return ERROR_CALL_NOT_IMPLEMENTED
;
367 return wv
->tables
->view
->ops
->delete_row(wv
->tables
->view
, rows
[0]);
370 static INT
INT_evaluate_binary( MSIWHEREVIEW
*wv
, const UINT rows
[],
371 const struct complex_expr
*expr
, INT
*val
, MSIRECORD
*record
)
376 rl
= WHERE_evaluate(wv
, rows
, expr
->left
, &lval
, record
);
377 if (rl
!= ERROR_SUCCESS
&& rl
!= ERROR_CONTINUE
)
379 rr
= WHERE_evaluate(wv
, rows
, expr
->right
, &rval
, record
);
380 if (rr
!= ERROR_SUCCESS
&& rr
!= ERROR_CONTINUE
)
383 if (rl
== ERROR_CONTINUE
|| rr
== ERROR_CONTINUE
)
388 return ERROR_CONTINUE
;
391 if (expr
->op
== OP_AND
)
393 if ((rl
== ERROR_CONTINUE
&& !rval
) || (rr
== ERROR_CONTINUE
&& !lval
))
396 return ERROR_SUCCESS
;
399 else if (expr
->op
== OP_OR
)
401 if ((rl
== ERROR_CONTINUE
&& rval
) || (rr
== ERROR_CONTINUE
&& lval
))
404 return ERROR_SUCCESS
;
409 return ERROR_CONTINUE
;
415 *val
= ( lval
== rval
);
418 *val
= ( lval
&& rval
);
421 *val
= ( lval
|| rval
);
424 *val
= ( lval
> rval
);
427 *val
= ( lval
< rval
);
430 *val
= ( lval
<= rval
);
433 *val
= ( lval
>= rval
);
436 *val
= ( lval
!= rval
);
439 ERR("Unknown operator %d\n", expr
->op
);
440 return ERROR_FUNCTION_FAILED
;
443 return ERROR_SUCCESS
;
446 static inline UINT
expr_fetch_value(const union ext_column
*expr
, const UINT rows
[], UINT
*val
)
448 JOINTABLE
*table
= expr
->parsed
.table
;
450 if( rows
[table
->table_index
] == INVALID_ROW_INDEX
)
453 return ERROR_CONTINUE
;
455 return table
->view
->ops
->fetch_int(table
->view
, rows
[table
->table_index
],
456 expr
->parsed
.column
, val
);
460 static UINT
INT_evaluate_unary( MSIWHEREVIEW
*wv
, const UINT rows
[],
461 const struct complex_expr
*expr
, INT
*val
, MSIRECORD
*record
)
466 r
= expr_fetch_value(&expr
->left
->u
.column
, rows
, &lval
);
467 if(r
!= ERROR_SUCCESS
)
479 ERR("Unknown operator %d\n", expr
->op
);
480 return ERROR_FUNCTION_FAILED
;
482 return ERROR_SUCCESS
;
485 static UINT
STRING_evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[],
486 const struct expr
*expr
,
487 const MSIRECORD
*record
,
490 UINT val
= 0, r
= ERROR_SUCCESS
;
494 case EXPR_COL_NUMBER_STRING
:
495 r
= expr_fetch_value(&expr
->u
.column
, rows
, &val
);
496 if (r
== ERROR_SUCCESS
)
497 *str
= msi_string_lookup(wv
->db
->strings
, val
, NULL
);
507 *str
= MSI_RecordGetString(record
, ++wv
->rec_index
);
511 ERR("Invalid expression type\n");
512 r
= ERROR_FUNCTION_FAILED
;
519 static UINT
STRCMP_Evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[], const struct complex_expr
*expr
,
520 INT
*val
, const MSIRECORD
*record
)
523 const WCHAR
*l_str
, *r_str
;
527 r
= STRING_evaluate(wv
, rows
, expr
->left
, record
, &l_str
);
528 if (r
== ERROR_CONTINUE
)
530 r
= STRING_evaluate(wv
, rows
, expr
->right
, record
, &r_str
);
531 if (r
== ERROR_CONTINUE
)
534 if( l_str
== r_str
||
535 ((!l_str
|| !*l_str
) && (!r_str
|| !*r_str
)) )
537 else if( l_str
&& ! r_str
)
539 else if( r_str
&& ! l_str
)
542 sr
= strcmpW( l_str
, r_str
);
544 *val
= ( expr
->op
== OP_EQ
&& ( sr
== 0 ) ) ||
545 ( expr
->op
== OP_NE
&& ( sr
!= 0 ) );
547 return ERROR_SUCCESS
;
550 static UINT
WHERE_evaluate( MSIWHEREVIEW
*wv
, const UINT rows
[],
551 struct expr
*cond
, INT
*val
, MSIRECORD
*record
)
558 return ERROR_SUCCESS
;
563 case EXPR_COL_NUMBER
:
564 r
= expr_fetch_value(&cond
->u
.column
, rows
, &tval
);
565 if( r
!= ERROR_SUCCESS
)
567 *val
= tval
- 0x8000;
568 return ERROR_SUCCESS
;
570 case EXPR_COL_NUMBER32
:
571 r
= expr_fetch_value(&cond
->u
.column
, rows
, &tval
);
572 if( r
!= ERROR_SUCCESS
)
574 *val
= tval
- 0x80000000;
579 return ERROR_SUCCESS
;
582 return INT_evaluate_binary(wv
, rows
, &cond
->u
.expr
, val
, record
);
585 return INT_evaluate_unary( wv
, rows
, &cond
->u
.expr
, val
, record
);
588 return STRCMP_Evaluate( wv
, rows
, &cond
->u
.expr
, val
, record
);
591 *val
= MSI_RecordGetInteger( record
, ++wv
->rec_index
);
592 return ERROR_SUCCESS
;
595 ERR("Invalid expression type\n");
599 return ERROR_SUCCESS
;
602 static UINT
check_condition( MSIWHEREVIEW
*wv
, MSIRECORD
*record
, JOINTABLE
**tables
,
605 UINT r
= ERROR_FUNCTION_FAILED
;
608 for (table_rows
[(*tables
)->table_index
] = 0;
609 table_rows
[(*tables
)->table_index
] < (*tables
)->row_count
;
610 table_rows
[(*tables
)->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
, tables
+ 1, table_rows
);
622 if (r
!= ERROR_SUCCESS
)
627 if (r
!= ERROR_SUCCESS
)
629 add_row (wv
, table_rows
);
633 table_rows
[(*tables
)->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 void add_to_array( JOINTABLE
**array
, JOINTABLE
*elem
)
686 while (*array
&& *array
!= elem
)
692 static BOOL
in_array( JOINTABLE
**array
, JOINTABLE
*elem
)
694 while (*array
&& *array
!= elem
)
696 return *array
!= NULL
;
699 #define CONST_EXPR 1 /* comparison to a constant value */
700 #define JOIN_TO_CONST_EXPR 0x10000 /* comparison to a table involved with
701 a CONST_EXPR comaprison */
703 static UINT
reorder_check( const struct expr
*expr
, JOINTABLE
**ordered_tables
,
704 BOOL process_joins
, JOINTABLE
**lastused
)
714 case EXPR_COL_NUMBER
:
715 case EXPR_COL_NUMBER32
:
716 case EXPR_COL_NUMBER_STRING
:
717 if (in_array(ordered_tables
, expr
->u
.column
.parsed
.table
))
718 return JOIN_TO_CONST_EXPR
;
719 *lastused
= expr
->u
.column
.parsed
.table
;
723 res
= reorder_check(expr
->u
.expr
.right
, ordered_tables
, process_joins
, lastused
);
726 res
+= reorder_check(expr
->u
.expr
.left
, ordered_tables
, process_joins
, lastused
);
729 if (res
== CONST_EXPR
)
730 add_to_array(ordered_tables
, *lastused
);
731 if (process_joins
&& res
== JOIN_TO_CONST_EXPR
+ CONST_EXPR
)
732 add_to_array(ordered_tables
, *lastused
);
735 ERR("Unknown expr type: %i\n", expr
->type
);
741 /* reorders the tablelist in a way to evaluate the condition as fast as possible */
742 static JOINTABLE
**ordertables( MSIWHEREVIEW
*wv
)
747 tables
= msi_alloc_zero( (wv
->table_count
+ 1) * sizeof(*tables
) );
752 reorder_check(wv
->cond
, tables
, FALSE
, &table
);
754 reorder_check(wv
->cond
, tables
, TRUE
, &table
);
760 add_to_array(tables
, table
);
766 static UINT
WHERE_execute( struct tagMSIVIEW
*view
, MSIRECORD
*record
)
768 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
770 JOINTABLE
*table
= wv
->tables
;
772 JOINTABLE
**ordered_tables
;
775 TRACE("%p %p\n", wv
, record
);
778 return ERROR_FUNCTION_FAILED
;
780 r
= init_reorder(wv
);
781 if (r
!= ERROR_SUCCESS
)
786 table
->view
->ops
->execute(table
->view
, NULL
);
788 r
= table
->view
->ops
->get_dimensions(table
->view
, &table
->row_count
, NULL
);
789 if (r
!= ERROR_SUCCESS
)
791 ERR("failed to get table dimensions\n");
795 /* each table must have at least one row */
796 if (table
->row_count
== 0)
797 return ERROR_SUCCESS
;
799 while ((table
= table
->next
));
801 ordered_tables
= ordertables( wv
);
803 rows
= msi_alloc( wv
->table_count
* sizeof(*rows
) );
804 for (i
= 0; i
< wv
->table_count
; i
++)
805 rows
[i
] = INVALID_ROW_INDEX
;
807 r
= check_condition(wv
, record
, ordered_tables
, rows
);
810 wv
->order_info
->error
= ERROR_SUCCESS
;
812 qsort(wv
->reorder
, wv
->row_count
, sizeof(MSIROWENTRY
*), compare_entry
);
815 r
= wv
->order_info
->error
;
818 msi_free( ordered_tables
);
822 static UINT
WHERE_close( struct tagMSIVIEW
*view
)
824 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
825 JOINTABLE
*table
= wv
->tables
;
830 return ERROR_FUNCTION_FAILED
;
833 table
->view
->ops
->close(table
->view
);
834 while ((table
= table
->next
));
836 return ERROR_SUCCESS
;
839 static UINT
WHERE_get_dimensions( struct tagMSIVIEW
*view
, UINT
*rows
, UINT
*cols
)
841 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
843 TRACE("%p %p %p\n", wv
, rows
, cols
);
846 return ERROR_FUNCTION_FAILED
;
851 return ERROR_FUNCTION_FAILED
;
852 *rows
= wv
->row_count
;
856 *cols
= wv
->col_count
;
858 return ERROR_SUCCESS
;
861 static UINT
WHERE_get_column_info( struct tagMSIVIEW
*view
, UINT n
, LPCWSTR
*name
,
862 UINT
*type
, BOOL
*temporary
, LPCWSTR
*table_name
)
864 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
867 TRACE("%p %d %p %p %p %p\n", wv
, n
, name
, type
, temporary
, table_name
);
870 return ERROR_FUNCTION_FAILED
;
872 table
= find_table(wv
, n
, &n
);
874 return ERROR_FUNCTION_FAILED
;
876 return table
->view
->ops
->get_column_info(table
->view
, n
, name
,
877 type
, temporary
, table_name
);
880 static UINT
join_find_row( MSIWHEREVIEW
*wv
, MSIRECORD
*rec
, UINT
*row
)
885 str
= MSI_RecordGetString( rec
, 1 );
886 r
= msi_string2id( wv
->db
->strings
, str
, -1, &id
);
887 if (r
!= ERROR_SUCCESS
)
890 for (i
= 0; i
< wv
->row_count
; i
++)
892 WHERE_fetch_int( &wv
->view
, i
, 1, &data
);
897 return ERROR_SUCCESS
;
901 return ERROR_FUNCTION_FAILED
;
904 static UINT
join_modify_update( struct tagMSIVIEW
*view
, MSIRECORD
*rec
)
906 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
907 UINT r
, row
, i
, mask
= 0;
911 r
= join_find_row( wv
, rec
, &row
);
912 if (r
!= ERROR_SUCCESS
)
915 r
= msi_view_get_row( wv
->db
, view
, row
, ¤t
);
916 if (r
!= ERROR_SUCCESS
)
919 assert(MSI_RecordGetFieldCount(rec
) == MSI_RecordGetFieldCount(current
));
921 for (i
= MSI_RecordGetFieldCount(rec
); i
> 0; i
--)
923 if (!MSI_RecordsAreFieldsEqual(rec
, current
, i
))
924 mask
|= 1 << (i
- 1);
926 msiobj_release(¤t
->hdr
);
928 return WHERE_set_row( view
, row
, rec
, mask
);
931 static UINT
WHERE_modify( struct tagMSIVIEW
*view
, MSIMODIFY eModifyMode
,
932 MSIRECORD
*rec
, UINT row
)
934 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
935 JOINTABLE
*table
= wv
->tables
;
938 TRACE("%p %d %p\n", wv
, eModifyMode
, rec
);
941 return ERROR_FUNCTION_FAILED
;
947 if (find_row(wv
, row
- 1, &rows
) == ERROR_SUCCESS
)
952 return table
->view
->ops
->modify(table
->view
, eModifyMode
, rec
, row
);
957 case MSIMODIFY_UPDATE
:
958 return join_modify_update( view
, rec
);
960 case MSIMODIFY_ASSIGN
:
961 case MSIMODIFY_DELETE
:
962 case MSIMODIFY_INSERT
:
963 case MSIMODIFY_INSERT_TEMPORARY
:
964 case MSIMODIFY_MERGE
:
965 case MSIMODIFY_REPLACE
:
967 case MSIMODIFY_VALIDATE
:
968 case MSIMODIFY_VALIDATE_DELETE
:
969 case MSIMODIFY_VALIDATE_FIELD
:
970 case MSIMODIFY_VALIDATE_NEW
:
971 r
= ERROR_FUNCTION_FAILED
;
974 case MSIMODIFY_REFRESH
:
975 r
= ERROR_CALL_NOT_IMPLEMENTED
;
979 WARN("%p %d %p %u - unknown mode\n", view
, eModifyMode
, rec
, row
);
980 r
= ERROR_INVALID_PARAMETER
;
987 static UINT
WHERE_delete( struct tagMSIVIEW
*view
)
989 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
990 JOINTABLE
*table
= wv
->tables
;
998 table
->view
->ops
->delete(table
->view
);
1005 wv
->table_count
= 0;
1009 msi_free(wv
->order_info
);
1010 wv
->order_info
= NULL
;
1012 msiobj_release( &wv
->db
->hdr
);
1015 return ERROR_SUCCESS
;
1018 static UINT
WHERE_find_matching_rows( struct tagMSIVIEW
*view
, UINT col
,
1019 UINT val
, UINT
*row
, MSIITERHANDLE
*handle
)
1021 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
1024 TRACE("%p, %d, %u, %p\n", view
, col
, val
, *handle
);
1027 return ERROR_FUNCTION_FAILED
;
1029 if (col
== 0 || col
> wv
->col_count
)
1030 return ERROR_INVALID_PARAMETER
;
1032 for (i
= PtrToUlong(*handle
); i
< wv
->row_count
; i
++)
1034 if (view
->ops
->fetch_int( view
, i
, col
, &row_value
) != ERROR_SUCCESS
)
1037 if (row_value
== val
)
1040 *handle
= UlongToPtr(i
+ 1);
1041 return ERROR_SUCCESS
;
1045 return ERROR_NO_MORE_ITEMS
;
1048 static UINT
WHERE_sort(struct tagMSIVIEW
*view
, column_info
*columns
)
1050 MSIWHEREVIEW
*wv
= (MSIWHEREVIEW
*)view
;
1051 JOINTABLE
*table
= wv
->tables
;
1052 column_info
*column
= columns
;
1053 MSIORDERINFO
*orderinfo
;
1057 TRACE("%p %p\n", view
, columns
);
1060 return ERROR_FUNCTION_FAILED
;
1065 column
= column
->next
;
1069 return ERROR_SUCCESS
;
1071 orderinfo
= msi_alloc(FIELD_OFFSET(MSIORDERINFO
, columns
[count
]));
1073 return ERROR_OUTOFMEMORY
;
1075 orderinfo
->col_count
= count
;
1079 for (i
= 0; i
< count
; i
++)
1081 orderinfo
->columns
[i
].unparsed
.column
= column
->column
;
1082 orderinfo
->columns
[i
].unparsed
.table
= column
->table
;
1084 r
= parse_column(wv
, &orderinfo
->columns
[i
], NULL
);
1085 if (r
!= ERROR_SUCCESS
)
1089 wv
->order_info
= orderinfo
;
1091 return ERROR_SUCCESS
;
1093 msi_free(orderinfo
);
1097 static const MSIVIEWOPS where_ops
=
1107 WHERE_get_dimensions
,
1108 WHERE_get_column_info
,
1111 WHERE_find_matching_rows
,
1120 static UINT
WHERE_VerifyCondition( MSIWHEREVIEW
*wv
, struct expr
*cond
,
1125 switch( cond
->type
)
1133 r
= parse_column(wv
, &cond
->u
.column
, &type
);
1134 if (r
!= ERROR_SUCCESS
)
1137 if (type
&MSITYPE_STRING
)
1138 cond
->type
= EXPR_COL_NUMBER_STRING
;
1139 else if ((type
&0xff) == 4)
1140 cond
->type
= EXPR_COL_NUMBER32
;
1142 cond
->type
= EXPR_COL_NUMBER
;
1148 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.left
, valid
);
1149 if( r
!= ERROR_SUCCESS
)
1152 return ERROR_SUCCESS
;
1153 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.right
, valid
);
1154 if( r
!= ERROR_SUCCESS
)
1157 /* check the type of the comparison */
1158 if( ( cond
->u
.expr
.left
->type
== EXPR_SVAL
) ||
1159 ( cond
->u
.expr
.left
->type
== EXPR_COL_NUMBER_STRING
) ||
1160 ( cond
->u
.expr
.right
->type
== EXPR_SVAL
) ||
1161 ( cond
->u
.expr
.right
->type
== EXPR_COL_NUMBER_STRING
) )
1163 switch( cond
->u
.expr
.op
)
1170 return ERROR_INVALID_PARAMETER
;
1173 /* FIXME: check we're comparing a string to a column */
1175 cond
->type
= EXPR_STRCMP
;
1180 if ( cond
->u
.expr
.left
->type
!= EXPR_COLUMN
)
1183 return ERROR_INVALID_PARAMETER
;
1185 r
= WHERE_VerifyCondition( wv
, cond
->u
.expr
.left
, valid
);
1186 if( r
!= ERROR_SUCCESS
)
1191 cond
->type
= EXPR_UVAL
;
1192 cond
->u
.uval
= cond
->u
.ival
;
1201 ERR("Invalid expression type\n");
1206 return ERROR_SUCCESS
;
1209 UINT
WHERE_CreateView( MSIDATABASE
*db
, MSIVIEW
**view
, LPWSTR tables
,
1212 MSIWHEREVIEW
*wv
= NULL
;
1216 TRACE("(%s)\n", debugstr_w(tables
) );
1218 wv
= msi_alloc_zero( sizeof *wv
);
1220 return ERROR_FUNCTION_FAILED
;
1222 /* fill the structure */
1223 wv
->view
.ops
= &where_ops
;
1224 msiobj_addref( &db
->hdr
);
1232 if ((ptr
= strchrW(tables
, ' ')))
1235 table
= msi_alloc(sizeof(JOINTABLE
));
1238 r
= ERROR_OUTOFMEMORY
;
1242 r
= TABLE_CreateView(db
, tables
, &table
->view
);
1243 if (r
!= ERROR_SUCCESS
)
1245 WARN("can't create table: %s\n", debugstr_w(tables
));
1247 r
= ERROR_BAD_QUERY_SYNTAX
;
1251 r
= table
->view
->ops
->get_dimensions(table
->view
, NULL
,
1253 if (r
!= ERROR_SUCCESS
)
1255 ERR("can't get table dimensions\n");
1256 table
->view
->ops
->delete(table
->view
);
1261 wv
->col_count
+= table
->col_count
;
1262 table
->table_index
= wv
->table_count
++;
1264 table
->next
= wv
->tables
;
1275 r
= WHERE_VerifyCondition( wv
, cond
, &valid
);
1276 if( r
!= ERROR_SUCCESS
)
1279 r
= ERROR_FUNCTION_FAILED
;
1284 *view
= (MSIVIEW
*) wv
;
1286 return ERROR_SUCCESS
;
1288 WHERE_delete(&wv
->view
);