1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2002 Mike McCormack for CodeWeavers 5 * Copyright 2011 Bernhard Loos 6 * 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. 11 * 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. 16 * 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 20 */ 21 22 #include <stdarg.h> 23 #include <assert.h> 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "winerror.h" 28 #include "wine/debug.h" 29 #include "msi.h" 30 #include "msiquery.h" 31 #include "objbase.h" 32 #include "objidl.h" 33 #include "msipriv.h" 34 #include "winnls.h" 35 36 #include "query.h" 37 38 WINE_DEFAULT_DEBUG_CHANNEL(msidb); 39 40 /* below is the query interface to a table */ 41 typedef struct tagMSIROWENTRY 42 { 43 struct tagMSIWHEREVIEW *wv; /* used during sorting */ 44 UINT values[1]; 45 } MSIROWENTRY; 46 47 typedef struct tagJOINTABLE 48 { 49 struct tagJOINTABLE *next; 50 MSIVIEW *view; 51 UINT col_count; 52 UINT row_count; 53 UINT table_index; 54 } JOINTABLE; 55 56 typedef struct tagMSIORDERINFO 57 { 58 UINT col_count; 59 UINT error; 60 union ext_column columns[1]; 61 } MSIORDERINFO; 62 63 typedef struct tagMSIWHEREVIEW 64 { 65 MSIVIEW view; 66 MSIDATABASE *db; 67 JOINTABLE *tables; 68 UINT row_count; 69 UINT col_count; 70 UINT table_count; 71 MSIROWENTRY **reorder; 72 UINT reorder_size; /* number of entries available in reorder */ 73 struct expr *cond; 74 UINT rec_index; 75 MSIORDERINFO *order_info; 76 } MSIWHEREVIEW; 77 78 static UINT WHERE_evaluate( MSIWHEREVIEW *wv, const UINT rows[], 79 struct expr *cond, INT *val, MSIRECORD *record ); 80 81 #define INITIAL_REORDER_SIZE 16 82 83 #define INVALID_ROW_INDEX (-1) 84 85 static void free_reorder(MSIWHEREVIEW *wv) 86 { 87 UINT i; 88 89 if (!wv->reorder) 90 return; 91 92 for (i = 0; i < wv->row_count; i++) 93 msi_free(wv->reorder[i]); 94 95 msi_free( wv->reorder ); 96 wv->reorder = NULL; 97 wv->reorder_size = 0; 98 wv->row_count = 0; 99 } 100 101 static UINT init_reorder(MSIWHEREVIEW *wv) 102 { 103 MSIROWENTRY **new = msi_alloc_zero(sizeof(MSIROWENTRY *) * INITIAL_REORDER_SIZE); 104 if (!new) 105 return ERROR_OUTOFMEMORY; 106 107 free_reorder(wv); 108 109 wv->reorder = new; 110 wv->reorder_size = INITIAL_REORDER_SIZE; 111 112 return ERROR_SUCCESS; 113 } 114 115 static inline UINT find_row(MSIWHEREVIEW *wv, UINT row, UINT *(values[])) 116 { 117 if (row >= wv->row_count) 118 return ERROR_NO_MORE_ITEMS; 119 120 *values = wv->reorder[row]->values; 121 122 return ERROR_SUCCESS; 123 } 124 125 static UINT add_row(MSIWHEREVIEW *wv, UINT vals[]) 126 { 127 MSIROWENTRY *new; 128 129 if (wv->reorder_size <= wv->row_count) 130 { 131 MSIROWENTRY **new_reorder; 132 UINT newsize = wv->reorder_size * 2; 133 134 new_reorder = msi_realloc(wv->reorder, newsize * sizeof(*new_reorder)); 135 if (!new_reorder) 136 return ERROR_OUTOFMEMORY; 137 memset(new_reorder + wv->reorder_size, 0, (newsize - wv->reorder_size) * sizeof(*new_reorder)); 138 139 wv->reorder = new_reorder; 140 wv->reorder_size = newsize; 141 } 142 143 new = msi_alloc(FIELD_OFFSET( MSIROWENTRY, values[wv->table_count] )); 144 145 if (!new) 146 return ERROR_OUTOFMEMORY; 147 148 wv->reorder[wv->row_count++] = new; 149 150 memcpy(new->values, vals, wv->table_count * sizeof(UINT)); 151 new->wv = wv; 152 153 return ERROR_SUCCESS; 154 } 155 156 static JOINTABLE *find_table(MSIWHEREVIEW *wv, UINT col, UINT *table_col) 157 { 158 JOINTABLE *table = wv->tables; 159 160 if(col == 0 || col > wv->col_count) 161 return NULL; 162 163 while (col > table->col_count) 164 { 165 col -= table->col_count; 166 table = table->next; 167 assert(table); 168 } 169 170 *table_col = col; 171 return table; 172 } 173 174 static UINT parse_column(MSIWHEREVIEW *wv, union ext_column *column, 175 UINT *column_type) 176 { 177 JOINTABLE *table = wv->tables; 178 UINT i, r; 179 180 do 181 { 182 LPCWSTR table_name; 183 184 if (column->unparsed.table) 185 { 186 r = table->view->ops->get_column_info(table->view, 1, NULL, NULL, 187 NULL, &table_name); 188 if (r != ERROR_SUCCESS) 189 return r; 190 if (wcscmp(table_name, column->unparsed.table) != 0) 191 continue; 192 } 193 194 for(i = 1; i <= table->col_count; i++) 195 { 196 LPCWSTR col_name; 197 198 r = table->view->ops->get_column_info(table->view, i, &col_name, column_type, 199 NULL, NULL); 200 if(r != ERROR_SUCCESS ) 201 return r; 202 203 if(wcscmp(col_name, column->unparsed.column)) 204 continue; 205 column->parsed.column = i; 206 column->parsed.table = table; 207 return ERROR_SUCCESS; 208 } 209 } 210 while ((table = table->next)); 211 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; 214 } 215 216 static UINT WHERE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) 217 { 218 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 219 JOINTABLE *table; 220 UINT *rows; 221 UINT r; 222 223 TRACE("%p %d %d %p\n", wv, row, col, val ); 224 225 if( !wv->tables ) 226 return ERROR_FUNCTION_FAILED; 227 228 r = find_row(wv, row, &rows); 229 if (r != ERROR_SUCCESS) 230 return r; 231 232 table = find_table(wv, col, &col); 233 if (!table) 234 return ERROR_FUNCTION_FAILED; 235 236 return table->view->ops->fetch_int(table->view, rows[table->table_index], col, val); 237 } 238 239 static UINT WHERE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm ) 240 { 241 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 242 JOINTABLE *table; 243 UINT *rows; 244 UINT r; 245 246 TRACE("%p %d %d %p\n", wv, row, col, stm ); 247 248 if( !wv->tables ) 249 return ERROR_FUNCTION_FAILED; 250 251 r = find_row(wv, row, &rows); 252 if (r != ERROR_SUCCESS) 253 return r; 254 255 table = find_table(wv, col, &col); 256 if (!table) 257 return ERROR_FUNCTION_FAILED; 258 259 return table->view->ops->fetch_stream( table->view, rows[table->table_index], col, stm ); 260 } 261 262 static UINT WHERE_set_int(struct tagMSIVIEW *view, UINT row, UINT col, int val) 263 { 264 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 265 JOINTABLE *table; 266 UINT *rows; 267 UINT r; 268 269 TRACE("view %p, row %u, col %u, val %d.\n", wv, row, col, val ); 270 271 r = find_row(wv, row, &rows); 272 if (r != ERROR_SUCCESS) 273 return r; 274 275 table = find_table(wv, col, &col); 276 if (!table) 277 return ERROR_FUNCTION_FAILED; 278 279 return table->view->ops->set_int(table->view, rows[table->table_index], col, val); 280 } 281 282 static UINT WHERE_set_string(struct tagMSIVIEW *view, UINT row, UINT col, const WCHAR *val, int len) 283 { 284 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 285 JOINTABLE *table; 286 UINT *rows; 287 UINT r; 288 289 TRACE("view %p, row %u, col %u, val %s.\n", wv, row, col, debugstr_wn(val, len)); 290 291 r = find_row(wv, row, &rows); 292 if (r != ERROR_SUCCESS) 293 return r; 294 295 table = find_table(wv, col, &col); 296 if (!table) 297 return ERROR_FUNCTION_FAILED; 298 299 return table->view->ops->set_string(table->view, rows[table->table_index], col, val, len); 300 } 301 302 static UINT WHERE_set_stream(MSIVIEW *view, UINT row, UINT col, IStream *stream) 303 { 304 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 305 JOINTABLE *table; 306 UINT *rows; 307 UINT r; 308 309 TRACE("view %p, row %u, col %u, stream %p.\n", wv, row, col, stream); 310 311 r = find_row(wv, row, &rows); 312 if (r != ERROR_SUCCESS) 313 return r; 314 315 table = find_table(wv, col, &col); 316 if (!table) 317 return ERROR_FUNCTION_FAILED; 318 319 return table->view->ops->set_stream(table->view, rows[table->table_index], col, stream); 320 } 321 322 static UINT WHERE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask ) 323 { 324 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 325 UINT i, r, offset = 0; 326 JOINTABLE *table = wv->tables; 327 UINT *rows; 328 UINT mask_copy = mask; 329 330 TRACE("%p %d %p %08x\n", wv, row, rec, mask ); 331 332 if( !wv->tables ) 333 return ERROR_FUNCTION_FAILED; 334 335 r = find_row(wv, row, &rows); 336 if (r != ERROR_SUCCESS) 337 return r; 338 339 if (mask >= 1 << wv->col_count) 340 return ERROR_INVALID_PARAMETER; 341 342 do 343 { 344 for (i = 0; i < table->col_count; i++) { 345 UINT type; 346 347 if (!(mask_copy & (1 << i))) 348 continue; 349 r = table->view->ops->get_column_info(table->view, i + 1, NULL, 350 &type, NULL, NULL ); 351 if (r != ERROR_SUCCESS) 352 return r; 353 if (type & MSITYPE_KEY) 354 return ERROR_FUNCTION_FAILED; 355 } 356 mask_copy >>= table->col_count; 357 } 358 while (mask_copy && (table = table->next)); 359 360 table = wv->tables; 361 362 do 363 { 364 const UINT col_count = table->col_count; 365 UINT i; 366 MSIRECORD *reduced; 367 UINT reduced_mask = (mask >> offset) & ((1 << col_count) - 1); 368 369 if (!reduced_mask) 370 { 371 offset += col_count; 372 continue; 373 } 374 375 reduced = MSI_CreateRecord(col_count); 376 if (!reduced) 377 return ERROR_FUNCTION_FAILED; 378 379 for (i = 1; i <= col_count; i++) 380 { 381 r = MSI_RecordCopyField(rec, i + offset, reduced, i); 382 if (r != ERROR_SUCCESS) 383 break; 384 } 385 386 offset += col_count; 387 388 if (r == ERROR_SUCCESS) 389 r = table->view->ops->set_row(table->view, rows[table->table_index], reduced, reduced_mask); 390 391 msiobj_release(&reduced->hdr); 392 } 393 while ((table = table->next)); 394 return r; 395 } 396 397 static UINT WHERE_delete_row(struct tagMSIVIEW *view, UINT row) 398 { 399 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view; 400 UINT r; 401 UINT *rows; 402 403 TRACE("(%p %d)\n", view, row); 404 405 if (!wv->tables) 406 return ERROR_FUNCTION_FAILED; 407 408 r = find_row(wv, row, &rows); 409 if ( r != ERROR_SUCCESS ) 410 return r; 411 412 if (wv->table_count > 1) 413 return ERROR_CALL_NOT_IMPLEMENTED; 414 415 return wv->tables->view->ops->delete_row(wv->tables->view, rows[0]); 416 } 417 418 static INT INT_evaluate_binary( MSIWHEREVIEW *wv, const UINT rows[], 419 const struct complex_expr *expr, INT *val, MSIRECORD *record ) 420 { 421 UINT rl, rr; 422 INT lval, rval; 423 424 rl = WHERE_evaluate(wv, rows, expr->left, &lval, record); 425 if (rl != ERROR_SUCCESS && rl != ERROR_CONTINUE) 426 return rl; 427 rr = WHERE_evaluate(wv, rows, expr->right, &rval, record); 428 if (rr != ERROR_SUCCESS && rr != ERROR_CONTINUE) 429 return rr; 430 431 if (rl == ERROR_CONTINUE || rr == ERROR_CONTINUE) 432 { 433 if (rl == rr) 434 { 435 *val = TRUE; 436 return ERROR_CONTINUE; 437 } 438 439 if (expr->op == OP_AND) 440 { 441 if ((rl == ERROR_CONTINUE && !rval) || (rr == ERROR_CONTINUE && !lval)) 442 { 443 *val = FALSE; 444 return ERROR_SUCCESS; 445 } 446 } 447 else if (expr->op == OP_OR) 448 { 449 if ((rl == ERROR_CONTINUE && rval) || (rr == ERROR_CONTINUE && lval)) 450 { 451 *val = TRUE; 452 return ERROR_SUCCESS; 453 } 454 } 455 456 *val = TRUE; 457 return ERROR_CONTINUE; 458 } 459 460 switch( expr->op ) 461 { 462 case OP_EQ: 463 *val = ( lval == rval ); 464 break; 465 case OP_AND: 466 *val = ( lval && rval ); 467 break; 468 case OP_OR: 469 *val = ( lval || rval ); 470 break; 471 case OP_GT: 472 *val = ( lval > rval ); 473 break; 474 case OP_LT: 475 *val = ( lval < rval ); 476 break; 477 case OP_LE: 478 *val = ( lval <= rval ); 479 break; 480 case OP_GE: 481 *val = ( lval >= rval ); 482 break; 483 case OP_NE: 484 *val = ( lval != rval ); 485 break; 486 default: 487 ERR("Unknown operator %d\n", expr->op ); 488 return ERROR_FUNCTION_FAILED; 489 } 490 491 return ERROR_SUCCESS; 492 } 493 494 static inline UINT expr_fetch_value(const union ext_column *expr, const UINT rows[], UINT *val) 495 { 496 JOINTABLE *table = expr->parsed.table; 497 498 if( rows[table->table_index] == INVALID_ROW_INDEX ) 499 { 500 *val = 1; 501 return ERROR_CONTINUE; 502 } 503 return table->view->ops->fetch_int(table->view, rows[table->table_index], 504 expr->parsed.column, val); 505 } 506 507 508 static UINT INT_evaluate_unary( MSIWHEREVIEW *wv, const UINT rows[], 509 const struct complex_expr *expr, INT *val, MSIRECORD *record ) 510 { 511 UINT r; 512 UINT lval; 513 514 r = expr_fetch_value(&expr->left->u.column, rows, &lval); 515 if(r != ERROR_SUCCESS) 516 return r; 517 518 switch( expr->op ) 519 { 520 case OP_ISNULL: 521 *val = !lval; 522 break; 523 case OP_NOTNULL: 524 *val = lval; 525 break; 526 default: 527 ERR("Unknown operator %d\n", expr->op ); 528 return ERROR_FUNCTION_FAILED; 529 } 530 return ERROR_SUCCESS; 531 } 532 533 static UINT STRING_evaluate( MSIWHEREVIEW *wv, const UINT rows[], 534 const struct expr *expr, 535 const MSIRECORD *record, 536 const WCHAR **str ) 537 { 538 UINT val = 0, r = ERROR_SUCCESS; 539 540 switch( expr->type ) 541 { 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); 546 else 547 *str = NULL; 548 break; 549 550 case EXPR_SVAL: 551 *str = expr->u.sval; 552 break; 553 554 case EXPR_WILDCARD: 555 *str = MSI_RecordGetString(record, ++wv->rec_index); 556 break; 557 558 default: 559 ERR("Invalid expression type\n"); 560 r = ERROR_FUNCTION_FAILED; 561 *str = NULL; 562 break; 563 } 564 return r; 565 } 566 567 static UINT STRCMP_Evaluate( MSIWHEREVIEW *wv, const UINT rows[], const struct complex_expr *expr, 568 INT *val, const MSIRECORD *record ) 569 { 570 int sr; 571 const WCHAR *l_str, *r_str; 572 UINT r; 573 574 *val = TRUE; 575 r = STRING_evaluate(wv, rows, expr->left, record, &l_str); 576 if (r == ERROR_CONTINUE) 577 return r; 578 r = STRING_evaluate(wv, rows, expr->right, record, &r_str); 579 if (r == ERROR_CONTINUE) 580 return r; 581 582 if( l_str == r_str || 583 ((!l_str || !*l_str) && (!r_str || !*r_str)) ) 584 sr = 0; 585 else if( l_str && ! r_str ) 586 sr = 1; 587 else if( r_str && ! l_str ) 588 sr = -1; 589 else 590 sr = wcscmp( l_str, r_str ); 591 592 *val = ( expr->op == OP_EQ && ( sr == 0 ) ) || 593 ( expr->op == OP_NE && ( sr != 0 ) ); 594 595 return ERROR_SUCCESS; 596 } 597 598 static UINT WHERE_evaluate( MSIWHEREVIEW *wv, const UINT rows[], 599 struct expr *cond, INT *val, MSIRECORD *record ) 600 { 601 UINT r, tval; 602 603 if( !cond ) 604 { 605 *val = TRUE; 606 return ERROR_SUCCESS; 607 } 608 609 switch( cond->type ) 610 { 611 case EXPR_COL_NUMBER: 612 r = expr_fetch_value(&cond->u.column, rows, &tval); 613 if( r != ERROR_SUCCESS ) 614 return r; 615 *val = tval - 0x8000; 616 return ERROR_SUCCESS; 617 618 case EXPR_COL_NUMBER32: 619 r = expr_fetch_value(&cond->u.column, rows, &tval); 620 if( r != ERROR_SUCCESS ) 621 return r; 622 *val = tval - 0x80000000; 623 return r; 624 625 case EXPR_UVAL: 626 *val = cond->u.uval; 627 return ERROR_SUCCESS; 628 629 case EXPR_COMPLEX: 630 return INT_evaluate_binary(wv, rows, &cond->u.expr, val, record); 631 632 case EXPR_UNARY: 633 return INT_evaluate_unary( wv, rows, &cond->u.expr, val, record ); 634 635 case EXPR_STRCMP: 636 return STRCMP_Evaluate( wv, rows, &cond->u.expr, val, record ); 637 638 case EXPR_WILDCARD: 639 *val = MSI_RecordGetInteger( record, ++wv->rec_index ); 640 return ERROR_SUCCESS; 641 642 default: 643 ERR("Invalid expression type\n"); 644 return ERROR_FUNCTION_FAILED; 645 } 646 647 return ERROR_SUCCESS; 648 } 649 650 static UINT check_condition( MSIWHEREVIEW *wv, MSIRECORD *record, JOINTABLE **tables, 651 UINT table_rows[] ) 652 { 653 UINT r = ERROR_FUNCTION_FAILED; 654 INT val; 655 656 for (table_rows[(*tables)->table_index] = 0; 657 table_rows[(*tables)->table_index] < (*tables)->row_count; 658 table_rows[(*tables)->table_index]++) 659 { 660 val = 0; 661 wv->rec_index = 0; 662 r = WHERE_evaluate( wv, table_rows, wv->cond, &val, record ); 663 if (r != ERROR_SUCCESS && r != ERROR_CONTINUE) 664 break; 665 if (val) 666 { 667 if (*(tables + 1)) 668 { 669 r = check_condition(wv, record, tables + 1, table_rows); 670 if (r != ERROR_SUCCESS) 671 break; 672 } 673 else 674 { 675 if (r != ERROR_SUCCESS) 676 break; 677 add_row (wv, table_rows); 678 } 679 } 680 } 681 table_rows[(*tables)->table_index] = INVALID_ROW_INDEX; 682 return r; 683 } 684 685 static int __cdecl compare_entry( const void *left, const void *right ) 686 { 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; 692 693 assert(le->wv == re->wv); 694 695 if (order) 696 { 697 for (i = 0; i < order->col_count; i++) 698 { 699 const union ext_column *column = &order->columns[i]; 700 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) 705 { 706 order->error = r; 707 return 0; 708 } 709 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) 714 { 715 order->error = r; 716 return 0; 717 } 718 719 if (l_val != r_val) 720 return l_val < r_val ? -1 : 1; 721 } 722 } 723 724 for (j = 0; j < wv->table_count; j++) 725 { 726 if (le->values[j] != re->values[j]) 727 return le->values[j] < re->values[j] ? -1 : 1; 728 } 729 return 0; 730 } 731 732 static void add_to_array( JOINTABLE **array, JOINTABLE *elem ) 733 { 734 while (*array && *array != elem) 735 array++; 736 if (!*array) 737 *array = elem; 738 } 739 740 static BOOL in_array( JOINTABLE **array, JOINTABLE *elem ) 741 { 742 while (*array && *array != elem) 743 array++; 744 return *array != NULL; 745 } 746 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 */ 750 751 static UINT reorder_check( const struct expr *expr, JOINTABLE **ordered_tables, 752 BOOL process_joins, JOINTABLE **lastused ) 753 { 754 UINT res = 0; 755 756 switch (expr->type) 757 { 758 case EXPR_WILDCARD: 759 case EXPR_SVAL: 760 case EXPR_UVAL: 761 return 0; 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; 768 return CONST_EXPR; 769 case EXPR_STRCMP: 770 case EXPR_COMPLEX: 771 res = reorder_check(expr->u.expr.right, ordered_tables, process_joins, lastused); 772 /* fall through */ 773 case EXPR_UNARY: 774 res += reorder_check(expr->u.expr.left, ordered_tables, process_joins, lastused); 775 if (res == 0) 776 return 0; 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); 781 return res; 782 default: 783 ERR("Unknown expr type: %i\n", expr->type); 784 assert(0); 785 return 0x1000000; 786 } 787 } 788 789 /* reorders the tablelist in a way to evaluate the condition as fast as possible */ 790 static JOINTABLE **ordertables( MSIWHEREVIEW *wv ) 791 { 792 JOINTABLE *table; 793 JOINTABLE **tables; 794 795 tables = msi_alloc_zero( (wv->table_count + 1) * sizeof(*tables) ); 796 797 if (wv->cond) 798 { 799 table = NULL; 800 reorder_check(wv->cond, tables, FALSE, &table); 801 table = NULL; 802 reorder_check(wv->cond, tables, TRUE, &table); 803 } 804 805 table = wv->tables; 806 while (table) 807 { 808 add_to_array(tables, table); 809 table = table->next; 810 } 811 return tables; 812 } 813 814 static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) 815 { 816 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 817 UINT r; 818 JOINTABLE *table = wv->tables; 819 UINT *rows; 820 JOINTABLE **ordered_tables; 821 UINT i = 0; 822 823 TRACE("%p %p\n", wv, record); 824 825 if( !table ) 826 return ERROR_FUNCTION_FAILED; 827 828 r = init_reorder(wv); 829 if (r != ERROR_SUCCESS) 830 return r; 831 832 do 833 { 834 table->view->ops->execute(table->view, NULL); 835 836 r = table->view->ops->get_dimensions(table->view, &table->row_count, NULL); 837 if (r != ERROR_SUCCESS) 838 { 839 ERR("failed to get table dimensions\n"); 840 return r; 841 } 842 843 /* each table must have at least one row */ 844 if (table->row_count == 0) 845 return ERROR_SUCCESS; 846 } 847 while ((table = table->next)); 848 849 ordered_tables = ordertables( wv ); 850 851 rows = msi_alloc( wv->table_count * sizeof(*rows) ); 852 for (i = 0; i < wv->table_count; i++) 853 rows[i] = INVALID_ROW_INDEX; 854 855 r = check_condition(wv, record, ordered_tables, rows); 856 857 if (wv->order_info) 858 wv->order_info->error = ERROR_SUCCESS; 859 860 qsort(wv->reorder, wv->row_count, sizeof(MSIROWENTRY *), compare_entry); 861 862 if (wv->order_info) 863 r = wv->order_info->error; 864 865 msi_free( rows ); 866 msi_free( ordered_tables ); 867 return r; 868 } 869 870 static UINT WHERE_close( struct tagMSIVIEW *view ) 871 { 872 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 873 JOINTABLE *table = wv->tables; 874 875 TRACE("%p\n", wv ); 876 877 if (!table) 878 return ERROR_FUNCTION_FAILED; 879 880 do 881 table->view->ops->close(table->view); 882 while ((table = table->next)); 883 884 return ERROR_SUCCESS; 885 } 886 887 static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) 888 { 889 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 890 891 TRACE("%p %p %p\n", wv, rows, cols ); 892 893 if(!wv->tables) 894 return ERROR_FUNCTION_FAILED; 895 896 if (rows) 897 { 898 if (!wv->reorder) 899 return ERROR_FUNCTION_FAILED; 900 *rows = wv->row_count; 901 } 902 903 if (cols) 904 *cols = wv->col_count; 905 906 return ERROR_SUCCESS; 907 } 908 909 static UINT WHERE_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name, 910 UINT *type, BOOL *temporary, LPCWSTR *table_name ) 911 { 912 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 913 JOINTABLE *table; 914 915 TRACE("%p %d %p %p %p %p\n", wv, n, name, type, temporary, table_name ); 916 917 if(!wv->tables) 918 return ERROR_FUNCTION_FAILED; 919 920 table = find_table(wv, n, &n); 921 if (!table) 922 return ERROR_FUNCTION_FAILED; 923 924 return table->view->ops->get_column_info(table->view, n, name, 925 type, temporary, table_name); 926 } 927 928 static UINT join_find_row( MSIWHEREVIEW *wv, MSIRECORD *rec, UINT *row ) 929 { 930 LPCWSTR str; 931 UINT r, i, id, data; 932 933 str = MSI_RecordGetString( rec, 1 ); 934 r = msi_string2id( wv->db->strings, str, -1, &id ); 935 if (r != ERROR_SUCCESS) 936 return r; 937 938 for (i = 0; i < wv->row_count; i++) 939 { 940 WHERE_fetch_int( &wv->view, i, 1, &data ); 941 942 if (data == id) 943 { 944 *row = i; 945 return ERROR_SUCCESS; 946 } 947 } 948 949 return ERROR_FUNCTION_FAILED; 950 } 951 952 static UINT join_modify_update( struct tagMSIVIEW *view, MSIRECORD *rec ) 953 { 954 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view; 955 UINT r, row, i, mask = 0; 956 MSIRECORD *current; 957 958 959 r = join_find_row( wv, rec, &row ); 960 if (r != ERROR_SUCCESS) 961 return r; 962 963 r = msi_view_get_row( wv->db, view, row, ¤t ); 964 if (r != ERROR_SUCCESS) 965 return r; 966 967 assert(MSI_RecordGetFieldCount(rec) == MSI_RecordGetFieldCount(current)); 968 969 for (i = MSI_RecordGetFieldCount(rec); i > 0; i--) 970 { 971 if (!MSI_RecordsAreFieldsEqual(rec, current, i)) 972 mask |= 1 << (i - 1); 973 } 974 msiobj_release(¤t->hdr); 975 976 return WHERE_set_row( view, row, rec, mask ); 977 } 978 979 static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, 980 MSIRECORD *rec, UINT row ) 981 { 982 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 983 JOINTABLE *table = wv->tables; 984 UINT r; 985 986 TRACE("%p %d %p\n", wv, eModifyMode, rec); 987 988 if (!table) 989 return ERROR_FUNCTION_FAILED; 990 991 if (!table->next) 992 { 993 UINT *rows; 994 995 if (find_row(wv, row, &rows) == ERROR_SUCCESS) 996 row = rows[0]; 997 else 998 row = -1; 999 1000 return table->view->ops->modify(table->view, eModifyMode, rec, row); 1001 } 1002 1003 switch (eModifyMode) 1004 { 1005 case MSIMODIFY_UPDATE: 1006 return join_modify_update( view, rec ); 1007 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; 1020 break; 1021 1022 case MSIMODIFY_REFRESH: 1023 r = ERROR_CALL_NOT_IMPLEMENTED; 1024 break; 1025 1026 default: 1027 WARN("%p %d %p %u - unknown mode\n", view, eModifyMode, rec, row ); 1028 r = ERROR_INVALID_PARAMETER; 1029 break; 1030 } 1031 1032 return r; 1033 } 1034 1035 static UINT WHERE_delete( struct tagMSIVIEW *view ) 1036 { 1037 MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; 1038 JOINTABLE *table = wv->tables; 1039 1040 TRACE("%p\n", wv ); 1041 1042 while(table) 1043 { 1044 JOINTABLE *next; 1045 1046 table->view->ops->delete(table->view); 1047 table->view = NULL; 1048 next = table->next; 1049 msi_free(table); 1050 table = next; 1051 } 1052 wv->tables = NULL; 1053 wv->table_count = 0; 1054 1055 free_reorder(wv); 1056 1057 msi_free(wv->order_info); 1058 wv->order_info = NULL; 1059 1060 msiobj_release( &wv->db->hdr ); 1061 msi_free( wv ); 1062 1063 return ERROR_SUCCESS; 1064 } 1065 1066 static UINT WHERE_sort(struct tagMSIVIEW *view, column_info *columns) 1067 { 1068 MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view; 1069 JOINTABLE *table = wv->tables; 1070 column_info *column = columns; 1071 MSIORDERINFO *orderinfo; 1072 UINT r, count = 0; 1073 UINT i; 1074 1075 TRACE("%p %p\n", view, columns); 1076 1077 if (!table) 1078 return ERROR_FUNCTION_FAILED; 1079 1080 while (column) 1081 { 1082 count++; 1083 column = column->next; 1084 } 1085 1086 if (count == 0) 1087 return ERROR_SUCCESS; 1088 1089 orderinfo = msi_alloc(FIELD_OFFSET(MSIORDERINFO, columns[count])); 1090 if (!orderinfo) 1091 return ERROR_OUTOFMEMORY; 1092 1093 orderinfo->col_count = count; 1094 1095 column = columns; 1096 1097 for (i = 0; i < count; i++) 1098 { 1099 orderinfo->columns[i].unparsed.column = column->column; 1100 orderinfo->columns[i].unparsed.table = column->table; 1101 1102 r = parse_column(wv, &orderinfo->columns[i], NULL); 1103 if (r != ERROR_SUCCESS) 1104 goto error; 1105 } 1106 1107 wv->order_info = orderinfo; 1108 1109 return ERROR_SUCCESS; 1110 error: 1111 msi_free(orderinfo); 1112 return r; 1113 } 1114 1115 static const MSIVIEWOPS where_ops = 1116 { 1117 WHERE_fetch_int, 1118 WHERE_fetch_stream, 1119 WHERE_set_int, 1120 WHERE_set_string, 1121 WHERE_set_stream, 1122 WHERE_set_row, 1123 NULL, 1124 WHERE_delete_row, 1125 WHERE_execute, 1126 WHERE_close, 1127 WHERE_get_dimensions, 1128 WHERE_get_column_info, 1129 WHERE_modify, 1130 WHERE_delete, 1131 NULL, 1132 NULL, 1133 NULL, 1134 WHERE_sort, 1135 NULL, 1136 }; 1137 1138 static UINT WHERE_VerifyCondition( MSIWHEREVIEW *wv, struct expr *cond, 1139 UINT *valid ) 1140 { 1141 UINT r; 1142 1143 switch( cond->type ) 1144 { 1145 case EXPR_COLUMN: 1146 { 1147 UINT type; 1148 1149 *valid = FALSE; 1150 1151 r = parse_column(wv, &cond->u.column, &type); 1152 if (r != ERROR_SUCCESS) 1153 break; 1154 1155 if (type&MSITYPE_STRING) 1156 cond->type = EXPR_COL_NUMBER_STRING; 1157 else if ((type&0xff) == 4) 1158 cond->type = EXPR_COL_NUMBER32; 1159 else 1160 cond->type = EXPR_COL_NUMBER; 1161 1162 *valid = TRUE; 1163 break; 1164 } 1165 case EXPR_COMPLEX: 1166 r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid ); 1167 if( r != ERROR_SUCCESS ) 1168 return r; 1169 if( !*valid ) 1170 return ERROR_SUCCESS; 1171 r = WHERE_VerifyCondition( wv, cond->u.expr.right, valid ); 1172 if( r != ERROR_SUCCESS ) 1173 return r; 1174 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 ) ) 1180 { 1181 switch( cond->u.expr.op ) 1182 { 1183 case OP_EQ: 1184 case OP_NE: 1185 break; 1186 default: 1187 *valid = FALSE; 1188 return ERROR_INVALID_PARAMETER; 1189 } 1190 1191 /* FIXME: check we're comparing a string to a column */ 1192 1193 cond->type = EXPR_STRCMP; 1194 } 1195 1196 break; 1197 case EXPR_UNARY: 1198 if ( cond->u.expr.left->type != EXPR_COLUMN ) 1199 { 1200 *valid = FALSE; 1201 return ERROR_INVALID_PARAMETER; 1202 } 1203 r = WHERE_VerifyCondition( wv, cond->u.expr.left, valid ); 1204 if( r != ERROR_SUCCESS ) 1205 return r; 1206 break; 1207 case EXPR_IVAL: 1208 *valid = 1; 1209 cond->type = EXPR_UVAL; 1210 cond->u.uval = cond->u.ival; 1211 break; 1212 case EXPR_WILDCARD: 1213 *valid = 1; 1214 break; 1215 case EXPR_SVAL: 1216 *valid = 1; 1217 break; 1218 default: 1219 ERR("Invalid expression type\n"); 1220 *valid = 0; 1221 break; 1222 } 1223 1224 return ERROR_SUCCESS; 1225 } 1226 1227 UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables, 1228 struct expr *cond ) 1229 { 1230 MSIWHEREVIEW *wv = NULL; 1231 UINT r, valid = 0; 1232 WCHAR *ptr; 1233 1234 TRACE("(%s)\n", debugstr_w(tables) ); 1235 1236 wv = msi_alloc_zero( sizeof *wv ); 1237 if( !wv ) 1238 return ERROR_FUNCTION_FAILED; 1239 1240 /* fill the structure */ 1241 wv->view.ops = &where_ops; 1242 msiobj_addref( &db->hdr ); 1243 wv->db = db; 1244 wv->cond = cond; 1245 1246 while (*tables) 1247 { 1248 JOINTABLE *table; 1249 1250 if ((ptr = wcschr(tables, ' '))) 1251 *ptr = '\0'; 1252 1253 table = msi_alloc(sizeof(JOINTABLE)); 1254 if (!table) 1255 { 1256 r = ERROR_OUTOFMEMORY; 1257 goto end; 1258 } 1259 1260 r = TABLE_CreateView(db, tables, &table->view); 1261 if (r != ERROR_SUCCESS) 1262 { 1263 WARN("can't create table: %s\n", debugstr_w(tables)); 1264 msi_free(table); 1265 r = ERROR_BAD_QUERY_SYNTAX; 1266 goto end; 1267 } 1268 1269 r = table->view->ops->get_dimensions(table->view, NULL, 1270 &table->col_count); 1271 if (r != ERROR_SUCCESS) 1272 { 1273 ERR("can't get table dimensions\n"); 1274 table->view->ops->delete(table->view); 1275 msi_free(table); 1276 goto end; 1277 } 1278 1279 wv->col_count += table->col_count; 1280 table->table_index = wv->table_count++; 1281 1282 table->next = wv->tables; 1283 wv->tables = table; 1284 1285 if (!ptr) 1286 break; 1287 1288 tables = ptr + 1; 1289 } 1290 1291 if( cond ) 1292 { 1293 r = WHERE_VerifyCondition( wv, cond, &valid ); 1294 if( r != ERROR_SUCCESS ) 1295 goto end; 1296 if( !valid ) { 1297 r = ERROR_FUNCTION_FAILED; 1298 goto end; 1299 } 1300 } 1301 1302 *view = (MSIVIEW*) wv; 1303 1304 return ERROR_SUCCESS; 1305 end: 1306 WHERE_delete(&wv->view); 1307 1308 return r; 1309 } 1310