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