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