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