Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenwhere.c
Go to the documentation of this file.
00001 /* 00002 * Implementation of the Microsoft Installer (msi.dll) 00003 * 00004 * Copyright 2002 Mike McCormack for CodeWeavers 00005 * Copyright 2011 Bernhard Loos 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include <stdarg.h> 00023 #include <assert.h> 00024 00025 #include "windef.h" 00026 #include "winbase.h" 00027 #include "winerror.h" 00028 #include "wine/debug.h" 00029 #include "wine/unicode.h" 00030 #include "msi.h" 00031 #include "msiquery.h" 00032 #include "objbase.h" 00033 #include "objidl.h" 00034 #include "msipriv.h" 00035 #include "winnls.h" 00036 00037 #include "query.h" 00038 00039 WINE_DEFAULT_DEBUG_CHANNEL(msidb); 00040 00041 /* below is the query interface to a table */ 00042 typedef struct tagMSIROWENTRY 00043 { 00044 struct tagMSIWHEREVIEW *wv; /* used during sorting */ 00045 UINT values[1]; 00046 } MSIROWENTRY; 00047 00048 typedef struct tagJOINTABLE 00049 { 00050 struct tagJOINTABLE *next; 00051 MSIVIEW *view; 00052 UINT col_count; 00053 UINT row_count; 00054 UINT table_index; 00055 } JOINTABLE; 00056 00057 typedef struct tagMSIORDERINFO 00058 { 00059 UINT col_count; 00060 UINT error; 00061 union ext_column columns[1]; 00062 } MSIORDERINFO; 00063 00064 typedef struct tagMSIWHEREVIEW 00065 { 00066 MSIVIEW view; 00067 MSIDATABASE *db; 00068 JOINTABLE *tables; 00069 UINT row_count; 00070 UINT col_count; 00071 UINT table_count; 00072 MSIROWENTRY **reorder; 00073 UINT reorder_size; /* number of entries available in reorder */ 00074 struct expr *cond; 00075 UINT rec_index; 00076 MSIORDERINFO *order_info; 00077 } MSIWHEREVIEW; 00078 00079 static UINT WHERE_evaluate( MSIWHEREVIEW *wv, const UINT rows[], 00080 struct expr *cond, INT *val, MSIRECORD *record ); 00081 00082 #define INITIAL_REORDER_SIZE 16 00083 00084 #define INVALID_ROW_INDEX (-1) 00085 00086 static void free_reorder(MSIWHEREVIEW *wv) 00087 { 00088 UINT i; 00089 00090 if (!wv->reorder) 00091 return; 00092 00093 for (i = 0; i < wv->row_count; i++) 00094 msi_free(wv->reorder[i]); 00095 00096 msi_free( wv->reorder ); 00097 wv->reorder = NULL; 00098 wv->reorder_size = 0; 00099 wv->row_count = 0; 00100 } 00101 00102 static UINT init_reorder(MSIWHEREVIEW *wv) 00103 { 00104 MSIROWENTRY **new = msi_alloc_zero(sizeof(MSIROWENTRY *) * INITIAL_REORDER_SIZE); 00105 if (!new) 00106 return ERROR_OUTOFMEMORY; 00107 00108 free_reorder(wv); 00109 00110 wv->reorder = new; 00111 wv->reorder_size = INITIAL_REORDER_SIZE; 00112 00113 return ERROR_SUCCESS; 00114 } 00115 00116 static inline UINT find_row(MSIWHEREVIEW *wv, UINT row, UINT *(values[])) 00117 { 00118 if (row >= wv->row_count) 00119 return ERROR_NO_MORE_ITEMS; 00120 00121 *values = wv->reorder[row]->values; 00122 00123 return ERROR_SUCCESS; 00124 } 00125 00126 static UINT add_row(MSIWHEREVIEW *wv, UINT vals[]) 00127 { 00128 MSIROWENTRY *new; 00129 00130 if (wv->reorder_size <= wv->row_count) 00131 { 00132 MSIROWENTRY **new_reorder; 00133 UINT newsize = wv->reorder_size * 2; 00134 00135 new_reorder = msi_realloc_zero(wv->reorder, sizeof(MSIROWENTRY *) * newsize); 00136 if (!new_reorder) 00137 return ERROR_OUTOFMEMORY; 00138 00139 wv->reorder = new_reorder; 00140 wv->reorder_size = newsize; 00141 } 00142 00143 new = msi_alloc(FIELD_OFFSET( MSIROWENTRY, values[wv->table_count] )); 00144 00145 if (!new) 00146 return ERROR_OUTOFMEMORY; 00147 00148 wv->reorder[wv->row_count++] = new; 00149 00150 memcpy(new->values, vals, wv->table_count * sizeof(UINT)); 00151 new->wv = wv; 00152 00153 return ERROR_SUCCESS; 00154 } 00155 00156 static JOINTABLE *find_table(MSIWHEREVIEW *wv, UINT col, UINT *table_col) 00157 { 00158 JOINTABLE *table = wv->tables; 00159 00160 if(col == 0 || col > wv->col_count) 00161 return NULL; 00162 00163 while (col > table->col_count) 00164 { 00165 col -= table->col_count; 00166 table = table->next; 00167 assert(table); 00168 } 00169 00170 *table_col = col; 00171 return table; 00172 } 00173 00174 static UINT parse_column(MSIWHEREVIEW *wv, union ext_column *column, 00175 UINT *column_type) 00176 { 00177 JOINTABLE *table = wv->tables; 00178 UINT i, r; 00179 00180 do 00181 { 00182 LPCWSTR table_name; 00183 00184 if (column->unparsed.table) 00185 { 00186 r = table->view->ops->get_column_info(table->view, 1, NULL, NULL, 00187 NULL, &table_name); 00188 if (r != ERROR_SUCCESS) 00189 return r; 00190 if (strcmpW(table_name, column->unparsed.table) != 0) 00191 continue; 00192 } 00193 00194 for(i = 1; i <= table->col_count; i++) 00195 { 00196 LPCWSTR col_name; 00197 00198 r = table->view->ops->get_column_info(table->view, i, &col_name, column_type, 00199 NULL, NULL); 00200 if(r != ERROR_SUCCESS ) 00201 return r; 00202 00203 if(strcmpW(col_name, column->unparsed.column)) 00204 continue; 00205 column->parsed.column = i; 00206 column->parsed.table = table; 00207 return ERROR_SUCCESS; 00208 } 00209 } 00210 while ((table = table->next)); 00211 00212 WARN("Couldn't find column %s.%s\n", debugstr_w( column->unparsed.table ), debugstr_w( column->unparsed.column ) ); 00213 return ERROR_BAD_QUERY_SYNTAX; 00214 } 00215 00216 static UINT WHERE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) 00217 { 00218 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 00219 JOINTABLE *table; 00220 UINT *rows; 00221 UINT r; 00222 00223 TRACE("%p %d %d %p\n", wv, row, col, val ); 00224 00225 if( !wv->tables ) 00226 return ERROR_FUNCTION_FAILED; 00227 00228 r = find_row(wv, row, &rows); 00229 if (r != ERROR_SUCCESS) 00230 return r; 00231 00232 table = find_table(wv, col, &col); 00233 if (!table) 00234 return ERROR_FUNCTION_FAILED; 00235 00236 return table->view->ops->fetch_int(table->view, rows[table->table_index], col, val); 00237 } 00238 00239 static UINT WHERE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm ) 00240 { 00241 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 00242 JOINTABLE *table; 00243 UINT *rows; 00244 UINT r; 00245 00246 TRACE("%p %d %d %p\n", wv, row, col, stm ); 00247 00248 if( !wv->tables ) 00249 return ERROR_FUNCTION_FAILED; 00250 00251 r = find_row(wv, row, &rows); 00252 if (r != ERROR_SUCCESS) 00253 return r; 00254 00255 table = find_table(wv, col, &col); 00256 if (!table) 00257 return ERROR_FUNCTION_FAILED; 00258 00259 return table->view->ops->fetch_stream( table->view, rows[table->table_index], col, stm ); 00260 } 00261 00262 static UINT WHERE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec ) 00263 { 00264 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view; 00265 00266 TRACE("%p %d %p\n", wv, row, rec ); 00267 00268 if (!wv->tables) 00269 return ERROR_FUNCTION_FAILED; 00270 00271 return msi_view_get_row( wv->db, view, row, rec ); 00272 } 00273 00274 static UINT WHERE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask ) 00275 { 00276 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 00277 UINT i, r, offset = 0; 00278 JOINTABLE *table = wv->tables; 00279 UINT *rows; 00280 UINT mask_copy = mask; 00281 00282 TRACE("%p %d %p %08x\n", wv, row, rec, mask ); 00283 00284 if( !wv->tables ) 00285 return ERROR_FUNCTION_FAILED; 00286 00287 r = find_row(wv, row, &rows); 00288 if (r != ERROR_SUCCESS) 00289 return r; 00290 00291 if (mask >= 1 << wv->col_count) 00292 return ERROR_INVALID_PARAMETER; 00293 00294 do 00295 { 00296 for (i = 0; i < table->col_count; i++) { 00297 UINT type; 00298 00299 if (!(mask_copy & (1 << i))) 00300 continue; 00301 r = table->view->ops->get_column_info(table->view, i + 1, NULL, 00302 &type, NULL, NULL ); 00303 if (r != ERROR_SUCCESS) 00304 return r; 00305 if (type & MSITYPE_KEY) 00306 return ERROR_FUNCTION_FAILED; 00307 } 00308 mask_copy >>= table->col_count; 00309 } 00310 while (mask_copy && (table = table->next)); 00311 00312 table = wv->tables; 00313 00314 do 00315 { 00316 const UINT col_count = table->col_count; 00317 UINT i; 00318 MSIRECORD *reduced; 00319 UINT reduced_mask = (mask >> offset) & ((1 << col_count) - 1); 00320 00321 if (!reduced_mask) 00322 { 00323 offset += col_count; 00324 continue; 00325 } 00326 00327 reduced = MSI_CreateRecord(col_count); 00328 if (!reduced) 00329 return ERROR_FUNCTION_FAILED; 00330 00331 for (i = 1; i <= col_count; i++) 00332 { 00333 r = MSI_RecordCopyField(rec, i + offset, reduced, i); 00334 if (r != ERROR_SUCCESS) 00335 break; 00336 } 00337 00338 offset += col_count; 00339 00340 if (r == ERROR_SUCCESS) 00341 r = table->view->ops->set_row(table->view, rows[table->table_index], reduced, reduced_mask); 00342 00343 msiobj_release(&reduced->hdr); 00344 } 00345 while ((table = table->next)); 00346 return r; 00347 } 00348 00349 static UINT WHERE_delete_row(struct tagMSIVIEW *view, UINT row) 00350 { 00351 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view; 00352 UINT r; 00353 UINT *rows; 00354 00355 TRACE("(%p %d)\n", view, row); 00356 00357 if (!wv->tables) 00358 return ERROR_FUNCTION_FAILED; 00359 00360 r = find_row(wv, row, &rows); 00361 if ( r != ERROR_SUCCESS ) 00362 return r; 00363 00364 if (wv->table_count > 1) 00365 return ERROR_CALL_NOT_IMPLEMENTED; 00366 00367 return wv->tables->view->ops->delete_row(wv->tables->view, rows[0]); 00368 } 00369 00370 static INT INT_evaluate_binary( MSIWHEREVIEW *wv, const UINT rows[], 00371 const struct complex_expr *expr, INT *val, MSIRECORD *record ) 00372 { 00373 UINT rl, rr; 00374 INT lval, rval; 00375 00376 rl = WHERE_evaluate(wv, rows, expr->left, &lval, record); 00377 if (rl != ERROR_SUCCESS && rl != ERROR_CONTINUE) 00378 return rl; 00379 rr = WHERE_evaluate(wv, rows, expr->right, &rval, record); 00380 if (rr != ERROR_SUCCESS && rr != ERROR_CONTINUE) 00381 return rr; 00382 00383 if (rl == ERROR_CONTINUE || rr == ERROR_CONTINUE) 00384 { 00385 if (rl == rr) 00386 { 00387 *val = TRUE; 00388 return ERROR_CONTINUE; 00389 } 00390 00391 if (expr->op == OP_AND) 00392 { 00393 if ((rl == ERROR_CONTINUE && !rval) || (rr == ERROR_CONTINUE && !lval)) 00394 { 00395 *val = FALSE; 00396 return ERROR_SUCCESS; 00397 } 00398 } 00399 else if (expr->op == OP_OR) 00400 { 00401 if ((rl == ERROR_CONTINUE && rval) || (rr == ERROR_CONTINUE && lval)) 00402 { 00403 *val = TRUE; 00404 return ERROR_SUCCESS; 00405 } 00406 } 00407 00408 *val = TRUE; 00409 return ERROR_CONTINUE; 00410 } 00411 00412 switch( expr->op ) 00413 { 00414 case OP_EQ: 00415 *val = ( lval == rval ); 00416 break; 00417 case OP_AND: 00418 *val = ( lval && rval ); 00419 break; 00420 case OP_OR: 00421 *val = ( lval || rval ); 00422 break; 00423 case OP_GT: 00424 *val = ( lval > rval ); 00425 break; 00426 case OP_LT: 00427 *val = ( lval < rval ); 00428 break; 00429 case OP_LE: 00430 *val = ( lval <= rval ); 00431 break; 00432 case OP_GE: 00433 *val = ( lval >= rval ); 00434 break; 00435 case OP_NE: 00436 *val = ( lval != rval ); 00437 break; 00438 default: 00439 ERR("Unknown operator %d\n", expr->op ); 00440 return ERROR_FUNCTION_FAILED; 00441 } 00442 00443 return ERROR_SUCCESS; 00444 } 00445 00446 static inline UINT expr_fetch_value(const union ext_column *expr, const UINT rows[], UINT *val) 00447 { 00448 JOINTABLE *table = expr->parsed.table; 00449 00450 if( rows[table->table_index] == INVALID_ROW_INDEX ) 00451 { 00452 *val = 1; 00453 return ERROR_CONTINUE; 00454 } 00455 return table->view->ops->fetch_int(table->view, rows[table->table_index], 00456 expr->parsed.column, val); 00457 } 00458 00459 00460 static UINT INT_evaluate_unary( MSIWHEREVIEW *wv, const UINT rows[], 00461 const struct complex_expr *expr, INT *val, MSIRECORD *record ) 00462 { 00463 UINT r; 00464 UINT lval; 00465 00466 r = expr_fetch_value(&expr->left->u.column, rows, &lval); 00467 if(r != ERROR_SUCCESS) 00468 return r; 00469 00470 switch( expr->op ) 00471 { 00472 case OP_ISNULL: 00473 *val = !lval; 00474 break; 00475 case OP_NOTNULL: 00476 *val = lval; 00477 break; 00478 default: 00479 ERR("Unknown operator %d\n", expr->op ); 00480 return ERROR_FUNCTION_FAILED; 00481 } 00482 return ERROR_SUCCESS; 00483 } 00484 00485 static UINT STRING_evaluate( MSIWHEREVIEW *wv, const UINT rows[], 00486 const struct expr *expr, 00487 const MSIRECORD *record, 00488 const WCHAR **str ) 00489 { 00490 UINT val = 0, r = ERROR_SUCCESS; 00491 00492 switch( expr->type ) 00493 { 00494 case EXPR_COL_NUMBER_STRING: 00495 r = expr_fetch_value(&expr->u.column, rows, &val); 00496 if (r == ERROR_SUCCESS) 00497 *str = msi_string_lookup_id(wv->db->strings, val); 00498 else 00499 *str = NULL; 00500 break; 00501 00502 case EXPR_SVAL: 00503 *str = expr->u.sval; 00504 break; 00505 00506 case EXPR_WILDCARD: 00507 *str = MSI_RecordGetString(record, ++wv->rec_index); 00508 break; 00509 00510 default: 00511 ERR("Invalid expression type\n"); 00512 r = ERROR_FUNCTION_FAILED; 00513 *str = NULL; 00514 break; 00515 } 00516 return r; 00517 } 00518 00519 static UINT STRCMP_Evaluate( MSIWHEREVIEW *wv, const UINT rows[], const struct complex_expr *expr, 00520 INT *val, const MSIRECORD *record ) 00521 { 00522 int sr; 00523 const WCHAR *l_str, *r_str; 00524 UINT r; 00525 00526 *val = TRUE; 00527 r = STRING_evaluate(wv, rows, expr->left, record, &l_str); 00528 if (r == ERROR_CONTINUE) 00529 return r; 00530 r = STRING_evaluate(wv, rows, expr->right, record, &r_str); 00531 if (r == ERROR_CONTINUE) 00532 return r; 00533 00534 if( l_str == r_str || 00535 ((!l_str || !*l_str) && (!r_str || !*r_str)) ) 00536 sr = 0; 00537 else if( l_str && ! r_str ) 00538 sr = 1; 00539 else if( r_str && ! l_str ) 00540 sr = -1; 00541 else 00542 sr = strcmpW( l_str, r_str ); 00543 00544 *val = ( expr->op == OP_EQ && ( sr == 0 ) ) || 00545 ( expr->op == OP_NE && ( sr != 0 ) ); 00546 00547 return ERROR_SUCCESS; 00548 } 00549 00550 static UINT WHERE_evaluate( MSIWHEREVIEW *wv, const UINT rows[], 00551 struct expr *cond, INT *val, MSIRECORD *record ) 00552 { 00553 UINT r, tval; 00554 00555 if( !cond ) 00556 { 00557 *val = TRUE; 00558 return ERROR_SUCCESS; 00559 } 00560 00561 switch( cond->type ) 00562 { 00563 case EXPR_COL_NUMBER: 00564 r = expr_fetch_value(&cond->u.column, rows, &tval); 00565 if( r != ERROR_SUCCESS ) 00566 return r; 00567 *val = tval - 0x8000; 00568 return ERROR_SUCCESS; 00569 00570 case EXPR_COL_NUMBER32: 00571 r = expr_fetch_value(&cond->u.column, rows, &tval); 00572 if( r != ERROR_SUCCESS ) 00573 return r; 00574 *val = tval - 0x80000000; 00575 return r; 00576 00577 case EXPR_UVAL: 00578 *val = cond->u.uval; 00579 return ERROR_SUCCESS; 00580 00581 case EXPR_COMPLEX: 00582 return INT_evaluate_binary(wv, rows, &cond->u.expr, val, record); 00583 00584 case EXPR_UNARY: 00585 return INT_evaluate_unary( wv, rows, &cond->u.expr, val, record ); 00586 00587 case EXPR_STRCMP: 00588 return STRCMP_Evaluate( wv, rows, &cond->u.expr, val, record ); 00589 00590 case EXPR_WILDCARD: 00591 *val = MSI_RecordGetInteger( record, ++wv->rec_index ); 00592 return ERROR_SUCCESS; 00593 00594 default: 00595 ERR("Invalid expression type\n"); 00596 break; 00597 } 00598 00599 return ERROR_SUCCESS; 00600 } 00601 00602 static UINT check_condition( MSIWHEREVIEW *wv, MSIRECORD *record, JOINTABLE **tables, 00603 UINT table_rows[] ) 00604 { 00605 UINT r = ERROR_FUNCTION_FAILED; 00606 INT val; 00607 00608 for (table_rows[(*tables)->table_index] = 0; 00609 table_rows[(*tables)->table_index] < (*tables)->row_count; 00610 table_rows[(*tables)->table_index]++) 00611 { 00612 val = 0; 00613 wv->rec_index = 0; 00614 r = WHERE_evaluate( wv, table_rows, wv->cond, &val, record ); 00615 if (r != ERROR_SUCCESS && r != ERROR_CONTINUE) 00616 break; 00617 if (val) 00618 { 00619 if (*(tables + 1)) 00620 { 00621 r = check_condition(wv, record, tables + 1, table_rows); 00622 if (r != ERROR_SUCCESS) 00623 break; 00624 } 00625 else 00626 { 00627 if (r != ERROR_SUCCESS) 00628 break; 00629 add_row (wv, table_rows); 00630 } 00631 } 00632 } 00633 table_rows[(*tables)->table_index] = INVALID_ROW_INDEX; 00634 return r; 00635 } 00636 00637 static int compare_entry( const void *left, const void *right ) 00638 { 00639 const MSIROWENTRY *le = *(const MSIROWENTRY**)left; 00640 const MSIROWENTRY *re = *(const MSIROWENTRY**)right; 00641 const MSIWHEREVIEW *wv = le->wv; 00642 MSIORDERINFO *order = wv->order_info; 00643 UINT i, j, r, l_val, r_val; 00644 00645 assert(le->wv == re->wv); 00646 00647 if (order) 00648 { 00649 for (i = 0; i < order->col_count; i++) 00650 { 00651 const union ext_column *column = &order->columns[i]; 00652 00653 r = column->parsed.table->view->ops->fetch_int(column->parsed.table->view, 00654 le->values[column->parsed.table->table_index], 00655 column->parsed.column, &l_val); 00656 if (r != ERROR_SUCCESS) 00657 { 00658 order->error = r; 00659 return 0; 00660 } 00661 00662 r = column->parsed.table->view->ops->fetch_int(column->parsed.table->view, 00663 re->values[column->parsed.table->table_index], 00664 column->parsed.column, &r_val); 00665 if (r != ERROR_SUCCESS) 00666 { 00667 order->error = r; 00668 return 0; 00669 } 00670 00671 if (l_val != r_val) 00672 return l_val < r_val ? -1 : 1; 00673 } 00674 } 00675 00676 for (j = 0; j < wv->table_count; j++) 00677 { 00678 if (le->values[j] != re->values[j]) 00679 return le->values[j] < re->values[j] ? -1 : 1; 00680 } 00681 return 0; 00682 } 00683 00684 static void add_to_array( JOINTABLE **array, JOINTABLE *elem ) 00685 { 00686 while (*array && *array != elem) 00687 array++; 00688 if (!*array) 00689 *array = elem; 00690 } 00691 00692 static BOOL in_array( JOINTABLE **array, JOINTABLE *elem ) 00693 { 00694 while (*array && *array != elem) 00695 array++; 00696 return *array != NULL; 00697 } 00698 00699 #define CONST_EXPR 1 /* comparison to a constant value */ 00700 #define JOIN_TO_CONST_EXPR 0x10000 /* comparison to a table involved with 00701 a CONST_EXPR comaprison */ 00702 00703 static UINT reorder_check( const struct expr *expr, JOINTABLE **ordered_tables, 00704 BOOL process_joins, JOINTABLE **lastused ) 00705 { 00706 UINT res = 0; 00707 00708 switch (expr->type) 00709 { 00710 case EXPR_WILDCARD: 00711 case EXPR_SVAL: 00712 case EXPR_UVAL: 00713 return 0; 00714 case EXPR_COL_NUMBER: 00715 case EXPR_COL_NUMBER32: 00716 case EXPR_COL_NUMBER_STRING: 00717 if (in_array(ordered_tables, expr->u.column.parsed.table)) 00718 return JOIN_TO_CONST_EXPR; 00719 *lastused = expr->u.column.parsed.table; 00720 return CONST_EXPR; 00721 case EXPR_STRCMP: 00722 case EXPR_COMPLEX: 00723 res = reorder_check(expr->u.expr.right, ordered_tables, process_joins, lastused); 00724 /* fall through */ 00725 case EXPR_UNARY: 00726 res += reorder_check(expr->u.expr.left, ordered_tables, process_joins, lastused); 00727 if (res == 0) 00728 return 0; 00729 if (res == CONST_EXPR) 00730 add_to_array(ordered_tables, *lastused); 00731 if (process_joins && res == JOIN_TO_CONST_EXPR + CONST_EXPR) 00732 add_to_array(ordered_tables, *lastused); 00733 return res; 00734 default: 00735 ERR("Unknown expr type: %i\n", expr->type); 00736 assert(0); 00737 return 0x1000000; 00738 } 00739 } 00740 00741 /* reorders the tablelist in a way to evaluate the condition as fast as possible */ 00742 static JOINTABLE **ordertables( MSIWHEREVIEW *wv ) 00743 { 00744 JOINTABLE *table; 00745 JOINTABLE **tables; 00746 00747 tables = msi_alloc_zero( (wv->table_count + 1) * sizeof(*tables) ); 00748 00749 if (wv->cond) 00750 { 00751 table = NULL; 00752 reorder_check(wv->cond, tables, FALSE, &table); 00753 table = NULL; 00754 reorder_check(wv->cond, tables, TRUE, &table); 00755 } 00756 00757 table = wv->tables; 00758 while (table) 00759 { 00760 add_to_array(tables, table); 00761 table = table->next; 00762 } 00763 return tables; 00764 } 00765 00766 static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) 00767 { 00768 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 00769 UINT r; 00770 JOINTABLE *table = wv->tables; 00771 UINT *rows; 00772 JOINTABLE **ordered_tables; 00773 int i = 0; 00774 00775 TRACE("%p %p\n", wv, record); 00776 00777 if( !table ) 00778 return ERROR_FUNCTION_FAILED; 00779 00780 r = init_reorder(wv); 00781 if (r != ERROR_SUCCESS) 00782 return r; 00783 00784 do 00785 { 00786 table->view->ops->execute(table->view, NULL); 00787 00788 r = table->view->ops->get_dimensions(table->view, &table->row_count, NULL); 00789 if (r != ERROR_SUCCESS) 00790 { 00791 ERR("failed to get table dimensions\n"); 00792 return r; 00793 } 00794 00795 /* each table must have at least one row */ 00796 if (table->row_count == 0) 00797 return ERROR_SUCCESS; 00798 } 00799 while ((table = table->next)); 00800 00801 ordered_tables = ordertables( wv ); 00802 00803 rows = msi_alloc( wv->table_count * sizeof(*rows) ); 00804 for (i = 0; i < wv->table_count; i++) 00805 rows[i] = INVALID_ROW_INDEX; 00806 00807 r = check_condition(wv, record, ordered_tables, rows); 00808 00809 if (wv->order_info) 00810 wv->order_info->error = ERROR_SUCCESS; 00811 00812 qsort(wv->reorder, wv->row_count, sizeof(MSIROWENTRY *), compare_entry); 00813 00814 if (wv->order_info) 00815 r = wv->order_info->error; 00816 00817 msi_free( rows ); 00818 msi_free( ordered_tables ); 00819 return r; 00820 } 00821 00822 static UINT WHERE_close( struct tagMSIVIEW *view ) 00823 { 00824 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 00825 JOINTABLE *table = wv->tables; 00826 00827 TRACE("%p\n", wv ); 00828 00829 if (!table) 00830 return ERROR_FUNCTION_FAILED; 00831 00832 do 00833 table->view->ops->close(table->view); 00834 while ((table = table->next)); 00835 00836 return ERROR_SUCCESS; 00837 } 00838 00839 static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) 00840 { 00841 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 00842 00843 TRACE("%p %p %p\n", wv, rows, cols ); 00844 00845 if(!wv->tables) 00846 return ERROR_FUNCTION_FAILED; 00847 00848 if (rows) 00849 { 00850 if (!wv->reorder) 00851 return ERROR_FUNCTION_FAILED; 00852 *rows = wv->row_count; 00853 } 00854 00855 if (cols) 00856 *cols = wv->col_count; 00857 00858 return ERROR_SUCCESS; 00859 } 00860 00861 static UINT WHERE_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name, 00862 UINT *type, BOOL *temporary, LPCWSTR *table_name ) 00863 { 00864 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 00865 JOINTABLE *table; 00866 00867 TRACE("%p %d %p %p %p %p\n", wv, n, name, type, temporary, table_name ); 00868 00869 if(!wv->tables) 00870 return ERROR_FUNCTION_FAILED; 00871 00872 table = find_table(wv, n, &n); 00873 if (!table) 00874 return ERROR_FUNCTION_FAILED; 00875 00876 return table->view->ops->get_column_info(table->view, n, name, 00877 type, temporary, table_name); 00878 } 00879 00880 static UINT join_find_row( MSIWHEREVIEW *wv, MSIRECORD *rec, UINT *row ) 00881 { 00882 LPCWSTR str; 00883 UINT r, i, id, data; 00884 00885 str = MSI_RecordGetString( rec, 1 ); 00886 r = msi_string2idW( wv->db->strings, str, &id ); 00887 if (r != ERROR_SUCCESS) 00888 return r; 00889 00890 for (i = 0; i < wv->row_count; i++) 00891 { 00892 WHERE_fetch_int( &wv->view, i, 1, &data ); 00893 00894 if (data == id) 00895 { 00896 *row = i; 00897 return ERROR_SUCCESS; 00898 } 00899 } 00900 00901 return ERROR_FUNCTION_FAILED; 00902 } 00903 00904 static UINT join_modify_update( struct tagMSIVIEW *view, MSIRECORD *rec ) 00905 { 00906 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view; 00907 UINT r, row, i, mask = 0; 00908 MSIRECORD *current; 00909 00910 00911 r = join_find_row( wv, rec, &row ); 00912 if (r != ERROR_SUCCESS) 00913 return r; 00914 00915 r = msi_view_get_row( wv->db, view, row, ¤t ); 00916 if (r != ERROR_SUCCESS) 00917 return r; 00918 00919 assert(MSI_RecordGetFieldCount(rec) == MSI_RecordGetFieldCount(current)); 00920 00921 for (i = MSI_RecordGetFieldCount(rec); i > 0; i--) 00922 { 00923 if (!MSI_RecordsAreFieldsEqual(rec, current, i)) 00924 mask |= 1 << (i - 1); 00925 } 00926 msiobj_release(¤t->hdr); 00927 00928 return WHERE_set_row( view, row, rec, mask ); 00929 } 00930 00931 static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, 00932 MSIRECORD *rec, UINT row ) 00933 { 00934 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 00935 JOINTABLE *table = wv->tables; 00936 UINT r; 00937 00938 TRACE("%p %d %p\n", wv, eModifyMode, rec); 00939 00940 if (!table) 00941 return ERROR_FUNCTION_FAILED; 00942 00943 if (!table->next) 00944 { 00945 UINT *rows; 00946 00947 if (find_row(wv, row - 1, &rows) == ERROR_SUCCESS) 00948 row = rows[0] + 1; 00949 else 00950 row = -1; 00951 00952 return table->view->ops->modify(table->view, eModifyMode, rec, row); 00953 } 00954 00955 switch (eModifyMode) 00956 { 00957 case MSIMODIFY_UPDATE: 00958 return join_modify_update( view, rec ); 00959 00960 case MSIMODIFY_ASSIGN: 00961 case MSIMODIFY_DELETE: 00962 case MSIMODIFY_INSERT: 00963 case MSIMODIFY_INSERT_TEMPORARY: 00964 case MSIMODIFY_MERGE: 00965 case MSIMODIFY_REPLACE: 00966 case MSIMODIFY_SEEK: 00967 case MSIMODIFY_VALIDATE: 00968 case MSIMODIFY_VALIDATE_DELETE: 00969 case MSIMODIFY_VALIDATE_FIELD: 00970 case MSIMODIFY_VALIDATE_NEW: 00971 r = ERROR_FUNCTION_FAILED; 00972 break; 00973 00974 case MSIMODIFY_REFRESH: 00975 r = ERROR_CALL_NOT_IMPLEMENTED; 00976 break; 00977 00978 default: 00979 WARN("%p %d %p %u - unknown mode\n", view, eModifyMode, rec, row ); 00980 r = ERROR_INVALID_PARAMETER; 00981 break; 00982 } 00983 00984 return r; 00985 } 00986 00987 static UINT WHERE_delete( struct tagMSIVIEW *view ) 00988 { 00989 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 00990 JOINTABLE *table = wv->tables; 00991 00992 TRACE("%p\n", wv ); 00993 00994 while(table) 00995 { 00996 JOINTABLE *next; 00997 00998 table->view->ops->delete(table->view); 00999 table->view = NULL; 01000 next = table->next; 01001 msi_free(table); 01002 table = next; 01003 } 01004 wv->tables = NULL; 01005 wv->table_count = 0; 01006 01007 free_reorder(wv); 01008 01009 msi_free(wv->order_info); 01010 wv->order_info = NULL; 01011 01012 msiobj_release( &wv->db->hdr ); 01013 msi_free( wv ); 01014 01015 return ERROR_SUCCESS; 01016 } 01017 01018 static UINT WHERE_find_matching_rows( struct tagMSIVIEW *view, UINT col, 01019 UINT val, UINT *row, MSIITERHANDLE *handle ) 01020 { 01021 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 01022 UINT i, row_value; 01023 01024 TRACE("%p, %d, %u, %p\n", view, col, val, *handle); 01025 01026 if (!wv->tables) 01027 return ERROR_FUNCTION_FAILED; 01028 01029 if (col == 0 || col > wv->col_count) 01030 return ERROR_INVALID_PARAMETER; 01031 01032 for (i = PtrToUlong(*handle); i < wv->row_count; i++) 01033 { 01034 if (view->ops->fetch_int( view, i, col, &row_value ) != ERROR_SUCCESS) 01035 continue; 01036 01037 if (row_value == val) 01038 { 01039 *row = i; 01040 *handle = UlongToPtr(i + 1); 01041 return ERROR_SUCCESS; 01042 } 01043 } 01044 01045 return ERROR_NO_MORE_ITEMS; 01046 } 01047 01048 static UINT WHERE_sort(struct tagMSIVIEW *view, column_info *columns) 01049 { 01050 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view; 01051 JOINTABLE *table = wv->tables; 01052 column_info *column = columns; 01053 MSIORDERINFO *orderinfo; 01054 UINT r, count = 0; 01055 int i; 01056 01057 TRACE("%p %p\n", view, columns); 01058 01059 if (!table) 01060 return ERROR_FUNCTION_FAILED; 01061 01062 while (column) 01063 { 01064 count++; 01065 column = column->next; 01066 } 01067 01068 if (count == 0) 01069 return ERROR_SUCCESS; 01070 01071 orderinfo = msi_alloc(sizeof(MSIORDERINFO) + (count - 1) * sizeof(union ext_column)); 01072 if (!orderinfo) 01073 return ERROR_OUTOFMEMORY; 01074 01075 orderinfo->col_count = count; 01076 01077 column = columns; 01078 01079 for (i = 0; i < count; i++) 01080 { 01081 orderinfo->columns[i].unparsed.column = column->column; 01082 orderinfo->columns[i].unparsed.table = column->table; 01083 01084 r = parse_column(wv, &orderinfo->columns[i], NULL); 01085 if (r != ERROR_SUCCESS) 01086 goto error; 01087 } 01088 01089 wv->order_info = orderinfo; 01090 01091 return ERROR_SUCCESS; 01092 error: 01093 msi_free(orderinfo); 01094 return r; 01095 } 01096 01097 static const MSIVIEWOPS where_ops = 01098 { 01099 WHERE_fetch_int, 01100 WHERE_fetch_stream, 01101 WHERE_get_row, 01102 WHERE_set_row, 01103 NULL, 01104 WHERE_delete_row, 01105 WHERE_execute, 01106 WHERE_close, 01107 WHERE_get_dimensions, 01108 WHERE_get_column_info, 01109 WHERE_modify, 01110 WHERE_delete, 01111 WHERE_find_matching_rows, 01112 NULL, 01113 NULL, 01114 NULL, 01115 NULL, 01116 WHERE_sort, 01117 NULL, 01118 }; 01119 01120 static UINT WHERE_VerifyCondition( MSIWHEREVIEW *wv, struct expr *cond, 01121 UINT *valid ) 01122 { 01123 UINT r; 01124 01125 switch( cond->type ) 01126 { 01127 case EXPR_COLUMN: 01128 { 01129 UINT type; 01130 01131 *valid = FALSE; 01132 01133 r = parse_column(wv, &cond->u.column, &type); 01134 if (r != ERROR_SUCCESS) 01135 break; 01136 01137 if (type&MSITYPE_STRING) 01138 cond->type = EXPR_COL_NUMBER_STRING; 01139 else if ((type&0xff) == 4) 01140 cond->type = EXPR_COL_NUMBER32; 01141 else 01142 cond->type = EXPR_COL_NUMBER; 01143 01144 *valid = TRUE; 01145 break; 01146 } 01147 case EXPR_COMPLEX: 01148 r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid ); 01149 if( r != ERROR_SUCCESS ) 01150 return r; 01151 if( !*valid ) 01152 return ERROR_SUCCESS; 01153 r = WHERE_VerifyCondition( wv, cond->u.expr.right, valid ); 01154 if( r != ERROR_SUCCESS ) 01155 return r; 01156 01157 /* check the type of the comparison */ 01158 if( ( cond->u.expr.left->type == EXPR_SVAL ) || 01159 ( cond->u.expr.left->type == EXPR_COL_NUMBER_STRING ) || 01160 ( cond->u.expr.right->type == EXPR_SVAL ) || 01161 ( cond->u.expr.right->type == EXPR_COL_NUMBER_STRING ) ) 01162 { 01163 switch( cond->u.expr.op ) 01164 { 01165 case OP_EQ: 01166 case OP_NE: 01167 break; 01168 default: 01169 *valid = FALSE; 01170 return ERROR_INVALID_PARAMETER; 01171 } 01172 01173 /* FIXME: check we're comparing a string to a column */ 01174 01175 cond->type = EXPR_STRCMP; 01176 } 01177 01178 break; 01179 case EXPR_UNARY: 01180 if ( cond->u.expr.left->type != EXPR_COLUMN ) 01181 { 01182 *valid = FALSE; 01183 return ERROR_INVALID_PARAMETER; 01184 } 01185 r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid ); 01186 if( r != ERROR_SUCCESS ) 01187 return r; 01188 break; 01189 case EXPR_IVAL: 01190 *valid = 1; 01191 cond->type = EXPR_UVAL; 01192 cond->u.uval = cond->u.ival; 01193 break; 01194 case EXPR_WILDCARD: 01195 *valid = 1; 01196 break; 01197 case EXPR_SVAL: 01198 *valid = 1; 01199 break; 01200 default: 01201 ERR("Invalid expression type\n"); 01202 *valid = 0; 01203 break; 01204 } 01205 01206 return ERROR_SUCCESS; 01207 } 01208 01209 UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables, 01210 struct expr *cond ) 01211 { 01212 MSIWHEREVIEW *wv = NULL; 01213 UINT r, valid = 0; 01214 WCHAR *ptr; 01215 01216 TRACE("(%s)\n", debugstr_w(tables) ); 01217 01218 wv = msi_alloc_zero( sizeof *wv ); 01219 if( !wv ) 01220 return ERROR_FUNCTION_FAILED; 01221 01222 /* fill the structure */ 01223 wv->view.ops = &where_ops; 01224 msiobj_addref( &db->hdr ); 01225 wv->db = db; 01226 wv->cond = cond; 01227 01228 while (*tables) 01229 { 01230 JOINTABLE *table; 01231 01232 if ((ptr = strchrW(tables, ' '))) 01233 *ptr = '\0'; 01234 01235 table = msi_alloc(sizeof(JOINTABLE)); 01236 if (!table) 01237 { 01238 r = ERROR_OUTOFMEMORY; 01239 goto end; 01240 } 01241 01242 r = TABLE_CreateView(db, tables, &table->view); 01243 if (r != ERROR_SUCCESS) 01244 { 01245 WARN("can't create table: %s\n", debugstr_w(tables)); 01246 msi_free(table); 01247 r = ERROR_BAD_QUERY_SYNTAX; 01248 goto end; 01249 } 01250 01251 r = table->view->ops->get_dimensions(table->view, NULL, 01252 &table->col_count); 01253 if (r != ERROR_SUCCESS) 01254 { 01255 ERR("can't get table dimensions\n"); 01256 goto end; 01257 } 01258 01259 wv->col_count += table->col_count; 01260 table->table_index = wv->table_count++; 01261 01262 table->next = wv->tables; 01263 wv->tables = table; 01264 01265 if (!ptr) 01266 break; 01267 01268 tables = ptr + 1; 01269 } 01270 01271 if( cond ) 01272 { 01273 r = WHERE_VerifyCondition( wv, cond, &valid ); 01274 if( r != ERROR_SUCCESS ) 01275 goto end; 01276 if( !valid ) { 01277 r = ERROR_FUNCTION_FAILED; 01278 goto end; 01279 } 01280 } 01281 01282 *view = (MSIVIEW*) wv; 01283 01284 return ERROR_SUCCESS; 01285 end: 01286 WHERE_delete(&wv->view); 01287 01288 return r; 01289 } Generated on Mon May 28 2012 04:18:05 for ReactOS by
1.7.6.1
|