ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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

Generated on Mon May 28 2012 04:18:05 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.