Wine sync of msi.dll
authorAleksey Bragin <aleksey@reactos.org>
Tue, 28 Nov 2006 11:21:39 +0000 (11:21 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Tue, 28 Nov 2006 11:21:39 +0000 (11:21 +0000)
Warning: msi_ros.diff needs to be updated with new sql.tab.c and sql.tab.h before performing any future autosyncs!

Log:
22 hours ago Mike McCormack msi: Use MSI_QueryGetRecord in ACTION_AppSearchReg.
22 hours ago Mike McCormack msi: Use MSI_QueryGetRecord in ACTION_AppSearchComponents.
22 hours ago Mike McCormack msi: Use MSI_QueryGetRecord in ACTION_AppSearchGetSigna ...
22 hours ago Mike McCormack msi: Use MSI_IterateRecords when cloning properties.
22 hours ago Francois Gouget msi: Add a Portuguese translation (contributed by Ameri ...
4 days ago Francois Gouget Replace SUBLANG_DEFAULT with the specific SUBLANG_XXX ...
6 days ago Mike McCormack msi: Treat the SourceDir folder the same as TargetDir.
6 days ago Mike McCormack msi: Load all folders in one query, rather one per ...
6 days ago Mike McCormack msi: Only wait for custom actions that don't have msidb ...
6 days ago Mike McCormack msi: Split process_action_return_value into two differe ...
6 days ago Mike McCormack msi: Remove an unused parameter. tree | commitdiff
6 days ago Mike McCormack msi: Fix use of integer fields in MsiFormatRecord.
6 days ago Mike McCormack msi: Test MsiRecordGetString on an integer record field ...
6 days ago Mike McCormack msi: Add a test for formatting records with strings.
6 days ago Mike McCormack msi: Don't access the list of controls after the dialog ...
6 days ago Mike McCormack msi: Create a function to free control data.
7 days ago Mike McCormack msi: Fix an access after freeing memory.
8 days ago Mike McCormack msi: Split msi_set_sourcedir_props into a separate ...
8 days ago Mike McCormack msi: Spelling fixes.
8 days ago Mike McCormack msi: Add another test for the SourceDir property.
8 days ago Mike McCormack msi: Clean up parameters of msi_media_get_disk_info().
8 days ago Mike McCormack msi: Fix some memory leaks.
8 days ago Mike McCormack msi: Don't leak row handles.
11 days ago Mike McCormack msi: Fix a memory leak in load_folder().
11 days ago Mike McCormack msi: Remove unnecessary includes.
11 days ago Mike McCormack msi: Remove a level of indent in resolve_folder().
11 days ago Mike McCormack msi: Add a test showing the _Properties table is a ...
11 days ago Mike McCormack msi: Add a test showing which tables are special.
11 days ago Mike McCormack msi: Remove some redundant else statements.
2006-11-14 Mike McCormack msi: Split MSI_CreatePackage into two functions.
2006-11-14 Mike McCormack msi: Delete the tempfile created by GetTempFileName.
2006-11-14 Mike McCormack msi: Defer package deletion until after the database ...
2006-11-14 Mike McCormack msi: Remove track_tempfile()'s unused 2nd parameter.
2006-11-14 Mike McCormack msi: Always delete temp files after creating them.
2006-11-14 Mike McCormack msi: Print a message if we fail to delete a file.
2006-11-14 James Hawkins msi: Notify the external UI handler when changing media.
2006-11-13 Mike McCormack msi: Only free a string in one place.
2006-11-13 Mike McCormack msi: Fix error handling.
2006-11-13 Mike McCormack msi: Track temp files as soon as they are created.
2006-11-13 Mike McCormack msi: Fail if we can't write out a temporary file.
2006-11-13 Mike McCormack msi: Fix an uninitialized variable in the test cases.
2006-11-13 Mike McCormack msi: Clean upstore_binary_to_temp.
2006-11-13 Francois Gouget Assorted spelling fixes.
2006-11-13 Francois Gouget msi: assert.h is not a local header (spotted by winapi ...
2006-11-13 Paul Vriens msi: Fix typo's (Coverity).
2006-11-13 James Hawkins msi: Fix a heap corruption bug by resizing the src ...
2006-11-10 Mike McCormack msi: Only log the Action, as it's the same as ActionReq ...
2006-11-10 Mike McCormack msi: Check whether the component is enabled first.
2006-11-10 Mike McCormack msi: Component attributes are bitmasks.
2006-11-09 Eric Pouech msi: Fixed bogus A -> W conversion.
2006-11-09 Eric Pouech msi: Don't call PropVariantClear on uninitialized variants.
2006-11-09 James Hawkins msi: Add support for continuous cabinets.
2006-11-09 James Hawkins msi: Extract cabinets in ACTION_InstallFiles. ready ...
2006-11-09 James Hawkins msi: Move the file sequence check out of ready_media ...
2006-11-09 James Hawkins msi: Factor out load_media_info from ready_media_for ...
2006-11-09 James Hawkins msi: Use disk_prompt from the media_info structure ...
2006-11-09 James Hawkins msi: Only add text to the scroll control if text is ...
2006-11-08 Stefan Leichter msi: Added stub for MsiGetFeatureValidStatesA/W.
2006-11-08 James Hawkins msi: Factor out download_remote_cabinet and reuse extra ...
2006-11-08 James Hawkins msi: Store the base URL of the MSI package if it is ...
2006-11-08 James Hawkins msi: Factor copy_install_file out of ACTION_InstallFiles.
2006-11-08 James Hawkins msi: Factor schedule_install_files out of ACTION_Instal ...
2006-11-08 James Hawkins msi: Model the media_info structure members after the ...
2006-11-08 James Hawkins msi: Use msi_alloc_zero instead of a helper function ...
2006-11-08 James Hawkins msi: Use the file's component instead of passing an ...
2006-11-08 James Hawkins msi: Use the media_info structure instead of passing ...
2006-11-08 James Hawkins msi: Add more tests for installing from cabinets.
2006-11-08 Mike McCormack msi: Fix a memory leak.
2006-11-07 Francois Gouget Assorted spelling fixes.
2006-11-07 Mike McCormack msi: By default, install components locally.
2006-11-07 Mike McCormack msi: Fix WHERE IS (NOT) NULL queries.
2006-11-07 Mike McCormack msi: Fix regression tests failing on Windows.
2006-11-07 Mike McCormack msi: Split ACTION_CostFinalize into two functions.
2006-11-06 Alexandre Julliard msi: Fixed definition of the MSIITERHANDLE type.
2006-11-02 Mike McCormack msi: Avoid a memory leak by freeing actions scripts ...
2006-11-02 Mike McCormack msi: Fix a memory leak.
2006-11-02 Mike McCormack msi: Fix a handle leak in the tests.
2006-11-01 Mike McCormack msi: Fix a typo.
2006-11-01 Mike McCormack msi: Don't print traces for addref and release.
2006-11-01 Mike McCormack msi: Search the patch package for source cabinet files.
2006-10-31 Mike McCormack msi: Add a test showing a join doesn't need a WHERE ...
2006-10-31 Mike McCormack msi: Use a simpler algorithm for joins.
2006-10-31 Mike McCormack msi: Test the data returned by join queries in one ...
2006-10-31 Mike McCormack msi: Remove tokens that aren't valid for MSI SQL.
2006-10-31 Mike McCormack msi: Fix a trace.
2006-10-31 Mike McCormack msi: Fix the ALTER and FREE keywords in the tokenizer.
2006-10-31 Mike McCormack msi: Mark components with missing or outdated files ...
2006-10-30 Mike McCormack msi: Split ACTION_UpdateInstallStates into two separate ...
2006-10-27 James Hawkins msi: Extract cabinets based on DiskId, not LastSequence.
2006-10-27 James Hawkins msi: Test the order in which cab files are handled ...
2006-10-27 James Hawkins msi: Implement handling for the ErrorDialog and use ...
2006-10-27 Mike McCormack msi: Avoid crashing if writeout_cabinet_stream fails.
2006-10-27 Mike McCormack msi: Remove redundant null checks before MSI_EvaluateCo ...
2006-10-26 Mike McCormack msi: Fix the join algorithm.
2006-10-26 Mike McCormack msi: Allow UPDATE queries without a condition.
2006-10-26 Mike McCormack msi: Update tables using records, not integer by integer.
2006-10-26 Mike McCormack msi: Remove some unused functions.
2006-10-26 Mike McCormack msi: Fixed the UPDATE query to work with explicit values.
2006-10-26 Mike McCormack msi: Use msi_feature_set_state and msi_component_set ...
2006-10-26 Mike McCormack msi: Create macro functions to set feature and componen ...
2006-10-26 James Hawkins msi: Add tests for the UPDATE sql command.
2006-10-25 Alexandre Julliard msi: Properly handle negative coordinates for mouse ...
2006-10-24 Mikołaj Zalewski resources: Change Dutch sublanguage code to SUBLANG ...
2006-10-24 Mikołaj Zalewski resources: Change German sublanguage code to SUBLANG ...
2006-10-24 Mike McCormack msi: Split code to get a file's verion into a separate ...
2006-10-24 James Hawkins msi: Add tests for installing from continuous cabinets.
2006-10-24 James Hawkins msi: Allow more customization of install test files.
2006-10-24 James Hawkins msi: Remove unused function pointer and definitions.
2006-10-24 James Hawkins msi: Remove two unnecessary install tables. tree | commitdiff
2006-10-24 James Hawkins msi: Add support for localizable strings in MsiDatabase ...

svn path=/trunk/; revision=24909

31 files changed:
reactos/dll/win32/msi/action.c
reactos/dll/win32/msi/alter.c
reactos/dll/win32/msi/database.c
reactos/dll/win32/msi/delete.c
reactos/dll/win32/msi/dialog.c
reactos/dll/win32/msi/events.c
reactos/dll/win32/msi/files.c
reactos/dll/win32/msi/handle.c
reactos/dll/win32/msi/helpers.c
reactos/dll/win32/msi/insert.c
reactos/dll/win32/msi/install.c
reactos/dll/win32/msi/join.c
reactos/dll/win32/msi/msi.spec
reactos/dll/win32/msi/msi_De.rc
reactos/dll/win32/msi/msi_Nl.rc
reactos/dll/win32/msi/msi_ros.diff
reactos/dll/win32/msi/msipriv.h
reactos/dll/win32/msi/package.c
reactos/dll/win32/msi/preview.c
reactos/dll/win32/msi/query.h
reactos/dll/win32/msi/registry.c
reactos/dll/win32/msi/select.c
reactos/dll/win32/msi/source.c
reactos/dll/win32/msi/sql.tab.c
reactos/dll/win32/msi/sql.tab.h
reactos/dll/win32/msi/sql.y
reactos/dll/win32/msi/suminfo.c
reactos/dll/win32/msi/table.c
reactos/dll/win32/msi/tokenize.c
reactos/dll/win32/msi/update.c
reactos/dll/win32/msi/where.c

index 252f1ba..b7e0fe6 100644 (file)
@@ -399,6 +399,28 @@ static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
     return ret;
 }
 
+static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
+{
+    WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
+    LPWSTR prod_code, patch_product;
+    UINT ret;
+
+    prod_code = msi_dup_property( package, szProductCode );
+    patch_product = msi_get_suminfo_product( patch );
+
+    TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
+
+    if ( strstrW( patch_product, prod_code ) )
+        ret = ERROR_SUCCESS;
+    else
+        ret = ERROR_FUNCTION_FAILED;
+
+    msi_free( patch_product );
+    msi_free( prod_code );
+
+    return ret;
+}
+
 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
                                  MSIDATABASE *patch_db, LPCWSTR name )
 {
@@ -417,14 +439,17 @@ static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
     r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
     if (SUCCEEDED(r))
     {
-        ret = msi_table_apply_transform( package->db, stg );
+        ret = msi_check_transform_applicable( package, stg );
+        if (ret == ERROR_SUCCESS)
+            msi_table_apply_transform( package->db, stg );
+        else
+            TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
         IStorage_Release( stg );
-        ret = ERROR_SUCCESS;
     }
     else
         ERR("failed to open substorage %s\n", debugstr_w(name));
 
-    return ret;
+    return ERROR_SUCCESS;
 }
 
 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
@@ -461,7 +486,7 @@ static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db
     LPWSTR str, *substorage;
     UINT i, r = ERROR_SUCCESS;
 
-    si = MSI_GetSummaryInformationW( patch_db, 0 );
+    si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
     if (!si)
         return ERROR_FUNCTION_FAILED;
 
@@ -502,6 +527,13 @@ static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
     }
 
     msi_parse_patch_summary( package, patch_db );
+
+    /*
+     * There might be a CAB file in the patch package,
+     * so append it to the list of storage to search for streams.
+     */
+    append_storage_to_db( package->db, patch_db->storage );
+
     msiobj_release( &patch_db->hdr );
 
     return ERROR_SUCCESS;
@@ -593,6 +625,7 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
         check = msi_dup_property( package, cszSourceDir );
         if (!check)
             MSI_SetPropertyW(package, cszSourceDir, path);
+        msi_free(check);
 
         check = msi_dup_property( package, cszSOURCEDIR );
         if (!check)
@@ -676,12 +709,10 @@ static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
 
         /* check conditions */
         cond = MSI_RecordGetString(row,2);
-        if (cond)
-        {
-            /* this is a hack to skip errors in the condition code */
-            if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
-                goto end;
-        }
+
+        /* this is a hack to skip errors in the condition code */
+        if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
+            goto end;
 
         action = MSI_RecordGetString(row,1);
         if (!action)
@@ -719,20 +750,17 @@ static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
     if (!action)
     {
         ERR("Error is retrieving action name\n");
-        return  ERROR_FUNCTION_FAILED;
+        return ERROR_FUNCTION_FAILED;
     }
 
     /* check conditions */
     cond = MSI_RecordGetString(row,2);
-    if (cond)
+
+    /* this is a hack to skip errors in the condition code */
+    if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
     {
-        /* this is a hack to skip errors in the condition code */
-        if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
-        {
-            TRACE("Skipping action: %s (condition is false)\n",
-                            debugstr_w(action));
-            return ERROR_SUCCESS;
-        }
+        TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
+        return ERROR_SUCCESS;
     }
 
     if (iap->UI)
@@ -1126,8 +1154,7 @@ static UINT load_component( MSIRECORD *row, LPVOID param )
     comp->KeyPath = msi_dup_record_field( row, 6 );
 
     comp->Installed = INSTALLSTATE_UNKNOWN;
-    comp->Action = INSTALLSTATE_UNKNOWN;
-    comp->ActionRequest = INSTALLSTATE_UNKNOWN;
+    msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
 
     return ERROR_SUCCESS;
 }
@@ -1258,8 +1285,7 @@ static UINT load_feature(MSIRECORD * row, LPVOID param)
     feature->Attributes = MSI_RecordGetInteger(row,8);
 
     feature->Installed = INSTALLSTATE_UNKNOWN;
-    feature->Action = INSTALLSTATE_UNKNOWN;
-    feature->ActionRequest = INSTALLSTATE_UNKNOWN;
+    msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
 
     list_add_tail( &package->features, &feature->entry );
 
@@ -1467,14 +1493,10 @@ static UINT execute_script(MSIPACKAGE *package, UINT script )
         ui_actionstart(package, action);
         TRACE("Executing Action (%s)\n",debugstr_w(action));
         rc = ACTION_PerformAction(package, action, TRUE);
-        msi_free(package->script->Actions[script][i]);
         if (rc != ERROR_SUCCESS)
             break;
     }
-    msi_free(package->script->Actions[script]);
-
-    package->script->ActionCount[script] = 0;
-    package->script->Actions[script] = NULL;
+    msi_free_action_script(package, script);
     return rc;
 }
 
@@ -1575,15 +1597,10 @@ static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
     return folder;
 }
 
-/* scan for and update current install states */
-static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
+static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
 {
     MSICOMPONENT *comp;
-    MSIFEATURE *feature;
 
-    /* FIXME: component's installed state should be determined
-     * by the component's registration
-     */
     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
     {
         INSTALLSTATE res;
@@ -1591,12 +1608,19 @@ static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
         if (!comp->ComponentId)
             continue;
 
-        res = MsiGetComponentPathW( package->ProductCode, 
+        res = MsiGetComponentPathW( package->ProductCode,
                                     comp->ComponentId, NULL, NULL);
         if (res < 0)
             res = INSTALLSTATE_ABSENT;
         comp->Installed = res;
     }
+}
+
+/* scan for and update current install states */
+static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
+{
+    MSICOMPONENT *comp;
+    MSIFEATURE *feature;
 
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
@@ -1641,14 +1665,11 @@ static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
     override = msi_dup_property( package, property );
     if (!override)
         return FALSE;
+
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
         if (strcmpiW(override,all)==0)
-        {
-            feature->ActionRequest= state;
-            feature->Action = state;
-        }
+            msi_feature_set_state( feature, state );
         else
         {
             LPWSTR ptr = override;
@@ -1659,8 +1680,7 @@ static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
                 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
                     || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
                 {
-                    feature->ActionRequest= state;
-                    feature->Action = state;
+                    msi_feature_set_state( feature, state );
                     break;
                 }
                 if (ptr2)
@@ -1672,7 +1692,7 @@ static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
                     break;
             }
         }
-    } 
+    }
     msi_free(override);
 
     return TRUE;
@@ -1716,7 +1736,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
      * 11) FILEADDDEFAULT
      * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
      * ignored for all the features. seems strange, especially since it is not
-     * documented anywhere, but it is how it works. 
+     * documented anywhere, but it is how it works.
      *
      * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
      * REMOVE are the big ones, since we don't handle administrative installs
@@ -1736,20 +1756,11 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
             if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
             {
                 if (feature->Attributes & msidbFeatureAttributesFavorSource)
-                {
-                    feature->ActionRequest = INSTALLSTATE_SOURCE;
-                    feature->Action = INSTALLSTATE_SOURCE;
-                }
+                    msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
                 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
-                {
-                    feature->ActionRequest = INSTALLSTATE_ADVERTISED;
-                    feature->Action = INSTALLSTATE_ADVERTISED;
-                }
+                    msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
                 else
-                {
-                    feature->ActionRequest = INSTALLSTATE_LOCAL;
-                    feature->Action = INSTALLSTATE_LOCAL;
-                }
+                    msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
             }
         }
 
@@ -1762,10 +1773,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
                 continue;
 
             LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
-            {
-                fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
-                fl->feature->Action = INSTALLSTATE_UNKNOWN;
-            }
+                msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
         }
     }
     else
@@ -1778,111 +1786,78 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
     }
 
     /*
-     * now we want to enable or disable components base on feature 
-    */
+     * now we want to enable or disable components base on feature
+     */
 
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
         ComponentList *cl;
 
-        TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
-            debugstr_w(feature->Feature), feature->Installed, feature->Action,
-            feature->ActionRequest);
+        TRACE("Examining Feature %s (Installed %i, Action %i)\n",
+            debugstr_w(feature->Feature), feature->Installed, feature->Action);
 
         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
         {
             component = cl->component;
 
-            switch (component->Attributes)
+            if (!component->Enabled)
+                continue;
+
+            if (component->Attributes & msidbComponentAttributesOptional)
+                msi_component_set_state( component, INSTALLSTATE_DEFAULT );
+            else
             {
-            case msidbComponentAttributesLocalOnly:
-                component->Action = INSTALLSTATE_LOCAL;
-                component->ActionRequest = INSTALLSTATE_LOCAL;
-                break;
-            case msidbComponentAttributesSourceOnly:
-                component->Action = INSTALLSTATE_SOURCE;
-                component->ActionRequest = INSTALLSTATE_SOURCE;
-                break;
-            case msidbComponentAttributesOptional:
-                component->Action = INSTALLSTATE_DEFAULT;
-                component->ActionRequest = INSTALLSTATE_DEFAULT;
-                break;
-            default:
-                component->Action = INSTALLSTATE_LOCAL;
-                component->ActionRequest = INSTALLSTATE_LOCAL;
+                if (component->Attributes & msidbComponentAttributesSourceOnly)
+                    msi_component_set_state( component, INSTALLSTATE_SOURCE );
+                else
+                    msi_component_set_state( component, INSTALLSTATE_LOCAL );
             }
 
             if (component->ForceLocalState)
+                msi_component_set_state( component, INSTALLSTATE_LOCAL );
+
+            if (feature->Attributes == msidbFeatureAttributesFavorLocal)
             {
-                component->Action = INSTALLSTATE_LOCAL;
-                component->ActionRequest = INSTALLSTATE_LOCAL;
+                if (!(component->Attributes & msidbComponentAttributesSourceOnly))
+                    msi_component_set_state( component, INSTALLSTATE_LOCAL );
             }
-
-            if (!component->Enabled)
+            else if (feature->Attributes == msidbFeatureAttributesFavorSource)
             {
-                component->Action = INSTALLSTATE_UNKNOWN;
-                component->ActionRequest = INSTALLSTATE_UNKNOWN;
+                if ((component->Action == INSTALLSTATE_UNKNOWN) ||
+                    (component->Action == INSTALLSTATE_ABSENT) ||
+                    (component->Action == INSTALLSTATE_ADVERTISED) ||
+                    (component->Action == INSTALLSTATE_DEFAULT))
+                    msi_component_set_state( component, INSTALLSTATE_SOURCE );
             }
-            else
+            else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
             {
-                if (feature->Attributes == msidbFeatureAttributesFavorLocal)
-                {
-                    if (!(component->Attributes & msidbComponentAttributesSourceOnly))
-                    {
-                        component->Action = INSTALLSTATE_LOCAL;
-                        component->ActionRequest = INSTALLSTATE_LOCAL;
-                    }
-                }
-                else if (feature->Attributes == msidbFeatureAttributesFavorSource)
-                {
-                    if ((component->Action == INSTALLSTATE_UNKNOWN) ||
-                        (component->Action == INSTALLSTATE_ABSENT) ||
-                        (component->Action == INSTALLSTATE_ADVERTISED) ||
-                        (component->Action == INSTALLSTATE_DEFAULT))
-                           
-                    {
-                        component->Action = INSTALLSTATE_SOURCE;
-                        component->ActionRequest = INSTALLSTATE_SOURCE;
-                    }
-                }
-                else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
-                {
-                    if ((component->Action == INSTALLSTATE_UNKNOWN) ||
-                        (component->Action == INSTALLSTATE_ABSENT))
-                           
-                    {
-                        component->Action = INSTALLSTATE_ADVERTISED;
-                        component->ActionRequest = INSTALLSTATE_ADVERTISED;
-                    }
-                }
-                else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
-                {
-                    if (component->Action == INSTALLSTATE_UNKNOWN)
-                    {
-                        component->Action = INSTALLSTATE_ABSENT;
-                        component->ActionRequest = INSTALLSTATE_ABSENT;
-                    }
-                }
-                else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
-                {
-                    component->Action = INSTALLSTATE_UNKNOWN;
-                    component->ActionRequest = INSTALLSTATE_UNKNOWN;
-                }
+                if ((component->Action == INSTALLSTATE_UNKNOWN) ||
+                    (component->Action == INSTALLSTATE_ABSENT))
+                    msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
             }
-
-            if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
+            else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
             {
-                feature->Action = INSTALLSTATE_LOCAL;
-                feature->ActionRequest = INSTALLSTATE_LOCAL;
+                if (component->Action == INSTALLSTATE_UNKNOWN)
+                    msi_component_set_state( component, INSTALLSTATE_ABSENT );
             }
+            else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
+                msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
+
+            if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
+                msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
         }
-    } 
+    }
 
     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
     {
-        TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
-            debugstr_w(component->Component), component->Installed, 
-            component->Action, component->ActionRequest);
+        if (component->Action == INSTALLSTATE_DEFAULT)
+        {
+            TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
+            msi_component_set_state( component, INSTALLSTATE_LOCAL );
+        }
+
+        TRACE("Result: Component %s (Installed %i, Action %i)\n",
+            debugstr_w(component->Component), component->Installed, component->Action);
     }
 
 
@@ -1933,45 +1908,43 @@ static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
     return ERROR_SUCCESS;
 }
 
-/* 
- * A lot is done in this function aside from just the costing.
- * The costing needs to be implemented at some point but for now I am going
- * to focus on the directory building
- *
- */
-static UINT ACTION_CostFinalize(MSIPACKAGE *package)
+LPWSTR msi_get_disk_file_version( LPCWSTR filename )
 {
-    static const WCHAR ExecSeqQuery[] =
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','D','i','r','e','c','t','o','r','y','`',0};
-    static const WCHAR ConditionQuery[] =
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','C','o','n','d','i','t','i','o','n','`',0};
-    static const WCHAR szCosting[] =
-        {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
-    static const WCHAR szlevel[] =
-        {'I','N','S','T','A','L','L','L','E','V','E','L',0};
-    static const WCHAR szOne[] = { '1', 0 };
-    MSICOMPONENT *comp;
-    MSIFILE *file;
-    UINT rc;
-    MSIQUERY * view;
-    LPWSTR level;
+    static const WCHAR name_fmt[] =
+        {'%','u','.','%','u','.','%','u','.','%','u',0};
+    static WCHAR name[] = {'\\',0};
+    VS_FIXEDFILEINFO *lpVer;
+    WCHAR filever[0x100];
+    LPVOID version;
+    DWORD versize;
+    DWORD handle;
+    UINT sz;
+
+    TRACE("%s\n", debugstr_w(filename));
+
+    versize = GetFileVersionInfoSizeW( filename, &handle );
+    if (!versize)
+        return NULL;
 
-    if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
-        return ERROR_SUCCESS;
-    
-    TRACE("Building Directory properties\n");
+    version = msi_alloc( versize );
+    GetFileVersionInfoW( filename, 0, versize, version );
 
-    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
-    if (rc == ERROR_SUCCESS)
-    {
-        rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
-                        package);
-        msiobj_release(&view->hdr);
-    }
+    VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
+    msi_free( version );
 
-    TRACE("File calculations\n");
+    sprintfW( filever, name_fmt,
+        HIWORD(lpVer->dwFileVersionMS),
+        LOWORD(lpVer->dwFileVersionMS),
+        HIWORD(lpVer->dwFileVersionLS),
+        LOWORD(lpVer->dwFileVersionLS));
+
+    return strdupW( filever );
+}
+
+static UINT msi_check_file_install_states( MSIPACKAGE *package )
+{
+    LPWSTR file_version;
+    MSIFILE *file;
 
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
@@ -1990,63 +1963,97 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
         msi_free(file->TargetPath);
 
         TRACE("file %s is named %s\n",
-               debugstr_w(file->File),debugstr_w(file->FileName));       
+               debugstr_w(file->File), debugstr_w(file->FileName));
 
         file->TargetPath = build_directory_name(2, p, file->FileName);
 
         msi_free(p);
 
         TRACE("file %s resolves to %s\n",
-               debugstr_w(file->File),debugstr_w(file->TargetPath));       
+               debugstr_w(file->File), debugstr_w(file->TargetPath));
+
+        /* don't check files of components that aren't installed */
+        if (comp->Installed == INSTALLSTATE_UNKNOWN ||
+            comp->Installed == INSTALLSTATE_ABSENT)
+        {
+            file->state = msifs_missing;  /* assume files are missing */
+            continue;
+        }
 
         if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
         {
             file->state = msifs_missing;
             comp->Cost += file->FileSize;
+            comp->Installed = INSTALLSTATE_INCOMPLETE;
             continue;
         }
 
-        if (file->Version)
+        if (file->Version &&
+            (file_version = msi_get_disk_file_version( file->TargetPath )))
         {
-            DWORD handle;
-            DWORD versize;
-            UINT sz;
-            LPVOID version;
-            static WCHAR name[] = {'\\',0};
-            static const WCHAR name_fmt[] = 
-                {'%','u','.','%','u','.','%','u','.','%','u',0};
-            WCHAR filever[0x100];
-            VS_FIXEDFILEINFO *lpVer;
-
-            TRACE("Version comparison..\n");
-            versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
-            version = msi_alloc(versize);
-            GetFileVersionInfoW(file->TargetPath, 0, versize, version);
-
-            VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
-
-            sprintfW(filever,name_fmt,
-                HIWORD(lpVer->dwFileVersionMS),
-                LOWORD(lpVer->dwFileVersionMS),
-                HIWORD(lpVer->dwFileVersionLS),
-                LOWORD(lpVer->dwFileVersionLS));
-
             TRACE("new %s old %s\n", debugstr_w(file->Version),
-                  debugstr_w(filever));
-            if (strcmpiW(filever,file->Version)<0)
+                  debugstr_w(file_version));
+            /* FIXME: seems like a bad way to compare version numbers */
+            if (lstrcmpiW(file_version, file->Version)<0)
             {
                 file->state = msifs_overwrite;
-                /* FIXME: cost should be diff in size */
                 comp->Cost += file->FileSize;
+                comp->Installed = INSTALLSTATE_INCOMPLETE;
             }
             else
                 file->state = msifs_present;
-            msi_free(version);
+            msi_free( file_version );
         }
         else
             file->state = msifs_present;
     }
 
+    return ERROR_SUCCESS;
+}
+
+/*
+ * A lot is done in this function aside from just the costing.
+ * The costing needs to be implemented at some point but for now I am going
+ * to focus on the directory building
+ *
+ */
+static UINT ACTION_CostFinalize(MSIPACKAGE *package)
+{
+    static const WCHAR ExecSeqQuery[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','D','i','r','e','c','t','o','r','y','`',0};
+    static const WCHAR ConditionQuery[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','C','o','n','d','i','t','i','o','n','`',0};
+    static const WCHAR szCosting[] =
+        {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
+    static const WCHAR szlevel[] =
+        {'I','N','S','T','A','L','L','L','E','V','E','L',0};
+    static const WCHAR szOne[] = { '1', 0 };
+    MSICOMPONENT *comp;
+    UINT rc;
+    MSIQUERY * view;
+    LPWSTR level;
+
+    if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
+        return ERROR_SUCCESS;
+
+    TRACE("Building Directory properties\n");
+
+    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+    if (rc == ERROR_SUCCESS)
+    {
+        rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
+                        package);
+        msiobj_release(&view->hdr);
+    }
+
+    /* read components states from the registry */
+    ACTION_GetComponentInstallStates(package);
+
+    TRACE("File calculations\n");
+    msi_check_file_install_states( package );
+
     TRACE("Evaluating Condition Table\n");
 
     rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
@@ -2060,14 +2067,10 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
     TRACE("Enabling or Disabling Components\n");
     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
     {
-        if (comp->Condition)
+        if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
         {
-            if (MSI_EvaluateConditionW(package,
-                comp->Condition) == MSICONDITION_FALSE)
-            {
-                TRACE("Disabling component %s\n", debugstr_w(comp->Component));
-                comp->Enabled = FALSE;
-            }
+            TRACE("Disabling component %s\n", debugstr_w(comp->Component));
+            comp->Enabled = FALSE;
         }
     }
 
@@ -2078,7 +2081,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
         MSI_SetPropertyW(package,szlevel, szOne);
     msi_free(level);
 
-    ACTION_UpdateInstallStates(package);
+    ACTION_UpdateFeatureInstallStates(package);
 
     return MSI_SetFeatureStates(package);
 }
index 396354c..58a6099 100644 (file)
@@ -58,24 +58,6 @@ static UINT ALTER_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
     return ERROR_FUNCTION_FAILED;
 }
 
-static UINT ALTER_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
-{
-    MSIALTERVIEW *av = (MSIALTERVIEW*)view;
-
-    TRACE("%p %d %d %04x\n", av, row, col, val );
-
-    return ERROR_FUNCTION_FAILED;
-}
-
-static UINT ALTER_insert_row( struct tagMSIVIEW *view, MSIRECORD *record )
-{
-    MSIALTERVIEW *av = (MSIALTERVIEW*)view;
-
-    TRACE("%p %p\n", av, record );
-
-    return ERROR_FUNCTION_FAILED;
-}
-
 static UINT ALTER_execute( struct tagMSIVIEW *view, MSIRECORD *record )
 {
     MSIALTERVIEW *av = (MSIALTERVIEW*)view;
@@ -146,8 +128,8 @@ static const MSIVIEWOPS alter_ops =
 {
     ALTER_fetch_int,
     ALTER_fetch_stream,
-    ALTER_set_int,
-    ALTER_insert_row,
+    NULL,
+    NULL,
     ALTER_execute,
     ALTER_close,
     ALTER_get_dimensions,
@@ -159,9 +141,9 @@ static const MSIVIEWOPS alter_ops =
 
 UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, int hold )
 {
-    MSIALTERVIEW *av = NULL;
+    MSIALTERVIEW *av;
 
-    TRACE("%p\n", av );
+    TRACE("%p\n", view );
 
     av = msi_alloc_zero( sizeof *av );
     if( !av )
index c36139e..8abed5c 100644 (file)
@@ -57,15 +57,12 @@ DEFINE_GUID( CLSID_MsiPatch, 0x000c1086, 0x0000, 0x0000,
 static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
 {
     MSIDATABASE *db = (MSIDATABASE *) arg;
-    DWORD r;
 
     msi_free(db->path);
     free_cached_tables( db );
     msi_free_transforms( db );
     msi_destroy_stringtable( db->strings );
-    r = IStorage_Release( db->storage );
-    if( r )
-        ERR("database reference count was not zero (%d)\n", r);
+    IStorage_Release( db->storage );
     if (db->deletefile)
     {
         DeleteFileW( db->deletefile );
@@ -354,7 +351,7 @@ static LPWSTR msi_build_createsql_columns(LPWSTR *columns_data, LPWSTR *types, D
     LPCWSTR type;
     DWORD sql_size = 1, i, len;
     WCHAR expanded[128], *ptr;
-    WCHAR size[10], comma[2], extra[10];
+    WCHAR size[10], comma[2], extra[30];
 
     static const WCHAR column_fmt[] = {'`','%','s','`',' ','%','s','%','s','%','s','%','s',' ',0};
     static const WCHAR size_fmt[] = {'(','%','s',')',0};
@@ -362,6 +359,7 @@ static LPWSTR msi_build_createsql_columns(LPWSTR *columns_data, LPWSTR *types, D
     static const WCHAR type_int[] = {'I','N','T',0};
     static const WCHAR type_long[] = {'L','O','N','G',0};
     static const WCHAR type_notnull[] = {' ','N','O','T',' ','N','U','L','L',0};
+    static const WCHAR localizable[] = {' ','L','O','C','A','L','I','Z','A','B','L','E',0};
 
     columns = msi_alloc_zero(sql_size * sizeof(WCHAR));
     if (!columns)
@@ -379,12 +377,20 @@ static LPWSTR msi_build_createsql_columns(LPWSTR *columns_data, LPWSTR *types, D
 
         ptr = &types[i][1];
         len = atolW(ptr);
+        extra[0] = '\0';
 
         switch (types[i][0])
         {
-            case 'l': case 's':
+            case 'l':
                 lstrcpyW(extra, type_notnull);
-            case 'L': case 'S':
+            case 'L':
+                lstrcatW(extra, localizable);
+                type = type_char;
+                sprintfW(size, size_fmt, ptr);
+                break;
+            case 's':
+                lstrcpyW(extra, type_notnull);
+            case 'S':
                 type = type_char;
                 sprintfW(size, size_fmt, ptr);
                 break;
index 6a9d62a..1484f6a 100644 (file)
@@ -73,28 +73,11 @@ static UINT DELETE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IS
     return ERROR_FUNCTION_FAILED;
 }
 
-static UINT DELETE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
-{
-    MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view;
-
-    TRACE("%p %d %d %04x\n", dv, row, col, val );
-
-    return ERROR_FUNCTION_FAILED;
-}
-
-static UINT DELETE_insert_row( struct tagMSIVIEW *view, MSIRECORD *record )
-{
-    MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view;
-
-    TRACE("%p %p\n", dv, record );
-
-    return ERROR_FUNCTION_FAILED;
-}
-
 static UINT DELETE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
 {
     MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view;
-    UINT r, i, j, rows = 0, cols = 0;
+    UINT r, i, rows = 0, cols = 0;
+    MSIRECORD *empty;
 
     TRACE("%p %p\n", dv, record);
 
@@ -109,12 +92,17 @@ static UINT DELETE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
     if( r != ERROR_SUCCESS )
         return r;
 
-    TRACE("blanking %d rows\n", rows); 
+    TRACE("blanking %d rows\n", rows);
+
+    empty = MSI_CreateRecord( cols );
+    if (!empty)
+        return ERROR_FUNCTION_FAILED;
 
     /* blank out all the rows that match */
-    for( i=0; i<rows; i++ )
-        for( j=1; j<=cols; j++ )
-            dv->table->ops->set_int( dv->table, i, j, 0 );
+    for ( i=0; i<rows; i++ )
+        dv->table->ops->set_row( dv->table, i, empty, (1<<cols)-1 );
+
+    msiobj_release( &empty->hdr );
 
     return ERROR_SUCCESS;
 }
@@ -195,8 +183,8 @@ static const MSIVIEWOPS delete_ops =
 {
     DELETE_fetch_int,
     DELETE_fetch_stream,
-    DELETE_set_int,
-    DELETE_insert_row,
+    NULL,
+    NULL,
     DELETE_execute,
     DELETE_close,
     DELETE_get_dimensions,
index 5c4ca26..d928edc 100644 (file)
@@ -920,6 +920,7 @@ static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
     struct msi_scrolltext_info *info;
     msi_control *control;
     HMODULE hRichedit;
+    LPCWSTR text;
     DWORD style;
 
     info = msi_alloc( sizeof *info );
@@ -949,7 +950,9 @@ static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
     SetPropW( control->hwnd, szButtonData, info );
 
     /* add the text into the richedit */
-    msi_scrolltext_add_text( control, MSI_RecordGetString( rec, 10 ) );
+    text = MSI_RecordGetString( rec, 10 );
+    if (text)
+        msi_scrolltext_add_text( control, text );
 
     return ERROR_SUCCESS;
 }
@@ -1766,8 +1769,7 @@ msi_seltree_menu( HWND hwnd, HTREEITEM hItem )
     case INSTALLSTATE_LOCAL:
     case INSTALLSTATE_ADVERTISED:
     case INSTALLSTATE_ABSENT:
-        feature->ActionRequest = r;
-        feature->Action = r;
+        msi_feature_set_state( feature, r );
         break;
     default:
         FIXME("select feature and all children\n");
@@ -1800,8 +1802,8 @@ MSISelectionTree_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
     switch( msg )
     {
     case WM_LBUTTONDOWN:
-        tvhti.pt.x = LOWORD( lParam );
-        tvhti.pt.y = HIWORD( lParam );
+        tvhti.pt.x = (short)LOWORD( lParam );
+        tvhti.pt.y = (short)HIWORD( lParam );
         tvhti.flags = 0;
         tvhti.hItem = 0;
         r = CallWindowProcW(info->oldproc, hWnd, TVM_HITTEST, 0, (LPARAM) &tvhti );
@@ -3449,3 +3451,106 @@ void msi_dialog_unregister_class( void )
     UnregisterClassW( szMsiHiddenWindow, NULL );
     uiThreadId = 0;
 }
+
+static UINT error_dialog_handler(MSIPACKAGE *package, LPCWSTR event,
+                                 LPCWSTR argument, msi_dialog* dialog)
+{
+    static const WCHAR end_dialog[] = {'E','n','d','D','i','a','l','o','g',0};
+    static const WCHAR error_abort[] = {'E','r','r','o','r','A','b','o','r','t',0};
+    static const WCHAR error_cancel[] = {'E','r','r','o','r','C','a','n','c','e','l',0};
+    static const WCHAR error_no[] = {'E','r','r','o','r','N','o',0};
+    static const WCHAR result_prop[] = {
+        'M','S','I','E','r','r','o','r','D','i','a','l','o','g','R','e','s','u','l','t',0
+    };
+
+    if ( lstrcmpW( event, end_dialog ) )
+        return ERROR_SUCCESS;
+
+    if ( !lstrcmpW( argument, error_abort ) || !lstrcmpW( argument, error_cancel ) ||
+         !lstrcmpW( argument, error_no ) )
+    {
+         MSI_SetPropertyW( package, result_prop, error_abort );
+    }
+
+    ControlEvent_CleanupSubscriptions(package);
+    msi_dialog_end_dialog( dialog );
+
+    return ERROR_SUCCESS;
+}
+
+static UINT msi_error_dialog_set_error( MSIPACKAGE *package, LPWSTR error_dialog, LPWSTR error )
+{
+    MSIRECORD * row;
+
+    static const WCHAR update[] = 
+        {'U','P','D','A','T','E',' ','`','C','o','n','t','r','o','l','`',' ',
+         'S','E','T',' ','`','T','e','x','t','`',' ','=',' ','\'','%','s','\'',' ',
+         'W','H','E','R','E', ' ','`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',' ',
+         'A','N','D',' ','`','C','o','n','t','r','o','l','`',' ','=',' ',
+         '\'','E','r','r','o','r','T','e','x','t','\'',0};
+
+    row = MSI_QueryGetRecord( package->db, update, error, error_dialog );
+    if (!row)
+        return ERROR_FUNCTION_FAILED;
+
+    msiobj_release(&row->hdr);
+    return ERROR_SUCCESS;
+}
+
+UINT msi_spawn_error_dialog( MSIPACKAGE *package, LPWSTR error_dialog, LPWSTR error )
+{
+    msi_dialog *dialog;
+    WCHAR result[MAX_PATH];
+    UINT r = ERROR_SUCCESS;
+    DWORD size = MAX_PATH;
+    int res;
+
+    static const WCHAR pn_prop[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
+    static const WCHAR title_fmt[] = {'%','s',' ','W','a','r','n','i','n','g',0};
+    static const WCHAR error_abort[] = {'E','r','r','o','r','A','b','o','r','t',0};
+    static const WCHAR result_prop[] = {
+        'M','S','I','E','r','r','o','r','D','i','a','l','o','g','R','e','s','u','l','t',0
+    };
+
+    if ( !error_dialog )
+    {
+        LPWSTR product_name = msi_dup_property( package, pn_prop );
+        WCHAR title[MAX_PATH];
+
+        sprintfW( title, title_fmt, product_name );
+        res = MessageBoxW( NULL, error, title, MB_OKCANCEL | MB_ICONWARNING );
+
+        msi_free( product_name );
+
+        if ( res == IDOK )
+            return ERROR_SUCCESS;
+        else
+            return ERROR_FUNCTION_FAILED;
+    }
+
+    r = msi_error_dialog_set_error( package, error_dialog, error );
+    if ( r != ERROR_SUCCESS )
+        return r;
+
+    dialog = msi_dialog_create( package, error_dialog, package->dialog,
+                                error_dialog_handler );
+    if ( !dialog )
+        return ERROR_FUNCTION_FAILED;
+
+    dialog->finished = FALSE;
+    r = msi_dialog_run_message_loop( dialog );
+    if ( r != ERROR_SUCCESS )
+        goto done;
+
+    r = MSI_GetPropertyW( package, result_prop, result, &size );
+    if ( r != ERROR_SUCCESS)
+        r = ERROR_SUCCESS;
+
+    if ( !lstrcmpW( result, error_abort ) )
+        r = ERROR_FUNCTION_FAILED;
+
+done:
+    msi_dialog_destroy( dialog );
+
+    return r;
+}
index 2b0397b..13805a6 100644 (file)
@@ -185,10 +185,8 @@ static UINT ControlEvent_AddLocal(MSIPACKAGE* package, LPCWSTR argument,
     else
     {
         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
-        {
-            feature->ActionRequest = INSTALLSTATE_LOCAL;
-            feature->Action = INSTALLSTATE_LOCAL;
-        }
+            msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
+
         ACTION_UpdateComponentStates(package,argument);
     }
     return ERROR_SUCCESS;
@@ -207,10 +205,8 @@ static UINT ControlEvent_Remove(MSIPACKAGE* package, LPCWSTR argument,
     else
     {
         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
-        {
-            feature->ActionRequest = INSTALLSTATE_ABSENT;
-            feature->Action= INSTALLSTATE_ABSENT;
-        }
+            msi_feature_set_state( feature, INSTALLSTATE_ABSENT );
+
         ACTION_UpdateComponentStates(package,argument);
     }
     return ERROR_SUCCESS;
@@ -229,10 +225,7 @@ static UINT ControlEvent_AddSource(MSIPACKAGE* package, LPCWSTR argument,
     else
     {
         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
-        {
-            feature->ActionRequest = INSTALLSTATE_SOURCE;
-            feature->Action = INSTALLSTATE_SOURCE;
-        }
+            msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
         ACTION_UpdateComponentStates(package,argument);
     }
     return ERROR_SUCCESS;
index 99cc6b5..38b1f8f 100644 (file)
@@ -57,6 +57,39 @@ extern const WCHAR szRemoveFiles[];
 
 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
 
+struct media_info {
+    UINT disk_id;
+    UINT last_sequence;
+    LPWSTR disk_prompt;
+    LPWSTR cabinet;
+    LPWSTR volume_label;
+    BOOL is_continuous;
+    WCHAR source[MAX_PATH];
+};
+
+static UINT msi_change_media( MSIPACKAGE *package, struct media_info *mi )
+{
+    LPWSTR error, error_dialog;
+    UINT r = ERROR_SUCCESS;
+
+    static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
+    static const WCHAR error_prop[] = {'E','r','r','o','r','D','i','a','l','o','g',0};
+
+    if ( msi_get_property_int(package, szUILevel, 0) == INSTALLUILEVEL_NONE )
+        return ERROR_SUCCESS;
+
+    error = generate_error_string( package, 1302, 1, mi->disk_prompt );
+    error_dialog = msi_dup_property( package, error_prop );
+
+    while ( r == ERROR_SUCCESS && GetFileAttributesW( mi->source ) == INVALID_FILE_ATTRIBUTES )
+        r = msi_spawn_error_dialog( package, error_dialog, error );
+
+    msi_free( error );
+    msi_free( error_dialog );
+
+    return r;
+}
+
 /*
  * This is a helper function for handling embedded cabinet media
  */
@@ -104,7 +137,7 @@ end:
 typedef struct
 {
     MSIPACKAGE* package;
-    LPCSTR cab_path;
+    struct media_info *mi;
 } CabData;
 
 static void * cabinet_alloc(ULONG cb)
@@ -200,10 +233,83 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *ac
     ui_progress( package, 2, f->FileSize, 0, 0);
 }
 
+static UINT msi_media_get_disk_info( CabData *data )
+{
+    MSIPACKAGE *package = data->package;
+    MSIRECORD *row;
+    LPWSTR ptr;
+
+    static const WCHAR query[] =
+        {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+         '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
+         '`','D','i','s','k','I','d','`',' ','=',' ','%','i',0};
+
+    row = MSI_QueryGetRecord(package->db, query, data->mi->disk_id);
+    if (!row)
+    {
+        TRACE("Unable to query row\n");
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    data->mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
+    data->mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
+
+    ptr = strrchrW(data->mi->source, '\\') + 1;
+    lstrcpyW(ptr, data->mi->cabinet);
+
+    return ERROR_SUCCESS;
+}
+
 static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
 {
+    TRACE("(%d)\n", fdint);
+
     switch (fdint)
     {
+    case fdintPARTIAL_FILE:
+    {
+        CabData *data = (CabData *)pfdin->pv;
+        data->mi->is_continuous = FALSE;
+        return 0;
+    }
+    case fdintNEXT_CABINET:
+    {
+        CabData *data = (CabData *)pfdin->pv;
+        struct media_info *mi = data->mi;
+        LPWSTR cab = strdupAtoW(pfdin->psz1);
+        UINT rc;
+
+        msi_free(mi->disk_prompt);
+
+        mi->disk_id++;
+        mi->is_continuous = TRUE;
+
+        rc = msi_media_get_disk_info(data);
+        if (rc != ERROR_SUCCESS)
+        {
+            ERR("Failed to get next cabinet information: %d\n", rc);
+            return -1;
+        }
+
+        if (lstrcmpiW(mi->cabinet, cab))
+        {
+            msi_free(cab);
+            ERR("Continuous cabinet does not match the next cabinet in the Media table\n");
+            return -1;
+        }
+
+        msi_free(cab);
+
+        TRACE("Searching for %s\n", debugstr_w(mi->source));
+
+        if (GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
+            rc = msi_change_media(data->package, mi);
+
+        if (rc != ERROR_SUCCESS)
+            return -1;
+
+        return 0;
+    }
     case fdintCOPY_FILE:
     {
         CabData *data = (CabData*) pfdin->pv;
@@ -272,69 +378,57 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
  *
  * Extract files from a cab file.
  */
-static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source, 
-                                 LPCWSTR path)
+static BOOL extract_cabinet_file(MSIPACKAGE* package, struct media_info *mi)
 {
+    LPSTR cabinet, cab_path = NULL;
+    LPWSTR ptr;
     HFDI hfdi;
     ERF erf;
-    BOOL ret;
-    char *cabinet;
-    char *cab_path;
-    static CHAR empty[] = "";
+    BOOL ret = FALSE;
     CabData data;
 
-    TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
-
-    hfdi = FDICreate(cabinet_alloc,
-                     cabinet_free,
-                     cabinet_open,
-                     cabinet_read,
-                     cabinet_write,
-                     cabinet_close,
-                     cabinet_seek,
-                     0,
-                     &erf);
+    TRACE("Extracting %s\n", debugstr_w(mi->source));
+
+    hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read,
+                     cabinet_write, cabinet_close, cabinet_seek, 0, &erf);
     if (!hfdi)
     {
         ERR("FDICreate failed\n");
         return FALSE;
     }
 
-    if (!(cabinet = strdupWtoA( source )))
-    {
-        FDIDestroy(hfdi);
-        return FALSE;
-    }
-    if (!(cab_path = strdupWtoA( path )))
-    {
-        FDIDestroy(hfdi);
-        msi_free(cabinet);
-        return FALSE;
-    }
+    ptr = strrchrW(mi->source, '\\') + 1;
+    cabinet = strdupWtoA(ptr);
+    if (!cabinet)
+        goto done;
 
-    data.package = package;
-    data.cab_path = cab_path;
+    cab_path = strdupWtoA(mi->source);
+    if (!cab_path)
+        goto done;
+
+    cab_path[ptr - mi->source] = '\0';
 
-    ret = FDICopy(hfdi, cabinet, empty, 0, cabinet_notify, NULL, &data);
+    data.package = package;
+    data.mi = mi;
 
+    ret = FDICopy(hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, &data);
     if (!ret)
         ERR("FDICopy failed\n");
 
+done:
     FDIDestroy(hfdi);
-
     msi_free(cabinet);
     msi_free(cab_path);
 
     return ret;
 }
 
-static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT*
-        comp, LPCWSTR path)
+static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, LPCWSTR path)
 {
     if (!file->IsCompressed)
     {
         LPWSTR p, path;
-        p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
+        p = resolve_folder(package, file->Component->Directory, TRUE, FALSE, NULL);
         path = build_directory_name(2, p, file->ShortName);
         if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( path ))
         {
@@ -348,224 +442,136 @@ static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT*
         file->SourcePath = build_directory_name(2, path, file->File);
 }
 
-struct media_info {
-    UINT last_sequence; 
-    LPWSTR last_volume;
-    LPWSTR last_path;
-    DWORD count;
-    WCHAR source[MAX_PATH];
-};
-
-static struct media_info *create_media_info( void )
-{
-    struct media_info *mi;
-
-    mi = msi_alloc( sizeof *mi  );
-    if (mi)
-    {
-        mi->last_sequence = 0; 
-        mi->last_volume = NULL;
-        mi->last_path = NULL;
-        mi->count = 0;
-        mi->source[0] = 0;
-    }
-
-    return mi;
-}
-
 static void free_media_info( struct media_info *mi )
 {
-    msi_free( mi->last_path );
+    msi_free( mi->disk_prompt );
+    msi_free( mi->cabinet );
+    msi_free( mi->volume_label );
     msi_free( mi );
 }
 
-/* downloads a remote cabinet and extracts it if it exists */
-static UINT msi_extract_remote_cabinet( MSIPACKAGE *package, struct media_info *mi )
+static UINT download_remote_cabinet(MSIPACKAGE *package, struct media_info *mi)
 {
-    FDICABINETINFO cabinfo;
     WCHAR temppath[MAX_PATH];
-    WCHAR src[MAX_PATH];
-    LPSTR cabpath;
-    LPCWSTR file;
-    LPWSTR ptr;
-    HFDI hfdi;
-    ERF erf;
-    int hf;
+    LPWSTR src, ptr;
+    LPCWSTR cab;
 
-    /* the URL is the path prefix of the package URL and the filename
-     * of the file to download
-     */
-    ptr = strrchrW(package->PackagePath, '/');
-    lstrcpynW(src, package->PackagePath, ptr - package->PackagePath + 2);
-    ptr = strrchrW(mi->source, '\\');
-    lstrcatW(src, ptr + 1);
-
-    file = msi_download_file( src, temppath );
-    lstrcpyW(mi->source, file);
+    src = strdupW(package->BaseURL);
+    if (!src)
+        return ERROR_OUTOFMEMORY;
 
-    /* check if the remote cabinet still exists, ignore if it doesn't */
-    hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read,
-                     cabinet_write, cabinet_close, cabinet_seek, 0, &erf);
-    if (!hfdi)
+    ptr = strrchrW(src, '/');
+    if (!ptr)
     {
-        ERR("FDICreate failed\n");
+        msi_free(src);
         return ERROR_FUNCTION_FAILED;
     }
 
-    cabpath = strdupWtoA(mi->source);
-    hf = cabinet_open(cabpath, _O_RDONLY, 0);
-    if (!FDIIsCabinet(hfdi, hf, &cabinfo))
-    {
-        WARN("Remote cabinet %s does not exist.\n", debugstr_w(mi->source));
-        msi_free(cabpath);
-        return ERROR_SUCCESS;
-    }
+    *(ptr + 1) = '\0';
+    ptr = strrchrW(mi->source, '\\');
+    lstrcatW(src, ptr + 1);
+
+    cab = msi_download_file(src, temppath);
+    lstrcpyW(mi->source, cab);
 
-    msi_free(cabpath);
-    return !extract_cabinet_file(package, mi->source, mi->last_path);
+    msi_free(src);
+    return ERROR_SUCCESS;
 }
 
-static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
-                                  MSIFILE *file )
+static UINT load_media_info(MSIPACKAGE *package, MSIFILE *file, struct media_info *mi)
 {
-    UINT rc = ERROR_SUCCESS;
-    MSIRECORD * row = 0;
-    static const WCHAR ExecSeqQuery[] =
-        {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
-         '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
-         '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
-         ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
-         '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
-    LPCWSTR cab, volume;
-    DWORD sz;
-    INT seq;
-    LPCWSTR prompt;
-    MSICOMPONENT *comp = file->Component;
+    MSIRECORD *row;
+    LPWSTR source_dir;
+    UINT r;
 
-    if (file->Sequence <= mi->last_sequence)
-    {
-        set_file_source(package,file,comp,mi->last_path);
-        TRACE("Media already ready (%u, %u)\n",file->Sequence,mi->last_sequence);
-        return ERROR_SUCCESS;
-    }
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+        '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
+        '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
+        ' ','%','i',' ','A','N','D',' ','`','D','i','s','k','I','d','`',' ','>','=',
+        ' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
+        '`','D','i','s','k','I','d','`',0
+    };
 
-    mi->count ++;
-    row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
+    row = MSI_QueryGetRecord(package->db, query, file->Sequence, mi->disk_id);
     if (!row)
     {
         TRACE("Unable to query row\n");
         return ERROR_FUNCTION_FAILED;
     }
 
-    volume = MSI_RecordGetString(row, 5);
-    prompt = MSI_RecordGetString(row, 3);
+    mi->disk_id = MSI_RecordGetInteger(row, 1);
+    mi->last_sequence = MSI_RecordGetInteger(row, 2);
+    mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
+    mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
+    mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
+    msiobj_release(&row->hdr);
 
-    msi_free(mi->last_path);
-    mi->last_path = NULL;
+    source_dir = msi_dup_property(package, cszSourceDir);
 
-    if (!file->IsCompressed)
+    if (mi->cabinet && mi->cabinet[0] == '#')
     {
-        mi->last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
-        set_file_source(package,file,comp,mi->last_path);
-
-        MsiSourceListAddMediaDiskW(package->ProductCode, NULL, 
-            MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count, volume,
-            prompt);
-
-        MsiSourceListSetInfoW(package->ProductCode, NULL, 
-                MSIINSTALLCONTEXT_USERMANAGED, 
-                MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
-                INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
-        msiobj_release(&row->hdr);
-        return rc;
+        r = writeout_cabinet_stream(package, &mi->cabinet[1], mi->source);
+        if (r != ERROR_SUCCESS)
+        {
+            ERR("Failed to extract cabinet stream\n");
+            return ERROR_FUNCTION_FAILED;
+        }
     }
+    else
+    {
+        lstrcpyW(mi->source, source_dir);
 
-    seq = MSI_RecordGetInteger(row,2);
-    mi->last_sequence = seq;
 
-    cab = MSI_RecordGetString(row,4);
-    if (cab)
-    {
-        TRACE("Source is CAB %s\n",debugstr_w(cab));
-        /* the stream does not contain the # character */
-        if (cab[0]=='#')
-        {
-            LPWSTR path;
+        if (mi->cabinet)
+            lstrcatW(mi->source, mi->cabinet);
+    }
 
-            writeout_cabinet_stream(package,&cab[1],mi->source);
-            mi->last_path = strdupW(mi->source);
-            *(strrchrW(mi->last_path,'\\')+1)=0;
+    MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
+        MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
+        mi->disk_id, mi->volume_label, mi->disk_prompt);
 
-            path = msi_dup_property( package, cszSourceDir );
+    MsiSourceListSetInfoW(package->ProductCode, NULL,
+        MSIINSTALLCONTEXT_USERMANAGED,
+        MSICODE_PRODUCT | MSISOURCETYPE_MEDIA,
+        INSTALLPROPERTY_LASTUSEDSOURCEW, mi->source);
 
-            MsiSourceListAddMediaDiskW(package->ProductCode, NULL, 
-                MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count,
-                volume, prompt);
+    msi_free(source_dir);
+    return ERROR_SUCCESS;
+}
 
-            MsiSourceListSetInfoW(package->ProductCode, NULL,
-                MSIINSTALLCONTEXT_USERMANAGED,
-                MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
-                INSTALLPROPERTY_LASTUSEDSOURCEW, path);
+static UINT ready_media(MSIPACKAGE *package, MSIFILE *file, struct media_info *mi)
+{
+    UINT rc = ERROR_SUCCESS;
+    BOOL found = FALSE;
 
-            msi_free(path);
-        }
-        else
+    /* media info for continuous cabinet is already loaded */
+    if (mi->is_continuous)
+        return ERROR_SUCCESS;
+
+    rc = load_media_info(package, file, mi);
+    if (rc != ERROR_SUCCESS)
+    {
+        ERR("Unable to load media info\n");
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    if (file->IsCompressed &&
+        GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
+    {
+        if (package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL))
         {
-            sz = MAX_PATH;
-            mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR));
-            if (MSI_GetPropertyW(package, cszSourceDir, mi->source, &sz))
-            {
-                ERR("No Source dir defined\n");
-                rc = ERROR_FUNCTION_FAILED;
-            }
-            else
+            rc = download_remote_cabinet(package, mi);
+            if (rc == ERROR_SUCCESS &&
+                GetFileAttributesW(mi->source) != INVALID_FILE_ATTRIBUTES)
             {
-                strcpyW(mi->last_path,mi->source);
-                strcatW(mi->source,cab);
-
-                MsiSourceListSetInfoW(package->ProductCode, NULL,
-                            MSIINSTALLCONTEXT_USERMANAGED,
-                            MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
-                            INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
-
-                /* extract the cab file into a folder in the temp folder */
-                sz = MAX_PATH;
-                if (MSI_GetPropertyW(package, cszTempFolder,mi->last_path, &sz) 
-                                    != ERROR_SUCCESS)
-                    GetTempPathW(MAX_PATH,mi->last_path);
+                found = TRUE;
             }
         }
 
-        /* only download the remote cabinet file if a local copy does not exist */
-        if (GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES &&
-            UrlIsW(package->PackagePath, URLIS_URL))
-        {
-            rc = msi_extract_remote_cabinet(package, mi);
-        }
-        else
-        {
-            rc = !extract_cabinet_file(package, mi->source, mi->last_path);
-        }
-    }
-    else
-    {
-        sz = MAX_PATH;
-        mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR));
-        MSI_GetPropertyW(package,cszSourceDir,mi->source,&sz);
-        strcpyW(mi->last_path,mi->source);
-
-        MsiSourceListSetInfoW(package->ProductCode, NULL,
-                    MSIINSTALLCONTEXT_USERMANAGED,
-                    MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
-                    INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
+        if (!found)
+            rc = msi_change_media(package, mi);
     }
-    set_file_source(package, file, comp, mi->last_path);
-
-    MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
-            MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count, volume,
-            prompt);
-
-    msiobj_release(&row->hdr);
 
     return rc;
 }
@@ -587,6 +593,58 @@ static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
     return ERROR_FUNCTION_FAILED;
 }
 
+static void schedule_install_files(MSIPACKAGE *package)
+{
+    MSIFILE *file;
+
+    LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
+    {
+        if (!ACTION_VerifyComponentForAction(file->Component, INSTALLSTATE_LOCAL))
+        {
+            TRACE("File %s is not scheduled for install\n", debugstr_w(file->File));
+
+            ui_progress(package,2,file->FileSize,0,0);
+            file->state = msifs_skipped;
+        }
+    }
+}
+
+static UINT copy_install_file(MSIFILE *file)
+{
+    BOOL ret;
+    UINT gle;
+
+    TRACE("Copying %s to %s\n", debugstr_w(file->SourcePath),
+          debugstr_w(file->TargetPath));
+
+    ret = CopyFileW(file->SourcePath, file->TargetPath, FALSE);
+    if (ret)
+    {
+        file->state = msifs_installed;
+        return ERROR_SUCCESS;
+    }
+
+    gle = GetLastError();
+    if (gle == ERROR_ALREADY_EXISTS && file->state == msifs_overwrite)
+    {
+        TRACE("overwriting existing file\n");
+        gle = ERROR_SUCCESS;
+    }
+    else if (gle == ERROR_FILE_NOT_FOUND)
+    {
+        /* FIXME: this needs to be tested, I'm pretty sure it fails */
+        TRACE("Source file not found\n");
+        gle = ERROR_SUCCESS;
+    }
+    else if (!(file->Attributes & msidbFileAttributesVital))
+    {
+        TRACE("Ignoring error for nonvital\n");
+        gle = ERROR_SUCCESS;
+    }
+
+    return gle;
+}
+
 /*
  * ACTION_InstallFiles()
  * 
@@ -608,26 +666,14 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
     ptr = strrchrW(package->PackagePath,'\\');
     if (ptr)
     {
-        ptr ++;
+        ptr++;
         MsiSourceListSetInfoW(package->ProductCode, NULL,
                 MSIINSTALLCONTEXT_USERMANAGED,
                 MSICODE_PRODUCT,
                 INSTALLPROPERTY_PACKAGENAMEW, ptr);
     }
-    /* FIXME("Write DiskPrompt\n"); */
-    
-    /* Pass 1 */
-    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
-    {
-        if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL ))
-        {
-            ui_progress(package,2,file->FileSize,0,0);
-            TRACE("File %s is not scheduled for install\n",
-                   debugstr_w(file->File));
 
-            file->state = msifs_skipped;
-        }
-    }
+    schedule_install_files(package);
 
     /*
      * Despite MSDN specifying that the CreateFolders action
@@ -637,68 +683,55 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
      */
     msi_create_component_directories( package );
 
-    mi = create_media_info();
+    mi = msi_alloc_zero( sizeof(struct media_info) );
 
-    /* Pass 2 */
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
         if (file->state != msifs_missing && file->state != msifs_overwrite)
             continue;
 
-        TRACE("Pass 2: %s\n",debugstr_w(file->File));
-
-        rc = ready_media_for_file( package, mi, file );
-        if (rc != ERROR_SUCCESS)
+        if (file->Sequence > mi->last_sequence || mi->is_continuous)
         {
-            ERR("Unable to ready media\n");
-            rc = ERROR_FUNCTION_FAILED;
-            break;
+            rc = ready_media(package, file, mi);
+            if (rc != ERROR_SUCCESS)
+            {
+                ERR("Failed to ready media\n");
+                rc = ERROR_FUNCTION_FAILED;
+                break;
+            }
+
+            if (file->IsCompressed && !extract_cabinet_file(package, mi))
+            {
+                ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
+                rc = ERROR_FUNCTION_FAILED;
+                break;
+            }
         }
 
+        set_file_source(package, file, mi->source);
+
         TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
               debugstr_w(file->TargetPath));
 
-        if (file->state != msifs_missing && file->state != msifs_overwrite)
-            continue;
-
-        /* compressed files are extracted in ready_media_for_file */
-        if (file->IsCompressed)
+        if (!file->IsCompressed)
         {
-            if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(file->TargetPath))
-                ERR("compressed file wasn't extracted (%s)\n",
-                    debugstr_w(file->TargetPath));
-            continue;
-        }
-
-        rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
-        if (!rc)
-        {
-            rc = GetLastError();
-            ERR("Unable to copy file (%s -> %s) (error %d)\n",
-                debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), rc);
-            if (rc == ERROR_ALREADY_EXISTS && file->state == msifs_overwrite)
-            {
-                rc = 0;
-            }
-            else if (rc == ERROR_FILE_NOT_FOUND)
+            rc = copy_install_file(file);
+            if (rc != ERROR_SUCCESS)
             {
-                ERR("Source File Not Found!  Continuing\n");
-                rc = 0;
-            }
-            else if (file->Attributes & msidbFileAttributesVital)
-            {
-                ERR("Ignoring Error and continuing (nonvital file)...\n");
-                rc = 0;
+                ERR("Failed to copy %s to %s (%d)\n", debugstr_w(file->SourcePath),
+                    debugstr_w(file->TargetPath), rc);
+                rc = ERROR_INSTALL_FAILURE;
+                break;
             }
         }
-        else
+        else if (file->state != msifs_installed)
         {
-            file->state = msifs_installed;
-            rc = ERROR_SUCCESS;
+            ERR("compressed file wasn't extracted (%s)\n", debugstr_w(file->TargetPath));
+            rc = ERROR_INSTALL_FAILURE;
+            break;
         }
     }
 
-    /* cleanup */
     free_media_info( mi );
     return rc;
 }
index 0193277..6af3c41 100644 (file)
@@ -128,7 +128,7 @@ void *msihandle2msiinfo(MSIHANDLE handle, UINT type)
         goto out;
     ret = msihandletable[handle].obj;
     msiobj_addref( ret );
-    
+
 out:
     LeaveCriticalSection( &MSI_handle_cs );
 
@@ -153,8 +153,6 @@ void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy )
 
 void msiobj_addref( MSIOBJECTHDR *info )
 {
-    TRACE("%p\n", info);
-
     if( !info )
         return;
 
@@ -181,8 +179,6 @@ int msiobj_release( MSIOBJECTHDR *info )
 {
     int ret;
 
-    TRACE("%p\n",info);
-
     if( !info )
         return -1;
 
index 314b53e..38f2614 100644 (file)
@@ -385,6 +385,17 @@ UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action)
    return ERROR_SUCCESS;
 }
 
+void msi_free_action_script(MSIPACKAGE *package, UINT script)
+{
+    int i;
+    for (i = 0; i < package->script->ActionCount[script]; i++)
+        msi_free(package->script->Actions[script][i]);
+
+    msi_free(package->script->Actions[script]);
+    package->script->Actions[script] = NULL;
+    package->script->ActionCount[script] = 0;
+}
+
 static void remove_tracked_tempfiles(MSIPACKAGE* package)
 {
     struct list *item, *cursor;
@@ -572,13 +583,7 @@ void ACTION_free_package_structures( MSIPACKAGE* package)
     if (package->script)
     {
         for (i = 0; i < TOTAL_SCRIPTS; i++)
-        {
-            int j;
-            for (j = 0; j < package->script->ActionCount[i]; j++)
-                msi_free(package->script->Actions[i][j]);
-        
-            msi_free(package->script->Actions[i]);
-        }
+            msi_free_action_script(package, i);
 
         for (i = 0; i < package->script->UniqueActionsCount; i++)
             msi_free(package->script->UniqueActions[i]);
@@ -587,6 +592,7 @@ void ACTION_free_package_structures( MSIPACKAGE* package)
         msi_free(package->script);
     }
 
+    msi_free(package->BaseURL);
     msi_free(package->PackagePath);
     msi_free(package->ProductCode);
     msi_free(package->ActionFormat);
@@ -866,17 +872,13 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
             continue;
  
         if (newstate == INSTALLSTATE_LOCAL)
-        {
-            component->ActionRequest = INSTALLSTATE_LOCAL;
-            component->Action = INSTALLSTATE_LOCAL;
-        }
+            msi_component_set_state( component, INSTALLSTATE_LOCAL );
         else 
         {
             ComponentList *clist;
             MSIFEATURE *f;
 
-            component->ActionRequest = newstate;
-            component->Action = newstate;
+            msi_component_set_state( component, newstate );
 
             /*if any other feature wants is local we need to set it local*/
             LIST_FOR_EACH_ENTRY( f, &package->features, MSIFEATURE, entry )
@@ -898,26 +900,14 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
                         if (component->Attributes & msidbComponentAttributesOptional)
                         {
                             if (f->Attributes & msidbFeatureAttributesFavorSource)
-                            {
-                                component->Action = INSTALLSTATE_SOURCE;
-                                component->ActionRequest = INSTALLSTATE_SOURCE;
-                            }
+                                msi_component_set_state( component, INSTALLSTATE_SOURCE );
                             else
-                            {
-                                component->Action = INSTALLSTATE_LOCAL;
-                                component->ActionRequest = INSTALLSTATE_LOCAL;
-                            }
+                                msi_component_set_state( component, INSTALLSTATE_LOCAL );
                         }
                         else if (component->Attributes & msidbComponentAttributesSourceOnly)
-                        {
-                            component->Action = INSTALLSTATE_SOURCE;
-                            component->ActionRequest = INSTALLSTATE_SOURCE;
-                        }
+                            msi_component_set_state( component, INSTALLSTATE_SOURCE );
                         else
-                        {
-                            component->Action = INSTALLSTATE_LOCAL;
-                            component->ActionRequest = INSTALLSTATE_LOCAL;
-                        } 
+                            msi_component_set_state( component, INSTALLSTATE_LOCAL );
                     }
                 }
             }
index 33c915f..aefc8fc 100644 (file)
@@ -57,12 +57,12 @@ static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT
 }
 
 /*
- * INSERT_merge_record
+ * msi_query_merge_record
  *
  * Merge a value_list and a record to create a second record.
  * Replace wildcard entries in the valuelist with values from the record
  */
-static MSIRECORD *INSERT_merge_record( UINT fields, column_info *vl, MSIRECORD *rec )
+MSIRECORD *msi_query_merge_record( UINT fields, column_info *vl, MSIRECORD *rec )
 {
     MSIRECORD *merged;
     DWORD wildcard_count = 1, i;
@@ -128,7 +128,7 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
      * Merge the wildcard values into the list of values provided
      * in the query, and create a record containing both.
      */
-    values = INSERT_merge_record( col_count, iv->vals, record );
+    values = msi_query_merge_record( col_count, iv->vals, record );
     if( !values )
         goto err;
 
index 63b1d64..6292861 100644 (file)
@@ -540,8 +540,7 @@ UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
         feature->Attributes & msidbFeatureAttributesDisallowAdvertise)
         return ERROR_FUNCTION_FAILED;
 
-    feature->ActionRequest = iState;
-    feature->Action = iState;
+    msi_feature_set_state( feature, iState );
 
     ACTION_UpdateComponentStates(package,szFeature);
 
@@ -829,3 +828,32 @@ UINT WINAPI MsiSetInstallLevel(MSIHANDLE hInstall, int iInstallLevel)
 
     return r;
 }
+
+/***********************************************************************
+ * MsiGetFeatureValidStatesW (MSI.@)
+ */
+UINT WINAPI MsiGetFeatureValidStatesW(MSIHANDLE hInstall, LPCWSTR szFeature,
+                  DWORD* pInstallState)
+{
+    if(pInstallState) *pInstallState = 1<<INSTALLSTATE_LOCAL;
+    FIXME("%ld %s %p stub returning %d\n",
+        hInstall, debugstr_w(szFeature), pInstallState, pInstallState ? *pInstallState : 0);
+
+    return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * MsiGetFeatureValidStatesA (MSI.@)
+ */
+UINT WINAPI MsiGetFeatureValidStatesA(MSIHANDLE hInstall, LPCSTR szFeature,
+                  DWORD* pInstallState)
+{
+    UINT ret;
+    LPWSTR szwFeature = strdupAtoW(szFeature);
+
+    ret = MsiGetFeatureValidStatesW(hInstall, szwFeature, pInstallState);
+
+    msi_free(szwFeature);
+
+    return ret;
+}
index fda6b1b..b384630 100644 (file)
@@ -39,9 +39,7 @@ typedef struct tagMSIJOINVIEW
     MSIDATABASE   *db;
     MSIVIEW       *left, *right;
     UINT           left_count, right_count;
-    UINT           left_key, right_key;
-    UINT          *pairs;
-    UINT           pair_count;
+    UINT           left_rows, right_rows;
 } MSIJOINVIEW;
 
 static UINT JOIN_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
@@ -57,18 +55,18 @@ static UINT JOIN_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *v
     if( (col==0) || (col>(jv->left_count + jv->right_count)) )
          return ERROR_FUNCTION_FAILED;
 
-    if( row >= jv->pair_count )
+    if( row >= (jv->left_rows * jv->right_rows) )
          return ERROR_FUNCTION_FAILED;
 
     if( col <= jv->left_count )
     {
         table = jv->left;
-        row = jv->pairs[ row*2 ];
+        row = (row/jv->right_rows);
     }
     else
     {
         table = jv->right;
-        row = jv->pairs[ row*2 + 1 ];
+        row = (row % jv->right_rows);
         col -= jv->left_count;
     }
 
@@ -88,130 +86,28 @@ static UINT JOIN_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStr
     if( (col==0) || (col>(jv->left_count + jv->right_count)) )
          return ERROR_FUNCTION_FAILED;
 
+    if( row >= jv->left_rows * jv->right_rows )
+         return ERROR_FUNCTION_FAILED;
+
     if( row <= jv->left_count )
     {
         table = jv->left;
-        row = jv->pairs[ row*2 ];
+        row = (row/jv->right_rows);
     }
     else
     {
         table = jv->right;
-        row = jv->pairs[ row*2 + 1 ];
+        row = (row % jv->right_rows);
         col -= jv->left_count;
     }
 
     return table->ops->fetch_stream( table, row, col, stm );
 }
 
-static UINT JOIN_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
-{
-    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
-
-    TRACE("%p %d %d %04x\n", jv, row, col, val );
-
-    return ERROR_FUNCTION_FAILED;
-}
-
-static UINT JOIN_insert_row( struct tagMSIVIEW *view, MSIRECORD *record )
-{
-    MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
-
-    TRACE("%p %p\n", jv, record );
-
-    return ERROR_FUNCTION_FAILED;
-}
-
-static int join_key_compare(const void *l, const void *r)
-{
-    const UINT *left = l, *right = r;
-    if (left[1] < right[1])
-        return -1;
-    if (left[1] == right[1])
-        return 0;
-    return 1;
-}
-
-static UINT join_load_key_column( MSIJOINVIEW *jv, MSIVIEW *table, UINT column,
-                                  UINT **pdata, UINT *pcount )
-{
-    UINT r, i, count = 0, *data = NULL;
-
-    r = table->ops->get_dimensions( table, &count, NULL );
-    if( r != ERROR_SUCCESS )
-        return r;
-
-    if (!count)
-        goto end;
-
-    data = msi_alloc( count * 2 * sizeof (UINT) );
-    if (!data)
-        return ERROR_SUCCESS;
-
-    for (i=0; i<count; i++)
-    {
-        data[i*2] = i;
-        r = table->ops->fetch_int( table, i, column, &data[i*2+1] );
-        if (r != ERROR_SUCCESS)
-            ERR("fetch data (%u,%u) failed\n", i, column);
-    }
-
-    qsort( data, count, 2 * sizeof (UINT), join_key_compare );
-
-end:
-    *pdata = data;
-    *pcount = count;
-
-    return ERROR_SUCCESS;
-}
-
-static UINT join_match( UINT *ldata, UINT lcount,
-                        UINT *rdata, UINT rcount,
-                        UINT **ppairs, UINT *ppair_count )
-{
-    UINT *pairs;
-    UINT n, i, j;
-
-    TRACE("left %u right %u\n", rcount, lcount);
-
-    /* there can be at most max(lcount, rcount) matches */
-    if (lcount > rcount)
-        n = lcount;
-    else
-        n = rcount;
-
-    pairs = msi_alloc( n * 2 * sizeof(UINT) );
-    if (!pairs)
-        return ERROR_OUTOFMEMORY;
-
-    for (n=0, i=0, j=0; i<lcount && j<rcount; )
-    {
-        /* values match... store the row numbers */
-        if (ldata[i*2+1] == rdata[j*2+1])
-        {
-            pairs[n*2] = ldata[i*2];
-            pairs[n*2+1] = rdata[j*2];
-            i++;  /* FIXME: assumes primary key on the right */
-            n++;
-            continue;
-        }
-
-        /* values differ... move along */
-        if (ldata[i*2+1] < rdata[j*2+1])
-            i++;
-        else
-            j++;
-    }
-
-    *ppairs = pairs;
-    *ppair_count = n;
-
-    return ERROR_SUCCESS;
-}
-
 static UINT JOIN_execute( struct tagMSIVIEW *view, MSIRECORD *record )
 {
     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
-    UINT r, *ldata = NULL, *rdata = NULL, lcount = 0, rcount = 0;
+    UINT r, *ldata = NULL, *rdata = NULL;
 
     TRACE("%p %p\n", jv, record);
 
@@ -226,15 +122,20 @@ static UINT JOIN_execute( struct tagMSIVIEW *view, MSIRECORD *record )
     if (r != ERROR_SUCCESS)
         return r;
 
-    r = join_load_key_column( jv, jv->left, jv->left_key, &ldata, &lcount );
-    if (r != ERROR_SUCCESS)
-        return r;
-
-    r = join_load_key_column( jv, jv->right, jv->right_key, &rdata, &rcount );
-    if (r != ERROR_SUCCESS)
+    /* get the number of rows in each table */
+    r = jv->left->ops->get_dimensions( jv->left, &jv->left_rows, NULL );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("can't get left table dimensions\n");
         goto end;
+    }
 
-    r = join_match( ldata, lcount, rdata, rcount, &jv->pairs, &jv->pair_count );
+    r = jv->right->ops->get_dimensions( jv->right, &jv->right_rows, NULL );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("can't get right table dimensions\n");
+        goto end;
+    }
 
 end:
     msi_free( ldata );
@@ -272,7 +173,7 @@ static UINT JOIN_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols
         if( !jv->left || !jv->right )
             return ERROR_FUNCTION_FAILED;
 
-        *rows = jv->pair_count;
+        *rows = jv->left_rows * jv->right_rows;
     }
 
     return ERROR_SUCCESS;
@@ -323,9 +224,6 @@ static UINT JOIN_delete( struct tagMSIVIEW *view )
         jv->right->ops->delete( jv->right );
     jv->right = NULL;
 
-    msi_free( jv->pairs );
-    jv->pairs = NULL;
-
     msi_free( jv );
 
     return ERROR_SUCCESS;
@@ -345,8 +243,8 @@ static const MSIVIEWOPS join_ops =
 {
     JOIN_fetch_int,
     JOIN_fetch_stream,
-    JOIN_set_int,
-    JOIN_insert_row,
+    NULL,
+    NULL,
     JOIN_execute,
     JOIN_close,
     JOIN_get_dimensions,
@@ -356,48 +254,8 @@ static const MSIVIEWOPS join_ops =
     JOIN_find_matching_rows
 };
 
-/*
- * join_check_condition
- *
- * This is probably overly strict about what kind of condition we need
- *  for a join query.
- */
-static UINT join_check_condition(MSIJOINVIEW *jv, struct expr *cond)
-{
-    UINT r;
-
-    /* assume that we have  `KeyColumn` = `SubkeyColumn` */
-    if ( cond->type != EXPR_COMPLEX )
-        return ERROR_FUNCTION_FAILED;
-
-    if ( cond->u.expr.op != OP_EQ )
-        return ERROR_FUNCTION_FAILED;
-
-    if ( cond->u.expr.left->type != EXPR_COLUMN )
-        return ERROR_FUNCTION_FAILED;
-
-    if ( cond->u.expr.right->type != EXPR_COLUMN )
-        return ERROR_FUNCTION_FAILED;
-
-    /* make sure both columns exist */
-    r = VIEW_find_column( jv->left, cond->u.expr.left->u.column, &jv->left_key );
-    if (r != ERROR_SUCCESS)
-        return ERROR_FUNCTION_FAILED;
-
-    r = VIEW_find_column( jv->right, cond->u.expr.right->u.column, &jv->right_key );
-    if (r != ERROR_SUCCESS)
-        return ERROR_FUNCTION_FAILED;
-
-    TRACE("left %s (%u) right %s (%u)\n",
-        debugstr_w(cond->u.expr.left->u.column), jv->left_key,
-        debugstr_w(cond->u.expr.right->u.column), jv->right_key);
-
-    return ERROR_SUCCESS;
-}
-
 UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
-                      LPCWSTR left, LPCWSTR right,
-                      struct expr *cond )
+                      LPCWSTR left, LPCWSTR right )
 {
     MSIJOINVIEW *jv = NULL;
     UINT r = ERROR_SUCCESS;
@@ -442,13 +300,6 @@ UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
         goto end;
     }
 
-    r = join_check_condition( jv, cond );
-    if( r != ERROR_SUCCESS )
-    {
-        ERR("can't get join condition\n");
-        goto end;
-    }
-
     *view = &jv->view;
     return ERROR_SUCCESS;
 
index 295ba7b..1bc1aef 100644 (file)
@@ -54,8 +54,8 @@
 58 stdcall MsiGetFeatureStateW(long wstr ptr ptr)
 59 stdcall MsiGetFeatureUsageA(str str ptr ptr)
 60 stdcall MsiGetFeatureUsageW(wstr wstr ptr ptr)
-61 stub MsiGetFeatureValidStatesA
-62 stub MsiGetFeatureValidStatesW
+61 stdcall MsiGetFeatureValidStatesA(long str ptr)
+62 stdcall MsiGetFeatureValidStatesW(long wstr ptr)
 63 stdcall MsiGetLanguage(long)
 64 stdcall MsiGetMode(long long)
 65 stdcall MsiGetProductCodeA(str str)
index ed1d537..d8cd72b 100644 (file)
@@ -18,7 +18,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT
+LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
 
 STRINGTABLE DISCARDABLE
 {
index 336af05..123b1c6 100644 (file)
@@ -18,7 +18,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-LANGUAGE LANG_DUTCH, SUBLANG_DEFAULT
+LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
 
 STRINGTABLE DISCARDABLE
 {
index e779ac1..d19a867 100644 (file)
@@ -5335,21 +5335,21 @@ Index: tokenize.c
 ===================================================================
 --- tokenize.c (revision 23808)
 +++ tokenize.c (working copy)
-@@ -156,7 +156,7 @@
+@@ -87,7 +87,7 @@
+ ** These are the keywords
+ */
  static const Keyword aKeywordTable[] = {
-   { ABORT_W, TK_ABORT },
-   { AFTER_W, TK_AFTER },
 +  /*{ ALTER_W, TK_ALTER },*/
 -  { ALTER_W, TK_ALTER },
-   { ALL_W, TK_ALL },
    { AND_W, TK_AND },
-   { AS_W, TK_AS },
-@@ -247,7 +247,7 @@
+   { BY_W, TK_BY },
+   { CHAR_W, TK_CHAR },
+@@ -118,7 +118,7 @@
+   { SET_W, TK_SET },
    { SHORT_W, TK_SHORT },
-   { STATEMENT_W, TK_STATEMENT },
    { TABLE_W, TK_TABLE },
 +  /*{ TEMPORARY_W, TK_TEMPORARY },*/
 -  { TEMPORARY_W, TK_TEMPORARY },
-   { THEN_W, TK_THEN },
-   { TRANSACTION_W, TK_TRANSACTION },
-   { TRIGGER_W, TK_TRIGGER },
+   { UPDATE_W, TK_UPDATE },
+   { VALUES_W, TK_VALUES },
+   { WHERE_W, TK_WHERE },
index 94edb23..44e9170 100644 (file)
@@ -109,7 +109,7 @@ typedef struct tagMSIRECORD
     MSIFIELD fields[1]; /* nb. array size is count+1 */
 } MSIRECORD;
 
-typedef void *MSIITERHANDLE;
+typedef const struct tagMSICOLUMNHASHENTRY *MSIITERHANDLE;
 
 typedef struct tagMSIVIEWOPS
 {
@@ -133,11 +133,11 @@ typedef struct tagMSIVIEWOPS
     UINT (*fetch_stream)( struct tagMSIVIEW *, UINT row, UINT col, IStream **stm );
 
     /*
-     * get_int - sets one integer at {row,col} in the table
+     * set_row - sets values in a row as specified by mask
      *
      *  Similar semantics to fetch_int
      */
-    UINT (*set_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT val );
+    UINT (*set_row)( struct tagMSIVIEW *, UINT row, MSIRECORD *rec, UINT mask );
 
     /*
      * Inserts a new row into the database from the records contents
@@ -228,6 +228,7 @@ typedef struct tagMSIPACKAGE
 
     struct list RunningActions;
 
+    LPWSTR BaseURL;
     LPWSTR PackagePath;
     LPWSTR ProductCode;
 
@@ -256,7 +257,7 @@ typedef struct tagMSIPREVIEW
 typedef struct tagMSISUMMARYINFO
 {
     MSIOBJECTHDR hdr;
-    MSIDATABASE *db;
+    IStorage *storage;
     DWORD update_count;
     PROPVARIANT property[MSI_MAX_PROPS];
 } MSISUMMARYINFO;
@@ -563,6 +564,7 @@ extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname,
 extern UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg );
 extern UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
                  LPCWSTR szTransformFile, int iErrorCond );
+extern void append_storage_to_db( MSIDATABASE *db, IStorage *stg );
 
 /* action internals */
 extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR );
@@ -619,7 +621,7 @@ extern UINT VIEW_find_column( MSIVIEW *, LPCWSTR, UINT * );
 extern UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel );
 
 /* package internals */
-extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE * );
+extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *, LPWSTR );
 extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE ** );
 extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
 extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
@@ -680,14 +682,16 @@ extern UINT msi_dialog_reset( msi_dialog *dialog );
 extern UINT msi_dialog_directorylist_up( msi_dialog *dialog );
 extern msi_dialog *msi_dialog_get_parent( msi_dialog *dialog );
 extern LPWSTR msi_dialog_get_name( msi_dialog *dialog );
+extern UINT msi_spawn_error_dialog( MSIPACKAGE*, LPWSTR, LPWSTR );
 
 /* preview */
 extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * );
 extern UINT MSI_PreviewDialogW( MSIPREVIEW *, LPCWSTR );
 
 /* summary information */
-extern MSISUMMARYINFO *MSI_GetSummaryInformationW( MSIDATABASE *db, UINT uiUpdateCount );
+extern MSISUMMARYINFO *MSI_GetSummaryInformationW( IStorage *stg, UINT uiUpdateCount );
 extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty );
+extern LPWSTR msi_get_suminfo_product( IStorage *stg );
 
 /* undocumented functions */
 UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD );
@@ -712,6 +716,18 @@ extern UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action);
 extern void ACTION_FinishCustomActions( MSIPACKAGE* package);
 extern UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL execute);
 
+static inline void msi_feature_set_state( MSIFEATURE *feature, INSTALLSTATE state )
+{
+    feature->ActionRequest = state;
+    feature->Action = state;
+}
+
+static inline void msi_component_set_state( MSICOMPONENT *comp, INSTALLSTATE state )
+{
+    comp->ActionRequest = state;
+    comp->Action = state;
+}
+
 /* actions in other modules */
 extern UINT ACTION_AppSearch(MSIPACKAGE *package);
 extern UINT ACTION_FindRelatedProducts(MSIPACKAGE *package);
@@ -737,6 +753,7 @@ extern MSIFILE *get_loaded_file( MSIPACKAGE* package, LPCWSTR file );
 extern MSIFOLDER *get_loaded_folder( MSIPACKAGE *package, LPCWSTR dir );
 extern int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
 extern UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action);
+extern void msi_free_action_script(MSIPACKAGE *package, UINT script);
 extern LPWSTR build_icon_path(MSIPACKAGE *, LPCWSTR);
 extern LPWSTR build_directory_name(DWORD , ...);
 extern BOOL create_full_pathW(const WCHAR *path);
index 3aaad69..1455c6d 100644 (file)
@@ -428,7 +428,7 @@ static UINT msi_get_word_count( MSIPACKAGE *package )
     return word_count;
 }
 
-MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
+MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPWSTR base_url )
 {
     static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
     static const WCHAR szpi[] = {'%','i',0};
@@ -466,6 +466,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
 
         package->WordCount = msi_get_word_count( package );
         package->PackagePath = strdupW( db->path );
+        package->BaseURL = strdupW( base_url );
 
         /* OK, here is where we do a slew of things to the database to 
          * prep for all that is to come as a package */
@@ -550,6 +551,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     MSIDATABASE *db = NULL;
     MSIPACKAGE *package;
     MSIHANDLE handle;
+    LPWSTR ptr, base_url = NULL;
     UINT r;
 
     static const WCHAR OriginalDatabase[] =
@@ -571,7 +573,16 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
         LPCWSTR file;
 
         if ( UrlIsW( szPackage, URLIS_URL ) )
+        {
             file = msi_download_file( szPackage, temppath );
+
+            base_url = strdupW( szPackage );
+            if ( !base_url )
+                return ERROR_OUTOFMEMORY;
+
+            ptr = strrchrW( base_url, '/' );
+            if (ptr) *(ptr + 1) = '\0';
+        }
         else
             file = copy_package_to_temp( szPackage, temppath );
 
@@ -589,7 +600,8 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
         }
     }
 
-    package = MSI_CreatePackage( db );
+    package = MSI_CreatePackage( db, base_url );
+    msi_free( base_url );
     msiobj_release( &db->hdr );
     if( !package )
         return ERROR_FUNCTION_FAILED;
index 4f4cc5c..ddf0a7a 100644 (file)
@@ -43,7 +43,7 @@ MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE *db )
     MSIPREVIEW *preview = NULL;
     MSIPACKAGE *package;
 
-    package = MSI_CreatePackage( db );
+    package = MSI_CreatePackage( db, NULL );
     if( package )
     {
         preview = alloc_msiobject( MSIHANDLETYPE_PREVIEW, sizeof (MSIPREVIEW),
index 16aeb66..86773ad 100644 (file)
@@ -54,6 +54,7 @@
 #define EXPR_WILDCARD 9
 #define EXPR_COL_NUMBER_STRING 10
 #define EXPR_COL_NUMBER32 11
+#define EXPR_UNARY    12
 
 struct sql_str {
     LPCWSTR data;
@@ -118,11 +119,12 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table,
 UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
 
 UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
-                      LPCWSTR left, LPCWSTR right,
-                      struct expr *cond );
+                      LPCWSTR left, LPCWSTR right );
 
 UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, int hold );
 
 int sqliteGetToken(const WCHAR *z, int *tokenType);
 
+MSIRECORD *msi_query_merge_record( UINT fields, column_info *vl, MSIRECORD *rec );
+
 #endif /* __WINE_MSI_QUERY_H */
index 6ea57b4..56f694e 100644 (file)
@@ -619,13 +619,8 @@ UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
     len = (p - &szDescriptor[20]);
     if( len > MAX_FEATURE_CHARS )
         return ERROR_INVALID_PARAMETER;
-    if (szFeature)
-    {
-        memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
-        szFeature[len] = 0;
-    }
 
-    TRACE("feature %s\n", debugstr_w( &szDescriptor[20] ));
+    TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
 
     r = decode_base85_guid( p+1, &component );
     if( !r )
@@ -637,6 +632,11 @@ UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
         StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
     if (szComponent)
         StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
+    if (szFeature)
+    {
+        memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
+        szFeature[len] = 0;
+    }
     len = ( &p[21] - szDescriptor );
 
     TRACE("length = %d\n", len);
@@ -670,12 +670,15 @@ UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
 
     r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
 
-    WideCharToMultiByte( CP_ACP, 0, p, MAX_FEATURE_CHARS+1,
-                         szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
-    WideCharToMultiByte( CP_ACP, 0, f, MAX_FEATURE_CHARS+1,
-                         szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
-    WideCharToMultiByte( CP_ACP, 0, c, MAX_FEATURE_CHARS+1,
-                         szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
+    if (r == ERROR_SUCCESS)
+    {
+        WideCharToMultiByte( CP_ACP, 0, p, -1,
+                             szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
+        WideCharToMultiByte( CP_ACP, 0, f, -1,
+                             szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
+        WideCharToMultiByte( CP_ACP, 0, c, -1,
+                             szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
+    }
 
     msi_free( str );
 
index c961130..60bb390 100644 (file)
@@ -82,21 +82,46 @@ static UINT SELECT_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IS
     return sv->table->ops->fetch_stream( sv->table, row, col, stm );
 }
 
-static UINT SELECT_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
+static UINT SELECT_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
 {
     MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+    UINT i, expanded_mask = 0, r = ERROR_SUCCESS, col_count = 0;
+    MSIRECORD *expanded;
 
-    TRACE("%p %d %d %04x\n", sv, row, col, val );
+    TRACE("%p %d %p %08x\n", sv, row, rec, mask );
 
-    if( !sv->table )
+    if ( !sv->table )
          return ERROR_FUNCTION_FAILED;
 
-    if( (col==0) || (col>sv->num_cols) )
-         return ERROR_FUNCTION_FAILED;
+    /* test if any of the mask bits are invalid */
+    if ( mask >= (1<<sv->num_cols) )
+        return ERROR_INVALID_PARAMETER;
 
-    col = sv->cols[ col - 1 ];
+    /* find the number of columns in the table below */
+    r = sv->table->ops->get_dimensions( sv->table, NULL, &col_count );
+    if( r )
+        return r;
+
+    /* expand the record to the right size for the underlying table */
+    expanded = MSI_CreateRecord( col_count );
+    if ( !expanded )
+        return ERROR_FUNCTION_FAILED;
 
-    return sv->table->ops->set_int( sv->table, row, col, val );
+    /* move the right fields across */
+    for ( i=0; i<sv->num_cols; i++ )
+    {
+        r = MSI_RecordCopyField( rec, i+1, expanded, sv->cols[ i ] );
+        if (r != ERROR_SUCCESS)
+            break;
+        expanded_mask |= (1<<(sv->cols[i]-1));
+    }
+
+    /* set the row in the underlying table */
+    if (r == ERROR_SUCCESS)
+        r = sv->table->ops->set_row( sv->table, row, expanded, expanded_mask );
+
+    msiobj_release( &expanded->hdr );
+    return r;
 }
 
 static UINT SELECT_insert_row( struct tagMSIVIEW *view, MSIRECORD *record )
@@ -240,7 +265,7 @@ static const MSIVIEWOPS select_ops =
 {
     SELECT_fetch_int,
     SELECT_fetch_stream,
-    SELECT_set_int,
+    SELECT_set_row,
     SELECT_insert_row,
     SELECT_execute,
     SELECT_close,
index 98796a2..3b18dc6 100644 (file)
@@ -515,6 +515,7 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
         /* found the source */
         if (dwIndex > 0 && current_index != dwIndex)
             FIXME("Need to reorder the sources!\n");
+        msi_free( source_struct.path );
     }
     else
     {
index f464395..afca69a 100644 (file)
@@ -1,7 +1,7 @@
-/* A Bison parser, made by GNU Bison 1.875c.  */
+/* A Bison parser, made by GNU Bison 2.1.  */
 
 /* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -15,8 +15,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 /* As a special exception, when this file is copied by Bison into a
    Bison output file, you may use that output file without restriction.
@@ -36,6 +36,9 @@
 /* Identify Bison output.  */
 #define YYBISON 1
 
+/* Bison version.  */
+#define YYBISON_VERSION "2.1"
+
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
 
@@ -45,8 +48,7 @@
 /* Using locations.  */
 #define YYLSP_NEEDED 0
 
-/* If NAME_PREFIX is specified substitute the variables and functions
-   names.  */
+/* Substitute the variable and function names.  */
 #define yyparse SQL_parse
 #define yylex   SQL_lex
 #define yyerror SQL_error
    /* Put the tokens into the symbol table, so that GDB and other debuggers
       know about them.  */
    enum yytokentype {
-     TK_ABORT = 258,
-     TK_AFTER = 259,
-     TK_AGG_FUNCTION = 260,
-     TK_ALL = 261,
-     TK_AND = 262,
-     TK_AS = 263,
-     TK_ASC = 264,
-     TK_BEFORE = 265,
-     TK_BEGIN = 266,
-     TK_BETWEEN = 267,
-     TK_BITAND = 268,
-     TK_BITNOT = 269,
-     TK_BITOR = 270,
-     TK_BY = 271,
-     TK_CASCADE = 272,
-     TK_CASE = 273,
-     TK_CHAR = 274,
-     TK_CHECK = 275,
-     TK_CLUSTER = 276,
-     TK_COLLATE = 277,
-     TK_COLUMN = 278,
-     TK_COMMA = 279,
-     TK_COMMENT = 280,
-     TK_COMMIT = 281,
-     TK_CONCAT = 282,
-     TK_CONFLICT = 283,
-     TK_CONSTRAINT = 284,
-     TK_COPY = 285,
-     TK_CREATE = 286,
-     TK_DEFAULT = 287,
-     TK_DEFERRABLE = 288,
-     TK_DEFERRED = 289,
-     TK_DELETE = 290,
-     TK_DELIMITERS = 291,
-     TK_DESC = 292,
-     TK_DISTINCT = 293,
-     TK_DOT = 294,
-     TK_DROP = 295,
-     TK_EACH = 296,
-     TK_ELSE = 297,
-     TK_END = 298,
-     TK_END_OF_FILE = 299,
-     TK_EQ = 300,
-     TK_EXCEPT = 301,
-     TK_EXPLAIN = 302,
-     TK_FAIL = 303,
-     TK_FLOAT = 304,
-     TK_FOR = 305,
-     TK_FOREIGN = 306,
-     TK_FROM = 307,
-     TK_FUNCTION = 308,
-     TK_GE = 309,
-     TK_GLOB = 310,
-     TK_GROUP = 311,
-     TK_GT = 312,
-     TK_HAVING = 313,
-     TK_HOLD = 314,
-     TK_IGNORE = 315,
-     TK_ILLEGAL = 316,
-     TK_IMMEDIATE = 317,
-     TK_IN = 318,
-     TK_INDEX = 319,
-     TK_INITIALLY = 320,
-     TK_ID = 321,
-     TK_INSERT = 322,
-     TK_INSTEAD = 323,
-     TK_INT = 324,
-     TK_INTEGER = 325,
-     TK_INTERSECT = 326,
-     TK_INTO = 327,
-     TK_IS = 328,
-     TK_ISNULL = 329,
-     TK_JOIN = 330,
-     TK_JOIN_KW = 331,
-     TK_KEY = 332,
-     TK_LE = 333,
-     TK_LIKE = 334,
-     TK_LIMIT = 335,
-     TK_LONG = 336,
-     TK_LONGCHAR = 337,
-     TK_LP = 338,
-     TK_LSHIFT = 339,
-     TK_LT = 340,
-     TK_LOCALIZABLE = 341,
-     TK_MATCH = 342,
-     TK_MINUS = 343,
-     TK_NE = 344,
-     TK_NOT = 345,
-     TK_NOTNULL = 346,
-     TK_NULL = 347,
-     TK_OBJECT = 348,
-     TK_OF = 349,
-     TK_OFFSET = 350,
-     TK_ON = 351,
-     TK_OR = 352,
-     TK_ORACLE_OUTER_JOIN = 353,
-     TK_ORDER = 354,
-     TK_PLUS = 355,
-     TK_PRAGMA = 356,
-     TK_PRIMARY = 357,
-     TK_RAISE = 358,
-     TK_REFERENCES = 359,
-     TK_REM = 360,
-     TK_REPLACE = 361,
-     TK_RESTRICT = 362,
-     TK_ROLLBACK = 363,
-     TK_ROW = 364,
-     TK_RP = 365,
-     TK_RSHIFT = 366,
-     TK_SELECT = 367,
-     TK_SEMI = 368,
-     TK_SET = 369,
-     TK_SHORT = 370,
-     TK_SLASH = 371,
-     TK_SPACE = 372,
-     TK_STAR = 373,
-     TK_STATEMENT = 374,
-     TK_STRING = 375,
-     TK_TABLE = 376,
-     TK_TEMP = 377,
-     TK_THEN = 378,
-     TK_TRANSACTION = 379,
-     TK_TRIGGER = 380,
-     TK_UMINUS = 381,
-     TK_UNCLOSED_STRING = 382,
-     TK_UNION = 383,
-     TK_UNIQUE = 384,
-     TK_UPDATE = 385,
-     TK_UPLUS = 386,
-     TK_USING = 387,
-     TK_VACUUM = 388,
-     TK_VALUES = 389,
-     TK_VIEW = 390,
-     TK_WHEN = 391,
-     TK_WHERE = 392,
-     TK_WILDCARD = 393,
-     COLUMN = 395,
-     FUNCTION = 396,
-     COMMENT = 397,
-     UNCLOSED_STRING = 398,
-     SPACE = 399,
-     ILLEGAL = 400,
-     END_OF_FILE = 401
+     TK_ALTER = 258,
+     TK_AND = 259,
+     TK_BY = 260,
+     TK_CHAR = 261,
+     TK_COMMA = 262,
+     TK_CREATE = 263,
+     TK_DELETE = 264,
+     TK_DISTINCT = 265,
+     TK_DOT = 266,
+     TK_EQ = 267,
+     TK_FREE = 268,
+     TK_FROM = 269,
+     TK_GE = 270,
+     TK_GT = 271,
+     TK_HOLD = 272,
+     TK_ID = 273,
+     TK_ILLEGAL = 274,
+     TK_INSERT = 275,
+     TK_INT = 276,
+     TK_INTEGER = 277,
+     TK_INTO = 278,
+     TK_IS = 279,
+     TK_KEY = 280,
+     TK_LE = 281,
+     TK_LONG = 282,
+     TK_LONGCHAR = 283,
+     TK_LP = 284,
+     TK_LT = 285,
+     TK_LOCALIZABLE = 286,
+     TK_MINUS = 287,
+     TK_NE = 288,
+     TK_NOT = 289,
+     TK_NULL = 290,
+     TK_OBJECT = 291,
+     TK_OR = 292,
+     TK_ORDER = 293,
+     TK_PRIMARY = 294,
+     TK_RP = 295,
+     TK_SELECT = 296,
+     TK_SET = 297,
+     TK_SHORT = 298,
+     TK_SPACE = 299,
+     TK_STAR = 300,
+     TK_STRING = 301,
+     TK_TABLE = 302,
+     TK_TEMPORARY = 303,
+     TK_UPDATE = 304,
+     TK_VALUES = 305,
+     TK_WHERE = 306,
+     TK_WILDCARD = 307,
+     COLUMN = 309,
+     FUNCTION = 310,
+     COMMENT = 311,
+     UNCLOSED_STRING = 312,
+     SPACE = 313,
+     ILLEGAL = 314,
+     END_OF_FILE = 315,
+     TK_LIKE = 316,
+     TK_NEGATION = 317
    };
 #endif
-#define TK_ABORT 258
-#define TK_AFTER 259
-#define TK_AGG_FUNCTION 260
-#define TK_ALL 261
-#define TK_AND 262
-#define TK_AS 263
-#define TK_ASC 264
-#define TK_BEFORE 265
-#define TK_BEGIN 266
-#define TK_BETWEEN 267
-#define TK_BITAND 268
-#define TK_BITNOT 269
-#define TK_BITOR 270
-#define TK_BY 271
-#define TK_CASCADE 272
-#define TK_CASE 273
-#define TK_CHAR 274
-#define TK_CHECK 275
-#define TK_CLUSTER 276
-#define TK_COLLATE 277
-#define TK_COLUMN 278
-#define TK_COMMA 279
-#define TK_COMMENT 280
-#define TK_COMMIT 281
-#define TK_CONCAT 282
-#define TK_CONFLICT 283
-#define TK_CONSTRAINT 284
-#define TK_COPY 285
-#define TK_CREATE 286
-#define TK_DEFAULT 287
-#define TK_DEFERRABLE 288
-#define TK_DEFERRED 289
-#define TK_DELETE 290
-#define TK_DELIMITERS 291
-#define TK_DESC 292
-#define TK_DISTINCT 293
-#define TK_DOT 294
-#define TK_DROP 295
-#define TK_EACH 296
-#define TK_ELSE 297
-#define TK_END 298
-#define TK_END_OF_FILE 299
-#define TK_EQ 300
-#define TK_EXCEPT 301
-#define TK_EXPLAIN 302
-#define TK_FAIL 303
-#define TK_FLOAT 304
-#define TK_FOR 305
-#define TK_FOREIGN 306
-#define TK_FROM 307
-#define TK_FUNCTION 308
-#define TK_GE 309
-#define TK_GLOB 310
-#define TK_GROUP 311
-#define TK_GT 312
-#define TK_HAVING 313
-#define TK_HOLD 314
-#define TK_IGNORE 315
-#define TK_ILLEGAL 316
-#define TK_IMMEDIATE 317
-#define TK_IN 318
-#define TK_INDEX 319
-#define TK_INITIALLY 320
-#define TK_ID 321
-#define TK_INSERT 322
-#define TK_INSTEAD 323
-#define TK_INT 324
-#define TK_INTEGER 325
-#define TK_INTERSECT 326
-#define TK_INTO 327
-#define TK_IS 328
-#define TK_ISNULL 329
-#define TK_JOIN 330
-#define TK_JOIN_KW 331
-#define TK_KEY 332
-#define TK_LE 333
-#define TK_LIKE 334
-#define TK_LIMIT 335
-#define TK_LONG 336
-#define TK_LONGCHAR 337
-#define TK_LP 338
-#define TK_LSHIFT 339
-#define TK_LT 340
-#define TK_LOCALIZABLE 341
-#define TK_MATCH 342
-#define TK_MINUS 343
-#define TK_NE 344
-#define TK_NOT 345
-#define TK_NOTNULL 346
-#define TK_NULL 347
-#define TK_OBJECT 348
-#define TK_OF 349
-#define TK_OFFSET 350
-#define TK_ON 351
-#define TK_OR 352
-#define TK_ORACLE_OUTER_JOIN 353
-#define TK_ORDER 354
-#define TK_PLUS 355
-#define TK_PRAGMA 356
-#define TK_PRIMARY 357
-#define TK_RAISE 358
-#define TK_REFERENCES 359
-#define TK_REM 360
-#define TK_REPLACE 361
-#define TK_RESTRICT 362
-#define TK_ROLLBACK 363
-#define TK_ROW 364
-#define TK_RP 365
-#define TK_RSHIFT 366
-#define TK_SELECT 367
-#define TK_SEMI 368
-#define TK_SET 369
-#define TK_SHORT 370
-#define TK_SLASH 371
-#define TK_SPACE 372
-#define TK_STAR 373
-#define TK_STATEMENT 374
-#define TK_STRING 375
-#define TK_TABLE 376
-#define TK_TEMP 377
-#define TK_THEN 378
-#define TK_TRANSACTION 379
-#define TK_TRIGGER 380
-#define TK_UMINUS 381
-#define TK_UNCLOSED_STRING 382
-#define TK_UNION 383
-#define TK_UNIQUE 384
-#define TK_UPDATE 385
-#define TK_UPLUS 386
-#define TK_USING 387
-#define TK_VACUUM 388
-#define TK_VALUES 389
-#define TK_VIEW 390
-#define TK_WHEN 391
-#define TK_WHERE 392
-#define TK_WILDCARD 393
-#define COLUMN 395
-#define FUNCTION 396
-#define COMMENT 397
-#define UNCLOSED_STRING 398
-#define SPACE 399
-#define ILLEGAL 400
-#define END_OF_FILE 401
+/* Tokens.  */
+#define TK_ALTER 258
+#define TK_AND 259
+#define TK_BY 260
+#define TK_CHAR 261
+#define TK_COMMA 262
+#define TK_CREATE 263
+#define TK_DELETE 264
+#define TK_DISTINCT 265
+#define TK_DOT 266
+#define TK_EQ 267
+#define TK_FREE 268
+#define TK_FROM 269
+#define TK_GE 270
+#define TK_GT 271
+#define TK_HOLD 272
+#define TK_ID 273
+#define TK_ILLEGAL 274
+#define TK_INSERT 275
+#define TK_INT 276
+#define TK_INTEGER 277
+#define TK_INTO 278
+#define TK_IS 279
+#define TK_KEY 280
+#define TK_LE 281
+#define TK_LONG 282
+#define TK_LONGCHAR 283
+#define TK_LP 284
+#define TK_LT 285
+#define TK_LOCALIZABLE 286
+#define TK_MINUS 287
+#define TK_NE 288
+#define TK_NOT 289
+#define TK_NULL 290
+#define TK_OBJECT 291
+#define TK_OR 292
+#define TK_ORDER 293
+#define TK_PRIMARY 294
+#define TK_RP 295
+#define TK_SELECT 296
+#define TK_SET 297
+#define TK_SHORT 298
+#define TK_SPACE 299
+#define TK_STAR 300
+#define TK_STRING 301
+#define TK_TABLE 302
+#define TK_TEMPORARY 303
+#define TK_UPDATE 304
+#define TK_VALUES 305
+#define TK_WHERE 306
+#define TK_WILDCARD 307
+#define COLUMN 309
+#define FUNCTION 310
+#define COMMENT 311
+#define UNCLOSED_STRING 312
+#define SPACE 313
+#define ILLEGAL 314
+#define END_OF_FILE 315
+#define TK_LIKE 316
+#define TK_NEGATION 317
 
 
 
 
 /* Copy the first part of user declarations.  */
-#line 1 "./sql.y"
+#line 1 "sql.y"
 
 
 /*
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 
 #define YYLEX_PARAM info
 #define YYPARSE_PARAM info
 
-extern int SQL_error(const char *str);
+static int SQL_error(const char *str);
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
@@ -417,6 +252,7 @@ static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR colu
 static BOOL SQL_MarkPrimaryKeys( column_info *cols, column_info *keys);
 
 static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r );
+static struct expr * EXPR_unary( void *info, struct expr *l, UINT op );
 static struct expr * EXPR_column( void *info, column_info *column );
 static struct expr * EXPR_ival( void *info, int val );
 static struct expr * EXPR_sval( void *info, struct sql_str * );
@@ -437,8 +273,13 @@ static struct expr * EXPR_wildcard( void *info );
 # define YYERROR_VERBOSE 0
 #endif
 
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
 #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
-#line 72 "./sql.y"
+#line 73 "sql.y"
 typedef union YYSTYPE {
     struct sql_str str;
     LPWSTR string;
@@ -448,8 +289,8 @@ typedef union YYSTYPE {
     USHORT column_type;
     int integer;
 } YYSTYPE;
-/* Line 191 of yacc.c.  */
-#line 453 "sql.tab.c"
+/* Line 196 of yacc.c.  */
+#line 294 "sql.tab.c"
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 # define YYSTYPE_IS_TRIVIAL 1
@@ -460,30 +301,49 @@ typedef union YYSTYPE {
 /* Copy the second part of user declarations.  */
 
 
-/* Line 214 of yacc.c.  */
-#line 465 "sql.tab.c"
+/* Line 219 of yacc.c.  */
+#line 306 "sql.tab.c"
 
-#if ! defined (yyoverflow) || YYERROR_VERBOSE
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T) && (defined (__STDC__) || defined (__cplusplus))
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
 
-# ifndef YYFREE
-#  define YYFREE free
+#ifndef YY_
+# if YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
 # endif
-# ifndef YYMALLOC
-#  define YYMALLOC malloc
+# ifndef YY_
+#  define YY_(msgid) msgid
 # endif
+#endif
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
 # ifdef YYSTACK_USE_ALLOCA
 #  if YYSTACK_USE_ALLOCA
-#   define YYSTACK_ALLOC alloca
-#  endif
-# else
-#  if defined (alloca) || defined (_ALLOCA_H)
-#   define YYSTACK_ALLOC alloca
-#  else
 #   ifdef __GNUC__
 #    define YYSTACK_ALLOC __builtin_alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if defined (__STDC__) || defined (__cplusplus)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     define YYINCLUDED_STDLIB_H
+#    endif
 #   endif
 #  endif
 # endif
@@ -491,13 +351,39 @@ typedef union YYSTYPE {
 # ifdef YYSTACK_ALLOC
    /* Pacify GCC's `empty if-body' warning. */
 #  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
-# else
-#  if defined (__STDC__) || defined (__cplusplus)
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   define YYSIZE_T size_t
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2005 */
 #  endif
+# else
 #  define YYSTACK_ALLOC YYMALLOC
 #  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM ((YYSIZE_T) -1)
+#  endif
+#  ifdef __cplusplus
+extern "C" {
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if (! defined (malloc) && ! defined (YYINCLUDED_STDLIB_H) \
+       && (defined (__STDC__) || defined (__cplusplus)))
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if (! defined (free) && ! defined (YYINCLUDED_STDLIB_H) \
+       && (defined (__STDC__) || defined (__cplusplus)))
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifdef __cplusplus
+}
+#  endif
 # endif
 #endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
 
@@ -509,7 +395,7 @@ typedef union YYSTYPE {
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  short yyss;
+  short int yyss;
   YYSTYPE yyvs;
   };
 
@@ -519,7 +405,7 @@ union yyalloc
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
 # define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (short) + sizeof (YYSTYPE))                                \
+     ((N) * (sizeof (short int) + sizeof (YYSTYPE))                    \
       + YYSTACK_GAP_MAXIMUM)
 
 /* Copy COUNT objects from FROM to TO.  The source and destination do
@@ -532,7 +418,7 @@ union yyalloc
 #   define YYCOPY(To, From, Count)             \
       do                                       \
        {                                       \
-         register YYSIZE_T yyi;                \
+         YYSIZE_T yyi;                         \
          for (yyi = 0; yyi < (Count); yyi++)   \
            (To)[yyi] = (From)[yyi];            \
        }                                       \
@@ -561,28 +447,28 @@ union yyalloc
 #if defined (__STDC__) || defined (__cplusplus)
    typedef signed char yysigned_char;
 #else
-   typedef short yysigned_char;
+   typedef short int yysigned_char;
 #endif
 
 /* YYFINAL -- State number of the termination state. */
-#define YYFINAL  29
+#define YYFINAL  32
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   124
+#define YYLAST   133
 
 /* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS  147
+#define YYNTOKENS  63
 /* YYNNTS -- Number of nonterminals. */
-#define YYNNTS  31
+#define YYNNTS  33
 /* YYNRULES -- Number of rules. */
-#define YYNRULES  69
+#define YYNRULES  75
 /* YYNRULES -- Number of states. */
-#define YYNSTATES  127
+#define YYNSTATES  136
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   401
+#define YYMAXUTOK   317
 
-#define YYTRANSLATE(YYX)                                               \
+#define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
 
 /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
@@ -619,16 +505,7 @@ static const unsigned char yytranslate[] =
       25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
       35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
       45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-      55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
-      65,    66,    67,    68,    69,    70,    71,    72,    73,    74,
-      75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
-      85,    86,    87,    88,    89,    90,    91,    92,    93,    94,
-      95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
-     105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
-     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
-     125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
-     135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
-     145,   146
+      55,    56,    57,    58,    59,    60,    61,    62
 };
 
 #if YYDEBUG
@@ -636,102 +513,90 @@ static const unsigned char yytranslate[] =
    YYRHS.  */
 static const unsigned char yyprhs[] =
 {
-       0,     0,     3,     5,     7,     9,    11,    13,    15,    26,
-      38,    45,    53,    60,    63,    68,    72,    74,    77,    79,
-      82,    84,    88,    90,    95,    97,    99,   101,   103,   105,
-     107,   112,   114,   117,   121,   124,   126,   130,   132,   134,
-     138,   141,   145,   149,   153,   157,   161,   165,   169,   173,
-     177,   181,   185,   190,   192,   194,   196,   200,   202,   206,
-     210,   212,   215,   217,   219,   221,   225,   227,   229,   231
+       0,     0,     3,     5,     7,     9,    11,    13,    15,    17,
+      28,    40,    47,    55,    62,    67,    70,    75,    77,    79,
+      84,    88,    90,    93,    95,    98,   101,   103,   107,   109,
+     114,   116,   118,   120,   122,   124,   126,   131,   133,   136,
+     140,   143,   145,   149,   151,   153,   157,   160,   165,   169,
+     173,   177,   181,   185,   189,   193,   197,   201,   205,   210,
+     212,   214,   216,   220,   222,   226,   230,   232,   235,   237,
+     239,   241,   245,   247,   249,   251
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const short yyrhs[] =
+static const yysigned_char yyrhs[] =
 {
-     148,     0,    -1,   149,    -1,   161,    -1,   151,    -1,   150,
-      -1,   152,    -1,   153,    -1,    67,    72,   175,    83,   164,
-     110,   134,    83,   169,   110,    -1,    67,    72,   175,    83,
-     164,   110,   134,    83,   169,   110,   122,    -1,    31,   121,
-     175,    83,   154,   110,    -1,    31,   121,   175,    83,   154,
-     110,    59,    -1,   130,   175,   114,   170,   137,   167,    -1,
-      35,   165,    -1,   155,   102,    77,   164,    -1,   155,    24,
-     156,    -1,   156,    -1,   174,   157,    -1,   158,    -1,   158,
-      86,    -1,   159,    -1,   159,    90,    92,    -1,    19,    -1,
-      19,    83,   160,   110,    -1,    82,    -1,   115,    -1,    69,
-      -1,    81,    -1,    93,    -1,   177,    -1,   162,    99,    16,
-     164,    -1,   162,    -1,   112,   163,    -1,   112,    38,   163,
-      -1,   164,   165,    -1,   174,    -1,   174,    24,   164,    -1,
-     118,    -1,   166,    -1,   166,   137,   167,    -1,    52,   175,
-      -1,    83,   167,   110,    -1,   173,    45,   173,    -1,   167,
-       7,   167,    -1,   167,    97,   167,    -1,   173,    45,   168,
-      -1,   173,    57,   168,    -1,   173,    85,   168,    -1,   173,
-      78,   168,    -1,   173,    54,   168,    -1,   173,    89,   168,
-      -1,   173,    73,    92,    -1,   173,    73,    90,    92,    -1,
-     173,    -1,   172,    -1,   172,    -1,   172,    24,   169,    -1,
-     171,    -1,   171,    24,   170,    -1,   174,    45,   172,    -1,
-     177,    -1,    88,   177,    -1,   120,    -1,   138,    -1,   174,
-      -1,   175,    39,   176,    -1,   176,    -1,   176,    -1,    66,
-      -1,    70,    -1
+      64,     0,    -1,    65,    -1,    79,    -1,    67,    -1,    66,
+      -1,    68,    -1,    69,    -1,    70,    -1,    20,    23,    93,
+      29,    82,    40,    50,    29,    87,    40,    -1,    20,    23,
+      93,    29,    82,    40,    50,    29,    87,    40,    48,    -1,
+       8,    47,    93,    29,    72,    40,    -1,     8,    47,    93,
+      29,    72,    40,    17,    -1,    49,    93,    42,    88,    51,
+      85,    -1,    49,    93,    42,    88,    -1,     9,    83,    -1,
+       3,    47,    93,    71,    -1,    17,    -1,    13,    -1,    73,
+      39,    25,    82,    -1,    73,     7,    74,    -1,    74,    -1,
+      92,    75,    -1,    76,    -1,    76,    31,    -1,    76,    48,
+      -1,    77,    -1,    77,    34,    35,    -1,     6,    -1,     6,
+      29,    78,    40,    -1,    28,    -1,    43,    -1,    21,    -1,
+      27,    -1,    36,    -1,    95,    -1,    80,    38,     5,    82,
+      -1,    80,    -1,    41,    81,    -1,    41,    10,    81,    -1,
+      82,    83,    -1,    92,    -1,    92,     7,    82,    -1,    45,
+      -1,    84,    -1,    84,    51,    85,    -1,    14,    93,    -1,
+      14,    93,     7,    93,    -1,    29,    85,    40,    -1,    85,
+       4,    85,    -1,    85,    37,    85,    -1,    91,    12,    86,
+      -1,    91,    16,    86,    -1,    91,    30,    86,    -1,    91,
+      26,    86,    -1,    91,    15,    86,    -1,    91,    33,    86,
+      -1,    91,    24,    35,    -1,    91,    24,    34,    35,    -1,
+      91,    -1,    90,    -1,    90,    -1,    90,     7,    87,    -1,
+      89,    -1,    89,     7,    88,    -1,    92,    12,    90,    -1,
+      95,    -1,    32,    95,    -1,    46,    -1,    52,    -1,    92,
+      -1,    93,    11,    94,    -1,    94,    -1,    94,    -1,    18,
+      -1,    22,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const unsigned short yyrline[] =
+static const unsigned short int yyrline[] =
 {
-       0,   138,   138,   146,   147,   148,   149,   150,   154,   165,
-     178,   190,   205,   218,   231,   241,   251,   258,   266,   270,
-     277,   281,   288,   292,   296,   300,   304,   308,   312,   319,
-     328,   340,   344,   348,   364,   385,   386,   390,   397,   398,
-     414,   427,   433,   439,   445,   451,   457,   463,   469,   475,
-     481,   487,   493,   502,   503,   507,   514,   525,   526,   534,
-     542,   548,   554,   560,   569,   578,   584,   593,   600,   609
+       0,   123,   123,   131,   132,   133,   134,   135,   136,   140,
+     151,   164,   176,   191,   201,   214,   227,   240,   244,   251,
+     261,   271,   278,   286,   290,   294,   301,   305,   312,   316,
+     320,   324,   328,   332,   336,   343,   352,   364,   368,   372,
+     388,   409,   410,   414,   421,   422,   438,   448,   461,   467,
+     473,   479,   485,   491,   497,   503,   509,   515,   521,   530,
+     531,   535,   542,   553,   554,   562,   570,   576,   582,   588,
+     597,   606,   612,   621,   628,   637
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE
-/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals. */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "TK_ABORT", "TK_AFTER",
-  "TK_AGG_FUNCTION", "TK_ALL", "TK_AND", "TK_AS", "TK_ASC", "TK_BEFORE",
-  "TK_BEGIN", "TK_BETWEEN", "TK_BITAND", "TK_BITNOT", "TK_BITOR", "TK_BY",
-  "TK_CASCADE", "TK_CASE", "TK_CHAR", "TK_CHECK", "TK_CLUSTER",
-  "TK_COLLATE", "TK_COLUMN", "TK_COMMA", "TK_COMMENT", "TK_COMMIT",
-  "TK_CONCAT", "TK_CONFLICT", "TK_CONSTRAINT", "TK_COPY", "TK_CREATE",
-  "TK_DEFAULT", "TK_DEFERRABLE", "TK_DEFERRED", "TK_DELETE",
-  "TK_DELIMITERS", "TK_DESC", "TK_DISTINCT", "TK_DOT", "TK_DROP",
-  "TK_EACH", "TK_ELSE", "TK_END", "TK_END_OF_FILE", "TK_EQ", "TK_EXCEPT",
-  "TK_EXPLAIN", "TK_FAIL", "TK_FLOAT", "TK_FOR", "TK_FOREIGN", "TK_FROM",
-  "TK_FUNCTION", "TK_GE", "TK_GLOB", "TK_GROUP", "TK_GT", "TK_HAVING",
-  "TK_HOLD", "TK_IGNORE", "TK_ILLEGAL", "TK_IMMEDIATE", "TK_IN",
-  "TK_INDEX", "TK_INITIALLY", "TK_ID", "TK_INSERT", "TK_INSTEAD", "TK_INT",
-  "TK_INTEGER", "TK_INTERSECT", "TK_INTO", "TK_IS", "TK_ISNULL", "TK_JOIN",
-  "TK_JOIN_KW", "TK_KEY", "TK_LE", "TK_LIKE", "TK_LIMIT", "TK_LONG",
-  "TK_LONGCHAR", "TK_LP", "TK_LSHIFT", "TK_LT", "TK_LOCALIZABLE",
-  "TK_MATCH", "TK_MINUS", "TK_NE", "TK_NOT", "TK_NOTNULL", "TK_NULL",
-  "TK_OBJECT", "TK_OF", "TK_OFFSET", "TK_ON", "TK_OR",
-  "TK_ORACLE_OUTER_JOIN", "TK_ORDER", "TK_PLUS", "TK_PRAGMA", "TK_PRIMARY",
-  "TK_RAISE", "TK_REFERENCES", "TK_REM", "TK_REPLACE", "TK_RESTRICT",
-  "TK_ROLLBACK", "TK_ROW", "TK_RP", "TK_RSHIFT", "TK_SELECT", "TK_SEMI",
-  "TK_SET", "TK_SHORT", "TK_SLASH", "TK_SPACE", "TK_STAR", "TK_STATEMENT",
-  "TK_STRING", "TK_TABLE", "TK_TEMP", "TK_THEN", "TK_TRANSACTION",
-  "TK_TRIGGER", "TK_UMINUS", "TK_UNCLOSED_STRING", "TK_UNION", "TK_UNIQUE",
-  "TK_UPDATE", "TK_UPLUS", "TK_USING", "TK_VACUUM", "TK_VALUES", "TK_VIEW",
-  "TK_WHEN", "TK_WHERE", "TK_WILDCARD", "AGG_FUNCTION.", "COLUMN",
-  "FUNCTION", "COMMENT", "UNCLOSED_STRING", "SPACE", "ILLEGAL",
-  "END_OF_FILE", "$accept", "query", "onequery", "oneinsert", "onecreate",
-  "oneupdate", "onedelete", "table_def", "column_def", "column_and_type",
-  "column_type", "data_type_l", "data_type", "data_count", "oneselect",
-  "unorderedsel", "selectfrom", "selcollist", "from", "fromtable", "expr",
-  "val", "constlist", "update_assign_list", "column_assignment",
-  "const_val", "column_val", "column", "table", "id", "number", 0
+  "$end", "error", "$undefined", "TK_ALTER", "TK_AND", "TK_BY", "TK_CHAR",
+  "TK_COMMA", "TK_CREATE", "TK_DELETE", "TK_DISTINCT", "TK_DOT", "TK_EQ",
+  "TK_FREE", "TK_FROM", "TK_GE", "TK_GT", "TK_HOLD", "TK_ID", "TK_ILLEGAL",
+  "TK_INSERT", "TK_INT", "TK_INTEGER", "TK_INTO", "TK_IS", "TK_KEY",
+  "TK_LE", "TK_LONG", "TK_LONGCHAR", "TK_LP", "TK_LT", "TK_LOCALIZABLE",
+  "TK_MINUS", "TK_NE", "TK_NOT", "TK_NULL", "TK_OBJECT", "TK_OR",
+  "TK_ORDER", "TK_PRIMARY", "TK_RP", "TK_SELECT", "TK_SET", "TK_SHORT",
+  "TK_SPACE", "TK_STAR", "TK_STRING", "TK_TABLE", "TK_TEMPORARY",
+  "TK_UPDATE", "TK_VALUES", "TK_WHERE", "TK_WILDCARD", "AGG_FUNCTION.",
+  "COLUMN", "FUNCTION", "COMMENT", "UNCLOSED_STRING", "SPACE", "ILLEGAL",
+  "END_OF_FILE", "TK_LIKE", "TK_NEGATION", "$accept", "query", "onequery",
+  "oneinsert", "onecreate", "oneupdate", "onedelete", "onealter",
+  "alterop", "table_def", "column_def", "column_and_type", "column_type",
+  "data_type_l", "data_type", "data_count", "oneselect", "unorderedsel",
+  "selectfrom", "selcollist", "from", "fromtable", "expr", "val",
+  "constlist", "update_assign_list", "column_assignment", "const_val",
+  "column_val", "column", "table", "id", "number", 0
 };
 #endif
 
 # ifdef YYPRINT
 /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
    token YYLEX-NUM.  */
-static const unsigned short yytoknum[] =
+static const unsigned short int yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
@@ -739,40 +604,34 @@ static const unsigned short yytoknum[] =
      285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
      295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
      305,   306,   307,   308,   309,   310,   311,   312,   313,   314,
-     315,   316,   317,   318,   319,   320,   321,   322,   323,   324,
-     325,   326,   327,   328,   329,   330,   331,   332,   333,   334,
-     335,   336,   337,   338,   339,   340,   341,   342,   343,   344,
-     345,   346,   347,   348,   349,   350,   351,   352,   353,   354,
-     355,   356,   357,   358,   359,   360,   361,   362,   363,   364,
-     365,   366,   367,   368,   369,   370,   371,   372,   373,   374,
-     375,   376,   377,   378,   379,   380,   381,   382,   383,   384,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,   399,   400,   401
+     315,   316,   317
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const unsigned char yyr1[] =
 {
-       0,   147,   148,   149,   149,   149,   149,   149,   150,   150,
-     151,   151,   152,   153,   154,   155,   155,   156,   157,   157,
-     158,   158,   159,   159,   159,   159,   159,   159,   159,   160,
-     161,   161,   162,   162,   163,   164,   164,   164,   165,   165,
-     166,   167,   167,   167,   167,   167,   167,   167,   167,   167,
-     167,   167,   167,   168,   168,   169,   169,   170,   170,   171,
-     172,   172,   172,   172,   173,   174,   174,   175,   176,   177
+       0,    63,    64,    65,    65,    65,    65,    65,    65,    66,
+      66,    67,    67,    68,    68,    69,    70,    71,    71,    72,
+      73,    73,    74,    75,    75,    75,    76,    76,    77,    77,
+      77,    77,    77,    77,    77,    78,    79,    79,    80,    80,
+      81,    82,    82,    82,    83,    83,    84,    84,    85,    85,
+      85,    85,    85,    85,    85,    85,    85,    85,    85,    86,
+      86,    87,    87,    88,    88,    89,    90,    90,    90,    90,
+      91,    92,    92,    93,    94,    95
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const unsigned char yyr2[] =
 {
-       0,     2,     1,     1,     1,     1,     1,     1,    10,    11,
-       6,     7,     6,     2,     4,     3,     1,     2,     1,     2,
-       1,     3,     1,     4,     1,     1,     1,     1,     1,     1,
-       4,     1,     2,     3,     2,     1,     3,     1,     1,     3,
-       2,     3,     3,     3,     3,     3,     3,     3,     3,     3,
-       3,     3,     4,     1,     1,     1,     3,     1,     3,     3,
-       1,     2,     1,     1,     1,     3,     1,     1,     1,     1
+       0,     2,     1,     1,     1,     1,     1,     1,     1,    10,
+      11,     6,     7,     6,     4,     2,     4,     1,     1,     4,
+       3,     1,     2,     1,     2,     2,     1,     3,     1,     4,
+       1,     1,     1,     1,     1,     1,     4,     1,     2,     3,
+       2,     1,     3,     1,     1,     3,     2,     4,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,     3,     4,     1,
+       1,     1,     3,     1,     3,     3,     1,     2,     1,     1,
+       1,     3,     1,     1,     1,     1
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -780,133 +639,122 @@ static const unsigned char yyr2[] =
    means the default is an error.  */
 static const unsigned char yydefact[] =
 {
-       0,     0,     0,     0,     0,     0,     0,     2,     5,     4,
-       6,     7,     3,    31,     0,     0,    13,    38,     0,     0,
-      68,    37,    32,     0,    35,     0,    66,     0,    67,     1,
-       0,     0,    40,     0,     0,    33,    34,     0,     0,     0,
-       0,     0,     0,    39,     0,    64,     0,    36,    65,     0,
-      57,     0,    30,     0,     0,    16,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     2,     5,
+       4,     6,     7,     8,     3,    37,     0,     0,     0,    15,
+      44,     0,     0,    74,    43,    38,     0,    41,     0,    72,
+       0,    73,     1,     0,     0,     0,    46,     0,     0,    39,
+      40,     0,     0,     0,     0,    18,    17,    16,     0,     0,
+       0,    45,     0,    70,     0,    42,    71,    14,    63,     0,
+      36,     0,     0,    21,     0,    47,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,    10,     0,     0,    22,    26,    27,    24,    28,    25,
-      17,    18,    20,    41,    43,    44,    69,     0,    62,    63,
-      45,    54,    42,    60,    49,    53,    46,     0,    51,    48,
-      47,    50,     0,    12,    58,    59,    11,    15,     0,     0,
-      19,     0,    61,    52,     0,    14,     0,    29,    21,     0,
-      23,     0,    55,     8,     0,     9,    56
+      11,     0,     0,    28,    32,    33,    30,    34,    31,    22,
+      23,    26,    48,    49,    50,    75,     0,    68,    69,    51,
+      60,    59,    66,    55,    52,     0,    57,    54,    53,    56,
+       0,    13,    64,    65,    12,    20,     0,     0,    24,    25,
+       0,    67,    58,     0,    19,     0,    35,    27,     0,    29,
+       0,    61,     9,     0,    10,    62
 };
 
 /* YYDEFGOTO[NTERM-NUM]. */
-static const yysigned_char yydefgoto[] =
+static const short int yydefgoto[] =
 {
-      -1,     6,     7,     8,     9,    10,    11,    53,    54,    55,
-      80,    81,    82,   116,    12,    13,    22,    23,    16,    17,
-      43,    90,   121,    49,    50,    91,    44,    45,    25,    26,
-      93
+      -1,     7,     8,     9,    10,    11,    12,    13,    47,    61,
+      62,    63,    89,    90,    91,   125,    14,    15,    25,    26,
+      19,    20,    51,    99,   130,    57,    58,   100,   101,    53,
+      28,    29,   102
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -111
+#define YYPACT_NINF -89
 static const yysigned_char yypact[] =
 {
-     -28,  -110,   -38,   -46,   -32,   -42,    29,  -111,  -111,  -111,
-    -111,  -111,  -111,   -67,   -42,   -42,  -111,   -99,   -42,   -48,
-    -111,  -111,  -111,   -38,    17,     7,    11,   -62,  -111,  -111,
-      37,   -22,  -111,   -43,   -16,  -111,  -111,   -48,   -42,   -42,
-     -48,   -42,   -43,    -3,   -29,  -111,   -48,  -111,  -111,   -68,
-      48,    28,  -111,   -36,   -19,  -111,   -18,    -5,   -43,   -43,
-     -58,   -58,   -58,   -70,   -58,   -58,   -58,   -34,   -43,   -42,
-     -61,    20,   -42,     5,     2,  -111,  -111,  -111,  -111,  -111,
-    -111,     1,    -2,  -111,    -3,    -3,  -111,    19,  -111,  -111,
-    -111,  -111,  -111,  -111,  -111,  -111,  -111,    -1,  -111,  -111,
-    -111,  -111,   -41,    -3,  -111,  -111,  -111,  -111,   -48,    19,
-    -111,     3,  -111,  -111,    13,  -111,   -12,  -111,  -111,   -61,
-    -111,    -9,    91,   -13,   -61,  -111,  -111
+       3,   -34,   -28,    31,    25,    48,    36,    60,   -89,   -89,
+     -89,   -89,   -89,   -89,   -89,    32,    36,    36,    36,   -89,
+      28,    36,    12,   -89,   -89,   -89,    31,    81,    78,    79,
+      49,   -89,   -89,    87,     1,    69,    92,    51,    74,   -89,
+     -89,    12,    36,    36,    12,   -89,   -89,   -89,    36,    36,
+      51,     5,    71,   -89,    12,   -89,   -89,    54,    93,    94,
+     -89,    67,    -4,   -89,    35,   -89,     0,    51,    51,    50,
+      50,    50,    -2,    50,    50,    50,    68,    51,    36,    29,
+      98,    36,    91,    88,   -89,   -89,   -89,   -89,   -89,   -89,
+     -24,    84,   -89,   -89,   115,   -89,    99,   -89,   -89,   -89,
+     -89,   -89,   -89,   -89,   -89,    85,   -89,   -89,   -89,   -89,
+      72,     5,   -89,   -89,   -89,   -89,    12,    99,   -89,   -89,
+      89,   -89,   -89,    96,   -89,    83,   -89,   -89,    29,   -89,
+      86,   120,    80,    29,   -89,   -89
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yysigned_char yypgoto[] =
 {
-    -111,  -111,  -111,  -111,  -111,  -111,  -111,  -111,  -111,    47,
-    -111,  -111,  -111,  -111,  -111,  -111,   101,   -27,    98,  -111,
-     -11,    52,     0,    53,  -111,   -53,    46,    -4,    85,    40,
-     -66
+     -89,   -89,   -89,   -89,   -89,   -89,   -89,   -89,   -89,   -89,
+     -89,    52,   -89,   -89,   -89,   -89,   -89,   -89,   107,   -39,
+     104,   -89,    17,    39,    -1,    53,   -89,   -78,    -3,    -5,
+      10,     4,   -88
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
    number is the opposite.  If zero, do what YYDEFACT says.
    If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -68
-static const yysigned_char yytable[] =
+#define YYTABLE_NINF -74
+static const short int yytable[] =
 {
-      24,    74,    58,     1,    58,    72,    19,     2,    20,    86,
-      47,    14,    86,    52,    15,    24,    60,   105,    20,    67,
-      97,   112,    98,    20,    20,    61,    18,    87,    62,    29,
-      87,    57,    30,    24,    20,    51,    24,    56,    33,     3,
-      42,    37,    24,   117,    63,    28,    38,    84,    85,    64,
-     -67,    75,    39,    40,    28,    28,    65,   103,    28,    88,
-      66,    41,    88,    76,    77,    51,   122,    46,    56,    68,
-      21,   122,    69,    70,    71,    78,   102,    89,    48,   106,
-      89,   115,   108,    73,     4,   109,    21,   110,   111,    86,
-      27,   113,    59,   114,    59,   118,   119,    79,   120,    31,
-      32,   123,     5,    34,    24,    83,    92,    95,    95,   125,
-      95,    95,    95,    94,    96,   124,    99,   100,   101,   107,
-      35,    36,   104,     0,   126
+      27,   113,    55,    81,    67,    60,     1,   118,   121,    67,
+      31,     2,     3,    16,    45,    76,    30,    27,    46,    17,
+      31,    31,    31,     4,   119,    31,    34,    35,    36,   126,
+      23,    38,   105,   106,    52,    82,    27,    68,    59,    27,
+      92,    83,    68,    64,     5,    18,    56,    52,    21,    27,
+     131,    95,     6,    31,    23,   131,    84,    24,    22,    65,
+      32,    96,    85,    86,    52,    52,    23,    66,    23,    23,
+      33,    87,    95,    59,    52,    97,    64,   124,    88,    37,
+      50,    98,    96,    69,    93,    94,    70,    71,    41,    42,
+     -73,    43,    44,    24,   111,    72,    97,    73,    48,    49,
+      78,    74,    98,    54,    75,    77,    79,    80,   110,   103,
+     104,    27,   107,   108,   109,   114,   116,   117,   120,    67,
+     122,    95,   123,   129,   127,   128,   132,   133,   134,    39,
+      40,   112,   135,   115
 };
 
-static const short yycheck[] =
+static const unsigned char yycheck[] =
 {
-       4,    19,     7,    31,     7,    24,    38,    35,    66,    70,
-      37,   121,    70,    40,    52,    19,    45,    70,    66,    46,
-      90,    87,    92,    66,    66,    54,    72,    88,    57,     0,
-      88,    42,    99,    37,    66,    39,    40,    41,   137,    67,
-      83,    24,    46,   109,    73,     5,    39,    58,    59,    78,
-      39,    69,   114,    16,    14,    15,    85,    68,    18,   120,
-      89,    83,   120,    81,    82,    69,   119,    83,    72,   137,
-     118,   124,    24,    45,   110,    93,   110,   138,    38,    59,
-     138,   108,    77,   102,   112,    83,   118,    86,    90,    70,
-       5,    92,    97,   134,    97,    92,    83,   115,   110,    14,
-      15,   110,   130,    18,   108,   110,    60,    61,    62,   122,
-      64,    65,    66,    61,    62,    24,    64,    65,    66,    72,
-      19,    23,    69,    -1,   124
+       5,    79,    41,     7,     4,    44,     3,    31,    96,     4,
+       6,     8,     9,    47,    13,    54,     6,    22,    17,    47,
+      16,    17,    18,    20,    48,    21,    16,    17,    18,   117,
+      18,    21,    34,    35,    37,    39,    41,    37,    43,    44,
+      40,     6,    37,    48,    41,    14,    42,    50,    23,    54,
+     128,    22,    49,    49,    18,   133,    21,    45,    10,    49,
+       0,    32,    27,    28,    67,    68,    18,    50,    18,    18,
+      38,    36,    22,    78,    77,    46,    81,   116,    43,    51,
+      29,    52,    32,    12,    67,    68,    15,    16,     7,    11,
+      11,    42,     5,    45,    77,    24,    46,    26,    29,     7,
+       7,    30,    52,    29,    33,    51,    12,    40,    40,    70,
+      71,   116,    73,    74,    75,    17,    25,    29,    34,     4,
+      35,    22,    50,    40,    35,    29,    40,     7,    48,    22,
+      26,    78,   133,    81
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const unsigned char yystos[] =
 {
-       0,    31,    35,    67,   112,   130,   148,   149,   150,   151,
-     152,   153,   161,   162,   121,    52,   165,   166,    72,    38,
-      66,   118,   163,   164,   174,   175,   176,   175,   176,     0,
-      99,   175,   175,   137,   175,   163,   165,    24,    39,   114,
-      16,    83,    83,   167,   173,   174,    83,   164,   176,   170,
-     171,   174,   164,   154,   155,   156,   174,   167,     7,    97,
-      45,    54,    57,    73,    78,    85,    89,   164,   137,    24,
-      45,   110,    24,   102,    19,    69,    81,    82,    93,   115,
-     157,   158,   159,   110,   167,   167,    70,    88,   120,   138,
-     168,   172,   173,   177,   168,   173,   168,    90,    92,   168,
-     168,   168,   110,   167,   170,   172,    59,   156,    77,    83,
-      86,    90,   177,    92,   134,   164,   160,   177,    92,    83,
-     110,   169,   172,   110,    24,   122,   169
+       0,     3,     8,     9,    20,    41,    49,    64,    65,    66,
+      67,    68,    69,    70,    79,    80,    47,    47,    14,    83,
+      84,    23,    10,    18,    45,    81,    82,    92,    93,    94,
+      93,    94,     0,    38,    93,    93,    93,    51,    93,    81,
+      83,     7,    11,    42,     5,    13,    17,    71,    29,     7,
+      29,    85,    91,    92,    29,    82,    94,    88,    89,    92,
+      82,    72,    73,    74,    92,    93,    85,     4,    37,    12,
+      15,    16,    24,    26,    30,    33,    82,    51,     7,    12,
+      40,     7,    39,     6,    21,    27,    28,    36,    43,    75,
+      76,    77,    40,    85,    85,    22,    32,    46,    52,    86,
+      90,    91,    95,    86,    86,    34,    35,    86,    86,    86,
+      40,    85,    88,    90,    17,    74,    25,    29,    31,    48,
+      34,    95,    35,    50,    82,    78,    95,    35,    29,    40,
+      87,    90,    40,     7,    48,    87
 };
 
-#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
-# define YYSIZE_T __SIZE_TYPE__
-#endif
-#if ! defined (YYSIZE_T) && defined (size_t)
-# define YYSIZE_T size_t
-#endif
-#if ! defined (YYSIZE_T)
-# if defined (__STDC__) || defined (__cplusplus)
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# endif
-#endif
-#if ! defined (YYSIZE_T)
-# define YYSIZE_T unsigned int
-#endif
-
 #define yyerrok                (yyerrstatus = 0)
 #define yyclearin      (yychar = YYEMPTY)
 #define YYEMPTY                (-2)
@@ -936,26 +784,59 @@ do                                                                \
       goto yybackup;                                           \
     }                                                          \
   else                                                         \
-    {                                                          \
-      yyerror ("syntax error: cannot back up");\
+    {                                                          \
+      yyerror (YY_("syntax error: cannot back up")); \
       YYERROR;                                                 \
     }                                                          \
 while (0)
 
+
 #define YYTERROR       1
 #define YYERRCODE      256
 
-/* YYLLOC_DEFAULT -- Compute the default location (before the actions
-   are run).  */
 
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)               \
-   ((Current).first_line   = (Rhs)[1].first_line,      \
-    (Current).first_column = (Rhs)[1].first_column,    \
-    (Current).last_line    = (Rhs)[N].last_line,       \
-    (Current).last_column  = (Rhs)[N].last_column)
+# define YYLLOC_DEFAULT(Current, Rhs, N)                               \
+    do                                                                 \
+      if (N)                                                           \
+       {                                                               \
+         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+       }                                                               \
+      else                                                             \
+       {                                                               \
+         (Current).first_line   = (Current).last_line   =              \
+           YYRHSLOC (Rhs, 0).last_line;                                \
+         (Current).first_column = (Current).last_column =              \
+           YYRHSLOC (Rhs, 0).last_column;                              \
+       }                                                               \
+    while (0)
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)                 \
+     fprintf (File, "%d.%d-%d.%d",                     \
+              (Loc).first_line, (Loc).first_column,    \
+              (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
 #endif
 
+
 /* YYLEX -- calling `yylex' with the right arguments.  */
 
 #ifdef YYLEX_PARAM
@@ -978,19 +859,13 @@ do {                                              \
     YYFPRINTF Args;                            \
 } while (0)
 
-# define YYDSYMPRINT(Args)                     \
-do {                                           \
-  if (yydebug)                                 \
-    yysymprint Args;                           \
-} while (0)
-
-# define YYDSYMPRINTF(Title, Token, Value, Location)           \
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)         \
 do {                                                           \
   if (yydebug)                                                 \
     {                                                          \
       YYFPRINTF (stderr, "%s ", Title);                                \
-      yysymprint (stderr,                                      \
-                  Token, Value);       \
+      yysymprint (stderr,                                      \
+                  Type, Value);        \
       YYFPRINTF (stderr, "\n");                                        \
     }                                                          \
 } while (0)
@@ -1002,12 +877,12 @@ do {                                                             \
 
 #if defined (__STDC__) || defined (__cplusplus)
 static void
-yy_stack_print (short *bottom, short *top)
+yy_stack_print (short int *bottom, short int *top)
 #else
 static void
 yy_stack_print (bottom, top)
-    short *bottom;
-    short *top;
+    short int *bottom;
+    short int *top;
 #endif
 {
   YYFPRINTF (stderr, "Stack now");
@@ -1037,13 +912,13 @@ yy_reduce_print (yyrule)
 #endif
 {
   int yyi;
-  unsigned int yylno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu), ",
              yyrule - 1, yylno);
   /* Print the symbols being reduced, and their result.  */
   for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
-    YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
-  YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+    YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+  YYFPRINTF (stderr, "-> %s\n", yytname[yyr1[yyrule]]);
 }
 
 # define YY_REDUCE_PRINT(Rule)         \
@@ -1057,8 +932,7 @@ do {                                       \
 int yydebug;
 #else /* !YYDEBUG */
 # define YYDPRINTF(Args)
-# define YYDSYMPRINT(Args)
-# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
 # define YY_STACK_PRINT(Bottom, Top)
 # define YY_REDUCE_PRINT(Rule)
 #endif /* !YYDEBUG */
@@ -1073,13 +947,9 @@ int yydebug;
    if the built-in stack extension method is used).
 
    Do not make this value too large; the results are undefined if
-   SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
    evaluated with infinite-precision integer arithmetic.  */
 
-#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0
-# undef YYMAXDEPTH
-#endif
-
 #ifndef YYMAXDEPTH
 # define YYMAXDEPTH 10000
 #endif
@@ -1101,7 +971,7 @@ yystrlen (yystr)
      const char *yystr;
 #   endif
 {
-  register const char *yys = yystr;
+  const char *yys = yystr;
 
   while (*yys++ != '\0')
     continue;
@@ -1126,8 +996,8 @@ yystpcpy (yydest, yysrc)
      const char *yysrc;
 #   endif
 {
-  register char *yyd = yydest;
-  register const char *yys = yysrc;
+  char *yyd = yydest;
+  const char *yys = yysrc;
 
   while ((*yyd++ = *yys++) != '\0')
     continue;
@@ -1137,7 +1007,55 @@ yystpcpy (yydest, yysrc)
 #  endif
 # endif
 
-#endif /* !YYERROR_VERBOSE */
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      size_t yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+       switch (*++yyp)
+         {
+         case '\'':
+         case ',':
+           goto do_not_strip_quotes;
+
+         case '\\':
+           if (*++yyp != '\\')
+             goto do_not_strip_quotes;
+           /* Fall through.  */
+         default:
+           if (yyres)
+             yyres[yyn] = *yyp;
+           yyn++;
+           break;
+
+         case '"':
+           if (yyres)
+             yyres[yyn] = '\0';
+           return yyn;
+         }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+#endif /* YYERROR_VERBOSE */
 
 \f
 
@@ -1161,15 +1079,15 @@ yysymprint (yyoutput, yytype, yyvaluep)
   (void) yyvaluep;
 
   if (yytype < YYNTOKENS)
-    {
-      YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-# ifdef YYPRINT
-      YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# endif
-    }
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
   else
     YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
 
+
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
   switch (yytype)
     {
       default:
@@ -1185,10 +1103,11 @@ yysymprint (yyoutput, yytype, yyvaluep)
 
 #if defined (__STDC__) || defined (__cplusplus)
 static void
-yydestruct (int yytype, YYSTYPE *yyvaluep)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
 #else
 static void
-yydestruct (yytype, yyvaluep)
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
     int yytype;
     YYSTYPE *yyvaluep;
 #endif
@@ -1196,6 +1115,10 @@ yydestruct (yytype, yyvaluep)
   /* Pacify ``unused variable'' warnings.  */
   (void) yyvaluep;
 
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
   switch (yytype)
     {
 
@@ -1244,25 +1167,25 @@ yyparse (void)
 #else
 int
 yyparse ()
-
+    ;
 #endif
 #endif
 {
-  /* The lookahead symbol.  */
+  /* The look-ahead symbol.  */
 int yychar;
 
-/* The semantic value of the lookahead symbol.  */
+/* The semantic value of the look-ahead symbol.  */
 YYSTYPE yylval;
 
 /* Number of syntax errors so far.  */
 int yynerrs;
 
-  register int yystate;
-  register int yyn;
+  int yystate;
+  int yyn;
   int yyresult;
   /* Number of tokens to shift before error messages enabled.  */
   int yyerrstatus;
-  /* Lookahead token as an internal (translated) token number.  */
+  /* Look-ahead token as an internal (translated) token number.  */
   int yytoken = 0;
 
   /* Three stacks and their tools:
@@ -1274,14 +1197,14 @@ int yynerrs;
      to reallocate them elsewhere.  */
 
   /* The state stack.  */
-  short        yyssa[YYINITDEPTH];
-  short *yyss = yyssa;
-  register short *yyssp;
+  short int yyssa[YYINITDEPTH];
+  short int *yyss = yyssa;
+  short int *yyssp;
 
   /* The semantic value stack.  */
   YYSTYPE yyvsa[YYINITDEPTH];
   YYSTYPE *yyvs = yyvsa;
-  register YYSTYPE *yyvsp;
+  YYSTYPE *yyvsp;
 
 
 
@@ -1338,14 +1261,14 @@ int yynerrs;
           these so that the &'s don't force the real ones into
           memory.  */
        YYSTYPE *yyvs1 = yyvs;
-       short *yyss1 = yyss;
+       short int *yyss1 = yyss;
 
 
        /* Each stack pointer address is followed by the size of the
           data in use in that stack, in bytes.  This used to be a
           conditional around just the two extra args, but that might
           be undefined if yyoverflow is a macro.  */
-       yyoverflow ("parser stack overflow",
+       yyoverflow (YY_("memory exhausted"),
                    &yyss1, yysize * sizeof (*yyssp),
                    &yyvs1, yysize * sizeof (*yyvsp),
 
@@ -1356,21 +1279,21 @@ int yynerrs;
       }
 #else /* no yyoverflow */
 # ifndef YYSTACK_RELOCATE
-      goto yyoverflowlab;
+      goto yyexhaustedlab;
 # else
       /* Extend the stack our own way.  */
       if (YYMAXDEPTH <= yystacksize)
-       goto yyoverflowlab;
+       goto yyexhaustedlab;
       yystacksize *= 2;
       if (YYMAXDEPTH < yystacksize)
        yystacksize = YYMAXDEPTH;
 
       {
-       short *yyss1 = yyss;
+       short int *yyss1 = yyss;
        union yyalloc *yyptr =
          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
        if (! yyptr)
-         goto yyoverflowlab;
+         goto yyexhaustedlab;
        YYSTACK_RELOCATE (yyss);
        YYSTACK_RELOCATE (yyvs);
 
@@ -1402,18 +1325,18 @@ int yynerrs;
 yybackup:
 
 /* Do appropriate processing given the current state.  */
-/* Read a lookahead token if we need one and don't already have one.  */
+/* Read a look-ahead token if we need one and don't already have one.  */
 /* yyresume: */
 
-  /* First try to decide what to do without reference to lookahead token.  */
+  /* First try to decide what to do without reference to look-ahead token.  */
 
   yyn = yypact[yystate];
   if (yyn == YYPACT_NINF)
     goto yydefault;
 
-  /* Not known => get a lookahead token if don't already have one.  */
+  /* Not known => get a look-ahead token if don't already have one.  */
 
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
   if (yychar == YYEMPTY)
     {
       YYDPRINTF ((stderr, "Reading a token: "));
@@ -1428,7 +1351,7 @@ yybackup:
   else
     {
       yytoken = YYTRANSLATE (yychar);
-      YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
     }
 
   /* If the proper action on seeing token YYTOKEN is to reduce or to
@@ -1448,8 +1371,8 @@ yybackup:
   if (yyn == YYFINAL)
     YYACCEPT;
 
-  /* Shift the lookahead token.  */
-  YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
 
   /* Discard the token being shifted unless it is eof.  */
   if (yychar != YYEOF)
@@ -1499,558 +1422,610 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-#line 139 "./sql.y"
+#line 124 "sql.y"
     {
         SQL_input* sql = (SQL_input*) info;
-        *sql->view = yyvsp[0].query;
+        *sql->view = (yyvsp[0].query);
     ;}
     break;
 
-  case 8:
-#line 155 "./sql.y"
+  case 9:
+#line 141 "sql.y"
     {
             SQL_input *sql = (SQL_input*) info;
-            MSIVIEW *insert = NULL; 
+            MSIVIEW *insert = NULL;
             UINT r;
 
-            r = INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].column_list, FALSE ); 
+            r = INSERT_CreateView( sql->db, &insert, (yyvsp[-7].string), (yyvsp[-5].column_list), (yyvsp[-1].column_list), FALSE );
             if( !insert )
                 YYABORT;
-            yyval.query = insert;
+            (yyval.query) = insert;
         ;}
     break;
 
-  case 9:
-#line 166 "./sql.y"
+  case 10:
+#line 152 "sql.y"
     {
             SQL_input *sql = (SQL_input*) info;
-            MSIVIEW *insert = NULL; 
+            MSIVIEW *insert = NULL;
 
-            INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].column_list, TRUE ); 
+            INSERT_CreateView( sql->db, &insert, (yyvsp[-8].string), (yyvsp[-6].column_list), (yyvsp[-2].column_list), TRUE );
             if( !insert )
                 YYABORT;
-            yyval.query = insert;
+            (yyval.query) = insert;
         ;}
     break;
 
-  case 10:
-#line 179 "./sql.y"
+  case 11:
+#line 165 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *create = NULL; 
+            MSIVIEW *create = NULL;
 
-            if( !yyvsp[-1].column_list )
+            if( !(yyvsp[-1].column_list) )
                 YYABORT;
-            CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_list, FALSE );
+            CREATE_CreateView( sql->db, &create, (yyvsp[-3].string), (yyvsp[-1].column_list), FALSE );
             if( !create )
                 YYABORT;
-            yyval.query = create;
+            (yyval.query) = create;
         ;}
     break;
 
-  case 11:
-#line 191 "./sql.y"
+  case 12:
+#line 177 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *create = NULL; 
+            MSIVIEW *create = NULL;
 
-            if( !yyvsp[-2].column_list )
+            if( !(yyvsp[-2].column_list) )
                 YYABORT;
-            CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_list, TRUE );
+            CREATE_CreateView( sql->db, &create, (yyvsp[-4].string), (yyvsp[-2].column_list), TRUE );
             if( !create )
                 YYABORT;
-            yyval.query = create;
+            (yyval.query) = create;
         ;}
     break;
 
-  case 12:
-#line 206 "./sql.y"
+  case 13:
+#line 192 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *update = NULL; 
+            MSIVIEW *update = NULL;
 
-            UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, yyvsp[-2].column_list, yyvsp[0].expr );
+            UPDATE_CreateView( sql->db, &update, (yyvsp[-4].string), (yyvsp[-2].column_list), (yyvsp[0].expr) );
             if( !update )
                 YYABORT;
-            yyval.query = update;
+            (yyval.query) = update;
         ;}
     break;
 
-  case 13:
-#line 219 "./sql.y"
+  case 14:
+#line 202 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *delete = NULL; 
+            MSIVIEW *update = NULL;
 
-            DELETE_CreateView( sql->db, &delete, yyvsp[0].query );
-            if( !delete )
+            UPDATE_CreateView( sql->db, &update, (yyvsp[-2].string), (yyvsp[0].column_list), NULL );
+            if( !update )
                 YYABORT;
-            yyval.query = delete;
-        ;}
-    break;
-
-  case 14:
-#line 232 "./sql.y"
-    {
-            if( SQL_MarkPrimaryKeys( yyvsp[-3].column_list, yyvsp[0].column_list ) )
-                yyval.column_list = yyvsp[-3].column_list;
-            else
-                yyval.column_list = NULL;
+            (yyval.query) = update;
         ;}
     break;
 
   case 15:
-#line 242 "./sql.y"
+#line 215 "sql.y"
     {
-            column_info *ci;
-
-            for( ci = yyvsp[-2].column_list; ci->next; ci = ci->next )
-                ;
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *delete = NULL;
 
-            ci->next = yyvsp[0].column_list;
-            yyval.column_list = yyvsp[-2].column_list;
+            DELETE_CreateView( sql->db, &delete, (yyvsp[0].query) );
+            if( !delete )
+                YYABORT;
+            (yyval.query) = delete;
         ;}
     break;
 
   case 16:
-#line 252 "./sql.y"
+#line 228 "sql.y"
     {
-            yyval.column_list = yyvsp[0].column_list;
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *alter = NULL;
+
+            ALTER_CreateView( sql->db, &alter, (yyvsp[-1].string), (yyvsp[0].integer) );
+            if( !alter )
+                YYABORT;
+            (yyval.query) = alter;
         ;}
     break;
 
   case 17:
-#line 259 "./sql.y"
+#line 241 "sql.y"
     {
-            yyval.column_list = yyvsp[-1].column_list;
-            yyval.column_list->type = yyvsp[0].column_type | MSITYPE_VALID;
+            (yyval.integer) = 1;
         ;}
     break;
 
   case 18:
-#line 267 "./sql.y"
+#line 245 "sql.y"
     {
-            yyval.column_type = yyvsp[0].column_type;
+            (yyval.integer) = -1;
         ;}
     break;
 
   case 19:
-#line 271 "./sql.y"
+#line 252 "sql.y"
     {
-            yyval.column_type = yyvsp[-1].column_type | MSITYPE_LOCALIZABLE;
+            if( SQL_MarkPrimaryKeys( (yyvsp[-3].column_list), (yyvsp[0].column_list) ) )
+                (yyval.column_list) = (yyvsp[-3].column_list);
+            else
+                (yyval.column_list) = NULL;
         ;}
     break;
 
   case 20:
-#line 278 "./sql.y"
+#line 262 "sql.y"
     {
-            yyval.column_type |= MSITYPE_NULLABLE;
+            column_info *ci;
+
+            for( ci = (yyvsp[-2].column_list); ci->next; ci = ci->next )
+                ;
+
+            ci->next = (yyvsp[0].column_list);
+            (yyval.column_list) = (yyvsp[-2].column_list);
         ;}
     break;
 
   case 21:
-#line 282 "./sql.y"
+#line 272 "sql.y"
     {
-            yyval.column_type = yyvsp[-2].column_type;
+            (yyval.column_list) = (yyvsp[0].column_list);
         ;}
     break;
 
   case 22:
-#line 289 "./sql.y"
+#line 279 "sql.y"
     {
-            yyval.column_type = MSITYPE_STRING | 1;
+            (yyval.column_list) = (yyvsp[-1].column_list);
+            (yyval.column_list)->type = (yyvsp[0].column_type) | MSITYPE_VALID;
         ;}
     break;
 
   case 23:
-#line 293 "./sql.y"
+#line 287 "sql.y"
     {
-            yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type;
+            (yyval.column_type) = (yyvsp[0].column_type);
         ;}
     break;
 
   case 24:
-#line 297 "./sql.y"
+#line 291 "sql.y"
     {
-            yyval.column_type = 2;
+            (yyval.column_type) = (yyvsp[-1].column_type) | MSITYPE_LOCALIZABLE;
         ;}
     break;
 
   case 25:
-#line 301 "./sql.y"
+#line 295 "sql.y"
     {
-            yyval.column_type = 2;
+            FIXME("temporary column\n");
         ;}
     break;
 
   case 26:
-#line 305 "./sql.y"
+#line 302 "sql.y"
     {
-            yyval.column_type = 2;
+            (yyval.column_type) |= MSITYPE_NULLABLE;
         ;}
     break;
 
   case 27:
-#line 309 "./sql.y"
+#line 306 "sql.y"
     {
-            yyval.column_type = 4;
+            (yyval.column_type) = (yyvsp[-2].column_type);
         ;}
     break;
 
   case 28:
-#line 313 "./sql.y"
+#line 313 "sql.y"
     {
-            yyval.column_type = MSITYPE_STRING | MSITYPE_VALID;
+            (yyval.column_type) = MSITYPE_STRING | 1;
         ;}
     break;
 
   case 29:
-#line 320 "./sql.y"
+#line 317 "sql.y"
     {
-            if( ( yyvsp[0].integer > 255 ) || ( yyvsp[0].integer < 0 ) )
-                YYABORT;
-            yyval.column_type = yyvsp[0].integer;
+            (yyval.column_type) = MSITYPE_STRING | 0x400 | (yyvsp[-1].column_type);
         ;}
     break;
 
   case 30:
-#line 329 "./sql.y"
+#line 321 "sql.y"
+    {
+            (yyval.column_type) = 2;
+        ;}
+    break;
+
+  case 31:
+#line 325 "sql.y"
+    {
+            (yyval.column_type) = 2;
+        ;}
+    break;
+
+  case 32:
+#line 329 "sql.y"
+    {
+            (yyval.column_type) = 2;
+        ;}
+    break;
+
+  case 33:
+#line 333 "sql.y"
+    {
+            (yyval.column_type) = 4;
+        ;}
+    break;
+
+  case 34:
+#line 337 "sql.y"
+    {
+            (yyval.column_type) = MSITYPE_STRING | MSITYPE_VALID;
+        ;}
+    break;
+
+  case 35:
+#line 344 "sql.y"
+    {
+            if( ( (yyvsp[0].integer) > 255 ) || ( (yyvsp[0].integer) < 0 ) )
+                YYABORT;
+            (yyval.column_type) = (yyvsp[0].integer);
+        ;}
+    break;
+
+  case 36:
+#line 353 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
 
-            yyval.query = NULL;
-            if( yyvsp[0].column_list )
-                ORDER_CreateView( sql->db, &yyval.query, yyvsp[-3].query, yyvsp[0].column_list );
+            (yyval.query) = NULL;
+            if( (yyvsp[0].column_list) )
+                ORDER_CreateView( sql->db, &(yyval.query), (yyvsp[-3].query), (yyvsp[0].column_list) );
             else
-                yyval.query = yyvsp[-3].query;
-            if( !yyval.query )
+                (yyval.query) = (yyvsp[-3].query);
+            if( !(yyval.query) )
                 YYABORT;
         ;}
     break;
 
-  case 32:
-#line 345 "./sql.y"
+  case 38:
+#line 369 "sql.y"
     {
-            yyval.query = yyvsp[0].query;
+            (yyval.query) = (yyvsp[0].query);
         ;}
     break;
 
-  case 33:
-#line 349 "./sql.y"
+  case 39:
+#line 373 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
             UINT r;
 
-            yyval.query = NULL;
-            r = DISTINCT_CreateView( sql->db, &yyval.query, yyvsp[0].query );
+            (yyval.query) = NULL;
+            r = DISTINCT_CreateView( sql->db, &(yyval.query), (yyvsp[0].query) );
             if (r != ERROR_SUCCESS)
             {
-                yyvsp[0].query->ops->delete(yyvsp[0].query);
+                (yyvsp[0].query)->ops->delete((yyvsp[0].query));
                 YYABORT;
             }
         ;}
     break;
 
-  case 34:
-#line 365 "./sql.y"
+  case 40:
+#line 389 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
             UINT r;
 
-            yyval.query = NULL;
-            if( yyvsp[-1].column_list )
+            (yyval.query) = NULL;
+            if( (yyvsp[-1].column_list) )
             {
-                r = SELECT_CreateView( sql->db, &yyval.query, yyvsp[0].query, yyvsp[-1].column_list );
+                r = SELECT_CreateView( sql->db, &(yyval.query), (yyvsp[0].query), (yyvsp[-1].column_list) );
                 if (r != ERROR_SUCCESS)
                 {
-                    yyvsp[0].query->ops->delete(yyvsp[0].query);
+                    (yyvsp[0].query)->ops->delete((yyvsp[0].query));
                     YYABORT;
                 }
             }
             else
-                yyval.query = yyvsp[0].query;
+                (yyval.query) = (yyvsp[0].query);
         ;}
     break;
 
-  case 36:
-#line 387 "./sql.y"
-    { 
-            yyvsp[-2].column_list->next = yyvsp[0].column_list;
+  case 42:
+#line 411 "sql.y"
+    {
+            (yyvsp[-2].column_list)->next = (yyvsp[0].column_list);
         ;}
     break;
 
-  case 37:
-#line 391 "./sql.y"
+  case 43:
+#line 415 "sql.y"
     {
-            yyval.column_list = NULL;
+            (yyval.column_list) = NULL;
         ;}
     break;
 
-  case 39:
-#line 399 "./sql.y"
-    { 
+  case 45:
+#line 423 "sql.y"
+    {
             SQL_input* sql = (SQL_input*) info;
             UINT r;
 
-            yyval.query = NULL;
-            r = WHERE_CreateView( sql->db, &yyval.query, yyvsp[-2].query, yyvsp[0].expr );
+            (yyval.query) = NULL;
+            r = WHERE_CreateView( sql->db, &(yyval.query), (yyvsp[-2].query), (yyvsp[0].expr) );
             if( r != ERROR_SUCCESS )
             {
-                yyvsp[-2].query->ops->delete( yyvsp[-2].query );
+                (yyvsp[-2].query)->ops->delete( (yyvsp[-2].query) );
                 YYABORT;
             }
         ;}
     break;
 
-  case 40:
-#line 415 "./sql.y"
+  case 46:
+#line 439 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
             UINT r;
 
-            yyval.query = NULL;
-            r = TABLE_CreateView( sql->db, yyvsp[0].string, &yyval.query );
-            if( r != ERROR_SUCCESS || !yyval.query )
+            (yyval.query) = NULL;
+            r = TABLE_CreateView( sql->db, (yyvsp[0].string), &(yyval.query) );
+            if( r != ERROR_SUCCESS || !(yyval.query) )
                 YYABORT;
         ;}
     break;
 
-  case 41:
-#line 428 "./sql.y"
+  case 47:
+#line 449 "sql.y"
     {
-            yyval.expr = yyvsp[-1].expr;
-            if( !yyval.expr )
+            SQL_input* sql = (SQL_input*) info;
+            UINT r;
+
+            /* only support inner joins on two tables */
+            r = JOIN_CreateView( sql->db, &(yyval.query), (yyvsp[-2].string), (yyvsp[0].string) );
+            if( r != ERROR_SUCCESS )
                 YYABORT;
         ;}
     break;
 
-  case 42:
-#line 434 "./sql.y"
+  case 48:
+#line 462 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr );
-            if( !yyval.expr )
+            (yyval.expr) = (yyvsp[-1].expr);
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 43:
-#line 440 "./sql.y"
+  case 49:
+#line 468 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_AND, yyvsp[0].expr );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_complex( info, (yyvsp[-2].expr), OP_AND, (yyvsp[0].expr) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 44:
-#line 446 "./sql.y"
+  case 50:
+#line 474 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_OR, yyvsp[0].expr );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_complex( info, (yyvsp[-2].expr), OP_OR, (yyvsp[0].expr) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 45:
-#line 452 "./sql.y"
+  case 51:
+#line 480 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_complex( info, (yyvsp[-2].expr), OP_EQ, (yyvsp[0].expr) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 46:
-#line 458 "./sql.y"
+  case 52:
+#line 486 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GT, yyvsp[0].expr );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_complex( info, (yyvsp[-2].expr), OP_GT, (yyvsp[0].expr) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 47:
-#line 464 "./sql.y"
+  case 53:
+#line 492 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LT, yyvsp[0].expr );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_complex( info, (yyvsp[-2].expr), OP_LT, (yyvsp[0].expr) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 48:
-#line 470 "./sql.y"
+  case 54:
+#line 498 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LE, yyvsp[0].expr );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_complex( info, (yyvsp[-2].expr), OP_LE, (yyvsp[0].expr) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 49:
-#line 476 "./sql.y"
+  case 55:
+#line 504 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GE, yyvsp[0].expr );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_complex( info, (yyvsp[-2].expr), OP_GE, (yyvsp[0].expr) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 50:
-#line 482 "./sql.y"
+  case 56:
+#line 510 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_NE, yyvsp[0].expr );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_complex( info, (yyvsp[-2].expr), OP_NE, (yyvsp[0].expr) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 51:
-#line 488 "./sql.y"
+  case 57:
+#line 516 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_ISNULL, NULL );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_unary( info, (yyvsp[-2].expr), OP_ISNULL );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 52:
-#line 494 "./sql.y"
+  case 58:
+#line 522 "sql.y"
     {
-            yyval.expr = EXPR_complex( info, yyvsp[-3].expr, OP_NOTNULL, NULL );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_unary( info, (yyvsp[-3].expr), OP_NOTNULL );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 55:
-#line 508 "./sql.y"
+  case 61:
+#line 536 "sql.y"
     {
-            yyval.column_list = parser_alloc_column( info, NULL, NULL );
-            if( !yyval.column_list )
+            (yyval.column_list) = parser_alloc_column( info, NULL, NULL );
+            if( !(yyval.column_list) )
                 YYABORT;
-            yyval.column_list->val = yyvsp[0].expr;
+            (yyval.column_list)->val = (yyvsp[0].expr);
         ;}
     break;
 
-  case 56:
-#line 515 "./sql.y"
+  case 62:
+#line 543 "sql.y"
     {
-            yyval.column_list = parser_alloc_column( info, NULL, NULL );
-            if( !yyval.column_list )
+            (yyval.column_list) = parser_alloc_column( info, NULL, NULL );
+            if( !(yyval.column_list) )
                 YYABORT;
-            yyval.column_list->val = yyvsp[-2].expr;
-            yyval.column_list->next = yyvsp[0].column_list;
+            (yyval.column_list)->val = (yyvsp[-2].expr);
+            (yyval.column_list)->next = (yyvsp[0].column_list);
         ;}
     break;
 
-  case 58:
-#line 527 "./sql.y"
+  case 64:
+#line 555 "sql.y"
     {
-            yyval.column_list = yyvsp[-2].column_list;
-            yyval.column_list->next = yyvsp[0].column_list;
+            (yyval.column_list) = (yyvsp[-2].column_list);
+            (yyval.column_list)->next = (yyvsp[0].column_list);
         ;}
     break;
 
-  case 59:
-#line 535 "./sql.y"
+  case 65:
+#line 563 "sql.y"
     {
-            yyval.column_list = yyvsp[-2].column_list;
-            yyval.column_list->val = yyvsp[0].expr;
+            (yyval.column_list) = (yyvsp[-2].column_list);
+            (yyval.column_list)->val = (yyvsp[0].expr);
         ;}
     break;
 
-  case 60:
-#line 543 "./sql.y"
+  case 66:
+#line 571 "sql.y"
     {
-            yyval.expr = EXPR_ival( info, yyvsp[0].integer );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_ival( info, (yyvsp[0].integer) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 61:
-#line 549 "./sql.y"
+  case 67:
+#line 577 "sql.y"
     {
-            yyval.expr = EXPR_ival( info, -yyvsp[0].integer );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_ival( info, -(yyvsp[0].integer) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 62:
-#line 555 "./sql.y"
+  case 68:
+#line 583 "sql.y"
     {
-            yyval.expr = EXPR_sval( info, &yyvsp[0].str );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_sval( info, &(yyvsp[0].str) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 63:
-#line 561 "./sql.y"
+  case 69:
+#line 589 "sql.y"
     {
-            yyval.expr = EXPR_wildcard( info );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_wildcard( info );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 64:
-#line 570 "./sql.y"
+  case 70:
+#line 598 "sql.y"
     {
-            yyval.expr = EXPR_column( info, yyvsp[0].column_list );
-            if( !yyval.expr )
+            (yyval.expr) = EXPR_column( info, (yyvsp[0].column_list) );
+            if( !(yyval.expr) )
                 YYABORT;
         ;}
     break;
 
-  case 65:
-#line 579 "./sql.y"
+  case 71:
+#line 607 "sql.y"
     {
-            yyval.column_list = parser_alloc_column( info, yyvsp[-2].string, yyvsp[0].string );
-            if( !yyval.column_list )
+            (yyval.column_list) = parser_alloc_column( info, (yyvsp[-2].string), (yyvsp[0].string) );
+            if( !(yyval.column_list) )
                 YYABORT;
         ;}
     break;
 
-  case 66:
-#line 585 "./sql.y"
+  case 72:
+#line 613 "sql.y"
     {
-            yyval.column_list = parser_alloc_column( info, NULL, yyvsp[0].string );
-            if( !yyval.column_list )
+            (yyval.column_list) = parser_alloc_column( info, NULL, (yyvsp[0].string) );
+            if( !(yyval.column_list) )
                 YYABORT;
         ;}
     break;
 
-  case 67:
-#line 594 "./sql.y"
+  case 73:
+#line 622 "sql.y"
     {
-            yyval.string = yyvsp[0].string;
+            (yyval.string) = (yyvsp[0].string);
         ;}
     break;
 
-  case 68:
-#line 601 "./sql.y"
+  case 74:
+#line 629 "sql.y"
     {
-            yyval.string = SQL_getstring( info, &yyvsp[0].str );
-            if( !yyval.string )
+            (yyval.string) = SQL_getstring( info, &(yyvsp[0].str) );
+            if( !(yyval.string) )
                 YYABORT;
         ;}
     break;
 
-  case 69:
-#line 610 "./sql.y"
+  case 75:
+#line 638 "sql.y"
     {
-            yyval.integer = SQL_getint( info );
+            (yyval.integer) = SQL_getint( info );
         ;}
     break;
 
 
+      default: break;
     }
 
-/* Line 1000 of yacc.c.  */
-#line 2054 "sql.tab.c"
+/* Line 1126 of yacc.c.  */
+#line 2029 "sql.tab.c"
 \f
   yyvsp -= yylen;
   yyssp -= yylen;
@@ -2089,12 +2064,36 @@ yyerrlab:
 
       if (YYPACT_NINF < yyn && yyn < YYLAST)
        {
-         YYSIZE_T yysize = 0;
          int yytype = YYTRANSLATE (yychar);
-         const char* yyprefix;
-         char *yymsg;
+         YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+         YYSIZE_T yysize = yysize0;
+         YYSIZE_T yysize1;
+         int yysize_overflow = 0;
+         char *yymsg = 0;
+#        define YYERROR_VERBOSE_ARGS_MAXIMUM 5
+         char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
          int yyx;
 
+#if 0
+         /* This is so xgettext sees the translatable formats that are
+            constructed on the fly.  */
+         YY_("syntax error, unexpected %s");
+         YY_("syntax error, unexpected %s, expecting %s");
+         YY_("syntax error, unexpected %s, expecting %s or %s");
+         YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+         YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+#endif
+         char *yyfmt;
+         char const *yyf;
+         static char const yyunexpected[] = "syntax error, unexpected %s";
+         static char const yyexpecting[] = ", expecting %s";
+         static char const yyor[] = " or %s";
+         char yyformat[sizeof yyunexpected
+                       + sizeof yyexpecting - 1
+                       + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+                          * (sizeof yyor - 1))];
+         char const *yyprefix = yyexpecting;
+
          /* Start YYX at -YYN if negative to avoid negative indexes in
             YYCHECK.  */
          int yyxbegin = yyn < 0 ? -yyn : 0;
@@ -2102,81 +2101,91 @@ yyerrlab:
          /* Stay within bounds of both yycheck and yytname.  */
          int yychecklim = YYLAST - yyn;
          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-         int yycount = 0;
+         int yycount = 1;
+
+         yyarg[0] = yytname[yytype];
+         yyfmt = yystpcpy (yyformat, yyunexpected);
 
-         yyprefix = ", expecting ";
          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
              {
-               yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
-               yycount += 1;
-               if (yycount == 5)
+               if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
                  {
-                   yysize = 0;
+                   yycount = 1;
+                   yysize = yysize0;
+                   yyformat[sizeof yyunexpected - 1] = '\0';
                    break;
                  }
+               yyarg[yycount++] = yytname[yyx];
+               yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+               yysize_overflow |= yysize1 < yysize;
+               yysize = yysize1;
+               yyfmt = yystpcpy (yyfmt, yyprefix);
+               yyprefix = yyor;
              }
-         yysize += (sizeof ("syntax error, unexpected ")
-                    + yystrlen (yytname[yytype]));
-         yymsg = (char *) YYSTACK_ALLOC (yysize);
-         if (yymsg != 0)
-           {
-             char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
-             yyp = yystpcpy (yyp, yytname[yytype]);
 
-             if (yycount < 5)
+         yyf = YY_(yyformat);
+         yysize1 = yysize + yystrlen (yyf);
+         yysize_overflow |= yysize1 < yysize;
+         yysize = yysize1;
+
+         if (!yysize_overflow && yysize <= YYSTACK_ALLOC_MAXIMUM)
+           yymsg = (char *) YYSTACK_ALLOC (yysize);
+         if (yymsg)
+           {
+             /* Avoid sprintf, as that infringes on the user's name space.
+                Don't have undefined behavior even if the translation
+                produced a string with the wrong number of "%s"s.  */
+             char *yyp = yymsg;
+             int yyi = 0;
+             while ((*yyp = *yyf))
                {
-                 yyprefix = ", expecting ";
-                 for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-                   if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-                     {
-                       yyp = yystpcpy (yyp, yyprefix);
-                       yyp = yystpcpy (yyp, yytname[yyx]);
-                       yyprefix = " or ";
-                     }
+                 if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+                   {
+                     yyp += yytnamerr (yyp, yyarg[yyi++]);
+                     yyf += 2;
+                   }
+                 else
+                   {
+                     yyp++;
+                     yyf++;
+                   }
                }
              yyerror (yymsg);
              YYSTACK_FREE (yymsg);
            }
          else
-           yyerror ("syntax error; also virtual memory exhausted");
+           {
+             yyerror (YY_("syntax error"));
+             goto yyexhaustedlab;
+           }
        }
       else
 #endif /* YYERROR_VERBOSE */
-       yyerror ("syntax error");
+       yyerror (YY_("syntax error"));
     }
 
 
 
   if (yyerrstatus == 3)
     {
-      /* If just tried and failed to reuse lookahead token after an
+      /* If just tried and failed to reuse look-ahead token after an
         error, discard it.  */
 
       if (yychar <= YYEOF)
         {
-          /* If at end of input, pop the error token,
-            then the rest of the stack, then return failure.  */
+         /* Return failure if at end of input.  */
          if (yychar == YYEOF)
-            for (;;)
-              {
-                YYPOPSTACK;
-                if (yyssp == yyss)
-                  YYABORT;
-                YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
-                yydestruct (yystos[*yyssp], yyvsp);
-              }
+           YYABORT;
         }
       else
        {
-         YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
-         yydestruct (yytoken, &yylval);
+         yydestruct ("Error: discarding", yytoken, &yylval);
          yychar = YYEMPTY;
-
        }
     }
 
-  /* Else will try to reuse lookahead token after shifting the error
+  /* Else will try to reuse look-ahead token after shifting the error
      token.  */
   goto yyerrlab1;
 
@@ -2186,14 +2195,13 @@ yyerrlab:
 `---------------------------------------------------*/
 yyerrorlab:
 
-#ifdef __GNUC__
-  /* Pacify GCC when the user code never invokes YYERROR and the label
-     yyerrorlab therefore never appears in user code.  */
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
   if (0)
      goto yyerrorlab;
-#endif
 
-  yyvsp -= yylen;
+yyvsp -= yylen;
   yyssp -= yylen;
   yystate = *yyssp;
   goto yyerrlab1;
@@ -2223,8 +2231,8 @@ yyerrlab1:
       if (yyssp == yyss)
        YYABORT;
 
-      YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
-      yydestruct (yystos[yystate], yyvsp);
+
+      yydestruct ("Error: popping", yystos[yystate], yyvsp);
       YYPOPSTACK;
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -2233,11 +2241,12 @@ yyerrlab1:
   if (yyn == YYFINAL)
     YYACCEPT;
 
-  YYDPRINTF ((stderr, "Shifting error token, "));
-
   *++yyvsp = yylval;
 
 
+  /* Shift the error token. */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
   yystate = yyn;
   goto yynewstate;
 
@@ -2257,16 +2266,25 @@ yyabortlab:
   goto yyreturn;
 
 #ifndef yyoverflow
-/*----------------------------------------------.
-| yyoverflowlab -- parser overflow comes here.  |
-`----------------------------------------------*/
-yyoverflowlab:
-  yyerror ("parser stack overflow");
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
   yyresult = 2;
   /* Fall through.  */
 #endif
 
 yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+                yytoken, &yylval);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+                 yystos[*yyssp], yyvsp);
+      YYPOPSTACK;
+    }
 #ifndef yyoverflow
   if (yyss != yyssa)
     YYSTACK_FREE (yyss);
@@ -2275,7 +2293,7 @@ yyreturn:
 }
 
 
-#line 615 "./sql.y"
+#line 643 "sql.y"
 
 
 static void *parser_alloc( void *info, unsigned int sz )
@@ -2305,7 +2323,7 @@ static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR colu
     return col;
 }
 
-int SQL_lex( void *SQL_lval, SQL_input *sql )
+static int SQL_lex( void *SQL_lval, SQL_input *sql )
 {
     int token;
     struct sql_str * str = SQL_lval;
@@ -2326,7 +2344,7 @@ int SQL_lex( void *SQL_lval, SQL_input *sql )
     while( token == TK_SPACE );
 
     /* TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); */
-    
+
     return token;
 }
 
@@ -2337,7 +2355,7 @@ LPWSTR SQL_getstring( void *info, struct sql_str *strdata )
     LPWSTR str;
 
     /* if there's quotes, remove them */
-    if( ( (p[0]=='`') && (p[len-1]=='`') ) || 
+    if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
         ( (p[0]=='\'') && (p[len-1]=='\'') ) )
     {
         p++;
@@ -2371,7 +2389,7 @@ INT SQL_getint( void *info )
     return r;
 }
 
-int SQL_error( const char *str )
+static int SQL_error( const char *str )
 {
     return 0;
 }
@@ -2399,6 +2417,19 @@ static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct e
     return e;
 }
 
+static struct expr * EXPR_unary( void *info, struct expr *l, UINT op )
+{
+    struct expr *e = parser_alloc( info, sizeof *e );
+    if( e )
+    {
+        e->type = EXPR_UNARY;
+        e->u.expr.left = l;
+        e->u.expr.op = op;
+        e->u.expr.right = NULL;
+    }
+    return e;
+}
+
 static struct expr * EXPR_column( void *info, column_info *column )
 {
     struct expr *e = parser_alloc( info, sizeof *e );
index 4726cbd..a4eb4de 100644 (file)
@@ -1,7 +1,7 @@
-/* A Bison parser, made by GNU Bison 1.875c.  */
+/* A Bison parser, made by GNU Bison 2.1.  */
 
 /* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -15,8 +15,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 /* As a special exception, when this file is copied by Bison into a
    Bison output file, you may use that output file without restriction.
    /* Put the tokens into the symbol table, so that GDB and other debuggers
       know about them.  */
    enum yytokentype {
-     TK_ABORT = 258,
-     TK_AFTER = 259,
-     TK_AGG_FUNCTION = 260,
-     TK_ALL = 261,
-     TK_AND = 262,
-     TK_AS = 263,
-     TK_ASC = 264,
-     TK_BEFORE = 265,
-     TK_BEGIN = 266,
-     TK_BETWEEN = 267,
-     TK_BITAND = 268,
-     TK_BITNOT = 269,
-     TK_BITOR = 270,
-     TK_BY = 271,
-     TK_CASCADE = 272,
-     TK_CASE = 273,
-     TK_CHAR = 274,
-     TK_CHECK = 275,
-     TK_CLUSTER = 276,
-     TK_COLLATE = 277,
-     TK_COLUMN = 278,
-     TK_COMMA = 279,
-     TK_COMMENT = 280,
-     TK_COMMIT = 281,
-     TK_CONCAT = 282,
-     TK_CONFLICT = 283,
-     TK_CONSTRAINT = 284,
-     TK_COPY = 285,
-     TK_CREATE = 286,
-     TK_DEFAULT = 287,
-     TK_DEFERRABLE = 288,
-     TK_DEFERRED = 289,
-     TK_DELETE = 290,
-     TK_DELIMITERS = 291,
-     TK_DESC = 292,
-     TK_DISTINCT = 293,
-     TK_DOT = 294,
-     TK_DROP = 295,
-     TK_EACH = 296,
-     TK_ELSE = 297,
-     TK_END = 298,
-     TK_END_OF_FILE = 299,
-     TK_EQ = 300,
-     TK_EXCEPT = 301,
-     TK_EXPLAIN = 302,
-     TK_FAIL = 303,
-     TK_FLOAT = 304,
-     TK_FOR = 305,
-     TK_FOREIGN = 306,
-     TK_FROM = 307,
-     TK_FUNCTION = 308,
-     TK_GE = 309,
-     TK_GLOB = 310,
-     TK_GROUP = 311,
-     TK_GT = 312,
-     TK_HAVING = 313,
-     TK_HOLD = 314,
-     TK_IGNORE = 315,
-     TK_ILLEGAL = 316,
-     TK_IMMEDIATE = 317,
-     TK_IN = 318,
-     TK_INDEX = 319,
-     TK_INITIALLY = 320,
-     TK_ID = 321,
-     TK_INSERT = 322,
-     TK_INSTEAD = 323,
-     TK_INT = 324,
-     TK_INTEGER = 325,
-     TK_INTERSECT = 326,
-     TK_INTO = 327,
-     TK_IS = 328,
-     TK_ISNULL = 329,
-     TK_JOIN = 330,
-     TK_JOIN_KW = 331,
-     TK_KEY = 332,
-     TK_LE = 333,
-     TK_LIKE = 334,
-     TK_LIMIT = 335,
-     TK_LONG = 336,
-     TK_LONGCHAR = 337,
-     TK_LP = 338,
-     TK_LSHIFT = 339,
-     TK_LT = 340,
-     TK_LOCALIZABLE = 341,
-     TK_MATCH = 342,
-     TK_MINUS = 343,
-     TK_NE = 344,
-     TK_NOT = 345,
-     TK_NOTNULL = 346,
-     TK_NULL = 347,
-     TK_OBJECT = 348,
-     TK_OF = 349,
-     TK_OFFSET = 350,
-     TK_ON = 351,
-     TK_OR = 352,
-     TK_ORACLE_OUTER_JOIN = 353,
-     TK_ORDER = 354,
-     TK_PLUS = 355,
-     TK_PRAGMA = 356,
-     TK_PRIMARY = 357,
-     TK_RAISE = 358,
-     TK_REFERENCES = 359,
-     TK_REM = 360,
-     TK_REPLACE = 361,
-     TK_RESTRICT = 362,
-     TK_ROLLBACK = 363,
-     TK_ROW = 364,
-     TK_RP = 365,
-     TK_RSHIFT = 366,
-     TK_SELECT = 367,
-     TK_SEMI = 368,
-     TK_SET = 369,
-     TK_SHORT = 370,
-     TK_SLASH = 371,
-     TK_SPACE = 372,
-     TK_STAR = 373,
-     TK_STATEMENT = 374,
-     TK_STRING = 375,
-     TK_TABLE = 376,
-     TK_TEMP = 377,
-     TK_THEN = 378,
-     TK_TRANSACTION = 379,
-     TK_TRIGGER = 380,
-     TK_UMINUS = 381,
-     TK_UNCLOSED_STRING = 382,
-     TK_UNION = 383,
-     TK_UNIQUE = 384,
-     TK_UPDATE = 385,
-     TK_UPLUS = 386,
-     TK_USING = 387,
-     TK_VACUUM = 388,
-     TK_VALUES = 389,
-     TK_VIEW = 390,
-     TK_WHEN = 391,
-     TK_WHERE = 392,
-     TK_WILDCARD = 393,
-     COLUMN = 395,
-     FUNCTION = 396,
-     COMMENT = 397,
-     UNCLOSED_STRING = 398,
-     SPACE = 399,
-     ILLEGAL = 400,
-     END_OF_FILE = 401
+     TK_ALTER = 258,
+     TK_AND = 259,
+     TK_BY = 260,
+     TK_CHAR = 261,
+     TK_COMMA = 262,
+     TK_CREATE = 263,
+     TK_DELETE = 264,
+     TK_DISTINCT = 265,
+     TK_DOT = 266,
+     TK_EQ = 267,
+     TK_FREE = 268,
+     TK_FROM = 269,
+     TK_GE = 270,
+     TK_GT = 271,
+     TK_HOLD = 272,
+     TK_ID = 273,
+     TK_ILLEGAL = 274,
+     TK_INSERT = 275,
+     TK_INT = 276,
+     TK_INTEGER = 277,
+     TK_INTO = 278,
+     TK_IS = 279,
+     TK_KEY = 280,
+     TK_LE = 281,
+     TK_LONG = 282,
+     TK_LONGCHAR = 283,
+     TK_LP = 284,
+     TK_LT = 285,
+     TK_LOCALIZABLE = 286,
+     TK_MINUS = 287,
+     TK_NE = 288,
+     TK_NOT = 289,
+     TK_NULL = 290,
+     TK_OBJECT = 291,
+     TK_OR = 292,
+     TK_ORDER = 293,
+     TK_PRIMARY = 294,
+     TK_RP = 295,
+     TK_SELECT = 296,
+     TK_SET = 297,
+     TK_SHORT = 298,
+     TK_SPACE = 299,
+     TK_STAR = 300,
+     TK_STRING = 301,
+     TK_TABLE = 302,
+     TK_TEMPORARY = 303,
+     TK_UPDATE = 304,
+     TK_VALUES = 305,
+     TK_WHERE = 306,
+     TK_WILDCARD = 307,
+     COLUMN = 309,
+     FUNCTION = 310,
+     COMMENT = 311,
+     UNCLOSED_STRING = 312,
+     SPACE = 313,
+     ILLEGAL = 314,
+     END_OF_FILE = 315,
+     TK_LIKE = 316,
+     TK_NEGATION = 317
    };
 #endif
-#define TK_ABORT 258
-#define TK_AFTER 259
-#define TK_AGG_FUNCTION 260
-#define TK_ALL 261
-#define TK_AND 262
-#define TK_AS 263
-#define TK_ASC 264
-#define TK_BEFORE 265
-#define TK_BEGIN 266
-#define TK_BETWEEN 267
-#define TK_BITAND 268
-#define TK_BITNOT 269
-#define TK_BITOR 270
-#define TK_BY 271
-#define TK_CASCADE 272
-#define TK_CASE 273
-#define TK_CHAR 274
-#define TK_CHECK 275
-#define TK_CLUSTER 276
-#define TK_COLLATE 277
-#define TK_COLUMN 278
-#define TK_COMMA 279
-#define TK_COMMENT 280
-#define TK_COMMIT 281
-#define TK_CONCAT 282
-#define TK_CONFLICT 283
-#define TK_CONSTRAINT 284
-#define TK_COPY 285
-#define TK_CREATE 286
-#define TK_DEFAULT 287
-#define TK_DEFERRABLE 288
-#define TK_DEFERRED 289
-#define TK_DELETE 290
-#define TK_DELIMITERS 291
-#define TK_DESC 292
-#define TK_DISTINCT 293
-#define TK_DOT 294
-#define TK_DROP 295
-#define TK_EACH 296
-#define TK_ELSE 297
-#define TK_END 298
-#define TK_END_OF_FILE 299
-#define TK_EQ 300
-#define TK_EXCEPT 301
-#define TK_EXPLAIN 302
-#define TK_FAIL 303
-#define TK_FLOAT 304
-#define TK_FOR 305
-#define TK_FOREIGN 306
-#define TK_FROM 307
-#define TK_FUNCTION 308
-#define TK_GE 309
-#define TK_GLOB 310
-#define TK_GROUP 311
-#define TK_GT 312
-#define TK_HAVING 313
-#define TK_HOLD 314
-#define TK_IGNORE 315
-#define TK_ILLEGAL 316
-#define TK_IMMEDIATE 317
-#define TK_IN 318
-#define TK_INDEX 319
-#define TK_INITIALLY 320
-#define TK_ID 321
-#define TK_INSERT 322
-#define TK_INSTEAD 323
-#define TK_INT 324
-#define TK_INTEGER 325
-#define TK_INTERSECT 326
-#define TK_INTO 327
-#define TK_IS 328
-#define TK_ISNULL 329
-#define TK_JOIN 330
-#define TK_JOIN_KW 331
-#define TK_KEY 332
-#define TK_LE 333
-#define TK_LIKE 334
-#define TK_LIMIT 335
-#define TK_LONG 336
-#define TK_LONGCHAR 337
-#define TK_LP 338
-#define TK_LSHIFT 339
-#define TK_LT 340
-#define TK_LOCALIZABLE 341
-#define TK_MATCH 342
-#define TK_MINUS 343
-#define TK_NE 344
-#define TK_NOT 345
-#define TK_NOTNULL 346
-#define TK_NULL 347
-#define TK_OBJECT 348
-#define TK_OF 349
-#define TK_OFFSET 350
-#define TK_ON 351
-#define TK_OR 352
-#define TK_ORACLE_OUTER_JOIN 353
-#define TK_ORDER 354
-#define TK_PLUS 355
-#define TK_PRAGMA 356
-#define TK_PRIMARY 357
-#define TK_RAISE 358
-#define TK_REFERENCES 359
-#define TK_REM 360
-#define TK_REPLACE 361
-#define TK_RESTRICT 362
-#define TK_ROLLBACK 363
-#define TK_ROW 364
-#define TK_RP 365
-#define TK_RSHIFT 366
-#define TK_SELECT 367
-#define TK_SEMI 368
-#define TK_SET 369
-#define TK_SHORT 370
-#define TK_SLASH 371
-#define TK_SPACE 372
-#define TK_STAR 373
-#define TK_STATEMENT 374
-#define TK_STRING 375
-#define TK_TABLE 376
-#define TK_TEMP 377
-#define TK_THEN 378
-#define TK_TRANSACTION 379
-#define TK_TRIGGER 380
-#define TK_UMINUS 381
-#define TK_UNCLOSED_STRING 382
-#define TK_UNION 383
-#define TK_UNIQUE 384
-#define TK_UPDATE 385
-#define TK_UPLUS 386
-#define TK_USING 387
-#define TK_VACUUM 388
-#define TK_VALUES 389
-#define TK_VIEW 390
-#define TK_WHEN 391
-#define TK_WHERE 392
-#define TK_WILDCARD 393
-#define COLUMN 395
-#define FUNCTION 396
-#define COMMENT 397
-#define UNCLOSED_STRING 398
-#define SPACE 399
-#define ILLEGAL 400
-#define END_OF_FILE 401
+/* Tokens.  */
+#define TK_ALTER 258
+#define TK_AND 259
+#define TK_BY 260
+#define TK_CHAR 261
+#define TK_COMMA 262
+#define TK_CREATE 263
+#define TK_DELETE 264
+#define TK_DISTINCT 265
+#define TK_DOT 266
+#define TK_EQ 267
+#define TK_FREE 268
+#define TK_FROM 269
+#define TK_GE 270
+#define TK_GT 271
+#define TK_HOLD 272
+#define TK_ID 273
+#define TK_ILLEGAL 274
+#define TK_INSERT 275
+#define TK_INT 276
+#define TK_INTEGER 277
+#define TK_INTO 278
+#define TK_IS 279
+#define TK_KEY 280
+#define TK_LE 281
+#define TK_LONG 282
+#define TK_LONGCHAR 283
+#define TK_LP 284
+#define TK_LT 285
+#define TK_LOCALIZABLE 286
+#define TK_MINUS 287
+#define TK_NE 288
+#define TK_NOT 289
+#define TK_NULL 290
+#define TK_OBJECT 291
+#define TK_OR 292
+#define TK_ORDER 293
+#define TK_PRIMARY 294
+#define TK_RP 295
+#define TK_SELECT 296
+#define TK_SET 297
+#define TK_SHORT 298
+#define TK_SPACE 299
+#define TK_STAR 300
+#define TK_STRING 301
+#define TK_TABLE 302
+#define TK_TEMPORARY 303
+#define TK_UPDATE 304
+#define TK_VALUES 305
+#define TK_WHERE 306
+#define TK_WILDCARD 307
+#define COLUMN 309
+#define FUNCTION 310
+#define COMMENT 311
+#define UNCLOSED_STRING 312
+#define SPACE 313
+#define ILLEGAL 314
+#define END_OF_FILE 315
+#define TK_LIKE 316
+#define TK_NEGATION 317
 
 
 
 
 #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
-#line 72 "./sql.y"
+#line 73 "sql.y"
 typedef union YYSTYPE {
     struct sql_str str;
     LPWSTR string;
@@ -332,8 +165,8 @@ typedef union YYSTYPE {
     USHORT column_type;
     int integer;
 } YYSTYPE;
-/* Line 1275 of yacc.c.  */
-#line 337 "sql.tab.h"
+/* Line 1447 of yacc.c.  */
+#line 170 "sql.tab.h"
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 # define YYSTYPE_IS_TRIVIAL 1
index abffb2f..17cb957 100644 (file)
@@ -59,6 +59,7 @@ static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR colu
 static BOOL SQL_MarkPrimaryKeys( column_info *cols, column_info *keys);
 
 static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r );
+static struct expr * EXPR_unary( void *info, struct expr *l, UINT op );
 static struct expr * EXPR_column( void *info, column_info *column );
 static struct expr * EXPR_ival( void *info, int val );
 static struct expr * EXPR_sval( void *info, struct sql_str * );
@@ -79,40 +80,17 @@ static struct expr * EXPR_wildcard( void *info );
     int integer;
 }
 
-%token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_ALTER TK_AND TK_AS TK_ASC
-%token TK_BEFORE TK_BEGIN TK_BETWEEN TK_BITAND TK_BITNOT TK_BITOR TK_BY
-%token TK_CASCADE TK_CASE TK_CHAR TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN
-%token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
-%token TK_CONSTRAINT TK_COPY TK_CREATE
-%token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
-%token TK_DISTINCT TK_DOT TK_DROP TK_EACH
-%token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
-%token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FREE TK_FROM TK_FUNCTION
-%token TK_GE TK_GLOB TK_GROUP TK_GT
-%token TK_HAVING TK_HOLD
-%token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
-%token <str> TK_ID 
-%token TK_INSERT TK_INSTEAD TK_INT 
+%token TK_ALTER TK_AND TK_BY TK_CHAR TK_COMMA TK_CREATE TK_DELETE
+%token TK_DISTINCT TK_DOT TK_EQ TK_FREE TK_FROM TK_GE TK_GT TK_HOLD
+%token <str> TK_ID
+%token TK_ILLEGAL TK_INSERT TK_INT
 %token <str> TK_INTEGER
-%token TK_INTERSECT TK_INTO TK_IS
-%token TK_ISNULL
-%token TK_JOIN TK_JOIN_KW
-%token TK_KEY
-%token TK_LE TK_LIKE TK_LIMIT TK_LONG TK_LONGCHAR TK_LP TK_LSHIFT TK_LT
-%token TK_LOCALIZABLE
-%token TK_MATCH TK_MINUS
-%token TK_NE TK_NOT TK_NOTNULL TK_NULL
-%token TK_OBJECT TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
-%token TK_PLUS TK_PRAGMA TK_PRIMARY
-%token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
-%token TK_ROW TK_RP TK_RSHIFT
-%token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT 
+%token TK_INTO TK_IS TK_KEY TK_LE TK_LONG TK_LONGCHAR TK_LP TK_LT
+%token TK_LOCALIZABLE TK_MINUS TK_NE TK_NOT TK_NULL
+%token TK_OBJECT TK_OR TK_ORDER TK_PRIMARY TK_RP
+%token TK_SELECT TK_SET TK_SHORT TK_SPACE TK_STAR
 %token <str> TK_STRING
-%token TK_TABLE TK_TEMPORARY TK_THEN TK_TRANSACTION TK_TRIGGER
-%token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
-%token TK_UPDATE TK_UPLUS TK_USING
-%token TK_VACUUM TK_VALUES TK_VIEW
-%token TK_WHEN TK_WHERE TK_WILDCARD
+%token TK_TABLE TK_TEMPORARY TK_UPDATE TK_VALUES TK_WHERE TK_WILDCARD
 
 /*
  * These are extra tokens used by the lexer but never seen by the
@@ -126,7 +104,7 @@ static struct expr * EXPR_wildcard( void *info );
 %type <string> table id
 %type <column_list> selcollist column column_and_type column_def table_def
 %type <column_list> column_assignment update_assign_list constlist
-%type <query> query multifrom from fromtable selectfrom unorderedsel
+%type <query> query from fromtable selectfrom unorderedsel
 %type <query> oneupdate onedelete oneselect onequery onecreate oneinsert onealter
 %type <expr> expr val column_val const_val
 %type <column_type> column_type data_type data_type_l data_count
@@ -136,8 +114,7 @@ static struct expr * EXPR_wildcard( void *info );
 %left TK_OR
 %left TK_AND
 %left TK_NOT
-%left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_ISNULL TK_LIKE TK_BETWEEN TK_IN
-%left TK_PLUS TK_MINUS TK_CONCAT
+%left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE
 %right TK_NEGATION
 
 %%
@@ -163,10 +140,10 @@ oneinsert:
     TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP
         {
             SQL_input *sql = (SQL_input*) info;
-            MSIVIEW *insert = NULL; 
+            MSIVIEW *insert = NULL;
             UINT r;
 
-            r = INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE ); 
+            r = INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
             if( !insert )
                 YYABORT;
             $$ = insert;
@@ -174,9 +151,9 @@ oneinsert:
   | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMPORARY
         {
             SQL_input *sql = (SQL_input*) info;
-            MSIVIEW *insert = NULL; 
+            MSIVIEW *insert = NULL;
 
-            INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE ); 
+            INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
             if( !insert )
                 YYABORT;
             $$ = insert;
@@ -187,7 +164,7 @@ onecreate:
     TK_CREATE TK_TABLE table TK_LP table_def TK_RP
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *create = NULL; 
+            MSIVIEW *create = NULL;
 
             if( !$5 )
                 YYABORT;
@@ -199,7 +176,7 @@ onecreate:
   | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *create = NULL; 
+            MSIVIEW *create = NULL;
 
             if( !$5 )
                 YYABORT;
@@ -214,20 +191,30 @@ oneupdate:
     TK_UPDATE table TK_SET update_assign_list TK_WHERE expr
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *update = NULL; 
+            MSIVIEW *update = NULL;
 
             UPDATE_CreateView( sql->db, &update, $2, $4, $6 );
             if( !update )
                 YYABORT;
             $$ = update;
         }
+  | TK_UPDATE table TK_SET update_assign_list
+        {
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *update = NULL;
+
+            UPDATE_CreateView( sql->db, &update, $2, $4, NULL );
+            if( !update )
+                YYABORT;
+            $$ = update;
+        }
     ;
 
 onedelete:
     TK_DELETE from
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *delete = NULL; 
+            MSIVIEW *delete = NULL;
 
             DELETE_CreateView( sql->db, &delete, $2 );
             if( !delete )
@@ -398,7 +385,7 @@ unorderedsel:
     ;
 
 selectfrom:
-    selcollist multifrom 
+    selcollist from
         {
             SQL_input* sql = (SQL_input*) info;
             UINT r;
@@ -419,9 +406,9 @@ selectfrom:
     ;
 
 selcollist:
-    column 
+    column
   | column TK_COMMA selcollist
-        { 
+        {
             $1->next = $3;
         }
   | TK_STAR
@@ -430,24 +417,10 @@ selcollist:
         }
     ;
 
-multifrom:
-    from
-  | TK_FROM table TK_COMMA table TK_WHERE expr
-        {
-            SQL_input* sql = (SQL_input*) info;
-            UINT r;
-
-            /* only support inner joins on two tables */
-            r = JOIN_CreateView( sql->db, &$$, $2, $4, $6 );
-            if( r != ERROR_SUCCESS )
-                YYABORT;
-        }
-    ;
-
 from:
     fromtable
   | fromtable TK_WHERE expr
-        { 
+        {
             SQL_input* sql = (SQL_input*) info;
             UINT r;
 
@@ -472,6 +445,16 @@ fromtable:
             if( r != ERROR_SUCCESS || !$$ )
                 YYABORT;
         }
+  | TK_FROM table TK_COMMA table
+        {
+            SQL_input* sql = (SQL_input*) info;
+            UINT r;
+
+            /* only support inner joins on two tables */
+            r = JOIN_CreateView( sql->db, &$$, $2, $4 );
+            if( r != ERROR_SUCCESS )
+                YYABORT;
+        }
     ;
 
 expr:
@@ -531,13 +514,13 @@ expr:
         }
   | column_val TK_IS TK_NULL
         {
-            $$ = EXPR_complex( info, $1, OP_ISNULL, NULL );
+            $$ = EXPR_unary( info, $1, OP_ISNULL );
             if( !$$ )
                 YYABORT;
         }
   | column_val TK_IS TK_NOT TK_NULL
         {
-            $$ = EXPR_complex( info, $1, OP_NOTNULL, NULL );
+            $$ = EXPR_unary( info, $1, OP_NOTNULL );
             if( !$$ )
                 YYABORT;
         }
@@ -611,7 +594,7 @@ const_val:
     ;
 
 column_val:
-    column 
+    column
         {
             $$ = EXPR_column( info, $1 );
             if( !$$ )
@@ -707,7 +690,7 @@ static int sql_lex( void *SQL_lval, SQL_input *sql )
     while( token == TK_SPACE );
 
     /* TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); */
-    
+
     return token;
 }
 
@@ -718,7 +701,7 @@ LPWSTR SQL_getstring( void *info, struct sql_str *strdata )
     LPWSTR str;
 
     /* if there's quotes, remove them */
-    if( ( (p[0]=='`') && (p[len-1]=='`') ) || 
+    if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
         ( (p[0]=='\'') && (p[len-1]=='\'') ) )
     {
         p++;
@@ -780,6 +763,19 @@ static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct e
     return e;
 }
 
+static struct expr * EXPR_unary( void *info, struct expr *l, UINT op )
+{
+    struct expr *e = parser_alloc( info, sizeof *e );
+    if( e )
+    {
+        e->type = EXPR_UNARY;
+        e->u.expr.left = l;
+        e->u.expr.op = op;
+        e->u.expr.right = NULL;
+    }
+    return e;
+}
+
 static struct expr * EXPR_column( void *info, column_info *column )
 {
     struct expr *e = parser_alloc( info, sizeof *e );
index 5d51e4f..f7f5787 100644 (file)
@@ -96,7 +96,7 @@ static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
 
     for( i = 0; i < MSI_MAX_PROPS; i++ )
         free_prop( &si->property[i] );
-    msiobj_release( &si->db->hdr );
+    IStorage_Release( si->storage );
 }
 
 static UINT get_type( UINT uiProperty )
@@ -105,7 +105,7 @@ static UINT get_type( UINT uiProperty )
     {
     case PID_CODEPAGE:
          return VT_I2;
-    
+
     case PID_SUBJECT:
     case PID_AUTHOR:
     case PID_KEYWORDS:
@@ -405,28 +405,28 @@ static UINT save_summary_info( MSISUMMARYINFO * si, IStream *stm )
     return ERROR_SUCCESS;
 }
 
-MSISUMMARYINFO *MSI_GetSummaryInformationW( MSIDATABASE *db, UINT uiUpdateCount )
+MSISUMMARYINFO *MSI_GetSummaryInformationW( IStorage *stg, UINT uiUpdateCount )
 {
     IStream *stm = NULL;
     MSISUMMARYINFO *si;
     DWORD grfMode;
     HRESULT r;
 
-    TRACE("%p %d\n", db, uiUpdateCount );
+    TRACE("%p %d\n", stg, uiUpdateCount );
 
     si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, 
                   sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
     if( !si )
         return si;
 
-    msiobj_addref( &db->hdr );
-    si->db = db;
     memset( &si->property, 0, sizeof si->property );
     si->update_count = uiUpdateCount;
+    IStorage_AddRef( stg );
+    si->storage = stg;
 
     /* read the stream... if we fail, we'll start with an empty property set */
     grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
-    r = IStorage_OpenStream( si->db->storage, szSumInfo, 0, grfMode, 0, &stm );
+    r = IStorage_OpenStream( si->storage, szSumInfo, 0, grfMode, 0, &stm );
     if( SUCCEEDED(r) )
     {
         load_summary_info( si, stm );
@@ -462,7 +462,7 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
             return ERROR_INVALID_PARAMETER;
     }
 
-    si = MSI_GetSummaryInformationW( db, uiUpdateCount );
+    si = MSI_GetSummaryInformationW( db->storage, uiUpdateCount );
     if (si)
     {
         *pHandle = alloc_msihandle( &si->hdr );
@@ -602,6 +602,22 @@ LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty )
     return strdupAtoW( prop->u.pszVal );
 }
 
+LPWSTR msi_get_suminfo_product( IStorage *stg )
+{
+    MSISUMMARYINFO *si;
+    LPWSTR prod;
+
+    si = MSI_GetSummaryInformationW( stg, 0 );
+    if (!si)
+    {
+        ERR("no summary information!\n");
+        return NULL;
+    }
+    prod = msi_suminfo_dup_string( si, PID_REVNUMBER );
+    msiobj_release( &si->hdr );
+    return prod;
+}
+
 UINT WINAPI MsiSummaryInfoGetPropertyA(
       MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
       FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf)
@@ -749,7 +765,7 @@ UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
         return ERROR_INVALID_HANDLE;
 
     grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
-    r = IStorage_CreateStream( si->db->storage, szSumInfo, grfMode, 0, 0, &stm );
+    r = IStorage_CreateStream( si->storage, szSumInfo, grfMode, 0, 0, &stm );
     if( SUCCEEDED(r) )
     {
         ret = save_summary_info( si, stm );
index 8d416f2..c66048a 100644 (file)
@@ -1101,7 +1101,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
     {
     case 4:
         offset = tv->columns[col-1].offset/2;
-        *val = tv->table->data[row][offset] + 
+        *val = tv->table->data[row][offset] +
                (tv->table->data[row][offset + 1] << 16);
         break;
     case 2:
@@ -1186,9 +1186,8 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
     return r;
 }
 
-static UINT TABLE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
+static UINT TABLE_set_int( MSITABLEVIEW *tv, UINT row, UINT col, UINT val )
 {
-    MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
     UINT offset, n;
 
     if( !tv->table )
@@ -1223,6 +1222,61 @@ static UINT TABLE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val
     return ERROR_SUCCESS;
 }
 
+static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
+{
+    MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
+    UINT i, val, r = ERROR_SUCCESS;
+
+    if ( !tv->table )
+        return ERROR_INVALID_PARAMETER;
+
+    /* test if any of the mask bits are invalid */
+    if ( mask >= (1<<tv->num_cols) )
+        return ERROR_INVALID_PARAMETER;
+
+    for ( i = 0; i < tv->num_cols; i++ )
+    {
+        /* only update the fields specified in the mask */
+        if ( !(mask&(1<<i)) )
+            continue;
+
+        /* FIXME: should we allow updating keys? */
+
+        val = 0;
+        if ( !MSI_RecordIsNull( rec, i + 1 ) )
+        {
+            if ( MSITYPE_IS_BINARY(tv->columns[ i ].type) )
+            {
+                val = 1; /* refers to the first key column */
+            }
+            else if ( tv->columns[i].type & MSITYPE_STRING )
+            {
+                LPCWSTR sval = MSI_RecordGetString( rec, i + 1 );
+                val = msi_addstringW( tv->db->strings, 0, sval, -1, 1 );
+            }
+            else if ( 2 == bytes_per_column( &tv->columns[ i ] ) )
+            {
+                val = 0x8000 + MSI_RecordGetInteger( rec, i + 1 );
+                if ( val & 0xffff0000 )
+                {
+                    ERR("field %u value %d out of range\n", i+1, val - 0x8000 );
+                    return ERROR_FUNCTION_FAILED;
+                }
+            }
+            else
+            {
+                INT ival = MSI_RecordGetInteger( rec, i + 1 );
+                val = ival ^ 0x80000000;
+            }
+        }
+
+        r = TABLE_set_int( tv, row, i+1, val );
+        if ( r != ERROR_SUCCESS )
+            break;
+    }
+    return r;
+}
+
 static UINT table_create_new_row( struct tagMSIVIEW *view, UINT *num )
 {
     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
@@ -1365,41 +1419,6 @@ static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
     return ERROR_SUCCESS;
 }
 
-static UINT msi_table_modify_row( MSITABLEVIEW *tv, MSIRECORD *rec,
-                                  UINT row, UINT mask )
-{
-    UINT i, val, r = ERROR_SUCCESS;
-
-    TRACE("%p %p %u %08x\n", tv, rec, row, mask );
-
-    for( i = 0; i < tv->num_cols; i++ )
-    {
-        /* set keys or values specified in the mask */
-        if( (~tv->columns[i].type & MSITYPE_KEY) && (~mask & (1<<i)) )
-            continue;
-
-        if( (tv->columns[i].type & MSITYPE_STRING) &&
-            ! MSITYPE_IS_BINARY(tv->columns[i].type) )
-        {
-            const WCHAR *str = MSI_RecordGetString( rec, i+1 );
-            val = msi_addstringW( tv->db->strings, 0, str, -1, 1 );
-        }
-        else
-        {
-            val = MSI_RecordGetInteger( rec, i+1 );
-            if ( 2 == bytes_per_column( &tv->columns[i] ) )
-                val ^= 0x8000;
-            else
-                val ^= 0x80000000;
-        }
-        r = TABLE_set_int( &tv->view, row, i+1, val );
-        if( r )
-            break;
-    }
-
-    return r;
-}
-
 static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec )
 {
     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
@@ -1417,7 +1436,7 @@ static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec )
     if( r != ERROR_SUCCESS )
         return r;
 
-    return msi_table_modify_row( tv, rec, row, ~0 );
+    return TABLE_set_row( view, row, rec, (1<<tv->num_cols) - 1 );
 }
 
 static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
@@ -1568,12 +1587,12 @@ static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
     if( !*handle )
         entry = tv->columns[col-1].hash_table[val % MSITABLE_HASH_TABLE_SIZE];
     else
-        entry = ((const MSICOLUMNHASHENTRY *)*handle)->next;
+        entry = (*handle)->next;
 
     while (entry && entry->value != val)
         entry = entry->next;
 
-    *handle = (MSIITERHANDLE)entry;
+    *handle = entry;
     if (!entry)
         return ERROR_NO_MORE_ITEMS;
 
@@ -1586,7 +1605,7 @@ static const MSIVIEWOPS table_ops =
 {
     TABLE_fetch_int,
     TABLE_fetch_stream,
-    TABLE_set_int,
+    TABLE_set_row,
     TABLE_insert_row,
     TABLE_execute,
     TABLE_close,
@@ -1872,8 +1891,9 @@ static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
 static UINT msi_delete_row( MSITABLEVIEW *tv, UINT row )
 {
     UINT i;
+
     for( i=1; i<=tv->num_cols; i++ )
-        tv->view.ops->set_int( &tv->view, row, i, 0 );
+        TABLE_set_int( tv, row, i, 0 );
     return ERROR_SUCCESS;
 }
 
@@ -1995,7 +2015,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
                 else if ( mask )
                 {
                     TRACE("modifying row [%d]:\n", row);
-                    msi_table_modify_row( tv, rec, row, mask );
+                    TABLE_set_row( &tv->view, row, rec, mask );
                 }
                 else
                 {
@@ -2045,7 +2065,7 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
         goto end;
 
     /*
-     * Apply _Tables and _Coluimns transforms first so that
+     * Apply _Tables and _Columns transforms first so that
      * the table metadata is correct, and empty tables exist.
      */
     ret = msi_table_load_transform( db, stg, strings, szTables );
@@ -2081,14 +2101,7 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
     }
 
     if ( ret == ERROR_SUCCESS )
-    {
-        MSITRANSFORM *t;
-
-        t = msi_alloc( sizeof *t );
-        t->stg = stg;
-        IStorage_AddRef( stg );
-        list_add_tail( &db->transforms, &t->entry );
-    }
+        append_storage_to_db( db, stg );
 
 end:
     if ( stgenum )
@@ -2099,6 +2112,16 @@ end:
     return ret;
 }
 
+void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
+{
+    MSITRANSFORM *t;
+
+    t = msi_alloc( sizeof *t );
+    t->stg = stg;
+    IStorage_AddRef( stg );
+    list_add_tail( &db->transforms, &t->entry );
+}
+
 void msi_free_transforms( MSIDATABASE *db )
 {
     while( !list_empty( &db->transforms ) )
index a63dd1f..96aa67c 100644 (file)
@@ -38,224 +38,89 @@ struct Keyword {
 
 #define MAX_TOKEN_LEN 11
 
-static const WCHAR ABORT_W[] = { 'A','B','O','R','T',0 };
-static const WCHAR AFTER_W[] = { 'A','F','T','E','R',0 };
 static const WCHAR ALTER_W[] = { 'A','L','T','E','R',0 };
-static const WCHAR ALL_W[] = { 'A','L','L',0 };
 static const WCHAR AND_W[] = { 'A','N','D',0 };
-static const WCHAR AS_W[] = { 'A','S',0 };
-static const WCHAR ASC_W[] = { 'A','S','C',0 };
-static const WCHAR BEFORE_W[] = { 'B','E','F','O','R','E',0 };
-static const WCHAR BEGIN_W[] = { 'B','E','G','I','N','W',0 };
-static const WCHAR BETWEEN_W[] = { 'B','E','T','W','E','E','N',0 };
 static const WCHAR BY_W[] = { 'B','Y',0 };
-static const WCHAR CASCADE_W[] = { 'C','A','S','C','A','D','E',0 };
-static const WCHAR CASE_W[] = { 'C','A','S','E',0 };
 static const WCHAR CHAR_W[] = { 'C','H','A','R',0 };
 static const WCHAR CHARACTER_W[] = { 'C','H','A','R','A','C','T','E','R',0 };
-static const WCHAR CHECK_W[] = { 'C','H','E','C','K',0 };
-static const WCHAR CLUSTER_W[] = { 'C','L','U','S','T','E','R',0 };
-static const WCHAR COLLATE_W[] = { 'C','O','L','L','A','T','E',0 };
-static const WCHAR COMMIT_W[] = { 'C','O','M','M','I','T',0 };
-static const WCHAR CONFLICT_W[] = { 'C','O','N','F','L','I','C','T',0 };
-static const WCHAR CONSTRAINT_W[] = { 'C','O','N','S','T','R','A','I','N','T',0 };
-static const WCHAR COPY_W[] = { 'C','O','P','Y',0 };
 static const WCHAR CREATE_W[] = { 'C','R','E','A','T','E',0 };
 static const WCHAR CROSS_W[] = { 'C','R','O','S','S',0 };
-static const WCHAR DEFAULT_W[] = { 'D','E','F','A','U','L','T',0 };
-static const WCHAR DEFERRED_W[] = { 'D','E','F','E','R','R','E','D',0 };
-static const WCHAR DEFERRABLE_W[] = { 'D','E','F','E','R','R','A','B','L','E',0 };
 static const WCHAR DELETE_W[] = { 'D','E','L','E','T','E',0 };
-static const WCHAR DELIMITERS_W[] = { 'D','E','L','I','M','I','T','E','R','S',0 };
-static const WCHAR DESC_W[] = { 'D','E','S','C',0 };
 static const WCHAR DISTINCT_W[] = { 'D','I','S','T','I','N','C','T',0 };
-static const WCHAR DROP_W[] = { 'D','R','O','P',0 };
-static const WCHAR END_W[] = { 'E','N','D',0 };
-static const WCHAR EACH_W[] = { 'E','A','C','H',0 };
-static const WCHAR ELSE_W[] = { 'E','L','S','E',0 };
-static const WCHAR EXCEPT_W[] = { 'E','X','C','E','P','T',0 };
-static const WCHAR EXPLAIN_W[] = { 'E','X','P','L','A','I','N',0 };
-static const WCHAR FAIL_W[] = { 'F','A','I','L',0 };
-static const WCHAR FOR_W[] = { 'F','O','R',0 };
-static const WCHAR FOREIGN_W[] = { 'F','O','R','E','I','G','N',0 };
 static const WCHAR FREE_W[] = { 'F','R','E','E',0 };
 static const WCHAR FROM_W[] = { 'F','R','O','M',0 };
 static const WCHAR FULL_W[] = { 'F','U','L','L',0 };
-static const WCHAR GLOB_W[] = { 'G','L','O','B',0 };
-static const WCHAR GROUP_W[] = { 'G','R','O','U','P',0 };
-static const WCHAR HAVING_W[] = { 'H','A','V','I','N','G',0 };
 static const WCHAR HOLD_W[] = { 'H','O','L','D',0 };
-static const WCHAR IGNORE_W[] = { 'I','G','N','O','R','E',0 };
-static const WCHAR IMMEDIATE_W[] = { 'I','M','M','E','D','I','A','T','E',0 };
-static const WCHAR IN_W[] = { 'I','N',0 };
-static const WCHAR INDEX_W[] = { 'I','N','D','E','X',0 };
-static const WCHAR INITIALLY_W[] = { 'I','N','I','T','I','A','L','L','Y',0 };
 static const WCHAR INNER_W[] = { 'I','N','N','E','R',0 };
 static const WCHAR INSERT_W[] = { 'I','N','S','E','R','T',0 };
-static const WCHAR INSTEAD_W[] = { 'I','N','S','T','E','A','D',0 };
 static const WCHAR INT_W[] = { 'I','N','T',0 };
-static const WCHAR INTERSECT_W[] = { 'I','N','T','E','R','S','E','C','T',0 };
+static const WCHAR INTEGER_W[] = { 'I','N','T','E','G','E','R',0 };
 static const WCHAR INTO_W[] = { 'I','N','T','O',0 };
 static const WCHAR IS_W[] = { 'I','S',0 };
-static const WCHAR ISNULL_W[] = { 'I','S','N','U','L','L',0 };
 static const WCHAR JOIN_W[] = { 'J','O','I','N',0 };
 static const WCHAR KEY_W[] = { 'K','E','Y',0 };
 static const WCHAR LEFT_W[] = { 'L','E','F','T',0 };
 static const WCHAR LIKE_W[] = { 'L','I','K','E',0 };
-static const WCHAR LIMIT_W[] = { 'L','I','M','I','T',0 };
 static const WCHAR LOCALIZABLE_W[] = { 'L','O','C','A','L','I','Z','A','B','L','E',0 };
 static const WCHAR LONG_W[] = { 'L','O','N','G',0 };
 static const WCHAR LONGCHAR_W[] = { 'L','O','N','G','C','H','A','R',0 };
-static const WCHAR MATCH_W[] = { 'M','A','T','C','H',0 };
 static const WCHAR NATURAL_W[] = { 'N','A','T','U','R','A','L',0 };
 static const WCHAR NOT_W[] = { 'N','O','T',0 };
-static const WCHAR NOTNULL_W[] = { 'N','O','T','N','U','L','L',0 };
 static const WCHAR NULL_W[] = { 'N','U','L','L',0 };
 static const WCHAR OBJECT_W[] = { 'O','B','J','E','C','T',0 };
-static const WCHAR OF_W[] = { 'O','F',0 };
-static const WCHAR OFFSET_W[] = { 'O','F','F','S','E','T',0 };
-static const WCHAR ON_W[] = { 'O','N',0 };
 static const WCHAR OR_W[] = { 'O','R',0 };
 static const WCHAR ORDER_W[] = { 'O','R','D','E','R',0 };
 static const WCHAR OUTER_W[] = { 'O','U','T','E','R',0 };
-static const WCHAR PRAGMA_W[] = { 'P','R','A','G','M','A',0 };
 static const WCHAR PRIMARY_W[] = { 'P','R','I','M','A','R','Y',0 };
-static const WCHAR RAISE_W[] = { 'R','A','I','S','E',0 };
-static const WCHAR REFERENCES_W[] = { 'R','E','F','E','R','E','N','C','E','S',0 };
-static const WCHAR REPLACE_W[] = { 'R','E','P','L','A','C','E',0 };
-static const WCHAR RESTRICT_W[] = { 'R','E','S','T','R','I','C','T',0 };
 static const WCHAR RIGHT_W[] = { 'R','I','G','H','T',0 };
-static const WCHAR ROLLBACK_W[] = { 'R','O','L','L','B','A','C','K',0 };
-static const WCHAR ROW_W[] = { 'R','O','W',0 };
 static const WCHAR SELECT_W[] = { 'S','E','L','E','C','T',0 };
 static const WCHAR SET_W[] = { 'S','E','T',0 };
 static const WCHAR SHORT_W[] = { 'S','H','O','R','T',0 };
-static const WCHAR STATEMENT_W[] = { 'S','T','A','T','E','M','E','N','T',0 };
 static const WCHAR TABLE_W[] = { 'T','A','B','L','E',0 };
 static const WCHAR TEMP_W[] = { 'T','E','M','P',0 };
 static const WCHAR TEMPORARY_W[] = { 'T','E','M','P','O','R','A','R','Y',0 };
-static const WCHAR THEN_W[] = { 'T','H','E','N',0 };
-static const WCHAR TRANSACTION_W[] = { 'T','R','A','N','S','A','C','T','I','O','N',0 };
-static const WCHAR TRIGGER_W[] = { 'T','R','I','G','G','E','R',0 };
-static const WCHAR UNION_W[] = { 'U','N','I','O','N',0 };
-static const WCHAR UNIQUE_W[] = { 'U','N','I','Q','U','E',0 };
 static const WCHAR UPDATE_W[] = { 'U','P','D','A','T','E',0 };
-static const WCHAR USING_W[] = { 'U','S','I','N','G',0 };
-static const WCHAR VACUUM_W[] = { 'V','A','C','U','U','M',0 };
 static const WCHAR VALUES_W[] = { 'V','A','L','U','E','S',0 };
-static const WCHAR VIEW_W[] = { 'V','I','E','W',0 };
-static const WCHAR WHEN_W[] = { 'W','H','E','N',0 };
 static const WCHAR WHERE_W[] = { 'W','H','E','R','E',0 };
 
 /*
 ** These are the keywords
 */
 static const Keyword aKeywordTable[] = {
-  { ABORT_W, TK_ABORT },
-  { AFTER_W, TK_AFTER },
   /*{ ALTER_W, TK_ALTER },*/
-  { ALL_W, TK_ALL },
   { AND_W, TK_AND },
-  { AS_W, TK_AS },
-  { ASC_W, TK_ASC },
-  { BEFORE_W, TK_BEFORE },
-  { BEGIN_W, TK_BEGIN },
-  { BETWEEN_W, TK_BETWEEN },
   { BY_W, TK_BY },
-  { CASCADE_W, TK_CASCADE },
-  { CASE_W, TK_CASE },
   { CHAR_W, TK_CHAR },
   { CHARACTER_W, TK_CHAR },
-  { CHECK_W, TK_CHECK },
-  { CLUSTER_W, TK_CLUSTER },
-  { COLLATE_W, TK_COLLATE },
-  { COMMIT_W, TK_COMMIT },
-  { CONFLICT_W, TK_CONFLICT },
-  { CONSTRAINT_W, TK_CONSTRAINT },
-  { COPY_W, TK_COPY },
   { CREATE_W, TK_CREATE },
-  { CROSS_W, TK_JOIN_KW },
-  { DEFAULT_W, TK_DEFAULT },
-  { DEFERRED_W, TK_DEFERRED },
-  { DEFERRABLE_W, TK_DEFERRABLE },
   { DELETE_W, TK_DELETE },
-  { DELIMITERS_W, TK_DELIMITERS },
-  { DESC_W, TK_DESC },
   { DISTINCT_W, TK_DISTINCT },
-  { DROP_W, TK_DROP },
-  { END_W, TK_END },
-  { EACH_W, TK_EACH },
-  { ELSE_W, TK_ELSE },
-  { EXCEPT_W, TK_EXCEPT },
-  { EXPLAIN_W, TK_EXPLAIN },
-  { FAIL_W, TK_FAIL },
-  { FOR_W, TK_FOR },
-  { FOREIGN_W, TK_FOREIGN },
+  { FREE_W, TK_FREE },
   { FROM_W, TK_FROM },
-  { FULL_W, TK_JOIN_KW },
-  { GLOB_W, TK_GLOB },
-  { GROUP_W, TK_GROUP },
-  { HAVING_W, TK_HAVING },
   { HOLD_W, TK_HOLD },
-  { IGNORE_W, TK_IGNORE },
-  { IMMEDIATE_W, TK_IMMEDIATE },
-  { IN_W, TK_IN },
-  { INDEX_W, TK_INDEX },
-  { INITIALLY_W, TK_INITIALLY },
-  { INNER_W, TK_JOIN_KW },
   { INSERT_W, TK_INSERT },
-  { INSTEAD_W, TK_INSTEAD },
   { INT_W, TK_INT },
-  { INTERSECT_W, TK_INTERSECT },
+  { INTEGER_W, TK_INT },
   { INTO_W, TK_INTO },
   { IS_W, TK_IS },
-  { ISNULL_W, TK_ISNULL },
-  { JOIN_W, TK_JOIN },
   { KEY_W, TK_KEY },
-  { LEFT_W, TK_JOIN_KW },
   { LIKE_W, TK_LIKE },
-  { LIMIT_W, TK_LIMIT },
   { LOCALIZABLE_W, TK_LOCALIZABLE },
   { LONG_W, TK_LONG },
   { LONGCHAR_W, TK_LONGCHAR },
-  { MATCH_W, TK_MATCH },
-  { NATURAL_W, TK_JOIN_KW },
   { NOT_W, TK_NOT },
-  { NOTNULL_W, TK_NOTNULL },
   { NULL_W, TK_NULL },
   { OBJECT_W, TK_OBJECT },
-  { OF_W, TK_OF },
-  { OFFSET_W, TK_OFFSET },
-  { ON_W, TK_ON },
   { OR_W, TK_OR },
   { ORDER_W, TK_ORDER },
-  { OUTER_W, TK_JOIN_KW },
-  { PRAGMA_W, TK_PRAGMA },
   { PRIMARY_W, TK_PRIMARY },
-  { RAISE_W, TK_RAISE },
-  { REFERENCES_W, TK_REFERENCES },
-  { REPLACE_W, TK_REPLACE },
-  { RESTRICT_W, TK_RESTRICT },
-  { RIGHT_W, TK_JOIN_KW },
-  { ROLLBACK_W, TK_ROLLBACK },
-  { ROW_W, TK_ROW },
   { SELECT_W, TK_SELECT },
   { SET_W, TK_SET },
   { SHORT_W, TK_SHORT },
-  { STATEMENT_W, TK_STATEMENT },
   { TABLE_W, TK_TABLE },
   /*{ TEMPORARY_W, TK_TEMPORARY },*/
-  { THEN_W, TK_THEN },
-  { TRANSACTION_W, TK_TRANSACTION },
-  { TRIGGER_W, TK_TRIGGER },
-  { UNION_W, TK_UNION },
-  { UNIQUE_W, TK_UNIQUE },
   { UPDATE_W, TK_UPDATE },
-  { USING_W, TK_USING },
-  { VACUUM_W, TK_VACUUM },
   { VALUES_W, TK_VALUES },
-  { VIEW_W, TK_VIEW },
-  { WHEN_W, TK_WHEN },
   { WHERE_W, TK_WHERE },
 };
 
@@ -339,57 +204,21 @@ int sqliteGetToken(const WCHAR *z, int *tokenType){
     }
     case '-': {
       if( z[1]==0 ) return -1;
-      if( z[1]=='-' ){
-        for(i=2; z[i] && z[i]!='\n'; i++){}
-        *tokenType = TK_COMMENT;
-        return i;
-      }
       *tokenType = TK_MINUS;
       return 1;
     }
-    case '(': {
-      if( z[1]=='+' && z[2]==')' ){
-        *tokenType = TK_ORACLE_OUTER_JOIN;
-        return 3;
-      }else{
-        *tokenType = TK_LP;
-        return 1;
-      }
-    }
-    case ')': {
-      *tokenType = TK_RP;
-      return 1;
-    }
-    case ';': {
-      *tokenType = TK_SEMI;
+    case '(':
+      *tokenType = TK_LP;
       return 1;
-    }
-    case '+': {
-      *tokenType = TK_PLUS;
+    case ')':
+      *tokenType = TK_RP;
       return 1;
-    }
-    case '*': {
+    case '*':
       *tokenType = TK_STAR;
       return 1;
-    }
-    case '/': {
-      if( z[1]!='*' || z[2]==0 ){
-        *tokenType = TK_SLASH;
-        return 1;
-      }
-      for(i=3; z[i] && (z[i]!='/' || z[i-1]!='*'); i++){}
-      if( z[i] ) i++;
-      *tokenType = TK_COMMENT;
-      return i;
-    }
-    case '%': {
-      *tokenType = TK_REM;
-      return 1;
-    }
-    case '=': {
+    case '=':
       *tokenType = TK_EQ;
-      return 1 + (z[1]=='=');
-    }
+      return 1;
     case '<': {
       if( z[1]=='=' ){
         *tokenType = TK_LE;
@@ -397,9 +226,6 @@ int sqliteGetToken(const WCHAR *z, int *tokenType){
       }else if( z[1]=='>' ){
         *tokenType = TK_NE;
         return 2;
-      }else if( z[1]=='<' ){
-        *tokenType = TK_LSHIFT;
-        return 2;
       }else{
         *tokenType = TK_LT;
         return 1;
@@ -409,9 +235,6 @@ int sqliteGetToken(const WCHAR *z, int *tokenType){
       if( z[1]=='=' ){
         *tokenType = TK_GE;
         return 2;
-      }else if( z[1]=='>' ){
-        *tokenType = TK_RSHIFT;
-        return 2;
       }else{
         *tokenType = TK_GT;
         return 1;
@@ -426,31 +249,12 @@ int sqliteGetToken(const WCHAR *z, int *tokenType){
         return 2;
       }
     }
-    case '|': {
-      if( z[1]!='|' ){
-        *tokenType = TK_BITOR;
-        return 1;
-      }else{
-        *tokenType = TK_CONCAT;
-        return 2;
-      }
-    }
-    case '?': {
+    case '?':
       *tokenType = TK_WILDCARD;
       return 1;
-    }
-    case ',': {
+    case ',':
       *tokenType = TK_COMMA;
       return 1;
-    }
-    case '&': {
-      *tokenType = TK_BITAND;
-      return 1;
-    }
-    case '~': {
-      *tokenType = TK_BITNOT;
-      return 1;
-    }
     case '`': case '\'': case '"': {
       int delim = z[0];
       for(i=1; z[i]; i++){
@@ -480,22 +284,6 @@ int sqliteGetToken(const WCHAR *z, int *tokenType){
     case '5': case '6': case '7': case '8': case '9': {
       *tokenType = TK_INTEGER;
       for(i=1; isdigit(z[i]); i++){}
-      if( z[i]=='.' ){
-        i++;
-        while( isdigit(z[i]) ){ i++; }
-        *tokenType = TK_FLOAT;
-      }
-      if( (z[i]=='e' || z[i]=='E') &&
-           ( isdigit(z[i+1]) 
-            || ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
-           )
-      ){
-        i += 2;
-        while( isdigit(z[i]) ){ i++; }
-        *tokenType = TK_FLOAT;
-      }else if( z[0]=='.' ){
-        *tokenType = TK_FLOAT;
-      }
       return i;
     }
     case '[': {
index 9cbe55a..502af14 100644 (file)
@@ -58,14 +58,12 @@ static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT
 static UINT UPDATE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
 {
     MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
-    UINT n, type, val, r, row, col_count = 0, row_count = 0;
+    UINT i, r, col_count = 0, row_count = 0;
+    MSIRECORD *values = NULL;
     MSIVIEW *wv;
 
     TRACE("%p %p\n", uv, record );
 
-    if( !record )
-        return ERROR_FUNCTION_FAILED;
-
     wv = uv->wv;
     if( !wv )
         return ERROR_FUNCTION_FAILED;
@@ -77,34 +75,22 @@ static UINT UPDATE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
 
     r = wv->ops->get_dimensions( wv, &row_count, &col_count );
     if( r )
-        goto err;
+        return r;
 
-    for( row = 0; row < row_count; row++ )
+    values = msi_query_merge_record( col_count, uv->vals, record );
+    if (!values)
+        return ERROR_FUNCTION_FAILED;
+
+    for ( i=0; i<row_count; i++ )
     {
-        for( n = 1; n <= col_count; n++ )
-        {
-            r = wv->ops->get_column_info( wv, n, NULL, &type );
-            if( r )
-                break;
-
-            if( type & MSITYPE_STRING )
-            {
-                const WCHAR *str = MSI_RecordGetString( record, n );
-                val = msi_addstringW( uv->db->strings, 0, str, -1, 1 );
-            }
-            else
-            {
-                val = MSI_RecordGetInteger( record, n );
-                val |= 0x8000;
-            }
-            r = wv->ops->set_int( wv, row, n, val );
-            if( r )
-                break;
-        }
+        r = wv->ops->set_row( wv, i, values, (1 << col_count) - 1 );
+        if (r != ERROR_SUCCESS)
+            break;
     }
 
-err:
-    return ERROR_SUCCESS;
+    msiobj_release( &values->hdr );
+
+    return r;
 }
 
 
@@ -213,14 +199,19 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
     if( r != ERROR_SUCCESS )
         return r;
 
-    /* add conditions first */
-    r = WHERE_CreateView( db, &wv, tv, expr );
-    if( r != ERROR_SUCCESS )
+    if (expr)
     {
-        tv->ops->delete( tv );
-        return r;
+        /* add conditions first */
+        r = WHERE_CreateView( db, &wv, tv, expr );
+        if( r != ERROR_SUCCESS )
+        {
+            tv->ops->delete( tv );
+            return r;
+        }
     }
-    
+    else
+       wv = tv;
+
     /* then select the columns we want */
     r = SELECT_CreateView( db, &sv, wv, columns );
     if( r != ERROR_SUCCESS )
index d01510b..a30ebcb 100644 (file)
@@ -82,24 +82,24 @@ static UINT WHERE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
     return wv->table->ops->fetch_stream( wv->table, row, col, stm );
 }
 
-static UINT WHERE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
+static UINT WHERE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
 {
     MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
 
-    TRACE("%p %d %d %04x\n", wv, row, col, val );
+    TRACE("%p %d %p %08x\n", wv, row, rec, mask );
 
     if( !wv->table )
          return ERROR_FUNCTION_FAILED;
-    
+
     if( row > wv->row_count )
         return ERROR_NO_MORE_ITEMS;
-    
+
     row = wv->reorder[ row ];
-    
-    return wv->table->ops->set_int( wv->table, row, col, val );
+
+    return wv->table->ops->set_row( wv->table, row, rec, mask );
 }
 
-static INT INT_evaluate( INT lval, UINT op, INT rval )
+static INT INT_evaluate_binary( INT lval, UINT op, INT rval )
 {
     switch( op )
     {
@@ -119,6 +119,16 @@ static INT INT_evaluate( INT lval, UINT op, INT rval )
         return ( lval >= rval );
     case OP_NE:
         return ( lval != rval );
+    default:
+        ERR("Unknown operator %d\n", op );
+    }
+    return 0;
+}
+
+static INT INT_evaluate_unary( INT lval, UINT op )
+{
+    switch( op )
+    {
     case OP_ISNULL:
         return ( !lval );
     case OP_NOTNULL:
@@ -211,7 +221,14 @@ static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row,
         r = WHERE_evaluate( db, table, row, cond->u.expr.right, &rval, record );
         if( r != ERROR_SUCCESS )
             return r;
-        *val = INT_evaluate( lval, cond->u.expr.op, rval );
+        *val = INT_evaluate_binary( lval, cond->u.expr.op, rval );
+        return ERROR_SUCCESS;
+
+    case EXPR_UNARY:
+        r = table->ops->fetch_int( table, row, cond->u.expr.left->u.col_number, &tval );
+        if( r != ERROR_SUCCESS )
+            return r;
+        *val = INT_evaluate_unary( tval, cond->u.expr.op );
         return ERROR_SUCCESS;
 
     case EXPR_STRCMP:
@@ -224,7 +241,7 @@ static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row,
     default:
         ERR("Invalid expression type\n");
         break;
-    } 
+    }
 
     return ERROR_SUCCESS;
 
@@ -420,7 +437,7 @@ static const MSIVIEWOPS where_ops =
 {
     WHERE_fetch_int,
     WHERE_fetch_stream,
-    WHERE_set_int,
+    WHERE_set_row,
     NULL,
     WHERE_execute,
     WHERE_close,
@@ -497,6 +514,16 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr
         }
 
         break;
+    case EXPR_UNARY:
+        if ( cond->u.expr.left->type != EXPR_COLUMN )
+        {
+            *valid = FALSE;
+            return ERROR_INVALID_PARAMETER;
+        }
+        r = WHERE_VerifyCondition( db, table, cond->u.expr.left, valid );
+        if( r != ERROR_SUCCESS )
+            return r;
+        break;
     case EXPR_IVAL:
         *valid = 1;
         cond->type = EXPR_UVAL;
@@ -512,7 +539,7 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr
         ERR("Invalid expression type\n");
         *valid = 0;
         break;
-    } 
+    }
 
     return ERROR_SUCCESS;
 }