sync msi with wine 1.1.35
authorChristoph von Wittich <christoph_vw@reactos.org>
Tue, 22 Dec 2009 09:28:03 +0000 (09:28 +0000)
committerChristoph von Wittich <christoph_vw@reactos.org>
Tue, 22 Dec 2009 09:28:03 +0000 (09:28 +0000)
svn path=/trunk/; revision=44693

23 files changed:
reactos/dll/win32/msi/action.c
reactos/dll/win32/msi/alter.c
reactos/dll/win32/msi/appsearch.c
reactos/dll/win32/msi/automation.c
reactos/dll/win32/msi/database.c
reactos/dll/win32/msi/drop.c
reactos/dll/win32/msi/files.c
reactos/dll/win32/msi/join.c
reactos/dll/win32/msi/media.c
reactos/dll/win32/msi/msi.c
reactos/dll/win32/msi/msipriv.h
reactos/dll/win32/msi/msiserver.idl
reactos/dll/win32/msi/msiserver_dispids.h
reactos/dll/win32/msi/package.c
reactos/dll/win32/msi/record.c
reactos/dll/win32/msi/sql.tab.c
reactos/dll/win32/msi/sql.tab.h
reactos/dll/win32/msi/sql.y
reactos/dll/win32/msi/storages.c
reactos/dll/win32/msi/streams.c
reactos/dll/win32/msi/string.c
reactos/dll/win32/msi/table.c
reactos/dll/win32/msi/where.c

index 0755f42..7904770 100644 (file)
@@ -5008,12 +5008,30 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
         FIXME("Not removing environment variable on uninstall!\n");
 
     size = 0;
+    type = REG_SZ;
     res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
     if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
         (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
         goto done;
 
-    if (res != ERROR_FILE_NOT_FOUND)
+    if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
+    {
+        /* Nothing to do. */
+        if (!value)
+        {
+            res = ERROR_SUCCESS;
+            goto done;
+        }
+
+        size = (lstrlenW(value) + 1) * sizeof(WCHAR);
+        newval = strdupW(value);
+        if (!newval)
+        {
+            res = ERROR_OUTOFMEMORY;
+            goto done;
+        }
+    }
+    else
     {
         if (flags & ENV_ACT_SETABSENT)
         {
@@ -5038,8 +5056,18 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
             goto done;
         }
 
-        size += (lstrlenW(value) + 1) * sizeof(WCHAR);
-        newval =  msi_alloc(size);
+        size = (lstrlenW(data) + 1) * sizeof(WCHAR);
+        if (flags & ENV_MOD_MASK)
+        {
+            DWORD mod_size;
+            int multiplier = 0;
+            if (flags & ENV_MOD_APPEND) multiplier++;
+            if (flags & ENV_MOD_PREFIX) multiplier++;
+            mod_size = (lstrlenW(value) + 1) * multiplier;
+            size += mod_size * sizeof(WCHAR);
+        }
+
+        newval = msi_alloc(size);
         ptr = newval;
         if (!newval)
         {
@@ -5047,37 +5075,20 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
             goto done;
         }
 
-        if (!(flags & ENV_MOD_MASK))
-            lstrcpyW(newval, value);
-        else
+        if (flags & ENV_MOD_PREFIX)
         {
-            if (flags & ENV_MOD_PREFIX)
-            {
-                lstrcpyW(newval, value);
-                lstrcatW(newval, szSemiColon);
-                ptr = newval + lstrlenW(value) + 1;
-            }
+            lstrcpyW(newval, value);
+            lstrcatW(newval, szSemiColon);
+            ptr = newval + lstrlenW(value) + 1;
+        }
 
-            lstrcpyW(ptr, data);
+        lstrcpyW(ptr, data);
 
-            if (flags & ENV_MOD_APPEND)
-            {
-                lstrcatW(newval, szSemiColon);
-                lstrcatW(newval, value);
-            }
-        }
-    }
-    else if (value)
-    {
-        size = (lstrlenW(value) + 1) * sizeof(WCHAR);
-        newval = msi_alloc(size);
-        if (!newval)
+        if (flags & ENV_MOD_APPEND)
         {
-            res = ERROR_OUTOFMEMORY;
-            goto done;
+            lstrcatW(newval, szSemiColon);
+            lstrcatW(newval, value);
         }
-
-        lstrcpyW(newval, value);
     }
 
     if (newval)
@@ -5288,6 +5299,11 @@ static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
         goto done;
     }
 
+    /* file->dest may be shorter after the reallocation, so add a NULL
+     * terminator.  This is needed for the call to strrchrW, as there will no
+     * longer be a NULL terminator within the bounds of the allocation in this case.
+     */
+    file->dest[size - 1] = '\0';
     lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
 
     while (!list_empty(&files.entry))
index a62b13e..93d322b 100644 (file)
@@ -125,7 +125,10 @@ static UINT alter_add_column(MSIALTERVIEW *av)
         return r;
 
     if (check_column_exists(av->db, av->colinfo->table, av->colinfo->column))
+    {
+        columns->ops->delete(columns);
         return ERROR_BAD_QUERY_SYNTAX;
+    }
 
     r = MSI_OpenQuery(av->db, &view, query, av->colinfo->table, av->colinfo->column);
     if (r == ERROR_SUCCESS)
index 95daabb..b99b4f5 100644 (file)
@@ -739,6 +739,7 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue,
     size_t dirLen = lstrlenW(dir), fileLen = lstrlenW(sig->File);
     WCHAR subpath[MAX_PATH];
     WCHAR *buf;
+    DWORD len;
 
     static const WCHAR starDotStarW[] = { '*','.','*',0 };
 
@@ -753,7 +754,8 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue,
      * here.  Add two because we might need to add a backslash if the dir name
      * isn't backslash-terminated.
      */
-    buf = msi_alloc( (dirLen + max(fileLen, strlenW(starDotStarW)) + 2) * sizeof(WCHAR));
+    len = dirLen + max(fileLen, strlenW(starDotStarW)) + 2;
+    buf = msi_alloc(len * sizeof(WCHAR));
     if (!buf)
         return ERROR_OUTOFMEMORY;
 
@@ -815,7 +817,7 @@ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue,
         }
     }
 
-    if (!*appValue)
+    if (*appValue != buf)
         msi_free(buf);
 
     return rc;
index 3b6dd2d..5305f9c 100644 (file)
@@ -1534,6 +1534,760 @@ static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYT
     }
 }
 
+static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
+                                          DISPPARAMS* pDispParams,
+                                          VARIANT* pVarResult,
+                                          EXCEPINFO* pExcepInfo,
+                                          UINT* puArgErr)
+{
+    HRESULT hr;
+    VARIANTARG varg0;
+    MSIHANDLE hrec;
+    IDispatch* dispatch;
+
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    VariantInit(&varg0);
+    hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+    if (FAILED(hr))
+        return hr;
+
+    V_VT(pVarResult) = VT_DISPATCH;
+
+    hrec = MsiCreateRecord(V_I4(&varg0));
+    if (!hrec)
+        return DISP_E_EXCEPTION;
+
+    hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
+                                  &DIID_Record, RecordImpl_Invoke, NULL, 0);
+    if (SUCCEEDED(hr))
+        V_DISPATCH(pVarResult) = dispatch;
+
+    return hr;
+}
+
+static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
+                                         WORD wFlags,
+                                         DISPPARAMS* pDispParams,
+                                         VARIANT* pVarResult,
+                                         EXCEPINFO* pExcepInfo,
+                                         UINT* puArgErr)
+{
+    UINT ret;
+    HRESULT hr;
+    MSIHANDLE hpkg;
+    IDispatch* dispatch;
+    VARIANTARG varg0, varg1;
+
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    if (pDispParams->cArgs == 0)
+        return DISP_E_TYPEMISMATCH;
+
+    if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
+        return DISP_E_TYPEMISMATCH;
+
+    VariantInit(&varg0);
+    hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+    if (FAILED(hr))
+        return hr;
+
+    VariantInit(&varg1);
+    if (pDispParams->cArgs == 2)
+    {
+        hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
+        if (FAILED(hr))
+            goto done;
+    }
+    else
+    {
+        V_VT(&varg1) = VT_I4;
+        V_I4(&varg1) = 0;
+    }
+
+    V_VT(pVarResult) = VT_DISPATCH;
+
+    ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
+    if (ret != ERROR_SUCCESS)
+    {
+        hr = DISP_E_EXCEPTION;
+        goto done;
+    }
+
+    hr = create_session(hpkg, (IDispatch *)This, &dispatch);
+    if (SUCCEEDED(hr))
+        V_DISPATCH(pVarResult) = dispatch;
+
+done:
+    VariantClear(&varg0);
+    VariantClear(&varg1);
+    return hr;
+}
+
+static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
+                                         DISPPARAMS* pDispParams,
+                                         VARIANT* pVarResult,
+                                         EXCEPINFO* pExcepInfo,
+                                         UINT* puArgErr)
+{
+    HRESULT hr;
+    VARIANTARG varg0;
+
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    VariantInit(&varg0);
+    hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+    if (FAILED(hr))
+        return hr;
+
+    FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
+
+    VariantInit(pVarResult);
+
+    VariantClear(&varg0);
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
+                                          DISPPARAMS* pDispParams,
+                                          VARIANT* pVarResult,
+                                          EXCEPINFO* pExcepInfo,
+                                          UINT* puArgErr)
+{
+    UINT ret;
+    HRESULT hr;
+    MSIHANDLE hdb;
+    IDispatch* dispatch;
+    VARIANTARG varg0, varg1;
+
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    VariantInit(&varg0);
+    hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+    if (FAILED(hr))
+        return hr;
+
+    VariantInit(&varg1);
+    hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+    if (FAILED(hr))
+        goto done;
+
+    V_VT(pVarResult) = VT_DISPATCH;
+
+    ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
+    if (ret != ERROR_SUCCESS)
+    {
+        hr = DISP_E_EXCEPTION;
+        goto done;
+    }
+
+    hr = create_automation_object(hdb, NULL, (LPVOID *)&dispatch,
+                                  &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
+    if (SUCCEEDED(hr))
+        V_DISPATCH(pVarResult) = dispatch;
+
+done:
+    VariantClear(&varg0);
+    VariantClear(&varg1);
+    return hr;
+}
+
+static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
+                                                DISPPARAMS* pDispParams,
+                                                VARIANT* pVarResult,
+                                                EXCEPINFO* pExcepInfo,
+                                                UINT* puArgErr)
+{
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    FIXME("\n");
+
+    VariantInit(pVarResult);
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_UILevel(WORD wFlags,
+                                     DISPPARAMS* pDispParams,
+                                     VARIANT* pVarResult,
+                                     EXCEPINFO* pExcepInfo,
+                                     UINT* puArgErr)
+{
+    HRESULT hr;
+    VARIANTARG varg0;
+    INSTALLUILEVEL ui;
+
+    if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
+        return DISP_E_MEMBERNOTFOUND;
+
+    if (wFlags & DISPATCH_PROPERTYPUT)
+    {
+        VariantInit(&varg0);
+        hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+        if (FAILED(hr))
+            return hr;
+
+        ui = MsiSetInternalUI(V_I4(&varg0), NULL);
+        if (ui == INSTALLUILEVEL_NOCHANGE)
+            return DISP_E_EXCEPTION;
+    }
+    else if (wFlags & DISPATCH_PROPERTYGET)
+    {
+        ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
+        if (ui == INSTALLUILEVEL_NOCHANGE)
+            return DISP_E_EXCEPTION;
+
+        V_VT(pVarResult) = VT_I4;
+        V_I4(pVarResult) = ui;
+    }
+
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_EnableLog(WORD wFlags,
+                                       DISPPARAMS* pDispParams,
+                                       VARIANT* pVarResult,
+                                       EXCEPINFO* pExcepInfo,
+                                       UINT* puArgErr)
+{
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    FIXME("\n");
+
+    VariantInit(pVarResult);
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
+                                            DISPPARAMS* pDispParams,
+                                            VARIANT* pVarResult,
+                                            EXCEPINFO* pExcepInfo,
+                                            UINT* puArgErr)
+{
+    UINT ret;
+    HRESULT hr;
+    VARIANTARG varg0, varg1;
+
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    VariantInit(&varg0);
+    hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+    if (FAILED(hr))
+        return hr;
+
+    VariantInit(&varg1);
+    hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+    if (FAILED(hr))
+        goto done;
+
+    ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
+    if (ret != ERROR_SUCCESS)
+    {
+        hr = DISP_E_EXCEPTION;
+        goto done;
+    }
+
+done:
+    VariantClear(&varg0);
+    VariantClear(&varg1);
+    return hr;
+}
+
+static HRESULT InstallerImpl_Version(WORD wFlags,
+                                     VARIANT* pVarResult,
+                                     EXCEPINFO* pExcepInfo,
+                                     UINT* puArgErr)
+{
+    HRESULT hr;
+    DLLVERSIONINFO verinfo;
+    WCHAR version[MAX_PATH];
+
+    static const WCHAR format[] = {
+        '%','d','.','%','d','.','%','d','.','%','d',0};
+
+    if (!(wFlags & DISPATCH_PROPERTYGET))
+        return DISP_E_MEMBERNOTFOUND;
+
+    verinfo.cbSize = sizeof(DLLVERSIONINFO);
+    hr = DllGetVersion(&verinfo);
+    if (FAILED(hr))
+        return hr;
+
+    sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
+             verinfo.dwBuildNumber, verinfo.dwPlatformID);
+
+    V_VT(pVarResult) = VT_BSTR;
+    V_BSTR(pVarResult) = SysAllocString(version);
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
+                                             DISPPARAMS* pDispParams,
+                                             VARIANT* pVarResult,
+                                             EXCEPINFO* pExcepInfo,
+                                             UINT* puArgErr)
+{
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    FIXME("\n");
+
+    VariantInit(pVarResult);
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
+                                           DISPPARAMS* pDispParams,
+                                           VARIANT* pVarResult,
+                                           EXCEPINFO* pExcepInfo,
+                                           UINT* puArgErr)
+{
+    UINT ret;
+    HKEY hkey = NULL;
+    HRESULT hr;
+    UINT posValue;
+    DWORD type, size;
+    LPWSTR szString = NULL;
+    VARIANTARG varg0, varg1, varg2;
+
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    VariantInit(&varg0);
+    hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+    if (FAILED(hr))
+        return hr;
+
+    VariantInit(&varg1);
+    hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+    if (FAILED(hr))
+        goto done;
+
+    /* Save valuePos so we can save puArgErr if we are unable to do our type
+     * conversions.
+     */
+    posValue = 2;
+    VariantInit(&varg2);
+    hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
+    if (FAILED(hr))
+        goto done;
+
+    if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
+        V_I4(&varg0) <= REG_INDEX_DYN_DATA)
+    {
+        V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
+    }
+
+    ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
+
+    /* Only VT_EMPTY case can do anything if the key doesn't exist. */
+    if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
+    {
+        hr = DISP_E_BADINDEX;
+        goto done;
+    }
+
+    /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
+    switch (V_VT(&varg2))
+    {
+        /* Return VT_BOOL clarifying whether registry key exists or not. */
+        case VT_EMPTY:
+            V_VT(pVarResult) = VT_BOOL;
+            V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
+            break;
+
+        /* Return the value of specified key if it exists. */
+        case VT_BSTR:
+            ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
+                                   NULL, NULL, NULL, &size);
+            if (ret != ERROR_SUCCESS)
+            {
+                hr = DISP_E_BADINDEX;
+                goto done;
+            }
+
+            szString = msi_alloc(size);
+            if (!szString)
+            {
+                hr = E_OUTOFMEMORY;
+                goto done;
+            }
+
+            ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
+                                   &type, (LPBYTE)szString, &size);
+            if (ret != ERROR_SUCCESS)
+            {
+                msi_free(szString);
+                hr = DISP_E_BADINDEX;
+                goto done;
+            }
+
+            variant_from_registry_value(pVarResult, type,
+                                        (LPBYTE)szString, size);
+            msi_free(szString);
+            break;
+
+        /* Try to make it into VT_I4, can use VariantChangeType for this. */
+        default:
+            hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
+            if (FAILED(hr))
+            {
+                if (hr == DISP_E_TYPEMISMATCH)
+                    *puArgErr = posValue;
+
+                goto done;
+            }
+
+            /* Retrieve class name or maximum value name or subkey name size. */
+            if (!V_I4(&varg2))
+                ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL, NULL);
+            else if (V_I4(&varg2) > 0)
+                ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
+                                       NULL, NULL, &size, NULL, NULL, NULL);
+            else /* V_I4(&varg2) < 0 */
+                ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
+                                       NULL, NULL, NULL, NULL, NULL, NULL);
+
+            if (ret != ERROR_SUCCESS)
+                goto done;
+
+            szString = msi_alloc(++size * sizeof(WCHAR));
+            if (!szString)
+            {
+                hr = E_OUTOFMEMORY;
+                goto done;
+            }
+
+            if (!V_I4(&varg2))
+                ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL, NULL);
+            else if (V_I4(&varg2) > 0)
+                ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
+                                    &size, 0, 0, NULL, NULL);
+            else /* V_I4(&varg2) < 0 */
+                ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
+
+            if (ret == ERROR_SUCCESS)
+            {
+                V_VT(pVarResult) = VT_BSTR;
+                V_BSTR(pVarResult) = SysAllocString(szString);
+            }
+
+            msi_free(szString);
+    }
+
+done:
+    VariantClear(&varg0);
+    VariantClear(&varg1);
+    VariantClear(&varg2);
+    RegCloseKey(hkey);
+    return hr;
+}
+
+static HRESULT InstallerImpl_Environment(WORD wFlags,
+                                         DISPPARAMS* pDispParams,
+                                         VARIANT* pVarResult,
+                                         EXCEPINFO* pExcepInfo,
+                                         UINT* puArgErr)
+{
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    FIXME("\n");
+
+    VariantInit(pVarResult);
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
+                                            DISPPARAMS* pDispParams,
+                                            VARIANT* pVarResult,
+                                            EXCEPINFO* pExcepInfo,
+                                            UINT* puArgErr)
+{
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    FIXME("\n");
+
+    VariantInit(pVarResult);
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_FileSize(WORD wFlags,
+                                      DISPPARAMS* pDispParams,
+                                      VARIANT* pVarResult,
+                                      EXCEPINFO* pExcepInfo,
+                                      UINT* puArgErr)
+{
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    FIXME("\n");
+
+    VariantInit(pVarResult);
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_FileVersion(WORD wFlags,
+                                         DISPPARAMS* pDispParams,
+                                         VARIANT* pVarResult,
+                                         EXCEPINFO* pExcepInfo,
+                                         UINT* puArgErr)
+{
+    if (!(wFlags & DISPATCH_METHOD))
+        return DISP_E_MEMBERNOTFOUND;
+
+    FIXME("\n");
+
+    VariantInit(pVarResult);
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_ProductState(WORD wFlags,
+                                          DISPPARAMS* pDispParams,
+                                          VARIANT* pVarResult,
+                                          EXCEPINFO* pExcepInfo,
+                                          UINT* puArgErr)
+{
+    HRESULT hr;
+    VARIANTARG varg0;
+
+    if (!(wFlags & DISPATCH_PROPERTYGET))
+        return DISP_E_MEMBERNOTFOUND;
+
+    VariantInit(&varg0);
+    hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+    if (FAILED(hr))
+        return hr;
+
+    V_VT(pVarResult) = VT_I4;
+    V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
+
+    VariantClear(&varg0);
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
+                                         DISPPARAMS* pDispParams,
+                                         VARIANT* pVarResult,
+                                         EXCEPINFO* pExcepInfo,
+                                         UINT* puArgErr)
+{
+    UINT ret;
+    HRESULT hr;
+    DWORD size;
+    LPWSTR str = NULL;
+    VARIANTARG varg0, varg1;
+
+    if (!(wFlags & DISPATCH_PROPERTYGET))
+        return DISP_E_MEMBERNOTFOUND;
+
+    VariantInit(&varg0);
+    hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+    if (FAILED(hr))
+        return hr;
+
+    VariantInit(&varg1);
+    hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+    if (FAILED(hr))
+        goto done;
+
+    V_VT(pVarResult) = VT_BSTR;
+    V_BSTR(pVarResult) = NULL;
+
+    ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
+    if (ret != ERROR_SUCCESS)
+    {
+        hr = DISP_E_EXCEPTION;
+        goto done;
+    }
+
+    str = msi_alloc(++size * sizeof(WCHAR));
+    if (!str)
+    {
+        hr = E_OUTOFMEMORY;
+        goto done;
+    }
+
+    ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
+    if (ret != ERROR_SUCCESS)
+    {
+        hr = DISP_E_EXCEPTION;
+        goto done;
+    }
+
+    V_BSTR(pVarResult) = SysAllocString(str);
+    hr = S_OK;
+
+done:
+    msi_free(str);
+    VariantClear(&varg0);
+    VariantClear(&varg1);
+    return hr;
+}
+
+static void cleanup_products(IDispatch* dispatch, ULONG count)
+{
+    UINT i;
+    ListData* ldata = private_data((AutomationObject *)dispatch);
+
+    for (i = 0; i < count - 1; i++)
+        VariantClear(&ldata->pVars[i]);
+
+    ldata->ulCount = 0;
+    msi_free(ldata->pVars);
+
+    IDispatch_Release(dispatch);
+}
+
+static HRESULT InstallerImpl_Products(WORD wFlags,
+                                      DISPPARAMS* pDispParams,
+                                      VARIANT* pVarResult,
+                                      EXCEPINFO* pExcepInfo,
+                                      UINT* puArgErr)
+{
+    UINT ret;
+    HRESULT hr;
+    ULONG idx = 0;
+    ListData *ldata;
+    IDispatch *dispatch;
+    WCHAR product[GUID_SIZE];
+
+    if (!(wFlags & DISPATCH_PROPERTYGET))
+        return DISP_E_MEMBERNOTFOUND;
+
+    /* Find number of products. */
+    while ((ret = MsiEnumProductsW(idx, product)) == ERROR_SUCCESS)
+        idx++;
+
+    if (ret != ERROR_NO_MORE_ITEMS)
+        return DISP_E_EXCEPTION;
+
+    V_VT(pVarResult) = VT_DISPATCH;
+    hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
+                                  &DIID_StringList, ListImpl_Invoke,
+                                  ListImpl_Free, sizeof(ListData));
+    if (FAILED(hr))
+        return hr;
+
+    V_DISPATCH(pVarResult) = dispatch;
+
+    /* Save product strings. */
+    ldata = private_data((AutomationObject *)dispatch);
+    ldata->ulCount = 0;
+    ldata->pVars = msi_alloc_zero(sizeof(VARIANT) * idx);
+    if (!ldata->pVars)
+    {
+        IDispatch_Release(dispatch);
+        return E_OUTOFMEMORY;
+    }
+
+    ldata->ulCount = idx;
+    for (idx = 0; idx < ldata->ulCount; idx++)
+    {
+        ret = MsiEnumProductsW(idx, product);
+        if (ret != ERROR_SUCCESS)
+        {
+            cleanup_products(dispatch, idx - 1);
+            return DISP_E_EXCEPTION;
+        }
+
+        VariantInit(&ldata->pVars[idx]);
+        V_VT(&ldata->pVars[idx]) = VT_BSTR;
+        V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
+    }
+
+    return S_OK;
+}
+
+static HRESULT InstallerImpl_RelatedProducts(WORD wFlags,
+                                             DISPPARAMS* pDispParams,
+                                             VARIANT* pVarResult,
+                                             EXCEPINFO* pExcepInfo,
+                                             UINT* puArgErr)
+{
+    UINT ret;
+    ULONG idx;
+    HRESULT hr;
+    ListData *ldata;
+    VARIANTARG varg0;
+    IDispatch* dispatch;
+    WCHAR product[GUID_SIZE];
+
+    if (!(wFlags & DISPATCH_PROPERTYGET))
+        return DISP_E_MEMBERNOTFOUND;
+
+    VariantInit(&varg0);
+    hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+    if (FAILED(hr))
+        return hr;
+
+    /* Find number of related products. */
+    idx = 0;
+    do
+    {
+        ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
+        if (ret == ERROR_SUCCESS)
+            idx++;
+    } while (ret == ERROR_SUCCESS);
+
+    if (ret != ERROR_NO_MORE_ITEMS)
+    {
+        hr = DISP_E_EXCEPTION;
+        goto done;
+    }
+
+    V_VT(pVarResult) = VT_DISPATCH;
+
+    hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
+                                  &DIID_StringList, ListImpl_Invoke,
+                                  ListImpl_Free, sizeof(ListData));
+    if (FAILED(hr))
+        goto done;
+
+    V_DISPATCH(pVarResult) = dispatch;
+
+    /* Save product strings. */
+    ldata = private_data((AutomationObject *)dispatch);
+    ldata->pVars = msi_alloc(sizeof(VARIANT) * idx);
+    if (!ldata->pVars)
+    {
+        IDispatch_Release(dispatch);
+        hr = E_OUTOFMEMORY;
+        goto done;
+    }
+
+    ldata->ulCount = idx;
+    for (idx = 0; idx < ldata->ulCount; idx++)
+    {
+        ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
+        if (ret != ERROR_SUCCESS)
+        {
+            cleanup_products(dispatch, idx - 1);
+            hr = DISP_E_EXCEPTION;
+            goto done;
+        }
+
+        VariantInit(&ldata->pVars[idx]);
+        V_VT(&ldata->pVars[idx]) = VT_BSTR;
+        V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
+    }
+
+    hr = S_OK;
+
+done:
+    VariantClear(&varg0);
+    return hr;
+}
+
 static HRESULT WINAPI InstallerImpl_Invoke(
         AutomationObject* This,
         DISPID dispIdMember,
@@ -1545,405 +2299,93 @@ static HRESULT WINAPI InstallerImpl_Invoke(
         EXCEPINFO* pExcepInfo,
         UINT* puArgErr)
 {
-    MSIHANDLE msiHandle;
-    IDispatch *pDispatch = NULL;
-    UINT ret;
-    VARIANTARG varg0, varg1, varg2;
-    HRESULT hr;
-    LPWSTR szString = NULL;
-    DWORD dwSize = 0;
-    INSTALLUILEVEL ui;
-
-    VariantInit(&varg0);
-    VariantInit(&varg1);
-    VariantInit(&varg2);
-
     switch (dispIdMember)
     {
         case DISPID_INSTALLER_CREATERECORD:
-            if (wFlags & DISPATCH_METHOD)
-            {
-                hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
-                if (FAILED(hr)) return hr;
-                V_VT(pVarResult) = VT_DISPATCH;
-                if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
-                {
-                    if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
-                        V_DISPATCH(pVarResult) = pDispatch;
-                    else
-                        ERR("Failed to create Record object, hresult 0x%08x\n", hr);
-                }
-                else
-                {
-                    ERR("MsiCreateRecord failed\n");
-                    return DISP_E_EXCEPTION;
-                }
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+            return InstallerImpl_CreateRecord(wFlags, pDispParams,
+                                              pVarResult, pExcepInfo, puArgErr);
 
         case DISPID_INSTALLER_OPENPACKAGE:
-            if (wFlags & DISPATCH_METHOD)
-            {
-                hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
-                if (FAILED(hr)) return hr;
-                hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
-                if (FAILED(hr))
-                {
-                    VariantClear(&varg0);
-                    return hr;
-                }
-                V_VT(pVarResult) = VT_DISPATCH;
-                if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
-                {
-                    if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
-                        V_DISPATCH(pVarResult) = pDispatch;
-                    else
-                        ERR("Failed to create Session object, hresult 0x%08x\n", hr);
-                }
-                else
-                {
-                    VariantClear(&varg0);
-                    ERR("MsiOpenPackageEx returned %d\n", ret);
-                    return DISP_E_EXCEPTION;
-                }
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+            return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
+                                             pVarResult, pExcepInfo, puArgErr);
 
-        case DISPID_INSTALLER_OPENDATABASE:
-            if (wFlags & DISPATCH_METHOD)
-            {
-                hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
-                if (FAILED(hr)) return hr;
+        case DISPID_INSTALLER_OPENPRODUCT:
+            return InstallerImpl_OpenProduct(wFlags, pDispParams,
+                                             pVarResult, pExcepInfo, puArgErr);
 
-                hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
-                if (FAILED(hr))
-                {
-                    VariantClear(&varg0);
-                    return hr;
-                }
+        case DISPID_INSTALLER_OPENDATABASE:
+            return InstallerImpl_OpenDatabase(wFlags, pDispParams,
+                                              pVarResult, pExcepInfo, puArgErr);
 
-                V_VT(pVarResult) = VT_DISPATCH;
-                if ((ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &msiHandle)) == ERROR_SUCCESS)
-                {
-                    hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch,
-                                                  &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
-                    if (SUCCEEDED(hr))
-                        V_DISPATCH(pVarResult) = pDispatch;
-                    else
-                        ERR("Failed to create Database object: 0x%08x\n", hr);
-                }
-                else
-                {
-                    VariantClear(&varg0);
-                    VariantClear(&varg1);
-                    ERR("MsiOpenDatabase returned %d\n", ret);
-                    return DISP_E_EXCEPTION;
-                }
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+        case DISPID_INSTALLER_SUMMARYINFORMATION:
+            return InstallerImpl_SummaryInformation(wFlags, pDispParams,
+                                                    pVarResult, pExcepInfo,
+                                                    puArgErr);
 
         case DISPID_INSTALLER_UILEVEL:
-            if (wFlags & DISPATCH_PROPERTYPUT)
-            {
-                hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
-                if (FAILED(hr)) return hr;
-                if ((ui = MsiSetInternalUI(V_I4(&varg0), NULL) == INSTALLUILEVEL_NOCHANGE))
-                {
-                    ERR("MsiSetInternalUI failed\n");
-                    return DISP_E_EXCEPTION;
-                }
-            }
-            else if (wFlags & DISPATCH_PROPERTYGET)
-            {
-                if ((ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL) == INSTALLUILEVEL_NOCHANGE))
-                {
-                    ERR("MsiSetInternalUI failed\n");
-                    return DISP_E_EXCEPTION;
-                }
+            return InstallerImpl_UILevel(wFlags, pDispParams,
+                                         pVarResult, pExcepInfo, puArgErr);
 
-                V_VT(pVarResult) = VT_I4;
-                V_I4(pVarResult) = ui;
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+        case DISPID_INSTALLER_ENABLELOG:
+            return InstallerImpl_EnableLog(wFlags, pDispParams,
+                                           pVarResult, pExcepInfo, puArgErr);
 
         case DISPID_INSTALLER_INSTALLPRODUCT:
-            if (wFlags & DISPATCH_METHOD)
-            {
-                hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
-                if (FAILED(hr)) return hr;
-                hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
-                if (FAILED(hr))
-                {
-                    VariantClear(&varg0);
-                    return hr;
-                }
-                if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
-                {
-                    VariantClear(&varg1);
-                    VariantClear(&varg0);
-                    ERR("MsiInstallProduct returned %d\n", ret);
-                    return DISP_E_EXCEPTION;
-                }
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+            return InstallerImpl_InstallProduct(wFlags, pDispParams,
+                                                pVarResult, pExcepInfo,
+                                                puArgErr);
 
         case DISPID_INSTALLER_VERSION:
-            if (wFlags & DISPATCH_PROPERTYGET) {
-                DLLVERSIONINFO verinfo;
-                WCHAR version[MAX_PATH];
+            return InstallerImpl_Version(wFlags, pVarResult,
+                                         pExcepInfo, puArgErr);
 
-                static const WCHAR format[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
-
-                verinfo.cbSize = sizeof(DLLVERSIONINFO);
-                hr = DllGetVersion(&verinfo);
-                if (FAILED(hr)) return hr;
-
-                sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
-                         verinfo.dwBuildNumber, verinfo.dwPlatformID);
-
-                V_VT(pVarResult) = VT_BSTR;
-                V_BSTR(pVarResult) = SysAllocString(version);
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+        case DISPID_INSTALLER_LASTERRORRECORD:
+            return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
+                                                 pVarResult, pExcepInfo,
+                                                 puArgErr);
 
         case DISPID_INSTALLER_REGISTRYVALUE:
-            if (wFlags & DISPATCH_METHOD) {
-                HKEY hkey;
-                DWORD dwType;
-                UINT posValue = 2;    /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
-
-                hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
-                if (FAILED(hr)) return hr;
-                hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
-                if (FAILED(hr)) return hr;
-                hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
-                if (FAILED(hr))
-                {
-                    VariantClear(&varg1);
-                    return hr;
-                }
-
-                if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
-                    V_I4(&varg0) <= REG_INDEX_DYN_DATA)
-                    V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
-
-                ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
-
-                /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
-                switch (V_VT(&varg2))
-                {
-                    case VT_EMPTY:  /* Return VT_BOOL as to whether or not registry key exists */
-                        V_VT(pVarResult) = VT_BOOL;
-                        V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
-                        break;
-
-                    case VT_BSTR:   /* Return value of specified key if it exists */
-                        if (ret == ERROR_SUCCESS &&
-                            (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
-                        {
-                            if (!(szString = msi_alloc(dwSize)))
-                                ERR("Out of memory\n");
-                            else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
-                                variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
-                        }
-
-                        if (ret != ERROR_SUCCESS)
-                        {
-                            msi_free(szString);
-                            VariantClear(&varg2);
-                            VariantClear(&varg1);
-                            return DISP_E_BADINDEX;
-                        }
-                        break;
+            return InstallerImpl_RegistryValue(wFlags, pDispParams,
+                                               pVarResult, pExcepInfo,
+                                               puArgErr);
 
-                    default:     /* Try to make it into VT_I4, can use VariantChangeType for this */
-                        hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
-                        if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
-                        if (FAILED(hr))
-                        {
-                            if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
-                            VariantClear(&varg2);   /* Unknown type, so let's clear it */
-                            VariantClear(&varg1);
-                            return hr;
-                        }
+        case DISPID_INSTALLER_ENVIRONMENT:
+            return InstallerImpl_Environment(wFlags, pDispParams,
+                                             pVarResult, pExcepInfo, puArgErr);
 
-                        /* Retrieve class name or maximum value name or subkey name size */
-                        if (!V_I4(&varg2))
-                            ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-                        else if (V_I4(&varg2) > 0)
-                            ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
-                        else /* V_I4(&varg2) < 0 */
-                            ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
+        case DISPID_INSTALLER_FILEATTRIBUTES:
+            return InstallerImpl_FileAttributes(wFlags, pDispParams,
+                                                pVarResult, pExcepInfo,
+                                                puArgErr);
 
-                        if (ret == ERROR_SUCCESS)
-                        {
-                            if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
-                                ERR("Out of memory\n");
-                            else if (!V_I4(&varg2))
-                                ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-                            else if (V_I4(&varg2) > 0)
-                                ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
-                            else /* V_I4(&varg2) < 0 */
-                                ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
-
-                            if (szString && ret == ERROR_SUCCESS)
-                            {
-                                V_VT(pVarResult) = VT_BSTR;
-                                V_BSTR(pVarResult) = SysAllocString(szString);
-                            }
-                        }
-                }
+        case DISPID_INSTALLER_FILESIZE:
+            return InstallerImpl_FileSize(wFlags, pDispParams,
+                                          pVarResult, pExcepInfo, puArgErr);
 
-                msi_free(szString);
-                RegCloseKey(hkey);
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+        case DISPID_INSTALLER_FILEVERSION:
+            return InstallerImpl_FileVersion(wFlags, pDispParams,
+                                             pVarResult, pExcepInfo, puArgErr);
 
         case DISPID_INSTALLER_PRODUCTSTATE:
-            if (wFlags & DISPATCH_PROPERTYGET) {
-                hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
-                if (FAILED(hr)) return hr;
-                V_VT(pVarResult) = VT_I4;
-                V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+            return InstallerImpl_ProductState(wFlags, pDispParams,
+                                              pVarResult, pExcepInfo, puArgErr);
 
         case DISPID_INSTALLER_PRODUCTINFO:
-            if (wFlags & DISPATCH_PROPERTYGET) {
-                hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
-                if (FAILED(hr)) return hr;
-                hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
-                if (FAILED(hr))
-                {
-                    VariantClear(&varg0);
-                    return hr;
-                }
-                V_VT(pVarResult) = VT_BSTR;
-                V_BSTR(pVarResult) = NULL;
-                if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &dwSize)) == ERROR_SUCCESS)
-                {
-                    if (!(szString = msi_alloc((++dwSize)*sizeof(WCHAR))))
-                        ERR("Out of memory\n");
-                    else if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), szString, &dwSize)) == ERROR_SUCCESS)
-                        V_BSTR(pVarResult) = SysAllocString(szString);
-                    msi_free(szString);
-                }
-                if (ret != ERROR_SUCCESS)
-                {
-                    ERR("MsiGetProductInfo returned %d\n", ret);
-                    VariantClear(&varg1);
-                    VariantClear(&varg0);
-                    return DISP_E_EXCEPTION;
-                }
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+            return InstallerImpl_ProductInfo(wFlags, pDispParams,
+                                             pVarResult, pExcepInfo, puArgErr);
 
         case DISPID_INSTALLER_PRODUCTS:
-            if (wFlags & DISPATCH_PROPERTYGET)
-            {
-                ListData *ldata = NULL;
-                ULONG idx = 0;
-                WCHAR szProductBuf[GUID_SIZE];
-
-                /* Find number of products */
-                while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
-                if (ret != ERROR_NO_MORE_ITEMS)
-                {
-                    ERR("MsiEnumProducts returned %d\n", ret);
-                    return DISP_E_EXCEPTION;
-                }
-
-                V_VT(pVarResult) = VT_DISPATCH;
-                if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
-                {
-                    V_DISPATCH(pVarResult) = pDispatch;
-
-                    /* Save product strings */
-                    ldata = private_data((AutomationObject *)pDispatch);
-                    if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
-                        ERR("Out of memory\n");
-                    else
-                    {
-                        ldata->ulCount = idx;
-                        for (idx = 0; idx < ldata->ulCount; idx++)
-                        {
-                            ret = MsiEnumProductsW(idx, szProductBuf);
-                            VariantInit(&ldata->pVars[idx]);
-                            V_VT(&ldata->pVars[idx]) = VT_BSTR;
-                            V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
-                        }
-                    }
-                }
-                else
-                    ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+            return InstallerImpl_Products(wFlags, pDispParams,
+                                          pVarResult, pExcepInfo, puArgErr);
 
         case DISPID_INSTALLER_RELATEDPRODUCTS:
-            if (wFlags & DISPATCH_PROPERTYGET)
-            {
-                ListData *ldata = NULL;
-                ULONG idx = 0;
-                WCHAR szProductBuf[GUID_SIZE];
-
-                hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
-                if (FAILED(hr)) return hr;
-
-                /* Find number of related products */
-                while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
-                if (ret != ERROR_NO_MORE_ITEMS)
-                {
-                    VariantClear(&varg0);
-                    ERR("MsiEnumRelatedProducts returned %d\n", ret);
-                    return DISP_E_EXCEPTION;
-                }
-
-                V_VT(pVarResult) = VT_DISPATCH;
-                if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
-                {
-                    V_DISPATCH(pVarResult) = pDispatch;
-
-                    /* Save product strings */
-                    ldata = private_data((AutomationObject *)pDispatch);
-                    if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
-                        ERR("Out of memory\n");
-                    else
-                    {
-                        ldata->ulCount = idx;
-                        for (idx = 0; idx < ldata->ulCount; idx++)
-                        {
-                            ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
-                            VariantInit(&ldata->pVars[idx]);
-                            V_VT(&ldata->pVars[idx]) = VT_BSTR;
-                            V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
-                        }
-                    }
-                }
-                else
-                    ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
-            }
-            else return DISP_E_MEMBERNOTFOUND;
-            break;
+            return InstallerImpl_RelatedProducts(wFlags, pDispParams,
+                                                 pVarResult, pExcepInfo,
+                                                 puArgErr);
 
-         default:
+        default:
             return DISP_E_MEMBERNOTFOUND;
     }
-
-    VariantClear(&varg2);
-    VariantClear(&varg1);
-    VariantClear(&varg0);
-
-    return S_OK;
 }
 
 /* Wrapper around create_automation_object to create an installer object. */
index adbdb9d..b0966a2 100644 (file)
@@ -51,13 +51,220 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
  *  Any binary data in a table is a reference to a stream.
  */
 
+typedef struct tagMSITRANSFORM {
+    struct list entry;
+    IStorage *stg;
+} MSITRANSFORM;
+
+typedef struct tagMSISTREAM {
+    struct list entry;
+    IStream *stm;
+} MSISTREAM;
+
+static UINT find_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
+{
+    MSISTREAM *stream;
+
+    LIST_FOR_EACH_ENTRY( stream, &db->streams, MSISTREAM, entry )
+    {
+        HRESULT r;
+        STATSTG stat;
+
+        r = IStream_Stat( stream->stm, &stat, 0 );
+        if( FAILED( r ) )
+        {
+            WARN("failed to stat stream r = %08x!\n", r);
+            continue;
+        }
+
+        if( !lstrcmpW( name, stat.pwcsName ) )
+        {
+            TRACE("found %s\n", debugstr_w(name));
+            *stm = stream->stm;
+            CoTaskMemFree( stat.pwcsName );
+            return ERROR_SUCCESS;
+        }
+
+        CoTaskMemFree( stat.pwcsName );
+    }
+
+    return ERROR_FUNCTION_FAILED;
+}
+
+static UINT clone_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
+{
+    IStream *stream;
+
+    if (find_open_stream( db, name, &stream ) == ERROR_SUCCESS)
+    {
+        HRESULT r;
+        LARGE_INTEGER pos;
+
+        r = IStream_Clone( stream, stm );
+        if( FAILED( r ) )
+        {
+            WARN("failed to clone stream r = %08x!\n", r);
+            return ERROR_FUNCTION_FAILED;
+        }
+
+        pos.QuadPart = 0;
+        r = IStream_Seek( *stm, pos, STREAM_SEEK_SET, NULL );
+        if( FAILED( r ) )
+        {
+            IStream_Release( *stm );
+            return ERROR_FUNCTION_FAILED;
+        }
+
+        return ERROR_SUCCESS;
+    }
+
+    return ERROR_FUNCTION_FAILED;
+}
+
+UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
+{
+    LPWSTR encname;
+    HRESULT r;
+
+    encname = encode_streamname(FALSE, stname);
+
+    TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
+
+    if (clone_open_stream( db, encname, stm ) == ERROR_SUCCESS)
+    {
+        msi_free( encname );
+        return ERROR_SUCCESS;
+    }
+
+    r = IStorage_OpenStream( db->storage, encname, NULL,
+                             STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
+    if( FAILED( r ) )
+    {
+        MSITRANSFORM *transform;
+
+        LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
+        {
+            TRACE("looking for %s in transform storage\n", debugstr_w(stname) );
+            r = IStorage_OpenStream( transform->stg, encname, NULL,
+                                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
+            if (SUCCEEDED(r))
+                break;
+        }
+    }
+
+    msi_free( encname );
+
+    if( SUCCEEDED(r) )
+    {
+        MSISTREAM *stream;
+
+        stream = msi_alloc( sizeof(MSISTREAM) );
+        if( !stream )
+            return ERROR_NOT_ENOUGH_MEMORY;
+
+        stream->stm = *stm;
+        IStream_AddRef( *stm );
+        list_add_tail( &db->streams, &stream->entry );
+    }
+
+    return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
+}
+
+UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
+                              USHORT **pdata, UINT *psz )
+{
+    HRESULT r;
+    UINT ret = ERROR_FUNCTION_FAILED;
+    VOID *data;
+    ULONG sz, count;
+    IStream *stm = NULL;
+    STATSTG stat;
+
+    r = db_get_raw_stream( db, stname, &stm );
+    if( r != ERROR_SUCCESS)
+        return ret;
+    r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
+    if( FAILED( r ) )
+    {
+        WARN("open stream failed r = %08x!\n", r);
+        goto end;
+    }
+
+    if( stat.cbSize.QuadPart >> 32 )
+    {
+        WARN("Too big!\n");
+        goto end;
+    }
+
+    sz = stat.cbSize.QuadPart;
+    data = msi_alloc( sz );
+    if( !data )
+    {
+        WARN("couldn't allocate memory r=%08x!\n", r);
+        ret = ERROR_NOT_ENOUGH_MEMORY;
+        goto end;
+    }
+
+    r = IStream_Read(stm, data, sz, &count );
+    if( FAILED( r ) || ( count != sz ) )
+    {
+        msi_free( data );
+        WARN("read stream failed r = %08x!\n", r);
+        goto end;
+    }
+
+    *pdata = data;
+    *psz = sz;
+    ret = ERROR_SUCCESS;
+
+end:
+    IStream_Release( stm );
+
+    return ret;
+}
+
+void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
+{
+    MSITRANSFORM *t;
+
+    t = msi_alloc( sizeof *t );
+    t->stg = stg;
+    IStorage_AddRef( stg );
+    list_add_tail( &db->transforms, &t->entry );
+}
+
+static void free_transforms( MSIDATABASE *db )
+{
+    while( !list_empty( &db->transforms ) )
+    {
+        MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
+                                      MSITRANSFORM, entry );
+        list_remove( &t->entry );
+        IStorage_Release( t->stg );
+        msi_free( t );
+    }
+}
+
+static void free_streams( MSIDATABASE *db )
+{
+    while( !list_empty( &db->streams ) )
+    {
+        MSISTREAM *s = LIST_ENTRY( list_head( &db->streams ),
+                                   MSISTREAM, entry );
+        list_remove( &s->entry );
+        IStream_Release( s->stm );
+        msi_free( s );
+    }
+}
+
 static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
 {
     MSIDATABASE *db = (MSIDATABASE *) arg;
 
     msi_free(db->path);
     free_cached_tables( db );
-    msi_free_transforms( db );
+    free_streams( db );
+    free_transforms( db );
     msi_destroy_stringtable( db->strings );
     IStorage_Release( db->storage );
     if (db->deletefile)
@@ -198,6 +405,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
         db->deletefile = strdupW( szDBPath );
     list_init( &db->tables );
     list_init( &db->transforms );
+    list_init( &db->streams );
 
     db->strings = msi_load_string_table( stg, &db->bytes_per_strref );
     if( !db->strings )
@@ -493,10 +701,10 @@ done:
 
 static UINT msi_add_table_to_db(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types, LPWSTR *labels, DWORD num_labels, DWORD num_columns)
 {
-    UINT r;
+    UINT r = ERROR_OUTOFMEMORY;
     DWORD size;
     MSIQUERY *view;
-    LPWSTR create_sql;
+    LPWSTR create_sql = NULL;
     LPWSTR prelude, columns_sql, postlude;
 
     prelude = msi_build_createsql_prelude(labels[0]);
@@ -504,31 +712,30 @@ static UINT msi_add_table_to_db(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types,
     postlude = msi_build_createsql_postlude(labels + 1, num_labels - 1); /* skip over table name */
 
     if (!prelude || !columns_sql || !postlude)
-        return ERROR_OUTOFMEMORY;
+        goto done;
 
     size = lstrlenW(prelude) + lstrlenW(columns_sql) + lstrlenW(postlude) + 1;
     create_sql = msi_alloc(size * sizeof(WCHAR));
     if (!create_sql)
-        return ERROR_OUTOFMEMORY;
+        goto done;
 
     lstrcpyW(create_sql, prelude);
     lstrcatW(create_sql, columns_sql);
     lstrcatW(create_sql, postlude);
 
-    msi_free(prelude);
-    msi_free(columns_sql);
-    msi_free(postlude);
-
     r = MSI_DatabaseOpenViewW( db, create_sql, &view );
-    msi_free(create_sql);
-
     if (r != ERROR_SUCCESS)
-        return r;
+        goto done;
 
     r = MSI_ViewExecute(view, NULL);
     MSI_ViewClose(view);
     msiobj_release(&view->hdr);
 
+done:
+    msi_free(prelude);
+    msi_free(columns_sql);
+    msi_free(postlude);
+    msi_free(create_sql);
     return r;
 }
 
@@ -622,6 +829,7 @@ static UINT msi_add_records_to_table(MSIDATABASE *db, LPWSTR *columns, LPWSTR *t
     while (MSI_ViewFetch(view, &rec) != ERROR_NO_MORE_ITEMS)
     {
         r = MSI_ViewModify(view, MSIMODIFY_DELETE, rec);
+        msiobj_release(&rec->hdr);
         if (r != ERROR_SUCCESS)
             goto done;
     }
@@ -1451,6 +1659,7 @@ static UINT msi_get_query_types(MSIQUERY *query, LPWSTR **types, DWORD *numtypes
         goto end;
     }
 
+    *numtypes = count;
     for (i=1; i<=count; i++ )
     {
         (*types)[i-1] = strdupW(MSI_RecordGetString(prec, i));
@@ -1477,32 +1686,36 @@ static void merge_free_rows(MERGETABLE *table)
 
 static void free_merge_table(MERGETABLE *table)
 {
-        UINT i;
+    UINT i;
 
-        if (table->labels != NULL)
-        {
-            for (i = 0; i < table->numlabels; i++)
-                msi_free(table->labels[i]);
-            msi_free(table->labels);
-        }
+    if (table->labels != NULL)
+    {
+        for (i = 0; i < table->numlabels; i++)
+            msi_free(table->labels[i]);
 
-        if (table->columns != NULL)
-        {
-            for (i = 0; i < table->numcolumns; i++)
-                msi_free(table->columns[i]);
-            msi_free(table->columns);
-        }
+        msi_free(table->labels);
+    }
 
-        if (table->types != NULL)
-        {
-            for (i = 0; i < table->numtypes; i++)
-                msi_free(table->types[i]);
-            msi_free(table->types);
-        }
-        msi_free(table->name);
-        merge_free_rows(table);
+    if (table->columns != NULL)
+    {
+        for (i = 0; i < table->numcolumns; i++)
+            msi_free(table->columns[i]);
 
-        msi_free(table);
+        msi_free(table->columns);
+    }
+
+    if (table->types != NULL)
+    {
+        for (i = 0; i < table->numtypes; i++)
+            msi_free(table->types[i]);
+
+        msi_free(table->types);
+    }
+
+    msi_free(table->name);
+    merge_free_rows(table);
+
+    msi_free(table);
 }
 
 static UINT msi_get_merge_table (MSIDATABASE *db, LPCWSTR name, MERGETABLE **ptable)
@@ -1753,7 +1966,6 @@ UINT WINAPI MsiDatabaseMergeW(MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge,
     LIST_FOR_EACH_SAFE(item, cursor, &tabledata)
     {
         MERGETABLE *table = LIST_ENTRY(item, MERGETABLE, entry);
-
         list_remove(&table->entry);
         free_merge_table(table);
     }
index a385633..f0b5803 100644 (file)
@@ -78,6 +78,20 @@ static UINT DROP_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *cols)
     return ERROR_FUNCTION_FAILED;
 }
 
+static UINT DROP_delete( struct tagMSIVIEW *view )
+{
+    MSIDROPVIEW *dv = (MSIDROPVIEW*)view;
+
+    TRACE("%p\n", dv );
+
+    if( dv->table )
+        dv->table->ops->delete( dv->table );
+
+    msi_free( dv );
+
+    return ERROR_SUCCESS;
+}
+
 static const MSIVIEWOPS drop_ops =
 {
     NULL,
@@ -91,7 +105,7 @@ static const MSIVIEWOPS drop_ops =
     DROP_get_dimensions,
     NULL,
     NULL,
-    NULL,
+    DROP_delete,
     NULL,
     NULL,
     NULL,
index 381ceca..7e74dca 100644 (file)
@@ -155,7 +155,7 @@ static UINT copy_install_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR source)
         gle = copy_file(file, source);
         TRACE("Overwriting existing file: %d\n", gle);
     }
-    if ((gle == ERROR_SHARING_VIOLATION) || (gle == ERROR_USER_MAPPED_FILE))
+    if (gle == ERROR_SHARING_VIOLATION || gle == ERROR_USER_MAPPED_FILE)
     {
         WCHAR tmpfileW[MAX_PATH], *pathW, *p;
         DWORD len;
index 1aeb17c..134c569 100644 (file)
@@ -229,14 +229,18 @@ static UINT JOIN_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
 static UINT JOIN_delete( struct tagMSIVIEW *view )
 {
     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
-    JOINTABLE *table;
+    struct list *item, *cursor;
 
     TRACE("%p\n", jv );
 
-    LIST_FOR_EACH_ENTRY(table, &jv->tables, JOINTABLE, entry)
+    LIST_FOR_EACH_SAFE(item, cursor, &jv->tables)
     {
+        JOINTABLE* table = LIST_ENTRY(item, JOINTABLE, entry);
+
+        list_remove(&table->entry);
         table->view->ops->delete(table->view);
         table->view = NULL;
+        msi_free(table);
     }
 
     msi_free(jv);
@@ -349,11 +353,13 @@ UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables )
         if( r != ERROR_SUCCESS )
         {
             WARN("can't create table: %s\n", debugstr_w(tables));
+            msi_free(table);
             r = ERROR_BAD_QUERY_SYNTAX;
             goto end;
         }
 
-        r = table->view->ops->get_dimensions( table->view, NULL, &table->columns );
+        r = table->view->ops->get_dimensions( table->view, NULL,
+                                              &table->columns );
         if( r != ERROR_SUCCESS )
         {
             ERR("can't get table dimensions\n");
index 67cb7dc..0a6c431 100644 (file)
@@ -334,7 +334,12 @@ static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint,
     data->curfile = strdupAtoW(pfdin->psz1);
     if (!data->cb(data->package, data->curfile, MSICABEXTRACT_BEGINEXTRACT, &path,
                   &attrs, data->user))
+    {
+        /* We're not extracting this file, so free the filename. */
+        msi_free(data->curfile);
+        data->curfile = NULL;
         goto done;
+    }
 
     TRACE("extracting %s\n", debugstr_w(path));
 
@@ -362,7 +367,7 @@ static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint,
             if (handle != INVALID_HANDLE_VALUE) goto done;
             err = GetLastError();
         }
-        if ((err == ERROR_SHARING_VIOLATION) || (err == ERROR_USER_MAPPED_FILE))
+        if (err == ERROR_SHARING_VIOLATION || err == ERROR_USER_MAPPED_FILE)
         {
             WCHAR tmpfileW[MAX_PATH], *tmppathW, *p;
             DWORD len;
index 2515714..4d9da4c 100644 (file)
@@ -901,7 +901,7 @@ static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
     WCHAR packagecode[GUID_SIZE];
     BOOL badconfig = FALSE;
     LONG res;
-    DWORD save, type = REG_NONE;
+    DWORD type = REG_NONE;
 
     static WCHAR empty[] = {0};
     static const WCHAR sourcelist[] = {
@@ -1036,22 +1036,26 @@ static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
 
     if (pcchValueBuf)
     {
-        save = *pcchValueBuf;
-
-        if (strlenW(val) < *pcchValueBuf)
-            r = msi_strcpy_to_awstring(val, szValue, pcchValueBuf);
-        else if (szValue->str.a || szValue->str.w)
-            r = ERROR_MORE_DATA;
+        /* If szBuffer (szValue->str) is NULL, there's no need to copy the value
+         * out.  Also, *pcchValueBuf may be uninitialized in this case, so we
+         * can't rely on its value.
+         */
+        if (szValue->str.a || szValue->str.w)
+        {
+            DWORD size = *pcchValueBuf;
+            if (strlenW(val) < size)
+                r = msi_strcpy_to_awstring(val, szValue, &size);
+            else
+            {
+                r = ERROR_MORE_DATA;
+            }
+        }
 
         if (!badconfig)
             *pcchValueBuf = lstrlenW(val);
-        else if (r == ERROR_SUCCESS)
-        {
-            *pcchValueBuf = save;
-            r = ERROR_BAD_CONFIGURATION;
-        }
     }
-    else if (badconfig)
+
+    if (badconfig)
         r = ERROR_BAD_CONFIGURATION;
 
     if (val != empty)
index 5b23f55..ac247ac 100644 (file)
@@ -80,6 +80,7 @@ typedef struct tagMSIDATABASE
     LPCWSTR mode;
     struct list tables;
     struct list transforms;
+    struct list streams;
 } MSIDATABASE;
 
 typedef struct tagMSIVIEW MSIVIEW;
@@ -649,7 +650,6 @@ extern void msiobj_unlock(MSIOBJECTHDR *);
 extern void msi_free_handle_table(void);
 
 extern void free_cached_tables( MSIDATABASE *db );
-extern void msi_free_transforms( MSIDATABASE *db );
 extern UINT MSI_CommitTables( MSIDATABASE *db );
 
 
@@ -698,6 +698,7 @@ extern UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
                                     BOOL preserve_case );
 
 /* record internals */
+extern void MSI_CloseRecord( MSIOBJECTHDR * );
 extern UINT MSI_RecordSetIStream( MSIRECORD *, UINT, IStream *);
 extern UINT MSI_RecordGetIStream( MSIRECORD *, UINT, IStream **);
 extern const WCHAR *MSI_RecordGetString( const MSIRECORD *, UINT );
@@ -718,11 +719,12 @@ extern MSIRECORD *MSI_CloneRecord( MSIRECORD * );
 extern BOOL MSI_RecordsAreEqual( MSIRECORD *, MSIRECORD * );
 
 /* stream internals */
-extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
 extern void enum_stream_names( IStorage *stg );
+extern LPWSTR encode_streamname(BOOL bTable, LPCWSTR in);
 extern BOOL decode_streamname(LPCWSTR in, LPWSTR out);
 
 /* database internals */
+extern UINT db_get_raw_stream( MSIDATABASE *, LPCWSTR, IStream ** );
 extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** );
 extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** );
 extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... );
@@ -755,7 +757,7 @@ extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR );
 extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPCWSTR, INSTALLSTATE *, INSTALLSTATE * );
 extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPCWSTR, INSTALLSTATE *, INSTALLSTATE * );
 extern UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE );
-extern LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename );
+extern UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename );
 extern UINT msi_package_add_info(MSIPACKAGE *, DWORD, DWORD, LPCWSTR, LPWSTR);
 extern UINT msi_package_add_media_disk(MSIPACKAGE *, DWORD, DWORD, DWORD, LPWSTR, LPWSTR);
 extern UINT msi_clone_properties(MSIPACKAGE *);
index 9972a02..a814695 100644 (file)
@@ -153,21 +153,48 @@ library WindowsInstaller
             Session* OpenPackage(
                 [in] VARIANT PackagePath,
                 [in, optional, defaultvalue(0)] long Options);
+        [id(DISPID_INSTALLER_OPENPRODUCT)]
+            Session* OpenProduct(
+                [in] BSTR ProductCode);
+        [id(DISPID_INSTALLER_SUMMARYINFORMATION)]
+            SummaryInfo* SummaryInformation(
+                [in] BSTR PackagePath,
+                [in, optional, defaultvalue(0)] long UpdateCount);
         [id(DISPID_INSTALLER_OPENDATABASE)]
             Database *OpenDatabase(
                     [in] BSTR DatabasePath,
                     [in] VARIANT OpenMode);
+        [id(DISPID_INSTALLER_ENABLELOG)]
+            void EnableLog(
+                    [in] BSTR LogMode,
+                    [in] BSTR LogFile);
         [id(DISPID_INSTALLER_INSTALLPRODUCT)]
             void InstallProduct(
                 [in] BSTR PackagePath,
                 [in, optional, defaultvalue("0")] BSTR PropertyValues);
         [id(DISPID_INSTALLER_VERSION)]
             BSTR Version();
+        [id(DISPID_INSTALLER_LASTERRORRECORD)]
+            Record* LastErrorRecord();
         [id(DISPID_INSTALLER_REGISTRYVALUE), propget]
             BSTR RegistryValue(
                 [in] VARIANT Root,
                 [in] BSTR Key,
                 [in, optional] VARIANT Value);
+        [id(DISPID_INSTALLER_ENVIRONMENT), propget]
+            BSTR Environment([in] BSTR Variable);
+        [id(DISPID_INSTALLER_ENVIRONMENT), propput]
+            void Environment(
+                [in] BSTR Variable,
+                [in] BSTR rhs);
+        [id(DISPID_INSTALLER_FILEATTRIBUTES)]
+            long FileAttributes([in] BSTR FilePath);
+        [id(DISPID_INSTALLER_FILESIZE)]
+            long FileSize([in] BSTR FilePath);
+        [id(DISPID_INSTALLER_FILEVERSION)]
+            BSTR FileVersion(
+                [in] BSTR FilePath,
+                [in, optional] VARIANT Language);
         [id(DISPID_INSTALLER_PRODUCTSTATE), propget]
             MsiInstallState ProductState(
                 [in] BSTR Product);
index e6078fd..d98d784 100644 (file)
 
 #define DISPID_INSTALLER_CREATERECORD 1
 #define DISPID_INSTALLER_OPENPACKAGE 2
+#define DISPID_INSTALLER_OPENPRODUCT 3
 #define DISPID_INSTALLER_OPENDATABASE 4
+#define DISPID_INSTALLER_SUMMARYINFORMATION 5
 #define DISPID_INSTALLER_UILEVEL 6
+#define DISPID_INSTALLER_ENABLELOG 7
 #define DISPID_INSTALLER_INSTALLPRODUCT 8
 #define DISPID_INSTALLER_VERSION 9
+#define DISPID_INSTALLER_LASTERRORRECORD 10
 #define DISPID_INSTALLER_REGISTRYVALUE 11
+#define DISPID_INSTALLER_ENVIRONMENT 12
+#define DISPID_INSTALLER_FILEATTRIBUTES 13
+#define DISPID_INSTALLER_FILESIZE 15
+#define DISPID_INSTALLER_FILEVERSION 16
 #define DISPID_INSTALLER_PRODUCTSTATE 17
 #define DISPID_INSTALLER_PRODUCTINFO 18
 #define DISPID_INSTALLER_PRODUCTS 35
index 574289f..120972f 100644 (file)
@@ -779,6 +779,16 @@ static UINT msi_load_admin_properties(MSIPACKAGE *package)
     return r;
 }
 
+static void adjust_allusers_property( MSIPACKAGE *package )
+{
+    /* FIXME: this should depend on the user's privileges */
+    if (msi_get_property_int( package, szAllUsers, 0 ) == 2)
+    {
+        TRACE("resetting ALLUSERS property from 2 to 1\n");
+        MSI_SetPropertyW( package, szAllUsers, szOne );
+    }
+}
+
 MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
 {
     static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
@@ -818,6 +828,8 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
 
         if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
             msi_load_admin_properties( package );
+
+        adjust_allusers_property( package );
     }
 
     return package;
@@ -833,7 +845,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
  *        we should read all the tables to memory, then open the
  *        database to read binary streams on demand.
  */ 
-static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
+static UINT copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
 {
     WCHAR path[MAX_PATH];
 
@@ -842,16 +854,16 @@ static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
 
     if( !CopyFileW( szPackage, filename, FALSE ) )
     {
+        UINT error = GetLastError();
+        ERR("failed to copy package %s to %s (%u)\n", debugstr_w(szPackage), debugstr_w(filename), error);
         DeleteFileW( filename );
-        ERR("failed to copy package %s\n", debugstr_w(szPackage) );
-        return szPackage;
+        return error;
     }
 
-    TRACE("Opening relocated package %s\n", debugstr_w( filename ));
-    return filename;
+    return ERROR_SUCCESS;
 }
 
-LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename )
+UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename )
 {
     LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
     DWORD size = 0;
@@ -867,20 +879,24 @@ LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename )
         cache_entry = HeapAlloc( GetProcessHeap(), 0, size );
         if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
         {
+            UINT error = GetLastError();
             HeapFree( GetProcessHeap(), 0, cache_entry );
-            return szUrl;
+            return error;
         }
 
         lstrcpyW( filename, cache_entry->lpszLocalFileName );
         HeapFree( GetProcessHeap(), 0, cache_entry );
-        return filename;
+        return ERROR_SUCCESS;
     }
 
     hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
     if ( FAILED(hr) )
-        return szUrl;
+    {
+        WARN("failed to download %s to cache file\n", debugstr_w(szUrl));
+        return ERROR_FUNCTION_FAILED;
+    }
 
-    return filename;
+    return ERROR_SUCCESS;
 }
 
 static UINT msi_get_local_package_name( LPWSTR path )
@@ -925,7 +941,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     MSIHANDLE handle;
     LPWSTR ptr, base_url = NULL;
     UINT r;
-    WCHAR temppath[MAX_PATH], localfile[MAX_PATH];
+    WCHAR temppath[MAX_PATH], localfile[MAX_PATH], cachefile[MAX_PATH];
     LPCWSTR file = szPackage;
 
     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
@@ -952,9 +968,15 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     {
         if ( UrlIsW( szPackage, URLIS_URL ) )
         {
-            file = msi_download_file( szPackage, temppath );
-            if ( file != szPackage )
-                file = copy_package_to_temp( file, temppath );
+            r = msi_download_file( szPackage, cachefile );
+            if ( r != ERROR_SUCCESS )
+                return r;
+
+            r = copy_package_to_temp( cachefile, temppath );
+            if ( r != ERROR_SUCCESS )
+                return r;
+
+            file = temppath;
 
             base_url = strdupW( szPackage );
             if ( !base_url )
@@ -964,7 +986,13 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
             if (ptr) *(ptr + 1) = '\0';
         }
         else
-            file = copy_package_to_temp( szPackage, temppath );
+        {
+            r = copy_package_to_temp( szPackage, temppath );
+            if ( r != ERROR_SUCCESS )
+                return r;
+
+            file = temppath;
+        }
 
         r = msi_get_local_package_name( localfile );
         if (r != ERROR_SUCCESS)
@@ -979,6 +1007,8 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
             return GetLastError();
         }
 
+        TRACE("Opening relocated package %s\n", debugstr_w( file ));
+
         /* transforms that add binary streams require that we open the database
          * read/write, which is safe because we always create a copy that is thrown
          * away when we're done.
index 68eab69..45adbac 100644 (file)
@@ -64,7 +64,7 @@ static void MSI_FreeField( MSIFIELD *field )
     }
 }
 
-static void MSI_CloseRecord( MSIOBJECTHDR *arg )
+void MSI_CloseRecord( MSIOBJECTHDR *arg )
 {
     MSIRECORD *rec = (MSIRECORD *) arg;
     UINT i;
index 84597a4..72e230c 100644 (file)
@@ -126,7 +126,10 @@ typedef struct tag_SQL_input
     LPCWSTR command;
     DWORD n, len;
     UINT r;
-    MSIVIEW **view;  /* view structure for the resulting query */
+    MSIVIEW **view;  /* View structure for the resulting query.  This value
+                      * tracks the view currently being created so we can free
+                      * this view on syntax error.
+                      */
     struct list *mem;
 } SQL_input;
 
@@ -147,10 +150,14 @@ static struct expr * EXPR_ival( void *info, int val );
 static struct expr * EXPR_sval( void *info, const struct sql_str *str );
 static struct expr * EXPR_wildcard( void *info );
 
+#define PARSER_BUBBLE_UP_VIEW( sql, result, current_view ) \
+    *sql->view = current_view; \
+    result = current_view
+
 
 
 /* Line 189 of yacc.c  */
-#line 154 "sql.tab.c"
+#line 161 "sql.tab.c"
 
 /* Enabling traces.  */
 #ifndef YYDEBUG
@@ -248,7 +255,7 @@ typedef union YYSTYPE
 {
 
 /* Line 214 of yacc.c  */
-#line 76 "sql.y"
+#line 83 "sql.y"
 
     struct sql_str str;
     LPWSTR string;
@@ -261,7 +268,7 @@ typedef union YYSTYPE
 
 
 /* Line 214 of yacc.c  */
-#line 265 "sql.tab.c"
+#line 272 "sql.tab.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -273,7 +280,7 @@ typedef union YYSTYPE
 
 
 /* Line 264 of yacc.c  */
-#line 277 "sql.tab.c"
+#line 284 "sql.tab.c"
 
 #ifdef short
 # undef short
@@ -595,15 +602,15 @@ static const yytype_int8 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   126,   126,   134,   135,   136,   137,   138,   139,   140,
-     144,   154,   167,   183,   198,   208,   221,   234,   244,   254,
-     267,   271,   278,   291,   301,   311,   318,   327,   331,   335,
-     342,   346,   353,   357,   361,   365,   369,   373,   377,   384,
-     393,   406,   410,   414,   430,   451,   452,   456,   463,   464,
-     480,   490,   502,   507,   516,   522,   528,   534,   540,   546,
-     552,   558,   564,   570,   576,   585,   586,   590,   597,   608,
-     609,   617,   625,   631,   637,   643,   652,   661,   667,   676,
-     683,   691
+       0,   133,   133,   141,   142,   143,   144,   145,   146,   147,
+     151,   162,   176,   193,   209,   220,   234,   248,   259,   270,
+     284,   288,   295,   310,   320,   330,   337,   346,   350,   354,
+     361,   365,   372,   376,   380,   384,   388,   392,   396,   403,
+     412,   425,   429,   433,   448,   468,   469,   473,   480,   481,
+     496,   508,   523,   528,   537,   543,   549,   555,   561,   567,
+     573,   579,   585,   591,   597,   606,   607,   611,   618,   629,
+     630,   638,   646,   652,   658,   664,   673,   682,   688,   697,
+     704,   712
 };
 #endif
 
@@ -1612,7 +1619,7 @@ yyreduce:
         case 2:
 
 /* Line 1455 of yacc.c  */
-#line 127 "sql.y"
+#line 134 "sql.y"
     {
         SQL_input* sql = (SQL_input*) info;
         *sql->view = (yyvsp[(1) - (1)].query);
@@ -1622,7 +1629,7 @@ yyreduce:
   case 10:
 
 /* Line 1455 of yacc.c  */
-#line 145 "sql.y"
+#line 152 "sql.y"
     {
             SQL_input *sql = (SQL_input*) info;
             MSIVIEW *insert = NULL;
@@ -1630,14 +1637,15 @@ yyreduce:
             INSERT_CreateView( sql->db, &insert, (yyvsp[(3) - (10)].string), (yyvsp[(5) - (10)].column_list), (yyvsp[(9) - (10)].column_list), FALSE );
             if( !insert )
                 YYABORT;
-            (yyval.query) = insert;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query),  insert );
         ;}
     break;
 
   case 11:
 
 /* Line 1455 of yacc.c  */
-#line 155 "sql.y"
+#line 163 "sql.y"
     {
             SQL_input *sql = (SQL_input*) info;
             MSIVIEW *insert = NULL;
@@ -1645,14 +1653,15 @@ yyreduce:
             INSERT_CreateView( sql->db, &insert, (yyvsp[(3) - (11)].string), (yyvsp[(5) - (11)].column_list), (yyvsp[(9) - (11)].column_list), TRUE );
             if( !insert )
                 YYABORT;
-            (yyval.query) = insert;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query),  insert );
         ;}
     break;
 
   case 12:
 
 /* Line 1455 of yacc.c  */
-#line 168 "sql.y"
+#line 177 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
             MSIVIEW *create = NULL;
@@ -1666,14 +1675,15 @@ yyreduce:
                 sql->r = r;
                 YYABORT;
             }
-            (yyval.query) = create;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query),  create );
         ;}
     break;
 
   case 13:
 
 /* Line 1455 of yacc.c  */
-#line 184 "sql.y"
+#line 194 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
             MSIVIEW *create = NULL;
@@ -1683,14 +1693,15 @@ yyreduce:
             CREATE_CreateView( sql->db, &create, (yyvsp[(3) - (7)].string), (yyvsp[(5) - (7)].column_list), TRUE );
             if( !create )
                 YYABORT;
-            (yyval.query) = create;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query),  create );
         ;}
     break;
 
   case 14:
 
 /* Line 1455 of yacc.c  */
-#line 199 "sql.y"
+#line 210 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
             MSIVIEW *update = NULL;
@@ -1698,14 +1709,15 @@ yyreduce:
             UPDATE_CreateView( sql->db, &update, (yyvsp[(2) - (6)].string), (yyvsp[(4) - (6)].column_list), (yyvsp[(6) - (6)].expr) );
             if( !update )
                 YYABORT;
-            (yyval.query) = update;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query),  update );
         ;}
     break;
 
   case 15:
 
 /* Line 1455 of yacc.c  */
-#line 209 "sql.y"
+#line 221 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
             MSIVIEW *update = NULL;
@@ -1713,14 +1725,15 @@ yyreduce:
             UPDATE_CreateView( sql->db, &update, (yyvsp[(2) - (4)].string), (yyvsp[(4) - (4)].column_list), NULL );
             if( !update )
                 YYABORT;
-            (yyval.query) = update;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query),  update );
         ;}
     break;
 
   case 16:
 
 /* Line 1455 of yacc.c  */
-#line 222 "sql.y"
+#line 235 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
             MSIVIEW *delete = NULL;
@@ -1728,14 +1741,15 @@ yyreduce:
             DELETE_CreateView( sql->db, &delete, (yyvsp[(2) - (2)].query) );
             if( !delete )
                 YYABORT;
-            (yyval.query) = delete;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), delete );
         ;}
     break;
 
   case 17:
 
 /* Line 1455 of yacc.c  */
-#line 235 "sql.y"
+#line 249 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
             MSIVIEW *alter = NULL;
@@ -1743,14 +1757,15 @@ yyreduce:
             ALTER_CreateView( sql->db, &alter, (yyvsp[(3) - (4)].string), NULL, (yyvsp[(4) - (4)].integer) );
             if( !alter )
                 YYABORT;
-            (yyval.query) = alter;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), alter );
         ;}
     break;
 
   case 18:
 
 /* Line 1455 of yacc.c  */
-#line 245 "sql.y"
+#line 260 "sql.y"
     {
             SQL_input *sql = (SQL_input *)info;
             MSIVIEW *alter = NULL;
@@ -1758,14 +1773,15 @@ yyreduce:
             ALTER_CreateView( sql->db, &alter, (yyvsp[(3) - (5)].string), (yyvsp[(5) - (5)].column_list), 0 );
             if (!alter)
                 YYABORT;
-            (yyval.query) = alter;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), alter );
         ;}
     break;
 
   case 19:
 
 /* Line 1455 of yacc.c  */
-#line 255 "sql.y"
+#line 271 "sql.y"
     {
             SQL_input *sql = (SQL_input *)info;
             MSIVIEW *alter = NULL;
@@ -1773,14 +1789,15 @@ yyreduce:
             ALTER_CreateView( sql->db, &alter, (yyvsp[(3) - (6)].string), (yyvsp[(5) - (6)].column_list), 1 );
             if (!alter)
                 YYABORT;
-            (yyval.query) = alter;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), alter );
         ;}
     break;
 
   case 20:
 
 /* Line 1455 of yacc.c  */
-#line 268 "sql.y"
+#line 285 "sql.y"
     {
             (yyval.integer) = 1;
         ;}
@@ -1789,7 +1806,7 @@ yyreduce:
   case 21:
 
 /* Line 1455 of yacc.c  */
-#line 272 "sql.y"
+#line 289 "sql.y"
     {
             (yyval.integer) = -1;
         ;}
@@ -1798,22 +1815,24 @@ yyreduce:
   case 22:
 
 /* Line 1455 of yacc.c  */
-#line 279 "sql.y"
+#line 296 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* drop = NULL;
             UINT r;
 
-            (yyval.query) = NULL;
-            r = DROP_CreateView( sql->db, &(yyval.query), (yyvsp[(3) - (3)].string) );
+            r = DROP_CreateView( sql->db, &drop, (yyvsp[(3) - (3)].string) );
             if( r != ERROR_SUCCESS || !(yyval.query) )
                 YYABORT;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), drop );
         ;}
     break;
 
   case 23:
 
 /* Line 1455 of yacc.c  */
-#line 292 "sql.y"
+#line 311 "sql.y"
     {
             if( SQL_MarkPrimaryKeys( &(yyvsp[(1) - (4)].column_list), (yyvsp[(4) - (4)].column_list) ) )
                 (yyval.column_list) = (yyvsp[(1) - (4)].column_list);
@@ -1825,7 +1844,7 @@ yyreduce:
   case 24:
 
 /* Line 1455 of yacc.c  */
-#line 302 "sql.y"
+#line 321 "sql.y"
     {
             column_info *ci;
 
@@ -1840,7 +1859,7 @@ yyreduce:
   case 25:
 
 /* Line 1455 of yacc.c  */
-#line 312 "sql.y"
+#line 331 "sql.y"
     {
             (yyval.column_list) = (yyvsp[(1) - (1)].column_list);
         ;}
@@ -1849,7 +1868,7 @@ yyreduce:
   case 26:
 
 /* Line 1455 of yacc.c  */
-#line 319 "sql.y"
+#line 338 "sql.y"
     {
             (yyval.column_list) = (yyvsp[(1) - (2)].column_list);
             (yyval.column_list)->type = ((yyvsp[(2) - (2)].column_type) | MSITYPE_VALID);
@@ -1860,7 +1879,7 @@ yyreduce:
   case 27:
 
 /* Line 1455 of yacc.c  */
-#line 328 "sql.y"
+#line 347 "sql.y"
     {
             (yyval.column_type) = (yyvsp[(1) - (1)].column_type);
         ;}
@@ -1869,7 +1888,7 @@ yyreduce:
   case 28:
 
 /* Line 1455 of yacc.c  */
-#line 332 "sql.y"
+#line 351 "sql.y"
     {
             (yyval.column_type) = (yyvsp[(1) - (2)].column_type) | MSITYPE_LOCALIZABLE;
         ;}
@@ -1878,7 +1897,7 @@ yyreduce:
   case 29:
 
 /* Line 1455 of yacc.c  */
-#line 336 "sql.y"
+#line 355 "sql.y"
     {
             (yyval.column_type) = (yyvsp[(1) - (2)].column_type) | MSITYPE_TEMPORARY;
         ;}
@@ -1887,7 +1906,7 @@ yyreduce:
   case 30:
 
 /* Line 1455 of yacc.c  */
-#line 343 "sql.y"
+#line 362 "sql.y"
     {
             (yyval.column_type) |= MSITYPE_NULLABLE;
         ;}
@@ -1896,7 +1915,7 @@ yyreduce:
   case 31:
 
 /* Line 1455 of yacc.c  */
-#line 347 "sql.y"
+#line 366 "sql.y"
     {
             (yyval.column_type) = (yyvsp[(1) - (3)].column_type);
         ;}
@@ -1905,7 +1924,7 @@ yyreduce:
   case 32:
 
 /* Line 1455 of yacc.c  */
-#line 354 "sql.y"
+#line 373 "sql.y"
     {
             (yyval.column_type) = MSITYPE_STRING | 1;
         ;}
@@ -1914,7 +1933,7 @@ yyreduce:
   case 33:
 
 /* Line 1455 of yacc.c  */
-#line 358 "sql.y"
+#line 377 "sql.y"
     {
             (yyval.column_type) = MSITYPE_STRING | 0x400 | (yyvsp[(3) - (4)].column_type);
         ;}
@@ -1923,7 +1942,7 @@ yyreduce:
   case 34:
 
 /* Line 1455 of yacc.c  */
-#line 362 "sql.y"
+#line 381 "sql.y"
     {
             (yyval.column_type) = MSITYPE_STRING | 0x400;
         ;}
@@ -1932,7 +1951,7 @@ yyreduce:
   case 35:
 
 /* Line 1455 of yacc.c  */
-#line 366 "sql.y"
+#line 385 "sql.y"
     {
             (yyval.column_type) = 2 | 0x400;
         ;}
@@ -1941,7 +1960,7 @@ yyreduce:
   case 36:
 
 /* Line 1455 of yacc.c  */
-#line 370 "sql.y"
+#line 389 "sql.y"
     {
             (yyval.column_type) = 2 | 0x400;
         ;}
@@ -1950,7 +1969,7 @@ yyreduce:
   case 37:
 
 /* Line 1455 of yacc.c  */
-#line 374 "sql.y"
+#line 393 "sql.y"
     {
             (yyval.column_type) = 4;
         ;}
@@ -1959,7 +1978,7 @@ yyreduce:
   case 38:
 
 /* Line 1455 of yacc.c  */
-#line 378 "sql.y"
+#line 397 "sql.y"
     {
             (yyval.column_type) = MSITYPE_STRING | MSITYPE_VALID;
         ;}
@@ -1968,7 +1987,7 @@ yyreduce:
   case 39:
 
 /* Line 1455 of yacc.c  */
-#line 385 "sql.y"
+#line 404 "sql.y"
     {
             if( ( (yyvsp[(1) - (1)].integer) > 255 ) || ( (yyvsp[(1) - (1)].integer) < 0 ) )
                 YYABORT;
@@ -1979,7 +1998,7 @@ yyreduce:
   case 40:
 
 /* Line 1455 of yacc.c  */
-#line 394 "sql.y"
+#line 413 "sql.y"
     {
             UINT r;
 
@@ -1997,7 +2016,7 @@ yyreduce:
   case 42:
 
 /* Line 1455 of yacc.c  */
-#line 411 "sql.y"
+#line 430 "sql.y"
     {
             (yyval.query) = (yyvsp[(2) - (2)].query);
         ;}
@@ -2006,38 +2025,36 @@ yyreduce:
   case 43:
 
 /* Line 1455 of yacc.c  */
-#line 415 "sql.y"
+#line 434 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* distinct = NULL;
             UINT r;
 
-            (yyval.query) = NULL;
-            r = DISTINCT_CreateView( sql->db, &(yyval.query), (yyvsp[(3) - (3)].query) );
+            r = DISTINCT_CreateView( sql->db, &distinct, (yyvsp[(3) - (3)].query) );
             if (r != ERROR_SUCCESS)
-            {
-                (yyvsp[(3) - (3)].query)->ops->delete((yyvsp[(3) - (3)].query));
                 YYABORT;
-            }
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), distinct );
         ;}
     break;
 
   case 44:
 
 /* Line 1455 of yacc.c  */
-#line 431 "sql.y"
+#line 449 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* select = NULL;
             UINT r;
 
-            (yyval.query) = NULL;
             if( (yyvsp[(1) - (2)].column_list) )
             {
-                r = SELECT_CreateView( sql->db, &(yyval.query), (yyvsp[(2) - (2)].query), (yyvsp[(1) - (2)].column_list) );
+                r = SELECT_CreateView( sql->db, &select, (yyvsp[(2) - (2)].query), (yyvsp[(1) - (2)].column_list) );
                 if (r != ERROR_SUCCESS)
-                {
-                    (yyvsp[(2) - (2)].query)->ops->delete((yyvsp[(2) - (2)].query));
                     YYABORT;
-                }
+
+                PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), select );
             }
             else
                 (yyval.query) = (yyvsp[(2) - (2)].query);
@@ -2047,7 +2064,7 @@ yyreduce:
   case 46:
 
 /* Line 1455 of yacc.c  */
-#line 453 "sql.y"
+#line 470 "sql.y"
     {
             (yyvsp[(1) - (3)].column_list)->next = (yyvsp[(3) - (3)].column_list);
         ;}
@@ -2056,7 +2073,7 @@ yyreduce:
   case 47:
 
 /* Line 1455 of yacc.c  */
-#line 457 "sql.y"
+#line 474 "sql.y"
     {
             (yyval.column_list) = NULL;
         ;}
@@ -2065,54 +2082,58 @@ yyreduce:
   case 49:
 
 /* Line 1455 of yacc.c  */
-#line 465 "sql.y"
+#line 482 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* where = NULL;
             UINT r;
 
-            (yyval.query) = NULL;
-            r = WHERE_CreateView( sql->db, &(yyval.query), (yyvsp[(1) - (3)].query), (yyvsp[(3) - (3)].expr) );
+            r = WHERE_CreateView( sql->db, &where, (yyvsp[(1) - (3)].query), (yyvsp[(3) - (3)].expr) );
             if( r != ERROR_SUCCESS )
-            {
-                (yyvsp[(1) - (3)].query)->ops->delete( (yyvsp[(1) - (3)].query) );
                 YYABORT;
-            }
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), where );
         ;}
     break;
 
   case 50:
 
 /* Line 1455 of yacc.c  */
-#line 481 "sql.y"
+#line 497 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* table = NULL;
             UINT r;
 
-            (yyval.query) = NULL;
-            r = TABLE_CreateView( sql->db, (yyvsp[(2) - (2)].string), &(yyval.query) );
+            r = TABLE_CreateView( sql->db, (yyvsp[(2) - (2)].string), &table );
             if( r != ERROR_SUCCESS || !(yyval.query) )
                 YYABORT;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), table );
         ;}
     break;
 
   case 51:
 
 /* Line 1455 of yacc.c  */
-#line 491 "sql.y"
+#line 509 "sql.y"
     {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* join = NULL;
             UINT r;
 
-            r = JOIN_CreateView( sql->db, &(yyval.query), (yyvsp[(2) - (2)].string) );
+            r = JOIN_CreateView( sql->db, &join, (yyvsp[(2) - (2)].string) );
             if( r != ERROR_SUCCESS )
                 YYABORT;
+
+            PARSER_BUBBLE_UP_VIEW( sql, (yyval.query), join );
         ;}
     break;
 
   case 52:
 
 /* Line 1455 of yacc.c  */
-#line 503 "sql.y"
+#line 524 "sql.y"
     {
             (yyval.string) = (yyvsp[(1) - (1)].string);
         ;}
@@ -2121,7 +2142,7 @@ yyreduce:
   case 53:
 
 /* Line 1455 of yacc.c  */
-#line 508 "sql.y"
+#line 529 "sql.y"
     {
             (yyval.string) = parser_add_table( info, (yyvsp[(3) - (3)].string), (yyvsp[(1) - (3)].string) );
             if (!(yyval.string))
@@ -2132,7 +2153,7 @@ yyreduce:
   case 54:
 
 /* Line 1455 of yacc.c  */
-#line 517 "sql.y"
+#line 538 "sql.y"
     {
             (yyval.expr) = (yyvsp[(2) - (3)].expr);
             if( !(yyval.expr) )
@@ -2143,7 +2164,7 @@ yyreduce:
   case 55:
 
 /* Line 1455 of yacc.c  */
-#line 523 "sql.y"
+#line 544 "sql.y"
     {
             (yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_AND, (yyvsp[(3) - (3)].expr) );
             if( !(yyval.expr) )
@@ -2154,7 +2175,7 @@ yyreduce:
   case 56:
 
 /* Line 1455 of yacc.c  */
-#line 529 "sql.y"
+#line 550 "sql.y"
     {
             (yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_OR, (yyvsp[(3) - (3)].expr) );
             if( !(yyval.expr) )
@@ -2165,7 +2186,7 @@ yyreduce:
   case 57:
 
 /* Line 1455 of yacc.c  */
-#line 535 "sql.y"
+#line 556 "sql.y"
     {
             (yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_EQ, (yyvsp[(3) - (3)].expr) );
             if( !(yyval.expr) )
@@ -2176,7 +2197,7 @@ yyreduce:
   case 58:
 
 /* Line 1455 of yacc.c  */
-#line 541 "sql.y"
+#line 562 "sql.y"
     {
             (yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_GT, (yyvsp[(3) - (3)].expr) );
             if( !(yyval.expr) )
@@ -2187,7 +2208,7 @@ yyreduce:
   case 59:
 
 /* Line 1455 of yacc.c  */
-#line 547 "sql.y"
+#line 568 "sql.y"
     {
             (yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_LT, (yyvsp[(3) - (3)].expr) );
             if( !(yyval.expr) )
@@ -2198,7 +2219,7 @@ yyreduce:
   case 60:
 
 /* Line 1455 of yacc.c  */
-#line 553 "sql.y"
+#line 574 "sql.y"
     {
             (yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_LE, (yyvsp[(3) - (3)].expr) );
             if( !(yyval.expr) )
@@ -2209,7 +2230,7 @@ yyreduce:
   case 61:
 
 /* Line 1455 of yacc.c  */
-#line 559 "sql.y"
+#line 580 "sql.y"
     {
             (yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_GE, (yyvsp[(3) - (3)].expr) );
             if( !(yyval.expr) )
@@ -2220,7 +2241,7 @@ yyreduce:
   case 62:
 
 /* Line 1455 of yacc.c  */
-#line 565 "sql.y"
+#line 586 "sql.y"
     {
             (yyval.expr) = EXPR_complex( info, (yyvsp[(1) - (3)].expr), OP_NE, (yyvsp[(3) - (3)].expr) );
             if( !(yyval.expr) )
@@ -2231,7 +2252,7 @@ yyreduce:
   case 63:
 
 /* Line 1455 of yacc.c  */
-#line 571 "sql.y"
+#line 592 "sql.y"
     {
             (yyval.expr) = EXPR_unary( info, (yyvsp[(1) - (3)].expr), OP_ISNULL );
             if( !(yyval.expr) )
@@ -2242,7 +2263,7 @@ yyreduce:
   case 64:
 
 /* Line 1455 of yacc.c  */
-#line 577 "sql.y"
+#line 598 "sql.y"
     {
             (yyval.expr) = EXPR_unary( info, (yyvsp[(1) - (4)].expr), OP_NOTNULL );
             if( !(yyval.expr) )
@@ -2253,7 +2274,7 @@ yyreduce:
   case 67:
 
 /* Line 1455 of yacc.c  */
-#line 591 "sql.y"
+#line 612 "sql.y"
     {
             (yyval.column_list) = parser_alloc_column( info, NULL, NULL );
             if( !(yyval.column_list) )
@@ -2265,7 +2286,7 @@ yyreduce:
   case 68:
 
 /* Line 1455 of yacc.c  */
-#line 598 "sql.y"
+#line 619 "sql.y"
     {
             (yyval.column_list) = parser_alloc_column( info, NULL, NULL );
             if( !(yyval.column_list) )
@@ -2278,7 +2299,7 @@ yyreduce:
   case 70:
 
 /* Line 1455 of yacc.c  */
-#line 610 "sql.y"
+#line 631 "sql.y"
     {
             (yyval.column_list) = (yyvsp[(1) - (3)].column_list);
             (yyval.column_list)->next = (yyvsp[(3) - (3)].column_list);
@@ -2288,7 +2309,7 @@ yyreduce:
   case 71:
 
 /* Line 1455 of yacc.c  */
-#line 618 "sql.y"
+#line 639 "sql.y"
     {
             (yyval.column_list) = (yyvsp[(1) - (3)].column_list);
             (yyval.column_list)->val = (yyvsp[(3) - (3)].expr);
@@ -2298,7 +2319,7 @@ yyreduce:
   case 72:
 
 /* Line 1455 of yacc.c  */
-#line 626 "sql.y"
+#line 647 "sql.y"
     {
             (yyval.expr) = EXPR_ival( info, (yyvsp[(1) - (1)].integer) );
             if( !(yyval.expr) )
@@ -2309,7 +2330,7 @@ yyreduce:
   case 73:
 
 /* Line 1455 of yacc.c  */
-#line 632 "sql.y"
+#line 653 "sql.y"
     {
             (yyval.expr) = EXPR_ival( info, -(yyvsp[(2) - (2)].integer) );
             if( !(yyval.expr) )
@@ -2320,7 +2341,7 @@ yyreduce:
   case 74:
 
 /* Line 1455 of yacc.c  */
-#line 638 "sql.y"
+#line 659 "sql.y"
     {
             (yyval.expr) = EXPR_sval( info, &(yyvsp[(1) - (1)].str) );
             if( !(yyval.expr) )
@@ -2331,7 +2352,7 @@ yyreduce:
   case 75:
 
 /* Line 1455 of yacc.c  */
-#line 644 "sql.y"
+#line 665 "sql.y"
     {
             (yyval.expr) = EXPR_wildcard( info );
             if( !(yyval.expr) )
@@ -2342,7 +2363,7 @@ yyreduce:
   case 76:
 
 /* Line 1455 of yacc.c  */
-#line 653 "sql.y"
+#line 674 "sql.y"
     {
             (yyval.expr) = EXPR_column( info, (yyvsp[(1) - (1)].column_list) );
             if( !(yyval.expr) )
@@ -2353,7 +2374,7 @@ yyreduce:
   case 77:
 
 /* Line 1455 of yacc.c  */
-#line 662 "sql.y"
+#line 683 "sql.y"
     {
             (yyval.column_list) = parser_alloc_column( info, (yyvsp[(1) - (3)].string), (yyvsp[(3) - (3)].string) );
             if( !(yyval.column_list) )
@@ -2364,7 +2385,7 @@ yyreduce:
   case 78:
 
 /* Line 1455 of yacc.c  */
-#line 668 "sql.y"
+#line 689 "sql.y"
     {
             (yyval.column_list) = parser_alloc_column( info, NULL, (yyvsp[(1) - (1)].string) );
             if( !(yyval.column_list) )
@@ -2375,7 +2396,7 @@ yyreduce:
   case 79:
 
 /* Line 1455 of yacc.c  */
-#line 677 "sql.y"
+#line 698 "sql.y"
     {
             (yyval.string) = (yyvsp[(1) - (1)].string);
         ;}
@@ -2384,7 +2405,7 @@ yyreduce:
   case 80:
 
 /* Line 1455 of yacc.c  */
-#line 684 "sql.y"
+#line 705 "sql.y"
     {
             if ( SQL_getstring( info, &(yyvsp[(1) - (1)].str), &(yyval.string) ) != ERROR_SUCCESS || !(yyval.string) )
                 YYABORT;
@@ -2394,7 +2415,7 @@ yyreduce:
   case 81:
 
 /* Line 1455 of yacc.c  */
-#line 692 "sql.y"
+#line 713 "sql.y"
     {
             (yyval.integer) = SQL_getint( info );
         ;}
@@ -2403,7 +2424,7 @@ yyreduce:
 
 
 /* Line 1455 of yacc.c  */
-#line 2407 "sql.tab.c"
+#line 2428 "sql.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -2615,7 +2636,7 @@ yyreturn:
 
 
 /* Line 1675 of yacc.c  */
-#line 697 "sql.y"
+#line 718 "sql.y"
 
 
 static LPWSTR parser_add_table( void *info, LPCWSTR list, LPCWSTR table )
index d19f0fd..35f67fb 100644 (file)
@@ -110,7 +110,7 @@ typedef union YYSTYPE
 {
 
 /* Line 1676 of yacc.c  */
-#line 76 "sql.y"
+#line 83 "sql.y"
 
     struct sql_str str;
     LPWSTR string;
index e2484df..548a878 100644 (file)
@@ -47,7 +47,10 @@ typedef struct tag_SQL_input
     LPCWSTR command;
     DWORD n, len;
     UINT r;
-    MSIVIEW **view;  /* view structure for the resulting query */
+    MSIVIEW **view;  /* View structure for the resulting query.  This value
+                      * tracks the view currently being created so we can free
+                      * this view on syntax error.
+                      */
     struct list *mem;
 } SQL_input;
 
@@ -68,6 +71,10 @@ static struct expr * EXPR_ival( void *info, int val );
 static struct expr * EXPR_sval( void *info, const struct sql_str *str );
 static struct expr * EXPR_wildcard( void *info );
 
+#define PARSER_BUBBLE_UP_VIEW( sql, result, current_view ) \
+    *sql->view = current_view; \
+    result = current_view
+
 %}
 
 %pure-parser
@@ -149,7 +156,8 @@ oneinsert:
             INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
             if( !insert )
                 YYABORT;
-            $$ = insert;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$,  insert );
         }
   | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMPORARY
         {
@@ -159,7 +167,8 @@ oneinsert:
             INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
             if( !insert )
                 YYABORT;
-            $$ = insert;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$,  insert );
         }
     ;
 
@@ -178,7 +187,8 @@ onecreate:
                 sql->r = r;
                 YYABORT;
             }
-            $$ = create;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$,  create );
         }
   | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
         {
@@ -190,7 +200,8 @@ onecreate:
             CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
             if( !create )
                 YYABORT;
-            $$ = create;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$,  create );
         }
     ;
 
@@ -203,7 +214,8 @@ oneupdate:
             UPDATE_CreateView( sql->db, &update, $2, $4, $6 );
             if( !update )
                 YYABORT;
-            $$ = update;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$,  update );
         }
   | TK_UPDATE table TK_SET update_assign_list
         {
@@ -213,7 +225,8 @@ oneupdate:
             UPDATE_CreateView( sql->db, &update, $2, $4, NULL );
             if( !update )
                 YYABORT;
-            $$ = update;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$,  update );
         }
     ;
 
@@ -226,7 +239,8 @@ onedelete:
             DELETE_CreateView( sql->db, &delete, $2 );
             if( !delete )
                 YYABORT;
-            $$ = delete;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$, delete );
         }
     ;
 
@@ -239,7 +253,8 @@ onealter:
             ALTER_CreateView( sql->db, &alter, $3, NULL, $4 );
             if( !alter )
                 YYABORT;
-            $$ = alter;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$, alter );
         }
   | TK_ALTER TK_TABLE table TK_ADD column_and_type
         {
@@ -249,7 +264,8 @@ onealter:
             ALTER_CreateView( sql->db, &alter, $3, $5, 0 );
             if (!alter)
                 YYABORT;
-            $$ = alter;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$, alter );
         }
   | TK_ALTER TK_TABLE table TK_ADD column_and_type TK_HOLD
         {
@@ -259,7 +275,8 @@ onealter:
             ALTER_CreateView( sql->db, &alter, $3, $5, 1 );
             if (!alter)
                 YYABORT;
-            $$ = alter;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$, alter );
         }
     ;
 
@@ -278,12 +295,14 @@ onedrop:
     TK_DROP TK_TABLE table
         {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* drop = NULL;
             UINT r;
 
-            $$ = NULL;
-            r = DROP_CreateView( sql->db, &$$, $3 );
+            r = DROP_CreateView( sql->db, &drop, $3 );
             if( r != ERROR_SUCCESS || !$$ )
                 YYABORT;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$, drop );
         }
   ;
 
@@ -414,15 +433,14 @@ unorderedsel:
   | TK_SELECT TK_DISTINCT selectfrom
         {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* distinct = NULL;
             UINT r;
 
-            $$ = NULL;
-            r = DISTINCT_CreateView( sql->db, &$$, $3 );
+            r = DISTINCT_CreateView( sql->db, &distinct, $3 );
             if (r != ERROR_SUCCESS)
-            {
-                $3->ops->delete($3);
                 YYABORT;
-            }
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$, distinct );
         }
     ;
 
@@ -430,17 +448,16 @@ selectfrom:
     selcollist from
         {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* select = NULL;
             UINT r;
 
-            $$ = NULL;
             if( $1 )
             {
-                r = SELECT_CreateView( sql->db, &$$, $2, $1 );
+                r = SELECT_CreateView( sql->db, &select, $2, $1 );
                 if (r != ERROR_SUCCESS)
-                {
-                    $2->ops->delete($2);
                     YYABORT;
-                }
+
+                PARSER_BUBBLE_UP_VIEW( sql, $$, select );
             }
             else
                 $$ = $2;
@@ -464,15 +481,14 @@ from:
   | fromtable TK_WHERE expr
         {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* where = NULL;
             UINT r;
 
-            $$ = NULL;
-            r = WHERE_CreateView( sql->db, &$$, $1, $3 );
+            r = WHERE_CreateView( sql->db, &where, $1, $3 );
             if( r != ERROR_SUCCESS )
-            {
-                $1->ops->delete( $1 );
                 YYABORT;
-            }
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$, where );
         }
     ;
 
@@ -480,21 +496,26 @@ fromtable:
     TK_FROM table
         {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* table = NULL;
             UINT r;
 
-            $$ = NULL;
-            r = TABLE_CreateView( sql->db, $2, &$$ );
+            r = TABLE_CreateView( sql->db, $2, &table );
             if( r != ERROR_SUCCESS || !$$ )
                 YYABORT;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$, table );
         }
   | TK_FROM tablelist
         {
             SQL_input* sql = (SQL_input*) info;
+            MSIVIEW* join = NULL;
             UINT r;
 
-            r = JOIN_CreateView( sql->db, &$$, $2 );
+            r = JOIN_CreateView( sql->db, &join, $2 );
             if( r != ERROR_SUCCESS )
                 YYABORT;
+
+            PARSER_BUBBLE_UP_VIEW( sql, $$, join );
         }
     ;
 
index 844db8d..a54d46f 100644 (file)
@@ -437,11 +437,13 @@ static UINT STORAGES_delete(struct tagMSIVIEW *view)
         if (sv->storages[i]->storage)
             IStorage_Release(sv->storages[i]->storage);
 
+        msi_free(sv->storages[i]->name);
         msi_free(sv->storages[i]);
     }
 
     msi_free(sv->storages);
     sv->storages = NULL;
+    msi_free(sv);
 
     return ERROR_SUCCESS;
 }
index faa27c8..4825ae6 100644 (file)
@@ -400,12 +400,18 @@ static UINT STREAMS_delete(struct tagMSIVIEW *view)
 
     for (i = 0; i < sv->num_rows; i++)
     {
-        if (sv->streams[i] && sv->streams[i]->stream)
-            IStream_Release(sv->streams[i]->stream);
-        msi_free(sv->streams[i]);
+        if (sv->streams[i])
+        {
+            if (sv->streams[i]->stream)
+                IStream_Release(sv->streams[i]->stream);
+
+            msi_free(sv->streams[i]->name);
+            msi_free(sv->streams[i]);
+        }
     }
 
     msi_free(sv->streams);
+    msi_free(sv);
 
     return ERROR_SUCCESS;
 }
index e5b5cc2..3bdc436 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
-#define HASH_SIZE 0x101
 #define LONG_STR_BYTES 3
 
 typedef struct _msistring
 {
-    int hash_next;
     UINT persistent_refcount;
     UINT nonpersistent_refcount;
     LPWSTR str;
@@ -56,30 +54,14 @@ struct string_table
     UINT maxcount;         /* the number of strings */
     UINT freeslot;
     UINT codepage;
-    int hash[HASH_SIZE];
-    msistring *strings; /* an array of strings (in the tree) */
+    UINT sortcount;
+    msistring *strings; /* an array of strings */
+    UINT *sorted;       /* index */
 };
 
-static UINT msistring_makehash( const WCHAR *str )
-{
-    UINT hash = 0;
-
-    if (str==NULL)
-        return hash;
-
-    while( *str )
-    {
-        hash ^= *str++;
-        hash *= 53;
-        hash = (hash<<5) | (hash>>27);
-    }
-    return hash % HASH_SIZE;
-}
-
 static string_table *init_stringtable( int entries, UINT codepage )
 {
     string_table *st;
-    int i;
 
     if (codepage != CP_ACP && !IsValidCodePage(codepage))
     {
@@ -92,18 +74,26 @@ static string_table *init_stringtable( int entries, UINT codepage )
         return NULL;    
     if( entries < 1 )
         entries = 1;
+
     st->strings = msi_alloc_zero( sizeof (msistring) * entries );
     if( !st->strings )
     {
         msi_free( st );
         return NULL;    
     }
+
+    st->sorted = msi_alloc( sizeof (UINT) * entries );
+    if( !st->sorted )
+    {
+        msi_free( st->strings );
+        msi_free( st );
+        return NULL;
+    }
+
     st->maxcount = entries;
     st->freeslot = 1;
     st->codepage = codepage;
-
-    for( i=0; i<HASH_SIZE; i++ )
-        st->hash[i] = -1;
+    st->sortcount = 0;
 
     return st;
 }
@@ -119,12 +109,13 @@ VOID msi_destroy_stringtable( string_table *st )
             msi_free( st->strings[i].str );
     }
     msi_free( st->strings );
+    msi_free( st->sorted );
     msi_free( st );
 }
 
 static int st_find_free_entry( string_table *st )
 {
-    UINT i, sz;
+    UINT i, sz, *s;
     msistring *p;
 
     TRACE("%p\n", st);
@@ -146,7 +137,17 @@ static int st_find_free_entry( string_table *st )
     p = msi_realloc_zero( st->strings, sz*sizeof(msistring) );
     if( !p )
         return -1;
+
+    s = msi_realloc( st->sorted, sz*sizeof(UINT) );
+    if( !s )
+    {
+        msi_free( p );
+        return -1;
+    }
+
     st->strings = p;
+    st->sorted = s;
+
     st->freeslot = st->maxcount;
     st->maxcount = sz;
     if( st->strings[st->freeslot].persistent_refcount ||
@@ -155,10 +156,40 @@ static int st_find_free_entry( string_table *st )
     return st->freeslot;
 }
 
-static void set_st_entry( string_table *st, UINT n, LPWSTR str, UINT refcount, enum StringPersistence persistence )
+static int find_insert_index( const string_table *st, UINT string_id )
 {
-    UINT hash = msistring_makehash( str );
+    int i, c, low = 0, high = st->sortcount - 1;
+
+    while (low <= high)
+    {
+        i = (low + high) / 2;
+        c = lstrcmpW( st->strings[string_id].str, st->strings[st->sorted[i]].str );
 
+        if (c < 0)
+            high = i - 1;
+        else if (c > 0)
+            low = i + 1;
+        else
+            return -1; /* already exists */
+    }
+    return high + 1;
+}
+
+static void insert_string_sorted( string_table *st, UINT string_id )
+{
+    int i;
+
+    i = find_insert_index( st, string_id );
+    if (i == -1)
+        return;
+
+    memmove( &st->sorted[i] + 1, &st->sorted[i], (st->sortcount - i) * sizeof(UINT) );
+    st->sorted[i] = string_id;
+    st->sortcount++;
+}
+
+static void set_st_entry( string_table *st, UINT n, LPWSTR str, UINT refcount, enum StringPersistence persistence )
+{
     if (persistence == StringPersistent)
     {
         st->strings[n].persistent_refcount = refcount;
@@ -172,8 +203,7 @@ static void set_st_entry( string_table *st, UINT n, LPWSTR str, UINT refcount, e
 
     st->strings[n].str = str;
 
-    st->strings[n].hash_next = st->hash[hash];
-    st->hash[hash] = n;
+    insert_string_sorted( st, n );
 
     if( n < st->maxcount )
         st->freeslot = n + 1;
@@ -382,14 +412,20 @@ static UINT msi_id2stringA( const string_table *st, UINT id, LPSTR buffer, UINT
  */
 UINT msi_string2idW( const string_table *st, LPCWSTR str, UINT *id )
 {
-    UINT n, hash = msistring_makehash( str );
-    msistring *se = st->strings;
+    int i, c, low = 0, high = st->sortcount - 1;
 
-    for (n = st->hash[hash]; n != -1; n = st->strings[n].hash_next )
+    while (low <= high)
     {
-        if ((str == se[n].str) || !lstrcmpW(str, se[n].str))
+        i = (low + high) / 2;
+        c = lstrcmpW( str, st->strings[st->sorted[i]].str );
+
+        if (c < 0)
+            high = i - 1;
+        else if (c > 0)
+            low = i + 1;
+        else
         {
-            *id = n;
+            *id = st->sorted[i];
             return ERROR_SUCCESS;
         }
     }
index fa32a04..cc40515 100644 (file)
@@ -83,11 +83,6 @@ struct tagMSITABLE
     WCHAR name[1];
 };
 
-typedef struct tagMSITRANSFORM {
-    struct list entry;
-    IStorage *stg;
-} MSITRANSFORM;
-
 static const WCHAR szStringData[] = {
     '_','S','t','r','i','n','g','D','a','t','a',0 };
 static const WCHAR szStringPool[] = {
@@ -154,7 +149,7 @@ static int utf2mime(int x)
     return -1;
 }
 
-static LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
+LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
 {
     DWORD count = MAX_STREAM_NAME;
     DWORD ch, next;
@@ -332,89 +327,6 @@ end:
     return ret;
 }
 
-static UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
-{
-    LPWSTR encname;
-    HRESULT r;
-
-    encname = encode_streamname(FALSE, stname);
-
-    TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
-
-    r = IStorage_OpenStream(db->storage, encname, NULL, 
-            STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm);
-    if( FAILED( r ) )
-    {
-        MSITRANSFORM *transform;
-
-        LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
-        {
-            TRACE("looking for %s in transform storage\n", debugstr_w(stname) );
-            r = IStorage_OpenStream( transform->stg, encname, NULL, 
-                    STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
-            if (SUCCEEDED(r))
-                break;
-        }
-    }
-
-    msi_free( encname );
-
-    return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
-}
-
-UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
-                              USHORT **pdata, UINT *psz )
-{
-    HRESULT r;
-    UINT ret = ERROR_FUNCTION_FAILED;
-    VOID *data;
-    ULONG sz, count;
-    IStream *stm = NULL;
-    STATSTG stat;
-
-    r = db_get_raw_stream( db, stname, &stm );
-    if( r != ERROR_SUCCESS)
-        return ret;
-    r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
-    if( FAILED( r ) )
-    {
-        WARN("open stream failed r = %08x!\n", r);
-        goto end;
-    }
-
-    if( stat.cbSize.QuadPart >> 32 )
-    {
-        WARN("Too big!\n");
-        goto end;
-    }
-        
-    sz = stat.cbSize.QuadPart;
-    data = msi_alloc( sz );
-    if( !data )
-    {
-        WARN("couldn't allocate memory r=%08x!\n", r);
-        ret = ERROR_NOT_ENOUGH_MEMORY;
-        goto end;
-    }
-        
-    r = IStream_Read(stm, data, sz, &count );
-    if( FAILED( r ) || ( count != sz ) )
-    {
-        msi_free( data );
-        WARN("read stream failed r = %08x!\n", r);
-        goto end;
-    }
-
-    *pdata = data;
-    *psz = sz;
-    ret = ERROR_SUCCESS;
-
-end:
-    IStream_Release( stm );
-
-    return ret;
-}
-
 UINT write_stream_data( IStorage *stg, LPCWSTR stname,
                         LPCVOID data, UINT sz, BOOL bTable )
 {
@@ -1042,17 +954,22 @@ static UINT get_tablecolumns( MSIDATABASE *db,
 static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR name )
 {
     MSITABLE *table;
+    LPWSTR tablename;
     UINT size, offset, old_count;
     UINT n;
 
-    table = find_cached_table( db, name );
+    /* We may free name in msi_free_colinfo. */
+    tablename = strdupW( name );
+
+    table = find_cached_table( db, tablename );
     old_count = table->col_count;
+    msi_free_colinfo( table->colinfo, table->col_count );
     msi_free( table->colinfo );
     table->colinfo = NULL;
 
-    table_get_column_info( db, name, &table->colinfo, &table->col_count );
+    table_get_column_info( db, tablename, &table->colinfo, &table->col_count );
     if (!table->col_count)
-        return;
+        goto done;
 
     size = msi_table_get_row_size( db, table->colinfo, table->col_count );
     offset = table->colinfo[table->col_count - 1].offset;
@@ -1063,6 +980,9 @@ static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR name )
         if (old_count < table->col_count)
             memset( &table->data[n][offset], 0, size - offset );
     }
+
+done:
+    msi_free(tablename);
 }
 
 /* try to find the table name in the _Tables table */
@@ -1754,15 +1674,14 @@ static UINT TABLE_delete_row( struct tagMSIVIEW *view, UINT row )
         tv->columns[i].hash_table = NULL;
     }
 
-    if ( row == num_rows - 1 )
-        return ERROR_SUCCESS;
-
     for (i = row + 1; i < num_rows; i++)
     {
         memcpy(tv->table->data[i - 1], tv->table->data[i], tv->row_size);
         tv->table->data_persistent[i - 1] = tv->table->data_persistent[i];
     }
 
+    msi_free(tv->table->data[num_rows - 1]);
+
     return ERROR_SUCCESS;
 }
 
@@ -1828,6 +1747,9 @@ static UINT msi_refresh_record( struct tagMSIVIEW *view, MSIRECORD *rec, UINT ro
     if (r != ERROR_SUCCESS)
         return r;
 
+    /* Close the original record */
+    MSI_CloseRecord(&rec->hdr);
+
     count = MSI_RecordGetFieldCount(rec);
     for (i = 0; i < count; i++)
         MSI_RecordCopyField(curr, i + 1, rec, i + 1);
@@ -2316,7 +2238,6 @@ static UINT TABLE_drop(struct tagMSIVIEW *view)
 
     list_remove(&tv->table->entry);
     free_table(tv->table);
-    TABLE_delete(view);
 
 done:
     msiobj_release(&rec->hdr);
@@ -3010,25 +2931,3 @@ end:
 
     return ret;
 }
-
-void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
-{
-    MSITRANSFORM *t;
-
-    t = msi_alloc( sizeof *t );
-    t->stg = stg;
-    IStorage_AddRef( stg );
-    list_add_tail( &db->transforms, &t->entry );
-}
-
-void msi_free_transforms( MSIDATABASE *db )
-{
-    while( !list_empty( &db->transforms ) )
-    {
-        MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
-                                      MSITRANSFORM, entry );
-        list_remove( &t->entry );
-        IStorage_Release( t->stg );
-        msi_free( t );
-    }
-}
index 32f71b9..545d6a8 100644 (file)
@@ -309,9 +309,7 @@ static UINT STRCMP_Evaluate( MSIWHEREVIEW *wv, UINT row, const struct expr *cond
         sr = lstrcmpW( l_str, r_str );
 
     *val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) ||
-           ( cond->u.expr.op == OP_NE && ( sr != 0 ) ) ||
-           ( cond->u.expr.op == OP_LT && ( sr < 0 ) ) ||
-           ( cond->u.expr.op == OP_GT && ( sr > 0 ) );
+           ( cond->u.expr.op == OP_NE && ( sr != 0 ) );
 
     return ERROR_SUCCESS;
 }
@@ -644,8 +642,6 @@ static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr
             switch( cond->u.expr.op )
             {
             case OP_EQ:
-            case OP_GT:
-            case OP_LT:
             case OP_NE:
                 break;
             default: