Sync to Wine-20050111:
authorGé van Geldorp <ge@gse.nl>
Wed, 12 Jan 2005 09:31:44 +0000 (09:31 +0000)
committerGé van Geldorp <ge@gse.nl>
Wed, 12 Jan 2005 09:31:44 +0000 (09:31 +0000)
Vitaly Lipatov <lav@etersoft.ru>
- Get real screen properties.
- Add description for MsiGetMode, MSIRUNMODE constants.
- Add ScreenX, ScreenY, ColorBits installer properties.
Mike McCormack <mike@codeweavers.com>
- Add a simple test case for MSI databases.
- Remove unneeded whitespace, indent correctly.
- Remove more fixed length buffers, rewrite functions to return
malloc'ed memory.
- Remove a lot of fixed length buffers.
- Implement thread safety for records.
- Fix selecting string columns and matching against a wildcard.
- Implement MsiRecordSetStreamA/W and add tests for records containing
streams.
- Fix records according to test cases.
- Fix transposition of 4 byte values when reading in table data from
storage.
- MsiCloseAllHandles only closes handles allocated in the calling
thread.
Francois Gouget <fgouget@free.fr>
- Assorted spelling fixes.
Aric Stewart <aric@codeweavers.com>
- Make all custom type 1 actions happen in a seperate thread and close
all handles for that thread when it exits. Honors the concept of
temporary MSI handles for custom actions.
- Properly deformat keys written to the registry.
- Because directory mappings can change between the CostFinalize step
  and the InstallFiles step we need to do a final resolution of the
  target file name before installing.
- When checking for an existing .lnk shortcut extension on the filename
do not just search for '.' but actually verify it is '.lnk'.
- CustomAction 35 should call SetTargetPath not just set the property.
- TARGETDIR and SOURCEDIR may not be entries 0 in the directory
  tables. So when resolving the folder we need to seek them out.
- When we handle SetTargetPath we need to be sure to recalculate the
  resulting paths as things with the now set Directory as the parent
  will change.
- Change how we install files so that we extract files as we need them,
cuts down on extraction time and unused files.
- Improve progress bar tracking.
- Be sure that set paths are terminated with a backslash.
- Free allocated buffers.
- Parse out the full features by using the ',' character and do
comparisons based on the full feature names.
- Continue when a duplicate component is found and loaded.
- Rework how we handle Feature and Component States. I have confirmed
  from testing that, although documented nowhere, having ADDLOCAL on
  the install line overrides INSTALLLEVEL.
- Track all files extracted from cabinents as tempfiles so they can be
  removed at the end of the install to not leave uninstalled but
  uncabbed files laying around.
- Move Install Features selection and evaluation into CostFinalize.
- Allow for end of install actions.
- Create the shortcut directory if it does not exist.
- Set the INSTALLLEVEL in CostFinalize if it is not set.
- Eliminate some fixed length buffers.
- Enable asynchronous dll custom action calls.
- Make sure to include trailing backslash in path.
- Move around and rename some functions.
- Fix incorrect return code check.
- Fix folder resolution.
- Let negative number be parsed correctly. Needed for accessing actions
with sequences such as -1.
- Added MsiSetExternalUIW.
- Include a System16Folder definition.
- Free allocated buffers.
- Blank the property buffers even if the property is not found.
- Include the trailing backslash on the Windows volume.
- Fix folder resolution.
Eric Pouech <pouech-eric@wanadoo.fr>
- Fixed some errors in function prototypes.
Steven Edwards <steven@codeweavers.com>
- Add and fix some stubs.
Ulrich Czekalla <ulrich@codeweavers.com>
- Set the out buffer count to zero on read error.
Michael Stefaniuc <mstefani@redhat.de>
- Add missing HeapFree's (found by smatch).
Paul Vriens <Paul.Vriens@xs4all.nl>
- Use Interlocked* functions in AddRef and Release.

svn path=/trunk/; revision=12948

15 files changed:
reactos/include/wine/msiquery.h
reactos/lib/msi/Makefile.in
reactos/lib/msi/action.c
reactos/lib/msi/handle.c
reactos/lib/msi/msi.c
reactos/lib/msi/msi.spec
reactos/lib/msi/msipriv.h
reactos/lib/msi/package.c
reactos/lib/msi/query.h
reactos/lib/msi/record.c
reactos/lib/msi/sql.tab.c
reactos/lib/msi/sql.tab.h
reactos/lib/msi/sql.y
reactos/lib/msi/table.c
reactos/lib/msi/where.c

index cfd07b9..9b61ae6 100644 (file)
@@ -59,7 +59,30 @@ typedef enum tagMSIMODIFY
 #define MSIDBOPEN_TRANSACT (LPCTSTR)1
 #define MSIDBOPEN_DIRECT   (LPCTSTR)2
 #define MSIDBOPEN_CREATE   (LPCTSTR)3
+#define MSIDBOPEN_CREATEDIRECT (LPCTSTR)4
 
+typedef enum tagMSIRUNMODE
+{
+    MSIRUNMODE_ADMIN = 0,
+    MSIRUNMODE_ADVERTISE = 1,
+    MSIRUNMODE_MAINTENANCE = 2,
+    MSIRUNMODE_ROLLBACKENABLED = 3,
+    MSIRUNMODE_LOGENABLED = 4,
+    MSIRUNMODE_OPERATIONS = 5,
+    MSIRUNMODE_REBOOTATEND = 6,
+    MSIRUNMODE_REBOOTNOW = 7,
+    MSIRUNMODE_CABINET = 8,
+    MSIRUNMODE_SOURCESHORTNAMES = 9,
+    MSIRUNMODE_TARGETSHORTNAMES = 10,
+    MSIRUNMODE_RESERVED11 = 11,
+    MSIRUNMODE_WINDOWS9X = 12,
+    MSIRUNMODE_ZAWENABLED = 13,
+    MSIRUNMODE_RESERVED14 = 14,
+    MSIRUNMODE_RESERVED15 = 15,
+    MSIRUNMODE_SCHEDULED = 16,
+    MSIRUNMODE_ROLLBACK = 17,
+    MSIRUNMODE_COMMIT = 18
+} MSIRUNMODE;
 
 /* view manipulation */
 UINT WINAPI MsiViewFetch(MSIHANDLE,MSIHANDLE*);
@@ -123,15 +146,12 @@ MSICONDITION WINAPI MsiEvaluateConditionW(MSIHANDLE,LPCWSTR);
 #define     MsiEvaluateCondition WINELIB_NAME_AW(MsiEvaluateCondition)
 
 /* property functions */
-UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName,
-                           LPSTR szValueBuf, DWORD* pchValueBuf);
-UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
-                           LPWSTR szValueBuf, DWORD* pchValueBuf);
+UINT WINAPI MsiGetPropertyA(MSIHANDLE, LPCSTR, LPSTR, DWORD*);
+UINT WINAPI MsiGetPropertyW(MSIHANDLE, LPCWSTR, LPWSTR, DWORD*);
 #define     MsiGetProperty WINELIB_NAME_AW(MsiGetProperty)
 
-UINT WINAPI MsiSetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue);
-UINT WINAPI MsiSetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, 
-                              LPCWSTR szValue);
+UINT WINAPI MsiSetPropertyA(MSIHANDLE, LPCSTR, LPCSTR);
+UINT WINAPI MsiSetPropertyW(MSIHANDLE, LPCWSTR, LPCWSTR);
 #define     MsiSetProperty WINELIB_NAME_AW(MsiSetProperty)
 
 UINT WINAPI MsiGetTargetPathA(MSIHANDLE,LPCSTR,LPSTR,DWORD*);
@@ -148,11 +168,13 @@ UINT WINAPI MsiGetSourcePathW(MSIHANDLE,LPCWSTR,LPWSTR,DWORD*);
 
 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE);
 
-UINT WINAPI MsiViewGetColumnInfo( MSIHANDLE, MSICOLINFO, MSIHANDLE*);
-INT WINAPI MsiProcessMessage( MSIHANDLE, INSTALLMESSAGE, MSIHANDLE);
+UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE, MSICOLINFO, MSIHANDLE*);
+INT WINAPI MsiProcessMessage(MSIHANDLE, INSTALLMESSAGE, MSIHANDLE);
 
-UINT WINAPI MsiSetFeatureStateA( MSIHANDLE, LPCSTR, INSTALLSTATE);
-UINT WINAPI MsiSetFeatureStateW( MSIHANDLE, LPCWSTR, INSTALLSTATE);
+UINT WINAPI MsiSetFeatureStateA(MSIHANDLE, LPCSTR, INSTALLSTATE);
+UINT WINAPI MsiSetFeatureStateW(MSIHANDLE, LPCWSTR, INSTALLSTATE);
 #define     MsiSetFeatureState WINELIB_NAME_AW(MsiSetFeatureState)
 
+BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE);
+
 #endif /* __WINE_MSIQUERY_H */
index 95f3ecd..df24898 100644 (file)
@@ -3,7 +3,7 @@ TOPOBJDIR = ../..
 SRCDIR    = @srcdir@\r
 VPATH     = @srcdir@\r
 MODULE    = msi.dll\r
-IMPORTS   = shell32 cabinet oleaut32 ole32 version user32 advapi32 kernel32\r
+IMPORTS   = shell32 cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32\r
 EXTRALIBS = -luuid $(LIBUNICODE)\r
 \r
 C_SRCS = \\r
@@ -31,6 +31,8 @@ RC_SRCS = version.rc
 EXTRA_SRCS = sql.y cond.y\r
 EXTRA_OBJS = sql.tab.o cond.tab.o\r
 \r
+SUBDIRS = tests\r
+\r
 @MAKE_DLL_RULES@\r
 \r
 sql.tab.c sql.tab.h: sql.y\r
index e32e1f9..ec066ac 100644 (file)
@@ -51,6 +51,8 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand
 #include "ver.h"\r
 \r
 #define CUSTOM_ACTION_TYPE_MASK 0x3F\r
+#define REG_PROGRESS_VALUE 13200\r
+#define COMPONENT_PROGRESS_VALUE 24000\r
 \r
 WINE_DEFAULT_DEBUG_CHANNEL(msi);\r
 \r
@@ -65,8 +67,10 @@ typedef struct tagMSIFEATURE
     WCHAR Directory[96];\r
     INT Attributes;\r
     \r
-    INSTALLSTATE State;\r
-    BOOL Enabled;\r
+    INSTALLSTATE Installed;\r
+    INSTALLSTATE ActionRequest;\r
+    INSTALLSTATE Action;\r
+\r
     INT ComponentCount;\r
     INT Components[1024]; /* yes hardcoded limit.... I am bad */\r
     INT Cost;\r
@@ -81,21 +85,23 @@ typedef struct tagMSICOMPONENT
     WCHAR Condition[0x100];\r
     WCHAR KeyPath[96];\r
 \r
-    INSTALLSTATE State;\r
-    BOOL FeatureState;\r
+    INSTALLSTATE Installed;\r
+    INSTALLSTATE ActionRequest;\r
+    INSTALLSTATE Action;\r
+\r
     BOOL Enabled;\r
     INT  Cost;\r
 } MSICOMPONENT;\r
 \r
 typedef struct tagMSIFOLDER\r
 {\r
-    WCHAR Directory[96];\r
-    WCHAR TargetDefault[96];\r
-    WCHAR SourceDefault[96];\r
+    LPWSTR Directory;\r
+    LPWSTR TargetDefault;\r
+    LPWSTR SourceDefault;\r
 \r
-    WCHAR ResolvedTarget[MAX_PATH];\r
-    WCHAR ResolvedSource[MAX_PATH];\r
-    WCHAR Property[MAX_PATH];   /* initially set property */\r
+    LPWSTR ResolvedTarget;\r
+    LPWSTR ResolvedSource;\r
+    LPWSTR Property;   /* initially set property */\r
     INT   ParentIndex;\r
     INT   State;\r
         /* 0 = uninitialized */\r
@@ -108,12 +114,12 @@ typedef struct tagMSIFOLDER
 \r
 typedef struct tagMSIFILE\r
 {\r
-    WCHAR File[72];\r
+    LPWSTR File;\r
     INT ComponentIndex;\r
-    WCHAR FileName[MAX_PATH];\r
+    LPWSTR FileName;\r
     INT FileSize;\r
-    WCHAR Version[72];\r
-    WCHAR Language[20];\r
+    LPWSTR Version;\r
+    LPWSTR Language;\r
     INT Attributes;\r
     INT Sequence;   \r
 \r
@@ -123,8 +129,8 @@ typedef struct tagMSIFILE
        /* 2 = present but replace */\r
        /* 3 = present do not replace */\r
        /* 4 = Installed */\r
-    WCHAR   SourcePath[MAX_PATH];\r
-    WCHAR   TargetPath[MAX_PATH];\r
+    LPWSTR  SourcePath;\r
+    LPWSTR  TargetPath;\r
     BOOL    Temporary; \r
 }MSIFILE;\r
 \r
@@ -134,6 +140,7 @@ typedef struct tagMSIFILE
 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);\r
 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);\r
 \r
+static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq);\r
 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);\r
 \r
 static UINT ACTION_LaunchConditions(MSIPACKAGE *package);\r
@@ -158,15 +165,15 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source,
                                 const LPWSTR target, const INT type);\r
 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, \r
                                 const LPWSTR target, const INT type);\r
-static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, \r
+static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source,\r
                                 const LPWSTR target, const INT type);\r
-static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source, \r
+static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source,\r
                                 const LPWSTR target, const INT type);\r
-static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source, \r
+static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source,\r
                                 const LPWSTR target, const INT type);\r
 \r
 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data);\r
-static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path, \r
+static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name,\r
                            BOOL source, BOOL set_prop, MSIFOLDER **folder);\r
 \r
 static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);\r
@@ -223,12 +230,9 @@ const static WCHAR szPublishProduct[] =
  ********************************************************/\r
 inline static void reduce_to_longfilename(WCHAR* filename)\r
 {\r
-    if (strchrW(filename,'|'))\r
-    {\r
-        WCHAR newname[MAX_PATH];\r
-        strcpyW(newname,strchrW(filename,'|')+1);\r
-        strcpyW(filename,newname);\r
-    }\r
+    LPWSTR p = strchrW(filename,'|');\r
+    if (p)\r
+        memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));\r
 }\r
 \r
 inline static char *strdupWtoA( const WCHAR *str )\r
@@ -256,6 +260,15 @@ inline static WCHAR *strdupAtoW( const char *str )
     return ret;\r
 }\r
 \r
+static LPWSTR dupstrW(LPCWSTR src)\r
+{\r
+    LPWSTR dest;\r
+    if (!src) return NULL;\r
+    dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR));\r
+    strcpyW(dest, src);\r
+    return dest;\r
+}\r
+\r
 inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)\r
 {\r
     UINT rc;\r
@@ -263,16 +276,58 @@ inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
     LPWSTR ret;\r
    \r
     sz = 0; \r
-    rc = MSI_RecordGetStringW(row,index,NULL,&sz);\r
-    if (sz <= 0)\r
+    if (MSI_RecordIsNull(row,index))\r
         return NULL;\r
 \r
+    rc = MSI_RecordGetStringW(row,index,NULL,&sz);\r
+\r
+    /* having an empty string is different than NULL */\r
+    if (sz == 0)\r
+    {\r
+        ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));\r
+        ret[0] = 0;\r
+        return ret;\r
+    }\r
+\r
     sz ++;\r
     ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));\r
     rc = MSI_RecordGetStringW(row,index,ret,&sz);\r
+    if (rc!=ERROR_SUCCESS)\r
+    {\r
+        ERR("Unable to load dynamic string\n");\r
+        HeapFree(GetProcessHeap(), 0, ret);\r
+        ret = NULL;\r
+    }\r
     return ret;\r
 }\r
 \r
+inline static LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop,\r
+                                           UINT* rc)\r
+{\r
+    DWORD sz = 0;\r
+    LPWSTR str;\r
+    UINT r;\r
+\r
+    r = MSI_GetPropertyW(package, prop, NULL, &sz);\r
+    if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)\r
+    {\r
+        if (rc)\r
+            *rc = r;\r
+        return NULL;\r
+    }\r
+    sz++;\r
+    str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));\r
+    r = MSI_GetPropertyW(package, prop, str, &sz);\r
+    if (r != ERROR_SUCCESS)\r
+    {\r
+        HeapFree(GetProcessHeap(),0,str);\r
+        str = NULL;\r
+    }\r
+    if (rc)\r
+        *rc = r;\r
+    return str;\r
+}\r
+\r
 inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )\r
 {\r
     int rc = -1;\r
@@ -321,6 +376,7 @@ inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
     return rc;\r
 }\r
 \r
+\r
 static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)\r
 {\r
     DWORD i;\r
@@ -343,8 +399,8 @@ static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
 \r
     memset(&package->files[index],0,sizeof(MSIFILE));\r
 \r
-    strcpyW(package->files[index].File,name);\r
-    strcpyW(package->files[index].TargetPath,path);\r
+    package->files[index].File = dupstrW(name);\r
+    package->files[index].TargetPath = dupstrW(path);\r
     package->files[index].Temporary = TRUE;\r
 \r
     TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));  \r
@@ -362,11 +418,103 @@ void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package)
     for (i = 0; i < package->loaded_files; i++)\r
     {\r
         if (package->files[i].Temporary)\r
+        {\r
+            TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));\r
             DeleteFileW(package->files[i].TargetPath);\r
+        }\r
 \r
     }\r
 }\r
 \r
+/* Called when the package is being closed */\r
+extern void ACTION_free_package_structures( MSIPACKAGE* package)\r
+{\r
+    INT i;\r
+    \r
+    TRACE("Freeing package action data\n");\r
+\r
+    /* No dynamic buffers in features */\r
+    if (package->features && package->loaded_features > 0)\r
+        HeapFree(GetProcessHeap(),0,package->features);\r
+\r
+    for (i = 0; i < package->loaded_folders; i++)\r
+    {\r
+        HeapFree(GetProcessHeap(),0,package->folders[i].Directory);\r
+        HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);\r
+        HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);\r
+        HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);\r
+        HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);\r
+        HeapFree(GetProcessHeap(),0,package->folders[i].Property);\r
+    }\r
+    if (package->folders && package->loaded_folders > 0)\r
+        HeapFree(GetProcessHeap(),0,package->folders);\r
+\r
+    /* no dynamic buffers in components */ \r
+    if (package->components && package->loaded_components > 0)\r
+        HeapFree(GetProcessHeap(),0,package->components);\r
+\r
+    for (i = 0; i < package->loaded_files; i++)\r
+    {\r
+        HeapFree(GetProcessHeap(),0,package->files[i].File);\r
+        HeapFree(GetProcessHeap(),0,package->files[i].FileName);\r
+        HeapFree(GetProcessHeap(),0,package->files[i].Version);\r
+        HeapFree(GetProcessHeap(),0,package->files[i].Language);\r
+        HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);\r
+        HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);\r
+    }\r
+\r
+    if (package->files && package->loaded_files > 0)\r
+        HeapFree(GetProcessHeap(),0,package->files);\r
+}\r
+\r
+static UINT ACTION_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )\r
+{\r
+    LPWSTR szQuery;\r
+    LPCWSTR p;\r
+    UINT sz, rc;\r
+    va_list va;\r
+\r
+    /* figure out how much space we need to allocate */\r
+    va_start(va, fmt);\r
+    sz = strlenW(fmt) + 1;\r
+    p = fmt;\r
+    while (*p)\r
+    {\r
+        p = strchrW(p, '%');\r
+        if (!p)\r
+            break;\r
+        p++;\r
+        switch (*p)\r
+        {\r
+        case 's':  /* a string */\r
+            sz += strlenW(va_arg(va,LPCWSTR));\r
+            break;\r
+        case 'd':\r
+        case 'i':  /* an integer -2147483648 seems to be longest */\r
+            sz += 3*sizeof(int);\r
+            (void)va_arg(va,int);\r
+            break;\r
+        case '%':  /* a single % - leave it alone */\r
+            break;\r
+        default:\r
+            FIXME("Unhandled character type %c\n",*p);\r
+        }\r
+        p++;\r
+    }\r
+    va_end(va);\r
+\r
+    /* construct the string */\r
+    szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));\r
+    va_start(va, fmt);\r
+    vsnprintfW(szQuery, sz, fmt, va);\r
+    va_end(va);\r
+\r
+    /* perform the query */\r
+    rc = MSI_DatabaseOpenViewW(db, szQuery, view);\r
+    HeapFree(GetProcessHeap(), 0, szQuery);\r
+    return rc;\r
+}\r
+\r
 static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )\r
 {\r
     MSIRECORD * row;\r
@@ -390,17 +538,14 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor
     UINT rc;\r
     MSIQUERY * view;\r
     MSIRECORD * row = 0;\r
-    static WCHAR *ActionFormat=NULL;\r
-    static WCHAR LastAction[0x100] = {0};\r
-    WCHAR Query[1024];\r
     LPWSTR ptr;\r
 \r
-    if (strcmpW(LastAction,action)!=0)\r
+    if (!package->LastAction || strcmpW(package->LastAction,action))\r
     {\r
-        sprintfW(Query,Query_t,action);\r
-        rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
+        rc = ACTION_OpenQuery(package->db, &view, Query_t, action);\r
         if (rc != ERROR_SUCCESS)\r
             return;\r
+\r
         rc = MSI_ViewExecute(view, 0);\r
         if (rc != ERROR_SUCCESS)\r
         {\r
@@ -422,18 +567,22 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor
             return;\r
         }\r
 \r
-        if (ActionFormat)\r
-            HeapFree(GetProcessHeap(),0,ActionFormat);\r
+        /* update the cached actionformat */\r
+        if (package->ActionFormat)\r
+            HeapFree(GetProcessHeap(),0,package->ActionFormat);\r
+        package->ActionFormat = load_dynamic_stringW(row,3);\r
+\r
+        if (package->LastAction)\r
+            HeapFree(GetProcessHeap(),0,package->LastAction);\r
+        package->LastAction = dupstrW(action);\r
 \r
-        ActionFormat = load_dynamic_stringW(row,3);\r
-        strcpyW(LastAction,action);\r
         msiobj_release(&row->hdr);\r
         MSI_ViewClose(view);\r
         msiobj_release(&view->hdr);\r
     }\r
 \r
     message[0]=0;\r
-    ptr = ActionFormat;\r
+    ptr = package->ActionFormat;\r
     while (*ptr)\r
     {\r
         LPWSTR ptr2;\r
@@ -489,12 +638,10 @@ static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
     MSIQUERY * view;\r
     MSIRECORD * row = 0;\r
     WCHAR *ActionText=NULL;\r
-    WCHAR Query[1024];\r
 \r
     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);\r
 \r
-    sprintfW(Query,Query_t,action);\r
-    rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
+    rc = ACTION_OpenQuery(package->db, &view, Query_t, action);\r
     if (rc != ERROR_SUCCESS)\r
         return;\r
     rc = MSI_ViewExecute(view, 0);\r
@@ -555,6 +702,58 @@ static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
     msiobj_release(&row->hdr);\r
 }\r
 \r
+/*\r
+ *  build_directory_name()\r
+ *\r
+ *  This function is to save messing round with directory names\r
+ *  It handles adding backslashes between path segments, \r
+ *   and can add \ at the end of the directory name if told to.\r
+ *\r
+ *  It takes a variable number of arguments.\r
+ *  It always allocates a new string for the result, so make sure\r
+ *   to free the return value when finished with it.\r
+ *\r
+ *  The first arg is the number of path segments that follow.\r
+ *  The arguments following count are a list of path segments.\r
+ *  A path segment may be NULL.\r
+ *\r
+ *  Path segments will be added with a \ separating them.\r
+ *  A \ will not be added after the last segment, however if the\r
+ *    last segment is NULL, then the last character will be a \\r
+ * \r
+ */\r
+static LPWSTR build_directory_name(DWORD count, ...)\r
+{\r
+    DWORD sz = 1, i;\r
+    LPWSTR dir;\r
+    va_list va;\r
+\r
+    va_start(va,count);\r
+    for(i=0; i<count; i++)\r
+    {\r
+        LPCWSTR str = va_arg(va,LPCWSTR);\r
+        if (str)\r
+            sz += strlenW(str) + 1;\r
+    }\r
+    va_end(va);\r
+\r
+    dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));\r
+    dir[0]=0;\r
+\r
+    va_start(va,count);\r
+    for(i=0; i<count; i++)\r
+    {\r
+        LPCWSTR str = va_arg(va,LPCWSTR);\r
+        if (!str)\r
+            continue;\r
+        strcatW(dir, str);\r
+        if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')\r
+            strcatW(dir, cszbs);\r
+    }\r
+    return dir;\r
+}\r
+\r
+\r
 /****************************************************\r
  * TOP level entry points \r
  *****************************************************/\r
@@ -569,23 +768,23 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
 \r
     if (szPackagePath)   \r
     {\r
-        LPWSTR p;\r
-        WCHAR check[MAX_PATH];\r
-        WCHAR pth[MAX_PATH];\r
-        DWORD size;\r
+        LPWSTR p, check, path;\r
  \r
-        strcpyW(pth,szPackagePath);\r
-        p = strrchrW(pth,'\\');    \r
+        path = dupstrW(szPackagePath);\r
+        p = strrchrW(path,'\\');    \r
         if (p)\r
         {\r
             p++;\r
             *p=0;\r
         }\r
 \r
-        size = MAX_PATH;\r
-        if (MSI_GetPropertyW(package,cszSourceDir,check,&size) \r
-            != ERROR_SUCCESS )\r
-            MSI_SetPropertyW(package, cszSourceDir, pth);\r
+        check = load_dynamic_property(package, cszSourceDir,NULL);\r
+        if (!check)\r
+            MSI_SetPropertyW(package, cszSourceDir, path);\r
+        else\r
+            HeapFree(GetProcessHeap(), 0, check);\r
+\r
+        HeapFree(GetProcessHeap(), 0, path);\r
     }\r
 \r
     if (szCommandLine)\r
@@ -595,8 +794,8 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
        \r
         while (*ptr)\r
         {\r
-            WCHAR prop[0x100];\r
-            WCHAR val[0x100];\r
+            WCHAR *prop = NULL;\r
+            WCHAR *val = NULL;\r
 \r
             TRACE("Looking at %s\n",debugstr_w(ptr));\r
 \r
@@ -607,10 +806,13 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
                 DWORD len = 0;\r
 \r
                 while (*ptr == ' ') ptr++;\r
-                strncpyW(prop,ptr,ptr2-ptr);\r
-                prop[ptr2-ptr]=0;\r
+                len = ptr2-ptr;\r
+                prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));\r
+                strncpyW(prop,ptr,len);\r
+                prop[len]=0;\r
                 ptr2++;\r
-            \r
+           \r
+                len = 0; \r
                 ptr = ptr2; \r
                 while (*ptr && (quote || (!quote && *ptr!=' ')))\r
                 {\r
@@ -625,14 +827,18 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
                     ptr2++;\r
                     len -= 2;\r
                 }\r
+                val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));\r
                 strncpyW(val,ptr2,len);\r
-                val[len]=0;\r
+                val[len] = 0;\r
 \r
                 if (strlenW(prop) > 0)\r
                 {\r
-                    TRACE("Found commandline property (%s) = (%s)\n", debugstr_w(prop), debugstr_w(val));\r
+                    TRACE("Found commandline property (%s) = (%s)\n", \r
+                                       debugstr_w(prop), debugstr_w(val));\r
                     MSI_SetPropertyW(package,prop,val);\r
                 }\r
+                HeapFree(GetProcessHeap(),0,val);\r
+                HeapFree(GetProcessHeap(),0,prop);\r
             }\r
             ptr++;\r
         }\r
@@ -653,9 +859,92 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
     else\r
         rc = ACTION_ProcessExecSequence(package,FALSE);\r
 \r
+    /* process the ending type action */\r
+    if (rc == ERROR_SUCCESS)\r
+        rc = ACTION_PerformActionSequence(package,-1);\r
+    else if (rc == ERROR_FUNCTION_FAILED) \r
+        rc = ACTION_PerformActionSequence(package,-3);\r
+    \r
     return rc;\r
 }\r
 \r
+static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)\r
+{\r
+    MSIQUERY * view;\r
+    UINT rc;\r
+    WCHAR buffer[0x100];\r
+    DWORD sz = 0x100;\r
+    MSIRECORD * row = 0;\r
+    static const WCHAR ExecSeqQuery[] =  {\r
+   's','e','l','e','c','t',' ','*',' ',\r
+   'f','r','o','m',' ',\r
+       'I','n','s','t','a','l','l','E','x','e','c','u','t','e',\r
+       'S','e','q','u','e','n','c','e',' ',\r
+   'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',\r
+       '=',' ','%','i',0};\r
+\r
+    rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, seq);\r
+\r
+    if (rc == ERROR_SUCCESS)\r
+    {\r
+        rc = MSI_ViewExecute(view, 0);\r
+\r
+        if (rc != ERROR_SUCCESS)\r
+        {\r
+            MSI_ViewClose(view);\r
+            msiobj_release(&view->hdr);\r
+            goto end;\r
+        }\r
+       \r
+        TRACE("Running the actions\n"); \r
+\r
+        rc = MSI_ViewFetch(view,&row);\r
+        if (rc != ERROR_SUCCESS)\r
+        {\r
+            rc = ERROR_SUCCESS;\r
+            goto end;\r
+        }\r
+\r
+        /* check conditions */\r
+        if (!MSI_RecordIsNull(row,2))\r
+        {\r
+            LPWSTR cond = NULL;\r
+            cond = load_dynamic_stringW(row,2);\r
+\r
+            if (cond)\r
+            {\r
+                /* this is a hack to skip errors in the condition code */\r
+                if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)\r
+                {\r
+                    HeapFree(GetProcessHeap(),0,cond);\r
+                    msiobj_release(&row->hdr);\r
+                    goto end;\r
+                }\r
+                else\r
+                    HeapFree(GetProcessHeap(),0,cond);\r
+            }\r
+        }\r
+\r
+        sz=0x100;\r
+        rc =  MSI_RecordGetStringW(row,1,buffer,&sz);\r
+        if (rc != ERROR_SUCCESS)\r
+        {\r
+            ERR("Error is %x\n",rc);\r
+            msiobj_release(&row->hdr);\r
+            goto end;\r
+        }\r
+\r
+        rc = ACTION_PerformAction(package,buffer);\r
+        msiobj_release(&row->hdr);\r
+end:\r
+        MSI_ViewClose(view);\r
+        msiobj_release(&view->hdr);\r
+    }\r
+    else\r
+        rc = ERROR_SUCCESS;\r
+\r
+    return rc;\r
+}\r
 \r
 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)\r
 {\r
@@ -669,7 +958,6 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
        'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',\r
            '>',' ','%','i',' ','o','r','d','e','r',' ',\r
        'b','y',' ','S','e','q','u','e','n','c','e',0 };\r
-    WCHAR Query[1024];\r
     MSIRECORD * row = 0;\r
     static const WCHAR IVQuery[] = {\r
        's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',\r
@@ -678,11 +966,11 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
        'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',\r
            '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',\r
        0};\r
+    INT seq = 0;\r
 \r
+    /* get the sequence number */\r
     if (UIran)\r
     {\r
-        INT seq = 0;\r
-        \r
         rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);\r
         if (rc != ERROR_SUCCESS)\r
             return rc;\r
@@ -704,12 +992,9 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
         msiobj_release(&row->hdr);\r
         MSI_ViewClose(view);\r
         msiobj_release(&view->hdr);\r
-        sprintfW(Query,ExecSeqQuery,seq);\r
     }\r
-    else\r
-        sprintfW(Query,ExecSeqQuery,0);\r
-    \r
-    rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
+\r
+    rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, seq);\r
     if (rc == ERROR_SUCCESS)\r
     {\r
         rc = MSI_ViewExecute(view, 0);\r
@@ -721,7 +1006,7 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
             goto end;\r
         }\r
        \r
-        TRACE("Running the actions \n"); \r
+        TRACE("Running the actions\n"); \r
 \r
         while (1)\r
         {\r
@@ -900,7 +1185,6 @@ UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
     TRACE("Performing action (%s)\n",debugstr_w(action));\r
     ui_actioninfo(package, action, TRUE, 0);\r
     ui_actionstart(package, action);\r
-    ui_progress(package,2,1,0,0);\r
 \r
     /* pre install, setup and configuration block */\r
     if (strcmpW(action,szLaunchConditions)==0)\r
@@ -961,21 +1245,16 @@ static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action)
     UINT rc = ERROR_SUCCESS;\r
     MSIQUERY * view;\r
     MSIRECORD * row = 0;\r
-    WCHAR ExecSeqQuery[1024] = \r
+    static const WCHAR ExecSeqQuery[] =\r
     {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o'\r
-,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'\r
-,'o','n','`',' ','=',' ','`',0};\r
-    static const WCHAR end[]={'`',0};\r
+        ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'\r
+        ,'o','n','`',' ','=',' ','`','%','s','`',0};\r
     UINT type;\r
     LPWSTR source;\r
     LPWSTR target;\r
     WCHAR *deformated=NULL;\r
 \r
-    strcatW(ExecSeqQuery,action);\r
-    strcatW(ExecSeqQuery,end);\r
-\r
-    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
-\r
+    rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, action);\r
     if (rc != ERROR_SUCCESS)\r
         return rc;\r
 \r
@@ -1022,6 +1301,10 @@ static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action)
             rc = HANDLE_CustomType34(package,source,target,type);\r
             break;\r
         case 35: /* Directory set with formatted text. */\r
+            deformat_string(package,target,&deformated);\r
+            MSI_SetTargetPathW(package, source, deformated);\r
+            HeapFree(GetProcessHeap(),0,deformated);\r
+            break;\r
         case 51: /* Property set with formatted text. */\r
             deformat_string(package,target,&deformated);\r
             rc = MSI_SetPropertyW(package,source,deformated);\r
@@ -1063,10 +1346,9 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source,
         UINT rc;\r
         MSIQUERY * view;\r
         MSIRECORD * row = 0;\r
-        WCHAR Query[1024] =\r
+        static const WCHAR fmt[] =\r
         {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i'\r
-,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`',0};\r
-        static const WCHAR end[]={'`',0};\r
+,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`','%','s','`',0};\r
         HANDLE the_file;\r
         CHAR buffer[1024];\r
 \r
@@ -1079,10 +1361,7 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source,
         if (the_file == INVALID_HANDLE_VALUE)\r
             return ERROR_FUNCTION_FAILED;\r
 \r
-        strcatW(Query,source);\r
-        strcatW(Query,end);\r
-\r
-        rc = MSI_DatabaseOpenViewW( package->db, Query, &view);\r
+        rc = ACTION_OpenQuery(package->db, &view, fmt, source);\r
         if (rc != ERROR_SUCCESS)\r
             return rc;\r
 \r
@@ -1127,66 +1406,82 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source,
     return ERROR_SUCCESS;\r
 }\r
 \r
-\r
 typedef UINT __stdcall CustomEntry(MSIHANDLE);\r
 typedef struct \r
 {\r
         MSIPACKAGE *package;\r
-        WCHAR target[MAX_PATH];\r
-        WCHAR source[MAX_PATH];\r
+        WCHAR *target;\r
+        WCHAR *source;\r
 } thread_struct;\r
 \r
-#if 0\r
-static DWORD WINAPI DllThread(LPVOID info)\r
+static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff)\r
 {\r
-    HANDLE DLL;\r
+    HANDLE hModule;\r
     LPSTR proc;\r
-    thread_struct *stuff;\r
     CustomEntry *fn;\r
-     \r
-    stuff = (thread_struct*)info;\r
 \r
-    TRACE("Asynchronous start (%s, %s) \n", debugstr_w(stuff->source),\r
+    TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source),\r
           debugstr_w(stuff->target));\r
 \r
-    DLL = LoadLibraryW(stuff->source);\r
-    if (DLL)\r
+    hModule = LoadLibraryW(stuff->source);\r
+    if (hModule)\r
     {\r
         proc = strdupWtoA( stuff->target );\r
-        fn = (CustomEntry*)GetProcAddress(DLL,proc);\r
+        fn = (CustomEntry*)GetProcAddress(hModule,proc);\r
         if (fn)\r
         {\r
             MSIHANDLE hPackage;\r
             MSIPACKAGE *package = stuff->package;\r
 \r
-            TRACE("Calling function\n");\r
+            TRACE("Calling function %s\n", proc);\r
             hPackage = msiobj_findhandle( &package->hdr );\r
-            if( !hPackage )\r
+            if (hPackage )\r
+            {\r
+                fn(hPackage);\r
+                msiobj_release( &package->hdr );\r
+            }\r
+            else\r
                 ERR("Handle for object %p not found\n", package );\r
-            fn(hPackage);\r
-            msiobj_release( &package->hdr );\r
         }\r
         else\r
             ERR("Cannot load functon\n");\r
 \r
         HeapFree(GetProcessHeap(),0,proc);\r
-        FreeLibrary(DLL);\r
+        FreeLibrary(hModule);\r
     }\r
     else\r
         ERR("Unable to load library\n");\r
     msiobj_release( &stuff->package->hdr );\r
-    HeapFree( GetProcessHeap(), 0, info );\r
+    HeapFree(GetProcessHeap(),0,stuff->source);\r
+    HeapFree(GetProcessHeap(),0,stuff->target);\r
+    HeapFree(GetProcessHeap(), 0, stuff);\r
     return 0;\r
 }\r
-#endif\r
+\r
+static DWORD WINAPI DllThread(LPVOID info)\r
+{\r
+    thread_struct *stuff;\r
+    DWORD rc = 0;\r
+  \r
+    TRACE("MSI Thread (0x%lx) started for custom action\n",\r
+                        GetCurrentThreadId());\r
+    \r
+    stuff = (thread_struct*)info;\r
+    rc = ACTION_CallDllFunction(stuff);\r
+\r
+    TRACE("MSI Thread (0x%lx) finished\n",GetCurrentThreadId());\r
+    /* clse all handles for this thread */\r
+    MsiCloseAllHandles();\r
+    return rc;\r
+}\r
 \r
 static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, \r
                                 const LPWSTR target, const INT type)\r
 {\r
     WCHAR tmp_file[MAX_PATH];\r
-    CustomEntry *fn;\r
-    HANDLE DLL;\r
-    LPSTR proc;\r
+    thread_struct *info;\r
+    DWORD ThreadId;\r
+    HANDLE ThreadHandle;\r
 \r
     store_binary_to_temp(package, source, tmp_file);\r
 \r
@@ -1199,76 +1494,57 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source,
         strcatW(tmp_file,dot);\r
     } \r
 \r
-    if (type & 0xc0)\r
-    {\r
-        /* DWORD ThreadId; */\r
-        thread_struct *info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );\r
-\r
-        /* msiobj_addref( &package->hdr ); */\r
-        info->package = package;\r
-        strcpyW(info->target,target);\r
-        strcpyW(info->source,tmp_file);\r
-        TRACE("Start Asynchronous execution\n");\r
-        FIXME("DATABASE NOT THREADSAFE... not starting\n");\r
-        /* CreateThread(NULL,0,DllThread,(LPVOID)&info,0,&ThreadId); */\r
-        /* FIXME: release the package if the CreateThread fails */\r
-        HeapFree( GetProcessHeap(), 0, info );\r
-        return ERROR_SUCCESS;\r
-    }\r
\r
-    DLL = LoadLibraryW(tmp_file);\r
-    if (DLL)\r
-    {\r
-        proc = strdupWtoA( target );\r
-        fn = (CustomEntry*)GetProcAddress(DLL,proc);\r
-        if (fn)\r
-        {\r
-            MSIHANDLE hPackage;\r
+    info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );\r
+    msiobj_addref( &package->hdr );\r
+    info->package = package;\r
+    info->target = dupstrW(target);\r
+    info->source = dupstrW(tmp_file);\r
 \r
-            TRACE("Calling function\n");\r
-            hPackage = msiobj_findhandle( &package->hdr );\r
-            if( !hPackage )\r
-                ERR("Handle for object %p not found\n", package );\r
-            fn(hPackage);\r
-            msiobj_release( &package->hdr );\r
-        }\r
-        else\r
-            ERR("Cannot load functon\n");\r
+    ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);\r
 \r
-        HeapFree(GetProcessHeap(),0,proc);\r
-        FreeLibrary(DLL);\r
-    }\r
-    else\r
-        ERR("Unable to load library\n");\r
+    if (!(type & 0xc0))\r
+        WaitForSingleObject(ThreadHandle,INFINITE);\r
 \r
+    CloseHandle(ThreadHandle);\r
\r
     return ERROR_SUCCESS;\r
 }\r
 \r
 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, \r
                                 const LPWSTR target, const INT type)\r
 {\r
-    WCHAR tmp_file[MAX_PATH*2];\r
+    WCHAR tmp_file[MAX_PATH];\r
     STARTUPINFOW si;\r
     PROCESS_INFORMATION info;\r
     BOOL rc;\r
+    INT len;\r
     WCHAR *deformated;\r
+    WCHAR *cmd;\r
     static const WCHAR spc[] = {' ',0};\r
 \r
     memset(&si,0,sizeof(STARTUPINFOW));\r
 \r
     store_binary_to_temp(package, source, tmp_file);\r
 \r
-    strcatW(tmp_file,spc);\r
     deformat_string(package,target,&deformated);\r
-    strcatW(tmp_file,deformated);\r
+\r
+    len = strlenW(tmp_file) + strlenW(deformated) + 2;\r
+   \r
+    cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);\r
+\r
+    strcpyW(cmd,tmp_file);\r
+    strcatW(cmd,spc);\r
+    strcatW(cmd,deformated);\r
 \r
     HeapFree(GetProcessHeap(),0,deformated);\r
 \r
-    TRACE("executing exe %s \n",debugstr_w(tmp_file));\r
+    TRACE("executing exe %s \n",debugstr_w(cmd));\r
 \r
-    rc = CreateProcessW(NULL, tmp_file, NULL, NULL, FALSE, 0, NULL,\r
+    rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,\r
                   c_collen, &si, &info);\r
 \r
+    HeapFree(GetProcessHeap(),0,cmd);\r
+\r
     if ( !rc )\r
     {\r
         ERR("Unable to execute command\n");\r
@@ -1283,33 +1559,43 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source,
     return ERROR_SUCCESS;\r
 }\r
 \r
-static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, \r
+static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source,\r
                                 const LPWSTR target, const INT type)\r
 {\r
-    WCHAR filename[MAX_PATH*2];\r
     STARTUPINFOW si;\r
     PROCESS_INFORMATION info;\r
     BOOL rc;\r
     WCHAR *deformated;\r
+    WCHAR *cmd;\r
+    INT len;\r
     static const WCHAR spc[] = {' ',0};\r
     int index;\r
 \r
     memset(&si,0,sizeof(STARTUPINFOW));\r
 \r
     index = get_loaded_file(package,source);\r
-    strcpyW(filename,package->files[index].TargetPath);\r
 \r
-    strcatW(filename,spc);\r
+    len = strlenW(package->files[index].TargetPath);\r
+\r
     deformat_string(package,target,&deformated);\r
-    strcatW(filename,deformated);\r
+    len += strlenW(deformated);\r
+    len += 2;\r
+\r
+    cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR));\r
+\r
+    strcpyW(cmd, package->files[index].TargetPath);\r
+    strcatW(cmd, spc);\r
+    strcatW(cmd, deformated);\r
 \r
     HeapFree(GetProcessHeap(),0,deformated);\r
 \r
-    TRACE("executing exe %s \n",debugstr_w(filename));\r
+    TRACE("executing exe %s \n",debugstr_w(cmd));\r
 \r
-    rc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL,\r
+    rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,\r
                   c_collen, &si, &info);\r
 \r
+    HeapFree(GetProcessHeap(),0,cmd);\r
+    \r
     if ( !rc )\r
     {\r
         ERR("Unable to execute command\n");\r
@@ -1324,34 +1610,43 @@ static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source,
     return ERROR_SUCCESS;\r
 }\r
 \r
-static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source, \r
+static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source,\r
                                 const LPWSTR target, const INT type)\r
 {\r
-    WCHAR filename[MAX_PATH*2];\r
     STARTUPINFOW si;\r
     PROCESS_INFORMATION info;\r
+    WCHAR *prop;\r
     BOOL rc;\r
     WCHAR *deformated;\r
+    WCHAR *cmd;\r
+    INT len;\r
+    UINT prc;\r
     static const WCHAR spc[] = {' ',0};\r
-    DWORD sz;\r
 \r
     memset(&si,0,sizeof(STARTUPINFOW));\r
+    memset(&info,0,sizeof(PROCESS_INFORMATION));\r
 \r
-    sz = MAX_PATH*2;\r
-    if (MSI_GetPropertyW(package,source,filename,&sz) != ERROR_SUCCESS)\r
-        return ERROR_FUNCTION_FAILED;\r
+    prop = load_dynamic_property(package,source,&prc);\r
+    if (!prop)\r
+        return prc;\r
 \r
-    strcatW(filename,spc);\r
     deformat_string(package,target,&deformated);\r
-    strcatW(filename,deformated);\r
+    len = strlenW(prop) + strlenW(deformated) + 2;\r
+    cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);\r
+\r
+    strcpyW(cmd,prop);\r
+    strcatW(cmd,spc);\r
+    strcatW(cmd,deformated);\r
 \r
     HeapFree(GetProcessHeap(),0,deformated);\r
 \r
-    TRACE("executing exe %s \n",debugstr_w(filename));\r
+    TRACE("executing exe %s \n",debugstr_w(cmd));\r
 \r
-    rc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL,\r
+    rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,\r
                   c_collen, &si, &info);\r
 \r
+    HeapFree(GetProcessHeap(),0,cmd);\r
+    \r
     if ( !rc )\r
     {\r
         ERR("Unable to execute command\n");\r
@@ -1366,32 +1661,31 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source,
     return ERROR_SUCCESS;\r
 }\r
 \r
-static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source, \r
+static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source,\r
                                 const LPWSTR target, const INT type)\r
 {\r
-    WCHAR filename[MAX_PATH*2];\r
+    LPWSTR filename, deformated;\r
     STARTUPINFOW si;\r
     PROCESS_INFORMATION info;\r
     BOOL rc;\r
-    WCHAR *deformated;\r
 \r
     memset(&si,0,sizeof(STARTUPINFOW));\r
 \r
-    rc = resolve_folder(package, source, filename, FALSE, FALSE, NULL);\r
-    if (rc != ERROR_SUCCESS)\r
-        return rc;\r
+    filename = resolve_folder(package, source, FALSE, FALSE, NULL);\r
+\r
+    if (!filename)\r
+        return ERROR_FUNCTION_FAILED;\r
 \r
     SetCurrentDirectoryW(filename);\r
+    HeapFree(GetProcessHeap(),0,filename);\r
 \r
     deformat_string(package,target,&deformated);\r
-    strcpyW(filename,deformated);\r
-\r
-    HeapFree(GetProcessHeap(),0,deformated);\r
 \r
-    TRACE("executing exe %s \n",debugstr_w(filename));\r
+    TRACE("executing exe %s \n",debugstr_w(deformated));\r
 \r
-    rc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL,\r
+    rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL,\r
                   c_collen, &si, &info);\r
+    HeapFree(GetProcessHeap(),0,deformated);\r
 \r
     if ( !rc )\r
     {\r
@@ -1421,7 +1715,8 @@ static BOOL create_full_pathW(const WCHAR *path)
     WCHAR *new_path;\r
 \r
     new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *\r
-sizeof(WCHAR));\r
+                                              sizeof(WCHAR));\r
+\r
     strcpyW(new_path, path);\r
 \r
     while((len = strlenW(new_path)) && new_path[len - 1] == '\\')\r
@@ -1429,31 +1724,31 @@ sizeof(WCHAR));
 \r
     while(!CreateDirectoryW(new_path, NULL))\r
     {\r
-    WCHAR *slash;\r
-    DWORD last_error = GetLastError();\r
-    if(last_error == ERROR_ALREADY_EXISTS)\r
-        break;\r
+        WCHAR *slash;\r
+        DWORD last_error = GetLastError();\r
+        if(last_error == ERROR_ALREADY_EXISTS)\r
+            break;\r
 \r
-    if(last_error != ERROR_PATH_NOT_FOUND)\r
-    {\r
-        ret = FALSE;\r
-        break;\r
-    }\r
+        if(last_error != ERROR_PATH_NOT_FOUND)\r
+        {\r
+            ret = FALSE;\r
+            break;\r
+        }\r
 \r
-    if(!(slash = strrchrW(new_path, '\\')))\r
-    {\r
-        ret = FALSE;\r
-        break;\r
-    }\r
+        if(!(slash = strrchrW(new_path, '\\')))\r
+        {\r
+            ret = FALSE;\r
+            break;\r
+        }\r
 \r
-    len = slash - new_path;\r
-    new_path[len] = 0;\r
-    if(!create_full_pathW(new_path))\r
-    {\r
-        ret = FALSE;\r
-        break;\r
-    }\r
-    new_path[len] = '\\';\r
+        len = slash - new_path;\r
+        new_path[len] = 0;\r
+        if(!create_full_pathW(new_path))\r
+        {\r
+            ret = FALSE;\r
+            break;\r
+        }\r
+        new_path[len] = '\\';\r
     }\r
 \r
     HeapFree(GetProcessHeap(), 0, new_path);\r
@@ -1488,7 +1783,7 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package)
     while (1)\r
     {\r
         WCHAR dir[0x100];\r
-        WCHAR full_path[MAX_PATH];\r
+        LPWSTR full_path;\r
         DWORD sz;\r
         MSIRECORD *row = NULL, *uirow;\r
 \r
@@ -1510,9 +1805,8 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package)
         }\r
 \r
         sz = MAX_PATH;\r
-        rc = resolve_folder(package,dir,full_path,FALSE,FALSE,&folder);\r
-\r
-        if (rc != ERROR_SUCCESS)\r
+        full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);\r
+        if (!full_path)\r
         {\r
             ERR("Unable to resolve folder id %s\n",debugstr_w(dir));\r
             msiobj_release(&row->hdr);\r
@@ -1533,6 +1827,7 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package)
         folder->State = 3;\r
 \r
         msiobj_release(&row->hdr);\r
+        HeapFree(GetProcessHeap(),0,full_path);\r
     }\r
     MSI_ViewClose(view);\r
     msiobj_release(&view->hdr);\r
@@ -1579,9 +1874,11 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row)
     sz = 96;       \r
     MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);\r
 \r
-    package->components[index].State = INSTALLSTATE_UNKNOWN;\r
+    package->components[index].Installed = INSTALLSTATE_ABSENT;\r
+    package->components[index].Action = INSTALLSTATE_UNKNOWN;\r
+    package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;\r
+\r
     package->components[index].Enabled = TRUE;\r
-    package->components[index].FeatureState= FALSE;\r
 \r
     return index;\r
 }\r
@@ -1591,13 +1888,12 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
     int index = package->loaded_features;\r
     DWORD sz;\r
     static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p',\r
-'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',\r
-'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',\r
-'a','t','u','r','e','_','=','\'','%','s','\'',0};\r
+        'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',\r
+        'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',\r
+        'a','t','u','r','e','_','=','\'','%','s','\'',0};\r
     static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R',\r
-'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',\r
-'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};\r
-    WCHAR Query[1024];\r
+        'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',\r
+        'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};\r
     MSIQUERY * view;\r
     MSIQUERY * view2;\r
     MSIRECORD * row2;\r
@@ -1642,12 +1938,14 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
         MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);\r
 \r
     package->features[index].Attributes= MSI_RecordGetInteger(row,8);\r
-    package->features[index].State = INSTALLSTATE_UNKNOWN;\r
+\r
+    package->features[index].Installed = INSTALLSTATE_ABSENT;\r
+    package->features[index].Action = INSTALLSTATE_UNKNOWN;\r
+    package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;\r
 \r
     /* load feature components */\r
 \r
-    sprintfW(Query,Query1,package->features[index].Feature);\r
-    rc = MSI_DatabaseOpenViewW(package->db,Query,&view);\r
+    rc = ACTION_OpenQuery(package->db, &view, Query1, package->features[index].Feature);\r
     if (rc != ERROR_SUCCESS)\r
         return;\r
     rc = MSI_ViewExecute(view,0);\r
@@ -1680,11 +1978,10 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
                   c_indx);\r
             package->features[index].Components[cnt] = c_indx;\r
             package->features[index].ComponentCount ++;\r
+            continue;\r
         }\r
 \r
-        sprintfW(Query,Query2,buffer);\r
-   \r
-        rc = MSI_DatabaseOpenViewW(package->db,Query,&view2);\r
+        rc = ACTION_OpenQuery(package->db, &view2, Query2, buffer);\r
         if (rc != ERROR_SUCCESS)\r
         {\r
             msiobj_release( &row2->hdr );\r
@@ -1710,6 +2007,7 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
 \r
             package->features[index].Components[cnt] = c_indx;\r
             package->features[index].ComponentCount ++;\r
+            TRACE("Loaded new component to index %i\n",c_indx);\r
         }\r
         MSI_ViewClose(view2);\r
         msiobj_release( &view2->hdr );\r
@@ -1736,7 +2034,6 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package)
 {\r
     MSIQUERY * view;\r
     MSIRECORD * row;\r
-    DWORD sz;\r
     UINT rc;\r
     static const WCHAR Query_all[] = {\r
        'S','E','L','E','C','T',' ','*',' ',\r
@@ -1748,7 +2045,6 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package)
     MSI_SetPropertyW(package, szCosting, szZero);\r
     MSI_SetPropertyW(package, cszRootDrive , c_collen);\r
 \r
-    sz = 0x100;\r
     rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);\r
     if (rc != ERROR_SUCCESS)\r
         return rc;\r
@@ -1780,8 +2076,7 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
 {\r
     DWORD index = package->loaded_files;\r
     DWORD i;\r
-    WCHAR buffer[0x100];\r
-    DWORD sz;\r
+    LPWSTR buffer;\r
 \r
     /* fill in the data */\r
 \r
@@ -1793,12 +2088,9 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
             package->files , package->loaded_files * sizeof(MSIFILE));\r
 \r
     memset(&package->files[index],0,sizeof(MSIFILE));\r
-\r
-    sz = 72;       \r
-    MSI_RecordGetStringW(row,1,package->files[index].File,&sz);\r
-\r
-    sz = 0x100;       \r
-    MSI_RecordGetStringW(row,2,buffer,&sz);\r
\r
+    package->files[index].File = load_dynamic_stringW(row, 1);\r
+    buffer = load_dynamic_stringW(row, 2);\r
 \r
     package->files[index].ComponentIndex = -1;\r
     for (i = 0; i < package->loaded_components; i++)\r
@@ -1809,25 +2101,16 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
         }\r
     if (package->files[index].ComponentIndex == -1)\r
         ERR("Unfound Component %s\n",debugstr_w(buffer));\r
+    HeapFree(GetProcessHeap(), 0, buffer);\r
 \r
-    sz = MAX_PATH;       \r
-    MSI_RecordGetStringW(row,3,package->files[index].FileName,&sz);\r
+    package->files[index].FileName = load_dynamic_stringW(row,3);\r
 \r
     reduce_to_longfilename(package->files[index].FileName);\r
     \r
     package->files[index].FileSize = MSI_RecordGetInteger(row,4);\r
-\r
-    sz = 72;       \r
-    if (!MSI_RecordIsNull(row,5))\r
-        MSI_RecordGetStringW(row,5,package->files[index].Version,&sz);\r
-\r
-    sz = 20;       \r
-    if (!MSI_RecordIsNull(row,6))\r
-        MSI_RecordGetStringW(row,6,package->files[index].Language,&sz);\r
-\r
-    if (!MSI_RecordIsNull(row,7))\r
-        package->files[index].Attributes= MSI_RecordGetInteger(row,7);\r
-\r
+    package->files[index].Version = load_dynamic_stringW(row, 5);\r
+    package->files[index].Language = load_dynamic_stringW(row, 6);\r
+    package->files[index].Attributes= MSI_RecordGetInteger(row,7);\r
     package->files[index].Sequence= MSI_RecordGetInteger(row,8);\r
 \r
     package->files[index].Temporary = FALSE;\r
@@ -1883,18 +2166,13 @@ static UINT ACTION_FileCost(MSIPACKAGE *package)
 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)\r
 \r
 {\r
-    WCHAR Query[1024] = \r
-{'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',\r
-'t','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',\r
-'o','r','y','`',' ','=',' ','`',0};\r
-    static const WCHAR end[]={'`',0};\r
+    static const WCHAR Query[] =\r
+        {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',\r
+         't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',\r
+         'o','r','y','`',' ','=',' ','`','%','s','`',0};\r
     UINT rc;\r
     MSIQUERY * view;\r
-    WCHAR targetbuffer[0x100];\r
-    WCHAR *srcdir = NULL;\r
-    WCHAR *targetdir = NULL;\r
-    WCHAR parent[0x100];\r
-    DWORD sz=0x100;\r
+    LPWSTR targetdir, parent, srcdir;\r
     MSIRECORD * row = 0;\r
     INT index = -1;\r
     DWORD i;\r
@@ -1912,10 +2190,8 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
 \r
     TRACE("Working to load %s\n",debugstr_w(dir));\r
 \r
-    index = package->loaded_folders; \r
-\r
-    package->loaded_folders++;\r
-    if (package->loaded_folders== 1)\r
+    index = package->loaded_folders++;\r
+    if (package->loaded_folders==1)\r
         package->folders = HeapAlloc(GetProcessHeap(),0,\r
                                         sizeof(MSIFOLDER));\r
     else\r
@@ -1925,13 +2201,9 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
 \r
     memset(&package->folders[index],0,sizeof(MSIFOLDER));\r
 \r
-    strcpyW(package->folders[index].Directory,dir);\r
-\r
-    strcatW(Query,dir);\r
-    strcatW(Query,end);\r
-\r
-    rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
+    package->folders[index].Directory = dupstrW(dir);\r
 \r
+    rc = ACTION_OpenQuery(package->db, &view, Query, dir);\r
     if (rc != ERROR_SUCCESS)\r
         return -1;\r
 \r
@@ -1951,9 +2223,7 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
         return -1;\r
     }\r
 \r
-    sz=0x100;\r
-    MSI_RecordGetStringW(row,3,targetbuffer,&sz);\r
-    targetdir=targetbuffer;\r
+    targetdir = load_dynamic_stringW(row,3);\r
 \r
     /* split src and target dir */\r
     if (strchrW(targetdir,':'))\r
@@ -1986,38 +2256,35 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
     if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)\r
         srcdir = NULL;\r
 \r
-     if (targetdir)\r
-        strcpyW(package->folders[index].TargetDefault,targetdir);\r
-\r
-     if (srcdir)\r
-        strcpyW(package->folders[index].SourceDefault,srcdir);\r
-     else if (targetdir)\r
-        strcpyW(package->folders[index].SourceDefault,targetdir);\r
-\r
-    if (MSI_RecordIsNull(row,2))\r
-        parent[0]=0;\r
-    else\r
+    if (targetdir)\r
     {\r
-            sz=0x100;\r
-            MSI_RecordGetStringW(row,2,parent,&sz);\r
+        TRACE("   TargetDefault = %s\n",debugstr_w(targetdir));\r
+        if (package->folders[index].TargetDefault)\r
+            HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);\r
+        package->folders[index].TargetDefault = dupstrW(targetdir);\r
     }\r
 \r
-    if (parent[0]) \r
+    if (srcdir)\r
+       package->folders[index].SourceDefault = dupstrW(srcdir);\r
+    else if (targetdir)\r
+        package->folders[index].SourceDefault = dupstrW(targetdir);\r
+    HeapFree(GetProcessHeap(), 0, targetdir);\r
+\r
+    parent = load_dynamic_stringW(row,2);\r
+    if (parent) \r
     {\r
         i = load_folder(package,parent);\r
         package->folders[index].ParentIndex = i;\r
         TRACE("Parent is index %i... %s %s\n",\r
                     package->folders[index].ParentIndex,\r
-    debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),\r
+        debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),\r
                     debugstr_w(parent));\r
     }\r
     else\r
         package->folders[index].ParentIndex = -2;\r
+    HeapFree(GetProcessHeap(), 0, parent);\r
 \r
-    sz = MAX_PATH;\r
-    rc = MSI_GetPropertyW(package, dir, package->folders[index].Property, &sz);\r
-    if (rc != ERROR_SUCCESS)\r
-        package->folders[index].Property[0]=0;\r
+    package->folders[index].Property = load_dynamic_property(package, dir,NULL);\r
 \r
     msiobj_release(&row->hdr);\r
     MSI_ViewClose(view);\r
@@ -2026,57 +2293,61 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
     return index;\r
 }\r
 \r
-static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path, \r
+\r
+static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name,\r
                            BOOL source, BOOL set_prop, MSIFOLDER **folder)\r
 {\r
     DWORD i;\r
-    UINT rc = ERROR_SUCCESS;\r
-    DWORD sz;\r
+    LPWSTR p, path = NULL;\r
 \r
     TRACE("Working to resolve %s\n",debugstr_w(name));\r
 \r
-    if (!path)\r
-        return rc;\r
-\r
     /* special resolving for Target and Source root dir */\r
     if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)\r
     {\r
         if (!source)\r
         {\r
-            sz = MAX_PATH;\r
-            rc = MSI_GetPropertyW(package,cszTargetDir,path,&sz);\r
-            if (rc != ERROR_SUCCESS)\r
+            path = load_dynamic_property(package,cszTargetDir,NULL);\r
+            if (!path)\r
             {\r
-                sz = MAX_PATH;\r
-                rc = MSI_GetPropertyW(package,cszRootDrive,path,&sz);\r
+                path = load_dynamic_property(package,cszRootDrive,NULL);\r
                 if (set_prop)\r
                     MSI_SetPropertyW(package,cszTargetDir,path);\r
             }\r
             if (folder)\r
-                *folder = &(package->folders[0]);\r
-            return rc;\r
+            {\r
+                for (i = 0; i < package->loaded_folders; i++)\r
+                {\r
+                    if (strcmpW(package->folders[i].Directory,name)==0)\r
+                        break;\r
+                }\r
+                *folder = &(package->folders[i]);\r
+            }\r
+            return path;\r
         }\r
         else\r
         {\r
-            sz = MAX_PATH;\r
-            rc = MSI_GetPropertyW(package,cszSourceDir,path,&sz);\r
-            if (rc != ERROR_SUCCESS)\r
+            path = load_dynamic_property(package,cszSourceDir,NULL);\r
+            if (!path)\r
             {\r
-                sz = MAX_PATH;\r
-                rc = MSI_GetPropertyW(package,cszDatabase,path,&sz);\r
-                if (rc == ERROR_SUCCESS)\r
+                path = load_dynamic_property(package,cszDatabase,NULL);\r
+                if (path)\r
                 {\r
-                    LPWSTR ptr = strrchrW(path,'\\');\r
-                    if (ptr)\r
-                    {\r
-                        ptr++;\r
-                        *ptr = 0;\r
-                    }\r
+                    p = strrchrW(path,'\\');\r
+                    if (p)\r
+                        *(p+1) = 0;\r
                 }\r
             }\r
             if (folder)\r
-                *folder = &(package->folders[0]);\r
-            return rc;\r
+            {\r
+                for (i = 0; i < package->loaded_folders; i++)\r
+                {\r
+                    if (strcmpW(package->folders[i].Directory,name)==0)\r
+                        break;\r
+                }\r
+                *folder = &(package->folders[i]);\r
+            }\r
+            return path;\r
         }\r
     }\r
 \r
@@ -2087,67 +2358,186 @@ static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path,
     }\r
 \r
     if (i >= package->loaded_folders)\r
-        return ERROR_FUNCTION_FAILED;\r
+        return NULL;\r
 \r
     if (folder)\r
         *folder = &(package->folders[i]);\r
 \r
-    if (!source && package->folders[i].ResolvedTarget[0])\r
+    if (!source && package->folders[i].ResolvedTarget)\r
     {\r
-        strcpyW(path,package->folders[i].ResolvedTarget);\r
+        path = dupstrW(package->folders[i].ResolvedTarget);\r
         TRACE("   already resolved to %s\n",debugstr_w(path));\r
-        return ERROR_SUCCESS;\r
+        return path;\r
     }\r
-    else if (source && package->folders[i].ResolvedSource[0])\r
+    else if (source && package->folders[i].ResolvedSource)\r
     {\r
-        strcpyW(path,package->folders[i].ResolvedSource);\r
-        return ERROR_SUCCESS;\r
+        path = dupstrW(package->folders[i].ResolvedSource);\r
+        return path;\r
     }\r
-    else if (!source && package->folders[i].Property[0])\r
+    else if (!source && package->folders[i].Property)\r
     {\r
-        strcpyW(path,package->folders[i].Property);\r
+        path = dupstrW(package->folders[i].Property);\r
         TRACE("   internally set to %s\n",debugstr_w(path));\r
         if (set_prop)\r
             MSI_SetPropertyW(package,name,path);\r
-        return ERROR_SUCCESS;\r
+        return path;\r
+    }\r
+\r
+    if (package->folders[i].ParentIndex >= 0)\r
+    {\r
+        LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;\r
+\r
+        TRACE(" ! Parent is %s\n", debugstr_w(parent));\r
+\r
+        p = resolve_folder(package, parent, source, set_prop, NULL);\r
+        if (!source)\r
+        {\r
+            TRACE("   TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));\r
+            path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);\r
+            package->folders[i].ResolvedTarget = dupstrW(path);\r
+            TRACE("   resolved into %s\n",debugstr_w(path));\r
+            if (set_prop)\r
+                MSI_SetPropertyW(package,name,path);\r
+        }\r
+        else \r
+        {\r
+            path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);\r
+            package->folders[i].ResolvedSource = dupstrW(path);\r
+        }\r
+        HeapFree(GetProcessHeap(),0,p);\r
+    }\r
+    return path;\r
+}\r
+\r
+static UINT SetFeatureStates(MSIPACKAGE *package)\r
+{\r
+    LPWSTR level;\r
+    INT install_level;\r
+    DWORD i;\r
+    INT j;\r
+    LPWSTR override = NULL;\r
+    static const WCHAR all[]={'A','L','L',0};\r
+    static const WCHAR szlevel[] = {\r
+        'I','N','S','T','A','L','L','L','E','V','E','L',0};\r
+    static const WCHAR szAddLocal[] = {\r
+        'A','D','D','L','O','C','A','L',0};\r
+\r
+    /* I do not know if this is where it should happen.. but */\r
+\r
+    TRACE("Checking Install Level\n");\r
+\r
+    level = load_dynamic_property(package,szlevel,NULL);\r
+    if (level)\r
+    {\r
+        install_level = atoiW(level);\r
+        HeapFree(GetProcessHeap(), 0, level);\r
+    }\r
+    else\r
+        install_level = 1;\r
+\r
+    /* ok hereis the rub\r
+     * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE\r
+     * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is\r
+     * itnored for all the features. seems strange, epsecially since it is not\r
+     * documented anywhere, but it is how it works. \r
+     */\r
+    \r
+    override = load_dynamic_property(package,szAddLocal,NULL);\r
+  \r
+    if (override)\r
+    {\r
+        for(i = 0; i < package->loaded_features; i++)\r
+        {\r
+            if (strcmpiW(override,all)==0)\r
+            {\r
+                package->features[i].ActionRequest= INSTALLSTATE_LOCAL;\r
+                package->features[i].Action = INSTALLSTATE_LOCAL;\r
+            }\r
+            else\r
+            {\r
+                LPWSTR ptr = override;\r
+                LPWSTR ptr2 = strchrW(override,',');\r
+\r
+                while (ptr)\r
+                {\r
+                    if ((ptr2 && \r
+                        strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0)\r
+                        || (!ptr2 &&\r
+                        strcmpW(ptr,package->features[i].Feature)==0))\r
+                    {\r
+                        package->features[i].ActionRequest= INSTALLSTATE_LOCAL;\r
+                        package->features[i].Action = INSTALLSTATE_LOCAL;\r
+                        break;\r
+                    }\r
+                    if (ptr2)\r
+                    {\r
+                        ptr=ptr2+1;\r
+                        ptr2 = strchrW(ptr,',');\r
+                    }\r
+                    else\r
+                        break;\r
+                }\r
+            }\r
+        }\r
+        HeapFree(GetProcessHeap(),0,override);\r
+    } \r
+    else\r
+    {\r
+        for(i = 0; i < package->loaded_features; i++)\r
+        {\r
+            BOOL feature_state= ((package->features[i].Level > 0) &&\r
+                             (package->features[i].Level <= install_level));\r
+\r
+            if (feature_state)\r
+            {\r
+                package->features[i].ActionRequest= INSTALLSTATE_LOCAL;\r
+                package->features[i].Action = INSTALLSTATE_LOCAL;\r
+            }\r
+        }\r
     }\r
 \r
-    if (package->folders[i].ParentIndex >= 0)\r
-    {\r
-        int len;\r
-        TRACE(" ! Parent is %s\n", debugstr_w(package->folders[\r
-                   package->folders[i].ParentIndex].Directory));\r
-        resolve_folder(package, package->folders[\r
-                       package->folders[i].ParentIndex].Directory, path,source,\r
-                       set_prop, NULL);\r
+    /*\r
+     * now we want to enable or disable components base on feature \r
+    */\r
 \r
-        len = strlenW(path);\r
-        if (len && path[len-1] != '\\')\r
-            strcatW(path, cszbs);\r
+    for(i = 0; i < package->loaded_features; i++)\r
+    {\r
+        MSIFEATURE* feature = &package->features[i];\r
+        TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",\r
+            debugstr_w(feature->Feature), feature->Installed, feature->Action,\r
+            feature->ActionRequest);\r
 \r
-        if (!source)\r
+        for( j = 0; j < feature->ComponentCount; j++)\r
         {\r
-            if (package->folders[i].TargetDefault[0])\r
+            MSICOMPONENT* component = &package->components[\r
+                                                    feature->Components[j]];\r
+\r
+            if (!component->Enabled)\r
             {\r
-                strcatW(path,package->folders[i].TargetDefault);\r
-                strcatW(path,cszbs);\r
+                component->Action = INSTALLSTATE_ABSENT;\r
+                component->ActionRequest = INSTALLSTATE_ABSENT;\r
             }\r
-            strcpyW(package->folders[i].ResolvedTarget,path);\r
-            TRACE("   resolved into %s\n",debugstr_w(path));\r
-            if (set_prop)\r
-                MSI_SetPropertyW(package,name,path);\r
-        }\r
-        else \r
-        {\r
-            if (package->folders[i].SourceDefault[0])\r
+            else\r
             {\r
-                strcatW(path,package->folders[i].SourceDefault);\r
-                strcatW(path,cszbs);\r
+                if (feature->Action == INSTALLSTATE_LOCAL)\r
+                    component->Action = INSTALLSTATE_LOCAL;\r
+                if (feature->ActionRequest == INSTALLSTATE_LOCAL)\r
+                    component->ActionRequest = INSTALLSTATE_LOCAL;\r
             }\r
-            strcpyW(package->folders[i].ResolvedSource,path);\r
         }\r
+    } \r
+\r
+    for(i = 0; i < package->loaded_components; i++)\r
+    {\r
+        MSICOMPONENT* component= &package->components[i];\r
+\r
+        TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",\r
+            debugstr_w(component->Component), component->Installed, \r
+            component->Action, component->ActionRequest);\r
     }\r
-    return rc;\r
+\r
+\r
+    return ERROR_SUCCESS;\r
 }\r
 \r
 /* \r
@@ -2166,10 +2556,13 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
         'C','o','n','d','i','t','i','o','n',0};\r
     static const WCHAR szCosting[] = {\r
        'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };\r
+    static const WCHAR szlevel[] = {\r
+        'I','N','S','T','A','L','L','L','E','V','E','L',0};\r
     static const WCHAR szOne[] = { '1', 0 };\r
     UINT rc;\r
     MSIQUERY * view;\r
     DWORD i;\r
+    LPWSTR level;\r
 \r
     TRACE("Building Directory properties\n");\r
 \r
@@ -2187,7 +2580,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
         while (1)\r
         {\r
             WCHAR name[0x100];\r
-            WCHAR path[MAX_PATH];\r
+            LPWSTR path;\r
             MSIRECORD * row = 0;\r
             DWORD sz;\r
 \r
@@ -2204,8 +2597,9 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
             /* This helper function now does ALL the work */\r
             TRACE("Dir %s ...\n",debugstr_w(name));\r
             load_folder(package,name);\r
-            resolve_folder(package,name,path,FALSE,TRUE,NULL);\r
+            path = resolve_folder(package,name,FALSE,TRUE,NULL);\r
             TRACE("resolves to %s\n",debugstr_w(path));\r
+            HeapFree( GetProcessHeap(), 0, path);\r
 \r
             msiobj_release(&row->hdr);\r
         }\r
@@ -2224,21 +2618,29 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
         if (file->ComponentIndex >= 0)\r
             comp = &package->components[file->ComponentIndex];\r
 \r
+        if (file->Temporary == TRUE)\r
+            continue;\r
+\r
         if (comp)\r
         {\r
-            int len;\r
+            LPWSTR p;\r
+\r
             /* calculate target */\r
-            resolve_folder(package, comp->Directory, file->TargetPath, FALSE,\r
-                       FALSE, NULL);\r
-            /* make sure that the path ends in a \ */\r
-            len = strlenW(file->TargetPath);\r
-            if (len && file->TargetPath[len-1] != '\\')\r
-                strcatW(file->TargetPath, cszbs);\r
-            strcatW(file->TargetPath,file->FileName);\r
+            p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);\r
+\r
+            if (file->TargetPath)\r
+                HeapFree(GetProcessHeap(),0,file->TargetPath);\r
+\r
+            TRACE("file %s is named %s\n",\r
+                   debugstr_w(file->File),debugstr_w(file->FileName));       \r
+\r
+            file->TargetPath = build_directory_name(2, p, file->FileName);\r
+\r
+            HeapFree(GetProcessHeap(),0,p);\r
 \r
             TRACE("file %s resolves to %s\n",\r
                    debugstr_w(file->File),debugstr_w(file->TargetPath));       \r
\r
+\r
             if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)\r
             {\r
                 file->State = 1;\r
@@ -2246,7 +2648,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
             }\r
             else\r
             {\r
-                if (file->Version[0])\r
+                if (file->Version)\r
                 {\r
                     DWORD handle;\r
                     DWORD versize;\r
@@ -2295,55 +2697,55 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
     rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);\r
     if (rc == ERROR_SUCCESS)\r
     {\r
-    rc = MSI_ViewExecute(view, 0);\r
-    if (rc != ERROR_SUCCESS)\r
-    {\r
-        MSI_ViewClose(view);\r
-        msiobj_release(&view->hdr);\r
-        return rc;\r
-    }\r
-    \r
-    while (1)\r
-    {\r
-        WCHAR Feature[0x100];\r
-        MSIRECORD * row = 0;\r
-        DWORD sz;\r
-        int feature_index;\r
-\r
-        rc = MSI_ViewFetch(view,&row);\r
-\r
+        rc = MSI_ViewExecute(view, 0);\r
         if (rc != ERROR_SUCCESS)\r
         {\r
-            rc = ERROR_SUCCESS;\r
-            break;\r
+            MSI_ViewClose(view);\r
+            msiobj_release(&view->hdr);\r
+            return rc;\r
         }\r
+    \r
+        while (1)\r
+        {\r
+            WCHAR Feature[0x100];\r
+            MSIRECORD * row = 0;\r
+            DWORD sz;\r
+            int feature_index;\r
 \r
-        sz = 0x100;\r
-        MSI_RecordGetStringW(row,1,Feature,&sz);\r
+            rc = MSI_ViewFetch(view,&row);\r
 \r
-        feature_index = get_loaded_feature(package,Feature);\r
-        if (feature_index < 0)\r
-            ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));\r
-        else\r
-        {\r
-            LPWSTR Condition;\r
-            Condition = load_dynamic_stringW(row,3);\r
+            if (rc != ERROR_SUCCESS)\r
+            {\r
+                rc = ERROR_SUCCESS;\r
+                break;\r
+            }\r
+\r
+            sz = 0x100;\r
+            MSI_RecordGetStringW(row,1,Feature,&sz);\r
+\r
+            feature_index = get_loaded_feature(package,Feature);\r
+            if (feature_index < 0)\r
+                ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));\r
+            else\r
+            {\r
+                LPWSTR Condition;\r
+                Condition = load_dynamic_stringW(row,3);\r
 \r
                 if (MSI_EvaluateConditionW(package,Condition) == \r
                     MSICONDITION_TRUE)\r
-            {\r
-                int level = MSI_RecordGetInteger(row,2);\r
+                {\r
+                    int level = MSI_RecordGetInteger(row,2);\r
                     TRACE("Reseting feature %s to level %i\n",\r
                            debugstr_w(Feature), level);\r
-                package->features[feature_index].Level = level;\r
+                    package->features[feature_index].Level = level;\r
+                }\r
+                HeapFree(GetProcessHeap(),0,Condition);\r
             }\r
-            HeapFree(GetProcessHeap(),0,Condition);\r
-        }\r
 \r
-        msiobj_release(&row->hdr);\r
-    }\r
-    MSI_ViewClose(view);\r
-    msiobj_release(&view->hdr);\r
+            msiobj_release(&row->hdr);\r
+        }\r
+        MSI_ViewClose(view);\r
+        msiobj_release(&view->hdr);\r
     }\r
 \r
     TRACE("Enabling or Disabling Components\n");\r
@@ -2362,7 +2764,15 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
     }\r
 \r
     MSI_SetPropertyW(package,szCosting,szOne);\r
-    return ERROR_SUCCESS;\r
+    /* set default run level if not set */\r
+    level = load_dynamic_property(package,szlevel,NULL);\r
+    if (!level)\r
+        MSI_SetPropertyW(package,szlevel, szOne);\r
+    else\r
+        HeapFree(GetProcessHeap(),0,level);\r
+\r
+    return SetFeatureStates(package);\r
+\r
 }\r
 \r
 /*\r
@@ -2408,6 +2818,12 @@ end:
 \r
 \r
 /* Support functions for FDI functions */\r
+typedef struct\r
+{\r
+    MSIPACKAGE* package;\r
+    LPCSTR cab_path;\r
+    LPCSTR file_name;\r
+} CabData;\r
 \r
 static void * cabinet_alloc(ULONG cb)\r
 {\r
@@ -2480,14 +2896,39 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
     {\r
     case fdintCOPY_FILE:\r
     {\r
-        ULONG len = strlen((char*)pfdin->pv) + strlen(pfdin->psz1);\r
-        char *file = cabinet_alloc((len+1)*sizeof(char));\r
+        CabData *data = (CabData*) pfdin->pv;\r
+        ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);\r
+        char *file;\r
 \r
-        strcpy(file, (char*)pfdin->pv);\r
+        LPWSTR trackname;\r
+        LPWSTR trackpath;\r
+        LPWSTR tracknametmp;\r
+        static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};\r
+       \r
+        if (data->file_name && strcmp(data->file_name,pfdin->psz1))\r
+                return 0;\r
+        \r
+        file = cabinet_alloc((len+1)*sizeof(char));\r
+        strcpy(file, data->cab_path);\r
         strcat(file, pfdin->psz1);\r
 \r
         TRACE("file: %s\n", debugstr_a(file));\r
 \r
+        /* track this file so it can be deleted if not installed */\r
+        trackpath=strdupAtoW(file);\r
+        tracknametmp=strdupAtoW(strrchr(file,'\\')+1);\r
+        trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + \r
+                                  strlenW(tmpprefix)+1) * sizeof(WCHAR));\r
+\r
+        strcpyW(trackname,tmpprefix);\r
+        strcatW(trackname,tracknametmp);\r
+\r
+        track_tempfile(data->package, trackname, trackpath);\r
+\r
+        HeapFree(GetProcessHeap(),0,trackpath);\r
+        HeapFree(GetProcessHeap(),0,trackname);\r
+        HeapFree(GetProcessHeap(),0,tracknametmp);\r
+\r
         return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);\r
     }\r
     case fdintCLOSE_FILE_INFO:\r
@@ -2514,15 +2955,19 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
  *\r
  * Extract files from a cab file.\r
  */\r
-static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)\r
+static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, \r
+                                 const WCHAR* path, const WCHAR* file)\r
 {\r
     HFDI hfdi;\r
     ERF erf;\r
     BOOL ret;\r
     char *cabinet;\r
     char *cab_path;\r
+    char *file_name;\r
+    CabData data;\r
 \r
-    TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));\r
+    TRACE("Extracting %s (%s) to %s\n",debugstr_w(source), \r
+                    debugstr_w(file), debugstr_w(path));\r
 \r
     hfdi = FDICreate(cabinet_alloc,\r
                      cabinet_free,\r
@@ -2551,7 +2996,12 @@ static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)
         return FALSE;\r
     }\r
 \r
-    ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, cab_path);\r
+    data.package = package;\r
+    data.cab_path = cab_path;\r
+    file_name = strdupWtoA(file);\r
+    data.file_name = file_name;\r
+\r
+    ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);\r
 \r
     if (!ret)\r
         ERR("FDICopy failed\n");\r
@@ -2560,17 +3010,18 @@ static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)
 \r
     HeapFree(GetProcessHeap(), 0, cabinet);\r
     HeapFree(GetProcessHeap(), 0, cab_path);\r
+    HeapFree(GetProcessHeap(), 0, file_name);\r
 \r
     return ret;\r
 }\r
 \r
 static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, \r
-                                 WCHAR* path)\r
+                                 WCHAR* path, WCHAR* file)\r
 {\r
     UINT rc;\r
     MSIQUERY * view;\r
     MSIRECORD * row = 0;\r
-    WCHAR source[MAX_PATH];\r
+    static WCHAR source[MAX_PATH];\r
     static const WCHAR ExecSeqQuery[] = {\r
         's','e','l','e','c','t',' ','*',' ',\r
         'f','r','o','m',' ','M','e','d','i','a',' ',\r
@@ -2585,6 +3036,7 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence,
     if (sequence <= last_sequence)\r
     {\r
         TRACE("Media already ready (%u, %u)\n",sequence,last_sequence);\r
+        extract_a_cabinet_file(package, source,path,file);\r
         return ERROR_SUCCESS;\r
     }\r
 \r
@@ -2643,7 +3095,7 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence,
                     GetTempPathW(MAX_PATH,path);\r
             }\r
         }\r
-        rc = !extract_cabinet_file(source,path);\r
+        rc = !extract_a_cabinet_file(package, source,path,file);\r
     }\r
     msiobj_release(&row->hdr);\r
     MSI_ViewClose(view);\r
@@ -2655,13 +3107,12 @@ inline static UINT create_component_directory ( MSIPACKAGE* package, INT compone
 {\r
     UINT rc;\r
     MSIFOLDER *folder;\r
-    WCHAR install_path[MAX_PATH];\r
+    LPWSTR install_path;\r
 \r
-    rc = resolve_folder(package, package->components[component].Directory,\r
-                        install_path, FALSE, FALSE, &folder);\r
-\r
-    if (rc != ERROR_SUCCESS)\r
-        return rc; \r
+    install_path = resolve_folder(package, package->components[component].Directory,\r
+                        FALSE, FALSE, &folder);\r
+    if (!install_path)\r
+        return ERROR_FUNCTION_FAILED; \r
 \r
     /* create the path */\r
     if (folder->State == 0)\r
@@ -2669,6 +3120,7 @@ inline static UINT create_component_directory ( MSIPACKAGE* package, INT compone
         create_full_pathW(install_path);\r
         folder->State = 2;\r
     }\r
+    HeapFree(GetProcessHeap(), 0, install_path);\r
 \r
     return rc;\r
 }\r
@@ -2684,7 +3136,7 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package)
         return ERROR_INVALID_HANDLE;\r
 \r
     /* increment progress bar each time action data is sent */\r
-    ui_progress(package,1,1,1,0);\r
+    ui_progress(package,1,1,0,0);\r
 \r
     for (index = 0; index < package->loaded_files; index++)\r
     {\r
@@ -2696,18 +3148,25 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package)
         if (file->Temporary)\r
             continue;\r
 \r
-        if (!package->components[file->ComponentIndex].Enabled ||\r
-            !package->components[file->ComponentIndex].FeatureState)\r
+        if (package->components[file->ComponentIndex].ActionRequest != \r
+             INSTALLSTATE_LOCAL)\r
         {\r
+            ui_progress(package,2,file->FileSize,0,0);\r
             TRACE("File %s is not scheduled for install\n",\r
                    debugstr_w(file->File));\r
+\r
             continue;\r
         }\r
 \r
         if ((file->State == 1) || (file->State == 2))\r
         {\r
+            LPWSTR p;\r
+            INT len;\r
+            MSICOMPONENT* comp = NULL;\r
+\r
             TRACE("Installing %s\n",debugstr_w(file->File));\r
-            rc = ready_media_for_file(package,file->Sequence,path_to_source);\r
+            rc = ready_media_for_file(package,file->Sequence,path_to_source,\r
+                            file->File);\r
             /* \r
              * WARNING!\r
              * our file table could change here because a new temp file\r
@@ -2723,6 +3182,19 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package)
 \r
             create_component_directory( package, file->ComponentIndex);\r
 \r
+            /* recalculate file paths because things may have changed */\r
+\r
+            if (file->ComponentIndex >= 0)\r
+                comp = &package->components[file->ComponentIndex];\r
+\r
+            p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);\r
+            if (file->TargetPath)\r
+                HeapFree(GetProcessHeap(),0,file->TargetPath);\r
+\r
+            file->TargetPath = build_directory_name(2, p, file->FileName);\r
+\r
+            len = strlenW(path_to_source) + strlenW(file->File) + 2;\r
+            file->SourcePath = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));\r
             strcpyW(file->SourcePath, path_to_source);\r
             strcatW(file->SourcePath, file->File);\r
 \r
@@ -2738,6 +3210,7 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package)
             MSI_RecordSetInteger(uirow,6,file->FileSize);\r
             ui_actiondata(package,szInstallFiles,uirow);\r
             msiobj_release( &uirow->hdr );\r
+            ui_progress(package,2,file->FileSize,0,0);\r
 \r
             if (!MoveFileW(file->SourcePath,file->TargetPath))\r
             {\r
@@ -2751,13 +3224,19 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package)
                     DeleteFileW(file->SourcePath);\r
                     rc = 0;\r
                 }\r
+                else if (rc == ERROR_FILE_NOT_FOUND)\r
+                {\r
+                    ERR("Source File Not Found!  Continueing\n");\r
+                    rc = 0;\r
+                }\r
                 else\r
-                    break;\r
+                {\r
+                    ERR("Ignoring Error and continuing...\n");\r
+                    rc = 0;\r
+                }\r
             }\r
             else\r
                 file->State = 4;\r
-\r
-            ui_progress(package,2,0,0,0);\r
         }\r
     }\r
 \r
@@ -2765,7 +3244,7 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package)
 }\r
 \r
 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, \r
-                                   LPWSTR file_source)\r
+                                   LPWSTR* file_source)\r
 {\r
     DWORD index;\r
 \r
@@ -2778,7 +3257,7 @@ inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
         {\r
             if (package->files[index].State >= 3)\r
             {\r
-                strcpyW(file_source,package->files[index].TargetPath);\r
+                *file_source = dupstrW(package->files[index].TargetPath);\r
                 return ERROR_SUCCESS;\r
             }\r
             else\r
@@ -2816,9 +3295,9 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
     while (1)\r
     {\r
         WCHAR file_key[0x100];\r
-        WCHAR file_source[MAX_PATH];\r
+        WCHAR *file_source = NULL;\r
         WCHAR dest_name[0x100];\r
-        WCHAR dest_path[MAX_PATH];\r
+        LPWSTR dest_path, dest;\r
         WCHAR component[0x100];\r
         INT component_index;\r
 \r
@@ -2841,8 +3320,8 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
         }\r
 \r
         component_index = get_loaded_component(package,component);\r
-        if (!package->components[component_index].Enabled ||\r
-            !package->components[component_index].FeatureState)\r
+        if (package->components[component_index].ActionRequest != \r
+             INSTALLSTATE_LOCAL)\r
         {\r
             TRACE("Skipping copy due to disabled component\n");\r
             msiobj_release(&row->hdr);\r
@@ -2858,12 +3337,14 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
             break;\r
         }\r
 \r
-        rc = get_file_target(package,file_key,file_source);\r
+        rc = get_file_target(package,file_key,&file_source);\r
 \r
         if (rc != ERROR_SUCCESS)\r
         {\r
             ERR("Original file unknown %s\n",debugstr_w(file_key));\r
             msiobj_release(&row->hdr);\r
+            if (file_source)\r
+                HeapFree(GetProcessHeap(),0,file_source);\r
             break;\r
         }\r
 \r
@@ -2880,8 +3361,11 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
 \r
         if (MSI_RecordIsNull(row,5))\r
         {\r
-            strcpyW(dest_path,file_source);\r
-            *strrchrW(dest_path,'\\')=0;\r
+            LPWSTR p;\r
+            dest_path = dupstrW(file_source);\r
+            p = strrchrW(dest_path,'\\');\r
+            if (p)\r
+                *p=0;\r
         }\r
         else\r
         {\r
@@ -2889,22 +3373,25 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
             sz=0x100;\r
             MSI_RecordGetStringW(row,5,destkey,&sz);\r
             sz = 0x100;\r
-            rc = resolve_folder(package, destkey, dest_path,FALSE,FALSE,NULL);\r
-            if (rc != ERROR_SUCCESS)\r
+            dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);\r
+            if (!dest_path)\r
             {\r
                 ERR("Unable to get destination folder\n");\r
                 msiobj_release(&row->hdr);\r
+                if (file_source)\r
+                    HeapFree(GetProcessHeap(),0,file_source);\r
                 break;\r
             }\r
         }\r
 \r
-        strcatW(dest_path,dest_name);\r
+        dest = build_directory_name(2, dest_path, dest_name);\r
+        HeapFree(GetProcessHeap(), 0, dest_path);\r
            \r
         TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),\r
-              debugstr_w(dest_path)); \r
+              debugstr_w(dest)); \r
         \r
-        if (strcmpW(file_source,dest_path))\r
-            rc = !CopyFileW(file_source,dest_path,TRUE);\r
+        if (strcmpW(file_source,dest))\r
+            rc = !CopyFileW(file_source,dest,TRUE);\r
         else\r
             rc = ERROR_SUCCESS;\r
         \r
@@ -2914,11 +3401,12 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
         FIXME("We should track these duplicate files as well\n");   \r
  \r
         msiobj_release(&row->hdr);\r
+        HeapFree(GetProcessHeap(),0,dest);\r
+        HeapFree(GetProcessHeap(),0,file_source);\r
     }\r
     MSI_ViewClose(view);\r
     msiobj_release(&view->hdr);\r
     return rc;\r
-\r
 }\r
 \r
 \r
@@ -3024,7 +3512,7 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
     }\r
 \r
     /* increment progress bar each time action data is sent */\r
-    ui_progress(package,1,1,1,0);\r
+    ui_progress(package,1,REG_PROGRESS_VALUE,1,0);\r
 \r
     while (1)\r
     {\r
@@ -3038,19 +3526,15 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
         static const WCHAR szHU[] =\r
 {'H','K','E','Y','_','U','S','E','R','S','\\',0};\r
 \r
-        WCHAR key[0x100];\r
-        WCHAR name[0x100];\r
-        LPWSTR value;\r
         LPSTR value_data = NULL;\r
         HKEY  root_key, hkey;\r
         DWORD type,size;\r
-        WCHAR component[0x100];\r
+        LPWSTR value, key, name, component, deformated;\r
+        LPCWSTR szRoot;\r
         INT component_index;\r
         MSIRECORD * uirow;\r
-        WCHAR uikey[0x110];\r
-\r
+        LPWSTR uikey;\r
         INT   root;\r
-        DWORD sz=0x100;\r
 \r
         rc = MSI_ViewFetch(view,&row);\r
         if (rc != ERROR_SUCCESS)\r
@@ -3058,17 +3542,22 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
             rc = ERROR_SUCCESS;\r
             break;\r
         }\r
+        ui_progress(package,2,0,0,0);\r
+\r
+        value = NULL;\r
+        key = NULL;\r
+        uikey = NULL;\r
+        name = NULL;\r
 \r
-        sz= 0x100;\r
-        MSI_RecordGetStringW(row,6,component,&sz);\r
+        component = load_dynamic_stringW(row, 6);\r
         component_index = get_loaded_component(package,component);\r
 \r
-        if (!package->components[component_index].Enabled ||\r
-            !package->components[component_index].FeatureState)\r
+        if (package->components[component_index].ActionRequest != \r
+             INSTALLSTATE_LOCAL)\r
         {\r
             TRACE("Skipping write due to disabled component\n");\r
             msiobj_release(&row->hdr);\r
-            continue;\r
+            goto next;\r
         }\r
 \r
         /* null values have special meanings during uninstalls and such */\r
@@ -3076,59 +3565,68 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
         if(MSI_RecordIsNull(row,5))\r
         {\r
             msiobj_release(&row->hdr);\r
-            continue;\r
+            goto next;\r
         }\r
 \r
         root = MSI_RecordGetInteger(row,2);\r
-        sz = 0x100;\r
-        MSI_RecordGetStringW(row,3,key,&sz);\r
+        key = load_dynamic_stringW(row, 3);\r
       \r
-        sz = 0x100; \r
-        if (MSI_RecordIsNull(row,4))\r
-            name[0]=0;\r
-        else\r
-            MSI_RecordGetStringW(row,4,name,&sz);\r
+        name = load_dynamic_stringW(row, 4);\r
    \r
         /* get the root key */\r
         switch (root)\r
         {\r
             case 0:  root_key = HKEY_CLASSES_ROOT; \r
-                     strcpyW(uikey,szHCR); break;\r
+                     szRoot = szHCR;\r
+                     break;\r
             case 1:  root_key = HKEY_CURRENT_USER;\r
-                     strcpyW(uikey,szHCU); break;\r
+                     szRoot = szHCU;\r
+                     break;\r
             case 2:  root_key = HKEY_LOCAL_MACHINE;\r
-                     strcpyW(uikey,szHLM); break;\r
+                     szRoot = szHLM;\r
+                     break;\r
             case 3:  root_key = HKEY_USERS; \r
-                     strcpyW(uikey,szHU); break;\r
+                     szRoot = szHU;\r
+                     break;\r
             default:\r
                  ERR("Unknown root %i\n",root);\r
                  root_key=NULL;\r
+                 szRoot = NULL;\r
                  break;\r
         }\r
         if (!root_key)\r
         {\r
             msiobj_release(&row->hdr);\r
-            continue;\r
+            goto next;\r
         }\r
 \r
-        strcatW(uikey,key);\r
-        if (RegCreateKeyW( root_key, key, &hkey))\r
+        deformat_string(package, key , &deformated);\r
+        size = strlenW(deformated) + strlenW(szRoot) + 1;\r
+        uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));\r
+        strcpyW(uikey,szRoot);\r
+        strcatW(uikey,deformated);\r
+\r
+        if (RegCreateKeyW( root_key, deformated, &hkey))\r
         {\r
-            ERR("Could not create key %s\n",debugstr_w(key));\r
+            ERR("Could not create key %s\n",debugstr_w(deformated));\r
             msiobj_release(&row->hdr);\r
-            continue;\r
+            HeapFree(GetProcessHeap(),0,deformated);\r
+            goto next;\r
         }\r
+        HeapFree(GetProcessHeap(),0,deformated);\r
 \r
         value = load_dynamic_stringW(row,5);\r
         value_data = parse_value(package, value, &type, &size); \r
 \r
+        deformat_string(package, name, &deformated);\r
+\r
         if (value_data)\r
         {\r
-            TRACE("Setting value %s\n",debugstr_w(name));\r
-            RegSetValueExW(hkey, name, 0, type, value_data, size);\r
+            TRACE("Setting value %s\n",debugstr_w(deformated));\r
+            RegSetValueExW(hkey, deformated, 0, type, value_data, size);\r
 \r
             uirow = MSI_CreateRecord(3);\r
-            MSI_RecordSetStringW(uirow,2,name);\r
+            MSI_RecordSetStringW(uirow,2,deformated);\r
             MSI_RecordSetStringW(uirow,1,uikey);\r
 \r
             if (type == REG_SZ)\r
@@ -3137,15 +3635,24 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
                 MSI_RecordSetStringW(uirow,3,value);\r
 \r
             ui_actiondata(package,szWriteRegistryValues,uirow);\r
-            ui_progress(package,2,0,0,0);\r
             msiobj_release( &uirow->hdr );\r
 \r
             HeapFree(GetProcessHeap(),0,value_data);\r
         }\r
         HeapFree(GetProcessHeap(),0,value);\r
+        HeapFree(GetProcessHeap(),0,deformated);\r
 \r
         msiobj_release(&row->hdr);\r
         RegCloseKey(hkey);\r
+next:\r
+        if (uikey)\r
+            HeapFree(GetProcessHeap(),0,uikey);\r
+        if (key)\r
+            HeapFree(GetProcessHeap(),0,key);\r
+        if (name)\r
+            HeapFree(GetProcessHeap(),0,name);\r
+        if (component)\r
+            HeapFree(GetProcessHeap(),0,component);\r
     }\r
     MSI_ViewClose(view);\r
     msiobj_release(&view->hdr);\r
@@ -3167,6 +3674,12 @@ static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data)
     DWORD sz;\r
     UINT rc;\r
 \r
+    if (ptr==NULL)\r
+    {\r
+        TRACE("Deformatting NULL string\n");\r
+        *data = NULL;\r
+        return 0;\r
+    }\r
     /* scan for special characters */\r
     if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']')))\r
     {\r
@@ -3241,82 +3754,21 @@ static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data)
 \r
 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)\r
 {\r
-    WCHAR level[10000];\r
-    INT install_level;\r
-    DWORD sz;\r
-    DWORD i;\r
-    INT j;\r
-    DWORD rc;\r
-    LPWSTR override = NULL;\r
-    static const WCHAR addlocal[]={'A','D','D','L','O','C','A','L',0};\r
-    static const WCHAR all[]={'A','L','L',0};\r
-    static const WCHAR szlevel[] = {\r
-        'I','N','S','T','A','L','L','L','E','V','E','L',0};\r
-    static const WCHAR szAddLocal[] = {\r
-        'A','D','D','L','O','C','A','L',0};\r
-\r
-    /* I do not know if this is where it should happen.. but */\r
-\r
-    TRACE("Checking Install Level\n");\r
-\r
-    sz = 10000;\r
-    if (MSI_GetPropertyW(package,szlevel,level,&sz)==ERROR_SUCCESS)\r
-        install_level = atoiW(level);\r
-    else\r
-        install_level = 1;\r
-\r
-    sz = 0;\r
-    rc = MSI_GetPropertyW(package,szAddLocal,NULL,&sz);\r
-    if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)\r
-    {\r
-        sz++;\r
-        override = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));\r
-        MSI_GetPropertyW(package, addlocal,override,&sz);\r
-    }\r
-   \r
-    /*\r
-     * Components FeatureState defaults to FALSE. The idea is we want to \r
-     * enable the component is ANY feature that uses it is enabled to install\r
-     */\r
-    for(i = 0; i < package->loaded_features; i++)\r
-    {\r
-        BOOL feature_state= ((package->features[i].Level > 0) &&\r
-                             (package->features[i].Level <= install_level));\r
-\r
-        if (override && (strcmpiW(override,all)==0 || \r
-                         strstrW(override,package->features[i].Feature)))\r
-        {\r
-            TRACE("Override of install level found\n");\r
-            feature_state = TRUE;\r
-            package->features[i].Enabled = feature_state;\r
-        }\r
-\r
-        TRACE("Feature %s has a state of %i\n",\r
-               debugstr_w(package->features[i].Feature), feature_state);\r
-        for( j = 0; j < package->features[i].ComponentCount; j++)\r
-        {\r
-            package->components[package->features[i].Components[j]].FeatureState\r
-            |= feature_state;\r
-        }\r
-    } \r
-    if (override != NULL)\r
-        HeapFree(GetProcessHeap(),0,override);\r
-    /* \r
-     * So basically we ONLY want to install a component if its Enabled AND\r
-     * FeatureState are both TRUE \r
-     */\r
     return ERROR_SUCCESS;\r
 }\r
 \r
+\r
 static UINT ACTION_InstallValidate(MSIPACKAGE *package)\r
 {\r
     DWORD progress = 0;\r
+    DWORD total = 0;\r
     static const WCHAR q1[]={\r
         'S','E','L','E','C','T',' ','*',' ',\r
         'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};\r
     UINT rc;\r
     MSIQUERY * view;\r
     MSIRECORD * row = 0;\r
+    int i;\r
 \r
     TRACE(" InstallValidate \n");\r
 \r
@@ -3346,7 +3798,11 @@ static UINT ACTION_InstallValidate(MSIPACKAGE *package)
     MSI_ViewClose(view);\r
     msiobj_release(&view->hdr);\r
 \r
-    ui_progress(package,0,progress+package->loaded_files,0,0);\r
+    total = total + progress * REG_PROGRESS_VALUE;\r
+    total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE;\r
+    for (i=0; i < package->loaded_files; i++)\r
+        total += package->files[i].FileSize;\r
+    ui_progress(package,0,total,0,0);\r
 \r
     return ERROR_SUCCESS;\r
 }\r
@@ -3406,20 +3862,20 @@ static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
     return rc;\r
 }\r
 \r
-static void resolve_keypath( MSIPACKAGE* package, INT\r
-                            component_index, WCHAR *keypath)\r
+static LPWSTR resolve_keypath( MSIPACKAGE* package, INT\r
+                            component_index)\r
 {\r
     MSICOMPONENT* cmp = &package->components[component_index];\r
 \r
     if (cmp->KeyPath[0]==0)\r
     {\r
-        resolve_folder(package,cmp->Directory,keypath,FALSE,FALSE,NULL);\r
-        return;\r
+        LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);\r
+        return p;\r
     }\r
     if ((cmp->Attributes & 0x4) || (cmp->Attributes & 0x20))\r
     {\r
         FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n");\r
-        keypath[0]=0;\r
+        return NULL;\r
     }\r
     else\r
     {\r
@@ -3427,8 +3883,12 @@ static void resolve_keypath( MSIPACKAGE* package, INT
         j = get_loaded_file(package,cmp->KeyPath);\r
 \r
         if (j>=0)\r
-            strcpyW(keypath,package->files[j].TargetPath);\r
+        {\r
+            LPWSTR p = dupstrW(package->files[j].TargetPath);\r
+            return p;\r
+        }\r
     }\r
+    return NULL;\r
 }\r
 \r
 /*\r
@@ -3440,34 +3900,32 @@ static void resolve_keypath( MSIPACKAGE* package, INT
  */\r
 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)\r
 {\r
-    WCHAR productcode[0x100];\r
+    LPWSTR productcode;\r
     WCHAR squished_pc[0x100];\r
     WCHAR squished_cc[0x100];\r
-    DWORD sz;\r
     UINT rc;\r
     DWORD i;\r
     HKEY hkey=0,hkey2=0,hkey3=0;\r
     static const WCHAR szProductCode[]=\r
-{'P','r','o','d','u','c','t','C','o','d','e',0};\r
+         {'P','r','o','d','u','c','t','C','o','d','e',0};\r
     static const WCHAR szInstaller[] = {\r
-'S','o','f','t','w','a','r','e','\\',\r
-'M','i','c','r','o','s','o','f','t','\\',\r
-'W','i','n','d','o','w','s','\\',\r
-'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',\r
-'I','n','s','t','a','l','l','e','r',0 };\r
+         'S','o','f','t','w','a','r','e','\\',\r
+         'M','i','c','r','o','s','o','f','t','\\',\r
+         'W','i','n','d','o','w','s','\\',\r
+         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',\r
+         'I','n','s','t','a','l','l','e','r',0 };\r
     static const WCHAR szFeatures[] = {\r
-'F','e','a','t','u','r','e','s',0 };\r
+         'F','e','a','t','u','r','e','s',0 };\r
     static const WCHAR szComponents[] = {\r
-'C','o','m','p','o','n','e','n','t','s',0 };\r
+         'C','o','m','p','o','n','e','n','t','s',0 };\r
 \r
     if (!package)\r
         return ERROR_INVALID_HANDLE;\r
 \r
     /* writes the Component and Features values to the registry */\r
-    sz = 0x100;\r
-    rc = MSI_GetPropertyW(package,szProductCode,productcode,&sz);\r
-    if (rc != ERROR_SUCCESS)\r
-        return ERROR_SUCCESS;\r
+    productcode = load_dynamic_property(package,szProductCode,&rc);\r
+    if (!productcode)\r
+        return rc;\r
 \r
     squash_guid(productcode,squished_pc);\r
     rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller,&hkey);\r
@@ -3519,12 +3977,14 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
     rc = RegCreateKeyW(hkey,szComponents,&hkey2);\r
     if (rc != ERROR_SUCCESS)\r
         goto end;\r
-  \r
+      \r
+    ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);\r
     for (i = 0; i < package->loaded_components; i++)\r
     {\r
+        ui_progress(package,2,0,0,0);\r
         if (package->components[i].ComponentId[0]!=0)\r
         {\r
-            WCHAR keypath[0x1000];\r
+            WCHAR *keypath = NULL;\r
             MSIRECORD * uirow;\r
 \r
             squash_guid(package->components[i].ComponentId,squished_cc);\r
@@ -3532,22 +3992,27 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
             if (rc != ERROR_SUCCESS)\r
                 continue;\r
            \r
-            resolve_keypath(package,i,keypath);\r
-\r
-            RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath,\r
+            keypath = resolve_keypath(package,i);\r
+            if (keypath)\r
+            {\r
+                RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath,\r
                             (strlenW(keypath)+1)*sizeof(WCHAR));\r
-            RegCloseKey(hkey3);\r
+                RegCloseKey(hkey3);\r
         \r
-            /* UI stuff */\r
-            uirow = MSI_CreateRecord(3);\r
-            MSI_RecordSetStringW(uirow,1,productcode);\r
-            MSI_RecordSetStringW(uirow,2,package->components[i].ComponentId);\r
-            MSI_RecordSetStringW(uirow,3,keypath);\r
-            ui_actiondata(package,szProcessComponents,uirow);\r
-            msiobj_release( &uirow->hdr );\r
+                /* UI stuff */\r
+                uirow = MSI_CreateRecord(3);\r
+                MSI_RecordSetStringW(uirow,1,productcode);\r
+                MSI_RecordSetStringW(uirow,2,package->components[i].\r
+                                                        ComponentId);\r
+                MSI_RecordSetStringW(uirow,3,keypath);\r
+                ui_actiondata(package,szProcessComponents,uirow);\r
+                msiobj_release( &uirow->hdr );\r
+                HeapFree(GetProcessHeap(),0,keypath);\r
+            }\r
         }\r
     } \r
 end:\r
+    HeapFree(GetProcessHeap(), 0, productcode);\r
     RegCloseKey(hkey2);\r
     RegCloseKey(hkey);\r
     return rc;\r
@@ -3608,8 +4073,7 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
             continue;\r
         }\r
 \r
-        if (!package->components[index].Enabled ||\r
-            !package->components[index].FeatureState)\r
+        if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)\r
         {\r
             TRACE("Skipping typelib reg due to disabled component\n");\r
             msiobj_release(&row->hdr);\r
@@ -3627,15 +4091,16 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
         res = LoadTypeLib(package->files[index].TargetPath,&ptLib);\r
         if (SUCCEEDED(res))\r
         {\r
-            WCHAR help[MAX_PATH];\r
+            LPWSTR help;\r
             WCHAR helpid[0x100];\r
 \r
             sz = 0x100;\r
             MSI_RecordGetStringW(row,6,helpid,&sz);\r
 \r
-            resolve_folder(package,helpid,help,FALSE,FALSE,NULL);\r
-\r
+            help = resolve_folder(package,helpid,FALSE,FALSE,NULL);\r
             res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);\r
+            HeapFree(GetProcessHeap(),0,help);\r
+\r
             if (!SUCCEEDED(res))\r
                 ERR("Failed to register type library %s\n",\r
                      debugstr_w(package->files[index].TargetPath));\r
@@ -3672,18 +4137,15 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
     MSIQUERY * view;\r
     MSIRECORD * row = 0;\r
     static const WCHAR ExecSeqQuery[] = \r
-{'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'\r
-,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};\r
-    WCHAR Query[0x1000];\r
+        {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'\r
+        ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};\r
     HKEY hkey2,hkey3;\r
     LPWSTR buffer=0;\r
 \r
     if (!package)\r
         return ERROR_INVALID_HANDLE;\r
 \r
-    sprintfW(Query,ExecSeqQuery,clsid);\r
-\r
-    rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
+    rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, clsid);\r
     if (rc != ERROR_SUCCESS)\r
         return rc;\r
 \r
@@ -3713,7 +4175,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
         LPWSTR deformated=0;\r
         UINT size; \r
         static const WCHAR szRemoteServerName[] =\r
-{'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};\r
+             {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};\r
         buffer = load_dynamic_stringW(row,2);\r
         size = deformat_string(package,buffer,&deformated);\r
         RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,\r
@@ -3725,7 +4187,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
     if (!MSI_RecordIsNull(row,3)) \r
     {\r
         static const WCHAR szLocalService[] =\r
-{'L','o','c','a','l','S','e','r','v','i','c','e',0};\r
+             {'L','o','c','a','l','S','e','r','v','i','c','e',0};\r
         UINT size;\r
         buffer = load_dynamic_stringW(row,3);\r
         size = (strlenW(buffer)+1) * sizeof(WCHAR);\r
@@ -3736,7 +4198,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
     if (!MSI_RecordIsNull(row,4)) \r
     {\r
         static const WCHAR szService[] =\r
-{'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};\r
+             {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};\r
         UINT size;\r
         buffer = load_dynamic_stringW(row,4);\r
         size = (strlenW(buffer)+1) * sizeof(WCHAR);\r
@@ -3747,7 +4209,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
     if (!MSI_RecordIsNull(row,5)) \r
     {\r
         static const WCHAR szDLL[] =\r
-{'D','l','l','S','u','r','r','o','g','a','t','e',0};\r
+             {'D','l','l','S','u','r','r','o','g','a','t','e',0};\r
         UINT size;\r
         buffer = load_dynamic_stringW(row,5);\r
         size = (strlenW(buffer)+1) * sizeof(WCHAR);\r
@@ -3758,7 +4220,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
     if (!MSI_RecordIsNull(row,6)) \r
     {\r
         static const WCHAR szActivate[] =\r
-{'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};\r
+             {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};\r
         static const WCHAR szY[] = {'Y',0};\r
 \r
         if (MSI_RecordGetInteger(row,6))\r
@@ -3769,7 +4231,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
     {\r
         static const WCHAR szRunAs[] = {'R','u','n','A','s',0};\r
         static const WCHAR szUser[] = \r
-{'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};\r
+             {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};\r
 \r
         if (MSI_RecordGetInteger(row,7))\r
             RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);\r
@@ -3855,8 +4317,7 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
             continue;\r
         }\r
 \r
-        if (!package->components[index].Enabled ||\r
-            !package->components[index].FeatureState)\r
+        if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)\r
         {\r
             TRACE("Skipping class reg due to disabled component\n");\r
             msiobj_release(&row->hdr);\r
@@ -3984,17 +4445,14 @@ static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent,
     MSIQUERY * view;\r
     MSIRECORD * row = 0;\r
     static const WCHAR Query_t[] = \r
-{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'\r
-,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'\r
-,'%','s','`',0};\r
-    WCHAR Query[0x1000];\r
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'\r
+        ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'\r
+        ,'%','s','`',0};\r
 \r
     if (!package)\r
         return ERROR_INVALID_HANDLE;\r
 \r
-    sprintfW(Query,Query_t,parent);\r
-\r
-    rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
+    rc = ACTION_OpenQuery(package->db, &view, Query_t, parent);\r
     if (rc != ERROR_SUCCESS)\r
         return rc;\r
 \r
@@ -4127,33 +4585,35 @@ static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
 }\r
 \r
 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, \r
-                            LPWSTR FilePath)\r
+                            LPWSTR *FilePath)\r
 {\r
-    WCHAR ProductCode[0x100];\r
-    WCHAR SystemFolder[MAX_PATH];\r
-    DWORD sz;\r
+    LPWSTR ProductCode;\r
+    LPWSTR SystemFolder;\r
+    LPWSTR dest;\r
+    UINT rc;\r
 \r
     static const WCHAR szInstaller[] = \r
-{'I','n','s','t','a','l','l','e','r','\\',0};\r
+        {'I','n','s','t','a','l','l','e','r','\\',0};\r
     static const WCHAR szProductCode[] =\r
-{'P','r','o','d','u','c','t','C','o','d','e',0};\r
+        {'P','r','o','d','u','c','t','C','o','d','e',0};\r
     static const WCHAR szFolder[] =\r
-{'W','i','n','d','o','w','s','F','o','l','d','e','r',0};\r
+        {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};\r
 \r
-    sz = 0x100;\r
-    MSI_GetPropertyW(package,szProductCode,ProductCode,&sz);\r
-    if (strlenW(ProductCode)==0)\r
-        return ERROR_FUNCTION_FAILED;\r
+    ProductCode = load_dynamic_property(package,szProductCode,&rc);\r
+    if (!ProductCode)\r
+        return rc;\r
 \r
-    sz = MAX_PATH;\r
-    MSI_GetPropertyW(package,szFolder,SystemFolder,&sz);\r
-    strcatW(SystemFolder,szInstaller); \r
-    strcatW(SystemFolder,ProductCode);\r
-    create_full_pathW(SystemFolder);\r
+    SystemFolder = load_dynamic_property(package,szFolder,NULL);\r
 \r
-    strcpyW(FilePath,SystemFolder);\r
-    strcatW(FilePath,cszbs);\r
-    strcatW(FilePath,icon_name);\r
+    dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);\r
+\r
+    create_full_pathW(dest);\r
+\r
+    *FilePath = build_directory_name(2, dest, icon_name);\r
+\r
+    HeapFree(GetProcessHeap(),0,SystemFolder);\r
+    HeapFree(GetProcessHeap(),0,ProductCode);\r
+    HeapFree(GetProcessHeap(),0,dest);\r
     return ERROR_SUCCESS;\r
 }\r
 \r
@@ -4193,7 +4653,7 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
 \r
     while (1)\r
     {\r
-        WCHAR target_file[MAX_PATH];\r
+        LPWSTR target_file, target_folder;\r
         WCHAR buffer[0x100];\r
         DWORD sz;\r
         DWORD index;\r
@@ -4217,8 +4677,7 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
             continue;\r
         }\r
 \r
-        if (!package->components[index].Enabled ||\r
-            !package->components[index].FeatureState)\r
+        if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)\r
         {\r
             TRACE("Skipping shortcut creation due to disabled component\n");\r
             msiobj_release(&row->hdr);\r
@@ -4247,14 +4706,18 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
 \r
         sz = 0x100;\r
         MSI_RecordGetStringW(row,2,buffer,&sz);\r
-        resolve_folder(package, buffer,target_file,FALSE,FALSE,NULL);\r
+        target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);\r
+\r
+        /* may be needed because of a bug somehwere else */\r
+        create_full_pathW(target_folder);\r
 \r
         sz = 0x100;\r
         MSI_RecordGetStringW(row,3,buffer,&sz);\r
         reduce_to_longfilename(buffer);\r
-        strcatW(target_file,buffer);\r
-        if (!strchrW(target_file,'.'))\r
-            strcatW(target_file,szlnk);\r
+        if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk))\r
+            strcatW(buffer,szlnk);\r
+        target_file = build_directory_name(2, target_folder, buffer);\r
+        HeapFree(GetProcessHeap(),0,target_folder);\r
 \r
         sz = 0x100;\r
         MSI_RecordGetStringW(row,5,buffer,&sz);\r
@@ -4297,16 +4760,17 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
 \r
         if (!MSI_RecordIsNull(row,9))\r
         {\r
-            WCHAR Path[MAX_PATH];\r
+            WCHAR *Path = NULL;\r
             INT index; \r
 \r
             sz = 0x100;\r
             MSI_RecordGetStringW(row,9,buffer,&sz);\r
 \r
-            build_icon_path(package,buffer,Path);\r
+            build_icon_path(package,buffer,&Path);\r
             index = MSI_RecordGetInteger(row,10);\r
 \r
             IShellLinkW_SetIconLocation(sl,Path,index);\r
+            HeapFree(GetProcessHeap(),0,Path);\r
         }\r
 \r
         if (!MSI_RecordIsNull(row,11))\r
@@ -4314,17 +4778,19 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
 \r
         if (!MSI_RecordIsNull(row,12))\r
         {\r
-            WCHAR Path[MAX_PATH];\r
-\r
+            LPWSTR Path;\r
             sz = 0x100;\r
             MSI_RecordGetStringW(row,12,buffer,&sz);\r
-            resolve_folder(package, buffer, Path, FALSE, FALSE, NULL);\r
+            Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);\r
             IShellLinkW_SetWorkingDirectory(sl,Path);\r
+            HeapFree(GetProcessHeap(), 0, Path);\r
         }\r
 \r
         TRACE("Writing shortcut to %s\n",debugstr_w(target_file));\r
         IPersistFile_Save(pf,target_file,FALSE);\r
-        \r
+    \r
+        HeapFree(GetProcessHeap(),0,target_file);    \r
+\r
         IPersistFile_Release( pf );\r
         IShellLinkW_Release( sl );\r
 \r
@@ -4374,8 +4840,8 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
     while (1)\r
     {\r
         HANDLE the_file;\r
-        WCHAR FilePath[MAX_PATH];\r
-        WCHAR FileName[MAX_PATH];\r
+        WCHAR *FilePath=NULL;\r
+        WCHAR *FileName=NULL;\r
         CHAR buffer[1024];\r
 \r
         rc = MSI_ViewFetch(view,&row);\r
@@ -4385,16 +4851,17 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
             break;\r
         }\r
     \r
-        sz = MAX_PATH;\r
-        MSI_RecordGetStringW(row,1,FileName,&sz);\r
-        if (sz == 0)\r
+        FileName = load_dynamic_stringW(row,1);\r
+        if (!FileName)\r
         {\r
             ERR("Unable to get FileName\n");\r
             msiobj_release(&row->hdr);\r
             continue;\r
         }\r
 \r
-        build_icon_path(package,FileName,FilePath);\r
+        build_icon_path(package,FileName,&FilePath);\r
+\r
+        HeapFree(GetProcessHeap(),0,FileName);\r
 \r
         TRACE("Creating icon file at %s\n",debugstr_w(FilePath));\r
         \r
@@ -4405,6 +4872,7 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
         {\r
             ERR("Unable to create file %s\n",debugstr_w(FilePath));\r
             msiobj_release(&row->hdr);\r
+            HeapFree(GetProcessHeap(),0,FilePath);\r
             continue;\r
         }\r
 \r
@@ -4423,6 +4891,8 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
             WriteFile(the_file,buffer,sz,&write,NULL);\r
         } while (sz == 1024);\r
 \r
+        HeapFree(GetProcessHeap(),0,FilePath);\r
+\r
         CloseHandle(the_file);\r
         msiobj_release(&row->hdr);\r
     }\r
@@ -4507,29 +4977,31 @@ UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR\r
                                 szPathBuf, DWORD* pcchPathBuf) \r
 {\r
-    WCHAR path[MAX_PATH];\r
-    UINT rc;\r
+    LPWSTR path;\r
+    UINT rc = ERROR_FUNCTION_FAILED;\r
     MSIPACKAGE *package;\r
 \r
     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);\r
 \r
     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);\r
-    if( !package )\r
+    if (!package)\r
         return ERROR_INVALID_HANDLE;\r
-    rc = resolve_folder(package, szFolder, path, FALSE, FALSE, NULL);\r
+    path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);\r
     msiobj_release( &package->hdr );\r
 \r
-    if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)\r
+    if (path && (strlenW(path) > *pcchPathBuf))\r
     {\r
         *pcchPathBuf = strlenW(path)+1;\r
-        return ERROR_MORE_DATA;\r
+        rc = ERROR_MORE_DATA;\r
     }\r
-    else if (rc == ERROR_SUCCESS)\r
+    else if (path)\r
     {\r
         *pcchPathBuf = strlenW(path)+1;\r
         strcpyW(szPathBuf,path);\r
         TRACE("Returning Path %s\n",debugstr_w(path));\r
+        rc = ERROR_SUCCESS;\r
     }\r
+    HeapFree(GetProcessHeap(),0,path);\r
     \r
     return rc;\r
 }\r
@@ -4569,8 +5041,8 @@ UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR\r
                                 szPathBuf, DWORD* pcchPathBuf) \r
 {\r
-    WCHAR path[MAX_PATH];\r
-    UINT rc;\r
+    LPWSTR path;\r
+    UINT rc = ERROR_FUNCTION_FAILED;\r
     MSIPACKAGE *package;\r
 \r
     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);\r
@@ -4578,20 +5050,22 @@ UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);\r
     if( !package )\r
         return ERROR_INVALID_HANDLE;\r
-    rc = resolve_folder(package, szFolder, path, TRUE, FALSE, NULL);\r
+    path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);\r
     msiobj_release( &package->hdr );\r
 \r
-    if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)\r
+    if (path && strlenW(path) > *pcchPathBuf)\r
     {\r
         *pcchPathBuf = strlenW(path)+1;\r
-        return ERROR_MORE_DATA;\r
+        rc = ERROR_MORE_DATA;\r
     }\r
-    else if (rc == ERROR_SUCCESS)\r
+    else if (path)\r
     {\r
         *pcchPathBuf = strlenW(path)+1;\r
         strcpyW(szPathBuf,path);\r
         TRACE("Returning Path %s\n",debugstr_w(path));\r
+        rc = ERROR_SUCCESS;\r
     }\r
+    HeapFree(GetProcessHeap(),0,path);\r
     \r
     return rc;\r
 }\r
@@ -4632,7 +5106,9 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
                              LPCWSTR szFolderPath)\r
 {\r
     DWORD i;\r
-    WCHAR path[MAX_PATH];\r
+    LPWSTR path = NULL;\r
+    LPWSTR path2 = NULL;\r
+    INT len;\r
     MSIFOLDER *folder;\r
 \r
     TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));\r
@@ -4646,19 +5122,54 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
     if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)\r
         return ERROR_FUNCTION_FAILED;\r
 \r
-    resolve_folder(package,szFolder,path,FALSE,FALSE,&folder);\r
+    path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);\r
 \r
-    if (!folder)\r
+    if (!path)\r
         return ERROR_INVALID_PARAMETER;\r
 \r
-    strcpyW(folder->Property,szFolderPath);\r
+    if (folder->Property)\r
+        HeapFree(GetProcessHeap(),0,folder->Property);\r
 \r
-    for (i = 0; i < package->loaded_folders; i++)\r
-        package->folders[i].ResolvedTarget[0]=0;\r
+    len = strlenW(szFolderPath);\r
 \r
-    for (i = 0; i < package->loaded_folders; i++)\r
-        resolve_folder(package, package->folders[i].Directory, path, FALSE,\r
+    if (szFolderPath[len-1]!='\\')\r
+    {\r
+        len +=2;\r
+        folder->Property = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));\r
+        strcpyW(folder->Property,szFolderPath);\r
+        strcatW(folder->Property,cszbs);\r
+    }\r
+    else\r
+        folder->Property = dupstrW(szFolderPath);\r
+\r
+    if (strcmpiW(path, szFolderPath) == 0)\r
+    {\r
+        /*\r
+         *  Resolved Target has not really changed, so just \r
+         *  set this folder and do not recalculate everything.\r
+         */\r
+        HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);\r
+        folder->ResolvedTarget = NULL;\r
+        path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);\r
+        HeapFree(GetProcessHeap(),0,path2);\r
+    }\r
+    else\r
+    {\r
+        for (i = 0; i < package->loaded_folders; i++)\r
+        {\r
+            if (package->folders[i].ResolvedTarget)\r
+                HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);\r
+            package->folders[i].ResolvedTarget=NULL;\r
+        }\r
+\r
+        for (i = 0; i < package->loaded_folders; i++)\r
+        {\r
+            path2=resolve_folder(package, package->folders[i].Directory, FALSE,\r
                        TRUE, NULL);\r
+            HeapFree(GetProcessHeap(),0,path2);\r
+        }\r
+    }\r
+    HeapFree(GetProcessHeap(),0,path);\r
 \r
     return ERROR_SUCCESS;\r
 }\r
@@ -4677,10 +5188,44 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
     return ret;\r
 }\r
 \r
-BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, DWORD iRunMode)\r
+/***********************************************************************\r
+ *           MsiGetMode    (MSI.@)\r
+ *\r
+ * Returns an internal installer state (if it is running in a mode iRunMode)\r
+ *\r
+ * PARAMS\r
+ *   hInstall    [I]  Handle to the installation\r
+ *   hRunMode    [I]  Checking run mode\r
+ *        MSIRUNMODE_ADMIN             Administrative mode\r
+ *        MSIRUNMODE_ADVERTISE         Advertisement mode\r
+ *        MSIRUNMODE_MAINTENANCE       Maintenance mode\r
+ *        MSIRUNMODE_ROLLBACKENABLED   Rollback is enabled\r
+ *        MSIRUNMODE_LOGENABLED        Log file is writing\r
+ *        MSIRUNMODE_OPERATIONS        Operations in progress??\r
+ *        MSIRUNMODE_REBOOTATEND       We need to reboot after installation completed\r
+ *        MSIRUNMODE_REBOOTNOW         We need to reboot to continue the installation\r
+ *        MSIRUNMODE_CABINET           Files from cabinet are installed\r
+ *        MSIRUNMODE_SOURCESHORTNAMES  Long names in source files is supressed\r
+ *        MSIRUNMODE_TARGETSHORTNAMES  Long names in destination files is supressed\r
+ *        MSIRUNMODE_RESERVED11        Reserved\r
+ *        MSIRUNMODE_WINDOWS9X         Running under Windows95/98\r
+ *        MSIRUNMODE_ZAWENABLED        Demand installation is supported\r
+ *        MSIRUNMODE_RESERVED14        Reserved\r
+ *        MSIRUNMODE_RESERVED15        Reserved\r
+ *        MSIRUNMODE_SCHEDULED         called from install script\r
+ *        MSIRUNMODE_ROLLBACK          called from rollback script\r
+ *        MSIRUNMODE_COMMIT            called from commit script\r
+ *\r
+ * RETURNS\r
+ *    In the state: TRUE\r
+ *    Not in the state: FALSE\r
+ *\r
+ */\r
+\r
+BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)\r
 {\r
-    FIXME("STUB (%li)\n",iRunMode);\r
-    return FALSE;\r
+    FIXME("STUB (iRunMode=%i)\n",iRunMode);\r
+    return TRUE;\r
 }\r
 \r
 /*\r
@@ -4721,7 +5266,7 @@ UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
     if (index < 0)\r
         return ERROR_UNKNOWN_FEATURE;\r
 \r
-    package->features[index].State = iState;\r
+    package->features[index].ActionRequest= iState;\r
 \r
     return ERROR_SUCCESS;\r
 }\r
@@ -4751,15 +5296,12 @@ UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
         return ERROR_UNKNOWN_FEATURE;\r
 \r
     if (piInstalled)\r
-        *piInstalled = package->features[index].State;\r
+        *piInstalled = package->features[index].Installed;\r
 \r
     if (piAction)\r
-    {\r
-        if (package->features[index].Enabled)\r
-            *piAction = INSTALLSTATE_LOCAL;\r
-        else\r
-            *piAction = INSTALLSTATE_UNKNOWN;\r
-    }\r
+        *piAction = package->features[index].Action;\r
+\r
+    TRACE("returning %i %i\n",*piInstalled,*piAction);\r
 \r
     return ERROR_SUCCESS;\r
 }\r
@@ -4809,16 +5351,10 @@ piAction);
         return ERROR_UNKNOWN_COMPONENT;\r
 \r
     if (piInstalled)\r
-        *piInstalled = package->components[index].State;\r
+        *piInstalled = package->components[index].Installed;\r
 \r
     if (piAction)\r
-    {\r
-        if (package->components[index].Enabled &&\r
-            package->components[index].FeatureState)\r
-            *piAction = INSTALLSTATE_LOCAL;\r
-        else\r
-            *piAction = INSTALLSTATE_UNKNOWN;\r
-    }\r
+        *piInstalled = package->components[index].Action;\r
 \r
     return ERROR_SUCCESS;\r
 }\r
index ade5e1b..bd33099 100644 (file)
@@ -41,7 +41,23 @@ static CRITICAL_SECTION_DEBUG MSI_handle_cs_debug =
 };\r
 static CRITICAL_SECTION MSI_handle_cs = { &MSI_handle_cs_debug, -1, 0, 0, 0, 0 };\r
 \r
-MSIOBJECTHDR *msihandletable[MSIMAXHANDLES];\r
+static CRITICAL_SECTION MSI_object_cs;\r
+static CRITICAL_SECTION_DEBUG MSI_object_cs_debug =\r
+{\r
+    0, 0, &MSI_object_cs,\r
+    { &MSI_object_cs_debug.ProcessLocksList, \r
+      &MSI_object_cs_debug.ProcessLocksList },\r
+      0, 0, { 0, (DWORD)(__FILE__ ": MSI_object_cs") }\r
+};\r
+static CRITICAL_SECTION MSI_object_cs = { &MSI_object_cs_debug, -1, 0, 0, 0, 0 };\r
+\r
+typedef struct msi_handle_info_t\r
+{\r
+    MSIOBJECTHDR *obj;\r
+    DWORD dwThreadId;\r
+} msi_handle_info;\r
+\r
+static msi_handle_info msihandletable[MSIMAXHANDLES];\r
 \r
 MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj )\r
 {\r
@@ -52,13 +68,14 @@ MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj )
 \r
     /* find a slot */\r
     for(i=0; i<MSIMAXHANDLES; i++)\r
-        if( !msihandletable[i] )\r
+        if( !msihandletable[i].obj )\r
             break;\r
-    if( (i>=MSIMAXHANDLES) || msihandletable[i] )\r
+    if( (i>=MSIMAXHANDLES) || msihandletable[i].obj )\r
         goto out;\r
 \r
     msiobj_addref( obj );\r
-    msihandletable[i] = obj;\r
+    msihandletable[i].obj = obj;\r
+    msihandletable[i].dwThreadId = GetCurrentThreadId();\r
     ret = (MSIHANDLE) (i+1);\r
 out:\r
     TRACE("%p -> %ld\n", obj, ret );\r
@@ -77,13 +94,13 @@ void *msihandle2msiinfo(MSIHANDLE handle, UINT type)
         goto out;\r
     if( handle>=MSIMAXHANDLES )\r
         goto out;\r
-    if( !msihandletable[handle] )\r
+    if( !msihandletable[handle].obj )\r
         goto out;\r
-    if( msihandletable[handle]->magic != MSIHANDLE_MAGIC )\r
+    if( msihandletable[handle].obj->magic != MSIHANDLE_MAGIC )\r
         goto out;\r
-    if( type && (msihandletable[handle]->type != type) )\r
+    if( type && (msihandletable[handle].obj->type != type) )\r
         goto out;\r
-    ret = msihandletable[handle];\r
+    ret = msihandletable[handle].obj;\r
     msiobj_addref( ret );\r
     \r
 out:\r
@@ -101,7 +118,7 @@ MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr )
 \r
     EnterCriticalSection( &MSI_handle_cs );\r
     for(i=0; (i<MSIMAXHANDLES) && !ret; i++)\r
-        if( msihandletable[i] == hdr )\r
+        if( msihandletable[i].obj == hdr )\r
             ret = i+1;\r
     LeaveCriticalSection( &MSI_handle_cs );\r
 \r
@@ -143,6 +160,16 @@ void msiobj_addref( MSIOBJECTHDR *info )
     info->refcount++;\r
 }\r
 \r
+void msiobj_lock( MSIOBJECTHDR *info )\r
+{\r
+    EnterCriticalSection( &MSI_object_cs );\r
+}\r
+\r
+void msiobj_unlock( MSIOBJECTHDR *info )\r
+{\r
+    LeaveCriticalSection( &MSI_object_cs );\r
+}\r
+\r
 int msiobj_release( MSIOBJECTHDR *info )\r
 {\r
     int ret;\r
@@ -170,6 +197,9 @@ int msiobj_release( MSIOBJECTHDR *info )
     return ret;\r
 }\r
 \r
+/***********************************************************\r
+ *   MsiCloseHandle   [MSI.@]\r
+ */\r
 UINT WINAPI MsiCloseHandle(MSIHANDLE handle)\r
 {\r
     MSIOBJECTHDR *info;\r
@@ -190,7 +220,7 @@ UINT WINAPI MsiCloseHandle(MSIHANDLE handle)
     }\r
 \r
     msiobj_release( info );\r
-    msihandletable[handle-1] = NULL;\r
+    msihandletable[handle-1].obj = NULL;\r
     ret = ERROR_SUCCESS;\r
 \r
     TRACE("handle %lx Destroyed\n", handle);\r
@@ -202,14 +232,28 @@ out:
     return ret;\r
 }\r
 \r
+/***********************************************************\r
+ *   MsiCloseAllHandles   [MSI.@]\r
+ *\r
+ *  Closes all handles owned by the current thread\r
+ *\r
+ *  RETURNS:\r
+ *   The number of handles closed\r
+ */\r
 UINT WINAPI MsiCloseAllHandles(void)\r
 {\r
-    UINT i;\r
+    UINT i, n=0;\r
 \r
     TRACE("\n");\r
 \r
     for(i=0; i<MSIMAXHANDLES; i++)\r
-        MsiCloseHandle( i+1 );\r
+    {\r
+        if(msihandletable[i].dwThreadId == GetCurrentThreadId())\r
+        {\r
+            MsiCloseHandle( i+1 );\r
+            n++;\r
+        }\r
+    }\r
 \r
-    return 0;\r
+    return n;\r
 }\r
index 48735f4..77ccf30 100644 (file)
@@ -71,6 +71,7 @@ static const WCHAR szComponents[] = {
 INSTALLUILEVEL gUILevel;\r
 HWND           gUIhwnd;\r
 INSTALLUI_HANDLERA gUIHandler;\r
+INSTALLUI_HANDLERW gUIHandlerW;\r
 DWORD gUIFilter;\r
 LPVOID gUIContext;\r
 WCHAR gszLogFile[MAX_PATH];\r
@@ -841,7 +842,7 @@ INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
 {\r
     INSTALLUI_HANDLERA prev = gUIHandler;\r
 \r
-    TRACE("(%p %lx %p)\n",puiHandler,dwMessageFilter,pvContext);\r
+    TRACE("(%p %lx %p)\n",puiHandler, dwMessageFilter,pvContext);\r
     gUIHandler = puiHandler;\r
     gUIFilter = dwMessageFilter;\r
     gUIContext = pvContext;\r
@@ -849,6 +850,19 @@ INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
     return prev;\r
 }\r
 \r
+INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,\r
+                                  DWORD dwMessageFilter, LPVOID pvContext)\r
+{\r
+    INSTALLUI_HANDLERW prev = gUIHandlerW;\r
+\r
+    TRACE("(%p %lx %p)\n",puiHandler,dwMessageFilter,pvContext);\r
+    gUIHandlerW = puiHandler;\r
+    gUIFilter = dwMessageFilter;\r
+    gUIContext = pvContext;\r
+\r
+    return prev;\r
+}\r
+\r
 UINT WINAPI MsiLoadStringA(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int nBufferMax, DWORD e)\r
 {\r
     /*FIXME("%08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e);*/\r
@@ -1505,13 +1519,13 @@ static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVO
 \r
 static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface) {\r
   IClassFactoryImpl *This = (IClassFactoryImpl *)iface;\r
-  return ++(This->ref);\r
+  return InterlockedIncrement(&This->ref);\r
 }\r
 \r
 static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface) {\r
   IClassFactoryImpl *This = (IClassFactoryImpl *)iface;\r
   /* static class, won't be  freed */\r
-  return --(This->ref);\r
+  return InterlockedDecrement(&This->ref);\r
 }\r
 \r
 static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) {\r
@@ -1592,10 +1606,34 @@ BOOL WINAPI MSI_DllCanUnloadNow(void)
   return S_FALSE;\r
 }\r
 \r
-UINT WINAPI MsiEnumRelatedProductsA (LPCSTR lpUpgradeCode, DWORD dwReserved,\r
+UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,\r
+                                    DWORD iProductIndex, LPWSTR lpProductBuf)\r
+{\r
+    FIXME("%s %lu %lu %p\n", debugstr_w(szUpgradeCode), dwReserved,\r
+          iProductIndex, lpProductBuf);\r
+    return ERROR_CALL_NOT_IMPLEMENTED;\r
+}\r
+\r
+UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,\r
                                     DWORD iProductIndex, LPSTR lpProductBuf)\r
 {\r
-    FIXME("STUB: (%s, %li %li %s)\n",lpUpgradeCode, dwReserved, iProductIndex,\r
-          lpProductBuf);\r
+    FIXME("%s %lu %lu %p\n", debugstr_a(szUpgradeCode), dwReserved,\r
+          iProductIndex, lpProductBuf);\r
+    return ERROR_CALL_NOT_IMPLEMENTED;\r
+}\r
+\r
+UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature,\r
+                                DWORD* pdwUseCount, WORD* pwDateUsed)\r
+{\r
+    FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),\r
+          pdwUseCount, pwDateUsed);\r
+    return ERROR_CALL_NOT_IMPLEMENTED;\r
+}\r
+\r
+UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature,\r
+                                DWORD* pdwUseCount, WORD* pwDateUsed)\r
+{\r
+    FIXME("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),\r
+          pdwUseCount, pwDateUsed);\r
     return ERROR_CALL_NOT_IMPLEMENTED;\r
 }\r
index e8a98a3..7b6029a 100644 (file)
@@ -56,8 +56,8 @@
 56 stub MsiGetFeatureInfoW\r
 57 stdcall MsiGetFeatureStateA(long str ptr ptr)\r
 58 stdcall MsiGetFeatureStateW(long wstr ptr ptr)\r
-59 stub MsiGetFeatureUsageA\r
-60 stub MsiGetFeatureUsageW\r
+59 stdcall MsiGetFeatureUsageA(str str ptr ptr)\r
+60 stdcall MsiGetFeatureUsageW(wstr wstr ptr ptr)\r
 61 stub MsiGetFeatureValidStatesA\r
 62 stub MsiGetFeatureValidStatesW\r
 63 stub MsiGetLanguage\r
 134 stub MsiSetComponentStateA\r
 135 stub MsiSetComponentStateW\r
 136 stdcall MsiSetExternalUIA(ptr long ptr)\r
-137 stub MsiSetExternalUIW\r
+137 stdcall MsiSetExternalUIW(ptr long ptr)\r
 138 stdcall MsiSetFeatureStateA(long str long)\r
 139 stdcall MsiSetFeatureStateW(long wstr long)\r
 140 stub MsiSetInstallLevel\r
 201 stub MsiDecomposeDescriptorW\r
 202 stub MsiProvideQualifiedComponentExA\r
 203 stub MsiProvideQualifiedComponentExW\r
-204 stdcall MsiEnumRelatedProductsA(str long long str)\r
-205 stub MsiEnumRelatedProductsW\r
+204 stdcall MsiEnumRelatedProductsA(str long long ptr)\r
+205 stdcall MsiEnumRelatedProductsW(wstr long long ptr)\r
 206 stub MsiSetFeatureAttributesA\r
 207 stub MsiSetFeatureAttributesW\r
 208 stub MsiSourceListClearAllA\r
index ba36dcb..306feca 100644 (file)
@@ -194,6 +194,8 @@ typedef struct tagMSIPACKAGE
     UINT loaded_components;\r
     struct tagMSIFILE *files;\r
     UINT loaded_files;\r
+    LPWSTR ActionFormat;\r
+    LPWSTR LastAction;\r
 } MSIPACKAGE;\r
 \r
 #define MSIHANDLETYPE_ANY 0\r
@@ -228,6 +230,8 @@ extern MSIHANDLE alloc_msihandle( MSIOBJECTHDR * );
 extern void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy );\r
 extern void msiobj_addref(MSIOBJECTHDR *);\r
 extern int msiobj_release(MSIOBJECTHDR *);\r
+extern void msiobj_lock(MSIOBJECTHDR *);\r
+extern void msiobj_unlock(MSIOBJECTHDR *);\r
 extern MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr );\r
 \r
 /* add this table to the list of cached tables in the database */\r
@@ -269,6 +273,7 @@ extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname,
                               USHORT **pdata, UINT *psz );\r
 extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR );\r
 extern void ACTION_remove_tracked_tempfiles( MSIPACKAGE* );\r
+extern void ACTION_free_package_structures( MSIPACKAGE* );\r
 \r
 /* record internals */\r
 extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *);\r
index cad20ed..639af42 100644 (file)
@@ -27,6 +27,7 @@
 #include "winreg.h"\r
 #include "winnls.h"\r
 #include "shlwapi.h"\r
+#include "wingdi.h"\r
 #include "wine/debug.h"\r
 #include "msi.h"\r
 #include "msiquery.h"\r
@@ -53,18 +54,8 @@ void MSI_FreePackage( MSIOBJECTHDR *arg)
     MSIPACKAGE *package= (MSIPACKAGE*) arg;\r
 \r
     ACTION_remove_tracked_tempfiles(package);\r
+    ACTION_free_package_structures(package);\r
 \r
-    if (package->features && package->loaded_features > 0)\r
-        HeapFree(GetProcessHeap(),0,package->features);\r
-\r
-    if (package->folders && package->loaded_folders > 0)\r
-        HeapFree(GetProcessHeap(),0,package->folders);\r
-    \r
-    if (package->components && package->loaded_components > 0)\r
-        HeapFree(GetProcessHeap(),0,package->components);\r
-\r
-    if (package->files && package->loaded_files > 0)\r
-        HeapFree(GetProcessHeap(),0,package->files);\r
     msiobj_release( &package->db->hdr );\r
 }\r
 \r
@@ -169,9 +160,11 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/prope
 static VOID set_installer_properties(MSIPACKAGE *package)\r
 {\r
     WCHAR pth[MAX_PATH];\r
+    WCHAR *ptr;\r
     OSVERSIONINFOA OSVersion;\r
     DWORD verval;\r
-    WCHAR verstr[10], msiver[10];\r
+    WCHAR verstr[10], bufstr[20];\r
+    HDC dc;\r
 \r
     static const WCHAR cszbs[]={'\\',0};\r
     static const WCHAR CFF[] = \r
@@ -202,6 +195,8 @@ static VOID set_installer_properties(MSIPACKAGE *package)
 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};\r
     static const WCHAR SF[] = \r
 {'S','y','s','t','e','m','F','o','l','d','e','r',0};\r
+    static const WCHAR SF16[] = \r
+{'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};\r
     static const WCHAR LADF[] = \r
 {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};\r
     static const WCHAR MPF[] = \r
@@ -210,6 +205,8 @@ static VOID set_installer_properties(MSIPACKAGE *package)
 {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};\r
     static const WCHAR WF[] = \r
 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};\r
+    static const WCHAR WV[] = \r
+{'W','i','n','d','o','w','s','V','o','l','u','m','e',0};\r
     static const WCHAR TF[]=\r
 {'T','e','m','p','F','o','l','d','e','r',0};\r
     static const WCHAR szAdminUser[] =\r
@@ -229,12 +226,15 @@ static VOID set_installer_properties(MSIPACKAGE *package)
 \r
     static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };\r
     static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};\r
+/* Screen properties */\r
+    static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};\r
+    static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};\r
+    static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};\r
+    static const WCHAR szScreenFormat[] = {'%','d',0};\r
 \r
 /*\r
  * Other things I notice set\r
  *\r
-ScreenY\r
-ScreenX\r
 SystemLanguageID\r
 ComputerName\r
 UserLanguageID\r
@@ -251,7 +251,6 @@ CaptionHeight
 BorderTop\r
 BorderSide\r
 TextHeight\r
-ColorBits\r
 RedirectedDllSupport\r
 Time\r
 Date\r
@@ -313,6 +312,7 @@ Privileged
     SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);\r
     strcatW(pth,cszbs);\r
     MSI_SetPropertyW(package, SF, pth);\r
+    MSI_SetPropertyW(package, SF16, pth);\r
 \r
     SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);\r
     strcatW(pth,cszbs);\r
@@ -330,6 +330,12 @@ Privileged
     strcatW(pth,cszbs);\r
     MSI_SetPropertyW(package, WF, pth);\r
 \r
+    SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);\r
+    ptr = strchrW(pth,'\\');\r
+    if (ptr)\r
+       *(ptr+1) = 0;\r
+    MSI_SetPropertyW(package, WV, pth);\r
+    \r
     GetTempPathW(MAX_PATH,pth);\r
     MSI_SetPropertyW(package, TF, pth);\r
 \r
@@ -357,8 +363,18 @@ Privileged
     /* just fudge this */\r
     MSI_SetPropertyW(package,szSPL,szSix);\r
 \r
-    sprintfW( msiver, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);\r
-    MSI_SetPropertyW( package, szVersionMsi, msiver );\r
+    sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);\r
+    MSI_SetPropertyW( package, szVersionMsi, bufstr );\r
+\r
+    /* Screen properties. */\r
+    dc = GetDC(0);\r
+    sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) );\r
+    MSI_SetPropertyW( package, szScreenX, bufstr );\r
+    sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, VERTRES ));\r
+    MSI_SetPropertyW( package, szScreenY, bufstr );\r
+    sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL ));\r
+    MSI_SetPropertyW( package, szColorBits, bufstr );\r
+    ReleaseDC(0, dc);\r
 }\r
 \r
 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)\r
@@ -406,6 +422,8 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
         package->loaded_folders = 0;\r
         package->loaded_components= 0;\r
         package->loaded_files = 0;\r
+        package->ActionFormat = NULL;\r
+        package->LastAction = NULL;\r
 \r
         /* OK, here is where we do a slew of things to the database to \r
          * prep for all that is to come as a package */\r
@@ -747,6 +765,10 @@ UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName,
     UINT rc;\r
 \r
     rc = MSI_GetPropertyRow(package, szName, &row);\r
+\r
+    if (*pchValueBuf > 0)\r
+        szValueBuf[0] = 0;\r
+\r
     if (rc == ERROR_SUCCESS)\r
     {\r
         rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf);\r
@@ -756,6 +778,9 @@ UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName,
     if (rc == ERROR_SUCCESS)\r
         TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),\r
             debugstr_w(szName));\r
+    else if (rc == ERROR_MORE_DATA)\r
+        TRACE("need %li sized buffer for %s\n", *pchValueBuf,\r
+            debugstr_w(szName));\r
     else\r
     {\r
         *pchValueBuf = 0;\r
@@ -772,6 +797,9 @@ UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName,
     UINT rc, len;\r
     LPWSTR szwName;\r
 \r
+    if (*pchValueBuf > 0)\r
+        szValueBuf[0] = 0;\r
+    \r
     len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );\r
     szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );\r
     if (!szwName)\r
@@ -788,6 +816,9 @@ UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName,
     if (rc == ERROR_SUCCESS)\r
         TRACE("returning %s for property %s\n", debugstr_a(szValueBuf),\r
             debugstr_a(szName));\r
+    else if (rc == ERROR_MORE_DATA)\r
+        TRACE("need %ld sized buffer for %s\n", *pchValueBuf,\r
+            debugstr_a(szName));\r
     else\r
     {\r
         *pchValueBuf = 0;\r
index fc8ce42..dfe5816 100644 (file)
@@ -52,6 +52,7 @@
 #define EXPR_STRCMP   7\r
 #define EXPR_UTF8     8\r
 #define EXPR_WILDCARD 9\r
+#define EXPR_COL_NUMBER_STRING 10\r
 \r
 struct sql_str {\r
     LPCWSTR data;\r
index 3def097..30cde0f 100644 (file)
@@ -32,6 +32,7 @@
 #include "msipriv.h"\r
 #include "objidl.h"\r
 #include "winnls.h"\r
+#include "ole2.h"\r
 \r
 #include "query.h"\r
 \r
@@ -77,10 +78,13 @@ MSIRECORD *MSI_CreateRecord( unsigned int cParams )
 \r
     TRACE("%d\n", cParams);\r
 \r
+    if( cParams>65535 )\r
+        return NULL;\r
+\r
     len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams;\r
     rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord );\r
     if( rec )\r
-    rec->count = cParams;\r
+        rec->count = cParams;\r
     return rec;\r
 }\r
 \r
@@ -111,12 +115,11 @@ unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
 \r
     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );\r
     if( !rec )\r
-    {\r
-        ERR("Record not found!\n");\r
-        return 0;\r
-    }\r
+        return -1;\r
 \r
+    msiobj_lock( &rec->hdr );\r
     ret = MSI_RecordGetFieldCount( rec );\r
+    msiobj_unlock( &rec->hdr );\r
     msiobj_release( &rec->hdr );\r
 \r
     return ret;\r
@@ -180,7 +183,9 @@ int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField)
     if( !rec )\r
         return MSI_NULL_INTEGER;\r
 \r
+    msiobj_lock( &rec->hdr );\r
     ret = MSI_RecordGetInteger( rec, iField );\r
+    msiobj_unlock( &rec->hdr );\r
     msiobj_release( &rec->hdr );\r
 \r
     return ret;\r
@@ -197,12 +202,14 @@ UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
     if( !rec )\r
         return ERROR_INVALID_HANDLE;\r
 \r
+    msiobj_lock( &rec->hdr );\r
     for( i=0; i<=rec->count; i++)\r
     {\r
         MSI_FreeField( &rec->fields[i] );\r
         rec->fields[i].type = MSIFIELD_NULL;\r
         rec->fields[i].u.iVal = 0;\r
     }\r
+    msiobj_unlock( &rec->hdr );\r
 \r
     return ERROR_SUCCESS;\r
 }\r
@@ -211,12 +218,12 @@ UINT MSI_RecordSetInteger( MSIRECORD *rec, unsigned int iField, int iVal )
 {\r
     TRACE("%p %u %d\n", rec, iField, iVal);\r
 \r
-    if( iField <= rec->count )\r
-    {\r
-        MSI_FreeField( &rec->fields[iField] );\r
-        rec->fields[iField].type = MSIFIELD_INT;\r
-        rec->fields[iField].u.iVal = iVal;\r
-    }\r
+    if( iField > rec->count )\r
+        return ERROR_INVALID_PARAMETER;\r
\r
+    MSI_FreeField( &rec->fields[iField] );\r
+    rec->fields[iField].type = MSIFIELD_INT;\r
+    rec->fields[iField].u.iVal = iVal;\r
 \r
     return ERROR_SUCCESS;\r
 }\r
@@ -232,7 +239,9 @@ UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal
     if( !rec )\r
         return ERROR_INVALID_HANDLE;\r
 \r
+    msiobj_lock( &rec->hdr );\r
     ret = MSI_RecordSetInteger( rec, iField, iVal );\r
+    msiobj_unlock( &rec->hdr );\r
     msiobj_release( &rec->hdr );\r
     return ret;\r
 }\r
@@ -258,8 +267,10 @@ BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField )
 \r
     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );\r
     if( !rec )\r
-        return ERROR_INVALID_HANDLE;\r
+        return 0;\r
+    msiobj_lock( &rec->hdr );\r
     ret = MSI_RecordIsNull( rec, iField );\r
+    msiobj_unlock( &rec->hdr );\r
     msiobj_release( &rec->hdr );\r
     return ret;\r
 \r
@@ -289,9 +300,12 @@ UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField,
                              NULL, 0 , NULL, NULL);\r
         WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,\r
                              szValue, *pcchValue, NULL, NULL);\r
+        if( *pcchValue && len>*pcchValue )\r
+            szValue[*pcchValue-1] = 0;\r
+        if( len )\r
+            len--;\r
         break;\r
     case MSIFIELD_NULL:\r
-        len = 1;\r
         if( *pcchValue > 0 )\r
             szValue[0] = 0;\r
         break;\r
@@ -318,7 +332,9 @@ UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField,
     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );\r
     if( !rec )\r
         return ERROR_INVALID_HANDLE;\r
+    msiobj_lock( &rec->hdr );\r
     ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);\r
+    msiobj_unlock( &rec->hdr );\r
     msiobj_release( &rec->hdr );\r
     return ret;\r
 }\r
@@ -385,17 +401,49 @@ UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField,
     if( !rec )\r
         return ERROR_INVALID_HANDLE;\r
 \r
+    msiobj_lock( &rec->hdr );\r
     ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );\r
+    msiobj_unlock( &rec->hdr );\r
     msiobj_release( &rec->hdr );\r
     return ret;\r
 }\r
 \r
-UINT WINAPI MsiRecordDataSize(MSIHANDLE hRecord, unsigned int iField)\r
+UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField)\r
 {\r
-    FIXME("%ld %d\n", hRecord, iField);\r
+    TRACE("%p %d\n", rec, iField);\r
+\r
+    if( iField > rec->count )\r
+        return 0;\r
+\r
+    switch( rec->fields[iField].type )\r
+    {\r
+    case MSIFIELD_INT:\r
+        return sizeof (INT);\r
+    case MSIFIELD_WSTR:\r
+        return lstrlenW( rec->fields[iField].u.szwVal );\r
+    case MSIFIELD_NULL:\r
+        break;\r
+    }\r
     return 0;\r
 }\r
 \r
+UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, unsigned int iField)\r
+{\r
+    MSIRECORD *rec;\r
+    UINT ret;\r
+\r
+    TRACE("%ld %d\n", handle, iField);\r
+\r
+    rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );\r
+    if( !rec )\r
+        return 0;\r
+    msiobj_lock( &rec->hdr );\r
+    ret = MSI_RecordDataSize( rec, iField);\r
+    msiobj_unlock( &rec->hdr );\r
+    msiobj_release( &rec->hdr );\r
+    return ret;\r
+}\r
+\r
 UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue )\r
 {\r
     LPWSTR str;\r
@@ -426,7 +474,9 @@ UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR s
     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );\r
     if( !rec )\r
         return ERROR_INVALID_HANDLE;\r
+    msiobj_lock( &rec->hdr );\r
     ret = MSI_RecordSetStringA( rec, iField, szValue );\r
+    msiobj_unlock( &rec->hdr );\r
     msiobj_release( &rec->hdr );\r
     return ret;\r
 }\r
@@ -463,7 +513,9 @@ UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR
     if( !rec )\r
         return ERROR_INVALID_HANDLE;\r
 \r
+    msiobj_lock( &rec->hdr );\r
     ret = MSI_RecordSetStringW( rec, iField, szValue );\r
+    msiobj_unlock( &rec->hdr );\r
     msiobj_release( &rec->hdr );\r
     return ret;\r
 }\r
@@ -480,16 +532,133 @@ UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szRes
     return ERROR_CALL_NOT_IMPLEMENTED;\r
 }\r
 \r
+/* read the data in a file into an IStream */\r
+UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)\r
+{\r
+    DWORD sz, szHighWord = 0, read;\r
+    HANDLE handle;\r
+    HGLOBAL hGlob = 0;\r
+    HRESULT hr;\r
+    ULARGE_INTEGER ulSize;\r
+\r
+    TRACE("reading %s\n", debugstr_w(szFile));\r
+\r
+    /* read the file into memory */\r
+    handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);\r
+    if( handle == INVALID_HANDLE_VALUE )\r
+        return GetLastError();\r
+    sz = GetFileSize(handle, &szHighWord);\r
+    if( sz != INVALID_FILE_SIZE && szHighWord == 0 )\r
+    {\r
+        hGlob = GlobalAlloc(GMEM_FIXED, sz);\r
+        if( hGlob )\r
+        {\r
+            BOOL r = ReadFile(handle, hGlob, sz, &read, NULL);\r
+            if( !r )\r
+            {\r
+                GlobalFree(hGlob);\r
+                hGlob = 0;\r
+            }\r
+        }\r
+    }\r
+    CloseHandle(handle);\r
+    if( !hGlob )\r
+        return ERROR_FUNCTION_FAILED;\r
+\r
+    /* make a stream out of it, and set the correct file size */\r
+    hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);\r
+    if( FAILED( hr ) )\r
+    {\r
+        GlobalFree(hGlob);\r
+        return ERROR_FUNCTION_FAILED;\r
+    }\r
+\r
+    /* set the correct size - CreateStreamOnHGlobal screws it up */\r
+    ulSize.QuadPart = sz;\r
+    IStream_SetSize(*pstm, ulSize);\r
+\r
+    TRACE("read %s, %ld bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);\r
+\r
+    return ERROR_SUCCESS;\r
+}\r
+\r
+UINT MSI_RecordSetStreamW(MSIRECORD *rec, unsigned int iField, LPCWSTR szFilename)\r
+{\r
+    IStream *stm = NULL;\r
+    HRESULT r;\r
+\r
+    if( (iField == 0) || (iField > rec->count) )\r
+        return ERROR_INVALID_PARAMETER;\r
+\r
+    /* no filename means we should seek back to the start of the stream */\r
+    if( !szFilename )\r
+    {\r
+        LARGE_INTEGER ofs;\r
+        ULARGE_INTEGER cur;\r
+\r
+        if( rec->fields[iField].type != MSIFIELD_STREAM )\r
+            return ERROR_INVALID_FIELD;\r
+\r
+        stm = rec->fields[iField].u.stream;\r
+        if( !stm )\r
+            return ERROR_INVALID_FIELD;\r
+\r
+        ofs.QuadPart = 0;\r
+        r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );\r
+        if( FAILED( r ) )\r
+            return ERROR_FUNCTION_FAILED;\r
+    }\r
+    else\r
+    {\r
+        /* read the file into a stream and save the stream in the record */\r
+        r = RECORD_StreamFromFile(szFilename, &stm);\r
+        if( r != ERROR_SUCCESS )\r
+            return r;\r
+\r
+        /* if all's good, store it in the record */\r
+        MSI_FreeField( &rec->fields[iField] );\r
+        rec->fields[iField].type = MSIFIELD_STREAM;\r
+        rec->fields[iField].u.stream = stm;\r
+    }\r
+\r
+    return ERROR_SUCCESS;\r
+}\r
+\r
 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename)\r
 {\r
-    FIXME("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));\r
-    return ERROR_CALL_NOT_IMPLEMENTED;\r
+    LPWSTR wstr = NULL;\r
+    UINT ret, len;\r
+\r
+    TRACE("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));\r
+\r
+    if( szFilename )\r
+    {\r
+        len = MultiByteToWideChar(CP_ACP,0,szFilename,-1,NULL,0);\r
+        wstr = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));\r
+        MultiByteToWideChar(CP_ACP,0,szFilename,-1,wstr,len);\r
+    }\r
+    ret = MsiRecordSetStreamW(hRecord, iField, wstr);\r
+    HeapFree(GetProcessHeap(),0,wstr);\r
+\r
+    return ret;\r
 }\r
 \r
-UINT WINAPI MsiRecordSetStreamW(MSIHANDLE hRecord, unsigned int iField, LPCWSTR szFilename)\r
+UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, unsigned int iField, LPCWSTR szFilename)\r
 {\r
-    FIXME("%ld %d %s\n", hRecord, iField, debugstr_w(szFilename));\r
-    return ERROR_CALL_NOT_IMPLEMENTED;\r
+    MSIRECORD *rec;\r
+    UINT ret;\r
+\r
+    TRACE("%ld %d %s\n", handle, iField, debugstr_w(szFilename));\r
+\r
+    rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );\r
+    if( !rec )\r
+        return ERROR_INVALID_HANDLE;\r
+\r
+    msiobj_lock( &rec->hdr );\r
+    ret = MSI_RecordSetStreamW( rec, iField, szFilename );\r
+    msiobj_unlock( &rec->hdr );\r
+    msiobj_release( &rec->hdr );\r
+    return ret;\r
 }\r
 \r
 UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD *sz)\r
@@ -500,18 +669,18 @@ UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD
 \r
     TRACE("%p %d %p %p\n", rec, iField, buf, sz);\r
 \r
-    if( iField > rec->count )\r
-        return ERROR_INVALID_FIELD;\r
+    if( !sz )\r
+        return ERROR_INVALID_PARAMETER;\r
+\r
+    if( iField > rec->count)\r
+        return ERROR_INVALID_PARAMETER;\r
 \r
     if( rec->fields[iField].type != MSIFIELD_STREAM )\r
-    {\r
-        *sz = 0;\r
-        return ERROR_INVALID_FIELD;\r
-    }\r
+        return ERROR_INVALID_DATATYPE;\r
 \r
     stm = rec->fields[iField].u.stream;\r
     if( !stm )\r
-        return ERROR_INVALID_FIELD;\r
+        return ERROR_INVALID_PARAMETER;\r
 \r
     /* if there's no buffer pointer, calculate the length to the end */\r
     if( !buf )\r
@@ -554,7 +723,9 @@ UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf
     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );\r
     if( !rec )\r
         return ERROR_INVALID_HANDLE;\r
+    msiobj_lock( &rec->hdr );\r
     ret = MSI_RecordReadStream( rec, iField, buf, sz );\r
+    msiobj_unlock( &rec->hdr );\r
     msiobj_release( &rec->hdr );\r
     return ret;\r
 }\r
index dafec32..7cfd6c0 100644 (file)
-/* A Bison parser, made from ./sql.y\r
-   by GNU bison 1.35.  */\r
-\r
-#define YYBISON 1  /* Identify Bison output.  */\r
-\r
-#define yyparse SQL_parse\r
-#define yylex SQL_lex\r
-#define yyerror SQL_error\r
-#define yylval SQL_lval\r
-#define yychar SQL_char\r
-#define yydebug SQL_debug\r
-#define yynerrs SQL_nerrs\r
-# define       TK_ABORT        257\r
-# define       TK_AFTER        258\r
-# define       TK_AGG_FUNCTION 259\r
-# define       TK_ALL  260\r
-# define       TK_AND  261\r
-# define       TK_AS   262\r
-# define       TK_ASC  263\r
-# define       TK_BEFORE       264\r
-# define       TK_BEGIN        265\r
-# define       TK_BETWEEN      266\r
-# define       TK_BITAND       267\r
-# define       TK_BITNOT       268\r
-# define       TK_BITOR        269\r
-# define       TK_BY   270\r
-# define       TK_CASCADE      271\r
-# define       TK_CASE 272\r
-# define       TK_CHAR 273\r
-# define       TK_CHECK        274\r
-# define       TK_CLUSTER      275\r
-# define       TK_COLLATE      276\r
-# define       TK_COLUMN       277\r
-# define       TK_COMMA        278\r
-# define       TK_COMMENT      279\r
-# define       TK_COMMIT       280\r
-# define       TK_CONCAT       281\r
-# define       TK_CONFLICT     282\r
-# define       TK_CONSTRAINT   283\r
-# define       TK_COPY 284\r
-# define       TK_CREATE       285\r
-# define       TK_DEFAULT      286\r
-# define       TK_DEFERRABLE   287\r
-# define       TK_DEFERRED     288\r
-# define       TK_DELETE       289\r
-# define       TK_DELIMITERS   290\r
-# define       TK_DESC 291\r
-# define       TK_DISTINCT     292\r
-# define       TK_DOT  293\r
-# define       TK_DROP 294\r
-# define       TK_EACH 295\r
-# define       TK_ELSE 296\r
-# define       TK_END  297\r
-# define       TK_END_OF_FILE  298\r
-# define       TK_EQ   299\r
-# define       TK_EXCEPT       300\r
-# define       TK_EXPLAIN      301\r
-# define       TK_FAIL 302\r
-# define       TK_FLOAT        303\r
-# define       TK_FOR  304\r
-# define       TK_FOREIGN      305\r
-# define       TK_FROM 306\r
-# define       TK_FUNCTION     307\r
-# define       TK_GE   308\r
-# define       TK_GLOB 309\r
-# define       TK_GROUP        310\r
-# define       TK_GT   311\r
-# define       TK_HAVING       312\r
-# define       TK_HOLD 313\r
-# define       TK_IGNORE       314\r
-# define       TK_ILLEGAL      315\r
-# define       TK_IMMEDIATE    316\r
-# define       TK_IN   317\r
-# define       TK_INDEX        318\r
-# define       TK_INITIALLY    319\r
-# define       TK_ID   320\r
-# define       TK_INSERT       321\r
-# define       TK_INSTEAD      322\r
-# define       TK_INT  323\r
-# define       TK_INTEGER      324\r
-# define       TK_INTERSECT    325\r
-# define       TK_INTO 326\r
-# define       TK_IS   327\r
-# define       TK_ISNULL       328\r
-# define       TK_JOIN 329\r
-# define       TK_JOIN_KW      330\r
-# define       TK_KEY  331\r
-# define       TK_LE   332\r
-# define       TK_LIKE 333\r
-# define       TK_LIMIT        334\r
-# define       TK_LONG 335\r
-# define       TK_LONGCHAR     336\r
-# define       TK_LP   337\r
-# define       TK_LSHIFT       338\r
-# define       TK_LT   339\r
-# define       TK_LOCALIZABLE  340\r
-# define       TK_MATCH        341\r
-# define       TK_MINUS        342\r
-# define       TK_NE   343\r
-# define       TK_NOT  344\r
-# define       TK_NOTNULL      345\r
-# define       TK_NULL 346\r
-# define       TK_OBJECT       347\r
-# define       TK_OF   348\r
-# define       TK_OFFSET       349\r
-# define       TK_ON   350\r
-# define       TK_OR   351\r
-# define       TK_ORACLE_OUTER_JOIN    352\r
-# define       TK_ORDER        353\r
-# define       TK_PLUS 354\r
-# define       TK_PRAGMA       355\r
-# define       TK_PRIMARY      356\r
-# define       TK_RAISE        357\r
-# define       TK_REFERENCES   358\r
-# define       TK_REM  359\r
-# define       TK_REPLACE      360\r
-# define       TK_RESTRICT     361\r
-# define       TK_ROLLBACK     362\r
-# define       TK_ROW  363\r
-# define       TK_RP   364\r
-# define       TK_RSHIFT       365\r
-# define       TK_SELECT       366\r
-# define       TK_SEMI 367\r
-# define       TK_SET  368\r
-# define       TK_SHORT        369\r
-# define       TK_SLASH        370\r
-# define       TK_SPACE        371\r
-# define       TK_STAR 372\r
-# define       TK_STATEMENT    373\r
-# define       TK_STRING       374\r
-# define       TK_TABLE        375\r
-# define       TK_TEMP 376\r
-# define       TK_THEN 377\r
-# define       TK_TRANSACTION  378\r
-# define       TK_TRIGGER      379\r
-# define       TK_UMINUS       380\r
-# define       TK_UNCLOSED_STRING      381\r
-# define       TK_UNION        382\r
-# define       TK_UNIQUE       383\r
-# define       TK_UPDATE       384\r
-# define       TK_UPLUS        385\r
-# define       TK_USING        386\r
-# define       TK_VACUUM       387\r
-# define       TK_VALUES       388\r
-# define       TK_VIEW 389\r
-# define       TK_WHEN 390\r
-# define       TK_WHERE        391\r
-# define       TK_WILDCARD     392\r
-# define       END_OF_FILE     393\r
-# define       ILLEGAL 394\r
-# define       SPACE   395\r
-# define       UNCLOSED_STRING 396\r
-# define       COMMENT 397\r
-# define       FUNCTION        398\r
-# define       COLUMN  399\r
-\r
-#line 1 "./sql.y"\r
-\r
-\r
-/*\r
- * Implementation of the Microsoft Installer (msi.dll)\r
- *\r
- * Copyright 2002-2004 Mike McCormack for CodeWeavers\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- */\r
-\r
-\r
-#include "config.h"\r
-\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "query.h"\r
-#include "wine/debug.h"\r
-#include "wine/unicode.h"\r
-\r
-#define YYLEX_PARAM info\r
-#define YYPARSE_PARAM info\r
-\r
-extern int SQL_error(const char *str);\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(msi);\r
-\r
-typedef struct tag_SQL_input\r
-{\r
-    MSIDATABASE *db;\r
-    LPCWSTR command;\r
-    DWORD n, len;\r
-    MSIVIEW **view;  /* view structure for the resulting query */\r
-} SQL_input;\r
-\r
-static LPWSTR SQL_getstring( struct sql_str *str );\r
-static INT SQL_getint( SQL_input *sql );\r
-static int SQL_lex( void *SQL_lval, SQL_input *info);\r
-\r
-static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, \r
-                               string_list *columns );\r
-static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, \r
-                             string_list *columns );\r
-\r
-static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,\r
-                                 string_list *keys);\r
-\r
-static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );\r
-static struct expr * EXPR_column( LPWSTR );\r
-static struct expr * EXPR_ival( struct sql_str *);\r
-static struct expr * EXPR_sval( struct sql_str *);\r
-static struct expr * EXPR_wildcard(void);\r
-\r
-\r
-#line 73 "./sql.y"\r
-#ifndef YYSTYPE\r
-typedef union\r
-{\r
-    struct sql_str str;\r
-    LPWSTR string;\r
-    string_list *column_list;\r
-    value_list *val_list;\r
-    MSIVIEW *query;\r
-    struct expr *expr;\r
-    USHORT column_type;\r
-    create_col_info *column_info;\r
-    column_assignment update_col_info;\r
-} yystype;\r
-# define YYSTYPE yystype\r
-# define YYSTYPE_IS_TRIVIAL 1\r
-#endif\r
-#ifndef YYDEBUG\r
-# define YYDEBUG 0\r
-#endif\r
-\r
-\r
-\r
-#define        YYFINAL         121\r
-#define        YYFLAG          -32768\r
-#define        YYNTBASE        147\r
-\r
-/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */\r
-#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 171)\r
-\r
-/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */\r
-static const short yytranslate[] =\r
-{\r
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\r
-       2,     2,     2,     2,     2,     2,     1,     3,     4,     5,\r
-       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,\r
-      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,\r
-      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,\r
-      36,    37,    38,    39,    40,    41,    42,    43,    44,    45,\r
-      46,    47,    48,    49,    50,    51,    52,    53,    54,    55,\r
-      56,    57,    58,    59,    60,    61,    62,    63,    64,    65,\r
-      66,    67,    68,    69,    70,    71,    72,    73,    74,    75,\r
-      76,    77,    78,    79,    80,    81,    82,    83,    84,    85,\r
-      86,    87,    88,    89,    90,    91,    92,    93,    94,    95,\r
-      96,    97,    98,    99,   100,   101,   102,   103,   104,   105,\r
-     106,   107,   108,   109,   110,   111,   112,   113,   114,   115,\r
-     116,   117,   118,   119,   120,   121,   122,   123,   124,   125,\r
-     126,   127,   128,   129,   130,   131,   132,   133,   134,   135,\r
-     136,   137,   138,   139,   140,   141,   142,   143,   144,   145,\r
-     146\r
-};\r
-\r
-#if YYDEBUG\r
-static const short yyprhs[] =\r
-{\r
-       0,     0,     2,     4,     6,     8,    19,    31,    38,    46,\r
-      53,    58,    63,    66,    68,    71,    73,    77,    79,    84,\r
-      86,    88,    90,    92,    94,    96,   101,   103,   107,   112,\r
-     114,   118,   120,   123,   128,   132,   136,   140,   144,   148,\r
-     152,   156,   160,   164,   168,   172,   177,   179,   181,   183,\r
-     187,   189,   193,   197,   199,   201,   203,   205,   209,   211,\r
-     213,   215\r
-};\r
-static const short yyrhs[] =\r
-{\r
-     157,     0,   149,     0,   148,     0,   150,     0,    67,    72,\r
-     169,    83,   159,   110,   134,    83,   163,   110,     0,    67,\r
-      72,   169,    83,   159,   110,   134,    83,   163,   110,   122,\r
-       0,    31,   121,   169,    83,   151,   110,     0,    31,   121,\r
-     169,    83,   151,   110,    59,     0,   130,   169,   114,   164,\r
-     137,   161,     0,   152,   102,    77,   159,     0,   152,    24,\r
-     168,   153,     0,   168,   153,     0,   154,     0,   154,    86,\r
-       0,   155,     0,   155,    90,    92,     0,    19,     0,    19,\r
-      83,   156,   110,     0,    82,     0,   115,     0,    69,     0,\r
-      81,     0,    93,     0,    70,     0,   158,    99,    16,   159,\r
-       0,   158,     0,   112,   159,   160,     0,   112,    38,   159,\r
-     160,     0,   168,     0,   168,    24,   159,     0,   118,     0,\r
-      52,   169,     0,    52,   169,   137,   161,     0,    83,   161,\r
-     110,     0,   167,    45,   167,     0,   161,     7,   161,     0,\r
-     161,    97,   161,     0,   167,    45,   162,     0,   167,    57,\r
-     162,     0,   167,    85,   162,     0,   167,    78,   162,     0,\r
-     167,    54,   162,     0,   167,    89,   162,     0,   167,    73,\r
-      92,     0,   167,    73,    90,    92,     0,   167,     0,   166,\r
-       0,   166,     0,   163,    24,   166,     0,   165,     0,   165,\r
-      24,   164,     0,   168,    45,   166,     0,    70,     0,   120,\r
-       0,   138,     0,   168,     0,   169,    39,   170,     0,   170,\r
-       0,   170,     0,    66,     0,   120,     0\r
-};\r
-\r
-#endif\r
-\r
-#if YYDEBUG\r
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */\r
-static const short yyrline[] =\r
-{\r
-       0,   141,   147,   152,   157,   164,   173,   183,   194,   206,\r
-     217,   227,   247,   258,   263,   270,   275,   281,   286,   290,\r
-     294,   298,   302,   306,   312,   323,   335,   338,   353,   370,\r
-     384,   397,   403,   415,   433,   438,   442,   446,   450,   454,\r
-     458,   462,   466,   470,   474,   478,   484,   486,   489,   502,\r
-     517,   519,   527,   543,   548,   552,   558,   565,   570,   576,\r
-     583,   588\r
-};\r
-#endif\r
-\r
-\r
-#if (YYDEBUG) || defined YYERROR_VERBOSE\r
-\r
-/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */\r
-static const char *const yytname[] =\r
-{\r
-  "$", "error", "$undefined.", "TK_ABORT", "TK_AFTER", "TK_AGG_FUNCTION", \r
-  "TK_ALL", "TK_AND", "TK_AS", "TK_ASC", "TK_BEFORE", "TK_BEGIN", \r
-  "TK_BETWEEN", "TK_BITAND", "TK_BITNOT", "TK_BITOR", "TK_BY", \r
-  "TK_CASCADE", "TK_CASE", "TK_CHAR", "TK_CHECK", "TK_CLUSTER", \r
-  "TK_COLLATE", "TK_COLUMN", "TK_COMMA", "TK_COMMENT", "TK_COMMIT", \r
-  "TK_CONCAT", "TK_CONFLICT", "TK_CONSTRAINT", "TK_COPY", "TK_CREATE", \r
-  "TK_DEFAULT", "TK_DEFERRABLE", "TK_DEFERRED", "TK_DELETE", \r
-  "TK_DELIMITERS", "TK_DESC", "TK_DISTINCT", "TK_DOT", "TK_DROP", \r
-  "TK_EACH", "TK_ELSE", "TK_END", "TK_END_OF_FILE", "TK_EQ", "TK_EXCEPT", \r
-  "TK_EXPLAIN", "TK_FAIL", "TK_FLOAT", "TK_FOR", "TK_FOREIGN", "TK_FROM", \r
-  "TK_FUNCTION", "TK_GE", "TK_GLOB", "TK_GROUP", "TK_GT", "TK_HAVING", \r
-  "TK_HOLD", "TK_IGNORE", "TK_ILLEGAL", "TK_IMMEDIATE", "TK_IN", \r
-  "TK_INDEX", "TK_INITIALLY", "TK_ID", "TK_INSERT", "TK_INSTEAD", \r
-  "TK_INT", "TK_INTEGER", "TK_INTERSECT", "TK_INTO", "TK_IS", "TK_ISNULL", \r
-  "TK_JOIN", "TK_JOIN_KW", "TK_KEY", "TK_LE", "TK_LIKE", "TK_LIMIT", \r
-  "TK_LONG", "TK_LONGCHAR", "TK_LP", "TK_LSHIFT", "TK_LT", \r
-  "TK_LOCALIZABLE", "TK_MATCH", "TK_MINUS", "TK_NE", "TK_NOT", \r
-  "TK_NOTNULL", "TK_NULL", "TK_OBJECT", "TK_OF", "TK_OFFSET", "TK_ON", \r
-  "TK_OR", "TK_ORACLE_OUTER_JOIN", "TK_ORDER", "TK_PLUS", "TK_PRAGMA", \r
-  "TK_PRIMARY", "TK_RAISE", "TK_REFERENCES", "TK_REM", "TK_REPLACE", \r
-  "TK_RESTRICT", "TK_ROLLBACK", "TK_ROW", "TK_RP", "TK_RSHIFT", \r
-  "TK_SELECT", "TK_SEMI", "TK_SET", "TK_SHORT", "TK_SLASH", "TK_SPACE", \r
-  "TK_STAR", "TK_STATEMENT", "TK_STRING", "TK_TABLE", "TK_TEMP", \r
-  "TK_THEN", "TK_TRANSACTION", "TK_TRIGGER", "TK_UMINUS", \r
-  "TK_UNCLOSED_STRING", "TK_UNION", "TK_UNIQUE", "TK_UPDATE", "TK_UPLUS", \r
-  "TK_USING", "TK_VACUUM", "TK_VALUES", "TK_VIEW", "TK_WHEN", "TK_WHERE", \r
-  "TK_WILDCARD", "END_OF_FILE", "ILLEGAL", "SPACE", "UNCLOSED_STRING", \r
-  "COMMENT", "FUNCTION", "COLUMN", "AGG_FUNCTION.", "onequery", \r
-  "oneinsert", "onecreate", "oneupdate", "table_def", "column_def", \r
-  "column_type", "data_type_l", "data_type", "data_count", "oneselect", \r
-  "unorderedsel", "selcollist", "from", "expr", "val", "constlist", \r
-  "update_assign_list", "column_assignment", "const_val", "column_val", \r
-  "column", "table", "string_or_id", 0\r
-};\r
-#endif\r
-\r
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */\r
-static const short yyr1[] =\r
-{\r
-       0,   147,   147,   147,   147,   148,   148,   149,   149,   150,\r
-     151,   152,   152,   153,   153,   154,   154,   155,   155,   155,\r
-     155,   155,   155,   155,   156,   157,   157,   158,   158,   159,\r
-     159,   159,   160,   160,   161,   161,   161,   161,   161,   161,\r
-     161,   161,   161,   161,   161,   161,   162,   162,   163,   163,\r
-     164,   164,   165,   166,   166,   166,   167,   168,   168,   169,\r
-     170,   170\r
-};\r
-\r
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */\r
-static const short yyr2[] =\r
-{\r
-       0,     1,     1,     1,     1,    10,    11,     6,     7,     6,\r
-       4,     4,     2,     1,     2,     1,     3,     1,     4,     1,\r
-       1,     1,     1,     1,     1,     4,     1,     3,     4,     1,\r
-       3,     1,     2,     4,     3,     3,     3,     3,     3,     3,\r
-       3,     3,     3,     3,     3,     4,     1,     1,     1,     3,\r
-       1,     3,     3,     1,     1,     1,     1,     3,     1,     1,\r
-       1,     1\r
-};\r
-\r
-/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE\r
-   doesn't specify something else to do.  Zero means the default is an\r
-   error. */\r
-static const short yydefact[] =\r
-{\r
-       0,     0,     0,     0,     0,     3,     2,     4,     1,    26,\r
-       0,     0,     0,    60,    31,    61,     0,    29,     0,    58,\r
-       0,    59,     0,     0,     0,     0,     0,    27,     0,     0,\r
-       0,     0,     0,     0,    28,    32,    30,    57,     0,    50,\r
-       0,    25,     0,     0,     0,     0,     0,     0,     0,     0,\r
-       7,     0,     0,    17,    21,    22,    19,    23,    20,    12,\r
-      13,    15,     0,     0,    33,     0,    56,     9,    51,    53,\r
-      54,    55,    52,     8,     0,     0,     0,    14,     0,     0,\r
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,\r
-      11,    10,    24,     0,    16,     0,    34,    36,    37,    54,\r
-      38,    47,    35,    42,    46,    39,     0,    44,    41,    40,\r
-      43,    18,     0,    48,    45,     0,     5,    49,     6,     0,\r
-       0,     0\r
-};\r
-\r
-static const short yydefgoto[] =\r
-{\r
-     119,     5,     6,     7,    42,    43,    59,    60,    61,    93,\r
-       8,     9,    16,    27,    64,   100,   112,    38,    39,   101,\r
-      65,    66,    18,    19\r
-};\r
-\r
-static const short yypact[] =\r
-{\r
-     -30,  -113,   -49,   -34,   -50,-32768,-32768,-32768,-32768,   -79,\r
-     -50,   -50,   -52,-32768,-32768,-32768,   -25,     4,   -10,     0,\r
-     -72,-32768,    30,   -36,   -35,   -25,   -50,-32768,   -52,   -50,\r
-     -50,   -52,   -50,   -52,-32768,   -87,-32768,-32768,   -84,    33,\r
-      13,-32768,   -51,   -15,   -17,   -41,   -53,   -53,   -50,   -58,\r
-       1,   -50,    -5,    -8,-32768,-32768,-32768,-32768,-32768,-32768,\r
-     -13,    -9,   -57,   -53,    -4,    47,-32768,    -4,-32768,-32768,\r
-  -32768,-32768,-32768,-32768,   -17,   -52,    18,-32768,    -3,    11,\r
-      -7,   -53,   -53,   -59,   -59,   -59,   -71,   -59,   -59,   -59,\r
-  -32768,-32768,-32768,   -14,-32768,   -58,-32768,    -4,    -4,    56,\r
-  -32768,-32768,-32768,-32768,-32768,-32768,     5,-32768,-32768,-32768,\r
-  -32768,-32768,   -19,-32768,-32768,   -58,   -23,-32768,-32768,   102,\r
-     108,-32768\r
-};\r
-\r
-static const short yypgoto[] =\r
-{\r
-  -32768,-32768,-32768,-32768,-32768,-32768,    40,-32768,-32768,-32768,\r
-  -32768,-32768,    10,    93,   -37,    28,-32768,    71,-32768,   -32,\r
-      22,     3,    14,    45\r
-};\r
-\r
-\r
-#define        YYLAST          136\r
-\r
-\r
-static const short yytable[] =\r
-{\r
-      81,     1,    53,    81,    12,   115,    17,    13,    10,    51,\r
-      67,    69,    69,    13,    13,    17,    13,    72,    20,   106,\r
-      22,   107,    25,    11,    23,    24,    80,    26,    28,    29,\r
-      63,    17,    13,    40,    17,    44,    17,     2,    36,   -59,\r
-      35,    41,    30,    45,    97,    98,    31,    32,    33,    21,\r
-      46,    40,    54,    47,    74,    21,    21,    48,    49,    50,\r
-      73,    99,    70,   113,    55,    56,    14,    15,    15,    62,\r
-      15,    21,    75,    77,    37,    76,    57,    79,    17,    71,\r
-      71,    78,     3,   117,    14,    91,    15,    52,    92,    94,\r
-      82,   116,    83,    82,    95,   -61,   111,   114,    58,   118,\r
-       4,    84,   120,    96,    85,   102,   104,   104,   121,   104,\r
-     104,   104,   103,   105,    90,   108,   109,   110,    34,    68,\r
-      86,     0,     0,     0,     0,    87,     0,     0,     0,     0,\r
-       0,     0,    88,     0,     0,     0,    89\r
-};\r
-\r
-static const short yycheck[] =\r
-{\r
-       7,    31,    19,     7,    38,    24,     3,    66,   121,    24,\r
-      47,    70,    70,    66,    66,    12,    66,    49,     4,    90,\r
-      99,    92,    12,    72,    10,    11,    63,    52,    24,    39,\r
-      83,    28,    66,    30,    31,    32,    33,    67,    28,    39,\r
-      26,    31,   114,    33,    81,    82,    16,    83,    83,     4,\r
-     137,    48,    69,   137,    51,    10,    11,    24,    45,   110,\r
-      59,   120,   120,    95,    81,    82,   118,   120,   120,   110,\r
-     120,    26,    77,    86,    29,    83,    93,   134,    75,   138,\r
-     138,    90,   112,   115,   118,    75,   120,   102,    70,    92,\r
-      97,   110,    45,    97,    83,    39,   110,    92,   115,   122,\r
-     130,    54,     0,   110,    57,    83,    84,    85,     0,    87,\r
-      88,    89,    84,    85,    74,    87,    88,    89,    25,    48,\r
-      73,    -1,    -1,    -1,    -1,    78,    -1,    -1,    -1,    -1,\r
-      -1,    -1,    85,    -1,    -1,    -1,    89\r
-};\r
-#define YYPURE 1\r
-\r
-/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */\r
-#line 3 "/usr/share/bison/bison.simple"\r
-\r
-/* Skeleton output parser for bison,\r
-\r
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software\r
-   Foundation, Inc.\r
-\r
-   This program is free software; you can redistribute it and/or modify\r
-   it under the terms of the GNU General Public License as published by\r
-   the Free Software Foundation; either version 2, or (at your option)\r
-   any later version.\r
-\r
-   This program is distributed in the hope that it will be useful,\r
-   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-   GNU General Public License for more details.\r
-\r
-   You should have received a copy of the GNU General Public License\r
-   along with this program; if not, write to the Free Software\r
-   Foundation, Inc., 59 Temple Place - Suite 330,\r
-   Boston, MA 02111-1307, USA.  */\r
-\r
-/* As a special exception, when this file is copied by Bison into a\r
-   Bison output file, you may use that output file without restriction.\r
-   This special exception was added by the Free Software Foundation\r
-   in version 1.24 of Bison.  */\r
-\r
-/* This is the parser code that is written into each bison parser when\r
-   the %semantic_parser declaration is not specified in the grammar.\r
-   It was written by Richard Stallman by simplifying the hairy parser\r
-   used when %semantic_parser is specified.  */\r
-\r
-/* All symbols defined below should begin with yy or YY, to avoid\r
-   infringing on user name space.  This should be done even for local\r
-   variables, as they might otherwise be expanded by user macros.\r
-   There are some unavoidable exceptions within include files to\r
-   define necessary library symbols; they are noted "INFRINGES ON\r
-   USER NAME SPACE" below.  */\r
-\r
-#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE)\r
-\r
-/* The parser invokes alloca or malloc; define the necessary symbols.  */\r
-\r
-# if YYSTACK_USE_ALLOCA\r
-#  define YYSTACK_ALLOC alloca\r
-# else\r
-#  ifndef YYSTACK_USE_ALLOCA\r
-#   if defined (alloca) || defined (_ALLOCA_H)\r
-#    define YYSTACK_ALLOC alloca\r
-#   else\r
-#    ifdef __GNUC__\r
-#     define YYSTACK_ALLOC __builtin_alloca\r
-#    endif\r
-#   endif\r
-#  endif\r
-# endif\r
-\r
-# ifdef YYSTACK_ALLOC\r
-   /* Pacify GCC's `empty if-body' warning. */\r
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)\r
-# else\r
-#  if defined (__STDC__) || defined (__cplusplus)\r
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */\r
-#   define YYSIZE_T size_t\r
-#  endif\r
-#  define YYSTACK_ALLOC malloc\r
-#  define YYSTACK_FREE free\r
-# endif\r
-#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */\r
-\r
-\r
-#if (! defined (yyoverflow) \\r
-     && (! defined (__cplusplus) \\r
-        || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))\r
-\r
-/* A type that is properly aligned for any stack member.  */\r
-union yyalloc\r
-{\r
-  short yyss;\r
-  YYSTYPE yyvs;\r
-# if YYLSP_NEEDED\r
-  YYLTYPE yyls;\r
-# endif\r
-};\r
-\r
-/* The size of the maximum gap between one aligned stack and the next.  */\r
-# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1)\r
-\r
-/* The size of an array large to enough to hold all stacks, each with\r
-   N elements.  */\r
-# if YYLSP_NEEDED\r
-#  define YYSTACK_BYTES(N) \\r
-     ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE))     \\r
-      + 2 * YYSTACK_GAP_MAX)\r
-# else\r
-#  define YYSTACK_BYTES(N) \\r
-     ((N) * (sizeof (short) + sizeof (YYSTYPE))                                \\r
-      + YYSTACK_GAP_MAX)\r
-# endif\r
-\r
-/* Copy COUNT objects from FROM to TO.  The source and destination do\r
-   not overlap.  */\r
-# ifndef YYCOPY\r
-#  if 1 < __GNUC__\r
-#   define YYCOPY(To, From, Count) \\r
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))\r
-#  else\r
-#   define YYCOPY(To, From, Count)             \\r
-      do                                       \\r
-       {                                       \\r
-         register YYSIZE_T yyi;                \\r
-         for (yyi = 0; yyi < (Count); yyi++)   \\r
-           (To)[yyi] = (From)[yyi];            \\r
-       }                                       \\r
-      while (0)\r
-#  endif\r
-# endif\r
-\r
-/* Relocate STACK from its old location to the new one.  The\r
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of\r
-   elements in the stack, and YYPTR gives the new location of the\r
-   stack.  Advance YYPTR to a properly aligned location for the next\r
-   stack.  */\r
-# define YYSTACK_RELOCATE(Stack)                                       \\r
-    do                                                                 \\r
-      {                                                                        \\r
-       YYSIZE_T yynewbytes;                                            \\r
-       YYCOPY (&yyptr->Stack, Stack, yysize);                          \\r
-       Stack = &yyptr->Stack;                                          \\r
-       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX;   \\r
-       yyptr += yynewbytes / sizeof (*yyptr);                          \\r
-      }                                                                        \\r
-    while (0)\r
-\r
-#endif\r
-\r
-\r
-#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)\r
-# define YYSIZE_T __SIZE_TYPE__\r
-#endif\r
-#if ! defined (YYSIZE_T) && defined (size_t)\r
-# define YYSIZE_T size_t\r
-#endif\r
-#if ! defined (YYSIZE_T)\r
-# if defined (__STDC__) || defined (__cplusplus)\r
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */\r
-#  define YYSIZE_T size_t\r
-# endif\r
-#endif\r
-#if ! defined (YYSIZE_T)\r
-# define YYSIZE_T unsigned int\r
-#endif\r
-\r
-#define yyerrok                (yyerrstatus = 0)\r
-#define yyclearin      (yychar = YYEMPTY)\r
-#define YYEMPTY                -2\r
-#define YYEOF          0\r
-#define YYACCEPT       goto yyacceptlab\r
-#define YYABORT        goto yyabortlab\r
-#define YYERROR                goto yyerrlab1\r
-/* Like YYERROR except do call yyerror.  This remains here temporarily\r
-   to ease the transition to the new meaning of YYERROR, for GCC.\r
-   Once GCC version 2 has supplanted version 1, this can go.  */\r
-#define YYFAIL         goto yyerrlab\r
-#define YYRECOVERING()  (!!yyerrstatus)\r
-#define YYBACKUP(Token, Value)                                 \\r
-do                                                             \\r
-  if (yychar == YYEMPTY && yylen == 1)                         \\r
-    {                                                          \\r
-      yychar = (Token);                                                \\r
-      yylval = (Value);                                                \\r
-      yychar1 = YYTRANSLATE (yychar);                          \\r
-      YYPOPSTACK;                                              \\r
-      goto yybackup;                                           \\r
-    }                                                          \\r
-  else                                                         \\r
-    {                                                          \\r
-      yyerror ("syntax error: cannot back up");                        \\r
-      YYERROR;                                                 \\r
-    }                                                          \\r
-while (0)\r
-\r
-#define YYTERROR       1\r
-#define YYERRCODE      256\r
-\r
-\r
-/* YYLLOC_DEFAULT -- Compute the default location (before the actions\r
-   are run).\r
-\r
-   When YYLLOC_DEFAULT is run, CURRENT is set the location of the\r
-   first token.  By default, to implement support for ranges, extend\r
-   its range to the last symbol.  */\r
-\r
-#ifndef YYLLOC_DEFAULT\r
-# define YYLLOC_DEFAULT(Current, Rhs, N)               \\r
-   Current.last_line   = Rhs[N].last_line;     \\r
-   Current.last_column = Rhs[N].last_column;\r
-#endif\r
-\r
-\r
-/* YYLEX -- calling `yylex' with the right arguments.  */\r
-\r
-#if YYPURE\r
-# if YYLSP_NEEDED\r
-#  ifdef YYLEX_PARAM\r
-#   define YYLEX               yylex (&yylval, &yylloc, YYLEX_PARAM)\r
-#  else\r
-#   define YYLEX               yylex (&yylval, &yylloc)\r
-#  endif\r
-# else /* !YYLSP_NEEDED */\r
-#  ifdef YYLEX_PARAM\r
-#   define YYLEX               yylex (&yylval, YYLEX_PARAM)\r
-#  else\r
-#   define YYLEX               yylex (&yylval)\r
-#  endif\r
-# endif /* !YYLSP_NEEDED */\r
-#else /* !YYPURE */\r
-# define YYLEX                 yylex ()\r
-#endif /* !YYPURE */\r
-\r
-\r
-/* Enable debugging if requested.  */\r
-#if YYDEBUG\r
-\r
-# ifndef YYFPRINTF\r
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */\r
-#  define YYFPRINTF fprintf\r
-# endif\r
-\r
-# define YYDPRINTF(Args)                       \\r
-do {                                           \\r
-  if (yydebug)                                 \\r
-    YYFPRINTF Args;                            \\r
-} while (0)\r
-/* Nonzero means print parse trace.  It is left uninitialized so that\r
-   multiple parsers can coexist.  */\r
-int yydebug;\r
-#else /* !YYDEBUG */\r
-# define YYDPRINTF(Args)\r
-#endif /* !YYDEBUG */\r
-\r
-/* YYINITDEPTH -- initial size of the parser's stacks.  */\r
-#ifndef        YYINITDEPTH\r
-# define YYINITDEPTH 200\r
-#endif\r
-\r
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only\r
-   if the built-in stack extension method is used).\r
-\r
-   Do not make this value too large; the results are undefined if\r
-   SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)\r
-   evaluated with infinite-precision integer arithmetic.  */\r
-\r
-#if YYMAXDEPTH == 0\r
-# undef YYMAXDEPTH\r
-#endif\r
-\r
-#ifndef YYMAXDEPTH\r
-# define YYMAXDEPTH 10000\r
-#endif\r
-\f\r
-#ifdef YYERROR_VERBOSE\r
-\r
-# ifndef yystrlen\r
-#  if defined (__GLIBC__) && defined (_STRING_H)\r
-#   define yystrlen strlen\r
-#  else\r
-/* Return the length of YYSTR.  */\r
-static YYSIZE_T\r
-#   if defined (__STDC__) || defined (__cplusplus)\r
-yystrlen (const char *yystr)\r
-#   else\r
-yystrlen (yystr)\r
-     const char *yystr;\r
-#   endif\r
-{\r
-  register const char *yys = yystr;\r
-\r
-  while (*yys++ != '\0')\r
-    continue;\r
-\r
-  return yys - yystr - 1;\r
-}\r
-#  endif\r
-# endif\r
-\r
-# ifndef yystpcpy\r
-#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)\r
-#   define yystpcpy stpcpy\r
-#  else\r
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in\r
-   YYDEST.  */\r
-static char *\r
-#   if defined (__STDC__) || defined (__cplusplus)\r
-yystpcpy (char *yydest, const char *yysrc)\r
-#   else\r
-yystpcpy (yydest, yysrc)\r
-     char *yydest;\r
-     const char *yysrc;\r
-#   endif\r
-{\r
-  register char *yyd = yydest;\r
-  register const char *yys = yysrc;\r
-\r
-  while ((*yyd++ = *yys++) != '\0')\r
-    continue;\r
-\r
-  return yyd - 1;\r
-}\r
-#  endif\r
-# endif\r
-#endif\r
-\f\r
-#line 315 "/usr/share/bison/bison.simple"\r
-\r
-\r
-/* The user can define YYPARSE_PARAM as the name of an argument to be passed\r
-   into yyparse.  The argument should have type void *.\r
-   It should actually point to an object.\r
-   Grammar actions can access the variable by casting it\r
-   to the proper pointer type.  */\r
-\r
-#ifdef YYPARSE_PARAM\r
-# if defined (__STDC__) || defined (__cplusplus)\r
-#  define YYPARSE_PARAM_ARG void *YYPARSE_PARAM\r
-#  define YYPARSE_PARAM_DECL\r
-# else\r
-#  define YYPARSE_PARAM_ARG YYPARSE_PARAM\r
-#  define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;\r
-# endif\r
-#else /* !YYPARSE_PARAM */\r
-# define YYPARSE_PARAM_ARG\r
-# define YYPARSE_PARAM_DECL\r
-#endif /* !YYPARSE_PARAM */\r
-\r
-/* Prevent warning if -Wstrict-prototypes.  */\r
-#ifdef __GNUC__\r
-# ifdef YYPARSE_PARAM\r
-int yyparse (void *);\r
-# else\r
-int yyparse (void);\r
-# endif\r
-#endif\r
-\r
-/* YY_DECL_VARIABLES -- depending whether we use a pure parser,\r
-   variables are global, or local to YYPARSE.  */\r
-\r
-#define YY_DECL_NON_LSP_VARIABLES                      \\r
-/* The lookahead symbol.  */                           \\r
-int yychar;                                            \\r
-                                                       \\r
-/* The semantic value of the lookahead symbol. */      \\r
-YYSTYPE yylval;                                                \\r
-                                                       \\r
-/* Number of parse errors so far.  */                  \\r
-int yynerrs;\r
-\r
-#if YYLSP_NEEDED\r
-# define YY_DECL_VARIABLES                     \\r
-YY_DECL_NON_LSP_VARIABLES                      \\r
-                                               \\r
-/* Location data for the lookahead symbol.  */ \\r
-YYLTYPE yylloc;\r
-#else\r
-# define YY_DECL_VARIABLES                     \\r
-YY_DECL_NON_LSP_VARIABLES\r
-#endif\r
-\r
-\r
-/* If nonreentrant, generate the variables here. */\r
-\r
-#if !YYPURE\r
-YY_DECL_VARIABLES\r
-#endif  /* !YYPURE */\r
-\r
-int\r
-yyparse (YYPARSE_PARAM_ARG)\r
-     YYPARSE_PARAM_DECL\r
-{\r
-  /* If reentrant, generate the variables here. */\r
-#if YYPURE\r
-  YY_DECL_VARIABLES\r
-#endif  /* !YYPURE */\r
-\r
-  register int yystate;\r
-  register int yyn;\r
-  int yyresult;\r
-  /* Number of tokens to shift before error messages enabled.  */\r
-  int yyerrstatus;\r
-  /* Lookahead token as an internal (translated) token number.  */\r
-  int yychar1 = 0;\r
-\r
-  /* Three stacks and their tools:\r
-     `yyss': related to states,\r
-     `yyvs': related to semantic values,\r
-     `yyls': related to locations.\r
-\r
-     Refer to the stacks thru separate pointers, to allow yyoverflow\r
-     to reallocate them elsewhere.  */\r
-\r
-  /* The state stack. */\r
-  short        yyssa[YYINITDEPTH];\r
-  short *yyss = yyssa;\r
-  register short *yyssp;\r
-\r
-  /* The semantic value stack.  */\r
-  YYSTYPE yyvsa[YYINITDEPTH];\r
-  YYSTYPE *yyvs = yyvsa;\r
-  register YYSTYPE *yyvsp;\r
-\r
-#if YYLSP_NEEDED\r
-  /* The location stack.  */\r
-  YYLTYPE yylsa[YYINITDEPTH];\r
-  YYLTYPE *yyls = yylsa;\r
-  YYLTYPE *yylsp;\r
-#endif\r
-\r
-#if YYLSP_NEEDED\r
-# define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)\r
-#else\r
-# define YYPOPSTACK   (yyvsp--, yyssp--)\r
-#endif\r
-\r
-  YYSIZE_T yystacksize = YYINITDEPTH;\r
-\r
-\r
-  /* The variables used to return semantic value and location from the\r
-     action routines.  */\r
-  YYSTYPE yyval;\r
-#if YYLSP_NEEDED\r
-  YYLTYPE yyloc;\r
-#endif\r
-\r
-  /* When reducing, the number of symbols on the RHS of the reduced\r
-     rule. */\r
-  int yylen;\r
-\r
-  YYDPRINTF ((stderr, "Starting parse\n"));\r
-\r
-  yystate = 0;\r
-  yyerrstatus = 0;\r
-  yynerrs = 0;\r
-  yychar = YYEMPTY;            /* Cause a token to be read.  */\r
-\r
-  /* Initialize stack pointers.\r
-     Waste one element of value and location stack\r
-     so that they stay on the same level as the state stack.\r
-     The wasted elements are never initialized.  */\r
-\r
-  yyssp = yyss;\r
-  yyvsp = yyvs;\r
-#if YYLSP_NEEDED\r
-  yylsp = yyls;\r
-#endif\r
-  goto yysetstate;\r
-\r
-/*------------------------------------------------------------.\r
-| yynewstate -- Push a new state, which is found in yystate.  |\r
-`------------------------------------------------------------*/\r
- yynewstate:\r
-  /* In all cases, when you get here, the value and location stacks\r
-     have just been pushed. so pushing a state here evens the stacks.\r
-     */\r
-  yyssp++;\r
-\r
- yysetstate:\r
-  *yyssp = yystate;\r
-\r
-  if (yyssp >= yyss + yystacksize - 1)\r
-    {\r
-      /* Get the current used size of the three stacks, in elements.  */\r
-      YYSIZE_T yysize = yyssp - yyss + 1;\r
-\r
-#ifdef yyoverflow\r
-      {\r
-       /* Give user a chance to reallocate the stack. Use copies of\r
-          these so that the &'s don't force the real ones into\r
-          memory.  */\r
-       YYSTYPE *yyvs1 = yyvs;\r
-       short *yyss1 = yyss;\r
-\r
-       /* Each stack pointer address is followed by the size of the\r
-          data in use in that stack, in bytes.  */\r
-# if YYLSP_NEEDED\r
-       YYLTYPE *yyls1 = yyls;\r
-       /* This used to be a conditional around just the two extra args,\r
-          but that might be undefined if yyoverflow is a macro.  */\r
-       yyoverflow ("parser stack overflow",\r
-                   &yyss1, yysize * sizeof (*yyssp),\r
-                   &yyvs1, yysize * sizeof (*yyvsp),\r
-                   &yyls1, yysize * sizeof (*yylsp),\r
-                   &yystacksize);\r
-       yyls = yyls1;\r
-# else\r
-       yyoverflow ("parser stack overflow",\r
-                   &yyss1, yysize * sizeof (*yyssp),\r
-                   &yyvs1, yysize * sizeof (*yyvsp),\r
-                   &yystacksize);\r
-# endif\r
-       yyss = yyss1;\r
-       yyvs = yyvs1;\r
-      }\r
-#else /* no yyoverflow */\r
-# ifndef YYSTACK_RELOCATE\r
-      goto yyoverflowlab;\r
-# else\r
-      /* Extend the stack our own way.  */\r
-      if (yystacksize >= YYMAXDEPTH)\r
-       goto yyoverflowlab;\r
-      yystacksize *= 2;\r
-      if (yystacksize > YYMAXDEPTH)\r
-       yystacksize = YYMAXDEPTH;\r
-\r
-      {\r
-       short *yyss1 = yyss;\r
-       union yyalloc *yyptr =\r
-         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));\r
-       if (! yyptr)\r
-         goto yyoverflowlab;\r
-       YYSTACK_RELOCATE (yyss);\r
-       YYSTACK_RELOCATE (yyvs);\r
-# if YYLSP_NEEDED\r
-       YYSTACK_RELOCATE (yyls);\r
-# endif\r
-# undef YYSTACK_RELOCATE\r
-       if (yyss1 != yyssa)\r
-         YYSTACK_FREE (yyss1);\r
-      }\r
-# endif\r
-#endif /* no yyoverflow */\r
-\r
-      yyssp = yyss + yysize - 1;\r
-      yyvsp = yyvs + yysize - 1;\r
-#if YYLSP_NEEDED\r
-      yylsp = yyls + yysize - 1;\r
-#endif\r
-\r
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",\r
-                 (unsigned long int) yystacksize));\r
-\r
-      if (yyssp >= yyss + yystacksize - 1)\r
-       YYABORT;\r
-    }\r
-\r
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));\r
-\r
-  goto yybackup;\r
-\r
-\r
-/*-----------.\r
-| yybackup.  |\r
-`-----------*/\r
-yybackup:\r
-\r
-/* Do appropriate processing given the current state.  */\r
-/* Read a lookahead token if we need one and don't already have one.  */\r
-/* yyresume: */\r
-\r
-  /* First try to decide what to do without reference to lookahead token.  */\r
-\r
-  yyn = yypact[yystate];\r
-  if (yyn == YYFLAG)\r
-    goto yydefault;\r
-\r
-  /* Not known => get a lookahead token if don't already have one.  */\r
-\r
-  /* yychar is either YYEMPTY or YYEOF\r
-     or a valid token in external form.  */\r
-\r
-  if (yychar == YYEMPTY)\r
-    {\r
-      YYDPRINTF ((stderr, "Reading a token: "));\r
-      yychar = YYLEX;\r
-    }\r
-\r
-  /* Convert token to internal form (in yychar1) for indexing tables with */\r
-\r
-  if (yychar <= 0)             /* This means end of input. */\r
-    {\r
-      yychar1 = 0;\r
-      yychar = YYEOF;          /* Don't call YYLEX any more */\r
-\r
-      YYDPRINTF ((stderr, "Now at end of input.\n"));\r
-    }\r
-  else\r
-    {\r
-      yychar1 = YYTRANSLATE (yychar);\r
-\r
-#if YYDEBUG\r
-     /* We have to keep this `#if YYDEBUG', since we use variables\r
-       which are defined only if `YYDEBUG' is set.  */\r
-      if (yydebug)\r
-       {\r
-         YYFPRINTF (stderr, "Next token is %d (%s",\r
-                    yychar, yytname[yychar1]);\r
-         /* Give the individual parser a way to print the precise\r
-            meaning of a token, for further debugging info.  */\r
-# ifdef YYPRINT\r
-         YYPRINT (stderr, yychar, yylval);\r
-# endif\r
-         YYFPRINTF (stderr, ")\n");\r
-       }\r
-#endif\r
-    }\r
-\r
-  yyn += yychar1;\r
-  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)\r
-    goto yydefault;\r
-\r
-  yyn = yytable[yyn];\r
-\r
-  /* yyn is what to do for this token type in this state.\r
-     Negative => reduce, -yyn is rule number.\r
-     Positive => shift, yyn is new state.\r
-       New state is final state => don't bother to shift,\r
-       just return success.\r
-     0, or most negative number => error.  */\r
-\r
-  if (yyn < 0)\r
-    {\r
-      if (yyn == YYFLAG)\r
-       goto yyerrlab;\r
-      yyn = -yyn;\r
-      goto yyreduce;\r
-    }\r
-  else if (yyn == 0)\r
-    goto yyerrlab;\r
-\r
-  if (yyn == YYFINAL)\r
-    YYACCEPT;\r
-\r
-  /* Shift the lookahead token.  */\r
-  YYDPRINTF ((stderr, "Shifting token %d (%s), ",\r
-             yychar, yytname[yychar1]));\r
-\r
-  /* Discard the token being shifted unless it is eof.  */\r
-  if (yychar != YYEOF)\r
-    yychar = YYEMPTY;\r
-\r
-  *++yyvsp = yylval;\r
-#if YYLSP_NEEDED\r
-  *++yylsp = yylloc;\r
-#endif\r
-\r
-  /* Count tokens shifted since error; after three, turn off error\r
-     status.  */\r
-  if (yyerrstatus)\r
-    yyerrstatus--;\r
-\r
-  yystate = yyn;\r
-  goto yynewstate;\r
-\r
-\r
-/*-----------------------------------------------------------.\r
-| yydefault -- do the default action for the current state.  |\r
-`-----------------------------------------------------------*/\r
-yydefault:\r
-  yyn = yydefact[yystate];\r
-  if (yyn == 0)\r
-    goto yyerrlab;\r
-  goto yyreduce;\r
-\r
-\r
-/*-----------------------------.\r
-| yyreduce -- Do a reduction.  |\r
-`-----------------------------*/\r
-yyreduce:\r
-  /* yyn is the number of a rule to reduce with.  */\r
-  yylen = yyr2[yyn];\r
-\r
-  /* If YYLEN is nonzero, implement the default value of the action:\r
-     `$$ = $1'.\r
-\r
-     Otherwise, the following line sets YYVAL to the semantic value of\r
-     the lookahead token.  This behavior is undocumented and Bison\r
-     users should not rely upon it.  Assigning to YYVAL\r
-     unconditionally makes the parser a bit smaller, and it avoids a\r
-     GCC warning that YYVAL may be used uninitialized.  */\r
-  yyval = yyvsp[1-yylen];\r
-\r
-#if YYLSP_NEEDED\r
-  /* Similarly for the default location.  Let the user run additional\r
-     commands if for instance locations are ranges.  */\r
-  yyloc = yylsp[1-yylen];\r
-  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);\r
-#endif\r
-\r
-#if YYDEBUG\r
-  /* We have to keep this `#if YYDEBUG', since we use variables which\r
-     are defined only if `YYDEBUG' is set.  */\r
-  if (yydebug)\r
-    {\r
-      int yyi;\r
-\r
-      YYFPRINTF (stderr, "Reducing via rule %d (line %d), ",\r
-                yyn, yyrline[yyn]);\r
-\r
-      /* Print the symbols being reduced, and their result.  */\r
-      for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++)\r
-       YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);\r
-      YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]);\r
-    }\r
-#endif\r
-\r
-  switch (yyn) {\r
-\r
-case 1:\r
-#line 143 "./sql.y"\r
-{\r
-        SQL_input* sql = (SQL_input*) info;\r
-        *sql->view = yyvsp[0].query;\r
-    ;\r
-    break;}\r
-case 2:\r
-#line 148 "./sql.y"\r
-{\r
-        SQL_input* sql = (SQL_input*) info;\r
-        *sql->view = yyvsp[0].query;\r
-    ;\r
-    break;}\r
-case 3:\r
-#line 153 "./sql.y"\r
-{\r
-        SQL_input* sql = (SQL_input*) info;\r
-        *sql->view = yyvsp[0].query;\r
-    ;\r
-    break;}\r
-case 4:\r
-#line 158 "./sql.y"\r
-{\r
-        SQL_input* sql = (SQL_input*) info;\r
-        *sql->view = yyvsp[0].query;\r
-    ;\r
-    break;}\r
-case 5:\r
-#line 166 "./sql.y"\r
-{\r
-        SQL_input *sql = (SQL_input*) info;\r
-        MSIVIEW *insert = NULL; \r
-\r
-        INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE ); \r
-        yyval.query = insert;\r
-    ;\r
-    break;}\r
-case 6:\r
-#line 174 "./sql.y"\r
-{\r
-        SQL_input *sql = (SQL_input*) info;\r
-        MSIVIEW *insert = NULL; \r
-\r
-        INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE ); \r
-        yyval.query = insert;\r
-    ;\r
-    break;}\r
-case 7:\r
-#line 185 "./sql.y"\r
-{\r
-            SQL_input* sql = (SQL_input*) info;\r
-            MSIVIEW *create = NULL; \r
-\r
-            if( !yyvsp[-1].column_info )\r
-                YYABORT;\r
-            CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE );\r
-            yyval.query = create;\r
-        ;\r
-    break;}\r
-case 8:\r
-#line 195 "./sql.y"\r
-{\r
-            SQL_input* sql = (SQL_input*) info;\r
-            MSIVIEW *create = NULL; \r
-\r
-            if( !yyvsp[-2].column_info )\r
-                YYABORT;\r
-            CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE );\r
-            yyval.query = create;\r
-        ;\r
-    break;}\r
-case 9:\r
-#line 208 "./sql.y"\r
-{\r
-            SQL_input* sql = (SQL_input*) info;\r
-            MSIVIEW *update = NULL; \r
-\r
-            UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr );\r
-            yyval.query = update;\r
-        ;\r
-    break;}\r
-case 10:\r
-#line 219 "./sql.y"\r
-{\r
-            if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) )\r
-                yyval.column_info = yyvsp[-3].column_info;\r
-            else\r
-                yyval.column_info = NULL;\r
-        ;\r
-    break;}\r
-case 11:\r
-#line 229 "./sql.y"\r
-{\r
-            create_col_info *ci;\r
-\r
-            for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next )\r
-                ;\r
-\r
-            ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info );\r
-            if( !ci->next )\r
-            {\r
-                /* FIXME: free $1 */\r
-                YYABORT;\r
-            }\r
-            ci->next->colname = yyvsp[-1].string;\r
-            ci->next->type = yyvsp[0].column_type;\r
-            ci->next->next = NULL;\r
-\r
-            yyval.column_info = yyvsp[-3].column_info;\r
-        ;\r
-    break;}\r
-case 12:\r
-#line 248 "./sql.y"\r
-{\r
-            yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info );\r
-            if( ! yyval.column_info )\r
-                YYABORT;\r
-            yyval.column_info->colname = yyvsp[-1].string;\r
-            yyval.column_info->type = yyvsp[0].column_type;\r
-            yyval.column_info->next = NULL;\r
-        ;\r
-    break;}\r
-case 13:\r
-#line 260 "./sql.y"\r
-{\r
-            yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID;\r
-        ;\r
-    break;}\r
-case 14:\r
-#line 264 "./sql.y"\r
-{\r
-            FIXME("LOCALIZABLE ignored\n");\r
-            yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID;\r
-        ;\r
-    break;}\r
-case 15:\r
-#line 272 "./sql.y"\r
-{\r
-            yyval.column_type |= MSITYPE_NULLABLE;\r
-        ;\r
-    break;}\r
-case 16:\r
-#line 276 "./sql.y"\r
-{\r
-            yyval.column_type = yyvsp[-2].column_type;\r
-        ;\r
-    break;}\r
-case 17:\r
-#line 283 "./sql.y"\r
-{\r
-            yyval.column_type = MSITYPE_STRING | 1;\r
-        ;\r
-    break;}\r
-case 18:\r
-#line 287 "./sql.y"\r
-{\r
-            yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type;\r
-        ;\r
-    break;}\r
-case 19:\r
-#line 291 "./sql.y"\r
-{\r
-            yyval.column_type = 2;\r
-        ;\r
-    break;}\r
-case 20:\r
-#line 295 "./sql.y"\r
-{\r
-            yyval.column_type = 2;\r
-        ;\r
-    break;}\r
-case 21:\r
-#line 299 "./sql.y"\r
-{\r
-            yyval.column_type = 2;\r
-        ;\r
-    break;}\r
-case 22:\r
-#line 303 "./sql.y"\r
-{\r
-            yyval.column_type = 4;\r
-        ;\r
-    break;}\r
-case 23:\r
-#line 307 "./sql.y"\r
-{\r
-            yyval.column_type = 0;\r
-        ;\r
-    break;}\r
-case 24:\r
-#line 314 "./sql.y"\r
-{\r
-            SQL_input* sql = (SQL_input*) info;\r
-            int val = SQL_getint(sql);\r
-            if( ( val > 255 ) || ( val < 0 ) )\r
-                YYABORT;\r
-            yyval.column_type = val;\r
-        ;\r
-    break;}\r
-case 25:\r
-#line 325 "./sql.y"\r
-{\r
-            SQL_input* sql = (SQL_input*) info;\r
-\r
-            if( !yyvsp[-3].query )\r
-                YYABORT;\r
-            if( yyvsp[0].column_list )\r
-                yyval.query = do_order_by( sql->db, yyvsp[-3].query, yyvsp[0].column_list );\r
-            else\r
-                yyval.query = yyvsp[-3].query;\r
-        ;\r
-    break;}\r
-case 27:\r
-#line 340 "./sql.y"\r
-{\r
-            SQL_input* sql = (SQL_input*) info;\r
-            if( !yyvsp[0].query )\r
-                YYABORT;\r
-            if( yyvsp[-1].column_list )\r
-            {\r
-                yyval.query = do_one_select( sql->db, yyvsp[0].query, yyvsp[-1].column_list );\r
-                if( !yyval.query )\r
-                    YYABORT;\r
-            }\r
-            else\r
-                yyval.query = yyvsp[0].query;\r
-        ;\r
-    break;}\r
-case 28:\r
-#line 354 "./sql.y"\r
-{\r
-            SQL_input* sql = (SQL_input*) info;\r
-            MSIVIEW *view = yyvsp[0].query;\r
-\r
-            if( !view )\r
-                YYABORT;\r
-            if( yyvsp[-1].column_list )\r
-            {\r
-                view = do_one_select( sql->db, view, yyvsp[-1].column_list );\r
-                if( !view )\r
-                    YYABORT;\r
-            }\r
-            DISTINCT_CreateView( sql->db, & yyval.query, view );\r
-        ;\r
-    break;}\r
-case 29:\r
-#line 372 "./sql.y"\r
-{ \r
-            string_list *list;\r
-\r
-            list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );\r
-            if( !list )\r
-                YYABORT;\r
-            list->string = yyvsp[0].string;\r
-            list->next = NULL;\r
-\r
-            yyval.column_list = list;\r
-            TRACE("Collist %s\n",debugstr_w(yyval.column_list->string));\r
-        ;\r
-    break;}\r
-case 30:\r
-#line 385 "./sql.y"\r
-{ \r
-            string_list *list;\r
-\r
-            list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );\r
-            if( !list )\r
-                YYABORT;\r
-            list->string = yyvsp[-2].string;\r
-            list->next = yyvsp[0].column_list;\r
-\r
-            yyval.column_list = list;\r
-            TRACE("From table: %s\n",debugstr_w(yyval.column_list->string));\r
-        ;\r
-    break;}\r
-case 31:\r
-#line 398 "./sql.y"\r
-{\r
-            yyval.column_list = NULL;\r
-        ;\r
-    break;}\r
-case 32:\r
-#line 405 "./sql.y"\r
-{ \r
-            SQL_input* sql = (SQL_input*) info;\r
-            UINT r;\r
-\r
-            yyval.query = NULL;\r
-            TRACE("From table: %s\n",debugstr_w(yyvsp[0].string));\r
-            r = TABLE_CreateView( sql->db, yyvsp[0].string, & yyval.query );\r
-            if( r != ERROR_SUCCESS )\r
-                YYABORT;\r
-        ;\r
-    break;}\r
-case 33:\r
-#line 416 "./sql.y"\r
-{ \r
-            SQL_input* sql = (SQL_input*) info;\r
-            MSIVIEW *view = NULL;\r
-            UINT r;\r
-\r
-            yyval.query = NULL;\r
-            TRACE("From table: %s\n",debugstr_w(yyvsp[-2].string));\r
-            r = TABLE_CreateView( sql->db, yyvsp[-2].string, &view );\r
-            if( r != ERROR_SUCCESS )\r
-                YYABORT;\r
-            r = WHERE_CreateView( sql->db, &view, view, yyvsp[0].expr );\r
-            if( r != ERROR_SUCCESS )\r
-                YYABORT;\r
-            yyval.query = view;\r
-        ;\r
-    break;}\r
-case 34:\r
-#line 435 "./sql.y"\r
-{\r
-            yyval.expr = yyvsp[-1].expr;\r
-        ;\r
-    break;}\r
-case 35:\r
-#line 439 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr );\r
-        ;\r
-    break;}\r
-case 36:\r
-#line 443 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_AND, yyvsp[0].expr );\r
-        ;\r
-    break;}\r
-case 37:\r
-#line 447 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_OR, yyvsp[0].expr );\r
-        ;\r
-    break;}\r
-case 38:\r
-#line 451 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr );\r
-        ;\r
-    break;}\r
-case 39:\r
-#line 455 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GT, yyvsp[0].expr );\r
-        ;\r
-    break;}\r
-case 40:\r
-#line 459 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LT, yyvsp[0].expr );\r
-        ;\r
-    break;}\r
-case 41:\r
-#line 463 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LE, yyvsp[0].expr );\r
-        ;\r
-    break;}\r
-case 42:\r
-#line 467 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GE, yyvsp[0].expr );\r
-        ;\r
-    break;}\r
-case 43:\r
-#line 471 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_NE, yyvsp[0].expr );\r
-        ;\r
-    break;}\r
-case 44:\r
-#line 475 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_ISNULL, NULL );\r
-        ;\r
-    break;}\r
-case 45:\r
-#line 479 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_complex( yyvsp[-3].expr, OP_NOTNULL, NULL );\r
-        ;\r
-    break;}\r
-case 48:\r
-#line 491 "./sql.y"\r
-{\r
-            value_list *vals;\r
-\r
-            vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );\r
-            if( vals )\r
-            {\r
-                vals->val = yyvsp[0].expr;\r
-                vals->next = NULL;\r
-            }\r
-            yyval.val_list = vals;\r
-        ;\r
-    break;}\r
-case 49:\r
-#line 503 "./sql.y"\r
-{\r
-            value_list *vals;\r
-\r
-            vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );\r
-            if( vals )\r
-            {\r
-                vals->val = yyvsp[0].expr;\r
-                vals->next = NULL;\r
-            }\r
-            yyvsp[-2].val_list->next = vals;\r
-            yyval.val_list = yyvsp[-2].val_list;\r
-        ;\r
-    break;}\r
-case 51:\r
-#line 520 "./sql.y"\r
-{\r
-            yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list;\r
-            yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list;\r
-            yyval.update_col_info = yyvsp[-2].update_col_info;\r
-        ;\r
-    break;}\r
-case 52:\r
-#line 529 "./sql.y"\r
-{\r
-            yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list );\r
-            if( !yyval.update_col_info.col_list )\r
-                YYABORT;\r
-            yyval.update_col_info.col_list->string = yyvsp[-2].string;\r
-            yyval.update_col_info.col_list->next = NULL;\r
-            yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list );\r
-            if( !yyval.update_col_info.val_list )\r
-                YYABORT;\r
-            yyval.update_col_info.val_list->val = yyvsp[0].expr;\r
-            yyval.update_col_info.val_list->next = 0;\r
-        ;\r
-    break;}\r
-case 53:\r
-#line 545 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_ival( &yyvsp[0].str );\r
-        ;\r
-    break;}\r
-case 54:\r
-#line 549 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_sval( &yyvsp[0].str );\r
-        ;\r
-    break;}\r
-case 55:\r
-#line 553 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_wildcard();\r
-        ;\r
-    break;}\r
-case 56:\r
-#line 560 "./sql.y"\r
-{\r
-            yyval.expr = EXPR_column( yyvsp[0].string );\r
-        ;\r
-    break;}\r
-case 57:\r
-#line 567 "./sql.y"\r
-{\r
-            yyval.string = yyvsp[0].string;  /* FIXME */\r
-        ;\r
-    break;}\r
-case 58:\r
-#line 571 "./sql.y"\r
-{\r
-            yyval.string = yyvsp[0].string;\r
-        ;\r
-    break;}\r
-case 59:\r
-#line 578 "./sql.y"\r
-{\r
-            yyval.string = yyvsp[0].string;\r
-        ;\r
-    break;}\r
-case 60:\r
-#line 585 "./sql.y"\r
-{\r
-            yyval.string = SQL_getstring( &yyvsp[0].str );\r
-        ;\r
-    break;}\r
-case 61:\r
-#line 589 "./sql.y"\r
-{\r
-            yyval.string = SQL_getstring( &yyvsp[0].str );\r
-        ;\r
-    break;}\r
-}\r
-\r
-#line 705 "/usr/share/bison/bison.simple"\r
-\r
-\f\r
-  yyvsp -= yylen;\r
-  yyssp -= yylen;\r
-#if YYLSP_NEEDED\r
-  yylsp -= yylen;\r
-#endif\r
-\r
-#if YYDEBUG\r
-  if (yydebug)\r
-    {\r
-      short *yyssp1 = yyss - 1;\r
-      YYFPRINTF (stderr, "state stack now");\r
-      while (yyssp1 != yyssp)\r
-       YYFPRINTF (stderr, " %d", *++yyssp1);\r
-      YYFPRINTF (stderr, "\n");\r
-    }\r
-#endif\r
-\r
-  *++yyvsp = yyval;\r
-#if YYLSP_NEEDED\r
-  *++yylsp = yyloc;\r
-#endif\r
-\r
-  /* Now `shift' the result of the reduction.  Determine what state\r
-     that goes to, based on the state we popped back to and the rule\r
-     number reduced by.  */\r
-\r
-  yyn = yyr1[yyn];\r
-\r
-  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;\r
-  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)\r
-    yystate = yytable[yystate];\r
-  else\r
-    yystate = yydefgoto[yyn - YYNTBASE];\r
-\r
-  goto yynewstate;\r
-\r
-\r
-/*------------------------------------.\r
-| yyerrlab -- here on detecting error |\r
-`------------------------------------*/\r
-yyerrlab:\r
-  /* If not already recovering from an error, report this error.  */\r
-  if (!yyerrstatus)\r
-    {\r
-      ++yynerrs;\r
-\r
-#ifdef YYERROR_VERBOSE\r
-      yyn = yypact[yystate];\r
-\r
-      if (yyn > YYFLAG && yyn < YYLAST)\r
-       {\r
-         YYSIZE_T yysize = 0;\r
-         char *yymsg;\r
-         int yyx, yycount;\r
-\r
-         yycount = 0;\r
-         /* Start YYX at -YYN if negative to avoid negative indexes in\r
-            YYCHECK.  */\r
-         for (yyx = yyn < 0 ? -yyn : 0;\r
-              yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)\r
-           if (yycheck[yyx + yyn] == yyx)\r
-             yysize += yystrlen (yytname[yyx]) + 15, yycount++;\r
-         yysize += yystrlen ("parse error, unexpected ") + 1;\r
-         yysize += yystrlen (yytname[YYTRANSLATE (yychar)]);\r
-         yymsg = (char *) YYSTACK_ALLOC (yysize);\r
-         if (yymsg != 0)\r
-           {\r
-             char *yyp = yystpcpy (yymsg, "parse error, unexpected ");\r
-             yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]);\r
-\r
-             if (yycount < 5)\r
-               {\r
-                 yycount = 0;\r
-                 for (yyx = yyn < 0 ? -yyn : 0;\r
-                      yyx < (int) (sizeof (yytname) / sizeof (char *));\r
-                      yyx++)\r
-                   if (yycheck[yyx + yyn] == yyx)\r
-                     {\r
-                       const char *yyq = ! yycount ? ", expecting " : " or ";\r
-                       yyp = yystpcpy (yyp, yyq);\r
-                       yyp = yystpcpy (yyp, yytname[yyx]);\r
-                       yycount++;\r
-                     }\r
-               }\r
-             yyerror (yymsg);\r
-             YYSTACK_FREE (yymsg);\r
-           }\r
-         else\r
-           yyerror ("parse error; also virtual memory exhausted");\r
-       }\r
-      else\r
-#endif /* defined (YYERROR_VERBOSE) */\r
-       yyerror ("parse error");\r
-    }\r
-  goto yyerrlab1;\r
-\r
-\r
-/*--------------------------------------------------.\r
-| yyerrlab1 -- error raised explicitly by an action |\r
-`--------------------------------------------------*/\r
-yyerrlab1:\r
-  if (yyerrstatus == 3)\r
-    {\r
-      /* If just tried and failed to reuse lookahead token after an\r
-        error, discard it.  */\r
-\r
-      /* return failure if at end of input */\r
-      if (yychar == YYEOF)\r
-       YYABORT;\r
-      YYDPRINTF ((stderr, "Discarding token %d (%s).\n",\r
-                 yychar, yytname[yychar1]));\r
-      yychar = YYEMPTY;\r
-    }\r
-\r
-  /* Else will try to reuse lookahead token after shifting the error\r
-     token.  */\r
-\r
-  yyerrstatus = 3;             /* Each real token shifted decrements this */\r
-\r
-  goto yyerrhandle;\r
-\r
-\r
-/*-------------------------------------------------------------------.\r
-| yyerrdefault -- current state does not do anything special for the |\r
-| error token.                                                       |\r
-`-------------------------------------------------------------------*/\r
-yyerrdefault:\r
-#if 0\r
-  /* This is wrong; only states that explicitly want error tokens\r
-     should shift them.  */\r
-\r
-  /* If its default is to accept any token, ok.  Otherwise pop it.  */\r
-  yyn = yydefact[yystate];\r
-  if (yyn)\r
-    goto yydefault;\r
-#endif\r
-\r
-\r
-/*---------------------------------------------------------------.\r
-| yyerrpop -- pop the current state because it cannot handle the |\r
-| error token                                                    |\r
-`---------------------------------------------------------------*/\r
-yyerrpop:\r
-  if (yyssp == yyss)\r
-    YYABORT;\r
-  yyvsp--;\r
-  yystate = *--yyssp;\r
-#if YYLSP_NEEDED\r
-  yylsp--;\r
-#endif\r
-\r
-#if YYDEBUG\r
-  if (yydebug)\r
-    {\r
-      short *yyssp1 = yyss - 1;\r
-      YYFPRINTF (stderr, "Error: state stack now");\r
-      while (yyssp1 != yyssp)\r
-       YYFPRINTF (stderr, " %d", *++yyssp1);\r
-      YYFPRINTF (stderr, "\n");\r
-    }\r
-#endif\r
-\r
-/*--------------.\r
-| yyerrhandle.  |\r
-`--------------*/\r
-yyerrhandle:\r
-  yyn = yypact[yystate];\r
-  if (yyn == YYFLAG)\r
-    goto yyerrdefault;\r
-\r
-  yyn += YYTERROR;\r
-  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)\r
-    goto yyerrdefault;\r
-\r
-  yyn = yytable[yyn];\r
-  if (yyn < 0)\r
-    {\r
-      if (yyn == YYFLAG)\r
-       goto yyerrpop;\r
-      yyn = -yyn;\r
-      goto yyreduce;\r
-    }\r
-  else if (yyn == 0)\r
-    goto yyerrpop;\r
-\r
-  if (yyn == YYFINAL)\r
-    YYACCEPT;\r
-\r
-  YYDPRINTF ((stderr, "Shifting error token, "));\r
-\r
-  *++yyvsp = yylval;\r
-#if YYLSP_NEEDED\r
-  *++yylsp = yylloc;\r
-#endif\r
-\r
-  yystate = yyn;\r
-  goto yynewstate;\r
-\r
-\r
-/*-------------------------------------.\r
-| yyacceptlab -- YYACCEPT comes here.  |\r
-`-------------------------------------*/\r
-yyacceptlab:\r
-  yyresult = 0;\r
-  goto yyreturn;\r
-\r
-/*-----------------------------------.\r
-| yyabortlab -- YYABORT comes here.  |\r
-`-----------------------------------*/\r
-yyabortlab:\r
-  yyresult = 1;\r
-  goto yyreturn;\r
-\r
-/*---------------------------------------------.\r
-| yyoverflowab -- parser overflow comes here.  |\r
-`---------------------------------------------*/\r
-yyoverflowlab:\r
-  yyerror ("parser stack overflow");\r
-  yyresult = 2;\r
-  /* Fall through.  */\r
-\r
-yyreturn:\r
-#ifndef yyoverflow\r
-  if (yyss != yyssa)\r
-    YYSTACK_FREE (yyss);\r
-#endif\r
-  return yyresult;\r
-}\r
-#line 594 "./sql.y"\r
-\r
-\r
-int SQL_lex( void *SQL_lval, SQL_input *sql)\r
-{\r
-    int token;\r
-    struct sql_str * str = SQL_lval;\r
-\r
-    do\r
-    {\r
-        sql->n += sql->len;\r
-        if( ! sql->command[sql->n] )\r
-            return 0;  /* end of input */\r
-\r
-        TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));\r
-        sql->len = sqliteGetToken( &sql->command[sql->n], &token );\r
-        if( sql->len==0 )\r
-            break;\r
-        str->data = &sql->command[sql->n];\r
-        str->len = sql->len;\r
-    }\r
-    while( token == TK_SPACE );\r
-\r
-    TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));\r
-    \r
-    return token;\r
-}\r
-\r
-LPWSTR SQL_getstring( struct sql_str *strdata)\r
-{\r
-    LPCWSTR p = strdata->data;\r
-    UINT len = strdata->len;\r
-    LPWSTR str;\r
-\r
-    /* if there's quotes, remove them */\r
-    if( ( (p[0]=='`') && (p[len-1]=='`') ) || \r
-        ( (p[0]=='\'') && (p[len-1]=='\'') ) )\r
-    {\r
-        p++;\r
-        len -= 2;\r
-    }\r
-    str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));\r
-    if(!str )\r
-        return str;\r
-    memcpy(str, p, len*sizeof(WCHAR) );\r
-    str[len]=0;\r
-\r
-    return str;\r
-}\r
-\r
-INT SQL_getint( SQL_input *sql )\r
-{\r
-    LPCWSTR p = &sql->command[sql->n];\r
-\r
-    return atoiW( p );\r
-}\r
-\r
-int SQL_error(const char *str)\r
-{\r
-    return 0;\r
-}\r
-\r
-static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, \r
-                               string_list *columns )\r
-{\r
-    MSIVIEW *view = NULL;\r
-\r
-    SELECT_CreateView( db, &view, in, columns );\r
-    delete_string_list( columns );\r
-    if( !view )\r
-        ERR("Error creating select query\n");\r
-    return view;\r
-}\r
-\r
-static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, \r
-                             string_list *columns )\r
-{\r
-    MSIVIEW *view = NULL;\r
-\r
-    ORDER_CreateView( db, &view, in );\r
-    if( view )\r
-    {\r
-        string_list *x = columns;\r
-\r
-        for( x = columns; x ; x = x->next )\r
-            ORDER_AddColumn( view, x->string );\r
-    }\r
-    else\r
-        ERR("Error creating select query\n");\r
-    delete_string_list( columns );\r
-    return view;\r
-}\r
-\r
-static struct expr * EXPR_wildcard()\r
-{\r
-    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );\r
-    if( e )\r
-    {\r
-        e->type = EXPR_WILDCARD;\r
-    }\r
-    return e;\r
-}\r
-\r
-static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )\r
-{\r
-    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );\r
-    if( e )\r
-    {\r
-        e->type = EXPR_COMPLEX;\r
-        e->u.expr.left = l;\r
-        e->u.expr.op = op;\r
-        e->u.expr.right = r;\r
-    }\r
-    return e;\r
-}\r
-\r
-static struct expr * EXPR_column( LPWSTR str )\r
-{\r
-    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );\r
-    if( e )\r
-    {\r
-        e->type = EXPR_COLUMN;\r
-        e->u.sval = str;\r
-    }\r
-    return e;\r
-}\r
-\r
-static struct expr * EXPR_ival( struct sql_str *str )\r
-{\r
-    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );\r
-    if( e )\r
-    {\r
-        e->type = EXPR_IVAL;\r
-        e->u.ival = atoiW( str->data );\r
-    }\r
-    return e;\r
-}\r
-\r
-static struct expr * EXPR_sval( struct sql_str *str )\r
-{\r
-    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );\r
-    if( e )\r
-    {\r
-        e->type = EXPR_SVAL;\r
-        e->u.sval = SQL_getstring( str );\r
-    }\r
-    return e;\r
-}\r
-\r
-void delete_expr( struct expr *e )\r
-{\r
-    if( !e )\r
-        return;\r
-    if( e->type == EXPR_COMPLEX )\r
-    {\r
-        delete_expr( e->u.expr.left );\r
-        delete_expr( e->u.expr.right );\r
-    }\r
-    else if( e->type == EXPR_UTF8 )\r
-        HeapFree( GetProcessHeap(), 0, e->u.utf8 );\r
-    else if( e->type == EXPR_SVAL )\r
-        HeapFree( GetProcessHeap(), 0, e->u.sval );\r
-    HeapFree( GetProcessHeap(), 0, e );\r
-}\r
-\r
-void delete_string_list( string_list *sl )\r
-{\r
-    while( sl )\r
-    {\r
-        string_list *t = sl->next;\r
-        HeapFree( GetProcessHeap(), 0, sl->string );\r
-        HeapFree( GetProcessHeap(), 0, sl );\r
-        sl = t;\r
-    }\r
-}\r
-\r
-void delete_value_list( value_list *vl )\r
-{\r
-    while( vl )\r
-    {\r
-        value_list *t = vl->next;\r
-        delete_expr( vl->val );\r
-        HeapFree( GetProcessHeap(), 0, vl );\r
-        vl = t;\r
-    }\r
-}\r
-\r
-static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,\r
-                                 string_list *keys )\r
-{\r
-    string_list *k;\r
-    BOOL found = TRUE;\r
-\r
-    for( k = keys; k && found; k = k->next )\r
-    {\r
-        create_col_info *c;\r
-\r
-        found = FALSE;\r
-        for( c = cols; c && !found; c = c->next )\r
-        {\r
-             if( lstrcmpW( k->string, c->colname ) )\r
-                 continue;\r
-             c->type |= MSITYPE_KEY;\r
-             found = TRUE;\r
-        }\r
-    }\r
-\r
-    return found;\r
-}\r
-\r
-UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )\r
-{\r
-    SQL_input sql;\r
-    int r;\r
-\r
-    *phview = NULL;\r
-\r
-    sql.db = db;\r
-    sql.command = command;\r
-    sql.n = 0;\r
-    sql.len = 0;\r
-    sql.view = phview;\r
-\r
-    r = SQL_parse(&sql);\r
-\r
-    TRACE("Parse returned %d\n", r);\r
-    if( r )\r
-    {\r
-        if( *sql.view )\r
-            (*sql.view)->ops->delete( *sql.view );\r
-        *sql.view = NULL;\r
-        return ERROR_BAD_QUERY_SYNTAX;\r
-    }\r
-\r
-    return ERROR_SUCCESS;\r
-}\r
+/* A Bison parser, made by GNU Bison 1.875b.  */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 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
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* Written by Richard Stallman by simplifying the original so called
+   ``semantic'' parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* If NAME_PREFIX is specified substitute the variables and functions
+   names.  */
+#define yyparse SQL_parse
+#define yylex   SQL_lex
+#define yyerror SQL_error
+#define yylval  SQL_lval
+#define yychar  SQL_char
+#define yydebug SQL_debug
+#define yynerrs SQL_nerrs
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* 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
+   };
+#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
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 1 "./sql.y"
+
+
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002-2004 Mike McCormack for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * 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
+ */
+
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "query.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+#define YYLEX_PARAM info
+#define YYPARSE_PARAM info
+
+extern int SQL_error(const char *str);
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+typedef struct tag_SQL_input
+{
+    MSIDATABASE *db;
+    LPCWSTR command;
+    DWORD n, len;
+    MSIVIEW **view;  /* view structure for the resulting query */
+} SQL_input;
+
+static LPWSTR SQL_getstring( struct sql_str *str );
+static INT SQL_getint( SQL_input *sql );
+static int SQL_lex( void *SQL_lval, SQL_input *info);
+
+static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, 
+                               string_list *columns );
+static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, 
+                             string_list *columns );
+
+static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
+                                 string_list *keys);
+
+static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
+static struct expr * EXPR_column( LPWSTR );
+static struct expr * EXPR_ival( struct sql_str *, int sign);
+static struct expr * EXPR_sval( struct sql_str *);
+static struct expr * EXPR_wildcard(void);
+
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 74 "./sql.y"
+typedef union YYSTYPE {
+    struct sql_str str;
+    LPWSTR string;
+    string_list *column_list;
+    value_list *val_list;
+    MSIVIEW *query;
+    struct expr *expr;
+    USHORT column_type;
+    create_col_info *column_info;
+    column_assignment update_col_info;
+} YYSTYPE;
+/* Line 191 of yacc.c.  */
+#line 457 "sql.tab.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 214 of yacc.c.  */
+#line 469 "sql.tab.c"
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# if YYSTACK_USE_ALLOCA
+#  define YYSTACK_ALLOC alloca
+# else
+#  ifndef YYSTACK_USE_ALLOCA
+#   if defined (alloca) || defined (_ALLOCA_H)
+#    define YYSTACK_ALLOC alloca
+#   else
+#    ifdef __GNUC__
+#     define YYSTACK_ALLOC __builtin_alloca
+#    endif
+#   endif
+#  endif
+# endif
+
+# 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
+#  endif
+#  define YYSTACK_ALLOC malloc
+#  define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+     && (! defined (__cplusplus) \
+        || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  short yyss;
+  YYSTYPE yyvs;
+  };
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* 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))                                \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)             \
+      do                                       \
+       {                                       \
+         register YYSIZE_T yyi;                \
+         for (yyi = 0; yyi < (Count); yyi++)   \
+           (To)[yyi] = (From)[yyi];            \
+       }                                       \
+      while (0)
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)                                       \
+    do                                                                 \
+      {                                                                        \
+       YYSIZE_T yynewbytes;                                            \
+       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
+       Stack = &yyptr->Stack;                                          \
+       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+       yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                        \
+    while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+   typedef signed char yysigned_char;
+#else
+   typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL  23
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   125
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS  147
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS  25
+/* YYNRULES -- Number of rules. */
+#define YYNRULES  63
+/* YYNRULES -- Number of states. */
+#define YYNSTATES  123
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   401
+
+#define YYTRANSLATE(YYX)                                               \
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const unsigned char yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const unsigned char yyprhs[] =
+{
+       0,     0,     3,     5,     7,     9,    11,    22,    34,    41,
+      49,    56,    61,    66,    69,    71,    74,    76,    80,    82,
+      87,    89,    91,    93,    95,    97,    99,   104,   106,   110,
+     115,   117,   121,   123,   126,   131,   135,   139,   143,   147,
+     151,   155,   159,   163,   167,   171,   175,   180,   182,   184,
+     186,   190,   192,   196,   200,   202,   205,   207,   209,   211,
+     215,   217,   219,   221
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const short yyrhs[] =
+{
+     148,     0,    -1,   158,    -1,   150,    -1,   149,    -1,   151,
+      -1,    67,    72,   170,    83,   160,   110,   134,    83,   164,
+     110,    -1,    67,    72,   170,    83,   160,   110,   134,    83,
+     164,   110,   122,    -1,    31,   121,   170,    83,   152,   110,
+      -1,    31,   121,   170,    83,   152,   110,    59,    -1,   130,
+     170,   114,   165,   137,   162,    -1,   153,   102,    77,   160,
+      -1,   153,    24,   169,   154,    -1,   169,   154,    -1,   155,
+      -1,   155,    86,    -1,   156,    -1,   156,    90,    92,    -1,
+      19,    -1,    19,    83,   157,   110,    -1,    82,    -1,   115,
+      -1,    69,    -1,    81,    -1,    93,    -1,    70,    -1,   159,
+      99,    16,   160,    -1,   159,    -1,   112,   160,   161,    -1,
+     112,    38,   160,   161,    -1,   169,    -1,   169,    24,   160,
+      -1,   118,    -1,    52,   170,    -1,    52,   170,   137,   162,
+      -1,    83,   162,   110,    -1,   168,    45,   168,    -1,   162,
+       7,   162,    -1,   162,    97,   162,    -1,   168,    45,   163,
+      -1,   168,    57,   163,    -1,   168,    85,   163,    -1,   168,
+      78,   163,    -1,   168,    54,   163,    -1,   168,    89,   163,
+      -1,   168,    73,    92,    -1,   168,    73,    90,    92,    -1,
+     168,    -1,   167,    -1,   167,    -1,   164,    24,   167,    -1,
+     166,    -1,   166,    24,   165,    -1,   169,    45,   167,    -1,
+      70,    -1,    88,    70,    -1,   120,    -1,   138,    -1,   169,
+      -1,   170,    39,   171,    -1,   171,    -1,   171,    -1,    66,
+      -1,   120,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const unsigned short yyrline[] =
+{
+       0,   142,   142,   147,   152,   157,   165,   173,   184,   194,
+     207,   218,   228,   247,   259,   263,   271,   275,   282,   286,
+     290,   294,   298,   302,   306,   313,   324,   335,   339,   353,
+     371,   384,   397,   404,   415,   434,   438,   442,   446,   450,
+     454,   458,   462,   466,   470,   474,   478,   485,   486,   490,
+     502,   518,   519,   528,   544,   548,   552,   556,   563,   570,
+     574,   581,   588,   592
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[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", 
+  "onequery", "oneinsert", "onecreate", "oneupdate", "table_def", 
+  "column_def", "column_type", "data_type_l", "data_type", "data_count", 
+  "oneselect", "unorderedsel", "selcollist", "from", "expr", "val", 
+  "constlist", "update_assign_list", "column_assignment", "const_val", 
+  "column_val", "column", "table", "string_or_id", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const unsigned short yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     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
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const unsigned char yyr1[] =
+{
+       0,   147,   148,   148,   148,   148,   149,   149,   150,   150,
+     151,   152,   153,   153,   154,   154,   155,   155,   156,   156,
+     156,   156,   156,   156,   156,   157,   158,   158,   159,   159,
+     160,   160,   160,   161,   161,   162,   162,   162,   162,   162,
+     162,   162,   162,   162,   162,   162,   162,   163,   163,   164,
+     164,   165,   165,   166,   167,   167,   167,   167,   168,   169,
+     169,   170,   171,   171
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const unsigned char yyr2[] =
+{
+       0,     2,     1,     1,     1,     1,    10,    11,     6,     7,
+       6,     4,     4,     2,     1,     2,     1,     3,     1,     4,
+       1,     1,     1,     1,     1,     1,     4,     1,     3,     4,
+       1,     3,     1,     2,     4,     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
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const unsigned char yydefact[] =
+{
+       0,     0,     0,     0,     0,     0,     4,     3,     5,     2,
+      27,     0,     0,     0,    62,    32,    63,     0,    30,     0,
+      60,     0,    61,     1,     0,     0,     0,     0,     0,    28,
+       0,     0,     0,     0,     0,     0,    29,    33,    31,    59,
+       0,    51,     0,    26,     0,     0,     0,     0,     0,     0,
+       0,     0,     8,     0,     0,    18,    22,    23,    20,    24,
+      21,    13,    14,    16,     0,     0,    34,     0,    58,    10,
+      52,    54,     0,    56,    57,    53,     9,     0,     0,     0,
+      15,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    55,    12,    11,    25,     0,    17,     0,
+      35,    37,    38,    56,    39,    48,    36,    43,    47,    40,
+       0,    45,    42,    41,    44,    19,     0,    49,    46,     0,
+       6,    50,     7
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+      -1,     5,     6,     7,     8,    44,    45,    61,    62,    63,
+      97,     9,    10,    17,    29,    66,   104,   116,    40,    41,
+     105,    67,    68,    19,    20
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -105
+static const yysigned_char yypact[] =
+{
+     -30,  -104,   -46,   -34,   -51,    21,  -105,  -105,  -105,  -105,
+     -77,   -51,   -51,   -52,  -105,  -105,  -105,   -25,     7,    -1,
+       2,   -79,  -105,  -105,    31,   -33,   -32,   -25,   -51,  -105,
+     -52,   -51,   -51,   -52,   -51,   -52,  -105,   -88,  -105,  -105,
+     -82,    33,    14,  -105,   -48,   -15,   -17,   -43,   -50,   -50,
+     -51,   -64,    13,   -51,    -2,    -6,  -105,  -105,  -105,  -105,
+    -105,  -105,     6,    -9,   -49,   -50,    -4,    26,  -105,    -4,
+    -105,  -105,    24,  -105,  -105,  -105,  -105,   -17,   -52,    25,
+    -105,     9,    19,    -7,   -50,   -50,   -59,   -59,   -59,   -44,
+     -59,   -59,   -59,  -105,  -105,  -105,  -105,    -3,  -105,   -64,
+    -105,    -4,    -4,    73,  -105,  -105,  -105,  -105,  -105,  -105,
+      22,  -105,  -105,  -105,  -105,  -105,   -19,  -105,  -105,   -64,
+       1,  -105,  -105
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yysigned_char yypgoto[] =
+{
+    -105,  -105,  -105,  -105,  -105,  -105,  -105,    42,  -105,  -105,
+    -105,  -105,  -105,    -5,    97,   -31,    18,  -105,    75,  -105,
+     -41,    30,    10,    85,     8
+};
+
+/* 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 -64
+static const yysigned_char yytable[] =
+{
+      84,     1,    55,    84,    13,   119,    71,    14,    27,    53,
+      75,    71,    22,    18,    14,    14,    14,    11,    69,    22,
+      22,    23,    24,    18,    72,    38,    12,    28,    43,    72,
+      47,    30,    14,    65,    83,    32,    22,     2,    31,    39,
+      18,   -61,    42,    18,    46,    18,   110,    33,   111,    48,
+      34,    35,    56,   101,   102,    49,    73,    50,   117,    51,
+      42,   103,    52,    77,    57,    58,    15,    64,    16,    16,
+      16,    86,    76,    95,    74,    78,    59,    79,   121,    74,
+      87,    81,     3,    88,    15,    82,    16,    54,    18,    21,
+      85,   120,    80,    85,    93,    96,    25,    26,    60,    89,
+       4,    98,    99,   100,    90,   107,   109,   115,   112,   113,
+     114,    91,   -63,    37,   118,    92,   106,   108,   108,    94,
+     108,   108,   108,   122,    36,    70
+};
+
+static const unsigned char yycheck[] =
+{
+       7,    31,    19,     7,    38,    24,    70,    66,    13,    24,
+      51,    70,     4,     3,    66,    66,    66,   121,    49,    11,
+      12,     0,    99,    13,    88,    30,    72,    52,    33,    88,
+      35,    24,    66,    83,    65,   114,    28,    67,    39,    31,
+      30,    39,    32,    33,    34,    35,    90,    16,    92,   137,
+      83,    83,    69,    84,    85,   137,   120,    24,    99,    45,
+      50,   120,   110,    53,    81,    82,   118,   110,   120,   120,
+     120,    45,    59,    78,   138,    77,    93,    83,   119,   138,
+      54,    90,   112,    57,   118,   134,   120,   102,    78,     4,
+      97,   110,    86,    97,    70,    70,    11,    12,   115,    73,
+     130,    92,    83,   110,    78,    87,    88,   110,    90,    91,
+      92,    85,    39,    28,    92,    89,    86,    87,    88,    77,
+      90,    91,    92,   122,    27,    50
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const unsigned char yystos[] =
+{
+       0,    31,    67,   112,   130,   148,   149,   150,   151,   158,
+     159,   121,    72,    38,    66,   118,   120,   160,   169,   170,
+     171,   170,   171,     0,    99,   170,   170,   160,    52,   161,
+      24,    39,   114,    16,    83,    83,   161,   170,   160,   171,
+     165,   166,   169,   160,   152,   153,   169,   160,   137,   137,
+      24,    45,   110,    24,   102,    19,    69,    81,    82,    93,
+     115,   154,   155,   156,   110,    83,   162,   168,   169,   162,
+     165,    70,    88,   120,   138,   167,    59,   169,    77,    83,
+      86,    90,   134,   162,     7,    97,    45,    54,    57,    73,
+      78,    85,    89,    70,   154,   160,    70,   157,    92,    83,
+     110,   162,   162,   120,   163,   167,   168,   163,   168,   163,
+      90,    92,   163,   163,   163,   110,   164,   167,    92,    24,
+     110,   167,   122
+};
+
+#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)
+#define YYEOF          0
+
+#define YYACCEPT       goto yyacceptlab
+#define YYABORT                goto yyabortlab
+#define YYERROR                goto yyerrlab1
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL         goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                 \
+do                                                             \
+  if (yychar == YYEMPTY && yylen == 1)                         \
+    {                                                          \
+      yychar = (Token);                                                \
+      yylval = (Value);                                                \
+      yytoken = YYTRANSLATE (yychar);                          \
+      YYPOPSTACK;                                              \
+      goto yybackup;                                           \
+    }                                                          \
+  else                                                         \
+    {                                                          \
+      yyerror ("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).  */
+
+#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;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                       \
+do {                                           \
+  if (yydebug)                                 \
+    YYFPRINTF Args;                            \
+} while (0)
+
+# define YYDSYMPRINT(Args)                     \
+do {                                           \
+  if (yydebug)                                 \
+    yysymprint Args;                           \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location)           \
+do {                                                           \
+  if (yydebug)                                                 \
+    {                                                          \
+      YYFPRINTF (stderr, "%s ", Title);                                \
+      yysymprint (stderr,                                      \
+                  Token, Value);       \
+      YYFPRINTF (stderr, "\n");                                        \
+    }                                                          \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded).                                                   |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    short *bottom;
+    short *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (/* Nothing. */; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)                           \
+do {                                                           \
+  if (yydebug)                                                 \
+    yy_stack_print ((Bottom), (Top));                          \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+    int yyrule;
+#endif
+{
+  int yyi;
+  unsigned int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+             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]]);
+}
+
+# define YY_REDUCE_PRINT(Rule)         \
+do {                                   \
+  if (yydebug)                         \
+    yy_reduce_print (Rule);            \
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef        YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   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)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined (__GLIBC__) && defined (_STRING_H)
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+#   if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+#   else
+yystrlen (yystr)
+     const char *yystr;
+#   endif
+{
+  register const char *yys = yystr;
+
+  while (*yys++ != '\0')
+    continue;
+
+  return yys - yystr - 1;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+#   if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+#   else
+yystpcpy (yydest, yysrc)
+     char *yydest;
+     const char *yysrc;
+#   endif
+{
+  register char *yyd = yydest;
+  register const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+\f
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  if (yytype < YYNTOKENS)
+    {
+      YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+      YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+    }
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  switch (yytype)
+    {
+      default:
+        break;
+    }
+  YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  switch (yytype)
+    {
+
+      default:
+        break;
+    }
+}
+\f
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+  void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  /* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+  register int yystate;
+  register int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  short        yyssa[YYINITDEPTH];
+  short *yyss = yyssa;
+  register short *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* When reducing, the number of symbols on the RHS of the reduced
+     rule.  */
+  int yylen;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;            /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed. so pushing a state here evens the stacks.
+     */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+       /* Give user a chance to reallocate the stack. Use copies of
+          these so that the &'s don't force the real ones into
+          memory.  */
+       YYSTYPE *yyvs1 = yyvs;
+       short *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",
+                   &yyss1, yysize * sizeof (*yyssp),
+                   &yyvs1, yysize * sizeof (*yyvsp),
+
+                   &yystacksize);
+
+       yyss = yyss1;
+       yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyoverflowlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+       goto yyoverflowlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+       yystacksize = YYMAXDEPTH;
+
+      {
+       short *yyss1 = yyss;
+       union yyalloc *yyptr =
+         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+       if (! yyptr)
+         goto yyoverflowlab;
+       YYSTACK_RELOCATE (yyss);
+       YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+       if (yyss1 != yyssa)
+         YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+                 (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+       YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+       goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+  YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 2:
+#line 143 "./sql.y"
+    {
+        SQL_input* sql = (SQL_input*) info;
+        *sql->view = yyvsp[0].query;
+    ;}
+    break;
+
+  case 3:
+#line 148 "./sql.y"
+    {
+        SQL_input* sql = (SQL_input*) info;
+        *sql->view = yyvsp[0].query;
+    ;}
+    break;
+
+  case 4:
+#line 153 "./sql.y"
+    {
+        SQL_input* sql = (SQL_input*) info;
+        *sql->view = yyvsp[0].query;
+    ;}
+    break;
+
+  case 5:
+#line 158 "./sql.y"
+    {
+        SQL_input* sql = (SQL_input*) info;
+        *sql->view = yyvsp[0].query;
+    ;}
+    break;
+
+  case 6:
+#line 166 "./sql.y"
+    {
+        SQL_input *sql = (SQL_input*) info;
+        MSIVIEW *insert = NULL; 
+
+        INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE ); 
+        yyval.query = insert;
+    ;}
+    break;
+
+  case 7:
+#line 174 "./sql.y"
+    {
+        SQL_input *sql = (SQL_input*) info;
+        MSIVIEW *insert = NULL; 
+
+        INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE ); 
+        yyval.query = insert;
+    ;}
+    break;
+
+  case 8:
+#line 185 "./sql.y"
+    {
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *create = NULL; 
+
+            if( !yyvsp[-1].column_info )
+                YYABORT;
+            CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE );
+            yyval.query = create;
+        ;}
+    break;
+
+  case 9:
+#line 195 "./sql.y"
+    {
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *create = NULL; 
+
+            if( !yyvsp[-2].column_info )
+                YYABORT;
+            CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE );
+            yyval.query = create;
+        ;}
+    break;
+
+  case 10:
+#line 208 "./sql.y"
+    {
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *update = NULL; 
+
+            UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr );
+            yyval.query = update;
+        ;}
+    break;
+
+  case 11:
+#line 219 "./sql.y"
+    {
+            if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) )
+                yyval.column_info = yyvsp[-3].column_info;
+            else
+                yyval.column_info = NULL;
+        ;}
+    break;
+
+  case 12:
+#line 229 "./sql.y"
+    {
+            create_col_info *ci;
+
+            for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next )
+                ;
+
+            ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info );
+            if( !ci->next )
+            {
+                /* FIXME: free $1 */
+                YYABORT;
+            }
+            ci->next->colname = yyvsp[-1].string;
+            ci->next->type = yyvsp[0].column_type;
+            ci->next->next = NULL;
+
+            yyval.column_info = yyvsp[-3].column_info;
+        ;}
+    break;
+
+  case 13:
+#line 248 "./sql.y"
+    {
+            yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info );
+            if( ! yyval.column_info )
+                YYABORT;
+            yyval.column_info->colname = yyvsp[-1].string;
+            yyval.column_info->type = yyvsp[0].column_type;
+            yyval.column_info->next = NULL;
+        ;}
+    break;
+
+  case 14:
+#line 260 "./sql.y"
+    {
+            yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID;
+        ;}
+    break;
+
+  case 15:
+#line 264 "./sql.y"
+    {
+            FIXME("LOCALIZABLE ignored\n");
+            yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID;
+        ;}
+    break;
+
+  case 16:
+#line 272 "./sql.y"
+    {
+            yyval.column_type |= MSITYPE_NULLABLE;
+        ;}
+    break;
+
+  case 17:
+#line 276 "./sql.y"
+    {
+            yyval.column_type = yyvsp[-2].column_type;
+        ;}
+    break;
+
+  case 18:
+#line 283 "./sql.y"
+    {
+            yyval.column_type = MSITYPE_STRING | 1;
+        ;}
+    break;
+
+  case 19:
+#line 287 "./sql.y"
+    {
+            yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type;
+        ;}
+    break;
+
+  case 20:
+#line 291 "./sql.y"
+    {
+            yyval.column_type = 2;
+        ;}
+    break;
+
+  case 21:
+#line 295 "./sql.y"
+    {
+            yyval.column_type = 2;
+        ;}
+    break;
+
+  case 22:
+#line 299 "./sql.y"
+    {
+            yyval.column_type = 2;
+        ;}
+    break;
+
+  case 23:
+#line 303 "./sql.y"
+    {
+            yyval.column_type = 4;
+        ;}
+    break;
+
+  case 24:
+#line 307 "./sql.y"
+    {
+            yyval.column_type = 0;
+        ;}
+    break;
+
+  case 25:
+#line 314 "./sql.y"
+    {
+            SQL_input* sql = (SQL_input*) info;
+            int val = SQL_getint(sql);
+            if( ( val > 255 ) || ( val < 0 ) )
+                YYABORT;
+            yyval.column_type = val;
+        ;}
+    break;
+
+  case 26:
+#line 325 "./sql.y"
+    {
+            SQL_input* sql = (SQL_input*) info;
+
+            if( !yyvsp[-3].query )
+                YYABORT;
+            if( yyvsp[0].column_list )
+                yyval.query = do_order_by( sql->db, yyvsp[-3].query, yyvsp[0].column_list );
+            else
+                yyval.query = yyvsp[-3].query;
+        ;}
+    break;
+
+  case 28:
+#line 340 "./sql.y"
+    {
+            SQL_input* sql = (SQL_input*) info;
+            if( !yyvsp[0].query )
+                YYABORT;
+            if( yyvsp[-1].column_list )
+            {
+                yyval.query = do_one_select( sql->db, yyvsp[0].query, yyvsp[-1].column_list );
+                if( !yyval.query )
+                    YYABORT;
+            }
+            else
+                yyval.query = yyvsp[0].query;
+        ;}
+    break;
+
+  case 29:
+#line 354 "./sql.y"
+    {
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *view = yyvsp[0].query;
+
+            if( !view )
+                YYABORT;
+            if( yyvsp[-1].column_list )
+            {
+                view = do_one_select( sql->db, view, yyvsp[-1].column_list );
+                if( !view )
+                    YYABORT;
+            }
+            DISTINCT_CreateView( sql->db, & yyval.query, view );
+        ;}
+    break;
+
+  case 30:
+#line 372 "./sql.y"
+    { 
+            string_list *list;
+
+            list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
+            if( !list )
+                YYABORT;
+            list->string = yyvsp[0].string;
+            list->next = NULL;
+
+            yyval.column_list = list;
+            TRACE("Collist %s\n",debugstr_w(yyval.column_list->string));
+        ;}
+    break;
+
+  case 31:
+#line 385 "./sql.y"
+    { 
+            string_list *list;
+
+            list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
+            if( !list )
+                YYABORT;
+            list->string = yyvsp[-2].string;
+            list->next = yyvsp[0].column_list;
+
+            yyval.column_list = list;
+            TRACE("From table: %s\n",debugstr_w(yyval.column_list->string));
+        ;}
+    break;
+
+  case 32:
+#line 398 "./sql.y"
+    {
+            yyval.column_list = NULL;
+        ;}
+    break;
+
+  case 33:
+#line 405 "./sql.y"
+    { 
+            SQL_input* sql = (SQL_input*) info;
+            UINT r;
+
+            yyval.query = NULL;
+            TRACE("From table: %s\n",debugstr_w(yyvsp[0].string));
+            r = TABLE_CreateView( sql->db, yyvsp[0].string, & yyval.query );
+            if( r != ERROR_SUCCESS )
+                YYABORT;
+        ;}
+    break;
+
+  case 34:
+#line 416 "./sql.y"
+    { 
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *view = NULL;
+            UINT r;
+
+            yyval.query = NULL;
+            TRACE("From table: %s\n",debugstr_w(yyvsp[-2].string));
+            r = TABLE_CreateView( sql->db, yyvsp[-2].string, &view );
+            if( r != ERROR_SUCCESS )
+                YYABORT;
+            r = WHERE_CreateView( sql->db, &view, view, yyvsp[0].expr );
+            if( r != ERROR_SUCCESS )
+                YYABORT;
+            yyval.query = view;
+        ;}
+    break;
+
+  case 35:
+#line 435 "./sql.y"
+    {
+            yyval.expr = yyvsp[-1].expr;
+        ;}
+    break;
+
+  case 36:
+#line 439 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr );
+        ;}
+    break;
+
+  case 37:
+#line 443 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_AND, yyvsp[0].expr );
+        ;}
+    break;
+
+  case 38:
+#line 447 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_OR, yyvsp[0].expr );
+        ;}
+    break;
+
+  case 39:
+#line 451 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr );
+        ;}
+    break;
+
+  case 40:
+#line 455 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GT, yyvsp[0].expr );
+        ;}
+    break;
+
+  case 41:
+#line 459 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LT, yyvsp[0].expr );
+        ;}
+    break;
+
+  case 42:
+#line 463 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LE, yyvsp[0].expr );
+        ;}
+    break;
+
+  case 43:
+#line 467 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GE, yyvsp[0].expr );
+        ;}
+    break;
+
+  case 44:
+#line 471 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_NE, yyvsp[0].expr );
+        ;}
+    break;
+
+  case 45:
+#line 475 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_ISNULL, NULL );
+        ;}
+    break;
+
+  case 46:
+#line 479 "./sql.y"
+    {
+            yyval.expr = EXPR_complex( yyvsp[-3].expr, OP_NOTNULL, NULL );
+        ;}
+    break;
+
+  case 49:
+#line 491 "./sql.y"
+    {
+            value_list *vals;
+
+            vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
+            if( vals )
+            {
+                vals->val = yyvsp[0].expr;
+                vals->next = NULL;
+            }
+            yyval.val_list = vals;
+        ;}
+    break;
+
+  case 50:
+#line 503 "./sql.y"
+    {
+            value_list *vals;
+
+            vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
+            if( vals )
+            {
+                vals->val = yyvsp[0].expr;
+                vals->next = NULL;
+            }
+            yyvsp[-2].val_list->next = vals;
+            yyval.val_list = yyvsp[-2].val_list;
+        ;}
+    break;
+
+  case 52:
+#line 520 "./sql.y"
+    {
+            yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list;
+            yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list;
+            yyval.update_col_info = yyvsp[-2].update_col_info;
+        ;}
+    break;
+
+  case 53:
+#line 529 "./sql.y"
+    {
+            yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list );
+            if( !yyval.update_col_info.col_list )
+                YYABORT;
+            yyval.update_col_info.col_list->string = yyvsp[-2].string;
+            yyval.update_col_info.col_list->next = NULL;
+            yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list );
+            if( !yyval.update_col_info.val_list )
+                YYABORT;
+            yyval.update_col_info.val_list->val = yyvsp[0].expr;
+            yyval.update_col_info.val_list->next = 0;
+        ;}
+    break;
+
+  case 54:
+#line 545 "./sql.y"
+    {
+            yyval.expr = EXPR_ival( &yyvsp[0].str, 1 );
+        ;}
+    break;
+
+  case 55:
+#line 549 "./sql.y"
+    {
+            yyval.expr = EXPR_ival( &yyvsp[0].str, -1 );
+        ;}
+    break;
+
+  case 56:
+#line 553 "./sql.y"
+    {
+            yyval.expr = EXPR_sval( &yyvsp[0].str );
+        ;}
+    break;
+
+  case 57:
+#line 557 "./sql.y"
+    {
+            yyval.expr = EXPR_wildcard();
+        ;}
+    break;
+
+  case 58:
+#line 564 "./sql.y"
+    {
+            yyval.expr = EXPR_column( yyvsp[0].string );
+        ;}
+    break;
+
+  case 59:
+#line 571 "./sql.y"
+    {
+            yyval.string = yyvsp[0].string;  /* FIXME */
+        ;}
+    break;
+
+  case 60:
+#line 575 "./sql.y"
+    {
+            yyval.string = yyvsp[0].string;
+        ;}
+    break;
+
+  case 61:
+#line 582 "./sql.y"
+    {
+            yyval.string = yyvsp[0].string;
+        ;}
+    break;
+
+  case 62:
+#line 589 "./sql.y"
+    {
+            yyval.string = SQL_getstring( &yyvsp[0].str );
+        ;}
+    break;
+
+  case 63:
+#line 593 "./sql.y"
+    {
+            yyval.string = SQL_getstring( &yyvsp[0].str );
+        ;}
+    break;
+
+
+    }
+
+/* Line 999 of yacc.c.  */
+#line 2055 "sql.tab.c"
+\f
+  yyvsp -= yylen;
+  yyssp -= yylen;
+
+
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (YYPACT_NINF < yyn && yyn < YYLAST)
+       {
+         YYSIZE_T yysize = 0;
+         int yytype = YYTRANSLATE (yychar);
+         const char* yyprefix;
+         char *yymsg;
+         int yyx;
+
+         /* Start YYX at -YYN if negative to avoid negative indexes in
+            YYCHECK.  */
+         int yyxbegin = yyn < 0 ? -yyn : 0;
+
+         /* Stay within bounds of both yycheck and yytname.  */
+         int yychecklim = YYLAST - yyn;
+         int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+         int yycount = 0;
+
+         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)
+                 {
+                   yysize = 0;
+                   break;
+                 }
+             }
+         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)
+               {
+                 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 ";
+                     }
+               }
+             yyerror (yymsg);
+             YYSTACK_FREE (yymsg);
+           }
+         else
+           yyerror ("syntax error; also virtual memory exhausted");
+       }
+      else
+#endif /* YYERROR_VERBOSE */
+       yyerror ("syntax error");
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+        error, discard it.  */
+
+      /* Return failure if at end of input.  */
+      if (yychar == YYEOF)
+        {
+         /* Pop the error token.  */
+          YYPOPSTACK;
+         /* Pop the rest of the stack.  */
+         while (yyss < yyssp)
+           {
+             YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+             yydestruct (yystos[*yyssp], yyvsp);
+             YYPOPSTACK;
+           }
+         YYABORT;
+        }
+
+      YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+      yydestruct (yytoken, &yylval);
+      yychar = YYEMPTY;
+
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action.  |
+`----------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;     /* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+       {
+         yyn += YYTERROR;
+         if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+           {
+             yyn = yytable[yyn];
+             if (0 < yyn)
+               break;
+           }
+       }
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+       YYABORT;
+
+      YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+      yydestruct (yystos[yystate], yyvsp);
+      yyvsp--;
+      yystate = *--yyssp;
+
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  YYDPRINTF ((stderr, "Shifting error token, "));
+
+  *++yyvsp = yylval;
+
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here.  |
+`----------------------------------------------*/
+yyoverflowlab:
+  yyerror ("parser stack overflow");
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+  return yyresult;
+}
+
+
+#line 598 "./sql.y"
+
+
+int SQL_lex( void *SQL_lval, SQL_input *sql)
+{
+    int token;
+    struct sql_str * str = SQL_lval;
+
+    do
+    {
+        sql->n += sql->len;
+        if( ! sql->command[sql->n] )
+            return 0;  /* end of input */
+
+        TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
+        sql->len = sqliteGetToken( &sql->command[sql->n], &token );
+        if( sql->len==0 )
+            break;
+        str->data = &sql->command[sql->n];
+        str->len = sql->len;
+    }
+    while( token == TK_SPACE );
+
+    TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
+    
+    return token;
+}
+
+LPWSTR SQL_getstring( struct sql_str *strdata)
+{
+    LPCWSTR p = strdata->data;
+    UINT len = strdata->len;
+    LPWSTR str;
+
+    /* if there's quotes, remove them */
+    if( ( (p[0]=='`') && (p[len-1]=='`') ) || 
+        ( (p[0]=='\'') && (p[len-1]=='\'') ) )
+    {
+        p++;
+        len -= 2;
+    }
+    str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
+    if(!str )
+        return str;
+    memcpy(str, p, len*sizeof(WCHAR) );
+    str[len]=0;
+
+    return str;
+}
+
+INT SQL_getint( SQL_input *sql )
+{
+    LPCWSTR p = &sql->command[sql->n];
+
+    return atoiW( p );
+}
+
+int SQL_error(const char *str)
+{
+    return 0;
+}
+
+static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, 
+                               string_list *columns )
+{
+    MSIVIEW *view = NULL;
+
+    SELECT_CreateView( db, &view, in, columns );
+    delete_string_list( columns );
+    if( !view )
+        ERR("Error creating select query\n");
+    return view;
+}
+
+static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, 
+                             string_list *columns )
+{
+    MSIVIEW *view = NULL;
+
+    ORDER_CreateView( db, &view, in );
+    if( view )
+    {
+        string_list *x = columns;
+
+        for( x = columns; x ; x = x->next )
+            ORDER_AddColumn( view, x->string );
+    }
+    else
+        ERR("Error creating select query\n");
+    delete_string_list( columns );
+    return view;
+}
+
+static struct expr * EXPR_wildcard()
+{
+    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+    if( e )
+    {
+        e->type = EXPR_WILDCARD;
+    }
+    return e;
+}
+
+static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
+{
+    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+    if( e )
+    {
+        e->type = EXPR_COMPLEX;
+        e->u.expr.left = l;
+        e->u.expr.op = op;
+        e->u.expr.right = r;
+    }
+    return e;
+}
+
+static struct expr * EXPR_column( LPWSTR str )
+{
+    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+    if( e )
+    {
+        e->type = EXPR_COLUMN;
+        e->u.sval = str;
+    }
+    return e;
+}
+
+static struct expr * EXPR_ival( struct sql_str *str , int sign)
+{
+    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+    if( e )
+    {
+        e->type = EXPR_IVAL;
+        e->u.ival = atoiW( str->data ) * sign;
+    }
+    return e;
+}
+
+static struct expr * EXPR_sval( struct sql_str *str )
+{
+    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+    if( e )
+    {
+        e->type = EXPR_SVAL;
+        e->u.sval = SQL_getstring( str );
+    }
+    return e;
+}
+
+void delete_expr( struct expr *e )
+{
+    if( !e )
+        return;
+    if( e->type == EXPR_COMPLEX )
+    {
+        delete_expr( e->u.expr.left );
+        delete_expr( e->u.expr.right );
+    }
+    else if( e->type == EXPR_UTF8 )
+        HeapFree( GetProcessHeap(), 0, e->u.utf8 );
+    else if( e->type == EXPR_SVAL )
+        HeapFree( GetProcessHeap(), 0, e->u.sval );
+    HeapFree( GetProcessHeap(), 0, e );
+}
+
+void delete_string_list( string_list *sl )
+{
+    while( sl )
+    {
+        string_list *t = sl->next;
+        HeapFree( GetProcessHeap(), 0, sl->string );
+        HeapFree( GetProcessHeap(), 0, sl );
+        sl = t;
+    }
+}
+
+void delete_value_list( value_list *vl )
+{
+    while( vl )
+    {
+        value_list *t = vl->next;
+        delete_expr( vl->val );
+        HeapFree( GetProcessHeap(), 0, vl );
+        vl = t;
+    }
+}
+
+static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
+                                 string_list *keys )
+{
+    string_list *k;
+    BOOL found = TRUE;
+
+    for( k = keys; k && found; k = k->next )
+    {
+        create_col_info *c;
+
+        found = FALSE;
+        for( c = cols; c && !found; c = c->next )
+        {
+             if( lstrcmpW( k->string, c->colname ) )
+                 continue;
+             c->type |= MSITYPE_KEY;
+             found = TRUE;
+        }
+    }
+
+    return found;
+}
+
+UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
+{
+    SQL_input sql;
+    int r;
+
+    *phview = NULL;
+
+    sql.db = db;
+    sql.command = command;
+    sql.n = 0;
+    sql.len = 0;
+    sql.view = phview;
+
+    r = SQL_parse(&sql);
+
+    TRACE("Parse returned %d\n", r);
+    if( r )
+    {
+        if( *sql.view )
+            (*sql.view)->ops->delete( *sql.view );
+        *sql.view = NULL;
+        return ERROR_BAD_QUERY_SYNTAX;
+    }
+
+    return ERROR_SUCCESS;
+}
+
index 62fdccd..bfc66b3 100644 (file)
-#ifndef BISON_SQL_TAB_H\r
-# define BISON_SQL_TAB_H\r
-\r
-#ifndef YYSTYPE\r
-typedef union\r
-{\r
-    struct sql_str str;\r
-    LPWSTR string;\r
-    string_list *column_list;\r
-    value_list *val_list;\r
-    MSIVIEW *query;\r
-    struct expr *expr;\r
-    USHORT column_type;\r
-    create_col_info *column_info;\r
-    column_assignment update_col_info;\r
-} yystype;\r
-# define YYSTYPE yystype\r
-# define YYSTYPE_IS_TRIVIAL 1\r
-#endif\r
-# define       TK_ABORT        257\r
-# define       TK_AFTER        258\r
-# define       TK_AGG_FUNCTION 259\r
-# define       TK_ALL  260\r
-# define       TK_AND  261\r
-# define       TK_AS   262\r
-# define       TK_ASC  263\r
-# define       TK_BEFORE       264\r
-# define       TK_BEGIN        265\r
-# define       TK_BETWEEN      266\r
-# define       TK_BITAND       267\r
-# define       TK_BITNOT       268\r
-# define       TK_BITOR        269\r
-# define       TK_BY   270\r
-# define       TK_CASCADE      271\r
-# define       TK_CASE 272\r
-# define       TK_CHAR 273\r
-# define       TK_CHECK        274\r
-# define       TK_CLUSTER      275\r
-# define       TK_COLLATE      276\r
-# define       TK_COLUMN       277\r
-# define       TK_COMMA        278\r
-# define       TK_COMMENT      279\r
-# define       TK_COMMIT       280\r
-# define       TK_CONCAT       281\r
-# define       TK_CONFLICT     282\r
-# define       TK_CONSTRAINT   283\r
-# define       TK_COPY 284\r
-# define       TK_CREATE       285\r
-# define       TK_DEFAULT      286\r
-# define       TK_DEFERRABLE   287\r
-# define       TK_DEFERRED     288\r
-# define       TK_DELETE       289\r
-# define       TK_DELIMITERS   290\r
-# define       TK_DESC 291\r
-# define       TK_DISTINCT     292\r
-# define       TK_DOT  293\r
-# define       TK_DROP 294\r
-# define       TK_EACH 295\r
-# define       TK_ELSE 296\r
-# define       TK_END  297\r
-# define       TK_END_OF_FILE  298\r
-# define       TK_EQ   299\r
-# define       TK_EXCEPT       300\r
-# define       TK_EXPLAIN      301\r
-# define       TK_FAIL 302\r
-# define       TK_FLOAT        303\r
-# define       TK_FOR  304\r
-# define       TK_FOREIGN      305\r
-# define       TK_FROM 306\r
-# define       TK_FUNCTION     307\r
-# define       TK_GE   308\r
-# define       TK_GLOB 309\r
-# define       TK_GROUP        310\r
-# define       TK_GT   311\r
-# define       TK_HAVING       312\r
-# define       TK_HOLD 313\r
-# define       TK_IGNORE       314\r
-# define       TK_ILLEGAL      315\r
-# define       TK_IMMEDIATE    316\r
-# define       TK_IN   317\r
-# define       TK_INDEX        318\r
-# define       TK_INITIALLY    319\r
-# define       TK_ID   320\r
-# define       TK_INSERT       321\r
-# define       TK_INSTEAD      322\r
-# define       TK_INT  323\r
-# define       TK_INTEGER      324\r
-# define       TK_INTERSECT    325\r
-# define       TK_INTO 326\r
-# define       TK_IS   327\r
-# define       TK_ISNULL       328\r
-# define       TK_JOIN 329\r
-# define       TK_JOIN_KW      330\r
-# define       TK_KEY  331\r
-# define       TK_LE   332\r
-# define       TK_LIKE 333\r
-# define       TK_LIMIT        334\r
-# define       TK_LONG 335\r
-# define       TK_LONGCHAR     336\r
-# define       TK_LP   337\r
-# define       TK_LSHIFT       338\r
-# define       TK_LT   339\r
-# define       TK_LOCALIZABLE  340\r
-# define       TK_MATCH        341\r
-# define       TK_MINUS        342\r
-# define       TK_NE   343\r
-# define       TK_NOT  344\r
-# define       TK_NOTNULL      345\r
-# define       TK_NULL 346\r
-# define       TK_OBJECT       347\r
-# define       TK_OF   348\r
-# define       TK_OFFSET       349\r
-# define       TK_ON   350\r
-# define       TK_OR   351\r
-# define       TK_ORACLE_OUTER_JOIN    352\r
-# define       TK_ORDER        353\r
-# define       TK_PLUS 354\r
-# define       TK_PRAGMA       355\r
-# define       TK_PRIMARY      356\r
-# define       TK_RAISE        357\r
-# define       TK_REFERENCES   358\r
-# define       TK_REM  359\r
-# define       TK_REPLACE      360\r
-# define       TK_RESTRICT     361\r
-# define       TK_ROLLBACK     362\r
-# define       TK_ROW  363\r
-# define       TK_RP   364\r
-# define       TK_RSHIFT       365\r
-# define       TK_SELECT       366\r
-# define       TK_SEMI 367\r
-# define       TK_SET  368\r
-# define       TK_SHORT        369\r
-# define       TK_SLASH        370\r
-# define       TK_SPACE        371\r
-# define       TK_STAR 372\r
-# define       TK_STATEMENT    373\r
-# define       TK_STRING       374\r
-# define       TK_TABLE        375\r
-# define       TK_TEMP 376\r
-# define       TK_THEN 377\r
-# define       TK_TRANSACTION  378\r
-# define       TK_TRIGGER      379\r
-# define       TK_UMINUS       380\r
-# define       TK_UNCLOSED_STRING      381\r
-# define       TK_UNION        382\r
-# define       TK_UNIQUE       383\r
-# define       TK_UPDATE       384\r
-# define       TK_UPLUS        385\r
-# define       TK_USING        386\r
-# define       TK_VACUUM       387\r
-# define       TK_VALUES       388\r
-# define       TK_VIEW 389\r
-# define       TK_WHEN 390\r
-# define       TK_WHERE        391\r
-# define       TK_WILDCARD     392\r
-# define       END_OF_FILE     393\r
-# define       ILLEGAL 394\r
-# define       SPACE   395\r
-# define       UNCLOSED_STRING 396\r
-# define       COMMENT 397\r
-# define       FUNCTION        398\r
-# define       COLUMN  399\r
-\r
-\r
-#endif /* not BISON_SQL_TAB_H */\r
+/* A Bison parser, made by GNU Bison 1.875b.  */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 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
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* 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
+   };
+#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
+
+
+
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 74 "./sql.y"
+typedef union YYSTYPE {
+    struct sql_str str;
+    LPWSTR string;
+    string_list *column_list;
+    value_list *val_list;
+    MSIVIEW *query;
+    struct expr *expr;
+    USHORT column_type;
+    create_col_info *column_info;
+    column_assignment update_col_info;
+} YYSTYPE;
+/* Line 1252 of yacc.c.  */
+#line 339 "sql.tab.h"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+
+
index 709e78e..4f05a6a 100644 (file)
@@ -62,7 +62,7 @@ static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
 \r
 static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );\r
 static struct expr * EXPR_column( LPWSTR );\r
-static struct expr * EXPR_ival( struct sql_str *);\r
+static struct expr * EXPR_ival( struct sql_str *, int sign);\r
 static struct expr * EXPR_sval( struct sql_str *);\r
 static struct expr * EXPR_wildcard(void);\r
 \r
@@ -543,7 +543,11 @@ column_assignment:
 const_val:\r
     TK_INTEGER\r
         {\r
-            $$ = EXPR_ival( &$1 );\r
+            $$ = EXPR_ival( &$1, 1 );\r
+        }\r
+  | TK_MINUS  TK_INTEGER\r
+        {\r
+            $$ = EXPR_ival( &$2, -1 );\r
         }\r
   | TK_STRING\r
         {\r
@@ -717,13 +721,13 @@ static struct expr * EXPR_column( LPWSTR str )
     return e;\r
 }\r
 \r
-static struct expr * EXPR_ival( struct sql_str *str )\r
+static struct expr * EXPR_ival( struct sql_str *str , int sign)\r
 {\r
     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );\r
     if( e )\r
     {\r
         e->type = EXPR_IVAL;\r
-        e->u.ival = atoiW( str->data );\r
+        e->u.ival = atoiW( str->data ) * sign;\r
     }\r
     return e;\r
 }\r
index 7f097e9..52a5f01 100644 (file)
@@ -1088,7 +1088,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
         return ERROR_FUNCTION_FAILED;\r
     }\r
 \r
-    TRACE("Data [%d][%d] = %d \n", row, col, *val );\r
+    /* TRACE("Data [%d][%d] = %d \n", row, col, *val ); */\r
 \r
     return ERROR_SUCCESS;\r
 }\r
index 8500dee..9ae2048 100644 (file)
@@ -137,7 +137,7 @@ static const WCHAR *STRING_evaluate( string_table *st,
 \r
     switch( expr->type )\r
     {\r
-    case EXPR_COL_NUMBER:\r
+    case EXPR_COL_NUMBER_STRING:\r
         r = table->ops->fetch_int( table, row, expr->u.col_number, &val );\r
         if( r != ERROR_SUCCESS )\r
             return NULL;\r
@@ -190,6 +190,7 @@ static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row,
 \r
     switch( cond->type )\r
     {\r
+    case EXPR_COL_NUMBER_STRING:\r
     case EXPR_COL_NUMBER:\r
         return table->ops->fetch_int( table, row, cond->u.col_number, val );\r
 \r
@@ -368,9 +369,19 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr
         r = VIEW_find_column( table, cond->u.column, &val );\r
         if( r == ERROR_SUCCESS )\r
         {\r
-            *valid = 1;\r
-            cond->type = EXPR_COL_NUMBER;\r
-            cond->u.col_number = val;\r
+            UINT type = 0;\r
+            r = table->ops->get_column_info( table, val, NULL, &type );\r
+            if( r == ERROR_SUCCESS )\r
+            {\r
+                if (type&MSITYPE_STRING)\r
+                    cond->type = EXPR_COL_NUMBER_STRING;\r
+                else\r
+                    cond->type = EXPR_COL_NUMBER;\r
+                cond->u.col_number = val;\r
+                *valid = 1;\r
+            }\r
+            else\r
+                *valid = 0;\r
         }\r
         else\r
         {\r
@@ -390,7 +401,9 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr
 \r
         /* check the type of the comparison */\r
         if( ( cond->u.expr.left->type == EXPR_SVAL ) ||\r
-            ( cond->u.expr.right->type == EXPR_SVAL ) )\r
+            ( cond->u.expr.left->type == EXPR_COL_NUMBER_STRING ) ||\r
+            ( cond->u.expr.right->type == EXPR_SVAL ) ||\r
+            ( cond->u.expr.right->type == EXPR_COL_NUMBER_STRING ) )\r
         {\r
             switch( cond->u.expr.op )\r
             {\r