diff options
405 files changed, 12002 insertions, 21146 deletions
diff --git a/Makefile.in b/Makefile.in index f196af545..26cd688d4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -299,13 +299,6 @@ MAKE_SYM_STORE_ARGS += --install-manifest=$(DEPTH)/_build_manifests/install/dist SYM_STORE_SOURCE_DIRS := $(topsrcdir) -ifdef MOZ_CRASHREPORTER -include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk - -SYMBOL_INDEX_NAME = \ - $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)-$(CPU_ARCH)-symbols.txt -endif - .PHONY: generatesymbols generatesymbols: echo building symbol store @@ -337,18 +330,9 @@ symbolsarchive: generatesymbols cd $(DIST)/crashreporter-symbols && \ zip -r5D '../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip' . -i '*.sym' -i '*.txt' -ifdef MOZ_CRASHREPORTER -buildsymbols: symbolsfullarchive symbolsarchive -else buildsymbols: -endif uploadsymbols: -ifdef MOZ_CRASHREPORTER -ifdef SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE - $(PYTHON) -u $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.py '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip' -endif -endif .PHONY: update-packaging update-packaging: diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp index 2590969a0..46d4dde01 100644 --- a/accessible/base/nsAccessibilityService.cpp +++ b/accessible/base/nsAccessibilityService.cpp @@ -53,10 +53,6 @@ #include "Logging.h" #endif -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - #include "nsImageFrame.h" #include "nsIObserverService.h" #include "nsLayoutUtils.h" @@ -1283,12 +1279,6 @@ nsAccessibilityService::Init() NS_ADDREF(gApplicationAccessible); // will release in Shutdown() gApplicationAccessible->Init(); -#ifdef MOZ_CRASHREPORTER - CrashReporter:: - AnnotateCrashReport(NS_LITERAL_CSTRING("Accessibility"), - NS_LITERAL_CSTRING("Active")); -#endif - #ifdef XP_WIN sPendingPlugins = new nsTArray<nsCOMPtr<nsIContent> >; sPluginTimers = new nsTArray<nsCOMPtr<nsITimer> >; diff --git a/accessible/windows/msaa/IUnknownImpl.cpp b/accessible/windows/msaa/IUnknownImpl.cpp index c74f86e33..c5e614b60 100644 --- a/accessible/windows/msaa/IUnknownImpl.cpp +++ b/accessible/windows/msaa/IUnknownImpl.cpp @@ -9,10 +9,6 @@ #include "nsDebug.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - namespace mozilla { namespace a11y { diff --git a/application/palemoon/app.mozbuild b/application/palemoon/app.mozbuild index 0cbce0f72..1727d4f6b 100644 --- a/application/palemoon/app.mozbuild +++ b/application/palemoon/app.mozbuild @@ -13,5 +13,5 @@ DIRS += ['/%s' % CONFIG['MOZ_BRANDING_DIRECTORY']] # Never add tier dirs after browser because they apparently won't get # packaged properly on Mac. -DIRS += ['/browser'] +DIRS += ['/application/palemoon'] diff --git a/application/palemoon/app/blocklist.xml b/application/palemoon/app/blocklist.xml index 9c64af987..296b8ad24 100644 --- a/application/palemoon/app/blocklist.xml +++ b/application/palemoon/app/blocklist.xml @@ -1,5 +1,5 @@ <?xml version='1.0' encoding='utf-8'?> -<blocklist lastupdate="1508456048000" +<blocklist lastupdate="1521130300000" xmlns="http://www.mozilla.org/2006/addons-blocklist"> <emItems> <emItem blockID="i545" id="superlrcs@svenyor.net"> @@ -2441,6 +2441,18 @@ xmlns="http://www.mozilla.org/2006/addons-blocklist"> <versionRange minVersion="4.0.0a" maxVersion="4.1.20a" severity="1" /> </emItem> + <emItem blockID="2447476f-043b-4d0b-9d3c-8e859c97d950" id="{44e4b2cf-77ba-4f76-aca7-f3fcbc2dda2f}"> + <prefs/> + <versionRange minVersion="0" maxVersion="*" severity="3"/> + </emItem> + <emItem blockID="f58729ec-f93c-41d9-870d-dd9c9fd811b6" id="/^(addon@fasterweb\.com|\{5f398d3f-25db-47f5-b422-aa2364ff6c0b\}|addon@fasterp\.com|addon@calculator)$/"> + <prefs/> + <versionRange minVersion="0" maxVersion="*" severity="3"/> + </emItem> + <emItem blockID="3d55fab0-ec1a-4bca-84c9-3b74f5d01509" id="/^.*extension.*@asdf\.pl$/"> + <prefs/> + <versionRange minVersion="0" maxVersion="*" severity="3"/> + </emItem> <emItem blockID="pm100" id="{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}"> <versionRange minVersion="0" maxVersion="*" severity="1"> </versionRange> diff --git a/application/palemoon/app/macbuild/Contents/Info.plist.in b/application/palemoon/app/macbuild/Contents/Info.plist.in index c77ab1ec5..b224064cf 100644 --- a/application/palemoon/app/macbuild/Contents/Info.plist.in +++ b/application/palemoon/app/macbuild/Contents/Info.plist.in @@ -205,6 +205,11 @@ <true/> <key>LSApplicationCategoryType</key> <string>public.app-category.productivity</string> + <key>LSEnvironment</key> + <dict> + <key>MallocNanoZone</key> + <string>0</string> + </dict> <key>LSMinimumSystemVersion</key> <string>10.6</string> <key>LSMinimumSystemVersionByArchitecture</key> diff --git a/application/palemoon/app/moz.build b/application/palemoon/app/moz.build index 929139a6a..8b358b622 100644 --- a/application/palemoon/app/moz.build +++ b/application/palemoon/app/moz.build @@ -7,12 +7,9 @@ DIRS += ['profile/extensions'] -if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_ASAN']: - GoannaProgram(CONFIG['MOZ_APP_NAME']) -else: - GoannaProgram(CONFIG['MOZ_APP_NAME'], msvcrt='static') +GeckoProgram(CONFIG['MOZ_APP_NAME']) -JS_PREFERENCE_FILES += [ +JS_PREFERENCE_PP_FILES += [ 'profile/palemoon.js', ] @@ -30,14 +27,8 @@ FINAL_TARGET_FILES.defaults.profile += ['profile/prefs.js'] DEFINES['APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] -for var in ('MOZILLA_OFFICIAL', 'LIBXUL_SDK'): - if CONFIG[var]: - DEFINES[var] = True - -DEFINES['XPCOM_GLUE'] = True - -GENERATED_INCLUDES += [ - '/build', +LOCAL_INCLUDES += [ + '!/build', ] LOCAL_INCLUDES += [ @@ -46,11 +37,9 @@ LOCAL_INCLUDES += [ '/xpcom/build', ] -DELAYLOAD_DLLS += [ - 'mozglue.dll', +USE_LIBS += [ + 'mozglue', ] -USE_STATIC_LIBS = True - if CONFIG['_MSC_VER']: # Always enter a Windows program through wmain, whether or not we're @@ -72,16 +61,6 @@ if CONFIG['OS_ARCH'] == 'WINNT': if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']: LDFLAGS += ['/HEAP:0x40000'] -if CONFIG['OS_ARCH'] == 'WINNT': - USE_LIBS += [ - 'mozglue', - 'xpcomglue_staticruntime', - ] -else: - USE_LIBS += [ - 'xpcomglue', - ] - DISABLE_STL_WRAPPING = True if CONFIG['MOZ_LINKER']: diff --git a/application/palemoon/app/nsBrowserApp.cpp b/application/palemoon/app/nsBrowserApp.cpp index f9645b0c6..5b866d6b4 100644 --- a/application/palemoon/app/nsBrowserApp.cpp +++ b/application/palemoon/app/nsBrowserApp.cpp @@ -8,25 +8,13 @@ #include "application.ini.h" #include "nsXPCOMGlue.h" #if defined(XP_WIN) -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 #include <windows.h> -#include <winbase.h> -#include <VersionHelpers.h> #include <stdlib.h> -#include <io.h> -#include <fcntl.h> #elif defined(XP_UNIX) #include <sys/resource.h> -#include <time.h> #include <unistd.h> #endif -#ifdef XP_MACOSX -#include <mach/mach_time.h> -#include "MacQuirks.h" -#endif - #include <stdio.h> #include <stdarg.h> #include <time.h> @@ -35,20 +23,26 @@ #include "nsIFile.h" #include "nsStringGlue.h" -// Easy access to a five second startup delay used to get -// a debugger attached in the metro environment. -// #define DEBUG_delay_start_metro - #ifdef XP_WIN -// we want a wmain entry point -#include "nsWindowsWMain.cpp" -#define snprintf _snprintf +#define XRE_WANT_ENVIRON #define strcasecmp _stricmp +#ifdef MOZ_SANDBOX +#include "mozilla/sandboxing/SandboxInitialization.h" +#endif #endif #include "BinaryPath.h" #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL -#include "mozilla/StartupTimeline.h" + +#include "mozilla/Sprintf.h" +#include "mozilla/Telemetry.h" +#include "mozilla/WindowsDllBlocklist.h" + +#if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID) \ + && !(defined(XP_LINUX) && defined(MOZ_SANDBOX)) +#define MOZ_BROWSER_CAN_BE_CONTENTPROC +#include "../../ipc/contentproc/plugin-container.cpp" +#endif using namespace mozilla; @@ -56,12 +50,6 @@ using namespace mozilla; #define kOSXResourcesFolder "Resources" #endif #define kDesktopFolder "browser" -#define kMetroFolder "metro" -#define kMetroAppIniFilename "metroapp.ini" -#ifdef XP_WIN -#define kMetroTestFile "tests.ini" -const char* kMetroConsoleIdParam = "testconsoleid="; -#endif static void Output(const char *fmt, ... ) { @@ -84,10 +72,19 @@ static void Output(const char *fmt, ... ) #if MOZ_WINCONSOLE fwprintf_s(stderr, wide_msg); #else - MessageBoxW(nullptr, - wide_msg, - L"Pale Moon", - MB_OK | MB_ICONERROR | MB_SETFOREGROUND); + // Linking user32 at load-time interferes with the DLL blocklist (bug 932100). + // This is a rare codepath, so we can load user32 at run-time instead. + HMODULE user32 = LoadLibraryW(L"user32.dll"); + if (user32) { + decltype(MessageBoxW)* messageBoxW = + (decltype(MessageBoxW)*) GetProcAddress(user32, "MessageBoxW"); + if (messageBoxW) { + messageBoxW(nullptr, wide_msg, L"Pale Moon", MB_OK + | MB_ICONERROR + | MB_SETFOREGROUND); + } + FreeLibrary(user32); + } #endif #endif @@ -114,76 +111,60 @@ static bool IsArg(const char* arg, const char* s) return false; } -#ifdef XP_WIN -/* - * AttachToTestHarness - Windows helper for when we are running - * in the immersive environment. Firefox is launched by Windows in - * response to a request by metrotestharness, which is launched by - * runtests.py. As such stdout in fx doesn't point to the right - * stream. This helper touches up stdout such that test output gets - * routed to a named pipe metrotestharness creates and dumps to its - * stdout. - */ -static void AttachToTestHarness() -{ - // attach to the metrotestharness named logging pipe - HANDLE winOut = CreateFileA("\\\\.\\pipe\\metrotestharness", - GENERIC_WRITE, - FILE_SHARE_WRITE, 0, - OPEN_EXISTING, 0, 0); - - if (winOut == INVALID_HANDLE_VALUE) { - OutputDebugStringW(L"Could not create named logging pipe.\n"); - return; - } - - // Set the c runtime handle - int stdOut = _open_osfhandle((intptr_t)winOut, _O_APPEND); - if (stdOut == -1) { - OutputDebugStringW(L"Could not open c-runtime handle.\n"); - return; - } - FILE *fp = _fdopen(stdOut, "a"); - *stdout = *fp; -} -#endif - XRE_GetFileFromPathType XRE_GetFileFromPath; XRE_CreateAppDataType XRE_CreateAppData; XRE_FreeAppDataType XRE_FreeAppData; -#ifdef XRE_HAS_DLL_BLOCKLIST -XRE_SetupDllBlocklistType XRE_SetupDllBlocklist; -#endif +XRE_TelemetryAccumulateType XRE_TelemetryAccumulate; XRE_StartupTimelineRecordType XRE_StartupTimelineRecord; XRE_mainType XRE_main; XRE_StopLateWriteChecksType XRE_StopLateWriteChecks; +XRE_XPCShellMainType XRE_XPCShellMain; +XRE_GetProcessTypeType XRE_GetProcessType; +XRE_SetProcessTypeType XRE_SetProcessType; +XRE_InitChildProcessType XRE_InitChildProcess; +XRE_EnableSameExecutableForContentProcType XRE_EnableSameExecutableForContentProc; +#ifdef LIBFUZZER +XRE_LibFuzzerSetMainType XRE_LibFuzzerSetMain; +XRE_LibFuzzerGetFuncsType XRE_LibFuzzerGetFuncs; +#endif static const nsDynamicFunctionLoad kXULFuncs[] = { { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, -#ifdef XRE_HAS_DLL_BLOCKLIST - { "XRE_SetupDllBlocklist", (NSFuncPtr*) &XRE_SetupDllBlocklist }, -#endif + { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate }, { "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord }, { "XRE_main", (NSFuncPtr*) &XRE_main }, { "XRE_StopLateWriteChecks", (NSFuncPtr*) &XRE_StopLateWriteChecks }, + { "XRE_XPCShellMain", (NSFuncPtr*) &XRE_XPCShellMain }, + { "XRE_GetProcessType", (NSFuncPtr*) &XRE_GetProcessType }, + { "XRE_SetProcessType", (NSFuncPtr*) &XRE_SetProcessType }, + { "XRE_InitChildProcess", (NSFuncPtr*) &XRE_InitChildProcess }, + { "XRE_EnableSameExecutableForContentProc", (NSFuncPtr*) &XRE_EnableSameExecutableForContentProc }, +#ifdef LIBFUZZER + { "XRE_LibFuzzerSetMain", (NSFuncPtr*) &XRE_LibFuzzerSetMain }, + { "XRE_LibFuzzerGetFuncs", (NSFuncPtr*) &XRE_LibFuzzerGetFuncs }, +#endif { nullptr, nullptr } }; -static int do_main(int argc, char* argv[], nsIFile *xreDirectory) +#ifdef LIBFUZZER +int libfuzzer_main(int argc, char **argv); + +/* This wrapper is used by the libFuzzer main to call into libxul */ + +void libFuzzerGetFuncs(const char* moduleName, LibFuzzerInitFunc* initFunc, + LibFuzzerTestingFunc* testingFunc) { + return XRE_LibFuzzerGetFuncs(moduleName, initFunc, testingFunc); +} +#endif + +static int do_main(int argc, char* argv[], char* envp[], nsIFile *xreDirectory) { nsCOMPtr<nsIFile> appini; nsresult rv; uint32_t mainFlags = 0; -#ifdef XP_WIN - if (!IsWindowsVistaOrGreater()) { - Output("Couldn't load valid PE image.\n"); - return 255; - } - -#endif // Allow palemoon.exe to launch XULRunner apps via -app <application.ini> // Note that -app must be the *first* argument. const char *appDataFile = getenv("XUL_APP_FILE"); @@ -207,14 +188,26 @@ static int do_main(int argc, char* argv[], nsIFile *xreDirectory) } char appEnv[MAXPATHLEN]; - snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]); - if (putenv(appEnv)) { + SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]); + if (putenv(strdup(appEnv))) { Output("Couldn't set %s.\n", appEnv); return 255; } argv[2] = argv[0]; argv += 2; argc -= 2; + } else if (argc > 1 && IsArg(argv[1], "xpcshell")) { + for (int i = 1; i < argc; i++) { + argv[i] = argv[i + 1]; + } + + XREShellData shellData; +#if defined(XP_WIN) && defined(MOZ_SANDBOX) + shellData.sandboxBrokerServices = + sandboxing::GetInitializedBrokerServices(); +#endif + + return XRE_XPCShellMain(--argc, argv, envp, &shellData); } if (appini) { @@ -224,6 +217,13 @@ static int do_main(int argc, char* argv[], nsIFile *xreDirectory) Output("Couldn't read application.ini"); return 255; } +#if defined(HAS_DLL_BLOCKLIST) + // The dll blocklist operates in the exe vs. xullib. Pass a flag to + // xullib so automated tests can check the result once the browser + // is up and running. + appData->flags |= + DllBlocklist_CheckStatus() ? NS_XRE_DLL_BLOCKLIST_ENABLED : 0; +#endif // xreDirectory already has a refcount from NS_NewLocalFile appData->xreDirectory = xreDirectory; int result = XRE_main(argc, argv, appData, mainFlags); @@ -231,7 +231,6 @@ static int do_main(int argc, char* argv[], nsIFile *xreDirectory) return result; } - // Desktop browser launch ScopedAppData appData(&sAppData); nsCOMPtr<nsIFile> exeFile; rv = mozilla::BinaryPath::GetFile(argv[0], getter_AddRefs(exeFile)); @@ -243,10 +242,7 @@ static int do_main(int argc, char* argv[], nsIFile *xreDirectory) nsCOMPtr<nsIFile> greDir; exeFile->GetParent(getter_AddRefs(greDir)); #ifdef XP_MACOSX - nsCOMPtr<nsIFile> parent; - greDir->GetParent(getter_AddRefs(parent)); - greDir = parent.forget(); - greDir->AppendNative(NS_LITERAL_CSTRING(kOSXResourcesFolder)); + greDir->SetNativeLeafName(NS_LITERAL_CSTRING(kOSXResourcesFolder)); #endif nsCOMPtr<nsIFile> appSubdir; greDir->Clone(getter_AddRefs(appSubdir)); @@ -256,33 +252,29 @@ static int do_main(int argc, char* argv[], nsIFile *xreDirectory) // xreDirectory already has a refcount from NS_NewLocalFile appData.xreDirectory = xreDirectory; - return XRE_main(argc, argv, &appData, mainFlags); -} +#if defined(HAS_DLL_BLOCKLIST) + appData.flags |= + DllBlocklist_CheckStatus() ? NS_XRE_DLL_BLOCKLIST_ENABLED : 0; +#endif -/** - * Local TimeStamp::Now()-compatible implementation used to record timestamps - * which will be passed to XRE_StartupTimelineRecord(). - */ -static uint64_t -TimeStamp_Now() -{ -#ifdef XP_WIN - LARGE_INTEGER freq; - ::QueryPerformanceFrequency(&freq); - return GetTickCount64() * freq.QuadPart; -#elif defined(XP_MACOSX) - return mach_absolute_time(); -#elif defined(HAVE_CLOCK_MONOTONIC) - struct timespec ts; - int rv = clock_gettime(CLOCK_MONOTONIC, &ts); - - if (rv != 0) { - return 0; +#if defined(XP_WIN) && defined(MOZ_SANDBOX) + sandbox::BrokerServices* brokerServices = + sandboxing::GetInitializedBrokerServices(); +#if defined(MOZ_CONTENT_SANDBOX) + if (!brokerServices) { + Output("Couldn't initialize the broker services.\n"); + return 255; } +#endif + appData.sandboxBrokerServices = brokerServices; +#endif - uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000; - return baseNs + (uint64_t)ts.tv_nsec; +#ifdef LIBFUZZER + if (getenv("LIBFUZZER")) + XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main); #endif + + return XRE_main(argc, argv, &appData, mainFlags); } static bool @@ -298,11 +290,6 @@ FileExists(const char *path) #endif } -#ifdef LIBXUL_SDK -# define XPCOM_PATH "xulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL -#else -# define XPCOM_PATH XPCOM_DLL -#endif static nsresult InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory) { @@ -315,55 +302,13 @@ InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory) } char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); - if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_PATH) - 1)) + if (!lastSlash || + (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_DLL) - 1)) return NS_ERROR_FAILURE; - strcpy(lastSlash + 1, XPCOM_PATH); - lastSlash += sizeof(XPCOM_PATH) - sizeof(XPCOM_DLL); + strcpy(lastSlash + 1, XPCOM_DLL); if (!FileExists(exePath)) { -#if defined(LIBXUL_SDK) && defined(XP_MACOSX) - // Check for <bundle>/Contents/Frameworks/XUL.framework/libxpcom.dylib - bool greFound = false; - CFBundleRef appBundle = CFBundleGetMainBundle(); - if (!appBundle) - return NS_ERROR_FAILURE; - CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle); - CFURLRef absfwurl = nullptr; - if (fwurl) { - absfwurl = CFURLCopyAbsoluteURL(fwurl); - CFRelease(fwurl); - } - if (absfwurl) { - CFURLRef xulurl = - CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl, - CFSTR("XUL.framework"), - true); - - if (xulurl) { - CFURLRef xpcomurl = - CFURLCreateCopyAppendingPathComponent(nullptr, xulurl, - CFSTR("libxpcom.dylib"), - false); - - if (xpcomurl) { - if (CFURLGetFileSystemRepresentation(xpcomurl, true, - (UInt8*) exePath, - sizeof(exePath)) && - access(tbuffer, R_OK | X_OK) == 0) { - if (realpath(tbuffer, exePath)) { - greFound = true; - } - } - CFRelease(xpcomurl); - } - CFRelease(xulurl); - } - CFRelease(absfwurl); - } - } - if (!greFound) { -#endif Output("Could not find the Mozilla runtime.\n"); return NS_ERROR_FAILURE; } @@ -383,45 +328,72 @@ InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory) return rv; } + // This will set this thread as the main thread. NS_LogInit(); - // chop XPCOM_DLL off exePath - *lastSlash = '\0'; + if (xreDirectory) { + // chop XPCOM_DLL off exePath + *lastSlash = '\0'; #ifdef XP_MACOSX - lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); - strcpy(lastSlash + 1, kOSXResourcesFolder); + lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); + strcpy(lastSlash + 1, kOSXResourcesFolder); #endif #ifdef XP_WIN - rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), false, - xreDirectory); + rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), false, + xreDirectory); #else - rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false, - xreDirectory); + rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false, + xreDirectory); #endif + } return rv; } -int main(int argc, char* argv[]) +int main(int argc, char* argv[], char* envp[]) { -#ifdef DEBUG_delay_start_metro - Sleep(5000); + mozilla::TimeStamp start = mozilla::TimeStamp::Now(); + +#ifdef HAS_DLL_BLOCKLIST + DllBlocklist_Initialize(); + +#ifdef DEBUG + // In order to be effective against AppInit DLLs, the blocklist must be + // initialized before user32.dll is loaded into the process (bug 932100). + if (GetModuleHandleA("user32.dll")) { + fprintf(stderr, "DLL blocklist was unable to intercept AppInit DLLs.\n"); + } +#endif #endif - uint64_t start = TimeStamp_Now(); -#ifdef XP_MACOSX - TriggerQuirks(); +#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC + // We are launching as a content process, delegate to the appropriate + // main + if (argc > 1 && IsArg(argv[1], "contentproc")) { +#if defined(XP_WIN) && defined(MOZ_SANDBOX) + // We need to initialize the sandbox TargetServices before InitXPCOMGlue + // because we might need the sandbox broker to give access to some files. + if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) { + Output("Failed to initialize the sandbox target services."); + return 255; + } #endif - int gotCounters; -#if defined(XP_UNIX) - struct rusage initialRUsage; - gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage); -#elif defined(XP_WIN) - IO_COUNTERS ioCounters; - gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); + nsresult rv = InitXPCOMGlue(argv[0], nullptr); + if (NS_FAILED(rv)) { + return 255; + } + + int result = content_process_main(argc, argv); + + // InitXPCOMGlue calls NS_LogInit, so we need to balance it here. + NS_LogTerm(); + + return result; + } #endif + nsIFile *xreDirectory; nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory); @@ -431,11 +403,11 @@ int main(int argc, char* argv[]) XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start); -#ifdef XRE_HAS_DLL_BLOCKLIST - XRE_SetupDllBlocklist(); +#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC + XRE_EnableSameExecutableForContentProc(); #endif - int result = do_main(argc, argv, xreDirectory); + int result = do_main(argc, argv, envp, xreDirectory); NS_LogTerm(); diff --git a/application/palemoon/app/profile/palemoon.js b/application/palemoon/app/profile/palemoon.js index 7338a83a2..ee4a95d38 100644 --- a/application/palemoon/app/profile/palemoon.js +++ b/application/palemoon/app/profile/palemoon.js @@ -1036,6 +1036,9 @@ pref("browser.newtab.preload", false); // Toggles the content of 'about:newtab'. Shows the grid when enabled. pref("browser.newtabpage.enabled", true); +// XXX: Remove this when "enhanced" tiles are dead +pref("browser.newtabpage.enhanced", false); + // number of columns of newtab grid pref("browser.newtabpage.columns", 4); diff --git a/application/palemoon/base/content/autorecovery.js b/application/palemoon/base/content/autorecovery.js index 29ccaed3f..01a092f5c 100644 --- a/application/palemoon/base/content/autorecovery.js +++ b/application/palemoon/base/content/autorecovery.js @@ -10,9 +10,9 @@ * have been properly initialized already. */ -let Cc = Components.classes; -let Ci = Components.interfaces; -let Cu = Components.utils; +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; // Services = object with smart getters for common XPCOM services Cu.import("resource://gre/modules/Services.jsm"); diff --git a/application/palemoon/base/content/baseMenuOverlay.xul b/application/palemoon/base/content/baseMenuOverlay.xul index c6c1b16dc..f61348c9f 100644 --- a/application/palemoon/base/content/baseMenuOverlay.xul +++ b/application/palemoon/base/content/baseMenuOverlay.xul @@ -29,7 +29,7 @@ <menuitem id="menu_mac_show_all" label="&showAllAppsCmdMac.label;"/> </menupopup> <!-- Mac window menu --> -#include ../../../toolkit/content/macWindowMenu.inc +#include ../../../../toolkit/content/macWindowMenu.inc #endif #ifdef XP_WIN diff --git a/application/palemoon/base/content/browser-appmenu.inc b/application/palemoon/base/content/browser-appmenu.inc index 835bf22bc..cfc855484 100644 --- a/application/palemoon/base/content/browser-appmenu.inc +++ b/application/palemoon/base/content/browser-appmenu.inc @@ -132,38 +132,8 @@ </splitmenu> <menuseparator class="appmenu-menuseparator"/> <splitmenu id="appmenu_webDeveloper" - command="Tools:DevToolbox" label="&appMenuWebDeveloper.label;"> <menupopup id="appmenu_webDeveloper_popup"> -#ifdef MOZ_DEVTOOLS - <menuitem id="appmenu_devToolbox" - observes="devtoolsMenuBroadcaster_DevToolbox"/> - <menuseparator id="appmenu_devtools_separator"/> - <menuitem id="appmenu_devToolbar" - observes="devtoolsMenuBroadcaster_DevToolbar"/> - <menuitem id="appmenu_chromeDebugger" - observes="devtoolsMenuBroadcaster_ChromeDebugger"/> - <menuitem id="appmenu_browserConsole" - observes="devtoolsMenuBroadcaster_BrowserConsole"/> - <menuitem id="appmenu_responsiveUI" - observes="devtoolsMenuBroadcaster_ResponsiveUI"/> - <menuitem id="appmenu_eyedropper" - observes="devtoolsMenuBroadcaster_Eyedropper"/> - <menuitem id="appmenu_scratchpad" - observes="devtoolsMenuBroadcaster_Scratchpad"/> -#endif - <menuitem id="appmenu_pageSource" - observes="devtoolsMenuBroadcaster_PageSource"/> - <menuitem id="appmenu_errorConsole" - observes="devtoolsMenuBroadcaster_ErrorConsole"/> -#ifdef MOZ_DEVTOOLS - <menuitem id="appmenu_devtools_connect" - observes="devtoolsMenuBroadcaster_connect"/> -#endif - <menuseparator id="appmenu_devToolsEndSeparator"/> - <menuitem id="appmenu_getMoreDevtools" - observes="devtoolsMenuBroadcaster_GetMoreTools"/> - <menuseparator/> #define ID_PREFIX appmenu_developer_ #define OMIT_ACCESSKEYS #include browser-charsetmenu.inc @@ -173,6 +143,11 @@ type="checkbox" observes="workOfflineMenuitemState" oncommand="BrowserOffline.toggleOfflineStatus();"/> + <menuseparator/> + <menuitem id="appmenu_pageSource" + observes="devtoolsMenuBroadcaster_PageSource"/> + <menuitem id="appmenu_javascriptConsole" + observes="devtoolsMenuBroadcaster_ErrorConsole"/> </menupopup> </splitmenu> <menuseparator class="appmenu-menuseparator"/> diff --git a/application/palemoon/base/content/browser-fullScreen.js b/application/palemoon/base/content/browser-fullScreen.js index b8a29199e..400340e77 100644 --- a/application/palemoon/base/content/browser-fullScreen.js +++ b/application/palemoon/base/content/browser-fullScreen.js @@ -304,7 +304,7 @@ var FullScreen = { }, _cancelAnimation: function() { - window.mozCancelAnimationFrame(this._animationHandle); + window.cancelAnimationFrame(this._animationHandle); this._animationHandle = 0; clearTimeout(this._animationTimeout); this._isAnimating = false; diff --git a/application/palemoon/base/content/browser-fullZoom.js b/application/palemoon/base/content/browser-fullZoom.js index 0837bf7c2..890cd8440 100644 --- a/application/palemoon/base/content/browser-fullZoom.js +++ b/application/palemoon/base/content/browser-fullZoom.js @@ -1,14 +1,6 @@ -/* -#ifdef 0 - * This Source Code Form is subject to the terms of the Mozilla Public +/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -#endif - */ - -// One of the possible values for the mousewheel.* preferences. -// From nsEventStateManager.cpp. -const MOUSE_SCROLL_ZOOM = 3; + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * Controls the "full zoom" setting and its site-specific preferences. @@ -36,7 +28,6 @@ var FullZoom = { return this._siteSpecificPref; }, - //**************************************************************************// // nsISupports QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener, @@ -45,12 +36,10 @@ var FullZoom = { Ci.nsISupportsWeakReference, Ci.nsISupports]), - //**************************************************************************// // Initialization & Destruction init: function FullZoom_init() { - // Listen for scrollwheel events so we can save scrollwheel-based changes. - window.addEventListener("DOMMouseScroll", this, false); + gBrowser.addEventListener("ZoomChangeUsingMouseWheel", this); // Register ourselves with the service so we know when our pref changes. this._cps2 = Cc["@mozilla.org/content-pref/service;1"]. @@ -74,76 +63,30 @@ var FullZoom = { } // This should be nulled after initialization. - this._initialLocations.clear(); this._initialLocations = null; }, destroy: function FullZoom_destroy() { gPrefService.removeObserver("browser.zoom.", this); this._cps2.removeObserverForName(this.name, this); - window.removeEventListener("DOMMouseScroll", this, false); + gBrowser.removeEventListener("ZoomChangeUsingMouseWheel", this); }, - //**************************************************************************// // Event Handlers // nsIDOMEventListener handleEvent: function FullZoom_handleEvent(event) { switch (event.type) { - case "DOMMouseScroll": - this._handleMouseScrolled(event); + case "ZoomChangeUsingMouseWheel": + let browser = this._getTargetedBrowser(event); + this._ignorePendingZoomAccesses(browser); + this._applyZoomToPref(browser); break; } }, - _handleMouseScrolled: function FullZoom__handleMouseScrolled(event) { - // Construct the "mousewheel action" pref key corresponding to this event. - // Based on nsEventStateManager::WheelPrefs::GetBasePrefName(). - var pref = "mousewheel."; - - var pressedModifierCount = event.shiftKey + event.ctrlKey + event.altKey + - event.metaKey + event.getModifierState("OS"); - if (pressedModifierCount != 1) { - pref += "default."; - } else if (event.shiftKey) { - pref += "with_shift."; - } else if (event.ctrlKey) { - pref += "with_control."; - } else if (event.altKey) { - pref += "with_alt."; - } else if (event.metaKey) { - pref += "with_meta."; - } else { - pref += "with_win."; - } - - pref += "action"; - - // Don't do anything if this isn't a "zoom" scroll event. - var isZoomEvent = false; - try { - isZoomEvent = (gPrefService.getIntPref(pref) == MOUSE_SCROLL_ZOOM); - } catch (e) {} - if (!isZoomEvent) - return; - - // XXX Lazily cache all the possible action prefs so we don't have to get - // them anew from the pref service for every scroll event? We'd have to - // make sure to observe them so we can update the cache when they change. - - // We have to call _applyZoomToPref in a timeout because we handle the - // event before the event state manager has a chance to apply the zoom - // during nsEventStateManager::PostHandleEvent. - let browser = gBrowser.selectedBrowser; - let token = this._getBrowserToken(browser); - window.setTimeout(function () { - if (token.isCurrent) - this._applyZoomToPref(browser); - }.bind(this), 0); - }, - // nsIObserver observe: function (aSubject, aTopic, aData) { @@ -165,12 +108,12 @@ var FullZoom = { // nsIContentPrefObserver - onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue) { - this._onContentPrefChanged(aGroup, aValue); + onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue, aIsPrivate) { + this._onContentPrefChanged(aGroup, aValue, aIsPrivate); }, - onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName) { - this._onContentPrefChanged(aGroup, undefined); + onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName, aIsPrivate) { + this._onContentPrefChanged(aGroup, undefined, aIsPrivate); }, /** @@ -181,7 +124,7 @@ var FullZoom = { * @param aValue The new value of the changed preference. Pass undefined to * indicate the preference's removal. */ - _onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue) { + _onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue, aIsPrivate) { if (this._isNextContentPrefChangeInternal) { // Ignore changes that FullZoom itself makes. This works because the // content pref service calls callbacks before notifying observers, and it @@ -194,9 +137,10 @@ var FullZoom = { if (!browser.currentURI) return; + let ctxt = this._loadContextFromBrowser(browser); let domain = this._cps2.extractDomain(browser.currentURI.spec); if (aGroup) { - if (aGroup == domain) + if (aGroup == domain && ctxt.usePrivateBrowsing == aIsPrivate) this._applyPrefToZoom(aValue, browser); return; } @@ -208,10 +152,9 @@ var FullZoom = { // zoom should be set to the new global preference now that the global // preference has changed. let hasPref = false; - let ctxt = this._loadContextFromBrowser(browser); let token = this._getBrowserToken(browser); this._cps2.getByDomainAndName(browser.currentURI.spec, this.name, ctxt, { - handleResult: function () hasPref = true, + handleResult: function () { hasPref = true; }, handleCompletion: function () { if (!hasPref && token.isCurrent) this._applyPrefToZoom(undefined, browser); @@ -234,6 +177,7 @@ var FullZoom = { */ onLocationChange: function FullZoom_onLocationChange(aURI, aIsTabSwitch, aBrowser) { let browser = aBrowser || gBrowser.selectedBrowser; + // If we haven't been initialized yet but receive an onLocationChange // notification then let's store and replay it upon initialization. if (this._initialLocations) { @@ -247,14 +191,14 @@ var FullZoom = { this._ignorePendingZoomAccesses(browser); if (!aURI || (aIsTabSwitch && !this.siteSpecific)) { - this._notifyOnLocationChange(); + this._notifyOnLocationChange(browser); return; } // Avoid the cps roundtrip and apply the default/global pref. if (aURI.spec == "about:blank") { this._applyPrefToZoom(undefined, browser, - this._notifyOnLocationChange.bind(this)); + this._notifyOnLocationChange.bind(this, browser)); return; } @@ -262,7 +206,7 @@ var FullZoom = { if (!aIsTabSwitch && browser.isSyntheticDocument) { ZoomManager.setZoomForBrowser(browser, 1); // _ignorePendingZoomAccesses already called above, so no need here. - this._notifyOnLocationChange(); + this._notifyOnLocationChange(browser); return; } @@ -271,7 +215,7 @@ var FullZoom = { let pref = this._cps2.getCachedByDomainAndName(aURI.spec, this.name, ctxt); if (pref) { this._applyPrefToZoom(pref.value, browser, - this._notifyOnLocationChange.bind(this)); + this._notifyOnLocationChange.bind(this, browser)); return; } @@ -279,14 +223,14 @@ var FullZoom = { let value = undefined; let token = this._getBrowserToken(browser); this._cps2.getByDomainAndName(aURI.spec, this.name, ctxt, { - handleResult: function (resultPref) value = resultPref.value, + handleResult: function (resultPref) { value = resultPref.value; }, handleCompletion: function () { if (!token.isCurrent) { - this._notifyOnLocationChange(); + this._notifyOnLocationChange(browser); return; } this._applyPrefToZoom(value, browser, - this._notifyOnLocationChange.bind(this)); + this._notifyOnLocationChange.bind(this, browser)); }.bind(this) }); }, @@ -299,7 +243,6 @@ var FullZoom = { menuItem.setAttribute("checked", !ZoomManager.useFullZoom); }, - //**************************************************************************// // Setting & Pref Manipulation /** @@ -323,19 +266,32 @@ var FullZoom = { }, /** - * Sets the zoom level of the page in the current browser to the global zoom + * Sets the zoom level for the given browser to the given floating + * point value, where 1 is the default zoom level. + */ + setZoom: function (value, browser = gBrowser.selectedBrowser) { + ZoomManager.setZoomForBrowser(browser, value); + this._ignorePendingZoomAccesses(browser); + this._applyZoomToPref(browser); + }, + + /** + * Sets the zoom level of the page in the given browser to the global zoom * level. + * + * @return A promise which resolves when the zoom reset has been applied. */ - reset: function FullZoom_reset() { - let browser = gBrowser.selectedBrowser; + reset: function FullZoom_reset(browser = gBrowser.selectedBrowser) { let token = this._getBrowserToken(browser); - this._getGlobalValue(browser, function (value) { + let result = this._getGlobalValue(browser).then(value => { if (token.isCurrent) { ZoomManager.setZoomForBrowser(browser, value === undefined ? 1 : value); this._ignorePendingZoomAccesses(browser); + Services.obs.notifyObservers(browser, "browser-fullZoom:zoomReset", ""); } }); this._removePref(browser); + return result; }, /** @@ -383,7 +339,7 @@ var FullZoom = { } let token = this._getBrowserToken(aBrowser); - this._getGlobalValue(aBrowser, function (value) { + this._getGlobalValue(aBrowser).then(value => { if (token.isCurrent) { ZoomManager.setZoomForBrowser(aBrowser, value === undefined ? 1 : value); this._ignorePendingZoomAccesses(aBrowser); @@ -399,6 +355,7 @@ var FullZoom = { * @param browser The zoom of this browser will be saved. Required. */ _applyZoomToPref: function FullZoom__applyZoomToPref(browser) { + Services.obs.notifyObservers(browser, "browser-fullZoom:zoomChange", ""); if (!this.siteSpecific || gInPrintPreviewMode || browser.isSyntheticDocument) @@ -419,6 +376,7 @@ var FullZoom = { * @param browser The zoom of this browser will be removed. Required. */ _removePref: function FullZoom__removePref(browser) { + Services.obs.notifyObservers(browser, "browser-fullZoom:zoomReset", ""); if (browser.isSyntheticDocument) return; let ctxt = this._loadContextFromBrowser(browser); @@ -429,7 +387,6 @@ var FullZoom = { }); }, - //**************************************************************************// // Utilities /** @@ -462,6 +419,30 @@ var FullZoom = { }, /** + * Returns the browser that the supplied zoom event is associated with. + * @param event The ZoomChangeUsingMouseWheel event. + * @return The associated browser element, if one exists, otherwise null. + */ + _getTargetedBrowser: function FullZoom__getTargetedBrowser(event) { + let target = event.originalTarget; + + // With remote content browsers, the event's target is the browser + // we're looking for. + const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + if (target instanceof window.XULElement && + target.localName == "browser" && + target.namespaceURI == XUL_NS) + return target; + + // With in-process content browsers, the event's target is the content + // document. + if (target.nodeType == Node.DOCUMENT_NODE) + return gBrowser.getBrowserForDocument(target); + + throw new Error("Unexpected ZoomChangeUsingMouseWheel event source"); + }, + + /** * Increments the zoom change token for the given browser so that pending * async operations know that it may be unsafe to access they zoom when they * finish. @@ -491,54 +472,49 @@ var FullZoom = { /** * Gets the global browser.content.full-zoom content preference. * - * WARNING: callback may be called synchronously or asynchronously. The - * reason is that it's usually desirable to avoid turns of the event loop - * where possible, since they can lead to visible, jarring jumps in zoom - * level. It's not always possible to avoid them, though. As a convenience, - * then, this method takes a callback and returns nothing. - * - * @param browser The content browser pertaining to the zoom. - * @param callback Synchronously or asynchronously called when done. It's - * bound to this object (FullZoom) and called as: - * callback(prefValue) + * @param browser The browser pertaining to the zoom. + * @returns Promise<prefValue> + * Resolves to the preference value when done. */ - _getGlobalValue: function FullZoom__getGlobalValue(browser, callback) { + _getGlobalValue: function FullZoom__getGlobalValue(browser) { // * !("_globalValue" in this) => global value not yet cached. // * this._globalValue === undefined => global value known not to exist. // * Otherwise, this._globalValue is a number, the global value. - if ("_globalValue" in this) { - callback.call(this, this._globalValue, true); - return; - } - let value = undefined; - this._cps2.getGlobal(this.name, this._loadContextFromBrowser(browser), { - handleResult: function (pref) value = pref.value, - handleCompletion: function (reason) { - this._globalValue = this._ensureValid(value); - callback.call(this, this._globalValue); - }.bind(this) + return new Promise(resolve => { + if ("_globalValue" in this) { + resolve(this._globalValue); + return; + } + let value = undefined; + this._cps2.getGlobal(this.name, this._loadContextFromBrowser(browser), { + handleResult: function (pref) { value = pref.value; }, + handleCompletion: (reason) => { + this._globalValue = this._ensureValid(value); + resolve(this._globalValue); + } + }); }); }, /** - * Gets the load context from the given content browser. + * Gets the load context from the given Browser. * * @param Browser The Browser whose load context will be returned. - * @return The nsILoadContext of the given Browser. + * @return The nsILoadContext of the given Browser. */ _loadContextFromBrowser: function FullZoom__loadContextFromBrowser(browser) { return browser.loadContext; }, /** - * Asynchronously broadcasts a "browser-fullZoom:locationChange" notification - * so that tests can select tabs, load pages, etc. and be notified when the - * zoom levels on those pages change. The notification is always asynchronous - * so that observers are guaranteed a consistent behavior. + * Asynchronously broadcasts "browser-fullZoom:location-change" so that + * listeners can be notified when the zoom levels on those pages change. + * The notification is always asynchronous so that observers are guaranteed a + * consistent behavior. */ - _notifyOnLocationChange: function FullZoom__notifyOnLocationChange() { + _notifyOnLocationChange: function FullZoom__notifyOnLocationChange(browser) { this._executeSoon(function () { - Services.obs.notifyObservers(null, "browser-fullZoom:locationChange", ""); + Services.obs.notifyObservers(browser, "browser-fullZoom:location-change", ""); }); }, diff --git a/application/palemoon/base/content/browser-menubar.inc b/application/palemoon/base/content/browser-menubar.inc index fa9d7f0f4..fc6bc7694 100644 --- a/application/palemoon/base/content/browser-menubar.inc +++ b/application/palemoon/base/content/browser-menubar.inc @@ -534,43 +534,12 @@ label="&webDeveloperMenu.label;" accesskey="&webDeveloperMenu.accesskey;"> <menupopup id="menuWebDeveloperPopup"> -#ifdef MOZ_DEVTOOLS - <menuitem id="menu_devToolbox" - observes="devtoolsMenuBroadcaster_DevToolbox" - accesskey="&devToolboxMenuItem.accesskey;"/> - <menuseparator id="menu_devtools_separator"/> - <menuitem id="menu_devToolbar" - observes="devtoolsMenuBroadcaster_DevToolbar" - accesskey="&devToolbarMenu.accesskey;"/> - <menuitem id="menu_chromeDebugger" - observes="devtoolsMenuBroadcaster_ChromeDebugger"/> - <menuitem id="menu_browserConsole" - observes="devtoolsMenuBroadcaster_BrowserConsole" - accesskey="&browserConsoleCmd.accesskey;"/> - <menuitem id="menu_responsiveUI" - observes="devtoolsMenuBroadcaster_ResponsiveUI" - accesskey="&responsiveDesignTool.accesskey;"/> - <menuitem id="menu_eyedropper" - observes="devtoolsMenuBroadcaster_Eyedropper" - accesskey="&eyedropper.accesskey;"/> - <menuitem id="menu_scratchpad" - observes="devtoolsMenuBroadcaster_Scratchpad" - accesskey="&scratchpad.accesskey;"/> -#endif <menuitem id="menu_pageSource" observes="devtoolsMenuBroadcaster_PageSource" accesskey="&pageSourceCmd.accesskey;"/> <menuitem id="javascriptConsole" observes="devtoolsMenuBroadcaster_ErrorConsole" accesskey="&errorConsoleCmd.accesskey;"/> -#ifdef MOZ_DEVTOOLS - <menuitem id="menu_devtools_connect" - observes="devtoolsMenuBroadcaster_connect"/> -#endif - <menuseparator id="devToolsEndSeparator"/> - <menuitem id="getMoreDevtools" - observes="devtoolsMenuBroadcaster_GetMoreTools" - accesskey="&getMoreDevtoolsCmd.accesskey;"/> </menupopup> </menu> <menuitem id="menu_pageInfo" diff --git a/application/palemoon/base/content/browser-sets.inc b/application/palemoon/base/content/browser-sets.inc index 78cfb7faa..64228678e 100644 --- a/application/palemoon/base/content/browser-sets.inc +++ b/application/palemoon/base/content/browser-sets.inc @@ -92,24 +92,9 @@ <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/> <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/> -#ifdef MOZ_DEVTOOLS - <command id="Tools:DevToolbox" oncommand="gDevToolsBrowser.toggleToolboxCommand(gBrowser);"/> - <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/> - <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focusToggle();" disabled="true"/> - <command id="Tools:DevAppMgr" oncommand="gDevToolsBrowser.openAppManager(gBrowser);" disabled="true" hidden="true"/> - <command id="Tools:WebIDE" oncommand="gDevToolsBrowser.openWebIDE();" disabled="true" hidden="true"/> - <command id="Tools:ChromeDebugger" oncommand="BrowserToolboxProcess.init();" disabled="true" hidden="true"/> - <command id="Tools:BrowserConsole" oncommand="HUDService.openBrowserConsoleOrFocus();"/> - <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true" hidden="true"/> - <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/> - <command id="Tools:Eyedropper" oncommand="openEyedropper();"/> -#endif <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/> <command id="Tools:Permissions" oncommand="BrowserOpenPermissionsMgr();"/> <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/> -#ifdef MOZ_DEVTOOLS - <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/> -#endif <command id="Tools:Sanitize" oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/> <command id="Tools:PrivateBrowsing" @@ -170,46 +155,6 @@ #endif <broadcaster id="workOfflineMenuitemState"/> -#ifdef MOZ_DEVTOOLS - <!-- DevTools broadcasters --> - <broadcaster id="devtoolsMenuBroadcaster_DevToolbox" - label="&devToolboxMenuItem.label;" - type="checkbox" autocheck="false" - command="Tools:DevToolbox" - key="key_devToolbox"/> - <broadcaster id="devtoolsMenuBroadcaster_DevToolbar" - label="&devToolbarMenu.label;" - type="checkbox" autocheck="false" - command="Tools:DevToolbar" - key="key_devToolbar"/> - <broadcaster id="devtoolsMenuBroadcaster_DevAppMgr" - label="&devAppMgrMenu.label;" - command="Tools:DevAppMgr"/> - <broadcaster id="devtoolsMenuBroadcaster_webide" - label="&webide.label;" - command="Tools:WebIDE" - key="key_webide"/> - <broadcaster id="devtoolsMenuBroadcaster_ChromeDebugger" - label="&chromeDebuggerMenu.label;" - command="Tools:ChromeDebugger"/> - <broadcaster id="devtoolsMenuBroadcaster_BrowserConsole" - label="&browserConsoleCmd.label;" - key="key_browserConsole" - command="Tools:BrowserConsole"/> - <broadcaster id="devtoolsMenuBroadcaster_Scratchpad" - label="&scratchpad.label;" - command="Tools:Scratchpad" - key="key_scratchpad"/> - <broadcaster id="devtoolsMenuBroadcaster_ResponsiveUI" - label="&responsiveDesignTool.label;" - type="checkbox" autocheck="false" - command="Tools:ResponsiveUI" - key="key_responsiveUI"/> - <broadcaster id="devtoolsMenuBroadcaster_Eyedropper" - label="&eyedropper.label;" - type="checkbox" autocheck="false" - command="Tools:Eyedropper"/> -#endif <broadcaster id="devtoolsMenuBroadcaster_PageSource" label="&pageSourceCmd.label;" key="key_viewSource" @@ -217,14 +162,6 @@ <broadcaster id="devtoolsMenuBroadcaster_ErrorConsole" label="&errorConsoleCmd.label;" command="Tools:ErrorConsole"/> - <broadcaster id="devtoolsMenuBroadcaster_GetMoreTools" - label="&getMoreDevtoolsCmd.label;" - oncommand="openUILinkIn(gPrefService.getCharPref('browser.getdevtools.url'), 'tab');"/> -#ifdef MOZ_DEVTOOLS - <broadcaster id="devtoolsMenuBroadcaster_connect" - label="&devtoolsConnect.label;" - command="Tools:DevToolsConnect"/> -#endif </broadcasterset> <keyset id="mainKeyset"> @@ -271,21 +208,6 @@ <key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/> #endif <key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/> -#ifdef MOZ_DEVTOOLS - <key id="key_browserConsole" key="&browserConsoleCmd.commandkey;" command="Tools:BrowserConsole" modifiers="accel,shift"/> - <key id="key_devToolbox" keycode="VK_F12" keytext="F12" command="Tools:DevToolbox"/> - <key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift" - keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/> - <key id="key_responsiveUI" key="&responsiveDesignTool.commandkey;" command="Tools:ResponsiveUI" -#ifdef XP_MACOSX - modifiers="accel,alt" -#else - modifiers="accel,shift" -#endif - /> - <key id="key_scratchpad" keycode="&scratchpad.keycode;" modifiers="shift" - keytext="&scratchpad.keytext;" command="Tools:Scratchpad"/> -#endif <key id="openFileKb" key="&openFileCmd.commandkey;" command="Browser:OpenFile" modifiers="accel"/> <key id="key_savePage" key="&savePageCmd.commandkey;" command="Browser:SavePage" modifiers="accel"/> <key id="printKb" key="&printCmd.commandkey;" command="cmd_print" modifiers="accel"/> diff --git a/application/palemoon/base/content/browser-thumbnails.js b/application/palemoon/base/content/browser-thumbnails.js index dbe33e3ed..b06dfd503 100644 --- a/application/palemoon/base/content/browser-thumbnails.js +++ b/application/palemoon/base/content/browser-thumbnails.js @@ -92,7 +92,12 @@ let gBrowserThumbnails = { filterForThumbnailExpiration: function Thumbnails_filterForThumbnailExpiration(aCallback) { - aCallback([browser.currentURI.spec for (browser of gBrowser.browsers)]); + // Tycho: aCallback([browser.currentURI.spec for (browser of gBrowser.browsers)]); + let result = []; + for (let browser of gBrowser.browsers) { + result.push(browser.currentURI.spec); + } + aCallback(result); }, /** @@ -137,7 +142,7 @@ let gBrowserThumbnails = { // FIXME Bug 720575 - Don't capture thumbnails for SVG or XML documents as // that currently regresses Talos SVG tests. - if (doc instanceof SVGDocument || doc instanceof XMLDocument) + if (doc instanceof XMLDocument) return false; // There's no point in taking screenshot of loading pages. diff --git a/application/palemoon/base/content/browser.css b/application/palemoon/base/content/browser.css index 2c8ba3e69..e6a84421b 100644 --- a/application/palemoon/base/content/browser.css +++ b/application/palemoon/base/content/browser.css @@ -115,8 +115,17 @@ toolbar[printpreview="true"] { #titlebar { -moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox"); + -moz-window-dragging: drag; } +%ifdef XP_WIN +#main-window[tabsontop="true"] #TabsToolbar, +#main-window[tabsontop="true"] #toolbar-menubar, +#main-window[tabsontop="true"] #navigator-toolbox > toolbar:-moz-lwtheme { + -moz-window-dragging: drag; +} +%endif + #titlebar-spacer { pointer-events: none; } diff --git a/application/palemoon/base/content/browser.js b/application/palemoon/base/content/browser.js index 34b91b6cb..8cc091e85 100644 --- a/application/palemoon/base/content/browser.js +++ b/application/palemoon/base/content/browser.js @@ -3,8 +3,8 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -let Ci = Components.interfaces; -let Cu = Components.utils; +var Ci = Components.interfaces; +var Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource:///modules/RecentWindow.jsm"); @@ -109,20 +109,6 @@ XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () { } }); -#ifdef MOZ_DEVTOOLS -XPCOMUtils.defineLazyGetter(this, "DeveloperToolbar", function() { - let tmp = {}; - Cu.import("resource://gre/modules/devtools/DeveloperToolbar.jsm", tmp); - return new tmp.DeveloperToolbar(window, document.getElementById("developer-toolbar")); -}); - -XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function() { - let tmp = {}; - Cu.import("resource://gre/modules/devtools/ToolboxProcess.jsm", tmp); - return tmp.BrowserToolboxProcess; -}); -#endif - XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", "resource://gre/modules/PageThumbs.jsm"); @@ -152,7 +138,11 @@ let gInitialPages = [ #include browser-plugins.js #include browser-tabPreviews.js #include browser-thumbnails.js + +#ifdef MOZ_WEBRTC #include browser-webrtcUI.js +#endif + #include browser-gestureSupport.js #ifdef MOZ_SERVICES_SYNC @@ -336,6 +326,48 @@ const gSessionHistoryObserver = { } }; +var gURLBarSettings = { + prefSuggest: "browser.urlbar.suggest.", + /* + For searching in the source code: + browser.urlbar.suggest.bookmark + browser.urlbar.suggest.history + browser.urlbar.suggest.openpage + */ + prefSuggests: [ + "bookmark", + "history", + "openpage" + ], + prefKeyword: "keyword.enabled", + + observe: function(aSubject, aTopic, aData) { + if (aTopic != "nsPref:changed") + return; + + this.writePlaceholder(); + }, + + writePlaceholder: function() { + let attribute = "placeholder"; + let prefs = this.prefSuggests.map(pref => { + return this.prefSuggest + pref; + }); + prefs.push(this.prefKeyword); + let placeholderDefault = prefs.some(pref => { + return gPrefService.getBoolPref(pref); + }); + + if (placeholderDefault) { + gURLBar.setAttribute( + attribute, gNavigatorBundle.getString("urlbar.placeholder")); + } else { + gURLBar.setAttribute( + attribute, gNavigatorBundle.getString("urlbar.placeholderURLOnly")); + } + } +}; + /** * Given a starting docshell and a URI to look up, find the docshell the URI * is loaded in. @@ -663,6 +695,8 @@ const gXSSObserver = { }; var gBrowserInit = { + delayedStartupFinished: false, + onLoad: function() { gMultiProcessBrowser = gPrefService.getBoolPref("browser.tabs.remote"); @@ -968,11 +1002,18 @@ var gBrowserInit = { Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false); Services.obs.addObserver(gXSSObserver, "xss-on-violate-policy", false); + gPrefService.addObserver(gURLBarSettings.prefSuggest, gURLBarSettings, false); + gPrefService.addObserver(gURLBarSettings.prefKeyword, gURLBarSettings, false); + + gURLBarSettings.writePlaceholder(); + BrowserOffline.init(); OfflineApps.init(); IndexedDBPromptHelper.init(); AddonManager.addAddonListener(AddonsMgrListener); +#ifdef MOZ_WEBRTC WebrtcIndicator.init(); +#endif // Ensure login manager is up and running. Services.logins; @@ -1114,27 +1155,6 @@ var gBrowserInit = { setUrlAndSearchBarWidthForConditionalForwardButton(); }); -#ifdef MOZ_DEVTOOLS - // Enable Chrome Debugger? - let chromeEnabled = gPrefService.getBoolPref("devtools.chrome.enabled"); - let remoteEnabled = chromeEnabled && - gPrefService.getBoolPref("devtools.debugger.chrome-enabled") && - gPrefService.getBoolPref("devtools.debugger.remote-enabled"); - if (remoteEnabled) { - let cmd = document.getElementById("Tools:ChromeDebugger"); - cmd.removeAttribute("disabled"); - cmd.removeAttribute("hidden"); - } - - // Enable Scratchpad in the UI, if the preference allows this. - let scratchpadEnabled = gPrefService.getBoolPref(Scratchpad.prefEnabledName); - if (scratchpadEnabled) { - let cmd = document.getElementById("Tools:Scratchpad"); - cmd.removeAttribute("disabled"); - cmd.removeAttribute("hidden"); - } -#endif - // Enable Error Console? let consoleEnabled = gPrefService.getBoolPref("devtools.errorconsole.enabled"); if (consoleEnabled) { @@ -1152,19 +1172,6 @@ var gBrowserInit = { document.getElementById("appmenu_charsetMenu").hidden = true; #endif -#ifdef MOZ_DEVTOOLS - // Enable Responsive UI? - let responsiveUIEnabled = gPrefService.getBoolPref("devtools.responsiveUI.enabled"); - if (responsiveUIEnabled) { - let cmd = document.getElementById("Tools:ResponsiveUI"); - cmd.removeAttribute("disabled"); - cmd.removeAttribute("hidden"); - } - - // Add Devtools menuitems and listeners - gDevToolsBrowser.registerBrowserWindow(window); -#endif - let appMenuButton = document.getElementById("appmenu-button"); let appMenuPopup = document.getElementById("appmenu-popup"); if (appMenuButton && appMenuPopup) { @@ -1205,6 +1212,8 @@ var gBrowserInit = { setTimeout(function () { BrowserChromeTest.markAsReady(); }, 0); }); + this.delayedStartupFinished = true; + Services.obs.notifyObservers(window, "browser-delayed-startup-finished", ""); }, @@ -1240,15 +1249,6 @@ var gBrowserInit = { if (!this._loadHandled) return; -#ifdef MOZ_DEVTOOLS - gDevToolsBrowser.forgetBrowserWindow(window); - - let desc = Object.getOwnPropertyDescriptor(window, "DeveloperToolbar"); - if (desc && !desc.get) { - DeveloperToolbar.destroy(); - } -#endif - // First clean up services initialized in gBrowserInit.onLoad (or those whose // uninit methods don't depend on the services having been initialized). @@ -1314,6 +1314,13 @@ var gBrowserInit = { Services.obs.removeObserver(gXSSObserver, "xss-on-violate-policy"); try { + gPrefService.removeObserver(gURLBarSettings.prefSuggest, gURLBarSettings); + gPrefService.removeObserver(gURLBarSettings.prefKeyword, gURLBarSettings); + } catch (ex) { + Cu.reportError(ex); + } + + try { gPrefService.removeObserver(gHomeButton.prefDomain, gHomeButton); } catch (ex) { Cu.reportError(ex); @@ -6825,20 +6832,9 @@ var TabContextMenu = { }; #ifdef MOZ_DEVTOOLS +// Note: Do not delete! It is used for: base/content/nsContextMenu.js XPCOMUtils.defineLazyModuleGetter(this, "gDevTools", - "resource://gre/modules/devtools/gDevTools.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "gDevToolsBrowser", - "resource://gre/modules/devtools/gDevTools.jsm"); - -Object.defineProperty(this, "HUDService", { - get: function HUDService_getter() { - let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools; - return devtools.require("devtools/webconsole/hudservice").HUDService; - }, - configurable: true, - enumerable: true -}); + "resource://devtools/client/framework/gDevTools.jsm"); #endif // Prompt user to restart the browser in safe mode or normally @@ -6929,49 +6925,6 @@ function toggleAddonBar() { setToolbarVisibility(addonBar, addonBar.collapsed); } -#ifdef MOZ_DEVTOOLS -var Scratchpad = { - prefEnabledName: "devtools.scratchpad.enabled", - - openScratchpad: function SP_openScratchpad() { - return this.ScratchpadManager.openScratchpad(); - } -}; - -XPCOMUtils.defineLazyGetter(Scratchpad, "ScratchpadManager", function() { - let tmp = {}; - Cu.import("resource://gre/modules/devtools/scratchpad-manager.jsm", tmp); - return tmp.ScratchpadManager; -}); - -var ResponsiveUI = { - toggle: function RUI_toggle() { - this.ResponsiveUIManager.toggle(window, gBrowser.selectedTab); - } -}; - -XPCOMUtils.defineLazyGetter(ResponsiveUI, "ResponsiveUIManager", function() { - let tmp = {}; - Cu.import("resource://gre/modules/devtools/responsivedesign.jsm", tmp); - return tmp.ResponsiveUIManager; -}); - -function openEyedropper() { - var eyedropper = new this.Eyedropper(this, { context: "menu", - copyOnSelect: true }); - eyedropper.open(); -} - -Object.defineProperty(this, "Eyedropper", { - get: function() { - let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools; - return devtools.require("devtools/eyedropper/eyedropper").Eyedropper; - }, - configurable: true, - enumerable: true -}); -#endif - XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () { #ifdef XP_WIN // Only show resizers on Windows 2000 and XP diff --git a/application/palemoon/base/content/browser.xul b/application/palemoon/base/content/browser.xul index f83010023..0a0ce01dc 100644 --- a/application/palemoon/base/content/browser.xul +++ b/application/palemoon/base/content/browser.xul @@ -410,7 +410,7 @@ <toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true" title="&locationItem.title;" class="chromeclass-location" removable="true"> <textbox id="urlbar" flex="1" - placeholder="&urlbar.placeholder2;" + placeholder="" type="autocomplete" autocompletesearch="urlinline history" autocompletesearchparam="enable-actions" @@ -440,8 +440,10 @@ <image id="alert-plugins-notification-icon" class="notification-anchor-icon" role="button"/> <image id="blocked-plugins-notification-icon" class="notification-anchor-icon" role="button"/> <image id="mixed-content-blocked-notification-icon" class="notification-anchor-icon" role="button"/> +#ifdef MOZ_WEBRTC <image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"/> <image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"/> +#endif <image id="pointerLock-notification-icon" class="notification-anchor-icon" role="button"/> <image id="servicesInstall-notification-icon" class="notification-anchor-icon" role="button"/> </box> @@ -513,7 +515,7 @@ flex="100" persist="width" removable="true"> <searchbar id="searchbar" flex="1"/> </toolbaritem> - +#ifdef MOZ_WEBRTC <toolbarbutton id="webrtc-status-button" class="toolbarbutton-1 chromeclass-toolbar-additional" type="menu" @@ -525,7 +527,7 @@ onpopuphiding="WebrtcIndicator.clearPopup(this);" oncommand="WebrtcIndicator.menuCommand(event.target);"/> </toolbarbutton> - +#endif <toolbarbutton id="bookmarks-menu-button" class="toolbarbutton-1 chromeclass-toolbar-additional" persist="class" @@ -971,33 +973,6 @@ <vbox id="browser-bottombox" layer="true"> <notificationbox id="global-notificationbox"/> -#ifdef MOZ_DEVTOOLS - <toolbar id="developer-toolbar" - class="devtools-toolbar" - hidden="true"> -#ifdef XP_MACOSX - <toolbarbutton id="developer-toolbar-closebutton" - class="devtools-closebutton" - oncommand="DeveloperToolbar.hide();" - tooltiptext="&devToolbarCloseButton.tooltiptext;"/> -#endif - <stack class="gclitoolbar-stack-node" flex="1"> - <textbox class="gclitoolbar-input-node" rows="1"/> - <hbox class="gclitoolbar-complete-node"/> - </stack> - <toolbarbutton id="developer-toolbar-toolbox-button" - class="developer-toolbar-button" - observes="devtoolsMenuBroadcaster_DevToolbox" - tooltiptext="&devToolbarToolsButton.tooltip;"/> -#ifndef XP_MACOSX - <toolbarbutton id="developer-toolbar-closebutton" - class="devtools-closebutton" - oncommand="DeveloperToolbar.hide();" - tooltiptext="&devToolbarCloseButton.tooltiptext;"/> -#endif - </toolbar> -#endif - <toolbar id="addon-bar" toolbarname="&statusBar.label;" accesskey="&statusBar.accesskey;" collapsed="true" diff --git a/application/palemoon/base/content/content.js b/application/palemoon/base/content/content.js index 19032eb84..19c8b0682 100644 --- a/application/palemoon/base/content/content.js +++ b/application/palemoon/base/content/content.js @@ -3,9 +3,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -let Cc = Components.classes; -let Ci = Components.interfaces; -let Cu = Components.utils; +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); @@ -13,6 +13,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent", "resource://gre/modules/LoginManagerContent.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "LoginFormFactory", + "resource://gre/modules/LoginManagerContent.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "InsecurePasswordUtils", "resource://gre/modules/InsecurePasswordUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "FormSubmitObserver", @@ -47,8 +49,9 @@ addMessageListener("Browser:HideSessionRestoreButton", function (message) { }); addEventListener("DOMFormHasPassword", function(event) { - InsecurePasswordUtils.checkForInsecurePasswords(event.target); - LoginManagerContent.onFormPassword(event); + LoginManagerContent.onDOMFormHasPassword(event, content); + let formLike = LoginFormFactory.createFromForm(event.target); + InsecurePasswordUtils.reportInsecurePasswords(formLike); }); addEventListener("DOMAutoComplete", function(event) { LoginManagerContent.onUsernameInput(event); @@ -61,4 +64,8 @@ addEventListener("blur", function(event) { addMessageListener("Finder:Initialize", function () { let {RemoteFinderListener} = Cu.import("resource://gre/modules/RemoteFinder.jsm", {}); new RemoteFinderListener(global); -});
\ No newline at end of file +}); + +addEventListener("DOMWebNotificationClicked", function(event) { + sendAsyncMessage("DOMWebNotificationClicked", {}); +}, false); diff --git a/application/palemoon/base/content/newtab/grid.js b/application/palemoon/base/content/newtab/grid.js index 37559a063..3b7dfc35f 100644 --- a/application/palemoon/base/content/newtab/grid.js +++ b/application/palemoon/base/content/newtab/grid.js @@ -109,7 +109,12 @@ let gGrid = { // (Re-)initialize all cells. let cellElements = this.node.querySelectorAll(".newtab-cell"); - this._cells = [new Cell(this, cell) for (cell of cellElements)]; + // Tycho: this._cells = [new Cell(this, cell) for (cell of cellElements)]; + this.cells = []; + + for (let cellItem of cellElements) { + this.cells.push(new Cell(this, cellItem)); + } }, /** diff --git a/application/palemoon/base/content/newtab/newTab.js b/application/palemoon/base/content/newtab/newTab.js index 77c929125..6d8647ab6 100644 --- a/application/palemoon/base/content/newtab/newTab.js +++ b/application/palemoon/base/content/newtab/newTab.js @@ -4,8 +4,8 @@ "use strict"; -let Cu = Components.utils; -let Ci = Components.interfaces; +var Cu = Components.utils; +var Ci = Components.interfaces; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/application/palemoon/base/content/nsContextMenu.js b/application/palemoon/base/content/nsContextMenu.js index 8e6bc96c2..f914f5841 100644 --- a/application/palemoon/base/content/nsContextMenu.js +++ b/application/palemoon/base/content/nsContextMenu.js @@ -422,12 +422,17 @@ nsContextMenu.prototype = { }, inspectNode: function CM_inspectNode() { - let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); + let {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {}); let gBrowser = this.browser.ownerDocument.defaultView.gBrowser; - let tt = devtools.TargetFactory.forTab(gBrowser.selectedTab); - return gDevTools.showToolbox(tt, "inspector").then(function(toolbox) { + let target = devtools.TargetFactory.forTab(gBrowser.selectedTab); + + return gDevTools.showToolbox(target, "inspector").then(function(toolbox) { let inspector = toolbox.getCurrentPanel(); - inspector.selection.setNode(this.target, "browser-context-menu"); + + this.browser.messageManager.sendAsyncMessage("debug:inspect", {}, {node: this.target}); + inspector.walker.findInspectingNode().then(nodeFront => { + inspector.selection.setNodeFront(nodeFront, "browser-context-menu"); + }); }.bind(this)); }, diff --git a/application/palemoon/base/content/padlock.js b/application/palemoon/base/content/padlock.js index 53477fd17..9c29524ce 100644 --- a/application/palemoon/base/content/padlock.js +++ b/application/palemoon/base/content/padlock.js @@ -1,6 +1,6 @@ -let Cc = Components.classes; -let Ci = Components.interfaces; -let Cu = Components.utils; +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); var padlock_PadLock = diff --git a/application/palemoon/base/content/pageinfo/pageInfo.js b/application/palemoon/base/content/pageinfo/pageInfo.js index ba93ee817..83f0ddb91 100644 --- a/application/palemoon/base/content/pageinfo/pageInfo.js +++ b/application/palemoon/base/content/pageinfo/pageInfo.js @@ -359,7 +359,7 @@ function loadPageInfo() makeTabs(gDocument, gWindow); initFeedTab(); - onLoadPermission(); + onLoadPermission(gDocument.nodePrincipal); /* Call registered overlay init functions */ onLoadRegistry.forEach(function(func) { func(); }); @@ -857,7 +857,7 @@ function onBlockImage() if (checkbox.checked) permissionManager.add(uri, "image", nsIPermissionManager.DENY_ACTION); else - permissionManager.remove(uri.host, "image"); + permissionManager.remove(uri, "image"); } function onImageSelect() diff --git a/application/palemoon/base/content/pageinfo/permissions.js b/application/palemoon/base/content/pageinfo/permissions.js index 7a0006b61..2fa0cc303 100644 --- a/application/palemoon/base/content/pageinfo/permissions.js +++ b/application/palemoon/base/content/pageinfo/permissions.js @@ -12,9 +12,10 @@ const IMAGE_DENY = 2; const COOKIE_DENY = 2; const COOKIE_SESSION = 2; -const nsIQuotaManager = Components.interfaces.nsIQuotaManager; +const nsIQuotaManagerService = Components.interfaces.nsIQuotaManagerService; var gPermURI; +var gPermPrincipal; var gPrefs; var gUsageRequest; @@ -107,7 +108,7 @@ var permissionObserver = { } }; -function onLoadPermission() +function onLoadPermission(principal) { gPrefs = Components.classes[PREFERENCES_CONTRACTID] .getService(Components.interfaces.nsIPrefBranch); @@ -116,6 +117,7 @@ function onLoadPermission() var permTab = document.getElementById("permTab"); if (/^https?$/.test(uri.scheme)) { gPermURI = uri; + gPermPrincipal = principal; var hostText = document.getElementById("hostText"); hostText.value = gPermURI.host; @@ -187,7 +189,7 @@ function onCheckboxClick(aPartId) var command = document.getElementById("cmd_" + aPartId + "Toggle"); var checkbox = document.getElementById(aPartId + "Def"); if (checkbox.checked) { - permissionManager.remove(gPermURI.host, aPartId); + permissionManager.remove(gPermURI, aPartId); command.setAttribute("disabled", "true"); var perm = gPermObj[aPartId](); setRadioState(aPartId, perm); @@ -211,7 +213,7 @@ function onRadioClick(aPartId) var id = radioGroup.selectedItem.id; var permission = id.split('#')[1]; if (permission == UNKNOWN) { - permissionManager.remove(gPermURI.host, aPartId); + permissionManager.remove(gPermURI, aPartId); } else { permissionManager.add(gPermURI, aPartId, permission); } @@ -230,10 +232,13 @@ function initIndexedDBRow() row.appendChild(extras); - var quotaManager = Components.classes["@mozilla.org/dom/quota/manager;1"] - .getService(nsIQuotaManager); + var quotaManagerService = + Components.classes["@mozilla.org/dom/quota-manager-service;1"] + .getService(nsIQuotaManagerService); + gUsageRequest = - quotaManager.getUsageForURI(gPermURI, onIndexedDBUsageCallback); + quotaManagerService.getUsageForPrincipal(gPermPrincipal, + onIndexedDBUsageCallback); var status = document.getElementById("indexedDBStatus"); var button = document.getElementById("indexedDBClear"); @@ -245,22 +250,24 @@ function initIndexedDBRow() function onIndexedDBClear() { - Components.classes["@mozilla.org/dom/quota/manager;1"] - .getService(nsIQuotaManager) - .clearStoragesForURI(gPermURI); + Components.classes["@mozilla.org/dom/quota-manager-service;1"] + .getService(nsIQuotaManagerService) + .clearStoragesForPrincipal(gPermPrincipal); var permissionManager = Components.classes[PERMISSION_CONTRACTID] .getService(nsIPermissionManager); - permissionManager.remove(gPermURI.host, "indexedDB"); + permissionManager.remove(gPermURI, "indexedDB"); initIndexedDBRow(); } -function onIndexedDBUsageCallback(uri, usage, fileUsage) +function onIndexedDBUsageCallback(request) { + let uri = request.principal.URI; if (!uri.equals(gPermURI)) { - throw new Error("Callback received for bad URI: " + uri); + throw new Error("Callback received for bad URI: " + uri.spec); } + let usage = request.result.usage; if (usage) { if (!("DownloadUtils" in window)) { Components.utils.import("resource://gre/modules/DownloadUtils.jsm"); @@ -355,20 +362,33 @@ function initPluginsRow() { } } - let entries = [ - { + // Tycho: + // let entries = [ + // { + // "permission": item[0], + // "obj": item[1], + // } + // for (item of permissionMap) + // ]; + let entries = []; + for (let item of permissionMap) { + entries.push({ "permission": item[0], - "obj": item[1], - } - for (item of permissionMap) - ]; + "obj": item[1] + }); + } entries.sort(function(a, b) { return ((a.obj.name < b.obj.name) ? -1 : (a.obj.name == b.obj.name ? 0 : 1)); }); - let permissionEntries = [ - fillInPluginPermissionTemplate(p.permission, p.obj) for (p of entries) - ]; + // Tycho: + // let permissionEntries = [ + // fillInPluginPermissionTemplate(p.permission, p.obj) for (p of entries) + // ]; + let permissionEntries = []; + entries.forEach(function (p) { + permissionEntries.push(fillInPluginPermissionTemplate(p.permission, p.obj)); + }); let permPluginsRow = document.getElementById("permPluginsRow"); clearPluginPermissionTemplate(); diff --git a/application/palemoon/base/content/popup-notifications.inc b/application/palemoon/base/content/popup-notifications.inc index 04f4cb5b7..7be975b7f 100644 --- a/application/palemoon/base/content/popup-notifications.inc +++ b/application/palemoon/base/content/popup-notifications.inc @@ -54,7 +54,7 @@ </hbox> </panel> - +#ifdef MOZ_WEBRTC <popupnotification id="webRTC-shareDevices-notification" hidden="true"> <popupnotificationcontent id="webRTC-selectCamera" orient="vertical"> <separator class="thin"/> @@ -75,7 +75,7 @@ </menulist> </popupnotificationcontent> </popupnotification> - +#endif <popupnotification id="servicesInstall-notification" hidden="true"> <popupnotificationcontent orient="vertical" align="start"> <!-- XXX bug 974146, tests are looking for this, can't remove yet. --> @@ -89,6 +89,14 @@ </popupnotificationcontent> </popupnotification> + <popupnotification id="password-notification" hidden="true"> + <popupnotificationcontent orient="vertical"> + <textbox id="password-notification-username"/> + <textbox id="password-notification-password" type="password" show-content=""/> + <checkbox id="password-notification-visibilityToggle" hidden="true"/> + </popupnotificationcontent> + </popupnotification> + <popupnotification id="mixed-content-blocked-notification" hidden="true"> <popupnotificationcontent orient="vertical" align="start"> <separator/> diff --git a/application/palemoon/base/content/sanitize.js b/application/palemoon/base/content/sanitize.js index 89843c86d..fccec6c98 100644 --- a/application/palemoon/base/content/sanitize.js +++ b/application/palemoon/base/content/sanitize.js @@ -15,7 +15,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise", XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "console", - "resource://gre/modules/devtools/Console.jsm"); + "resource://gre/modules/Console.jsm"); function Sanitizer() {} Sanitizer.prototype = { diff --git a/application/palemoon/base/content/tabbrowser.xml b/application/palemoon/base/content/tabbrowser.xml index b8d5f3e41..b5395bbd9 100644 --- a/application/palemoon/base/content/tabbrowser.xml +++ b/application/palemoon/base/content/tabbrowser.xml @@ -73,7 +73,7 @@ .getService(Components.interfaces.nsIFaviconService); </field> <field name="_placesAutocomplete" readonly="true"> - Components.classes["@mozilla.org/autocomplete/search;1?name=history"] + Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"] .getService(Components.interfaces.mozIPlacesAutoComplete); </field> <field name="mTabBox" readonly="true"> @@ -302,6 +302,16 @@ </body> </method> + <method name="getBrowserForContentWindow"> + <parameter name="aWindow"/> + <body> + <![CDATA[ + var tab = this._getTabForContentWindow(aWindow); + return tab ? tab.linkedBrowser : null; + ]]> + </body> + </method> + <method name="getBrowserForOuterWindowID"> <parameter name="aID"/> <body> @@ -707,7 +717,8 @@ let autocomplete = this.mTabBrowser._placesAutocomplete; if (this.mBrowser.registeredOpenURI) { - autocomplete.unregisterOpenPage(this.mBrowser.registeredOpenURI); + autocomplete.unregisterOpenPage(this.mBrowser.registeredOpenURI, + this.mBrowser.getAttribute("usercontextid") || 0); delete this.mBrowser.registeredOpenURI; } // Tabs in private windows aren't registered as "Open" so @@ -715,7 +726,8 @@ if (!isBlankPageURL(aLocation.spec) && (!PrivateBrowsingUtils.isWindowPrivate(window) || PrivateBrowsingUtils.permanentPrivateBrowsing)) { - autocomplete.registerOpenPage(aLocation); + autocomplete.registerOpenPage(aLocation, + this.mBrowser.getAttribute("usercontextid") || 0); this.mBrowser.registeredOpenURI = aLocation; } } @@ -1566,7 +1578,7 @@ } if (animate) { - mozRequestAnimationFrame(function () { + requestAnimationFrame(function () { this.tabContainer._handleTabTelemetryStart(t, aURI); // kick the animation off @@ -1865,7 +1877,8 @@ this.mTabListeners[aTab._tPos].destroy(); if (browser.registeredOpenURI && !aTabWillBeMoved) { - this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI); + this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI, + browser.getAttribute("usercontextid") || 0); delete browser.registeredOpenURI; } @@ -2209,7 +2222,8 @@ <![CDATA[ // If the current URI is registered as open remove it from the list. if (aOurBrowser.registeredOpenURI) { - this._placesAutocomplete.unregisterOpenPage(aOurBrowser.registeredOpenURI); + this._placesAutocomplete.unregisterOpenPage(aOurBrowser.registeredOpenURI, + aOurBrowser.getAttribute("usercontextid") || 0); delete aOurBrowser.registeredOpenURI; } @@ -2950,13 +2964,23 @@ let browser = aMessage.target; switch (aMessage.name) { - case "DOMTitleChanged": + case "DOMTitleChanged": { let tab = this.getTabForBrowser(browser); if (!tab) return; let titleChanged = this.setTabTitle(tab); if (titleChanged && !tab.selected && !tab.hasAttribute("busy")) tab.setAttribute("titlechanged", "true"); + break; + } + case "DOMWebNotificationClicked": { + let tab = this.getTabForBrowser(browser); + if (!tab) + return; + this.selectedTab = tab; + window.focus(); + break; + } } ]]></body> </method> @@ -3022,6 +3046,7 @@ this._outerWindowIDBrowserMap.set(this.mCurrentBrowser.outerWindowID, this.mCurrentBrowser); } + messageManager.addMessageListener("DOMWebNotificationClicked", this); ]]> </constructor> @@ -3055,7 +3080,8 @@ for (var i = 0; i < this.mTabListeners.length; ++i) { let browser = this.getBrowserAtIndex(i); if (browser.registeredOpenURI) { - this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI); + this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI, + browser.getAttribute("usercontextid") || 0); delete browser.registeredOpenURI; } browser.webProgress.removeProgressListener(this.mTabFilters[i]); diff --git a/application/palemoon/branding/official/moz.build b/application/palemoon/branding/official/moz.build index 847510ec0..8cb90130f 100644 --- a/application/palemoon/branding/official/moz.build +++ b/application/palemoon/branding/official/moz.build @@ -4,4 +4,10 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +DIRS += ['content', 'locales'] + +DIST_SUBDIR = 'browser' +export('DIST_SUBDIR') + include('../shared/branding.mozbuild') +ApplicationBranding() diff --git a/application/palemoon/branding/shared/branding.mozbuild b/application/palemoon/branding/shared/branding.mozbuild index 0636be64a..fc832dbe7 100644 --- a/application/palemoon/branding/shared/branding.mozbuild +++ b/application/palemoon/branding/shared/branding.mozbuild @@ -4,52 +4,49 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -DIRS += ['content', 'locales'] - -DIST_SUBDIR = 'browser' -export('DIST_SUBDIR') - -JS_PREFERENCE_FILES += [ - 'pref/palemoon-branding.js', -] - -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': - FINAL_TARGET_FILES['..'] += [ - 'palemoon.VisualElementsManifest.xml', - ] - FINAL_TARGET_FILES.VisualElements += [ - 'VisualElements_150.png', - 'VisualElements_70.png', - ] - BRANDING_FILES += [ - '../shared/newtab.ico', - '../shared/newwindow.ico', - '../shared/pbmode.ico', - 'appname.bmp', - 'branding.nsi', - 'document.ico', - 'firefox.ico', - 'wizHeader.bmp', - 'wizHeaderRTL.bmp', - 'wizWatermark.bmp', - ] -elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': - BRANDING_FILES += [ - '../shared/background.png', - 'disk.icns', - 'document.icns', - 'dsstore', - 'firefox.icns', - ] -elif CONFIG['MOZ_WIDGET_GTK']: - BRANDING_FILES += [ - 'default16.png', - 'default32.png', - 'default48.png', - 'mozicon128.png', +@template +def ApplicationBranding(): + JS_PREFERENCE_PP_FILES += [ + 'pref/palemoon-branding.js', ] -DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] -DEFINES['MOZ_BRANDING_DIRECTORY'] = CONFIG['MOZ_BRANDING_DIRECTORY'] -DEFINES['MOZILLA_UAVERSION_U'] = CONFIG['MOZILLA_UAVERSION_U'] -DEFINES['MOZILLA_COMPATVERSION_U'] = CONFIG['MOZILLA_COMPATVERSION_U']
\ No newline at end of file + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': + FINAL_TARGET_FILES['..'] += [ + 'palemoon.VisualElementsManifest.xml', + ] + FINAL_TARGET_FILES.VisualElements += [ + 'VisualElements_150.png', + 'VisualElements_70.png', + ] + BRANDING_FILES += [ + '../shared/newtab.ico', + '../shared/newwindow.ico', + '../shared/pbmode.ico', + 'appname.bmp', + 'branding.nsi', + 'document.ico', + 'firefox.ico', + 'wizHeader.bmp', + 'wizHeaderRTL.bmp', + 'wizWatermark.bmp', + ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + BRANDING_FILES += [ + '../shared/background.png', + 'disk.icns', + 'document.icns', + 'dsstore', + 'firefox.icns', + ] + elif CONFIG['MOZ_WIDGET_GTK']: + BRANDING_FILES += [ + 'default16.png', + 'default32.png', + 'default48.png', + 'mozicon128.png', + ] + + DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] + DEFINES['MOZ_BRANDING_DIRECTORY'] = CONFIG['MOZ_BRANDING_DIRECTORY'] + DEFINES['MOZILLA_UAVERSION_U'] = CONFIG['MOZILLA_UAVERSION_U'] + DEFINES['MOZILLA_COMPATVERSION_U'] = "52.9" diff --git a/application/palemoon/branding/shared/pref/preferences.inc b/application/palemoon/branding/shared/pref/preferences.inc index a45870b01..a3cfcd138 100644 --- a/application/palemoon/branding/shared/pref/preferences.inc +++ b/application/palemoon/branding/shared/pref/preferences.inc @@ -119,3 +119,11 @@ pref("browser.sessionstore.interval",60000); //every minute instead of every 10 pref("accessibility.force_disabled", 1); // ============================================================================ + +// ===| DevTools |============================================================= + +// Number of usages of the web console or scratchpad. +// If this is less than 5, then pasting code into the web console or scratchpad is disabled +pref("devtools.selfxss.count", 100); + +// ============================================================================ diff --git a/application/palemoon/branding/shared/pref/uaoverrides.inc b/application/palemoon/branding/shared/pref/uaoverrides.inc index 20cc3ab86..db9ccaffa 100644 --- a/application/palemoon/branding/shared/pref/uaoverrides.inc +++ b/application/palemoon/branding/shared/pref/uaoverrides.inc @@ -36,6 +36,7 @@ pref("@GUAO_PREF@.yahoo.com","Mozilla/5.0 (@OS_SLICE@ rv:99.9) @GK_SLICE@ Firefo pref("@GUAO_PREF@.youtube.com","Mozilla/5.0 (@OS_SLICE@ rv:42.0) @GK_SLICE@ Firefox/42.0 @PM_SLICE@");
pref("@GUAO_PREF@.gaming.youtube.com","Mozilla/5.0 (@OS_SLICE@ rv:42.0) @GK_SLICE@ Firefox/42.0");
+pref("@GUAO_PREF@.dropbox.com","Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko");
pref("@GUAO_PREF@.players.brightcove.net","Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko");
// The never-ending Facebook debacle...
@@ -60,7 +61,6 @@ pref("@GUAO_PREF@.dailymotion.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) @GK_SLICE@ // The following requires native mode. Or it blocks.. "too old firefox", breakage, etc.
pref("@GUAO_PREF@.deviantart.com","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
pref("@GUAO_PREF@.deviantart.net","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
-pref("@GUAO_PREF@.dropbox.com","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
// UA-Sniffing domains below have indicated no interest in supporting Pale Moon (BOO!)
pref("@GUAO_PREF@.humblebundle.com","Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@ (Pale Moon)");
diff --git a/application/palemoon/branding/unofficial/moz.build b/application/palemoon/branding/unofficial/moz.build index 847510ec0..8cb90130f 100644 --- a/application/palemoon/branding/unofficial/moz.build +++ b/application/palemoon/branding/unofficial/moz.build @@ -4,4 +4,10 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +DIRS += ['content', 'locales'] + +DIST_SUBDIR = 'browser' +export('DIST_SUBDIR') + include('../shared/branding.mozbuild') +ApplicationBranding() diff --git a/application/palemoon/branding/unstable/moz.build b/application/palemoon/branding/unstable/moz.build index 847510ec0..8cb90130f 100644 --- a/application/palemoon/branding/unstable/moz.build +++ b/application/palemoon/branding/unstable/moz.build @@ -4,4 +4,10 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +DIRS += ['content', 'locales'] + +DIST_SUBDIR = 'browser' +export('DIST_SUBDIR') + include('../shared/branding.mozbuild') +ApplicationBranding() diff --git a/application/palemoon/build.mk b/application/palemoon/build.mk index fc692eda5..ae490aca7 100644 --- a/application/palemoon/build.mk +++ b/application/palemoon/build.mk @@ -3,40 +3,40 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. installer: - @$(MAKE) -C browser/installer installer + @$(MAKE) -C application/palemoon/installer installer package: - @$(MAKE) -C browser/installer + @$(MAKE) -C application/palemoon/installer package-compare: - @$(MAKE) -C browser/installer package-compare + @$(MAKE) -C application/palemoon/installer package-compare stage-package: - @$(MAKE) -C browser/installer stage-package + @$(MAKE) -C application/palemoon/installer stage-package install:: - @$(MAKE) -C browser/installer install + @$(MAKE) -C application/palemoon/installer install clean:: - @$(MAKE) -C browser/installer clean + @$(MAKE) -C application/palemoon/installer clean distclean:: - @$(MAKE) -C browser/installer distclean + @$(MAKE) -C application/palemoon/installer distclean source-package:: - @$(MAKE) -C browser/installer source-package + @$(MAKE) -C application/palemoon/installer source-package upload:: - @$(MAKE) -C browser/installer upload + @$(MAKE) -C application/palemoon/installer upload source-upload:: - @$(MAKE) -C browser/installer source-upload + @$(MAKE) -C application/palemoon/installer source-upload hg-bundle:: - @$(MAKE) -C browser/installer hg-bundle + @$(MAKE) -C application/palemoon/installer hg-bundle l10n-check:: - @$(MAKE) -C browser/locales l10n-check + @$(MAKE) -C application/palemoon/locales l10n-check ifdef ENABLE_TESTS # Implemented in testing/testsuite-targets.mk diff --git a/application/palemoon/components/about/AboutRedirector.cpp b/application/palemoon/components/about/AboutRedirector.cpp index d927b7936..d52b873b9 100644 --- a/application/palemoon/components/about/AboutRedirector.cpp +++ b/application/palemoon/components/about/AboutRedirector.cpp @@ -9,8 +9,6 @@ #include "nsNetUtil.h" #include "nsIScriptSecurityManager.h" #include "mozilla/ArrayUtils.h" -#include "nsDOMString.h" - namespace mozilla { namespace browser { @@ -21,7 +19,6 @@ struct RedirEntry { const char* id; const char* url; uint32_t flags; - const char* idbOriginPostfix; }; /* @@ -33,17 +30,47 @@ struct RedirEntry { URI_SAFE_FOR_UNTRUSTED_CONTENT. */ static RedirEntry kRedirMap[] = { - { "certerror", "chrome://browser/content/certerror/aboutCertError.xhtml", + { + "certerror", "chrome://browser/content/certerror/aboutCertError.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "feeds", "chrome://browser/content/feeds/subscribe.xhtml", + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "downloads", "chrome://browser/content/downloads/contentAreaDownloadsView.xul", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "feeds", "chrome://browser/content/feeds/subscribe.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "privatebrowsing", "chrome://browser/content/aboutPrivateBrowsing.xhtml", - nsIAboutModule::ALLOW_SCRIPT }, - { "rights", + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "home", "chrome://browser/content/abouthome/aboutHome.xhtml", + nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::MAKE_LINKABLE | + nsIAboutModule::ALLOW_SCRIPT + }, + { + "newtab", "chrome://browser/content/newtab/newTab.xul", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "palemoon", "chrome://global/content/memoriam.xhtml", + nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "permissions", "chrome://browser/content/preferences/aboutPermissions.xul", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "privatebrowsing", "chrome://browser/content/aboutPrivateBrowsing.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "rights", #ifdef MOZ_OFFICIAL_BRANDING "chrome://global/content/aboutRights.xhtml", #else @@ -51,34 +78,27 @@ static RedirEntry kRedirMap[] = { #endif nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::MAKE_LINKABLE | - nsIAboutModule::ALLOW_SCRIPT }, - { "palemoon", "chrome://global/content/palemoon.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "robots", "chrome://browser/content/aboutRobots.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "logopage", "chrome://global/content/logopage.xhtml", - nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "robots", "chrome://browser/content/aboutRobots.xhtml", - nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::ALLOW_SCRIPT }, - { "sessionrestore", "chrome://browser/content/aboutSessionRestore.xhtml", - nsIAboutModule::ALLOW_SCRIPT }, + nsIAboutModule::ALLOW_SCRIPT + }, + { + "sessionrestore", "chrome://browser/content/aboutSessionRestore.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, #ifdef MOZ_SERVICES_SYNC - { "sync-progress", "chrome://browser/content/sync/progress.xhtml", - nsIAboutModule::ALLOW_SCRIPT }, - { "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul", - nsIAboutModule::ALLOW_SCRIPT }, + { + "sync-progress", "chrome://browser/content/sync/progress.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul", + nsIAboutModule::ALLOW_SCRIPT + }, #endif - { "home", "chrome://browser/content/abouthome/aboutHome.xhtml", - nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::MAKE_LINKABLE | - nsIAboutModule::ALLOW_SCRIPT }, - { "newtab", "chrome://browser/content/newtab/newTab.xul", - nsIAboutModule::ALLOW_SCRIPT }, - { "permissions", "chrome://browser/content/preferences/aboutPermissions.xul", - nsIAboutModule::ALLOW_SCRIPT }, - { "downloads", "chrome://browser/content/downloads/contentAreaDownloadsView.xul", - nsIAboutModule::ALLOW_SCRIPT }, }; static const int kRedirTotal = ArrayLength(kRedirMap); @@ -148,30 +168,6 @@ AboutRedirector::GetURIFlags(nsIURI *aURI, uint32_t *result) return NS_ERROR_ILLEGAL_VALUE; } -NS_IMETHODIMP -AboutRedirector::GetIndexedDBOriginPostfix(nsIURI *aURI, nsAString &result) -{ - NS_ENSURE_ARG_POINTER(aURI); - - nsAutoCString name = GetAboutModuleName(aURI); - - for (int i = 0; i < kRedirTotal; i++) { - if (name.Equals(kRedirMap[i].id)) { - const char* postfix = kRedirMap[i].idbOriginPostfix; - if (!postfix) { - break; - } - - result.AssignASCII(postfix); - return NS_OK; - } - } - - SetDOMStringToNull(result); - return NS_ERROR_ILLEGAL_VALUE; -} - - nsresult AboutRedirector::Create(nsISupports *aOuter, REFNSIID aIID, void **result) { diff --git a/application/palemoon/components/build/moz.build b/application/palemoon/components/build/moz.build index f8073907e..5bc4858d7 100644 --- a/application/palemoon/components/build/moz.build +++ b/application/palemoon/components/build/moz.build @@ -24,11 +24,17 @@ LOCAL_INCLUDES += [ if CONFIG['OS_ARCH'] == 'WINNT': OS_LIBS += [ + 'esent', + 'netapi32', 'ole32', 'shell32', 'shlwapi', 'version', ] + DELAYLOAD_DLLS += [ + 'esent.dll', + 'netapi32.dll', + ] # Mac: Need to link with CoreFoundation for Mac Migrators (PList reading code) # GTK2: Need to link with glib for GNOME shell service diff --git a/application/palemoon/components/build/nsModule.cpp b/application/palemoon/components/build/nsModule.cpp index d5b79b455..fad87d831 100644 --- a/application/palemoon/components/build/nsModule.cpp +++ b/application/palemoon/components/build/nsModule.cpp @@ -91,7 +91,6 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = { { NS_ABOUT_MODULE_CONTRACTID_PREFIX "privatebrowsing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "rights", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "palemoon", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, - { NS_ABOUT_MODULE_CONTRACTID_PREFIX "logopage", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "robots", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sessionrestore", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, #ifdef MOZ_SERVICES_SYNC diff --git a/application/palemoon/components/dirprovider/DirectoryProvider.cpp b/application/palemoon/components/dirprovider/DirectoryProvider.cpp index 4d3993b7f..85728b351 100644 --- a/application/palemoon/components/dirprovider/DirectoryProvider.cpp +++ b/application/palemoon/components/dirprovider/DirectoryProvider.cpp @@ -34,57 +34,7 @@ NS_IMPL_ISUPPORTS(DirectoryProvider, NS_IMETHODIMP DirectoryProvider::GetFile(const char *aKey, bool *aPersist, nsIFile* *aResult) { - nsresult rv; - - *aResult = nullptr; - - // NOTE: This function can be reentrant through the NS_GetSpecialDirectory - // call, so be careful not to cause infinite recursion. - - nsCOMPtr<nsIFile> file; - - char const* leafName = nullptr; - - if (!strcmp(aKey, NS_APP_BOOKMARKS_50_FILE)) { - leafName = "bookmarks.html"; - - nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); - if (prefs) { - nsCString path; - rv = prefs->GetCharPref("browser.bookmarks.file", getter_Copies(path)); - if (NS_SUCCEEDED(rv)) { - NS_NewNativeLocalFile(path, true, getter_AddRefs(file)); - } - } - } - else { - return NS_ERROR_FAILURE; - } - - nsDependentCString leafstr(leafName); - - nsCOMPtr<nsIFile> parentDir; - if (file) { - rv = file->GetParent(getter_AddRefs(parentDir)); - if (NS_FAILED(rv)) - return rv; - } - else { - rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(parentDir)); - if (NS_FAILED(rv)) - return rv; - - rv = parentDir->Clone(getter_AddRefs(file)); - if (NS_FAILED(rv)) - return rv; - - file->AppendNative(leafstr); - } - - *aPersist = true; - NS_ADDREF(*aResult = file); - - return NS_OK; + return NS_ERROR_FAILURE; } static void diff --git a/application/palemoon/components/downloads/DownloadsCommon.jsm b/application/palemoon/components/downloads/DownloadsCommon.jsm index b90baaf9c..0921f8400 100644 --- a/application/palemoon/components/downloads/DownloadsCommon.jsm +++ b/application/palemoon/components/downloads/DownloadsCommon.jsm @@ -867,9 +867,19 @@ DownloadsDataCtor.prototype = { // Sort backwards by start time, ensuring that the most recent // downloads are added first regardless of their state. - let loadedItemsArray = [dataItem - for each (dataItem in this.dataItems) - if (dataItem)]; + // Tycho: + //let loadedItemsArray = [dataItem + // for each (dataItem in this.dataItems) + // if (dataItem)]; + + let loadedItemsArray = []; + + for each (let dataItem in this.dataItems) { + if (dataItem) { + loadedItemsArray.push(dataItem); + } + } + loadedItemsArray.sort(function(a, b) b.startTime - a.startTime); loadedItemsArray.forEach( function (dataItem) aView.onDataItemAdded(dataItem, false) diff --git a/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js b/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js index e1d0e75d4..9d90b20e1 100644 --- a/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js +++ b/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js @@ -8,9 +8,9 @@ * ON IT AS AN API. */ -let Cu = Components.utils; -let Ci = Components.interfaces; -let Cc = Components.classes; +var Cu = Components.utils; +var Ci = Components.interfaces; +var Cc = Components.classes; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); @@ -1408,7 +1408,12 @@ DownloadsPlacesView.prototype = { _copySelectedDownloadsToClipboard: function DPV__copySelectedDownloadsToClipboard() { let selectedElements = this._richlistbox.selectedItems; - let urls = [e._shell.downloadURI for each (e in selectedElements)]; + // Tycho: let urls = [e._shell.downloadURI for each (e in selectedElements)]; + let urls = []; + + for each (e in selectedElements) { + urls.push(e._shell.downloadURI); + } Cc["@mozilla.org/widget/clipboardhelper;1"]. getService(Ci.nsIClipboardHelper).copyString(urls.join("\n"), document); diff --git a/application/palemoon/components/feeds/moz.build b/application/palemoon/components/feeds/moz.build index 1dea0ce77..7ae9141aa 100644 --- a/application/palemoon/components/feeds/moz.build +++ b/application/palemoon/components/feeds/moz.build @@ -35,5 +35,3 @@ for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'): LOCAL_INCLUDES += [ '../build', ] - -FAIL_ON_WARNINGS = True diff --git a/application/palemoon/components/feeds/nsFeedSniffer.cpp b/application/palemoon/components/feeds/nsFeedSniffer.cpp index 61cc77bdd..f314d3d3b 100644 --- a/application/palemoon/components/feeds/nsFeedSniffer.cpp +++ b/application/palemoon/components/feeds/nsFeedSniffer.cpp @@ -135,7 +135,7 @@ FindChar(char c, const char *begin, const char *end) * it's possible that someone embedded one of these tags inside a document of * another type, e.g. a HTML document, and we don't want to show the preview * page if the document isn't actually a feed. - * + * * @param start * The beginning of the data being sniffed * @param end @@ -331,7 +331,7 @@ nsFeedSniffer::OnStartRequest(nsIRequest* request, nsISupports* context) return NS_OK; } -NS_METHOD +nsresult nsFeedSniffer::AppendSegmentToString(nsIInputStream* inputStream, void* closure, const char* rawSegment, diff --git a/application/palemoon/components/feeds/nsFeedSniffer.h b/application/palemoon/components/feeds/nsFeedSniffer.h index 57e10d954..a0eb9862c 100644 --- a/application/palemoon/components/feeds/nsFeedSniffer.h +++ b/application/palemoon/components/feeds/nsFeedSniffer.h @@ -10,7 +10,7 @@ #include "mozilla/Attributes.h" class nsFeedSniffer final : public nsIContentSniffer, - nsIStreamListener + nsIStreamListener { public: NS_DECL_ISUPPORTS @@ -18,12 +18,12 @@ public: NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER - static NS_METHOD AppendSegmentToString(nsIInputStream* inputStream, - void* closure, - const char* rawSegment, - uint32_t toOffset, - uint32_t count, - uint32_t* writeCount); + static nsresult AppendSegmentToString(nsIInputStream* inputStream, + void* closure, + const char* rawSegment, + uint32_t toOffset, + uint32_t count, + uint32_t* writeCount); protected: ~nsFeedSniffer() {} diff --git a/application/palemoon/components/fuel/fuelApplication.js b/application/palemoon/components/fuel/fuelApplication.js index 89d568ae1..017813143 100644 --- a/application/palemoon/components/fuel/fuelApplication.js +++ b/application/palemoon/components/fuel/fuelApplication.js @@ -729,7 +729,7 @@ var ApplicationFactory = { }; -#include ../../../toolkit/components/exthelper/extApplication.js +#include ../../../../toolkit/components/exthelper/extApplication.js //================================================= // Application constructor diff --git a/application/palemoon/components/migration/MigrationUtils.jsm b/application/palemoon/components/migration/MigrationUtils.jsm index fcd73a798..882c7cf32 100644 --- a/application/palemoon/components/migration/MigrationUtils.jsm +++ b/application/palemoon/components/migration/MigrationUtils.jsm @@ -176,7 +176,13 @@ this.MigratorPrototype = { * @see nsIBrowserProfileMigrator */ getMigrateData: function MP_getMigrateData(aProfile) { - let types = [r.type for each (r in this._getMaybeCachedResources(aProfile))]; + // Tycho: let types = [r.type for each (r in this._getMaybeCachedResources(aProfile))]; + let types = []; + + for each (r in this._getMaybeCachedResources(aProfile)) { + types.push(r.type); + } + return types.reduce(function(a, b) a |= b, 0); }, @@ -192,7 +198,14 @@ this.MigratorPrototype = { throw new Error("migrate called for a non-existent source"); if (aItems != Ci.nsIBrowserProfileMigrator.ALL) - resources = [r for each (r in resources) if (aItems & r.type)]; + // Tycho: resources = [r for each (r in resources) if (aItems & r.type)]; + resources = []; + + for each (r in resources) { + if (aItems & r.type) { + resources.push(r); + } + } // Called either directly or through the bookmarks import callback. function doMigrate() { diff --git a/application/palemoon/components/migration/SafariProfileMigrator.js b/application/palemoon/components/migration/SafariProfileMigrator.js index 70804793d..e3f73c2c8 100644 --- a/application/palemoon/components/migration/SafariProfileMigrator.js +++ b/application/palemoon/components/migration/SafariProfileMigrator.js @@ -4,9 +4,9 @@ "use strict"; -let Cc = Components.classes; -let Ci = Components.interfaces; -let Cu = Components.utils; +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm"); diff --git a/application/palemoon/components/migration/nsIEHistoryEnumerator.cpp b/application/palemoon/components/migration/nsIEHistoryEnumerator.cpp index 7fe31a666..0b377d27e 100644 --- a/application/palemoon/components/migration/nsIEHistoryEnumerator.cpp +++ b/application/palemoon/components/migration/nsIEHistoryEnumerator.cpp @@ -1,139 +1,119 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIEHistoryEnumerator.h"
-
-#include <urlhist.h>
-#include <shlguid.h>
-
-#include "nsStringAPI.h"
-#include "nsNetUtil.h"
-#include "nsIVariant.h"
-#include "nsCOMArray.h"
-#include "nsArrayEnumerator.h"
-
-namespace {
-
- PRTime FileTimeToPRTime(FILETIME* filetime)
- {
- SYSTEMTIME st;
- ::FileTimeToSystemTime(filetime, &st);
- PRExplodedTime prt;
- prt.tm_year = st.wYear;
- // SYSTEMTIME's day-of-month parameter is 1-based,
- // PRExplodedTime's is 0-based.
- prt.tm_month = st.wMonth - 1;
- prt.tm_mday = st.wDay;
- prt.tm_hour = st.wHour;
- prt.tm_min = st.wMinute;
- prt.tm_sec = st.wSecond;
- prt.tm_usec = st.wMilliseconds * 1000;
- prt.tm_wday = 0;
- prt.tm_yday = 0;
- prt.tm_params.tp_gmt_offset = 0;
- prt.tm_params.tp_dst_offset = 0;
- return PR_ImplodeTime(&prt);
- }
-
-} // Anonymous namespace.
-
-////////////////////////////////////////////////////////////////////////////////
-//// nsIEHistoryEnumerator
-
-NS_IMPL_ISUPPORTS(nsIEHistoryEnumerator, nsISimpleEnumerator)
-
-nsIEHistoryEnumerator::nsIEHistoryEnumerator()
-{
- ::CoInitialize(nullptr);
-}
-
-nsIEHistoryEnumerator::~nsIEHistoryEnumerator()
-{
- ::CoUninitialize();
-}
-
-void
-nsIEHistoryEnumerator::EnsureInitialized()
-{
- if (mURLEnumerator)
- return;
-
- HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory,
- nullptr,
- CLSCTX_INPROC_SERVER,
- IID_IUrlHistoryStg2,
- getter_AddRefs(mIEHistory));
- if (FAILED(hr))
- return;
-
- hr = mIEHistory->EnumUrls(getter_AddRefs(mURLEnumerator));
- if (FAILED(hr))
- return;
-}
-
-NS_IMETHODIMP
-nsIEHistoryEnumerator::HasMoreElements(bool* _retval)
-{
- *_retval = false;
-
- EnsureInitialized();
- MOZ_ASSERT(mURLEnumerator, "Should have instanced an IE History URLEnumerator");
- if (!mURLEnumerator)
- return NS_OK;
-
- STATURL statURL;
- ULONG fetched;
-
- // First argument is not implemented, so doesn't matter what we pass.
- HRESULT hr = mURLEnumerator->Next(1, &statURL, &fetched);
- if (FAILED(hr) || fetched != 1UL) {
- // Reached the last entry.
- return NS_OK;
- }
-
- nsCOMPtr<nsIURI> uri;
- if (statURL.pwcsUrl) {
- nsDependentString url(statURL.pwcsUrl);
- nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
- ::CoTaskMemFree(statURL.pwcsUrl);
- if (NS_FAILED(rv)) {
- // Got a corrupt or invalid URI, continue to the next entry.
- return HasMoreElements(_retval);
- }
- }
-
- nsDependentString title(statURL.pwcsTitle);
-
- PRTime lastVisited = FileTimeToPRTime(&(statURL.ftLastVisited));
-
- mCachedNextEntry = do_CreateInstance("@mozilla.org/hash-property-bag;1");
- MOZ_ASSERT(mCachedNextEntry, "Should have instanced a new property bag");
- if (mCachedNextEntry) {
- mCachedNextEntry->SetPropertyAsInterface(NS_LITERAL_STRING("uri"), uri);
- mCachedNextEntry->SetPropertyAsAString(NS_LITERAL_STRING("title"), title);
- mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited);
-
- *_retval = true;
- }
-
- if (statURL.pwcsTitle)
- ::CoTaskMemFree(statURL.pwcsTitle);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-nsIEHistoryEnumerator::GetNext(nsISupports** _retval)
-{
- *_retval = nullptr;
-
- if (!mCachedNextEntry)
- return NS_ERROR_FAILURE;
-
- NS_ADDREF(*_retval = mCachedNextEntry);
- // Release the cached entry, so it can't be returned twice.
- mCachedNextEntry = nullptr;
-
- return NS_OK;
-}
+/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsIEHistoryEnumerator.h" + +#include <urlhist.h> +#include <shlguid.h> + +#include "nsArrayEnumerator.h" +#include "nsCOMArray.h" +#include "nsIVariant.h" +#include "nsNetUtil.h" +#include "nsStringAPI.h" +#include "nsWindowsMigrationUtils.h" +#include "prtime.h" + +//////////////////////////////////////////////////////////////////////////////// +//// nsIEHistoryEnumerator + +NS_IMPL_ISUPPORTS(nsIEHistoryEnumerator, nsISimpleEnumerator) + +nsIEHistoryEnumerator::nsIEHistoryEnumerator() +{ + ::CoInitialize(nullptr); +} + +nsIEHistoryEnumerator::~nsIEHistoryEnumerator() +{ + ::CoUninitialize(); +} + +void +nsIEHistoryEnumerator::EnsureInitialized() +{ + if (mURLEnumerator) + return; + + HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IUrlHistoryStg2, + getter_AddRefs(mIEHistory)); + if (FAILED(hr)) + return; + + hr = mIEHistory->EnumUrls(getter_AddRefs(mURLEnumerator)); + if (FAILED(hr)) + return; +} + +NS_IMETHODIMP +nsIEHistoryEnumerator::HasMoreElements(bool* _retval) +{ + *_retval = false; + + EnsureInitialized(); + MOZ_ASSERT(mURLEnumerator, "Should have instanced an IE History URLEnumerator"); + if (!mURLEnumerator) + return NS_OK; + + STATURL statURL; + ULONG fetched; + + // First argument is not implemented, so doesn't matter what we pass. + HRESULT hr = mURLEnumerator->Next(1, &statURL, &fetched); + if (FAILED(hr) || fetched != 1UL) { + // Reached the last entry. + return NS_OK; + } + + nsCOMPtr<nsIURI> uri; + if (statURL.pwcsUrl) { + nsDependentString url(statURL.pwcsUrl); + nsresult rv = NS_NewURI(getter_AddRefs(uri), url); + ::CoTaskMemFree(statURL.pwcsUrl); + if (NS_FAILED(rv)) { + // Got a corrupt or invalid URI, continue to the next entry. + return HasMoreElements(_retval); + } + } + + nsDependentString title(statURL.pwcsTitle ? statURL.pwcsTitle : L""); + + bool lastVisitTimeIsValid; + PRTime lastVisited = WinMigrationFileTimeToPRTime(&(statURL.ftLastVisited), &lastVisitTimeIsValid); + + mCachedNextEntry = do_CreateInstance("@mozilla.org/hash-property-bag;1"); + MOZ_ASSERT(mCachedNextEntry, "Should have instanced a new property bag"); + if (mCachedNextEntry) { + mCachedNextEntry->SetPropertyAsInterface(NS_LITERAL_STRING("uri"), uri); + mCachedNextEntry->SetPropertyAsAString(NS_LITERAL_STRING("title"), title); + if (lastVisitTimeIsValid) { + mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited); + } + + *_retval = true; + } + + if (statURL.pwcsTitle) + ::CoTaskMemFree(statURL.pwcsTitle); + + return NS_OK; +} + +NS_IMETHODIMP +nsIEHistoryEnumerator::GetNext(nsISupports** _retval) +{ + *_retval = nullptr; + + if (!mCachedNextEntry) + return NS_ERROR_FAILURE; + + NS_ADDREF(*_retval = mCachedNextEntry); + // Release the cached entry, so it can't be returned twice. + mCachedNextEntry = nullptr; + + return NS_OK; +} diff --git a/application/palemoon/components/migration/nsIEHistoryEnumerator.h b/application/palemoon/components/migration/nsIEHistoryEnumerator.h index fc1419859..1572a8dd5 100644 --- a/application/palemoon/components/migration/nsIEHistoryEnumerator.h +++ b/application/palemoon/components/migration/nsIEHistoryEnumerator.h @@ -1,37 +1,37 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef iehistoryenumerator___h___
-#define iehistoryenumerator___h___
-
-#include <urlhist.h>
-
-#include "mozilla/Attributes.h"
-#include "nsISimpleEnumerator.h"
-#include "nsIWritablePropertyBag2.h"
-#include "nsAutoPtr.h"
-
-class nsIEHistoryEnumerator final : public nsISimpleEnumerator
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSISIMPLEENUMERATOR
-
- nsIEHistoryEnumerator();
-
-private:
- ~nsIEHistoryEnumerator();
-
- /**
- * Initializes the history reader, if needed.
- */
- void EnsureInitialized();
-
- nsRefPtr<IUrlHistoryStg2> mIEHistory;
- nsRefPtr<IEnumSTATURL> mURLEnumerator;
-
- nsCOMPtr<nsIWritablePropertyBag2> mCachedNextEntry;
-};
-
-#endif
+/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef iehistoryenumerator___h___ +#define iehistoryenumerator___h___ + +#include <urlhist.h> + +#include "mozilla/Attributes.h" +#include "nsCOMPtr.h" +#include "nsISimpleEnumerator.h" +#include "nsIWritablePropertyBag2.h" + +class nsIEHistoryEnumerator final : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + nsIEHistoryEnumerator(); + +private: + ~nsIEHistoryEnumerator(); + + /** + * Initializes the history reader, if needed. + */ + void EnsureInitialized(); + + RefPtr<IUrlHistoryStg2> mIEHistory; + RefPtr<IEnumSTATURL> mURLEnumerator; + + nsCOMPtr<nsIWritablePropertyBag2> mCachedNextEntry; +}; + +#endif diff --git a/application/palemoon/components/migration/nsWindowsMigrationUtils.h b/application/palemoon/components/migration/nsWindowsMigrationUtils.h new file mode 100644 index 000000000..0288d93d3 --- /dev/null +++ b/application/palemoon/components/migration/nsWindowsMigrationUtils.h @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef windowsmigrationutils__h__ +#define windowsmigrationutils__h__ + +#include "prtime.h" + +static +PRTime WinMigrationFileTimeToPRTime(FILETIME* filetime, bool* isValid) +{ + SYSTEMTIME st; + *isValid = ::FileTimeToSystemTime(filetime, &st); + if (!*isValid) { + return 0; + } + PRExplodedTime prt; + prt.tm_year = st.wYear; + // SYSTEMTIME's day-of-month parameter is 1-based, + // PRExplodedTime's is 0-based. + prt.tm_month = st.wMonth - 1; + prt.tm_mday = st.wDay; + prt.tm_hour = st.wHour; + prt.tm_min = st.wMinute; + prt.tm_sec = st.wSecond; + prt.tm_usec = st.wMilliseconds * 1000; + prt.tm_wday = 0; + prt.tm_yday = 0; + prt.tm_params.tp_gmt_offset = 0; + prt.tm_params.tp_dst_offset = 0; + return PR_ImplodeTime(&prt); +} + +#endif + diff --git a/application/palemoon/components/nsBrowserGlue.js b/application/palemoon/components/nsBrowserGlue.js index 705593b59..aafdced9f 100644 --- a/application/palemoon/components/nsBrowserGlue.js +++ b/application/palemoon/components/nsBrowserGlue.js @@ -13,59 +13,29 @@ const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", - "resource://gre/modules/AddonManager.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", - "resource://gre/modules/NetUtil.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "UserAgentOverrides", - "resource://gre/modules/UserAgentOverrides.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", - "resource://gre/modules/FileUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", - "resource://gre/modules/PlacesUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils", - "resource://gre/modules/BookmarkHTMLUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "BookmarkJSONUtils", - "resource://gre/modules/BookmarkJSONUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", - "resource://gre/modules/PageThumbs.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils", - "resource://gre/modules/NewTabUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "BrowserNewTabPreloader", - "resource:///modules/BrowserNewTabPreloader.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "webrtcUI", - "resource:///modules/webrtcUI.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", - "resource://gre/modules/PrivateBrowsingUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow", - "resource:///modules/RecentWindow.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Task", - "resource://gre/modules/Task.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "PlacesBackups", - "resource://gre/modules/PlacesBackups.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "OS", - "resource://gre/modules/osfile.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent", - "resource://gre/modules/LoginManagerParent.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "FormValidationHandler", - "resource:///modules/FormValidationHandler.jsm"); +// Define Lazy Module Gitters +[ + ["AddonManager", "resource://gre/modules/AddonManager.jsm"], + ["NetUtil", "resource://gre/modules/NetUtil.jsm"], + ["UserAgentOverrides", "resource://gre/modules/UserAgentOverrides.jsm"], + ["FileUtils", "resource://gre/modules/FileUtils.jsm"], + ["PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"], + ["BookmarkHTMLUtils", "resource://gre/modules/BookmarkHTMLUtils.jsm"], + ["BookmarkJSONUtils", "resource://gre/modules/BookmarkJSONUtils.jsm"], + ["PageThumbs", "resource://gre/modules/PageThumbs.jsm"], + ["NewTabUtils", "resource://gre/modules/NewTabUtils.jsm"], + ["BrowserNewTabPreloader", "resource:///modules/BrowserNewTabPreloader.jsm"], +#ifdef MOZ_WEBRTC + ["webrtcUI", "resource:///modules/webrtcUI.jsm"], +#endif + ["PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"], + ["RecentWindow", "resource:///modules/RecentWindow.jsm"], + ["Task", "resource://gre/modules/Task.jsm"], + ["PlacesBackups", "resource://gre/modules/PlacesBackups.jsm"], + ["OS", "resource://gre/modules/osfile.jsm"], + ["LoginManagerParent", "resource://gre/modules/LoginManagerParent.jsm"], + ["FormValidationHandler", "resource:///modules/FormValidationHandler.jsm"], +].forEach(([name, resource]) => XPCOMUtils.defineLazyModuleGetter(this, name, resource)); const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser"; const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; @@ -427,16 +397,13 @@ BrowserGlue.prototype = { PageThumbs.init(); NewTabUtils.init(); BrowserNewTabPreloader.init(); +#ifdef MOZ_WEBRTC webrtcUI.init(); +#endif FormValidationHandler.init(); LoginManagerParent.init(); - // Make sure conflicting MSE prefs don't coexist - if (Services.prefs.getBoolPref('media.mediasource.format-reader', true)) { - Services.prefs.setBoolPref('media.mediasource.webm.enabled', false); - } - Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); }, @@ -539,7 +506,9 @@ BrowserGlue.prototype = { _onProfileShutdown: function BG__onProfileShutdown() { BrowserNewTabPreloader.uninit(); UserAgentOverrides.uninit(); +#ifdef MOZ_WEBRTC webrtcUI.uninit(); +#endif FormValidationHandler.uninit(); this._dispose(); }, @@ -1213,7 +1182,7 @@ BrowserGlue.prototype = { }, _migrateUI: function BG__migrateUI() { - const UI_VERSION = 14; + const UI_VERSION = 15; const BROWSER_DOCURL = "chrome://browser/content/browser.xul#"; let currentUIVersion = 0; try { @@ -1395,7 +1364,7 @@ BrowserGlue.prototype = { } } - if (currentUIVersion < 14) { + if (currentUIVersion < 16) { // Migrate Sync from pmsync.palemoon.net to pmsync.palemoon.org try { let syncURL = Services.prefs.getCharPref("services.sync.clusterURL"); diff --git a/application/palemoon/components/places/content/treeView.js b/application/palemoon/components/places/content/treeView.js index c1879aacf..aba731470 100644 --- a/application/palemoon/components/places/content/treeView.js +++ b/application/palemoon/components/places/content/treeView.js @@ -144,7 +144,12 @@ PlacesTreeView.prototype = { // A node is removed form the view either if it has no parent or if its // root-ancestor is not the root node (in which case that's the node // for which nodeRemoved was called). - let ancestors = [x for (x of PlacesUtils.nodeAncestors(aNode))]; + // Tycho: let ancestors = [x for (x of PlacesUtils.nodeAncestors(aNode))]; + let ancestors = []; + for (let x of PlacesUtils.nodeAncestors(aNode)) { + ancestors.push(x); + } + if (ancestors.length == 0 || ancestors[ancestors.length - 1] != this._rootNode) { throw new Error("Removed node passed to _getRowForNode"); diff --git a/application/palemoon/components/preferences/aboutPermissions.js b/application/palemoon/components/preferences/aboutPermissions.js index 4d803145d..106d45f89 100644 --- a/application/palemoon/components/preferences/aboutPermissions.js +++ b/application/palemoon/components/preferences/aboutPermissions.js @@ -2,9 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -let Ci = Components.interfaces; -let Cc = Components.classes; -let Cu = Components.utils; +var Ci = Components.interfaces; +var Cc = Components.classes; +var Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/PluralForm.jsm"); diff --git a/application/palemoon/components/preferences/security.js b/application/palemoon/components/preferences/security.js index a337f398c..56664bf66 100644 --- a/application/palemoon/components/preferences/security.js +++ b/application/palemoon/components/preferences/security.js @@ -3,6 +3,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper", + "resource://gre/modules/LoginHelper.jsm"); + Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); var gSecurityPane = { @@ -141,7 +144,7 @@ var gSecurityPane = { */ _initMasterPasswordUI: function () { - var noMP = !this._masterPasswordSet(); + var noMP = !LoginHelper.isMasterPasswordSet(); var button = document.getElementById("changeMasterPassword"); button.disabled = noMP; @@ -151,26 +154,6 @@ var gSecurityPane = { }, /** - * Returns true if the user has a master password set and false otherwise. - */ - _masterPasswordSet: function () - { - const Cc = Components.classes, Ci = Components.interfaces; - var secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]. - getService(Ci.nsIPKCS11ModuleDB); - var slot = secmodDB.findSlotByName(""); - if (slot) { - var status = slot.status; - var hasMP = status != Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED && - status != Ci.nsIPKCS11Slot.SLOT_READY; - return hasMP; - } else { - // XXX I have no bloody idea what this means - return false; - } - }, - - /** * Enables/disables the master password button depending on the state of the * "use master password" checkbox, and prompts for master password removal if * one is set. diff --git a/application/palemoon/components/sessionstore/SessionStore.jsm b/application/palemoon/components/sessionstore/SessionStore.jsm index b74e68a2f..136a3d8de 100644 --- a/application/palemoon/components/sessionstore/SessionStore.jsm +++ b/application/palemoon/components/sessionstore/SessionStore.jsm @@ -106,12 +106,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", #ifdef MOZ_DEVTOOLS XPCOMUtils.defineLazyModuleGetter(this, "ScratchpadManager", - "resource://gre/modules/devtools/scratchpad-manager.jsm"); + "resource://devtools/client/scratchpad/scratchpad-manager.jsm"); Object.defineProperty(this, "HUDService", { get: function HUDService_getter() { - let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools; - return devtools.require("devtools/webconsole/hudservice").HUDService; + let devtools = Cu.import("resource://devtools/shared/Loader.jsm", {}).devtools; + return devtools.require("devtools/client/webconsole/hudservice").HUDService; }, configurable: true, enumerable: true diff --git a/application/palemoon/components/sessionstore/_SessionFile.jsm b/application/palemoon/components/sessionstore/_SessionFile.jsm index 7e1b05f74..e949112f2 100644 --- a/application/palemoon/components/sessionstore/_SessionFile.jsm +++ b/application/palemoon/components/sessionstore/_SessionFile.jsm @@ -41,7 +41,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "console", - "resource://gre/modules/devtools/Console.jsm"); + "resource://gre/modules/Console.jsm"); // An encoder to UTF-8. XPCOMUtils.defineLazyGetter(this, "gEncoder", function () { diff --git a/application/palemoon/components/sessionstore/nsSessionStartup.js b/application/palemoon/components/sessionstore/nsSessionStartup.js index 024246619..7f07e9050 100644 --- a/application/palemoon/components/sessionstore/nsSessionStartup.js +++ b/application/palemoon/components/sessionstore/nsSessionStartup.js @@ -77,9 +77,14 @@ SessionStartup.prototype = { return; } - _SessionFile.read().then( - this._onSessionFileRead.bind(this) - ); + if (Services.prefs.getBoolPref("browser.sessionstore.resume_session_once") || + Services.prefs.getIntPref("browser.startup.page") == 3) { + this._ensureInitialized(); + } else { + _SessionFile.read().then( + this._onSessionFileRead.bind(this) + ); + } }, // Wrap a string as a nsISupports diff --git a/application/palemoon/components/shell/ShellService.jsm b/application/palemoon/components/shell/ShellService.jsm new file mode 100644 index 000000000..12e275bdb --- /dev/null +++ b/application/palemoon/components/shell/ShellService.jsm @@ -0,0 +1,114 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this file, +* You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["ShellService"]; + +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + +Cu.import("resource://gre/modules/AppConstants.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry", + "resource://gre/modules/WindowsRegistry.jsm"); + +/** + * Internal functionality to save and restore the docShell.allow* properties. + */ +let ShellServiceInternal = { + /** + * Used to determine whether or not to offer "Set as desktop background" + * functionality. Even if shell service is available it is not + * guaranteed that it is able to set the background for every desktop + * which is especially true for Linux with its many different desktop + * environments. + */ + get canSetDesktopBackground() { + if (AppConstants.platform == "win" || + AppConstants.platform == "macosx") { + return true; + } + + if (AppConstants.platform == "linux") { + if (this.shellService) { + let linuxShellService = this.shellService + .QueryInterface(Ci.nsIGNOMEShellService); + return linuxShellService.canSetDesktopBackground; + } + } + + return false; + }, + + /** + * Used to determine whether or not to show a "Set Default Browser" + * query dialog. This attribute is true if the application is starting + * up and "browser.shell.checkDefaultBrowser" is true, otherwise it + * is false. + */ + _checkedThisSession: false, + get shouldCheckDefaultBrowser() { + // If we've already checked, the browser has been started and this is a + // new window open, and we don't want to check again. + if (this._checkedThisSession) { + return false; + } + + if (!Services.prefs.getBoolPref("browser.shell.checkDefaultBrowser")) { + return false; + } + + if (AppConstants.platform == "win") { + let optOutValue = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + "Software\\Mozilla\\PaleMoon", + "DefaultBrowserOptOut"); + WindowsRegistry.removeRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + "Software\\Mozilla\\PaleMoon", + "DefaultBrowserOptOut"); + if (optOutValue == "True") { + Services.prefs.setBoolPref("browser.shell.checkDefaultBrowser", false); + return false; + } + } + + return true; + }, + + set shouldCheckDefaultBrowser(shouldCheck) { + Services.prefs.setBoolPref("browser.shell.checkDefaultBrowser", !!shouldCheck); + }, + + isDefaultBrowser(startupCheck, forAllTypes) { + // If this is the first browser window, maintain internal state that we've + // checked this session (so that subsequent window opens don't show the + // default browser dialog). + if (startupCheck) { + this._checkedThisSession = true; + } + if (this.shellService) { + return this.shellService.isDefaultBrowser(startupCheck, forAllTypes); + } + return false; + } +}; + +XPCOMUtils.defineLazyServiceGetter(ShellServiceInternal, "shellService", + "@mozilla.org/browser/shell-service;1", Ci.nsIShellService); + +/** + * The external API exported by this module. + */ +this.ShellService = new Proxy(ShellServiceInternal, { + get(target, name) { + if (name in target) { + return target[name]; + } + if (target.shellService) { + return target.shellService[name]; + } + Services.console.logStringMessage(`${name} not found in ShellService: ${target.shellService}`); + return undefined; + } +}); diff --git a/application/palemoon/components/shell/content/setDesktopBackground.js b/application/palemoon/components/shell/content/setDesktopBackground.js index e90a32d03..53cc70db0 100644 --- a/application/palemoon/components/shell/content/setDesktopBackground.js +++ b/application/palemoon/components/shell/content/setDesktopBackground.js @@ -1,16 +1,14 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +Components.utils.import("resource://gre/modules/AppConstants.jsm"); var Ci = Components.interfaces; var gSetBackground = { -#ifndef XP_MACOSX - _position : "", - _backgroundColor : 0, -#else - _position : "STRETCH", -#endif + _position : AppConstants.platform == "macosx" ? "STRETCH" : "", + _backgroundColor : AppConstants.platform != "macosx" ? 0 : undefined, _screenWidth : 0, _screenHeight : 0, _image : null, @@ -27,23 +25,23 @@ var gSetBackground = { this._canvas = document.getElementById("screen"); this._screenWidth = screen.width; this._screenHeight = screen.height; -#ifdef XP_MACOSX - document.documentElement.getButton("accept").hidden = true; -#endif + if (AppConstants.platform == "macosx") { + document.documentElement.getButton("accept").hidden = true; + } if (this._screenWidth / this._screenHeight >= 1.6) document.getElementById("monitor").setAttribute("aspectratio", "16:10"); -#ifdef XP_WIN - // hide fill + fit options if <win7 since don't work - var version = Components.classes["@mozilla.org/system-info;1"] - .getService(Ci.nsIPropertyBag2) - .getProperty("version"); - var isWindows7OrHigher = (parseFloat(version) >= 6.1); - if (!isWindows7OrHigher) { - document.getElementById("fillPosition").hidden = true; - document.getElementById("fitPosition").hidden = true; + if (AppConstants.platform == "win") { + // Hide fill + fit options if < Win7 since they don't work. + var version = Components.classes["@mozilla.org/system-info;1"] + .getService(Ci.nsIPropertyBag2) + .getProperty("version"); + var isWindows7OrHigher = (parseFloat(version) >= 6.1); + if (!isWindows7OrHigher) { + document.getElementById("fillPosition").hidden = true; + document.getElementById("fitPosition").hidden = true; + } } -#endif // make sure that the correct dimensions will be used setTimeout(function(self) { @@ -62,92 +60,37 @@ var gSetBackground = { var ctx = this._canvas.getContext("2d"); ctx.scale(this._canvas.clientWidth / this._screenWidth, this._canvas.clientHeight / this._screenHeight); -#ifndef XP_MACOSX - this._initColor(); -#else - // Make sure to reset the button state in case the user has already - // set an image as their desktop background. - var setDesktopBackground = document.getElementById("setDesktopBackground"); - setDesktopBackground.hidden = false; - var bundle = document.getElementById("backgroundBundle"); - setDesktopBackground.label = bundle.getString("DesktopBackgroundSet"); - setDesktopBackground.disabled = false; - - document.getElementById("showDesktopPreferences").hidden = true; -#endif + if (AppConstants.platform != "macosx") { + this._initColor(); + } else { + // Make sure to reset the button state in case the user has already + // set an image as their desktop background. + var setDesktopBackground = document.getElementById("setDesktopBackground"); + setDesktopBackground.hidden = false; + var bundle = document.getElementById("backgroundBundle"); + setDesktopBackground.label = bundle.getString("DesktopBackgroundSet"); + setDesktopBackground.disabled = false; + + document.getElementById("showDesktopPreferences").hidden = true; + } this.updatePosition(); }, -#ifndef XP_MACOSX - _initColor: function () - { - var color = this._shell.desktopBackgroundColor; - - const rMask = 4294901760; - const gMask = 65280; - const bMask = 255; - var r = (color & rMask) >> 16; - var g = (color & gMask) >> 8; - var b = (color & bMask); - this.updateColor(this._rgbToHex(r, g, b)); - - var colorpicker = document.getElementById("desktopColor"); - colorpicker.color = this._backgroundColor; - }, - - updateColor: function (aColor) - { - this._backgroundColor = aColor; - this._canvas.style.backgroundColor = aColor; - }, - - // Converts a color string in the format "#RRGGBB" to an integer. - _hexStringToLong: function (aString) - { - return parseInt(aString.substring(1,3), 16) << 16 | - parseInt(aString.substring(3,5), 16) << 8 | - parseInt(aString.substring(5,7), 16); - }, - - _rgbToHex: function (aR, aG, aB) - { - return "#" + [aR, aG, aB].map(function(aInt) aInt.toString(16).replace(/^(.)$/, "0$1")) - .join("").toUpperCase(); - }, -#else - observe: function (aSubject, aTopic, aData) + setDesktopBackground: function () { - if (aTopic == "shell:desktop-background-changed") { - document.getElementById("setDesktopBackground").hidden = true; - document.getElementById("showDesktopPreferences").hidden = false; - + if (AppConstants.platform != "macosx") { + document.persist("menuPosition", "value"); + this._shell.desktopBackgroundColor = this._hexStringToLong(this._backgroundColor); + } else { Components.classes["@mozilla.org/observer-service;1"] .getService(Ci.nsIObserverService) - .removeObserver(this, "shell:desktop-background-changed"); - } - }, - - showDesktopPrefs: function() - { - this._shell.openApplication(Ci.nsIMacShellService.APPLICATION_DESKTOP); - }, -#endif + .addObserver(this, "shell:desktop-background-changed", false); - setDesktopBackground: function () - { -#ifndef XP_MACOSX - document.persist("menuPosition", "value"); - this._shell.desktopBackgroundColor = this._hexStringToLong(this._backgroundColor); -#else - Components.classes["@mozilla.org/observer-service;1"] - .getService(Ci.nsIObserverService) - .addObserver(this, "shell:desktop-background-changed", false); - - var bundle = document.getElementById("backgroundBundle"); - var setDesktopBackground = document.getElementById("setDesktopBackground"); - setDesktopBackground.disabled = true; - setDesktopBackground.label = bundle.getString("DesktopBackgroundDownloading"); -#endif + var bundle = document.getElementById("backgroundBundle"); + var setDesktopBackground = document.getElementById("setDesktopBackground"); + setDesktopBackground.disabled = true; + setDesktopBackground.label = bundle.getString("DesktopBackgroundDownloading"); + } this._shell.setDesktopBackground(this._image, Ci.nsIShellService["BACKGROUND_" + this._position]); }, @@ -157,9 +100,9 @@ var gSetBackground = { var ctx = this._canvas.getContext("2d"); ctx.clearRect(0, 0, this._screenWidth, this._screenHeight); -#ifndef XP_MACOSX - this._position = document.getElementById("menuPosition").value; -#endif + if (AppConstants.platform != "macosx") { + this._position = document.getElementById("menuPosition").value; + } switch (this._position) { case "TILE": @@ -171,43 +114,101 @@ var gSetBackground = { case "STRETCH": ctx.drawImage(this._image, 0, 0, this._screenWidth, this._screenHeight); break; - case "CENTER": - var x = (this._screenWidth - this._image.naturalWidth) / 2; - var y = (this._screenHeight - this._image.naturalHeight) / 2; + case "CENTER": { + let x = (this._screenWidth - this._image.naturalWidth) / 2; + let y = (this._screenHeight - this._image.naturalHeight) / 2; ctx.drawImage(this._image, x, y); break; - case "FILL": - //Try maxing width first, overflow height - var widthRatio = this._screenWidth / this._image.naturalWidth; - var width = this._image.naturalWidth * widthRatio; - var height = this._image.naturalHeight * widthRatio; + } + case "FILL": { + // Try maxing width first, overflow height. + let widthRatio = this._screenWidth / this._image.naturalWidth; + let width = this._image.naturalWidth * widthRatio; + let height = this._image.naturalHeight * widthRatio; if (height < this._screenHeight) { - //height less than screen, max height and overflow width - var heightRatio = this._screenHeight / this._image.naturalHeight; + // Height less than screen, max height and overflow width. + let heightRatio = this._screenHeight / this._image.naturalHeight; width = this._image.naturalWidth * heightRatio; height = this._image.naturalHeight * heightRatio; } - var x = (this._screenWidth - width) / 2; - var y = (this._screenHeight - height) / 2; + let x = (this._screenWidth - width) / 2; + let y = (this._screenHeight - height) / 2; ctx.drawImage(this._image, x, y, width, height); break; - case "FIT": - //Try maxing width first, top and bottom borders - var widthRatio = this._screenWidth / this._image.naturalWidth; - var width = this._image.naturalWidth * widthRatio; - var height = this._image.naturalHeight * widthRatio; - var x = 0; - var y = (this._screenHeight - height) / 2; + } + case "FIT": { + // Try maxing width first, top and bottom borders. + let widthRatio = this._screenWidth / this._image.naturalWidth; + let width = this._image.naturalWidth * widthRatio; + let height = this._image.naturalHeight * widthRatio; + let x = 0; + let y = (this._screenHeight - height) / 2; if (height > this._screenHeight) { - //height overflow, maximise height, side borders - var heightRatio = this._screenHeight / this._image.naturalHeight; + // Height overflow, maximise height, side borders. + let heightRatio = this._screenHeight / this._image.naturalHeight; width = this._image.naturalWidth * heightRatio; height = this._image.naturalHeight * heightRatio; x = (this._screenWidth - width) / 2; y = 0; } ctx.drawImage(this._image, x, y, width, height); - break; + break; + } } } }; + +if (AppConstants.platform != "macosx") { + gSetBackground["_initColor"] = function () + { + var color = this._shell.desktopBackgroundColor; + + const rMask = 4294901760; + const gMask = 65280; + const bMask = 255; + var r = (color & rMask) >> 16; + var g = (color & gMask) >> 8; + var b = (color & bMask); + this.updateColor(this._rgbToHex(r, g, b)); + + var colorpicker = document.getElementById("desktopColor"); + colorpicker.color = this._backgroundColor; + }; + + gSetBackground["updateColor"] = function (aColor) + { + this._backgroundColor = aColor; + this._canvas.style.backgroundColor = aColor; + }; + + // Converts a color string in the format "#RRGGBB" to an integer. + gSetBackground["_hexStringToLong"] = function (aString) + { + return parseInt(aString.substring(1, 3), 16) << 16 | + parseInt(aString.substring(3, 5), 16) << 8 | + parseInt(aString.substring(5, 7), 16); + }; + + gSetBackground["_rgbToHex"] = function (aR, aG, aB) + { + return "#" + [aR, aG, aB].map(aInt => aInt.toString(16).replace(/^(.)$/, "0$1")) + .join("").toUpperCase(); + }; +} else { + gSetBackground["observe"] = function (aSubject, aTopic, aData) + { + if (aTopic == "shell:desktop-background-changed") { + document.getElementById("setDesktopBackground").hidden = true; + document.getElementById("showDesktopPreferences").hidden = false; + + Components.classes["@mozilla.org/observer-service;1"] + .getService(Ci.nsIObserverService) + .removeObserver(this, "shell:desktop-background-changed"); + } + }; + + gSetBackground["showDesktopPrefs"] = function() + { + this._shell.openApplication(Ci.nsIMacShellService.APPLICATION_DESKTOP); + }; +} diff --git a/application/palemoon/components/shell/jar.mn b/application/palemoon/components/shell/jar.mn index eed15c397..1f33b5d56 100644 --- a/application/palemoon/components/shell/jar.mn +++ b/application/palemoon/components/shell/jar.mn @@ -4,4 +4,4 @@ browser.jar: * content/browser/setDesktopBackground.xul (content/setDesktopBackground.xul) -* content/browser/setDesktopBackground.js (content/setDesktopBackground.js) + content/browser/setDesktopBackground.js (content/setDesktopBackground.js) diff --git a/application/palemoon/components/shell/moz.build b/application/palemoon/components/shell/moz.build index 38965c5d7..94ec88571 100644 --- a/application/palemoon/components/shell/moz.build +++ b/application/palemoon/components/shell/moz.build @@ -1,4 +1,4 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this @@ -18,6 +18,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': XPIDL_SOURCES += [ 'nsIMacShellService.idl', ] +elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: + XPIDL_SOURCES += [ + 'nsIGNOMEShellService.idl', + ] XPIDL_MODULE = 'shellservice' @@ -29,7 +33,7 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': SOURCES += [ 'nsMacShellService.cpp', ] -elif CONFIG['MOZ_WIDGET_GTK']: +elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: SOURCES += [ 'nsGNOMEShellService.cpp', ] @@ -42,6 +46,10 @@ EXTRA_COMPONENTS += [ 'nsSetDefaultBrowser.manifest', ] +EXTRA_JS_MODULES += [ + 'ShellService.jsm', +] + for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION'): DEFINES[var] = '"%s"' % CONFIG[var] diff --git a/application/palemoon/components/shell/nsGNOMEShellService.cpp b/application/palemoon/components/shell/nsGNOMEShellService.cpp index 14510d111..9bc5f5913 100644 --- a/application/palemoon/components/shell/nsGNOMEShellService.cpp +++ b/application/palemoon/components/shell/nsGNOMEShellService.cpp @@ -21,12 +21,13 @@ #include "nsIStringBundle.h" #include "nsIOutputStream.h" #include "nsIProcess.h" -#include "nsNetUtil.h" +#include "nsServiceManagerUtils.h" +#include "nsComponentManagerUtils.h" #include "nsIDOMHTMLImageElement.h" #include "nsIImageLoadingContent.h" #include "imgIRequest.h" #include "imgIContainer.h" -#include "prprf.h" +#include "mozilla/Sprintf.h" #if defined(MOZ_WIDGET_GTK) #include "nsIImageToPixbuf.h" #endif @@ -116,7 +117,7 @@ nsGNOMEShellService::Init() return appPath->GetNativePath(mAppPath); } -NS_IMPL_ISUPPORTS(nsGNOMEShellService, nsIShellService) +NS_IMPL_ISUPPORTS(nsGNOMEShellService, nsIGNOMEShellService, nsIShellService) bool nsGNOMEShellService::GetAppPathFromLauncher() @@ -152,7 +153,8 @@ nsGNOMEShellService::KeyMatchesAppName(const char *aKeyValue) const gchar *commandPath; if (mUseLocaleFilenames) { - gchar *nativePath = g_filename_from_utf8(aKeyValue, -1, nullptr, nullptr, nullptr); + gchar *nativePath = g_filename_from_utf8(aKeyValue, -1, + nullptr, nullptr, nullptr); if (!nativePath) { NS_ERROR("Error converting path to filesystem encoding"); return false; @@ -199,8 +201,6 @@ nsGNOMEShellService::IsDefaultBrowser(bool aStartupCheck, bool* aIsDefaultBrowser) { *aIsDefaultBrowser = false; - if (aStartupCheck) - mCheckedThisSession = true; nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); @@ -284,7 +284,7 @@ nsGNOMEShellService::SetDefaultBrowser(bool aClaimAllTypes, NS_ENSURE_SUCCESS(rv, rv); nsString brandShortName; - brandBundle->GetStringFromName(MOZ_UTF16("brandShortName"), + brandBundle->GetStringFromName(u"brandShortName", getter_Copies(brandShortName)); // use brandShortName as the application id. @@ -312,41 +312,14 @@ nsGNOMEShellService::SetDefaultBrowser(bool aClaimAllTypes, } } - return NS_OK; -} - -NS_IMETHODIMP -nsGNOMEShellService::GetShouldCheckDefaultBrowser(bool* aResult) -{ - // If we've already checked, the browser has been started and this is a - // new window open, and we don't want to check again. - if (mCheckedThisSession) { - *aResult = false; - return NS_OK; + nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); + if (prefs) { + (void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true); + // Reset the number of times the dialog should be shown + // before it is silenced. + (void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0); } - nsCOMPtr<nsIPrefBranch> prefs; - nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID)); - if (pserve) - pserve->GetBranch("", getter_AddRefs(prefs)); - - if (prefs) - prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult); - - return NS_OK; -} - -NS_IMETHODIMP -nsGNOMEShellService::SetShouldCheckDefaultBrowser(bool aShouldCheck) -{ - nsCOMPtr<nsIPrefBranch> prefs; - nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID)); - if (pserve) - pserve->GetBranch("", getter_AddRefs(prefs)); - - if (prefs) - prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck); - return NS_OK; } @@ -386,7 +359,7 @@ WriteImage(const nsCString& aPath, imgIContainer* aImage) return res ? NS_OK : NS_ERROR_FAILURE; #endif } - + NS_IMETHODIMP nsGNOMEShellService::SetDesktopBackground(nsIDOMElement* aElement, int32_t aPosition) @@ -407,15 +380,15 @@ nsGNOMEShellService::SetDesktopBackground(nsIDOMElement* aElement, // Set desktop wallpaper filling style nsAutoCString options; if (aPosition == BACKGROUND_TILE) - options.Assign("wallpaper"); + options.AssignLiteral("wallpaper"); else if (aPosition == BACKGROUND_STRETCH) - options.Assign("stretched"); + options.AssignLiteral("stretched"); else if (aPosition == BACKGROUND_FILL) - options.Assign("zoom"); + options.AssignLiteral("zoom"); else if (aPosition == BACKGROUND_FIT) - options.Assign("scaled"); + options.AssignLiteral("scaled"); else - options.Assign("centered"); + options.AssignLiteral("centered"); // Write the background file to the home directory. nsAutoCString filePath(PR_GetEnv("HOME")); @@ -429,7 +402,7 @@ nsGNOMEShellService::SetDesktopBackground(nsIDOMElement* aElement, rv = bundleService->CreateBundle(BRAND_PROPERTIES, getter_AddRefs(brandBundle)); if (NS_SUCCEEDED(rv) && brandBundle) { - rv = brandBundle->GetStringFromName(MOZ_UTF16("brandShortName"), + rv = brandBundle->GetStringFromName(u"brandShortName", getter_Copies(brandName)); NS_ENSURE_SUCCESS(rv, rv); } @@ -438,7 +411,7 @@ nsGNOMEShellService::SetDesktopBackground(nsIDOMElement* aElement, // build the file name filePath.Append('/'); filePath.Append(NS_ConvertUTF16toUTF8(brandName)); - filePath.Append("_wallpaper.png"); + filePath.AppendLiteral("_wallpaper.png"); // write the image to a file in the home dir rv = WriteImage(filePath, container); @@ -478,7 +451,7 @@ nsGNOMEShellService::SetDesktopBackground(nsIDOMElement* aElement, // Set the image to an empty string first to force a refresh // (since we could be writing a new image on top of an existing - // Firefox_wallpaper.png and nautilus doesn't monitor the file for changes) + // PaleMoon_wallpaper.png and nautilus doesn't monitor the file for changes) gconf->SetString(NS_LITERAL_CSTRING(kDesktopImageKey), EmptyCString()); @@ -543,7 +516,7 @@ ColorToCString(uint32_t aColor, nsCString& aResult) uint16_t green = COLOR_8_TO_16_BIT((aColor >> 8) & 0xff); uint16_t blue = COLOR_8_TO_16_BIT(aColor & 0xff); - PR_snprintf(buf, 14, "#%04x%04x%04x", red, green, blue); + snprintf(buf, 14, "#%04x%04x%04x", red, green, blue); } NS_IMETHODIMP @@ -580,9 +553,9 @@ nsGNOMEShellService::OpenApplication(int32_t aApplication) { nsAutoCString scheme; if (aApplication == APPLICATION_MAIL) - scheme.Assign("mailto"); + scheme.AssignLiteral("mailto"); else if (aApplication == APPLICATION_NEWS) - scheme.Assign("news"); + scheme.AssignLiteral("news"); else return NS_ERROR_NOT_AVAILABLE; diff --git a/application/palemoon/components/shell/nsGNOMEShellService.h b/application/palemoon/components/shell/nsGNOMEShellService.h index 36a4a0c42..a7b003802 100644 --- a/application/palemoon/components/shell/nsGNOMEShellService.h +++ b/application/palemoon/components/shell/nsGNOMEShellService.h @@ -6,28 +6,28 @@ #ifndef nsgnomeshellservice_h____ #define nsgnomeshellservice_h____ -#include "nsIShellService.h" +#include "nsIGNOMEShellService.h" #include "nsStringAPI.h" #include "mozilla/Attributes.h" -class nsGNOMEShellService final : public nsIShellService +class nsGNOMEShellService final : public nsIGNOMEShellService { public: - nsGNOMEShellService() : mCheckedThisSession(false), mAppIsInPath(false) { } + nsGNOMEShellService() : mAppIsInPath(false) { } NS_DECL_ISUPPORTS NS_DECL_NSISHELLSERVICE + NS_DECL_NSIGNOMESHELLSERVICE - nsresult Init() NS_HIDDEN; + nsresult Init(); private: ~nsGNOMEShellService() {} - NS_HIDDEN_(bool) KeyMatchesAppName(const char *aKeyValue) const; - NS_HIDDEN_(bool) CheckHandlerMatchesAppName(const nsACString& handler) const; + bool KeyMatchesAppName(const char *aKeyValue) const; + bool CheckHandlerMatchesAppName(const nsACString& handler) const; - NS_HIDDEN_(bool) GetAppPathFromLauncher(); - bool mCheckedThisSession; + bool GetAppPathFromLauncher(); bool mUseLocaleFilenames; nsCString mAppPath; bool mAppIsInPath; diff --git a/application/palemoon/components/shell/nsIGNOMEShellService.idl b/application/palemoon/components/shell/nsIGNOMEShellService.idl new file mode 100644 index 000000000..842ce5e8a --- /dev/null +++ b/application/palemoon/components/shell/nsIGNOMEShellService.idl @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsIShellService.idl" + +[scriptable, uuid(2ce5c803-edcd-443d-98eb-ceba86d02d13)] +interface nsIGNOMEShellService : nsIShellService +{ + /** + * Used to determine whether or not to offer "Set as desktop background" + * functionality. Even if shell service is available it is not + * guaranteed that it is able to set the background for every desktop + * which is especially true for Linux with its many different desktop + * environments. + */ + readonly attribute boolean canSetDesktopBackground; +}; + diff --git a/application/palemoon/components/shell/nsIMacShellService.idl b/application/palemoon/components/shell/nsIMacShellService.idl index 3c2f42315..6a532bbd0 100644 --- a/application/palemoon/components/shell/nsIMacShellService.idl +++ b/application/palemoon/components/shell/nsIMacShellService.idl @@ -5,7 +5,7 @@ #include "nsIShellService.idl" -[scriptable, uuid(7f8ca08e-1df4-4735-86e9-50dedb48e5e8)] +[scriptable, uuid(387fdc80-0077-4b60-a0d9-d9e80a83ba64)] interface nsIMacShellService : nsIShellService { const long APPLICATION_KEYCHAIN_ACCESS = 2; diff --git a/application/palemoon/components/shell/nsIShellService.idl b/application/palemoon/components/shell/nsIShellService.idl index 4825741b3..3e7e94b00 100644 --- a/application/palemoon/components/shell/nsIShellService.idl +++ b/application/palemoon/components/shell/nsIShellService.idl @@ -8,7 +8,7 @@ interface nsIDOMElement; interface nsIFile; -[scriptable, uuid(99d2e9f1-3c86-40f7-81fd-3060c18489f0)] +[scriptable, uuid(2d1a95e4-5bd8-4eeb-b0a8-c1455fd2a357)] interface nsIShellService : nsISupports { /** @@ -39,23 +39,6 @@ interface nsIShellService : nsISupports void setDefaultBrowser(in boolean aClaimAllTypes, in boolean aForAllUsers); /** - * Used to determine whether or not to show a "Set Default Browser" - * query dialog. This attribute is true if the application is starting - * up and "browser.shell.checkDefaultBrowser" is true, otherwise it - * is false. - */ - attribute boolean shouldCheckDefaultBrowser; - - /** - * Used to determine whether or not to offer "Set as desktop background" - * functionality. Even if shell service is available it is not - * guaranteed that it is able to set the background for every desktop - * which is especially true for Linux with its many different desktop - * environments. - */ - readonly attribute boolean canSetDesktopBackground; - - /** * Flags for positioning/sizing of the Desktop Background image. */ const long BACKGROUND_TILE = 1; diff --git a/application/palemoon/components/shell/nsIWindowsShellService.idl b/application/palemoon/components/shell/nsIWindowsShellService.idl index 913eb4292..57ed37055 100644 --- a/application/palemoon/components/shell/nsIWindowsShellService.idl +++ b/application/palemoon/components/shell/nsIWindowsShellService.idl @@ -5,7 +5,7 @@ #include "nsIShellService.idl" -[scriptable, uuid(89b0a761-d9a0-4c39-ab83-d81566459a31)] +[scriptable, uuid(f8a26b94-49e5-4441-8fbc-315e0b4f22ef)] interface nsIWindowsShellService : nsIShellService { /** diff --git a/application/palemoon/components/shell/nsMacShellService.cpp b/application/palemoon/components/shell/nsMacShellService.cpp index 914b9ae65..d8d64039d 100644 --- a/application/palemoon/components/shell/nsMacShellService.cpp +++ b/application/palemoon/components/shell/nsMacShellService.cpp @@ -17,13 +17,13 @@ #include "nsIURL.h" #include "nsIWebBrowserPersist.h" #include "nsMacShellService.h" -#include "nsNetUtil.h" +#include "nsIProperties.h" +#include "nsServiceManagerUtils.h" #include "nsShellService.h" #include "nsStringAPI.h" #include "nsIDocShell.h" #include "nsILoadContext.h" - #include <CoreFoundation/CoreFoundation.h> #include <ApplicationServices/ApplicationServices.h> @@ -49,19 +49,14 @@ nsMacShellService::IsDefaultBrowser(bool aStartupCheck, return NS_ERROR_FAILURE; } - // Get the default http handler's bundle ID (or nullptr if it has not been explicitly set) + // Get the default http handler's bundle ID (or nullptr if it has not been + // explicitly set) CFStringRef defaultBrowserID = ::LSCopyDefaultHandlerForURLScheme(CFSTR("http")); if (defaultBrowserID) { *aIsDefaultBrowser = ::CFStringCompare(firefoxID, defaultBrowserID, 0) == kCFCompareEqualTo; ::CFRelease(defaultBrowserID); } - // If this is the first browser window, maintain internal state that we've - // checked this session (so that subsequent window opens don't show the - // default browser dialog). - if (aStartupCheck) - mCheckedThisSession = true; - return NS_OK; } @@ -90,47 +85,15 @@ nsMacShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers) return NS_ERROR_FAILURE; } } - - return NS_OK; -} -NS_IMETHODIMP -nsMacShellService::GetShouldCheckDefaultBrowser(bool* aResult) -{ - // If we've already checked, the browser has been started and this is a - // new window open, and we don't want to check again. - if (mCheckedThisSession) { - *aResult = false; - return NS_OK; + nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); + if (prefs) { + (void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true); + // Reset the number of times the dialog should be shown + // before it is silenced. + (void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0); } - nsCOMPtr<nsIPrefBranch> prefs; - nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID)); - if (pserve) - pserve->GetBranch("", getter_AddRefs(prefs)); - - prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult); - - return NS_OK; -} - -NS_IMETHODIMP -nsMacShellService::SetShouldCheckDefaultBrowser(bool aShouldCheck) -{ - nsCOMPtr<nsIPrefBranch> prefs; - nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID)); - if (pserve) - pserve->GetBranch("", getter_AddRefs(prefs)); - - prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck); - - return NS_OK; -} - -NS_IMETHODIMP -nsMacShellService::GetCanSetDesktopBackground(bool* aResult) -{ - *aResult = true; return NS_OK; } @@ -202,8 +165,10 @@ nsMacShellService::SetDesktopBackground(nsIDOMElement* aElement, loadContext = do_QueryInterface(docShell); } - return wbp->SaveURI(imageURI, nullptr, docURI, content->OwnerDoc()->GetReferrerPolicy(), - nullptr, nullptr, mBackgroundFile, loadContext); + return wbp->SaveURI(imageURI, nullptr, + docURI, content->OwnerDoc()->GetReferrerPolicy(), + nullptr, nullptr, + mBackgroundFile, loadContext); } NS_IMETHODIMP @@ -269,7 +234,8 @@ nsMacShellService::OnStateChange(nsIWebProgress* aWebProgress, OSStatus status; // Convert the path into a FSRef - status = ::FSPathMakeRef((const UInt8*)nativePath.get(), &pictureRef, nullptr); + status = ::FSPathMakeRef((const UInt8*)nativePath.get(), &pictureRef, + nullptr); if (status == noErr) { err = ::FSNewAlias(nil, &pictureRef, &aliasHandle); if (err == noErr && aliasHandle == nil) @@ -336,8 +302,8 @@ nsMacShellService::OpenApplication(int32_t aApplication) } break; case nsIMacShellService::APPLICATION_KEYCHAIN_ACCESS: - err = ::LSGetApplicationForInfo('APPL', 'kcmr', nullptr, kLSRolesAll, nullptr, - &appURL); + err = ::LSGetApplicationForInfo('APPL', 'kcmr', nullptr, kLSRolesAll, + nullptr, &appURL); break; case nsIMacShellService::APPLICATION_NETWORK: { @@ -349,8 +315,7 @@ nsMacShellService::OpenApplication(int32_t aApplication) if (!exists) return NS_ERROR_FILE_NOT_FOUND; return lf->Launch(); - } - break; + } case nsIMacShellService::APPLICATION_DESKTOP: { nsCOMPtr<nsIFile> lf; @@ -361,8 +326,7 @@ nsMacShellService::OpenApplication(int32_t aApplication) if (!exists) return NS_ERROR_FILE_NOT_FOUND; return lf->Launch(); - } - break; + } } if (appURL && err == noErr) { diff --git a/application/palemoon/components/shell/nsMacShellService.h b/application/palemoon/components/shell/nsMacShellService.h index 7ca1c71ac..db9527809 100644 --- a/application/palemoon/components/shell/nsMacShellService.h +++ b/application/palemoon/components/shell/nsMacShellService.h @@ -15,7 +15,7 @@ class nsMacShellService : public nsIMacShellService, public nsIWebProgressListener { public: - nsMacShellService() : mCheckedThisSession(false) {}; + nsMacShellService() {}; NS_DECL_ISUPPORTS NS_DECL_NSISHELLSERVICE @@ -27,8 +27,6 @@ protected: private: nsCOMPtr<nsIFile> mBackgroundFile; - - bool mCheckedThisSession; }; #endif // nsmacshellservice_h____ diff --git a/application/palemoon/components/shell/nsSetDefaultBrowser.js b/application/palemoon/components/shell/nsSetDefaultBrowser.js index d1d1e72cb..c7a78c538 100644 --- a/application/palemoon/components/shell/nsSetDefaultBrowser.js +++ b/application/palemoon/components/shell/nsSetDefaultBrowser.js @@ -2,13 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* - * -setDefaultBrowser commandline handler +/* + * --setDefaultBrowser commandline handler * Makes the current executable the "default browser". */ const Cc = Components.classes; const Ci = Components.interfaces; +Components.utils.import("resource:///modules/ShellService.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); function nsSetDefaultBrowser() {} @@ -16,13 +17,11 @@ function nsSetDefaultBrowser() {} nsSetDefaultBrowser.prototype = { handle: function nsSetDefault_handle(aCmdline) { if (aCmdline.handleFlag("setDefaultBrowser", false)) { - var shell = Cc["@mozilla.org/browser/shell-service;1"]. - getService(Ci.nsIShellService); - shell.setDefaultBrowser(true, true); + ShellService.setDefaultBrowser(true, true); } }, - helpInfo: " -setDefaultBrowser Set this app as the default browser.\n", + helpInfo: " --setDefaultBrowser Set this app as the default browser.\n", classID: Components.ID("{F57899D0-4E2C-4ac6-9E29-50C736103B0C}"), QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]), diff --git a/application/palemoon/components/shell/nsShellService.h b/application/palemoon/components/shell/nsShellService.h index d5fade37b..516a8423a 100644 --- a/application/palemoon/components/shell/nsShellService.h +++ b/application/palemoon/components/shell/nsShellService.h @@ -4,6 +4,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #define PREF_CHECKDEFAULTBROWSER "browser.shell.checkDefaultBrowser" +#define PREF_SKIPDEFAULTBROWSERCHECK "browser.shell.skipDefaultBrowserCheck" +#define PREF_DEFAULTBROWSERCHECKCOUNT "browser.shell.defaultBrowserCheckCount" #define SHELLSERVICE_PROPERTIES "chrome://browser/locale/shellservice.properties" #define BRAND_PROPERTIES "chrome://branding/locale/brand.properties" diff --git a/application/palemoon/components/shell/nsWindowsShellService.cpp b/application/palemoon/components/shell/nsWindowsShellService.cpp index 813ec4fe1..c4039b95a 100644 --- a/application/palemoon/components/shell/nsWindowsShellService.cpp +++ b/application/palemoon/components/shell/nsWindowsShellService.cpp @@ -3,6 +3,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "nsWindowsShellService.h" + #include "imgIContainer.h" #include "imgIRequest.h" #include "mozilla/gfx/2D.h" @@ -15,8 +17,8 @@ #include "nsIServiceManager.h" #include "nsIStringBundle.h" #include "nsNetUtil.h" +#include "nsServiceManagerUtils.h" #include "nsShellService.h" -#include "nsWindowsShellService.h" #include "nsIProcess.h" #include "nsICategoryManager.h" #include "nsBrowserCompsCID.h" @@ -27,6 +29,7 @@ #include "nsUnicharUtils.h" #include "nsIWinTaskbar.h" #include "nsISupportsPrimitives.h" +#include "nsIURLFormatter.h" #include "nsThreadUtils.h" #include "nsXULAppAPI.h" #include "mozilla/WindowsVersion.h" @@ -47,6 +50,9 @@ #include <mbstring.h> #include <shlwapi.h> +#include <lm.h> +#undef ACCESS_READ + #ifndef MAX_BUF #define MAX_BUF 4096 #endif @@ -129,7 +135,7 @@ OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey) // The following keys are set to make PaleMoon appear in the Start Menu as the // browser: // -// HKCU\SOFTWARE\Clients\StartMenuInternet\FIREFOX.EXE\ +// HKCU\SOFTWARE\Clients\StartMenuInternet\PaleMoon.EXE\ // (default) REG_SZ <appname> // DefaultIcon (default) REG_SZ <apppath>,0 // InstallInfo HideIconsCommand REG_SZ <uninstpath> /HideShortcuts @@ -278,20 +284,15 @@ nsWindowsShellService::ShortcutMaintenance() return NS_ERROR_UNEXPECTED; NS_NAMED_LITERAL_CSTRING(prefName, "browser.taskbar.lastgroupid"); - nsCOMPtr<nsIPrefService> prefs = + nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); if (!prefs) return NS_ERROR_UNEXPECTED; - nsCOMPtr<nsIPrefBranch> prefBranch; - prefs->GetBranch(nullptr, getter_AddRefs(prefBranch)); - if (!prefBranch) - return NS_ERROR_UNEXPECTED; - nsCOMPtr<nsISupportsString> prefString; - rv = prefBranch->GetComplexValue(prefName.get(), - NS_GET_IID(nsISupportsString), - getter_AddRefs(prefString)); + rv = prefs->GetComplexValue(prefName.get(), + NS_GET_IID(nsISupportsString), + getter_AddRefs(prefString)); if (NS_SUCCEEDED(rv)) { nsAutoString version; prefString->GetData(version); @@ -307,9 +308,9 @@ nsWindowsShellService::ShortcutMaintenance() return rv; prefString->SetData(appId); - rv = prefBranch->SetComplexValue(prefName.get(), - NS_GET_IID(nsISupportsString), - prefString); + rv = prefs->SetComplexValue(prefName.get(), + NS_GET_IID(nsISupportsString), + prefString); if (NS_FAILED(rv)) { NS_WARNING("Couldn't set last user model id!"); return NS_ERROR_UNEXPECTED; @@ -325,38 +326,47 @@ nsWindowsShellService::ShortcutMaintenance() } static bool -IsAARDefaultHTTP(IApplicationAssociationRegistration* pAAR, - bool* aIsDefaultBrowser) +IsAARDefault(const RefPtr<IApplicationAssociationRegistration>& pAAR, + LPCWSTR aClassName) { // Make sure the Prog ID matches what we have LPWSTR registeredApp; - HRESULT hr = pAAR->QueryCurrentDefault(L"http", AT_URLPROTOCOL, AL_EFFECTIVE, + bool isProtocol = *aClassName != L'.'; + ASSOCIATIONTYPE queryType = isProtocol ? AT_URLPROTOCOL : AT_FILEEXTENSION; + HRESULT hr = pAAR->QueryCurrentDefault(aClassName, queryType, AL_EFFECTIVE, ®isteredApp); - if (SUCCEEDED(hr)) { - LPCWSTR firefoxHTTPProgID = L"PaleMoonURL"; - *aIsDefaultBrowser = !wcsicmp(registeredApp, firefoxHTTPProgID); - CoTaskMemFree(registeredApp); - } else { - *aIsDefaultBrowser = false; + if (FAILED(hr)) { + return false; } - return SUCCEEDED(hr); + + LPCWSTR progID = isProtocol ? L"PaleMoonURL" : L"PaleMoonHTML"; + bool isDefault = !wcsicmp(registeredApp, progID); + CoTaskMemFree(registeredApp); + + return isDefault; } -static bool -IsAARDefaultHTML(IApplicationAssociationRegistration* pAAR, - bool* aIsDefaultBrowser) +static void +IsDefaultBrowserWin8(bool aCheckAllTypes, bool* aIsDefaultBrowser) { - LPWSTR registeredApp; - HRESULT hr = pAAR->QueryCurrentDefault(L".html", AT_FILEEXTENSION, AL_EFFECTIVE, - ®isteredApp); - if (SUCCEEDED(hr)) { - LPCWSTR firefoxHTMLProgID = L"PaleMoonHTML"; - *aIsDefaultBrowser = !wcsicmp(registeredApp, firefoxHTMLProgID); - CoTaskMemFree(registeredApp); - } else { - *aIsDefaultBrowser = false; + RefPtr<IApplicationAssociationRegistration> pAAR; + HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration, + nullptr, + CLSCTX_INPROC, + IID_IApplicationAssociationRegistration, + getter_AddRefs(pAAR)); + if (FAILED(hr)) { + return; + } + + bool res = IsAARDefault(pAAR, L"http"); + if (*aIsDefaultBrowser) { + *aIsDefaultBrowser = res; + } + res = IsAARDefault(pAAR, L".html"); + if (*aIsDefaultBrowser && aCheckAllTypes) { + *aIsDefaultBrowser = res; } - return SUCCEEDED(hr); } /* @@ -369,37 +379,27 @@ bool nsWindowsShellService::IsDefaultBrowserVista(bool aCheckAllTypes, bool* aIsDefaultBrowser) { - IApplicationAssociationRegistration* pAAR; + RefPtr<IApplicationAssociationRegistration> pAAR; HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration, nullptr, CLSCTX_INPROC, IID_IApplicationAssociationRegistration, - (void**)&pAAR); - - if (SUCCEEDED(hr)) { - if (aCheckAllTypes) { - BOOL res; - hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE, - APP_REG_NAME, - &res); - *aIsDefaultBrowser = res; - - // If we have all defaults, let's make sure that our ProgID - // is explicitly returned as well. Needed only for Windows 8. - if (*aIsDefaultBrowser && IsWin8OrLater()) { - IsAARDefaultHTTP(pAAR, aIsDefaultBrowser); - if (*aIsDefaultBrowser) { - IsAARDefaultHTML(pAAR, aIsDefaultBrowser); - } - } - } else { - IsAARDefaultHTTP(pAAR, aIsDefaultBrowser); - } + getter_AddRefs(pAAR)); + if (FAILED(hr)) { + return false; + } - pAAR->Release(); - return true; + if (aCheckAllTypes) { + BOOL res; + hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE, + APP_REG_NAME, + &res); + *aIsDefaultBrowser = res; + } else if (!IsWin8OrLater()) { + *aIsDefaultBrowser = IsAARDefault(pAAR, L"http"); } - return false; + + return true; } NS_IMETHODIMP @@ -407,12 +407,6 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck, bool aForAllTypes, bool* aIsDefaultBrowser) { - // If this is the first browser window, maintain internal state that we've - // checked this session (so that subsequent window opens don't show the - // default browser dialog). - if (aStartupCheck) - mCheckedThisSession = true; - // Assume we're the default unless one of the several checks below tell us // otherwise. *aIsDefaultBrowser = true; @@ -499,6 +493,9 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck, // previous checks show that PaleMoon is the default browser. if (*aIsDefaultBrowser) { IsDefaultBrowserVista(aForAllTypes, aIsDefaultBrowser); + if (IsWin8OrLater()) { + IsDefaultBrowserWin8(aForAllTypes, aIsDefaultBrowser); + } } // To handle the case where DDE isn't disabled due for a user because there @@ -603,13 +600,6 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck, return NS_OK; } -NS_IMETHODIMP -nsWindowsShellService::GetCanSetDesktopBackground(bool* aResult) -{ - *aResult = true; - return NS_OK; -} - static nsresult DynSHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo) { @@ -628,14 +618,34 @@ DynSHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo) return NS_ERROR_FAILURE; } - nsresult rv = - SUCCEEDED(SHOpenWithDialogFn(hwndParent, poainfo)) ? NS_OK : - NS_ERROR_FAILURE; + nsresult rv; + HRESULT hr = SHOpenWithDialogFn(hwndParent, poainfo); + if (SUCCEEDED(hr) || (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))) { + rv = NS_OK; + } else { + rv = NS_ERROR_FAILURE; + } FreeLibrary(shellDLL); return rv; } nsresult +nsWindowsShellService::LaunchControlPanelDefaultsSelectionUI() +{ + IApplicationAssociationRegistrationUI* pAARUI; + HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistrationUI, + NULL, + CLSCTX_INPROC, + IID_IApplicationAssociationRegistrationUI, + (void**)&pAARUI); + if (SUCCEEDED(hr)) { + hr = pAARUI->LaunchAdvancedAssociationUI(APP_REG_NAME); + pAARUI->Release(); + } + return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult nsWindowsShellService::LaunchControlPanelDefaultPrograms() { // Build the path control.exe path safely @@ -651,7 +661,8 @@ nsWindowsShellService::LaunchControlPanelDefaultPrograms() return NS_ERROR_FAILURE; } - WCHAR params[] = L"control.exe /name Microsoft.DefaultPrograms /page pageDefaultProgram"; + WCHAR params[] = L"control.exe /name Microsoft.DefaultPrograms /page " + "pageDefaultProgram\\pageAdvancedSettings?pszAppName=" APP_REG_NAME; STARTUPINFOW si = {sizeof(si), 0}; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOWDEFAULT; @@ -666,9 +677,62 @@ nsWindowsShellService::LaunchControlPanelDefaultPrograms() return NS_OK; } +static bool +IsWindowsLogonConnected() +{ + WCHAR userName[UNLEN + 1]; + DWORD size = ArrayLength(userName); + if (!GetUserNameW(userName, &size)) { + return false; + } + + LPUSER_INFO_24 info; + if (NetUserGetInfo(nullptr, userName, 24, (LPBYTE *)&info) + != NERR_Success) { + return false; + } + bool connected = info->usri24_internet_identity; + NetApiBufferFree(info); + + return connected; +} + +static bool +SettingsAppBelievesConnected() +{ + nsresult rv; + nsCOMPtr<nsIWindowsRegKey> regKey = + do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv); + if (NS_FAILED(rv)) { + return false; + } + + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, + NS_LITERAL_STRING("SOFTWARE\\Microsoft\\Windows\\Shell\\Associations"), + nsIWindowsRegKey::ACCESS_READ); + if (NS_FAILED(rv)) { + return false; + } + + uint32_t value; + rv = regKey->ReadIntValue(NS_LITERAL_STRING("IsConnectedAtLogon"), &value); + if (NS_FAILED(rv)) { + return false; + } + + return !!value; +} + nsresult nsWindowsShellService::LaunchModernSettingsDialogDefaultApps() { + if (!IsWindowsBuildOrLater(14965) && + !IsWindowsLogonConnected() && SettingsAppBelievesConnected()) { + // Use the classic Control Panel to work around a bug of older + // builds of Windows 10. + return LaunchControlPanelDefaultPrograms(); + } + IApplicationActivationManager* pActivator; HRESULT hr = CoCreateInstance(CLSID_ApplicationActivationManager, nullptr, @@ -682,6 +746,15 @@ nsWindowsShellService::LaunchModernSettingsDialogDefaultApps() L"windows.immersivecontrolpanel_cw5n1h2txyewy" L"!microsoft.windows.immersivecontrolpanel", L"page=SettingsPageAppsDefaults", AO_NONE, &pid); + if (SUCCEEDED(hr)) { + // Do not check error because we could at least open + // the "Default apps" setting. + pActivator->ActivateApplication( + L"windows.immersivecontrolpanel_cw5n1h2txyewy" + L"!microsoft.windows.immersivecontrolpanel", + L"page=SettingsPageAppsDefaults" + L"&target=SystemSettings_DefaultApps_Browser", AO_NONE, &pid); + } pActivator->Release(); return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE; } @@ -689,6 +762,36 @@ nsWindowsShellService::LaunchModernSettingsDialogDefaultApps() } nsresult +nsWindowsShellService::InvokeHTTPOpenAsVerb() +{ + nsCOMPtr<nsIURLFormatter> formatter( + do_GetService("@mozilla.org/toolkit/URLFormatterService;1")); + if (!formatter) { + return NS_ERROR_UNEXPECTED; + } + + nsString urlStr; + nsresult rv = formatter->FormatURLPref( + NS_LITERAL_STRING("app.support.baseURL"), urlStr); + if (NS_FAILED(rv)) { + return rv; + } + if (!StringBeginsWith(urlStr, NS_LITERAL_STRING("https://"))) { + return NS_ERROR_FAILURE; + } + urlStr.AppendLiteral("win10-default-browser"); + + SHELLEXECUTEINFOW seinfo = { sizeof(SHELLEXECUTEINFOW) }; + seinfo.lpVerb = L"openas"; + seinfo.lpFile = urlStr.get(); + seinfo.nShow = SW_SHOWNORMAL; + if (!ShellExecuteExW(&seinfo)) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +nsresult nsWindowsShellService::LaunchHTTPHandlerPane() { OPENASINFO info; @@ -716,16 +819,23 @@ nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers) nsresult rv = LaunchHelper(appHelperPath); if (NS_SUCCEEDED(rv) && IsWin8OrLater()) { if (aClaimAllTypes) { - rv = LaunchControlPanelDefaultPrograms(); + if (IsWin10OrLater()) { + rv = LaunchModernSettingsDialogDefaultApps(); + } else { + rv = LaunchControlPanelDefaultsSelectionUI(); + } // The above call should never really fail, but just in case // fall back to showing the HTTP association screen only. if (NS_FAILED(rv)) { - rv = LaunchHTTPHandlerPane(); + if (IsWin10OrLater()) { + rv = InvokeHTTPOpenAsVerb(); + } else { + rv = LaunchHTTPHandlerPane(); + } } } else { - // Windows 10 blocks attempts to load the HTTP Handler - // association dialog, so the modern Settings dialog - // is opened with the Default Apps view loaded. + // Windows 10 blocks attempts to load the + // HTTP Handler association dialog. if (IsWin10OrLater()) { rv = LaunchModernSettingsDialogDefaultApps(); } else { @@ -735,50 +845,20 @@ nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers) // The above call should never really fail, but just in case // fall back to showing control panel for all defaults if (NS_FAILED(rv)) { - rv = LaunchControlPanelDefaultPrograms(); + rv = LaunchControlPanelDefaultsSelectionUI(); } } } - return rv; -} - -NS_IMETHODIMP -nsWindowsShellService::GetShouldCheckDefaultBrowser(bool* aResult) -{ - NS_ENSURE_ARG_POINTER(aResult); - - // If we've already checked, the browser has been started and this is a - // new window open, and we don't want to check again. - if (mCheckedThisSession) { - *aResult = false; - return NS_OK; + nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); + if (prefs) { + (void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true); + // Reset the number of times the dialog should be shown + // before it is silenced. + (void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0); } - nsCOMPtr<nsIPrefBranch> prefs; - nsresult rv; - nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = pserve->GetBranch("", getter_AddRefs(prefs)); - NS_ENSURE_SUCCESS(rv, rv); - - return prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult); -} - -NS_IMETHODIMP -nsWindowsShellService::SetShouldCheckDefaultBrowser(bool aShouldCheck) -{ - nsCOMPtr<nsIPrefBranch> prefs; - nsresult rv; - - nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = pserve->GetBranch("", getter_AddRefs(prefs)); - NS_ENSURE_SUCCESS(rv, rv); - - return prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck); + return rv; } static nsresult @@ -912,7 +992,7 @@ nsWindowsShellService::SetDesktopBackground(nsIDOMElement* aElement, // e.g. "Desktop Background.bmp" nsString fileLeafName; rv = shellBundle->GetStringFromName - (MOZ_UTF16("desktopBackgroundLeafNameWin"), + (u"desktopBackgroundLeafNameWin", getter_Copies(fileLeafName)); NS_ENSURE_SUCCESS(rv, rv); @@ -948,24 +1028,24 @@ nsWindowsShellService::SetDesktopBackground(nsIDOMElement* aElement, nsAutoString style; switch (aPosition) { case BACKGROUND_TILE: - style.AssignLiteral("0"); - tile.AssignLiteral("1"); + style.Assign('0'); + tile.Assign('1'); break; case BACKGROUND_CENTER: - style.AssignLiteral("0"); - tile.AssignLiteral("0"); + style.Assign('0'); + tile.Assign('0'); break; case BACKGROUND_STRETCH: - style.AssignLiteral("2"); - tile.AssignLiteral("0"); + style.Assign('2'); + tile.Assign('0'); break; case BACKGROUND_FILL: style.AssignLiteral("10"); - tile.AssignLiteral("0"); + tile.Assign('0'); break; case BACKGROUND_FIT: - style.AssignLiteral("6"); - tile.AssignLiteral("0"); + style.Assign('6'); + tile.Assign('0'); break; } @@ -1023,7 +1103,7 @@ nsWindowsShellService::OpenApplication(int32_t aApplication) ::RegCloseKey(theKey); // Find the "open" command - application.AppendLiteral("\\"); + application.Append('\\'); application.Append(buf); application.AppendLiteral("\\shell\\open\\command"); @@ -1122,8 +1202,7 @@ nsWindowsShellService::SetDesktopBackgroundColor(uint32_t aColor) return regKey->Close(); } -nsWindowsShellService::nsWindowsShellService() : - mCheckedThisSession(false) +nsWindowsShellService::nsWindowsShellService() { } diff --git a/application/palemoon/components/shell/nsWindowsShellService.h b/application/palemoon/components/shell/nsWindowsShellService.h index f856ffd35..06c6c3c9b 100644 --- a/application/palemoon/components/shell/nsWindowsShellService.h +++ b/application/palemoon/components/shell/nsWindowsShellService.h @@ -16,9 +16,10 @@ class nsWindowsShellService : public nsIWindowsShellService { + virtual ~nsWindowsShellService(); + public: nsWindowsShellService(); - virtual ~nsWindowsShellService(); NS_DECL_ISUPPORTS NS_DECL_NSISHELLSERVICE @@ -26,12 +27,11 @@ public: protected: bool IsDefaultBrowserVista(bool aCheckAllTypes, bool* aIsDefaultBrowser); + nsresult LaunchControlPanelDefaultsSelectionUI(); nsresult LaunchControlPanelDefaultPrograms(); nsresult LaunchModernSettingsDialogDefaultApps(); + nsresult InvokeHTTPOpenAsVerb(); nsresult LaunchHTTPHandlerPane(); - -private: - bool mCheckedThisSession; }; #endif // nswindowsshellservice_h____ diff --git a/application/palemoon/config/version.txt b/application/palemoon/config/version.txt index 1d43844fa..b117d70fa 100644 --- a/application/palemoon/config/version.txt +++ b/application/palemoon/config/version.txt @@ -1 +1 @@ -27.9.0a1
\ No newline at end of file +28.0.0a1
\ No newline at end of file diff --git a/application/palemoon/configure.in b/application/palemoon/configure.in index 379c4e515..df5fb98a1 100644 --- a/application/palemoon/configure.in +++ b/application/palemoon/configure.in @@ -5,6 +5,11 @@ dnl License, v. 2.0. If a copy of the MPL was not distributed with this dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. dnl Things we need to carry from confvars.sh +AC_DEFINE(MOZ_PHOENIX) +AC_SUBST(MOZ_PHOENIX) + +AC_DEFINE(MC_PALEMOON) +AC_SUBST(MC_PALEMOON) dnl Optional parts of the build. diff --git a/application/palemoon/confvars.sh b/application/palemoon/confvars.sh index 7466d0c3c..8a1d00c68 100644 --- a/application/palemoon/confvars.sh +++ b/application/palemoon/confvars.sh @@ -3,58 +3,103 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -MOZ_APP_BASENAME=Palemoon +# Application Basename and Vendor +# MOZ_APP_BASENAME and MOZ_APP_VENDOR must not have spaces. +# These values where appropriate are hardcoded in application.ini +# to "Pale Moon" and "Moonchild Productions" respectively for +# Pale Moon +MOZ_APP_BASENAME=Palemoon MOZ_APP_VENDOR=Moonchild -MOZ_UPDATER=1 + +# Application Version +# MOZ_APP_VERSION is read from ./config/version.txt +# MOZ_APP_VERSION_DISPLAY is not used in Pale Moon so set it +# to MOZ_APP_VERSION +MOZ_APP_VERSION=`cat ${_topsrcdir}/$MOZ_BUILD_APP/config/version.txt` +MOZ_APP_VERSION_DISPLAY=$MOZ_APP_VERSION + +# Application ID +# This is a unique identifier used for the application +# Most frequently the AppID is used for targetApplication +# in extensions and for chrome manifests +MOZ_APP_ID={8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4} + +# Use static Application INI File +MOZ_APP_STATIC_INI=1 + +# Application Branding +# The default is MOZ_BRANDING_DIRECTORY and should never point to +# official branding by default. +# Changing MOZ_*BRANDING_DIRECTORY requires a clobber because branding +# dependencies are broken. +# MOZ_APP_DISPLAYNAME will be set by [branding]/configure.sh +MOZ_BRANDING_DIRECTORY=$MOZ_BUILD_APP/branding/unofficial +MOZ_OFFICIAL_BRANDING_DIRECTORY=$MOZ_BUILD_APP/branding/official + +# Enables conditional code in the platform for Pale Moon only +MC_PALEMOON=1 + +# Enables conditional code in the platform for historically +# Firefox-like browsers MOZ_PHOENIX=1 -if test "$OS_TARGET" = "WINNT"; then - MOZ_BUNDLED_FONTS=1 -fi +# Browser Feature: Status bar Component +MOZ_BROWSER_STATUSBAR=1 -MOZ_CHROME_FILE_FORMAT=omni +# Browser Feature: Profile Migration Component +MOZ_PROFILE_MIGRATOR=1 + +# Platform Feature: Application Update Service +# MAR_CHANNEL_ID must not contained the follow 3 characters: ",\t" +# ACCEPTED_MAR_CHANNEL_IDS should usually be the same as MAR_CHANNEL_ID +# If more than one ID is needed, then you should use a comma seperated list. +MOZ_UPDATER=1 +MAR_CHANNEL_ID=palemoon-release +ACCEPTED_MAR_CHANNEL_IDS=palemoon-release + +# Platform Feature: Developer Tools +# XXX: Devtools are disabled until they can be made to work with Pale Moon +MOZ_DEVTOOLS=1 + +# Platform Feature: "Phoenix" Extensions Support aka Dual-guid system. +# Allows installation of Firefox GUID targeted extensions despite having +# a different Application ID +# On UXP this is a possible feature only for the Tycho Add-ons Manager +MOZ_PHOENIX_EXTENSIONS=1 + +# Platform Feature: Sync Service MOZ_SERVICES_COMMON=1 -MOZ_MEDIA_NAVIGATOR=1 -MOZ_SERVICES_CRYPTO=1 MOZ_SERVICES_SYNC=1 -MOZ_APP_VERSION=`cat ${_topsrcdir}/$MOZ_BUILD_APP/config/version.txt` -MOZ_EXTENSIONS_DEFAULT=" gio" -MOZ_SERVICES_FXACCOUNTS=1 -MOZ_DISABLE_EXPORT_JS=1 -MOZ_WEBGL_CONFORMANT=1 -MOZ_ACTIVITIES=1 +# Platform Feature: JS based Downloads Manager MOZ_JSDOWNLOADS=1 -MOZ_WEBM_ENCODER=1 -MOZ_PHOENIX_EXTENSIONS=1 -MOZ_BROWSER_STATUSBAR=1 +# Platform Feature: Conformant WebGL +# Exposes the "webgl" context name, which is reserved for +# conformant implementations. +MOZ_WEBGL_CONFORMANT=1 -#disabled by default on desktop. -MOZ_DEVTOOLS= - -# MOZ_APP_DISPLAYNAME will be set by branding/configure.sh -# Changing MOZ_*BRANDING_DIRECTORY requires a clobber to ensure correct results, -# because branding dependencies are broken. -# MOZ_BRANDING_DIRECTORY is the default branding directory used when none is -# specified. It should never point to the "official" branding directory. -# For mozilla-beta, mozilla-release, or mozilla-central repositories, use -# "nightly" branding (until bug 659568 is fixed). -# For the mozilla-aurora repository, use "aurora". -MOZ_BRANDING_DIRECTORY=browser/branding/unofficial -MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official -# New Pale Moon App GUID -# Firefox MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384} -MOZ_APP_ID={8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4} -# This should usually be the same as the value MAR_CHANNEL_ID. -# If more than one ID is needed, then you should use a comma separated list -# of values. -ACCEPTED_MAR_CHANNEL_IDS=palemoon-release -# The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t " -MAR_CHANNEL_ID=palemoon-release -MOZ_PROFILE_MIGRATOR=1 -MOZ_EXTENSION_MANAGER=1 -MOZ_APP_STATIC_INI=1 +# Platform Feature: Windows Maintaince Service +# XXX: This is never used +if test "$OS_ARCH" = "WINNT"; then + MOZ_MAINTENANCE_SERVICE= +fi + +# Set the chrome packing format +# Possible values are omni, jar, and flat +# Currently, only omni and flat are supported +MOZ_CHROME_FILE_FORMAT=omni + +# Set the default top-level extensions +MOZ_EXTENSIONS_DEFAULT=" gio" + +# Fold Libs if test "$OS_TARGET" = "WINNT" -o "$OS_TARGET" = "Darwin"; then MOZ_FOLD_LIBS=1 fi + +# Include bundled fonts +if test "$OS_ARCH" = "WINNT" -o \ + "$OS_ARCH" = "Linux"; then + MOZ_BUNDLED_FONTS=1 +fi diff --git a/application/palemoon/fonts/EmojiOneMozilla.ttf b/application/palemoon/fonts/EmojiOneMozilla.ttf Binary files differdeleted file mode 100644 index 50356509d..000000000 --- a/application/palemoon/fonts/EmojiOneMozilla.ttf +++ /dev/null diff --git a/application/palemoon/fonts/README.txt b/application/palemoon/fonts/README.txt index 188ea3fff..bf5cb7e6e 100644 --- a/application/palemoon/fonts/README.txt +++ b/application/palemoon/fonts/README.txt @@ -1,9 +1,9 @@ -EmojiOne Mozilla +Twemoji Mozilla ================ -The upstream repository of EmojiOne Mozilla can be found at +The upstream repository of Twemoji Mozilla can be found at - https://github.com/mozilla/emojione-colr + https://github.com/mozilla/twemoji-colr Please refer commit history for the current version of the font. -This file purposely omit the version, so there is no need to update it here. +This file purposely omits the version, so there is no need to update it here. diff --git a/application/palemoon/fonts/TwemojiMozilla.ttf b/application/palemoon/fonts/TwemojiMozilla.ttf Binary files differnew file mode 100644 index 000000000..8139089f1 --- /dev/null +++ b/application/palemoon/fonts/TwemojiMozilla.ttf diff --git a/application/palemoon/fonts/moz.build b/application/palemoon/fonts/moz.build index 93d07120b..314d41bd0 100644 --- a/application/palemoon/fonts/moz.build +++ b/application/palemoon/fonts/moz.build @@ -7,5 +7,5 @@ if CONFIG['OS_ARCH'] in ('WINNT'): DIST_SUBDIR = '' FINAL_TARGET_FILES.fonts += [ - 'EmojiOneMozilla.ttf' + 'TwemojiMozilla.ttf' ] diff --git a/application/palemoon/installer/package-manifest.in b/application/palemoon/installer/package-manifest.in index a581ff469..ffe033596 100644 --- a/application/palemoon/installer/package-manifest.in +++ b/application/palemoon/installer/package-manifest.in @@ -282,7 +282,7 @@ @RESPATH@/components/jar.xpt @RESPATH@/components/jsdebugger.xpt @RESPATH@/components/jsdownloads.xpt -@RESPATH@/components/jsinspector.xpt +@RESPATH@/browser/components/jsinspector.xpt @RESPATH@/components/layout_base.xpt #ifdef NS_PRINTING @@ -322,7 +322,7 @@ @RESPATH@/components/plugin.xpt @RESPATH@/components/pref.xpt @RESPATH@/components/prefetch.xpt -@RESPATH@/components/profile.xpt +@RESPATH@/components/profiler.xpt @RESPATH@/components/rdf.xpt @RESPATH@/components/satchel.xpt @RESPATH@/components/saxparser.xpt @@ -421,8 +421,8 @@ @RESPATH@/components/jsconsole-clhandler.manifest @RESPATH@/components/jsconsole-clhandler.js #ifdef MOZ_DEVTOOLS -@RESPATH@/components/devtools-clhandler.manifest -@RESPATH@/components/devtools-clhandler.js +@RESPATH@/browser/components/devtools-startup.manifest +@RESPATH@/browser/components/devtools-startup.js #endif @RESPATH@/components/webvtt.xpt @RESPATH@/components/WebVTT.manifest @@ -677,6 +677,16 @@ @RESPATH@/browser/chrome/icons/default/default48.png #endif +; [Webide Files] +@RESPATH@/browser/chrome/webide@JAREXT@ +@RESPATH@/browser/chrome/webide.manifest +@RESPATH@/browser/@PREF_DIR@/webide-prefs.js + +; DevTools +@RESPATH@/browser/chrome/devtools@JAREXT@ +@RESPATH@/browser/chrome/devtools.manifest +@RESPATH@/browser/@PREF_DIR@/devtools.js + ; shell icons #ifdef XP_UNIX #ifndef XP_MACOSX diff --git a/application/palemoon/installer/windows/Makefile.in b/application/palemoon/installer/windows/Makefile.in index 127456765..600bdfeb6 100644 --- a/application/palemoon/installer/windows/Makefile.in +++ b/application/palemoon/installer/windows/Makefile.in @@ -5,9 +5,7 @@ include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk CONFIG_DIR = instgen -SFX_MODULE = $(topsrcdir)/other-licenses/7zstub/firefox/7zSD.sfx -APP_VERSION := $(shell cat $(srcdir)/../../config/version.txt) -DEFINES += -DAPP_VERSION=$(APP_VERSION) +SFX_MODULE = $(topsrcdir)/other-licenses/7zstub/uxp/7zSD.sfx INSTALLER_FILES = \ app.tag \ @@ -16,6 +14,12 @@ INSTALLER_FILES = \ nsis/shared.nsh \ $(NULL) +ifdef MOZ_MAINTENANCE_SERVICE +INSTALLER_FILES += \ + nsis/maintenanceservice_installer.nsi \ + $(NULL) +endif + BRANDING_FILES = \ branding.nsi \ appname.bmp \ @@ -24,13 +28,6 @@ BRANDING_FILES = \ wizWatermark.bmp \ $(NULL) -DEFINES += \ - -DAB_CD=$(AB_CD) \ - -DMOZ_APP_NAME=$(MOZ_APP_NAME) \ - -DMOZ_APP_DISPLAYNAME="${MOZ_APP_DISPLAYNAME}" \ - -DMOZILLA_VERSION=${MOZILLA_VERSION} \ - $(NULL) - include $(topsrcdir)/config/config.mk ifdef LOCALE_MERGEDIR @@ -61,6 +58,17 @@ uninstaller:: --preprocess-locale $(topsrcdir) \ $(PPL_LOCALE_ARGS) $(AB_CD) $(CONFIG_DIR) +# For building the maintenanceservice installer +ifdef MOZ_MAINTENANCE_SERVICE +maintenanceservice_installer:: + $(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR) + $(call py_action,preprocessor,-Fsubstitution $(DEFINES) $(ACDEFINES) \ + $(srcdir)/nsis/defines.nsi.in -o $(CONFIG_DIR)/defines.nsi) + $(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \ + --preprocess-locale $(topsrcdir) \ + $(PPL_LOCALE_ARGS) $(AB_CD) $(CONFIG_DIR) +endif + $(CONFIG_DIR)/setup.exe:: $(RM) -r $(CONFIG_DIR) $(MKDIR) $(CONFIG_DIR) diff --git a/application/palemoon/installer/windows/moz.build b/application/palemoon/installer/windows/moz.build index 895d11993..12e7831ed 100644 --- a/application/palemoon/installer/windows/moz.build +++ b/application/palemoon/installer/windows/moz.build @@ -1,6 +1,11 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +DEFINES['APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] + +DEFINES['MOZ_APP_NAME'] = CONFIG['MOZ_APP_NAME'] +DEFINES['MOZ_APP_DISPLAYNAME'] = CONFIG['MOZ_APP_DISPLAYNAME'] +DEFINES['MOZILLA_VERSION'] = CONFIG['MOZILLA_VERSION'] diff --git a/application/palemoon/installer/windows/nsis/defines.nsi.in b/application/palemoon/installer/windows/nsis/defines.nsi.in index ad171a5d6..97422c4f6 100644 --- a/application/palemoon/installer/windows/nsis/defines.nsi.in +++ b/application/palemoon/installer/windows/nsis/defines.nsi.in @@ -3,6 +3,23 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +# Defining FunnelcakeVersion will append the value of StubURLVersionAppend to +# StubURLVersion, append the value of URLManualDownloadAppend to +# URLManualDownload, and append the value of URLStubDownloadAppend to +# URLStubDownload. The value of FunnelcakeVersion should not be defined when it +# is not used and when it is defined its value should never be empty. +# !define FunnelcakeVersion "999" + +!ifdef FunnelcakeVersion +!define URLManualDownloadAppend "&f=${FunnelcakeVersion}" +!define URLStubDownloadAppend "-f${FunnelcakeVersion}" +!define StubURLVersionAppend "-${FunnelcakeVersion}" +!else +!define URLManualDownloadAppend "" +!define URLStubDownloadAppend "" +!define StubURLVersionAppend "" +!endif + # These defines should match application.ini settings !define AppName "Pale Moon" !define AppVersion "@APP_VERSION@" @@ -14,13 +31,17 @@ !define DDEApplication "Pale Moon" !define AppRegName "Pale Moon" +!ifndef DEV_EDITION !define BrandShortName "@MOZ_APP_DISPLAYNAME@" +!endif !define BrandFullName "${BrandFullNameInternal}" -!define NO_UNINSTALL_SURVEY - -# !define CERTIFICATE_NAME "Mozilla Corporation" -# !define CERTIFICATE_ISSUER "Thawte Code Signing CA - G2" +!define CERTIFICATE_NAME "Mozilla Corporation" +!define CERTIFICATE_ISSUER "DigiCert SHA2 Assured ID Code Signing CA" +; Changing the name or issuer requires us to have both the old and the new +; in the registry at the same time, temporarily. +!define CERTIFICATE_NAME_PREVIOUS "Mozilla Corporation" +!define CERTIFICATE_ISSUER_PREVIOUS "DigiCert Assured ID Code Signing CA-1" # LSP_CATEGORIES is the permitted LSP categories for the application. Each LSP # category value is ANDed together to set multiple permitted categories. @@ -39,20 +60,26 @@ #ifdef HAVE_64BIT_BUILD !define HAVE_64BIT_BUILD !define ARCH "x64" -!define MinSupportedVer "Microsoft Windows Vista x64" +!define MinSupportedVer "Microsoft Windows 7 x64" #else !define ARCH "x86" -!define MinSupportedVer "Microsoft Windows Vista" +!define MinSupportedVer "Microsoft Windows 7" +#endif + +!define MinSupportedCPU "SSE2" + +#ifdef MOZ_MAINTENANCE_SERVICE +!define MOZ_MAINTENANCE_SERVICE #endif # File details shared by both the installer and uninstaller VIProductVersion "1.0.0.0" -VIAddVersionKey "ProductName" "Pale Moon" -VIAddVersionKey "CompanyName" "Moonchild Productions" +VIAddVersionKey "ProductName" "${BrandShortName}" +VIAddVersionKey "CompanyName" "${CompanyName}" #ifdef MOZ_OFFICIAL_BRANDING -VIAddVersionKey "LegalTrademarks" "Pale Moon is the intellectual property of Moonchild Productions." +VIAddVersionKey "LegalTrademarks" "${BrandShortName} is a Trademark of Moonchild Productions." #endif -VIAddVersionKey "LegalCopyright" "Moonchild Productions" +VIAddVersionKey "LegalCopyright" "${CompanyName}" VIAddVersionKey "FileVersion" "${AppVersion}" VIAddVersionKey "ProductVersion" "${AppVersion}" # Comments is not used but left below commented out for future reference diff --git a/application/palemoon/installer/windows/nsis/installer.nsi b/application/palemoon/installer/windows/nsis/installer.nsi index 147a56c9b..276b94f74 100644 --- a/application/palemoon/installer/windows/nsis/installer.nsi +++ b/application/palemoon/installer/windows/nsis/installer.nsi @@ -5,7 +5,7 @@ # Required Plugins: # AppAssocReg http://nsis.sourceforge.net/Application_Association_Registration_plug-in # ApplicationID http://nsis.sourceforge.net/ApplicationID_plug-in -# CityHash http://mxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash +# CityHash http://dxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash # ShellLink http://nsis.sourceforge.net/ShellLink_plug-in # UAC http://nsis.sourceforge.net/UAC_plug-in # ServicesHelper Mozilla specific plugin that is located in /other-licenses/nsis @@ -21,15 +21,25 @@ CRCCheck on RequestExecutionLevel user +; The commands inside this ifdef require NSIS 3.0a2 or greater so the ifdef can +; be removed after we require NSIS 3.0a2 or greater. +!ifdef NSIS_PACKEDVERSION + Unicode true + ManifestSupportedOS all + ManifestDPIAware true +!endif + !addplugindir ./ Var TmpVal Var InstallType Var AddStartMenuSC +Var AddTaskbarSC Var AddQuickLaunchSC Var AddDesktopSC Var InstallMaintenanceService Var PageName +Var PreventRebootRequired ; By defining NO_STARTMENU_DIR an installer that doesn't provide an option for ; an application's Start Menu PROGRAMS directory and doesn't define the @@ -82,6 +92,7 @@ VIAddVersionKey "OriginalFilename" "setup.exe" !insertmacro InitHashAppModelId !insertmacro IsHandlerForInstallDir !insertmacro IsPinnedToTaskBar +!insertmacro IsUserAdmin !insertmacro LogDesktopShortcut !insertmacro LogQuickLaunchShortcut !insertmacro LogStartMenuShortcut @@ -90,6 +101,7 @@ VIAddVersionKey "OriginalFilename" "setup.exe" !insertmacro RegCleanAppHandler !insertmacro RegCleanMain !insertmacro RegCleanUninstall +!insertmacro RemovePrecompleteEntries !insertmacro SetAppLSPCategories !insertmacro SetBrandNameVars !insertmacro UpdateShortcutAppModelIDs @@ -153,6 +165,11 @@ Page custom preOptions leaveOptions !define MUI_DIRECTORYPAGE_VERIFYONLEAVE !insertmacro MUI_PAGE_DIRECTORY +; Custom Components Page +!ifdef MOZ_MAINTENANCE_SERVICE +Page custom preComponents leaveComponents +!endif + ; Custom Shortcuts Page Page custom preShortcuts leaveShortcuts @@ -185,7 +202,42 @@ Section "-InstallStartCleanup" SetOutPath "$INSTDIR" ${StartInstallLog} "${BrandFullName}" "${AB_CD}" "${AppVersion}" "${GREVersion}" - ; Delete the app exe to prevent launching the app while we are installing. + StrCpy $R9 "true" + StrCpy $PreventRebootRequired "false" + ${GetParameters} $R8 + ${GetOptions} "$R8" "/INI=" $R7 + ${Unless} ${Errors} + ; The configuration file must also exist + ${If} ${FileExists} "$R7" + ReadINIStr $R9 $R7 "Install" "RemoveDistributionDir" + ReadINIStr $R8 $R7 "Install" "PreventRebootRequired" + ${If} $R8 == "true" + StrCpy $PreventRebootRequired "true" + ${EndIf} + ${EndIf} + ${EndUnless} + + ; Remove directories and files we always control before parsing the uninstall + ; log so empty directories can be removed. + ${If} ${FileExists} "$INSTDIR\updates" + RmDir /r "$INSTDIR\updates" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\updated" + RmDir /r "$INSTDIR\updated" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\defaults\shortcuts" + RmDir /r "$INSTDIR\defaults\shortcuts" + ${EndIf} + ; Only remove the distribution directory if it exists and if the installer + ; isn't launched with an ini file that has RemoveDistributionDir=false in the + ; install section. + ${If} ${FileExists} "$INSTDIR\distribution" + ${AndIf} $R9 != "false" + RmDir /r "$INSTDIR\distribution" + ${EndIf} + + ; Delete the app exe if present to prevent launching the app while we are + ; installing. ClearErrors ${DeleteFile} "$INSTDIR\${FileMainEXE}" ${If} ${Errors} @@ -201,9 +253,31 @@ Section "-InstallStartCleanup" ${InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs" ; Remove the updates directory for Vista and above - ${CleanUpdateDirectories} "Mozilla\Firefox" "Mozilla\updates" + ${CleanUpdateDirectories} "Mozilla\Pale Moon" "Mozilla\updates" ${RemoveDeprecatedFiles} + ${RemovePrecompleteEntries} "false" + + ${If} ${FileExists} "$INSTDIR\defaults\pref\channel-prefs.js" + Delete "$INSTDIR\defaults\pref\channel-prefs.js" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\defaults\pref" + RmDir "$INSTDIR\defaults\pref" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\defaults" + RmDir "$INSTDIR\defaults" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\uninstall" + ; Remove the uninstall directory that we control + RmDir /r "$INSTDIR\uninstall" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\update-settings.ini" + Delete "$INSTDIR\update-settings.ini" + ${EndIf} + + ; Explictly remove empty webapprt dir in case it exists (bug 757978). + RmDir "$INSTDIR\webapprt\components" + RmDir "$INSTDIR\webapprt" ${InstallStartCleanupCommon} SectionEnd @@ -215,8 +289,6 @@ Section "-Application" APP_IDX DetailPrint $(STATUS_INSTALL_APP) SetDetailsPrint none - RmDir /r /REBOOTOK "$INSTDIR\${TO_BE_DELETED}" - ${LogHeader} "Installing Main Files" ${CopyFilesFromDir} "$EXEDIR\core" "$INSTDIR" \ "$(ERROR_CREATE_DIRECTORY_PREFIX)" \ @@ -237,18 +309,6 @@ Section "-Application" APP_IDX ${LogMsg} "Registered: $INSTDIR\AccessibleMarshal.dll" ${EndIf} - ; Write extra files created by the application to the uninstall log so they - ; will be removed when the application is uninstalled. To remove an empty - ; directory write a bogus filename to the deepest directory and all empty - ; parent directories will be removed. - ${LogUninstall} "File: \components\compreg.dat" - ${LogUninstall} "File: \components\xpti.dat" - ${LogUninstall} "File: \active-update.xml" - ${LogUninstall} "File: \install.log" - ${LogUninstall} "File: \install_status.log" - ${LogUninstall} "File: \install_wizard.log" - ${LogUninstall} "File: \updates.xml" - ClearErrors ; Default for creating Start Menu shortcut @@ -336,10 +396,12 @@ Section "-Application" APP_IDX ; If we are writing to HKLM and create either the desktop or start menu ; shortcuts set IconsVisible to 1 otherwise to 0. + ; Taskbar shortcuts imply having a start menu shortcut. ${StrFilter} "${FileMainEXE}" "+" "" "" $R9 StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo" ${If} $AddDesktopSC == 1 ${OrIf} $AddStartMenuSC == 1 + ${OrIf} $AddTaskbarSC == 1 WriteRegDWORD HKLM "$0" "IconsVisible" 1 ${Else} WriteRegDWORD HKLM "$0" "IconsVisible" 0 @@ -353,16 +415,53 @@ Section "-Application" APP_IDX ; If we create either the desktop or start menu shortcuts, then ; set IconsVisible to 1 otherwise to 0. + ; Taskbar shortcuts imply having a start menu shortcut. ${StrFilter} "${FileMainEXE}" "+" "" "" $R9 StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo" ${If} $AddDesktopSC == 1 ${OrIf} $AddStartMenuSC == 1 + ${OrIf} $AddTaskbarSC == 1 WriteRegDWORD HKCU "$0" "IconsVisible" 1 ${Else} WriteRegDWORD HKCU "$0" "IconsVisible" 0 ${EndIf} ${EndIf} +!ifdef MOZ_MAINTENANCE_SERVICE + ; If the maintenance service page was displayed then a value was already + ; explicitly selected for installing the maintenance service and + ; and so InstallMaintenanceService will already be 0 or 1. + ; If the maintenance service page was not displayed then + ; InstallMaintenanceService will be equal to "". + ${If} $InstallMaintenanceService == "" + Call IsUserAdmin + Pop $R0 + ${If} $R0 == "true" + ; Only proceed if we have HKLM write access + ${AndIf} $TmpVal == "HKLM" + ; On Windows < XP SP3 we do not install the maintenance service. + ${If} ${IsWinXP} + ${AndIf} ${AtMostServicePack} 2 + StrCpy $InstallMaintenanceService "0" + ${Else} + ; The user is an admin, so we should default to installing the service. + StrCpy $InstallMaintenanceService "1" + ${EndIf} + ${Else} + ; The user is not admin, so we can't install the service. + StrCpy $InstallMaintenanceService "0" + ${EndIf} + ${EndIf} + + ${If} $InstallMaintenanceService == "1" + ; The user wants to install the maintenance service, so execute + ; the pre-packaged maintenance service installer. + ; This option can only be turned on if the user is an admin so there + ; is no need to use ExecShell w/ verb runas to enforce elevated. + nsExec::Exec "$\"$INSTDIR\maintenanceservice_installer.exe$\"" + ${EndIf} +!endif + ; These need special handling on uninstall since they may be overwritten by ; an install into a different location. StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\App Paths\${FileMainEXE}" @@ -437,6 +536,13 @@ Section "-Application" APP_IDX ${EndIf} ${EndIf} + ; Update lastwritetime of the Start Menu shortcut to clear the tile cache. + ${If} ${AtLeastWin8} + ${AndIf} ${FileExists} "$SMPROGRAMS\${BrandFullName}.lnk" + FileOpen $0 "$SMPROGRAMS\${BrandFullName}.lnk" a + FileClose $0 + ${EndIf} + ${If} $AddDesktopSC == 1 CreateShortCut "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" ${If} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" @@ -472,6 +578,13 @@ Section "-Application" APP_IDX ${EndIf} ${EndUnless} ${EndIf} + +!ifdef MOZ_MAINTENANCE_SERVICE + ${If} $TmpVal == "HKLM" + ; Add the registry keys for allowed certificates. + ${AddMaintCertKeys} + ${EndIf} +!endif SectionEnd ; Cleanup operations to perform at the end of the installation. @@ -481,8 +594,35 @@ Section "-InstallEndCleanup" SetDetailsPrint none ${Unless} ${Silent} + ClearErrors ${MUI_INSTALLOPTIONS_READ} $0 "summary.ini" "Field 4" "State" ${If} "$0" == "1" + ; NB: this code is duplicated in stub.nsi. Please keep in sync. + ; For data migration in the app, we want to know what the default browser + ; value was before we changed it. To do so, we read it here and store it + ; in our own registry key. + StrCpy $0 "" + ${If} ${AtLeastWinVista} + AppAssocReg::QueryCurrentDefault "http" "protocol" "effective" + Pop $1 + ; If the method hasn't failed, $1 will contain the progid. Check: + ${If} "$1" != "method failed" + ${AndIf} "$1" != "method not available" + ; Read the actual command from the progid + ReadRegStr $0 HKCR "$1\shell\open\command" "" + ${EndIf} + ${EndIf} + ; If using the App Association Registry didn't happen or failed, fall back + ; to the effective http default: + ${If} "$0" == "" + ReadRegStr $0 HKCR "http\shell\open\command" "" + ${EndIf} + ; If we have something other than empty string now, write the value. + ${If} "$0" != "" + ClearErrors + WriteRegStr HKCU "Software\Mozilla\Pale Moon" "OldDefaultBrowserCommand" "$0" + ${EndIf} + ${LogHeader} "Setting as the default browser" ClearErrors ${GetParameters} $0 @@ -493,46 +633,64 @@ Section "-InstallEndCleanup" GetFunctionAddress $0 SetAsDefaultAppUserHKCU UAC::ExecCodeSegment $0 ${EndIf} + ${ElseIfNot} ${Errors} + ${LogHeader} "Writing default-browser opt-out" + ClearErrors + WriteRegStr HKCU "Software\Mozilla\Pale Moon" "DefaultBrowserOptOut" "True" + ${If} ${Errors} + ${LogMsg} "Error writing default-browser opt-out" + ${EndIf} ${EndIf} - ; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details). - ${MigrateTaskBarShortcut} ${EndUnless} - ${GetShortcutsLogPath} $0 - WriteIniStr "$0" "TASKBAR" "Migrated" "true" + ; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details). + ${MigrateTaskBarShortcut} + + ; Add the Firewall entries during install + Call AddFirewallEntries ; Refresh desktop icons System::Call "shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_DWORDFLUSH}, i 0, i 0)" ${InstallEndCleanupCommon} + ${If} $PreventRebootRequired == "true" + SetRebootFlag false + ${EndIf} + ${If} ${RebootFlag} - ; When a reboot is required give SHChangeNotify time to finish the - ; refreshing the icons so the OS doesn't display the icons from helper.exe - Sleep 10000 - ${LogHeader} "Reboot Required To Finish Installation" - ; ${FileMainEXE}.moz-upgrade should never exist but just in case... - ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}.moz-upgrade" - Rename "$INSTDIR\${FileMainEXE}" "$INSTDIR\${FileMainEXE}.moz-upgrade" - ${EndUnless} + ; Admin is required to delete files on reboot so only add the moz-delete if + ; the user is an admin. After calling UAC::IsAdmin $0 will equal 1 if the + ; user is an admin. + UAC::IsAdmin + ${If} "$0" == "1" + ; When a reboot is required give SHChangeNotify time to finish the + ; refreshing the icons so the OS doesn't display the icons from helper.exe + Sleep 10000 + ${LogHeader} "Reboot Required To Finish Installation" + ; ${FileMainEXE}.moz-upgrade should never exist but just in case... + ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}.moz-upgrade" + Rename "$INSTDIR\${FileMainEXE}" "$INSTDIR\${FileMainEXE}.moz-upgrade" + ${EndUnless} - ${If} ${FileExists} "$INSTDIR\${FileMainEXE}" - ClearErrors - Rename "$INSTDIR\${FileMainEXE}" "$INSTDIR\${FileMainEXE}.moz-delete" - ${Unless} ${Errors} - Delete /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-delete" + ${If} ${FileExists} "$INSTDIR\${FileMainEXE}" + ClearErrors + Rename "$INSTDIR\${FileMainEXE}" "$INSTDIR\${FileMainEXE}.moz-delete" + ${Unless} ${Errors} + Delete /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-delete" + ${EndUnless} + ${EndIf} + + ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}" + CopyFiles /SILENT "$INSTDIR\uninstall\helper.exe" "$INSTDIR" + FileOpen $0 "$INSTDIR\${FileMainEXE}" w + FileWrite $0 "Will be deleted on restart" + Rename /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-upgrade" "$INSTDIR\${FileMainEXE}" + FileClose $0 + Delete "$INSTDIR\${FileMainEXE}" + Rename "$INSTDIR\helper.exe" "$INSTDIR\${FileMainEXE}" ${EndUnless} ${EndIf} - - ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}" - CopyFiles /SILENT "$INSTDIR\uninstall\helper.exe" "$INSTDIR" - FileOpen $0 "$INSTDIR\${FileMainEXE}" w - FileWrite $0 "Will be deleted on restart" - Rename /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-upgrade" "$INSTDIR\${FileMainEXE}" - FileClose $0 - Delete "$INSTDIR\${FileMainEXE}" - Rename "$INSTDIR\helper.exe" "$INSTDIR\${FileMainEXE}" - ${EndUnless} ${EndIf} SectionEnd @@ -669,7 +827,9 @@ Function CheckExistingInstall FunctionEnd Function LaunchApp +!ifndef DEV_EDITION ${ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_LAUNCH)" +!endif ClearErrors ${GetParameters} $0 @@ -776,9 +936,7 @@ Function leaveShortcuts Abort ${EndIf} ${MUI_INSTALLOPTIONS_READ} $AddDesktopSC "shortcuts.ini" "Field 2" "State" - - ; If we have a Metro browser and are Win8, then we don't have a Field 3 - ${MUI_INSTALLOPTIONS_READ} $AddStartMenuSC "shortcuts.ini" "Field 3" "State" + ${MUI_INSTALLOPTIONS_READ} $AddStartMenuSC "shortcuts.ini" "Field 3" "State" ; Don't install the quick launch shortcut on Windows 7 ${Unless} ${AtLeastWin7} @@ -790,6 +948,59 @@ Function leaveShortcuts ${EndIf} FunctionEnd +!ifdef MOZ_MAINTENANCE_SERVICE +Function preComponents + ; If the service already exists, don't show this page + ServicesHelper::IsInstalled "MozillaMaintenance" + Pop $R9 + ${If} $R9 == 1 + ; The service already exists so don't show this page. + Abort + ${EndIf} + + ; On Windows < XP SP3 we do not install the maintenance service. + ${If} ${IsWinXP} + ${AndIf} ${AtMostServicePack} 2 + Abort + ${EndIf} + + ; Don't show the custom components page if the + ; user is not an admin + Call IsUserAdmin + Pop $R9 + ${If} $R9 != "true" + Abort + ${EndIf} + + ; Only show the maintenance service page if we have write access to HKLM + ClearErrors + WriteRegStr HKLM "Software\Mozilla" \ + "${BrandShortName}InstallerTest" "Write Test" + ${If} ${Errors} + ClearErrors + Abort + ${Else} + DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" + ${EndIf} + + StrCpy $PageName "Components" + ${CheckCustomCommon} + !insertmacro MUI_HEADER_TEXT "$(COMPONENTS_PAGE_TITLE)" "$(COMPONENTS_PAGE_SUBTITLE)" + !insertmacro MUI_INSTALLOPTIONS_DISPLAY "components.ini" +FunctionEnd + +Function leaveComponents + ${MUI_INSTALLOPTIONS_READ} $0 "components.ini" "Settings" "State" + ${If} $0 != 0 + Abort + ${EndIf} + ${MUI_INSTALLOPTIONS_READ} $InstallMaintenanceService "components.ini" "Field 2" "State" + ${If} $InstallType == ${INSTALLTYPE_CUSTOM} + Call CheckExistingInstall + ${EndIf} +FunctionEnd +!endif + Function preSummary StrCpy $PageName "Summary" ; Setup the summary.ini file for the Custom Summary Page @@ -838,14 +1049,14 @@ Function preSummary WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" "Write Test" ${Unless} ${Errors} DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" - ; Check if Firefox is the http handler for this user. + ; Check if Pale Moon is the http handler for this user. SetShellVarContext current ; Set SHCTX to the current user ${IsHandlerForInstallDir} "http" $R9 ${If} $TmpVal == "HKLM" SetShellVarContext all ; Set SHCTX to all users ${EndIf} - ; If Firefox isn't the http handler for this user show the option to set - ; Firefox as the default browser. + ; If Pale Moon isn't the http handler for this user show the option to set + ; Pale Moon as the default browser. ${If} "$R9" != "true" ${AndIf} ${AtMostWin2008R2} WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NumFields "4" @@ -926,7 +1137,46 @@ Function .onInit StrCpy $LANGUAGE 0 ${SetBrandNameVars} "$EXEDIR\core\distribution\setup.ini" - ${InstallOnInitCommon} "$(WARN_MIN_SUPPORTED_OS_MSG)" + ; Don't install on systems that don't support SSE2. The parameter value of + ; 10 is for PF_XMMI64_INSTRUCTIONS_AVAILABLE which will check whether the + ; SSE2 instruction set is available. Result returned in $R7. + System::Call "kernel32::IsProcessorFeaturePresent(i 10)i .R7" + + ; Windows NT 6.0 and lower are not supported on any architecture. + ${Unless} ${AtLeastWin7} + ${If} "$R7" == "0" + strCpy $R7 "$(WARN_MIN_SUPPORTED_OSVER_CPU_MSG)" + ${Else} + strCpy $R7 "$(WARN_MIN_SUPPORTED_OSVER_MSG)" + ${EndIf} + MessageBox MB_OKCANCEL|MB_ICONSTOP "$R7" IDCANCEL +2 + ExecShell "open" "${URLSystemRequirements}" + Quit + ${EndUnless} + + ; SSE2 support + ${If} "$R7" == "0" + MessageBox MB_OKCANCEL|MB_ICONSTOP "$(WARN_MIN_SUPPORTED_CPU_MSG)" IDCANCEL +2 + ExecShell "open" "${URLSystemRequirements}" + Quit + ${EndIf} + +!ifdef HAVE_64BIT_BUILD + ${Unless} ${RunningX64} + MessageBox MB_OKCANCEL|MB_ICONSTOP "$(WARN_MIN_SUPPORTED_OSVER_MSG)" IDCANCEL +2 + ExecShell "open" "${URLSystemRequirements}" + Quit + ${EndUnless} + SetRegView 64 +!endif + + ${InstallOnInitCommon} "$(WARN_MIN_SUPPORTED_OSVER_CPU_MSG)" + +; The commands inside this ifndef are needed prior to NSIS 3.0a2 and can be +; removed after we require NSIS 3.0a2 or greater. +!ifndef NSIS_PACKEDVERSION + System::Call 'user32::SetProcessDPIAware()' +!endif !insertmacro InitInstallOptionsFile "options.ini" !insertmacro InitInstallOptionsFile "shortcuts.ini" @@ -1016,6 +1266,25 @@ Function .onInit WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" State "1" ${EndUnless} + ; Setup the components.ini file for the Components Page + WriteINIStr "$PLUGINSDIR\components.ini" "Settings" NumFields "2" + + WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Type "label" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Text "$(OPTIONAL_COMPONENTS_DESC)" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Left "0" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Right "-1" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Top "5" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Bottom "25" + + WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Type "checkbox" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Text "$(MAINTENANCE_SERVICE_CHECKBOX_DESC)" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Left "0" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Right "-1" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Top "27" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Bottom "37" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" State "1" + WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Flags "GROUP" + ; There must always be a core directory. ${GetSize} "$EXEDIR\core\" "/S=0K" $R5 $R7 $R8 SectionSetSize ${APP_IDX} $R5 diff --git a/application/palemoon/installer/windows/nsis/maintenanceservice_installer.nsi b/application/palemoon/installer/windows/nsis/maintenanceservice_installer.nsi new file mode 100644 index 000000000..1f73bac6a --- /dev/null +++ b/application/palemoon/installer/windows/nsis/maintenanceservice_installer.nsi @@ -0,0 +1,332 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs +!verbose 3 + +; 7-Zip provides better compression than the lzma from NSIS so we add the files +; uncompressed and use 7-Zip to create a SFX archive of it +SetDatablockOptimize on +SetCompress off +CRCCheck on + +RequestExecutionLevel admin + +; The commands inside this ifdef require NSIS 3.0a2 or greater so the ifdef can +; be removed after we require NSIS 3.0a2 or greater. +!ifdef NSIS_PACKEDVERSION + Unicode true + ManifestSupportedOS all + ManifestDPIAware true +!endif + +!addplugindir ./ + +; Variables +Var TempMaintServiceName +Var BrandFullNameDA +Var BrandFullName + +; Other included files may depend upon these includes! +; The following includes are provided by NSIS. +!include FileFunc.nsh +!include LogicLib.nsh +!include MUI.nsh +!include WinMessages.nsh +!include WinVer.nsh +!include WordFunc.nsh + +!insertmacro GetOptions +!insertmacro GetParameters +!insertmacro GetSize + +; The test slaves use this fallback key to run tests. +; And anyone that wants to run tests themselves should already have +; this installed. +!define FallbackKey \ + "SOFTWARE\Mozilla\MaintenanceService\3932ecacee736d366d6436db0f55bce4" + +!define CompanyName "Mozilla Corporation" +!define BrandFullNameInternal "" + +; The following includes are custom. +!include defines.nsi +; We keep defines.nsi defined so that we get other things like +; the version number, but we redefine BrandFullName +!define MaintFullName "Mozilla Maintenance Service" +!undef BrandFullName +!define BrandFullName "${MaintFullName}" + +!include common.nsh +!include locales.nsi + +VIAddVersionKey "FileDescription" "${MaintFullName} Installer" +VIAddVersionKey "OriginalFilename" "maintenanceservice_installer.exe" + +Name "${MaintFullName}" +OutFile "maintenanceservice_installer.exe" + +; Get installation folder from registry if available +InstallDirRegKey HKLM "Software\Mozilla\MaintenanceService" "" + +SetOverwrite on + +; serviceinstall.cpp also uses this key, in case the path is changed, update +; there too. +!define MaintUninstallKey \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\MozillaMaintenanceService" + +; Always install into the 32-bit location even if we have a 64-bit build. +; This is because we use only 1 service for all Basilisk channels. +; Allow either x86 and x64 builds to exist at this location, depending on +; what is the latest build. +InstallDir "$PROGRAMFILES32\${MaintFullName}\" +ShowUnInstDetails nevershow + +################################################################################ +# Modern User Interface - MUI + +!define MUI_ICON setup.ico +!define MUI_UNICON setup.ico +!define MUI_WELCOMEPAGE_TITLE_3LINES +!define MUI_UNWELCOMEFINISHPAGE_BITMAP wizWatermark.bmp + +;Interface Settings +!define MUI_ABORTWARNING + +; Uninstaller Pages +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + +################################################################################ +# Language + +!insertmacro MOZ_MUI_LANGUAGE 'baseLocale' +!verbose push +!verbose 3 +!include "overrideLocale.nsh" +!include "customLocale.nsh" +!verbose pop + +; Set this after the locale files to override it if it is in the locale +; using " " for BrandingText will hide the "Nullsoft Install System..." branding +BrandingText " " + +Function .onInit + ; Remove the current exe directory from the search order. + ; This only effects LoadLibrary calls and not implicitly loaded DLLs. + System::Call 'kernel32::SetDllDirectoryW(w "")' + + SetSilent silent + + ${Unless} ${AtLeastWin7} + Abort + ${EndUnless} +FunctionEnd + +Function un.onInit + ; Remove the current exe directory from the search order. + ; This only effects LoadLibrary calls and not implicitly loaded DLLs. + System::Call 'kernel32::SetDllDirectoryW(w "")' + +; The commands inside this ifndef are needed prior to NSIS 3.0a2 and can be +; removed after we require NSIS 3.0a2 or greater. +!ifndef NSIS_PACKEDVERSION + ${If} ${AtLeastWinVista} + System::Call 'user32::SetProcessDPIAware()' + ${EndIf} +!endif + + StrCpy $BrandFullNameDA "${MaintFullName}" + StrCpy $BrandFullName "${MaintFullName}" +FunctionEnd + +Section "MaintenanceService" + AllowSkipFiles off + + CreateDirectory $INSTDIR + SetOutPath $INSTDIR + + ; If the service already exists, then it will be stopped when upgrading it + ; via the maintenanceservice_tmp.exe command executed below. + ; The maintenanceservice_tmp.exe command will rename the file to + ; maintenanceservice.exe if maintenanceservice_tmp.exe is newer. + ; If the service does not exist yet, we install it and drop the file on + ; disk as maintenanceservice.exe directly. + StrCpy $TempMaintServiceName "maintenanceservice.exe" + IfFileExists "$INSTDIR\maintenanceservice.exe" 0 skipAlreadyExists + StrCpy $TempMaintServiceName "maintenanceservice_tmp.exe" + skipAlreadyExists: + + ; We always write out a copy and then decide whether to install it or + ; not via calling its 'install' cmdline which works by version comparison. + CopyFiles "$EXEDIR\maintenanceservice.exe" "$INSTDIR\$TempMaintServiceName" + + ; The updater.ini file is only used when performing an install or upgrade, + ; and only if that install or upgrade is successful. If an old updater.ini + ; happened to be copied into the maintenance service installation directory + ; but the service was not newer, the updater.ini file would be unused. + ; It is used to fill the description of the service on success. + CopyFiles "$EXEDIR\updater.ini" "$INSTDIR\updater.ini" + + ; Install the application maintenance service. + ; If a service already exists, the command line parameter will stop the + ; service and only install itself if it is newer than the already installed + ; service. If successful it will remove the old maintenanceservice.exe + ; and replace it with maintenanceservice_tmp.exe. + ClearErrors + ${GetParameters} $0 + ${GetOptions} "$0" "/Upgrade" $0 + ${If} ${Errors} + ExecWait '"$INSTDIR\$TempMaintServiceName" install' + ${Else} + ; The upgrade cmdline is the same as install except + ; It will fail if the service isn't already installed. + ExecWait '"$INSTDIR\$TempMaintServiceName" upgrade' + ${EndIf} + + WriteUninstaller "$INSTDIR\Uninstall.exe" + WriteRegStr HKLM "${MaintUninstallKey}" "DisplayName" "${MaintFullName}" + WriteRegStr HKLM "${MaintUninstallKey}" "UninstallString" \ + '"$INSTDIR\uninstall.exe"' + WriteRegStr HKLM "${MaintUninstallKey}" "DisplayIcon" \ + "$INSTDIR\Uninstall.exe,0" + WriteRegStr HKLM "${MaintUninstallKey}" "DisplayVersion" "${AppVersion}" + WriteRegStr HKLM "${MaintUninstallKey}" "Publisher" "Mozilla" + WriteRegStr HKLM "${MaintUninstallKey}" "Comments" "${BrandFullName}" + WriteRegDWORD HKLM "${MaintUninstallKey}" "NoModify" 1 + ${GetSize} "$INSTDIR" "/S=0K" $R2 $R3 $R4 + WriteRegDWORD HKLM "${MaintUninstallKey}" "EstimatedSize" $R2 + + ; Write out that a maintenance service was attempted. + ; We do this because on upgrades we will check this value and we only + ; want to install once on the first upgrade to maintenance service. + ; Also write out that we are currently installed, preferences will check + ; this value to determine if we should show the service update pref. + ; Since the Maintenance service can be installed either x86 or x64, + ; always use the 64-bit registry for checking if an attempt was made. + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} + WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Attempted" 1 + WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Installed" 1 + DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "FFPrefetchDisabled" + + ; Included here for debug purposes only. + ; These keys are used to bypass the installation dir is a valid installation + ; check from the service so that tests can be run. + ; WriteRegStr HKLM "${FallbackKey}\0" "name" "Mozilla Corporation" + ; WriteRegStr HKLM "${FallbackKey}\0" "issuer" "DigiCert SHA2 Assured ID Code Signing CA" + ${If} ${RunningX64} + SetRegView lastused + ${EndIf} +SectionEnd + +; By renaming before deleting we improve things slightly in case +; there is a file in use error. In this case a new install can happen. +Function un.RenameDelete + Pop $9 + ; If the .moz-delete file already exists previously, delete it + ; If it doesn't exist, the call is ignored. + ; We don't need to pass /REBOOTOK here since it was already marked that way + ; if it exists. + Delete "$9.moz-delete" + Rename "$9" "$9.moz-delete" + ${If} ${Errors} + Delete /REBOOTOK "$9" + ${Else} + Delete /REBOOTOK "$9.moz-delete" + ${EndIf} + ClearErrors +FunctionEnd + +Section "Uninstall" + ; Delete the service so that no updates will be attempted + ExecWait '"$INSTDIR\maintenanceservice.exe" uninstall' + + Push "$INSTDIR\updater.ini" + Call un.RenameDelete + Push "$INSTDIR\maintenanceservice.exe" + Call un.RenameDelete + Push "$INSTDIR\maintenanceservice_tmp.exe" + Call un.RenameDelete + Push "$INSTDIR\maintenanceservice.old" + Call un.RenameDelete + Push "$INSTDIR\Uninstall.exe" + Call un.RenameDelete + Push "$INSTDIR\update\updater.ini" + Call un.RenameDelete + Push "$INSTDIR\update\updater.exe" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-1.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-2.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-3.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-4.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-5.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-6.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-7.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-8.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-9.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-10.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-install.log" + Call un.RenameDelete + Push "$INSTDIR\logs\maintenanceservice-uninstall.log" + Call un.RenameDelete + SetShellVarContext all + Push "$APPDATA\Mozilla\logs\maintenanceservice.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-1.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-2.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-3.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-4.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-5.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-6.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-7.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-8.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-9.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-10.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-install.log" + Call un.RenameDelete + Push "$APPDATA\Mozilla\logs\maintenanceservice-uninstall.log" + Call un.RenameDelete + RMDir /REBOOTOK "$APPDATA\Mozilla\logs" + RMDir /REBOOTOK "$APPDATA\Mozilla" + RMDir /REBOOTOK "$INSTDIR\logs" + RMDir /REBOOTOK "$INSTDIR\update" + RMDir /REBOOTOK "$INSTDIR" + + DeleteRegKey HKLM "${MaintUninstallKey}" + + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} + DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "Installed" + DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "FFPrefetchDisabled" + DeleteRegKey HKLM "${FallbackKey}\" + ${If} ${RunningX64} + SetRegView lastused + ${EndIf} +SectionEnd diff --git a/application/palemoon/installer/windows/nsis/shared.nsh b/application/palemoon/installer/windows/nsis/shared.nsh index 9770d4733..29136f47a 100644 --- a/application/palemoon/installer/windows/nsis/shared.nsh +++ b/application/palemoon/installer/windows/nsis/shared.nsh @@ -2,12 +2,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -; The registration ID of the COM server which is used for choosing wether -; to launch the Win8 metro browser or desktop browser. -!define DELEGATE_EXECUTE_HANDLER_ID {5100FEC1-212B-4BF5-9BF8-3E650FD794A3} - !macro PostUpdate - ; PostUpdate is called from both session 0 and from the user session ; for service updates, make sure that we only register with the user session ; Otherwise ApplicationID::Set can fail intermittently with a file in use error. @@ -15,7 +10,7 @@ System::Call "kernel32::ProcessIdToSessionId(i $0, *i ${NSIS_MAX_STRLEN} r9)" ; Determine if we're the protected UserChoice default or not. If so fix the - ; start menu tile. In case there are 2 Pale Moon installations, we only do + ; start menu tile. In case there are 2 PaleMoon installations, we only do ; this if the application being updated is the default. ReadRegStr $0 HKCU "Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice" "ProgId" ${If} $0 == "PaleMoonURL" @@ -61,6 +56,9 @@ ; Win7 taskbar and start menu link maintenance Call FixShortcutAppModelIDs + ; Add the Firewall entries after an update + Call AddFirewallEntries + ; Only update the Clients\StartMenuInternet registry key values in HKLM if ; they don't exist or this installation is the same as the one set in those ; keys. @@ -100,6 +98,13 @@ ; root of the Start Menu Programs directory. ${MigrateStartMenuShortcut} + ; Update lastwritetime of the Start Menu shortcut to clear the tile cache. + ${If} ${AtLeastWin8} + ${AndIf} ${FileExists} "$SMPROGRAMS\${BrandFullName}.lnk" + FileOpen $0 "$SMPROGRAMS\${BrandFullName}.lnk" a + FileClose $0 + ${EndIf} + ; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details). ${MigrateTaskBarShortcut} @@ -120,6 +125,50 @@ RmDir /r /REBOOTOK "$INSTDIR\${TO_BE_DELETED}" +!ifdef MOZ_MAINTENANCE_SERVICE + Call IsUserAdmin + Pop $R0 + ${If} $R0 == "true" + ; Only proceed if we have HKLM write access + ${AndIf} $TmpVal == "HKLM" + ; On Windows 2000 we do not install the maintenance service. + ${AndIf} ${AtLeastWinXP} + ; We check to see if the maintenance service install was already attempted. + ; Since the Maintenance service can be installed either x86 or x64, + ; always use the 64-bit registry for checking if an attempt was made. + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} + ReadRegDWORD $5 HKLM "Software\Mozilla\MaintenanceService" "Attempted" + ClearErrors + ${If} ${RunningX64} + SetRegView lastused + ${EndIf} + + ; Add the registry keys for allowed certificates. + ${AddMaintCertKeys} + + ; If the maintenance service is already installed, do nothing. + ; The maintenance service will launch: + ; maintenanceservice_installer.exe /Upgrade to upgrade the maintenance + ; service if necessary. If the update was done from updater.exe without + ; the service (i.e. service is failing), updater.exe will do the update of + ; the service. The reasons we do not do it here is because we don't want + ; to have to prompt for limited user accounts when the service isn't used + ; and we currently call the PostUpdate twice, once for the user and once + ; for the SYSTEM account. Also, this would stop the maintenance service + ; and we need a return result back to the service when run that way. + ${If} $5 == "" + ; An install of maintenance service was never attempted. + ; We know we are an Admin and that we have write access into HKLM + ; based on the above checks, so attempt to just run the EXE. + ; In the worst case, in case there is some edge case with the + ; IsAdmin check and the permissions check, the maintenance service + ; will just fail to be attempted to be installed. + nsExec::Exec "$\"$INSTDIR\maintenanceservice_installer.exe$\"" + ${EndIf} + ${EndIf} +!endif !macroend !define PostUpdate "!insertmacro PostUpdate" @@ -280,11 +329,11 @@ ${If} ${Errors} WriteRegStr SHCTX "SOFTWARE\Classes\${FILE_TYPE}" "" "PaleMoonHTML" ${EndIf} + WriteRegStr SHCTX "SOFTWARE\Classes\${FILE_TYPE}\OpenWithProgids" "PaleMoonHTML" "" !macroend !define AddAssociationIfNoneExist "!insertmacro AddAssociationIfNoneExist" - -; Adds the protocol and file handler registry entries for making Pale Moon the +; Adds the protocol and file handler registry entries for making PaleMoon the ; default handler (uses SHCTX). !macro SetHandlers ${GetLongPath} "$INSTDIR\${FileMainEXE}" $8 @@ -318,10 +367,11 @@ WriteRegStr SHCTX "$0\.xhtml" "" "PaleMoonHTML" ${EndIf} - ;Register file associations, but only if they don't exist yet. + ${AddAssociationIfNoneExist} ".pdf" ${AddAssociationIfNoneExist} ".oga" ${AddAssociationIfNoneExist} ".ogg" ${AddAssociationIfNoneExist} ".ogv" + ${AddAssociationIfNoneExist} ".pdf" ${AddAssociationIfNoneExist} ".webm" ; An empty string is used for the 5th param because PaleMoonHTML is not a @@ -331,7 +381,6 @@ ${AddDisabledDDEHandlerValues} "PaleMoonURL" "$2" "$8,1" "${AppRegName} URL" \ "true" - ; An empty string is used for the 4th & 5th params because the following ; protocol handlers already have a display name and the additional keys ; required for a protocol handler. @@ -341,7 +390,7 @@ !macroend !define SetHandlers "!insertmacro SetHandlers" -; Adds the HKLM\Software\Clients\StartMenuInternet\{EXE} registry +; Adds the HKLM\Software\Clients\StartMenuInternet\FIREFOX.EXE registry ; entries (does not use SHCTX). ; ; The values for StartMenuInternet are only valid under HKLM and there can only @@ -420,7 +469,7 @@ ; The IconHandler reference for PaleMoonHTML can end up in an inconsistent state ; due to changes not being detected by the IconHandler for side by side ; installs (see bug 268512). The symptoms can be either an incorrect icon or no -; icon being displayed for files associated with Pale Moon (does not use SHCTX). +; icon being displayed for files associated with PaleMoon (does not use SHCTX). !macro FixShellIconHandler RegKey ClearErrors ReadRegStr $1 ${RegKey} "Software\Classes\PaleMoonHTML\ShellEx\IconHandler" "" @@ -436,37 +485,67 @@ ; Add Software\Mozilla\ registry entries (uses SHCTX). !macro SetAppKeys + ; Check if this is an ESR release and if so add registry values so it is + ; possible to determine that this is an ESR install (bug 726781). + ClearErrors + ${WordFind} "${UpdateChannel}" "esr" "E#" $3 + ${If} ${Errors} + StrCpy $3 "" + ${Else} + StrCpy $3 " ESR" + ${EndIf} + ${GetLongPath} "$INSTDIR" $8 - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion} (${AB_CD})\Main" + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion}$3 (${ARCH} ${AB_CD})\Main" ${WriteRegStr2} $TmpVal "$0" "Install Directory" "$8" 0 ${WriteRegStr2} $TmpVal "$0" "PathToExe" "$8\${FileMainEXE}" 0 - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion} (${AB_CD})\Uninstall" - ${WriteRegStr2} $TmpVal "$0" "Description" "${BrandFullNameInternal} (${ARCH} ${AB_CD})" 0 + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion}$3 (${ARCH} ${AB_CD})\Uninstall" + ${WriteRegStr2} $TmpVal "$0" "Description" "${BrandFullNameInternal} ${AppVersion}$3 (${ARCH} ${AB_CD})" 0 - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion} (${AB_CD})" - ${WriteRegStr2} $TmpVal "$0" "" "${AppVersion} (${AB_CD})" 0 + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}\${AppVersion}$3 (${ARCH} ${AB_CD})" + ${WriteRegStr2} $TmpVal "$0" "" "${AppVersion}$3 (${ARCH} ${AB_CD})" 0 + ${If} "$3" == "" + DeleteRegValue SHCTX "$0" "ESR" + ${Else} + ${WriteRegDWORD2} $TmpVal "$0" "ESR" 1 0 + ${EndIf} - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}\bin" + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}$3\bin" ${WriteRegStr2} $TmpVal "$0" "PathToExe" "$8\${FileMainEXE}" 0 - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}\extensions" + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}$3\extensions" ${WriteRegStr2} $TmpVal "$0" "Components" "$8\components" 0 ${WriteRegStr2} $TmpVal "$0" "Plugins" "$8\plugins" 0 - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}" - ${WriteRegStr2} $TmpVal "$0" "GoannaVer" "${GREVersion}" 0 + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal} ${AppVersion}$3" + ${WriteRegStr2} $TmpVal "$0" "GeckoVer" "${GREVersion}" 0 + ${If} "$3" == "" + DeleteRegValue SHCTX "$0" "ESR" + ${Else} + ${WriteRegDWORD2} $TmpVal "$0" "ESR" 1 0 + ${EndIf} - StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}" + StrCpy $0 "Software\Mozilla\${BrandFullNameInternal}$3" ${WriteRegStr2} $TmpVal "$0" "" "${GREVersion}" 0 - ${WriteRegStr2} $TmpVal "$0" "CurrentVersion" "${AppVersion} (${AB_CD})" 0 + ${WriteRegStr2} $TmpVal "$0" "CurrentVersion" "${AppVersion}$3 (${ARCH} ${AB_CD})" 0 !macroend !define SetAppKeys "!insertmacro SetAppKeys" ; Add uninstall registry entries. This macro tests for write access to determine ; if the uninstall keys should be added to HKLM or HKCU. !macro SetUninstallKeys - StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} (${ARCH} ${AB_CD})" + ; Check if this is an ESR release and if so add registry values so it is + ; possible to determine that this is an ESR install (bug 726781). + ClearErrors + ${WordFind} "${UpdateChannel}" "esr" "E#" $3 + ${If} ${Errors} + StrCpy $3 "" + ${Else} + StrCpy $3 " ESR" + ${EndIf} + + StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} ${AppVersion}$3 (${ARCH} ${AB_CD})" StrCpy $2 "" ClearErrors @@ -493,15 +572,24 @@ ${GetLongPath} "$INSTDIR" $8 ; Write the uninstall registry keys - ${WriteRegStr2} $1 "$0" "Comments" "${BrandFullNameInternal} (${ARCH} ${AB_CD})" 0 + ${WriteRegStr2} $1 "$0" "Comments" "${BrandFullNameInternal} ${AppVersion}$3 (${ARCH} ${AB_CD})" 0 ${WriteRegStr2} $1 "$0" "DisplayIcon" "$8\${FileMainEXE},0" 0 - ${WriteRegStr2} $1 "$0" "DisplayName" "${BrandFullNameInternal} (${ARCH} ${AB_CD})" 0 + ${WriteRegStr2} $1 "$0" "DisplayName" "${BrandFullNameInternal} ${AppVersion}$3 (${ARCH} ${AB_CD})" 0 ${WriteRegStr2} $1 "$0" "DisplayVersion" "${AppVersion}" 0 + ${WriteRegStr2} $1 "$0" "HelpLink" "${HelpLink}" 0 ${WriteRegStr2} $1 "$0" "InstallLocation" "$8" 0 ${WriteRegStr2} $1 "$0" "Publisher" "Moonchild Productions" 0 ${WriteRegStr2} $1 "$0" "UninstallString" "$\"$8\uninstall\helper.exe$\"" 0 - ${WriteRegStr2} $1 "$0" "URLInfoAbout" "${URLInfoAbout}" 0 + DeleteRegValue SHCTX "$0" "URLInfoAbout" +; Don't add URLUpdateInfo which is the release notes url except for the release +; and esr channels since nightly, aurora, and beta do not have release notes. +; Note: URLUpdateInfo is only defined in the official branding.nsi. +!ifdef URLUpdateInfo +!ifndef BETA_UPDATE_CHANNEL ${WriteRegStr2} $1 "$0" "URLUpdateInfo" "${URLUpdateInfo}" 0 +!endif +!endif + ${WriteRegStr2} $1 "$0" "URLInfoAbout" "${URLInfoAbout}" 0 ${WriteRegDWORD2} $1 "$0" "NoModify" 1 0 ${WriteRegDWORD2} $1 "$0" "NoRepair" 1 0 @@ -518,7 +606,7 @@ !define SetUninstallKeys "!insertmacro SetUninstallKeys" ; Due to a bug when associating some file handlers, only SHCTX was checked for -; some file types such as ".webm". SHCTX is set to HKCU or HKLM depending on +; some file types such as ".pdf". SHCTX is set to HKCU or HKLM depending on ; whether the installer has write access to HKLM. The bug would happen when ; HCKU was checked and didn't exist since programs aren't required to set the ; HKCU Software\Classes keys when associating handlers. The fix uses the merged @@ -534,7 +622,7 @@ ReadRegStr $2 HKCR "${FILE_TYPE}\PersistentHandler" "" ${If} "$2" != "" ; Since there is a persistent handler remove PaleMoonHTML as the default - ; value from both HKCU and HKLM if it is set to PaleMoonHTML. + ; value from both HKCU and HKLM if it set to PaleMoonHTML. ${If} "$0" == "PaleMoonHTML" DeleteRegValue HKCU "Software\Classes\${FILE_TYPE}" "" ${EndIf} @@ -542,7 +630,7 @@ DeleteRegValue HKLM "Software\Classes\${FILE_TYPE}" "" ${EndIf} ${ElseIf} "$0" == "PaleMoonHTML" - ; Since KHCU is set to PaleMoonHTML, remove it as the default value + ; Since KHCU is set to PaleMoonHTML remove PaleMoonHTML as the default value ; from HKCU if HKLM is set to a value other than an empty string. ${If} "$1" != "" DeleteRegValue HKCU "Software\Classes\${FILE_TYPE}" "" @@ -630,21 +718,68 @@ !macroend !define UpdateProtocolHandlers "!insertmacro UpdateProtocolHandlers" +!ifdef MOZ_MAINTENANCE_SERVICE +; Adds maintenance service certificate keys for the install dir. +; For the cert to work, it must also be signed by a trusted cert for the user. +!macro AddMaintCertKeys + Push $R0 + ; Allow main Mozilla cert information for updates + ; This call will push the needed key on the stack + ServicesHelper::PathToUniqueRegistryPath "$INSTDIR" + Pop $R0 + ${If} $R0 != "" + ; More than one certificate can be specified in a different subfolder + ; for example: $R0\1, but each individual binary can be signed + ; with at most one certificate. A fallback certificate can only be used + ; if the binary is replaced with a different certificate. + ; We always use the 64bit registry for certs. + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} + + ; PrefetchProcessName was originally used to experiment with deleting + ; Windows prefetch as a speed optimization. It is no longer used though. + DeleteRegValue HKLM "$R0" "prefetchProcessName" + + ; Setting the Attempted value will ensure that a new Maintenance Service + ; install will never be attempted again after this from updates. The value + ; is used only to see if updates should attempt new service installs. + WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Attempted" 1 + + ; These values associate the allowed certificates for the current + ; installation. + WriteRegStr HKLM "$R0\0" "name" "${CERTIFICATE_NAME}" + WriteRegStr HKLM "$R0\0" "issuer" "${CERTIFICATE_ISSUER}" + ; These values associate the allowed certificates for the previous + ; installation, so that we can update from it cleanly using the + ; old updater.exe (which will still have this signature). + WriteRegStr HKLM "$R0\1" "name" "${CERTIFICATE_NAME_PREVIOUS}" + WriteRegStr HKLM "$R0\1" "issuer" "${CERTIFICATE_ISSUER_PREVIOUS}" + ${If} ${RunningX64} + SetRegView lastused + ${EndIf} + ClearErrors + ${EndIf} + ; Restore the previously used value back + Pop $R0 +!macroend +!define AddMaintCertKeys "!insertmacro AddMaintCertKeys" +!endif + ; Removes various registry entries for reasons noted below (does not use SHCTX). !macro RemoveDeprecatedKeys StrCpy $0 "SOFTWARE\Classes" ; Remove support for launching gopher urls from the shell during install or - ; update if the DefaultIcon is from palemoon.exe. + ; update if the DefaultIcon is from firefox.exe. ${RegCleanAppHandler} "gopher" ; Remove support for launching chrome urls from the shell during install or - ; update if the DefaultIcon is from palemoon.exe (Bug 301073). + ; update if the DefaultIcon is from firefox.exe (Bug 301073). ${RegCleanAppHandler} "chrome" - ; Remove the app compatibility registry key - StrCpy $0 "Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" - DeleteRegValue HKLM "$0" "$INSTDIR\${FileMainEXE}" - DeleteRegValue HKCU "$0" "$INSTDIR\${FileMainEXE}" + ; Remove protocol handler registry keys added by the MS shim + DeleteRegKey HKLM "Software\Classes\PaleMoon.URL" + DeleteRegKey HKCU "Software\Classes\PaleMoon.URL" ; Delete gopher from Capabilities\URLAssociations if it is present. ${StrFilter} "${FileMainEXE}" "+" "" "" $R9 @@ -671,147 +806,21 @@ RmDir /r /REBOOTOK "$INSTDIR\extensions\talkback@mozilla.org" ${EndIf} - ; Remove the Java Console extension (bug 597235) - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0012-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0012-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0013-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0013-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0014-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0014-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0015-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0015-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0016-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0016-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0017-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0017-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0018-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0018-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0019-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0019-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0020-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0020-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0021-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0021-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0022-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0015-0000-0022-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0000-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0000-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0001-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0001-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0002-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0002-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0003-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0003-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0004-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0004-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0005-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0005-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0006-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0006-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0007-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0007-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0010-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0010-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0011-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0011-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0012-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0012-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0013-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0013-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0014-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0014-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0015-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0015-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0016-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0016-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0017-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0017-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0018-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0018-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0019-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0019-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0020-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0020-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0021-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0021-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0022-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0022-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0023-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0023-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0024-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0024-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0025-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0025-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0026-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0026-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0027-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0027-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0028-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0028-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0029-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0029-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0030-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0030-ABCDEFFEDCBA}" - ${EndIf} + ; Remove the Java Console extension (bug 1165156) ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0031-ABCDEFFEDCBA}" RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0031-ABCDEFFEDCBA}" ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0032-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0032-ABCDEFFEDCBA}" + ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0034-ABCDEFFEDCBA}" + RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0034-ABCDEFFEDCBA}" ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0000-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0000-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0001-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0001-ABCDEFFEDCBA}" - ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0002-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0002-ABCDEFFEDCBA}" + ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0039-ABCDEFFEDCBA}" + RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0039-ABCDEFFEDCBA}" ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0003-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0003-ABCDEFFEDCBA}" + ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0045-ABCDEFFEDCBA}" + RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0016-0000-0045-ABCDEFFEDCBA}" ${EndIf} - ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0004-ABCDEFFEDCBA}" - RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0004-ABCDEFFEDCBA}" + ${If} ${FileExists} "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0000-ABCDEFFEDCBA}" + RmDir /r /REBOOTOK "$INSTDIR\extensions\{CAFEEFAC-0017-0000-0000-ABCDEFFEDCBA}" ${EndIf} !macroend !define RemoveDeprecatedFiles "!insertmacro RemoveDeprecatedFiles" @@ -876,15 +885,15 @@ ${If} $5 == "" ${Break} ${EndIf} - ${If} $5 == 233 ; ansi ?? + ${If} $5 == 233 ; ansi é StrCpy $0 "1" FileWriteByte $4 195 FileWriteByte $4 169 - ${ElseIf} $5 == 241 ; ansi ?? + ${ElseIf} $5 == 241 ; ansi ñ StrCpy $0 "1" FileWriteByte $4 195 FileWriteByte $4 177 - ${ElseIf} $5 == 252 ; ansi ?? + ${ElseIf} $5 == 252 ; ansi ü StrCpy $0 "1" FileWriteByte $4 195 FileWriteByte $4 188 @@ -926,17 +935,24 @@ ClearErrors WriteIniStr "$0" "TASKBAR" "Migrated" "true" ${If} ${AtLeastWin7} - ; No need to check the default on Win8 and later - ${If} ${AtMostWin2008R2} - ; Check if Pale Moon is the http handler for this user - SetShellVarContext current ; Set SHCTX to the current user - ${IsHandlerForInstallDir} "http" $R9 - ${If} $TmpVal == "HKLM" - SetShellVarContext all ; Set SHCTX to all users + ; If we didn't run the stub installer, AddTaskbarSC will be empty. + ; We determine whether to pin based on whether we're the default + ; browser, or if we're on win8 or later, we always pin. + ${If} $AddTaskbarSC == "" + ; No need to check the default on Win8 and later + ${If} ${AtMostWin2008R2} + ; Check if the PaleMoon is the http handler for this user + SetShellVarContext current ; Set SHCTX to the current user + ${IsHandlerForInstallDir} "http" $R9 + ${If} $TmpVal == "HKLM" + SetShellVarContext all ; Set SHCTX to all users + ${EndIf} ${EndIf} - ${EndIf} - ${If} "$R9" == "true" - ${OrIf} ${AtLeastWin8} + ${If} "$R9" == "true" + ${OrIf} ${AtLeastWin8} + ${PinToTaskBar} + ${EndIf} + ${ElseIf} $AddTaskbarSC == "1" ${PinToTaskBar} ${EndIf} ${EndIf} @@ -1152,17 +1168,86 @@ ; returns after the first check. Push "end" Push "AccessibleMarshal.dll" + Push "IA2Marshal.dll" Push "freebl3.dll" Push "nssckbi.dll" Push "nspr4.dll" Push "nssdbm3.dll" Push "mozsqlite3.dll" Push "xpcom.dll" + Push "crashreporter.exe" + Push "minidump-analyzer.exe" Push "updater.exe" Push "${FileMainEXE}" !macroend !define PushFilesToCheck "!insertmacro PushFilesToCheck" + +; Pushes the string "true" to the top of the stack if the Firewall service is +; running and pushes the string "false" to the top of the stack if it isn't. +!define SC_MANAGER_ALL_ACCESS 0x3F +!define SERVICE_QUERY_CONFIG 0x0001 +!define SERVICE_QUERY_STATUS 0x0004 +!define SERVICE_RUNNING 0x4 + +!macro IsFirewallSvcRunning + Push $R9 + Push $R8 + Push $R7 + Push $R6 + Push "false" + + System::Call 'advapi32::OpenSCManagerW(n, n, i ${SC_MANAGER_ALL_ACCESS}) i.R6' + ${If} $R6 != 0 + ; MpsSvc is the Firewall service on Windows Vista and above. + ; When opening the service with SERVICE_QUERY_CONFIG the return value will + ; be 0 if the service is not installed. + System::Call 'advapi32::OpenServiceW(i R6, t "MpsSvc", i ${SERVICE_QUERY_CONFIG}) i.R7' + ${If} $R7 != 0 + System::Call 'advapi32::CloseServiceHandle(i R7) n' + ; Open the service with SERVICE_QUERY_CONFIG so its status can be queried. + System::Call 'advapi32::OpenServiceW(i R6, t "MpsSvc", i ${SERVICE_QUERY_STATUS}) i.R7' + ${Else} + ; SharedAccess is the Firewall service on Windows XP. + ; When opening the service with SERVICE_QUERY_CONFIG the return value will + ; be 0 if the service is not installed. + System::Call 'advapi32::OpenServiceW(i R6, t "SharedAccess", i ${SERVICE_QUERY_CONFIG}) i.R7' + ${If} $R7 != 0 + System::Call 'advapi32::CloseServiceHandle(i R7) n' + ; Open the service with SERVICE_QUERY_CONFIG so its status can be + ; queried. + System::Call 'advapi32::OpenServiceW(i R6, t "SharedAccess", i ${SERVICE_QUERY_STATUS}) i.R7' + ${EndIf} + ${EndIf} + ; Did the calls to OpenServiceW succeed? + ${If} $R7 != 0 + System::Call '*(i,i,i,i,i,i,i) i.R9' + ; Query the current status of the service. + System::Call 'advapi32::QueryServiceStatus(i R7, i $R9) i' + System::Call '*$R9(i, i.R8)' + System::Free $R9 + System::Call 'advapi32::CloseServiceHandle(i R7) n' + IntFmt $R8 "0x%X" $R8 + ${If} $R8 == ${SERVICE_RUNNING} + Pop $R9 + Push "true" + ${EndIf} + ${EndIf} + System::Call 'advapi32::CloseServiceHandle(i R6) n' + ${EndIf} + + Exch 1 + Pop $R6 + Exch 1 + Pop $R7 + Exch 1 + Pop $R8 + Exch 1 + Pop $R9 +!macroend +!define IsFirewallSvcRunning "!insertmacro IsFirewallSvcRunning" +!define un.IsFirewallSvcRunning "!insertmacro IsFirewallSvcRunning" + ; Sets this installation as the default browser by setting the registry keys ; under HKEY_CURRENT_USER via registry calls and using the AppAssocReg NSIS ; plugin for Vista and above. This is a function instead of a macro so it is @@ -1214,7 +1299,7 @@ Function SetAsDefaultAppUserHKCU ${EndUnless} ${EndIf} ${RemoveDeprecatedKeys} - ${PinToTaskBar} + ${MigrateTaskBarShortcut} FunctionEnd ; Helper for updating the shortcut application model IDs. @@ -1225,6 +1310,15 @@ Function FixShortcutAppModelIDs ${EndIf} FunctionEnd +; Helper for adding Firewall exceptions during install and after app update. +Function AddFirewallEntries + ${IsFirewallSvcRunning} + Pop $0 + ${If} "$0" == "true" + liteFirewallW::AddRule "$INSTDIR\${FileMainEXE}" "${BrandShortName} ($INSTDIR)" + ${EndIf} +FunctionEnd + ; The !ifdef NO_LOG prevents warnings when compiling the installer.nsi due to ; this function only being used by the uninstaller.nsi. !ifdef NO_LOG @@ -1311,4 +1405,4 @@ Function SetAsDefaultAppUser FunctionEnd !define SetAsDefaultAppUser "Call SetAsDefaultAppUser" -!endif +!endif ; NO_LOG diff --git a/application/palemoon/installer/windows/nsis/uninstaller.nsi b/application/palemoon/installer/windows/nsis/uninstaller.nsi index 2ed5d9dfc..333fd33d6 100644 --- a/application/palemoon/installer/windows/nsis/uninstaller.nsi +++ b/application/palemoon/installer/windows/nsis/uninstaller.nsi @@ -4,7 +4,7 @@ # Required Plugins: # AppAssocReg http://nsis.sourceforge.net/Application_Association_Registration_plug-in -# CityHash http://mxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash +# CityHash http://dxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash # ShellLink http://nsis.sourceforge.net/ShellLink_plug-in # UAC http://nsis.sourceforge.net/UAC_plug-in @@ -19,6 +19,14 @@ CRCCheck on RequestExecutionLevel user +; The commands inside this ifdef require NSIS 3.0a2 or greater so the ifdef can +; be removed after we require NSIS 3.0a2 or greater. +!ifdef NSIS_PACKEDVERSION + Unicode true + ManifestSupportedOS all + ManifestDPIAware true +!endif + !addplugindir ./ ; On Vista and above attempt to elevate Standard Users in addition to users that @@ -32,6 +40,7 @@ RequestExecutionLevel user "Software\Microsoft\Windows\CurrentVersion\Uninstall\MozillaMaintenanceService" Var TmpVal +Var MaintCertKey ; Other included files may depend upon these includes! ; The following includes are provided by NSIS. @@ -67,6 +76,7 @@ VIAddVersionKey "OriginalFilename" "helper.exe" !insertmacro InitHashAppModelId !insertmacro IsHandlerForInstallDir !insertmacro IsPinnedToTaskBar +!insertmacro IsUserAdmin !insertmacro LogDesktopShortcut !insertmacro LogQuickLaunchShortcut !insertmacro LogStartMenuShortcut @@ -85,19 +95,18 @@ VIAddVersionKey "OriginalFilename" "helper.exe" !insertmacro un.CheckForFilesInUse !insertmacro un.CleanUpdateDirectories !insertmacro un.CleanVirtualStore -!insertmacro un.DeleteRelativeProfiles !insertmacro un.DeleteShortcuts !insertmacro un.GetLongPath !insertmacro un.GetSecondInstallPath !insertmacro un.InitHashAppModelId !insertmacro un.ManualCloseAppPrompt -!insertmacro un.ParseUninstallLog !insertmacro un.RegCleanAppHandler !insertmacro un.RegCleanFileHandler !insertmacro un.RegCleanMain !insertmacro un.RegCleanUninstall !insertmacro un.RegCleanProtocolHandler !insertmacro un.RemoveQuotesFromPath +!insertmacro un.RemovePrecompleteEntries !insertmacro un.SetAppLSPCategories !insertmacro un.SetBrandNameVars @@ -146,29 +155,69 @@ ShowUnInstDetails nevershow !insertmacro MUI_UNPAGE_WELCOME ; Custom Uninstall Confirm Page -UninstPage custom un.preConfirm un.leaveConfirm +UninstPage custom un.preConfirm ; Remove Files Page !insertmacro MUI_UNPAGE_INSTFILES ; Finish Page -; Don't setup the survey controls, functions, etc. when the application has -; defined NO_UNINSTALL_SURVEY -!ifndef NO_UNINSTALL_SURVEY -!define MUI_PAGE_CUSTOMFUNCTION_PRE un.preFinish -!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED -!define MUI_FINISHPAGE_SHOWREADME "" -!define MUI_FINISHPAGE_SHOWREADME_TEXT $(SURVEY_TEXT) -!define MUI_FINISHPAGE_SHOWREADME_FUNCTION un.Survey -!endif - !insertmacro MUI_UNPAGE_FINISH ; Use the default dialog for IDD_VERIFY for a simple Banner ChangeUI IDD_VERIFY "${NSISDIR}\Contrib\UIs\default.exe" ################################################################################ +# Helper Functions + +; This function is used to uninstall the maintenance service if the +; application currently being uninstalled is the last application to use the +; maintenance service. +Function un.UninstallServiceIfNotUsed + ; $0 will store if a subkey exists + ; $1 will store the first subkey if it exists or an empty string if it doesn't + ; Backup the old values + Push $0 + Push $1 + + ; The maintenance service always uses the 64-bit registry on x64 systems + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} + + ; Figure out the number of subkeys + StrCpy $0 0 + ${Do} + EnumRegKey $1 HKLM "Software\Mozilla\MaintenanceService" $0 + ${If} "$1" == "" + ${ExitDo} + ${EndIf} + IntOp $0 $0 + 1 + ${Loop} + + ; Restore back the registry view + ${If} ${RunningX64} + SetRegView lastUsed + ${EndIf} + ${If} $0 == 0 + ; Get the path of the maintenance service uninstaller + ReadRegStr $1 HKLM ${MaintUninstallKey} "UninstallString" + + ; If the uninstall string does not exist, skip executing it + StrCmp $1 "" doneUninstall + + ; $1 is already a quoted string pointing to the install path + ; so we're already protected against paths with spaces + nsExec::Exec "$1 /S" +doneUninstall: + ${EndIf} + + ; Restore the old value of $1 and $0 + Pop $1 + Pop $0 +FunctionEnd + +################################################################################ # Install Sections ; Empty section required for the installer to compile as an uninstaller Section "" @@ -194,15 +243,6 @@ Section "Uninstall" ClearErrors ${EndIf} - ${MUI_INSTALLOPTIONS_READ} $0 "unconfirm.ini" "Field 3" "State" - ${If} "$0" == "1" - ${un.DeleteRelativeProfiles} "Moonchild Productions\Pale Moon" - ${un.DeleteRelativeProfiles} "Moonchild Productions\MetroPM" - RmDir "$APPDATA\Mozilla\Extensions\{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}" - RmDir "$APPDATA\Mozilla\Extensions" - RmDir "$APPDATA\Mozilla" - ${EndIf} - ; setup the application model id registration value ${un.InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs" @@ -218,7 +258,7 @@ Section "Uninstall" ${EndIf} ; Remove the updates directory for Vista and above - ${un.CleanUpdateDirectories} "Moonchild Productions\Pale Moon" "Moonchild Productions\updates" + ${un.CleanUpdateDirectories} "Mozilla\PaleMoon" "Mozilla\updates" ; Remove any app model id's stored in the registry for this install path DeleteRegValue HKCU "Software\Mozilla\${AppName}\TaskBarIDs" "$INSTDIR" @@ -254,6 +294,10 @@ Section "Uninstall" ${un.RegCleanFileHandler} ".shtml" "PaleMoonHTML" ${un.RegCleanFileHandler} ".xht" "PaleMoonHTML" ${un.RegCleanFileHandler} ".xhtml" "PaleMoonHTML" + ${un.RegCleanFileHandler} ".oga" "PaleMoonHTML" + ${un.RegCleanFileHandler} ".ogg" "PaleMoonHTML" + ${un.RegCleanFileHandler} ".ogv" "PaleMoonHTML" + ${un.RegCleanFileHandler} ".pdf" "PaleMoonHTML" ${un.RegCleanFileHandler} ".webm" "PaleMoonHTML" ${EndIf} @@ -273,7 +317,7 @@ Section "Uninstall" ; The StartMenuInternet registry key is independent of the default browser ; settings. The XPInstall base un-installer always removes this key if it is ; uninstalling the default browser and it will always replace the keys when - ; installing even if there is another install of Firefox that is set as the + ; installing even if there is another install of PaleMoon that is set as the ; default browser. Now the key is always updated on install but it is only ; removed if it refers to this install location. ${If} "$INSTDIR" == "$R1" @@ -289,7 +333,7 @@ Section "Uninstall" ; The StartMenuInternet registry key is independent of the default browser ; settings. The XPInstall base un-installer always removes this key if it is ; uninstalling the default browser and it will always replace the keys when - ; installing even if there is another install of Firefox that is set as the + ; installing even if there is another install of PaleMoon that is set as the ; default browser. Now the key is always updated on install but it is only ; removed if it refers to this install location. ${If} "$INSTDIR" == "$R1" @@ -307,7 +351,7 @@ Section "Uninstall" StrCpy $0 "Software\Microsoft\MediaPlayer\ShimInclusionList\plugin-container.exe" DeleteRegKey HKLM "$0" DeleteRegKey HKCU "$0" - StrCpy $0 "Software\Classes\MIME\Database\Content Type\application/x-xpinstall;app=firefox" + StrCpy $0 "Software\Classes\MIME\Database\Content Type\application/x-xpinstall;app=PaleMoon" DeleteRegKey HKLM "$0" DeleteRegKey HKCU "$0" ${Else} @@ -335,42 +379,63 @@ Section "Uninstall" ${If} ${FileExists} "$INSTDIR\distribution" RmDir /r /REBOOTOK "$INSTDIR\distribution" ${EndIf} - ${If} ${FileExists} "$INSTDIR\removed-files" - Delete /REBOOTOK "$INSTDIR\removed-files" - ${EndIf} ; Remove files that may be left behind by the application in the ; VirtualStore directory. ${un.CleanVirtualStore} - ; Parse the uninstall log to unregister dll's and remove all installed - ; files / directories this install is responsible for. - ${un.ParseUninstallLog} + ; Only unregister the dll if the registration points to this installation + ReadRegStr $R1 HKCR "CLSID\{0D68D6D0-D93D-4D08-A30D-F00DD1F45B24}\InProcServer32" "" + ${If} "$INSTDIR\AccessibleMarshal.dll" == "$R1" + ${UnregisterDLL} "$INSTDIR\AccessibleMarshal.dll" + ${EndIf} + + ${un.RemovePrecompleteEntries} "false" - ; Remove the uninstall directory that we control - RmDir /r /REBOOTOK "$INSTDIR\uninstall" + ${If} ${FileExists} "$INSTDIR\defaults\pref\channel-prefs.js" + Delete /REBOOTOK "$INSTDIR\defaults\pref\channel-prefs.js" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\defaults\pref" + RmDir /REBOOTOK "$INSTDIR\defaults\pref" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\defaults" + RmDir /REBOOTOK "$INSTDIR\defaults" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\uninstall" + ; Remove the uninstall directory that we control + RmDir /r /REBOOTOK "$INSTDIR\uninstall" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\install.log" + Delete /REBOOTOK "$INSTDIR\install.log" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\update-settings.ini" + Delete /REBOOTOK "$INSTDIR\update-settings.ini" + ${EndIf} - ; Explictly remove empty webapprt dir in case it exists - ; See bug 757978 + ; Explicitly remove empty webapprt dir in case it exists (bug 757978). RmDir "$INSTDIR\webapprt\components" RmDir "$INSTDIR\webapprt" - RmDir /r /REBOOTOK "$INSTDIR\${TO_BE_DELETED}" - ; Remove the installation directory if it is empty - ${RemoveDir} "$INSTDIR" + RmDir "$INSTDIR" - ; If firefox.exe was successfully deleted yet we still need to restart to - ; remove other files create a dummy firefox.exe.moz-delete to prevent the + ; If PaleMoon.exe was successfully deleted yet we still need to restart to + ; remove other files create a dummy PaleMoon.exe.moz-delete to prevent the ; installer from allowing an install without restart when it is required ; to complete an uninstall. ${If} ${RebootFlag} - ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}.moz-delete" - FileOpen $0 "$INSTDIR\${FileMainEXE}.moz-delete" w - FileWrite $0 "Will be deleted on restart" - Delete /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-delete" - FileClose $0 - ${EndUnless} + ; Admin is required to delete files on reboot so only add the moz-delete if + ; the user is an admin. After calling UAC::IsAdmin $0 will equal 1 if the + ; user is an admin. + UAC::IsAdmin + ${If} "$0" == "1" + ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}.moz-delete" + FileOpen $0 "$INSTDIR\${FileMainEXE}.moz-delete" w + FileWrite $0 "Will be deleted on restart" + Delete /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-delete" + FileClose $0 + ${EndUnless} + ${EndIf} ${EndIf} ; Refresh desktop icons otherwise the start menu internet item won't be @@ -378,19 +443,38 @@ Section "Uninstall" ; clients registry key by the OS under some conditions. System::Call "shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i 0, i 0, i 0)" -SectionEnd - -################################################################################ -# Helper Functions - -; Don't setup the survey controls, functions, etc. when the application has -; defined NO_UNINSTALL_SURVEY -!ifndef NO_UNINSTALL_SURVEY -Function un.Survey - Exec "$\"$TmpVal$\" $\"${SurveyURL}$\"" -FunctionEnd + ; Users who uninstall then reinstall expecting PaleMoon to use a clean profile + ; may be surprised during first-run. This key is checked during startup of PaleMoon and + ; subsequently deleted after checking. If the value is found during startup + ; the browser will offer to Reset PaleMoon. We use the UpdateChannel to match + ; uninstalls of PaleMoon-release with reinstalls of PaleMoon-release, for example. + WriteRegStr HKCU "Software\Mozilla\PaleMoon" "Uninstalled-${UpdateChannel}" "True" + +!ifdef MOZ_MAINTENANCE_SERVICE + ; Get the path the allowed cert is at and remove it + ; Keep this block of code last since it modfies the reg view + ServicesHelper::PathToUniqueRegistryPath "$INSTDIR" + Pop $MaintCertKey + ${If} $MaintCertKey != "" + ; Always use the 64bit registry for certs on 64bit systems. + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} + DeleteRegKey HKLM "$MaintCertKey" + ${If} ${RunningX64} + SetRegView lastused + ${EndIf} + ${EndIf} + Call un.UninstallServiceIfNotUsed !endif + ${un.IsFirewallSvcRunning} + Pop $0 + ${If} "$0" == "true" + liteFirewallW::RemoveRule "$INSTDIR\${FileMainEXE}" "${BrandShortName} ($INSTDIR)" + ${EndIf} +SectionEnd + ################################################################################ # Language @@ -453,7 +537,7 @@ Function un.preConfirm ${EndIf} ; Setup the unconfirm.ini file for the Custom Uninstall Confirm Page - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Settings" NumFields "5" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Settings" NumFields "3" WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Type "label" WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Text "$(UN_CONFIRM_UNINSTALLED_FROM)" @@ -473,44 +557,22 @@ Function un.preConfirm WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Bottom "30" WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" flags "READONLY" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Type "checkbox" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Text "$(UN_REMOVE_PROFILES)" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Type "label" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Text "$(UN_CONFIRM_CLICK)" WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Left "0" WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Right "-1" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Top "40" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Bottom "50" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" State "0" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" flags "NOTIFY" - - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Type "text" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" State "$(UN_REMOVE_PROFILES_DESC)" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Left "0" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Right "-1" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Top "52" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Bottom "120" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" flags "MULTILINE|READONLY" - - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Type "label" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Text "$(UN_CONFIRM_CLICK)" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Left "0" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Right "-1" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Top "130" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Bottom "150" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Top "130" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Bottom "150" ${If} "$TmpVal" == "true" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Type "label" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Text "$(SUMMARY_REBOOT_REQUIRED_UNINSTALL)" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Left "0" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Right "-1" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Top "35" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Bottom "45" - - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Settings" NumFields "6" - - ; To insert this control reset Top / Bottom for controls below this one - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Top "55" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Bottom "65" - WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Top "67" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Type "label" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Text "$(SUMMARY_REBOOT_REQUIRED_UNINSTALL)" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Left "0" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Right "-1" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Top "35" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Bottom "45" + + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Settings" NumFields "4" ${EndIf} !insertmacro MUI_HEADER_TEXT "$(UN_CONFIRM_PAGE_TITLE)" "$(UN_CONFIRM_PAGE_SUBTITLE)" @@ -518,72 +580,12 @@ Function un.preConfirm ; focus. This sets the focus to the Install button instead. !insertmacro MUI_INSTALLOPTIONS_INITDIALOG "unconfirm.ini" GetDlgItem $0 $HWNDPARENT 1 - ${MUI_INSTALLOPTIONS_READ} $1 "unconfirm.ini" "Field 4" "HWND" - SetCtlColors $1 0x000000 0xFFFFEE - ShowWindow $1 ${SW_HIDE} System::Call "user32::SetFocus(i r0, i 0x0007, i,i)i" ${MUI_INSTALLOPTIONS_READ} $1 "unconfirm.ini" "Field 2" "HWND" SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR" !insertmacro MUI_INSTALLOPTIONS_SHOW FunctionEnd -Function un.leaveConfirm - ${MUI_INSTALLOPTIONS_READ} $0 "unconfirm.ini" "Settings" "State" - StrCmp $0 "3" +1 continue - ${MUI_INSTALLOPTIONS_READ} $0 "unconfirm.ini" "Field 3" "State" - ${MUI_INSTALLOPTIONS_READ} $1 "unconfirm.ini" "Field 4" "HWND" - StrCmp $0 1 +1 +3 - ShowWindow $1 ${SW_SHOW} - Abort - - ShowWindow $1 ${SW_HIDE} - Abort - - continue: - - ; Try to delete the app executable and if we can't delete it try to find the - ; app's message window and prompt the user to close the app. This allows - ; running an instance that is located in another directory. If for whatever - ; reason there is no message window we will just rename the app's files and - ; then remove them on restart if they are in use. - ClearErrors - ${DeleteFile} "$INSTDIR\${FileMainEXE}" - ${If} ${Errors} - ${un.ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_UNINSTALL)" - ${EndIf} -FunctionEnd - -!ifndef NO_UNINSTALL_SURVEY -Function un.preFinish - ; Do not modify the finish page if there is a reboot pending - ${Unless} ${RebootFlag} - ; Setup the survey controls, functions, etc. - StrCpy $TmpVal "SOFTWARE\Microsoft\IE Setup\Setup" - ClearErrors - ReadRegStr $0 HKLM $TmpVal "Path" - ${If} ${Errors} - !insertmacro MUI_INSTALLOPTIONS_WRITE "ioSpecial.ini" "settings" "NumFields" "3" - ${Else} - ExpandEnvStrings $0 "$0" ; this value will usually contain %programfiles% - ${If} $0 != "\" - StrCpy $0 "$0\" - ${EndIf} - StrCpy $0 "$0\iexplore.exe" - ClearErrors - GetFullPathName $TmpVal $0 - ${If} ${Errors} - !insertmacro MUI_INSTALLOPTIONS_WRITE "ioSpecial.ini" "settings" "NumFields" "3" - ${Else} - ; When we add an optional action to the finish page the cancel button - ; is enabled. This disables it and leaves the finish button as the - ; only choice. - !insertmacro MUI_INSTALLOPTIONS_WRITE "ioSpecial.ini" "settings" "cancelenabled" "0" - ${EndIf} - ${EndIf} - ${EndUnless} -FunctionEnd -!endif - ################################################################################ # Initialization Functions @@ -605,6 +607,14 @@ Function un.onInit ${un.UninstallUnOnInitCommon} +; The commands inside this ifndef are needed prior to NSIS 3.0a2 and can be +; removed after we require NSIS 3.0a2 or greater. +!ifndef NSIS_PACKEDVERSION + ${If} ${AtLeastWinVista} + System::Call 'user32::SetProcessDPIAware()' + ${EndIf} +!endif + !insertmacro InitInstallOptionsFile "unconfirm.ini" FunctionEnd diff --git a/application/palemoon/installer/windows/stub.tag b/application/palemoon/installer/windows/stub.tag deleted file mode 100644 index 4eae031d6..000000000 --- a/application/palemoon/installer/windows/stub.tag +++ /dev/null @@ -1,4 +0,0 @@ -;!@Install@!UTF-8! -Title="Pale Moon" -RunProgram="setup-stub.exe" -;!@InstallEnd@!
\ No newline at end of file diff --git a/application/palemoon/locales/Makefile.in b/application/palemoon/locales/Makefile.in index f00d7a040..5720a76df 100644 --- a/application/palemoon/locales/Makefile.in +++ b/application/palemoon/locales/Makefile.in @@ -96,11 +96,7 @@ NO_JA_JP_MAC_AB_CD := $(if $(filter ja-JP-mac, $(AB_CD)),ja,$(AB_CD)) %/defaults/profile/bookmarks.html: bookmarks.inc generic/profile/bookmarks.html.in $(SYSINSTALL) -D $(dir $@) - $(call py_action,preprocessor, \ - -I $< \ - -DAB_CD=$(NO_JA_JP_MAC_AB_CD) \ - $(srcdir)/generic/profile/bookmarks.html.in \ - -o $@) + $(call py_action,preprocessor,$< -DAB_CD=$(NO_JA_JP_MAC_AB_CD) $(srcdir)/generic/profile/bookmarks.html.in -o $@) libs:: $(FINAL_TARGET)/defaults/profile/bookmarks.html ; @@ -124,10 +120,10 @@ searchplugins: $(addprefix $(FINAL_TARGET)/searchplugins/,$(SEARCHPLUGINS)) libs-%: $(NSINSTALL) -D $(DIST)/install - @$(MAKE) -C ../../toolkit/locales libs-$* - @$(MAKE) -C ../../services/sync/locales AB_CD=$* XPI_NAME=locale-$* - @$(MAKE) -C ../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$* - @$(MAKE) -C ../../intl/locales AB_CD=$* XPI_NAME=locale-$* + @$(MAKE) -C ../../../toolkit/locales libs-$* + @$(MAKE) -C ../../../services/sync/locales AB_CD=$* XPI_NAME=locale-$* + @$(MAKE) -C ../../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$* + @$(MAKE) -C ../../../intl/locales AB_CD=$* XPI_NAME=locale-$* @$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=$(PREF_DIR) @$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales AB_CD=$* XPI_NAME=locale-$* diff --git a/application/palemoon/locales/en-US/chrome/browser/browser.dtd b/application/palemoon/locales/en-US/chrome/browser/browser.dtd index fe5f64854..65cc34fa0 100644 --- a/application/palemoon/locales/en-US/chrome/browser/browser.dtd +++ b/application/palemoon/locales/en-US/chrome/browser/browser.dtd @@ -337,7 +337,6 @@ These should match what Safari and other Apple applications use on OS X Lion. -- <!ENTITY appMenuSafeMode.label "Restart in Safe Mode…"> <!ENTITY openCmd.commandkey "l"> -<!ENTITY urlbar.placeholder2 "Search or enter address"> <!ENTITY urlbar.accesskey "d"> <!ENTITY urlbar.switchToTab.label "Switch to tab:"> @@ -643,8 +642,10 @@ just addresses the organization to follow, e.g. "This site is run by " --> <!ENTITY getUserMedia.selectMicrophone.label "Microphone to share:"> <!ENTITY getUserMedia.selectMicrophone.accesskey "M"> +#ifdef MOZ_WEBRTC <!ENTITY webrtcIndicatorButton.label "Camera / Microphone Access"> <!ENTITY webrtcIndicatorButton.tooltip "Display sites you are currently sharing your camera or microphone with"> +#endif <!ENTITY mixedContentBlocked.moreinfo "Most websites will still work properly even when this content is blocked."> diff --git a/application/palemoon/locales/en-US/chrome/browser/browser.properties b/application/palemoon/locales/en-US/chrome/browser/browser.properties index 5f75502ed..8b3fea4d5 100644 --- a/application/palemoon/locales/en-US/chrome/browser/browser.properties +++ b/application/palemoon/locales/en-US/chrome/browser/browser.properties @@ -220,6 +220,8 @@ tabHistory.goBack=Go back to this page tabHistory.goForward=Go forward to this page # URL Bar +urlbar.placeholder=Search or enter address +urlbar.placeholderURLOnly=Enter address pasteAndGo.label=Paste & Go # Block autorefresh diff --git a/application/palemoon/locales/en-US/chrome/overrides/netError.dtd b/application/palemoon/locales/en-US/chrome/overrides/netError.dtd index 3ed288d90..51aedb275 100644 --- a/application/palemoon/locales/en-US/chrome/overrides/netError.dtd +++ b/application/palemoon/locales/en-US/chrome/overrides/netError.dtd @@ -7,6 +7,8 @@ <!ENTITY loadError.label "Problem loading page"> <!ENTITY retry.label "Try Again"> +<!ENTITY returnToPreviousPage.label "Go Back"> +<!ENTITY advanced.label "Advanced"> <!-- Specific error messages --> @@ -14,7 +16,7 @@ <!ENTITY connectionFailure.longDesc "&sharedLongDesc;"> <!ENTITY deniedPortAccess.title "This address is restricted"> -<!ENTITY deniedPortAccess.longDesc "<p>The requested address specified a port (e.g. <q>palemoon.org:25</q> for port 25 on palemoon.org) normally used for purposes <em>other</em> than Web browsing. The browser has canceled the request for your protection and security.</p>"> +<!ENTITY deniedPortAccess.longDesc ""> <!ENTITY dnsNotFound.title "Server not found"> <!ENTITY dnsNotFound.longDesc " @@ -22,7 +24,7 @@ <li>Check the address for typing errors such as <strong>ww</strong>.example.com instead of <strong>www</strong>.example.com</li> - <li>If you are unable to load any pages, check your computer's network + <li>If you are unable to load any pages, check your computer’s network connection.</li> <li>If your computer or network is protected by a firewall or proxy, make sure that &brandShortName; is permitted to access the Web.</li> @@ -37,18 +39,32 @@ </ul> "> +<!ENTITY fileAccessDenied.title "Access to the file was denied"> +<!ENTITY fileAccessDenied.longDesc " +<ul> + <li>It may have been removed, moved, or file permissions may be preventing access.</li> +</ul> +"> <!ENTITY generic.title "Oops."> <!ENTITY generic.longDesc " -<p>&brandShortName; can't load this page for some reason.</p> +<p>&brandShortName; can’t load this page for some reason.</p> "> <!ENTITY malformedURI.title "The address isn't valid"> +<!ENTITY captivePortal.title "Login to network"> +<!ENTITY captivePortal.longDesc " +<p>This network may require you to login to access the internet.</p> +"> + +<!ENTITY openPortalLoginPage.label "Open Login Page"> + +<!ENTITY malformedURI.title "The address isn’t valid"> <!ENTITY malformedURI.longDesc " <ul> <li>Web addresses are usually written like <strong>http://www.example.com/</strong></li> - <li>Make sure that you're using forward slashes (i.e. + <li>Make sure that you’re using forward slashes (i.e. <strong>/</strong>).</li> </ul> "> @@ -57,7 +73,7 @@ <!ENTITY netInterrupt.longDesc "&sharedLongDesc;"> <!ENTITY notCached.title "Document Expired"> -<!ENTITY notCached.longDesc "<p>The requested document is not available in &brandShortName;'s cache.</p><ul><li>As a security precaution, &brandShortName; does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>"> +<!ENTITY notCached.longDesc "<p>The requested document is not available in &brandShortName;’s cache.</p><ul><li>As a security precaution, &brandShortName; does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>"> <!ENTITY netOffline.title "Offline mode"> <!ENTITY netOffline.longDesc2 " @@ -86,7 +102,7 @@ <!ENTITY netTimeout.title "The connection has timed out"> <!ENTITY netTimeout.longDesc "&sharedLongDesc;"> -<!ENTITY unknownProtocolFound.title "The address wasn't understood"> +<!ENTITY unknownProtocolFound.title "The address wasn’t understood"> <!ENTITY unknownProtocolFound.longDesc " <ul> <li>You might need to install other software to open this address.</li> @@ -112,7 +128,7 @@ </ul> "> -<!ENTITY redirectLoop.title "The page isn't redirecting properly"> +<!ENTITY redirectLoop.title "The page isn’t redirecting properly"> <!ENTITY redirectLoop.longDesc " <ul> <li>This problem can sometimes be caused by disabling or refusing to accept @@ -146,12 +162,17 @@ someone trying to impersonate the server.</li> be temporary, and you can try again later.</li> </ul> "> +<!ENTITY certerror.longpagetitle1 "Your connection is not secure"> +<!-- Localization note (certerror.introPara) - The text content of the span tag +will be replaced at runtime with the name of the server to which the user +was trying to connect. --> +<!ENTITY certerror.introPara "The owner of <span class='hostname'/> has configured their website improperly. To protect your information from being stolen, &brandShortName; has not connected to this website."> <!ENTITY sharedLongDesc " <ul> <li>The site could be temporarily unavailable or too busy. Try again in a few moments.</li> - <li>If you are unable to load any pages, check your computer's network + <li>If you are unable to load any pages, check your computer’s network connection.</li> <li>If your computer or network is protected by a firewall or proxy, make sure that &brandShortName; is permitted to access the Web.</li> @@ -186,6 +207,8 @@ be temporary, and you can try again later.</li> <!ENTITY corruptedContentError.title "Corrupted Content Error"> <!ENTITY corruptedContentError.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>"> +<!ENTITY corruptedContentErrorv2.title "Corrupted Content Error"> +<!ENTITY corruptedContentErrorv2.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>"> <!ENTITY securityOverride.linkText "Or you can add an exception…"> @@ -207,6 +230,7 @@ functionality specific to firefox. --> <!ENTITY errorReporting.title "Report this error"> <!ENTITY errorReporting.longDesc "Reporting the address and certificate information for <span id='hostname'></span> will help us identify and block malicious sites. Thanks for helping create a safer web!"> <!ENTITY errorReporting.automatic "Automatically report errors in the future"> +<!ENTITY errorReporting.automatic2 "Report errors like this to help Mozilla identify and block malicious sites"> <!ENTITY errorReporting.learnMore "Learn more…"> <!ENTITY errorReporting.sending "Sending report"> <!ENTITY errorReporting.sent "Report sent"> @@ -221,3 +245,33 @@ functionality specific to firefox. --> "ssl_error_unsupported_version". --> <!ENTITY sslv3Used.longDesc "Advanced info: ssl_error_unsupported_version"> <!ENTITY sslv3Used.learnMore "Learn More…"> +<!-- LOCALIZATION NOTE (sslv3Used.longDesc2) - Do not translate + "SSL_ERROR_UNSUPPORTED_VERSION". --> +<!ENTITY sslv3Used.longDesc2 "Advanced info: SSL_ERROR_UNSUPPORTED_VERSION"> + +<!ENTITY weakCryptoUsed.title "Your connection is not secure"> +<!-- LOCALIZATION NOTE (weakCryptoUsed.longDesc2) - Do not translate + "SSL_ERROR_NO_CYPHER_OVERLAP". --> +<!ENTITY weakCryptoUsed.longDesc2 "Advanced info: SSL_ERROR_NO_CYPHER_OVERLAP"> +<!ENTITY weakCryptoAdvanced.title "Advanced"> +<!ENTITY weakCryptoAdvanced.longDesc "<span class='hostname'></span> uses security technology that is outdated and vulnerable to attack. An attacker could easily reveal information which you thought to be safe."> +<!ENTITY weakCryptoAdvanced.override "(Not secure) Try loading <span class='hostname'></span> using outdated security"> + +<!-- LOCALIZATION NOTE (certerror.wrongSystemTime) - The <span id='..' /> tags will be injected with actual values, + please leave them unchanged. --> +<!ENTITY certerror.wrongSystemTime "<p>A secure connection to <span id='wrongSystemTime_URL'/> isn’t possible because your clock appears to show the wrong time.</p> <p>Your computer thinks it is <span id='wrongSystemTime_systemDate'/>. To fix this problem, change your date and time settings to match the correct time.</p>"> + +<!ENTITY certerror.pagetitle1 "Insecure Connection"> +<!ENTITY certerror.whatShouldIDo.badStsCertExplanation "This site uses HTTP +Strict Transport Security (HSTS) to specify that &brandShortName; may only connect +to it securely. As a result, it is not possible to add an exception for this +certificate."> +<!ENTITY certerror.copyToClipboard.label "Copy text to clipboard"> + +<!ENTITY inadequateSecurityError.title "Your connection is not secure"> +<!-- LOCALIZATION NOTE (inadequateSecurityError.longDesc) - Do not translate + "NS_ERROR_NET_INADEQUATE_SECURITY". --> +<!ENTITY inadequateSecurityError.longDesc "<p><span class='hostname'></span> uses security technology that is outdated and vulnerable to attack. An attacker could easily reveal information which you thought to be safe. The website administrator will need to fix the server first before you can visit the site.</p><p>Error code: NS_ERROR_NET_INADEQUATE_SECURITY</p>"> + +<!ENTITY prefReset.longDesc "It looks like your network security settings might be causing this. Do you want the default settings to be restored?"> +<!ENTITY prefReset.label "Restore default settings"> diff --git a/application/palemoon/locales/jar.mn b/application/palemoon/locales/jar.mn index 451a86ab7..6512c683e 100644 --- a/application/palemoon/locales/jar.mn +++ b/application/palemoon/locales/jar.mn @@ -16,7 +16,7 @@ locale/browser/syncProgress.dtd (%chrome/browser/syncProgress.dtd) locale/browser/aboutSyncTabs.dtd (%chrome/browser/aboutSyncTabs.dtd) #endif - locale/browser/browser.dtd (%chrome/browser/browser.dtd) +* locale/browser/browser.dtd (%chrome/browser/browser.dtd) locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd) locale/browser/charsetOverlay.dtd (%chrome/browser/charsetOverlay.dtd) locale/browser/browser.properties (%chrome/browser/browser.properties) diff --git a/application/palemoon/modules/QuotaManager.jsm b/application/palemoon/modules/QuotaManager.jsm index e03161a69..48cfe88b3 100644 --- a/application/palemoon/modules/QuotaManager.jsm +++ b/application/palemoon/modules/QuotaManager.jsm @@ -6,8 +6,9 @@ this.EXPORTED_SYMBOLS = ["QuotaManagerHelper"]; Components.utils.import('resource://gre/modules/Services.jsm'); -const Cc = Components.classes; const Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; this.QuotaManagerHelper = { clear: function(isShutDown) { @@ -34,12 +35,17 @@ this.QuotaManagerHelper = { } } } - var qm = Cc["@mozilla.org/dom/quota/manager;1"].getService(Ci.nsIQuotaManager); + var qm = Cc["@mozilla.org/dom/quota-manager-service;1"] + .getService(Ci.nsIQuotaManagerService); for (var dom in doms) { var uri = Services.io.newURI(dom, null, null); - qm.clearStoragesForURI(uri); + let principal = Services.scriptSecurityManager + .createCodebasePrincipal(uri, {}); + qm.clearStoragesForPrincipal(principal); } } - } catch(er) {} + } catch(er) { + Cu.reportError(er); + } } }; diff --git a/application/palemoon/modules/WindowsPreviewPerTab.jsm b/application/palemoon/modules/WindowsPreviewPerTab.jsm index 41b38f0cf..e186bcad2 100644 --- a/application/palemoon/modules/WindowsPreviewPerTab.jsm +++ b/application/palemoon/modules/WindowsPreviewPerTab.jsm @@ -510,7 +510,14 @@ TabWindow.prototype = { // Previews are internally stored using a map, so we need to iterate over // the tabbrowser's array of tabs to retrieve previews in the same order. - let inorder = [previews.get(t) for (t of tabs) if (previews.has(t))]; + // Tycho: let inorder = [previews.get(t) for (t of tabs) if (previews.has(t))]; + let inorder = []; + + for (let t of tabs) { + if (previews.has(t)) { + inorder.push(previews.get(t)); + } + } // Since the internal taskbar array has not yet been updated, we must force // the sorting order of our local array on it. To do so, we must walk diff --git a/application/palemoon/modules/moz.build b/application/palemoon/modules/moz.build index b3459bcd5..7620b9862 100644 --- a/application/palemoon/modules/moz.build +++ b/application/palemoon/modules/moz.build @@ -19,10 +19,12 @@ EXTRA_JS_MODULES += [ 'PageMenu.jsm', 'PopupNotifications.jsm', 'QuotaManager.jsm', - 'SharedFrame.jsm', - 'webrtcUI.jsm' + 'SharedFrame.jsm' ] +if CONFIG['MOZ_WEBRTC']: + EXTRA_JS_MODULES += ['webrtcUI.jsm'] + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': EXTRA_JS_MODULES += [ 'Windows8WindowFrameColor.jsm', diff --git a/application/palemoon/components/shell/Makefile.in b/application/palemoon/moz.configure index df084b709..72236254f 100644 --- a/application/palemoon/components/shell/Makefile.in +++ b/application/palemoon/moz.configure @@ -1,11 +1,7 @@ -# +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -include $(topsrcdir)/config/rules.mk - -CXXFLAGS += $(TK_CFLAGS) - -clobber:: - rm -f $(DIST)/lib/$(LIBRARY_NAME).lib +include('../../toolkit/moz.configure') diff --git a/application/palemoon/themes/linux/browser.css b/application/palemoon/themes/linux/browser.css index 07e9dae9c..a396ea5fd 100644 --- a/application/palemoon/themes/linux/browser.css +++ b/application/palemoon/themes/linux/browser.css @@ -728,9 +728,11 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button { opacity: .4; } +%ifdef MOZ_WEBRTC #webrtc-status-button { -moz-image-region: rect(0px 192px 24px 168px); } +%endif /* 16px primary toolbar buttons */ toolbar[iconsize="small"] .toolbarbutton-1:not([type="menu-button"]) { @@ -812,7 +814,9 @@ toolbar[iconsize="small"] #downloads-button { -moz-image-region: rect(0px 16px 16px 0px); } +%ifdef MOZ_WEBRTC toolbar[iconsize="small"] #webrtc-status-button /* temporary placeholder (bug 824825) */, +%endif toolbar[iconsize="small"] #history-button, toolbar[iconsize="small"] #history-menu-button { -moz-image-region: rect(0px 32px 16px 16px); @@ -884,9 +888,11 @@ toolbar[iconsize="small"] #feed-button { -moz-image-region: rect(0px 112px 16px 96px); } +%ifdef MOZ_WEBRTC toolbar[iconsize="small"] #webrtc-status-button { -moz-image-region: rect(0px 128px 16px 112px); } +%endif /* Fullscreen window controls */ #window-controls { @@ -1226,10 +1232,12 @@ toolbar[iconsize="small"] #webrtc-status-button { list-style-image: url(chrome://browser/skin/mixed-content-blocked-64.png); } +%ifdef MOZ_WEBRTC .popup-notification-icon[popupid="webRTC-sharingDevices"], .popup-notification-icon[popupid="webRTC-shareDevices"] { list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png); } +%endif .popup-notification-icon[popupid="pointerLock"] { list-style-image: url(chrome://browser/skin/pointerLock-64.png); @@ -1352,6 +1360,7 @@ toolbar[iconsize="small"] #webrtc-status-button { list-style-image: url(chrome://browser/skin/mixed-content-blocked-16.png); } +%ifdef MOZ_WEBRTC .webRTC-shareDevices-notification-icon, #webRTC-shareDevices-notification-icon { list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png); @@ -1361,6 +1370,7 @@ toolbar[iconsize="small"] #webrtc-status-button { #webRTC-sharingDevices-notification-icon { list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png); } +%endif .web-notifications-notification-icon, #web-notifications-notification-icon { @@ -2083,8 +2093,8 @@ toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon { } %ifdef MOZ_DEVTOOLS -%include ../../../toolkit/themes/shared/devtools/responsivedesign.inc.css -%include ../../../toolkit/themes/shared/devtools/commandline.inc.css +%include ../../../../devtools/client/themes/responsivedesign.inc.css +%include ../../../../devtools/client/themes/commandline.inc.css %endif %include ../shared/plugin-doorhanger.inc.css diff --git a/application/palemoon/themes/linux/jar.mn b/application/palemoon/themes/linux/jar.mn index a756edbc3..44d837778 100644 --- a/application/palemoon/themes/linux/jar.mn +++ b/application/palemoon/themes/linux/jar.mn @@ -53,9 +53,11 @@ browser.jar: skin/classic/browser/Toolbar.png skin/classic/browser/Toolbar-small.png skin/classic/browser/urlbar-arrow.png +#ifdef MOZ_WEBRTC skin/classic/browser/webRTC-shareDevice-16.png skin/classic/browser/webRTC-shareDevice-64.png skin/classic/browser/webRTC-sharingDevice-16.png +#endif skin/classic/browser/downloads/buttons.png (downloads/buttons.png) skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png) skin/classic/browser/downloads/download-glow-small.png (downloads/download-glow-small.png) diff --git a/application/palemoon/themes/osx/browser.css b/application/palemoon/themes/osx/browser.css index 58348a408..aa5918bab 100644 --- a/application/palemoon/themes/osx/browser.css +++ b/application/palemoon/themes/osx/browser.css @@ -801,10 +801,11 @@ toolbar[brighttext] #bookmarks-menu-button.bookmark-item { -moz-image-region: rect(0, 342px, 18px, 324px); } +%ifdef MOZ_WEBRTC #webrtc-status-button { -moz-image-region: rect(0, 360px, 18px, 342px); } - +%endif /* ::::: fullscreen window controls ::::: */ @@ -1955,11 +1956,13 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { list-style-image: url(chrome://browser/skin/mixed-content-blocked-64.png); } +%ifdef MOZ_WEBRTC .popup-notification-icon[popupid="webRTC-sharingDevices"], .popup-notification-icon[popupid="webRTC-shareDevices"] { list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png); } +%endif .popup-notification-icon[popupid="pointerLock"] { list-style-image: url(chrome://browser/skin/pointerLock-64.png); } @@ -2079,6 +2082,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { list-style-image: url(chrome://browser/skin/mixed-content-blocked-16.png); } +%ifdef MOZ_WEBRTC .webRTC-shareDevices-notification-icon, #webRTC-shareDevices-notification-icon { list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png); @@ -2088,6 +2092,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { #webRTC-sharingDevices-notification-icon { list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png); } +%endif .web-notifications-notification-icon, #web-notifications-notification-icon { @@ -2383,8 +2388,8 @@ toolbar[brighttext] #addonbar-closebutton { } %ifdef MOZ_DEVTOOLS -%include ../../../toolkit/themes/shared/devtools/responsivedesign.inc.css -%include ../../../toolkit/themes/shared/devtools/commandline.inc.css +%include ../../../../devtools/client/themes/responsivedesign.inc.css +%include ../../../../devtools/client/themes/commandline.inc.css %endif %include ../shared/plugin-doorhanger.inc.css diff --git a/application/palemoon/themes/osx/jar.mn b/application/palemoon/themes/osx/jar.mn index 00575bac8..8742f1b87 100644 --- a/application/palemoon/themes/osx/jar.mn +++ b/application/palemoon/themes/osx/jar.mn @@ -72,9 +72,11 @@ browser.jar: skin/classic/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png) skin/classic/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png) skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png) +#ifdef MOZ_WEBRTC skin/classic/browser/webRTC-shareDevice-16.png skin/classic/browser/webRTC-shareDevice-64.png skin/classic/browser/webRTC-sharingDevice-16.png +#endif skin/classic/browser/downloads/buttons.png (downloads/buttons.png) skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png) skin/classic/browser/downloads/download-notification-finish.png (downloads/download-notification-finish.png) diff --git a/application/palemoon/themes/osx/shared.inc b/application/palemoon/themes/osx/shared.inc index 2e8a8f269..ef27746a3 100644 --- a/application/palemoon/themes/osx/shared.inc +++ b/application/palemoon/themes/osx/shared.inc @@ -1,4 +1,4 @@ -%include ../../../toolkit/themes/osx/global/shared.inc
+%include ../../../../toolkit/themes/osx/global/shared.inc
%include ../shared/browser.inc
%define hudButton -moz-appearance: none; color: #434343; border-radius: 4px; border: 1px solid #b5b5b5; background: linear-gradient(#fff, #f2f2f2); box-shadow: inset 0 1px rgba(255,255,255,.8), inset 0 0 1px rgba(255,255, 255,.25), 0 1px rgba(255,255,255,.3); background-clip: padding-box; background-origin: padding-box; padding: 2px 6px;
diff --git a/application/palemoon/themes/shared/browser.inc b/application/palemoon/themes/shared/browser.inc index cd17903ce..18e69ad43 100644 --- a/application/palemoon/themes/shared/browser.inc +++ b/application/palemoon/themes/shared/browser.inc @@ -1,3 +1,8 @@ %filter substitution +%ifndef MOZ_WEBRTC +%define primaryToolbarButtons #back-button, #forward-button, #reload-button, #stop-button, #home-button, #print-button, #downloads-button, #downloads-indicator, #history-button, #history-menu-button, #bookmarks-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-in-button, #sync-button, #feed-button, #alltabs-button +%else %define primaryToolbarButtons #back-button, #forward-button, #reload-button, #stop-button, #home-button, #print-button, #downloads-button, #downloads-indicator, #history-button, #history-menu-button, #bookmarks-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-in-button, #sync-button, #feed-button, #alltabs-button, #webrtc-status-button +%endif + diff --git a/application/palemoon/themes/windows/browser.css b/application/palemoon/themes/windows/browser.css index 7c837764d..3e8c63af4 100644 --- a/application/palemoon/themes/windows/browser.css +++ b/application/palemoon/themes/windows/browser.css @@ -1192,10 +1192,11 @@ toolbar[brighttext] #bookmarks-menu-button.bookmark-item { -moz-image-region: rect(0, 342px, 18px, 324px); } +%ifdef MOZ_WEBRTC #webrtc-status-button { -moz-image-region: rect(0, 360px, 18px, 342px); } - +%endif /* ::::: fullscreen window controls ::::: */ @@ -2443,10 +2444,12 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { list-style-image: url(chrome://browser/skin/mixed-content-blocked-64.png); } +%ifdef MOZ_WEBRTC .popup-notification-icon[popupid="webRTC-sharingDevices"], .popup-notification-icon[popupid="webRTC-shareDevices"] { list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png); } +%endif .popup-notification-icon[popupid="pointerLock"] { list-style-image: url(chrome://browser/skin/pointerLock-64.png); @@ -2567,6 +2570,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { list-style-image: url(chrome://browser/skin/mixed-content-blocked-16.png); } +%ifdef MOZ_WEBRTC .webRTC-shareDevices-notification-icon, #webRTC-shareDevices-notification-icon { list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png); @@ -2576,6 +2580,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { #webRTC-sharingDevices-notification-icon { list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png); } +%endif .web-notifications-notification-icon, #web-notifications-notification-icon { @@ -2858,8 +2863,8 @@ toolbar[brighttext] #addonbar-closebutton { } %ifdef MOZ_DEVTOOLS -%include ../../../toolkit/themes/shared/devtools/responsivedesign.inc.css -%include ../../../toolkit/themes/shared/devtools/commandline.inc.css +%include ../../../../devtools/client/themes/responsivedesign.inc.css +%include ../../../../devtools/client/themes/commandline.inc.css %endif %include ../shared/plugin-doorhanger.inc.css diff --git a/application/palemoon/themes/windows/jar.mn b/application/palemoon/themes/windows/jar.mn index 1c1f139de..994e87be3 100644 --- a/application/palemoon/themes/windows/jar.mn +++ b/application/palemoon/themes/windows/jar.mn @@ -74,9 +74,11 @@ browser.jar: skin/classic/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png) skin/classic/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png) skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png) +#ifdef MOZ_WEBRTC skin/classic/browser/webRTC-shareDevice-16.png skin/classic/browser/webRTC-shareDevice-64.png skin/classic/browser/webRTC-sharingDevice-16.png +#endif skin/classic/browser/downloads/buttons.png (downloads/buttons.png) skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png) skin/classic/browser/downloads/download-notification-finish.png (downloads/download-notification-finish.png) @@ -98,7 +100,7 @@ browser.jar: skin/classic/browser/newtab/controls.png (newtab/controls.png) skin/classic/browser/newtab/noise.png (newtab/noise.png) skin/classic/browser/places/places.css (places/places.css) - skin/classic/browser/places/organizer.css (places/organizer.css) +* skin/classic/browser/places/organizer.css (places/organizer.css) skin/classic/browser/places/editBookmark.png (places/editBookmark.png) skin/classic/browser/places/bookmark.png (places/bookmark.png) skin/classic/browser/places/query.png (places/query.png) diff --git a/browser/LICENSE b/browser/LICENSE index 99d9d6bcd..f1b2067a7 100644 --- a/browser/LICENSE +++ b/browser/LICENSE @@ -2,6 +2,10 @@ Please see the file ../toolkit/content/license.html for the copyright licensing conditions attached to this codebase, including copies of the licenses concerned. -You are not granted rights or licenses to the trademarks of the -Mozilla Foundation or any party, including without limitation the -Firefox name or logo. +You are not granted rights or licenses to the trademarks of Moonchild +Productions or any other party, including without limitation the +Basilisk name or logo. + +The Serpent logo in branding/unofficial is derived from "Sea Serpent" +by Lorc, licensed under the Creative Commons license CC-BY 3.0 + diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp index ac2e85ea3..184b1fc2e 100644 --- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -24,11 +24,6 @@ #include "nsStringGlue.h" #ifdef XP_WIN -#ifdef MOZ_ASAN -// ASAN requires basilisk.exe to be built with -MD, and it's OK if we don't -// support Windows XP SP2 in ASAN builds. -#define XRE_DONT_SUPPORT_XPSP2 -#endif #define XRE_WANT_ENVIRON #define strcasecmp _stricmp #ifdef MOZ_SANDBOX diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index d6de538d7..0ef9d4ab5 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -229,11 +229,6 @@ pref("browser.slowStartup.notificationDisabled", false); pref("browser.slowStartup.timeThreshold", 40000); pref("browser.slowStartup.maxSamples", 5); -// This url, if changed, MUST continue to point to an https url. Pulling arbitrary content to inject into -// this page over http opens us up to a man-in-the-middle attack that we'd rather not face. If you are a downstream -// repackager of this code using an alternate snippet url, please keep your users safe -pref("browser.aboutHomeSnippets.updateUrl", "https://snippets.cdn.mozilla.net/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/"); - pref("browser.enable_automatic_image_resizing", true); pref("browser.casting.enabled", false); pref("browser.chrome.site_icons", true); @@ -1397,13 +1392,6 @@ pref("browser.translation.engine", "bing"); // Determines if Telemetry pings can be archived locally. pref("toolkit.telemetry.archive.enabled", true); -// Telemetry experiments settings. -pref("experiments.enabled", true); -pref("experiments.manifest.fetchIntervalSeconds", 86400); -pref("experiments.manifest.uri", "https://telemetry-experiment.cdn.mozilla.net/manifest/v1/firefox/%VERSION%/%CHANNEL%"); -// Whether experiments are supported by the current application profile. -pref("experiments.supported", true); - // Enable GMP support in the addon manager. pref("media.gmp-provider.enabled", true); diff --git a/browser/base/content/abouthome/aboutHome.css b/browser/base/content/abouthome/aboutHome.css index c0b02e257..bc3f9882c 100644 --- a/browser/base/content/abouthome/aboutHome.css +++ b/browser/base/content/abouthome/aboutHome.css @@ -49,8 +49,7 @@ a { background-repeat: no-repeat; } -#searchIconAndTextContainer, -#snippets { +#searchIconAndTextContainer { width: 470px; } @@ -168,48 +167,6 @@ a { transition-duration: 0ms; } -#defaultSnippet1, -#defaultSnippet2, -#rightsSnippet { - display: block; - min-height: 38px; - background: 0 center no-repeat; - padding: 6px 0; - padding-inline-start: 49px; -} - -#rightsSnippet[hidden] { - display: none; -} - -#defaultSnippet1:dir(rtl), -#defaultSnippet2:dir(rtl), -#rightsSnippet:dir(rtl) { - background-position: right 0 center; -} - -#defaultSnippet1 { - background-image: url("chrome://browser/content/abouthome/snippet1.png"); -} - -#defaultSnippet2 { - background-image: url("chrome://browser/content/abouthome/snippet2.png"); -} - -#snippets { - display: inline-block; - text-align: start; - margin: 12px 0; - color: #3c3c3c; - font-size: 75%; - /* 12px is the computed font size, 15px the computed line height of the snippets - with Segoe UI on a default Windows 7 setup. The 15/12 multiplier approximately - converts em from units of font-size to units of line-height. The goal is to - preset the height of a three-line snippet to avoid visual moving/flickering as - the snippets load. */ - min-height: calc(15/12 * 3em); -} - #launcher { display: -moz-box; -moz-box-align: center; @@ -385,20 +342,6 @@ body[narrow] #restorePreviousSession::before { background-image: url("chrome://branding/content/about-logo@2x.png"); } - #defaultSnippet1, - #defaultSnippet2, - #rightsSnippet { - background-size: 40px; - } - - #defaultSnippet1 { - background-image: url("chrome://browser/content/abouthome/snippet1@2x.png"); - } - - #defaultSnippet2 { - background-image: url("chrome://browser/content/abouthome/snippet2@2x.png"); - } - .launchButton::before, #aboutMozilla::before { transform: scale(.5); diff --git a/browser/base/content/abouthome/aboutHome.js b/browser/base/content/abouthome/aboutHome.js index 50f3e01cd..0cbcc835a 100644 --- a/browser/base/content/abouthome/aboutHome.js +++ b/browser/base/content/abouthome/aboutHome.js @@ -6,23 +6,10 @@ /* import-globals-from ../contentSearchUI.js */ -// The process of adding a new default snippet involves: -// * add a new entity to aboutHome.dtd -// * add a <span/> for it in aboutHome.xhtml -// * add an entry here in the proper ordering (based on spans) -// The <a/> part of the snippet will be linked to the corresponding url. -const DEFAULT_SNIPPETS_URLS = [ - "https://www.mozilla.org/firefox/features/?utm_source=snippet&utm_medium=snippet&utm_campaign=default+feature+snippet" -, "https://addons.mozilla.org/firefox/?utm_source=snippet&utm_medium=snippet&utm_campaign=addons" -]; - -const SNIPPETS_UPDATE_INTERVAL_MS = 14400000; // 4 hours. - // IndexedDB storage constants. const DATABASE_NAME = "abouthome"; const DATABASE_VERSION = 1; const DATABASE_STORAGE = "persistent"; -const SNIPPETS_OBJECTSTORE_NAME = "snippets"; var searchText; // This global tracks if the page has been set up before, to prevent double inits @@ -33,13 +20,6 @@ var gObserver = new MutationObserver(function (mutations) { if (mutation.attributeName == "session") { fitToWidth(); } - if (mutation.attributeName == "snippetsVersion") { - if (!gInitialized) { - ensureSnippetsMapThen(loadSnippets); - gInitialized = true; - } - return; - } } }); @@ -90,126 +70,6 @@ window.addEventListener("keypress", ev => { searchText.value += ev.key; }); -// This object has the same interface as Map and is used to store and retrieve -// the snippets data. It is lazily initialized by ensureSnippetsMapThen(), so -// be sure its callback returned before trying to use it. -var gSnippetsMap; -var gSnippetsMapCallbacks = []; - -/** - * Ensure the snippets map is properly initialized. - * - * @param aCallback - * Invoked once the map has been initialized, gets the map as argument. - * @note Snippets should never directly manage the underlying storage, since - * it may change inadvertently. - */ -function ensureSnippetsMapThen(aCallback) -{ - if (gSnippetsMap) { - aCallback(gSnippetsMap); - return; - } - - // Handle multiple requests during the async initialization. - gSnippetsMapCallbacks.push(aCallback); - if (gSnippetsMapCallbacks.length > 1) { - // We are already updating, the callbacks will be invoked when done. - return; - } - - let invokeCallbacks = function () { - if (!gSnippetsMap) { - gSnippetsMap = Object.freeze(new Map()); - } - - for (let callback of gSnippetsMapCallbacks) { - callback(gSnippetsMap); - } - gSnippetsMapCallbacks.length = 0; - } - - let openRequest = indexedDB.open(DATABASE_NAME, {version: DATABASE_VERSION, - storage: DATABASE_STORAGE}); - - openRequest.onerror = function (event) { - // Try to delete the old database so that we can start this process over - // next time. - indexedDB.deleteDatabase(DATABASE_NAME); - invokeCallbacks(); - }; - - openRequest.onupgradeneeded = function (event) { - let db = event.target.result; - if (!db.objectStoreNames.contains(SNIPPETS_OBJECTSTORE_NAME)) { - db.createObjectStore(SNIPPETS_OBJECTSTORE_NAME); - } - } - - openRequest.onsuccess = function (event) { - let db = event.target.result; - - db.onerror = function (event) { - invokeCallbacks(); - } - - db.onversionchange = function (event) { - event.target.close(); - invokeCallbacks(); - } - - let cache = new Map(); - let cursorRequest; - try { - cursorRequest = db.transaction(SNIPPETS_OBJECTSTORE_NAME) - .objectStore(SNIPPETS_OBJECTSTORE_NAME).openCursor(); - } catch (ex) { - console.error(ex); - invokeCallbacks(); - return; - } - - cursorRequest.onerror = function (event) { - invokeCallbacks(); - } - - cursorRequest.onsuccess = function(event) { - let cursor = event.target.result; - - // Populate the cache from the persistent storage. - if (cursor) { - cache.set(cursor.key, cursor.value); - cursor.continue(); - return; - } - - // The cache has been filled up, create the snippets map. - gSnippetsMap = Object.freeze({ - get: (aKey) => cache.get(aKey), - set: function (aKey, aValue) { - db.transaction(SNIPPETS_OBJECTSTORE_NAME, "readwrite") - .objectStore(SNIPPETS_OBJECTSTORE_NAME).put(aValue, aKey); - return cache.set(aKey, aValue); - }, - has: (aKey) => cache.has(aKey), - delete: function (aKey) { - db.transaction(SNIPPETS_OBJECTSTORE_NAME, "readwrite") - .objectStore(SNIPPETS_OBJECTSTORE_NAME).delete(aKey); - return cache.delete(aKey); - }, - clear: function () { - db.transaction(SNIPPETS_OBJECTSTORE_NAME, "readwrite") - .objectStore(SNIPPETS_OBJECTSTORE_NAME).clear(); - return cache.clear(); - }, - get size() { return cache.size; }, - }); - - setTimeout(invokeCallbacks, 0); - } - } -} - function onSearchSubmit(aEvent) { gContentSearchController.search(aEvent); @@ -246,146 +106,6 @@ function setupSearch() */ function loadCompleted() { - var event = new CustomEvent("AboutHomeLoadSnippetsCompleted", {bubbles:true}); - document.dispatchEvent(event); -} - -/** - * Update the local snippets from the remote storage, then show them through - * showSnippets. - */ -function loadSnippets() -{ - if (!gSnippetsMap) - throw new Error("Snippets map has not properly been initialized"); - - // Allow tests to modify the snippets map before using it. - var event = new CustomEvent("AboutHomeLoadSnippets", {bubbles:true}); - document.dispatchEvent(event); - - // Check cached snippets version. - let cachedVersion = gSnippetsMap.get("snippets-cached-version") || 0; - let currentVersion = document.documentElement.getAttribute("snippetsVersion"); - if (cachedVersion < currentVersion) { - // The cached snippets are old and unsupported, restart from scratch. - gSnippetsMap.clear(); - } - - // Check last snippets update. - let lastUpdate = gSnippetsMap.get("snippets-last-update"); - let updateURL = document.documentElement.getAttribute("snippetsURL"); - let shouldUpdate = !lastUpdate || - Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS; - if (updateURL && shouldUpdate) { - // Try to update from network. - let xhr = new XMLHttpRequest(); - xhr.timeout = 5000; - // Even if fetching should fail we don't want to spam the server, thus - // set the last update time regardless its results. Will retry tomorrow. - gSnippetsMap.set("snippets-last-update", Date.now()); - xhr.onloadend = function (event) { - if (xhr.status == 200) { - gSnippetsMap.set("snippets", xhr.responseText); - gSnippetsMap.set("snippets-cached-version", currentVersion); - } - showSnippets(); - loadCompleted(); - }; - try { - xhr.open("GET", updateURL, true); - xhr.send(null); - } catch (ex) { - showSnippets(); - loadCompleted(); - return; - } - } else { - showSnippets(); - loadCompleted(); - } -} - -/** - * Shows locally cached remote snippets, or default ones when not available. - * - * @note: snippets should never invoke showSnippets(), or they may cause - * a "too much recursion" exception. - */ -var _snippetsShown = false; -function showSnippets() -{ - let snippetsElt = document.getElementById("snippets"); - - // Show about:rights notification, if needed. - let showRights = document.documentElement.getAttribute("showKnowYourRights"); - if (showRights) { - let rightsElt = document.getElementById("rightsSnippet"); - let anchor = rightsElt.getElementsByTagName("a")[0]; - anchor.href = "about:rights"; - snippetsElt.appendChild(rightsElt); - rightsElt.removeAttribute("hidden"); - return; - } - - if (!gSnippetsMap) - throw new Error("Snippets map has not properly been initialized"); - if (_snippetsShown) { - // There's something wrong with the remote snippets, just in case fall back - // to the default snippets. - showDefaultSnippets(); - throw new Error("showSnippets should never be invoked multiple times"); - } - _snippetsShown = true; - - let snippets = gSnippetsMap.get("snippets"); - // If there are remotely fetched snippets, try to to show them. - if (snippets) { - // Injecting snippets can throw if they're invalid XML. - try { - snippetsElt.innerHTML = snippets; - // Scripts injected by innerHTML are inactive, so we have to relocate them - // through DOM manipulation to activate their contents. - Array.forEach(snippetsElt.getElementsByTagName("script"), function(elt) { - let relocatedScript = document.createElement("script"); - relocatedScript.type = "text/javascript;version=1.8"; - relocatedScript.text = elt.text; - elt.parentNode.replaceChild(relocatedScript, elt); - }); - return; - } catch (ex) { - // Bad content, continue to show default snippets. - } - } - - showDefaultSnippets(); -} - -/** - * Clear snippets element contents and show default snippets. - */ -function showDefaultSnippets() -{ - // Clear eventual contents... - let snippetsElt = document.getElementById("snippets"); - snippetsElt.innerHTML = ""; - - // ...then show default snippets. - let defaultSnippetsElt = document.getElementById("defaultSnippets"); - let entries = defaultSnippetsElt.querySelectorAll("span"); - // Choose a random snippet. Assume there is always at least one. - let randIndex = Math.floor(Math.random() * entries.length); - let entry = entries[randIndex]; - // Inject url in the eventual link. - if (DEFAULT_SNIPPETS_URLS[randIndex]) { - let links = entry.getElementsByTagName("a"); - // Default snippets can have only one link, otherwise something is messed - // up in the translation. - if (links.length == 1) { - links[0].href = DEFAULT_SNIPPETS_URLS[randIndex]; - } - } - // Move the default snippet to the snippets element. - snippetsElt.appendChild(entry); } function fitToWidth() { diff --git a/browser/base/content/abouthome/aboutHome.xhtml b/browser/base/content/abouthome/aboutHome.xhtml index c288e732e..22bf2e7e8 100644 --- a/browser/base/content/abouthome/aboutHome.xhtml +++ b/browser/base/content/abouthome/aboutHome.xhtml @@ -46,15 +46,6 @@ <input id="searchSubmit" type="button" onclick="onSearchSubmit(event)" title="&contentSearchSubmit.tooltip;"/> </div> - - <div id="snippetContainer"> - <div id="defaultSnippets" hidden="true"> - <span id="defaultSnippet1">&abouthome.defaultSnippet1.v1;</span> - <span id="defaultSnippet2">&abouthome.defaultSnippet2.v1;</span> - </div> - <span id="rightsSnippet" hidden="true">&abouthome.rightsSnippet;</span> - <div id="snippets"/> - </div> </div> <div class="spacer"/> @@ -73,7 +64,5 @@ <button class="launchButton" id="restorePreviousSession">&historyRestoreLastSession.label;</button> </div> - <a id="aboutMozilla" href="https://www.mozilla.org/about/?utm_source=about-home&utm_medium=Referral" - aria-label="&abouthome.aboutMozilla.label;"/> </body> </html> diff --git a/browser/base/content/browser-context.inc b/browser/base/content/browser-context.inc index 51b14d152..3061cccdd 100644 --- a/browser/base/content/browser-context.inc +++ b/browser/base/content/browser-context.inc @@ -456,12 +456,14 @@ oncommand="gContextMenu.openPasswordManager();"/> </menupopup> </menu> +#ifdef MOZ_DEVTOOLS <menuseparator id="inspect-separator" hidden="true"/> <menuitem id="context-inspect" hidden="true" label="&inspectContextMenu.label;" accesskey="&inspectContextMenu.accesskey;" oncommand="gContextMenu.inspectNode();"/> +#endif <menuseparator id="context-media-eme-separator" hidden="true"/> <menuitem id="context-media-eme-learnmore" class="menuitem-iconic" diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js index ad070df12..c1bc65860 100644 --- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -63,9 +63,7 @@ var gPluginHandler = { msg.data.pluginID); break; case "PluginContent:SubmitReport": - if (AppConstants.MOZ_CRASHREPORTER) { - this.submitReport(msg.data.runID, msg.data.keyVals, msg.data.submitURLOptIn); - } + // Nothing to do here break; case "PluginContent:LinkClickCallback": switch (msg.data.name) { @@ -98,11 +96,8 @@ var gPluginHandler = { }, submitReport: function submitReport(runID, keyVals, submitURLOptIn) { - if (!AppConstants.MOZ_CRASHREPORTER) { - return; - } - Services.prefs.setBoolPref("dom.ipc.plugins.reportCrashURL", submitURLOptIn); - PluginCrashReporter.submitCrashReport(runID, keyVals); + /*** STUB ***/ + return; }, // Callback for user clicking a "reload page" link @@ -461,18 +456,7 @@ var gPluginHandler = { // If we don't have a minidumpID, we can't (or didn't) submit anything. // This can happen if the plugin is killed from the task manager. - let state; - if (!AppConstants.MOZ_CRASHREPORTER || !gCrashReporter.enabled) { - // This state tells the user that crash reporting is disabled, so we - // cannot send a report. - state = "noSubmit"; - } else if (!pluginDumpID) { - // This state tells the user that there is no crash report available. - state = "noReport"; - } else { - // This state asks the user to submit a crash report. - state = "please"; - } + let state = "noSubmit"; let mm = window.getGroupMessageManager("browsers"); mm.broadcastAsyncMessage("BrowserPlugins:NPAPIPluginProcessCrashed", @@ -513,22 +497,6 @@ var gPluginHandler = { callback: function() { browser.reload(); }, }]; - if (AppConstants.MOZ_CRASHREPORTER && - PluginCrashReporter.hasCrashReport(pluginID)) { - let submitLabel = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.label"); - let submitKey = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.accesskey"); - let submitButton = { - label: submitLabel, - accessKey: submitKey, - popup: null, - callback: () => { - PluginCrashReporter.submitCrashReport(pluginID); - }, - }; - - buttons.push(submitButton); - } - notification = notificationBox.appendNotification(messageString, "plugin-crashed", iconURL, priority, buttons); diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index d41e94ae6..696a2871a 100755 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -53,19 +53,16 @@ Cu.import("resource://gre/modules/NotificationDB.jsm"); ["UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"], ["Weave", "resource://services-sync/main.js"], ["fxAccounts", "resource://gre/modules/FxAccounts.jsm"], +#ifdef MOZ_DEVTOOLS + // Note: Do not delete! It is used for: base/content/nsContextMenu.js ["gDevTools", "resource://devtools/client/framework/gDevTools.jsm"], - ["gDevToolsBrowser", "resource://devtools/client/framework/gDevTools.jsm"], +#endif ["webrtcUI", "resource:///modules/webrtcUI.jsm", ] ].forEach(([name, resource]) => XPCOMUtils.defineLazyModuleGetter(this, name, resource)); XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing", "resource://gre/modules/SafeBrowsing.jsm"); -if (AppConstants.MOZ_CRASHREPORTER) { - XPCOMUtils.defineLazyModuleGetter(this, "PluginCrashReporter", - "resource:///modules/ContentCrashHandlers.jsm"); -} - // lazy service getters [ ["Favicons", "@mozilla.org/browser/favicon-service;1", "mozIAsyncFavicons"], @@ -74,13 +71,6 @@ if (AppConstants.MOZ_CRASHREPORTER) { ["gDNSService", "@mozilla.org/network/dns-service;1", "nsIDNSService"], ].forEach(([name, cc, ci]) => XPCOMUtils.defineLazyServiceGetter(this, name, cc, ci)); -if (AppConstants.MOZ_CRASHREPORTER) { - XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter", - "@mozilla.org/xre/app-info;1", - "nsICrashReporter"); -} - - XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function() { let tmp = {}; Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", tmp); @@ -214,7 +204,8 @@ var gInitialPages = [ "about:home", "about:privatebrowsing", "about:welcomeback", - "about:sessionrestore" + "about:sessionrestore", + "about:logopage" ]; function* browserWindows() { @@ -4582,23 +4573,6 @@ var XULBrowserWindow = { setTimeout(function () { XULBrowserWindow.asyncUpdateUI(); }, 0); else this.asyncUpdateUI(); - - if (AppConstants.MOZ_CRASHREPORTER && aLocationURI) { - let uri = aLocationURI.clone(); - try { - // If the current URI contains a username/password, remove it. - uri.userPass = ""; - } catch (ex) { /* Ignore failures on about: URIs. */ } - - try { - gCrashReporter.annotateCrashReport("URL", uri.spec); - } catch (ex) { - // Don't make noise when the crash reporter is built but not enabled. - if (ex.result != Components.results.NS_ERROR_NOT_INITIALIZED) { - throw ex; - } - } - } }, asyncUpdateUI: function () { @@ -7893,15 +7867,6 @@ var TabContextMenu = { } }; -Object.defineProperty(this, "HUDService", { - get: function HUDService_getter() { - let devtools = Cu.import("resource://devtools/shared/Loader.jsm", {}).devtools; - return devtools.require("devtools/client/webconsole/hudservice").HUDService; - }, - configurable: true, - enumerable: true -}); - // Prompt user to restart the browser in safe mode function safeModeRestart() { if (Services.appinfo.inSafeMode) { @@ -7959,30 +7924,6 @@ function duplicateTabIn(aTab, where, delta) { } } -var Scratchpad = { - openScratchpad: function SP_openScratchpad() { - return this.ScratchpadManager.openScratchpad(); - } -}; - -XPCOMUtils.defineLazyGetter(Scratchpad, "ScratchpadManager", function() { - let tmp = {}; - Cu.import("resource://devtools/client/scratchpad/scratchpad-manager.jsm", tmp); - return tmp.ScratchpadManager; -}); - -var ResponsiveUI = { - toggle: function RUI_toggle() { - this.ResponsiveUIManager.toggle(window, gBrowser.selectedTab); - } -}; - -XPCOMUtils.defineLazyGetter(ResponsiveUI, "ResponsiveUIManager", function() { - let tmp = {}; - Cu.import("resource://devtools/client/responsivedesign/responsivedesign.jsm", tmp); - return tmp.ResponsiveUIManager; -}); - var MousePosTracker = { _listeners: new Set(), _x: 0, diff --git a/browser/base/content/tab-content.js b/browser/base/content/tab-content.js index 05f8e00ab..7e803796a 100644 --- a/browser/base/content/tab-content.js +++ b/browser/base/content/tab-content.js @@ -147,13 +147,10 @@ var AboutHomeListener = { if (aData.showRestoreLastSession && !PrivateBrowsingUtils.isContentWindowPrivate(content)) doc.getElementById("launcher").setAttribute("session", "true"); - // Inject search engine and snippets URL. + // Inject search engine URL. let docElt = doc.documentElement; - // Set snippetsVersion last, which triggers to show the snippets when it's set. - docElt.setAttribute("snippetsURL", aData.snippetsURL); if (aData.showKnowYourRights) docElt.setAttribute("showKnowYourRights", "true"); - docElt.setAttribute("snippetsVersion", aData.snippetsVersion); }, onPageLoad: function() { diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index 833369f4d..0b703b6f8 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -35,7 +35,7 @@ var gBidiUI = false; * Determines whether the given url is considered a special URL for new tabs. */ function isBlankPageURL(aURL) { - return aURL == "about:blank" || aURL == BROWSER_NEW_TAB_URL; + return aURL == "about:blank" || aURL == "about:newtab" || aURL == "about:logopage"; } function getBrowserURL() diff --git a/browser/base/jar.mn b/browser/base/jar.mn index a65c77338..9cbfe7c15 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -67,7 +67,7 @@ browser.jar: content/browser/aboutTabCrashed.js (content/aboutTabCrashed.js) content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml) * content/browser/browser.css (content/browser.css) - content/browser/browser.js (content/browser.js) +* content/browser/browser.js (content/browser.js) * content/browser/browser.xul (content/browser.xul) content/browser/browser-addons.js (content/browser-addons.js) content/browser/browser-captivePortal.js (content/browser-captivePortal.js) diff --git a/browser/branding/shared/preferences.inc b/browser/branding/shared/preferences.inc index 08f6c950b..90fd3da06 100644 --- a/browser/branding/shared/preferences.inc +++ b/browser/branding/shared/preferences.inc @@ -31,3 +31,5 @@ pref("browser.safebrowsing.downloads.remote.enabled", false); // Disable the UI controls for it as well for Basilisk-official. pref("browser.safebrowsing.UI.enabled", false); +// +pref("general.useragent.appVersionIsBuildID", true); diff --git a/browser/branding/unofficial/VisualElements_150.png b/browser/branding/unofficial/VisualElements_150.png Binary files differindex 461961e8d..eb74e4adc 100644 --- a/browser/branding/unofficial/VisualElements_150.png +++ b/browser/branding/unofficial/VisualElements_150.png diff --git a/browser/branding/unofficial/VisualElements_70.png b/browser/branding/unofficial/VisualElements_70.png Binary files differindex aad81f40d..571532a9b 100644 --- a/browser/branding/unofficial/VisualElements_70.png +++ b/browser/branding/unofficial/VisualElements_70.png diff --git a/browser/branding/unofficial/branding.nsi b/browser/branding/unofficial/branding.nsi index 34214453f..77f08a4cb 100644 --- a/browser/branding/unofficial/branding.nsi +++ b/browser/branding/unofficial/branding.nsi @@ -8,19 +8,19 @@ # BrandFullNameInternal is used for some registry and file system values # instead of BrandFullName and typically should not be modified. -!define BrandFullNameInternal "Mozilla Developer Preview" -!define CompanyName "mozilla.org" -!define URLInfoAbout "https://www.mozilla.org" -!define HelpLink "https://support.mozilla.org" +!define BrandFullNameInternal "Serpent" +!define CompanyName "Moonchild Productions" +!define URLInfoAbout "http://www.basilisk-browser.org" +!define HelpLink "https://forum.palemoon.org" -!define URLStubDownload "http://download.mozilla.org/?os=win&lang=${AB_CD}&product=firefox-latest" -!define URLManualDownload "https://www.mozilla.org/${AB_CD}/firefox/installer-help/?channel=release&installer_lang=${AB_CD}" -!define URLSystemRequirements "https://www.mozilla.org/firefox/system-requirements/" +!define URLStubDownload "" +!define URLManualDownload "" +!define URLSystemRequirements "" !define Channel "unofficial" # The installer's certificate name and issuer expected by the stub installer -!define CertNameDownload "Mozilla Corporation" -!define CertIssuerDownload "DigiCert SHA2 Assured ID Code Signing CA" +!define CertNameDownload "" +!define CertIssuerDownload "" # Dialog units are used so the UI displays correctly with the system's DPI # settings. diff --git a/browser/branding/unofficial/configure.sh b/browser/branding/unofficial/configure.sh index edd3bd3e8..ea4e37e45 100644 --- a/browser/branding/unofficial/configure.sh +++ b/browser/branding/unofficial/configure.sh @@ -2,4 +2,4 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -MOZ_APP_DISPLAYNAME=Nightly +MOZ_APP_DISPLAYNAME=Serpent diff --git a/browser/branding/unofficial/content/about-background.png b/browser/branding/unofficial/content/about-background.png Binary files differindex 70eb8dafd..e36211b08 100644 --- a/browser/branding/unofficial/content/about-background.png +++ b/browser/branding/unofficial/content/about-background.png diff --git a/browser/branding/unofficial/content/about-logo.png b/browser/branding/unofficial/content/about-logo.png Binary files differindex 4c7214ba3..c5a838178 100644 --- a/browser/branding/unofficial/content/about-logo.png +++ b/browser/branding/unofficial/content/about-logo.png diff --git a/browser/branding/unofficial/content/about-logo@2x.png b/browser/branding/unofficial/content/about-logo@2x.png Binary files differindex 3526eda54..48c31564c 100644 --- a/browser/branding/unofficial/content/about-logo@2x.png +++ b/browser/branding/unofficial/content/about-logo@2x.png diff --git a/browser/branding/unofficial/content/about-wordmark.svg b/browser/branding/unofficial/content/about-wordmark.svg index 60b278d03..ce7a5c07b 100644 --- a/browser/branding/unofficial/content/about-wordmark.svg +++ b/browser/branding/unofficial/content/about-wordmark.svg @@ -1,22 +1,87 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> -<svg xmlns="http://www.w3.org/2000/svg" width="132px" height="48px" viewBox="0 0 132 48"> - <path fill="#fff" d="M60.6,14.3l-2.4-2.4C57,12.7,56,13,54.7,13c-3,0-3.8-1.4-7.6-1.4c-5.4,0-9.2,3.4-9.2,8.4 - c0,3.3,2.2,6.1,5.6,7.2c-3.4,1-4.5,2.2-4.5,4.3c0,2.2,1.8,3.6,4.7,3.6h3.8c2.5,0,3.9,0.2,4.9,0.9c0.9,0.6,1.4,1.6,1.4,3 - c0,3.1-2.2,4.4-6,4.4c-2,0-3.8-0.5-5.1-1.2c-0.9-0.6-1.5-1.6-1.5-2.9c0-0.8,0.3-1.7,0.7-2.2l-4.1,0.4c-0.3,1-0.5,1.7-0.5,2.6 - c0,3.5,3,6.4,10.8,6.4c6.1,0,9.9-2.5,9.9-7.9c0-2.1-0.8-3.9-2.7-5.3c-1.5-1.1-3.1-1.4-6-1.4h-4c-1.3,0-2-0.5-2-1.2 - c0-0.8,1.1-1.7,4.5-2.9c1.8,0,3.4-0.3,4.7-1.1c2.3-1.4,3.7-4.1,3.7-6.8c0-1.6-0.5-3-1.5-4.3c0.4,0.2,1.1,0.3,1.7,0.3 - C57.9,15.8,59,15.4,60.6,14.3z M47.1,24.8c-3.1,0-4.8-1.7-4.8-4.8c0-3.5,1.6-5.1,4.7-5.1c3.3,0,4.6,1.5,4.6,4.9 - C51.6,23.1,50.1,24.8,47.1,24.8z M30.7,1.3c-1.7,0-3,1.4-3,3.1s1.4,3,3,3c1.7,0,3.1-1.3,3.1-3C33.7,2.7,32.4,1.3,30.7,1.3z - M107.7,34.5c-1.1,0-1.4-0.6-1.4-2.5V6.5c0-3.8-0.6-5.9-0.6-5.9l-3.9,0.8c0,0,0.6,1.9,0.6,5.1v26.4c0,1.8,0.4,2.8,1.2,3.5 - c0.7,0.7,1.7,1,2.9,1c1,0,1.5-0.1,2.5-0.5l-0.8-2.5C108.2,34.4,107.8,34.5,107.7,34.5z M74.7,11.6c-3.2,0-6.1,1.8-8.3,3.9 - c0,0,0.2-1.8,0.2-3.4V6.3c0-3.8-0.7-5.9-0.7-5.9l-3.9,0.7c0,0,0.7,1.9,0.7,5.1V37h3.9V19.3c2.1-2.7,4.9-4.2,7.2-4.2 - c1.3,0,2.3,0.4,2.9,1c0.7,0.7,0.9,1.8,0.9,3.7V37h3.8V19.1c0-1.8-0.1-2.6-0.4-3.6C80.4,13.2,77.7,11.6,74.7,11.6z M127.4,12.1 - l-4.9,16.4c-0.6,2-1.6,5.2-1.6,5.2s-0.7-3.9-1.5-6.2l-5.1-16.2l-3.9,1.3l5.4,15.6c0.8,2.5,2.2,7.4,2.5,9l1.6-0.3 - c-1.3,5.1-2.5,6.7-5.7,7.6l1.2,2.7c4.4-1,6.4-4.3,8-9.3l8.6-25.8H127.4z M96.9,15l1.2-2.9h-6.2c0-3.3,0.5-7.2,0.5-7.2l-4.1,0.9 - c0,0-0.4,3.9-0.4,6.3h-3.2V15h3.2v17.1c0,2.5,0.7,4.1,2.4,5c0.9,0.4,1.9,0.7,3.3,0.7c1.8,0,3.1-0.4,4.4-1l-0.6-2.5 - c-0.7,0.3-1.3,0.5-2.4,0.5c-2.4,0-3.2-0.9-3.2-3.7V15H96.9z M28.6,37h4.1V11.5l-4.1,0.6V37z M18.9,21.3c0,5,0.4,10.5,0.4,10.5 - s-1.4-3.8-3.2-7.2L4.8,2.7H0V37h4.2L4,17.1c0-4.5-0.4-9.3-0.4-9.3s1.7,4.1,3.9,8.2l11,21h4.3V2.7h-4L18.9,21.3z"/> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="132px" + height="48px" + viewBox="0 0 132 48" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="about-wordmark.svg"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1215" + inkscape:window-height="778" + id="namedview6" + showgrid="false" + inkscape:zoom="2.4090909" + inkscape:cx="91.154186" + inkscape:cy="24" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:current-layer="svg2" /> + <g + transform="scale(0.83939803,1.1913299)" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:42.56122971px;line-height:125%;font-family:'Levenim MT';-inkscape-font-specification:'Levenim MT';letter-spacing:0px;word-spacing:0px;fill:#a8e6db;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + id="text4138"> + <path + d="m 18.521413,24.115665 q 0,3.470569 -2.618513,5.881264 -2.535386,2.348349 -6.0475185,2.348349 -5.6942271,0 -9.22714164,-6.463156 L 3.2259712,24.323483 q 2.7432042,5.04999 6.3384644,5.04999 3.4082234,0 4.9460804,-2.639295 0.706583,-1.205347 0.706583,-2.556167 0,-1.537857 -1.039093,-3.013369 Q 12.827186,19.23193 9.1487985,16.488726 5.3872836,13.703958 4.1819363,12.082974 2.560952,9.9008792 2.560952,7.4070572 q 0,-4.2394975 3.6576056,-6.2345551 1.7248936,-0.93518331 3.761515,-0.93518331 4.3641884,0 8.0217944,5.00842591 L 15.508045,7.1368931 Q 14.115661,5.3080903 13.138914,4.5391618 11.684184,3.3961601 9.917727,3.3961601 q -1.7664573,0 -2.9510228,1.0598743 -1.246911,1.0806563 -1.246911,2.8263317 0,2.0574032 1.9327121,3.9693339 0.56111,0.540328 3.9485517,3.054932 3.117277,2.306785 4.655134,4.15637 2.265222,2.763986 2.265222,5.652663 z" + style="" + id="path4143" /> + <path + d="m 46.743165,20.499623 -20.324649,0 q 0.08313,3.803079 2.369131,6.338464 2.410694,2.660077 6.151427,2.660077 3.616042,0 6.130646,-2.202876 1.143002,-0.997529 2.47304,-3.221187 l 2.452259,1.288475 q -2.286004,4.468098 -6.338465,6.026737 -1.974275,0.768928 -4.468097,0.768928 -5.091554,0 -8.437432,-3.36666 -3.325096,-3.366659 -3.325096,-8.458213 0,-4.301843 2.639295,-7.668503 3.345878,-4.2810608 8.956978,-4.2810608 5.777354,0 9.227141,4.3849708 2.452259,3.117277 2.493822,7.730848 z M 43.54276,17.985019 q -1.080656,-4.301843 -4.634352,-5.964391 -1.828803,-0.852056 -3.844643,-0.852056 -3.325096,0 -5.715008,2.140531 -1.745676,1.558639 -2.639295,4.675916 l 16.833298,0 z" + style="" + id="path4145" /> + <path + d="m 62.516592,9.1527326 -1.517075,2.4522584 q -0.914401,-0.394855 -1.537857,-0.394855 -3.491351,0 -4.862953,4.904517 -0.540328,1.932712 -0.540328,7.813975 l 0,7.647721 -2.971805,0 0,-22.610653 2.971805,0 0,3.304314 q 2.639295,-3.8862058 5.881264,-3.8862058 1.205347,0 2.576949,0.7689284 z" + style="" + id="path4147" /> + <path + d="m 88.577029,20.208677 q 0,4.94608 -3.325096,8.416649 -3.366659,3.532915 -8.271176,3.532915 -5.382499,0 -9.060887,-4.468098 l 0,12.157383 -2.888677,0 0,-30.88183 2.888677,0 0,4.15637 q 3.449787,-4.7382618 8.977759,-4.7382618 4.883735,0 8.271177,3.4705688 3.408223,3.470569 3.408223,8.354304 z m -2.930241,0.103909 q 0,-2.410694 -1.205347,-4.572007 -1.205347,-2.161312 -3.283532,-3.345878 -2.057403,-1.205347 -4.48888,-1.205347 -3.865424,0 -6.421592,2.660077 -2.535385,2.660077 -2.535385,6.546283 0,5.403281 4.468097,7.897103 2.140531,1.205347 4.530444,1.205347 2.410694,0 4.488879,-1.246911 2.01584,-1.226129 3.221187,-3.387441 1.226129,-2.161313 1.226129,-4.551226 z" + style="" + id="path4149" /> + <path + d="m 116.23767,20.499623 -20.324647,0 q 0.08313,3.803079 2.36913,6.338464 2.410697,2.660077 6.151427,2.660077 3.61604,0 6.13065,-2.202876 1.143,-0.997529 2.47304,-3.221187 l 2.45226,1.288475 q -2.28601,4.468098 -6.33847,6.026737 -1.97427,0.768928 -4.4681,0.768928 -5.09155,0 -8.437428,-3.36666 -3.325096,-3.366659 -3.325096,-8.458213 0,-4.301843 2.639295,-7.668503 3.345878,-4.2810608 8.956979,-4.2810608 5.77735,0 9.22714,4.3849708 2.45226,3.117277 2.49382,7.730848 z m -3.2004,-2.514604 q -1.08066,-4.301843 -4.63436,-5.964391 -1.8288,-0.852056 -3.84464,-0.852056 -3.32509,0 -5.715007,2.140531 -1.745675,1.558639 -2.639295,4.675916 l 16.833302,0 z" + style="" + id="path4151" /> + <path + d="m 141.4045,31.576349 -2.88868,0 0,-10.78578 q 0,-3.823861 -0.33251,-5.216245 -1.08066,-4.509661 -5.69423,-4.509661 -2.63929,0 -4.73826,1.745675 -2.07819,1.724894 -2.7432,4.322625 -0.41564,1.641766 -0.41564,6.151428 l 0,8.291958 -2.90946,0 0,-22.610653 2.90946,0 0,4.052461 q 3.47057,-4.6343528 8.47899,-4.6343528 2.47304,0 4.44732,1.2676928 1.99506,1.246911 2.93024,3.470569 0.95597,2.202876 0.95597,6.816447 l 0,11.637836 z" + style="" + id="path4153" /> + <path + d="m 157.69747,11.459518 -4.61357,0 0,20.116831 -2.93024,0 0,-20.116831 -3.96934,0 0,-2.493822 3.96934,0 0,-8.3958676 2.93024,0 0,8.3958676 4.61357,0 0,2.493822 z" + style="" + id="path4155" /> + </g> </svg> diff --git a/browser/branding/unofficial/content/about.png b/browser/branding/unofficial/content/about.png Binary files differindex 231449344..e323c8df5 100644 --- a/browser/branding/unofficial/content/about.png +++ b/browser/branding/unofficial/content/about.png diff --git a/browser/branding/unofficial/content/icon48.png b/browser/branding/unofficial/content/icon48.png Binary files differindex 5fc7861e5..16e022a64 100644 --- a/browser/branding/unofficial/content/icon48.png +++ b/browser/branding/unofficial/content/icon48.png diff --git a/browser/branding/unofficial/content/icon64.png b/browser/branding/unofficial/content/icon64.png Binary files differindex 83f7016bc..9860917e3 100644 --- a/browser/branding/unofficial/content/icon64.png +++ b/browser/branding/unofficial/content/icon64.png diff --git a/browser/branding/unofficial/default16.png b/browser/branding/unofficial/default16.png Binary files differindex d285a90b4..67ef39df8 100644 --- a/browser/branding/unofficial/default16.png +++ b/browser/branding/unofficial/default16.png diff --git a/browser/branding/unofficial/default32.png b/browser/branding/unofficial/default32.png Binary files differindex 95adf2497..2f709e6b2 100644 --- a/browser/branding/unofficial/default32.png +++ b/browser/branding/unofficial/default32.png diff --git a/browser/branding/unofficial/default48.png b/browser/branding/unofficial/default48.png Binary files differindex d38185f54..02a1e14c1 100644 --- a/browser/branding/unofficial/default48.png +++ b/browser/branding/unofficial/default48.png diff --git a/browser/branding/unofficial/firefox.icns b/browser/branding/unofficial/firefox.icns Binary files differindex 0c6941acf..2c613634b 100644 --- a/browser/branding/unofficial/firefox.icns +++ b/browser/branding/unofficial/firefox.icns diff --git a/browser/branding/unofficial/firefox.ico b/browser/branding/unofficial/firefox.ico Binary files differindex 5217a6c0b..0c7acb61b 100644 --- a/browser/branding/unofficial/firefox.ico +++ b/browser/branding/unofficial/firefox.ico diff --git a/browser/branding/unofficial/locales/en-US/brand.dtd b/browser/branding/unofficial/locales/en-US/brand.dtd index cf4596ae0..17c243606 100644 --- a/browser/branding/unofficial/locales/en-US/brand.dtd +++ b/browser/branding/unofficial/locales/en-US/brand.dtd @@ -2,8 +2,9 @@ - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> -<!ENTITY brandShorterName "Nightly"> -<!ENTITY brandShortName "Nightly"> -<!ENTITY brandFullName "Nightly"> -<!ENTITY vendorShortName "Mozilla"> +<!ENTITY brandShorterName "Serpent"> +<!ENTITY brandShortName "Serpent"> +<!ENTITY brandFullName "Serpent"> +<!ENTITY vendorShortName "Moonchild"> +<!ENTITY vendorFullName "Moonchild Productions"> <!ENTITY trademarkInfo.part1 " "> diff --git a/browser/branding/unofficial/locales/en-US/brand.properties b/browser/branding/unofficial/locales/en-US/brand.properties index 8cd2c2ec9..80349f0e3 100644 --- a/browser/branding/unofficial/locales/en-US/brand.properties +++ b/browser/branding/unofficial/locales/en-US/brand.properties @@ -2,9 +2,10 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -brandShorterName=Nightly -brandShortName=Nightly -brandFullName=Nightly -vendorShortName=Mozilla +brandShorterName=Serpent +brandShortName=Serpent +brandFullName=Serpent +vendorShortName=Moonchild +vendorFullName=Moonchild Productions syncBrandShortName=Sync diff --git a/browser/branding/unofficial/mozicon128.png b/browser/branding/unofficial/mozicon128.png Binary files differindex 471cf4645..739b61084 100644 --- a/browser/branding/unofficial/mozicon128.png +++ b/browser/branding/unofficial/mozicon128.png diff --git a/browser/branding/unofficial/basilisk.VisualElementsManifest.xml b/browser/branding/unofficial/serpent.VisualElementsManifest.xml index 7654e0ab7..5046ee7da 100644 --- a/browser/branding/unofficial/basilisk.VisualElementsManifest.xml +++ b/browser/branding/unofficial/serpent.VisualElementsManifest.xml @@ -4,5 +4,5 @@ Square150x150Logo='browser\VisualElements\VisualElements_150.png' Square70x70Logo='browser\VisualElements\VisualElements_70.png' ForegroundText='light' - BackgroundColor='#14171a'/> + BackgroundColor='#304D7E'/> </Application> diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp index a09932d95..717ae9c48 100644 --- a/browser/components/about/AboutRedirector.cpp +++ b/browser/components/about/AboutRedirector.cpp @@ -35,75 +35,117 @@ struct RedirEntry { URI_SAFE_FOR_UNTRUSTED_CONTENT. */ static RedirEntry kRedirMap[] = { - { "blocked", "chrome://browser/content/blockedSite.xhtml", + { + "basilisk", "chrome://global/content/memoriam.xhtml", + nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "blocked", "chrome://browser/content/blockedSite.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "certerror", "chrome://browser/content/aboutNetError.xhtml", + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "certerror", "chrome://browser/content/aboutNetError.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "socialerror", "chrome://browser/content/aboutSocialError.xhtml", + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "socialerror", "chrome://browser/content/aboutSocialError.xhtml", nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "providerdirectory", "chrome://browser/content/aboutProviderDirectory.xhtml", + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "providerdirectory", "chrome://browser/content/aboutProviderDirectory.xhtml", nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "tabcrashed", "chrome://browser/content/aboutTabCrashed.xhtml", + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "tabcrashed", "chrome://browser/content/aboutTabCrashed.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "feeds", "chrome://browser/content/feeds/subscribe.xhtml", + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "feeds", "chrome://browser/content/feeds/subscribe.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "privatebrowsing", "chrome://browser/content/aboutPrivateBrowsing.xhtml", + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "privatebrowsing", "chrome://browser/content/aboutPrivateBrowsing.xhtml", nsIAboutModule::URI_MUST_LOAD_IN_CHILD | - nsIAboutModule::ALLOW_SCRIPT }, - { "rights", - "chrome://global/content/aboutRights.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "rights", "chrome://global/content/aboutRights.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::MAKE_LINKABLE | - nsIAboutModule::ALLOW_SCRIPT }, - { "robots", "chrome://browser/content/aboutRobots.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "robots", "chrome://browser/content/aboutRobots.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::ALLOW_SCRIPT }, - { "searchreset", "chrome://browser/content/search/searchReset.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "searchreset", "chrome://browser/content/search/searchReset.xhtml", nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "sessionrestore", "chrome://browser/content/aboutSessionRestore.xhtml", - nsIAboutModule::ALLOW_SCRIPT }, - { "welcomeback", "chrome://browser/content/aboutWelcomeBack.xhtml", - nsIAboutModule::ALLOW_SCRIPT }, - { "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul", - nsIAboutModule::ALLOW_SCRIPT }, - // Linkable because of indexeddb use (bug 1228118) + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, + { + "sessionrestore", "chrome://browser/content/aboutSessionRestore.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "welcomeback", "chrome://browser/content/aboutWelcomeBack.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul", + nsIAboutModule::ALLOW_SCRIPT + }, { "home", "chrome://browser/content/abouthome/aboutHome.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | + // Linkable because of indexeddb use (bug 1228118) nsIAboutModule::MAKE_LINKABLE | nsIAboutModule::ENABLE_INDEXED_DB }, - // the newtab's actual URL will be determined when the channel is created - { "newtab", "about:blank", - nsIAboutModule::ALLOW_SCRIPT }, - { "preferences", "chrome://browser/content/preferences/in-content/preferences.xul", - nsIAboutModule::ALLOW_SCRIPT }, - { "downloads", "chrome://browser/content/downloads/contentAreaDownloadsView.xul", - nsIAboutModule::ALLOW_SCRIPT }, + { + // the newtab's actual URL will be determined when the channel is created + "newtab", "about:blank", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "preferences", "chrome://browser/content/preferences/in-content/preferences.xul", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "downloads", "chrome://browser/content/downloads/contentAreaDownloadsView.xul", + nsIAboutModule::ALLOW_SCRIPT + }, #ifdef MOZ_SERVICES_HEALTHREPORT - { "healthreport", "chrome://browser/content/abouthealthreport/abouthealth.xhtml", - nsIAboutModule::ALLOW_SCRIPT }, + { + "healthreport", "chrome://browser/content/abouthealthreport/abouthealth.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, #endif - { "accounts", "chrome://browser/content/aboutaccounts/aboutaccounts.xhtml", - nsIAboutModule::ALLOW_SCRIPT }, - { "reader", "chrome://global/content/reader/aboutReader.html", + { + "accounts", "chrome://browser/content/aboutaccounts/aboutaccounts.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, + { + "reader", "chrome://global/content/reader/aboutReader.html", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::URI_MUST_LOAD_IN_CHILD | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, }; static const int kRedirTotal = ArrayLength(kRedirMap); diff --git a/browser/components/build/nsModule.cpp b/browser/components/build/nsModule.cpp index f85d8812c..1fad0ce68 100644 --- a/browser/components/build/nsModule.cpp +++ b/browser/components/build/nsModule.cpp @@ -85,6 +85,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = { { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID }, #endif { NS_FEEDSNIFFER_CONTRACTID, &kNS_FEEDSNIFFER_CID }, + { NS_ABOUT_MODULE_CONTRACTID_PREFIX "basilisk", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "blocked", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "certerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "socialerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, diff --git a/browser/components/nsBrowserContentHandler.js b/browser/components/nsBrowserContentHandler.js index b366c3f81..74144fc1b 100644 --- a/browser/components/nsBrowserContentHandler.js +++ b/browser/components/nsBrowserContentHandler.js @@ -558,7 +558,7 @@ nsBrowserContentHandler.prototype = { if (overridePage && startPage && !willRestoreSession && !skipStartPage) return overridePage + "|" + startPage; - return overridePage || startPage || "about:blank"; + return overridePage || startPage || "about:blank" || "about:logopage"; }, get startPage() { diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index f97c173a0..448bb910d 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -70,15 +70,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "AlertsService", "@mozilla.org/alerts-s ["webrtcUI", "resource:///modules/webrtcUI.jsm"], ].forEach(([name, resource]) => XPCOMUtils.defineLazyModuleGetter(this, name, resource)); -if (AppConstants.MOZ_CRASHREPORTER) { - XPCOMUtils.defineLazyModuleGetter(this, "PluginCrashReporter", - "resource:///modules/ContentCrashHandlers.jsm"); - XPCOMUtils.defineLazyModuleGetter(this, "UnsubmittedCrashHandler", - "resource:///modules/ContentCrashHandlers.jsm"); - XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit", - "resource://gre/modules/CrashSubmit.jsm"); -} - XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() { return Services.strings.createBundle('chrome://branding/locale/brand.properties'); }); @@ -710,10 +701,6 @@ BrowserGlue.prototype = { } TabCrashHandler.init(); - if (AppConstants.MOZ_CRASHREPORTER) { - PluginCrashReporter.init(); - UnsubmittedCrashHandler.init(); - } Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); }, diff --git a/browser/components/preferences/in-content/advanced.js b/browser/components/preferences/in-content/advanced.js index 448a21dae..5f9458eee 100644 --- a/browser/components/preferences/in-content/advanced.js +++ b/browser/components/preferences/in-content/advanced.js @@ -40,9 +40,6 @@ var gAdvancedPane = { this.updateReadPrefs(); } this.updateOfflineApps(); - if (AppConstants.MOZ_CRASHREPORTER) { - this.initSubmitCrashes(); - } this.initTelemetry(); if (AppConstants.MOZ_TELEMETRY_REPORTING) { this.initSubmitHealthReport(); diff --git a/browser/components/preferences/in-content/advanced.xul b/browser/components/preferences/in-content/advanced.xul index facaaeaa9..4973f8e09 100644 --- a/browser/components/preferences/in-content/advanced.xul +++ b/browser/components/preferences/in-content/advanced.xul @@ -54,13 +54,6 @@ type="bool"/> #endif - <!-- Data Choices tab --> -#ifdef MOZ_CRASHREPORTER - <preference id="browser.crashReports.unsubmittedCheck.autoSubmit2" - name="browser.crashReports.unsubmittedCheck.autoSubmit2" - type="bool"/> -#endif - <!-- Network tab --> <preference id="browser.cache.disk.capacity" name="browser.cache.disk.capacity" @@ -233,22 +226,6 @@ </vbox> </groupbox> #endif -#ifdef MOZ_CRASHREPORTER - <groupbox> - <caption> - <checkbox id="automaticallySubmitCrashesBox" - preference="browser.crashReports.unsubmittedCheck.autoSubmit2" - label="&alwaysSubmitCrashReports.label;" - accesskey="&alwaysSubmitCrashReports.accesskey;"/> - </caption> - <hbox class="indent"> - <label flex="1">&crashReporterDesc2.label;</label> - <spacer flex="10"/> - <label id="crashReporterLearnMore" - class="text-link">&crashReporterLearnMore.label;</label> - </hbox> - </groupbox> -#endif </tabpanel> #endif diff --git a/browser/confvars.sh b/browser/confvars.sh index 8cdd6e1f3..03b4cea97 100755 --- a/browser/confvars.sh +++ b/browser/confvars.sh @@ -56,6 +56,9 @@ MOZ_JSDOWNLOADS=1 MOZ_WEBRTC=1 MOZ_WEBEXTENSIONS=1 MOZ_DEVTOOLS=1 +MOZ_SERVICES_COMMON=1 +MOZ_SERVICES_SYNC=1 +MOZ_SERVICES_HEALTHREPORT=1 # Disable checking that add-ons are signed by the trusted root MOZ_ADDON_SIGNING=0 diff --git a/browser/experiments/.eslintrc.js b/browser/experiments/.eslintrc.js deleted file mode 100644 index 1f6b11d67..000000000 --- a/browser/experiments/.eslintrc.js +++ /dev/null @@ -1,11 +0,0 @@ -"use strict"; - -module.exports = { - "rules": { - "no-unused-vars": ["error", { - "vars": "all", - "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$", - "args": "none" - }] - } -}; diff --git a/browser/experiments/Experiments.jsm b/browser/experiments/Experiments.jsm deleted file mode 100644 index e9a63f19f..000000000 --- a/browser/experiments/Experiments.jsm +++ /dev/null @@ -1,2354 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = [ - "Experiments", -]; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); -Cu.import("resource://gre/modules/Log.jsm"); -Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("resource://gre/modules/AsyncShutdown.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils", - "resource://gre/modules/UpdateUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", - "resource://gre/modules/AddonManager.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate", - "resource://gre/modules/AddonManager.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "TelemetryEnvironment", - "resource://gre/modules/TelemetryEnvironment.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "TelemetryLog", - "resource://gre/modules/TelemetryLog.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "TelemetryUtils", - "resource://gre/modules/TelemetryUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils", - "resource://services-common/utils.js"); - -XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter", - "@mozilla.org/xre/app-info;1", - "nsICrashReporter"); - -const FILE_CACHE = "experiments.json"; -const EXPERIMENTS_CHANGED_TOPIC = "experiments-changed"; -const MANIFEST_VERSION = 1; -const CACHE_VERSION = 1; - -const KEEP_HISTORY_N_DAYS = 180; - -const PREF_BRANCH = "experiments."; -const PREF_ENABLED = "enabled"; // experiments.enabled -const PREF_ACTIVE_EXPERIMENT = "activeExperiment"; // whether we have an active experiment -const PREF_LOGGING = "logging"; -const PREF_LOGGING_LEVEL = PREF_LOGGING + ".level"; // experiments.logging.level -const PREF_LOGGING_DUMP = PREF_LOGGING + ".dump"; // experiments.logging.dump -const PREF_MANIFEST_URI = "manifest.uri"; // experiments.logging.manifest.uri -const PREF_FORCE_SAMPLE = "force-sample-value"; // experiments.force-sample-value - -const PREF_BRANCH_TELEMETRY = "toolkit.telemetry."; -const PREF_TELEMETRY_ENABLED = "enabled"; - -const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties"; -const STRING_TYPE_NAME = "type.%ID%.name"; - -const CACHE_WRITE_RETRY_DELAY_SEC = 60 * 3; -const MANIFEST_FETCH_TIMEOUT_MSEC = 60 * 3 * 1000; // 3 minutes - -const TELEMETRY_LOG = { - // log(key, [kind, experimentId, details]) - ACTIVATION_KEY: "EXPERIMENT_ACTIVATION", - ACTIVATION: { - // Successfully activated. - ACTIVATED: "ACTIVATED", - // Failed to install the add-on. - INSTALL_FAILURE: "INSTALL_FAILURE", - // Experiment does not meet activation requirements. Details will - // be provided. - REJECTED: "REJECTED", - }, - - // log(key, [kind, experimentId, optionalDetails...]) - TERMINATION_KEY: "EXPERIMENT_TERMINATION", - TERMINATION: { - // The Experiments service was disabled. - SERVICE_DISABLED: "SERVICE_DISABLED", - // Add-on uninstalled. - ADDON_UNINSTALLED: "ADDON_UNINSTALLED", - // The experiment disabled itself. - FROM_API: "FROM_API", - // The experiment expired (e.g. by exceeding the end date). - EXPIRED: "EXPIRED", - // Disabled after re-evaluating conditions. If this is specified, - // details will be provided. - RECHECK: "RECHECK", - }, -}; -XPCOMUtils.defineConstant(this, "TELEMETRY_LOG", TELEMETRY_LOG); - -const gPrefs = new Preferences(PREF_BRANCH); -const gPrefsTelemetry = new Preferences(PREF_BRANCH_TELEMETRY); -var gExperimentsEnabled = false; -var gAddonProvider = null; -var gExperiments = null; -var gLogAppenderDump = null; -var gPolicyCounter = 0; -var gExperimentsCounter = 0; -var gExperimentEntryCounter = 0; -var gPreviousProviderCounter = 0; - -// Tracks active AddonInstall we know about so we can deny external -// installs. -var gActiveInstallURLs = new Set(); - -// Tracks add-on IDs that are being uninstalled by us. This allows us -// to differentiate between expected uninstalled and user-driven uninstalls. -var gActiveUninstallAddonIDs = new Set(); - -var gLogger; -var gLogDumping = false; - -function configureLogging() { - if (!gLogger) { - gLogger = Log.repository.getLogger("Browser.Experiments"); - gLogger.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter())); - } - gLogger.level = gPrefs.get(PREF_LOGGING_LEVEL, Log.Level.Warn); - - let logDumping = gPrefs.get(PREF_LOGGING_DUMP, false); - if (logDumping != gLogDumping) { - if (logDumping) { - gLogAppenderDump = new Log.DumpAppender(new Log.BasicFormatter()); - gLogger.addAppender(gLogAppenderDump); - } else { - gLogger.removeAppender(gLogAppenderDump); - gLogAppenderDump = null; - } - gLogDumping = logDumping; - } -} - -// Loads a JSON file using OS.file. file is a string representing the path -// of the file to be read, options contains additional options to pass to -// OS.File.read. -// Returns a Promise resolved with the json payload or rejected with -// OS.File.Error or JSON.parse() errors. -function loadJSONAsync(file, options) { - return Task.spawn(function*() { - let rawData = yield OS.File.read(file, options); - // Read json file into a string - let data; - try { - // Obtain a converter to read from a UTF-8 encoded input stream. - let converter = new TextDecoder(); - data = JSON.parse(converter.decode(rawData)); - } catch (ex) { - gLogger.error("Experiments: Could not parse JSON: " + file + " " + ex); - throw ex; - } - return data; - }); -} - -// Returns a promise that is resolved with the AddonInstall for that URL. -function addonInstallForURL(url, hash) { - let deferred = Promise.defer(); - AddonManager.getInstallForURL(url, install => deferred.resolve(install), - "application/x-xpinstall", hash); - return deferred.promise; -} - -// Returns a promise that is resolved with an Array<Addon> of the installed -// experiment addons. -function installedExperimentAddons() { - let deferred = Promise.defer(); - AddonManager.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons.filter(a => !a.appDisabled)); - }); - return deferred.promise; -} - -// Takes an Array<Addon> and returns a promise that is resolved when the -// addons are uninstalled. -function uninstallAddons(addons) { - let ids = new Set(addons.map(addon => addon.id)); - let deferred = Promise.defer(); - - let listener = {}; - listener.onUninstalled = addon => { - if (!ids.has(addon.id)) { - return; - } - - ids.delete(addon.id); - if (ids.size == 0) { - AddonManager.removeAddonListener(listener); - deferred.resolve(); - } - }; - - AddonManager.addAddonListener(listener); - - for (let addon of addons) { - // Disabling the add-on before uninstalling is necessary to cause tests to - // pass. This might be indicative of a bug in XPIProvider. - // TODO follow up in bug 992396. - addon.userDisabled = true; - addon.uninstall(); - } - - return deferred.promise; -} - -/** - * The experiments module. - */ - -var Experiments = { - /** - * Provides access to the global `Experiments.Experiments` instance. - */ - instance: function () { - if (!gExperiments) { - gExperiments = new Experiments.Experiments(); - } - - return gExperiments; - }, -}; - -/* - * The policy object allows us to inject fake enviroment data from the - * outside by monkey-patching. - */ - -Experiments.Policy = function () { - this._log = Log.repository.getLoggerWithMessagePrefix( - "Browser.Experiments.Policy", - "Policy #" + gPolicyCounter++ + "::"); - - // Set to true to ignore hash verification on downloaded XPIs. This should - // not be used outside of testing. - this.ignoreHashes = false; -}; - -Experiments.Policy.prototype = { - now: function () { - return new Date(); - }, - - random: function () { - let pref = gPrefs.get(PREF_FORCE_SAMPLE); - if (pref !== undefined) { - let val = Number.parseFloat(pref); - this._log.debug("random sample forced: " + val); - if (isNaN(val) || val < 0) { - return 0; - } - if (val > 1) { - return 1; - } - return val; - } - return Math.random(); - }, - - futureDate: function (offset) { - return new Date(this.now().getTime() + offset); - }, - - oneshotTimer: function (callback, timeout, thisObj, name) { - return CommonUtils.namedTimer(callback, timeout, thisObj, name); - }, - - updatechannel: function () { - return UpdateUtils.UpdateChannel; - }, - - locale: function () { - let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); - return chrome.getSelectedLocale("global"); - }, - - /** - * For testing a race condition, one of the tests delays the callback of - * writing the cache by replacing this policy function. - */ - delayCacheWrite: function(promise) { - return promise; - }, -}; - -function AlreadyShutdownError(message="already shut down") { - Error.call(this, message); - let error = new Error(); - this.name = "AlreadyShutdownError"; - this.message = message; - this.stack = error.stack; -} -AlreadyShutdownError.prototype = Object.create(Error.prototype); -AlreadyShutdownError.prototype.constructor = AlreadyShutdownError; - -function CacheWriteError(message="Error writing cache file") { - Error.call(this, message); - let error = new Error(); - this.name = "CacheWriteError"; - this.message = message; - this.stack = error.stack; -} -CacheWriteError.prototype = Object.create(Error.prototype); -CacheWriteError.prototype.constructor = CacheWriteError; - -/** - * Manages the experiments and provides an interface to control them. - */ - -Experiments.Experiments = function (policy=new Experiments.Policy()) { - let log = Log.repository.getLoggerWithMessagePrefix( - "Browser.Experiments.Experiments", - "Experiments #" + gExperimentsCounter++ + "::"); - - // At the time of this writing, Experiments.jsm has severe - // crashes. For forensics purposes, keep the last few log - // messages in memory and upload them in case of crash. - this._forensicsLogs = []; - this._forensicsLogs.length = 30; - this._log = Object.create(log); - this._log.log = (level, string, params) => { - this._addToForensicsLog("Experiments", string); - log.log(level, string, params); - }; - - this._log.trace("constructor"); - - // Capture the latest error, for forensics purposes. - this._latestError = null; - - - this._policy = policy; - - // This is a Map of (string -> ExperimentEntry), keyed with the experiment id. - // It holds both the current experiments and history. - // Map() preserves insertion order, which means we preserve the manifest order. - // This is null until we've successfully completed loading the cache from - // disk the first time. - this._experiments = null; - this._refresh = false; - this._terminateReason = null; // or TELEMETRY_LOG.TERMINATION.... - this._dirty = false; - - // Loading the cache happens once asynchronously on startup - this._loadTask = null; - - // The _main task handles all other actions: - // * refreshing the manifest off the network (if _refresh) - // * disabling/enabling experiments - // * saving the cache (if _dirty) - this._mainTask = null; - - // Timer for re-evaluating experiment status. - this._timer = null; - - this._shutdown = false; - this._networkRequest = null; - - // We need to tell when we first evaluated the experiments to fire an - // experiments-changed notification when we only loaded completed experiments. - this._firstEvaluate = true; - - this.init(); -}; - -Experiments.Experiments.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback, Ci.nsIObserver]), - - /** - * `true` if the experiments manager is currently setup (has been fully initialized - * and not uninitialized yet). - */ - get isReady() { - return !this._shutdown; - }, - - init: function () { - this._shutdown = false; - configureLogging(); - - gExperimentsEnabled = gPrefs.get(PREF_ENABLED, false) && TelemetryUtils.isTelemetryEnabled; - this._log.trace("enabled=" + gExperimentsEnabled + ", " + this.enabled); - - gPrefs.observe(PREF_LOGGING, configureLogging); - gPrefs.observe(PREF_MANIFEST_URI, this.updateManifest, this); - gPrefs.observe(PREF_ENABLED, this._toggleExperimentsEnabled, this); - - gPrefsTelemetry.observe(PREF_TELEMETRY_ENABLED, this._telemetryStatusChanged, this); - - AddonManager.shutdown.addBlocker("Experiments.jsm shutdown", - this.uninit.bind(this), - this._getState.bind(this) - ); - - this._registerWithAddonManager(); - - this._loadTask = this._loadFromCache(); - - return this._loadTask.then( - () => { - this._log.trace("_loadTask finished ok"); - this._loadTask = null; - return this._run(); - }, - (e) => { - this._log.error("_loadFromCache caught error: " + e); - this._latestError = e; - throw e; - } - ); - }, - - /** - * Uninitialize this instance. - * - * This function is susceptible to race conditions. If it is called multiple - * times before the previous uninit() has completed or if it is called while - * an init() operation is being performed, the object may get in bad state - * and/or deadlock could occur. - * - * @return Promise<> - * The promise is fulfilled when all pending tasks are finished. - */ - uninit: Task.async(function* () { - this._log.trace("uninit: started"); - yield this._loadTask; - this._log.trace("uninit: finished with _loadTask"); - - if (!this._shutdown) { - this._log.trace("uninit: no previous shutdown"); - this._unregisterWithAddonManager(); - - gPrefs.ignore(PREF_LOGGING, configureLogging); - gPrefs.ignore(PREF_MANIFEST_URI, this.updateManifest, this); - gPrefs.ignore(PREF_ENABLED, this._toggleExperimentsEnabled, this); - - gPrefsTelemetry.ignore(PREF_TELEMETRY_ENABLED, this._telemetryStatusChanged, this); - - if (this._timer) { - this._timer.clear(); - } - } - - this._shutdown = true; - if (this._mainTask) { - if (this._networkRequest) { - try { - this._log.trace("Aborting pending network request: " + this._networkRequest); - this._networkRequest.abort(); - } catch (e) { - // pass - } - } - try { - this._log.trace("uninit: waiting on _mainTask"); - yield this._mainTask; - } catch (e) { - // We error out of tasks after shutdown via this exception. - this._log.trace(`uninit: caught error - ${e}`); - if (!(e instanceof AlreadyShutdownError)) { - this._latestError = e; - throw e; - } - } - } - - this._log.info("Completed uninitialization."); - }), - - // Return state information, for debugging purposes. - _getState: function() { - let activeExperiment = this._getActiveExperiment(); - let state = { - isShutdown: this._shutdown, - isEnabled: gExperimentsEnabled, - isRefresh: this._refresh, - isDirty: this._dirty, - isFirstEvaluate: this._firstEvaluate, - hasLoadTask: !!this._loadTask, - hasMainTask: !!this._mainTask, - hasTimer: !!this._hasTimer, - hasAddonProvider: !!gAddonProvider, - latestLogs: this._forensicsLogs, - experiments: this._experiments ? [...this._experiments.keys()] : null, - terminateReason: this._terminateReason, - activeExperiment: activeExperiment ? activeExperiment.id : null, - }; - if (this._latestError) { - if (typeof this._latestError == "object") { - state.latestError = { - message: this._latestError.message, - stack: this._latestError.stack - }; - } else { - state.latestError = "" + this._latestError; - } - } - return state; - }, - - _addToForensicsLog: function (what, string) { - this._forensicsLogs.shift(); - let timeInSec = Math.floor(Services.telemetry.msSinceProcessStart() / 1000); - this._forensicsLogs.push(`${timeInSec}: ${what} - ${string}`); - }, - - _registerWithAddonManager: function (previousExperimentsProvider) { - this._log.trace("Registering instance with Addon Manager."); - - AddonManager.addAddonListener(this); - AddonManager.addInstallListener(this); - - if (!gAddonProvider) { - // The properties of this AddonType should be kept in sync with the - // experiment AddonType registered in XPIProvider. - this._log.trace("Registering previous experiment add-on provider."); - gAddonProvider = previousExperimentsProvider || new Experiments.PreviousExperimentProvider(this); - AddonManagerPrivate.registerProvider(gAddonProvider, [ - new AddonManagerPrivate.AddonType("experiment", - URI_EXTENSION_STRINGS, - STRING_TYPE_NAME, - AddonManager.VIEW_TYPE_LIST, - 11000, - AddonManager.TYPE_UI_HIDE_EMPTY), - ]); - } - - }, - - _unregisterWithAddonManager: function () { - this._log.trace("Unregistering instance with Addon Manager."); - - this._log.trace("Removing install listener from add-on manager."); - AddonManager.removeInstallListener(this); - this._log.trace("Removing addon listener from add-on manager."); - AddonManager.removeAddonListener(this); - this._log.trace("Finished unregistering with addon manager."); - - if (gAddonProvider) { - this._log.trace("Unregistering previous experiment add-on provider."); - AddonManagerPrivate.unregisterProvider(gAddonProvider); - gAddonProvider = null; - } - }, - - /* - * Change the PreviousExperimentsProvider that this instance uses. - * For testing only. - */ - _setPreviousExperimentsProvider: function (provider) { - this._unregisterWithAddonManager(); - this._registerWithAddonManager(provider); - }, - - /** - * Throws an exception if we've already shut down. - */ - _checkForShutdown: function() { - if (this._shutdown) { - throw new AlreadyShutdownError("uninit() already called"); - } - }, - - /** - * Whether the experiments feature is enabled. - */ - get enabled() { - return gExperimentsEnabled; - }, - - /** - * Toggle whether the experiments feature is enabled or not. - */ - set enabled(enabled) { - this._log.trace("set enabled(" + enabled + ")"); - gPrefs.set(PREF_ENABLED, enabled); - }, - - _toggleExperimentsEnabled: Task.async(function* (enabled) { - this._log.trace("_toggleExperimentsEnabled(" + enabled + ")"); - let wasEnabled = gExperimentsEnabled; - gExperimentsEnabled = enabled && TelemetryUtils.isTelemetryEnabled; - - if (wasEnabled == gExperimentsEnabled) { - return; - } - - if (gExperimentsEnabled) { - yield this.updateManifest(); - } else { - yield this.disableExperiment(TELEMETRY_LOG.TERMINATION.SERVICE_DISABLED); - if (this._timer) { - this._timer.clear(); - } - } - }), - - _telemetryStatusChanged: function () { - this._toggleExperimentsEnabled(gExperimentsEnabled); - }, - - /** - * Returns a promise that is resolved with an array of `ExperimentInfo` objects, - * which provide info on the currently and recently active experiments. - * The array is in chronological order. - * - * The experiment info is of the form: - * { - * id: <string>, - * name: <string>, - * description: <string>, - * active: <boolean>, - * endDate: <integer>, // epoch ms - * detailURL: <string>, - * ... // possibly extended later - * } - * - * @return Promise<Array<ExperimentInfo>> Array of experiment info objects. - */ - getExperiments: function () { - return Task.spawn(function*() { - yield this._loadTask; - let list = []; - - for (let [id, experiment] of this._experiments) { - if (!experiment.startDate) { - // We only collect experiments that are or were active. - continue; - } - - list.push({ - id: id, - name: experiment._name, - description: experiment._description, - active: experiment.enabled, - endDate: experiment.endDate.getTime(), - detailURL: experiment._homepageURL, - branch: experiment.branch, - }); - } - - // Sort chronologically, descending. - list.sort((a, b) => b.endDate - a.endDate); - return list; - }.bind(this)); - }, - - /** - * Returns the ExperimentInfo for the active experiment, or null - * if there is none. - */ - getActiveExperiment: function () { - let experiment = this._getActiveExperiment(); - if (!experiment) { - return null; - } - - let info = { - id: experiment.id, - name: experiment._name, - description: experiment._description, - active: experiment.enabled, - endDate: experiment.endDate.getTime(), - detailURL: experiment._homepageURL, - }; - - return info; - }, - - /** - * Experiment "branch" support. If an experiment has multiple branches, it - * can record the branch with the experiment system and it will - * automatically be included in data reporting (FHR/telemetry payloads). - */ - - /** - * Set the experiment branch for the specified experiment ID. - * @returns Promise<> - */ - setExperimentBranch: Task.async(function*(id, branchstr) { - yield this._loadTask; - let e = this._experiments.get(id); - if (!e) { - throw new Error("Experiment not found"); - } - e.branch = String(branchstr); - this._log.trace("setExperimentBranch(" + id + ", " + e.branch + ") _dirty=" + this._dirty); - this._dirty = true; - Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC, null); - yield this._run(); - }), - /** - * Get the branch of the specified experiment. If the experiment is unknown, - * throws an error. - * - * @param id The ID of the experiment. Pass null for the currently running - * experiment. - * @returns Promise<string|null> - * @throws Error if the specified experiment ID is unknown, or if there is no - * current experiment. - */ - getExperimentBranch: Task.async(function*(id=null) { - yield this._loadTask; - let e; - if (id) { - e = this._experiments.get(id); - if (!e) { - throw new Error("Experiment not found"); - } - } else { - e = this._getActiveExperiment(); - if (e === null) { - throw new Error("No active experiment"); - } - } - return e.branch; - }), - - /** - * Determine whether another date has the same UTC day as now(). - */ - _dateIsTodayUTC: function (d) { - let now = this._policy.now(); - - return stripDateToMidnight(now).getTime() == stripDateToMidnight(d).getTime(); - }, - - /** - * Obtain the entry of the most recent active experiment that was active - * today. - * - * If no experiment was active today, this resolves to nothing. - * - * Assumption: Only a single experiment can be active at a time. - * - * @return Promise<object> - */ - lastActiveToday: function () { - return Task.spawn(function* getMostRecentActiveExperimentTask() { - let experiments = yield this.getExperiments(); - - // Assumption: Ordered chronologically, descending, with active always - // first. - for (let experiment of experiments) { - if (experiment.active) { - return experiment; - } - - if (experiment.endDate && this._dateIsTodayUTC(experiment.endDate)) { - return experiment; - } - } - return null; - }.bind(this)); - }, - - _run: function() { - this._log.trace("_run"); - this._checkForShutdown(); - if (!this._mainTask) { - this._mainTask = Task.spawn(function*() { - try { - yield this._main(); - } catch (e) { - // In the CacheWriteError case we want to reschedule - if (!(e instanceof CacheWriteError)) { - this._log.error("_main caught error: " + e); - return; - } - } finally { - this._mainTask = null; - } - this._log.trace("_main finished, scheduling next run"); - try { - yield this._scheduleNextRun(); - } catch (ex) { - // We error out of tasks after shutdown via this exception. - if (!(ex instanceof AlreadyShutdownError)) { - throw ex; - } - } - }.bind(this)); - } - return this._mainTask; - }, - - _main: function*() { - do { - this._log.trace("_main iteration"); - yield this._loadTask; - if (!gExperimentsEnabled) { - this._refresh = false; - } - - if (this._refresh) { - yield this._loadManifest(); - } - yield this._evaluateExperiments(); - if (this._dirty) { - yield this._saveToCache(); - } - // If somebody called .updateManifest() or disableExperiment() - // while we were running, go again right now. - } - while (this._refresh || this._terminateReason || this._dirty); - }, - - _loadManifest: function*() { - this._log.trace("_loadManifest"); - let uri = Services.urlFormatter.formatURLPref(PREF_BRANCH + PREF_MANIFEST_URI); - - this._checkForShutdown(); - - this._refresh = false; - try { - let responseText = yield this._httpGetRequest(uri); - this._log.trace("_loadManifest() - responseText=\"" + responseText + "\""); - - if (this._shutdown) { - return; - } - - let data = JSON.parse(responseText); - this._updateExperiments(data); - } catch (e) { - this._log.error("_loadManifest - failure to fetch/parse manifest (continuing anyway): " + e); - } - }, - - /** - * Fetch an updated list of experiments and trigger experiment updates. - * Do only use when experiments are enabled. - * - * @return Promise<> - * The promise is resolved when the manifest and experiment list is updated. - */ - updateManifest: function () { - this._log.trace("updateManifest()"); - - if (!gExperimentsEnabled) { - return Promise.reject(new Error("experiments are disabled")); - } - - if (this._shutdown) { - return Promise.reject(Error("uninit() alrady called")); - } - - this._refresh = true; - return this._run(); - }, - - notify: function (timer) { - this._log.trace("notify()"); - this._checkForShutdown(); - return this._run(); - }, - - // START OF ADD-ON LISTENERS - - onUninstalled: function (addon) { - this._log.trace("onUninstalled() - addon id: " + addon.id); - if (gActiveUninstallAddonIDs.has(addon.id)) { - this._log.trace("matches pending uninstall"); - return; - } - let activeExperiment = this._getActiveExperiment(); - if (!activeExperiment || activeExperiment._addonId != addon.id) { - return; - } - - this.disableExperiment(TELEMETRY_LOG.TERMINATION.ADDON_UNINSTALLED); - }, - - /** - * @returns {Boolean} returns false when we cancel the install. - */ - onInstallStarted: function (install) { - if (install.addon.type != "experiment") { - return true; - } - - this._log.trace("onInstallStarted() - " + install.addon.id); - if (install.addon.appDisabled) { - // This is a PreviousExperiment - return true; - } - - // We want to be in control of all experiment add-ons: reject installs - // for add-ons that we don't know about. - - // We have a race condition of sorts to worry about here. We have 2 - // onInstallStarted listeners. This one (the global one) and the one - // created as part of ExperimentEntry._installAddon. Because of the order - // they are registered in, this one likely executes first. Unfortunately, - // this means that the add-on ID is not yet set on the ExperimentEntry. - // So, we can't just look at this._trackedAddonIds because the new experiment - // will have its add-on ID set to null. We work around this by storing a - // identifying field - the source URL of the install - in a module-level - // variable (so multiple Experiments instances doesn't cancel each other - // out). - - if (this._trackedAddonIds.has(install.addon.id)) { - this._log.info("onInstallStarted allowing install because add-on ID " + - "tracked by us."); - return true; - } - - if (gActiveInstallURLs.has(install.sourceURI.spec)) { - this._log.info("onInstallStarted allowing install because install " + - "tracked by us."); - return true; - } - - this._log.warn("onInstallStarted cancelling install of unknown " + - "experiment add-on: " + install.addon.id); - return false; - }, - - // END OF ADD-ON LISTENERS. - - _getExperimentByAddonId: function (addonId) { - for (let [, entry] of this._experiments) { - if (entry._addonId === addonId) { - return entry; - } - } - - return null; - }, - - /* - * Helper function to make HTTP GET requests. Returns a promise that is resolved with - * the responseText when the request is complete. - */ - _httpGetRequest: function (url) { - this._log.trace("httpGetRequest(" + url + ")"); - let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); - - this._networkRequest = xhr; - let deferred = Promise.defer(); - - let log = this._log; - let errorhandler = (evt) => { - log.error("httpGetRequest::onError() - Error making request to " + url + ": " + evt.type); - deferred.reject(new Error("Experiments - XHR error for " + url + " - " + evt.type)); - this._networkRequest = null; - }; - xhr.onerror = errorhandler; - xhr.ontimeout = errorhandler; - xhr.onabort = errorhandler; - - xhr.onload = (event) => { - if (xhr.status !== 200 && xhr.state !== 0) { - log.error("httpGetRequest::onLoad() - Request to " + url + " returned status " + xhr.status); - deferred.reject(new Error("Experiments - XHR status for " + url + " is " + xhr.status)); - this._networkRequest = null; - return; - } - - deferred.resolve(xhr.responseText); - this._networkRequest = null; - }; - - try { - xhr.open("GET", url); - - if (xhr.channel instanceof Ci.nsISupportsPriority) { - xhr.channel.priority = Ci.nsISupportsPriority.PRIORITY_LOWEST; - } - - xhr.timeout = MANIFEST_FETCH_TIMEOUT_MSEC; - xhr.send(null); - } catch (e) { - this._log.error("httpGetRequest() - Error opening request to " + url + ": " + e); - return Promise.reject(new Error("Experiments - Error opening XHR for " + url)); - } - return deferred.promise; - }, - - /* - * Path of the cache file we use in the profile. - */ - get _cacheFilePath() { - return OS.Path.join(OS.Constants.Path.profileDir, FILE_CACHE); - }, - - /* - * Part of the main task to save the cache to disk, called from _main. - */ - _saveToCache: function* () { - this._log.trace("_saveToCache"); - let path = this._cacheFilePath; - this._dirty = false; - try { - let textData = JSON.stringify({ - version: CACHE_VERSION, - data: [...this._experiments.values()].map(e => e.toJSON()), - }); - - let encoder = new TextEncoder(); - let data = encoder.encode(textData); - let options = { tmpPath: path + ".tmp", compression: "lz4" }; - yield this._policy.delayCacheWrite(OS.File.writeAtomic(path, data, options)); - } catch (e) { - // We failed to write the cache, it's still dirty. - this._dirty = true; - this._log.error("_saveToCache failed and caught error: " + e); - throw new CacheWriteError(); - } - - this._log.debug("_saveToCache saved to " + path); - }, - - /* - * Task function, load the cached experiments manifest file from disk. - */ - _loadFromCache: Task.async(function* () { - this._log.trace("_loadFromCache"); - let path = this._cacheFilePath; - try { - let result = yield loadJSONAsync(path, { compression: "lz4" }); - this._populateFromCache(result); - } catch (e) { - if (e instanceof OS.File.Error && e.becauseNoSuchFile) { - // No cached manifest yet. - this._experiments = new Map(); - } else { - throw e; - } - } - }), - - _populateFromCache: function (data) { - this._log.trace("populateFromCache() - data: " + JSON.stringify(data)); - - // If the user has a newer cache version than we can understand, we fail - // hard; no experiments should be active in this older client. - if (CACHE_VERSION !== data.version) { - throw new Error("Experiments::_populateFromCache() - invalid cache version"); - } - - let experiments = new Map(); - for (let item of data.data) { - let entry = new Experiments.ExperimentEntry(this._policy); - if (!entry.initFromCacheData(item)) { - continue; - } - - // Discard old experiments if they ended more than 180 days ago. - if (entry.shouldDiscard()) { - // We discarded an experiment, the cache needs to be updated. - this._dirty = true; - continue; - } - - experiments.set(entry.id, entry); - } - - this._experiments = experiments; - }, - - /* - * Update the experiment entries from the experiments - * array in the manifest - */ - _updateExperiments: function (manifestObject) { - this._log.trace("_updateExperiments() - experiments: " + JSON.stringify(manifestObject)); - - if (manifestObject.version !== MANIFEST_VERSION) { - this._log.warning("updateExperiments() - unsupported version " + manifestObject.version); - } - - let experiments = new Map(); // The new experiments map - - // Collect new and updated experiments. - for (let data of manifestObject.experiments) { - let entry = this._experiments.get(data.id); - - if (entry) { - if (!entry.updateFromManifestData(data)) { - this._log.error("updateExperiments() - Invalid manifest data for " + data.id); - continue; - } - } else { - entry = new Experiments.ExperimentEntry(this._policy); - if (!entry.initFromManifestData(data)) { - continue; - } - } - - if (entry.shouldDiscard()) { - continue; - } - - experiments.set(entry.id, entry); - } - - // Make sure we keep experiments that are or were running. - // We remove them after KEEP_HISTORY_N_DAYS. - for (let [id, entry] of this._experiments) { - if (experiments.has(id)) { - continue; - } - - if (!entry.startDate || entry.shouldDiscard()) { - this._log.trace("updateExperiments() - discarding entry for " + id); - continue; - } - - experiments.set(id, entry); - } - - this._experiments = experiments; - this._dirty = true; - }, - - getActiveExperimentID: function() { - if (!this._experiments) { - return null; - } - let e = this._getActiveExperiment(); - if (!e) { - return null; - } - return e.id; - }, - - getActiveExperimentBranch: function() { - if (!this._experiments) { - return null; - } - let e = this._getActiveExperiment(); - if (!e) { - return null; - } - return e.branch; - }, - - _getActiveExperiment: function () { - let enabled = [...this._experiments.values()].filter(experiment => experiment._enabled); - - if (enabled.length == 1) { - return enabled[0]; - } - - if (enabled.length > 1) { - this._log.error("getActiveExperimentId() - should not have more than 1 active experiment"); - throw new Error("have more than 1 active experiment"); - } - - return null; - }, - - /** - * Disables all active experiments. - * - * @return Promise<> Promise that will get resolved once the task is done or failed. - */ - disableExperiment: function (reason) { - if (!reason) { - throw new Error("Must specify a termination reason."); - } - - this._log.trace("disableExperiment()"); - this._terminateReason = reason; - return this._run(); - }, - - /** - * The Set of add-on IDs that we know about from manifests. - */ - get _trackedAddonIds() { - if (!this._experiments) { - return new Set(); - } - - return new Set([...this._experiments.values()].map(e => e._addonId)); - }, - - /* - * Task function to check applicability of experiments, disable the active - * experiment if needed and activate the first applicable candidate. - */ - _evaluateExperiments: function*() { - this._log.trace("_evaluateExperiments"); - - this._checkForShutdown(); - - // The first thing we do is reconcile our state against what's in the - // Addon Manager. It's possible that the Addon Manager knows of experiment - // add-ons that we don't. This could happen if an experiment gets installed - // when we're not listening or if there is a bug in our synchronization - // code. - // - // We have a few options of what to do with unknown experiment add-ons - // coming from the Addon Manager. Ideally, we'd convert these to - // ExperimentEntry instances and stuff them inside this._experiments. - // However, since ExperimentEntry contain lots of metadata from the - // manifest and trying to make up data could be error prone, it's safer - // to not try. Furthermore, if an experiment really did come from us, we - // should have some record of it. In the end, we decide to discard all - // knowledge for these unknown experiment add-ons. - let installedExperiments = yield installedExperimentAddons(); - let expectedAddonIds = this._trackedAddonIds; - let unknownAddons = installedExperiments.filter(a => !expectedAddonIds.has(a.id)); - if (unknownAddons.length) { - this._log.warn("_evaluateExperiments() - unknown add-ons in AddonManager: " + - unknownAddons.map(a => a.id).join(", ")); - - yield uninstallAddons(unknownAddons); - } - - let activeExperiment = this._getActiveExperiment(); - let activeChanged = false; - - if (!activeExperiment) { - // Avoid this pref staying out of sync if there were e.g. crashes. - gPrefs.set(PREF_ACTIVE_EXPERIMENT, false); - } - - // Ensure the active experiment is in the proper state. This may install, - // uninstall, upgrade, or enable the experiment add-on. What exactly is - // abstracted away from us by design. - if (activeExperiment) { - let changes; - let shouldStopResult = yield activeExperiment.shouldStop(); - if (shouldStopResult.shouldStop) { - let expireReasons = ["endTime", "maxActiveSeconds"]; - let kind, reason; - - if (expireReasons.indexOf(shouldStopResult.reason[0]) != -1) { - kind = TELEMETRY_LOG.TERMINATION.EXPIRED; - reason = null; - } else { - kind = TELEMETRY_LOG.TERMINATION.RECHECK; - reason = shouldStopResult.reason; - } - changes = yield activeExperiment.stop(kind, reason); - } - else if (this._terminateReason) { - changes = yield activeExperiment.stop(this._terminateReason); - } - else { - changes = yield activeExperiment.reconcileAddonState(); - } - - if (changes) { - this._dirty = true; - activeChanged = true; - } - - if (!activeExperiment._enabled) { - activeExperiment = null; - activeChanged = true; - } - } - - this._terminateReason = null; - - if (!activeExperiment && gExperimentsEnabled) { - for (let [id, experiment] of this._experiments) { - let applicable; - let reason = null; - try { - applicable = yield experiment.isApplicable(); - } - catch (e) { - applicable = false; - reason = e; - } - - if (!applicable && reason && reason[0] != "was-active") { - // Report this from here to avoid over-reporting. - let data = [TELEMETRY_LOG.ACTIVATION.REJECTED, id]; - data = data.concat(reason); - const key = TELEMETRY_LOG.ACTIVATION_KEY; - TelemetryLog.log(key, data); - this._log.trace("evaluateExperiments() - added " + key + " to TelemetryLog: " + JSON.stringify(data)); - } - - if (!applicable) { - continue; - } - - this._log.debug("evaluateExperiments() - activating experiment " + id); - try { - yield experiment.start(); - activeChanged = true; - activeExperiment = experiment; - this._dirty = true; - break; - } catch (e) { - // On failure, clean up the best we can and try the next experiment. - this._log.error("evaluateExperiments() - Unable to start experiment: " + e.message); - experiment._enabled = false; - yield experiment.reconcileAddonState(); - } - } - } - - gPrefs.set(PREF_ACTIVE_EXPERIMENT, activeExperiment != null); - - if (activeChanged || this._firstEvaluate) { - Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC, null); - this._firstEvaluate = false; - } - - if ("@mozilla.org/toolkit/crash-reporter;1" in Cc && activeExperiment) { - try { - gCrashReporter.annotateCrashReport("ActiveExperiment", activeExperiment.id); - gCrashReporter.annotateCrashReport("ActiveExperimentBranch", activeExperiment.branch); - } catch (e) { - // It's ok if crash reporting is disabled. - } - } - }, - - /* - * Schedule the soonest re-check of experiment applicability that is needed. - */ - _scheduleNextRun: function () { - this._checkForShutdown(); - - if (this._timer) { - this._timer.clear(); - } - - if (!gExperimentsEnabled || this._experiments.length == 0) { - return; - } - - let time = null; - let now = this._policy.now().getTime(); - if (this._dirty) { - // If we failed to write the cache, we should try again periodically - time = now + 1000 * CACHE_WRITE_RETRY_DELAY_SEC; - } - - for (let [, experiment] of this._experiments) { - let scheduleTime = experiment.getScheduleTime(); - if (scheduleTime > now) { - if (time !== null) { - time = Math.min(time, scheduleTime); - } else { - time = scheduleTime; - } - } - } - - if (time === null) { - // No schedule time found. - return; - } - - this._log.trace("scheduleExperimentEvaluation() - scheduling for "+time+", now: "+now); - this._policy.oneshotTimer(this.notify, time - now, this, "_timer"); - }, -}; - - -/* - * Represents a single experiment. - */ - -Experiments.ExperimentEntry = function (policy) { - this._policy = policy || new Experiments.Policy(); - let log = Log.repository.getLoggerWithMessagePrefix( - "Browser.Experiments.Experiments", - "ExperimentEntry #" + gExperimentEntryCounter++ + "::"); - this._log = Object.create(log); - this._log.log = (level, string, params) => { - if (gExperiments) { - gExperiments._addToForensicsLog("ExperimentEntry", string); - } - log.log(level, string, params); - }; - - // Is the experiment supposed to be running. - this._enabled = false; - // When this experiment was started, if ever. - this._startDate = null; - // When this experiment was ended, if ever. - this._endDate = null; - // The condition data from the manifest. - this._manifestData = null; - // For an active experiment, signifies whether we need to update the xpi. - this._needsUpdate = false; - // A random sample value for comparison against the manifest conditions. - this._randomValue = null; - // When this entry was last changed for respecting history retention duration. - this._lastChangedDate = null; - // Has this experiment failed to activate before? - this._failedStart = false; - // The experiment branch - this._branch = null; - - // We grab these from the addon after download. - this._name = null; - this._description = null; - this._homepageURL = null; - this._addonId = null; -}; - -Experiments.ExperimentEntry.prototype = { - MANIFEST_REQUIRED_FIELDS: new Set([ - "id", - "xpiURL", - "xpiHash", - "startTime", - "endTime", - "maxActiveSeconds", - "appName", - "channel", - ]), - - MANIFEST_OPTIONAL_FIELDS: new Set([ - "maxStartTime", - "minVersion", - "maxVersion", - "version", - "minBuildID", - "maxBuildID", - "buildIDs", - "os", - "locale", - "sample", - "disabled", - "frozen", - "jsfilter", - ]), - - SERIALIZE_KEYS: new Set([ - "_enabled", - "_manifestData", - "_needsUpdate", - "_randomValue", - "_failedStart", - "_name", - "_description", - "_homepageURL", - "_addonId", - "_startDate", - "_endDate", - "_branch", - ]), - - DATE_KEYS: new Set([ - "_startDate", - "_endDate", - ]), - - UPGRADE_KEYS: new Map([ - ["_branch", null], - ]), - - ADDON_CHANGE_NONE: 0, - ADDON_CHANGE_INSTALL: 1, - ADDON_CHANGE_UNINSTALL: 2, - ADDON_CHANGE_ENABLE: 4, - - /* - * Initialize entry from the manifest. - * @param data The experiment data from the manifest. - * @return boolean Whether initialization succeeded. - */ - initFromManifestData: function (data) { - if (!this._isManifestDataValid(data)) { - return false; - } - - this._manifestData = data; - - this._randomValue = this._policy.random(); - this._lastChangedDate = this._policy.now(); - - return true; - }, - - get enabled() { - return this._enabled; - }, - - get id() { - return this._manifestData.id; - }, - - get branch() { - return this._branch; - }, - - set branch(v) { - this._branch = v; - }, - - get startDate() { - return this._startDate; - }, - - get endDate() { - if (!this._startDate) { - return null; - } - - let endTime = 0; - - if (!this._enabled) { - return this._endDate; - } - - let maxActiveMs = 1000 * this._manifestData.maxActiveSeconds; - endTime = Math.min(1000 * this._manifestData.endTime, - this._startDate.getTime() + maxActiveMs); - - return new Date(endTime); - }, - - get needsUpdate() { - return this._needsUpdate; - }, - - /* - * Initialize entry from the cache. - * @param data The entry data from the cache. - * @return boolean Whether initialization succeeded. - */ - initFromCacheData: function (data) { - for (let [key, dval] of this.UPGRADE_KEYS) { - if (!(key in data)) { - data[key] = dval; - } - } - - for (let key of this.SERIALIZE_KEYS) { - if (!(key in data) && !this.DATE_KEYS.has(key)) { - this._log.error("initFromCacheData() - missing required key " + key); - return false; - } - } - - if (!this._isManifestDataValid(data._manifestData)) { - return false; - } - - // Dates are restored separately from epoch ms, everything else is just - // copied in. - - this.SERIALIZE_KEYS.forEach(key => { - if (!this.DATE_KEYS.has(key)) { - this[key] = data[key]; - } - }); - - this.DATE_KEYS.forEach(key => { - if (key in data) { - let date = new Date(); - date.setTime(data[key]); - this[key] = date; - } - }); - - // In order for the experiment's data expiration mechanism to work, use the experiment's - // |_endData| as the |_lastChangedDate| (if available). - this._lastChangedDate = this._endDate ? this._endDate : this._policy.now(); - - return true; - }, - - /* - * Returns a JSON representation of this object. - */ - toJSON: function () { - let obj = {}; - - // Dates are serialized separately as epoch ms. - - this.SERIALIZE_KEYS.forEach(key => { - if (!this.DATE_KEYS.has(key)) { - obj[key] = this[key]; - } - }); - - this.DATE_KEYS.forEach(key => { - if (this[key]) { - obj[key] = this[key].getTime(); - } - }); - - return obj; - }, - - /* - * Update from the experiment data from the manifest. - * @param data The experiment data from the manifest. - * @return boolean Whether updating succeeded. - */ - updateFromManifestData: function (data) { - let old = this._manifestData; - - if (!this._isManifestDataValid(data)) { - return false; - } - - if (this._enabled) { - if (old.xpiHash !== data.xpiHash) { - // A changed hash means we need to update active experiments. - this._needsUpdate = true; - } - } else if (this._failedStart && - (old.xpiHash !== data.xpiHash) || - (old.xpiURL !== data.xpiURL)) { - // Retry installation of previously invalid experiments - // if hash or url changed. - this._failedStart = false; - } - - this._manifestData = data; - this._lastChangedDate = this._policy.now(); - - return true; - }, - - /* - * Is this experiment applicable? - * @return Promise<> Resolved if the experiment is applicable. - * If it is not applicable it is rejected with - * a Promise<string> which contains the reason. - */ - isApplicable: function () { - let versionCmp = Cc["@mozilla.org/xpcom/version-comparator;1"] - .getService(Ci.nsIVersionComparator); - let app = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo); - let runtime = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsIXULRuntime); - - let locale = this._policy.locale(); - let channel = this._policy.updatechannel(); - let data = this._manifestData; - - let now = this._policy.now() / 1000; // The manifest times are in seconds. - let maxActive = data.maxActiveSeconds || 0; - let startSec = (this.startDate || 0) / 1000; - - this._log.trace("isApplicable() - now=" + now - + ", randomValue=" + this._randomValue); - - // Not applicable if it already ran. - - if (!this.enabled && this._endDate) { - return Promise.reject(["was-active"]); - } - - // Define and run the condition checks. - - let simpleChecks = [ - { name: "failedStart", - condition: () => !this._failedStart }, - { name: "disabled", - condition: () => !data.disabled }, - { name: "frozen", - condition: () => !data.frozen || this._enabled }, - { name: "startTime", - condition: () => now >= data.startTime }, - { name: "endTime", - condition: () => now < data.endTime }, - { name: "maxStartTime", - condition: () => this._startDate || !data.maxStartTime || now <= data.maxStartTime }, - { name: "maxActiveSeconds", - condition: () => !this._startDate || now <= (startSec + maxActive) }, - { name: "appName", - condition: () => !data.appName || data.appName.indexOf(app.name) != -1 }, - { name: "minBuildID", - condition: () => !data.minBuildID || app.platformBuildID >= data.minBuildID }, - { name: "maxBuildID", - condition: () => !data.maxBuildID || app.platformBuildID <= data.maxBuildID }, - { name: "buildIDs", - condition: () => !data.buildIDs || data.buildIDs.indexOf(app.platformBuildID) != -1 }, - { name: "os", - condition: () => !data.os || data.os.indexOf(runtime.OS) != -1 }, - { name: "channel", - condition: () => !data.channel || data.channel.indexOf(channel) != -1 }, - { name: "locale", - condition: () => !data.locale || data.locale.indexOf(locale) != -1 }, - { name: "sample", - condition: () => data.sample === undefined || this._randomValue <= data.sample }, - { name: "version", - condition: () => !data.version || data.version.indexOf(app.version) != -1 }, - { name: "minVersion", - condition: () => !data.minVersion || versionCmp.compare(app.version, data.minVersion) >= 0 }, - { name: "maxVersion", - condition: () => !data.maxVersion || versionCmp.compare(app.version, data.maxVersion) <= 0 }, - ]; - - for (let check of simpleChecks) { - let result = check.condition(); - if (!result) { - this._log.debug("isApplicable() - id=" - + data.id + " - test '" + check.name + "' failed"); - return Promise.reject([check.name]); - } - } - - if (data.jsfilter) { - return this._runFilterFunction(data.jsfilter); - } - - return Promise.resolve(true); - }, - - /* - * Run the jsfilter function from the manifest in a sandbox and return the - * result (forced to boolean). - */ - _runFilterFunction: Task.async(function* (jsfilter) { - this._log.trace("runFilterFunction() - filter: " + jsfilter); - - let ssm = Services.scriptSecurityManager; - const nullPrincipal = ssm.createNullPrincipal({}); - let options = { - sandboxName: "telemetry experiments jsfilter sandbox", - wantComponents: false, - }; - - let sandbox = Cu.Sandbox(nullPrincipal, options); - try { - Cu.evalInSandbox(jsfilter, sandbox); - } catch (e) { - this._log.error("runFilterFunction() - failed to eval jsfilter: " + e.message); - throw ["jsfilter-evalfailed"]; - } - - let currentEnvironment = yield TelemetryEnvironment.onInitialized(); - - Object.defineProperty(sandbox, "_e", - { get: () => Cu.cloneInto(currentEnvironment, sandbox) }); - - let result = false; - try { - result = !!Cu.evalInSandbox("filter({get telemetryEnvironment() { return _e; } })", sandbox); - } - catch (e) { - this._log.debug("runFilterFunction() - filter function failed: " - + e.message + ", " + e.stack); - throw ["jsfilter-threw", e.message]; - } - finally { - Cu.nukeSandbox(sandbox); - } - - if (!result) { - throw ["jsfilter-false"]; - } - - return true; - }), - - /* - * Start running the experiment. - * - * @return Promise<> Resolved when the operation is complete. - */ - start: Task.async(function* () { - this._log.trace("start() for " + this.id); - - this._enabled = true; - return yield this.reconcileAddonState(); - }), - - // Async install of the addon for this experiment, part of the start task above. - _installAddon: Task.async(function* () { - let deferred = Promise.defer(); - - let hash = this._policy.ignoreHashes ? null : this._manifestData.xpiHash; - - let install = yield addonInstallForURL(this._manifestData.xpiURL, hash); - gActiveInstallURLs.add(install.sourceURI.spec); - - let failureHandler = (install, handler) => { - let message = "AddonInstall " + handler + " for " + this.id + ", state=" + - (install.state || "?") + ", error=" + install.error; - this._log.error("_installAddon() - " + message); - this._failedStart = true; - gActiveInstallURLs.delete(install.sourceURI.spec); - - TelemetryLog.log(TELEMETRY_LOG.ACTIVATION_KEY, - [TELEMETRY_LOG.ACTIVATION.INSTALL_FAILURE, this.id]); - - deferred.reject(new Error(message)); - }; - - let listener = { - _expectedID: null, - - onDownloadEnded: install => { - this._log.trace("_installAddon() - onDownloadEnded for " + this.id); - - if (install.existingAddon) { - this._log.warn("_installAddon() - onDownloadEnded, addon already installed"); - } - - if (install.addon.type !== "experiment") { - this._log.error("_installAddon() - onDownloadEnded, wrong addon type"); - install.cancel(); - } - }, - - onInstallStarted: install => { - this._log.trace("_installAddon() - onInstallStarted for " + this.id); - - if (install.existingAddon) { - this._log.warn("_installAddon() - onInstallStarted, addon already installed"); - } - - if (install.addon.type !== "experiment") { - this._log.error("_installAddon() - onInstallStarted, wrong addon type"); - return false; - } - return undefined; - }, - - onInstallEnded: install => { - this._log.trace("_installAddon() - install ended for " + this.id); - gActiveInstallURLs.delete(install.sourceURI.spec); - - this._lastChangedDate = this._policy.now(); - this._startDate = this._policy.now(); - this._enabled = true; - - TelemetryLog.log(TELEMETRY_LOG.ACTIVATION_KEY, - [TELEMETRY_LOG.ACTIVATION.ACTIVATED, this.id]); - - let addon = install.addon; - this._name = addon.name; - this._addonId = addon.id; - this._description = addon.description || ""; - this._homepageURL = addon.homepageURL || ""; - - // Experiment add-ons default to userDisabled=true. Enable if needed. - if (addon.userDisabled) { - this._log.trace("Add-on is disabled. Enabling."); - listener._expectedID = addon.id; - AddonManager.addAddonListener(listener); - addon.userDisabled = false; - } else { - this._log.trace("Add-on is enabled. start() completed."); - deferred.resolve(); - } - }, - - onEnabled: addon => { - this._log.info("onEnabled() for " + addon.id); - - if (addon.id != listener._expectedID) { - return; - } - - AddonManager.removeAddonListener(listener); - deferred.resolve(); - }, - }; - - ["onDownloadCancelled", "onDownloadFailed", "onInstallCancelled", "onInstallFailed"] - .forEach(what => { - listener[what] = install => failureHandler(install, what) - }); - - install.addListener(listener); - install.install(); - - return yield deferred.promise; - }), - - /** - * Stop running the experiment if it is active. - * - * @param terminationKind (optional) - * The termination kind, e.g. ADDON_UNINSTALLED or EXPIRED. - * @param terminationReason (optional) - * The termination reason details for termination kind RECHECK. - * @return Promise<> Resolved when the operation is complete. - */ - stop: Task.async(function* (terminationKind, terminationReason) { - this._log.trace("stop() - id=" + this.id + ", terminationKind=" + terminationKind); - if (!this._enabled) { - throw new Error("Must not call stop() on an inactive experiment."); - } - - this._enabled = false; - let now = this._policy.now(); - this._lastChangedDate = now; - this._endDate = now; - - let changes = yield this.reconcileAddonState(); - this._logTermination(terminationKind, terminationReason); - - if (terminationKind == TELEMETRY_LOG.TERMINATION.ADDON_UNINSTALLED) { - changes |= this.ADDON_CHANGE_UNINSTALL; - } - - return changes; - }), - - /** - * Reconcile the state of the add-on against what it's supposed to be. - * - * If we are active, ensure the add-on is enabled and up to date. - * - * If we are inactive, ensure the add-on is not installed. - */ - reconcileAddonState: Task.async(function* () { - this._log.trace("reconcileAddonState()"); - - if (!this._enabled) { - if (!this._addonId) { - this._log.trace("reconcileAddonState() - Experiment is not enabled and " + - "has no add-on. Doing nothing."); - return this.ADDON_CHANGE_NONE; - } - - let addon = yield this._getAddon(); - if (!addon) { - this._log.trace("reconcileAddonState() - Inactive experiment has no " + - "add-on. Doing nothing."); - return this.ADDON_CHANGE_NONE; - } - - this._log.info("reconcileAddonState() - Uninstalling add-on for inactive " + - "experiment: " + addon.id); - gActiveUninstallAddonIDs.add(addon.id); - yield uninstallAddons([addon]); - gActiveUninstallAddonIDs.delete(addon.id); - return this.ADDON_CHANGE_UNINSTALL; - } - - // If we get here, we're supposed to be active. - - let changes = 0; - - // That requires an add-on. - let currentAddon = yield this._getAddon(); - - // If we have an add-on but it isn't up to date, uninstall it - // (to prepare for reinstall). - if (currentAddon && this._needsUpdate) { - this._log.info("reconcileAddonState() - Uninstalling add-on because update " + - "needed: " + currentAddon.id); - gActiveUninstallAddonIDs.add(currentAddon.id); - yield uninstallAddons([currentAddon]); - gActiveUninstallAddonIDs.delete(currentAddon.id); - changes |= this.ADDON_CHANGE_UNINSTALL; - } - - if (!currentAddon || this._needsUpdate) { - this._log.info("reconcileAddonState() - Installing add-on."); - yield this._installAddon(); - changes |= this.ADDON_CHANGE_INSTALL; - } - - let addon = yield this._getAddon(); - if (!addon) { - throw new Error("Could not obtain add-on for experiment that should be " + - "enabled."); - } - - // If we have the add-on and it is enabled, we are done. - if (!addon.userDisabled) { - return changes; - } - - // Check permissions to see if we can enable the addon. - if (!(addon.permissions & AddonManager.PERM_CAN_ENABLE)) { - throw new Error("Don't have permission to enable addon " + addon.id + ", perm=" + addon.permission); - } - - // Experiment addons should not require a restart. - if (addon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE) { - throw new Error("Experiment addon requires a restart: " + addon.id); - } - - let deferred = Promise.defer(); - - // Else we need to enable it. - let listener = { - onEnabled: enabledAddon => { - if (enabledAddon.id != addon.id) { - return; - } - - AddonManager.removeAddonListener(listener); - deferred.resolve(); - }, - }; - - for (let handler of ["onDisabled", "onOperationCancelled", "onUninstalled"]) { - listener[handler] = (evtAddon) => { - if (evtAddon.id != addon.id) { - return; - } - - AddonManager.removeAddonListener(listener); - deferred.reject("Failed to enable addon " + addon.id + " due to: " + handler); - }; - } - - this._log.info("reconcileAddonState() - Activating add-on: " + addon.id); - AddonManager.addAddonListener(listener); - addon.userDisabled = false; - yield deferred.promise; - changes |= this.ADDON_CHANGE_ENABLE; - - this._log.info("reconcileAddonState() - Add-on has been enabled: " + addon.id); - return changes; - }), - - /** - * Obtain the underlying Addon from the Addon Manager. - * - * @return Promise<Addon|null> - */ - _getAddon: function () { - if (!this._addonId) { - return Promise.resolve(null); - } - - let deferred = Promise.defer(); - - AddonManager.getAddonByID(this._addonId, (addon) => { - if (addon && addon.appDisabled) { - // Don't return PreviousExperiments. - addon = null; - } - - deferred.resolve(addon); - }); - - return deferred.promise; - }, - - _logTermination: function (terminationKind, terminationReason) { - if (terminationKind === undefined) { - return; - } - - if (!(terminationKind in TELEMETRY_LOG.TERMINATION)) { - this._log.warn("stop() - unknown terminationKind " + terminationKind); - return; - } - - let data = [terminationKind, this.id]; - if (terminationReason) { - data = data.concat(terminationReason); - } - - TelemetryLog.log(TELEMETRY_LOG.TERMINATION_KEY, data); - }, - - /** - * Determine whether an active experiment should be stopped. - */ - shouldStop: function () { - if (!this._enabled) { - throw new Error("shouldStop must not be called on disabled experiments."); - } - - let deferred = Promise.defer(); - this.isApplicable().then( - () => deferred.resolve({shouldStop: false}), - reason => deferred.resolve({shouldStop: true, reason: reason}) - ); - - return deferred.promise; - }, - - /* - * Should this be discarded from the cache due to age? - */ - shouldDiscard: function () { - let limit = this._policy.now(); - limit.setDate(limit.getDate() - KEEP_HISTORY_N_DAYS); - return (this._lastChangedDate < limit); - }, - - /* - * Get next date (in epoch-ms) to schedule a re-evaluation for this. - * Returns 0 if it doesn't need one. - */ - getScheduleTime: function () { - if (this._enabled) { - let startTime = this._startDate.getTime(); - let maxActiveTime = startTime + 1000 * this._manifestData.maxActiveSeconds; - return Math.min(1000 * this._manifestData.endTime, maxActiveTime); - } - - if (this._endDate) { - return this._endDate.getTime(); - } - - return 1000 * this._manifestData.startTime; - }, - - /* - * Perform sanity checks on the experiment data. - */ - _isManifestDataValid: function (data) { - this._log.trace("isManifestDataValid() - data: " + JSON.stringify(data)); - - for (let key of this.MANIFEST_REQUIRED_FIELDS) { - if (!(key in data)) { - this._log.error("isManifestDataValid() - missing required key: " + key); - return false; - } - } - - for (let key in data) { - if (!this.MANIFEST_OPTIONAL_FIELDS.has(key) && - !this.MANIFEST_REQUIRED_FIELDS.has(key)) { - this._log.error("isManifestDataValid() - unknown key: " + key); - return false; - } - } - - return true; - }, -}; - -/** - * Strip a Date down to its UTC midnight. - * - * This will return a cloned Date object. The original is unchanged. - */ -var stripDateToMidnight = function (d) { - let m = new Date(d); - m.setUTCHours(0, 0, 0, 0); - - return m; -}; - -/** - * An Add-ons Manager provider that knows about old experiments. - * - * This provider exposes read-only add-ons corresponding to previously-active - * experiments. The existence of this provider (and the add-ons it knows about) - * facilitates the display of old experiments in the Add-ons Manager UI with - * very little custom code in that component. - */ -this.Experiments.PreviousExperimentProvider = function (experiments) { - this._experiments = experiments; - this._experimentList = []; - this._log = Log.repository.getLoggerWithMessagePrefix( - "Browser.Experiments.Experiments", - "PreviousExperimentProvider #" + gPreviousProviderCounter++ + "::"); -} - -this.Experiments.PreviousExperimentProvider.prototype = Object.freeze({ - name: "PreviousExperimentProvider", - - startup: function () { - this._log.trace("startup()"); - Services.obs.addObserver(this, EXPERIMENTS_CHANGED_TOPIC, false); - }, - - shutdown: function () { - this._log.trace("shutdown()"); - try { - Services.obs.removeObserver(this, EXPERIMENTS_CHANGED_TOPIC); - } catch (e) { - // Prevent crash in mochitest-browser3 on Mulet - } - }, - - observe: function (subject, topic, data) { - switch (topic) { - case EXPERIMENTS_CHANGED_TOPIC: - this._updateExperimentList(); - break; - } - }, - - getAddonByID: function (id, cb) { - for (let experiment of this._experimentList) { - if (experiment.id == id) { - cb(new PreviousExperimentAddon(experiment)); - return; - } - } - - cb(null); - }, - - getAddonsByTypes: function (types, cb) { - if (types && types.length > 0 && types.indexOf("experiment") == -1) { - cb([]); - return; - } - - cb(this._experimentList.map(e => new PreviousExperimentAddon(e))); - }, - - _updateExperimentList: function () { - return this._experiments.getExperiments().then((experiments) => { - let list = experiments.filter(e => !e.active); - - let newMap = new Map(list.map(e => [e.id, e])); - let oldMap = new Map(this._experimentList.map(e => [e.id, e])); - - let added = [...newMap.keys()].filter(id => !oldMap.has(id)); - let removed = [...oldMap.keys()].filter(id => !newMap.has(id)); - - for (let id of added) { - this._log.trace("updateExperimentList() - adding " + id); - let wrapper = new PreviousExperimentAddon(newMap.get(id)); - AddonManagerPrivate.callInstallListeners("onExternalInstall", null, wrapper, null, false); - AddonManagerPrivate.callAddonListeners("onInstalling", wrapper, false); - } - - for (let id of removed) { - this._log.trace("updateExperimentList() - removing " + id); - let wrapper = new PreviousExperimentAddon(oldMap.get(id)); - AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper, false); - } - - this._experimentList = list; - - for (let id of added) { - let wrapper = new PreviousExperimentAddon(newMap.get(id)); - AddonManagerPrivate.callAddonListeners("onInstalled", wrapper); - } - - for (let id of removed) { - let wrapper = new PreviousExperimentAddon(oldMap.get(id)); - AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper); - } - - return this._experimentList; - }); - }, -}); - -/** - * An add-on that represents a previously-installed experiment. - */ -function PreviousExperimentAddon(experiment) { - this._id = experiment.id; - this._name = experiment.name; - this._endDate = experiment.endDate; - this._description = experiment.description; -} - -PreviousExperimentAddon.prototype = Object.freeze({ - // BEGIN REQUIRED ADDON PROPERTIES - - get appDisabled() { - return true; - }, - - get blocklistState() { - Ci.nsIBlocklistService.STATE_NOT_BLOCKED - }, - - get creator() { - return new AddonManagerPrivate.AddonAuthor(""); - }, - - get foreignInstall() { - return false; - }, - - get id() { - return this._id; - }, - - get isActive() { - return false; - }, - - get isCompatible() { - return true; - }, - - get isPlatformCompatible() { - return true; - }, - - get name() { - return this._name; - }, - - get pendingOperations() { - return AddonManager.PENDING_NONE; - }, - - get permissions() { - return 0; - }, - - get providesUpdatesSecurely() { - return true; - }, - - get scope() { - return AddonManager.SCOPE_PROFILE; - }, - - get type() { - return "experiment"; - }, - - get userDisabled() { - return true; - }, - - get version() { - return null; - }, - - // END REQUIRED PROPERTIES - - // BEGIN OPTIONAL PROPERTIES - - get description() { - return this._description; - }, - - get updateDate() { - return new Date(this._endDate); - }, - - // END OPTIONAL PROPERTIES - - // BEGIN REQUIRED METHODS - - isCompatibleWith: function (appVersion, platformVersion) { - return true; - }, - - findUpdates: function (listener, reason, appVersion, platformVersion) { - AddonManagerPrivate.callNoUpdateListeners(this, listener, reason, - appVersion, platformVersion); - }, - - // END REQUIRED METHODS - - /** - * The end-date of the experiment, required for the Addon Manager UI. - */ - - get endDate() { - return this._endDate; - }, - -}); diff --git a/browser/experiments/Experiments.manifest b/browser/experiments/Experiments.manifest deleted file mode 100644 index 4a6a05a60..000000000 --- a/browser/experiments/Experiments.manifest +++ /dev/null @@ -1,6 +0,0 @@ -component {f7800463-3b97-47f9-9341-b7617e6d8d49} ExperimentsService.js -contract @mozilla.org/browser/experiments-service;1 {f7800463-3b97-47f9-9341-b7617e6d8d49} -category update-timer ExperimentsService @mozilla.org/browser/experiments-service;1,getService,experiments-update-timer,experiments.manifest.fetchIntervalSeconds,86400 -category profile-after-change ExperimentsService @mozilla.org/browser/experiments-service;1 - - diff --git a/browser/experiments/ExperimentsService.js b/browser/experiments/ExperimentsService.js deleted file mode 100644 index 53e811251..000000000 --- a/browser/experiments/ExperimentsService.js +++ /dev/null @@ -1,118 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Preferences.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Experiments", - "resource:///modules/experiments/Experiments.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "OS", - "resource://gre/modules/osfile.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils", - "resource://services-common/utils.js"); - -const PREF_EXPERIMENTS_ENABLED = "experiments.enabled"; -const PREF_ACTIVE_EXPERIMENT = "experiments.activeExperiment"; // whether we have an active experiment -const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled"; -const PREF_TELEMETRY_UNIFIED = "toolkit.telemetry.unified"; -const DELAY_INIT_MS = 30 * 1000; - -// Whether the FHR/Telemetry unification features are enabled. -// Changing this pref requires a restart. -const IS_UNIFIED_TELEMETRY = Preferences.get(PREF_TELEMETRY_UNIFIED, false); - -XPCOMUtils.defineLazyGetter( - this, "gPrefs", () => { - return new Preferences(); - }); - -XPCOMUtils.defineLazyGetter( - this, "gExperimentsEnabled", () => { - // We can enable experiments if either unified Telemetry or FHR is on, and the user - // has opted into Telemetry. - return gPrefs.get(PREF_EXPERIMENTS_ENABLED, false) && - IS_UNIFIED_TELEMETRY && gPrefs.get(PREF_TELEMETRY_ENABLED, false); - }); - -XPCOMUtils.defineLazyGetter( - this, "gActiveExperiment", () => { - return gPrefs.get(PREF_ACTIVE_EXPERIMENT); - }); - -function ExperimentsService() { - this._initialized = false; - this._delayedInitTimer = null; -} - -ExperimentsService.prototype = { - classID: Components.ID("{f7800463-3b97-47f9-9341-b7617e6d8d49}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback, Ci.nsIObserver]), - - notify: function (timer) { - if (!gExperimentsEnabled) { - return; - } - if (OS.Constants.Path.profileDir === undefined) { - throw Error("Update timer fired before profile was initialized?"); - } - let instance = Experiments.instance(); - if (instance.isReady) { - instance.updateManifest(); - } - }, - - _delayedInit: function () { - if (!this._initialized) { - this._initialized = true; - Experiments.instance(); // for side effects - } - }, - - observe: function (subject, topic, data) { - switch (topic) { - case "profile-after-change": - if (gExperimentsEnabled) { - Services.obs.addObserver(this, "quit-application", false); - Services.obs.addObserver(this, "sessionstore-state-finalized", false); - Services.obs.addObserver(this, "EM-loaded", false); - - if (gActiveExperiment) { - this._initialized = true; - Experiments.instance(); // for side effects - } - } - break; - case "sessionstore-state-finalized": - if (!this._initialized) { - CommonUtils.namedTimer(this._delayedInit, DELAY_INIT_MS, this, "_delayedInitTimer"); - } - break; - case "EM-loaded": - if (!this._initialized) { - Experiments.instance(); // for side effects - this._initialized = true; - - if (this._delayedInitTimer) { - this._delayedInitTimer.clear(); - } - } - break; - case "quit-application": - Services.obs.removeObserver(this, "quit-application"); - Services.obs.removeObserver(this, "sessionstore-state-finalized"); - Services.obs.removeObserver(this, "EM-loaded"); - if (this._delayedInitTimer) { - this._delayedInitTimer.clear(); - } - break; - } - }, -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ExperimentsService]); diff --git a/browser/experiments/Makefile.in b/browser/experiments/Makefile.in deleted file mode 100644 index 5558582a6..000000000 --- a/browser/experiments/Makefile.in +++ /dev/null @@ -1,16 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -include $(topsrcdir)/config/rules.mk - -# This is so hacky. Waiting on bug 988938. -addondir = $(srcdir)/test/addons -testdir = $(topobjdir)/_tests/xpcshell/browser/experiments/test/xpcshell - -misc:: $(call mkdir_deps,$(testdir)) - $(EXIT_ON_ERROR) \ - for dir in $(addondir)/*; do \ - base=`basename $$dir`; \ - (cd $$dir && zip -qr $(testdir)/$$base.xpi *); \ - done diff --git a/browser/experiments/docs/index.rst b/browser/experiments/docs/index.rst deleted file mode 100644 index 11e5d4faa..000000000 --- a/browser/experiments/docs/index.rst +++ /dev/null @@ -1,13 +0,0 @@ -===================== -Telemetry Experiments -===================== - -Telemetry Experiments is a feature of Firefox that allows the installation -of add-ons called experiments to a subset of the Firefox population for -the purposes of experimenting with changes and collecting data on specific -aspects of application usage. - -.. toctree:: - :maxdepth: 1 - - manifest diff --git a/browser/experiments/docs/manifest.rst b/browser/experiments/docs/manifest.rst deleted file mode 100644 index d4fad5243..000000000 --- a/browser/experiments/docs/manifest.rst +++ /dev/null @@ -1,429 +0,0 @@ -.. _experiments_manifests: - -===================== -Experiments Manifests -===================== - -*Experiments Manifests* are documents that describe the set of active -experiments a client may run. - -*Experiments Manifests* are fetched periodically by clients. When -fetched, clients look at the experiments within the manifest and -determine which experiments are applicable. If an experiment is -applicable, the client may download and start the experiment. - -Manifest Format -=============== - -Manifests are JSON documents where the main element is an object. - -The *schema* of the object is versioned and defined by the presence -of a top-level ``version`` property, whose integer value is the -schema version used by that manifest. Each version is documented -in the sections below. - -Version 1 ---------- - -Version 1 is the original manifest format. - -The following properties may exist in the root object: - -experiments - An array of objects describing candidate experiments. The format of - these objects is documented below. - - An array is used to create an explicit priority of experiments. - Experiments listed at the beginning of the array take priority over - experiments that follow. - -Experiments Objects -^^^^^^^^^^^^^^^^^^^ - -Each object in the ``experiments`` array may contain the following -properties: - -id - (required) String identifier of this experiment. The identifier should - be treated as opaque by clients. It is used to uniquely identify an - experiment for all of time. - -xpiURL - (required) String URL of the XPI that implements this experiment. - - If the experiment is activated, the client will download and install this - XPI. - -xpiHash - (required) String hash of the XPI that implements this experiment. - - The value is composed of a hash identifier followed by a colon - followed by the hash value. e.g. - `sha1:f677428b9172e22e9911039aef03f3736e7f78a7`. `sha1` and `sha256` - are the two supported hashing mechanisms. The hash value is the hex - encoding of the binary hash. - - When the client downloads the XPI for the experiment, it should compare - the hash of that XPI against this value. If the hashes don't match, - the client should not install the XPI. - - Clients may also use this hash as a means of determining when an - experiment's XPI has changed and should be refreshed. - -startTime - Integer seconds since UNIX epoch that this experiment should - start. Clients should not start an experiment if *now()* is less than - this value. - -maxStartTime - (optional) Integer seconds since UNIX epoch after which this experiment - should no longer start. - - Some experiments may wish to impose hard deadlines after which no new - clients should activate the experiment. This property may be used to - facilitate that. - -endTime - Integer seconds since UNIX epoch after which this experiment - should no longer run. Clients should cease an experiment when the current - time is beyond this value. - -maxActiveSeconds - Integer seconds defining the max wall time this experiment should be - active for. - - The client should deactivate the experiment this many seconds after - initial activation. - - This value only involves wall time, not browser activity or session time. - -appName - Array of application names this experiment should run on. - - An application name comes from ``nsIXULAppInfo.name``. It is a value - like ``Firefox``, ``Fennec``, or `B2G`. - - The client should compare its application name against the members of - this array. If a match is found, the experiment is applicable. - -minVersion - (optional) String version number of the minimum application version this - experiment should run on. - - A version number is something like ``27.0.0`` or ``28``. - - The client should compare its version number to this value. If the client's - version is greater or equal to this version (using a version-aware comparison - function), the experiment is applicable. - - If this is not specified, there is no lower bound to versions this - experiment should run on. - -maxVersion - (optional) String version number of the maximum application version this - experiment should run on. - - This is similar to ``minVersion`` except it sets the upper bound for - application versions. - - If the client's version is less than or equal to this version, the - experiment is applicable. - - If this is not specified, there is no upper bound to versions this - experiment should run on. - -version - (optional) Array of application versions this experiment should run on. - - This is similar to ``minVersion`` and ``maxVersion`` except only a - whitelisted set of specific versions are allowed. - - The client should compare its version to members of this array. If a match - is found, the experiment is applicable. - -minBuildID - (optional) String minimum Build ID this experiment should run on. - - Build IDs are values like ``201402261424``. - - The client should perform a string comparison of its Build ID against this - value. If its value is greater than or equal to this value, the experiment - is applicable. - -maxBuildID - (optional) String maximum Build ID this experiment should run on. - - This is similar to ``minBuildID`` except it sets the upper bound - for Build IDs. - - The client should perform a string comparison of its Build ID against - this value. If its value is less than or equal to this value, the - experiment is applicable. - -buildIDs - (optional) Array of Build IDs this experiment should run on. - - This is similar to ``minBuildID`` and ``maxBuildID`` except only a - whitelisted set of Build IDs are considered. - - The client should compare its Build ID to members of this array. If a - match is found, the experiment is applicable. - -os - (optional) Array of operating system identifiers this experiment should - run on. - - Values for this array come from ``nsIXULRuntime.OS``. - - The client will compare its operating system identifier to members - of this array. If a match is found, the experiment is applicable to the - client. - -channel - (optional) Array of release channel identifiers this experiment should run - on. - - The client will compare its channel to members of this array. If a match - is found, the experiment is applicable. - - If this property is not defined, the client should assume the experiment - is to run on all channels. - -locale - (optional) Array of locale identifiers this experiment should run on. - - A locale identifier is a string like ``en-US`` or ``zh-CN`` and is - obtained by looking at - ``nsIXULChromeRegistry.getSelectedLocale("global")``. - - The client should compare its locale identifier to members of this array. - If a match is found, the experiment is applicable. - - If this property is not defined, the client should assume the experiment - is to run on all locales. - -sample - (optional) Decimal number indicating the sampling rate for this experiment. - - This will contain a value between ``0.0`` and ``1.0``. The client should - generate a random decimal between ``0.0`` and ``1.0``. If the randomly - generated number is less than or equal to the value of this field, the - experiment is applicable. - -disabled - (optional) Boolean value indicating whether an experiment is disabled. - - Normally, experiments are deactivated after a certain time has passed or - after the experiment itself determines it no longer needs to run (perhaps - it collected sufficient data already). - - This property serves as a backup mechanism to remotely disable an - experiment before it was scheduled to be disabled. It can be used to - kill experiments that are found to be doing wrong or bad things or that - aren't useful. - - If this property is not defined or is false, the client should assume - the experiment is active and a candidate for activation. - -frozen - (optional) Boolean value indicating this experiment is frozen and no - longer accepting new enrollments. - - If a client sees a true value in this field, it should not attempt to - activate an experiment. - -jsfilter - (optional) JavaScript code that will be evaluated to determine experiment - applicability. - - This property contains the string representation of JavaScript code that - will be evaluated in a sandboxed environment using JavaScript's - ``eval()``. - - The string is expected to contain the definition of a JavaScript function - ``filter(context)``. This function receives as its argument an object - holding application state. See the section below for the definition of - this object. - - The purpose of this property is to allow experiments to define complex - rules and logic for evaluating experiment applicability in a manner - that is privacy conscious and doesn't require the transmission of - excessive data. - - The return value of this filter indicates whether the experiment is - applicable. Functions should return true if the experiment is - applicable. - - If an experiment is not applicable, they should throw an Error whose - message contains the reason the experiment is not applicable. This - message may be logged and sent to remote servers, so it should not - contain private or otherwise sensitive data that wouldn't normally - be submitted. - - If a falsey (or undefined) value is returned, the client should - assume the experiment is not applicable. - - If this property is not defined, the client does not consider a custom - JavaScript filter function when determining whether an experiment is - applicable. - -JavaScript Filter Context Objects -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The object passed to a ``jsfilter`` ``filter()`` function contains the -following properties: - -healthReportSubmissionEnabled - This property contains a boolean indicating whether Firefox Health - Report has its data submission flag enabled (whether Firefox Health - Report is sending data to remote servers). - -healthReportPayload - This property contains the current Firefox Health Report payload. - - The payload format is documented at :ref:`healthreport_dataformat`. - -telemetryPayload - This property contains the current Telemetry payload. - -The evaluation sandbox for the JavaScript filters may be destroyed -immediately after ``filter()`` returns. This function should not assume -async code will finish. - -Experiment Applicability and Client Behavior -============================================ - -The point of an experiment manifest is to define which experiments are -available and where and how to run them. This section explains those -rules in more detail. - -Many of the properties in *Experiment Objects* are related to determining -whether an experiment should run on a given client. This evaluation is -performed client side. - -1. Multiple conditions in an experiment ---------------------------------------- - -If multiple conditions are defined for an experiment, the client should -combine each condition with a logical *AND*: all conditions must be -satisfied for an experiment to run. If one condition fails, the experiment -is not applicable. - -2. Active experiment disappears from manifest ---------------------------------------------- - -If a specific experiment disappears from the manifest, the client should -continue conducting an already-active experiment. Furthermore, the -client should remember what the expiration events were for an experiment -and honor them. - -The rationale here is that we want to prevent an accidental deletion -or temporary failure on the server to inadvertantly deactivate -supposed-to-be-active experiments. We also don't want premature deletion -of an experiment from the manifest to result in indefinite activation -periods. - -3. Inactive experiment disappears from manifest ------------------------------------------------ - -If an inactive but scheduled-to-be-active experiment disappears from the -manifest, the client should not activate the experiment. - -If that experiment reappears in the manifest, the client should not -treat that experiment any differently than any other new experiment. Put -another way, the fact an inactive experiment disappears and then -reappears should not be significant. - -The rationale here is that server operators should have complete -control of an inactive experiment up to it's go-live date. - -4. Re-evaluating applicability on manifest refresh --------------------------------------------------- - -When an experiment manifest is refreshed or updated, the client should -re-evaluate the applicability of each experiment therein. - -The rationale here is that the server may change the parameters of an -experiment and want clients to pick those up. - -5. Activating a previously non-applicable experiment ----------------------------------------------------- - -If the conditions of an experiment change or the state of the client -changes to allow an experiment to transition from previously -non-applicable to applicable, the experiment should be activated. - -For example, if a client is running version 28 and the experiment -initially requires version 29 or above, the client will not mark the -experiment as applicable. But if the client upgrades to version 29 or if -the manifest is updated to require 28 or above, the experiment will -become applicable. - -6. Deactivating a previously active experiment ----------------------------------------------- - -If the conditions of an experiment change or the state of the client -changes and an active experiment is no longer applicable, that -experiment should be deactivated. - -7. Calculation of sampling-based applicability ----------------------------------------------- - -For calculating sampling-based applicability, the client will associate -a random value between ``0.0`` and ``1.0`` for each observed experiment -ID. This random value will be generated the first time sampling -applicability is evaluated. This random value will be persisted and used -in future applicability evaluations for this experiment. - -By saving and re-using the value, the client is able to reliably and -consistently evaluate applicability, even if the sampling threshold -in the manifest changes. - -Clients should retain the randomly-generated sampling value for -experiments that no longer appear in a manifest for a period of at least -30 days. The rationale is that if an experiment disappears and reappears -from a manifest, the client will not have multiple opportunities to -generate a random value that satisfies the sampling criteria. - -8. Incompatible version numbers -------------------------------- - -If a client receives a manifest with a version number that it doesn't -recognize, it should ignore the manifest. - -9. Usage of old manifests -------------------------- - -If a client experiences an error fetching a manifest (server not -available) or if the manifest is corrupt, not readable, or compatible, -the client may use a previously-fetched (cached) manifest. - -10. Updating XPIs ------------------ - -If the URL or hash of an active experiment's XPI changes, the client -should fetch the new XPI, uninstall the old XPI, and install the new -XPI. - -Examples -======== - -Here is an example manifest:: - - { - "version": 1, - "experiments": [ - { - "id": "da9d7f4f-f3f9-4f81-bacd-6f0626ffa360", - "xpiURL": "https://experiments.mozilla.org/foo.xpi", - "xpiHash": "sha1:cb1eb32b89d86d78b7326f416cf404548c5e0099", - "startTime": 1393000000, - "endTime": 1394000000, - "appName": ["Firefox", "Fennec"], - "minVersion": "28", - "maxVersion": "30", - "os": ["windows", "linux", "osx"], - "jsfilter": "function filter(context) { return context.healthReportEnabled; }" - } - ] - } diff --git a/browser/experiments/moz.build b/browser/experiments/moz.build deleted file mode 100644 index a11e4b725..000000000 --- a/browser/experiments/moz.build +++ /dev/null @@ -1,18 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -HAS_MISC_RULE = True - -EXTRA_COMPONENTS += [ - 'Experiments.manifest', - 'ExperimentsService.js', -] - -EXTRA_JS_MODULES.experiments += [ - 'Experiments.jsm', -] - -XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini'] - -SPHINX_TREES['experiments'] = 'docs' diff --git a/browser/experiments/test/addons/experiment-1/install.rdf b/browser/experiments/test/addons/experiment-1/install.rdf deleted file mode 100644 index f9d70054a..000000000 --- a/browser/experiments/test/addons/experiment-1/install.rdf +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0"?> - -<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - - <Description about="urn:mozilla:install-manifest"> - <em:id>test-experiment-1@tests.mozilla.org</em:id> - <em:version>1</em:version> - <em:type>128</em:type> - - <!-- Front End MetaData --> - <em:name>Test experiment 1</em:name> - <em:description>Yet another experiment that experiments experimentally.</em:description> - - </Description> -</RDF> diff --git a/browser/experiments/test/addons/experiment-1a/install.rdf b/browser/experiments/test/addons/experiment-1a/install.rdf deleted file mode 100644 index 7806b11b1..000000000 --- a/browser/experiments/test/addons/experiment-1a/install.rdf +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0"?> - -<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - - <Description about="urn:mozilla:install-manifest"> - <em:id>test-experiment-1@tests.mozilla.org</em:id> - <em:version>1.1</em:version> - <em:type>128</em:type> - - <!-- Front End MetaData --> - <em:name>Test experiment 1.1</em:name> - <em:description>And yet another experiment that experiments experimentally.</em:description> - - </Description> -</RDF> diff --git a/browser/experiments/test/addons/experiment-2/install.rdf b/browser/experiments/test/addons/experiment-2/install.rdf deleted file mode 100644 index 69122c0ef..000000000 --- a/browser/experiments/test/addons/experiment-2/install.rdf +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0"?> - -<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - - <Description about="urn:mozilla:install-manifest"> - <em:id>test-experiment-2@tests.mozilla.org</em:id> - <em:version>1</em:version> - <em:type>128</em:type> - - <!-- Front End MetaData --> - <em:name>Test experiment 2</em:name> - <em:description>And yet another experiment that experiments experimentally.</em:description> - - </Description> -</RDF> diff --git a/browser/experiments/test/addons/experiment-racybranch/bootstrap.js b/browser/experiments/test/addons/experiment-racybranch/bootstrap.js deleted file mode 100644 index e8278f50f..000000000 --- a/browser/experiments/test/addons/experiment-racybranch/bootstrap.js +++ /dev/null @@ -1,35 +0,0 @@ -/* exported startup, shutdown, install, uninstall */ - -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource:///modules/experiments/Experiments.jsm"); - -var gStarted = false; - -function startup(data, reasonCode) { - if (gStarted) { - return; - } - gStarted = true; - - // delay realstartup to trigger the race condition - Cc['@mozilla.org/thread-manager;1'].getService(Ci.nsIThreadManager) - .mainThread.dispatch(realstartup, 0); -} - -function realstartup() { - let experiments = Experiments.instance(); - let experiment = experiments._getActiveExperiment(); - if (experiment.branch) { - Cu.reportError("Found pre-existing branch: " + experiment.branch); - return; - } - - let branch = "racy-set"; - experiments.setExperimentBranch(experiment.id, branch) - .then(null, Cu.reportError); -} - -function shutdown() { } -function install() { } -function uninstall() { } diff --git a/browser/experiments/test/addons/experiment-racybranch/install.rdf b/browser/experiments/test/addons/experiment-racybranch/install.rdf deleted file mode 100644 index cebaede56..000000000 --- a/browser/experiments/test/addons/experiment-racybranch/install.rdf +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0"?>
-
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-
- <Description about="urn:mozilla:install-manifest">
- <em:id>test-experiment-racybranch@tests.mozilla.org</em:id>
- <em:version>1</em:version>
- <em:type>128</em:type>
-
- <!-- Front End MetaData -->
- <em:name>Test experiment racybranch</em:name>
- <em:description>An experiment that sets the experiment branch in a potentially racy way.</em:description>
-
- </Description>
-</RDF>
diff --git a/browser/experiments/test/xpcshell/.eslintrc.js b/browser/experiments/test/xpcshell/.eslintrc.js deleted file mode 100644 index 1f540a05b..000000000 --- a/browser/experiments/test/xpcshell/.eslintrc.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; - -module.exports = { - "extends": [ - "../../../../testing/xpcshell/xpcshell.eslintrc.js" - ], - - "rules": { - "no-unused-vars": ["error", { - "vars": "all", - "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$", - "args": "none" - }] - } -}; diff --git a/browser/experiments/test/xpcshell/experiments_1.manifest b/browser/experiments/test/xpcshell/experiments_1.manifest deleted file mode 100644 index 0401ea328..000000000 --- a/browser/experiments/test/xpcshell/experiments_1.manifest +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": 1, - "experiments": [ - { - "id": "test-experiment-1@tests.mozilla.org", - "xpiURL": "https://experiments.mozilla.org/foo.xpi", - "xpiHash": "sha1:cb1eb32b89d86d78b7326f416cf404548c5e0099", - "startTime": 1393000000, - "endTime": 1394000000, - "appName": ["Firefox", "Fennec"], - "minVersion": "28", - "maxVersion": "30", - "maxActiveSeconds": 60, - "os": ["windows", "linux", "osx"], - "channel": ["daily", "weekly", "nightly"], - "jsfilter": "function filter(context) { return true; }" - } - ] -} diff --git a/browser/experiments/test/xpcshell/head.js b/browser/experiments/test/xpcshell/head.js deleted file mode 100644 index ae356ea2d..000000000 --- a/browser/experiments/test/xpcshell/head.js +++ /dev/null @@ -1,199 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -/* exported PREF_EXPERIMENTS_ENABLED, PREF_LOGGING_LEVEL, PREF_LOGGING_DUMP - PREF_MANIFEST_URI, PREF_FETCHINTERVAL, EXPERIMENT1_ID, - EXPERIMENT1_NAME, EXPERIMENT1_XPI_SHA1, EXPERIMENT1A_NAME, - EXPERIMENT1A_XPI_SHA1, EXPERIMENT2_ID, EXPERIMENT2_XPI_SHA1, - EXPERIMENT3_ID, EXPERIMENT4_ID, FAKE_EXPERIMENTS_1, - FAKE_EXPERIMENTS_2, gAppInfo, removeCacheFile, defineNow, - futureDate, dateToSeconds, loadAddonManager, promiseRestartManager, - startAddonManagerOnly, getExperimentAddons, replaceExperiments */ - -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); -Cu.import("resource://testing-common/AddonManagerTesting.jsm"); -Cu.import("resource://testing-common/AddonTestUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", - "resource://gre/modules/AddonManager.jsm"); - -const PREF_EXPERIMENTS_ENABLED = "experiments.enabled"; -const PREF_LOGGING_LEVEL = "experiments.logging.level"; -const PREF_LOGGING_DUMP = "experiments.logging.dump"; -const PREF_MANIFEST_URI = "experiments.manifest.uri"; -const PREF_FETCHINTERVAL = "experiments.manifest.fetchIntervalSeconds"; -const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled"; - -function getExperimentPath(base) { - let p = do_get_cwd(); - p.append(base); - return p.path; -} - -function sha1File(path) { - let f = Cc["@mozilla.org/file/local;1"] - .createInstance(Ci.nsILocalFile); - f.initWithPath(path); - let hasher = Cc["@mozilla.org/security/hash;1"] - .createInstance(Ci.nsICryptoHash); - hasher.init(hasher.SHA1); - - let is = Cc["@mozilla.org/network/file-input-stream;1"] - .createInstance(Ci.nsIFileInputStream); - is.init(f, -1, 0, 0); - hasher.updateFromStream(is, Math.pow(2, 32) - 1); - is.close(); - let bytes = hasher.finish(false); - - let rv = ""; - for (let i = 0; i < bytes.length; i++) { - rv += ("0" + bytes.charCodeAt(i).toString(16)).substr(-2); - } - return rv; -} - -const EXPERIMENT1_ID = "test-experiment-1@tests.mozilla.org"; -const EXPERIMENT1_XPI_NAME = "experiment-1.xpi"; -const EXPERIMENT1_NAME = "Test experiment 1"; -const EXPERIMENT1_PATH = getExperimentPath(EXPERIMENT1_XPI_NAME); -const EXPERIMENT1_XPI_SHA1 = "sha1:" + sha1File(EXPERIMENT1_PATH); - - -const EXPERIMENT1A_XPI_NAME = "experiment-1a.xpi"; -const EXPERIMENT1A_NAME = "Test experiment 1.1"; -const EXPERIMENT1A_PATH = getExperimentPath(EXPERIMENT1A_XPI_NAME); -const EXPERIMENT1A_XPI_SHA1 = "sha1:" + sha1File(EXPERIMENT1A_PATH); - -const EXPERIMENT2_ID = "test-experiment-2@tests.mozilla.org" -const EXPERIMENT2_XPI_NAME = "experiment-2.xpi"; -const EXPERIMENT2_PATH = getExperimentPath(EXPERIMENT2_XPI_NAME); -const EXPERIMENT2_XPI_SHA1 = "sha1:" + sha1File(EXPERIMENT2_PATH); - -const EXPERIMENT3_ID = "test-experiment-3@tests.mozilla.org"; -const EXPERIMENT4_ID = "test-experiment-4@tests.mozilla.org"; - -const FAKE_EXPERIMENTS_1 = [ - { - id: "id1", - name: "experiment1", - description: "experiment 1", - active: true, - detailUrl: "https://dummy/experiment1", - branch: "foo", - }, -]; - -const FAKE_EXPERIMENTS_2 = [ - { - id: "id2", - name: "experiment2", - description: "experiment 2", - active: false, - endDate: new Date(2014, 2, 11, 2, 4, 35, 42).getTime(), - detailUrl: "https://dummy/experiment2", - branch: null, - }, - { - id: "id1", - name: "experiment1", - description: "experiment 1", - active: false, - endDate: new Date(2014, 2, 10, 0, 0, 0, 0).getTime(), - detailURL: "https://dummy/experiment1", - branch: null, - }, -]; - -var gAppInfo = null; - -function removeCacheFile() { - let path = OS.Path.join(OS.Constants.Path.profileDir, "experiments.json"); - return OS.File.remove(path); -} - -function patchPolicy(policy, data) { - for (let key of Object.keys(data)) { - Object.defineProperty(policy, key, { - value: data[key], - writable: true, - }); - } -} - -function defineNow(policy, time) { - patchPolicy(policy, { now: () => new Date(time) }); -} - -function futureDate(date, offset) { - return new Date(date.getTime() + offset); -} - -function dateToSeconds(date) { - return date.getTime() / 1000; -} - -var gGlobalScope = this; -function loadAddonManager() { - AddonTestUtils.init(gGlobalScope); - AddonTestUtils.overrideCertDB(); - createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); - return AddonTestUtils.promiseStartupManager(); -} - -const { - promiseRestartManager, -} = AddonTestUtils; - -// Starts the addon manager without creating app info. We can't directly use -// |loadAddonManager| defined above in test_conditions.js as it would make the test fail. -function startAddonManagerOnly() { - let addonManager = Cc["@mozilla.org/addons/integration;1"] - .getService(Ci.nsIObserver) - .QueryInterface(Ci.nsITimerCallback); - addonManager.observe(null, "addons-startup", null); -} - -function getExperimentAddons(previous=false) { - let deferred = Promise.defer(); - - AddonManager.getAddonsByTypes(["experiment"], (addons) => { - if (previous) { - deferred.resolve(addons); - } else { - deferred.resolve(addons.filter(a => !a.appDisabled)); - } - }); - - return deferred.promise; -} - -function createAppInfo(ID="xpcshell@tests.mozilla.org", name="XPCShell", - version="1.0", platformVersion="1.0") { - AddonTestUtils.createAppInfo(ID, name, version, platformVersion); - gAppInfo = AddonTestUtils.appInfo; -} - -/** - * Replace the experiments on an Experiments with a new list. - * - * This monkeypatches getExperiments(). It doesn't monkeypatch the internal - * experiments list. So its utility is not as great as it could be. - */ -function replaceExperiments(experiment, list) { - Object.defineProperty(experiment, "getExperiments", { - writable: true, - value: () => { - return Promise.resolve(list); - }, - }); -} - -// Experiments require Telemetry to be enabled, and that's not true for debug -// builds. Let's just enable it here instead of going through each test. -Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true); diff --git a/browser/experiments/test/xpcshell/test_activate.js b/browser/experiments/test/xpcshell/test_activate.js deleted file mode 100644 index 60deafbfb..000000000 --- a/browser/experiments/test/xpcshell/test_activate.js +++ /dev/null @@ -1,151 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource:///modules/experiments/Experiments.jsm"); - -const SEC_IN_ONE_DAY = 24 * 60 * 60; -const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000; - -var gHttpServer = null; -var gHttpRoot = null; -var gPolicy = null; - -function ManifestEntry(data) { - this.id = data.id || EXPERIMENT1_ID; - this.xpiURL = data.xpiURL || gHttpRoot + EXPERIMENT1_XPI_NAME; - this.xpiHash = data.xpiHash || EXPERIMENT1_XPI_SHA1; - this.appName = data.appName || ["XPCShell"]; - this.channel = data.appName || ["nightly"]; - this.startTime = data.startTime || new Date(2010, 0, 1, 12).getTime() / 1000; - this.endTime = data.endTime || new Date(9001, 0, 1, 12).getTime() / 1000; - this.maxActiveSeconds = data.maxActiveSeconds || 5 * SEC_IN_ONE_DAY; -} - -function run_test() { - run_next_test(); -} - -add_task(function* test_setup() { - loadAddonManager(); - gPolicy = new Experiments.Policy(); - - gHttpServer = new HttpServer(); - gHttpServer.start(-1); - let port = gHttpServer.identity.primaryPort; - gHttpRoot = "http://localhost:" + port + "/"; - gHttpServer.registerDirectory("/", do_get_cwd()); - do_register_cleanup(() => gHttpServer.stop(() => {})); - - patchPolicy(gPolicy, { - updatechannel: () => "nightly", - }); - - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); - Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); - Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); -}); - -function isApplicable(experiment) { - let deferred = Promise.defer(); - experiment.isApplicable().then( - result => deferred.resolve({ applicable: true, reason: null }), - reason => deferred.resolve({ applicable: false, reason: reason }) - ); - - return deferred.promise; -} - -add_task(function* test_startStop() { - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 30 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 60 * MS_IN_ONE_DAY); - let manifestData = new ManifestEntry({ - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - }); - let experiment = new Experiments.ExperimentEntry(gPolicy); - experiment.initFromManifestData(manifestData); - - // We need to associate it with the singleton so the onInstallStarted - // Addon Manager listener will know about it. - Experiments.instance()._experiments = new Map(); - Experiments.instance()._experiments.set(experiment.id, experiment); - - let result; - - defineNow(gPolicy, baseDate); - result = yield isApplicable(experiment); - Assert.equal(result.applicable, false, "Experiment should not be applicable."); - Assert.equal(experiment.enabled, false, "Experiment should not be enabled."); - - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "No experiment add-ons are installed."); - - defineNow(gPolicy, futureDate(startDate, 5 * MS_IN_ONE_DAY)); - result = yield isApplicable(experiment); - Assert.equal(result.applicable, true, "Experiment should now be applicable."); - Assert.equal(experiment.enabled, false, "Experiment should not be enabled."); - - let changes = yield experiment.start(); - Assert.equal(changes, experiment.ADDON_CHANGE_INSTALL, "Add-on was installed."); - addons = yield getExperimentAddons(); - Assert.equal(experiment.enabled, true, "Experiment should now be enabled."); - Assert.equal(addons.length, 1, "1 experiment add-on is installed."); - Assert.equal(addons[0].id, experiment._addonId, "The add-on is the one we expect."); - Assert.equal(addons[0].userDisabled, false, "The add-on is not userDisabled."); - Assert.ok(addons[0].isActive, "The add-on is active."); - - changes = yield experiment.stop(); - Assert.equal(changes, experiment.ADDON_CHANGE_UNINSTALL, "Add-on was uninstalled."); - addons = yield getExperimentAddons(); - Assert.equal(experiment.enabled, false, "Experiment should not be enabled."); - Assert.equal(addons.length, 0, "Experiment should be uninstalled from the Addon Manager."); - - changes = yield experiment.start(); - Assert.equal(changes, experiment.ADDON_CHANGE_INSTALL, "Add-on was installed."); - addons = yield getExperimentAddons(); - Assert.equal(experiment.enabled, true, "Experiment should now be enabled."); - Assert.equal(addons.length, 1, "1 experiment add-on is installed."); - Assert.equal(addons[0].id, experiment._addonId, "The add-on is the one we expect."); - Assert.equal(addons[0].userDisabled, false, "The add-on is not userDisabled."); - Assert.ok(addons[0].isActive, "The add-on is active."); - - result = yield experiment.shouldStop(); - Assert.equal(result.shouldStop, false, "shouldStop should be false."); - Assert.equal(experiment.enabled, true, "Experiment should be enabled."); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "Experiment still in add-ons manager."); - Assert.ok(addons[0].isActive, "The add-on is still active."); - - defineNow(gPolicy, futureDate(endDate, MS_IN_ONE_DAY)); - result = yield experiment.shouldStop(); - Assert.equal(result.shouldStop, true, "shouldStop should now be true."); - changes = yield experiment.stop(); - Assert.equal(changes, experiment.ADDON_CHANGE_UNINSTALL, "Add-on should be uninstalled."); - Assert.equal(experiment.enabled, false, "Experiment should be disabled."); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Experiment add-on is uninstalled."); - - // Ensure hash validation works. - // We set an incorrect hash and expect the install to fail. - experiment._manifestData.xpiHash = "sha1:41014dcc66b4dcedcd973491a1530a32f0517d8a"; - let errored = false; - try { - yield experiment.start(); - } catch (ex) { - errored = true; - } - Assert.ok(experiment._failedStart, "Experiment failed to start."); - Assert.ok(errored, "start() threw an exception."); - - // Make sure "ignore hashes" mode works. - gPolicy.ignoreHashes = true; - changes = yield experiment.start(); - Assert.equal(changes, experiment.ADDON_CHANGE_INSTALL); - yield experiment.stop(); - gPolicy.ignoreHashes = false; -}); diff --git a/browser/experiments/test/xpcshell/test_api.js b/browser/experiments/test/xpcshell/test_api.js deleted file mode 100644 index 9f0112570..000000000 --- a/browser/experiments/test/xpcshell/test_api.js +++ /dev/null @@ -1,1647 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource://testing-common/AddonManagerTesting.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Experiments", - "resource:///modules/experiments/Experiments.jsm"); - -const MANIFEST_HANDLER = "manifests/handler"; - -const SEC_IN_ONE_DAY = 24 * 60 * 60; -const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000; - -var gHttpServer = null; -var gHttpRoot = null; -var gDataRoot = null; -var gPolicy = null; -var gManifestObject = null; -var gManifestHandlerURI = null; -var gTimerScheduleOffset = -1; - -function uninstallExperimentAddons() { - return Task.spawn(function* () { - let addons = yield getExperimentAddons(); - for (let a of addons) { - yield AddonManagerTesting.uninstallAddonByID(a.id); - } - }); -} - -function testCleanup(experimentsInstance) { - return Task.spawn(function* () { - yield promiseRestartManager(); - yield uninstallExperimentAddons(); - yield removeCacheFile(); - }); -} - -function run_test() { - run_next_test(); -} - -add_task(function* test_setup() { - loadAddonManager(); - - gHttpServer = new HttpServer(); - gHttpServer.start(-1); - let port = gHttpServer.identity.primaryPort; - gHttpRoot = "http://localhost:" + port + "/"; - gDataRoot = gHttpRoot + "data/"; - gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER; - gHttpServer.registerDirectory("/data/", do_get_cwd()); - gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => { - response.setStatusLine(null, 200, "OK"); - response.write(JSON.stringify(gManifestObject)); - response.processAsync(); - response.finish(); - }); - do_register_cleanup(() => gHttpServer.stop(() => {})); - - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); - Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); - Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); - Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI); - Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0); - - gPolicy = new Experiments.Policy(); - patchPolicy(gPolicy, { - updatechannel: () => "nightly", - oneshotTimer: (callback, timeout, thisObj, name) => gTimerScheduleOffset = timeout, - }); -}); - -add_task(function* test_contract() { - Cc["@mozilla.org/browser/experiments-service;1"].getService(); -}); - -// Test basic starting and stopping of experiments. - -add_task(function* test_getExperiments() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY); - let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let startDate2 = futureDate(baseDate, 150 * MS_IN_ONE_DAY); - let endDate2 = futureDate(baseDate, 200 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT2_ID, - xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, - xpiHash: EXPERIMENT2_XPI_SHA1, - startTime: dateToSeconds(startDate2), - endTime: dateToSeconds(endDate2), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate1), - endTime: dateToSeconds(endDate1), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - // Data to compare the result of Experiments.getExperiments() against. - - let experimentListData = [ - { - id: EXPERIMENT2_ID, - name: "Test experiment 2", - description: "And yet another experiment that experiments experimentally.", - }, - { - id: EXPERIMENT1_ID, - name: EXPERIMENT1_NAME, - description: "Yet another experiment that experiments experimentally.", - }, - ]; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - // Use updateManifest() to provide for coverage of that path. - - let now = baseDate; - gTimerScheduleOffset = -1; - defineNow(gPolicy, now); - - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - Assert.equal(experiments.getActiveExperimentID(), null, - "getActiveExperimentID should return null"); - - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are installed."); - - try { - yield experiments.getExperimentBranch(); - Assert.ok(false, "getExperimentBranch should fail with no experiment"); - } - catch (e) { - Assert.ok(true, "getExperimentBranch correctly threw"); - } - - // Trigger update, clock set for experiment 1 to start. - - now = futureDate(startDate1, 5 * MS_IN_ONE_DAY); - gTimerScheduleOffset = -1; - defineNow(gPolicy, now); - - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT1_ID, - "getActiveExperimentID should return the active experiment1"); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "An experiment add-on was installed."); - - experimentListData[1].active = true; - experimentListData[1].endDate = now.getTime() + 10 * MS_IN_ONE_DAY; - for (let k of Object.keys(experimentListData[1])) { - Assert.equal(experimentListData[1][k], list[0][k], - "Property " + k + " should match reference data."); - } - - let b = yield experiments.getExperimentBranch(); - Assert.strictEqual(b, null, "getExperimentBranch should return null by default"); - - b = yield experiments.getExperimentBranch(EXPERIMENT1_ID); - Assert.strictEqual(b, null, "getExperimentsBranch should return null (with id)"); - - yield experiments.setExperimentBranch(EXPERIMENT1_ID, "foo"); - b = yield experiments.getExperimentBranch(); - Assert.strictEqual(b, "foo", "getExperimentsBranch should return the set value"); - - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - Assert.equal(gTimerScheduleOffset, 10 * MS_IN_ONE_DAY, - "Experiment re-evaluation should have been scheduled correctly."); - - // Trigger update, clock set for experiment 1 to stop. - - now = futureDate(endDate1, 1000); - gTimerScheduleOffset = -1; - defineNow(gPolicy, now); - - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - Assert.equal(experiments.getActiveExperimentID(), null, - "getActiveExperimentID should return null again"); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry."); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "The experiment add-on should be uninstalled."); - - experimentListData[1].active = false; - experimentListData[1].endDate = now.getTime(); - for (let k of Object.keys(experimentListData[1])) { - Assert.equal(experimentListData[1][k], list[0][k], - "Property " + k + " should match reference data."); - } - - Assert.equal(gTimerScheduleOffset, startDate2 - now, - "Experiment re-evaluation should have been scheduled correctly."); - - // Trigger update, clock set for experiment 2 to start. - // Use notify() to provide for coverage of that path. - - now = startDate2; - gTimerScheduleOffset = -1; - defineNow(gPolicy, now); - - yield experiments.notify(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT2_ID, - "getActiveExperimentID should return the active experiment2"); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 2, "Experiment list should have 2 entries now."); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "An experiment add-on is installed."); - - experimentListData[0].active = true; - experimentListData[0].endDate = now.getTime() + 10 * MS_IN_ONE_DAY; - for (let i=0; i<experimentListData.length; ++i) { - let entry = experimentListData[i]; - for (let k of Object.keys(entry)) { - Assert.equal(entry[k], list[i][k], - "Entry " + i + " - Property '" + k + "' should match reference data."); - } - } - - Assert.equal(gTimerScheduleOffset, 10 * MS_IN_ONE_DAY, - "Experiment re-evaluation should have been scheduled correctly."); - - // Trigger update, clock set for experiment 2 to stop. - - now = futureDate(startDate2, 10 * MS_IN_ONE_DAY + 1000); - gTimerScheduleOffset = -1; - defineNow(gPolicy, now); - yield experiments.notify(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - Assert.equal(experiments.getActiveExperimentID(), null, - "getActiveExperimentID should return null again2"); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 2, "Experiment list should have 2 entries now."); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "No experiments add-ons are installed."); - - experimentListData[0].active = false; - experimentListData[0].endDate = now.getTime(); - for (let i=0; i<experimentListData.length; ++i) { - let entry = experimentListData[i]; - for (let k of Object.keys(entry)) { - Assert.equal(entry[k], list[i][k], - "Entry " + i + " - Property '" + k + "' should match reference data."); - } - } - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield testCleanup(experiments); -}); - -add_task(function* test_getActiveExperimentID() { - // Check that getActiveExperimentID returns the correct result even - // after .uninit() - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY); - let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate1), - endTime: dateToSeconds(endDate1), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let now = futureDate(startDate1, 5 * MS_IN_ONE_DAY); - gTimerScheduleOffset = -1; - defineNow(gPolicy, now); - - let experiments = new Experiments.Experiments(gPolicy); - yield experiments.updateManifest(); - - Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT1_ID, - "getActiveExperimentID should return the active experiment1"); - - yield promiseRestartManager(); - Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT1_ID, - "getActiveExperimentID should return the active experiment1 after uninit()"); - - yield testCleanup(experiments); -}); - -// Test that we handle the experiments addon already being -// installed properly. -// We should just pave over them. - -add_task(function* test_addonAlreadyInstalled() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - - let now = baseDate; - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - // Trigger update, clock set for the experiment to start. - - now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should be active."); - - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "1 add-on is installed."); - - // Install conflicting addon. - - yield AddonManagerTesting.installXPIFromURL(gDataRoot + EXPERIMENT1_XPI_NAME, EXPERIMENT1_XPI_SHA1); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "1 add-on is installed."); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should still have 1 entry."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should be active."); - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield testCleanup(experiments); -}); - -add_task(function* test_lastActiveToday() { - let experiments = new Experiments.Experiments(gPolicy); - - replaceExperiments(experiments, FAKE_EXPERIMENTS_1); - - let e = yield experiments.getExperiments(); - Assert.equal(e.length, 1, "Monkeypatch successful."); - Assert.equal(e[0].id, "id1", "ID looks sane"); - Assert.ok(e[0].active, "Experiment is active."); - - let lastActive = yield experiments.lastActiveToday(); - Assert.equal(e[0], lastActive, "Last active object is expected."); - - replaceExperiments(experiments, FAKE_EXPERIMENTS_2); - e = yield experiments.getExperiments(); - Assert.equal(e.length, 2, "Monkeypatch successful."); - - defineNow(gPolicy, e[0].endDate); - - lastActive = yield experiments.lastActiveToday(); - Assert.ok(lastActive, "Have a last active experiment"); - Assert.equal(lastActive, e[0], "Last active object is expected."); - - yield testCleanup(experiments); -}); - -// Test explicitly disabling experiments. - -add_task(function* test_disableExperiment() { - // Dates this test is based on. - - let startDate = new Date(2004, 10, 9, 12); - let endDate = futureDate(startDate, 100 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - // Data to compare the result of Experiments.getExperiments() against. - - let experimentInfo = { - id: EXPERIMENT1_ID, - name: EXPERIMENT1_NAME, - description: "Yet another experiment that experiments experimentally.", - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set for the experiment to start. - - let now = futureDate(startDate, 5 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - - experimentInfo.active = true; - experimentInfo.endDate = now.getTime() + 10 * MS_IN_ONE_DAY; - for (let k of Object.keys(experimentInfo)) { - Assert.equal(experimentInfo[k], list[0][k], - "Property " + k + " should match reference data."); - } - - // Test disabling the experiment. - - now = futureDate(now, 1 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.disableExperiment("foo"); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry."); - - experimentInfo.active = false; - experimentInfo.endDate = now.getTime(); - for (let k of Object.keys(experimentInfo)) { - Assert.equal(experimentInfo[k], list[0][k], - "Property " + k + " should match reference data."); - } - - // Test that updating the list doesn't re-enable it. - - now = futureDate(now, 1 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry."); - - for (let k of Object.keys(experimentInfo)) { - Assert.equal(experimentInfo[k], list[0][k], - "Property " + k + " should match reference data."); - } - - yield testCleanup(experiments); -}); - -add_task(function* test_disableExperimentsFeature() { - // Dates this test is based on. - - let startDate = new Date(2004, 10, 9, 12); - let endDate = futureDate(startDate, 100 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - // Data to compare the result of Experiments.getExperiments() against. - - let experimentInfo = { - id: EXPERIMENT1_ID, - name: EXPERIMENT1_NAME, - description: "Yet another experiment that experiments experimentally.", - }; - - let experiments = new Experiments.Experiments(gPolicy); - Assert.equal(experiments.enabled, true, "Experiments feature should be enabled."); - - // Trigger update, clock set for the experiment to start. - - let now = futureDate(startDate, 5 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - - experimentInfo.active = true; - experimentInfo.endDate = now.getTime() + 10 * MS_IN_ONE_DAY; - for (let k of Object.keys(experimentInfo)) { - Assert.equal(experimentInfo[k], list[0][k], - "Property " + k + " should match reference data."); - } - - // Test disabling experiments. - - experiments._toggleExperimentsEnabled(false); - yield experiments.notify(); - Assert.equal(experiments.enabled, false, "Experiments feature should be disabled now."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry."); - - experimentInfo.active = false; - experimentInfo.endDate = now.getTime(); - for (let k of Object.keys(experimentInfo)) { - Assert.equal(experimentInfo[k], list[0][k], - "Property " + k + " should match reference data."); - } - - // Test that updating the list doesn't re-enable it. - - now = futureDate(now, 1 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - try { - yield experiments.updateManifest(); - } catch (e) { - // Exception expected, the feature is disabled. - } - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry."); - - for (let k of Object.keys(experimentInfo)) { - Assert.equal(experimentInfo[k], list[0][k], - "Property " + k + " should match reference data."); - } - - yield testCleanup(experiments); -}); - -// Test that after a failed experiment install: -// * the next applicable experiment gets installed -// * changing the experiments data later triggers re-evaluation - -add_task(function* test_installFailure() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - { - id: EXPERIMENT2_ID, - xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, - xpiHash: EXPERIMENT2_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - // Data to compare the result of Experiments.getExperiments() against. - - let experimentListData = [ - { - id: EXPERIMENT1_ID, - name: EXPERIMENT1_NAME, - description: "Yet another experiment that experiments experimentally.", - }, - { - id: EXPERIMENT2_ID, - name: "Test experiment 2", - description: "And yet another experiment that experiments experimentally.", - }, - ]; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - - let now = baseDate; - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - // Trigger update, clock set for experiment 1 & 2 to start, - // invalid hash for experiment 1. - // Order in the manifest matters, so we should start experiment 1, - // fail to install it & start experiment 2 instead. - - now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[0].xpiHash = "sha1:0000000000000000000000000000000000000000"; - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT2_ID, "Experiment 2 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 2 should be active."); - - // Trigger update, clock set for experiment 2 to stop. - - now = futureDate(now, 20 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - experimentListData[0].active = false; - experimentListData[0].endDate = now; - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT2_ID, "Experiment 2 should be the sole entry."); - Assert.equal(list[0].active, false, "Experiment should not be active."); - - // Trigger update with a fixed entry for experiment 1, - // which should get re-evaluated & started now. - - now = futureDate(now, 20 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[0].xpiHash = EXPERIMENT1_XPI_SHA1; - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - experimentListData[0].active = true; - experimentListData[0].endDate = now.getTime() + 10 * MS_IN_ONE_DAY; - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 2, "Experiment list should have 2 entries now."); - - for (let i=0; i<experimentListData.length; ++i) { - let entry = experimentListData[i]; - for (let k of Object.keys(entry)) { - Assert.equal(entry[k], list[i][k], - "Entry " + i + " - Property '" + k + "' should match reference data."); - } - } - - yield testCleanup(experiments); -}); - -// Test that after an experiment was disabled by user action, -// the experiment is not activated again if manifest data changes. - -add_task(function* test_userDisabledAndUpdated() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - - let now = baseDate; - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - // Trigger update, clock set for experiment 1 to start. - - now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should be active."); - let todayActive = yield experiments.lastActiveToday(); - Assert.ok(todayActive, "Last active for today reports a value."); - Assert.equal(todayActive.id, list[0].id, "The entry is what we expect."); - - // Explicitly disable an experiment. - - now = futureDate(now, 20 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.disableExperiment("foo"); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, false, "Experiment should not be active anymore."); - todayActive = yield experiments.lastActiveToday(); - Assert.ok(todayActive, "Last active for today still returns a value."); - Assert.equal(todayActive.id, list[0].id, "The ID is still the same."); - - // Trigger an update with a faked change for experiment 1. - - now = futureDate(now, 20 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - experiments._experiments.get(EXPERIMENT1_ID)._manifestData.xpiHash = - "sha1:0000000000000000000000000000000000000000"; - yield experiments.updateManifest(); - Assert.equal(observerFireCount, expectedObserverFireCount, - "Experiments observer should not have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, false, "Experiment should still be inactive."); - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield testCleanup(experiments); -}); - -// Test that changing the hash for an active experiments triggers an -// update for it. - -add_task(function* test_updateActiveExperiment() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - - let now = baseDate; - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - let todayActive = yield experiments.lastActiveToday(); - Assert.equal(todayActive, null, "No experiment active today."); - - // Trigger update, clock set for the experiment to start. - - now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should be active."); - Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match."); - todayActive = yield experiments.lastActiveToday(); - Assert.ok(todayActive, "todayActive() returns a value."); - Assert.equal(todayActive.id, list[0].id, "It returns the active experiment."); - - // Trigger an update for the active experiment by changing it's hash (and xpi) - // in the manifest. - - now = futureDate(now, 1 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[0].xpiHash = EXPERIMENT1A_XPI_SHA1; - gManifestObject.experiments[0].xpiURL = gDataRoot + EXPERIMENT1A_XPI_NAME; - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should still be active."); - Assert.equal(list[0].name, EXPERIMENT1A_NAME, "Experiments name should have been updated."); - todayActive = yield experiments.lastActiveToday(); - Assert.equal(todayActive.id, list[0].id, "last active today is still sane."); - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield testCleanup(experiments); -}); - -// Tests that setting the disable flag for an active experiment -// stops it. - -add_task(function* test_disableActiveExperiment() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - - let now = baseDate; - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - // Trigger update, clock set for the experiment to start. - - now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should be active."); - - // Trigger an update with the experiment being disabled. - - now = futureDate(now, 1 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[0].disabled = true; - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, false, "Experiment 1 should be disabled."); - - // Check that the experiment stays disabled. - - now = futureDate(now, 1 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - delete gManifestObject.experiments[0].disabled; - yield experiments.updateManifest(); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, false, "Experiment 1 should still be disabled."); - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield testCleanup(experiments); -}); - -// Test that: -// * setting the frozen flag for a not-yet-started experiment keeps -// it from starting -// * after a removing the frozen flag, the experiment can still start - -add_task(function* test_freezePendingExperiment() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - - let now = baseDate; - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - // Trigger update, clock set for the experiment to start but frozen. - - now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[0].frozen = true; - yield experiments.updateManifest(); - Assert.equal(observerFireCount, expectedObserverFireCount, - "Experiments observer should have not been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should have no entries yet."); - - // Trigger an update with the experiment not being frozen anymore. - - now = futureDate(now, 1 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - delete gManifestObject.experiments[0].frozen; - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should be active now."); - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield testCleanup(experiments); -}); - -// Test that setting the frozen flag for an active experiment doesn't -// stop it. - -add_task(function* test_freezeActiveExperiment() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - - let now = baseDate; - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - // Trigger update, clock set for the experiment to start. - - now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should be active."); - Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match."); - - // Trigger an update with the experiment being disabled. - - now = futureDate(now, 1 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[0].frozen = true; - yield experiments.updateManifest(); - Assert.equal(observerFireCount, expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should still be active."); - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield testCleanup(experiments); -}); - -// Test that removing an active experiment from the manifest doesn't -// stop it. - -add_task(function* test_removeActiveExperiment() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); - let startDate2 = futureDate(baseDate, 20000 * MS_IN_ONE_DAY); - let endDate2 = futureDate(baseDate, 30000 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - { - id: EXPERIMENT2_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT2_XPI_SHA1, - startTime: dateToSeconds(startDate2), - endTime: dateToSeconds(endDate2), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - - let now = baseDate; - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - // Trigger update, clock set for the experiment to start. - - now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should be active."); - Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match."); - - // Trigger an update with experiment 1 missing from the manifest - - now = futureDate(now, 1 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[0].frozen = true; - yield experiments.updateManifest(); - Assert.equal(observerFireCount, expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should still be active."); - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield testCleanup(experiments); -}); - -// Test that we correctly handle experiment start & install failures. - -add_task(function* test_invalidUrl() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME + ".invalid", - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: 0, - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set for the experiment to start. - - let now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gTimerScheduleOffset = null; - - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - Assert.equal(gTimerScheduleOffset, null, "No new timer should have been scheduled."); - - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield testCleanup(experiments); -}); - -// Test that we handle it properly when active experiment addons are being -// uninstalled. - -add_task(function* test_unexpectedUninstall() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - - let now = baseDate; - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - // Trigger update, clock set for the experiment to start. - - now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, true, "Experiment 1 should be active."); - - // Uninstall the addon through the addon manager instead of stopping it through - // the experiments API. - - yield AddonManagerTesting.uninstallAddonByID(EXPERIMENT1_ID); - yield experiments._mainTask; - - yield experiments.notify(); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.equal(list[0].active, false, "Experiment 1 should not be active anymore."); - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield testCleanup(experiments); -}); - -// If the Addon Manager knows of an experiment that we don't, it should get -// uninstalled. -add_task(function* testUnknownExperimentsUninstalled() { - let experiments = new Experiments.Experiments(gPolicy); - - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are present."); - - // Simulate us not listening. - experiments._unregisterWithAddonManager(); - yield AddonManagerTesting.installXPIFromURL(gDataRoot + EXPERIMENT1_XPI_NAME, EXPERIMENT1_XPI_SHA1); - experiments._registerWithAddonManager(); - - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "Experiment 1 installed via AddonManager"); - - // Simulate no known experiments. - gManifestObject = { - "version": 1, - experiments: [], - }; - - yield experiments.updateManifest(); - let fromManifest = yield experiments.getExperiments(); - Assert.equal(fromManifest.length, 0, "No experiments known in manifest."); - - // And the unknown add-on should be gone. - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Experiment 1 was uninstalled."); - - yield testCleanup(experiments); -}); - -// If someone else installs an experiment add-on, we detect and stop that. -add_task(function* testForeignExperimentInstall() { - let experiments = new Experiments.Experiments(gPolicy); - - gManifestObject = { - "version": 1, - experiments: [], - }; - - yield experiments.init(); - - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Precondition: No experiment add-ons present."); - - let failed = false; - try { - yield AddonManagerTesting.installXPIFromURL(gDataRoot + EXPERIMENT1_XPI_NAME, EXPERIMENT1_XPI_SHA1); - } catch (ex) { - failed = true; - } - Assert.ok(failed, "Add-on install should not have completed successfully"); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Add-on install should have been cancelled."); - - yield testCleanup(experiments); -}); - -// Experiment add-ons will be disabled after Addon Manager restarts. Ensure -// we enable them automatically. -add_task(function* testEnabledAfterRestart() { - let experiments = new Experiments.Experiments(gPolicy); - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: gPolicy.now().getTime() / 1000 - 60, - endTime: gPolicy.now().getTime() / 1000 + 60, - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Precondition: No experiment add-ons installed."); - - yield experiments.updateManifest(); - let fromManifest = yield experiments.getExperiments(); - Assert.equal(fromManifest.length, 1, "A single experiment is known."); - - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "A single experiment add-on is installed."); - Assert.ok(addons[0].isActive, "That experiment is active."); - - dump("Restarting Addon Manager\n"); - yield promiseRestartManager(); - experiments = new Experiments.Experiments(gPolicy); - - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "The experiment is still there after restart."); - Assert.ok(addons[0].userDisabled, "But it is disabled."); - Assert.equal(addons[0].isActive, false, "And not active."); - - yield experiments.updateManifest(); - Assert.ok(addons[0].isActive, "It activates when the manifest is evaluated."); - - yield testCleanup(experiments); -}); - -// If experiment add-ons were ever started, maxStartTime shouldn't be evaluated -// anymore. Ensure that if maxStartTime is passed but experiment has started -// already, maxStartTime does not cause deactivation. - -add_task(function* testMaxStartTimeEvaluation() { - - // Dates the following tests are based on. - - let startDate = new Date(2014, 5, 1, 12); - let now = futureDate(startDate, 10 * MS_IN_ONE_DAY); - let maxStartDate = futureDate(startDate, 100 * MS_IN_ONE_DAY); - let endDate = futureDate(startDate, 1000 * MS_IN_ONE_DAY); - - defineNow(gPolicy, now); - - // The manifest data we test with. - // We set a value for maxStartTime. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate), - endTime: dateToSeconds(endDate), - maxActiveSeconds: 1000 * SEC_IN_ONE_DAY, - maxStartTime: dateToSeconds(maxStartDate), - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Precondition: No experiment add-ons installed."); - - yield experiments.updateManifest(); - let fromManifest = yield experiments.getExperiments(); - Assert.equal(fromManifest.length, 1, "A single experiment is known."); - - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "A single experiment add-on is installed."); - Assert.ok(addons[0].isActive, "That experiment is active."); - - dump("Setting current time to maxStartTime + 100 days and reloading manifest\n"); - now = futureDate(maxStartDate, 100 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - yield experiments.updateManifest(); - - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "The experiment is still there."); - Assert.ok(addons[0].isActive, "It is still active."); - - yield testCleanup(experiments); -}); - -// Test coverage for an add-on uninstall disabling the experiment and that it stays -// disabled over restarts. -add_task(function* test_foreignUninstallAndRestart() { - let experiments = new Experiments.Experiments(gPolicy); - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: gPolicy.now().getTime() / 1000 - 60, - endTime: gPolicy.now().getTime() / 1000 + 60, - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Precondition: No experiment add-ons installed."); - - yield experiments.updateManifest(); - let experimentList = yield experiments.getExperiments(); - Assert.equal(experimentList.length, 1, "A single experiment is known."); - - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "A single experiment add-on is installed."); - Assert.ok(addons[0].isActive, "That experiment is active."); - - yield AddonManagerTesting.uninstallAddonByID(EXPERIMENT1_ID); - yield experiments._mainTask; - - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Experiment add-on should have been removed."); - - experimentList = yield experiments.getExperiments(); - Assert.equal(experimentList.length, 1, "A single experiment is known."); - Assert.equal(experimentList[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.ok(!experimentList[0].active, "Experiment 1 should not be active anymore."); - - // Fake restart behaviour. - yield promiseRestartManager(); - experiments = new Experiments.Experiments(gPolicy); - yield experiments.updateManifest(); - - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "No experiment add-ons installed."); - - experimentList = yield experiments.getExperiments(); - Assert.equal(experimentList.length, 1, "A single experiment is known."); - Assert.equal(experimentList[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); - Assert.ok(!experimentList[0].active, "Experiment 1 should not be active."); - - yield testCleanup(experiments); -}); diff --git a/browser/experiments/test/xpcshell/test_cache.js b/browser/experiments/test/xpcshell/test_cache.js deleted file mode 100644 index 4f2bce881..000000000 --- a/browser/experiments/test/xpcshell/test_cache.js +++ /dev/null @@ -1,399 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://testing-common/httpd.js"); -XPCOMUtils.defineLazyModuleGetter(this, "Experiments", - "resource:///modules/experiments/Experiments.jsm"); - -const MANIFEST_HANDLER = "manifests/handler"; - -const SEC_IN_ONE_DAY = 24 * 60 * 60; -const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000; - -var gHttpServer = null; -var gHttpRoot = null; -var gDataRoot = null; -var gPolicy = null; -var gManifestObject = null; -var gManifestHandlerURI = null; - -function run_test() { - run_next_test(); -} - -add_task(function* test_setup() { - loadAddonManager(); - yield removeCacheFile(); - - gHttpServer = new HttpServer(); - gHttpServer.start(-1); - let port = gHttpServer.identity.primaryPort; - gHttpRoot = "http://localhost:" + port + "/"; - gDataRoot = gHttpRoot + "data/"; - gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER; - gHttpServer.registerDirectory("/data/", do_get_cwd()); - gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => { - response.setStatusLine(null, 200, "OK"); - response.write(JSON.stringify(gManifestObject)); - response.processAsync(); - response.finish(); - }); - do_register_cleanup(() => gHttpServer.stop(() => {})); - - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); - Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); - Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); - Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI); - Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0); - - gPolicy = new Experiments.Policy(); - patchPolicy(gPolicy, { - updatechannel: () => "nightly", - oneshotTimer: (callback, timeout, thisObj, name) => {}, - }); -}); - -function checkExperimentListsEqual(list, list2) { - Assert.equal(list.length, list2.length, "Lists should have the same length.") - - for (let i=0; i<list.length; ++i) { - for (let k of Object.keys(list[i])) { - Assert.equal(list[i][k], list2[i][k], - "Field '" + k + "' should match for list entry " + i + "."); - } - } -} - -function checkExperimentSerializations(experimentEntryIterator) { - for (let experiment of experimentEntryIterator) { - let experiment2 = new Experiments.ExperimentEntry(gPolicy); - let jsonStr = JSON.stringify(experiment.toJSON()); - Assert.ok(experiment2.initFromCacheData(JSON.parse(jsonStr)), - "Should have initialized successfully from JSON serialization."); - Assert.equal(JSON.stringify(experiment), JSON.stringify(experiment2), - "Object stringifications should match."); - } -} - -function validateCache(cachedExperiments, experimentIds) { - let cachedExperimentIds = new Set(cachedExperiments); - Assert.equal(cachedExperimentIds.size, experimentIds.length, - "The number of cached experiments does not match with the provided list"); - for (let id of experimentIds) { - Assert.ok(cachedExperimentIds.has(id), "The cache must contain the experiment with id " + id); - } -} - -// Set up an experiments instance and check if it is properly restored from cache. - -add_task(function* test_cache() { - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - { - id: EXPERIMENT2_ID, - xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, - xpiHash: EXPERIMENT2_XPI_SHA1, - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - { - id: EXPERIMENT3_ID, - xpiURL: "https://inval.id/foo.xpi", - xpiHash: "sha1:0000000000000000000000000000000000000000", - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - // Setup dates for the experiments. - - let baseDate = new Date(2014, 5, 1, 12); - let startDates = []; - let endDates = []; - - for (let i=0; i<gManifestObject.experiments.length; ++i) { - let experiment = gManifestObject.experiments[i]; - startDates.push(futureDate(baseDate, (50 + (150 * i)) * MS_IN_ONE_DAY)); - endDates .push(futureDate(startDates[i], 50 * MS_IN_ONE_DAY)); - experiment.startTime = dateToSeconds(startDates[i]); - experiment.endTime = dateToSeconds(endDates[i]); - } - - // Data to compare the result of Experiments.getExperiments() against. - - let experimentListData = [ - { - id: EXPERIMENT2_ID, - name: "Test experiment 2", - description: "And yet another experiment that experiments experimentally.", - }, - { - id: EXPERIMENT1_ID, - name: EXPERIMENT1_NAME, - description: "Yet another experiment that experiments experimentally.", - }, - ]; - - // Trigger update & re-init, clock set to before any activation. - - let now = baseDate; - defineNow(gPolicy, now); - - let experiments = new Experiments.Experiments(gPolicy); - yield experiments.updateManifest(); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - checkExperimentSerializations(experiments._experiments.values()); - - yield promiseRestartManager(); - experiments = new Experiments.Experiments(gPolicy); - - yield experiments._run(); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - checkExperimentSerializations(experiments._experiments.values()); - - // Re-init, clock set for experiment 1 to start. - - now = futureDate(startDates[0], 5 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - - yield promiseRestartManager(); - experiments = new Experiments.Experiments(gPolicy); - yield experiments._run(); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - - experimentListData[1].active = true; - experimentListData[1].endDate = now.getTime() + 10 * MS_IN_ONE_DAY; - checkExperimentListsEqual(experimentListData.slice(1), list); - checkExperimentSerializations(experiments._experiments.values()); - - let branch = yield experiments.getExperimentBranch(EXPERIMENT1_ID); - Assert.strictEqual(branch, null); - - yield experiments.setExperimentBranch(EXPERIMENT1_ID, "testbranch"); - branch = yield experiments.getExperimentBranch(EXPERIMENT1_ID); - Assert.strictEqual(branch, "testbranch"); - - // Re-init, clock set for experiment 1 to stop. - - now = futureDate(now, 20 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - - yield promiseRestartManager(); - experiments = new Experiments.Experiments(gPolicy); - yield experiments._run(); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry."); - - experimentListData[1].active = false; - experimentListData[1].endDate = now.getTime(); - checkExperimentListsEqual(experimentListData.slice(1), list); - checkExperimentSerializations(experiments._experiments.values()); - - branch = yield experiments.getExperimentBranch(EXPERIMENT1_ID); - Assert.strictEqual(branch, "testbranch"); - - // Re-init, clock set for experiment 2 to start. - - now = futureDate(startDates[1], 20 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - - yield promiseRestartManager(); - experiments = new Experiments.Experiments(gPolicy); - yield experiments._run(); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 2, "Experiment list should have 2 entries."); - - experimentListData[0].active = true; - experimentListData[0].endDate = now.getTime() + 10 * MS_IN_ONE_DAY; - checkExperimentListsEqual(experimentListData, list); - checkExperimentSerializations(experiments._experiments.values()); - - // Re-init, clock set for experiment 2 to stop. - - now = futureDate(now, 20 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - - yield promiseRestartManager(); - experiments = new Experiments.Experiments(gPolicy); - yield experiments._run(); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 2, "Experiment list should have 2 entries."); - - experimentListData[0].active = false; - experimentListData[0].endDate = now.getTime(); - checkExperimentListsEqual(experimentListData, list); - checkExperimentSerializations(experiments._experiments.values()); - - // Cleanup. - - yield experiments._toggleExperimentsEnabled(false); - yield promiseRestartManager(); - yield removeCacheFile(); -}); - -add_task(function* test_expiration() { - // The manifest data we test with. - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - { - id: EXPERIMENT2_ID, - xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, - xpiHash: EXPERIMENT2_XPI_SHA1, - maxActiveSeconds: 50 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - // The 3rd experiment will never run, so it's ok to use experiment's 2 data. - { - id: EXPERIMENT3_ID, - xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, - xpiHash: EXPERIMENT2_XPI_SHA1, - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - } - ], - }; - - // Data to compare the result of Experiments.getExperiments() against. - let experimentListData = [ - { - id: EXPERIMENT2_ID, - name: "Test experiment 2", - description: "And yet another experiment that experiments experimentally.", - }, - { - id: EXPERIMENT1_ID, - name: EXPERIMENT1_NAME, - description: "Yet another experiment that experiments experimentally.", - }, - ]; - - // Setup dates for the experiments. - let baseDate = new Date(2014, 5, 1, 12); - let startDates = []; - let endDates = []; - - for (let i=0; i<gManifestObject.experiments.length; ++i) { - let experiment = gManifestObject.experiments[i]; - // Spread out experiments in time so that one experiment can end and expire while - // the next is still running. - startDates.push(futureDate(baseDate, (50 + (200 * i)) * MS_IN_ONE_DAY)); - endDates .push(futureDate(startDates[i], 50 * MS_IN_ONE_DAY)); - experiment.startTime = dateToSeconds(startDates[i]); - experiment.endTime = dateToSeconds(endDates[i]); - } - - let now = null; - let experiments = null; - - let setDateAndRestartExperiments = new Task.async(function* (newDate) { - now = newDate; - defineNow(gPolicy, now); - - yield promiseRestartManager(); - experiments = new Experiments.Experiments(gPolicy); - yield experiments._run(); - }); - - // Trigger update & re-init, clock set to before any activation. - now = baseDate; - defineNow(gPolicy, now); - - experiments = new Experiments.Experiments(gPolicy); - yield experiments.updateManifest(); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - // Re-init, clock set for experiment 1 to start... - yield setDateAndRestartExperiments(startDates[0]); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "The first experiment should have started."); - - // ... init again, and set the clock so that the first experiment ends. - yield setDateAndRestartExperiments(endDates[0]); - - // The experiment just ended, it should still be in the cache, but marked - // as finished. - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry."); - - experimentListData[1].active = false; - experimentListData[1].endDate = now.getTime(); - checkExperimentListsEqual(experimentListData.slice(1), list); - validateCache([...experiments._experiments.keys()], [EXPERIMENT1_ID, EXPERIMENT2_ID, EXPERIMENT3_ID]); - - // Start the second experiment. - yield setDateAndRestartExperiments(startDates[1]); - - // The experiments cache should contain the finished experiment and the - // one that's still running. - list = yield experiments.getExperiments(); - Assert.equal(list.length, 2, "Experiment list should have 2 entries."); - - experimentListData[0].active = true; - experimentListData[0].endDate = now.getTime() + 50 * MS_IN_ONE_DAY; - checkExperimentListsEqual(experimentListData, list); - - // Move the clock in the future, just 31 days after the start date of the second experiment, - // so that the cache for the first experiment expires and the second experiment is still running. - yield setDateAndRestartExperiments(futureDate(startDates[1], 31 * MS_IN_ONE_DAY)); - validateCache([...experiments._experiments.keys()], [EXPERIMENT2_ID, EXPERIMENT3_ID]); - - // Make sure that the expired experiment is not reported anymore. - let history = yield experiments.getExperiments(); - Assert.equal(history.length, 1, "Experiments older than 180 days must be removed from the cache."); - - // Test that we don't write expired experiments in the cache. - yield setDateAndRestartExperiments(now); - validateCache([...experiments._experiments.keys()], [EXPERIMENT2_ID, EXPERIMENT3_ID]); - - // The first experiment should be expired and not in the cache, it ended more than - // 180 days ago. We should see the one still running in the cache. - history = yield experiments.getExperiments(); - Assert.equal(history.length, 1, "Expired experiments must not be saved to cache."); - checkExperimentListsEqual(experimentListData.slice(0, 1), history); - - // Test that experiments that are cached locally but never ran are removed from cache - // when they are removed from the manifest (this is cached data, not really history). - gManifestObject["experiments"] = gManifestObject["experiments"].slice(1, 1); - yield experiments.updateManifest(); - validateCache([...experiments._experiments.keys()], [EXPERIMENT2_ID]); - - // Cleanup. - yield experiments._toggleExperimentsEnabled(false); - yield promiseRestartManager(); - yield removeCacheFile(); -}); diff --git a/browser/experiments/test/xpcshell/test_cacherace.js b/browser/experiments/test/xpcshell/test_cacherace.js deleted file mode 100644 index ff77cfdc4..000000000 --- a/browser/experiments/test/xpcshell/test_cacherace.js +++ /dev/null @@ -1,102 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource://gre/modules/Timer.jsm"); - -const MANIFEST_HANDLER = "manifests/handler"; - -const SEC_IN_ONE_DAY = 24 * 60 * 60; -const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000; - -var gHttpServer = null; -var gHttpRoot = null; -var gDataRoot = null; -var gPolicy = null; -var gManifestObject = null; -var gManifestHandlerURI = null; - -function run_test() { - run_next_test(); -} - -add_task(function* test_setup() { - loadAddonManager(); - yield removeCacheFile(); - - gHttpServer = new HttpServer(); - gHttpServer.start(-1); - let port = gHttpServer.identity.primaryPort; - gHttpRoot = "http://localhost:" + port + "/"; - gDataRoot = gHttpRoot + "data/"; - gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER; - gHttpServer.registerDirectory("/data/", do_get_cwd()); - gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => { - response.setStatusLine(null, 200, "OK"); - response.write(JSON.stringify(gManifestObject)); - response.processAsync(); - response.finish(); - }); - do_register_cleanup(() => gHttpServer.stop(() => {})); - - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); - Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); - Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); - Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI); - Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0); - - let ExperimentsScope = Cu.import("resource:///modules/experiments/Experiments.jsm"); - let Experiments = ExperimentsScope.Experiments; - - gPolicy = new Experiments.Policy(); - patchPolicy(gPolicy, { - updatechannel: () => "nightly", - delayCacheWrite: (promise) => { - return new Promise((resolve, reject) => { - promise.then( - (result) => { setTimeout(() => resolve(result), 500); }, - (err) => { reject(err); } - ); - }); - }, - }); - - let now = new Date(2014, 5, 1, 12); - defineNow(gPolicy, now); - - let experimentName = "experiment-racybranch.xpi"; - let experimentPath = getExperimentPath(experimentName); - let experimentHash = "sha1:" + sha1File(experimentPath); - - gManifestObject = { - version: 1, - experiments: [ - { - id: "test-experiment-racybranch@tests.mozilla.org", - xpiURL: gDataRoot + "experiment-racybranch.xpi", - xpiHash: experimentHash, - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - startTime: dateToSeconds(futureDate(now, -MS_IN_ONE_DAY)), - endTime: dateToSeconds(futureDate(now, MS_IN_ONE_DAY)), - }, - ], - }; - - do_print("gManifestObject: " + JSON.stringify(gManifestObject)); - - // In order for the addon manager to work properly, we hack - // Experiments.instance which is used by the XPIProvider - let experiments = new Experiments.Experiments(gPolicy); - Assert.strictEqual(ExperimentsScope.gExperiments, null); - ExperimentsScope.gExperiments = experiments; - - yield experiments.updateManifest(); - let active = experiments._getActiveExperiment(); - Assert.ok(active); - Assert.equal(active.branch, "racy-set"); - Assert.ok(!experiments._dirty); -}); diff --git a/browser/experiments/test/xpcshell/test_conditions.js b/browser/experiments/test/xpcshell/test_conditions.js deleted file mode 100644 index 23c147fdb..000000000 --- a/browser/experiments/test/xpcshell/test_conditions.js +++ /dev/null @@ -1,325 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - - -Cu.import("resource:///modules/experiments/Experiments.jsm"); -Cu.import("resource://gre/modules/TelemetryController.jsm", this); - -const SEC_IN_ONE_DAY = 24 * 60 * 60; - -var gPolicy = null; - -function ManifestEntry(data) { - this.id = EXPERIMENT1_ID; - this.xpiURL = "http://localhost:1/dummy.xpi"; - this.xpiHash = EXPERIMENT1_XPI_SHA1; - this.startTime = new Date(2010, 0, 1, 12).getTime() / 1000; - this.endTime = new Date(9001, 0, 1, 12).getTime() / 1000; - this.maxActiveSeconds = SEC_IN_ONE_DAY; - this.appName = ["XPCShell"]; - this.channel = ["nightly"]; - - data = data || {}; - for (let k of Object.keys(data)) { - this[k] = data[k]; - } - - if (!this.endTime) { - this.endTime = this.startTime + 5 * SEC_IN_ONE_DAY; - } -} - -function applicableFromManifestData(data, policy) { - let manifestData = new ManifestEntry(data); - let entry = new Experiments.ExperimentEntry(policy); - entry.initFromManifestData(manifestData); - return entry.isApplicable(); -} - -function run_test() { - run_next_test(); -} - -add_task(function* test_setup() { - createAppInfo(); - do_get_profile(); - startAddonManagerOnly(); - yield TelemetryController.testSetup(); - gPolicy = new Experiments.Policy(); - - patchPolicy(gPolicy, { - updatechannel: () => "nightly", - locale: () => "en-US", - random: () => 0.5, - }); - - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); - Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); - Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); -}); - -function arraysEqual(a, b) { - if (a.length !== b.length) { - return false; - } - - for (let i=0; i<a.length; ++i) { - if (a[i] !== b[i]) { - return false; - } - } - - return true; -} - -// This function exists solely to be .toSource()d -const sanityFilter = function filter(c) { - if (c.telemetryEnvironment === undefined) { - throw Error("No .telemetryEnvironment"); - } - if (c.telemetryEnvironment.build == undefined) { - throw Error("No .telemetryEnvironment.build"); - } - return true; -} - -// Utility function to generate build ID for previous/next date. -function addDate(buildId, diff) { - let m = /^([0-9]{4})([0-9]{2})([0-9]{2})(.*)$/.exec(buildId); - if (!m) { - throw Error("Unsupported build ID: " + buildId); - } - let year = Number.parseInt(m[1], 10); - let month = Number.parseInt(m[2], 10); - let date = Number.parseInt(m[3], 10); - let remainingParts = m[4]; - - let d = new Date(); - d.setUTCFullYear(year, month - 1, date); - d.setTime(d.getTime() + diff * 24 * 60 * 60 * 1000); - - let yearStr = String(d.getUTCFullYear()); - let monthStr = ("0" + String(d.getUTCMonth() + 1)).slice(-2); - let dateStr = ("0" + String(d.getUTCDate())).slice(-2); - return yearStr + monthStr + dateStr + remainingParts; -} -function prevDate(buildId) { - return addDate(buildId, -1); -} -function nextDate(buildId) { - return addDate(buildId, 1); -} - -add_task(function* test_simpleFields() { - let testData = [ - // "expected applicable?", failure reason or null, manifest data - - // misc. environment - - [false, ["appName"], {appName: []}], - [false, ["appName"], {appName: ["foo", gAppInfo.name + "-invalid"]}], - [true, null, {appName: ["not-an-app-name", gAppInfo.name]}], - - [false, ["os"], {os: []}], - [false, ["os"], {os: ["42", "abcdef"]}], - [true, null, {os: [gAppInfo.OS, "plan9"]}], - - [false, ["channel"], {channel: []}], - [false, ["channel"], {channel: ["foo", gPolicy.updatechannel() + "-invalid"]}], - [true, null, {channel: ["not-a-channel", gPolicy.updatechannel()]}], - - [false, ["locale"], {locale: []}], - [false, ["locale"], {locale: ["foo", gPolicy.locale + "-invalid"]}], - [true, null, {locale: ["not-a-locale", gPolicy.locale()]}], - - // version - - [false, ["version"], {version: []}], - [false, ["version"], {version: ["-1", gAppInfo.version + "-invalid", "asdf", "0,4", "99.99", "0.1.1.1"]}], - [true, null, {version: ["99999999.999", "-1", gAppInfo.version]}], - - [false, ["minVersion"], {minVersion: "1.0.1"}], - [true, null, {minVersion: "1.0b1"}], - [true, null, {minVersion: "1.0"}], - [true, null, {minVersion: "0.9"}], - - [false, ["maxVersion"], {maxVersion: "0.1"}], - [false, ["maxVersion"], {maxVersion: "0.9.9"}], - [false, ["maxVersion"], {maxVersion: "1.0b1"}], - [true, ["maxVersion"], {maxVersion: "1.0"}], - [true, ["maxVersion"], {maxVersion: "1.7pre"}], - - // build id - - [false, ["buildIDs"], {buildIDs: []}], - [false, ["buildIDs"], {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID + "-invalid"]}], - [true, null, {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID]}], - - [true, null, {minBuildID: prevDate(gAppInfo.platformBuildID)}], - [true, null, {minBuildID: gAppInfo.platformBuildID}], - [false, ["minBuildID"], {minBuildID: nextDate(gAppInfo.platformBuildID)}], - - [false, ["maxBuildID"], {maxBuildID: prevDate(gAppInfo.platformBuildID)}], - [true, null, {maxBuildID: gAppInfo.platformBuildID}], - [true, null, {maxBuildID: nextDate(gAppInfo.platformBuildID)}], - - // sample - - [false, ["sample"], {sample: -1 }], - [false, ["sample"], {sample: 0.0}], - [false, ["sample"], {sample: 0.1}], - [true, null, {sample: 0.5}], - [true, null, {sample: 0.6}], - [true, null, {sample: 1.0}], - [true, null, {sample: 0.5}], - - // experiment control - - [false, ["disabled"], {disabled: true}], - [true, null, {disabled: false}], - - [false, ["frozen"], {frozen: true}], - [true, null, {frozen: false}], - - [false, null, {frozen: true, disabled: true}], - [false, null, {frozen: true, disabled: false}], - [false, null, {frozen: false, disabled: true}], - [true, null, {frozen: false, disabled: false}], - - // jsfilter - - [true, null, {jsfilter: "function filter(c) { return true; }"}], - [false, ["jsfilter-false"], {jsfilter: "function filter(c) { return false; }"}], - [true, null, {jsfilter: "function filter(c) { return 123; }"}], // truthy - [false, ["jsfilter-false"], {jsfilter: "function filter(c) { return ''; }"}], // falsy - [false, ["jsfilter-false"], {jsfilter: "function filter(c) { var a = []; }"}], // undefined - [false, ["jsfilter-threw", "some error"], {jsfilter: "function filter(c) { throw new Error('some error'); }"}], - [false, ["jsfilter-evalfailed"], {jsfilter: "123, this won't work"}], - [true, null, {jsfilter: "var filter = " + sanityFilter.toSource()}], - ]; - - for (let i=0; i<testData.length; ++i) { - let entry = testData[i]; - let applicable; - let reason = null; - - yield applicableFromManifestData(entry[2], gPolicy).then( - value => applicable = value, - value => { - applicable = false; - reason = value; - } - ); - - Assert.equal(applicable, entry[0], - "Experiment entry applicability should match for test " - + i + ": " + JSON.stringify(entry[2])); - - let expectedReason = entry[1]; - if (!applicable && expectedReason) { - Assert.ok(arraysEqual(reason, expectedReason), - "Experiment rejection reasons should match for test " + i + ". " - + "Got " + JSON.stringify(reason) + ", expected " - + JSON.stringify(expectedReason)); - } - } -}); - -add_task(function* test_times() { - let now = new Date(2014, 5, 6, 12); - let nowSec = now.getTime() / 1000; - let testData = [ - // "expected applicable?", rejection reason or null, fake now date, manifest data - - // start time - - [true, null, now, - {startTime: nowSec - 5 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - [true, null, now, - {startTime: nowSec, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - [false, "startTime", now, - {startTime: nowSec + 5 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - - // end time - - [false, "endTime", now, - {startTime: nowSec - 5 * SEC_IN_ONE_DAY, - endTime: nowSec - 10 * SEC_IN_ONE_DAY}], - [false, "endTime", now, - {startTime: nowSec - 5 * SEC_IN_ONE_DAY, - endTime: nowSec - 5 * SEC_IN_ONE_DAY}], - - // max start time - - [false, "maxStartTime", now, - {maxStartTime: nowSec - 15 * SEC_IN_ONE_DAY, - startTime: nowSec - 10 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - [false, "maxStartTime", now, - {maxStartTime: nowSec - 1 * SEC_IN_ONE_DAY, - startTime: nowSec - 10 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - [false, "maxStartTime", now, - {maxStartTime: nowSec - 10 * SEC_IN_ONE_DAY, - startTime: nowSec - 10 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - [true, null, now, - {maxStartTime: nowSec, - startTime: nowSec - 10 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - [true, null, now, - {maxStartTime: nowSec + 1 * SEC_IN_ONE_DAY, - startTime: nowSec - 10 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - - // max active seconds - - [true, null, now, - {maxActiveSeconds: 5 * SEC_IN_ONE_DAY, - startTime: nowSec - 10 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - [true, null, now, - {maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - startTime: nowSec - 10 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - [true, null, now, - {maxActiveSeconds: 15 * SEC_IN_ONE_DAY, - startTime: nowSec - 10 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - [true, null, now, - {maxActiveSeconds: 20 * SEC_IN_ONE_DAY, - startTime: nowSec - 10 * SEC_IN_ONE_DAY, - endTime: nowSec + 10 * SEC_IN_ONE_DAY}], - ]; - - for (let i=0; i<testData.length; ++i) { - let entry = testData[i]; - let applicable; - let reason = null; - defineNow(gPolicy, entry[2]); - - yield applicableFromManifestData(entry[3], gPolicy).then( - value => applicable = value, - value => { - applicable = false; - reason = value; - } - ); - - Assert.equal(applicable, entry[0], - "Experiment entry applicability should match for test " - + i + ": " + JSON.stringify([entry[2], entry[3]])); - if (!applicable && entry[1]) { - Assert.equal(reason, entry[1], "Experiment rejection reason should match for test " + i); - } - } -}); - -add_task(function* test_shutdown() { - yield TelemetryController.testShutdown(); -}); diff --git a/browser/experiments/test/xpcshell/test_disableExperiments.js b/browser/experiments/test/xpcshell/test_disableExperiments.js deleted file mode 100644 index 8441b922d..000000000 --- a/browser/experiments/test/xpcshell/test_disableExperiments.js +++ /dev/null @@ -1,180 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource://testing-common/AddonManagerTesting.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Experiments", - "resource:///modules/experiments/Experiments.jsm"); - -const MANIFEST_HANDLER = "manifests/handler"; - -const SEC_IN_ONE_DAY = 24 * 60 * 60; -const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000; - -var gHttpServer = null; -var gHttpRoot = null; -var gDataRoot = null; -var gPolicy = null; -var gManifestObject = null; -var gManifestHandlerURI = null; - -function run_test() { - run_next_test(); -} - -add_task(function* test_setup() { - loadAddonManager(); - - gHttpServer = new HttpServer(); - gHttpServer.start(-1); - let port = gHttpServer.identity.primaryPort; - gHttpRoot = "http://localhost:" + port + "/"; - gDataRoot = gHttpRoot + "data/"; - gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER; - gHttpServer.registerDirectory("/data/", do_get_cwd()); - gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => { - response.setStatusLine(null, 200, "OK"); - response.write(JSON.stringify(gManifestObject)); - response.processAsync(); - response.finish(); - }); - do_register_cleanup(() => gHttpServer.stop(() => {})); - - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); - Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); - Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); - Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI); - Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0); - - gPolicy = new Experiments.Policy(); - patchPolicy(gPolicy, { - updatechannel: () => "nightly", - oneshotTimer: (callback, timeout, thisObj, name) => {}, - }); -}); - -// Test disabling the feature stops current and future experiments. - -add_task(function* test_disableExperiments() { - const OBSERVER_TOPIC = "experiments-changed"; - let observerFireCount = 0; - let expectedObserverFireCount = 0; - let observer = () => ++observerFireCount; - Services.obs.addObserver(observer, OBSERVER_TOPIC, false); - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY); - let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let startDate2 = futureDate(baseDate, 150 * MS_IN_ONE_DAY); - let endDate2 = futureDate(baseDate, 200 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT2_ID, - xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, - xpiHash: EXPERIMENT2_XPI_SHA1, - startTime: dateToSeconds(startDate2), - endTime: dateToSeconds(endDate2), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate1), - endTime: dateToSeconds(endDate1), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - // Use updateManifest() to provide for coverage of that path. - - let now = baseDate; - defineNow(gPolicy, now); - - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are installed."); - - // Trigger update, clock set for experiment 1 to start. - - now = futureDate(startDate1, 5 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - - yield experiments.updateManifest(); - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - Assert.equal(list[0].active, true, "Experiment should be active."); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 1, "An experiment add-on was installed."); - - // Disable the experiments feature. Check that we stop the running experiment. - - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, false); - yield experiments._mainTask; - - Assert.equal(observerFireCount, ++expectedObserverFireCount, - "Experiments observer should have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry."); - Assert.equal(list[0].active, false, "Experiment entry should not be active."); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "The experiment add-on should be uninstalled."); - - // Trigger update, clock set for experiment 2 to start. Verify we don't start it. - - now = startDate2; - defineNow(gPolicy, now); - - try { - yield experiments.updateManifest(); - } catch (e) { - // This exception is expected, we rethrow everything else - if (e.message != "experiments are disabled") { - throw e; - } - } - - experiments.notify(); - yield experiments._mainTask; - - Assert.equal(observerFireCount, expectedObserverFireCount, - "Experiments observer should not have been called."); - - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should still have 1 entry."); - Assert.equal(list[0].active, false, "Experiment entry should not be active."); - addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "There should still be no experiment add-on installed."); - - // Cleanup. - - Services.obs.removeObserver(observer, OBSERVER_TOPIC); - yield promiseRestartManager(); - yield removeCacheFile(); -}); diff --git a/browser/experiments/test/xpcshell/test_fetch.js b/browser/experiments/test/xpcshell/test_fetch.js deleted file mode 100644 index e8d76fa35..000000000 --- a/browser/experiments/test/xpcshell/test_fetch.js +++ /dev/null @@ -1,68 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); -Cu.import("resource:///modules/experiments/Experiments.jsm"); - -var gHttpServer = null; -var gHttpRoot = null; -var gPolicy = new Experiments.Policy(); - -function run_test() { - loadAddonManager(); - - gHttpServer = new HttpServer(); - gHttpServer.start(-1); - let port = gHttpServer.identity.primaryPort; - gHttpRoot = "http://localhost:" + port + "/"; - gHttpServer.registerDirectory("/", do_get_cwd()); - do_register_cleanup(() => gHttpServer.stop(() => {})); - - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); - Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); - Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); - - patchPolicy(gPolicy, { - updatechannel: () => "nightly", - }); - - run_next_test(); -} - -add_task(function* test_fetchAndCache() { - Services.prefs.setCharPref(PREF_MANIFEST_URI, gHttpRoot + "experiments_1.manifest"); - let ex = new Experiments.Experiments(gPolicy); - - Assert.equal(ex._experiments, null, "There should be no cached experiments yet."); - yield ex.updateManifest(); - Assert.notEqual(ex._experiments.size, 0, "There should be cached experiments now."); - - yield promiseRestartManager(); -}); - -add_task(function* test_checkCache() { - let ex = new Experiments.Experiments(gPolicy); - yield ex.notify(); - Assert.notEqual(ex._experiments.size, 0, "There should be cached experiments now."); - - yield promiseRestartManager(); -}); - -add_task(function* test_fetchInvalid() { - yield removeCacheFile(); - - Services.prefs.setCharPref(PREF_MANIFEST_URI, gHttpRoot + "experiments_1.manifest"); - let ex = new Experiments.Experiments(gPolicy); - yield ex.updateManifest(); - Assert.notEqual(ex._experiments.size, 0, "There should be experiments"); - - Services.prefs.setCharPref(PREF_MANIFEST_URI, gHttpRoot + "invalid.manifest"); - yield ex.updateManifest() - Assert.notEqual(ex._experiments.size, 0, "There should still be experiments: fetch failure shouldn't remove them."); - - yield promiseRestartManager(); -}); diff --git a/browser/experiments/test/xpcshell/test_nethang_bug1012924.js b/browser/experiments/test/xpcshell/test_nethang_bug1012924.js deleted file mode 100644 index 7ef604901..000000000 --- a/browser/experiments/test/xpcshell/test_nethang_bug1012924.js +++ /dev/null @@ -1,47 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource:///modules/experiments/Experiments.jsm"); - -const MANIFEST_HANDLER = "manifests/handler"; - -function run_test() { - run_next_test(); -} - -add_task(function* test_setup() { - loadAddonManager(); - do_get_profile(); - - let httpServer = new HttpServer(); - httpServer.start(-1); - let port = httpServer.identity.primaryPort; - let httpRoot = "http://localhost:" + port + "/"; - let handlerURI = httpRoot + MANIFEST_HANDLER; - httpServer.registerPathHandler("/" + MANIFEST_HANDLER, - (request, response) => { - response.processAsync(); - response.setStatus(null, 200, "OK"); - response.write("["); // never finish! - }); - - do_register_cleanup(() => httpServer.stop(() => {})); - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); - Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); - Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); - Services.prefs.setCharPref(PREF_MANIFEST_URI, handlerURI); - Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0); - - let experiments = Experiments.instance(); - experiments.updateManifest().then( - () => { - Assert.ok(true, "updateManifest finished successfully"); - }, - (e) => { - do_throw("updateManifest should not have failed: got error " + e); - }); - yield experiments.uninit(); -}); diff --git a/browser/experiments/test/xpcshell/test_previous_provider.js b/browser/experiments/test/xpcshell/test_previous_provider.js deleted file mode 100644 index f7186e159..000000000 --- a/browser/experiments/test/xpcshell/test_previous_provider.js +++ /dev/null @@ -1,179 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource:///modules/experiments/Experiments.jsm"); -Cu.import("resource://testing-common/httpd.js"); - -var gDataRoot; -var gHttpServer; -var gManifestObject; - -function run_test() { - run_next_test(); -} - -add_task(function test_setup() { - loadAddonManager(); - do_get_profile(); - - gHttpServer = new HttpServer(); - gHttpServer.start(-1); - let httpRoot = "http://localhost:" + gHttpServer.identity.primaryPort + "/"; - gDataRoot = httpRoot + "data/"; - gHttpServer.registerDirectory("/data/", do_get_cwd()); - gHttpServer.registerPathHandler("/manifests/handler", (req, res) => { - res.setStatusLine(null, 200, "OK"); - res.write(JSON.stringify(gManifestObject)); - res.processAsync(); - res.finish(); - }); - do_register_cleanup(() => gHttpServer.stop(() => {})); - - Services.prefs.setBoolPref("experiments.enabled", true); - Services.prefs.setCharPref("experiments.manifest.uri", - httpRoot + "manifests/handler"); - Services.prefs.setBoolPref("experiments.logging.dump", true); - Services.prefs.setCharPref("experiments.logging.level", "Trace"); -}); - -add_task(function* test_provider_basic() { - let e = Experiments.instance(); - - let provider = new Experiments.PreviousExperimentProvider(e); - e._setPreviousExperimentsProvider(provider); - - let deferred = Promise.defer(); - provider.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons); - }); - let experimentAddons = yield deferred.promise; - Assert.ok(Array.isArray(experimentAddons), "getAddonsByTypes returns an Array."); - Assert.equal(experimentAddons.length, 0, "No previous add-ons returned."); - - gManifestObject = { - version: 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: Date.now() / 1000 - 60, - endTime: Date.now() / 1000 + 60, - maxActiveSeconds: 60, - appName: ["XPCShell"], - channel: [e._policy.updatechannel()], - }, - ], - }; - - yield e.updateManifest(); - - deferred = Promise.defer(); - provider.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons); - }); - experimentAddons = yield deferred.promise; - Assert.equal(experimentAddons.length, 0, "Still no previous experiment."); - - let experiments = yield e.getExperiments(); - Assert.equal(experiments.length, 1, "1 experiment present."); - Assert.ok(experiments[0].active, "It is active."); - - // Deactivate it. - defineNow(e._policy, new Date(gManifestObject.experiments[0].endTime * 1000 + 1000)); - yield e.updateManifest(); - - experiments = yield e.getExperiments(); - Assert.equal(experiments.length, 1, "1 experiment present."); - Assert.equal(experiments[0].active, false, "It isn't active."); - - deferred = Promise.defer(); - provider.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons); - }); - experimentAddons = yield deferred.promise; - Assert.equal(experimentAddons.length, 1, "1 previous add-on known."); - Assert.equal(experimentAddons[0].id, EXPERIMENT1_ID, "ID matches expected."); - - deferred = Promise.defer(); - provider.getAddonByID(EXPERIMENT1_ID, (addon) => { - deferred.resolve(addon); - }); - let addon = yield deferred.promise; - Assert.ok(addon, "We got an add-on from its ID."); - Assert.equal(addon.id, EXPERIMENT1_ID, "ID matches expected."); - Assert.ok(addon.appDisabled, "Add-on is a previous experiment."); - Assert.ok(addon.userDisabled, "Add-on is disabled."); - Assert.equal(addon.type, "experiment", "Add-on is an experiment."); - Assert.equal(addon.isActive, false, "Add-on is not active."); - Assert.equal(addon.permissions, 0, "Add-on has no permissions."); - - deferred = Promise.defer(); - AddonManager.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons); - }); - experimentAddons = yield deferred.promise; - Assert.equal(experimentAddons.length, 1, "Got 1 experiment from add-on manager."); - Assert.equal(experimentAddons[0].id, EXPERIMENT1_ID, "ID matches expected."); - Assert.ok(experimentAddons[0].appDisabled, "It is a previous experiment add-on."); -}); - -add_task(function* test_active_and_previous() { - // Building on the previous test, activate experiment 2. - let e = Experiments.instance(); - let provider = new Experiments.PreviousExperimentProvider(e); - e._setPreviousExperimentsProvider(provider); - - gManifestObject = { - version: 1, - experiments: [ - { - id: EXPERIMENT2_ID, - xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, - xpiHash: EXPERIMENT2_XPI_SHA1, - startTime: Date.now() / 1000 - 60, - endTime: Date.now() / 1000 + 60, - maxActiveSeconds: 60, - appName: ["XPCShell"], - channel: [e._policy.updatechannel()], - }, - ], - }; - - defineNow(e._policy, new Date()); - yield e.updateManifest(); - - let experiments = yield e.getExperiments(); - Assert.equal(experiments.length, 2, "2 experiments known."); - - let deferred = Promise.defer(); - provider.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons); - }); - let experimentAddons = yield deferred.promise; - Assert.equal(experimentAddons.length, 1, "1 previous experiment."); - - deferred = Promise.defer(); - AddonManager.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons); - }); - experimentAddons = yield deferred.promise; - Assert.equal(experimentAddons.length, 2, "2 experiment add-ons known."); - - for (let addon of experimentAddons) { - if (addon.id == EXPERIMENT1_ID) { - Assert.equal(addon.isActive, false, "Add-on is not active."); - Assert.ok(addon.appDisabled, "Should be a previous experiment."); - } - else if (addon.id == EXPERIMENT2_ID) { - Assert.ok(addon.isActive, "Add-on is active."); - Assert.ok(!addon.appDisabled, "Should not be a previous experiment."); - } - else { - throw new Error("Unexpected add-on ID: " + addon.id); - } - } -}); diff --git a/browser/experiments/test/xpcshell/test_telemetry.js b/browser/experiments/test/xpcshell/test_telemetry.js deleted file mode 100644 index 02bd15d2b..000000000 --- a/browser/experiments/test/xpcshell/test_telemetry.js +++ /dev/null @@ -1,294 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource://gre/modules/TelemetryLog.jsm"); -var bsp = Cu.import("resource:///modules/experiments/Experiments.jsm"); - - -const MANIFEST_HANDLER = "manifests/handler"; - -const SEC_IN_ONE_DAY = 24 * 60 * 60; -const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000; - - -var gHttpServer = null; -var gHttpRoot = null; -var gDataRoot = null; -var gPolicy = null; -var gManifestObject = null; -var gManifestHandlerURI = null; - -const TLOG = bsp.TELEMETRY_LOG; - -function checkEvent(event, id, data) -{ - do_print("Checking message " + id); - Assert.equal(event[0], id, "id should match"); - Assert.ok(event[1] > 0, "timestamp should be greater than 0"); - - if (data === undefined) { - Assert.equal(event.length, 2, "event array should have 2 entries"); - } else { - Assert.equal(event.length, data.length + 2, "event entry count should match expected count"); - for (var i = 0; i < data.length; ++i) { - Assert.equal(typeof(event[i + 2]), "string", "event entry should be a string"); - Assert.equal(event[i + 2], data[i], "event entry should match expected entry"); - } - } -} - -function run_test() { - run_next_test(); -} - -add_task(function* test_setup() { - loadAddonManager(); - - gHttpServer = new HttpServer(); - gHttpServer.start(-1); - let port = gHttpServer.identity.primaryPort; - gHttpRoot = "http://localhost:" + port + "/"; - gDataRoot = gHttpRoot + "data/"; - gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER; - gHttpServer.registerDirectory("/data/", do_get_cwd()); - gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => { - response.setStatusLine(null, 200, "OK"); - response.write(JSON.stringify(gManifestObject)); - response.processAsync(); - response.finish(); - }); - do_register_cleanup(() => gHttpServer.stop(() => {})); - - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); - Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); - Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); - Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI); - Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0); - - gPolicy = new Experiments.Policy(); - let dummyTimer = { cancel: () => {}, clear: () => {} }; - patchPolicy(gPolicy, { - updatechannel: () => "nightly", - oneshotTimer: (callback, timeout, thisObj, name) => dummyTimer, - }); - - yield removeCacheFile(); -}); - -// Test basic starting and stopping of experiments. - -add_task(function* test_telemetryBasics() { - // Check TelemetryLog instead of TelemetrySession.getPayload().log because - // TelemetrySession gets Experiments.instance() and side-effects log entries. - - let expectedLogLength = 0; - - // Dates the following tests are based on. - - let baseDate = new Date(2014, 5, 1, 12); - let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY); - let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY); - let startDate2 = futureDate(baseDate, 150 * MS_IN_ONE_DAY); - let endDate2 = futureDate(baseDate, 200 * MS_IN_ONE_DAY); - - // The manifest data we test with. - - gManifestObject = { - "version": 1, - experiments: [ - { - id: EXPERIMENT1_ID, - xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, - xpiHash: EXPERIMENT1_XPI_SHA1, - startTime: dateToSeconds(startDate1), - endTime: dateToSeconds(endDate1), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - { - id: EXPERIMENT2_ID, - xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, - xpiHash: EXPERIMENT2_XPI_SHA1, - startTime: dateToSeconds(startDate2), - endTime: dateToSeconds(endDate2), - maxActiveSeconds: 10 * SEC_IN_ONE_DAY, - appName: ["XPCShell"], - channel: ["nightly"], - }, - ], - }; - - let experiments = new Experiments.Experiments(gPolicy); - - // Trigger update, clock set to before any activation. - // Use updateManifest() to provide for coverage of that path. - - let now = baseDate; - defineNow(gPolicy, now); - - yield experiments.updateManifest(); - let list = yield experiments.getExperiments(); - Assert.equal(list.length, 0, "Experiment list should be empty."); - - expectedLogLength += 2; - let log = TelemetryLog.entries(); - do_print("Telemetry log: " + JSON.stringify(log)); - Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries."); - checkEvent(log[log.length-2], TLOG.ACTIVATION_KEY, - [TLOG.ACTIVATION.REJECTED, EXPERIMENT1_ID, "startTime"]); - checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY, - [TLOG.ACTIVATION.REJECTED, EXPERIMENT2_ID, "startTime"]); - - // Trigger update, clock set for experiment 1 to start. - - now = futureDate(startDate1, 5 * MS_IN_ONE_DAY); - defineNow(gPolicy, now); - - yield experiments.updateManifest(); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); - - expectedLogLength += 1; - log = TelemetryLog.entries(); - Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries. Got " + log.toSource()); - checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY, - [TLOG.ACTIVATION.ACTIVATED, EXPERIMENT1_ID]); - - // Trigger update, clock set for experiment 1 to stop. - - now = futureDate(endDate1, 1000); - defineNow(gPolicy, now); - - yield experiments.updateManifest(); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entry."); - - expectedLogLength += 2; - log = TelemetryLog.entries(); - Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries."); - checkEvent(log[log.length-2], TLOG.TERMINATION_KEY, - [TLOG.TERMINATION.EXPIRED, EXPERIMENT1_ID]); - checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY, - [TLOG.ACTIVATION.REJECTED, EXPERIMENT2_ID, "startTime"]); - - // Trigger update, clock set for experiment 2 to start with invalid hash. - - now = startDate2; - defineNow(gPolicy, now); - gManifestObject.experiments[1].xpiHash = "sha1:0000000000000000000000000000000000000000"; - - yield experiments.updateManifest(); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 1, "Experiment list should have 1 entries."); - - expectedLogLength += 1; - log = TelemetryLog.entries(); - Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries."); - checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY, - [TLOG.ACTIVATION.INSTALL_FAILURE, EXPERIMENT2_ID]); - - // Trigger update, clock set for experiment 2 to properly start now. - - now = futureDate(now, MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[1].xpiHash = EXPERIMENT2_XPI_SHA1; - - yield experiments.updateManifest(); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 2, "Experiment list should have 2 entries."); - - expectedLogLength += 1; - log = TelemetryLog.entries(); - Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries."); - checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY, - [TLOG.ACTIVATION.ACTIVATED, EXPERIMENT2_ID]); - - // Fake user uninstall of experiment via add-on manager. - - now = futureDate(now, MS_IN_ONE_DAY); - defineNow(gPolicy, now); - - yield experiments.disableExperiment(TLOG.TERMINATION.ADDON_UNINSTALLED); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 2, "Experiment list should have 2 entries."); - - expectedLogLength += 1; - log = TelemetryLog.entries(); - Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries."); - checkEvent(log[log.length-1], TLOG.TERMINATION_KEY, - [TLOG.TERMINATION.ADDON_UNINSTALLED, EXPERIMENT2_ID]); - - // Trigger update with experiment 1a ready to start. - - now = futureDate(now, MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[0].id = EXPERIMENT3_ID; - gManifestObject.experiments[0].endTime = dateToSeconds(futureDate(now, 50 * MS_IN_ONE_DAY)); - - yield experiments.updateManifest(); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 3, "Experiment list should have 3 entries."); - - expectedLogLength += 1; - log = TelemetryLog.entries(); - Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries."); - checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY, - [TLOG.ACTIVATION.ACTIVATED, EXPERIMENT3_ID]); - - // Trigger disable of an experiment via the API. - - now = futureDate(now, MS_IN_ONE_DAY); - defineNow(gPolicy, now); - - yield experiments.disableExperiment(TLOG.TERMINATION.FROM_API); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 3, "Experiment list should have 3 entries."); - - expectedLogLength += 1; - log = TelemetryLog.entries(); - Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries."); - checkEvent(log[log.length-1], TLOG.TERMINATION_KEY, - [TLOG.TERMINATION.FROM_API, EXPERIMENT3_ID]); - - // Trigger update with experiment 1a ready to start. - - now = futureDate(now, MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[0].id = EXPERIMENT4_ID; - gManifestObject.experiments[0].endTime = dateToSeconds(futureDate(now, 50 * MS_IN_ONE_DAY)); - - yield experiments.updateManifest(); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 4, "Experiment list should have 4 entries."); - - expectedLogLength += 1; - log = TelemetryLog.entries(); - Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries."); - checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY, - [TLOG.ACTIVATION.ACTIVATED, EXPERIMENT4_ID]); - - // Trigger experiment termination by something other than expiry via the manifest. - - now = futureDate(now, MS_IN_ONE_DAY); - defineNow(gPolicy, now); - gManifestObject.experiments[0].os = "Plan9"; - - yield experiments.updateManifest(); - list = yield experiments.getExperiments(); - Assert.equal(list.length, 4, "Experiment list should have 4 entries."); - - expectedLogLength += 1; - log = TelemetryLog.entries(); - Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries."); - checkEvent(log[log.length-1], TLOG.TERMINATION_KEY, - [TLOG.TERMINATION.RECHECK, EXPERIMENT4_ID, "os"]); - - // Cleanup. - - yield promiseRestartManager(); - yield removeCacheFile(); -}); diff --git a/browser/experiments/test/xpcshell/test_telemetry_disabled.js b/browser/experiments/test/xpcshell/test_telemetry_disabled.js deleted file mode 100644 index 74f85ccfc..000000000 --- a/browser/experiments/test/xpcshell/test_telemetry_disabled.js +++ /dev/null @@ -1,21 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource:///modules/experiments/Experiments.jsm"); - -add_test(function test_experiments_activation() { - do_get_profile(); - loadAddonManager(); - - Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); - Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, false); - - let experiments = Experiments.instance(); - Assert.ok(!experiments.enabled, "Experiments must be disabled if Telemetry is disabled."); - - // TODO: Test that Experiments are turned back on when bug 1232648 lands. - - run_next_test(); -}); diff --git a/browser/experiments/test/xpcshell/test_upgrade.js b/browser/experiments/test/xpcshell/test_upgrade.js deleted file mode 100644 index f094a406d..000000000 --- a/browser/experiments/test/xpcshell/test_upgrade.js +++ /dev/null @@ -1,52 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; -Cu.import("resource:///modules/experiments/Experiments.jsm"); - -var cacheData = { - _enabled: true, - _manifestData: { - id: "foobartestid", - xpiURL: "http://example.com/foo.xpi", - xpiHash: "sha256:abcde", - startTime: 0, - endTime: 2000000000, - maxActiveSeconds: 40000000, - appName: "TestApp", - channel: "test-foo", - }, - _needsUpdate: false, - _randomValue: 0.5, - _failedStart: false, - _name: "Foo", - _description: "Foobar", - _homepageURL: "", - _addonId: "foo@test", - _startDate: 0, - _endDate: 2000000000, - _branch: null -}; - -add_task(function* test_valid() { - let e = new Experiments.ExperimentEntry(); - Assert.ok(e.initFromCacheData(cacheData)); - Assert.ok(e.enabled); -}); - -add_task(function* test_upgrade() { - let e = new Experiments.ExperimentEntry(); - delete cacheData._branch; - Assert.ok(e.initFromCacheData(cacheData)); - Assert.ok(e.enabled); -}); - -add_task(function* test_missing() { - let e = new Experiments.ExperimentEntry(); - delete cacheData._name; - Assert.ok(!e.initFromCacheData(cacheData)); -}); - -function run_test() { - run_next_test(); -} diff --git a/browser/experiments/test/xpcshell/xpcshell.ini b/browser/experiments/test/xpcshell/xpcshell.ini deleted file mode 100644 index 5921c9c47..000000000 --- a/browser/experiments/test/xpcshell/xpcshell.ini +++ /dev/null @@ -1,31 +0,0 @@ -[DEFAULT] -head = head.js -tail = -tags = addons -firefox-appdir = browser -skip-if = toolkit == 'android' -support-files = - experiments_1.manifest - experiment-1.xpi - experiment-1a.xpi - experiment-2.xpi - experiment-racybranch.xpi - !/toolkit/mozapps/webextensions/test/xpcshell/head_addons.js -generated-files = - experiment-1.xpi - experiment-1a.xpi - experiment-2.xpi - experiment-racybranch.xpi - -[test_activate.js] -[test_api.js] -[test_cache.js] -[test_cacherace.js] -[test_conditions.js] -[test_disableExperiments.js] -[test_fetch.js] -[test_telemetry.js] -[test_telemetry_disabled.js] -[test_previous_provider.js] -[test_upgrade.js] -[test_nethang_bug1012924.js] diff --git a/browser/fonts/EmojiOneMozilla.ttf b/browser/fonts/EmojiOneMozilla.ttf Binary files differdeleted file mode 100644 index 50356509d..000000000 --- a/browser/fonts/EmojiOneMozilla.ttf +++ /dev/null diff --git a/browser/fonts/README.txt b/browser/fonts/README.txt index 188ea3fff..ac1f6d9de 100644 --- a/browser/fonts/README.txt +++ b/browser/fonts/README.txt @@ -1,9 +1,9 @@ -EmojiOne Mozilla +Twemoji Mozilla ================ -The upstream repository of EmojiOne Mozilla can be found at +The upstream repository of Twemoji Mozilla can be found at - https://github.com/mozilla/emojione-colr + https://github.com/mozilla/twemoji-colr Please refer commit history for the current version of the font. This file purposely omit the version, so there is no need to update it here. diff --git a/browser/fonts/TwemojiMozilla.ttf b/browser/fonts/TwemojiMozilla.ttf Binary files differnew file mode 100644 index 000000000..1933891d9 --- /dev/null +++ b/browser/fonts/TwemojiMozilla.ttf diff --git a/browser/fonts/moz.build b/browser/fonts/moz.build index b1a43e528..5cb98333b 100644 --- a/browser/fonts/moz.build +++ b/browser/fonts/moz.build @@ -7,5 +7,5 @@ if CONFIG['OS_ARCH'] in ('WINNT', 'Linux'): DIST_SUBDIR = '' FINAL_TARGET_FILES.fonts += [ - 'EmojiOneMozilla.ttf' + 'TwemojiMozilla.ttf' ] diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 015daa8c7..5540feed9 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -374,8 +374,6 @@ @RESPATH@/browser/components/devtools-startup.js @RESPATH@/browser/components/webideCli.js @RESPATH@/browser/components/webideComponents.manifest -@RESPATH@/browser/components/Experiments.manifest -@RESPATH@/browser/components/ExperimentsService.js @RESPATH@/browser/components/browser-newtab.xpt @RESPATH@/browser/components/aboutNewTabService.js @RESPATH@/browser/components/NewTabComponents.manifest @@ -781,28 +779,6 @@ bin/libfreebl_32int64_3.so @BINPATH@/maintenanceservice_installer.exe #endif -; [Crash Reporter] -; -#ifdef MOZ_CRASHREPORTER -@RESPATH@/components/CrashService.manifest -@RESPATH@/components/CrashService.js -@RESPATH@/components/toolkit_crashservice.xpt -#ifdef XP_MACOSX -@BINPATH@/crashreporter.app/ -#else -@BINPATH@/crashreporter@BIN_SUFFIX@ -@BINPATH@/minidump-analyzer@BIN_SUFFIX@ -@RESPATH@/crashreporter.ini -#ifdef XP_UNIX -@RESPATH@/Throbber-small.gif -#endif -#endif -@RESPATH@/browser/crashreporter-override.ini -#ifdef MOZ_CRASHREPORTER_INJECTOR -@BINPATH@/breakpadinjector.dll -#endif -#endif - @RESPATH@/components/dom_audiochannel.xpt ; Shutdown Terminator diff --git a/browser/locales/Makefile.in b/browser/locales/Makefile.in index b3ecfd359..af200147f 100644 --- a/browser/locales/Makefile.in +++ b/browser/locales/Makefile.in @@ -165,11 +165,6 @@ else endif endif -ifdef MOZ_CRASHREPORTER -libs:: crashreporter-override.ini - $(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET) -endif - ident: @printf 'fx_revision ' @$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \ diff --git a/browser/modules/AboutHome.jsm b/browser/modules/AboutHome.jsm index 01cbafba9..8c0fc4c15 100644 --- a/browser/modules/AboutHome.jsm +++ b/browser/modules/AboutHome.jsm @@ -24,17 +24,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm"); -// Url to fetch snippets, in the urlFormatter service format. -const SNIPPETS_URL_PREF = "browser.aboutHomeSnippets.updateUrl"; - -// Should be bumped up if the snippets content format changes. -const STARTPAGE_VERSION = 4; +// Should be bumped up if any data content format changes. +const STARTPAGE_VERSION = 5; this.AboutHomeUtils = { - get snippetsVersion() { - return STARTPAGE_VERSION; - }, - /* * showKnowYourRights - Determines if the user should be shown the * about:rights notification. The notification should *not* be shown if @@ -77,16 +70,6 @@ this.AboutHomeUtils = { }; /** - * Returns the URL to fetch snippets from, in the urlFormatter service format. - */ -XPCOMUtils.defineLazyGetter(AboutHomeUtils, "snippetsURL", function() { - let updateURL = Services.prefs - .getCharPref(SNIPPETS_URL_PREF) - .replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION); - return Services.urlFormatter.formatURL(updateURL); -}); - -/** * This code provides services to the about:home page. Whenever * about:home needs to do something chrome-privileged, it sends a * message that's handled here. @@ -169,9 +152,7 @@ var AboutHome = { ss.promiseInitialized.then(function() { let data = { showRestoreLastSession: ss.canRestoreLastSession, - snippetsURL: AboutHomeUtils.snippetsURL, - showKnowYourRights: AboutHomeUtils.showKnowYourRights, - snippetsVersion: AboutHomeUtils.snippetsVersion, + showKnowYourRights: AboutHomeUtils.showKnowYourRights }; if (AboutHomeUtils.showKnowYourRights) { diff --git a/browser/modules/ContentCrashHandlers.jsm b/browser/modules/ContentCrashHandlers.jsm index 2f755d142..488cc4f26 100644 --- a/browser/modules/ContentCrashHandlers.jsm +++ b/browser/modules/ContentCrashHandlers.jsm @@ -90,8 +90,6 @@ this.TabCrashHandler = { Services.telemetry .getHistogramById("FX_CONTENT_CRASH_DUMP_UNAVAILABLE") .add(1); - } else if (AppConstants.MOZ_CRASHREPORTER) { - this.childMap.set(childID, dumpID); } if (!this.flushCrashedBrowserQueue(childID)) { @@ -115,15 +113,6 @@ this.TabCrashHandler = { } } - // check for environment affecting crash reporting - let env = Cc["@mozilla.org/process/environment;1"] - .getService(Ci.nsIEnvironment); - let shutdown = env.exists("MOZ_CRASHREPORTER_SHUTDOWN"); - - if (shutdown) { - Services.startup.quit(Ci.nsIAppStartup.eForceQuit); - } - break; } case "oop-frameloader-crashed": { @@ -306,105 +295,10 @@ this.TabCrashHandler = { /** * Submits a crash report from about:tabcrashed, if the crash * reporter is enabled and a crash report can be found. - * - * @param aBrowser - * The <xul:browser> that the report was sent from. - * @param aFormData - * An Object with the following properties: - * - * includeURL (bool): - * Whether to include the URL that the user was on - * in the crashed tab before the crash occurred. - * URL (String) - * The URL that the user was on in the crashed tab - * before the crash occurred. - * emailMe (bool): - * Whether or not to include the user's email address - * in the crash report. - * email (String): - * The email address of the user. - * comments (String): - * Any additional comments from the user. - * - * Note that it is expected that all properties are set, - * even if they are empty. */ maybeSendCrashReport(message) { - if (!AppConstants.MOZ_CRASHREPORTER) { - return; - } - - if (!message.data.hasReport) { - // There was no report, so nothing to do. - return; - } - - let browser = message.target.browser; - - if (message.data.autoSubmit) { - // The user has opted in to autosubmitted backlogged - // crash reports in the future. - UnsubmittedCrashHandler.autoSubmit = true; - } - - let childID = this.browserMap.get(browser.permanentKey); - let dumpID = this.childMap.get(childID); - if (!dumpID) { - return; - } - - if (!message.data.sendReport) { - Services.telemetry.getHistogramById("FX_CONTENT_CRASH_NOT_SUBMITTED").add(1); - this.prefs.setBoolPref("sendReport", false); - return; - } - - let { - includeURL, - comments, - email, - emailMe, - URL, - } = message.data; - - let extraExtraKeyVals = { - "Comments": comments, - "Email": email, - "URL": URL, - }; - - // For the entries in extraExtraKeyVals, we only want to submit the - // extra data values where they are not the empty string. - for (let key in extraExtraKeyVals) { - let val = extraExtraKeyVals[key].trim(); - if (!val) { - delete extraExtraKeyVals[key]; - } - } - - // URL is special, since it's already been written to extra data by - // default. In order to make sure we don't send it, we overwrite it - // with the empty string. - if (!includeURL) { - extraExtraKeyVals["URL"] = ""; - } - - CrashSubmit.submit(dumpID, { - recordSubmission: true, - extraExtraKeyVals, - }).then(null, Cu.reportError); - - this.prefs.setBoolPref("sendReport", true); - this.prefs.setBoolPref("includeURL", includeURL); - this.prefs.setBoolPref("emailMe", emailMe); - if (emailMe) { - this.prefs.setCharPref("email", email); - } else { - this.prefs.setCharPref("email", ""); - } - - this.childMap.set(childID, null); // Avoid resubmission. - this.removeSubmitCheckboxesForSameCrash(childID); + /*** STUB ***/ + return; }, removeSubmitCheckboxesForSameCrash: function(childID) { @@ -518,17 +412,10 @@ this.TabCrashHandler = { /** * For some <xul:browser>, return a crash report dump ID for that browser * if we have been informed of one. Otherwise, return null. - * - * @param browser (<xul:browser) - * The browser to try to get the dump ID for - * @returns dumpID (String) */ getDumpID(browser) { - if (!AppConstants.MOZ_CRASHREPORTER) { - return null; - } - - return this.childMap.get(this.browserMap.get(browser.permanentKey)); + /*** STUB ***/ + return null; }, } diff --git a/browser/modules/PluginContent.jsm b/browser/modules/PluginContent.jsm index 1bbfa9a50..622d608bc 100644 --- a/browser/modules/PluginContent.jsm +++ b/browser/modules/PluginContent.jsm @@ -660,30 +660,8 @@ PluginContent.prototype = { }, submitReport: function submitReport(plugin) { - if (!AppConstants.MOZ_CRASHREPORTER) { - return; - } - if (!plugin) { - Cu.reportError("Attempted to submit crash report without an associated plugin."); - return; - } - if (!(plugin instanceof Ci.nsIObjectLoadingContent)) { - Cu.reportError("Attempted to submit crash report on plugin that does not" + - "implement nsIObjectLoadingContent."); - return; - } - - let runID = plugin.runID; - let submitURLOptIn = this.getPluginUI(plugin, "submitURLOptIn").checked; - let keyVals = {}; - let userComment = this.getPluginUI(plugin, "submitComment").value.trim(); - if (userComment) - keyVals.PluginUserComment = userComment; - if (submitURLOptIn) - keyVals.PluginContentURL = plugin.ownerDocument.URL; - - this.global.sendAsyncMessage("PluginContent:SubmitReport", - { runID, keyVals, submitURLOptIn }); + /*** STUB ***/ + return; }, reloadPage: function () { diff --git a/browser/moz.build b/browser/moz.build index a691aeef2..0985148c0 100644 --- a/browser/moz.build +++ b/browser/moz.build @@ -11,7 +11,6 @@ SPHINX_TREES['browser'] = 'docs' DIRS += [ 'base', 'components', - 'experiments', 'fonts', 'locales', 'modules', diff --git a/browser/moz.configure b/browser/moz.configure index fba4603be..d5e7dba11 100644 --- a/browser/moz.configure +++ b/browser/moz.configure @@ -4,9 +4,4 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -imply_option('MOZ_PLACES', True) -imply_option('MOZ_SERVICES_HEALTHREPORT', True) -imply_option('MOZ_SERVICES_SYNC', True) -imply_option('MOZ_SERVICES_CLOUDSYNC', True) - include('../toolkit/moz.configure') diff --git a/browser/themes/osx/shared.inc b/browser/themes/osx/shared.inc index b3ea4e199..3076450e2 100644 --- a/browser/themes/osx/shared.inc +++ b/browser/themes/osx/shared.inc @@ -1,4 +1,4 @@ -%include ../../../toolkit/themes/osx/global/shared.inc
+%include ../../../../toolkit/themes/osx/global/shared.inc
%include ../shared/browser.inc
%filter substitution
diff --git a/build/application.ini b/build/application.ini index 6b2e43a34..e60f86b69 100644 --- a/build/application.ini +++ b/build/application.ini @@ -54,8 +54,3 @@ MaxVersion=@GRE_MILESTONE@ EnableProfileMigrator=1 #endif -#if MOZ_CRASHREPORTER -[Crash Reporter] -Enabled=1 -ServerURL=https://crash-reports.mozilla.com/submit?id=@MOZ_APP_ID@&version=@MOZ_APP_VERSION@&buildid=@MOZ_BUILDID@ -#endif diff --git a/build/automation-build.mk b/build/automation-build.mk index e25f90c5d..6599cb032 100644 --- a/build/automation-build.mk +++ b/build/automation-build.mk @@ -48,11 +48,7 @@ else AUTOMATION_PPARGS += -DIS_DEBUG_BUILD=0 endif -ifdef MOZ_CRASHREPORTER -AUTOMATION_PPARGS += -DCRASHREPORTER=1 -else AUTOMATION_PPARGS += -DCRASHREPORTER=0 -endif ifdef MOZ_ASAN AUTOMATION_PPARGS += -DIS_ASAN=1 diff --git a/build/automation.py.in b/build/automation.py.in index 1c63977e8..09c9d0071 100644 --- a/build/automation.py.in +++ b/build/automation.py.in @@ -228,11 +228,7 @@ class Automation(object): if dmdPath and dmdLibrary and preloadEnvVar: env[preloadEnvVar] = os.path.join(dmdPath, dmdLibrary) - if crashreporter and not debugger: - env['MOZ_CRASHREPORTER_NO_REPORT'] = '1' - env['MOZ_CRASHREPORTER'] = '1' - else: - env['MOZ_CRASHREPORTER_DISABLE'] = '1' + env['MOZ_CRASHREPORTER_DISABLE'] = '1' # Crash on non-local network connections by default. # MOZ_DISABLE_NONLOCAL_CONNECTIONS can be set to "0" to temporarily diff --git a/build/directive4.py b/build/directive4.py index 8f05eeed5..dd8c111cf 100644 --- a/build/directive4.py +++ b/build/directive4.py @@ -49,6 +49,7 @@ if ('MOZ_OFFICIAL_BRANDING' in listConfig) or (strBrandingDirectory.endswith("br # Applies to Pale Moon Only if 'MC_PALEMOON' in listConfig: listViolations += [ + 'MOZ_EME', 'MOZ_WEBRTC' ] diff --git a/build/mobile/b2gautomation.py b/build/mobile/b2gautomation.py index d73edd419..a21809068 100644 --- a/build/mobile/b2gautomation.py +++ b/build/mobile/b2gautomation.py @@ -156,10 +156,6 @@ class B2GRemoteAutomation(Automation): if env is None: env = {} - if crashreporter: - env['MOZ_CRASHREPORTER'] = '1' - env['MOZ_CRASHREPORTER_NO_REPORT'] = '1' - # We always hide the results table in B2G; it's much slower if we don't. env['MOZ_HIDE_RESULTS_TABLE'] = '1' return env diff --git a/build/mobile/remoteautomation.py b/build/mobile/remoteautomation.py index 1358e0dfe..f098d5bba 100644 --- a/build/mobile/remoteautomation.py +++ b/build/mobile/remoteautomation.py @@ -74,11 +74,7 @@ class RemoteAutomation(Automation): if 'MOZ_HIDE_RESULTS_TABLE' in os.environ: env['MOZ_HIDE_RESULTS_TABLE'] = os.environ['MOZ_HIDE_RESULTS_TABLE'] - if crashreporter and not debugger: - env['MOZ_CRASHREPORTER_NO_REPORT'] = '1' - env['MOZ_CRASHREPORTER'] = '1' - else: - env['MOZ_CRASHREPORTER_DISABLE'] = '1' + env['MOZ_CRASHREPORTER_DISABLE'] = '1' # Crash on non-local network connections by default. # MOZ_DISABLE_NONLOCAL_CONNECTIONS can be set to "0" to temporarily @@ -215,36 +211,9 @@ class RemoteAutomation(Automation): if javaException: return True - # If crash reporting is disabled (MOZ_CRASHREPORTER!=1), we can't say - # anything. - if not self.CRASHREPORTER: - return False - - try: - dumpDir = tempfile.mkdtemp() - remoteCrashDir = posixpath.join(self._remoteProfile, 'minidumps') - if not self._devicemanager.dirExists(remoteCrashDir): - # If crash reporting is enabled (MOZ_CRASHREPORTER=1), the - # minidumps directory is automatically created when Fennec - # (first) starts, so its lack of presence is a hint that - # something went wrong. - print "Automation Error: No crash directory (%s) found on remote device" % remoteCrashDir - # Whilst no crash was found, the run should still display as a failure - return True - self._devicemanager.getDirectory(remoteCrashDir, dumpDir) + # No crash reporting means we can't say anything. + return False - logger = get_default_logger() - if logger is not None: - crashed = mozcrash.log_crashes(logger, dumpDir, symbolsPath, test=self.lastTestSeen) - else: - crashed = Automation.checkForCrashes(self, dumpDir, symbolsPath) - - finally: - try: - shutil.rmtree(dumpDir) - except: - print "WARNING: unable to remove directory: %s" % dumpDir - return crashed def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs): # If remote profile is specified, use that instead diff --git a/build/moz.build b/build/moz.build index 8d86b52bf..f25e5cfa5 100644 --- a/build/moz.build +++ b/build/moz.build @@ -42,7 +42,7 @@ if CONFIG['MC_PALEMOON']: if CONFIG['MOZ_APP_PROFILE']: DEFINES['MOZ_APP_PROFILE'] = CONFIG['MOZ_APP_PROFILE'] -for var in ('MOZ_CRASHREPORTER', 'MOZ_PROFILE_MIGRATOR', +for var in ('MOZ_PROFILE_MIGRATOR', 'MOZ_APP_STATIC_INI'): if CONFIG[var]: DEFINES[var] = True diff --git a/build/pgo/profileserver.py b/build/pgo/profileserver.py index 3e5a870c3..adc93d9b1 100644 --- a/build/pgo/profileserver.py +++ b/build/pgo/profileserver.py @@ -53,7 +53,6 @@ if __name__ == '__main__': locations=locations) env = os.environ.copy() - env["MOZ_CRASHREPORTER_NO_REPORT"] = "1" env["XPCOM_DEBUG_BREAK"] = "warn" # For VC12+, make sure we can find the right bitness of pgort1x0.dll diff --git a/build/valgrind/mach_commands.py b/build/valgrind/mach_commands.py index ba2575247..8109f0784 100644 --- a/build/valgrind/mach_commands.py +++ b/build/valgrind/mach_commands.py @@ -90,7 +90,6 @@ class MachCommands(MachCommandBase): env = os.environ.copy() env['G_SLICE'] = 'always-malloc' env['MOZ_CC_RUN_DURING_SHUTDOWN'] = '1' - env['MOZ_CRASHREPORTER_NO_REPORT'] = '1' env['XPCOM_DEBUG_BREAK'] = 'warn' env.update(self.extra_environment_variables) diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index b768d5c1f..93ffcf129 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -7,9 +7,6 @@ #include "mozilla/BasePrincipal.h" #include "nsDocShell.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif #include "nsIAddonPolicyService.h" #include "nsIContentSecurityPolicy.h" #include "nsIEffectiveTLDService.h" @@ -149,10 +146,6 @@ OriginAttributes::CreateSuffix(nsACString& aStr) const if (!mAddonId.IsEmpty()) { if (mAddonId.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) != kNotFound) { -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Crash_AddonId"), - NS_ConvertUTF16toUTF8(mAddonId)); -#endif MOZ_CRASH(); } params->Set(NS_LITERAL_STRING("addonId"), mAddonId); diff --git a/db/sqlite3/src/sqlite3.c b/db/sqlite3/src/sqlite3.c index 9c8fd6204..320d6355e 100644 --- a/db/sqlite3/src/sqlite3.c +++ b/db/sqlite3/src/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.19.3. By combining all the individual C code files into this +** version 3.21.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -22,6 +22,761 @@ #ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static #endif +/************** Begin file ctime.c *******************************************/ +/* +** 2010 February 23 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file implements routines used to report what compile-time options +** SQLite was built with. +*/ + +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS + +/* +** Include the configuration header output by 'configure' if we're using the +** autoconf-based build +*/ +#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) +#include "config.h" +#define SQLITECONFIG_H 1 +#endif + +/* These macros are provided to "stringify" the value of the define +** for those options in which the value is meaningful. */ +#define CTIMEOPT_VAL_(opt) #opt +#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) + +/* +** An array of names of all compile-time options. This array should +** be sorted A-Z. +** +** This array looks large, but in a typical installation actually uses +** only a handful of compile-time options, so most times this array is usually +** rather short and uses little memory space. +*/ +static const char * const sqlite3azCompileOpt[] = { + +/* +** BEGIN CODE GENERATED BY tool/mkctime.tcl +*/ +#if SQLITE_32BIT_ROWID + "32BIT_ROWID", +#endif +#if SQLITE_4_BYTE_ALIGNED_MALLOC + "4_BYTE_ALIGNED_MALLOC", +#endif +#if SQLITE_64BIT_STATS + "64BIT_STATS", +#endif +#if SQLITE_ALLOW_COVERING_INDEX_SCAN + "ALLOW_COVERING_INDEX_SCAN", +#endif +#if SQLITE_ALLOW_URI_AUTHORITY + "ALLOW_URI_AUTHORITY", +#endif +#ifdef SQLITE_BITMASK_TYPE + "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), +#endif +#if SQLITE_BUG_COMPATIBLE_20160819 + "BUG_COMPATIBLE_20160819", +#endif +#if SQLITE_CASE_SENSITIVE_LIKE + "CASE_SENSITIVE_LIKE", +#endif +#if SQLITE_CHECK_PAGES + "CHECK_PAGES", +#endif +#if defined(__clang__) && defined(__clang_major__) + "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "." + CTIMEOPT_VAL(__clang_minor__) "." + CTIMEOPT_VAL(__clang_patchlevel__), +#elif defined(_MSC_VER) + "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER), +#elif defined(__GNUC__) && defined(__VERSION__) + "COMPILER=gcc-" __VERSION__, +#endif +#if SQLITE_COVERAGE_TEST + "COVERAGE_TEST", +#endif +#if SQLITE_DEBUG + "DEBUG", +#endif +#if SQLITE_DEFAULT_AUTOMATIC_INDEX + "DEFAULT_AUTOMATIC_INDEX", +#endif +#if SQLITE_DEFAULT_AUTOVACUUM + "DEFAULT_AUTOVACUUM", +#endif +#ifdef SQLITE_DEFAULT_CACHE_SIZE + "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE), +#endif +#if SQLITE_DEFAULT_CKPTFULLFSYNC + "DEFAULT_CKPTFULLFSYNC", +#endif +#ifdef SQLITE_DEFAULT_FILE_FORMAT + "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT), +#endif +#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS + "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS), +#endif +#if SQLITE_DEFAULT_FOREIGN_KEYS + "DEFAULT_FOREIGN_KEYS", +#endif +#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT + "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT), +#endif +#ifdef SQLITE_DEFAULT_LOCKING_MODE + "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), +#endif +#ifdef SQLITE_DEFAULT_LOOKASIDE + "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOOKASIDE), +#endif +#if SQLITE_DEFAULT_MEMSTATUS + "DEFAULT_MEMSTATUS", +#endif +#ifdef SQLITE_DEFAULT_MMAP_SIZE + "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), +#endif +#ifdef SQLITE_DEFAULT_PAGE_SIZE + "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE), +#endif +#ifdef SQLITE_DEFAULT_PCACHE_INITSZ + "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ), +#endif +#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS + "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS), +#endif +#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS + "DEFAULT_RECURSIVE_TRIGGERS", +#endif +#ifdef SQLITE_DEFAULT_ROWEST + "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST), +#endif +#ifdef SQLITE_DEFAULT_SECTOR_SIZE + "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE), +#endif +#ifdef SQLITE_DEFAULT_SYNCHRONOUS + "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS), +#endif +#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT + "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT), +#endif +#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS + "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS), +#endif +#ifdef SQLITE_DEFAULT_WORKER_THREADS + "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS), +#endif +#if SQLITE_DIRECT_OVERFLOW_READ + "DIRECT_OVERFLOW_READ", +#endif +#if SQLITE_DISABLE_DIRSYNC + "DISABLE_DIRSYNC", +#endif +#if SQLITE_DISABLE_FTS3_UNICODE + "DISABLE_FTS3_UNICODE", +#endif +#if SQLITE_DISABLE_FTS4_DEFERRED + "DISABLE_FTS4_DEFERRED", +#endif +#if SQLITE_DISABLE_INTRINSIC + "DISABLE_INTRINSIC", +#endif +#if SQLITE_DISABLE_LFS + "DISABLE_LFS", +#endif +#if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS + "DISABLE_PAGECACHE_OVERFLOW_STATS", +#endif +#if SQLITE_DISABLE_SKIPAHEAD_DISTINCT + "DISABLE_SKIPAHEAD_DISTINCT", +#endif +#ifdef SQLITE_ENABLE_8_3_NAMES + "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), +#endif +#if SQLITE_ENABLE_API_ARMOR + "ENABLE_API_ARMOR", +#endif +#if SQLITE_ENABLE_ATOMIC_WRITE + "ENABLE_ATOMIC_WRITE", +#endif +#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE + "ENABLE_BATCH_ATOMIC_WRITE", +#endif +#if SQLITE_ENABLE_CEROD + "ENABLE_CEROD", +#endif +#if SQLITE_ENABLE_COLUMN_METADATA + "ENABLE_COLUMN_METADATA", +#endif +#if SQLITE_ENABLE_COLUMN_USED_MASK + "ENABLE_COLUMN_USED_MASK", +#endif +#if SQLITE_ENABLE_COSTMULT + "ENABLE_COSTMULT", +#endif +#if SQLITE_ENABLE_CURSOR_HINTS + "ENABLE_CURSOR_HINTS", +#endif +#if SQLITE_ENABLE_DBSTAT_VTAB + "ENABLE_DBSTAT_VTAB", +#endif +#if SQLITE_ENABLE_EXPENSIVE_ASSERT + "ENABLE_EXPENSIVE_ASSERT", +#endif +#if SQLITE_ENABLE_FTS1 + "ENABLE_FTS1", +#endif +#if SQLITE_ENABLE_FTS2 + "ENABLE_FTS2", +#endif +#if SQLITE_ENABLE_FTS3 + "ENABLE_FTS3", +#endif +#if SQLITE_ENABLE_FTS3_PARENTHESIS + "ENABLE_FTS3_PARENTHESIS", +#endif +#if SQLITE_ENABLE_FTS3_TOKENIZER + "ENABLE_FTS3_TOKENIZER", +#endif +#if SQLITE_ENABLE_FTS4 + "ENABLE_FTS4", +#endif +#if SQLITE_ENABLE_FTS5 + "ENABLE_FTS5", +#endif +#if SQLITE_ENABLE_HIDDEN_COLUMNS + "ENABLE_HIDDEN_COLUMNS", +#endif +#if SQLITE_ENABLE_ICU + "ENABLE_ICU", +#endif +#if SQLITE_ENABLE_IOTRACE + "ENABLE_IOTRACE", +#endif +#if SQLITE_ENABLE_JSON1 + "ENABLE_JSON1", +#endif +#if SQLITE_ENABLE_LOAD_EXTENSION + "ENABLE_LOAD_EXTENSION", +#endif +#ifdef SQLITE_ENABLE_LOCKING_STYLE + "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), +#endif +#if SQLITE_ENABLE_MEMORY_MANAGEMENT + "ENABLE_MEMORY_MANAGEMENT", +#endif +#if SQLITE_ENABLE_MEMSYS3 + "ENABLE_MEMSYS3", +#endif +#if SQLITE_ENABLE_MEMSYS5 + "ENABLE_MEMSYS5", +#endif +#if SQLITE_ENABLE_MULTIPLEX + "ENABLE_MULTIPLEX", +#endif +#if SQLITE_ENABLE_NULL_TRIM + "ENABLE_NULL_TRIM", +#endif +#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK + "ENABLE_OVERSIZE_CELL_CHECK", +#endif +#if SQLITE_ENABLE_PREUPDATE_HOOK + "ENABLE_PREUPDATE_HOOK", +#endif +#if SQLITE_ENABLE_QPSG + "ENABLE_QPSG", +#endif +#if SQLITE_ENABLE_RBU + "ENABLE_RBU", +#endif +#if SQLITE_ENABLE_RTREE + "ENABLE_RTREE", +#endif +#if SQLITE_ENABLE_SELECTTRACE + "ENABLE_SELECTTRACE", +#endif +#if SQLITE_ENABLE_SESSION + "ENABLE_SESSION", +#endif +#if SQLITE_ENABLE_SNAPSHOT + "ENABLE_SNAPSHOT", +#endif +#if SQLITE_ENABLE_SQLLOG + "ENABLE_SQLLOG", +#endif +#if defined(SQLITE_ENABLE_STAT4) + "ENABLE_STAT4", +#elif defined(SQLITE_ENABLE_STAT3) + "ENABLE_STAT3", +#endif +#if SQLITE_ENABLE_STMTVTAB + "ENABLE_STMTVTAB", +#endif +#if SQLITE_ENABLE_STMT_SCANSTATUS + "ENABLE_STMT_SCANSTATUS", +#endif +#if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + "ENABLE_UNKNOWN_SQL_FUNCTION", +#endif +#if SQLITE_ENABLE_UNLOCK_NOTIFY + "ENABLE_UNLOCK_NOTIFY", +#endif +#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT + "ENABLE_UPDATE_DELETE_LIMIT", +#endif +#if SQLITE_ENABLE_URI_00_ERROR + "ENABLE_URI_00_ERROR", +#endif +#if SQLITE_ENABLE_VFSTRACE + "ENABLE_VFSTRACE", +#endif +#if SQLITE_ENABLE_WHERETRACE + "ENABLE_WHERETRACE", +#endif +#if SQLITE_ENABLE_ZIPVFS + "ENABLE_ZIPVFS", +#endif +#if SQLITE_EXPLAIN_ESTIMATED_ROWS + "EXPLAIN_ESTIMATED_ROWS", +#endif +#if SQLITE_EXTRA_IFNULLROW + "EXTRA_IFNULLROW", +#endif +#ifdef SQLITE_EXTRA_INIT + "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), +#endif +#ifdef SQLITE_EXTRA_SHUTDOWN + "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), +#endif +#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH + "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), +#endif +#if SQLITE_FTS5_ENABLE_TEST_MI + "FTS5_ENABLE_TEST_MI", +#endif +#if SQLITE_FTS5_NO_WITHOUT_ROWID + "FTS5_NO_WITHOUT_ROWID", +#endif +#if SQLITE_HAS_CODEC + "HAS_CODEC", +#endif +#if HAVE_ISNAN || SQLITE_HAVE_ISNAN + "HAVE_ISNAN", +#endif +#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX + "HOMEGROWN_RECURSIVE_MUTEX", +#endif +#if SQLITE_IGNORE_AFP_LOCK_ERRORS + "IGNORE_AFP_LOCK_ERRORS", +#endif +#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS + "IGNORE_FLOCK_LOCK_ERRORS", +#endif +#if SQLITE_INLINE_MEMCPY + "INLINE_MEMCPY", +#endif +#if SQLITE_INT64_TYPE + "INT64_TYPE", +#endif +#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX + "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX), +#endif +#if SQLITE_LIKE_DOESNT_MATCH_BLOBS + "LIKE_DOESNT_MATCH_BLOBS", +#endif +#if SQLITE_LOCK_TRACE + "LOCK_TRACE", +#endif +#if SQLITE_LOG_CACHE_SPILL + "LOG_CACHE_SPILL", +#endif +#ifdef SQLITE_MALLOC_SOFT_LIMIT + "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT), +#endif +#ifdef SQLITE_MAX_ATTACHED + "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED), +#endif +#ifdef SQLITE_MAX_COLUMN + "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN), +#endif +#ifdef SQLITE_MAX_COMPOUND_SELECT + "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT), +#endif +#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE + "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE), +#endif +#ifdef SQLITE_MAX_EXPR_DEPTH + "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH), +#endif +#ifdef SQLITE_MAX_FUNCTION_ARG + "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG), +#endif +#ifdef SQLITE_MAX_LENGTH + "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH), +#endif +#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH + "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH), +#endif +#ifdef SQLITE_MAX_MEMORY + "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY), +#endif +#ifdef SQLITE_MAX_MMAP_SIZE + "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE), +#endif +#ifdef SQLITE_MAX_MMAP_SIZE_ + "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_), +#endif +#ifdef SQLITE_MAX_PAGE_COUNT + "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT), +#endif +#ifdef SQLITE_MAX_PAGE_SIZE + "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE), +#endif +#ifdef SQLITE_MAX_SCHEMA_RETRY + "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), +#endif +#ifdef SQLITE_MAX_SQL_LENGTH + "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH), +#endif +#ifdef SQLITE_MAX_TRIGGER_DEPTH + "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH), +#endif +#ifdef SQLITE_MAX_VARIABLE_NUMBER + "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER), +#endif +#ifdef SQLITE_MAX_VDBE_OP + "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP), +#endif +#ifdef SQLITE_MAX_WORKER_THREADS + "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS), +#endif +#if SQLITE_MEMDEBUG + "MEMDEBUG", +#endif +#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT + "MIXED_ENDIAN_64BIT_FLOAT", +#endif +#if SQLITE_MMAP_READWRITE + "MMAP_READWRITE", +#endif +#if SQLITE_MUTEX_NOOP + "MUTEX_NOOP", +#endif +#if SQLITE_MUTEX_NREF + "MUTEX_NREF", +#endif +#if SQLITE_MUTEX_OMIT + "MUTEX_OMIT", +#endif +#if SQLITE_MUTEX_PTHREADS + "MUTEX_PTHREADS", +#endif +#if SQLITE_MUTEX_W32 + "MUTEX_W32", +#endif +#if SQLITE_NEED_ERR_NAME + "NEED_ERR_NAME", +#endif +#if SQLITE_NOINLINE + "NOINLINE", +#endif +#if SQLITE_NO_SYNC + "NO_SYNC", +#endif +#if SQLITE_OMIT_ALTERTABLE + "OMIT_ALTERTABLE", +#endif +#if SQLITE_OMIT_ANALYZE + "OMIT_ANALYZE", +#endif +#if SQLITE_OMIT_ATTACH + "OMIT_ATTACH", +#endif +#if SQLITE_OMIT_AUTHORIZATION + "OMIT_AUTHORIZATION", +#endif +#if SQLITE_OMIT_AUTOINCREMENT + "OMIT_AUTOINCREMENT", +#endif +#if SQLITE_OMIT_AUTOINIT + "OMIT_AUTOINIT", +#endif +#if SQLITE_OMIT_AUTOMATIC_INDEX + "OMIT_AUTOMATIC_INDEX", +#endif +#if SQLITE_OMIT_AUTORESET + "OMIT_AUTORESET", +#endif +#if SQLITE_OMIT_AUTOVACUUM + "OMIT_AUTOVACUUM", +#endif +#if SQLITE_OMIT_BETWEEN_OPTIMIZATION + "OMIT_BETWEEN_OPTIMIZATION", +#endif +#if SQLITE_OMIT_BLOB_LITERAL + "OMIT_BLOB_LITERAL", +#endif +#if SQLITE_OMIT_BTREECOUNT + "OMIT_BTREECOUNT", +#endif +#if SQLITE_OMIT_CAST + "OMIT_CAST", +#endif +#if SQLITE_OMIT_CHECK + "OMIT_CHECK", +#endif +#if SQLITE_OMIT_COMPLETE + "OMIT_COMPLETE", +#endif +#if SQLITE_OMIT_COMPOUND_SELECT + "OMIT_COMPOUND_SELECT", +#endif +#if SQLITE_OMIT_CONFLICT_CLAUSE + "OMIT_CONFLICT_CLAUSE", +#endif +#if SQLITE_OMIT_CTE + "OMIT_CTE", +#endif +#if SQLITE_OMIT_DATETIME_FUNCS + "OMIT_DATETIME_FUNCS", +#endif +#if SQLITE_OMIT_DECLTYPE + "OMIT_DECLTYPE", +#endif +#if SQLITE_OMIT_DEPRECATED + "OMIT_DEPRECATED", +#endif +#if SQLITE_OMIT_DISKIO + "OMIT_DISKIO", +#endif +#if SQLITE_OMIT_EXPLAIN + "OMIT_EXPLAIN", +#endif +#if SQLITE_OMIT_FLAG_PRAGMAS + "OMIT_FLAG_PRAGMAS", +#endif +#if SQLITE_OMIT_FLOATING_POINT + "OMIT_FLOATING_POINT", +#endif +#if SQLITE_OMIT_FOREIGN_KEY + "OMIT_FOREIGN_KEY", +#endif +#if SQLITE_OMIT_GET_TABLE + "OMIT_GET_TABLE", +#endif +#if SQLITE_OMIT_HEX_INTEGER + "OMIT_HEX_INTEGER", +#endif +#if SQLITE_OMIT_INCRBLOB + "OMIT_INCRBLOB", +#endif +#if SQLITE_OMIT_INTEGRITY_CHECK + "OMIT_INTEGRITY_CHECK", +#endif +#if SQLITE_OMIT_LIKE_OPTIMIZATION + "OMIT_LIKE_OPTIMIZATION", +#endif +#if SQLITE_OMIT_LOAD_EXTENSION + "OMIT_LOAD_EXTENSION", +#endif +#if SQLITE_OMIT_LOCALTIME + "OMIT_LOCALTIME", +#endif +#if SQLITE_OMIT_LOOKASIDE + "OMIT_LOOKASIDE", +#endif +#if SQLITE_OMIT_MEMORYDB + "OMIT_MEMORYDB", +#endif +#if SQLITE_OMIT_OR_OPTIMIZATION + "OMIT_OR_OPTIMIZATION", +#endif +#if SQLITE_OMIT_PAGER_PRAGMAS + "OMIT_PAGER_PRAGMAS", +#endif +#if SQLITE_OMIT_PARSER_TRACE + "OMIT_PARSER_TRACE", +#endif +#if SQLITE_OMIT_POPEN + "OMIT_POPEN", +#endif +#if SQLITE_OMIT_PRAGMA + "OMIT_PRAGMA", +#endif +#if SQLITE_OMIT_PROGRESS_CALLBACK + "OMIT_PROGRESS_CALLBACK", +#endif +#if SQLITE_OMIT_QUICKBALANCE + "OMIT_QUICKBALANCE", +#endif +#if SQLITE_OMIT_REINDEX + "OMIT_REINDEX", +#endif +#if SQLITE_OMIT_SCHEMA_PRAGMAS + "OMIT_SCHEMA_PRAGMAS", +#endif +#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS + "OMIT_SCHEMA_VERSION_PRAGMAS", +#endif +#if SQLITE_OMIT_SHARED_CACHE + "OMIT_SHARED_CACHE", +#endif +#if SQLITE_OMIT_SHUTDOWN_DIRECTORIES + "OMIT_SHUTDOWN_DIRECTORIES", +#endif +#if SQLITE_OMIT_SUBQUERY + "OMIT_SUBQUERY", +#endif +#if SQLITE_OMIT_TCL_VARIABLE + "OMIT_TCL_VARIABLE", +#endif +#if SQLITE_OMIT_TEMPDB + "OMIT_TEMPDB", +#endif +#if SQLITE_OMIT_TEST_CONTROL + "OMIT_TEST_CONTROL", +#endif +#if SQLITE_OMIT_TRACE + "OMIT_TRACE", +#endif +#if SQLITE_OMIT_TRIGGER + "OMIT_TRIGGER", +#endif +#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION + "OMIT_TRUNCATE_OPTIMIZATION", +#endif +#if SQLITE_OMIT_UTF16 + "OMIT_UTF16", +#endif +#if SQLITE_OMIT_VACUUM + "OMIT_VACUUM", +#endif +#if SQLITE_OMIT_VIEW + "OMIT_VIEW", +#endif +#if SQLITE_OMIT_VIRTUALTABLE + "OMIT_VIRTUALTABLE", +#endif +#if SQLITE_OMIT_WAL + "OMIT_WAL", +#endif +#if SQLITE_OMIT_WSD + "OMIT_WSD", +#endif +#if SQLITE_OMIT_XFER_OPT + "OMIT_XFER_OPT", +#endif +#if SQLITE_PCACHE_SEPARATE_HEADER + "PCACHE_SEPARATE_HEADER", +#endif +#if SQLITE_PERFORMANCE_TRACE + "PERFORMANCE_TRACE", +#endif +#if SQLITE_POWERSAFE_OVERWRITE + "POWERSAFE_OVERWRITE", +#endif +#if SQLITE_PREFER_PROXY_LOCKING + "PREFER_PROXY_LOCKING", +#endif +#if SQLITE_PROXY_DEBUG + "PROXY_DEBUG", +#endif +#if SQLITE_REVERSE_UNORDERED_SELECTS + "REVERSE_UNORDERED_SELECTS", +#endif +#if SQLITE_RTREE_INT_ONLY + "RTREE_INT_ONLY", +#endif +#if SQLITE_SECURE_DELETE + "SECURE_DELETE", +#endif +#if SQLITE_SMALL_STACK + "SMALL_STACK", +#endif +#ifdef SQLITE_SORTER_PMASZ + "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ), +#endif +#if SQLITE_SOUNDEX + "SOUNDEX", +#endif +#ifdef SQLITE_STAT4_SAMPLES + "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES), +#endif +#ifdef SQLITE_STMTJRNL_SPILL + "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), +#endif +#if SQLITE_SUBSTR_COMPATIBILITY + "SUBSTR_COMPATIBILITY", +#endif +#if SQLITE_SYSTEM_MALLOC + "SYSTEM_MALLOC", +#endif +#if SQLITE_TCL + "TCL", +#endif +#ifdef SQLITE_TEMP_STORE + "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), +#endif +#if SQLITE_TEST + "TEST", +#endif +#if defined(SQLITE_THREADSAFE) + "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), +#elif defined(THREADSAFE) + "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE), +#else + "THREADSAFE=1", +#endif +#if SQLITE_UNLINK_AFTER_CLOSE + "UNLINK_AFTER_CLOSE", +#endif +#if SQLITE_UNTESTABLE + "UNTESTABLE", +#endif +#if SQLITE_USER_AUTHENTICATION + "USER_AUTHENTICATION", +#endif +#if SQLITE_USE_ALLOCA + "USE_ALLOCA", +#endif +#if SQLITE_USE_FCNTL_TRACE + "USE_FCNTL_TRACE", +#endif +#if SQLITE_USE_URI + "USE_URI", +#endif +#if SQLITE_VDBE_COVERAGE + "VDBE_COVERAGE", +#endif +#if SQLITE_WIN32_MALLOC + "WIN32_MALLOC", +#endif +#if SQLITE_ZERO_MALLOC + "ZERO_MALLOC", +#endif +/* +** END CODE GENERATED BY tool/mkctime.tcl +*/ +}; + +SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){ + *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]); + return (const char**)sqlite3azCompileOpt; +} + +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ + +/************** End of ctime.c ***********************************************/ /************** Begin file sqliteInt.h ***************************************/ /* ** 2001 September 15 @@ -76,14 +831,6 @@ #endif /* -** Make sure that rand_s() is available on Windows systems with MSVC 2005 -** or higher. -*/ -#if defined(_MSC_VER) && _MSC_VER>=1400 -# define _CRT_RAND_S -#endif - -/* ** Include the header file used to customize the compiler options for MSVC. ** This should be done first so that it can successfully prevent spurious ** compiler warnings due to subsequent content in this file and other files @@ -276,7 +1023,7 @@ /************** Include sqlite3.h in the middle of sqliteInt.h ***************/ /************** Begin file sqlite3.h *****************************************/ /* -** 2001 September 15 +** 2001-09-15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -392,15 +1139,17 @@ extern "C" { ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID ** string contains the date and time of the check-in (UTC) and a SHA1 -** or SHA3-256 hash of the entire source tree. +** or SHA3-256 hash of the entire source tree. If the source code has +** been edited in any way since it was last checked in, then the last +** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.19.3" -#define SQLITE_VERSION_NUMBER 3019003 -#define SQLITE_SOURCE_ID "2017-06-08 14:26:16 0ee482a1e0eae22e08edc8978c9733a96603d4509645f348ebf55b579e89636b" +#define SQLITE_VERSION "3.21.0" +#define SQLITE_VERSION_NUMBER 3021000 +#define SQLITE_SOURCE_ID "2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de48827" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -416,7 +1165,7 @@ extern "C" { ** ** <blockquote><pre> ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER ); -** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 ); +** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 ); ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 ); ** </pre></blockquote>)^ ** @@ -426,9 +1175,11 @@ extern "C" { ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to -** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns +** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns ** a pointer to a string constant whose value is the same as the -** [SQLITE_SOURCE_ID] C preprocessor macro. +** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built +** using an edited copy of [the amalgamation], then the last four characters +** of the hash might be different from [SQLITE_SOURCE_ID].)^ ** ** See also: [sqlite_version()] and [sqlite_source_id()]. */ @@ -694,7 +1445,7 @@ SQLITE_API int sqlite3_exec( */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ -#define SQLITE_ERROR 1 /* SQL error or missing database */ +#define SQLITE_ERROR 1 /* Generic error */ #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ #define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */ @@ -709,7 +1460,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Database is empty */ +#define SQLITE_EMPTY 16 /* Internal use only */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ @@ -717,7 +1468,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_FORMAT 24 /* Not used */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ @@ -771,6 +1522,9 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) +#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) +#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) +#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) @@ -857,6 +1611,11 @@ SQLITE_API int sqlite3_exec( ** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on ** read-only media and cannot be changed even by processes with ** elevated privileges. +** +** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying +** filesystem supports doing multiple write operations atomically when those +** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and +** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -872,6 +1631,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 +#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels @@ -1006,6 +1766,7 @@ struct sqlite3_file { ** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN] ** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE] ** <li> [SQLITE_IOCAP_IMMUTABLE] +** <li> [SQLITE_IOCAP_BATCH_ATOMIC] ** </ul> ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -1289,6 +2050,40 @@ struct sqlite3_io_methods { ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by ** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for ** this opcode. +** +** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]] +** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then +** the file descriptor is placed in "batch write mode", which +** means all subsequent write operations will be deferred and done +** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems +** that do not support batch atomic writes will return SQLITE_NOTFOUND. +** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to +** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or +** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make +** no VFS interface calls on the same [sqlite3_file] file descriptor +** except for calls to the xWrite method and the xFileControl method +** with [SQLITE_FCNTL_SIZE_HINT]. +** +** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically. +** This file control returns [SQLITE_OK] if and only if the writes were +** all performed successfully and have been committed to persistent storage. +** ^Regardless of whether or not it is successful, this file control takes +** the file descriptor out of batch write mode so that all subsequent +** write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. +** +** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back. +** ^This file control takes the file descriptor out of batch write mode +** so that all subsequent write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1320,6 +2115,9 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_JOURNAL_POINTER 28 #define SQLITE_FCNTL_WIN32_GET_HANDLE 29 #define SQLITE_FCNTL_PDB 30 +#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 +#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 +#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -1890,6 +2688,16 @@ struct sqlite3_mem_methods { ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example. </dd> ** +** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt> +** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of +** type int, interpreted as a boolean, which if true provides a hint to +** SQLite that it should avoid large memory allocations if possible. +** SQLite will run faster if it is free to make large memory allocations, +** but some application might prefer to run slower in exchange for +** guarantees about memory fragmentation that are possible if large +** allocations are avoided. This hint is normally off. +** </dd> +** ** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt> ** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, ** interpreted as a boolean, which enables or disables the collection of @@ -1907,25 +2715,7 @@ struct sqlite3_mem_methods { ** </dd> ** ** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt> -** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer -** that SQLite can use for scratch memory. ^(There are three arguments -** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte -** aligned memory buffer from which the scratch allocations will be -** drawn, the size of each scratch allocation (sz), -** and the maximum number of scratch allocations (N).)^ -** The first argument must be a pointer to an 8-byte aligned buffer -** of at least sz*N bytes of memory. -** ^SQLite will not use more than one scratch buffers per thread. -** ^SQLite will never request a scratch buffer that is more than 6 -** times the database page size. -** ^If SQLite needs needs additional -** scratch memory beyond what is provided by this configuration option, then -** [sqlite3_malloc()] will be used to obtain the memory needed.<p> -** ^When the application provides any amount of scratch memory using -** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large -** [sqlite3_malloc|heap allocations]. -** This can help [Robson proof|prevent memory allocation failures] due to heap -** fragmentation in low-memory embedded systems. +** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used. ** </dd> ** ** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt> @@ -1961,8 +2751,7 @@ struct sqlite3_mem_methods { ** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt> ** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer ** that SQLite will use for all of its dynamic memory allocation needs -** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and -** [SQLITE_CONFIG_PAGECACHE]. +** beyond those provided for by [SQLITE_CONFIG_PAGECACHE]. ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns ** [SQLITE_ERROR] if invoked otherwise. @@ -2155,7 +2944,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ -#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ +#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ @@ -2176,6 +2965,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ +#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ /* ** CAPI3REF: Database Connection Configuration Options @@ -2284,6 +3074,17 @@ struct sqlite3_mem_methods { ** have been disabled - 0 if they are not disabled, 1 if they are. ** </dd> ** +** <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt> +** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates +** the [query planner stability guarantee] (QPSG). When the QPSG is active, +** a single SQL query statement will always use the same algorithm regardless +** of values of [bound parameters].)^ The QPSG disables some query optimizations +** that look at the values of bound parameters, which can make some queries +** slower. But the QPSG has the advantage of more predictable behavior. With +** the QPSG active, SQLite will always use the same query plan in the field as +** was used during testing in the lab. +** </dd> +** ** </dl> */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -2293,6 +3094,7 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ /* @@ -2956,7 +3758,8 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** [database connection], supplied in the first argument. ** ^The authorizer callback is invoked as SQL statements are being compiled ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], -** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various +** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()], +** and [sqlite3_prepare16_v3()]. ^At various ** points during the compilation process, as logic is being created ** to perform various actions, the authorizer callback is invoked to ** see if those actions are allowed. ^The authorizer callback should @@ -3363,10 +4166,10 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** ^If [URI filename] interpretation is enabled, and the filename argument ** begins with "file:", then the filename is interpreted as a URI. ^URI ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is -** set in the fourth argument to sqlite3_open_v2(), or if it has +** set in the third argument to sqlite3_open_v2(), or if it has ** been enabled globally using the [SQLITE_CONFIG_URI] option with the ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. -** As of SQLite version 3.7.7, URI filename interpretation is turned off +** URI filename interpretation is turned off ** by default, but future releases of SQLite might enable URI filename ** interpretation by default. See "[URI filenames]" for additional ** information. @@ -3745,6 +4548,29 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +/* +** CAPI3REF: Prepare Flags +** +** These constants define various flags that can be passed into +** "prepFlags" parameter of the [sqlite3_prepare_v3()] and +** [sqlite3_prepare16_v3()] interfaces. +** +** New flags may be added in future releases of SQLite. +** +** <dl> +** [[SQLITE_PREPARE_PERSISTENT]] ^(<dt>SQLITE_PREPARE_PERSISTENT</dt> +** <dd>The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner +** that the prepared statement will be retained for a long time and +** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()] +** and [sqlite3_prepare16_v3()] assume that the prepared statement will +** be used just once or at most a few times and then destroyed using +** [sqlite3_finalize()] relatively soon. The current implementation acts +** on this hint by avoiding the use of [lookaside memory] so as not to +** deplete the limited store of lookaside memory. Future versions of +** SQLite may act on this hint differently. +** </dl> +*/ +#define SQLITE_PREPARE_PERSISTENT 0x01 /* ** CAPI3REF: Compiling An SQL Statement @@ -3752,17 +4578,29 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** METHOD: sqlite3 ** CONSTRUCTOR: sqlite3_stmt ** -** To execute an SQL query, it must first be compiled into a byte-code -** program using one of these routines. +** To execute an SQL statement, it must first be compiled into a byte-code +** program using one of these routines. Or, in other words, these routines +** are constructors for the [prepared statement] object. +** +** The preferred routine to use is [sqlite3_prepare_v2()]. The +** [sqlite3_prepare()] interface is legacy and should be avoided. +** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used +** for special purposes. +** +** The use of the UTF-8 interfaces is preferred, as SQLite currently +** does all parsing using UTF-8. The UTF-16 interfaces are provided +** as a convenience. The UTF-16 interfaces work by converting the +** input text into UTF-8, then invoking the corresponding UTF-8 interface. ** ** The first argument, "db", is a [database connection] obtained from a ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or ** [sqlite3_open16()]. The database connection must not have been closed. ** ** The second argument, "zSql", is the statement to be compiled, encoded -** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() -** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() -** use UTF-16. +** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(), +** and sqlite3_prepare_v3() +** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the ** first zero terminator. ^If nByte is positive, then it is the @@ -3789,10 +4627,11 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; ** otherwise an [error code] is returned. ** -** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are -** recommended for all new programs. The two older interfaces are retained -** for backwards compatibility, but their use is discouraged. -** ^In the "v2" interfaces, the prepared statement +** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() interfaces are recommended for all new programs. +** The older interfaces (sqlite3_prepare() and sqlite3_prepare16()) +** are retained for backwards compatibility, but their use is discouraged. +** ^In the "vX" interfaces, the prepared statement ** that is returned (the [sqlite3_stmt] object) contains a copy of the ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: @@ -3825,6 +4664,12 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. ** </li> +** +** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having +** the extra prepFlags parameter, which is a bit array consisting of zero or +** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The +** sqlite3_prepare_v2() interface works exactly the same as +** sqlite3_prepare_v3() with a zero prepFlags parameter. ** </ol> */ SQLITE_API int sqlite3_prepare( @@ -3841,6 +4686,14 @@ SQLITE_API int sqlite3_prepare_v2( sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); +SQLITE_API int sqlite3_prepare_v3( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); SQLITE_API int sqlite3_prepare16( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ @@ -3855,6 +4708,14 @@ SQLITE_API int sqlite3_prepare16_v2( sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); +SQLITE_API int sqlite3_prepare16_v3( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); /* ** CAPI3REF: Retrieving Statement SQL @@ -3862,7 +4723,8 @@ SQLITE_API int sqlite3_prepare16_v2( ** ** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 ** SQL text used to create [prepared statement] P if P was -** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], +** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. @@ -3981,8 +4843,9 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); ** implementation of [application-defined SQL functions] are protected. ** ^The sqlite3_value object returned by ** [sqlite3_column_value()] is unprotected. -** Unprotected sqlite3_value objects may only be used with -** [sqlite3_result_value()] and [sqlite3_bind_value()]. +** Unprotected sqlite3_value objects may only be used as arguments +** to [sqlite3_result_value()], [sqlite3_bind_value()], and +** [sqlite3_value_dup()]. ** The [sqlite3_value_blob | sqlite3_value_type()] family of ** interfaces require protected sqlite3_value objects. */ @@ -4088,6 +4951,15 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_blob_open | incremental BLOB I/O] routines. ** ^A negative value for the zeroblob results in a zero-length BLOB. ** +** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in +** [prepared statement] S to have an SQL value of NULL, but to also be +** associated with the pointer P of type T. ^D is either a NULL pointer or +** a pointer to a destructor function for P. ^SQLite will invoke the +** destructor D with a single argument of P when it is finished using +** P. The T parameter should be a static string, preferably a string +** literal. The sqlite3_bind_pointer() routine is part of the +** [pointer passing interface] added for SQLite 3.20.0. +** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which ** [sqlite3_step()] has been called more recently than [sqlite3_reset()], @@ -4121,6 +4993,7 @@ SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*) SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void(*)(void*), unsigned char encoding); SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); +SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); @@ -4164,8 +5037,8 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); ** ^If the value N is out of range or if the N-th parameter is ** nameless, then NULL is returned. ^The returned string is ** always in UTF-8 encoding even if the named parameter was -** originally specified as UTF-16 in [sqlite3_prepare16()] or -** [sqlite3_prepare16_v2()]. +** originally specified as UTF-16 in [sqlite3_prepare16()], +** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and @@ -4182,7 +5055,8 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); ** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero ** is returned if no matching parameter is found. ^The parameter ** name must be given in UTF-8 even if the original statement -** was prepared from UTF-16 text using [sqlite3_prepare16_v2()]. +** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or +** [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and @@ -4336,16 +5210,18 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** CAPI3REF: Evaluate An SQL Statement ** METHOD: sqlite3_stmt ** -** After a [prepared statement] has been prepared using either -** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy +** After a [prepared statement] has been prepared using any of +** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()], +** or [sqlite3_prepare16_v3()] or one of the legacy ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function ** must be called one or more times to evaluate the statement. ** ** The details of the behavior of the sqlite3_step() interface depend -** on whether the statement was prepared using the newer "v2" interface -** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy -** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the -** new "v2" interface is recommended for new applications but the legacy +** on whether the statement was prepared using the newer "vX" interfaces +** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()], +** [sqlite3_prepare16_v2()] or the older legacy +** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the +** new "vX" interface is recommended for new applications but the legacy ** interface will continue to be supported. ** ** ^In the legacy interface, the return value will be either [SQLITE_BUSY], @@ -4406,10 +5282,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** specific [error codes] that better describes the error. ** We admit that this is a goofy design. The problem has been fixed ** with the "v2" interface. If you prepare all of your SQL statements -** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead +** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()] +** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, ** then the more specific [error codes] are returned directly -** by sqlite3_step(). The use of the "v2" interface is recommended. +** by sqlite3_step(). The use of the "vX" interfaces is recommended. */ SQLITE_API int sqlite3_step(sqlite3_stmt*); @@ -4471,6 +5348,28 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** KEYWORDS: {column access functions} ** METHOD: sqlite3_stmt ** +** <b>Summary:</b> +** <blockquote><table border=0 cellpadding=0 cellspacing=0> +** <tr><td><b>sqlite3_column_blob</b><td>→<td>BLOB result +** <tr><td><b>sqlite3_column_double</b><td>→<td>REAL result +** <tr><td><b>sqlite3_column_int</b><td>→<td>32-bit INTEGER result +** <tr><td><b>sqlite3_column_int64</b><td>→<td>64-bit INTEGER result +** <tr><td><b>sqlite3_column_text</b><td>→<td>UTF-8 TEXT result +** <tr><td><b>sqlite3_column_text16</b><td>→<td>UTF-16 TEXT result +** <tr><td><b>sqlite3_column_value</b><td>→<td>The result as an +** [sqlite3_value|unprotected sqlite3_value] object. +** <tr><td> <td> <td> +** <tr><td><b>sqlite3_column_bytes</b><td>→<td>Size of a BLOB +** or a UTF-8 TEXT result in bytes +** <tr><td><b>sqlite3_column_bytes16 </b> +** <td>→ <td>Size of UTF-16 +** TEXT in bytes +** <tr><td><b>sqlite3_column_type</b><td>→<td>Default +** datatype of the result +** </table></blockquote> +** +** <b>Details:</b> +** ** ^These routines return information about a single column of the current ** result row of a query. ^In every case the first argument is a pointer ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] @@ -4492,16 +5391,29 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** are called from a different thread while any of these routines ** are pending, then the results are undefined. ** +** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16) +** each return the value of a result column in a specific data format. If +** the result column is not initially in the requested format (for example, +** if the query returns an integer but the sqlite3_column_text() interface +** is used to extract the value) then an automatic type conversion is performed. +** ** ^The sqlite3_column_type() routine returns the ** [SQLITE_INTEGER | datatype code] for the initial data type ** of the result column. ^The returned value is one of [SQLITE_INTEGER], -** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value -** returned by sqlite3_column_type() is only meaningful if no type -** conversions have occurred as described below. After a type conversion, -** the value returned by sqlite3_column_type() is undefined. Future +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. +** The return value of sqlite3_column_type() can be used to decide which +** of the first six interface should be used to extract the column value. +** The value returned by sqlite3_column_type() is only meaningful if no +** automatic type conversions have occurred for the value in question. +** After a type conversion, the result of calling sqlite3_column_type() +** is undefined, though harmless. Future ** versions of SQLite may change the behavior of sqlite3_column_type() ** following a type conversion. ** +** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes() +** or sqlite3_column_bytes16() interfaces can be used to determine the size +** of that BLOB or string. +** ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() ** routine returns the number of bytes in that BLOB or string. ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts @@ -4538,9 +5450,13 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** [sqlite3_column_value()] is used in any other way, including calls ** to routines like [sqlite3_value_int()], [sqlite3_value_text()], ** or [sqlite3_value_bytes()], the behavior is not threadsafe. +** Hence, the sqlite3_column_value() interface +** is normally only useful within the implementation of +** [application-defined SQL functions] or [virtual tables], not within +** top-level application code. ** -** These routines attempt to convert the value where appropriate. ^For -** example, if the internal representation is FLOAT and a text result +** The these routines may attempt to convert the datatype of the result. +** ^For example, if the internal representation is FLOAT and a text result ** is requested, [sqlite3_snprintf()] is used internally to perform the ** conversion automatically. ^(The following table details the conversions ** that are applied: @@ -4612,7 +5528,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings -** and BLOBs is freed automatically. Do <em>not</em> pass the pointers returned +** and BLOBs is freed automatically. Do not pass the pointers returned ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** @@ -4623,15 +5539,15 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** [SQLITE_NOMEM].)^ */ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); /* ** CAPI3REF: Destroy A Prepared Statement Object @@ -4865,21 +5781,40 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** CAPI3REF: Obtaining SQL Values ** METHOD: sqlite3_value ** -** The C-language implementation of SQL functions and aggregates uses -** this set of interface routines to access the parameter values on -** the function or aggregate. -** -** The xFunc (for scalar functions) or xStep (for aggregates) parameters -** to [sqlite3_create_function()] and [sqlite3_create_function16()] -** define callbacks that implement the SQL functions and aggregates. -** The 3rd parameter to these callbacks is an array of pointers to -** [protected sqlite3_value] objects. There is one [sqlite3_value] object for -** each parameter to the SQL function. These routines are used to -** extract values from the [sqlite3_value] objects. +** <b>Summary:</b> +** <blockquote><table border=0 cellpadding=0 cellspacing=0> +** <tr><td><b>sqlite3_value_blob</b><td>→<td>BLOB value +** <tr><td><b>sqlite3_value_double</b><td>→<td>REAL value +** <tr><td><b>sqlite3_value_int</b><td>→<td>32-bit INTEGER value +** <tr><td><b>sqlite3_value_int64</b><td>→<td>64-bit INTEGER value +** <tr><td><b>sqlite3_value_pointer</b><td>→<td>Pointer value +** <tr><td><b>sqlite3_value_text</b><td>→<td>UTF-8 TEXT value +** <tr><td><b>sqlite3_value_text16</b><td>→<td>UTF-16 TEXT value in +** the native byteorder +** <tr><td><b>sqlite3_value_text16be</b><td>→<td>UTF-16be TEXT value +** <tr><td><b>sqlite3_value_text16le</b><td>→<td>UTF-16le TEXT value +** <tr><td> <td> <td> +** <tr><td><b>sqlite3_value_bytes</b><td>→<td>Size of a BLOB +** or a UTF-8 TEXT in bytes +** <tr><td><b>sqlite3_value_bytes16 </b> +** <td>→ <td>Size of UTF-16 +** TEXT in bytes +** <tr><td><b>sqlite3_value_type</b><td>→<td>Default +** datatype of the value +** <tr><td><b>sqlite3_value_numeric_type </b> +** <td>→ <td>Best numeric datatype of the value +** </table></blockquote> +** +** <b>Details:</b> +** +** These routines extract type, size, and content information from +** [protected sqlite3_value] objects. Protected sqlite3_value objects +** are used to pass parameter information into implementation of +** [application-defined SQL functions] and [virtual tables]. ** ** These routines work only with [protected sqlite3_value] objects. ** Any attempt to use these routines on an [unprotected sqlite3_value] -** object results in undefined behavior. +** is not threadsafe. ** ** ^These routines work just like the corresponding [column access functions] ** except that these routines take a single [protected sqlite3_value] object @@ -4890,6 +5825,24 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces ** extract UTF-16 strings as big-endian and little-endian respectively. ** +** ^If [sqlite3_value] object V was initialized +** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)] +** and if X and Y are strings that compare equal according to strcmp(X,Y), +** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise, +** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** +** ^(The sqlite3_value_type(V) interface returns the +** [SQLITE_INTEGER | datatype code] for the initial datatype of the +** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER], +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ +** Other interfaces might change the datatype for an sqlite3_value object. +** For example, if the datatype is initially SQLITE_INTEGER and +** sqlite3_value_text(V) is called to extract a text value for that +** integer, then subsequent calls to sqlite3_value_type(V) might return +** SQLITE_TEXT. Whether or not a persistent internal datatype conversion +** occurs is undefined and may change from one release of SQLite to the next. +** ** ^(The sqlite3_value_numeric_type() interface attempts to apply ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If @@ -4908,15 +5861,16 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** the SQL function that supplied the [sqlite3_value*] parameters. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); -SQLITE_API int sqlite3_value_bytes(sqlite3_value*); -SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); SQLITE_API int sqlite3_value_int(sqlite3_value*); SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); +SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*); SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); @@ -4929,10 +5883,6 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. -** -** SQLite makes no use of subtype itself. It merely passes the subtype -** from the result of one [application-defined SQL function] into the -** input of another. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); @@ -5202,7 +6152,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** when it has finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT -** then SQLite makes a copy of the result into space obtained from +** then SQLite makes a copy of the result into space obtained ** from [sqlite3_malloc()] before it returns. ** ** ^The sqlite3_result_value() interface sets the result of @@ -5215,6 +6165,17 @@ typedef void (*sqlite3_destructor_type)(void*); ** [unprotected sqlite3_value] object is required, so either ** kind of [sqlite3_value] object can be used with this interface. ** +** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an +** SQL NULL value, just like [sqlite3_result_null(C)], except that it +** also associates the host-language pointer P or type T with that +** NULL value such that the pointer can be retrieved within an +** [application-defined SQL function] using [sqlite3_value_pointer()]. +** ^If the D parameter is not NULL, then it is a pointer to a destructor +** for the P parameter. ^SQLite invokes D with P as its only argument +** when SQLite is finished with P. The T parameter should be a static +** string and preferably a string literal. The sqlite3_result_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** ** If these routines are called from within the different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. @@ -5238,6 +6199,7 @@ SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(* SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); +SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*)); SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); @@ -5897,7 +6859,9 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** ^If the column-name parameter to sqlite3_table_column_metadata() is a ** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it -** does not. +** does not. If the table name parameter T in a call to +** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is +** undefined behavior. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^(The second parameter is either the name of the database @@ -6307,15 +7271,20 @@ struct sqlite3_index_info { ** an operator that is part of a constraint term in the wHERE clause of ** a query that uses a [virtual table]. */ -#define SQLITE_INDEX_CONSTRAINT_EQ 2 -#define SQLITE_INDEX_CONSTRAINT_GT 4 -#define SQLITE_INDEX_CONSTRAINT_LE 8 -#define SQLITE_INDEX_CONSTRAINT_LT 16 -#define SQLITE_INDEX_CONSTRAINT_GE 32 -#define SQLITE_INDEX_CONSTRAINT_MATCH 64 -#define SQLITE_INDEX_CONSTRAINT_LIKE 65 -#define SQLITE_INDEX_CONSTRAINT_GLOB 66 -#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 +#define SQLITE_INDEX_CONSTRAINT_EQ 2 +#define SQLITE_INDEX_CONSTRAINT_GT 4 +#define SQLITE_INDEX_CONSTRAINT_LE 8 +#define SQLITE_INDEX_CONSTRAINT_LT 16 +#define SQLITE_INDEX_CONSTRAINT_GE 32 +#define SQLITE_INDEX_CONSTRAINT_MATCH 64 +#define SQLITE_INDEX_CONSTRAINT_LIKE 65 +#define SQLITE_INDEX_CONSTRAINT_GLOB 66 +#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 +#define SQLITE_INDEX_CONSTRAINT_NE 68 +#define SQLITE_INDEX_CONSTRAINT_ISNOT 69 +#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 +#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 +#define SQLITE_INDEX_CONSTRAINT_IS 72 /* ** CAPI3REF: Register A Virtual Table Implementation @@ -7067,7 +8036,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_RESERVE 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 -#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 +#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 @@ -7126,8 +8095,7 @@ SQLITE_API int sqlite3_status64( ** <dd>This parameter is the current amount of memory checked out ** using [sqlite3_malloc()], either directly or indirectly. The ** figure includes calls made to [sqlite3_malloc()] by the application -** and internal memory usage by the SQLite library. Scratch memory -** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache +** and internal memory usage by the SQLite library. Auxiliary page-cache ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in ** this parameter. The amount returned is the sum of the allocation ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^ @@ -7165,29 +8133,14 @@ SQLITE_API int sqlite3_status64( ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.</dd>)^ ** -** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> -** <dd>This parameter returns the number of allocations used out of the -** [scratch memory allocator] configured using -** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not -** in bytes. Since a single thread may only have one scratch allocation -** outstanding at time, this parameter also reports the number of threads -** using scratch memory at the same time.</dd>)^ +** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt> +** <dd>No longer used.</dd> ** ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> -** <dd>This parameter returns the number of bytes of scratch memory -** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] -** buffer and where forced to overflow to [sqlite3_malloc()]. The values -** returned include overflows because the requested allocation was too -** larger (that is, because the requested allocation was larger than the -** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer -** slots were available. -** </dd>)^ -** -** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> -** <dd>This parameter records the largest memory allocation request -** handed to [scratch memory allocator]. Only the value returned in the -** *pHighwater parameter to [sqlite3_status()] is of interest. -** The value written into the *pCurrent parameter is undefined.</dd>)^ +** <dd>No longer used.</dd> +** +** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt> +** <dd>No longer used.</dd> ** ** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> ** <dd>The *pHighwater parameter records the deepest parser stack. @@ -7200,12 +8153,12 @@ SQLITE_API int sqlite3_status64( #define SQLITE_STATUS_MEMORY_USED 0 #define SQLITE_STATUS_PAGECACHE_USED 1 #define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 -#define SQLITE_STATUS_SCRATCH_USED 3 -#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 +#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */ +#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */ #define SQLITE_STATUS_MALLOC_SIZE 5 #define SQLITE_STATUS_PARSER_STACK 6 #define SQLITE_STATUS_PAGECACHE_SIZE 7 -#define SQLITE_STATUS_SCRATCH_SIZE 8 +#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */ #define SQLITE_STATUS_MALLOC_COUNT 9 /* @@ -7410,6 +8363,24 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 ** then the value returned by this statement status code is undefined. +** +** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt> +** <dd>^This is the number of times that the prepare statement has been +** automatically regenerated due to schema changes or change to +** [bound parameters] that might affect the query plan. +** +** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt> +** <dd>^This is the number of times that the prepared statement has +** been run. A single "run" for the purposes of this counter is one +** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. +** The counter is incremented on the first [sqlite3_step()] call of each +** cycle. +** +** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt> +** <dd>^This is the approximate number of bytes of heap memory +** used to store the prepared statement. ^This value is not actually +** a counter, and so the resetFlg parameter to sqlite3_stmt_status() +** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED. ** </dd> ** </dl> */ @@ -7417,6 +8388,9 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 #define SQLITE_STMTSTATUS_VM_STEP 4 +#define SQLITE_STMTSTATUS_REPREPARE 5 +#define SQLITE_STMTSTATUS_RUN 6 +#define SQLITE_STMTSTATUS_MEMUSED 99 /* ** CAPI3REF: Custom Page Cache Object @@ -9281,8 +10255,8 @@ SQLITE_API int sqlite3session_diff( */ SQLITE_API int sqlite3session_patchset( sqlite3_session *pSession, /* Session object */ - int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */ - void **ppPatchset /* OUT: Buffer containing changeset */ + int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */ + void **ppPatchset /* OUT: Buffer containing patchset */ ); /* @@ -10049,12 +11023,12 @@ SQLITE_API int sqlite3changeset_apply( ** ** <table border=1 style="margin-left:8ex;margin-right:8ex"> ** <tr><th>Streaming function<th>Non-streaming equivalent</th> -** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply] -** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat] -** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert] -** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start] -** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset] -** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset] +** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply] +** <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat] +** <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert] +** <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start] +** <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset] +** <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset] ** </table> ** ** Non-streaming functions that accept changesets (or patchsets) as input @@ -10783,8 +11757,9 @@ struct fts5_api { ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ -#ifdef _HAVE_SQLITE_CONFIG_H -#include "config.h" +#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) +/* #include "config.h" */ +#define SQLITECONFIG_H 1 #endif /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/ @@ -11094,6 +12069,11 @@ struct fts5_api { ** ** Older versions of SQLite used an optional THREADSAFE macro. ** We support that for legacy. +** +** To ensure that the correct value of "THREADSAFE" is reported when querying +** for compile-time options at runtime (e.g. "PRAGMA compile_options"), this +** logic is partially replicated in ctime.c. If it is updated here, it should +** also be updated there. */ #if !defined(SQLITE_THREADSAFE) # if defined(THREADSAFE) @@ -11269,6 +12249,21 @@ SQLITE_PRIVATE void sqlite3Coverage(int); #endif /* +** Some conditionals are optimizations only. In other words, if the +** conditionals are replaced with a constant 1 (true) or 0 (false) then +** the correct answer is still obtained, though perhaps not as quickly. +** +** The following macros mark these optimizations conditionals. +*/ +#if defined(SQLITE_MUTATION_TEST) +# define OK_IF_ALWAYS_TRUE(X) (1) +# define OK_IF_ALWAYS_FALSE(X) (0) +#else +# define OK_IF_ALWAYS_TRUE(X) (X) +# define OK_IF_ALWAYS_FALSE(X) (X) +#endif + +/* ** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is ** defined. We need to defend against those failures when testing with ** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches @@ -11462,63 +12457,63 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_AS 24 #define TK_WITHOUT 25 #define TK_COMMA 26 -#define TK_ID 27 -#define TK_ABORT 28 -#define TK_ACTION 29 -#define TK_AFTER 30 -#define TK_ANALYZE 31 -#define TK_ASC 32 -#define TK_ATTACH 33 -#define TK_BEFORE 34 -#define TK_BY 35 -#define TK_CASCADE 36 -#define TK_CAST 37 -#define TK_COLUMNKW 38 -#define TK_CONFLICT 39 -#define TK_DATABASE 40 -#define TK_DESC 41 -#define TK_DETACH 42 -#define TK_EACH 43 -#define TK_FAIL 44 -#define TK_FOR 45 -#define TK_IGNORE 46 -#define TK_INITIALLY 47 -#define TK_INSTEAD 48 -#define TK_LIKE_KW 49 -#define TK_MATCH 50 -#define TK_NO 51 -#define TK_KEY 52 -#define TK_OF 53 -#define TK_OFFSET 54 -#define TK_PRAGMA 55 -#define TK_RAISE 56 -#define TK_RECURSIVE 57 -#define TK_REPLACE 58 -#define TK_RESTRICT 59 -#define TK_ROW 60 -#define TK_TRIGGER 61 -#define TK_VACUUM 62 -#define TK_VIEW 63 -#define TK_VIRTUAL 64 -#define TK_WITH 65 -#define TK_REINDEX 66 -#define TK_RENAME 67 -#define TK_CTIME_KW 68 -#define TK_ANY 69 -#define TK_OR 70 -#define TK_AND 71 -#define TK_IS 72 -#define TK_BETWEEN 73 -#define TK_IN 74 -#define TK_ISNULL 75 -#define TK_NOTNULL 76 -#define TK_NE 77 -#define TK_EQ 78 -#define TK_GT 79 -#define TK_LE 80 -#define TK_LT 81 -#define TK_GE 82 -#define TK_ESCAPE 83 +#define TK_ABORT 27 +#define TK_ACTION 28 +#define TK_AFTER 29 +#define TK_ANALYZE 30 +#define TK_ASC 31 +#define TK_ATTACH 32 +#define TK_BEFORE 33 +#define TK_BY 34 +#define TK_CASCADE 35 +#define TK_CAST 36 +#define TK_CONFLICT 37 +#define TK_DATABASE 38 +#define TK_DESC 39 +#define TK_DETACH 40 +#define TK_EACH 41 +#define TK_FAIL 42 +#define TK_OR 43 +#define TK_AND 44 +#define TK_IS 45 +#define TK_MATCH 46 +#define TK_LIKE_KW 47 +#define TK_BETWEEN 48 +#define TK_IN 49 +#define TK_ISNULL 50 +#define TK_NOTNULL 51 +#define TK_NE 52 +#define TK_EQ 53 +#define TK_GT 54 +#define TK_LE 55 +#define TK_LT 56 +#define TK_GE 57 +#define TK_ESCAPE 58 +#define TK_ID 59 +#define TK_COLUMNKW 60 +#define TK_FOR 61 +#define TK_IGNORE 62 +#define TK_INITIALLY 63 +#define TK_INSTEAD 64 +#define TK_NO 65 +#define TK_KEY 66 +#define TK_OF 67 +#define TK_OFFSET 68 +#define TK_PRAGMA 69 +#define TK_RAISE 70 +#define TK_RECURSIVE 71 +#define TK_REPLACE 72 +#define TK_RESTRICT 73 +#define TK_ROW 74 +#define TK_TRIGGER 75 +#define TK_VACUUM 76 +#define TK_VIEW 77 +#define TK_VIRTUAL 78 +#define TK_WITH 79 +#define TK_REINDEX 80 +#define TK_RENAME 81 +#define TK_CTIME_KW 82 +#define TK_ANY 83 #define TK_BITAND 84 #define TK_BITOR 85 #define TK_LSHIFT 86 @@ -11578,28 +12573,23 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_INDEX 140 #define TK_ALTER 141 #define TK_ADD 142 -#define TK_TO_TEXT 143 -#define TK_TO_BLOB 144 -#define TK_TO_NUMERIC 145 -#define TK_TO_INT 146 -#define TK_TO_REAL 147 -#define TK_ISNOT 148 -#define TK_END_OF_FILE 149 -#define TK_UNCLOSED_STRING 150 -#define TK_FUNCTION 151 -#define TK_COLUMN 152 -#define TK_AGG_FUNCTION 153 -#define TK_AGG_COLUMN 154 -#define TK_UMINUS 155 -#define TK_UPLUS 156 -#define TK_REGISTER 157 -#define TK_VECTOR 158 -#define TK_SELECT_COLUMN 159 -#define TK_IF_NULL_ROW 160 -#define TK_ASTERISK 161 -#define TK_SPAN 162 -#define TK_SPACE 163 -#define TK_ILLEGAL 164 +#define TK_ISNOT 143 +#define TK_FUNCTION 144 +#define TK_COLUMN 145 +#define TK_AGG_FUNCTION 146 +#define TK_AGG_COLUMN 147 +#define TK_UMINUS 148 +#define TK_UPLUS 149 +#define TK_REGISTER 150 +#define TK_VECTOR 151 +#define TK_SELECT_COLUMN 152 +#define TK_IF_NULL_ROW 153 +#define TK_ASTERISK 154 +#define TK_SPAN 155 +#define TK_END_OF_FILE 156 +#define TK_UNCLOSED_STRING 157 +#define TK_SPACE 158 +#define TK_ILLEGAL 159 /* The token codes above must all fit in 8 bits */ #define TKFLG_MASK 0xff @@ -11684,7 +12674,6 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 -# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */ #endif /* @@ -11721,6 +12710,15 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #endif /* +** The compile-time options SQLITE_MMAP_READWRITE and +** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another. +** You must choose one or the other (or neither) but not both. +*/ +#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) +#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE +#endif + +/* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. */ @@ -11985,7 +12983,6 @@ typedef INT16_TYPE LogEst; # else # define SQLITE_MAX_MMAP_SIZE 0 # endif -# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */ #endif /* @@ -11995,7 +12992,6 @@ typedef INT16_TYPE LogEst; */ #ifndef SQLITE_DEFAULT_MMAP_SIZE # define SQLITE_DEFAULT_MMAP_SIZE 0 -# define SQLITE_DEFAULT_MMAP_SIZE_xc 1 /* Exclude from ctime.c */ #endif #if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE # undef SQLITE_DEFAULT_MMAP_SIZE @@ -12020,7 +13016,7 @@ typedef INT16_TYPE LogEst; ** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not ** the Select query generator tracing logic is turned on. */ -#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE) +#if defined(SQLITE_ENABLE_SELECTTRACE) # define SELECTTRACE_ENABLED 1 #else # define SELECTTRACE_ENABLED 0 @@ -12424,6 +13420,7 @@ SQLITE_PRIVATE int sqlite3BtreeCursor( struct KeyInfo*, /* First argument to compare function */ BtCursor *pCursor /* Space to write cursor structure */ ); +SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void); SQLITE_PRIVATE int sqlite3BtreeCursorSize(void); SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); @@ -12480,9 +13477,9 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int flags, int seekResult); SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); -SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes); +SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags); SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); -SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes); +SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags); SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*); SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); @@ -12633,7 +13630,7 @@ struct VdbeOp { #ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif - int (*xAdvance)(BtCursor *, int *); + int (*xAdvance)(BtCursor *, int); } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */ @@ -12677,24 +13674,26 @@ typedef struct VdbeOpList VdbeOpList; /* ** Allowed values of VdbeOp.p4type */ -#define P4_NOTUSED 0 /* The P4 parameter is not used */ -#define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ -#define P4_STATIC (-2) /* Pointer to a static string */ -#define P4_COLLSEQ (-3) /* P4 is a pointer to a CollSeq structure */ -#define P4_FUNCDEF (-4) /* P4 is a pointer to a FuncDef structure */ -#define P4_KEYINFO (-5) /* P4 is a pointer to a KeyInfo structure */ -#define P4_EXPR (-6) /* P4 is a pointer to an Expr tree */ -#define P4_MEM (-7) /* P4 is a pointer to a Mem* structure */ -#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ -#define P4_VTAB (-8) /* P4 is a pointer to an sqlite3_vtab structure */ -#define P4_REAL (-9) /* P4 is a 64-bit floating point value */ -#define P4_INT64 (-10) /* P4 is a 64-bit signed integer */ -#define P4_INT32 (-11) /* P4 is a 32-bit signed integer */ -#define P4_INTARRAY (-12) /* P4 is a vector of 32-bit integers */ -#define P4_SUBPROGRAM (-13) /* P4 is a pointer to a SubProgram structure */ -#define P4_ADVANCE (-14) /* P4 is a pointer to BtreeNext() or BtreePrev() */ -#define P4_TABLE (-15) /* P4 is a pointer to a Table structure */ -#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ +#define P4_NOTUSED 0 /* The P4 parameter is not used */ +#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ +#define P4_STATIC (-1) /* Pointer to a static string */ +#define P4_COLLSEQ (-2) /* P4 is a pointer to a CollSeq structure */ +#define P4_INT32 (-3) /* P4 is a 32-bit signed integer */ +#define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */ +#define P4_ADVANCE (-5) /* P4 is a pointer to BtreeNext() or BtreePrev() */ +#define P4_TABLE (-6) /* P4 is a pointer to a Table structure */ +/* Above do not own any resources. Must free those below */ +#define P4_FREE_IF_LE (-7) +#define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */ +#define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */ +#define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */ +#define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */ +#define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */ +#define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */ +#define P4_REAL (-13) /* P4 is a 64-bit floating point value */ +#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */ +#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ +#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 @@ -12740,87 +13739,87 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Savepoint 0 #define OP_AutoCommit 1 #define OP_Transaction 2 -#define OP_SorterNext 3 -#define OP_PrevIfOpen 4 -#define OP_NextIfOpen 5 -#define OP_Prev 6 -#define OP_Next 7 +#define OP_SorterNext 3 /* jump */ +#define OP_PrevIfOpen 4 /* jump */ +#define OP_NextIfOpen 5 /* jump */ +#define OP_Prev 6 /* jump */ +#define OP_Next 7 /* jump */ #define OP_Checkpoint 8 #define OP_JournalMode 9 #define OP_Vacuum 10 -#define OP_VFilter 11 /* synopsis: iplan=r[P3] zplan='P4' */ +#define OP_VFilter 11 /* jump, synopsis: iplan=r[P3] zplan='P4' */ #define OP_VUpdate 12 /* synopsis: data=r[P3@P2] */ -#define OP_Goto 13 -#define OP_Gosub 14 -#define OP_InitCoroutine 15 -#define OP_Yield 16 -#define OP_MustBeInt 17 -#define OP_Jump 18 +#define OP_Goto 13 /* jump */ +#define OP_Gosub 14 /* jump */ +#define OP_InitCoroutine 15 /* jump */ +#define OP_Yield 16 /* jump */ +#define OP_MustBeInt 17 /* jump */ +#define OP_Jump 18 /* jump */ #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ -#define OP_Once 20 -#define OP_If 21 -#define OP_IfNot 22 -#define OP_IfNullRow 23 /* synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ -#define OP_SeekLT 24 /* synopsis: key=r[P3@P4] */ -#define OP_SeekLE 25 /* synopsis: key=r[P3@P4] */ -#define OP_SeekGE 26 /* synopsis: key=r[P3@P4] */ -#define OP_SeekGT 27 /* synopsis: key=r[P3@P4] */ -#define OP_NoConflict 28 /* synopsis: key=r[P3@P4] */ -#define OP_NotFound 29 /* synopsis: key=r[P3@P4] */ -#define OP_Found 30 /* synopsis: key=r[P3@P4] */ -#define OP_SeekRowid 31 /* synopsis: intkey=r[P3] */ -#define OP_NotExists 32 /* synopsis: intkey=r[P3] */ -#define OP_Last 33 -#define OP_IfSmaller 34 -#define OP_SorterSort 35 -#define OP_Sort 36 -#define OP_Rewind 37 -#define OP_IdxLE 38 /* synopsis: key=r[P3@P4] */ -#define OP_IdxGT 39 /* synopsis: key=r[P3@P4] */ -#define OP_IdxLT 40 /* synopsis: key=r[P3@P4] */ -#define OP_IdxGE 41 /* synopsis: key=r[P3@P4] */ -#define OP_RowSetRead 42 /* synopsis: r[P3]=rowset(P1) */ -#define OP_RowSetTest 43 /* synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Program 44 -#define OP_FkIfZero 45 /* synopsis: if fkctr[P1]==0 goto P2 */ -#define OP_IfPos 46 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ -#define OP_IfNotZero 47 /* synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ -#define OP_DecrJumpZero 48 /* synopsis: if (--r[P1])==0 goto P2 */ -#define OP_IncrVacuum 49 -#define OP_VNext 50 -#define OP_Init 51 /* synopsis: Start at P2 */ -#define OP_Return 52 -#define OP_EndCoroutine 53 -#define OP_HaltIfNull 54 /* synopsis: if r[P3]=null halt */ -#define OP_Halt 55 -#define OP_Integer 56 /* synopsis: r[P2]=P1 */ -#define OP_Int64 57 /* synopsis: r[P2]=P4 */ -#define OP_String 58 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_Null 59 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 60 /* synopsis: r[P1]=NULL */ -#define OP_Blob 61 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 62 /* synopsis: r[P2]=parameter(P1,P4) */ -#define OP_Move 63 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 64 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 65 /* synopsis: r[P2]=r[P1] */ -#define OP_IntCopy 66 /* synopsis: r[P2]=r[P1] */ -#define OP_ResultRow 67 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 68 -#define OP_Function0 69 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_Or 70 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ -#define OP_And 71 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_Function 72 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_AddImm 73 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_RealAffinity 74 -#define OP_IsNull 75 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ -#define OP_NotNull 76 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ -#define OP_Ne 77 /* same as TK_NE, synopsis: IF r[P3]!=r[P1] */ -#define OP_Eq 78 /* same as TK_EQ, synopsis: IF r[P3]==r[P1] */ -#define OP_Gt 79 /* same as TK_GT, synopsis: IF r[P3]>r[P1] */ -#define OP_Le 80 /* same as TK_LE, synopsis: IF r[P3]<=r[P1] */ -#define OP_Lt 81 /* same as TK_LT, synopsis: IF r[P3]<r[P1] */ -#define OP_Ge 82 /* same as TK_GE, synopsis: IF r[P3]>=r[P1] */ -#define OP_ElseNotEq 83 /* same as TK_ESCAPE */ +#define OP_Once 20 /* jump */ +#define OP_If 21 /* jump */ +#define OP_IfNot 22 /* jump */ +#define OP_IfNullRow 23 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ +#define OP_SeekLT 24 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekLE 25 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGE 26 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGT 27 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NoConflict 28 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NotFound 29 /* jump, synopsis: key=r[P3@P4] */ +#define OP_Found 30 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekRowid 31 /* jump, synopsis: intkey=r[P3] */ +#define OP_NotExists 32 /* jump, synopsis: intkey=r[P3] */ +#define OP_Last 33 /* jump */ +#define OP_IfSmaller 34 /* jump */ +#define OP_SorterSort 35 /* jump */ +#define OP_Sort 36 /* jump */ +#define OP_Rewind 37 /* jump */ +#define OP_IdxLE 38 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGT 39 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxLT 40 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGE 41 /* jump, synopsis: key=r[P3@P4] */ +#define OP_RowSetRead 42 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ +#define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ +#define OP_RowSetTest 45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 46 /* jump */ +#define OP_FkIfZero 47 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_IfPos 48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ +#define OP_IfNotZero 49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ +#define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ +#define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ +#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ +#define OP_Eq 53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */ +#define OP_Gt 54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */ +#define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */ +#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */ +#define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */ +#define OP_ElseNotEq 58 /* jump, same as TK_ESCAPE */ +#define OP_DecrJumpZero 59 /* jump, synopsis: if (--r[P1])==0 goto P2 */ +#define OP_IncrVacuum 60 /* jump */ +#define OP_VNext 61 /* jump */ +#define OP_Init 62 /* jump, synopsis: Start at P2 */ +#define OP_Return 63 +#define OP_EndCoroutine 64 +#define OP_HaltIfNull 65 /* synopsis: if r[P3]=null halt */ +#define OP_Halt 66 +#define OP_Integer 67 /* synopsis: r[P2]=P1 */ +#define OP_Int64 68 /* synopsis: r[P2]=P4 */ +#define OP_String 69 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_Null 70 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 71 /* synopsis: r[P1]=NULL */ +#define OP_Blob 72 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 73 /* synopsis: r[P2]=parameter(P1,P4) */ +#define OP_Move 74 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 75 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 76 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 77 /* synopsis: r[P2]=r[P1] */ +#define OP_ResultRow 78 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 79 +#define OP_AddImm 80 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 81 +#define OP_Cast 82 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 83 #define OP_BitAnd 84 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 85 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 86 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */ @@ -12831,78 +13830,80 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Divide 91 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ #define OP_Remainder 92 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ #define OP_Concat 93 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ -#define OP_Cast 94 /* synopsis: affinity(r[P1]) */ +#define OP_Compare 94 /* synopsis: r[P1@P3] <-> r[P2@P3] */ #define OP_BitNot 95 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */ -#define OP_Permutation 96 +#define OP_Column 96 /* synopsis: r[P3]=PX */ #define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_Compare 98 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_Column 99 /* synopsis: r[P3]=PX */ -#define OP_Affinity 100 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 101 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 102 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 103 -#define OP_SetCookie 104 -#define OP_ReopenIdx 105 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 106 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 107 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenDup 108 -#define OP_OpenAutoindex 109 /* synopsis: nColumn=P2 */ -#define OP_OpenEphemeral 110 /* synopsis: nColumn=P2 */ -#define OP_SorterOpen 111 -#define OP_SequenceTest 112 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ -#define OP_OpenPseudo 113 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 114 -#define OP_ColumnsUsed 115 -#define OP_Sequence 116 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_NewRowid 117 /* synopsis: r[P2]=rowid */ -#define OP_Insert 118 /* synopsis: intkey=r[P3] data=r[P2] */ -#define OP_InsertInt 119 /* synopsis: intkey=P3 data=r[P2] */ -#define OP_Delete 120 -#define OP_ResetCount 121 -#define OP_SorterCompare 122 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ -#define OP_SorterData 123 /* synopsis: r[P2]=data */ -#define OP_RowData 124 /* synopsis: r[P2]=data */ -#define OP_Rowid 125 /* synopsis: r[P2]=rowid */ -#define OP_NullRow 126 -#define OP_SorterInsert 127 /* synopsis: key=r[P2] */ -#define OP_IdxInsert 128 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 129 /* synopsis: key=r[P2@P3] */ -#define OP_Seek 130 /* synopsis: Move P3 to P1.rowid */ -#define OP_IdxRowid 131 /* synopsis: r[P2]=rowid */ +#define OP_Affinity 98 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 99 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 100 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 101 +#define OP_SetCookie 102 +#define OP_ReopenIdx 103 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenRead 104 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 105 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenDup 106 +#define OP_OpenAutoindex 107 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 108 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 109 +#define OP_SequenceTest 110 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 111 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 112 +#define OP_ColumnsUsed 113 +#define OP_Sequence 114 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 115 /* synopsis: r[P2]=rowid */ +#define OP_Insert 116 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_InsertInt 117 /* synopsis: intkey=P3 data=r[P2] */ +#define OP_Delete 118 +#define OP_ResetCount 119 +#define OP_SorterCompare 120 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 121 /* synopsis: r[P2]=data */ +#define OP_RowData 122 /* synopsis: r[P2]=data */ +#define OP_Rowid 123 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 124 +#define OP_SeekEnd 125 +#define OP_SorterInsert 126 /* synopsis: key=r[P2] */ +#define OP_IdxInsert 127 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 128 /* synopsis: key=r[P2@P3] */ +#define OP_DeferredSeek 129 /* synopsis: Move P3 to P1.rowid if needed */ +#define OP_IdxRowid 130 /* synopsis: r[P2]=rowid */ +#define OP_Destroy 131 #define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_Destroy 133 -#define OP_Clear 134 -#define OP_ResetSorter 135 -#define OP_CreateIndex 136 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_CreateTable 137 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_SqlExec 138 -#define OP_ParseSchema 139 -#define OP_LoadAnalysis 140 -#define OP_DropTable 141 -#define OP_DropIndex 142 -#define OP_DropTrigger 143 -#define OP_IntegrityCk 144 -#define OP_RowSetAdd 145 /* synopsis: rowset(P1)=r[P2] */ -#define OP_Param 146 -#define OP_FkCounter 147 /* synopsis: fkctr[P1]+=P2 */ -#define OP_MemMax 148 /* synopsis: r[P1]=max(r[P1],r[P2]) */ -#define OP_OffsetLimit 149 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggStep0 150 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep 151 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggFinal 152 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 153 -#define OP_TableLock 154 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 155 -#define OP_VCreate 156 -#define OP_VDestroy 157 -#define OP_VOpen 158 -#define OP_VColumn 159 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 160 -#define OP_Pagecount 161 -#define OP_MaxPgcnt 162 -#define OP_CursorHint 163 -#define OP_Noop 164 -#define OP_Explain 165 +#define OP_Clear 133 +#define OP_ResetSorter 134 +#define OP_CreateBtree 135 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ +#define OP_SqlExec 136 +#define OP_ParseSchema 137 +#define OP_LoadAnalysis 138 +#define OP_DropTable 139 +#define OP_DropIndex 140 +#define OP_DropTrigger 141 +#define OP_IntegrityCk 142 +#define OP_RowSetAdd 143 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 144 +#define OP_FkCounter 145 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 146 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 147 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggStep0 148 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep 149 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggFinal 150 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 151 +#define OP_TableLock 152 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 153 +#define OP_VCreate 154 +#define OP_VDestroy 155 +#define OP_VOpen 156 +#define OP_VColumn 157 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 158 +#define OP_Pagecount 159 +#define OP_MaxPgcnt 160 +#define OP_PureFunc0 161 +#define OP_Function0 162 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_PureFunc 163 +#define OP_Function 164 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_CursorHint 165 +#define OP_Noop 166 +#define OP_Explain 167 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -12920,22 +13921,23 @@ typedef struct VdbeOpList VdbeOpList; /* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x01,\ /* 24 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\ /* 32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\ -/* 40 */ 0x01, 0x01, 0x23, 0x0b, 0x01, 0x01, 0x03, 0x03,\ -/* 48 */ 0x03, 0x01, 0x01, 0x01, 0x02, 0x02, 0x08, 0x00,\ -/* 56 */ 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00,\ -/* 64 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x26, 0x26,\ -/* 72 */ 0x00, 0x02, 0x02, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\ -/* 80 */ 0x0b, 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26,\ -/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x02, 0x12,\ -/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\ +/* 40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\ +/* 48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ +/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x02,\ +/* 64 */ 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00,\ +/* 72 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ +/* 80 */ 0x02, 0x02, 0x02, 0x00, 0x26, 0x26, 0x26, 0x26,\ +/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00, 0x12,\ +/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ /* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 112 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ -/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04,\ -/* 128 */ 0x04, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\ -/* 136 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 144 */ 0x00, 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 160 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,} +/* 112 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\ +/* 120 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x04,\ +/* 128 */ 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10,\ +/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,\ +/* 144 */ 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00,\ +/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ +/* 160 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +} /* The sqlite3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum @@ -12943,12 +13945,18 @@ typedef struct VdbeOpList VdbeOpList; ** generated this include file strives to group all JUMP opcodes ** together near the beginning of the list. */ -#define SQLITE_MX_JUMP_OPCODE 83 /* Maximum JUMP opcode */ +#define SQLITE_MX_JUMP_OPCODE 62 /* Maximum JUMP opcode */ /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ /* +** Additional non-public SQLITE_PREPARE_* flags +*/ +#define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */ +#define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */ + +/* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ @@ -13005,7 +14013,8 @@ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*); SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*); -SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int); +SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, u8); SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*); SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); @@ -13027,6 +14036,8 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif +SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); + /* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on ** each VDBE opcode. ** @@ -13252,6 +14263,7 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); SQLITE_PRIVATE void sqlite3PagerRef(DbPage*); SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*); SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*); +SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*); /* Operations on page references. */ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*); @@ -13371,6 +14383,7 @@ struct PgHdr { sqlite3_pcache_page *pPage; /* Pcache object page handle */ void *pData; /* Page data */ void *pExtra; /* Extra content */ + PCache *pCache; /* PRIVATE: Cache that owns this page */ PgHdr *pDirty; /* Transient list of dirty sorted by pgno */ Pager *pPager; /* The pager this page is part of */ Pgno pgno; /* Page number for this page */ @@ -13380,14 +14393,15 @@ struct PgHdr { u16 flags; /* PGHDR flags defined below */ /********************************************************************** - ** Elements above are public. All that follows is private to pcache.c - ** and should not be accessed by other modules. + ** Elements above, except pCache, are public. All that follow are + ** private to pcache.c and should not be accessed by other modules. + ** pCache is grouped with the public elements for efficiency. */ i16 nRef; /* Number of users of this page */ - PCache *pCache; /* Cache that owns this page */ - PgHdr *pDirtyNext; /* Next element in list of dirty pages */ PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */ + /* NB: pDirtyNext and pDirtyPrev are undefined if the + ** PgHdr object is not dirty */ }; /* Bit values for PgHdr.flags */ @@ -13769,10 +14783,12 @@ SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*); #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id); +#ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int); SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int); +#endif /* SQLITE_OMIT_WAL */ SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **); SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *); @@ -13981,6 +14997,7 @@ struct Schema { #define DB_SchemaLoaded 0x0001 /* The schema has been loaded */ #define DB_UnresetViews 0x0002 /* Some views have defined column names */ #define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */ +#define DB_ResetWanted 0x0008 /* Reset the schema when nSchemaLock==0 */ /* ** The number of different kinds of things that can be limited @@ -14012,9 +15029,9 @@ struct Lookaside { u32 bDisable; /* Only operate the lookaside when zero */ u16 sz; /* Size of each buffer in bytes */ u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */ - int nOut; /* Number of buffers currently checked out */ - int mxOut; /* Highwater mark for nOut */ - int anStat[3]; /* 0: hits. 1: size misses. 2: full misses */ + u32 nSlot; /* Number of lookaside slots allocated */ + u32 anStat[3]; /* 0: hits. 1: size misses. 2: full misses */ + LookasideSlot *pInit; /* List of buffers not previously used */ LookasideSlot *pFree; /* List of available buffers */ void *pStart; /* First byte of available memory space */ void *pEnd; /* First byte past end of available space */ @@ -14093,9 +15110,11 @@ struct sqlite3 { sqlite3_mutex *mutex; /* Connection mutex */ Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ - int flags; /* Miscellaneous flags. See below */ + u32 mDbFlags; /* flags recording internal state */ + u32 flags; /* flags settable by pragmas. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 szMmap; /* Default mmap_size setting */ + u32 nSchemaLock; /* Do not reset the schema when non-zero */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ @@ -14227,8 +15246,8 @@ struct sqlite3 { ** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC ** SQLITE_CacheSpill == PAGER_CACHE_SPILL */ -#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ -#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */ +#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_MASTER */ +#define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */ #define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */ #define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */ #define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */ @@ -14239,30 +15258,36 @@ struct sqlite3 { /* the count using a callback. */ #define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */ /* result set is empty */ -#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */ -#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */ -#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */ -#define SQLITE_VdbeAddopTrace 0x00001000 /* Trace sqlite3VdbeAddOp() calls */ -#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */ -#define SQLITE_ReadUncommitted 0x0004000 /* For shared-cache mode */ -#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ -#define SQLITE_RecoveryMode 0x00010000 /* Ignore schema errors */ -#define SQLITE_ReverseOrder 0x00020000 /* Reverse unordered SELECTs */ -#define SQLITE_RecTriggers 0x00040000 /* Enable recursive triggers */ -#define SQLITE_ForeignKeys 0x00080000 /* Enforce foreign key constraints */ -#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */ -#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */ -#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */ -#define SQLITE_LoadExtFunc 0x00800000 /* Enable load_extension() SQL func */ -#define SQLITE_EnableTrigger 0x01000000 /* True to enable triggers */ -#define SQLITE_DeferFKs 0x02000000 /* Defer all FK constraints */ -#define SQLITE_QueryOnly 0x04000000 /* Disable database changes */ -#define SQLITE_VdbeEQP 0x08000000 /* Debug EXPLAIN QUERY PLAN */ -#define SQLITE_Vacuum 0x10000000 /* Currently in a VACUUM */ -#define SQLITE_CellSizeCk 0x20000000 /* Check btree cell sizes on load */ -#define SQLITE_Fts3Tokenizer 0x40000000 /* Enable fts3_tokenizer(2) */ -#define SQLITE_NoCkptOnClose 0x80000000 /* No checkpoint on close()/DETACH */ +#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */ +#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */ +#define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */ +#define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */ +#define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */ +#define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */ +#define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */ +#define SQLITE_LoadExtension 0x00010000 /* Enable load_extension */ +#define SQLITE_LoadExtFunc 0x00020000 /* Enable load_extension() SQL func */ +#define SQLITE_EnableTrigger 0x00040000 /* True to enable triggers */ +#define SQLITE_DeferFKs 0x00080000 /* Defer all FK constraints */ +#define SQLITE_QueryOnly 0x00100000 /* Disable database changes */ +#define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */ +#define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */ +#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee */ +/* Flags used only if debugging */ +#ifdef SQLITE_DEBUG +#define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */ +#define SQLITE_VdbeListing 0x10000000 /* Debug listings of VDBE programs */ +#define SQLITE_VdbeTrace 0x20000000 /* True to trace VDBE execution */ +#define SQLITE_VdbeAddopTrace 0x40000000 /* Trace sqlite3VdbeAddOp() calls */ +#define SQLITE_VdbeEQP 0x80000000 /* Debug EXPLAIN QUERY PLAN */ +#endif +/* +** Allowed values for sqlite3.mDbFlags +*/ +#define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */ +#define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */ +#define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the @@ -14273,15 +15298,15 @@ struct sqlite3 { #define SQLITE_ColumnCache 0x0002 /* Column cache */ #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ -/* not used 0x0010 // Was: SQLITE_IdxRealAsInt */ -#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ -#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ -#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ -#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ -#define SQLITE_Transitive 0x0200 /* Transitive constraints */ -#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ +#define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */ +#define SQLITE_CoverIdxScan 0x0020 /* Covering index scans */ +#define SQLITE_OrderByIdxJoin 0x0040 /* ORDER BY of joins via index */ +#define SQLITE_Transitive 0x0080 /* Transitive constraints */ +#define SQLITE_OmitNoopJoin 0x0100 /* Omit unused tables in joins */ +#define SQLITE_CountOfView 0x0200 /* The count-of-view optimization */ +#define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */ #define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ -#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */ + /* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* @@ -14399,7 +15424,14 @@ struct FuncDestructor { ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and ** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions ** and functions like sqlite_version() that can change, but not during -** a single query. +** a single query. The iArg is ignored. The user-data is always set +** to a NULL pointer. The bNC parameter is not used. +** +** PURE_DATE(zName, nArg, iArg, bNC, xFunc) +** Used for "pure" date/time functions, this macro is like DFUNCTION +** except that it does set the SQLITE_FUNC_CONSTANT flags. iArg is +** ignored and the user-data for these functions is set to an +** arbitrary non-NULL pointer. The bNC parameter is not used. ** ** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal) ** Used to create an aggregate function definition implemented by @@ -14422,8 +15454,11 @@ struct FuncDestructor { {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } + {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ + 0, 0, xFunc, 0, #zName, {0} } +#define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \ + {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ + (void*)&sqlite3Config, 0, xFunc, 0, #zName, {0} } #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } @@ -14802,8 +15837,8 @@ struct FKey { struct KeyInfo { u32 nRef; /* Number of references to this KeyInfo object */ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */ - u16 nField; /* Number of key columns in the index */ - u16 nXField; /* Number of columns beyond the key columns */ + u16 nKeyField; /* Number of key columns in the index */ + u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ u8 *aSortOrder; /* Sort order for each column. */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ @@ -14850,8 +15885,8 @@ struct UnpackedRecord { u16 nField; /* Number of entries in apMem[] */ i8 default_rc; /* Comparison result if keys are equal */ u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */ - i8 r1; /* Value to return if (lhs > rhs) */ - i8 r2; /* Value to return if (rhs < lhs) */ + i8 r1; /* Value to return if (lhs < rhs) */ + i8 r2; /* Value to return if (lhs > rhs) */ u8 eqSeen; /* True if an equality comparison has been seen */ }; @@ -15135,7 +16170,8 @@ struct Expr { ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ - Table *pTab; /* Table for TK_COLUMN expressions. */ + Table *pTab; /* Table for TK_COLUMN expressions. Can be NULL + ** for a column of an index on an expression */ }; /* @@ -15143,8 +16179,8 @@ struct Expr { */ #define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ #define EP_Agg 0x000002 /* Contains one or more aggregate functions */ -#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */ -#define EP_Error 0x000008 /* Expression contains one or more errors */ + /* 0x000004 // available for use */ + /* 0x000008 // available for use */ #define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ @@ -15223,7 +16259,6 @@ struct Expr { */ struct ExprList { int nExpr; /* Number of expressions on the list */ - int nAlloc; /* Number of a[] slots allocated */ struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The parse tree for this expression */ char *zName; /* Token associated with this expression */ @@ -15611,10 +16646,10 @@ struct Select { */ struct SelectDest { u8 eDest; /* How to dispose of the results. On of SRT_* above. */ - char *zAffSdst; /* Affinity used when eDest==SRT_Set */ int iSDParm; /* A parameter used by the eDest disposal method */ int iSdst; /* Base register where results are written */ int nSdst; /* Number of registers allocated */ + char *zAffSdst; /* Affinity used when eDest==SRT_Set */ ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */ }; @@ -15724,8 +16759,8 @@ struct Parse { int nMem; /* Number of memory cells used so far */ int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ - int ckBase; /* Base register of data during check constraints */ - int iSelfTab; /* Table of an index whose exprs are being coded */ + int iSelfTab; /* Table for associated with an index on expr, or negative + ** of the base register during check-constraint eval */ int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ int iCacheCnt; /* Counter used to generate aColCache[].lru values */ int nLabel; /* Number of labels used */ @@ -15748,7 +16783,7 @@ struct Parse { AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ - int addrCrTab; /* Address of OP_CreateTable opcode on CREATE TABLE */ + int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */ u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u32 oldmask; /* Mask of old.* columns referenced */ u32 newmask; /* Mask of new.* columns referenced */ @@ -15977,11 +17012,10 @@ struct DbFixer { */ struct StrAccum { sqlite3 *db; /* Optional database for lookaside. Can be NULL */ - char *zBase; /* A base allocation. Not from malloc. */ char *zText; /* The string collected so far */ - u32 nChar; /* Length of the string so far */ u32 nAlloc; /* Amount of space allocated in zText */ u32 mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */ + u32 nChar; /* Length of the string so far */ u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */ u8 printfFlags; /* SQLITE_PRINTF flags below */ }; @@ -16016,6 +17050,7 @@ struct Sqlite3Config { int bFullMutex; /* True to enable full mutexing */ int bOpenUri; /* True to interpret filenames as URIs */ int bUseCis; /* Use covering indices for full-scans */ + int bSmallMalloc; /* Avoid large memory allocations if true */ int mxStrlen; /* Maximum string length */ int neverCorrupt; /* Database is always well-formed */ int szLookaside; /* Default lookaside buffer size */ @@ -16029,9 +17064,6 @@ struct Sqlite3Config { int mnReq, mxReq; /* Min and max heap requests sizes */ sqlite3_int64 szMmap; /* mmap() space per open file */ sqlite3_int64 mxMmap; /* Maximum value for szMmap */ - void *pScratch; /* Scratch memory */ - int szScratch; /* Size of each scratch buffer */ - int nScratch; /* Number of scratch buffers */ void *pPage; /* Page cache memory */ int szPage; /* Size of each page in pPage[] */ int nPage; /* Number of pages in pPage[] */ @@ -16117,6 +17149,11 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*); SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*); SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*); SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*); +SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*); +SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*); +#endif /* ** Return code from the parse-tree walking primitives and their @@ -16178,11 +17215,14 @@ SQLITE_PRIVATE int sqlite3CantopenError(int); #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3NomemError(int); SQLITE_PRIVATE int sqlite3IoerrnomemError(int); +SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); # define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__) # define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__) +# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) #else # define SQLITE_NOMEM_BKPT SQLITE_NOMEM # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM +# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) #endif /* @@ -16263,8 +17303,6 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*); SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*); SQLITE_PRIVATE int sqlite3MallocSize(void*); SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*); -SQLITE_PRIVATE void *sqlite3ScratchMalloc(int); -SQLITE_PRIVATE void sqlite3ScratchFree(void*); SQLITE_PRIVATE void *sqlite3PageMalloc(int); SQLITE_PRIVATE void sqlite3PageFree(void*); SQLITE_PRIVATE void sqlite3MemSetDefault(void); @@ -16320,6 +17358,7 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int); SQLITE_PRIVATE void sqlite3StatusUp(int, int); SQLITE_PRIVATE void sqlite3StatusDown(int, int); SQLITE_PRIVATE void sqlite3StatusHighwater(int, int); +SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*); /* Access to mutexes used by sqlite3_status() */ SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void); @@ -16551,10 +17590,10 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*); SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int); SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*); -SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCompare(Parse*,Expr*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int); -SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); @@ -16568,8 +17607,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int); SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); -SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); -SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*); +SQLITE_PRIVATE void sqlite3EndTransaction(Parse*,int); SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*); SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*); @@ -16690,7 +17728,9 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3Atoi(const char*); +#ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); +#endif SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); SQLITE_PRIVATE LogEst sqlite3LogEst(u64); @@ -16755,6 +17795,8 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); +SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr); +SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*); SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); @@ -16779,7 +17821,9 @@ SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*); SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); +#ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); +#endif SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION @@ -17036,7 +18080,8 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*); SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *); -#ifdef SQLITE_ENABLE_ATOMIC_WRITE +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *); #endif @@ -17122,8 +18167,7 @@ SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8); #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ #define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */ -#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */ -#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */ +#define MEMTYPE_PCACHE 0x04 /* Page cache allocations */ /* ** Threading interface @@ -17133,6 +18177,9 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*); SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**); #endif +#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST) +SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*); +#endif #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST) SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*); #endif @@ -17143,6 +18190,10 @@ SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int); SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int); SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*); +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt); +#endif + #endif /* SQLITEINT_H */ /************** End of sqliteInt.h *******************************************/ @@ -17348,6 +18399,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { SQLITE_THREADSAFE==1, /* bFullMutex */ SQLITE_USE_URI, /* bOpenUri */ SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ + 0, /* bSmallMalloc */ 0x7ffffffe, /* mxStrlen */ 0, /* neverCorrupt */ SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */ @@ -17360,9 +18412,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0, 0, /* mnHeap, mxHeap */ SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */ SQLITE_MAX_MMAP_SIZE, /* mxMmap */ - (void*)0, /* pScratch */ - 0, /* szScratch */ - 0, /* nScratch */ (void*)0, /* pPage */ 0, /* szPage */ SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */ @@ -17447,472 +18496,6 @@ SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER; SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY"; /************** End of global.c **********************************************/ -/************** Begin file ctime.c *******************************************/ -/* -** 2010 February 23 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This file implements routines used to report what compile-time options -** SQLite was built with. -*/ - -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS - -/* #include "sqliteInt.h" */ - -/* -** An array of names of all compile-time options. This array should -** be sorted A-Z. -** -** This array looks large, but in a typical installation actually uses -** only a handful of compile-time options, so most times this array is usually -** rather short and uses little memory space. -*/ -static const char * const azCompileOpt[] = { - -/* These macros are provided to "stringify" the value of the define -** for those options in which the value is meaningful. */ -#define CTIMEOPT_VAL_(opt) #opt -#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) - -#if SQLITE_32BIT_ROWID - "32BIT_ROWID", -#endif -#if SQLITE_4_BYTE_ALIGNED_MALLOC - "4_BYTE_ALIGNED_MALLOC", -#endif -#if SQLITE_CASE_SENSITIVE_LIKE - "CASE_SENSITIVE_LIKE", -#endif -#if SQLITE_CHECK_PAGES - "CHECK_PAGES", -#endif -#if defined(__clang__) && defined(__clang_major__) - "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "." - CTIMEOPT_VAL(__clang_minor__) "." - CTIMEOPT_VAL(__clang_patchlevel__), -#elif defined(_MSC_VER) - "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER), -#elif defined(__GNUC__) && defined(__VERSION__) - "COMPILER=gcc-" __VERSION__, -#endif -#if SQLITE_COVERAGE_TEST - "COVERAGE_TEST", -#endif -#ifdef SQLITE_DEBUG - "DEBUG", -#endif -#if SQLITE_DEFAULT_LOCKING_MODE - "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), -#endif -#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc) - "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), -#endif -#if SQLITE_DEFAULT_SYNCHRONOUS - "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS), -#endif -#if SQLITE_DEFAULT_WAL_SYNCHRONOUS - "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS), -#endif -#if SQLITE_DIRECT_OVERFLOW_READ - "DIRECT_OVERFLOW_READ", -#endif -#if SQLITE_DISABLE_DIRSYNC - "DISABLE_DIRSYNC", -#endif -#if SQLITE_DISABLE_LFS - "DISABLE_LFS", -#endif -#if SQLITE_ENABLE_8_3_NAMES - "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), -#endif -#if SQLITE_ENABLE_API_ARMOR - "ENABLE_API_ARMOR", -#endif -#if SQLITE_ENABLE_ATOMIC_WRITE - "ENABLE_ATOMIC_WRITE", -#endif -#if SQLITE_ENABLE_CEROD - "ENABLE_CEROD", -#endif -#if SQLITE_ENABLE_COLUMN_METADATA - "ENABLE_COLUMN_METADATA", -#endif -#if SQLITE_ENABLE_DBSTAT_VTAB - "ENABLE_DBSTAT_VTAB", -#endif -#if SQLITE_ENABLE_EXPENSIVE_ASSERT - "ENABLE_EXPENSIVE_ASSERT", -#endif -#if SQLITE_ENABLE_FTS1 - "ENABLE_FTS1", -#endif -#if SQLITE_ENABLE_FTS2 - "ENABLE_FTS2", -#endif -#if SQLITE_ENABLE_FTS3 - "ENABLE_FTS3", -#endif -#if SQLITE_ENABLE_FTS3_PARENTHESIS - "ENABLE_FTS3_PARENTHESIS", -#endif -#if SQLITE_ENABLE_FTS4 - "ENABLE_FTS4", -#endif -#if SQLITE_ENABLE_FTS5 - "ENABLE_FTS5", -#endif -#if SQLITE_ENABLE_ICU - "ENABLE_ICU", -#endif -#if SQLITE_ENABLE_IOTRACE - "ENABLE_IOTRACE", -#endif -#if SQLITE_ENABLE_JSON1 - "ENABLE_JSON1", -#endif -#if SQLITE_ENABLE_LOAD_EXTENSION - "ENABLE_LOAD_EXTENSION", -#endif -#if SQLITE_ENABLE_LOCKING_STYLE - "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), -#endif -#if SQLITE_ENABLE_MEMORY_MANAGEMENT - "ENABLE_MEMORY_MANAGEMENT", -#endif -#if SQLITE_ENABLE_MEMSYS3 - "ENABLE_MEMSYS3", -#endif -#if SQLITE_ENABLE_MEMSYS5 - "ENABLE_MEMSYS5", -#endif -#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK - "ENABLE_OVERSIZE_CELL_CHECK", -#endif -#if SQLITE_ENABLE_RTREE - "ENABLE_RTREE", -#endif -#if defined(SQLITE_ENABLE_STAT4) - "ENABLE_STAT4", -#elif defined(SQLITE_ENABLE_STAT3) - "ENABLE_STAT3", -#endif -#if SQLITE_ENABLE_UNLOCK_NOTIFY - "ENABLE_UNLOCK_NOTIFY", -#endif -#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT - "ENABLE_UPDATE_DELETE_LIMIT", -#endif -#if defined(SQLITE_ENABLE_URI_00_ERROR) - "ENABLE_URI_00_ERROR", -#endif -#if SQLITE_HAS_CODEC - "HAS_CODEC", -#endif -#if HAVE_ISNAN || SQLITE_HAVE_ISNAN - "HAVE_ISNAN", -#endif -#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX - "HOMEGROWN_RECURSIVE_MUTEX", -#endif -#if SQLITE_IGNORE_AFP_LOCK_ERRORS - "IGNORE_AFP_LOCK_ERRORS", -#endif -#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS - "IGNORE_FLOCK_LOCK_ERRORS", -#endif -#ifdef SQLITE_INT64_TYPE - "INT64_TYPE", -#endif -#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS - "LIKE_DOESNT_MATCH_BLOBS", -#endif -#if SQLITE_LOCK_TRACE - "LOCK_TRACE", -#endif -#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc) - "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE), -#endif -#ifdef SQLITE_MAX_SCHEMA_RETRY - "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), -#endif -#if SQLITE_MEMDEBUG - "MEMDEBUG", -#endif -#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT - "MIXED_ENDIAN_64BIT_FLOAT", -#endif -#if SQLITE_NO_SYNC - "NO_SYNC", -#endif -#if SQLITE_OMIT_ALTERTABLE - "OMIT_ALTERTABLE", -#endif -#if SQLITE_OMIT_ANALYZE - "OMIT_ANALYZE", -#endif -#if SQLITE_OMIT_ATTACH - "OMIT_ATTACH", -#endif -#if SQLITE_OMIT_AUTHORIZATION - "OMIT_AUTHORIZATION", -#endif -#if SQLITE_OMIT_AUTOINCREMENT - "OMIT_AUTOINCREMENT", -#endif -#if SQLITE_OMIT_AUTOINIT - "OMIT_AUTOINIT", -#endif -#if SQLITE_OMIT_AUTOMATIC_INDEX - "OMIT_AUTOMATIC_INDEX", -#endif -#if SQLITE_OMIT_AUTORESET - "OMIT_AUTORESET", -#endif -#if SQLITE_OMIT_AUTOVACUUM - "OMIT_AUTOVACUUM", -#endif -#if SQLITE_OMIT_BETWEEN_OPTIMIZATION - "OMIT_BETWEEN_OPTIMIZATION", -#endif -#if SQLITE_OMIT_BLOB_LITERAL - "OMIT_BLOB_LITERAL", -#endif -#if SQLITE_OMIT_BTREECOUNT - "OMIT_BTREECOUNT", -#endif -#if SQLITE_OMIT_CAST - "OMIT_CAST", -#endif -#if SQLITE_OMIT_CHECK - "OMIT_CHECK", -#endif -#if SQLITE_OMIT_COMPLETE - "OMIT_COMPLETE", -#endif -#if SQLITE_OMIT_COMPOUND_SELECT - "OMIT_COMPOUND_SELECT", -#endif -#if SQLITE_OMIT_CTE - "OMIT_CTE", -#endif -#if SQLITE_OMIT_DATETIME_FUNCS - "OMIT_DATETIME_FUNCS", -#endif -#if SQLITE_OMIT_DECLTYPE - "OMIT_DECLTYPE", -#endif -#if SQLITE_OMIT_DEPRECATED - "OMIT_DEPRECATED", -#endif -#if SQLITE_OMIT_DISKIO - "OMIT_DISKIO", -#endif -#if SQLITE_OMIT_EXPLAIN - "OMIT_EXPLAIN", -#endif -#if SQLITE_OMIT_FLAG_PRAGMAS - "OMIT_FLAG_PRAGMAS", -#endif -#if SQLITE_OMIT_FLOATING_POINT - "OMIT_FLOATING_POINT", -#endif -#if SQLITE_OMIT_FOREIGN_KEY - "OMIT_FOREIGN_KEY", -#endif -#if SQLITE_OMIT_GET_TABLE - "OMIT_GET_TABLE", -#endif -#if SQLITE_OMIT_INCRBLOB - "OMIT_INCRBLOB", -#endif -#if SQLITE_OMIT_INTEGRITY_CHECK - "OMIT_INTEGRITY_CHECK", -#endif -#if SQLITE_OMIT_LIKE_OPTIMIZATION - "OMIT_LIKE_OPTIMIZATION", -#endif -#if SQLITE_OMIT_LOAD_EXTENSION - "OMIT_LOAD_EXTENSION", -#endif -#if SQLITE_OMIT_LOCALTIME - "OMIT_LOCALTIME", -#endif -#if SQLITE_OMIT_LOOKASIDE - "OMIT_LOOKASIDE", -#endif -#if SQLITE_OMIT_MEMORYDB - "OMIT_MEMORYDB", -#endif -#if SQLITE_OMIT_OR_OPTIMIZATION - "OMIT_OR_OPTIMIZATION", -#endif -#if SQLITE_OMIT_PAGER_PRAGMAS - "OMIT_PAGER_PRAGMAS", -#endif -#if SQLITE_OMIT_PRAGMA - "OMIT_PRAGMA", -#endif -#if SQLITE_OMIT_PROGRESS_CALLBACK - "OMIT_PROGRESS_CALLBACK", -#endif -#if SQLITE_OMIT_QUICKBALANCE - "OMIT_QUICKBALANCE", -#endif -#if SQLITE_OMIT_REINDEX - "OMIT_REINDEX", -#endif -#if SQLITE_OMIT_SCHEMA_PRAGMAS - "OMIT_SCHEMA_PRAGMAS", -#endif -#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS - "OMIT_SCHEMA_VERSION_PRAGMAS", -#endif -#if SQLITE_OMIT_SHARED_CACHE - "OMIT_SHARED_CACHE", -#endif -#if SQLITE_OMIT_SUBQUERY - "OMIT_SUBQUERY", -#endif -#if SQLITE_OMIT_TCL_VARIABLE - "OMIT_TCL_VARIABLE", -#endif -#if SQLITE_OMIT_TEMPDB - "OMIT_TEMPDB", -#endif -#if SQLITE_OMIT_TRACE - "OMIT_TRACE", -#endif -#if SQLITE_OMIT_TRIGGER - "OMIT_TRIGGER", -#endif -#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION - "OMIT_TRUNCATE_OPTIMIZATION", -#endif -#if SQLITE_OMIT_UTF16 - "OMIT_UTF16", -#endif -#if SQLITE_OMIT_VACUUM - "OMIT_VACUUM", -#endif -#if SQLITE_OMIT_VIEW - "OMIT_VIEW", -#endif -#if SQLITE_OMIT_VIRTUALTABLE - "OMIT_VIRTUALTABLE", -#endif -#if SQLITE_OMIT_WAL - "OMIT_WAL", -#endif -#if SQLITE_OMIT_WSD - "OMIT_WSD", -#endif -#if SQLITE_OMIT_XFER_OPT - "OMIT_XFER_OPT", -#endif -#if SQLITE_PERFORMANCE_TRACE - "PERFORMANCE_TRACE", -#endif -#if SQLITE_PROXY_DEBUG - "PROXY_DEBUG", -#endif -#if SQLITE_RTREE_INT_ONLY - "RTREE_INT_ONLY", -#endif -#if SQLITE_SECURE_DELETE - "SECURE_DELETE", -#endif -#if SQLITE_SMALL_STACK - "SMALL_STACK", -#endif -#if SQLITE_SOUNDEX - "SOUNDEX", -#endif -#if SQLITE_SYSTEM_MALLOC - "SYSTEM_MALLOC", -#endif -#if SQLITE_TCL - "TCL", -#endif -#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc) - "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), -#endif -#if SQLITE_TEST - "TEST", -#endif -#if defined(SQLITE_THREADSAFE) - "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), -#endif -#if SQLITE_UNTESTABLE - "UNTESTABLE" -#endif -#if SQLITE_USE_ALLOCA - "USE_ALLOCA", -#endif -#if SQLITE_USER_AUTHENTICATION - "USER_AUTHENTICATION", -#endif -#if SQLITE_WIN32_MALLOC - "WIN32_MALLOC", -#endif -#if SQLITE_ZERO_MALLOC - "ZERO_MALLOC" -#endif -}; - -/* -** Given the name of a compile-time option, return true if that option -** was used and false if not. -** -** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix -** is not required for a match. -*/ -SQLITE_API int sqlite3_compileoption_used(const char *zOptName){ - int i, n; - -#if SQLITE_ENABLE_API_ARMOR - if( zOptName==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif - if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; - n = sqlite3Strlen30(zOptName); - - /* Since ArraySize(azCompileOpt) is normally in single digits, a - ** linear search is adequate. No need for a binary search. */ - for(i=0; i<ArraySize(azCompileOpt); i++){ - if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0 - && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0 - ){ - return 1; - } - } - return 0; -} - -/* -** Return the N-th compile-time option string. If N is out of range, -** return a NULL pointer. -*/ -SQLITE_API const char *sqlite3_compileoption_get(int N){ - if( N>=0 && N<ArraySize(azCompileOpt) ){ - return azCompileOpt[N]; - } - return 0; -} - -#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ - -/************** End of ctime.c ***********************************************/ /************** Begin file status.c ******************************************/ /* ** 2008 June 18 @@ -18030,18 +18613,18 @@ struct VdbeCursor { u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0 ** if there have been no prior seeks on the cursor. */ - /* NB: seekResult does not distinguish between "no seeks have ever occurred - ** on this cursor" and "the most recent seek was an exact match". */ + /* seekResult does not distinguish between "no seeks have ever occurred + ** on this cursor" and "the most recent seek was an exact match". + ** For CURTYPE_PSEUDO, seekResult is the register holding the record */ /* When a new VdbeCursor is allocated, only the fields above are zeroed. ** The fields that follow are uninitialized, and must be individually ** initialized prior to first use. */ VdbeCursor *pAltCursor; /* Associated index cursor from which to read */ union { - BtCursor *pCursor; /* CURTYPE_BTREE. Btree cursor */ - sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */ - int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */ - VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */ + BtCursor *pCursor; /* CURTYPE_BTREE or _PSEUDO. Btree cursor */ + sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */ + VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */ } uc; KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ u32 iHdrOffset; /* Offset to next unparsed byte of the header */ @@ -18123,7 +18706,8 @@ struct sqlite3_value { union MemValue { double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ - int nZero; /* Used when bit MEM_Zero is set in flags */ + int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ + const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ @@ -18155,7 +18739,8 @@ struct sqlite3_value { ** representations of the value stored in the Mem struct. ** ** If the MEM_Null flag is set, then the value is an SQL NULL value. -** No other flags may be set in this case. +** For a pointer type created using sqlite3_bind_pointer() or +** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set. ** ** If the MEM_Str flag is set then Mem.z points at a string representation. ** Usually this is encoded in the same unicode encoding as the main @@ -18163,7 +18748,7 @@ struct sqlite3_value { ** set, then the string is nul terminated. The MEM_Int and MEM_Real ** flags may coexist with the MEM_Str flag. */ -#define MEM_Null 0x0001 /* Value is NULL */ +#define MEM_Null 0x0001 /* Value is NULL (or a pointer) */ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ @@ -18173,7 +18758,7 @@ struct sqlite3_value { #define MEM_Frame 0x0040 /* Value is a VdbeFrame object */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ -#define MEM_TypeMask 0x81ff /* Mask of type bits */ +#define MEM_TypeMask 0xc1ff /* Mask of type bits */ /* Whenever Mem contains a valid string or blob representation, one of @@ -18181,7 +18766,7 @@ struct sqlite3_value { ** policy for Mem.z. The MEM_Term flag tells us whether or not the ** string is \000 or \u0000 terminated */ -#define MEM_Term 0x0200 /* String rep is nul terminated */ +#define MEM_Term 0x0200 /* String in Mem.z is zero terminated */ #define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */ #define MEM_Static 0x0800 /* Mem.z points to a static string */ #define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */ @@ -18316,6 +18901,7 @@ struct Vdbe { u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ + u8 prepFlags; /* SQLITE_PREPARE_* flags */ bft expired:1; /* True if the VM needs to be recompiled */ bft doingRerun:1; /* True if rerunning after an auto-reprepare */ bft explain:2; /* True if EXPLAIN present on SQL command */ @@ -18324,10 +18910,9 @@ struct Vdbe { bft usesStmtJournal:1; /* True if uses a statement journal */ bft readOnly:1; /* True for statements that do not write */ bft bIsReader:1; /* True for statements that read */ - bft isPrepareV2:1; /* True if prepared with prepare_v2() */ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ yDbMask lockMask; /* Subset of btreeMask that requires a lock */ - u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */ + u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ void *pFree; /* Free this when deleting the vdbe */ VdbeFrame *pFrame; /* Parent frame */ @@ -18409,6 +18994,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64); #else SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double); #endif +SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*); SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int); @@ -18440,7 +19026,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); -SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); +SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); @@ -18468,12 +19054,14 @@ SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int); # define sqlite3VdbeCheckFk(p,i) 0 #endif -SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8); #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf); #endif -SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem); +#ifndef SQLITE_OMIT_UTF16 +SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8); +SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem); +#endif #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *); @@ -18594,7 +19182,6 @@ SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){ : sqlite3MallocMutex()) ); assert( op==SQLITE_STATUS_MALLOC_SIZE || op==SQLITE_STATUS_PAGECACHE_SIZE - || op==SQLITE_STATUS_SCRATCH_SIZE || op==SQLITE_STATUS_PARSER_STACK ); if( newValue>wsdStat.mxValue[op] ){ wsdStat.mxValue[op] = newValue; @@ -18644,6 +19231,28 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF } /* +** Return the number of LookasideSlot elements on the linked list +*/ +static u32 countLookasideSlots(LookasideSlot *p){ + u32 cnt = 0; + while( p ){ + p = p->pNext; + cnt++; + } + return cnt; +} + +/* +** Count the number of slots of lookaside memory that are outstanding +*/ +SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){ + u32 nInit = countLookasideSlots(db->lookaside.pInit); + u32 nFree = countLookasideSlots(db->lookaside.pFree); + if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit; + return db->lookaside.nSlot - (nInit+nFree); +} + +/* ** Query status information for a single database connection */ SQLITE_API int sqlite3_db_status( @@ -18662,10 +19271,15 @@ SQLITE_API int sqlite3_db_status( sqlite3_mutex_enter(db->mutex); switch( op ){ case SQLITE_DBSTATUS_LOOKASIDE_USED: { - *pCurrent = db->lookaside.nOut; - *pHighwater = db->lookaside.mxOut; + *pCurrent = sqlite3LookasideUsed(db, pHighwater); if( resetFlag ){ - db->lookaside.mxOut = db->lookaside.nOut; + LookasideSlot *p = db->lookaside.pFree; + if( p ){ + while( p->pNext ) p = p->pNext; + p->pNext = db->lookaside.pInit; + db->lookaside.pInit = db->lookaside.pFree; + db->lookaside.pFree = 0; + } } break; } @@ -19212,7 +19826,7 @@ static int parseDateOrTime( return 0; }else if( parseHhMmSs(zDate, p)==0 ){ return 0; - }else if( sqlite3StrICmp(zDate,"now")==0){ + }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){ setRawDateNumber(p, r); @@ -19495,7 +20109,7 @@ static int parseModifier( ** Assuming the current time value is UTC (a.k.a. GMT), shift it to ** show local time. */ - if( sqlite3_stricmp(z, "localtime")==0 ){ + if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){ computeJD(p); p->iJD += localtimeOffset(p, pCtx, &rc); clearYMD_HMS_TZ(p); @@ -19521,7 +20135,7 @@ static int parseModifier( } } #ifndef SQLITE_OMIT_LOCALTIME - else if( sqlite3_stricmp(z, "utc")==0 ){ + else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ if( p->tzSet==0 ){ sqlite3_int64 c1; computeJD(p); @@ -20057,11 +20671,11 @@ static void currentTimeFunc( SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){ static FuncDef aDateTimeFuncs[] = { #ifndef SQLITE_OMIT_DATETIME_FUNCS - DFUNCTION(julianday, -1, 0, 0, juliandayFunc ), - DFUNCTION(date, -1, 0, 0, dateFunc ), - DFUNCTION(time, -1, 0, 0, timeFunc ), - DFUNCTION(datetime, -1, 0, 0, datetimeFunc ), - DFUNCTION(strftime, -1, 0, 0, strftimeFunc ), + PURE_DATE(julianday, -1, 0, 0, juliandayFunc ), + PURE_DATE(date, -1, 0, 0, dateFunc ), + PURE_DATE(time, -1, 0, 0, timeFunc ), + PURE_DATE(datetime, -1, 0, 0, datetimeFunc ), + PURE_DATE(strftime, -1, 0, 0, strftimeFunc ), DFUNCTION(current_time, 0, 0, 0, ctimeFunc ), DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), DFUNCTION(current_date, 0, 0, 0, cdateFunc ), @@ -20176,7 +20790,7 @@ SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){ } SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){ DO_OS_MALLOC_TEST(id); - return id->pMethods->xSync(id, flags); + return flags ? id->pMethods->xSync(id, flags) : SQLITE_OK; } SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ DO_OS_MALLOC_TEST(id); @@ -20231,6 +20845,7 @@ SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){ SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ return id->pMethods->xDeviceCharacteristics(id); } +#ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){ return id->pMethods->xShmLock(id, offset, n, flags); } @@ -20250,6 +20865,7 @@ SQLITE_PRIVATE int sqlite3OsShmMap( DO_OS_MALLOC_TEST(id); return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); } +#endif /* SQLITE_OMIT_WAL */ #if SQLITE_MAX_MMAP_SIZE>0 /* The real implementation of xFetch and xUnfetch */ @@ -24247,14 +24863,6 @@ SQLITE_API int sqlite3_release_memory(int n){ } /* -** An instance of the following object records the location of -** each unused scratch buffer. -*/ -typedef struct ScratchFreeslot { - struct ScratchFreeslot *pNext; /* Next unused scratch buffer */ -} ScratchFreeslot; - -/* ** State information local to the memory allocation subsystem. */ static SQLITE_WSD struct Mem0Global { @@ -24262,21 +24870,11 @@ static SQLITE_WSD struct Mem0Global { sqlite3_int64 alarmThreshold; /* The soft heap limit */ /* - ** Pointers to the end of sqlite3GlobalConfig.pScratch memory - ** (so that a range test can be used to determine if an allocation - ** being freed came from pScratch) and a pointer to the list of - ** unused scratch allocations. - */ - void *pScratchEnd; - ScratchFreeslot *pScratchFree; - u32 nScratchFree; - - /* ** True if heap is nearly "full" where "full" is defined by the ** sqlite3_soft_heap_limit() setting. */ int nearlyFull; -} mem0 = { 0, 0, 0, 0, 0, 0 }; +} mem0 = { 0, 0, 0 }; #define mem0 GLOBAL(struct Mem0Global, mem0) @@ -24346,28 +24944,6 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){ } memset(&mem0, 0, sizeof(mem0)); mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); - if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100 - && sqlite3GlobalConfig.nScratch>0 ){ - int i, n, sz; - ScratchFreeslot *pSlot; - sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch); - sqlite3GlobalConfig.szScratch = sz; - pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch; - n = sqlite3GlobalConfig.nScratch; - mem0.pScratchFree = pSlot; - mem0.nScratchFree = n; - for(i=0; i<n-1; i++){ - pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot); - pSlot = pSlot->pNext; - } - pSlot->pNext = 0; - mem0.pScratchEnd = (void*)&pSlot[1]; - }else{ - mem0.pScratchEnd = 0; - sqlite3GlobalConfig.pScratch = 0; - sqlite3GlobalConfig.szScratch = 0; - sqlite3GlobalConfig.nScratch = 0; - } if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512 || sqlite3GlobalConfig.nPage<=0 ){ sqlite3GlobalConfig.pPage = 0; @@ -24519,105 +25095,6 @@ SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){ } /* -** Each thread may only have a single outstanding allocation from -** xScratchMalloc(). We verify this constraint in the single-threaded -** case by setting scratchAllocOut to 1 when an allocation -** is outstanding clearing it when the allocation is freed. -*/ -#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) -static int scratchAllocOut = 0; -#endif - - -/* -** Allocate memory that is to be used and released right away. -** This routine is similar to alloca() in that it is not intended -** for situations where the memory might be held long-term. This -** routine is intended to get memory to old large transient data -** structures that would not normally fit on the stack of an -** embedded processor. -*/ -SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){ - void *p; - assert( n>0 ); - - sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusHighwater(SQLITE_STATUS_SCRATCH_SIZE, n); - if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){ - p = mem0.pScratchFree; - mem0.pScratchFree = mem0.pScratchFree->pNext; - mem0.nScratchFree--; - sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1); - sqlite3_mutex_leave(mem0.mutex); - }else{ - sqlite3_mutex_leave(mem0.mutex); - p = sqlite3Malloc(n); - if( sqlite3GlobalConfig.bMemstat && p ){ - sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p)); - sqlite3_mutex_leave(mem0.mutex); - } - sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH); - } - assert( sqlite3_mutex_notheld(mem0.mutex) ); - - -#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) - /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch - ** buffers per thread. - ** - ** This can only be checked in single-threaded mode. - */ - assert( scratchAllocOut==0 ); - if( p ) scratchAllocOut++; -#endif - - return p; -} -SQLITE_PRIVATE void sqlite3ScratchFree(void *p){ - if( p ){ - -#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) - /* Verify that no more than two scratch allocation per thread - ** is outstanding at one time. (This is only checked in the - ** single-threaded case since checking in the multi-threaded case - ** would be much more complicated.) */ - assert( scratchAllocOut>=1 && scratchAllocOut<=2 ); - scratchAllocOut--; -#endif - - if( SQLITE_WITHIN(p, sqlite3GlobalConfig.pScratch, mem0.pScratchEnd) ){ - /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */ - ScratchFreeslot *pSlot; - pSlot = (ScratchFreeslot*)p; - sqlite3_mutex_enter(mem0.mutex); - pSlot->pNext = mem0.pScratchFree; - mem0.pScratchFree = pSlot; - mem0.nScratchFree++; - assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch ); - sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1); - sqlite3_mutex_leave(mem0.mutex); - }else{ - /* Release memory back to the heap */ - assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) ); - assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) ); - sqlite3MemdebugSetType(p, MEMTYPE_HEAP); - if( sqlite3GlobalConfig.bMemstat ){ - int iSize = sqlite3MallocSize(p); - sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize); - sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize); - sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1); - sqlite3GlobalConfig.m.xFree(p); - sqlite3_mutex_leave(mem0.mutex); - }else{ - sqlite3GlobalConfig.m.xFree(p); - } - } - } -} - -/* ** TRUE if p is a lookaside memory allocation from db */ #ifndef SQLITE_OMIT_LOOKASIDE @@ -24707,7 +25184,6 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){ #endif pBuf->pNext = db->lookaside.pFree; db->lookaside.pFree = pBuf; - db->lookaside.nOut--; return; } } @@ -24868,16 +25344,16 @@ SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){ assert( db->mallocFailed==0 ); if( n>db->lookaside.sz ){ db->lookaside.anStat[1]++; - }else if( (pBuf = db->lookaside.pFree)==0 ){ - db->lookaside.anStat[2]++; - }else{ + }else if( (pBuf = db->lookaside.pFree)!=0 ){ db->lookaside.pFree = pBuf->pNext; - db->lookaside.nOut++; db->lookaside.anStat[0]++; - if( db->lookaside.nOut>db->lookaside.mxOut ){ - db->lookaside.mxOut = db->lookaside.nOut; - } return (void*)pBuf; + }else if( (pBuf = db->lookaside.pInit)!=0 ){ + db->lookaside.pInit = pBuf->pNext; + db->lookaside.anStat[0]++; + return (void*)pBuf; + }else{ + db->lookaside.anStat[2]++; } }else if( db->mallocFailed ){ return 0; @@ -25715,7 +26191,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf( if( precision>=0 ){ for(length=0; length<precision && bufpt[length]; length++){} }else{ - length = sqlite3Strlen30(bufpt); + length = 0x7fffffff & (int)strlen(bufpt); } break; case etSQLESCAPE: /* Escape ' characters */ @@ -25841,7 +26317,6 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ }else{ char *zOld = isMalloced(p) ? p->zText : 0; i64 szNew = p->nChar; - assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) ); szNew += N + 1; if( szNew+p->nChar<=p->mxAlloc ){ /* Force exponential buffer size growth as long as it does not overflow, @@ -25883,7 +26358,6 @@ SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){ if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){ return; } - assert( (p->zText==p->zBase)==!isMalloced(p) ); while( (N--)>0 ) p->zText[p->nChar++] = c; } @@ -25901,7 +26375,6 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ memcpy(&p->zText[p->nChar], z, N); p->nChar += N; } - assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) ); } /* @@ -25936,19 +26409,20 @@ SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){ ** pointer if any kind of error was encountered. */ static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){ + char *zText; assert( p->mxAlloc>0 && !isMalloced(p) ); - p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); - if( p->zText ){ - memcpy(p->zText, p->zBase, p->nChar+1); + zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); + if( zText ){ + memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ setStrAccumError(p, STRACCUM_NOMEM); } - return p->zText; + p->zText = zText; + return zText; } SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){ if( p->zText ){ - assert( (p->zText==p->zBase)==!isMalloced(p) ); p->zText[p->nChar] = 0; if( p->mxAlloc>0 && !isMalloced(p) ){ return strAccumFinishRealloc(p); @@ -25961,7 +26435,6 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){ ** Reset an StrAccum string. Reclaim all malloced memory. */ SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){ - assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) ); if( isMalloced(p) ){ sqlite3DbFree(p->db, p->zText); p->printfFlags &= ~SQLITE_PRINTF_MALLOCED; @@ -25984,11 +26457,11 @@ SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){ ** allocations will ever occur. */ SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){ - p->zText = p->zBase = zBase; + p->zText = zBase; p->db = db; - p->nChar = 0; p->nAlloc = n; p->mxAlloc = mx; + p->nChar = 0; p->accError = 0; p->printfFlags = 0; } @@ -26557,17 +27030,17 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { - sqlite3TreeViewLine(pView, "EXISTS-expr"); + sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { - sqlite3TreeViewLine(pView, "SELECT-expr"); + sqlite3TreeViewLine(pView, "SELECT-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_IN: { - sqlite3TreeViewLine(pView, "IN"); + sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); @@ -27455,7 +27928,9 @@ translate_out: #endif return SQLITE_OK; } +#endif /* SQLITE_OMIT_UTF16 */ +#ifndef SQLITE_OMIT_UTF16 /* ** This routine checks for a byte-order mark at the beginning of the ** UTF-16 string stored in *pMem. If one is present, it is removed and @@ -28147,7 +28622,11 @@ do_atof_calc: if( esign<0 ){ result = 0.0*s; }else{ +#ifdef INFINITY + result = INFINITY*s; +#else result = 1e308*1e308*s; /* Infinity */ +#endif } } }else{ @@ -28209,16 +28688,12 @@ static int compare2pow63(const char *zNum, int incr){ ** Convert zNum to a 64-bit signed integer. zNum must be decimal. This ** routine does *not* accept hexadecimal notation. ** -** If the zNum value is representable as a 64-bit twos-complement -** integer, then write that value into *pNum and return 0. -** -** If zNum is exactly 9223372036854775808, return 2. This special -** case is broken out because while 9223372036854775808 cannot be a -** signed 64-bit integer, its negative -9223372036854775808 can be. +** Returns: ** -** If zNum is too big for a 64-bit integer and is not -** 9223372036854775808 or if zNum contains any non-numeric text, -** then return 1. +** 0 Successful transformation. Fits in a 64-bit signed integer. +** 1 Excess text after the integer value +** 2 Integer too large for a 64-bit signed integer or is malformed +** 3 Special case of 9223372036854775808 ** ** length is the number of bytes in the string (bytes, not characters). ** The string is not necessarily zero-terminated. The encoding is @@ -28231,6 +28706,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc int i; int c = 0; int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ + int rc; /* Baseline return code */ const char *zStart; const char *zEnd = zNum + length; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); @@ -28270,31 +28746,35 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc testcase( i==20 ); if( &zNum[i]<zEnd /* Extra bytes at the end */ || (i==0 && zStart==zNum) /* No digits */ - || i>19*incr /* Too many digits */ || nonNum /* UTF16 with high-order bytes non-zero */ ){ + rc = 1; + }else{ + rc = 0; + } + if( i>19*incr ){ /* Too many digits */ /* zNum is empty or contains non-numeric text or is longer ** than 19 digits (thus guaranteeing that it is too large) */ - return 1; + return 2; }else if( i<19*incr ){ /* Less than 19 digits, so we know that it fits in 64 bits */ assert( u<=LARGEST_INT64 ); - return 0; + return rc; }else{ /* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */ c = compare2pow63(zNum, incr); if( c<0 ){ /* zNum is less than 9223372036854775808 so it fits */ assert( u<=LARGEST_INT64 ); - return 0; + return rc; }else if( c>0 ){ /* zNum is greater than 9223372036854775808 so it overflows */ - return 1; + return 2; }else{ /* zNum is exactly 9223372036854775808. Fits if negative. The ** special case 2 overflow if positive */ assert( u-1==LARGEST_INT64 ); - return neg ? 0 : 2; + return neg ? rc : 3; } } } @@ -28307,8 +28787,9 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc ** Returns: ** ** 0 Successful transformation. Fits in a 64-bit signed integer. -** 1 Integer too large for a 64-bit signed integer or is malformed -** 2 Special case of 9223372036854775808 +** 1 Excess text after the integer value +** 2 Integer too large for a 64-bit signed integer or is malformed +** 3 Special case of 9223372036854775808 */ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ #ifndef SQLITE_OMIT_HEX_INTEGER @@ -28322,7 +28803,7 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ u = u*16 + sqlite3HexToInt(z[k]); } memcpy(pOut, &u, 8); - return (z[k]==0 && k-i<=16) ? 0 : 1; + return (z[k]==0 && k-i<=16) ? 0 : 2; }else #endif /* SQLITE_OMIT_HEX_INTEGER */ { @@ -28932,7 +29413,7 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ ** overflow, leave *pA unchanged and return 1. */ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){ -#if GCC_VERSION>=5004000 +#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) return __builtin_add_overflow(*pA, iB, pA); #else i64 iA = *pA; @@ -28952,7 +29433,7 @@ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){ #endif } SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ -#if GCC_VERSION>=5004000 +#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) return __builtin_sub_overflow(*pA, iB, pA); #else testcase( iB==SMALLEST_INT64+1 ); @@ -28967,7 +29448,7 @@ SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ #endif } SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ -#if GCC_VERSION>=5004000 +#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) return __builtin_mul_overflow(*pA, iB, pA); #else i64 iA = *pA; @@ -29069,8 +29550,14 @@ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){ if( x<2 ) return 0; while( x<8 ){ y -= 10; x <<= 1; } }else{ +#if GCC_VERSION>=5004000 + int i = 60 - __builtin_clzll(x); + y += i*10; + x >>= i; +#else while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/ while( x>15 ){ y += 10; x >>= 1; } +#endif } return a[x&7] + y - 10; } @@ -29366,8 +29853,9 @@ static int rehash(Hash *pH, unsigned int new_size){ } /* This function (for internal use only) locates an element in an -** hash table that matches the given key. The hash for this key is -** also computed and returned in the *pH parameter. +** hash table that matches the given key. If no element is found, +** a pointer to a static null element with HashElem.data==0 is returned. +** If pH is not NULL, then the hash for this key is written to *pH. */ static HashElem *findElementWithHash( const Hash *pH, /* The pH to be searched */ @@ -29377,6 +29865,7 @@ static HashElem *findElementWithHash( HashElem *elem; /* Used to loop thru the element list */ int count; /* Number of elements left to test */ unsigned int h; /* The computed hash */ + static HashElem nullElement = { 0, 0, 0, 0 }; if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/ struct _ht *pEntry; @@ -29389,7 +29878,7 @@ static HashElem *findElementWithHash( elem = pH->first; count = pH->count; } - *pHash = h; + if( pHash ) *pHash = h; while( count-- ){ assert( elem!=0 ); if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ @@ -29397,7 +29886,7 @@ static HashElem *findElementWithHash( } elem = elem->next; } - return 0; + return &nullElement; } /* Remove a single entry from the hash table given a pointer to that @@ -29439,13 +29928,9 @@ static void removeElementGivenHash( ** found, or NULL if there is no match. */ SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){ - HashElem *elem; /* The element that matches key */ - unsigned int h; /* A hash on key */ - assert( pH!=0 ); assert( pKey!=0 ); - elem = findElementWithHash(pH, pKey, &h); - return elem ? elem->data : 0; + return findElementWithHash(pH, pKey, 0)->data; } /* Insert an element into the hash table pH. The key is pKey @@ -29470,7 +29955,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ assert( pH!=0 ); assert( pKey!=0 ); elem = findElementWithHash(pH,pKey,&h); - if( elem ){ + if( elem->data ){ void *old_data = elem->data; if( data==0 ){ removeElementGivenHash(pH,elem,h); @@ -29553,47 +30038,47 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 40 */ "IdxLT" OpHelp("key=r[P3@P4]"), /* 41 */ "IdxGE" OpHelp("key=r[P3@P4]"), /* 42 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), - /* 43 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), - /* 44 */ "Program" OpHelp(""), - /* 45 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), - /* 46 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), - /* 47 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), - /* 48 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), - /* 49 */ "IncrVacuum" OpHelp(""), - /* 50 */ "VNext" OpHelp(""), - /* 51 */ "Init" OpHelp("Start at P2"), - /* 52 */ "Return" OpHelp(""), - /* 53 */ "EndCoroutine" OpHelp(""), - /* 54 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), - /* 55 */ "Halt" OpHelp(""), - /* 56 */ "Integer" OpHelp("r[P2]=P1"), - /* 57 */ "Int64" OpHelp("r[P2]=P4"), - /* 58 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 59 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 60 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 61 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 62 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), - /* 63 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 64 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 65 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 66 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 67 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 68 */ "CollSeq" OpHelp(""), - /* 69 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), - /* 70 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), - /* 71 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), - /* 72 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), - /* 73 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 74 */ "RealAffinity" OpHelp(""), - /* 75 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), - /* 76 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), - /* 77 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), - /* 78 */ "Eq" OpHelp("IF r[P3]==r[P1]"), - /* 79 */ "Gt" OpHelp("IF r[P3]>r[P1]"), - /* 80 */ "Le" OpHelp("IF r[P3]<=r[P1]"), - /* 81 */ "Lt" OpHelp("IF r[P3]<r[P1]"), - /* 82 */ "Ge" OpHelp("IF r[P3]>=r[P1]"), - /* 83 */ "ElseNotEq" OpHelp(""), + /* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), + /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), + /* 45 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 46 */ "Program" OpHelp(""), + /* 47 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 48 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), + /* 49 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), + /* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), + /* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), + /* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), + /* 53 */ "Eq" OpHelp("IF r[P3]==r[P1]"), + /* 54 */ "Gt" OpHelp("IF r[P3]>r[P1]"), + /* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"), + /* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"), + /* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"), + /* 58 */ "ElseNotEq" OpHelp(""), + /* 59 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 60 */ "IncrVacuum" OpHelp(""), + /* 61 */ "VNext" OpHelp(""), + /* 62 */ "Init" OpHelp("Start at P2"), + /* 63 */ "Return" OpHelp(""), + /* 64 */ "EndCoroutine" OpHelp(""), + /* 65 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), + /* 66 */ "Halt" OpHelp(""), + /* 67 */ "Integer" OpHelp("r[P2]=P1"), + /* 68 */ "Int64" OpHelp("r[P2]=P4"), + /* 69 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 70 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 71 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 72 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 73 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), + /* 74 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 75 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 76 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 77 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 78 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 79 */ "CollSeq" OpHelp(""), + /* 80 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 81 */ "RealAffinity" OpHelp(""), + /* 82 */ "Cast" OpHelp("affinity(r[P1])"), + /* 83 */ "Permutation" OpHelp(""), /* 84 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 85 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 86 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"), @@ -29604,78 +30089,80 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 91 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), /* 92 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), /* 93 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), - /* 94 */ "Cast" OpHelp("affinity(r[P1])"), + /* 94 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), /* 95 */ "BitNot" OpHelp("r[P1]= ~r[P1]"), - /* 96 */ "Permutation" OpHelp(""), + /* 96 */ "Column" OpHelp("r[P3]=PX"), /* 97 */ "String8" OpHelp("r[P2]='P4'"), - /* 98 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 99 */ "Column" OpHelp("r[P3]=PX"), - /* 100 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 101 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 102 */ "Count" OpHelp("r[P2]=count()"), - /* 103 */ "ReadCookie" OpHelp(""), - /* 104 */ "SetCookie" OpHelp(""), - /* 105 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 106 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 107 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 108 */ "OpenDup" OpHelp(""), - /* 109 */ "OpenAutoindex" OpHelp("nColumn=P2"), - /* 110 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 111 */ "SorterOpen" OpHelp(""), - /* 112 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), - /* 113 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 114 */ "Close" OpHelp(""), - /* 115 */ "ColumnsUsed" OpHelp(""), - /* 116 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), - /* 117 */ "NewRowid" OpHelp("r[P2]=rowid"), - /* 118 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), - /* 119 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), - /* 120 */ "Delete" OpHelp(""), - /* 121 */ "ResetCount" OpHelp(""), - /* 122 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), - /* 123 */ "SorterData" OpHelp("r[P2]=data"), - /* 124 */ "RowData" OpHelp("r[P2]=data"), - /* 125 */ "Rowid" OpHelp("r[P2]=rowid"), - /* 126 */ "NullRow" OpHelp(""), - /* 127 */ "SorterInsert" OpHelp("key=r[P2]"), - /* 128 */ "IdxInsert" OpHelp("key=r[P2]"), - /* 129 */ "IdxDelete" OpHelp("key=r[P2@P3]"), - /* 130 */ "Seek" OpHelp("Move P3 to P1.rowid"), - /* 131 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 100 */ "Count" OpHelp("r[P2]=count()"), + /* 101 */ "ReadCookie" OpHelp(""), + /* 102 */ "SetCookie" OpHelp(""), + /* 103 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 104 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 105 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 106 */ "OpenDup" OpHelp(""), + /* 107 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 108 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 109 */ "SorterOpen" OpHelp(""), + /* 110 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 111 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 112 */ "Close" OpHelp(""), + /* 113 */ "ColumnsUsed" OpHelp(""), + /* 114 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 115 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 116 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 117 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), + /* 118 */ "Delete" OpHelp(""), + /* 119 */ "ResetCount" OpHelp(""), + /* 120 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 121 */ "SorterData" OpHelp("r[P2]=data"), + /* 122 */ "RowData" OpHelp("r[P2]=data"), + /* 123 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 124 */ "NullRow" OpHelp(""), + /* 125 */ "SeekEnd" OpHelp(""), + /* 126 */ "SorterInsert" OpHelp("key=r[P2]"), + /* 127 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 128 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 129 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), + /* 130 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 131 */ "Destroy" OpHelp(""), /* 132 */ "Real" OpHelp("r[P2]=P4"), - /* 133 */ "Destroy" OpHelp(""), - /* 134 */ "Clear" OpHelp(""), - /* 135 */ "ResetSorter" OpHelp(""), - /* 136 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), - /* 137 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), - /* 138 */ "SqlExec" OpHelp(""), - /* 139 */ "ParseSchema" OpHelp(""), - /* 140 */ "LoadAnalysis" OpHelp(""), - /* 141 */ "DropTable" OpHelp(""), - /* 142 */ "DropIndex" OpHelp(""), - /* 143 */ "DropTrigger" OpHelp(""), - /* 144 */ "IntegrityCk" OpHelp(""), - /* 145 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), - /* 146 */ "Param" OpHelp(""), - /* 147 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), - /* 148 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), - /* 149 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 150 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 151 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 152 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 153 */ "Expire" OpHelp(""), - /* 154 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 155 */ "VBegin" OpHelp(""), - /* 156 */ "VCreate" OpHelp(""), - /* 157 */ "VDestroy" OpHelp(""), - /* 158 */ "VOpen" OpHelp(""), - /* 159 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 160 */ "VRename" OpHelp(""), - /* 161 */ "Pagecount" OpHelp(""), - /* 162 */ "MaxPgcnt" OpHelp(""), - /* 163 */ "CursorHint" OpHelp(""), - /* 164 */ "Noop" OpHelp(""), - /* 165 */ "Explain" OpHelp(""), + /* 133 */ "Clear" OpHelp(""), + /* 134 */ "ResetSorter" OpHelp(""), + /* 135 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), + /* 136 */ "SqlExec" OpHelp(""), + /* 137 */ "ParseSchema" OpHelp(""), + /* 138 */ "LoadAnalysis" OpHelp(""), + /* 139 */ "DropTable" OpHelp(""), + /* 140 */ "DropIndex" OpHelp(""), + /* 141 */ "DropTrigger" OpHelp(""), + /* 142 */ "IntegrityCk" OpHelp(""), + /* 143 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 144 */ "Param" OpHelp(""), + /* 145 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 146 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 147 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 148 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 149 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 150 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 151 */ "Expire" OpHelp(""), + /* 152 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 153 */ "VBegin" OpHelp(""), + /* 154 */ "VCreate" OpHelp(""), + /* 155 */ "VDestroy" OpHelp(""), + /* 156 */ "VOpen" OpHelp(""), + /* 157 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 158 */ "VRename" OpHelp(""), + /* 159 */ "Pagecount" OpHelp(""), + /* 160 */ "MaxPgcnt" OpHelp(""), + /* 161 */ "PureFunc0" OpHelp(""), + /* 162 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), + /* 163 */ "PureFunc" OpHelp(""), + /* 164 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), + /* 165 */ "CursorHint" OpHelp(""), + /* 166 */ "Noop" OpHelp(""), + /* 167 */ "Explain" OpHelp(""), }; return azName[i]; } @@ -29775,6 +30262,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <sys/ioctl.h> #include <unistd.h> /* #include <time.h> */ #include <sys/time.h> @@ -29784,7 +30272,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #endif #if SQLITE_ENABLE_LOCKING_STYLE -# include <sys/ioctl.h> +/* # include <sys/ioctl.h> */ # include <sys/file.h> # include <sys/param.h> #endif /* SQLITE_ENABLE_LOCKING_STYLE */ @@ -29894,7 +30382,7 @@ struct unixFile { unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ int lastErrno; /* The unix errno from last I/O error */ void *lockingContext; /* Locking style specific state */ - UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ + UnixUnusedFd *pPreallocatedUnused; /* Pre-allocated UnixUnusedFd */ const char *zPath; /* Name of the file */ unixShm *pShm; /* Shared memory segment information */ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ @@ -29905,10 +30393,8 @@ struct unixFile { sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ void *pMapRegion; /* Memory mapped region */ #endif -#ifdef __QNXNTO__ int sectorSize; /* Device sector size */ int deviceCharacteristics; /* Precomputed device characteristics */ -#endif #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif @@ -30211,6 +30697,20 @@ SQLITE_API extern int sqlite3_open_file_count; # define lseek lseek64 #endif +#ifdef __linux__ +/* +** Linux-specific IOCTL magic numbers used for controlling F2FS +*/ +#define F2FS_IOCTL_MAGIC 0xf5 +#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) +#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) +#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) +#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) +#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32) +#define F2FS_FEATURE_ATOMIC_WRITE 0x0004 +#endif /* __linux__ */ + + /* ** Different Unix systems declare open() in different ways. Same use ** open(const char*,int,mode_t). Others use open(const char*,int,...). @@ -30383,6 +30883,9 @@ static struct unix_syscall { #endif #define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) + { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 }, +#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent) + }; /* End of the overrideable system calls */ @@ -30987,7 +31490,8 @@ struct unixInodeInfo { /* ** A lists of all unixInodeInfo objects. */ -static unixInodeInfo *inodeList = 0; +static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */ +static unsigned int nUnusedFd = 0; /* Total unused file descriptors */ /* ** @@ -31097,6 +31601,7 @@ static void closePendingFds(unixFile *pFile){ pNext = p->pNext; robust_close(pFile, p->fd, __LINE__); sqlite3_free(p); + nUnusedFd--; } pInode->pUnused = 0; } @@ -31129,6 +31634,7 @@ static void releaseInodeInfo(unixFile *pFile){ sqlite3_free(pInode); } } + assert( inodeList!=0 || nUnusedFd==0 ); } /* @@ -31198,6 +31704,7 @@ static int findInodeInfo( #else fileId.ino = (u64)statbuf.st_ino; #endif + assert( inodeList!=0 || nUnusedFd==0 ); pInode = inodeList; while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){ pInode = pInode->pNext; @@ -31617,11 +32124,12 @@ end_lock: */ static void setPendingFd(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; - UnixUnusedFd *p = pFile->pUnused; + UnixUnusedFd *p = pFile->pPreallocatedUnused; p->pNext = pInode->pUnused; pInode->pUnused = p; pFile->h = -1; - pFile->pUnused = 0; + pFile->pPreallocatedUnused = 0; + nUnusedFd++; } /* @@ -31846,7 +32354,7 @@ static int closeUnixFile(sqlite3_file *id){ #endif OSTRACE(("CLOSE %-3d\n", pFile->h)); OpenCounter(-1); - sqlite3_free(pFile->pUnused); + sqlite3_free(pFile->pPreallocatedUnused); memset(pFile, 0, sizeof(unixFile)); return SQLITE_OK; } @@ -32183,7 +32691,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved)); #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS - if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){ + if( (rc & 0xff) == SQLITE_IOERR ){ rc = SQLITE_OK; reserved=1; } @@ -32250,7 +32758,7 @@ static int flockLock(sqlite3_file *id, int eFileLock) { OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS - if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){ + if( (rc & 0xff) == SQLITE_IOERR ){ rc = SQLITE_BUSY; } #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ @@ -32787,7 +33295,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){ /* Can't reestablish the shared lock. Sqlite can't deal, this is ** a critical I/O error */ - rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 : + rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 : SQLITE_IOERR_LOCK; goto afp_end_lock; } @@ -33067,7 +33575,7 @@ static int unixRead( /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 - assert( pFile->pUnused==0 + assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); @@ -33180,7 +33688,7 @@ static int unixWrite( /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 - assert( pFile->pUnused==0 + assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); @@ -33660,6 +34168,21 @@ static int unixGetTempname(int nBuf, char *zBuf); static int unixFileControl(sqlite3_file *id, int op, void *pArg){ unixFile *pFile = (unixFile*)id; switch( op ){ +#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE); + return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK; + } + case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE); + return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK; + } + case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE); + return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK; + } +#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ + case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->eFileLock; return SQLITE_OK; @@ -33710,6 +34233,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } + + /* The value of newLimit may be eventually cast to (size_t) and passed + ** to mmap(). Restrict its value to 2GB if (size_t) is not at least a + ** 64-bit type. */ + if( newLimit>0 && sizeof(size_t)<8 ){ + newLimit = (newLimit & 0x7FFFFFFF); + } + *(i64*)pArg = pFile->mmapSizeMax; if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ pFile->mmapSizeMax = newLimit; @@ -33743,30 +34274,41 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ } /* -** Return the sector size in bytes of the underlying block device for -** the specified file. This is almost always 512 bytes, but may be -** larger for some devices. +** If pFd->sectorSize is non-zero when this function is called, it is a +** no-op. Otherwise, the values of pFd->sectorSize and +** pFd->deviceCharacteristics are set according to the file-system +** characteristics. ** -** SQLite code assumes this function cannot fail. It also assumes that -** if two files are created in the same file-system directory (i.e. -** a database and its journal file) that the sector size will be the -** same for both. +** There are two versions of this function. One for QNX and one for all +** other systems. */ -#ifndef __QNXNTO__ -static int unixSectorSize(sqlite3_file *NotUsed){ - UNUSED_PARAMETER(NotUsed); - return SQLITE_DEFAULT_SECTOR_SIZE; -} -#endif +#ifndef __QNXNTO__ +static void setDeviceCharacteristics(unixFile *pFd){ + assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 ); + if( pFd->sectorSize==0 ){ +#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + int res; + u32 f = 0; -/* -** The following version of unixSectorSize() is optimized for QNX. -*/ -#ifdef __QNXNTO__ + /* Check for support for F2FS atomic batch writes. */ + res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f); + if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){ + pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC; + } +#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ + + /* Set the POWERSAFE_OVERWRITE flag if requested. */ + if( pFd->ctrlFlags & UNIXFILE_PSOW ){ + pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; + } + + pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; + } +} +#else #include <sys/dcmd_blk.h> #include <sys/statvfs.h> -static int unixSectorSize(sqlite3_file *id){ - unixFile *pFile = (unixFile*)id; +static void setDeviceCharacteristics(unixFile *pFile){ if( pFile->sectorSize == 0 ){ struct statvfs fsInfo; @@ -33835,9 +34377,24 @@ static int unixSectorSize(sqlite3_file *id){ pFile->deviceCharacteristics = 0; pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; } - return pFile->sectorSize; } -#endif /* __QNXNTO__ */ +#endif + +/* +** Return the sector size in bytes of the underlying block device for +** the specified file. This is almost always 512 bytes, but may be +** larger for some devices. +** +** SQLite code assumes this function cannot fail. It also assumes that +** if two files are created in the same file-system directory (i.e. +** a database and its journal file) that the sector size will be the +** same for both. +*/ +static int unixSectorSize(sqlite3_file *id){ + unixFile *pFd = (unixFile*)id; + setDeviceCharacteristics(pFd); + return pFd->sectorSize; +} /* ** Return the device characteristics for the file. @@ -33853,16 +34410,9 @@ static int unixSectorSize(sqlite3_file *id){ ** available to turn it off and URI query parameter available to turn it off. */ static int unixDeviceCharacteristics(sqlite3_file *id){ - unixFile *p = (unixFile*)id; - int rc = 0; -#ifdef __QNXNTO__ - if( p->sectorSize==0 ) unixSectorSize(id); - rc = p->deviceCharacteristics; -#endif - if( p->ctrlFlags & UNIXFILE_PSOW ){ - rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; - } - return rc; + unixFile *pFd = (unixFile*)id; + setDeviceCharacteristics(pFd); + return pFd->deviceCharacteristics; } #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 @@ -35120,17 +35670,6 @@ static int fillInUnixFile( assert( pNew->pInode==NULL ); - /* Usually the path zFilename should not be a relative pathname. The - ** exception is when opening the proxy "conch" file in builds that - ** include the special Apple locking styles. - */ -#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE - assert( zFilename==0 || zFilename[0]=='/' - || pVfs->pAppData==(void*)&autolockIoFinder ); -#else - assert( zFilename==0 || zFilename[0]=='/' ); -#endif - /* No locking occurs in temporary files */ assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); @@ -35389,6 +35928,8 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ #if !OS_VXWORKS struct stat sStat; /* Results of stat() call */ + unixEnterMutex(); + /* A stat() call may fail for various reasons. If this happens, it is ** almost certain that an open() call on the same path will also fail. ** For this reason, if an error occurs in the stat() call here, it is @@ -35397,10 +35938,9 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ ** ** Even if a subsequent open() call does succeed, the consequences of ** not searching for a reusable file descriptor are not dire. */ - if( 0==osStat(zPath, &sStat) ){ + if( nUnusedFd>0 && 0==osStat(zPath, &sStat) ){ unixInodeInfo *pInode; - unixEnterMutex(); pInode = inodeList; while( pInode && (pInode->fileId.dev!=sStat.st_dev || pInode->fileId.ino!=(u64)sStat.st_ino) ){ @@ -35411,11 +35951,12 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); pUnused = *pp; if( pUnused ){ + nUnusedFd--; *pp = pUnused->pNext; } } - unixLeaveMutex(); } + unixLeaveMutex(); #endif /* if !OS_VXWORKS */ return pUnused; } @@ -35491,16 +36032,11 @@ static int findCreateFileMode( */ nDb = sqlite3Strlen30(zPath) - 1; while( zPath[nDb]!='-' ){ -#ifndef SQLITE_ENABLE_8_3_NAMES - /* In the normal case (8+3 filenames disabled) the journal filename - ** is guaranteed to contain a '-' character. */ - assert( nDb>0 ); - assert( sqlite3Isalnum(zPath[nDb]) ); -#else - /* If 8+3 names are possible, then the journal file might not contain - ** a '-' character. So check for that case and return early. */ + /* In normal operation, the journal file name will always contain + ** a '-' character. However in 8+3 filename mode, or if a corrupt + ** rollback journal specifies a master journal with a goofy name, then + ** the '-' might be missing. */ if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; -#endif nDb--; } memcpy(zDb, zPath, nDb); @@ -35636,7 +36172,7 @@ static int unixOpen( return SQLITE_NOMEM_BKPT; } } - p->pUnused = pUnused; + p->pPreallocatedUnused = pUnused; /* Database filenames are double-zero terminated if they are not ** URIs with parameters. Hence, they can always be passed into @@ -35673,7 +36209,7 @@ static int unixOpen( gid_t gid; /* Groupid for the file */ rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid); if( rc!=SQLITE_OK ){ - assert( !p->pUnused ); + assert( !p->pPreallocatedUnused ); assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL ); return rc; } @@ -35707,9 +36243,9 @@ static int unixOpen( *pOutFlags = flags; } - if( p->pUnused ){ - p->pUnused->fd = fd; - p->pUnused->flags = flags; + if( p->pPreallocatedUnused ){ + p->pPreallocatedUnused->fd = fd; + p->pPreallocatedUnused->flags = flags; } if( isDelete ){ @@ -35786,11 +36322,14 @@ static int unixOpen( } #endif + assert( zPath==0 || zPath[0]=='/' + || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL + ); rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); open_finished: if( rc!=SQLITE_OK ){ - sqlite3_free(p->pUnused); + sqlite3_free(p->pPreallocatedUnused); } return rc; } @@ -36531,7 +37070,7 @@ static int proxyCreateUnixFile( dummyVfs.zName = "dummy"; pUnused->fd = fd; pUnused->flags = openFlags; - pNew->pUnused = pUnused; + pNew->pPreallocatedUnused = pUnused; rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0); if( rc==SQLITE_OK ){ @@ -37481,7 +38020,7 @@ SQLITE_API int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==28 ); + assert( ArraySize(aSyscall)==29 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ @@ -41264,6 +41803,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } + + /* The value of newLimit may be eventually cast to (SIZE_T) and passed + ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at + ** least a 64-bit type. */ + if( newLimit>0 && sizeof(SIZE_T)<8 ){ + newLimit = (newLimit & 0x7FFFFFFF); + } + *(i64*)pArg = pFile->mmapSizeMax; if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ pFile->mmapSizeMax = newLimit; @@ -42576,6 +43123,14 @@ static int winIsDir(const void *zConverted){ return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY); } +/* forward reference */ +static int winAccess( + sqlite3_vfs *pVfs, /* Not used on win32 */ + const char *zFilename, /* Name of file to check */ + int flags, /* Type of test to make on this file */ + int *pResOut /* OUT: Result */ +); + /* ** Open a file. */ @@ -42752,37 +43307,52 @@ static int winOpen( extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; extendedParameters.lpSecurityAttributes = NULL; extendedParameters.hTemplateFile = NULL; - while( (h = osCreateFile2((LPCWSTR)zConverted, - dwDesiredAccess, - dwShareMode, - dwCreationDisposition, - &extendedParameters))==INVALID_HANDLE_VALUE && - winRetryIoerr(&cnt, &lastErrno) ){ - /* Noop */ - } + do{ + h = osCreateFile2((LPCWSTR)zConverted, + dwDesiredAccess, + dwShareMode, + dwCreationDisposition, + &extendedParameters); + if( h!=INVALID_HANDLE_VALUE ) break; + if( isReadWrite ){ + int isRO = 0; + int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + if( rc2==SQLITE_OK && isRO ) break; + } + }while( winRetryIoerr(&cnt, &lastErrno) ); #else - while( (h = osCreateFileW((LPCWSTR)zConverted, - dwDesiredAccess, - dwShareMode, NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL))==INVALID_HANDLE_VALUE && - winRetryIoerr(&cnt, &lastErrno) ){ - /* Noop */ - } + do{ + h = osCreateFileW((LPCWSTR)zConverted, + dwDesiredAccess, + dwShareMode, NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL); + if( h!=INVALID_HANDLE_VALUE ) break; + if( isReadWrite ){ + int isRO = 0; + int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + if( rc2==SQLITE_OK && isRO ) break; + } + }while( winRetryIoerr(&cnt, &lastErrno) ); #endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ - while( (h = osCreateFileA((LPCSTR)zConverted, - dwDesiredAccess, - dwShareMode, NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL))==INVALID_HANDLE_VALUE && - winRetryIoerr(&cnt, &lastErrno) ){ - /* Noop */ - } + do{ + h = osCreateFileA((LPCSTR)zConverted, + dwDesiredAccess, + dwShareMode, NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL); + if( h!=INVALID_HANDLE_VALUE ) break; + if( isReadWrite ){ + int isRO = 0; + int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + if( rc2==SQLITE_OK && isRO ) break; + } + }while( winRetryIoerr(&cnt, &lastErrno) ); } #endif winLogIoerr(cnt, __LINE__); @@ -42791,8 +43361,6 @@ static int winOpen( dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); if( h==INVALID_HANDLE_VALUE ){ - pFile->lastErrno = lastErrno; - winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); sqlite3_free(zConverted); sqlite3_free(zTmpname); if( isReadWrite && !isExclusive ){ @@ -42801,6 +43369,8 @@ static int winOpen( ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); }else{ + pFile->lastErrno = lastErrno; + winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); return SQLITE_CANTOPEN_BKPT; } } @@ -43393,9 +43963,6 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ EntropyGatherer e; UNUSED_PARAMETER(pVfs); memset(zBuf, 0, nBuf); -#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE - rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */ -#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */ e.a = (unsigned char*)zBuf; e.na = nBuf; e.nXor = 0; @@ -44314,12 +44881,9 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ p->eCreate = 2; } } - pPage->pDirtyNext = 0; - pPage->pDirtyPrev = 0; } if( addRemove & PCACHE_DIRTYLIST_ADD ){ - assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage ); - + pPage->pDirtyPrev = 0; pPage->pDirtyNext = p->pDirty; if( pPage->pDirtyNext ){ assert( pPage->pDirtyNext->pDirtyPrev==0 ); @@ -44636,11 +45200,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ if( (--p->nRef)==0 ){ if( p->flags&PGHDR_CLEAN ){ pcacheUnpin(p); - }else if( p->pDirtyPrev!=0 ){ /*OPTIMIZATION-IF-FALSE*/ - /* Move the page to the head of the dirty list. If p->pDirtyPrev==0, - ** then page p is already at the head of the dirty list and the - ** following call would be a no-op. Hence the OPTIMIZATION-IF-FALSE - ** tag above. */ + }else{ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } @@ -45101,7 +45661,6 @@ typedef struct PGroup PGroup; struct PgHdr1 { sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */ unsigned int iKey; /* Key value (page number) */ - u8 isPinned; /* Page in use, not on the LRU list */ u8 isBulkLocal; /* This page from bulk local storage */ u8 isAnchor; /* This is the PGroup.lru element */ PgHdr1 *pNext; /* Next in hash table chain */ @@ -45110,6 +45669,12 @@ struct PgHdr1 { PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */ }; +/* +** A page is pinned if it is no on the LRU list +*/ +#define PAGE_IS_PINNED(p) ((p)->pLruNext==0) +#define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0) + /* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set ** of one or more PCaches that are able to recycle each other's unpinned ** pages when they are under memory pressure. A PGroup is an instance of @@ -45137,7 +45702,7 @@ struct PGroup { unsigned int nMaxPage; /* Sum of nMax for purgeable caches */ unsigned int nMinPage; /* Sum of nMin for purgeable caches */ unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */ - unsigned int nCurrentPage; /* Number of purgeable pages allocated */ + unsigned int nPurgeable; /* Number of purgeable pages allocated */ PgHdr1 lru; /* The beginning and end of the LRU list */ }; @@ -45151,11 +45716,13 @@ struct PGroup { */ struct PCache1 { /* Cache configuration parameters. Page size (szPage) and the purgeable - ** flag (bPurgeable) are set when the cache is created. nMax may be + ** flag (bPurgeable) and the pnPurgeable pointer are all set when the + ** cache is created and are never changed thereafter. nMax may be ** modified at any time by a call to the pcache1Cachesize() method. ** The PGroup mutex must be held when accessing nMax. */ PGroup *pGroup; /* PGroup this cache belongs to */ + unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */ int szPage; /* Size of database content section */ int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */ int szAlloc; /* Total size of one pcache line */ @@ -45250,6 +45817,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ if( pcache1.isInit ){ PgFreeslot *p; if( pBuf==0 ) sz = n = 0; + if( n==0 ) sz = 0; sz = ROUNDDOWN8(sz); pcache1.szSlot = sz; pcache1.nSlot = pcache1.nFreeSlot = n; @@ -45442,9 +46010,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){ p->isBulkLocal = 0; p->isAnchor = 0; } - if( pCache->bPurgeable ){ - pCache->pGroup->nCurrentPage++; - } + (*pCache->pnPurgeable)++; return p; } @@ -45465,9 +46031,7 @@ static void pcache1FreePage(PgHdr1 *p){ sqlite3_free(p); #endif } - if( pCache->bPurgeable ){ - pCache->pGroup->nCurrentPage--; - } + (*pCache->pnPurgeable)--; } /* @@ -45562,22 +46126,18 @@ static void pcache1ResizeHash(PCache1 *p){ ** The PGroup mutex must be held when this function is called. */ static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){ - PCache1 *pCache; - assert( pPage!=0 ); - assert( pPage->isPinned==0 ); - pCache = pPage->pCache; + assert( PAGE_IS_UNPINNED(pPage) ); assert( pPage->pLruNext ); assert( pPage->pLruPrev ); - assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); + assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) ); pPage->pLruPrev->pLruNext = pPage->pLruNext; pPage->pLruNext->pLruPrev = pPage->pLruPrev; pPage->pLruNext = 0; pPage->pLruPrev = 0; - pPage->isPinned = 1; assert( pPage->isAnchor==0 ); - assert( pCache->pGroup->lru.isAnchor==1 ); - pCache->nRecyclable--; + assert( pPage->pCache->pGroup->lru.isAnchor==1 ); + pPage->pCache->nRecyclable--; return pPage; } @@ -45611,11 +46171,11 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){ PGroup *pGroup = pCache->pGroup; PgHdr1 *p; assert( sqlite3_mutex_held(pGroup->mutex) ); - while( pGroup->nCurrentPage>pGroup->nMaxPage + while( pGroup->nPurgeable>pGroup->nMaxPage && (p=pGroup->lru.pLruPrev)->isAnchor==0 ){ assert( p->pCache->pGroup==pGroup ); - assert( p->isPinned==0 ); + assert( PAGE_IS_UNPINNED(p) ); pcache1PinPage(p); pcache1RemoveFromHash(p, 1); } @@ -45664,7 +46224,7 @@ static void pcache1TruncateUnsafe( if( pPage->iKey>=iLimit ){ pCache->nPage--; *pp = pPage->pNext; - if( !pPage->isPinned ) pcache1PinPage(pPage); + if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage); pcache1FreePage(pPage); }else{ pp = &pPage->pNext; @@ -45782,6 +46342,10 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ pCache->nMin = 10; pGroup->nMinPage += pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; + pCache->pnPurgeable = &pGroup->nPurgeable; + }else{ + static unsigned int dummyCurrentPage; + pCache->pnPurgeable = &dummyCurrentPage; } pcache1LeaveMutex(pGroup); if( pCache->nHash==0 ){ @@ -45883,7 +46447,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( ){ PCache1 *pOther; pPage = pGroup->lru.pLruPrev; - assert( pPage->isPinned==0 ); + assert( PAGE_IS_UNPINNED(pPage) ); pcache1RemoveFromHash(pPage, 0); pcache1PinPage(pPage); pOther = pPage->pCache; @@ -45891,7 +46455,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( pcache1FreePage(pPage); pPage = 0; }else{ - pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable); + pGroup->nPurgeable -= (pOther->bPurgeable - pCache->bPurgeable); } } @@ -45910,7 +46474,6 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( pPage->pCache = pCache; pPage->pLruPrev = 0; pPage->pLruNext = 0; - pPage->isPinned = 1; *(void **)pPage->page.pExtra = 0; pCache->apHash[h] = pPage; if( iKey>pCache->iMaxKey ){ @@ -45996,7 +46559,7 @@ static PgHdr1 *pcache1FetchNoMutex( ** Otherwise (page not in hash and createFlag!=0) continue with ** subsequent steps to try to create the page. */ if( pPage ){ - if( !pPage->isPinned ){ + if( PAGE_IS_UNPINNED(pPage) ){ return pcache1PinPage(pPage); }else{ return pPage; @@ -46071,9 +46634,9 @@ static void pcache1Unpin( ** part of the PGroup LRU list. */ assert( pPage->pLruPrev==0 && pPage->pLruNext==0 ); - assert( pPage->isPinned==1 ); + assert( PAGE_IS_PINNED(pPage) ); - if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){ + if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){ pcache1RemoveFromHash(pPage, 1); }else{ /* Add the page to the PGroup LRU list. */ @@ -46082,7 +46645,6 @@ static void pcache1Unpin( (pPage->pLruNext = *ppFirst)->pLruPrev = pPage; *ppFirst = pPage; pCache->nRecyclable++; - pPage->isPinned = 0; } pcache1LeaveMutex(pCache->pGroup); @@ -46226,7 +46788,7 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){ #ifdef SQLITE_PCACHE_SEPARATE_HEADER nFree += sqlite3MemSize(p); #endif - assert( p->isPinned==0 ); + assert( PAGE_IS_UNPINNED(p) ); pcache1PinPage(p); pcache1RemoveFromHash(p, 1); } @@ -46250,10 +46812,10 @@ SQLITE_PRIVATE void sqlite3PcacheStats( PgHdr1 *p; int nRecyclable = 0; for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){ - assert( p->isPinned==0 ); + assert( PAGE_IS_UNPINNED(p) ); nRecyclable++; } - *pnCurrent = pcache1.grp.nCurrentPage; + *pnCurrent = pcache1.grp.nPurgeable; *pnMax = (int)pcache1.grp.nMaxPage; *pnMin = (int)pcache1.grp.nMinPage; *pnRecyclable = nRecyclable; @@ -46808,11 +47370,11 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 /* #include "sqliteInt.h" */ -/* Additional values that can be added to the sync_flags argument of -** sqlite3WalFrames(): +/* Macros for extracting appropriate sync flags for either transaction +** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)): */ -#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */ -#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */ +#define WAL_SYNC_FLAGS(X) ((X)&0x03) +#define CKPT_SYNC_FLAGS(X) (((X)>>2)&0x03) #ifdef SQLITE_OMIT_WAL # define sqlite3WalOpen(x,y,z) 0 @@ -47045,8 +47607,8 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file ** struct as its argument. */ -#define PAGERID(p) ((int)(p->fd)) -#define FILEHANDLEID(fd) ((int)fd) +#define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd)) +#define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd)) /* ** The Pager.eState variable stores the current 'state' of a pager. A @@ -47533,6 +48095,18 @@ struct PagerSavepoint { ** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode ** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX ** sub-codes. +** +** syncFlags, walSyncFlags +** +** syncFlags is either SQLITE_SYNC_NORMAL (0x02) or SQLITE_SYNC_FULL (0x03). +** syncFlags is used for rollback mode. walSyncFlags is used for WAL mode +** and contains the flags used to sync the checkpoint operations in the +** lower two bits, and sync flags used for transaction commits in the WAL +** file in bits 0x04 and 0x08. In other words, to get the correct sync flags +** for checkpoint operations, use (walSyncFlags&0x03) and to get the correct +** sync flags for transaction commit, use ((walSyncFlags>>2)&0x03). Note +** that with synchronous=NORMAL in WAL mode, transaction commit is not synced +** meaning that the 0x04 and 0x08 bits are both zero. */ struct Pager { sqlite3_vfs *pVfs; /* OS functions to use for IO */ @@ -47542,9 +48116,8 @@ struct Pager { u8 noSync; /* Do not sync the journal if true */ u8 fullSync; /* Do extra syncs of the journal for robustness */ u8 extraSync; /* sync directory after journal delete */ - u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */ - u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ + u8 walSyncFlags; /* See description above */ u8 tempFile; /* zFilename is a temporary or immutable file */ u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ @@ -47864,6 +48437,7 @@ static int assert_pager_state(Pager *p){ assert( isOpen(p->jfd) || p->journalMode==PAGER_JOURNALMODE_OFF || p->journalMode==PAGER_JOURNALMODE_WAL + || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC) ); assert( pPager->dbOrigSize<=pPager->dbHintSize ); break; @@ -47875,6 +48449,7 @@ static int assert_pager_state(Pager *p){ assert( isOpen(p->jfd) || p->journalMode==PAGER_JOURNALMODE_OFF || p->journalMode==PAGER_JOURNALMODE_WAL + || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC) ); break; @@ -48085,34 +48660,47 @@ static int pagerLockDb(Pager *pPager, int eLock){ } /* -** This function determines whether or not the atomic-write optimization -** can be used with this pager. The optimization can be used if: +** This function determines whether or not the atomic-write or +** atomic-batch-write optimizations can be used with this pager. The +** atomic-write optimization can be used if: ** ** (a) the value returned by OsDeviceCharacteristics() indicates that ** a database page may be written atomically, and ** (b) the value returned by OsSectorSize() is less than or equal ** to the page size. ** -** The optimization is also always enabled for temporary files. It is -** an error to call this function if pPager is opened on an in-memory -** database. +** If it can be used, then the value returned is the size of the journal +** file when it contains rollback data for exactly one page. ** -** If the optimization cannot be used, 0 is returned. If it can be used, -** then the value returned is the size of the journal file when it -** contains rollback data for exactly one page. +** The atomic-batch-write optimization can be used if OsDeviceCharacteristics() +** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is +** returned in this case. +** +** If neither optimization can be used, 0 is returned. */ -#ifdef SQLITE_ENABLE_ATOMIC_WRITE static int jrnlBufferSize(Pager *pPager){ assert( !MEMDB ); - if( !pPager->tempFile ){ - int dc; /* Device characteristics */ - int nSector; /* Sector size */ - int szPage; /* Page size */ - assert( isOpen(pPager->fd) ); - dc = sqlite3OsDeviceCharacteristics(pPager->fd); - nSector = pPager->sectorSize; - szPage = pPager->pageSize; +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + int dc; /* Device characteristics */ + + assert( isOpen(pPager->fd) ); + dc = sqlite3OsDeviceCharacteristics(pPager->fd); +#else + UNUSED_PARAMETER(pPager); +#endif + +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){ + return -1; + } +#endif + +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + { + int nSector = pPager->sectorSize; + int szPage = pPager->pageSize; assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); @@ -48122,11 +48710,11 @@ static int jrnlBufferSize(Pager *pPager){ } return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager); -} -#else -# define jrnlBufferSize(x) 0 #endif + return 0; +} + /* ** If SQLITE_CHECK_PAGES is defined then we do some sanity checking ** on the cache using a hash function. This is used for testing @@ -48208,6 +48796,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){ || szJ<16 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) || len>=nMaster + || len>szJ-16 || len==0 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum)) || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8)) @@ -48929,7 +49518,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ } releaseAllSavepoints(pPager); - assert( isOpen(pPager->jfd) || pPager->pInJournal==0 ); + assert( isOpen(pPager->jfd) || pPager->pInJournal==0 + || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC) + ); if( isOpen(pPager->jfd) ){ assert( !pagerUseWal(pPager) ); @@ -49697,6 +50288,7 @@ static int pager_playback(Pager *pPager, int isHot){ char *zMaster = 0; /* Name of master journal file if any */ int needPagerReset; /* True to reset page prior to first page rollback */ int nPlayback = 0; /* Total number of pages restored from journal */ + u32 savedPageSize = pPager->pageSize; /* Figure out how many records are in the journal. Abort early if ** the journal is empty. @@ -49826,6 +50418,9 @@ static int pager_playback(Pager *pPager, int isHot){ assert( 0 ); end_playback: + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1); + } /* Following a rollback, the database file should be back in its original ** state prior to the start of the transaction, so invoke the ** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the @@ -49884,7 +50479,8 @@ end_playback: /* -** Read the content for page pPg out of the database file and into +** Read the content for page pPg out of the database file (or out of +** the WAL if that is where the most recent copy if found) into ** pPg->pData. A shared lock or greater must be held on the database ** file before this function is called. ** @@ -49894,30 +50490,33 @@ end_playback: ** If an IO error occurs, then the IO error is returned to the caller. ** Otherwise, SQLITE_OK is returned. */ -static int readDbPage(PgHdr *pPg, u32 iFrame){ +static int readDbPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */ - Pgno pgno = pPg->pgno; /* Page number to read */ int rc = SQLITE_OK; /* Return code */ - int pgsz = pPager->pageSize; /* Number of bytes to read */ + +#ifndef SQLITE_OMIT_WAL + u32 iFrame = 0; /* Frame of WAL containing pgno */ assert( pPager->eState>=PAGER_READER && !MEMDB ); assert( isOpen(pPager->fd) ); -#ifndef SQLITE_OMIT_WAL + if( pagerUseWal(pPager) ){ + rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); + if( rc ) return rc; + } if( iFrame ){ - /* Try to pull the page from the write-ahead log. */ - rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData); + rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData); }else #endif { - i64 iOffset = (pgno-1)*(i64)pPager->pageSize; - rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset); + i64 iOffset = (pPg->pgno-1)*(i64)pPager->pageSize; + rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } } - if( pgno==1 ){ + if( pPg->pgno==1 ){ if( rc ){ /* If the read is unsuccessful, set the dbFileVers[] to something ** that will never be a valid file version. dbFileVers[] is a copy @@ -49937,13 +50536,13 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){ memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); } } - CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM_BKPT); + CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT); PAGER_INCR(sqlite3_pager_readdb_count); PAGER_INCR(pPager->nRead); - IOTRACE(("PGIN %p %d\n", pPager, pgno)); + IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); PAGERTRACE(("FETCH %d page %d hash(%08x)\n", - PAGERID(pPager), pgno, pager_pagehash(pPg))); + PAGERID(pPager), pPg->pgno, pager_pagehash(pPg))); return rc; } @@ -49994,11 +50593,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){ if( sqlite3PcachePageRefcount(pPg)==1 ){ sqlite3PcacheDrop(pPg); }else{ - u32 iFrame = 0; - rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); - if( rc==SQLITE_OK ){ - rc = readDbPage(pPg, iFrame); - } + rc = readDbPage(pPg); if( rc==SQLITE_OK ){ pPager->xReiniter(pPg); } @@ -50170,7 +50765,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ nPage = sqlite3WalDbsize(pPager->pWal); /* If the number of pages in the database is not available from the - ** WAL sub-system, determine the page counte based on the size of + ** WAL sub-system, determine the page count based on the size of ** the database file. If the size of the database file is not an ** integer multiple of the page-size, round up the result. */ @@ -50221,23 +50816,21 @@ static int pagerOpenWalIfPresent(Pager *pPager){ if( !pPager->tempFile ){ int isWal; /* True if WAL file exists */ - Pgno nPage; /* Size of the database file */ - - rc = pagerPagecount(pPager, &nPage); - if( rc ) return rc; - if( nPage==0 ){ - rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); - if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK; - isWal = 0; - }else{ - rc = sqlite3OsAccess( - pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal - ); - } + rc = sqlite3OsAccess( + pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal + ); if( rc==SQLITE_OK ){ if( isWal ){ - testcase( sqlite3PcachePagecount(pPager->pPCache)==0 ); - rc = sqlite3PagerOpenWal(pPager, 0); + Pgno nPage; /* Size of the database file */ + + rc = pagerPagecount(pPager, &nPage); + if( rc ) return rc; + if( nPage==0 ){ + rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); + }else{ + testcase( sqlite3PcachePagecount(pPager->pPCache)==0 ); + rc = sqlite3PagerOpenWal(pPager, 0); + } }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){ pPager->journalMode = PAGER_JOURNALMODE_DELETE; } @@ -50506,20 +51099,17 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags( } if( pPager->noSync ){ pPager->syncFlags = 0; - pPager->ckptSyncFlags = 0; }else if( pgFlags & PAGER_FULLFSYNC ){ pPager->syncFlags = SQLITE_SYNC_FULL; - pPager->ckptSyncFlags = SQLITE_SYNC_FULL; - }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){ - pPager->syncFlags = SQLITE_SYNC_NORMAL; - pPager->ckptSyncFlags = SQLITE_SYNC_FULL; }else{ pPager->syncFlags = SQLITE_SYNC_NORMAL; - pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL; } - pPager->walSyncFlags = pPager->syncFlags; + pPager->walSyncFlags = (pPager->syncFlags<<2); if( pPager->fullSync ){ - pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS; + pPager->walSyncFlags |= pPager->syncFlags; + } + if( (pgFlags & PAGER_CKPT_FULLFSYNC) && !pPager->noSync ){ + pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2); } if( pgFlags & PAGER_CACHESPILL ){ pPager->doNotSpill &= ~SPILLFLAG_OFF; @@ -51018,7 +51608,7 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL assert( db || pPager->pWal==0 ); - sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags, pPager->pageSize, + sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize, (db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp) ); pPager->pWal = 0; @@ -51486,6 +52076,13 @@ static int pagerStress(void *p, PgHdr *pPg){ rc = pagerWalFrames(pPager, pPg, 0, 0); } }else{ + +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + if( pPager->tempFile==0 ){ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc!=SQLITE_OK ) return pager_error(pPager, rc); + } +#endif /* Sync the journal file if required. */ if( pPg->flags&PGHDR_NEED_SYNC @@ -51819,13 +52416,11 @@ act_like_temp_file: assert( pPager->extraSync==0 ); assert( pPager->syncFlags==0 ); assert( pPager->walSyncFlags==0 ); - assert( pPager->ckptSyncFlags==0 ); }else{ pPager->fullSync = 1; pPager->extraSync = 0; pPager->syncFlags = SQLITE_SYNC_NORMAL; - pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS; - pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL; + pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2); } /* pPager->pFirst = 0; */ /* pPager->pFirstSynced = 0; */ @@ -52180,19 +52775,14 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** detected. The chance of an undetected change is so small that ** it can be neglected. */ - Pgno nPage = 0; char dbFileVers[sizeof(pPager->dbFileVers)]; - rc = pagerPagecount(pPager, &nPage); - if( rc ) goto failed; - - if( nPage>0 ){ - IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); - rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); - if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ + IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); + rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); + if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_IOERR_SHORT_READ ){ goto failed; } - }else{ memset(dbFileVers, 0, sizeof(dbFileVers)); } @@ -52250,7 +52840,8 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** nothing to rollback, so this routine is a no-op. */ static void pagerUnlockIfUnused(Pager *pPager){ - if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){ + if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){ + assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */ pagerUnlockAndRollback(pPager); } } @@ -52391,14 +52982,9 @@ static int getPageNormal( memset(pPg->pData, 0, pPager->pageSize); IOTRACE(("ZERO %p %d\n", pPager, pgno)); }else{ - u32 iFrame = 0; /* Frame to read from WAL file */ - if( pagerUseWal(pPager) ){ - rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); - if( rc!=SQLITE_OK ) goto pager_acquire_err; - } assert( pPg->pPager==pPager ); pPager->aStat[PAGER_STAT_MISS]++; - rc = readDbPage(pPg, iFrame); + rc = readDbPage(pPg); if( rc!=SQLITE_OK ){ goto pager_acquire_err; } @@ -52541,25 +53127,39 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ /* ** Release a page reference. ** -** If the number of references to the page drop to zero, then the -** page is added to the LRU list. When all references to all pages -** are released, a rollback occurs and the lock on the database is -** removed. +** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be +** used if we know that the page being released is not the last page. +** The btree layer always holds page1 open until the end, so these first +** to routines can be used to release any page other than BtShared.pPage1. +** +** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine +** checks the total number of outstanding pages and if the number of +** pages reaches zero it drops the database lock. */ SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){ - Pager *pPager; + TESTONLY( Pager *pPager = pPg->pPager; ) assert( pPg!=0 ); - pPager = pPg->pPager; if( pPg->flags & PGHDR_MMAP ){ + assert( pPg->pgno!=1 ); /* Page1 is never memory mapped */ pagerReleaseMapPage(pPg); }else{ sqlite3PcacheRelease(pPg); } - pagerUnlockIfUnused(pPager); + /* Do not use this routine to release the last reference to page1 */ + assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); } SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){ if( pPg ) sqlite3PagerUnrefNotNull(pPg); } +SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage *pPg){ + Pager *pPager; + assert( pPg!=0 ); + assert( pPg->pgno==1 ); + assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */ + pPager = pPg->pPager; + sqlite3PcacheRelease(pPg); + pagerUnlockIfUnused(pPager); +} /* ** This function is called at the start of every write transaction. @@ -53271,6 +53871,21 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( sqlite3PcacheCleanAll(pPager->pPCache); } }else{ + /* The bBatch boolean is true if the batch-atomic-write commit method + ** should be used. No rollback journal is created if batch-atomic-write + ** is enabled. + */ + sqlite3_file *fd = pPager->fd; +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + const int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */ + && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC) + && !pPager->noSync + && sqlite3JournalIsInMemory(pPager->jfd); +#else +# define bBatch 0 +#endif + +#ifdef SQLITE_ENABLE_ATOMIC_WRITE /* The following block updates the change-counter. Exactly how it ** does this depends on whether or not the atomic-update optimization ** was enabled at compile time, and if this transaction meets the @@ -53294,33 +53909,40 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( ** in 'direct' mode. In this case the journal file will never be ** created for this transaction. */ - #ifdef SQLITE_ENABLE_ATOMIC_WRITE - PgHdr *pPg; - assert( isOpen(pPager->jfd) - || pPager->journalMode==PAGER_JOURNALMODE_OFF - || pPager->journalMode==PAGER_JOURNALMODE_WAL - ); - if( !zMaster && isOpen(pPager->jfd) - && pPager->journalOff==jrnlBufferSize(pPager) - && pPager->dbSize>=pPager->dbOrigSize - && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty) - ){ - /* Update the db file change counter via the direct-write method. The - ** following call will modify the in-memory representation of page 1 - ** to include the updated change counter and then write page 1 - ** directly to the database file. Because of the atomic-write - ** property of the host file-system, this is safe. - */ - rc = pager_incr_changecounter(pPager, 1); - }else{ - rc = sqlite3JournalCreate(pPager->jfd); - if( rc==SQLITE_OK ){ - rc = pager_incr_changecounter(pPager, 0); + if( bBatch==0 ){ + PgHdr *pPg; + assert( isOpen(pPager->jfd) + || pPager->journalMode==PAGER_JOURNALMODE_OFF + || pPager->journalMode==PAGER_JOURNALMODE_WAL + ); + if( !zMaster && isOpen(pPager->jfd) + && pPager->journalOff==jrnlBufferSize(pPager) + && pPager->dbSize>=pPager->dbOrigSize + && (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty) + ){ + /* Update the db file change counter via the direct-write method. The + ** following call will modify the in-memory representation of page 1 + ** to include the updated change counter and then write page 1 + ** directly to the database file. Because of the atomic-write + ** property of the host file-system, this is safe. + */ + rc = pager_incr_changecounter(pPager, 1); + }else{ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc==SQLITE_OK ){ + rc = pager_incr_changecounter(pPager, 0); + } } } - #else +#else +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + if( zMaster ){ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + } +#endif rc = pager_incr_changecounter(pPager, 0); - #endif +#endif if( rc!=SQLITE_OK ) goto commit_phase_one_exit; /* Write the master journal name into the journal file. If a master @@ -53343,8 +53965,24 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( */ rc = syncJournal(pPager, 0); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; - + + if( bBatch ){ + /* The pager is now in DBMOD state. But regardless of what happens + ** next, attempting to play the journal back into the database would + ** be unsafe. Close it now to make sure that does not happen. */ + sqlite3OsClose(pPager->jfd); + rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0); + if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + } rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache)); + if( bBatch ){ + if( rc==SQLITE_OK ){ + rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0); + }else{ + sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0); + } + } + if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_IOERR_BLOCKED ); goto commit_phase_one_exit; @@ -54245,7 +54883,7 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint( rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode, (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), pPager->pBusyHandlerArg, - pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, + pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, pnLog, pnCkpt ); } @@ -54402,7 +55040,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ if( rc==SQLITE_OK && pPager->pWal ){ rc = pagerExclusiveLock(pPager); if( rc==SQLITE_OK ){ - rc = sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags, + rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize, (u8*)pPager->pTmpSpace); pPager->pWal = 0; pagerFixMaplimit(pPager); @@ -56274,9 +56912,7 @@ static int walCheckpoint( pInfo->nBackfillAttempted = mxSafeFrame; /* Sync the WAL to disk */ - if( sync_flags ){ - rc = sqlite3OsSync(pWal->pWalFd, sync_flags); - } + rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); /* If the database may grow as a result of this checkpoint, hint ** about the eventual size of the db file to the VFS layer. @@ -56317,8 +56953,8 @@ static int walCheckpoint( i64 szDb = pWal->hdr.nPage*(i64)szPage; testcase( IS_BIG_INT(szDb) ); rc = sqlite3OsTruncate(pWal->pDbFd, szDb); - if( rc==SQLITE_OK && sync_flags ){ - rc = sqlite3OsSync(pWal->pDbFd, sync_flags); + if( rc==SQLITE_OK ){ + rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); } } if( rc==SQLITE_OK ){ @@ -57424,8 +58060,8 @@ static int walWriteToLog( iOffset += iFirstAmt; iAmt -= iFirstAmt; pContent = (void*)(iFirstAmt + (char*)pContent); - assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) ); - rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK); + assert( WAL_SYNC_FLAGS(p->syncFlags)!=0 ); + rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags)); if( iAmt==0 || rc ) return rc; } rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset); @@ -57595,10 +58231,10 @@ SQLITE_PRIVATE int sqlite3WalFrames( ** an out-of-order write following a WAL restart could result in ** database corruption. See the ticket: ** - ** http://localhost:591/sqlite/info/ff5be73dee + ** https://sqlite.org/src/info/ff5be73dee */ - if( pWal->syncHeader && sync_flags ){ - rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK); + if( pWal->syncHeader ){ + rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); if( rc ) return rc; } } @@ -57673,7 +58309,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ - if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){ + if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){ int bSync = 1; if( pWal->padToSectorBoundary ){ int sectorSize = sqlite3SectorSize(pWal->pWalFd); @@ -57689,7 +58325,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( } if( bSync ){ assert( rc==SQLITE_OK ); - rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK); + rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags)); } } @@ -58485,10 +59121,12 @@ struct BtShared { #define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ #define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ #define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */ -#define BTS_INITIALLY_EMPTY 0x0008 /* Database was empty at trans start */ -#define BTS_NO_WAL 0x0010 /* Do not open write-ahead-log files */ -#define BTS_EXCLUSIVE 0x0020 /* pWriter has an exclusive lock */ -#define BTS_PENDING 0x0040 /* Waiting for read-locks to clear */ +#define BTS_OVERWRITE 0x0008 /* Overwrite deleted content with zeros */ +#define BTS_FAST_SECURE 0x000c /* Combination of the previous two */ +#define BTS_INITIALLY_EMPTY 0x0010 /* Database was empty at trans start */ +#define BTS_NO_WAL 0x0020 /* Do not open write-ahead-log files */ +#define BTS_EXCLUSIVE 0x0040 /* pWriter has an exclusive lock */ +#define BTS_PENDING 0x0080 /* Waiting for read-locks to clear */ /* ** An instance of the following structure is used to hold information @@ -58534,6 +59172,11 @@ struct CellInfo { ** eState==FAULT: Cursor fault with skipNext as error code. */ struct BtCursor { + u8 eState; /* One of the CURSOR_XXX constants (see below) */ + u8 curFlags; /* zero or more BTCF_* flags defined below */ + u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ + u8 hints; /* As configured by CursorSetHints() */ + int nOvflAlloc; /* Allocated size of aOverflow[] array */ Btree *pBtree; /* The Btree to which this cursor belongs */ BtShared *pBt; /* The BtShared this cursor points to */ BtCursor *pNext; /* Forms a linked list of all cursors */ @@ -58542,13 +59185,8 @@ struct BtCursor { i64 nKey; /* Size of pKey, or last integer key */ void *pKey; /* Saved key that was cursor last known position */ Pgno pgnoRoot; /* The root page of this tree */ - int nOvflAlloc; /* Allocated size of aOverflow[] array */ int skipNext; /* Prev() is noop if negative. Next() is noop if positive. ** Error code if eState==CURSOR_FAULT */ - u8 curFlags; /* zero or more BTCF_* flags defined below */ - u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ - u8 eState; /* One of the CURSOR_XXX constants (see below) */ - u8 hints; /* As configured by CursorSetHints() */ /* All fields above are zeroed when the cursor is allocated. See ** sqlite3BtreeCursorZero(). Fields that follow must be manually ** initialized. */ @@ -58557,7 +59195,8 @@ struct BtCursor { u16 ix; /* Current index for apPage[iPage] */ u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */ struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */ - MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ + MemPage *pPage; /* Current page */ + MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */ }; /* @@ -59186,7 +59825,7 @@ static int hasSharedCacheTableLock( ** Return true immediately. */ if( (pBtree->sharable==0) - || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted)) + || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommit)) ){ return 1; } @@ -59263,7 +59902,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){ for(p=pBtree->pBt->pCursor; p; p=p->pNext){ if( p->pgnoRoot==iRoot && p->pBtree!=pBtree - && 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted) + && 0==(p->pBtree->db->flags & SQLITE_ReadUncommit) ){ return 1; } @@ -59285,7 +59924,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); - assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 ); + assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 ); /* If requesting a write-lock, then the Btree must have an open write ** transaction on this file. And, obviously, for this to be so there @@ -59363,7 +60002,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ ** obtain a read-lock using this function. The only read-lock obtained ** by a connection in read-uncommitted mode is on the sqlite_master ** table, and that lock is obtained in BtreeBeginTrans(). */ - assert( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK ); + assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK ); /* This function should only be called on a sharable b-tree after it ** has been determined that no other b-tree holds a conflicting lock. */ @@ -59473,7 +60112,9 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){ #endif /* SQLITE_OMIT_SHARED_CACHE */ -static void releasePage(MemPage *pPage); /* Forward reference */ +static void releasePage(MemPage *pPage); /* Forward reference */ +static void releasePageOne(MemPage *pPage); /* Forward reference */ +static void releasePageNotNull(MemPage *pPage); /* Forward reference */ /* ***** This routine is used inside of assert() only **** @@ -59632,11 +60273,13 @@ static void btreeClearHasContent(BtShared *pBt){ */ static void btreeReleaseAllCursorPages(BtCursor *pCur){ int i; - for(i=0; i<=pCur->iPage; i++){ - releasePage(pCur->apPage[i]); - pCur->apPage[i] = 0; + if( pCur->iPage>=0 ){ + for(i=0; i<pCur->iPage; i++){ + releasePageNotNull(pCur->apPage[i]); + } + releasePageNotNull(pCur->pPage); + pCur->iPage = -1; } - pCur->iPage = -1; } /* @@ -59765,7 +60408,7 @@ static int SQLITE_NOINLINE saveCursorsOnList( return rc; } }else{ - testcase( p->iPage>0 ); + testcase( p->iPage>=0 ); btreeReleaseAllCursorPages(p); } } @@ -59870,6 +60513,17 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ } /* +** Return a pointer to a fake BtCursor object that will always answer +** false to the sqlite3BtreeCursorHasMoved() routine above. The fake +** cursor returned must not be used with any other Btree interface. +*/ +SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){ + static u8 fakeCursor = CURSOR_VALID; + assert( offsetof(BtCursor, eState)==0 ); + return (BtCursor*)&fakeCursor; +} + +/* ** This routine restores a cursor back to its original position after it ** has been moved by some outside activity (such as a btree rebalance or ** a row having been deleted out from under the cursor). @@ -60034,7 +60688,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); sqlite3PagerUnref(pDbPage); - if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT; + if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); return SQLITE_OK; } @@ -60418,8 +61072,11 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ int sz2 = 0; int sz = get2byte(&data[iFree+2]); int top = get2byte(&data[hdr+5]); + if( top>=iFree ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } if( iFree2 ){ - if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_BKPT; + assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */ sz2 = get2byte(&data[iFree2+2]); assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize ); memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); @@ -60450,13 +61107,13 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** if PRAGMA cell_size_check=ON. */ if( pc<iCellFirst || pc>iCellLast ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } assert( pc>=iCellFirst && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; if( cbrk<iCellFirst || pc+size>usableSize ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } assert( cbrk+size<=usableSize && cbrk>=iCellFirst ); testcase( cbrk+size==usableSize ); @@ -60476,7 +61133,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ defragment_out: if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); @@ -60508,16 +61165,10 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ int pc = get2byte(&aData[iAddr]); int x; int usableSize = pPg->pBt->usableSize; + int size; /* Size of the free slot */ assert( pc>0 ); - do{ - int size; /* Size of the free slot */ - /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of - ** increasing offset. */ - if( pc>usableSize-4 || pc<iAddr+4 ){ - *pRc = SQLITE_CORRUPT_BKPT; - return 0; - } + while( pc<=usableSize-4 ){ /* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each ** freeblock form a big-endian integer which is the size of the freeblock ** in bytes, including the 4-byte header. */ @@ -60525,8 +61176,8 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ if( (x = size - nByte)>=0 ){ testcase( x==4 ); testcase( x==3 ); - if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){ - *pRc = SQLITE_CORRUPT_BKPT; + if( size+pc > usableSize ){ + *pRc = SQLITE_CORRUPT_PGNO(pPg->pgno); return 0; }else if( x<4 ){ /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total @@ -60546,7 +61197,11 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ } iAddr = pc; pc = get2byte(&aData[pc]); - }while( pc ); + if( pc<iAddr+size ) break; + } + if( pc ){ + *pRc = SQLITE_CORRUPT_PGNO(pPg->pgno); + } return 0; } @@ -60593,7 +61248,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ if( top==0 && pPage->pBt->usableSize==65536 ){ top = 65536; }else{ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } } @@ -60660,7 +61315,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ u8 hdr; /* Page header size. 0 or 100 */ u8 nFrag = 0; /* Reduction in fragmentation */ u16 iOrigSize = iSize; /* Original value of iSize */ - u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */ + u16 x; /* Offset to cell content area */ u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ unsigned char *data = pPage->aData; /* Page content */ @@ -60670,13 +61325,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( iSize>=4 ); /* Minimum cell size is 4 */ - assert( iStart<=iLast ); - - /* Overwrite deleted information with zeros when the secure_delete - ** option is enabled */ - if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){ - memset(&data[iStart], 0, iSize); - } + assert( iStart<=pPage->pBt->usableSize-4 ); /* The list of freeblocks must be in ascending order. Find the ** spot on the list where iStart should be inserted. @@ -60689,11 +61338,13 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){ if( iFreeBlk<iPtr+4 ){ if( iFreeBlk==0 ) break; - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } iPtr = iFreeBlk; } - if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT; + if( iFreeBlk>pPage->pBt->usableSize-4 ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } assert( iFreeBlk>iPtr || iFreeBlk==0 ); /* At this point: @@ -60704,9 +61355,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ */ if( iFreeBlk && iEnd+3>=iFreeBlk ){ nFrag = iFreeBlk - iEnd; - if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT; + if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PGNO(pPage->pgno); iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); - if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT; + if( iEnd > pPage->pBt->usableSize ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } iSize = iEnd - iStart; iFreeBlk = get2byte(&data[iFreeBlk]); } @@ -60718,28 +61371,34 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ if( iPtr>hdr+1 ){ int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); if( iPtrEnd+3>=iStart ){ - if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT; + if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PGNO(pPage->pgno); nFrag += iStart - iPtrEnd; iSize = iEnd - iPtr; iStart = iPtr; } } - if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT; + if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PGNO(pPage->pgno); data[hdr+7] -= nFrag; } - if( iStart==get2byte(&data[hdr+5]) ){ + x = get2byte(&data[hdr+5]); + if( iStart<=x ){ /* The new freeblock is at the beginning of the cell content area, ** so just extend the cell content area rather than create another ** freelist entry */ - if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT; + if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PGNO(pPage->pgno); put2byte(&data[hdr+1], iFreeBlk); put2byte(&data[hdr+5], iEnd); }else{ /* Insert the new freeblock into the freelist */ put2byte(&data[iPtr], iStart); - put2byte(&data[iStart], iFreeBlk); - put2byte(&data[iStart+2], iSize); } + if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){ + /* Overwrite deleted information with zeros when the secure_delete + ** option is enabled */ + memset(&data[iStart], 0, iSize); + } + put2byte(&data[iStart], iFreeBlk); + put2byte(&data[iStart+2], iSize); pPage->nFree += iOrigSize; return SQLITE_OK; } @@ -60799,7 +61458,7 @@ static int decodeFlags(MemPage *pPage, int flagByte){ }else{ /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is ** an error. */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } pPage->max1bytePayload = pBt->max1bytePayload; return SQLITE_OK; @@ -60815,6 +61474,16 @@ static int decodeFlags(MemPage *pPage, int flagByte){ ** we failed to detect any corruption. */ static int btreeInitPage(MemPage *pPage){ + int pc; /* Address of a freeblock within pPage->aData[] */ + u8 hdr; /* Offset to beginning of page header */ + u8 *data; /* Equal to pPage->aData */ + BtShared *pBt; /* The main btree structure */ + int usableSize; /* Amount of usable space on each page */ + u16 cellOffset; /* Offset from start of page to first cell pointer */ + int nFree; /* Number of unused bytes on the page */ + int top; /* First byte of the cell content area */ + int iCellFirst; /* First allowable cell or freeblock offset */ + int iCellLast; /* Last possible cell or freeblock offset */ assert( pPage->pBt!=0 ); assert( pPage->pBt->db!=0 ); @@ -60822,127 +61491,119 @@ static int btreeInitPage(MemPage *pPage){ assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); + assert( pPage->isInit==0 ); - if( !pPage->isInit ){ - int pc; /* Address of a freeblock within pPage->aData[] */ - u8 hdr; /* Offset to beginning of page header */ - u8 *data; /* Equal to pPage->aData */ - BtShared *pBt; /* The main btree structure */ - int usableSize; /* Amount of usable space on each page */ - u16 cellOffset; /* Offset from start of page to first cell pointer */ - int nFree; /* Number of unused bytes on the page */ - int top; /* First byte of the cell content area */ - int iCellFirst; /* First allowable cell or freeblock offset */ - int iCellLast; /* Last possible cell or freeblock offset */ - - pBt = pPage->pBt; - - hdr = pPage->hdrOffset; - data = pPage->aData; - /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating - ** the b-tree page type. */ - if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT; - assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); - pPage->maskPage = (u16)(pBt->pageSize - 1); - pPage->nOverflow = 0; - usableSize = pBt->usableSize; - pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize; - pPage->aDataEnd = &data[usableSize]; - pPage->aCellIdx = &data[cellOffset]; - pPage->aDataOfst = &data[pPage->childPtrSize]; - /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates - ** the start of the cell content area. A zero value for this integer is - ** interpreted as 65536. */ - top = get2byteNotZero(&data[hdr+5]); - /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the - ** number of cells on the page. */ - pPage->nCell = get2byte(&data[hdr+3]); - if( pPage->nCell>MX_CELL(pBt) ){ - /* To many cells for a single page. The page must be corrupt */ - return SQLITE_CORRUPT_BKPT; - } - testcase( pPage->nCell==MX_CELL(pBt) ); - /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only - ** possible for a root page of a table that contains no rows) then the - ** offset to the cell content area will equal the page size minus the - ** bytes of reserved space. */ - assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB ); - - /* A malformed database page might cause us to read past the end - ** of page when parsing a cell. - ** - ** The following block of code checks early to see if a cell extends - ** past the end of a page boundary and causes SQLITE_CORRUPT to be - ** returned if it does. - */ - iCellFirst = cellOffset + 2*pPage->nCell; - iCellLast = usableSize - 4; - if( pBt->db->flags & SQLITE_CellSizeCk ){ - int i; /* Index into the cell pointer array */ - int sz; /* Size of a cell */ - - if( !pPage->leaf ) iCellLast--; - for(i=0; i<pPage->nCell; i++){ - pc = get2byteAligned(&data[cellOffset+i*2]); - testcase( pc==iCellFirst ); - testcase( pc==iCellLast ); - if( pc<iCellFirst || pc>iCellLast ){ - return SQLITE_CORRUPT_BKPT; - } - sz = pPage->xCellSize(pPage, &data[pc]); - testcase( pc+sz==usableSize ); - if( pc+sz>usableSize ){ - return SQLITE_CORRUPT_BKPT; - } - } - if( !pPage->leaf ) iCellLast++; - } + pBt = pPage->pBt; + hdr = pPage->hdrOffset; + data = pPage->aData; + /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating + ** the b-tree page type. */ + if( decodeFlags(pPage, data[hdr]) ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); + pPage->maskPage = (u16)(pBt->pageSize - 1); + pPage->nOverflow = 0; + usableSize = pBt->usableSize; + pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize; + pPage->aDataEnd = &data[usableSize]; + pPage->aCellIdx = &data[cellOffset]; + pPage->aDataOfst = &data[pPage->childPtrSize]; + /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates + ** the start of the cell content area. A zero value for this integer is + ** interpreted as 65536. */ + top = get2byteNotZero(&data[hdr+5]); + /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the + ** number of cells on the page. */ + pPage->nCell = get2byte(&data[hdr+3]); + if( pPage->nCell>MX_CELL(pBt) ){ + /* To many cells for a single page. The page must be corrupt */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + testcase( pPage->nCell==MX_CELL(pBt) ); + /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only + ** possible for a root page of a table that contains no rows) then the + ** offset to the cell content area will equal the page size minus the + ** bytes of reserved space. */ + assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB ); + + /* A malformed database page might cause us to read past the end + ** of page when parsing a cell. + ** + ** The following block of code checks early to see if a cell extends + ** past the end of a page boundary and causes SQLITE_CORRUPT to be + ** returned if it does. + */ + iCellFirst = cellOffset + 2*pPage->nCell; + iCellLast = usableSize - 4; + if( pBt->db->flags & SQLITE_CellSizeCk ){ + int i; /* Index into the cell pointer array */ + int sz; /* Size of a cell */ - /* Compute the total free space on the page - ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the - ** start of the first freeblock on the page, or is zero if there are no - ** freeblocks. */ - pc = get2byte(&data[hdr+1]); - nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */ - if( pc>0 ){ - u32 next, size; - if( pc<iCellFirst ){ - /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will - ** always be at least one cell before the first freeblock. - */ - return SQLITE_CORRUPT_BKPT; + if( !pPage->leaf ) iCellLast--; + for(i=0; i<pPage->nCell; i++){ + pc = get2byteAligned(&data[cellOffset+i*2]); + testcase( pc==iCellFirst ); + testcase( pc==iCellLast ); + if( pc<iCellFirst || pc>iCellLast ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); } - while( 1 ){ - if( pc>iCellLast ){ - return SQLITE_CORRUPT_BKPT; /* Freeblock off the end of the page */ - } - next = get2byte(&data[pc]); - size = get2byte(&data[pc+2]); - nFree = nFree + size; - if( next<=pc+size+3 ) break; - pc = next; - } - if( next>0 ){ - return SQLITE_CORRUPT_BKPT; /* Freeblock not in ascending order */ - } - if( pc+size>(unsigned int)usableSize ){ - return SQLITE_CORRUPT_BKPT; /* Last freeblock extends past page end */ + sz = pPage->xCellSize(pPage, &data[pc]); + testcase( pc+sz==usableSize ); + if( pc+sz>usableSize ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); } } + if( !pPage->leaf ) iCellLast++; + } - /* At this point, nFree contains the sum of the offset to the start - ** of the cell-content area plus the number of free bytes within - ** the cell-content area. If this is greater than the usable-size - ** of the page, then the page must be corrupted. This check also - ** serves to verify that the offset to the start of the cell-content - ** area, according to the page header, lies within the page. - */ - if( nFree>usableSize ){ - return SQLITE_CORRUPT_BKPT; + /* Compute the total free space on the page + ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the + ** start of the first freeblock on the page, or is zero if there are no + ** freeblocks. */ + pc = get2byte(&data[hdr+1]); + nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */ + if( pc>0 ){ + u32 next, size; + if( pc<iCellFirst ){ + /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will + ** always be at least one cell before the first freeblock. + */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + while( 1 ){ + if( pc>iCellLast ){ + /* Freeblock off the end of the page */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + next = get2byte(&data[pc]); + size = get2byte(&data[pc+2]); + nFree = nFree + size; + if( next<=pc+size+3 ) break; + pc = next; + } + if( next>0 ){ + /* Freeblock not in ascending order */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + if( pc+size>(unsigned int)usableSize ){ + /* Last freeblock extends past page end */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); } - pPage->nFree = (u16)(nFree - iCellFirst); - pPage->isInit = 1; } + + /* At this point, nFree contains the sum of the offset to the start + ** of the cell-content area plus the number of free bytes within + ** the cell-content area. If this is greater than the usable-size + ** of the page, then the page must be corrupted. This check also + ** serves to verify that the offset to the start of the cell-content + ** area, according to the page header, lies within the page. + */ + if( nFree>usableSize ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + pPage->nFree = (u16)(nFree - iCellFirst); + pPage->isInit = 1; return SQLITE_OK; } @@ -60961,7 +61622,7 @@ static void zeroPage(MemPage *pPage, int flags){ assert( sqlite3PagerGetData(pPage->pDbPage) == data ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pBt->mutex) ); - if( pBt->btsFlags & BTS_SECURE_DELETE ){ + if( pBt->btsFlags & BTS_FAST_SECURE ){ memset(&data[hdr], 0, pBt->usableSize - hdr); } data[hdr] = (char)flags; @@ -61052,7 +61713,7 @@ static Pgno btreePagecount(BtShared *pBt){ } SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){ assert( sqlite3BtreeHoldsMutex(p) ); - assert( ((p->pBt->nPage)&0x8000000)==0 ); + assert( ((p->pBt->nPage)&0x80000000)==0 ); return btreePagecount(p->pBt); } @@ -61079,7 +61740,7 @@ static int getAndInitPage( int rc; DbPage *pDbPage; assert( sqlite3_mutex_held(pBt->mutex) ); - assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] ); + assert( pCur==0 || ppPage==&pCur->pPage ); assert( pCur==0 || bReadOnly==pCur->curPagerFlags ); assert( pCur==0 || pCur->iPage>0 ); @@ -61106,14 +61767,17 @@ static int getAndInitPage( /* If obtaining a child page for a cursor, we must verify that the page is ** compatible with the root page. */ if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(pgno); releasePage(*ppPage); goto getAndInitPage_error; } return SQLITE_OK; getAndInitPage_error: - if( pCur ) pCur->iPage--; + if( pCur ){ + pCur->iPage--; + pCur->pPage = pCur->apPage[pCur->iPage]; + } testcase( pgno==0 ); assert( pgno!=0 || rc==SQLITE_CORRUPT ); return rc; @@ -61122,6 +61786,8 @@ getAndInitPage_error: /* ** Release a MemPage. This should be called once for each prior ** call to btreeGetPage. +** +** Page1 is a special case and must be released using releasePageOne(). */ static void releasePageNotNull(MemPage *pPage){ assert( pPage->aData ); @@ -61135,6 +61801,16 @@ static void releasePageNotNull(MemPage *pPage){ static void releasePage(MemPage *pPage){ if( pPage ) releasePageNotNull(pPage); } +static void releasePageOne(MemPage *pPage){ + assert( pPage!=0 ); + assert( pPage->aData ); + assert( pPage->pBt ); + assert( pPage->pDbPage!=0 ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + sqlite3PagerUnrefPageOne(pPage->pDbPage); +} /* ** Get an unused page. @@ -61384,8 +62060,10 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( pBt->pCursor = 0; pBt->pPage1 = 0; if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY; -#ifdef SQLITE_SECURE_DELETE +#if defined(SQLITE_SECURE_DELETE) pBt->btsFlags |= BTS_SECURE_DELETE; +#elif defined(SQLITE_FAST_SECURE_DELETE) + pBt->btsFlags |= BTS_OVERWRITE; #endif /* EVIDENCE-OF: R-51873-39618 The page size for a database file is ** determined by the 2-byte integer located at an offset of 16 bytes from @@ -61833,19 +62511,34 @@ SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){ } /* -** Set the BTS_SECURE_DELETE flag if newFlag is 0 or 1. If newFlag is -1, -** then make no changes. Always return the value of the BTS_SECURE_DELETE -** setting after the change. +** Change the values for the BTS_SECURE_DELETE and BTS_OVERWRITE flags: +** +** newFlag==0 Both BTS_SECURE_DELETE and BTS_OVERWRITE are cleared +** newFlag==1 BTS_SECURE_DELETE set and BTS_OVERWRITE is cleared +** newFlag==2 BTS_SECURE_DELETE cleared and BTS_OVERWRITE is set +** newFlag==(-1) No changes +** +** This routine acts as a query if newFlag is less than zero +** +** With BTS_OVERWRITE set, deleted content is overwritten by zeros, but +** freelist leaf pages are not written back to the database. Thus in-page +** deleted content is cleared, but freelist deleted content is not. +** +** With BTS_SECURE_DELETE, operation is like BTS_OVERWRITE with the addition +** that freelist leaf pages are written back into the database, increasing +** the amount of disk I/O. */ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ int b; if( p==0 ) return 0; sqlite3BtreeEnter(p); + assert( BTS_OVERWRITE==BTS_SECURE_DELETE*2 ); + assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) ); if( newFlag>=0 ){ - p->pBt->btsFlags &= ~BTS_SECURE_DELETE; - if( newFlag ) p->pBt->btsFlags |= BTS_SECURE_DELETE; - } - b = (p->pBt->btsFlags & BTS_SECURE_DELETE)!=0; + p->pBt->btsFlags &= ~BTS_FAST_SECURE; + p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag; + } + b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE; sqlite3BtreeLeave(p); return b; } @@ -61902,7 +62595,8 @@ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){ ** set to the value passed to this function as the second parameter, ** set it so. */ -#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS +#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS \ + && !defined(SQLITE_OMIT_WAL) static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){ sqlite3 *db; Db *pDb; @@ -61996,7 +62690,7 @@ static int lockBtree(BtShared *pBt){ }else{ setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1); if( isOpen==0 ){ - releasePage(pPage1); + releasePageOne(pPage1); return SQLITE_OK; } } @@ -62043,7 +62737,7 @@ static int lockBtree(BtShared *pBt){ ** zero and return SQLITE_OK. The caller will call this function ** again with the correct page-size. */ - releasePage(pPage1); + releasePageOne(pPage1); pBt->usableSize = usableSize; pBt->pageSize = pageSize; freeTempSpace(pBt); @@ -62051,7 +62745,7 @@ static int lockBtree(BtShared *pBt){ pageSize-usableSize); return rc; } - if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){ + if( (pBt->db->flags & SQLITE_WriteSchema)==0 && nPage>nPageFile ){ rc = SQLITE_CORRUPT_BKPT; goto page1_init_failed; } @@ -62097,7 +62791,7 @@ static int lockBtree(BtShared *pBt){ return SQLITE_OK; page1_init_failed: - releasePage(pPage1); + releasePageOne(pPage1); pBt->pPage1 = 0; return rc; } @@ -62142,7 +62836,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){ assert( pPage1->aData ); assert( sqlite3PagerRefcount(pBt->pPager)==1 ); pBt->pPage1 = 0; - releasePageNotNull(pPage1); + releasePageOne(pPage1); } } @@ -62394,7 +63088,7 @@ static int setChildPtrmaps(MemPage *pPage){ Pgno pgno = pPage->pgno; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - rc = btreeInitPage(pPage); + rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage); if( rc!=SQLITE_OK ) return rc; nCell = pPage->nCell; @@ -62437,7 +63131,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( eType==PTRMAP_OVERFLOW2 ){ /* The pointer is always the first 4 bytes of the page in this case. */ if( get4byte(pPage->aData)!=iFrom ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } put4byte(pPage->aData, iTo); }else{ @@ -62445,7 +63139,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ int nCell; int rc; - rc = btreeInitPage(pPage); + rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage); if( rc ) return rc; nCell = pPage->nCell; @@ -62456,7 +63150,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ pPage->xParseCell(pPage, pCell, &info); if( info.nLocal<info.nPayload ){ if( pCell+info.nSize > pPage->aData+pPage->pBt->usableSize ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } if( iFrom==get4byte(pCell+info.nSize-4) ){ put4byte(pCell+info.nSize-4, iTo); @@ -62474,7 +63168,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( i==nCell ){ if( eType!=PTRMAP_BTREE || get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); } @@ -62994,7 +63688,6 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr if( pBtree ){ sqlite3BtreeEnter(pBtree); for(p=pBtree->pBt->pCursor; p; p=p->pNext){ - int i; if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){ rc = saveCursorPosition(p); @@ -63008,10 +63701,7 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr p->eState = CURSOR_FAULT; p->skipNext = errCode; } - for(i=0; i<=p->iPage; i++){ - releasePage(p->apPage[i]); - p->apPage[i] = 0; - } + btreeReleaseAllCursorPages(p); } sqlite3BtreeLeave(pBtree); } @@ -63068,7 +63758,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); testcase( pBt->nPage!=nPage ); pBt->nPage = nPage; - releasePage(pPage1); + releasePageOne(pPage1); } assert( countValidCursors(pBt, 1)==0 ); pBt->inTransaction = TRANS_READ; @@ -63310,10 +64000,8 @@ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ Btree *pBtree = pCur->pBtree; if( pBtree ){ - int i; BtShared *pBt = pCur->pBt; sqlite3BtreeEnter(pBtree); - sqlite3BtreeClearCursor(pCur); assert( pBt->pCursor!=0 ); if( pBt->pCursor==pCur ){ pBt->pCursor = pCur->pNext; @@ -63327,12 +64015,10 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ pPrev = pPrev->pNext; }while( ALWAYS(pPrev) ); } - for(i=0; i<=pCur->iPage; i++){ - releasePage(pCur->apPage[i]); - } + btreeReleaseAllCursorPages(pCur); unlockBtreeIfUnused(pBt); sqlite3_free(pCur->aOverflow); - /* sqlite3_free(pCur); */ + sqlite3_free(pCur->pKey); sqlite3BtreeLeave(pBtree); } return SQLITE_OK; @@ -63349,9 +64035,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ #ifndef NDEBUG static void assertCellInfo(BtCursor *pCur){ CellInfo info; - int iPage = pCur->iPage; memset(&info, 0, sizeof(info)); - btreeParseCell(pCur->apPage[iPage], pCur->ix, &info); + btreeParseCell(pCur->pPage, pCur->ix, &info); assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 ); } #else @@ -63359,9 +64044,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ #endif static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ - int iPage = pCur->iPage; pCur->curFlags |= BTCF_ValidNKey; - btreeParseCell(pCur->apPage[iPage],pCur->ix,&pCur->info); + btreeParseCell(pCur->pPage,pCur->ix,&pCur->info); }else{ assertCellInfo(pCur); } @@ -63559,7 +64243,7 @@ static int accessPayload( unsigned char *aPayload; int rc = SQLITE_OK; int iIdx = 0; - MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ + MemPage *pPage = pCur->pPage; /* Btree page of current entry */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ #ifdef SQLITE_DIRECT_OVERFLOW_READ unsigned char * const pBufStart = pBuf; /* Start of original out buffer */ @@ -63582,7 +64266,7 @@ static int accessPayload( ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ** but is recast into its current form to avoid integer overflow problems */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } /* Check if data must be read/written to/from the btree page itself. */ @@ -63729,7 +64413,8 @@ static int accessPayload( } if( rc==SQLITE_OK && amt>0 ){ - return SQLITE_CORRUPT_BKPT; /* Overflow chain ends prematurely */ + /* Overflow chain ends prematurely */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); } return rc; } @@ -63754,8 +64439,8 @@ static int accessPayload( SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); - assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell ); + assert( pCur->iPage>=0 && pCur->pPage ); + assert( pCur->ix<pCur->pPage->nCell ); return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } @@ -63812,18 +64497,23 @@ static const void *fetchPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 *pAmt /* Write the number of available bytes here */ ){ - u32 amt; - assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); + int amt; + assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage); assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorOwnsBtShared(pCur) ); - assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell ); + assert( pCur->ix<pCur->pPage->nCell ); assert( pCur->info.nSize>0 ); - assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB ); - assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB); - amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload); - if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal; - *pAmt = amt; + assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB ); + assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB); + amt = pCur->info.nLocal; + if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){ + /* There is too little space on the page for the expected amount + ** of local content. Database must be corrupt. */ + assert( CORRUPT_DB ); + amt = MAX(0, (int)(pCur->pPage->aDataEnd - pCur->info.pPayload)); + } + *pAmt = (u32)amt; return (void*)pCur->info.pPayload; } @@ -63868,10 +64558,11 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ } pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); - pCur->aiIdx[pCur->iPage++] = pCur->ix; + pCur->aiIdx[pCur->iPage] = pCur->ix; + pCur->apPage[pCur->iPage] = pCur->pPage; pCur->ix = 0; - return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage], - pCur, pCur->curPagerFlags); + pCur->iPage++; + return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags); } #ifdef SQLITE_DEBUG @@ -63905,20 +64596,23 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){ ** the largest cell index. */ static void moveToParent(BtCursor *pCur){ + MemPage *pLeaf; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>0 ); - assert( pCur->apPage[pCur->iPage] ); + assert( pCur->pPage ); assertParentIndex( pCur->apPage[pCur->iPage-1], pCur->aiIdx[pCur->iPage-1], - pCur->apPage[pCur->iPage]->pgno + pCur->pPage->pgno ); testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); pCur->ix = pCur->aiIdx[pCur->iPage-1]; - releasePageNotNull(pCur->apPage[pCur->iPage--]); + pLeaf = pCur->pPage; + pCur->pPage = pCur->apPage[--pCur->iPage]; + releasePageNotNull(pLeaf); } /* @@ -63930,9 +64624,9 @@ static void moveToParent(BtCursor *pCur){ ** single child page. This can only happen with the table rooted at page 1. ** ** If the b-tree structure is empty, the cursor state is set to -** CURSOR_INVALID. Otherwise, the cursor is set to point to the first -** cell located on the root (or virtual root) page and the cursor state -** is set to CURSOR_VALID. +** CURSOR_INVALID and this routine returns SQLITE_EMPTY. Otherwise, +** the cursor is set to point to the first cell located on the root +** (or virtual root) page and the cursor state is set to CURSOR_VALID. ** ** If this function returns successfully, it may be assumed that the ** page-header flags indicate that the [virtual] root-page is the expected @@ -63950,37 +64644,40 @@ static int moveToRoot(BtCursor *pCur){ assert( CURSOR_INVALID < CURSOR_REQUIRESEEK ); assert( CURSOR_VALID < CURSOR_REQUIRESEEK ); assert( CURSOR_FAULT > CURSOR_REQUIRESEEK ); - if( pCur->eState>=CURSOR_REQUIRESEEK ){ - if( pCur->eState==CURSOR_FAULT ){ - assert( pCur->skipNext!=SQLITE_OK ); - return pCur->skipNext; - } - sqlite3BtreeClearCursor(pCur); - } + assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 ); + assert( pCur->pgnoRoot>0 || pCur->iPage<0 ); if( pCur->iPage>=0 ){ if( pCur->iPage ){ - do{ - assert( pCur->apPage[pCur->iPage]!=0 ); - releasePageNotNull(pCur->apPage[pCur->iPage--]); - }while( pCur->iPage); + releasePageNotNull(pCur->pPage); + while( --pCur->iPage ){ + releasePageNotNull(pCur->apPage[pCur->iPage]); + } + pCur->pPage = pCur->apPage[0]; goto skip_init; } }else if( pCur->pgnoRoot==0 ){ pCur->eState = CURSOR_INVALID; - return SQLITE_OK; + return SQLITE_EMPTY; }else{ assert( pCur->iPage==(-1) ); - rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0], + if( pCur->eState>=CURSOR_REQUIRESEEK ){ + if( pCur->eState==CURSOR_FAULT ){ + assert( pCur->skipNext!=SQLITE_OK ); + return pCur->skipNext; + } + sqlite3BtreeClearCursor(pCur); + } + rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage, 0, pCur->curPagerFlags); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; - return rc; + return rc; } pCur->iPage = 0; - pCur->curIntKey = pCur->apPage[0]->intKey; + pCur->curIntKey = pCur->pPage->intKey; } - pRoot = pCur->apPage[0]; + pRoot = pCur->pPage; assert( pRoot->pgno==pCur->pgnoRoot ); /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor @@ -63995,7 +64692,7 @@ static int moveToRoot(BtCursor *pCur){ ** (or the freelist). */ assert( pRoot->intKey==1 || pRoot->intKey==0 ); if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pCur->pPage->pgno); } skip_init: @@ -64003,7 +64700,7 @@ skip_init: pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); - pRoot = pCur->apPage[0]; + pRoot = pCur->pPage; if( pRoot->nCell>0 ){ pCur->eState = CURSOR_VALID; }else if( !pRoot->leaf ){ @@ -64014,6 +64711,7 @@ skip_init: rc = moveToChild(pCur, subpage); }else{ pCur->eState = CURSOR_INVALID; + rc = SQLITE_EMPTY; } return rc; } @@ -64032,7 +64730,7 @@ static int moveToLeftmost(BtCursor *pCur){ assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ assert( pCur->ix<pPage->nCell ); pgno = get4byte(findCell(pPage, pCur->ix)); rc = moveToChild(pCur, pgno); @@ -64057,7 +64755,7 @@ static int moveToRightmost(BtCursor *pCur){ assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + while( !(pPage = pCur->pPage)->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); pCur->ix = pPage->nCell; rc = moveToChild(pCur, pgno); @@ -64080,14 +64778,13 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ - if( pCur->eState==CURSOR_INVALID ){ - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); - *pRes = 1; - }else{ - assert( pCur->apPage[pCur->iPage]->nCell>0 ); - *pRes = 0; - rc = moveToLeftmost(pCur); - } + assert( pCur->pPage->nCell>0 ); + *pRes = 0; + rc = moveToLeftmost(pCur); + }else if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = 1; + rc = SQLITE_OK; } return rc; } @@ -64111,28 +64808,26 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ for(ii=0; ii<pCur->iPage; ii++){ assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell ); } - assert( pCur->ix==pCur->apPage[pCur->iPage]->nCell-1 ); - assert( pCur->apPage[pCur->iPage]->leaf ); + assert( pCur->ix==pCur->pPage->nCell-1 ); + assert( pCur->pPage->leaf ); #endif return SQLITE_OK; } rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ - if( CURSOR_INVALID==pCur->eState ){ - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); - *pRes = 1; + assert( pCur->eState==CURSOR_VALID ); + *pRes = 0; + rc = moveToRightmost(pCur); + if( rc==SQLITE_OK ){ + pCur->curFlags |= BTCF_AtLast; }else{ - assert( pCur->eState==CURSOR_VALID ); - *pRes = 0; - rc = moveToRightmost(pCur); - if( rc==SQLITE_OK ){ - pCur->curFlags |= BTCF_AtLast; - }else{ - pCur->curFlags &= ~BTCF_AtLast; - } - + pCur->curFlags &= ~BTCF_AtLast; } + }else if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = 1; + rc = SQLITE_OK; } return rc; } @@ -64200,16 +64895,19 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( /* If the requested key is one more than the previous key, then ** try to get there using sqlite3BtreeNext() rather than a full ** binary search. This is an optimization only. The correct answer - ** is still obtained without this ase, only a little more slowely */ + ** is still obtained without this case, only a little more slowely */ if( pCur->info.nKey+1==intKey && !pCur->skipNext ){ *pRes = 0; - rc = sqlite3BtreeNext(pCur, pRes); - if( rc ) return rc; - if( *pRes==0 ){ + rc = sqlite3BtreeNext(pCur, 0); + if( rc==SQLITE_OK ){ getCellInfo(pCur); if( pCur->info.nKey==intKey ){ return SQLITE_OK; } + }else if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + }else{ + return rc; } } } @@ -64228,22 +64926,23 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( rc = moveToRoot(pCur); if( rc ){ + if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = -1; + return SQLITE_OK; + } return rc; } - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] ); - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit ); - assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 ); - if( pCur->eState==CURSOR_INVALID ){ - *pRes = -1; - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); - return SQLITE_OK; - } - assert( pCur->apPage[0]->intKey==pCur->curIntKey ); + assert( pCur->pPage ); + assert( pCur->pPage->isInit ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->pPage->nCell > 0 ); + assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey ); assert( pCur->curIntKey || pIdxKey ); for(;;){ int lwr, upr, idx, c; Pgno chldPg; - MemPage *pPage = pCur->apPage[pCur->iPage]; + MemPage *pPage = pCur->pPage; u8 *pCell; /* Pointer to current cell in pPage */ /* pPage->nCell must be greater than zero. If this is the root-page @@ -64265,7 +64964,9 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( pCell = findCellPastPtr(pPage, idx); if( pPage->intKeyLeaf ){ while( 0x80 <= *(pCell++) ){ - if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT; + if( pCell>=pPage->aDataEnd ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } } } getVarint(pCell, (u64*)&nCellKey); @@ -64338,7 +65039,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ testcase( nCell==2 ); /* Minimum legal index key size */ if( nCell<2 ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(pPage->pgno); goto moveto_finish; } pCellKey = sqlite3Malloc( nCell+18 ); @@ -64369,7 +65070,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( *pRes = 0; rc = SQLITE_OK; pCur->ix = (u16)idx; - if( pIdxKey->errCode ) rc = SQLITE_CORRUPT; + if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT; goto moveto_finish; } if( lwr>upr ) break; @@ -64380,7 +65081,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); assert( pPage->isInit ); if( pPage->leaf ){ - assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell ); + assert( pCur->ix<pCur->pPage->nCell ); pCur->ix = (u16)idx; *pRes = c; rc = SQLITE_OK; @@ -64434,19 +65135,22 @@ SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){ ** opcode, and it that case the cursor will always be valid and ** will always point to a leaf node. */ if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1; - if( NEVER(pCur->apPage[pCur->iPage]->leaf==0) ) return -1; + if( NEVER(pCur->pPage->leaf==0) ) return -1; - for(n=1, i=0; i<=pCur->iPage; i++){ + n = pCur->pPage->nCell; + for(i=0; i<pCur->iPage; i++){ n *= pCur->apPage[i]->nCell; } return n; } /* -** Advance the cursor to the next entry in the database. If -** successful then set *pRes=0. If the cursor -** was already pointing to the last entry in the database before -** this routine was called, then set *pRes=1. +** Advance the cursor to the next entry in the database. +** Return value: +** +** SQLITE_OK success +** SQLITE_DONE cursor is already pointing at the last element +** otherwise some kind of error occurred ** ** The main entry point is sqlite3BtreeNext(). That routine is optimized ** for the common case of merely incrementing the cell counter BtCursor.aiIdx @@ -64454,23 +65158,19 @@ SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){ ** routine is called when it is necessary to move to a different page or ** to restore the cursor. ** -** The calling function will set *pRes to 0 or 1. The initial *pRes value -** will be 1 if the cursor being stepped corresponds to an SQL index and -** if this routine could have been skipped if that SQL index had been -** a unique index. Otherwise the caller will have set *pRes to zero. -** Zero is the common case. The btree implementation is free to use the -** initial *pRes value as a hint to improve performance, but the current -** SQLite btree implementation does not. (Note that the comdb2 btree -** implementation does use this hint, however.) +** If bit 0x01 of the F argument in sqlite3BtreeNext(C,F) is 1, then the +** cursor corresponds to an SQL index and this routine could have been +** skipped if the SQL index had been a unique index. The F argument +** is a hint to the implement. SQLite btree implementation does not use +** this hint, but COMDB2 does. */ -static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ +static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ int rc; int idx; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - assert( *pRes==0 ); if( pCur->eState!=CURSOR_VALID ){ assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); rc = restoreCursorPosition(pCur); @@ -64478,8 +65178,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ return rc; } if( CURSOR_INVALID==pCur->eState ){ - *pRes = 1; - return SQLITE_OK; + return SQLITE_DONE; } if( pCur->skipNext ){ assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT ); @@ -64492,7 +65191,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ } } - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; idx = ++pCur->ix; assert( pPage->isInit ); @@ -64511,15 +65210,14 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ } do{ if( pCur->iPage==0 ){ - *pRes = 1; pCur->eState = CURSOR_INVALID; - return SQLITE_OK; + return SQLITE_DONE; } moveToParent(pCur); - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; }while( pCur->ix>=pPage->nCell ); if( pPage->intKey ){ - return sqlite3BtreeNext(pCur, pRes); + return sqlite3BtreeNext(pCur, 0); }else{ return SQLITE_OK; } @@ -64530,20 +65228,19 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ return moveToLeftmost(pCur); } } -SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ +SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int flags){ MemPage *pPage; + UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ assert( cursorOwnsBtShared(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); + assert( flags==0 || flags==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); - *pRes = 0; - if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes); - pPage = pCur->apPage[pCur->iPage]; + if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur); + pPage = pCur->pPage; if( (++pCur->ix)>=pPage->nCell ){ pCur->ix--; - return btreeNext(pCur, pRes); + return btreeNext(pCur); } if( pPage->leaf ){ return SQLITE_OK; @@ -64553,10 +65250,12 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ } /* -** Step the cursor to the back to the previous entry in the database. If -** successful then set *pRes=0. If the cursor -** was already pointing to the first entry in the database before -** this routine was called, then set *pRes=1. +** Step the cursor to the back to the previous entry in the database. +** Return values: +** +** SQLITE_OK success +** SQLITE_DONE the cursor is already on the first element of the table +** otherwise some kind of error occurred ** ** The main entry point is sqlite3BtreePrevious(). That routine is optimized ** for the common case of merely decrementing the cell counter BtCursor.aiIdx @@ -64564,22 +65263,17 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ ** helper routine is called when it is necessary to move to a different page ** or to restore the cursor. ** -** The calling function will set *pRes to 0 or 1. The initial *pRes value -** will be 1 if the cursor being stepped corresponds to an SQL index and -** if this routine could have been skipped if that SQL index had been -** a unique index. Otherwise the caller will have set *pRes to zero. -** Zero is the common case. The btree implementation is free to use the -** initial *pRes value as a hint to improve performance, but the current -** SQLite btree implementation does not. (Note that the comdb2 btree -** implementation does use this hint, however.) +** If bit 0x01 of the F argument to sqlite3BtreePrevious(C,F) is 1, then +** the cursor corresponds to an SQL index and this routine could have been +** skipped if the SQL index had been a unique index. The F argument is a +** hint to the implement. The native SQLite btree implementation does not +** use this hint, but COMDB2 does. */ -static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ +static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){ int rc; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 ); assert( pCur->info.nSize==0 ); @@ -64589,8 +65283,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ return rc; } if( CURSOR_INVALID==pCur->eState ){ - *pRes = 1; - return SQLITE_OK; + return SQLITE_DONE; } if( pCur->skipNext ){ assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT ); @@ -64603,7 +65296,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ } } - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; assert( pPage->isInit ); if( !pPage->leaf ){ int idx = pCur->ix; @@ -64614,8 +65307,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ while( pCur->ix==0 ){ if( pCur->iPage==0 ){ pCur->eState = CURSOR_INVALID; - *pRes = 1; - return SQLITE_OK; + return SQLITE_DONE; } moveToParent(pCur); } @@ -64623,28 +65315,27 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 ); pCur->ix--; - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; if( pPage->intKey && !pPage->leaf ){ - rc = sqlite3BtreePrevious(pCur, pRes); + rc = sqlite3BtreePrevious(pCur, 0); }else{ rc = SQLITE_OK; } } return rc; } -SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ +SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){ assert( cursorOwnsBtShared(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); + assert( flags==0 || flags==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - *pRes = 0; + UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); pCur->info.nSize = 0; if( pCur->eState!=CURSOR_VALID || pCur->ix==0 - || pCur->apPage[pCur->iPage]->leaf==0 + || pCur->pPage->leaf==0 ){ - return btreePrevious(pCur, pRes); + return btreePrevious(pCur); } pCur->ix--; return SQLITE_OK; @@ -64752,7 +65443,7 @@ static int allocateBtreePage( } testcase( iTrunk==mxPage ); if( iTrunk>mxPage || nSearch++ > n ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1); }else{ rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); } @@ -64781,7 +65472,7 @@ static int allocateBtreePage( TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); }else if( k>(u32)(pBt->usableSize/4 - 2) ){ /* Value of k is out of range. Database corruption */ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; #ifndef SQLITE_OMIT_AUTOVACUUM }else if( searchList @@ -64815,7 +65506,7 @@ static int allocateBtreePage( MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); if( iNewTrunk>mxPage ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iNewTrunk==mxPage ); @@ -64880,7 +65571,7 @@ static int allocateBtreePage( iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); if( iPage>mxPage ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iPage==mxPage ); @@ -65138,7 +65829,7 @@ static int clearCell( unsigned char *pCell, /* First byte of the Cell */ CellInfo *pInfo /* Size information about the cell */ ){ - BtShared *pBt = pPage->pBt; + BtShared *pBt; Pgno ovflPgno; int rc; int nOvfl; @@ -65150,9 +65841,11 @@ static int clearCell( return SQLITE_OK; /* No overflow pages. Return without doing anything */ } if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){ - return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */ + /* Cell extends past end of page */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); } ovflPgno = get4byte(pCell + pInfo->nSize - 4); + pBt = pPage->pBt; assert( pBt->usableSize > 4 ); ovflPageSize = pBt->usableSize - 4; nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize; @@ -65220,21 +65913,20 @@ static int fillInCell( ){ int nPayload; const u8 *pSrc; - int nSrc, n, rc; + int nSrc, n, rc, mn; int spaceLeft; - MemPage *pOvfl = 0; - MemPage *pToRelease = 0; + MemPage *pToRelease; unsigned char *pPrior; unsigned char *pPayload; - BtShared *pBt = pPage->pBt; - Pgno pgnoOvfl = 0; + BtShared *pBt; + Pgno pgnoOvfl; int nHeader; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); /* pPage is not necessarily writeable since pCell might be auxiliary ** buffer space that is separate from the pPage buffer area */ - assert( pCell<pPage->aData || pCell>=&pPage->aData[pBt->pageSize] + assert( pCell<pPage->aData || pCell>=&pPage->aData[pPage->pBt->pageSize] || sqlite3PagerIswriteable(pPage->pDbPage) ); /* Fill in the header. */ @@ -65254,25 +65946,36 @@ static int fillInCell( } /* Fill in the payload */ + pPayload = &pCell[nHeader]; if( nPayload<=pPage->maxLocal ){ + /* This is the common case where everything fits on the btree page + ** and no overflow pages are required. */ n = nHeader + nPayload; testcase( n==3 ); testcase( n==4 ); if( n<4 ) n = 4; *pnSize = n; - spaceLeft = nPayload; - pPrior = pCell; - }else{ - int mn = pPage->minLocal; - n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4); - testcase( n==pPage->maxLocal ); - testcase( n==pPage->maxLocal+1 ); - if( n > pPage->maxLocal ) n = mn; - spaceLeft = n; - *pnSize = n + nHeader + 4; - pPrior = &pCell[nHeader+n]; + assert( nSrc<=nPayload ); + testcase( nSrc<nPayload ); + memcpy(pPayload, pSrc, nSrc); + memset(pPayload+nSrc, 0, nPayload-nSrc); + return SQLITE_OK; } - pPayload = &pCell[nHeader]; + + /* If we reach this point, it means that some of the content will need + ** to spill onto overflow pages. + */ + mn = pPage->minLocal; + n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4); + testcase( n==pPage->maxLocal ); + testcase( n==pPage->maxLocal+1 ); + if( n > pPage->maxLocal ) n = mn; + spaceLeft = n; + *pnSize = n + nHeader + 4; + pPrior = &pCell[nHeader+n]; + pToRelease = 0; + pgnoOvfl = 0; + pBt = pPage->pBt; /* At this point variables should be set as follows: ** @@ -65298,8 +66001,35 @@ static int fillInCell( #endif /* Write the payload into the local Cell and any extra into overflow pages */ - while( nPayload>0 ){ + while( 1 ){ + n = nPayload; + if( n>spaceLeft ) n = spaceLeft; + + /* If pToRelease is not zero than pPayload points into the data area + ** of pToRelease. Make sure pToRelease is still writeable. */ + assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); + + /* If pPayload is part of the data area of pPage, then make sure pPage + ** is still writeable */ + assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize] + || sqlite3PagerIswriteable(pPage->pDbPage) ); + + if( nSrc>=n ){ + memcpy(pPayload, pSrc, n); + }else if( nSrc>0 ){ + n = nSrc; + memcpy(pPayload, pSrc, n); + }else{ + memset(pPayload, 0, n); + } + nPayload -= n; + if( nPayload<=0 ) break; + pPayload += n; + pSrc += n; + nSrc -= n; + spaceLeft -= n; if( spaceLeft==0 ){ + MemPage *pOvfl = 0; #ifndef SQLITE_OMIT_AUTOVACUUM Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */ if( pBt->autoVacuum ){ @@ -65352,30 +66082,6 @@ static int fillInCell( pPayload = &pOvfl->aData[4]; spaceLeft = pBt->usableSize - 4; } - n = nPayload; - if( n>spaceLeft ) n = spaceLeft; - - /* If pToRelease is not zero than pPayload points into the data area - ** of pToRelease. Make sure pToRelease is still writeable. */ - assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); - - /* If pPayload is part of the data area of pPage, then make sure pPage - ** is still writeable */ - assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize] - || sqlite3PagerIswriteable(pPage->pDbPage) ); - - if( nSrc>0 ){ - if( n>nSrc ) n = nSrc; - assert( pSrc ); - memcpy(pPayload, pSrc, n); - }else{ - memset(pPayload, 0, n); - } - nPayload -= n; - pPayload += n; - pSrc += n; - nSrc -= n; - spaceLeft -= n; } releasePage(pToRelease); return SQLITE_OK; @@ -65407,7 +66113,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ hdr = pPage->hdrOffset; testcase( pc==get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); - if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){ + if( pc+sz > pPage->pBt->usableSize ){ *pRC = SQLITE_CORRUPT_BKPT; return; } @@ -66245,7 +66951,7 @@ static int balance_nonroot( ** In this case, temporarily copy the cell into the aOvflSpace[] ** buffer. It will be copied out again as soon as the aSpace[] buffer ** is allocated. */ - if( pBt->btsFlags & BTS_SECURE_DELETE ){ + if( pBt->btsFlags & BTS_FAST_SECURE ){ int iOff; iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData); @@ -66274,10 +66980,8 @@ static int balance_nonroot( + nMaxCells*sizeof(u16) /* b.szCell */ + pBt->pageSize; /* aSpace1 */ - /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer - ** that is more than 6 times the database page size. */ assert( szScratch<=6*(int)pBt->pageSize ); - b.apCell = sqlite3ScratchMalloc( szScratch ); + b.apCell = sqlite3StackAllocRaw(0, szScratch ); if( b.apCell==0 ){ rc = SQLITE_NOMEM_BKPT; goto balance_cleanup; @@ -66855,7 +67559,7 @@ static int balance_nonroot( ** Cleanup before returning. */ balance_cleanup: - sqlite3ScratchFree(b.apCell); + sqlite3StackFree(0, b.apCell); for(i=0; i<nOld; i++){ releasePage(apOld[i]); } @@ -66954,7 +67658,7 @@ static int balance(BtCursor *pCur){ do { int iPage = pCur->iPage; - MemPage *pPage = pCur->apPage[iPage]; + MemPage *pPage = pCur->pPage; if( iPage==0 ){ if( pPage->nOverflow ){ @@ -66970,7 +67674,9 @@ static int balance(BtCursor *pCur){ pCur->iPage = 1; pCur->ix = 0; pCur->aiIdx[0] = 0; - assert( pCur->apPage[1]->nOverflow ); + pCur->apPage[0] = pPage; + pCur->pPage = pCur->apPage[1]; + assert( pCur->pPage->nOverflow ); } }else{ break; @@ -67050,6 +67756,7 @@ static int balance(BtCursor *pCur){ releasePage(pPage); pCur->iPage--; assert( pCur->iPage>=0 ); + pCur->pPage = pCur->apPage[pCur->iPage]; } }while( rc==SQLITE_OK ); @@ -67181,7 +67888,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( } assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) ); - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; assert( pPage->intKey || pX->nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); @@ -67268,10 +67975,10 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( ** fails. Internal data structure corruption will result otherwise. ** Also, set the cursor state to invalid. This stops saveCursorPosition() ** from trying to save the current position of the cursor. */ - pCur->apPage[pCur->iPage]->nOverflow = 0; + pCur->pPage->nOverflow = 0; pCur->eState = CURSOR_INVALID; if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){ - rc = moveToRoot(pCur); + btreeReleaseAllCursorPages(pCur); if( pCur->pKeyInfo ){ assert( pCur->pKey==0 ); pCur->pKey = sqlite3Malloc( pX->nKey ); @@ -67285,7 +67992,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( pCur->nKey = pX->nKey; } } - assert( pCur->apPage[pCur->iPage]->nOverflow==0 ); + assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 ); end_insert: return rc; @@ -67326,13 +68033,13 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); - assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell ); + assert( pCur->ix<pCur->pPage->nCell ); assert( pCur->eState==CURSOR_VALID ); assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); iCellDepth = pCur->iPage; iCellIdx = pCur->ix; - pPage = pCur->apPage[iCellDepth]; + pPage = pCur->pPage; pCell = findCell(pPage, iCellIdx); /* If the bPreserve flag is set to true, then the cursor position must @@ -67365,8 +68072,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ ** sub-tree headed by the child page of the cell being deleted. This makes ** balancing the tree following the delete operation easier. */ if( !pPage->leaf ){ - int notUsed = 0; - rc = sqlite3BtreePrevious(pCur, ¬Used); + rc = sqlite3BtreePrevious(pCur, 0); + assert( rc!=SQLITE_DONE ); if( rc ) return rc; } @@ -67398,11 +68105,16 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ ** node. The cell from the leaf node needs to be moved to the internal ** node to replace the deleted cell. */ if( !pPage->leaf ){ - MemPage *pLeaf = pCur->apPage[pCur->iPage]; + MemPage *pLeaf = pCur->pPage; int nCell; - Pgno n = pCur->apPage[iCellDepth+1]->pgno; + Pgno n; unsigned char *pTmp; + if( iCellDepth<pCur->iPage-1 ){ + n = pCur->apPage[iCellDepth+1]->pgno; + }else{ + n = pCur->pPage->pgno; + } pCell = findCell(pLeaf, pLeaf->nCell-1); if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); @@ -67434,16 +68146,19 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ ** well. */ rc = balance(pCur); if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){ + releasePageNotNull(pCur->pPage); + pCur->iPage--; while( pCur->iPage>iCellDepth ){ releasePage(pCur->apPage[pCur->iPage--]); } + pCur->pPage = pCur->apPage[pCur->iPage]; rc = balance(pCur); } if( rc==SQLITE_OK ){ if( bSkipnext ){ assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) ); - assert( pPage==pCur->apPage[pCur->iPage] || CORRUPT_DB ); + assert( pPage==pCur->pPage || CORRUPT_DB ); assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell ); pCur->eState = CURSOR_SKIPNEXT; if( iCellIdx>=pPage->nCell ){ @@ -67455,8 +68170,10 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ }else{ rc = moveToRoot(pCur); if( bPreserve ){ + btreeReleaseAllCursorPages(pCur); pCur->eState = CURSOR_REQUIRESEEK; } + if( rc==SQLITE_EMPTY ) rc = SQLITE_OK; } } return rc; @@ -67921,11 +68638,11 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ i64 nEntry = 0; /* Value to return in *pnEntry */ int rc; /* Return code */ - if( pCur->pgnoRoot==0 ){ + rc = moveToRoot(pCur); + if( rc==SQLITE_EMPTY ){ *pnEntry = 0; return SQLITE_OK; } - rc = moveToRoot(pCur); /* Unless an error occurs, the following loop runs one iteration for each ** page in the B-Tree structure (not including overflow pages). @@ -67938,7 +68655,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ ** this page contains countable entries. Increment the entry counter ** accordingly. */ - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; if( pPage->leaf || !pPage->intKey ){ nEntry += pPage->nCell; } @@ -67961,10 +68678,10 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ return moveToRoot(pCur); } moveToParent(pCur); - }while ( pCur->ix>=pCur->apPage[pCur->iPage]->nCell ); + }while ( pCur->ix>=pCur->pPage->nCell ); pCur->ix++; - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; } /* Descend to the child node of the cell that the cursor currently @@ -68805,7 +69522,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void && pCsr->pBt->inTransaction==TRANS_WRITE ); assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) ); assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) ); - assert( pCsr->apPage[pCsr->iPage]->intKey ); + assert( pCsr->pPage->intKey ); return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1); } @@ -69728,7 +70445,7 @@ copy_finished: */ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ /* If MEM_Dyn is set then Mem.xDel!=0. - ** Mem.xDel is might not be initialized if MEM_Dyn is clear. + ** Mem.xDel might not be initialized if MEM_Dyn is clear. */ assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); @@ -69741,9 +70458,34 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ /* Cannot be both MEM_Int and MEM_Real at the same time */ assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); - /* Cannot be both MEM_Null and some other type */ - assert( (p->flags & MEM_Null)==0 || - (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob))==0 ); + if( p->flags & MEM_Null ){ + /* Cannot be both MEM_Null and some other type */ + assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob + |MEM_RowSet|MEM_Frame|MEM_Agg|MEM_Zero))==0 ); + + /* If MEM_Null is set, then either the value is a pure NULL (the usual + ** case) or it is a pointer set using sqlite3_bind_pointer() or + ** sqlite3_result_pointer(). If a pointer, then MEM_Term must also be + ** set. + */ + if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){ + /* This is a pointer type. There may be a flag to indicate what to + ** do with the pointer. */ + assert( ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + + ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 ); + + /* No other bits set */ + assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype + |MEM_Dyn|MEM_Ephem|MEM_Static))==0 ); + }else{ + /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn, + ** MEM_Ephem, MEM_Cleared, or MEM_Subtype */ + } + }else{ + /* The MEM_Cleared bit is only allowed on NULLs */ + assert( (p->flags & MEM_Cleared)==0 ); + } /* The szMalloc field holds the correct memory allocation size */ assert( p->szMalloc==0 @@ -69831,7 +70573,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre assert( pMem->szMalloc==0 || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) ); if( n<32 ) n = 32; - if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){ + if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); bPreserve = 0; }else{ @@ -69847,7 +70589,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); } - if( bPreserve && pMem->z && ALWAYS(pMem->z!=pMem->zMalloc) ){ + if( bPreserve && pMem->z ){ + assert( pMem->z!=pMem->zMalloc ); memcpy(pMem->zMalloc, pMem->z, pMem->n); } if( (pMem->flags&MEM_Dyn)!=0 ){ @@ -69886,6 +70629,20 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ } /* +** It is already known that pMem contains an unterminated string. +** Add the zero terminator. +*/ +static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ + if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ + return SQLITE_NOMEM_BKPT; + } + pMem->z[pMem->n] = 0; + pMem->z[pMem->n+1] = 0; + pMem->flags |= MEM_Term; + return SQLITE_OK; +} + +/* ** Change pMem so that its MEM_Str or MEM_Blob value is stored in ** MEM.zMalloc, where it can be safely written. ** @@ -69897,12 +70654,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){ if( ExpandBlob(pMem) ) return SQLITE_NOMEM; if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){ - if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){ - return SQLITE_NOMEM_BKPT; - } - pMem->z[pMem->n] = 0; - pMem->z[pMem->n+1] = 0; - pMem->flags |= MEM_Term; + int rc = vdbeMemAddTerminator(pMem); + if( rc ) return rc; } } pMem->flags &= ~MEM_Ephem; @@ -69942,20 +70695,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ #endif /* -** It is already known that pMem contains an unterminated string. -** Add the zero terminator. -*/ -static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ - if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ - return SQLITE_NOMEM_BKPT; - } - pMem->z[pMem->n] = 0; - pMem->z[pMem->n+1] = 0; - pMem->flags |= MEM_Term; - return SQLITE_OK; -} - -/* ** Make sure the given Mem is \u0000 terminated. */ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ @@ -70273,14 +71012,21 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ */ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){ + int rc; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){ + rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc); + if( rc==0 ){ MemSetTypeFlag(pMem, MEM_Int); }else{ - pMem->u.r = sqlite3VdbeRealValue(pMem); - MemSetTypeFlag(pMem, MEM_Real); - sqlite3VdbeIntegerAffinity(pMem); + i64 i = pMem->u.i; + sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + if( rc==1 && pMem->u.r==(double)i ){ + pMem->u.i = i; + MemSetTypeFlag(pMem, MEM_Int); + }else{ + MemSetTypeFlag(pMem, MEM_Real); + } } } assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 ); @@ -70406,6 +71152,27 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ } } +/* A no-op destructor */ +static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); } + +/* +** Set the value stored in *pMem should already be a NULL. +** Also store a pointer to go with it. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemSetPointer( + Mem *pMem, + void *pPtr, + const char *zPType, + void (*xDestructor)(void*) +){ + assert( pMem->flags==MEM_Null ); + pMem->u.zPType = zPType ? zPType : ""; + pMem->z = pPtr; + pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term; + pMem->eSubtype = 'p'; + pMem->xDel = xDestructor ? xDestructor : sqlite3NoopDestructor; +} + #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Delete any previous value and set the value stored in *pMem to val, @@ -70586,7 +71353,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( if( nByte<0 ){ assert( enc!=0 ); if( enc==SQLITE_UTF8 ){ - nByte = sqlite3Strlen30(z); + nByte = 0x7fffffff & (int)strlen(z); if( nByte>iLimit ) nByte = iLimit+1; }else{ for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} @@ -70664,12 +71431,11 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize( ){ int rc; pMem->flags = MEM_Null; - if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){ + if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){ rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z); if( rc==SQLITE_OK ){ - pMem->z[amt] = 0; - pMem->z[amt+1] = 0; - pMem->flags = MEM_Blob|MEM_Term; + pMem->z[amt] = 0; /* Overrun area used when reading malformed records */ + pMem->flags = MEM_Blob; pMem->n = (int)amt; }else{ sqlite3VdbeMemRelease(pMem); @@ -70818,7 +71584,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ if( pRec ){ pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx); if( pRec->pKeyInfo ){ - assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol ); + assert( pRec->pKeyInfo->nAllField==nCol ); assert( pRec->pKeyInfo->enc==ENC(db) ); pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord))); for(i=0; i<nCol; i++){ @@ -71026,7 +71792,7 @@ static int valueFromExpr( } }else if( op==TK_UMINUS ) { /* This branch happens for multiple negative signs. Ex: -(-5) */ - if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) + if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx) && pVal!=0 ){ sqlite3VdbeMemNumerify(pVal); @@ -71183,14 +71949,13 @@ static int stat4ValueFromExpr( /* Skip over any TK_COLLATE nodes */ pExpr = sqlite3ExprSkipCollate(pExpr); + assert( pExpr==0 || pExpr->op!=TK_REGISTER || pExpr->op2!=TK_VARIABLE ); if( !pExpr ){ pVal = valueNew(db, pAlloc); if( pVal ){ sqlite3VdbeMemSetNull((Mem*)pVal); } - }else if( pExpr->op==TK_VARIABLE - || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE) - ){ + }else if( pExpr->op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *v; int iBindVar = pExpr->iColumn; sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); @@ -71198,9 +71963,7 @@ static int stat4ValueFromExpr( pVal = valueNew(db, pAlloc); if( pVal ){ rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); - if( rc==SQLITE_OK ){ - sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); - } + sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); pVal->db = pParse->db; } } @@ -71357,7 +72120,7 @@ SQLITE_PRIVATE int sqlite3Stat4Column( SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){ if( pRec ){ int i; - int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField; + int nCol = pRec->pKeyInfo->nAllField; Mem *aMem = pRec->aMem; sqlite3 *db = aMem[0].db; for(i=0; i<nCol; i++){ @@ -71453,10 +72216,12 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){ db->pVdbe = p; p->magic = VDBE_MAGIC_INIT; p->pParse = pParse; + pParse->pVdbe = p; assert( pParse->aLabel==0 ); assert( pParse->nLabel==0 ); assert( pParse->nOpAlloc==0 ); assert( pParse->szOpAlloc==0 ); + sqlite3VdbeAddOp2(p, OP_Init, 0, 1); return p; } @@ -71474,16 +72239,14 @@ SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){ /* ** Remember the SQL string for a prepared statement. */ -SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){ - assert( isPrepareV2==1 || isPrepareV2==0 ); +SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlags){ if( p==0 ) return; - if( !isPrepareV2 ) p->expmask = 0; -#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG) - if( !isPrepareV2 ) return; -#endif + p->prepFlags = prepFlags; + if( (prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){ + p->expmask = 0; + } assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); - p->isPrepareV2 = (u8)isPrepareV2; } /* @@ -71505,8 +72268,10 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; - pB->isPrepareV2 = pA->isPrepareV2; pB->expmask = pA->expmask; + pB->prepFlags = pA->prepFlags; + memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter)); + pB->aCounter[SQLITE_STMTSTATUS_REPREPARE]++; } /* @@ -71662,6 +72427,9 @@ SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){ ** "s" character in zTypes[], the register is a string if the argument is ** not NULL, or OP_Null if the value is a null pointer. For each "i" character ** in zTypes[], the register is initialized to an integer. +** +** If the input string does not end with "X" then an OP_ResultRow instruction +** is generated for the values inserted. */ SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){ va_list ap; @@ -71671,12 +72439,15 @@ SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, for(i=0; (c = zTypes[i])!=0; i++){ if( c=='s' ){ const char *z = va_arg(ap, const char*); - sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest++, 0, z, 0); + sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest+i, 0, z, 0); + }else if( c=='i' ){ + sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest+i); }else{ - assert( c=='i' ); - sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++); + goto skip_op_resultrow; } } + sqlite3VdbeAddOp2(p, OP_ResultRow, iDest, i); +skip_op_resultrow: va_end(ap); } @@ -71904,7 +72675,8 @@ static Op *opIterNext(VdbeOpIter *p){ ** * OP_VUpdate ** * OP_VRename ** * OP_FkCounter with P2==0 (immediate foreign key constraint) -** * OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...) +** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine +** (for CREATE TABLE AS SELECT ...) ** ** Then check that the value of Parse.mayAbort is true if an ** ABORT may be thrown, or false otherwise. Return true if it does @@ -71932,7 +72704,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ hasAbort = 1; break; } - if( opcode==OP_CreateTable ) hasCreateTable = 1; + if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1; if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1; #ifndef SQLITE_OMIT_FOREIGN_KEY if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ @@ -72011,6 +72783,27 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ p->bIsReader = 1; break; } + case OP_Next: + case OP_NextIfOpen: + case OP_SorterNext: { + pOp->p4.xAdvance = sqlite3BtreeNext; + pOp->p4type = P4_ADVANCE; + /* The code generator never codes any of these opcodes as a jump + ** to a label. They are always coded as a jump backwards to a + ** known address */ + assert( pOp->p2>=0 ); + break; + } + case OP_Prev: + case OP_PrevIfOpen: { + pOp->p4.xAdvance = sqlite3BtreePrevious; + pOp->p4type = P4_ADVANCE; + /* The code generator never codes any of these opcodes as a jump + ** to a label. They are always coded as a jump backwards to a + ** known address */ + assert( pOp->p2>=0 ); + break; + } #ifndef SQLITE_OMIT_VIRTUALTABLE case OP_VUpdate: { if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; @@ -72022,27 +72815,25 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ assert( pOp[-1].opcode==OP_Integer ); n = pOp[-1].p1; if( n>nMaxArgs ) nMaxArgs = n; - break; + /* Fall through into the default case */ } #endif - case OP_Next: - case OP_NextIfOpen: - case OP_SorterNext: { - pOp->p4.xAdvance = sqlite3BtreeNext; - pOp->p4type = P4_ADVANCE; - break; - } - case OP_Prev: - case OP_PrevIfOpen: { - pOp->p4.xAdvance = sqlite3BtreePrevious; - pOp->p4type = P4_ADVANCE; + default: { + if( pOp->p2<0 ){ + /* The mkopcodeh.tcl script has so arranged things that the only + ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to + ** have non-negative values for P2. */ + assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ); + assert( ADDR(pOp->p2)<pParse->nLabel ); + pOp->p2 = aLabel[ADDR(pOp->p2)]; + } break; } } - if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){ - assert( ADDR(pOp->p2)<pParse->nLabel ); - pOp->p2 = aLabel[ADDR(pOp->p2)]; - } + /* The mkopcodeh.tcl script has so arranged things that the only + ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to + ** have non-negative values for P2. */ + assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0); } if( pOp==p->aOp ) break; pOp--; @@ -72300,7 +73091,7 @@ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ if( aOp ){ Op *pOp; for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){ - if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p); + if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS sqlite3DbFree(db, pOp->zComment); #endif @@ -72715,8 +73506,8 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ int j; KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; assert( pKeyInfo->aSortOrder!=0 ); - sqlite3XPrintf(&x, "k(%d", pKeyInfo->nField); - for(j=0; j<pKeyInfo->nField; j++){ + sqlite3XPrintf(&x, "k(%d", pKeyInfo->nKeyField); + for(j=0; j<pKeyInfo->nKeyField; j++){ CollSeq *pColl = pKeyInfo->aColl[j]; const char *zColl = pColl ? pColl->zName : ""; if( strcmp(zColl, "BINARY")==0 ) zColl = "B"; @@ -72788,7 +73579,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ int *ai = pOp->p4.ai; int n = ai[0]; /* The first element of an INTARRAY is always the ** count of the number of elements to follow */ - for(i=1; i<n; i++){ + for(i=1; i<=n; i++){ sqlite3XPrintf(&x, ",%d", ai[i]); } zTemp[0] = '['; @@ -73553,44 +74344,24 @@ static void closeAllCursors(Vdbe *p){ } /* -** Clean up the VM after a single run. -*/ -static void Cleanup(Vdbe *p){ - sqlite3 *db = p->db; - -#ifdef SQLITE_DEBUG - /* Execute assert() statements to ensure that the Vdbe.apCsr[] and - ** Vdbe.aMem[] arrays have already been cleaned up. */ - int i; - if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 ); - if( p->aMem ){ - for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); - } -#endif - - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = 0; - p->pResultSet = 0; -} - -/* ** Set the number of result columns that will be returned by this SQL ** statement. This is now set at compile time, rather than during ** execution of the vdbe program so that sqlite3_column_count() can ** be called on an SQL statement before sqlite3_step(). */ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ - Mem *pColName; int n; sqlite3 *db = p->db; - releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); - sqlite3DbFree(db, p->aColName); + if( p->nResColumn ){ + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); + sqlite3DbFree(db, p->aColName); + } n = nResColumn*COLNAME_N; p->nResColumn = (u16)nResColumn; - p->aColName = pColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n ); + p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n ); if( p->aColName==0 ) return; - initMemArray(p->aColName, n, p->db, MEM_Null); + initMemArray(p->aColName, n, db, MEM_Null); } /* @@ -74240,10 +75011,10 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){ sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT); sqlite3EndBenignMalloc(); db->bBenignMalloc--; - db->errCode = rc; - }else{ - sqlite3Error(db, rc); + }else if( db->pErr ){ + sqlite3ValueSetNull(db->pErr); } + db->errCode = rc; return rc; } @@ -74280,6 +75051,10 @@ static void vdbeInvokeSqllog(Vdbe *v){ ** VDBE_MAGIC_INIT. */ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + int i; +#endif + sqlite3 *db; db = p->db; @@ -74297,8 +75072,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ if( p->pc>=0 ){ vdbeInvokeSqllog(p); sqlite3VdbeTransferError(p); - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = 0; if( p->runOnlyOnce ) p->expired = 1; }else if( p->rc && p->expired ){ /* The expired flag was set on the VDBE before the first call @@ -74306,13 +75079,21 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ ** called), set the database error in this case as well. */ sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = 0; } - /* Reclaim all memory used by the VDBE + /* Reset register contents and reclaim error message memory. */ - Cleanup(p); +#ifdef SQLITE_DEBUG + /* Execute assert() statements to ensure that the Vdbe.apCsr[] and + ** Vdbe.aMem[] arrays have already been cleaned up. */ + if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 ); + if( p->aMem ){ + for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); + } +#endif + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = 0; + p->pResultSet = 0; /* Save profiling information from this VDBE run. */ @@ -74320,7 +75101,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ { FILE *out = fopen("vdbe_profile.out", "a"); if( out ){ - int i; fprintf(out, "---- "); for(i=0; i<p->nOp; i++){ fprintf(out, "%02x", p->aOp[i].opcode); @@ -74533,19 +75313,18 @@ SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){ */ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){ VdbeCursor *p = *pp; - if( p->eCurType==CURTYPE_BTREE ){ - if( p->deferredMoveto ){ - int iMap; - if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){ - *pp = p->pAltCursor; - *piCol = iMap - 1; - return SQLITE_OK; - } - return handleDeferredMoveto(p); - } - if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ - return handleMovedCursor(p); + assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO ); + if( p->deferredMoveto ){ + int iMap; + if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){ + *pp = p->pAltCursor; + *piCol = iMap - 1; + return SQLITE_OK; } + return handleDeferredMoveto(p); + } + if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ + return handleMovedCursor(p); } return SQLITE_OK; } @@ -74941,13 +75720,13 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( ){ UnpackedRecord *p; /* Unpacked record to return */ int nByte; /* Number of bytes required for *p */ - nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1); + nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1); p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); if( !p ) return 0; p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; assert( pKeyInfo->aSortOrder!=0 ); p->pKeyInfo = pKeyInfo; - p->nField = pKeyInfo->nField + 1; + p->nField = pKeyInfo->nKeyField + 1; return p; } @@ -74987,7 +75766,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( pMem++; if( (++u)>=p->nField ) break; } - assert( u<=pKeyInfo->nField + 1 ); + assert( u<=pKeyInfo->nKeyField + 1 ); p->nField = u; } @@ -75036,9 +75815,9 @@ static int vdbeRecordCompareDebug( idx1 = getVarint32(aKey1, szHdr1); if( szHdr1>98307 ) return SQLITE_CORRUPT; d1 = szHdr1; - assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB ); + assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); assert( pKeyInfo->aSortOrder!=0 ); - assert( pKeyInfo->nField>0 ); + assert( pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ u32 serial_type1; @@ -75100,12 +75879,12 @@ debugCompareEnd: /* ** Count the number of fields (a.k.a. columns) in the record given by ** pKey,nKey. The verify that this count is less than or equal to the -** limit given by pKeyInfo->nField + pKeyInfo->nXField. +** limit given by pKeyInfo->nAllField. ** ** If this constraint is not satisfied, it means that the high-speed ** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will ** not work correctly. If this assert() ever fires, it probably means -** that the KeyInfo.nField or KeyInfo.nXField values were computed +** that the KeyInfo.nKeyField or KeyInfo.nAllField values were computed ** incorrectly. */ static void vdbeAssertFieldCountWithinLimits( @@ -75126,7 +75905,7 @@ static void vdbeAssertFieldCountWithinLimits( idx += getVarint32(aKey+idx, notUsed); nField++; } - assert( nField <= pKeyInfo->nField+pKeyInfo->nXField ); + assert( nField <= pKeyInfo->nAllField ); } #else # define vdbeAssertFieldCountWithinLimits(A,B,C) @@ -75151,7 +75930,6 @@ static int vdbeCompareMemString( }else{ int rc; const void *v1, *v2; - int n1, n2; Mem c1; Mem c2; sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null); @@ -75159,11 +75937,13 @@ static int vdbeCompareMemString( sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); - n1 = v1==0 ? 0 : c1.n; v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); - n2 = v2==0 ? 0 : c2.n; - rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); - if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM_BKPT; + if( (v1==0 || v2==0) ){ + if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT; + rc = 0; + }else{ + rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2); + } sqlite3VdbeMemRelease(&c1); sqlite3VdbeMemRelease(&c2); return rc; @@ -75430,10 +76210,10 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( } VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ - assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField + assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); assert( pPKey2->pKeyInfo->aSortOrder!=0 ); - assert( pPKey2->pKeyInfo->nField>0 ); + assert( pPKey2->pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ u32 serial_type; @@ -75766,7 +76546,7 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ ** The easiest way to enforce this limit is to consider only records with ** 13 fields or less. If the first field is an integer, the maximum legal ** header size is (12*5 + 1 + 1) bytes. */ - if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){ + if( p->pKeyInfo->nAllField<=13 ){ int flags = p->aMem[0].flags; if( p->pKeyInfo->aSortOrder[0] ){ p->r1 = 1; @@ -75949,6 +76729,13 @@ SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){ } /* +** Return the SQLITE_PREPARE flags for a Vdbe. +*/ +SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe *v){ + return v->prepFlags; +} + +/* ** Return a pointer to an sqlite3_value structure containing the value bound ** parameter iVar of VM v. Except, if the value is an SQL NULL, return ** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_* @@ -75960,6 +76747,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff assert( iVar>0 ); if( v ){ Mem *pMem = &v->aVar[iVar-1]; + assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); if( 0==(pMem->flags & MEM_Null) ){ sqlite3_value *pRet = sqlite3ValueNew(v->db); if( pRet ){ @@ -75979,6 +76767,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff */ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ assert( iVar>0 ); + assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); if( iVar>=32 ){ v->expmask |= 0x80000000; }else{ @@ -75986,6 +76775,28 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ } } +/* +** Cause a function to throw an error if it was call from OP_PureFunc +** rather than OP_Function. +** +** OP_PureFunc means that the function must be deterministic, and should +** throw an error if it is given inputs that would make it non-deterministic. +** This routine is invoked by date/time functions that use non-deterministic +** features such as 'now'. +*/ +SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context *pCtx){ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( pCtx->pVdbe==0 ) return 1; +#endif + if( pCtx->pVdbe->aOp[pCtx->iOp].opcode==OP_PureFunc ){ + sqlite3_result_error(pCtx, + "non-deterministic function in index expression or CHECK constraint", + -1); + return 0; + } + return 1; +} + #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored @@ -76070,7 +76881,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( preupdate.iNewReg = iReg; preupdate.keyinfo.db = db; preupdate.keyinfo.enc = ENC(db); - preupdate.keyinfo.nField = pTab->nCol; + preupdate.keyinfo.nKeyField = pTab->nCol; preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder; preupdate.iKey1 = iKey1; preupdate.iKey2 = iKey2; @@ -76080,8 +76891,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2); db->pPreUpdate = 0; sqlite3DbFree(db, preupdate.aRecord); - vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pUnpacked); - vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pNewUnpacked); + vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked); + vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked); if( preupdate.aNew ){ int i; for(i=0; i<pCsr->nField; i++){ @@ -76250,7 +77061,7 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ sqlite3VdbeMemRelease(&p->aVar[i]); p->aVar[i].flags = MEM_Null; } - assert( p->isPrepareV2 || p->expmask==0 ); + assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 ); if( p->expmask ){ p->expired = 1; } @@ -76295,6 +77106,19 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value *pVal){ Mem *pMem = (Mem*)pVal; return ((pMem->flags & MEM_Subtype) ? pMem->eSubtype : 0); } +SQLITE_API void *sqlite3_value_pointer(sqlite3_value *pVal, const char *zPType){ + Mem *p = (Mem*)pVal; + if( (p->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) == + (MEM_Null|MEM_Term|MEM_Subtype) + && zPType!=0 + && p->eSubtype=='p' + && strcmp(p->u.zPType, zPType)==0 + ){ + return (void*)p->z; + }else{ + return 0; + } +} SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){ return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8); } @@ -76473,6 +77297,18 @@ SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); } +SQLITE_API void sqlite3_result_pointer( + sqlite3_context *pCtx, + void *pPtr, + const char *zPType, + void (*xDestructor)(void*) +){ + Mem *pOut = pCtx->pOut; + assert( sqlite3_mutex_held(pOut->db->mutex) ); + sqlite3VdbeMemRelease(pOut); + pOut->flags = MEM_Null; + sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor); +} SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ Mem *pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); @@ -76595,7 +77431,7 @@ static int doWalCallbacks(sqlite3 *db){ sqlite3BtreeEnter(pBt); nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); - if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){ + if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry); } } @@ -76705,7 +77541,7 @@ static int sqlite3Step(Vdbe *p){ if( rc!=SQLITE_ROW ) checkProfileCallback(db, p); #endif - if( rc==SQLITE_DONE ){ + if( rc==SQLITE_DONE && db->autoCommit ){ assert( p->rc==SQLITE_OK ); p->rc = doWalCallbacks(db); if( p->rc!=SQLITE_OK ){ @@ -76729,8 +77565,11 @@ end_of_step: || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE ); assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp ); - if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ - /* If this statement was prepared using sqlite3_prepare_v2(), and an + if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 + && rc!=SQLITE_ROW + && rc!=SQLITE_DONE + ){ + /* If this statement was prepared using saved SQL and an ** error has occurred, then return the error code in p->rc to the ** caller. Set the error code in the database handle to the same value. */ @@ -76746,7 +77585,6 @@ end_of_step: */ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ int rc = SQLITE_OK; /* Result from sqlite3Step() */ - int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */ Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */ int cnt = 0; /* Counter to prevent infinite loop of reprepares */ sqlite3 *db; /* The database connection */ @@ -76760,32 +77598,31 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ while( (rc = sqlite3Step(v))==SQLITE_SCHEMA && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ int savedPc = v->pc; - rc2 = rc = sqlite3Reprepare(v); - if( rc!=SQLITE_OK) break; + rc = sqlite3Reprepare(v); + if( rc!=SQLITE_OK ){ + /* This case occurs after failing to recompile an sql statement. + ** The error message from the SQL compiler has already been loaded + ** into the database handle. This block copies the error message + ** from the database handle into the statement and sets the statement + ** program counter to 0 to ensure that when the statement is + ** finalized or reset the parser error message is available via + ** sqlite3_errmsg() and sqlite3_errcode(). + */ + const char *zErr = (const char *)sqlite3_value_text(db->pErr); + sqlite3DbFree(db, v->zErrMsg); + if( !db->mallocFailed ){ + v->zErrMsg = sqlite3DbStrDup(db, zErr); + v->rc = rc = sqlite3ApiExit(db, rc); + } else { + v->zErrMsg = 0; + v->rc = rc = SQLITE_NOMEM_BKPT; + } + break; + } sqlite3_reset(pStmt); if( savedPc>=0 ) v->doingRerun = 1; assert( v->expired==0 ); } - if( rc2!=SQLITE_OK ){ - /* This case occurs after failing to recompile an sql statement. - ** The error message from the SQL compiler has already been loaded - ** into the database handle. This block copies the error message - ** from the database handle into the statement and sets the statement - ** program counter to 0 to ensure that when the statement is - ** finalized or reset the parser error message is available via - ** sqlite3_errmsg() and sqlite3_errcode(). - */ - const char *zErr = (const char *)sqlite3_value_text(db->pErr); - sqlite3DbFree(db, v->zErrMsg); - if( !db->mallocFailed ){ - v->zErrMsg = sqlite3DbStrDup(db, zErr); - v->rc = rc2; - } else { - v->zErrMsg = 0; - v->rc = rc = SQLITE_NOMEM_BKPT; - } - } - rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } @@ -77369,7 +78206,7 @@ static int vdbeUnbind(Vdbe *p, int i){ ** as if there had been a schema change, on the first sqlite3_step() call ** following any change to the bindings of that parameter. */ - assert( p->isPrepareV2 || p->expmask==0 ); + assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 ); if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<<i))!=0 ){ p->expired = 1; } @@ -77399,8 +78236,10 @@ static int bindText( if( rc==SQLITE_OK && encoding!=0 ){ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); } - sqlite3Error(p->db, rc); - rc = sqlite3ApiExit(p->db, rc); + if( rc ){ + sqlite3Error(p->db, rc); + rc = sqlite3ApiExit(p->db, rc); + } } sqlite3_mutex_leave(p->db->mutex); }else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){ @@ -77471,6 +78310,24 @@ SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ } return rc; } +SQLITE_API int sqlite3_bind_pointer( + sqlite3_stmt *pStmt, + int i, + void *pPtr, + const char *zPTtype, + void (*xDestructor)(void*) +){ + int rc; + Vdbe *p = (Vdbe*)pStmt; + rc = vdbeUnbind(p, i); + if( rc==SQLITE_OK ){ + sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor); + sqlite3_mutex_leave(p->db->mutex); + }else if( xDestructor ){ + xDestructor(pPtr); + } + return rc; +} SQLITE_API int sqlite3_bind_text( sqlite3_stmt *pStmt, int i, @@ -77633,11 +78490,11 @@ SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt * if( pFrom->nVar!=pTo->nVar ){ return SQLITE_ERROR; } - assert( pTo->isPrepareV2 || pTo->expmask==0 ); + assert( (pTo->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pTo->expmask==0 ); if( pTo->expmask ){ pTo->expired = 1; } - assert( pFrom->isPrepareV2 || pFrom->expmask==0 ); + assert( (pFrom->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pFrom->expmask==0 ); if( pFrom->expmask ){ pFrom->expired = 1; } @@ -77707,8 +78564,19 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ return 0; } #endif - v = pVdbe->aCounter[op]; - if( resetFlag ) pVdbe->aCounter[op] = 0; + if( op==SQLITE_STMTSTATUS_MEMUSED ){ + sqlite3 *db = pVdbe->db; + sqlite3_mutex_enter(db->mutex); + v = 0; + db->pnBytesFreed = (int*)&v; + sqlite3VdbeClearObject(db, pVdbe); + sqlite3DbFree(db, pVdbe); + db->pnBytesFreed = 0; + sqlite3_mutex_leave(db->mutex); + }else{ + v = pVdbe->aCounter[op]; + if( resetFlag ) pVdbe->aCounter[op] = 0; + } return (int)v; } @@ -77760,7 +78628,7 @@ static UnpackedRecord *vdbeUnpackRecord( pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); if( pRet ){ - memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1)); + memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1)); sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet); } return pRet; @@ -77833,7 +78701,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa */ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ PreUpdate *p = db->pPreUpdate; - return (p ? p->keyinfo.nField : 0); + return (p ? p->keyinfo.nKeyField : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -78086,7 +78954,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ #ifndef SQLITE_OMIT_UTF16 - Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */ + Mem utf8; /* Used to convert UTF16 into UTF8 for display */ #endif char zBase[100]; /* Initial working space */ @@ -78555,7 +79423,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){ return 0; } - if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ + if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){ return MEM_Int; } return MEM_Real; @@ -78863,7 +79731,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec( int iCompare = 0; /* Result of last comparison */ unsigned nVmStep = 0; /* Number of virtual machine steps */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK - unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */ + unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */ #endif Mem *aMem = p->aMem; /* Copy of p->aMem */ Mem *pIn1 = 0; /* 1st input operand */ @@ -78895,6 +79763,8 @@ SQLITE_PRIVATE int sqlite3VdbeExec( u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; assert( 0 < db->nProgressOps ); nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); + }else{ + nProgressLimit = 0xffffffff; } #endif #ifdef SQLITE_DEBUG @@ -79072,7 +79942,7 @@ check_for_interrupt: ** If the progress callback returns non-zero, exit the virtual machine with ** a return code SQLITE_ABORT. */ - if( db->xProgress!=0 && nVmStep>=nProgressLimit ){ + if( nVmStep>=nProgressLimit && db->xProgress!=0 ){ assert( db->nProgressOps!=0 ); nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps); if( db->xProgress(db->pProgressArg) ){ @@ -79614,7 +80484,7 @@ case OP_ResultRow: { /* Run the progress counter just before returning. */ if( db->xProgress!=0 - && nVmStep>=nProgressLimit + && nVmStep>=nProgressLimit && db->xProgress(db->pProgressArg)!=0 ){ rc = SQLITE_INTERRUPT; @@ -79878,117 +80748,6 @@ case OP_CollSeq: { break; } -/* Opcode: Function0 P1 P2 P3 P4 P5 -** Synopsis: r[P3]=func(r[P2@P5]) -** -** Invoke a user function (P4 is a pointer to a FuncDef object that -** defines the function) with P5 arguments taken from register P2 and -** successors. The result of the function is stored in register P3. -** Register P3 must not be one of the function inputs. -** -** P1 is a 32-bit bitmask indicating whether or not each argument to the -** function was determined to be constant at compile time. If the first -** argument was constant then bit 0 of P1 is set. This is used to determine -** whether meta data associated with a user function argument using the -** sqlite3_set_auxdata() API may be safely retained until the next -** invocation of this opcode. -** -** See also: Function, AggStep, AggFinal -*/ -/* Opcode: Function P1 P2 P3 P4 P5 -** Synopsis: r[P3]=func(r[P2@P5]) -** -** Invoke a user function (P4 is a pointer to an sqlite3_context object that -** contains a pointer to the function to be run) with P5 arguments taken -** from register P2 and successors. The result of the function is stored -** in register P3. Register P3 must not be one of the function inputs. -** -** P1 is a 32-bit bitmask indicating whether or not each argument to the -** function was determined to be constant at compile time. If the first -** argument was constant then bit 0 of P1 is set. This is used to determine -** whether meta data associated with a user function argument using the -** sqlite3_set_auxdata() API may be safely retained until the next -** invocation of this opcode. -** -** SQL functions are initially coded as OP_Function0 with P4 pointing -** to a FuncDef object. But on first evaluation, the P4 operand is -** automatically converted into an sqlite3_context object and the operation -** changed to this OP_Function opcode. In this way, the initialization of -** the sqlite3_context object occurs only once, rather than once for each -** evaluation of the function. -** -** See also: Function0, AggStep, AggFinal -*/ -case OP_Function0: { - int n; - sqlite3_context *pCtx; - - assert( pOp->p4type==P4_FUNCDEF ); - n = pOp->p5; - assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); - assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); - assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n ); - pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); - if( pCtx==0 ) goto no_mem; - pCtx->pOut = 0; - pCtx->pFunc = pOp->p4.pFunc; - pCtx->iOp = (int)(pOp - aOp); - pCtx->pVdbe = p; - pCtx->argc = n; - pOp->p4type = P4_FUNCCTX; - pOp->p4.pCtx = pCtx; - pOp->opcode = OP_Function; - /* Fall through into OP_Function */ -} -case OP_Function: { - int i; - sqlite3_context *pCtx; - - assert( pOp->p4type==P4_FUNCCTX ); - pCtx = pOp->p4.pCtx; - - /* If this function is inside of a trigger, the register array in aMem[] - ** might change from one evaluation to the next. The next block of code - ** checks to see if the register array has changed, and if so it - ** reinitializes the relavant parts of the sqlite3_context object */ - pOut = &aMem[pOp->p3]; - if( pCtx->pOut != pOut ){ - pCtx->pOut = pOut; - for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; - } - - memAboutToChange(p, pOut); -#ifdef SQLITE_DEBUG - for(i=0; i<pCtx->argc; i++){ - assert( memIsValid(pCtx->argv[i]) ); - REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); - } -#endif - MemSetTypeFlag(pOut, MEM_Null); - pCtx->fErrorOrAux = 0; - (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */ - - /* If the function returned an error, throw an exception */ - if( pCtx->fErrorOrAux ){ - if( pCtx->isError ){ - sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut)); - rc = pCtx->isError; - } - sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1); - if( rc ) goto abort_due_to_error; - } - - /* Copy the result of the function into register P3 */ - if( pOut->flags & (MEM_Str|MEM_Blob) ){ - sqlite3VdbeChangeEncoding(pOut, encoding); - if( sqlite3VdbeMemTooBig(pOut) ) goto too_big; - } - - REGISTER_TRACE(pOp->p3, pOut); - UPDATE_MAX_BLOBSIZE(pOut); - break; -} - /* Opcode: BitAnd P1 P2 P3 * * ** Synopsis: r[P3]=r[P1]&r[P2] ** @@ -80354,13 +81113,23 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); } compare_op: - switch( pOp->opcode ){ - case OP_Eq: res2 = res==0; break; - case OP_Ne: res2 = res; break; - case OP_Lt: res2 = res<0; break; - case OP_Le: res2 = res<=0; break; - case OP_Gt: res2 = res>0; break; - default: res2 = res>=0; break; + /* At this point, res is negative, zero, or positive if reg[P1] is + ** less than, equal to, or greater than reg[P3], respectively. Compute + ** the answer to this operator in res2, depending on what the comparison + ** operator actually is. The next block of code depends on the fact + ** that the 6 comparison operators are consecutive integers in this + ** order: NE, EQ, GT, LE, LT, GE */ + assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 ); + assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 ); + if( res<0 ){ /* ne, eq, gt, le, lt, ge */ + static const unsigned char aLTb[] = { 1, 0, 0, 1, 1, 0 }; + res2 = aLTb[pOp->opcode - OP_Ne]; + }else if( res==0 ){ + static const unsigned char aEQb[] = { 0, 1, 0, 1, 0, 1 }; + res2 = aEQb[pOp->opcode - OP_Ne]; + }else{ + static const unsigned char aGTb[] = { 1, 0, 1, 0, 0, 1 }; + res2 = aGTb[pOp->opcode - OP_Ne]; } /* Undo any changes made by applyAffinity() to the input registers. */ @@ -80372,7 +81141,6 @@ compare_op: if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &aMem[pOp->p2]; iCompare = res; - res2 = res2!=0; /* For this path res2 must be exactly 0 or 1 */ if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){ /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1 ** and prevents OP_Ne from overwriting NULL with 0. This flag @@ -80503,7 +81271,7 @@ case OP_Compare: { assert( memIsValid(&aMem[p2+idx]) ); REGISTER_TRACE(p1+idx, &aMem[p1+idx]); REGISTER_TRACE(p2+idx, &aMem[p2+idx]); - assert( i<pKeyInfo->nField ); + assert( i<pKeyInfo->nKeyField ); pColl = pKeyInfo->aColl[i]; bRev = pKeyInfo->aSortOrder[i]; iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl); @@ -80776,16 +81544,16 @@ case OP_Column: { const u8 *zData; /* Part of the record being decoded */ const u8 *zHdr; /* Next unparsed byte of the header */ const u8 *zEndHdr; /* Pointer to first byte after the header */ - u32 offset; /* Offset into the data */ u64 offset64; /* 64-bit offset */ - u32 avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ Mem *pReg; /* PseudoTable input register */ pC = p->apCsr[pOp->p1]; p2 = pOp->p2; - /* If the cursor cache is stale, bring it up-to-date */ + /* If the cursor cache is stale (meaning it is not currently point at + ** the correct row) then bring it up-to-date by doing the necessary + ** B-Tree seek. */ rc = sqlite3VdbeCursorMoveto(&pC, &p2); if( rc ) goto abort_due_to_error; @@ -80803,11 +81571,13 @@ case OP_Column: { if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/ if( pC->nullRow ){ if( pC->eCurType==CURTYPE_PSEUDO ){ - assert( pC->uc.pseudoTableReg>0 ); - pReg = &aMem[pC->uc.pseudoTableReg]; + /* For the special case of as pseudo-cursor, the seekResult field + ** identifies the register that holds the record */ + assert( pC->seekResult>0 ); + pReg = &aMem[pC->seekResult]; assert( pReg->flags & MEM_Blob ); assert( memIsValid(pReg) ); - pC->payloadSize = pC->szRow = avail = pReg->n; + pC->payloadSize = pC->szRow = pReg->n; pC->aRow = (u8*)pReg->z; }else{ sqlite3VdbeMemSetNull(pDest); @@ -80819,23 +81589,19 @@ case OP_Column: { assert( pCrsr ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); pC->payloadSize = sqlite3BtreePayloadSize(pCrsr); - pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &avail); - assert( avail<=65536 ); /* Maximum page size is 64KiB */ - if( pC->payloadSize <= (u32)avail ){ - pC->szRow = pC->payloadSize; - }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ + pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow); + assert( pC->szRow<=pC->payloadSize ); + assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */ + if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; - }else{ - pC->szRow = avail; } } pC->cacheStatus = p->cacheCtr; - pC->iHdrOffset = getVarint32(pC->aRow, offset); + pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]); pC->nHdrParsed = 0; - aOffset[0] = offset; - if( avail<offset ){ /*OPTIMIZATION-IF-FALSE*/ + if( pC->szRow<aOffset[0] ){ /*OPTIMIZATION-IF-FALSE*/ /* pC->aRow does not have to hold the entire row, but it does at least ** need to cover the header of the record. If pC->aRow does not contain ** the complete header, then set it to zero, forcing the header to be @@ -80852,17 +81618,26 @@ case OP_Column: { ** 3-byte type for each of the maximum of 32768 columns plus three ** extra bytes for the header length itself. 32768*3 + 3 = 98307. */ - if( offset > 98307 || offset > pC->payloadSize ){ - rc = SQLITE_CORRUPT_BKPT; - goto abort_due_to_error; + if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){ + goto op_column_corrupt; } - }else if( offset>0 ){ /*OPTIMIZATION-IF-TRUE*/ - /* The following goto is an optimization. It can be omitted and - ** everything will still work. But OP_Column is measurably faster - ** by skipping the subsequent conditional, which is always true. + }else{ + /* This is an optimization. By skipping over the first few tests + ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a + ** measurable performance gain. + ** + ** This branch is taken even if aOffset[0]==0. Such a record is never + ** generated by SQLite, and could be considered corruption, but we + ** accept it for historical reasons. When aOffset[0]==0, the code this + ** branch jumps to reads past the end of the record, but never more + ** than a few bytes. Even if the record occurs at the end of the page + ** content area, the "page header" comes after the page content and so + ** this overread is harmless. Similar overreads can occur for a corrupt + ** database file. */ zData = pC->aRow; assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ + testcase( aOffset[0]==0 ); goto op_column_read_header; } } @@ -80891,6 +81666,7 @@ case OP_Column: { offset64 = aOffset[i]; zHdr = zData + pC->iHdrOffset; zEndHdr = zData + aOffset[0]; + testcase( zHdr>=zEndHdr ); do{ if( (t = zHdr[0])<0x80 ){ zHdr++; @@ -80911,9 +81687,13 @@ case OP_Column: { if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize)) || (offset64 > pC->payloadSize) ){ - if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); - rc = SQLITE_CORRUPT_BKPT; - goto abort_due_to_error; + if( aOffset[0]==0 ){ + i = 0; + zHdr = zEndHdr; + }else{ + if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); + goto op_column_corrupt; + } } pC->nHdrParsed = i; @@ -81007,6 +81787,15 @@ op_column_out: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); break; + +op_column_corrupt: + if( aOp[0].p3>0 ){ + pOp = &aOp[aOp[0].p3-1]; + break; + }else{ + rc = SQLITE_CORRUPT_BKPT; + goto abort_due_to_error; + } } /* Opcode: Affinity P1 P2 * P4 * @@ -81347,7 +82136,7 @@ case OP_Savepoint: { int isSchemaChange; iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ - isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; + isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0; for(ii=0; ii<db->nDb; ii++){ rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT_ROLLBACK, @@ -81366,7 +82155,7 @@ case OP_Savepoint: { if( isSchemaChange ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); - db->flags = (db->flags | SQLITE_InternChanges); + db->mDbFlags |= DBFLAG_SchemaChange; } } @@ -81646,7 +82435,7 @@ case OP_SetCookie: { if( pOp->p2==BTREE_SCHEMA_VERSION ){ /* When the schema cookie changes, record the new cookie internally */ pDb->pSchema->schema_cookie = pOp->p3; - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ pDb->pSchema->file_format = pOp->p3; @@ -81785,7 +82574,7 @@ case OP_OpenWrite: assert( (pIn2->flags & MEM_Int)!=0 ); sqlite3VdbeMemIntegerify(pIn2); p2 = (int)pIn2->u.i; - /* The p2 value always comes from a prior OP_CreateTable opcode and + /* The p2 value always comes from a prior OP_CreateBtree opcode and ** that opcode will always set the p2 value to 2 or more or else fail. ** If there were a failure, the prepared statement would have halted ** before reaching this instruction. */ @@ -81795,7 +82584,7 @@ case OP_OpenWrite: pKeyInfo = pOp->p4.pKeyInfo; assert( pKeyInfo->enc==ENC(db) ); assert( pKeyInfo->db==db ); - nField = pKeyInfo->nField+pKeyInfo->nXField; + nField = pKeyInfo->nAllField; }else if( pOp->p4type==P4_INT32 ){ nField = pOp->p4.i; } @@ -82006,8 +82795,13 @@ case OP_OpenPseudo: { pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; - pCx->uc.pseudoTableReg = pOp->p2; + pCx->seekResult = pOp->p2; pCx->isTable = 1; + /* Give this pseudo-cursor a fake BtCursor pointer so that pCx + ** can be safely passed to sqlite3VdbeCursorMoveto(). This avoids a test + ** for pCx->eCurType==CURTYPE_BTREE inside of sqlite3VdbeCursorMoveto() + ** which is a performance optimization */ + pCx->uc.pCursor = sqlite3BtreeFakeValidCursor(); assert( pOp->p5==0 ); break; } @@ -82267,8 +83061,15 @@ case OP_SeekGT: { /* jump, in3 */ if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT ); if( res<0 || (res==0 && oc==OP_SeekGT) ){ res = 0; - rc = sqlite3BtreeNext(pC->uc.pCursor, &res); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + rc = sqlite3BtreeNext(pC->uc.pCursor, 0); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + res = 1; + }else{ + goto abort_due_to_error; + } + } }else{ res = 0; } @@ -82276,8 +83077,15 @@ case OP_SeekGT: { /* jump, in3 */ assert( oc==OP_SeekLT || oc==OP_SeekLE ); if( res>0 || (res==0 && oc==OP_SeekLT) ){ res = 0; - rc = sqlite3BtreePrevious(pC->uc.pCursor, &res); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + rc = sqlite3BtreePrevious(pC->uc.pCursor, 0); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + res = 1; + }else{ + goto abort_due_to_error; + } + } }else{ /* res might be negative because the table is empty. Check to ** see if this is the case. @@ -82785,14 +83593,9 @@ case OP_InsertInt: { if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey; - if( pData->flags & MEM_Null ){ - x.pData = 0; - x.nData = 0; - }else{ - assert( pData->flags & (MEM_Blob|MEM_Str) ); - x.pData = pData->z; - x.nData = pData->n; - } + assert( pData->flags & (MEM_Blob|MEM_Str) ); + x.pData = pData->z; + x.nData = pData->n; seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); if( pData->flags & MEM_Zero ){ x.nZero = pData->u.nZero; @@ -83159,7 +83962,17 @@ case OP_NullRow: { break; } -/* Opcode: Last P1 P2 P3 * * +/* Opcode: SeekEnd P1 * * * * +** +** Position cursor P1 at the end of the btree for the purpose of +** appending a new entry onto the btree. +** +** It is assumed that the cursor is used only for appending and so +** if the cursor is valid, then the cursor must already be pointing +** at the end of the btree and so no changes are made to +** the cursor. +*/ +/* Opcode: Last P1 P2 * * * ** ** The next use of the Rowid or Column or Prev instruction for P1 ** will refer to the last entry in the database table or index. @@ -83170,14 +83983,8 @@ case OP_NullRow: { ** This opcode leaves the cursor configured to move in reverse order, ** from the end toward the beginning. In other words, the cursor is ** configured to use Prev, not Next. -** -** If P3 is -1, then the cursor is positioned at the end of the btree -** for the purpose of appending a new entry onto the btree. In that -** case P2 must be 0. It is assumed that the cursor is used only for -** appending and so if the cursor is valid, then the cursor must already -** be pointing at the end of the btree and so no changes are made to -** the cursor. */ +case OP_SeekEnd: case OP_Last: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; @@ -83190,22 +83997,24 @@ case OP_Last: { /* jump */ pCrsr = pC->uc.pCursor; res = 0; assert( pCrsr!=0 ); - pC->seekResult = pOp->p3; #ifdef SQLITE_DEBUG - pC->seekOp = OP_Last; + pC->seekOp = pOp->opcode; #endif - if( pOp->p3==0 || !sqlite3BtreeCursorIsValidNN(pCrsr) ){ - rc = sqlite3BtreeLast(pCrsr, &res); - pC->nullRow = (u8)res; - pC->deferredMoveto = 0; - pC->cacheStatus = CACHE_STALE; - if( rc ) goto abort_due_to_error; - if( pOp->p2>0 ){ - VdbeBranchTaken(res!=0,2); - if( res ) goto jump_to_p2; - } - }else{ + if( pOp->opcode==OP_SeekEnd ){ assert( pOp->p2==0 ); + pC->seekResult = -1; + if( sqlite3BtreeCursorIsValidNN(pCrsr) ){ + break; + } + } + rc = sqlite3BtreeLast(pCrsr, &res); + pC->nullRow = (u8)res; + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; + if( rc ) goto abort_due_to_error; + if( pOp->p2>0 ){ + VdbeBranchTaken(res!=0,2); + if( res ) goto jump_to_p2; } break; } @@ -83383,12 +84192,10 @@ case OP_Rewind: { /* jump */ */ case OP_SorterNext: { /* jump */ VdbeCursor *pC; - int res; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); - res = 0; - rc = sqlite3VdbeSorterNext(db, pC, &res); + rc = sqlite3VdbeSorterNext(db, pC); goto next_tail; case OP_PrevIfOpen: /* jump */ case OP_NextIfOpen: /* jump */ @@ -83399,12 +84206,9 @@ case OP_Next: /* jump */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p5<ArraySize(p->aCounter) ); pC = p->apCsr[pOp->p1]; - res = pOp->p3; assert( pC!=0 ); assert( pC->deferredMoveto==0 ); assert( pC->eCurType==CURTYPE_BTREE ); - assert( res==0 || (res==1 && pC->isTable==0) ); - testcase( res==1 ); assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext ); @@ -83419,21 +84223,21 @@ case OP_Next: /* jump */ || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE || pC->seekOp==OP_Last ); - rc = pOp->p4.xAdvance(pC->uc.pCursor, &res); + rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3); next_tail: pC->cacheStatus = CACHE_STALE; - VdbeBranchTaken(res==0,2); - if( rc ) goto abort_due_to_error; - if( res==0 ){ + VdbeBranchTaken(rc==SQLITE_OK,2); + if( rc==SQLITE_OK ){ pC->nullRow = 0; p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST sqlite3_search_count++; #endif goto jump_to_p2_and_check_for_interrupt; - }else{ - pC->nullRow = 1; } + if( rc!=SQLITE_DONE ) goto abort_due_to_error; + rc = SQLITE_OK; + pC->nullRow = 1; goto check_for_interrupt; } @@ -83544,8 +84348,8 @@ case OP_IdxDelete: { break; } -/* Opcode: Seek P1 * P3 P4 * -** Synopsis: Move P3 to P1.rowid +/* Opcode: DeferredSeek P1 * P3 P4 * +** Synopsis: Move P3 to P1.rowid if needed ** ** P1 is an open index cursor and P3 is a cursor on the corresponding ** table. This opcode does a deferred seek of the P3 table cursor @@ -83572,11 +84376,11 @@ case OP_IdxDelete: { ** ** See also: Rowid, MakeRecord. */ -case OP_Seek: -case OP_IdxRowid: { /* out2 */ - VdbeCursor *pC; /* The P1 index cursor */ - VdbeCursor *pTabCur; /* The P2 table cursor (OP_Seek only) */ - i64 rowid; /* Rowid that P1 current points to */ +case OP_DeferredSeek: +case OP_IdxRowid: { /* out2 */ + VdbeCursor *pC; /* The P1 index cursor */ + VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */ + i64 rowid; /* Rowid that P1 current points to */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; @@ -83602,7 +84406,7 @@ case OP_IdxRowid: { /* out2 */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - if( pOp->opcode==OP_Seek ){ + if( pOp->opcode==OP_DeferredSeek ){ assert( pOp->p3>=0 && pOp->p3<p->nCursor ); pTabCur = p->apCsr[pOp->p3]; assert( pTabCur!=0 ); @@ -83839,50 +84643,28 @@ case OP_ResetSorter: { break; } -/* Opcode: CreateTable P1 P2 * * * -** Synopsis: r[P2]=root iDb=P1 -** -** Allocate a new table in the main database file if P1==0 or in the -** auxiliary database file if P1==1 or in an attached database if -** P1>1. Write the root page number of the new table into -** register P2 -** -** The difference between a table and an index is this: A table must -** have a 4-byte integer key and can have arbitrary data. An index -** has an arbitrary key but no data. -** -** See also: CreateIndex -*/ -/* Opcode: CreateIndex P1 P2 * * * -** Synopsis: r[P2]=root iDb=P1 -** -** Allocate a new index in the main database file if P1==0 or in the -** auxiliary database file if P1==1 or in an attached database if -** P1>1. Write the root page number of the new table into -** register P2. +/* Opcode: CreateBtree P1 P2 P3 * * +** Synopsis: r[P2]=root iDb=P1 flags=P3 ** -** See documentation on OP_CreateTable for additional information. +** Allocate a new b-tree in the main database file if P1==0 or in the +** TEMP database file if P1==1 or in an attached database if +** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table +** it must be 2 (BTREE_BLOBKEY) for a index or WITHOUT ROWID table. +** The root page number of the new b-tree is stored in register P2. */ -case OP_CreateIndex: /* out2 */ -case OP_CreateTable: { /* out2 */ +case OP_CreateBtree: { /* out2 */ int pgno; - int flags; Db *pDb; pOut = out2Prerelease(p, pOp); pgno = 0; + assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY ); assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); - if( pOp->opcode==OP_CreateTable ){ - /* flags = BTREE_INTKEY; */ - flags = BTREE_INTKEY; - }else{ - flags = BTREE_BLOBKEY; - } - rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags); + rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, pOp->p3); if( rc ) goto abort_due_to_error; pOut->u.i = pgno; break; @@ -84044,7 +84826,7 @@ case OP_IntegrityCk: { nRoot = pOp->p2; aRoot = pOp->p4.ai; assert( nRoot>0 ); - assert( aRoot[nRoot]==0 ); + assert( aRoot[0]==nRoot ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pnErr = &aMem[pOp->p3]; assert( (pnErr->flags & MEM_Int)!=0 ); @@ -84052,7 +84834,7 @@ case OP_IntegrityCk: { pIn1 = &aMem[pOp->p1]; assert( pOp->p5<db->nDb ); assert( DbMaskTest(p->btreeMask, pOp->p5) ); - z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot, + z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, &aRoot[1], nRoot, (int)pnErr->u.i+1, &nErr); sqlite3VdbeMemSetNull(pIn1); if( nErr==0 ){ @@ -84848,7 +85630,7 @@ case OP_Expire: { */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; - if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){ + if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){ int p1 = pOp->p1; assert( p1>=0 && p1<db->nDb ); assert( DbMaskTest(p->btreeMask, p1) ); @@ -85277,8 +86059,123 @@ case OP_MaxPgcnt: { /* out2 */ } #endif +/* Opcode: Function0 P1 P2 P3 P4 P5 +** Synopsis: r[P3]=func(r[P2@P5]) +** +** Invoke a user function (P4 is a pointer to a FuncDef object that +** defines the function) with P5 arguments taken from register P2 and +** successors. The result of the function is stored in register P3. +** Register P3 must not be one of the function inputs. +** +** P1 is a 32-bit bitmask indicating whether or not each argument to the +** function was determined to be constant at compile time. If the first +** argument was constant then bit 0 of P1 is set. This is used to determine +** whether meta data associated with a user function argument using the +** sqlite3_set_auxdata() API may be safely retained until the next +** invocation of this opcode. +** +** See also: Function, AggStep, AggFinal +*/ +/* Opcode: Function P1 P2 P3 P4 P5 +** Synopsis: r[P3]=func(r[P2@P5]) +** +** Invoke a user function (P4 is a pointer to an sqlite3_context object that +** contains a pointer to the function to be run) with P5 arguments taken +** from register P2 and successors. The result of the function is stored +** in register P3. Register P3 must not be one of the function inputs. +** +** P1 is a 32-bit bitmask indicating whether or not each argument to the +** function was determined to be constant at compile time. If the first +** argument was constant then bit 0 of P1 is set. This is used to determine +** whether meta data associated with a user function argument using the +** sqlite3_set_auxdata() API may be safely retained until the next +** invocation of this opcode. +** +** SQL functions are initially coded as OP_Function0 with P4 pointing +** to a FuncDef object. But on first evaluation, the P4 operand is +** automatically converted into an sqlite3_context object and the operation +** changed to this OP_Function opcode. In this way, the initialization of +** the sqlite3_context object occurs only once, rather than once for each +** evaluation of the function. +** +** See also: Function0, AggStep, AggFinal +*/ +case OP_PureFunc0: +case OP_Function0: { + int n; + sqlite3_context *pCtx; + + assert( pOp->p4type==P4_FUNCDEF ); + n = pOp->p5; + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); + assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n ); + pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); + if( pCtx==0 ) goto no_mem; + pCtx->pOut = 0; + pCtx->pFunc = pOp->p4.pFunc; + pCtx->iOp = (int)(pOp - aOp); + pCtx->pVdbe = p; + pCtx->argc = n; + pOp->p4type = P4_FUNCCTX; + pOp->p4.pCtx = pCtx; + assert( OP_PureFunc == OP_PureFunc0+2 ); + assert( OP_Function == OP_Function0+2 ); + pOp->opcode += 2; + /* Fall through into OP_Function */ +} +case OP_PureFunc: +case OP_Function: { + int i; + sqlite3_context *pCtx; + + assert( pOp->p4type==P4_FUNCCTX ); + pCtx = pOp->p4.pCtx; + + /* If this function is inside of a trigger, the register array in aMem[] + ** might change from one evaluation to the next. The next block of code + ** checks to see if the register array has changed, and if so it + ** reinitializes the relavant parts of the sqlite3_context object */ + pOut = &aMem[pOp->p3]; + if( pCtx->pOut != pOut ){ + pCtx->pOut = pOut; + for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; + } + + memAboutToChange(p, pOut); +#ifdef SQLITE_DEBUG + for(i=0; i<pCtx->argc; i++){ + assert( memIsValid(pCtx->argv[i]) ); + REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); + } +#endif + MemSetTypeFlag(pOut, MEM_Null); + pCtx->fErrorOrAux = 0; + (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */ + + /* If the function returned an error, throw an exception */ + if( pCtx->fErrorOrAux ){ + if( pCtx->isError ){ + sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut)); + rc = pCtx->isError; + } + sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1); + if( rc ) goto abort_due_to_error; + } -/* Opcode: Init P1 P2 * P4 * + /* Copy the result of the function into register P3 */ + if( pOut->flags & (MEM_Str|MEM_Blob) ){ + sqlite3VdbeChangeEncoding(pOut, encoding); + if( sqlite3VdbeMemTooBig(pOut) ) goto too_big; + } + + REGISTER_TRACE(pOp->p3, pOut); + UPDATE_MAX_BLOBSIZE(pOut); + break; +} + + +/* Opcode: Init P1 P2 P3 P4 * ** Synopsis: Start at P2 ** ** Programs contain a single instance of this opcode as the very first @@ -85292,6 +86189,9 @@ case OP_MaxPgcnt: { /* out2 */ ** ** Increment the value of P1 so that OP_Once opcodes will jump the ** first time they are evaluated for this run. +** +** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT +** error is encountered. */ case OP_Init: { /* jump */ char *zTrace; @@ -85356,6 +86256,7 @@ case OP_Init: { /* jump */ pOp->p1 = 0; } pOp->p1++; + p->aCounter[SQLITE_STMTSTATUS_RUN]++; goto jump_to_p2; } @@ -85565,11 +86466,12 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ v->aMem[1].u.i = iRow; /* If the statement has been run before (and is paused at the OP_ResultRow) - ** then back it up to the point where it does the OP_SeekRowid. This could + ** then back it up to the point where it does the OP_NotExists. This could ** have been down with an extra OP_Goto, but simply setting the program ** counter is faster. */ - if( v->pc>3 ){ - v->pc = 3; + if( v->pc>4 ){ + v->pc = 4; + assert( v->aOp[v->pc].opcode==OP_NotExists ); rc = sqlite3VdbeExec(v); }else{ rc = sqlite3_step(p->pStmt); @@ -85631,8 +86533,8 @@ SQLITE_API int sqlite3_blob_open( int rc = SQLITE_OK; char *zErr = 0; Table *pTab; - Parse *pParse = 0; Incrblob *pBlob = 0; + Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR if( ppBlob==0 ){ @@ -85650,37 +86552,34 @@ SQLITE_API int sqlite3_blob_open( sqlite3_mutex_enter(db->mutex); pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob)); - if( !pBlob ) goto blob_open_out; - pParse = sqlite3StackAllocRaw(db, sizeof(*pParse)); - if( !pParse ) goto blob_open_out; - do { - memset(pParse, 0, sizeof(Parse)); - pParse->db = db; + memset(&sParse, 0, sizeof(Parse)); + if( !pBlob ) goto blob_open_out; + sParse.db = db; sqlite3DbFree(db, zErr); zErr = 0; sqlite3BtreeEnterAll(db); - pTab = sqlite3LocateTable(pParse, 0, zTable, zDb); + pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb); if( pTab && IsVirtual(pTab) ){ pTab = 0; - sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable); + sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable); } if( pTab && !HasRowid(pTab) ){ pTab = 0; - sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable); + sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable); } #ifndef SQLITE_OMIT_VIEW if( pTab && pTab->pSelect ){ pTab = 0; - sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable); + sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable); } #endif if( !pTab ){ - if( pParse->zErrMsg ){ + if( sParse.zErrMsg ){ sqlite3DbFree(db, zErr); - zErr = pParse->zErrMsg; - pParse->zErrMsg = 0; + zErr = sParse.zErrMsg; + sParse.zErrMsg = 0; } rc = SQLITE_ERROR; sqlite3BtreeLeaveAll(db); @@ -85744,7 +86643,7 @@ SQLITE_API int sqlite3_blob_open( } } - pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse); + pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse); assert( pBlob->pStmt || db->mallocFailed ); if( pBlob->pStmt ){ @@ -85780,7 +86679,8 @@ SQLITE_API int sqlite3_blob_open( sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, pTab->pSchema->schema_cookie, pTab->pSchema->iGeneration); - sqlite3VdbeChangeP5(v, 1); + sqlite3VdbeChangeP5(v, 1); + assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed ); aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn); /* Make sure a mutex is held on the table to be accessed */ @@ -85795,7 +86695,7 @@ SQLITE_API int sqlite3_blob_open( aOp[0].p1 = iDb; aOp[0].p2 = pTab->tnum; aOp[0].p3 = wrFlag; - sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT); + sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT); } if( db->mallocFailed==0 ){ #endif @@ -85817,10 +86717,10 @@ SQLITE_API int sqlite3_blob_open( aOp[1].p4.i = pTab->nCol+1; aOp[3].p2 = pTab->nCol; - pParse->nVar = 0; - pParse->nMem = 1; - pParse->nTab = 1; - sqlite3VdbeMakeReady(v, pParse); + sParse.nVar = 0; + sParse.nMem = 1; + sParse.nTab = 1; + sqlite3VdbeMakeReady(v, &sParse); } } @@ -85842,8 +86742,7 @@ blob_open_out: } sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); - sqlite3ParserReset(pParse); - sqlite3StackFree(db, pParse); + sqlite3ParserReset(&sParse); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; @@ -86829,15 +87728,15 @@ static int vdbeSorterCompareText( int n2; int res; - getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2; - getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2; - res = memcmp(v1, v2, MIN(n1, n2)); + getVarint32(&p1[1], n1); + getVarint32(&p2[1], n2); + res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2); if( res==0 ){ res = n1 - n2; } if( res==0 ){ - if( pTask->pSorter->pKeyInfo->nField>1 ){ + if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); @@ -86906,7 +87805,7 @@ static int vdbeSorterCompareInt( } if( res==0 ){ - if( pTask->pSorter->pKeyInfo->nField>1 ){ + if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); @@ -86921,7 +87820,7 @@ static int vdbeSorterCompareInt( /* ** Initialize the temporary index cursor just opened as a sorter cursor. ** -** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField) +** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField) ** to determine the number of fields that should be compared from the ** records being sorted. However, if the value passed as argument nField ** is non-zero and the sorter is able to guarantee a stable sort, nField @@ -86974,7 +87873,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( assert( pCsr->pKeyInfo && pCsr->pBtx==0 ); assert( pCsr->eCurType==CURTYPE_SORTER ); - szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*); + szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*); sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); @@ -86986,8 +87885,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); pKeyInfo->db = 0; if( nField && nWorker==0 ){ - pKeyInfo->nXField += (pKeyInfo->nField - nField); - pKeyInfo->nField = nField; + pKeyInfo->nKeyField = nField; } pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); pSorter->nTask = nWorker + 1; @@ -87015,11 +87913,9 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( mxCache = MIN(mxCache, SQLITE_MAX_PMASZ); pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache); - /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of - ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary - ** large heap allocations. - */ - if( sqlite3GlobalConfig.pScratch==0 ){ + /* Avoid large memory allocations if the application has requested + ** SQLITE_CONFIG_SMALL_MALLOC. */ + if( sqlite3GlobalConfig.bSmallMalloc==0 ){ assert( pSorter->iMemory==0 ); pSorter->nMemory = pgsz; pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); @@ -87027,7 +87923,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( } } - if( (pKeyInfo->nField+pKeyInfo->nXField)<13 + if( pKeyInfo->nAllField<13 && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) ){ pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; @@ -87342,7 +88238,7 @@ static int vdbeSortAllocUnpacked(SortSubtask *pTask){ if( pTask->pUnpacked==0 ){ pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo); if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT; - pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField; + pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField; pTask->pUnpacked->errCode = 0; } return SQLITE_OK; @@ -88626,9 +89522,13 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ } /* -** Advance to the next element in the sorter. +** Advance to the next element in the sorter. Return value: +** +** SQLITE_OK success +** SQLITE_DONE end of data +** otherwise some kind of error. */ -SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ +SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){ VdbeSorter *pSorter; int rc; /* Return code */ @@ -88642,21 +89542,22 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, in #if SQLITE_MAX_WORKER_THREADS>0 if( pSorter->bUseThreads ){ rc = vdbePmaReaderNext(pSorter->pReader); - *pbEof = (pSorter->pReader->pFd==0); + if( rc==SQLITE_OK && pSorter->pReader->pFd==0 ) rc = SQLITE_DONE; }else #endif /*if( !pSorter->bUseThreads )*/ { + int res = 0; assert( pSorter->pMerger!=0 ); assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) ); - rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof); + rc = vdbeMergeEngineStep(pSorter->pMerger, &res); + if( rc==SQLITE_OK && res ) rc = SQLITE_DONE; } }else{ SorterRecord *pFree = pSorter->list.pList; pSorter->list.pList = pFree->u.pNext; pFree->u.pNext = 0; if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree); - *pbEof = !pSorter->list.pList; - rc = SQLITE_OK; + rc = pSorter->list.pList ? SQLITE_OK : SQLITE_DONE; } return rc; } @@ -88861,7 +89762,8 @@ static int memjrnlRead( int iChunkOffset; FileChunk *pChunk; -#ifdef SQLITE_ENABLE_ATOMIC_WRITE +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) if( (iAmt+iOfst)>p->endpoint.iOffset ){ return SQLITE_IOERR_SHORT_READ; } @@ -88980,7 +89882,8 @@ static int memjrnlWrite( ** atomic-write optimization. In this case the first 28 bytes of the ** journal file may be written as part of committing the transaction. */ assert( iOfst==p->endpoint.iOffset || iOfst==0 ); -#ifdef SQLITE_ENABLE_ATOMIC_WRITE +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) if( iOfst==0 && p->pFirst ){ assert( p->nChunkSize>iAmt ); memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt); @@ -89149,17 +90052,31 @@ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){ sqlite3JournalOpen(0, 0, pJfd, 0, -1); } -#ifdef SQLITE_ENABLE_ATOMIC_WRITE +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) /* ** If the argument p points to a MemJournal structure that is not an ** in-memory-only journal file (i.e. is one that was opened with a +ve -** nSpill parameter), and the underlying file has not yet been created, -** create it now. +** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying +** file has not yet been created, create it now. */ -SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){ +SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){ int rc = SQLITE_OK; - if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){ - rc = memjrnlCreateFile((MemJournal*)p); + MemJournal *p = (MemJournal*)pJfd; + if( p->pMethod==&MemJournalMethods && ( +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + p->nSpill>0 +#else + /* While this appears to not be possible without ATOMIC_WRITE, the + ** paths are complex, so it seems prudent to leave the test in as + ** a NEVER(), in case our analysis is subtly flawed. */ + NEVER(p->nSpill>0) +#endif +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + || (p->flags & SQLITE_OPEN_MAIN_JOURNAL) +#endif + )){ + rc = memjrnlCreateFile(p); } return rc; } @@ -89226,16 +90143,22 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ int rc; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); - rc = pWalker->xExprCallback(pWalker, pExpr); - if( rc || ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ - return rc & WRC_Abort; - } - if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; - if( pExpr->pRight && walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; - }else if( pExpr->x.pList ){ - if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; + while(1){ + rc = pWalker->xExprCallback(pWalker, pExpr); + if( rc ) return rc & WRC_Abort; + if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ + if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; + assert( pExpr->x.pList==0 || pExpr->pRight==0 ); + if( pExpr->pRight ){ + pExpr = pExpr->pRight; + continue; + }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; + }else if( pExpr->x.pList ){ + if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; + } + } + break; } return WRC_Continue; } @@ -89290,7 +90213,7 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ pSrc = p->pSrc; if( ALWAYS(pSrc) ){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ - if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){ + if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){ return WRC_Abort; } if( pItem->fg.isTabFunc @@ -89310,8 +90233,9 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ ** ** If it is not NULL, the xSelectCallback() callback is invoked before ** the walk of the expressions and FROM clause. The xSelectCallback2() -** method, if it is not NULL, is invoked following the walk of the -** expressions and FROM clause. +** method is invoked following the walk of the expressions and FROM clause, +** but only if both xSelectCallback and xSelectCallback2 are both non-NULL +** and if the expressions and FROM clause both return WRC_Continue; ** ** Return WRC_Continue under normal conditions. Return WRC_Abort if ** there is an abort request. @@ -89321,29 +90245,22 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ */ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){ int rc; - if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){ - return WRC_Continue; - } - rc = WRC_Continue; - pWalker->walkerDepth++; - while( p ){ - if( pWalker->xSelectCallback ){ - rc = pWalker->xSelectCallback(pWalker, p); - if( rc ) break; - } + if( p==0 ) return WRC_Continue; + if( pWalker->xSelectCallback==0 ) return WRC_Continue; + do{ + rc = pWalker->xSelectCallback(pWalker, p); + if( rc ) return rc & WRC_Abort; if( sqlite3WalkSelectExpr(pWalker, p) || sqlite3WalkSelectFrom(pWalker, p) ){ - pWalker->walkerDepth--; return WRC_Abort; } if( pWalker->xSelectCallback2 ){ pWalker->xSelectCallback2(pWalker, p); } p = p->pPrior; - } - pWalker->walkerDepth--; - return rc & WRC_Abort; + }while( p!=0 ); + return WRC_Continue; } /************** End of walker.c **********************************************/ @@ -89828,6 +90745,7 @@ static int lookupName( sqlite3ExprDelete(db, pExpr->pRight); pExpr->pRight = 0; pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); + ExprSetProperty(pExpr, EP_Leaf); lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); @@ -89866,7 +90784,6 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr testcase( iCol==BMS-1 ); pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); } - ExprSetProperty(p, EP_Resolved); } return p; } @@ -89926,8 +90843,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pParse = pNC->pParse; assert( pParse==pWalker->pParse ); - if( ExprHasProperty(pExpr, EP_Resolved) ) return WRC_Prune; - ExprSetProperty(pExpr, EP_Resolved); #ifndef NDEBUG if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){ SrcList *pSrcList = pNC->pSrcList; @@ -90260,7 +91175,7 @@ static int resolveOrderByTermToExprList( ** result-set entry. */ for(i=0; i<pEList->nExpr; i++){ - if( sqlite3ExprCompare(pEList->a[i].pExpr, pE, -1)<2 ){ + if( sqlite3ExprCompare(0, pEList->a[i].pExpr, pE, -1)<2 ){ return i+1; } } @@ -90311,12 +91226,10 @@ static int resolveCompoundOrderBy( pOrderBy = pSelect->pOrderBy; if( pOrderBy==0 ) return 0; db = pParse->db; -#if SQLITE_MAX_COLUMN if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause"); return 1; } -#endif for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; } @@ -90408,12 +91321,10 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy( struct ExprList_item *pItem; if( pOrderBy==0 || pParse->db->mallocFailed ) return 0; -#if SQLITE_MAX_COLUMN if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType); return 1; } -#endif pEList = pSelect->pEList; assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */ for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){ @@ -90494,7 +91405,7 @@ static int resolveOrderGroupBy( return 1; } for(j=0; j<pSelect->pEList->nExpr; j++){ - if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ + if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ pItem->u.x.iOrderByCol = j+1; } } @@ -90780,37 +91691,29 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( u16 savedHasAgg; Walker w; - if( pExpr==0 ) return 0; -#if SQLITE_MAX_EXPR_DEPTH>0 - { - Parse *pParse = pNC->pParse; - if( sqlite3ExprCheckHeight(pParse, pExpr->nHeight+pNC->pParse->nHeight) ){ - return 1; - } - pParse->nHeight += pExpr->nHeight; - } -#endif + if( pExpr==0 ) return SQLITE_OK; savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg); w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; w.xSelectCallback2 = 0; - w.walkerDepth = 0; - w.eCode = 0; w.u.pNC = pNC; +#if SQLITE_MAX_EXPR_DEPTH>0 + w.pParse->nHeight += pExpr->nHeight; + if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ + return SQLITE_ERROR; + } +#endif sqlite3WalkExpr(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 - pNC->pParse->nHeight -= pExpr->nHeight; + w.pParse->nHeight -= pExpr->nHeight; #endif - if( pNC->nErr>0 || w.pParse->nErr>0 ){ - ExprSetProperty(pExpr, EP_Error); - } if( pNC->ncFlags & NC_HasAgg ){ ExprSetProperty(pExpr, EP_Agg); } pNC->ncFlags |= savedHasAgg; - return ExprHasProperty(pExpr, EP_Error); + return pNC->nErr>0 || w.pParse->nErr>0; } /* @@ -90851,9 +91754,9 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames( Walker w; assert( p!=0 ); - memset(&w, 0, sizeof(w)); w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; + w.xSelectCallback2 = 0; w.pParse = pParse; w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); @@ -91022,6 +91925,11 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){ ** Return the collation sequence for the expression pExpr. If ** there is no defined collating sequence, return NULL. ** +** See also: sqlite3ExprNNCollSeq() +** +** The sqlite3ExprNNCollSeq() works the same exact that it returns the +** default collation if pExpr has no defined collation. +** ** The collating sequence might be determined by a COLLATE operator ** or by the presence of a column with a defined collating sequence. ** COLLATE operators take first precedence. Left operands take @@ -91087,6 +91995,32 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ } /* +** Return the collation sequence for the expression pExpr. If +** there is no defined collating sequence, return a pointer to the +** defautl collation sequence. +** +** See also: sqlite3ExprCollSeq() +** +** The sqlite3ExprCollSeq() routine works the same except that it +** returns NULL if there is no defined collation. +*/ +SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){ + CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr); + if( p==0 ) p = pParse->db->pDfltColl; + assert( p!=0 ); + return p; +} + +/* +** Return TRUE if the two expressions have equivalent collating sequences. +*/ +SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){ + CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1); + CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2); + return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0; +} + +/* ** pExpr is an operand of a comparison operator. aff2 is the ** type affinity of the other operand. This routine returns the ** type affinity that should be used for the comparison operator. @@ -91642,7 +92576,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( pNew->iAgg = -1; if( pToken ){ if( nExtra==0 ){ - pNew->flags |= EP_IntValue; + pNew->flags |= EP_IntValue|EP_Leaf; pNew->u.iValue = iValue; }else{ pNew->u.zToken = (char*)&pNew[1]; @@ -91673,7 +92607,7 @@ SQLITE_PRIVATE Expr *sqlite3Expr( ){ Token x; x.z = zToken; - x.n = zToken ? sqlite3Strlen30(zToken) : 0; + x.n = sqlite3Strlen30(zToken); return sqlite3ExprAlloc(db, op, &x, 0); } @@ -91923,8 +92857,9 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ /* The Expr.x union is never used at the same time as Expr.pRight */ assert( p->x.pList==0 || p->pRight==0 ); if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); - sqlite3ExprDelete(db, p->pRight); - if( ExprHasProperty(p, EP_xIsSelect) ){ + if( p->pRight ){ + sqlite3ExprDeleteNN(db, p->pRight); + }else if( ExprHasProperty(p, EP_xIsSelect) ){ sqlite3SelectDelete(db, p->x.pSelect); }else{ sqlite3ExprListDelete(db, p->x.pList); @@ -92199,10 +93134,9 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags) Expr *pPriorSelectCol = 0; assert( db!=0 ); if( p==0 ) return 0; - pNew = sqlite3DbMallocRawNN(db, - sizeof(*pNew)+sizeof(pNew->a[0])*(p->nExpr-1) ); + pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p)); if( pNew==0 ) return 0; - pNew->nAlloc = pNew->nExpr = p->nExpr; + pNew->nExpr = p->nExpr; pItem = pNew->a; pOldItem = p->a; for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){ @@ -92356,6 +93290,13 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ ** Add a new element to the end of an expression list. If pList is ** initially NULL, then create a new expression list. ** +** The pList argument must be either NULL or a pointer to an ExprList +** obtained from a prior call to sqlite3ExprListAppend(). This routine +** may not be used with an ExprList obtained from sqlite3ExprListDup(). +** Reason: This routine assumes that the number of slots in pList->a[] +** is a power of two. That is true for sqlite3ExprListAppend() returns +** but is not necessarily true from the return value of sqlite3ExprListDup(). +** ** If a memory allocation error occurs, the entire list is freed and ** NULL is returned. If non-NULL is returned, then it is guaranteed ** that the new entry was successfully appended. @@ -92374,19 +93315,19 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend( goto no_mem; } pList->nExpr = 0; - pList->nAlloc = 1; - }else if( pList->nExpr==pList->nAlloc ){ + }else if( (pList->nExpr & (pList->nExpr-1))==0 ){ ExprList *pNew; pNew = sqlite3DbRealloc(db, pList, - sizeof(*pList)+(2*pList->nAlloc - 1)*sizeof(pList->a[0])); + sizeof(*pList)+(2*pList->nExpr - 1)*sizeof(pList->a[0])); if( pNew==0 ){ goto no_mem; } pList = pNew; - pList->nAlloc *= 2; } pItem = &pList->a[pList->nExpr++]; - memset(pItem, 0, sizeof(*pItem)); + assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) ); + assert( offsetof(struct ExprList_item,pExpr)==0 ); + memset(&pItem->zName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zName)); pItem->pExpr = pExpr; return pList; @@ -92572,17 +93513,29 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){ int i; u32 m = 0; - if( pList ){ - for(i=0; i<pList->nExpr; i++){ - Expr *pExpr = pList->a[i].pExpr; - assert( pExpr!=0 ); - m |= pExpr->flags; - } + assert( pList!=0 ); + for(i=0; i<pList->nExpr; i++){ + Expr *pExpr = pList->a[i].pExpr; + assert( pExpr!=0 ); + m |= pExpr->flags; } return m; } /* +** This is a SELECT-node callback for the expression walker that +** always "fails". By "fail" in this case, we mean set +** pWalker->eCode to zero and abort. +** +** This callback is used by multiple expression walkers. +*/ +SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){ + UNUSED_PARAMETER(NotUsed); + pWalker->eCode = 0; + return WRC_Abort; +} + +/* ** These routines are Walker callbacks used to check expressions to ** see if they are "constant" for some definition of constant. The ** Walker.eCode value determines the type of "constant" we are looking @@ -92658,22 +93611,19 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ } /* Fall through */ default: - testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */ - testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */ + testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail will disallow */ + testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail will disallow */ return WRC_Continue; } } -static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){ - UNUSED_PARAMETER(NotUsed); - pWalker->eCode = 0; - return WRC_Abort; -} static int exprIsConst(Expr *p, int initFlag, int iCur){ Walker w; - memset(&w, 0, sizeof(w)); w.eCode = initFlag; w.xExprCallback = exprNodeIsConstant; - w.xSelectCallback = selectNodeIsConstant; + w.xSelectCallback = sqlite3SelectWalkFail; +#ifdef SQLITE_DEBUG + w.xSelectCallback2 = sqlite3SelectWalkAssert2; +#endif w.u.iCur = iCur; sqlite3WalkExpr(&w, p); return w.eCode; @@ -92723,9 +93673,9 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ ** it constant. */ for(i=0; i<pGroupBy->nExpr; i++){ Expr *p = pGroupBy->a[i].pExpr; - if( sqlite3ExprCompare(pExpr, p, -1)<2 ){ - CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p); - if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){ + if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){ + CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p); + if( sqlite3_stricmp("BINARY", pColl->zName)==0 ){ return WRC_Prune; } } @@ -92761,9 +93711,9 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ */ SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){ Walker w; - memset(&w, 0, sizeof(w)); w.eCode = 1; w.xExprCallback = exprNodeIsConstantOrGroupBy; + w.xSelectCallback = 0; w.u.pGroupBy = pGroupBy; w.pParse = pParse; sqlite3WalkExpr(&w, p); @@ -92791,10 +93741,12 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ */ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){ Walker w; - memset(&w, 0, sizeof(w)); w.eCode = 1; w.xExprCallback = sqlite3ExprWalkNoop; - w.xSelectCallback = selectNodeIsConstant; + w.xSelectCallback = sqlite3SelectWalkFail; +#ifdef SQLITE_DEBUG + w.xSelectCallback2 = sqlite3SelectWalkAssert2; +#endif sqlite3WalkExpr(&w, p); return w.eCode==0; } @@ -92864,8 +93816,8 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ case TK_BLOB: return 0; case TK_COLUMN: - assert( p->pTab!=0 ); return ExprHasProperty(p, EP_CanBeNull) || + p->pTab==0 || /* Reference to column of index on expression */ (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0); default: return 1; @@ -93527,7 +94479,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( /* Loop through each expression in <exprlist>. */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); - if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2); + if( isRowid ) sqlite3VdbeAddOp4(v, OP_Blob, 0, r2, 0, "", P4_STATIC); for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; int iValToIns; @@ -93955,7 +94907,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ const char *z = pExpr->u.zToken; assert( z!=0 ); c = sqlite3DecOrHexToI64(z, &value); - if( c==1 || (c==2 && !negFlag) || (negFlag && value==SMALLEST_INT64)){ + if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){ #ifdef SQLITE_OMIT_FLOATING_POINT sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); #else @@ -93969,7 +94921,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ } #endif }else{ - if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; } + if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; } sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64); } } @@ -94129,8 +95081,9 @@ SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn( if( iTabCol==XN_EXPR ){ assert( pIdx->aColExpr ); assert( pIdx->aColExpr->nExpr>iIdxCol ); - pParse->iSelfTab = iTabCur; + pParse->iSelfTab = iTabCur + 1; sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut); + pParse->iSelfTab = 0; }else{ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, iTabCol, regOut); @@ -94374,13 +95327,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) case TK_COLUMN: { int iTab = pExpr->iTable; if( iTab<0 ){ - if( pParse->ckBase>0 ){ + if( pParse->iSelfTab<0 ){ /* Generating CHECK constraints or inserting into partial index */ - return pExpr->iColumn + pParse->ckBase; + return pExpr->iColumn - pParse->iSelfTab; }else{ /* Coding an expression that is part of an index where column names ** in the index refer to the table to which the index belongs */ - iTab = pParse->iSelfTab; + iTab = pParse->iSelfTab - 1; } } return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, @@ -94717,8 +95670,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) if( !pColl ) pColl = db->pDfltColl; sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } - sqlite3VdbeAddOp4(v, OP_Function0, constMask, r1, target, - (char*)pDef, P4_FUNCDEF); + sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0, + constMask, r1, target, (char*)pDef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nFarg); if( nFarg && constMask==0 ){ sqlite3ReleaseTempRange(pParse, r1, nFarg); @@ -94997,7 +95950,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeAtInit( struct ExprList_item *pItem; int i; for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){ - if( pItem->reusable && sqlite3ExprCompare(pItem->pExpr,pExpr,-1)==0 ){ + if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){ return pItem->u.iConstExprReg; } } @@ -95123,7 +96076,9 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ ** Generate code that pushes the value of every element of the given ** expression list into a sequence of registers beginning at target. ** -** Return the number of elements evaluated. +** Return the number of elements evaluated. The number returned will +** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF +** is defined. ** ** The SQLITE_ECEL_DUP flag prevents the arguments from being ** filled using OP_SCopy. OP_Copy must be used instead. @@ -95134,6 +96089,8 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ ** The SQLITE_ECEL_REF flag means that expressions in the list with ** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored ** in registers at srcReg, and so the value can be copied from there. +** If SQLITE_ECEL_OMITREF is also set, then the values with u.x.iOrderByCol>0 +** are simply omitted rather than being copied from srcReg. */ SQLITE_PRIVATE int sqlite3ExprCodeExprList( Parse *pParse, /* Parsing context */ @@ -95552,6 +96509,41 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i sqlite3ExprDelete(db, pCopy); } +/* +** Expression pVar is guaranteed to be an SQL variable. pExpr may be any +** type of expression. +** +** If pExpr is a simple SQL value - an integer, real, string, blob +** or NULL value - then the VDBE currently being prepared is configured +** to re-prepare each time a new value is bound to variable pVar. +** +** Additionally, if pExpr is a simple SQL value and the value is the +** same as that currently bound to variable pVar, non-zero is returned. +** Otherwise, if the values are not the same or if pExpr is not a simple +** SQL value, zero is returned. +*/ +static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){ + int res = 0; + int iVar; + sqlite3_value *pL, *pR = 0; + + sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR); + if( pR ){ + iVar = pVar->iColumn; + sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); + pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB); + if( pL ){ + if( sqlite3_value_type(pL)==SQLITE_TEXT ){ + sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */ + } + res = 0==sqlite3MemCompare(pL, pR, 0); + } + sqlite3ValueFree(pR); + sqlite3ValueFree(pL); + } + + return res; +} /* ** Do a deep comparison of two expression trees. Return 0 if the two @@ -95574,12 +96566,22 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i ** this routine is used, it does not hurt to get an extra 2 - that ** just might result in some slightly slower code. But returning ** an incorrect 0 or 1 could lead to a malfunction. +** +** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in +** pParse->pReprepare can be matched against literals in pB. The +** pParse->pVdbe->expmask bitmask is updated for each variable referenced. +** If pParse is NULL (the normal case) then any TK_VARIABLE term in +** Argument pParse should normally be NULL. If it is not NULL and pA or +** pB causes a return value of 2. */ -SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ +SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ u32 combinedFlags; if( pA==0 || pB==0 ){ return pB==pA ? 0 : 2; } + if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){ + return 0; + } combinedFlags = pA->flags | pB->flags; if( combinedFlags & EP_IntValue ){ if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){ @@ -95588,10 +96590,10 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ return 2; } if( pA->op!=pB->op ){ - if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){ + if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){ return 1; } - if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft, iTab)<2 ){ + if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){ return 1; } return 2; @@ -95606,8 +96608,8 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ if( combinedFlags & EP_xIsSelect ) return 2; - if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2; - if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2; + if( sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; + if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){ if( pA->iColumn!=pB->iColumn ) return 2; @@ -95642,7 +96644,7 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ Expr *pExprA = pA->a[i].pExpr; Expr *pExprB = pB->a[i].pExpr; if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1; - if( sqlite3ExprCompare(pExprA, pExprB, iTab) ) return 1; + if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1; } return 0; } @@ -95652,7 +96654,7 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ ** are ignored. */ SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ - return sqlite3ExprCompare( + return sqlite3ExprCompare(0, sqlite3ExprSkipCollate(pA), sqlite3ExprSkipCollate(pB), iTab); @@ -95674,24 +96676,29 @@ SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has ** Expr.iTable<0 then assume a table number given by iTab. ** +** If pParse is not NULL, then the values of bound variables in pE1 are +** compared against literal values in pE2 and pParse->pVdbe->expmask is +** modified to record which bound variables are referenced. If pParse +** is NULL, then false will be returned if pE1 contains any bound variables. +** ** When in doubt, return false. Returning true might give a performance ** improvement. Returning false might cause a performance reduction, but ** it will always give the correct answer and is hence always safe. */ -SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){ - if( sqlite3ExprCompare(pE1, pE2, iTab)==0 ){ +SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){ + if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){ return 1; } if( pE2->op==TK_OR - && (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab) - || sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) ) + && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab) + || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) ) ){ return 1; } if( pE2->op==TK_NOTNULL && pE1->op!=TK_ISNULL && pE1->op!=TK_IS ){ Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft); testcase( pX!=pE1->pLeft ); - if( sqlite3ExprCompare(pX, pE2->pLeft, iTab)==0 ) return 1; + if( sqlite3ExprCompare(pParse, pX, pE2->pLeft, iTab)==0 ) return 1; } return 0; } @@ -95799,8 +96806,8 @@ SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){ Walker w; struct SrcCount cnt; assert( pExpr->op==TK_AGG_FUNCTION ); - memset(&w, 0, sizeof(w)); w.xExprCallback = exprSrcCount; + w.xSelectCallback = 0; w.u.pSrcCount = &cnt; cnt.pSrc = pSrcList; cnt.nThis = 0; @@ -95932,7 +96939,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ */ struct AggInfo_func *pItem = pAggInfo->aFunc; for(i=0; i<pAggInfo->nFunc; i++, pItem++){ - if( sqlite3ExprCompare(pItem->pExpr, pExpr, -1)==0 ){ + if( sqlite3ExprCompare(0, pItem->pExpr, pExpr, -1)==0 ){ break; } } @@ -95972,10 +96979,14 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ return WRC_Continue; } static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ - UNUSED_PARAMETER(pWalker); UNUSED_PARAMETER(pSelect); + pWalker->walkerDepth++; return WRC_Continue; } +static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){ + UNUSED_PARAMETER(pSelect); + pWalker->walkerDepth--; +} /* ** Analyze the pExpr expression looking for aggregate functions and @@ -95988,9 +96999,10 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ */ SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ Walker w; - memset(&w, 0, sizeof(w)); w.xExprCallback = analyzeAggregate; w.xSelectCallback = analyzeAggregatesInSelect; + w.xSelectCallback2 = analyzeAggregatesInSelectEnd; + w.walkerDepth = 0; w.u.pNC = pNC; assert( pNC->pSrcList!=0 ); sqlite3WalkExpr(&w, pExpr); @@ -96091,8 +97103,8 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){ int i; if( pParse->nRangeReg>0 - && pParse->iRangeReg+pParse->nRangeReg<iLast - && pParse->iRangeReg>=iFirst + && pParse->iRangeReg+pParse->nRangeReg > iFirst + && pParse->iRangeReg <= iLast ){ return 0; } @@ -96484,7 +97496,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){ ** Or, if zName is not a system table, zero is returned. */ static int isSystemTable(Parse *pParse, const char *zName){ - if( sqlite3Strlen30(zName)>6 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ + if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ sqlite3ErrorMsg(pParse, "table %s may not be altered", zName); return 1; } @@ -96512,9 +97524,9 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( char *zWhere = 0; /* Where clause to locate temp triggers */ #endif VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */ - int savedDbFlags; /* Saved value of db->flags */ + u32 savedDbFlags; /* Saved value of db->mDbFlags */ - savedDbFlags = db->flags; + savedDbFlags = db->mDbFlags; if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); @@ -96523,7 +97535,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; - db->flags |= SQLITE_PreferBuiltin; + db->mDbFlags |= DBFLAG_PreferBuiltin; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(db, pName); @@ -96688,7 +97700,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( exit_rename_table: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zName); - db->flags = savedDbFlags; + db->mDbFlags = savedDbFlags; } /* @@ -96789,11 +97801,11 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; - int savedDbFlags = db->flags; + u32 savedDbFlags = db->mDbFlags; while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){ *zEnd-- = '\0'; } - db->flags |= SQLITE_PreferBuiltin; + db->mDbFlags |= DBFLAG_PreferBuiltin; sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) " @@ -96802,7 +97814,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ zTab ); sqlite3DbFree(db, zCol); - db->flags = savedDbFlags; + db->mDbFlags = savedDbFlags; } /* Make sure the schema version is at least 3. But do not upgrade @@ -98903,7 +99915,8 @@ static void attachFunc( char *zPath = 0; char *zErr = 0; unsigned int flags; - Db *aNew; + Db *aNew; /* New array of Db pointers */ + Db *pNew; /* Db object for the newly attached database */ char *zErrDyn = 0; sqlite3_vfs *pVfs; @@ -98926,10 +99939,6 @@ static void attachFunc( ); goto attach_error; } - if( !db->autoCommit ){ - zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction"); - goto attach_error; - } for(i=0; i<db->nDb; i++){ char *z = db->aDb[i].zDbSName; assert( z && zName ); @@ -98951,8 +99960,8 @@ static void attachFunc( if( aNew==0 ) return; } db->aDb = aNew; - aNew = &db->aDb[db->nDb]; - memset(aNew, 0, sizeof(*aNew)); + pNew = &db->aDb[db->nDb]; + memset(pNew, 0, sizeof(*pNew)); /* Open the database file. If the btree is successfully opened, use ** it to obtain the database schema. At this point the schema may @@ -98968,7 +99977,7 @@ static void attachFunc( } assert( pVfs ); flags |= SQLITE_OPEN_MAIN_DB; - rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags); + rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags); sqlite3_free( zPath ); db->nDb++; db->skipBtreeMutex = 0; @@ -98977,28 +99986,28 @@ static void attachFunc( zErrDyn = sqlite3MPrintf(db, "database is already attached"); }else if( rc==SQLITE_OK ){ Pager *pPager; - aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); - if( !aNew->pSchema ){ + pNew->pSchema = sqlite3SchemaGet(db, pNew->pBt); + if( !pNew->pSchema ){ rc = SQLITE_NOMEM_BKPT; - }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ + }else if( pNew->pSchema->file_format && pNew->pSchema->enc!=ENC(db) ){ zErrDyn = sqlite3MPrintf(db, "attached databases must use the same text encoding as main database"); rc = SQLITE_ERROR; } - sqlite3BtreeEnter(aNew->pBt); - pPager = sqlite3BtreePager(aNew->pBt); + sqlite3BtreeEnter(pNew->pBt); + pPager = sqlite3BtreePager(pNew->pBt); sqlite3PagerLockingMode(pPager, db->dfltLockMode); - sqlite3BtreeSecureDelete(aNew->pBt, + sqlite3BtreeSecureDelete(pNew->pBt, sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) ); #ifndef SQLITE_OMIT_PAGER_PRAGMAS - sqlite3BtreeSetPagerFlags(aNew->pBt, + sqlite3BtreeSetPagerFlags(pNew->pBt, PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); #endif - sqlite3BtreeLeave(aNew->pBt); + sqlite3BtreeLeave(pNew->pBt); } - aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; - aNew->zDbSName = sqlite3DbStrDup(db, zName); - if( rc==SQLITE_OK && aNew->zDbSName==0 ){ + pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; + pNew->zDbSName = sqlite3DbStrDup(db, zName); + if( rc==SQLITE_OK && pNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } @@ -99121,11 +100130,6 @@ static void detachFunc( sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); goto detach_error; } - if( !db->autoCommit ){ - sqlite3_snprintf(sizeof(zErr), zErr, - "cannot DETACH database within transaction"); - goto detach_error; - } if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); goto detach_error; @@ -99538,11 +100542,9 @@ SQLITE_PRIVATE int sqlite3AuthReadCol( #endif ); if( rc==SQLITE_DENY ){ - if( db->nDb>2 || iDb!=0 ){ - sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol); - }else{ - sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol); - } + char *z = sqlite3_mprintf("%s.%s", zTab, zCol); + if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z); + sqlite3ErrorMsg(pParse, "access to %z is prohibited", z); pParse->rc = SQLITE_AUTH; }else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){ sqliteAuthBadReturnCode(pParse); @@ -100175,7 +101177,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char } freeIndex(db, pIndex); } - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; } /* @@ -100210,28 +101212,26 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){ /* ** Reset the schema for the database at index iDb. Also reset the -** TEMP schema. +** TEMP schema. The reset is deferred if db->nSchemaLock is not zero. +** Deferred resets may be run by calling with iDb<0. */ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ - Db *pDb; + int i; assert( iDb<db->nDb ); - /* Case 1: Reset the single schema identified by iDb */ - pDb = &db->aDb[iDb]; - assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - assert( pDb->pSchema!=0 ); - sqlite3SchemaClear(pDb->pSchema); + if( iDb>=0 ){ + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + DbSetProperty(db, iDb, DB_ResetWanted); + DbSetProperty(db, 1, DB_ResetWanted); + } - /* If any database other than TEMP is reset, then also reset TEMP - ** since TEMP might be holding triggers that reference tables in the - ** other database. - */ - if( iDb!=1 ){ - pDb = &db->aDb[1]; - assert( pDb->pSchema!=0 ); - sqlite3SchemaClear(pDb->pSchema); + if( db->nSchemaLock==0 ){ + for(i=0; i<db->nDb; i++){ + if( DbHasProperty(db, i, DB_ResetWanted) ){ + sqlite3SchemaClear(db->aDb[i].pSchema); + } + } } - return; } /* @@ -100241,13 +101241,14 @@ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ int i; sqlite3BtreeEnterAll(db); + assert( db->nSchemaLock==0 ); for(i=0; i<db->nDb; i++){ Db *pDb = &db->aDb[i]; if( pDb->pSchema ){ sqlite3SchemaClear(pDb->pSchema); } } - db->flags &= ~SQLITE_InternChanges; + db->mDbFlags &= ~DBFLAG_SchemaChange; sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); sqlite3CollapseDatabaseArray(db); @@ -100257,7 +101258,7 @@ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ ** This routine is called when a commit occurs. */ SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){ - db->flags &= ~SQLITE_InternChanges; + db->mDbFlags &= ~DBFLAG_SchemaChange; } /* @@ -100295,13 +101296,16 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ */ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; - TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */ +#ifdef SQLITE_DEBUG /* Record the number of outstanding lookaside allocations in schema Tables ** prior to doing any free() operations. Since schema Tables do not use ** lookaside, this number should not change. */ - TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ? - db->lookaside.nOut : 0 ); + int nLookaside = 0; + if( db && (pTable->tabFlags & TF_Ephemeral)==0 ){ + nLookaside = sqlite3LookasideUsed(db, 0); + } +#endif /* Delete all indices associated with this table. */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ @@ -100335,7 +101339,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ sqlite3DbFree(db, pTable); /* Verify that no lookaside memory was used by schema tables */ - assert( nLookaside==0 || nLookaside==db->lookaside.nOut ); + assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) ); } SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ /* Do not delete the table until the reference count reaches zero. */ @@ -100361,7 +101365,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char pDb = &db->aDb[iDb]; p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); sqlite3DeleteTable(db, p); - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; } /* @@ -100474,7 +101478,8 @@ SQLITE_PRIVATE int sqlite3TwoPartName( return -1; } }else{ - assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0); + assert( db->init.iDb==0 || db->init.busy + || (db->mDbFlags & DBFLAG_Vacuum)!=0); iDb = db->init.iDb; *pUnqual = pName1; } @@ -100635,7 +101640,11 @@ SQLITE_PRIVATE void sqlite3StartTable( pTable->iPKey = -1; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nTabRef = 1; +#ifdef SQLITE_DEFAULT_ROWEST + pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST); +#else pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); +#endif assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; @@ -100702,7 +101711,8 @@ SQLITE_PRIVATE void sqlite3StartTable( }else #endif { - pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2); + pParse->addrCrTab = + sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY); } sqlite3OpenMasterTable(pParse, iDb); sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1); @@ -100751,12 +101761,10 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){ Column *pCol; sqlite3 *db = pParse->db; if( (p = pParse->pNewTable)==0 ) return; -#if SQLITE_MAX_COLUMN if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); return; } -#endif z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2); if( z==0 ) return; memcpy(z, pName->z, pName->n); @@ -101362,9 +102370,8 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){ ** Changes include: ** ** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL. -** (2) Convert the OP_CreateTable into an OP_CreateIndex. There is -** no rowid btree for a WITHOUT ROWID. Instead, the canonical -** data storage is a covering index btree. +** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY +** into BTREE_BLOBKEY. ** (3) Bypass the creation of the sqlite_master table entry ** for the PRIMARY KEY as the primary key index is now ** identified by the sqlite_master table entry of the table itself. @@ -101372,7 +102379,7 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){ ** schema to the rootpage from the main table. ** (5) Add all table columns to the PRIMARY KEY Index object ** so that the PRIMARY KEY is a covering index. The surplus -** columns are part of KeyInfo.nXField and are not used for +** columns are part of KeyInfo.nAllField and are not used for ** sorting or lookup or uniqueness checks. ** (6) Replace the rowid tail on all automatically generated UNIQUE ** indices with the PRIMARY KEY columns. @@ -101401,13 +102408,12 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ ** virtual tables */ if( IN_DECLARE_VTAB ) return; - /* Convert the OP_CreateTable opcode that would normally create the - ** root-page for the table into an OP_CreateIndex opcode. The index - ** created will become the PRIMARY KEY index. + /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY + ** into BTREE_BLOBKEY. */ if( pParse->addrCrTab ){ assert( v ); - sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex); + sqlite3VdbeChangeP3(v, pParse->addrCrTab, BTREE_BLOBKEY); } /* Locate the PRIMARY KEY index. Or, if this table was originally @@ -101430,15 +102436,6 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ }else{ pPk = sqlite3PrimaryKeyIndex(pTab); - /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master - ** table entry. This is only required if currently generating VDBE - ** code for a CREATE TABLE (not when parsing one as part of reading - ** a database schema). */ - if( v ){ - assert( db->init.busy==0 ); - sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto); - } - /* ** Remove all redundant columns from the PRIMARY KEY. For example, change ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later @@ -101458,6 +102455,15 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ if( !db->init.imposterTable ) pPk->uniqNotNull = 1; nPk = pPk->nKeyCol; + /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master + ** table entry. This is only required if currently generating VDBE + ** code for a CREATE TABLE (not when parsing one as part of reading + ** a database schema). */ + if( v && pPk->tnum>0 ){ + assert( db->init.busy==0 ); + sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto); + } + /* The root page of the PRIMARY KEY is the table root page */ pPk->tnum = pTab->tnum; @@ -101747,7 +102753,7 @@ SQLITE_PRIVATE void sqlite3EndTable( return; } pParse->pNewTable = 0; - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; #ifndef SQLITE_OMIT_ALTERTABLE if( !p->pSelect ){ @@ -101846,6 +102852,9 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ int nErr = 0; /* Number of errors encountered */ int n; /* Temporarily holds the number of cursors assigned */ sqlite3 *db = pParse->db; /* Database connection for malloc errors */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + int rc; +#endif #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth; /* Saved xAuth pointer */ #endif @@ -101853,8 +102862,11 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ assert( pTable ); #ifndef SQLITE_OMIT_VIRTUALTABLE - if( sqlite3VtabCallConnect(pParse, pTable) ){ - return SQLITE_ERROR; + db->nSchemaLock++; + rc = sqlite3VtabCallConnect(pParse, pTable); + db->nSchemaLock--; + if( rc ){ + return 1; } if( IsVirtual(pTable) ) return 0; #endif @@ -102050,14 +103062,6 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){ ** is also added (this can happen with an auto-vacuum database). */ static void destroyTable(Parse *pParse, Table *pTab){ -#ifdef SQLITE_OMIT_AUTOVACUUM - Index *pIdx; - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - destroyRootPage(pParse, pTab->tnum, iDb); - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - destroyRootPage(pParse, pIdx->tnum, iDb); - } -#else /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM ** is not defined), then it is important to call OP_Destroy on the ** table and index root-pages in order, starting with the numerically @@ -102100,7 +103104,6 @@ static void destroyTable(Parse *pParse, Table *pTab){ iDestroyed = iLargest; } } -#endif } /* @@ -102527,7 +103530,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); - sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1); + sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); @@ -103016,7 +104019,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex( sqlite3OomFault(db); goto exit_create_index; } - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; if( pTblName!=0 ){ pIndex->tnum = db->init.newTnum; } @@ -103052,7 +104055,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex( ** that case the convertToWithoutRowidTable() routine will replace ** the Noop with a Goto to jump over the VDBE code generated below. */ pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop); - sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem); + sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY); /* Gather the complete text of the CREATE INDEX statement into ** the zStmt variable @@ -103464,12 +104467,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( pDatabase = 0; } if( pDatabase ){ - Token *pTemp = pDatabase; - pDatabase = pTable; - pTable = pTemp; + pItem->zName = sqlite3NameFromToken(db, pDatabase); + pItem->zDatabase = sqlite3NameFromToken(db, pTable); + }else{ + pItem->zName = sqlite3NameFromToken(db, pTable); + pItem->zDatabase = 0; } - pItem->zName = sqlite3NameFromToken(db, pTable); - pItem->zDatabase = sqlite3NameFromToken(db, pDatabase); return pList; } @@ -103574,8 +104577,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( */ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ assert( pIndexedBy!=0 ); - if( p && ALWAYS(p->nSrc>0) ){ - struct SrcList_item *pItem = &p->a[p->nSrc-1]; + if( p && pIndexedBy->n>0 ){ + struct SrcList_item *pItem; + assert( p->nSrc>0 ); + pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); @@ -103585,7 +104590,7 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI pItem->fg.notIndexed = 1; }else{ pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); - pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0); + pItem->fg.isIndexedBy = 1; } } } @@ -103658,36 +104663,25 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ } /* -** Generate VDBE code for a COMMIT statement. +** Generate VDBE code for a COMMIT or ROLLBACK statement. +** Code for ROLLBACK is generated if eType==TK_ROLLBACK. Otherwise +** code is generated for a COMMIT. */ -SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){ +SQLITE_PRIVATE void sqlite3EndTransaction(Parse *pParse, int eType){ Vdbe *v; + int isRollback; assert( pParse!=0 ); assert( pParse->db!=0 ); - if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){ + assert( eType==TK_COMMIT || eType==TK_END || eType==TK_ROLLBACK ); + isRollback = eType==TK_ROLLBACK; + if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, + isRollback ? "ROLLBACK" : "COMMIT", 0, 0) ){ return; } v = sqlite3GetVdbe(pParse); if( v ){ - sqlite3VdbeAddOp1(v, OP_AutoCommit, 1); - } -} - -/* -** Generate VDBE code for a ROLLBACK statement. -*/ -SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){ - Vdbe *v; - - assert( pParse!=0 ); - assert( pParse->db!=0 ); - if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){ - return; - } - v = sqlite3GetVdbe(pParse); - if( v ){ - sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1); + sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, isRollback); } } @@ -103877,7 +104871,9 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint( assert( pIdx->aiColumn[j]>=0 ); zCol = pTab->aCol[pIdx->aiColumn[j]].zName; if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); - sqlite3XPrintf(&errMsg, "%s.%s", pTab->zName, zCol); + sqlite3StrAccumAppendAll(&errMsg, pTab->zName); + sqlite3StrAccumAppend(&errMsg, ".", 1); + sqlite3StrAccumAppendAll(&errMsg, zCol); } } zErr = sqlite3StrAccumFinish(&errMsg); @@ -104266,7 +105262,7 @@ SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq( ** from the main database is substituted, if one is available. */ SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ - if( pColl ){ + if( pColl && pColl->xCmp==0 ){ const char *zName = pColl->zName; sqlite3 *db = pParse->db; CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName); @@ -104302,8 +105298,8 @@ static CollSeq *findCollSeqEntry( pColl = sqlite3HashFind(&db->aCollSeq, zName); if( 0==pColl && create ){ - int nName = sqlite3Strlen30(zName); - pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1); + int nName = sqlite3Strlen30(zName) + 1; + pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName); if( pColl ){ CollSeq *pDel = 0; pColl[0].zName = (char*)&pColl[3]; @@ -104313,7 +105309,6 @@ static CollSeq *findCollSeqEntry( pColl[2].zName = (char*)&pColl[3]; pColl[2].enc = SQLITE_UTF16BE; memcpy(pColl[0].zName, zName, nName); - pColl[0].zName[nName] = 0; pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl); /* If a malloc() failure occurred in sqlite3HashInsert(), it will @@ -104453,7 +105448,8 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs( FuncDef *pOther; const char *zName = aDef[i].zName; int nName = sqlite3Strlen30(zName); - int h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ; + int h = (zName[0] + nName) % SQLITE_FUNC_HASH_SZ; + assert( zName[0]>='a' && zName[0]<='z' ); pOther = functionSearch(h, zName); if( pOther ){ assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] ); @@ -104519,7 +105515,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( /* If no match is found, search the built-in functions. ** - ** If the SQLITE_PreferBuiltin flag is set, then search the built-in + ** If the DBFLAG_PreferBuiltin flag is set, then search the built-in ** functions even if a prior app-defined function was found. And give ** priority to built-in functions. ** @@ -104529,7 +105525,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( ** new function. But the FuncDefs for built-in functions are read-only. ** So we must not search for built-ins when creating a new function. */ - if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){ + if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){ bestScore = 0; h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ; p = functionSearch(h, zName); @@ -104602,8 +105598,8 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){ pSchema->pSeqTab = 0; if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; - pSchema->schemaFlags &= ~DB_SchemaLoaded; } + pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted); } /* @@ -104986,7 +105982,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( ** API function sqlite3_count_changes) to be set incorrectly. ** ** The "rcauth==SQLITE_OK" terms is the - ** IMPLEMENATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and + ** IMPLEMENTATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and ** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but ** the truncate optimization is disabled and all rows are deleted ** individually. @@ -105092,7 +106088,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk); }else{ /* Add the rowid of the row to be deleted to the RowSet */ - nKey = 1; /* OP_Seek always uses a single rowid */ + nKey = 1; /* OP_DeferredSeek always uses a single rowid */ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); } } @@ -105135,7 +106131,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( } }else if( pPk ){ addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey); + if( IsVirtual(pTab) ){ + sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey); + }else{ + sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey); + } assert( nKey==0 ); /* OP_Found will use a composite key */ }else{ addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey); @@ -105485,10 +106485,11 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); - pParse->iSelfTab = iDataCur; + pParse->iSelfTab = iDataCur + 1; sqlite3ExprCachePush(pParse); sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); + pParse->iSelfTab = 0; }else{ *piPartIdxLabel = 0; } @@ -105616,16 +106617,20 @@ static void typeofFunc( int NotUsed, sqlite3_value **argv ){ - const char *z = 0; + static const char *azType[] = { "integer", "real", "text", "blob", "null" }; + int i = sqlite3_value_type(argv[0]) - 1; UNUSED_PARAMETER(NotUsed); - switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_INTEGER: z = "integer"; break; - case SQLITE_TEXT: z = "text"; break; - case SQLITE_FLOAT: z = "real"; break; - case SQLITE_BLOB: z = "blob"; break; - default: z = "null"; break; - } - sqlite3_result_text(context, z, -1, SQLITE_STATIC); + assert( i>=0 && i<ArraySize(azType) ); + assert( SQLITE_INTEGER==1 ); + assert( SQLITE_FLOAT==2 ); + assert( SQLITE_TEXT==3 ); + assert( SQLITE_BLOB==4 ); + assert( SQLITE_NULL==5 ); + /* EVIDENCE-OF: R-01470-60482 The sqlite3_value_type(V) interface returns + ** the datatype code for the initial datatype of the sqlite3_value object + ** V. The returned value is one of SQLITE_INTEGER, SQLITE_FLOAT, + ** SQLITE_TEXT, SQLITE_BLOB, or SQLITE_NULL. */ + sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC); } @@ -106401,7 +107406,8 @@ static void likeFunc( #ifdef SQLITE_TEST sqlite3_like_count++; #endif - sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); + sqlite3_result_int(context, + patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); } } @@ -107242,9 +108248,14 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive) /* ** pExpr points to an expression which implements a function. If ** it is appropriate to apply the LIKE optimization to that function -** then set aWc[0] through aWc[2] to the wildcard characters and -** return TRUE. If the function is not a LIKE-style function then -** return FALSE. +** then set aWc[0] through aWc[2] to the wildcard characters and the +** escape character and then return TRUE. If the function is not a +** LIKE-style function then return FALSE. +** +** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE +** operator if c is a string literal that is exactly one byte in length. +** That one byte is stored in aWc[3]. aWc[3] is set to zero if there is +** no ESCAPE clause. ** ** *pIsNocase is set to true if uppercase and lowercase are equivalent for ** the function (default for LIKE). If the function makes the distinction @@ -107253,17 +108264,26 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive) */ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ FuncDef *pDef; - if( pExpr->op!=TK_FUNCTION - || !pExpr->x.pList - || pExpr->x.pList->nExpr!=2 - ){ + int nExpr; + if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){ return 0; } assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0); + nExpr = pExpr->x.pList->nExpr; + pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0); if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){ return 0; } + if( nExpr<3 ){ + aWc[3] = 0; + }else{ + Expr *pEscape = pExpr->x.pList->a[2].pExpr; + char *zEscape; + if( pEscape->op!=TK_STRING ) return 0; + zEscape = pEscape->u.zToken; + if( zEscape[0]==0 || zEscape[1]!=0 ) return 0; + aWc[3] = zEscape[0]; + } /* The memcpy() statement assumes that the wildcard characters are ** the first three statements in the compareInfo structure. The @@ -108046,10 +109066,12 @@ static void fkScanChildren( /* Create VDBE to loop through the entries in pSrc that match the WHERE ** clause. For each row found, increment either the deferred or immediate ** foreign key constraint counter. */ - pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); - sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); - if( pWInfo ){ - sqlite3WhereEnd(pWInfo); + if( pParse->nErr==0 ){ + pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); + sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); + if( pWInfo ){ + sqlite3WhereEnd(pWInfo); + } } /* Clean up the WHERE clause constructed above. */ @@ -109061,7 +110083,7 @@ static int autoIncBegin( ){ int memId = 0; /* Register holding maximum rowid */ if( (pTab->tabFlags & TF_Autoincrement)!=0 - && (pParse->db->flags & SQLITE_Vacuum)==0 + && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); AutoincInfo *pInfo; @@ -109319,7 +110341,6 @@ SQLITE_PRIVATE void sqlite3Insert( ){ sqlite3 *db; /* The main database structure */ Table *pTab; /* The table to insert into. aka TABLE */ - char *zTab; /* Name of the table into which we are inserting */ int i, j; /* Loop counters */ Vdbe *v; /* Generate code into this virtual machine */ Index *pIdx; /* For looping over indices of the table */ @@ -109356,10 +110377,10 @@ SQLITE_PRIVATE void sqlite3Insert( #endif db = pParse->db; - memset(&dest, 0, sizeof(dest)); if( pParse->nErr || db->mallocFailed ){ goto insert_cleanup; } + dest.iSDParm = 0; /* Suppress a harmless compiler warning */ /* If the Select object is really just a simple VALUES() list with a ** single row (the common case) then keep that one row of values @@ -109375,8 +110396,6 @@ SQLITE_PRIVATE void sqlite3Insert( /* Locate the table into which we will be inserting new information. */ assert( pTabList->nSrc==1 ); - zTab = pTabList->a[0].zName; - if( NEVER(zTab==0) ) goto insert_cleanup; pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ){ goto insert_cleanup; @@ -110168,7 +111187,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( #ifndef SQLITE_OMIT_CHECK if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ ExprList *pCheck = pTab->pCheck; - pParse->ckBase = regNewData+1; + pParse->iSelfTab = -(regNewData+1); onError = overrideError!=OE_Default ? overrideError : OE_Abort; for(i=0; i<pCheck->nExpr; i++){ int allOk; @@ -110188,6 +111207,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( } sqlite3VdbeResolveLabel(v, allOk); } + pParse->iSelfTab = 0; } #endif /* !defined(SQLITE_OMIT_CHECK) */ @@ -110332,10 +111352,10 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); - pParse->ckBase = regNewData+1; + pParse->iSelfTab = -(regNewData+1); sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk, SQLITE_JUMPIFNULL); - pParse->ckBase = 0; + pParse->iSelfTab = 0; } /* Create a record for this index entry as it should appear after @@ -110346,9 +111366,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( int iField = pIdx->aiColumn[i]; int x; if( iField==XN_EXPR ){ - pParse->ckBase = regNewData+1; + pParse->iSelfTab = -(regNewData+1); sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); - pParse->ckBase = 0; + pParse->iSelfTab = 0; VdbeComment((v, "%s column %d", pIdx->zName, i)); }else{ if( iField==XN_ROWID || iField==pTab->iPKey ){ @@ -110733,7 +111753,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ } if( pSrc->aiColumn[i]==XN_EXPR ){ assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 ); - if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr, + if( sqlite3ExprCompare(0, pSrc->aColExpr->a[i].pExpr, pDest->aColExpr->a[i].pExpr, -1)!=0 ){ return 0; /* Different expressions in the index */ } @@ -110745,7 +111765,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ return 0; /* Different collating sequences */ } } - if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){ + if( sqlite3ExprCompare(0, pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){ return 0; /* Different WHERE clauses */ } @@ -110893,7 +111913,7 @@ static int xferOptimization( Column *pDestCol = &pDest->aCol[i]; Column *pSrcCol = &pSrc->aCol[i]; #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS - if( (db->flags & SQLITE_Vacuum)==0 + if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN ){ return 0; /* Neither table may have __hidden__ columns */ @@ -110969,15 +111989,15 @@ static int xferOptimization( regRowid = sqlite3GetTempReg(pParse); sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); assert( HasRowid(pDest) || destHasUniqueIdx ); - if( (db->flags & SQLITE_Vacuum)==0 && ( + if( (db->mDbFlags & DBFLAG_Vacuum)==0 && ( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ || destHasUniqueIdx /* (2) */ || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */ )){ /* In some circumstances, we are able to run the xfer optimization ** only if the destination table is initially empty. Unless the - ** SQLITE_Vacuum flag is set, this block generates code to make - ** that determination. If SQLITE_Vacuum is set, then the destination + ** DBFLAG_Vacuum flag is set, this block generates code to make + ** that determination. If DBFLAG_Vacuum is set, then the destination ** table is always empty. ** ** Conditions under which the destination must be empty: @@ -111013,8 +112033,8 @@ static int xferOptimization( assert( (pDest->tabFlags & TF_Autoincrement)==0 ); } sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); - if( db->flags & SQLITE_Vacuum ){ - sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1); + if( db->mDbFlags & DBFLAG_Vacuum ){ + sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID| OPFLAG_APPEND|OPFLAG_USESEEKRESULT; }else{ @@ -111045,13 +112065,13 @@ static int xferOptimization( VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); - if( db->flags & SQLITE_Vacuum ){ + if( db->mDbFlags & DBFLAG_Vacuum ){ /* This INSERT command is part of a VACUUM operation, which guarantees ** that the destination table is empty. If all indexed columns use ** collation sequence BINARY, then it can also be assumed that the ** index will be populated by inserting keys in strictly sorted ** order. In this case, instead of seeking within the b-tree as part - ** of every OP_IdxInsert opcode, an OP_Last is added before the + ** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the ** OP_IdxInsert to seek to the point within the b-tree where each key ** should be inserted. This is faster. ** @@ -111066,7 +112086,7 @@ static int xferOptimization( } if( i==pSrcIdx->nColumn ){ idxInsFlags = OPFLAG_USESEEKRESULT; - sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1); + sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); } } if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){ @@ -111225,11 +112245,8 @@ exec_out: rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && pzErrMsg ){ - int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db)); - *pzErrMsg = sqlite3Malloc(nErrMsg); - if( *pzErrMsg ){ - memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg); - }else{ + *pzErrMsg = sqlite3DbStrDup(0, sqlite3_errmsg(db)); + if( *pzErrMsg==0 ){ rc = SQLITE_NOMEM_BKPT; sqlite3Error(db, SQLITE_NOMEM); } @@ -111400,7 +112417,7 @@ struct sqlite3_api_routines { int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); - char * (*snprintf)(int,char*,const char*,...); + char * (*xsnprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, char const**,char const**,int*,int*,int*); @@ -111512,7 +112529,7 @@ struct sqlite3_api_routines { int (*uri_boolean)(const char*,const char*,int); sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); const char *(*uri_parameter)(const char*,const char*); - char *(*vsnprintf)(int,char*,const char*,va_list); + char *(*xvsnprintf)(int,char*,const char*,va_list); int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); /* Version 3.8.7 and later */ int (*auto_extension)(void(*)(void)); @@ -111550,6 +112567,14 @@ struct sqlite3_api_routines { char *(*expanded_sql)(sqlite3_stmt*); /* Version 3.18.0 and later */ void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); + /* Version 3.20.0 and later */ + int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, + sqlite3_stmt**,const char**); + int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, + sqlite3_stmt**,const void**); + int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); + void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); + void *(*value_pointer)(sqlite3_value*,const char*); }; /* @@ -111676,7 +112701,7 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_rollback_hook sqlite3_api->rollback_hook #define sqlite3_set_authorizer sqlite3_api->set_authorizer #define sqlite3_set_auxdata sqlite3_api->set_auxdata -#define sqlite3_snprintf sqlite3_api->snprintf +#define sqlite3_snprintf sqlite3_api->xsnprintf #define sqlite3_step sqlite3_api->step #define sqlite3_table_column_metadata sqlite3_api->table_column_metadata #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup @@ -111700,7 +112725,7 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_value_text16le sqlite3_api->value_text16le #define sqlite3_value_type sqlite3_api->value_type #define sqlite3_vmprintf sqlite3_api->vmprintf -#define sqlite3_vsnprintf sqlite3_api->vsnprintf +#define sqlite3_vsnprintf sqlite3_api->xvsnprintf #define sqlite3_overload_function sqlite3_api->overload_function #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 @@ -111776,7 +112801,7 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_uri_boolean sqlite3_api->uri_boolean #define sqlite3_uri_int64 sqlite3_api->uri_int64 #define sqlite3_uri_parameter sqlite3_api->uri_parameter -#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf +#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 /* Version 3.8.7 and later */ #define sqlite3_auto_extension sqlite3_api->auto_extension @@ -111810,6 +112835,12 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_expanded_sql sqlite3_api->expanded_sql /* Version 3.18.0 and later */ #define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid +/* Version 3.20.0 and later */ +#define sqlite3_prepare_v3 sqlite3_api->prepare_v3 +#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3 +#define sqlite3_bind_pointer sqlite3_api->bind_pointer +#define sqlite3_result_pointer sqlite3_api->result_pointer +#define sqlite3_value_pointer sqlite3_api->value_pointer #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -111865,6 +112896,7 @@ typedef int (*sqlite3_loadext_entry)( # define sqlite3_open16 0 # define sqlite3_prepare16 0 # define sqlite3_prepare16_v2 0 +# define sqlite3_prepare16_v3 0 # define sqlite3_result_error16 0 # define sqlite3_result_text16 0 # define sqlite3_result_text16be 0 @@ -112237,7 +113269,13 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_trace_v2, sqlite3_expanded_sql, /* Version 3.18.0 and later */ - sqlite3_set_last_insert_rowid + sqlite3_set_last_insert_rowid, + /* Version 3.20.0 and later */ + sqlite3_prepare_v3, + sqlite3_prepare16_v3, + sqlite3_bind_pointer, + sqlite3_result_pointer, + sqlite3_value_pointer }; /* @@ -112659,35 +113697,38 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ #define PragTyp_ENCODING 12 #define PragTyp_FOREIGN_KEY_CHECK 13 #define PragTyp_FOREIGN_KEY_LIST 14 -#define PragTyp_INCREMENTAL_VACUUM 15 -#define PragTyp_INDEX_INFO 16 -#define PragTyp_INDEX_LIST 17 -#define PragTyp_INTEGRITY_CHECK 18 -#define PragTyp_JOURNAL_MODE 19 -#define PragTyp_JOURNAL_SIZE_LIMIT 20 -#define PragTyp_LOCK_PROXY_FILE 21 -#define PragTyp_LOCKING_MODE 22 -#define PragTyp_PAGE_COUNT 23 -#define PragTyp_MMAP_SIZE 24 -#define PragTyp_OPTIMIZE 25 -#define PragTyp_PAGE_SIZE 26 -#define PragTyp_SECURE_DELETE 27 -#define PragTyp_SHRINK_MEMORY 28 -#define PragTyp_SOFT_HEAP_LIMIT 29 -#define PragTyp_SYNCHRONOUS 30 -#define PragTyp_TABLE_INFO 31 -#define PragTyp_TEMP_STORE 32 -#define PragTyp_TEMP_STORE_DIRECTORY 33 -#define PragTyp_THREADS 34 -#define PragTyp_WAL_AUTOCHECKPOINT 35 -#define PragTyp_WAL_CHECKPOINT 36 -#define PragTyp_ACTIVATE_EXTENSIONS 37 -#define PragTyp_HEXKEY 38 -#define PragTyp_KEY 39 -#define PragTyp_REKEY 40 -#define PragTyp_LOCK_STATUS 41 -#define PragTyp_PARSER_TRACE 42 -#define PragTyp_STATS 43 +#define PragTyp_FUNCTION_LIST 15 +#define PragTyp_INCREMENTAL_VACUUM 16 +#define PragTyp_INDEX_INFO 17 +#define PragTyp_INDEX_LIST 18 +#define PragTyp_INTEGRITY_CHECK 19 +#define PragTyp_JOURNAL_MODE 20 +#define PragTyp_JOURNAL_SIZE_LIMIT 21 +#define PragTyp_LOCK_PROXY_FILE 22 +#define PragTyp_LOCKING_MODE 23 +#define PragTyp_PAGE_COUNT 24 +#define PragTyp_MMAP_SIZE 25 +#define PragTyp_MODULE_LIST 26 +#define PragTyp_OPTIMIZE 27 +#define PragTyp_PAGE_SIZE 28 +#define PragTyp_PRAGMA_LIST 29 +#define PragTyp_SECURE_DELETE 30 +#define PragTyp_SHRINK_MEMORY 31 +#define PragTyp_SOFT_HEAP_LIMIT 32 +#define PragTyp_SYNCHRONOUS 33 +#define PragTyp_TABLE_INFO 34 +#define PragTyp_TEMP_STORE 35 +#define PragTyp_TEMP_STORE_DIRECTORY 36 +#define PragTyp_THREADS 37 +#define PragTyp_WAL_AUTOCHECKPOINT 38 +#define PragTyp_WAL_CHECKPOINT 39 +#define PragTyp_ACTIVATE_EXTENSIONS 40 +#define PragTyp_HEXKEY 41 +#define PragTyp_KEY 42 +#define PragTyp_REKEY 43 +#define PragTyp_LOCK_STATUS 44 +#define PragTyp_PARSER_TRACE 45 +#define PragTyp_STATS 46 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ @@ -112733,26 +113774,29 @@ static const char *const pragCName[] = { /* 26 */ "seq", /* Used by: database_list */ /* 27 */ "name", /* 28 */ "file", - /* 29 */ "seq", /* Used by: collation_list */ - /* 30 */ "name", - /* 31 */ "id", /* Used by: foreign_key_list */ - /* 32 */ "seq", - /* 33 */ "table", - /* 34 */ "from", - /* 35 */ "to", - /* 36 */ "on_update", - /* 37 */ "on_delete", - /* 38 */ "match", - /* 39 */ "table", /* Used by: foreign_key_check */ - /* 40 */ "rowid", - /* 41 */ "parent", - /* 42 */ "fkid", - /* 43 */ "busy", /* Used by: wal_checkpoint */ - /* 44 */ "log", - /* 45 */ "checkpointed", - /* 46 */ "timeout", /* Used by: busy_timeout */ - /* 47 */ "database", /* Used by: lock_status */ - /* 48 */ "status", + /* 29 */ "name", /* Used by: function_list */ + /* 30 */ "builtin", + /* 31 */ "name", /* Used by: module_list pragma_list */ + /* 32 */ "seq", /* Used by: collation_list */ + /* 33 */ "name", + /* 34 */ "id", /* Used by: foreign_key_list */ + /* 35 */ "seq", + /* 36 */ "table", + /* 37 */ "from", + /* 38 */ "to", + /* 39 */ "on_update", + /* 40 */ "on_delete", + /* 41 */ "match", + /* 42 */ "table", /* Used by: foreign_key_check */ + /* 43 */ "rowid", + /* 44 */ "parent", + /* 45 */ "fkid", + /* 46 */ "busy", /* Used by: wal_checkpoint */ + /* 47 */ "log", + /* 48 */ "checkpointed", + /* 49 */ "timeout", /* Used by: busy_timeout */ + /* 50 */ "database", /* Used by: lock_status */ + /* 51 */ "status", }; /* Definitions of all built-in pragmas */ @@ -112798,7 +113842,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 46, 1, + /* ColNames: */ 49, 1, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "cache_size", @@ -112835,7 +113879,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 29, 2, + /* ColNames: */ 32, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) @@ -112906,15 +113950,15 @@ static const PragmaName aPragmaName[] = { #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) {/* zName: */ "foreign_key_check", /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, - /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 39, 4, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, + /* ColNames: */ 42, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) {/* zName: */ "foreign_key_list", /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 31, 8, + /* ColNames: */ 34, 8, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -112945,6 +113989,15 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ SQLITE_FullFSync }, #endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) +#if defined(SQLITE_INTROSPECTION_PRAGMAS) + {/* zName: */ "function_list", + /* ePragTyp: */ PragTyp_FUNCTION_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 29, 2, + /* iArg: */ 0 }, +#endif +#endif #if defined(SQLITE_HAS_CODEC) {/* zName: */ "hexkey", /* ePragTyp: */ PragTyp_HEXKEY, @@ -112993,7 +114046,7 @@ static const PragmaName aPragmaName[] = { #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "integrity_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, - /* ePragFlg: */ PragFlg_NeedSchema, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif @@ -113034,7 +114087,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "lock_status", /* ePragTyp: */ PragTyp_LOCK_STATUS, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 47, 2, + /* ColNames: */ 50, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -113054,6 +114107,17 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) +#if !defined(SQLITE_OMIT_VIRTUALTABLE) +#if defined(SQLITE_INTROSPECTION_PRAGMAS) + {/* zName: */ "module_list", + /* ePragTyp: */ PragTyp_MODULE_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 31, 1, + /* iArg: */ 0 }, +#endif +#endif +#endif {/* zName: */ "optimize", /* ePragTyp: */ PragTyp_OPTIMIZE, /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema, @@ -113078,6 +114142,13 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif +#if defined(SQLITE_INTROSPECTION_PRAGMAS) + {/* zName: */ "pragma_list", + /* ePragTyp: */ PragTyp_PRAGMA_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 31, 1, + /* iArg: */ 0 }, +#endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "query_only", /* ePragTyp: */ PragTyp_FLAG, @@ -113088,7 +114159,7 @@ static const PragmaName aPragmaName[] = { #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "quick_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, - /* ePragFlg: */ PragFlg_NeedSchema, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif @@ -113097,7 +114168,7 @@ static const PragmaName aPragmaName[] = { /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, - /* iArg: */ SQLITE_ReadUncommitted }, + /* iArg: */ SQLITE_ReadUncommit }, {/* zName: */ "recursive_triggers", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, @@ -113241,7 +114312,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 43, 3, + /* ColNames: */ 46, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -113249,10 +114320,10 @@ static const PragmaName aPragmaName[] = { /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, - /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, + /* iArg: */ SQLITE_WriteSchema }, #endif }; -/* Number of pragmas: 60 on by default, 74 total. */ +/* Number of pragmas: 60 on by default, 77 total. */ /************** End of pragma.h **********************************************/ /************** Continuing where we left off in pragma.c *********************/ @@ -113525,16 +114596,16 @@ static const PragmaName *pragmaLocate(const char *zName){ /* ** Helper subroutine for PRAGMA integrity_check: ** -** Generate code to output a single-column result row with the result -** held in register regResult. Decrement the result count and halt if -** the maximum number of result rows have been issued. +** Generate code to output a single-column result row with a value of the +** string held in register 3. Decrement the result count in register 1 +** and halt if the maximum number of result rows have been issued. */ -static int integrityCheckResultRow(Vdbe *v, int regResult){ +static int integrityCheckResultRow(Vdbe *v){ int addr; - sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 1); + sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); + sqlite3VdbeAddOp0(v, OP_Halt); return addr; } @@ -113742,18 +114813,22 @@ SQLITE_PRIVATE void sqlite3Pragma( /* ** PRAGMA [schema.]secure_delete - ** PRAGMA [schema.]secure_delete=ON/OFF + ** PRAGMA [schema.]secure_delete=ON/OFF/FAST ** ** The first form reports the current setting for the ** secure_delete flag. The second form changes the secure_delete - ** flag setting and reports thenew value. + ** flag setting and reports the new value. */ case PragTyp_SECURE_DELETE: { Btree *pBt = pDb->pBt; int b = -1; assert( pBt!=0 ); if( zRight ){ - b = sqlite3GetBoolean(zRight, 0); + if( sqlite3_stricmp(zRight, "fast")==0 ){ + b = 2; + }else{ + b = sqlite3GetBoolean(zRight, 0); + } } if( pId2->n==0 && b>=0 ){ int ii; @@ -114335,7 +115410,6 @@ SQLITE_PRIVATE void sqlite3Pragma( pCol->notNull ? 1 : 0, pCol->pDflt ? pCol->pDflt->u.zToken : 0, k); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); } } } @@ -114355,9 +115429,8 @@ SQLITE_PRIVATE void sqlite3Pragma( pTab->szTabRow, pTab->nRowLogEst, pTab->tabFlags); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - sqlite3VdbeMultiLoad(v, 2, "siii", + sqlite3VdbeMultiLoad(v, 2, "siiiX", pIdx->zName, pIdx->szIdxRow, pIdx->aiRowLogEst[0], @@ -114390,10 +115463,10 @@ SQLITE_PRIVATE void sqlite3Pragma( assert( pParse->nMem<=pPragma->nPragCName ); for(i=0; i<mx; i++){ i16 cnum = pIdx->aiColumn[i]; - sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum, + sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum, cnum<0 ? 0 : pTab->aCol[cnum].zName); if( pPragma->iArg ){ - sqlite3VdbeMultiLoad(v, 4, "isi", + sqlite3VdbeMultiLoad(v, 4, "isiX", pIdx->aSortOrder[i], pIdx->azColl[i], i<pIdx->nKeyCol); @@ -114420,7 +115493,6 @@ SQLITE_PRIVATE void sqlite3Pragma( IsUniqueIndex(pIdx), azOrigin[pIdx->idxType], pIdx->pPartIdxWhere!=0); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); } } } @@ -114436,7 +115508,6 @@ SQLITE_PRIVATE void sqlite3Pragma( i, db->aDb[i].zDbSName, sqlite3BtreeGetFilename(db->aDb[i].pBt)); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } } break; @@ -114448,10 +115519,49 @@ SQLITE_PRIVATE void sqlite3Pragma( for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ CollSeq *pColl = (CollSeq *)sqliteHashData(p); sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } } break; + +#ifdef SQLITE_INTROSPECTION_PRAGMAS + case PragTyp_FUNCTION_LIST: { + int i; + HashElem *j; + FuncDef *p; + pParse->nMem = 2; + for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){ + for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){ + sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1); + } + } + for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){ + p = (FuncDef*)sqliteHashData(j); + sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 0); + } + } + break; + +#ifndef SQLITE_OMIT_VIRTUALTABLE + case PragTyp_MODULE_LIST: { + HashElem *j; + pParse->nMem = 1; + for(j=sqliteHashFirst(&db->aModule); j; j=sqliteHashNext(j)){ + Module *pMod = (Module*)sqliteHashData(j); + sqlite3VdbeMultiLoad(v, 1, "s", pMod->zName); + } + } + break; +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + + case PragTyp_PRAGMA_LIST: { + int i; + for(i=0; i<ArraySize(aPragmaName); i++){ + sqlite3VdbeMultiLoad(v, 1, "s", aPragmaName[i].zName); + } + } + break; +#endif /* SQLITE_INTROSPECTION_PRAGMAS */ + #endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */ #ifndef SQLITE_OMIT_FOREIGN_KEY @@ -114477,7 +115587,6 @@ SQLITE_PRIVATE void sqlite3Pragma( actionName(pFK->aAction[1]), /* ON UPDATE */ actionName(pFK->aAction[0]), /* ON DELETE */ "NONE"); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8); } ++i; pFK = pFK->pNextFrom; @@ -114587,7 +115696,7 @@ SQLITE_PRIVATE void sqlite3Pragma( }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1); } - sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1); + sqlite3VdbeMultiLoad(v, regResult+2, "siX", pFK->zTo, i-1); sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4); sqlite3VdbeResolveLabel(v, addrOk); sqlite3DbFree(db, aiCols); @@ -114673,12 +115782,11 @@ SQLITE_PRIVATE void sqlite3Pragma( /* Do an integrity check on each database file */ for(i=0; i<db->nDb; i++){ - HashElem *x; - Hash *pTbls; - int *aRoot; - int cnt = 0; - int mxIdx = 0; - int nIdx; + HashElem *x; /* For looping over tables in the schema */ + Hash *pTbls; /* Set of all tables in the schema */ + int *aRoot; /* Array of root page numbers of all btrees */ + int cnt = 0; /* Number of entries in aRoot[] */ + int mxIdx = 0; /* Maximum number of indexes for any table */ if( OMIT_TEMPDB && i==1 ) continue; if( iDb>=0 && i!=iDb ) continue; @@ -114693,8 +115801,9 @@ SQLITE_PRIVATE void sqlite3Pragma( assert( sqlite3SchemaMutexHeld(db, i, 0) ); pTbls = &db->aDb[i].pSchema->tblHash; for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ - Table *pTab = sqliteHashData(x); - Index *pIdx; + Table *pTab = sqliteHashData(x); /* Current table */ + Index *pIdx; /* An index on pTab */ + int nIdx; /* Number of indexes on pTab */ if( HasRowid(pTab) ) cnt++; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } if( nIdx>mxIdx ) mxIdx = nIdx; @@ -114704,15 +115813,16 @@ SQLITE_PRIVATE void sqlite3Pragma( for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; - if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum; + if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - aRoot[cnt++] = pIdx->tnum; + aRoot[++cnt] = pIdx->tnum; } } - aRoot[cnt] = 0; + aRoot[0] = cnt; /* Make sure sufficient number of registers have been allocated */ pParse->nMem = MAX( pParse->nMem, 8+mxIdx ); + sqlite3ClearTempRegCache(pParse); /* Do the b-tree integrity checks */ sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY); @@ -114721,9 +115831,8 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName), P4_DYNAMIC); - sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); - integrityCheckResultRow(v, 2); + sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3); + integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, addr); /* Make sure all the indices are constructed correctly. @@ -114737,16 +115846,13 @@ SQLITE_PRIVATE void sqlite3Pragma( int r1 = -1; if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */ - if( pTab->pCheck==0 - && (pTab->tabFlags & TF_HasNotNull)==0 - && (pTab->pIndex==0 || isQuick) - ){ - continue; /* No additional checks needed for this table */ - } pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); sqlite3ExprCacheClear(pParse); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, 1, 0, &iDataCur, &iIdxCur); + /* reg[7] counts the number of entries in the table. + ** reg[8+i] counts the number of entries in the i-th index + */ sqlite3VdbeAddOp2(v, OP_Integer, 0, 7); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */ @@ -114767,7 +115873,7 @@ SQLITE_PRIVATE void sqlite3Pragma( zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, pTab->aCol[j].zName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); - integrityCheckResultRow(v, 3); + integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, jmp2); } /* Verify CHECK constraints */ @@ -114778,7 +115884,7 @@ SQLITE_PRIVATE void sqlite3Pragma( int addrCkOk = sqlite3VdbeMakeLabel(v); char *zErr; int k; - pParse->iSelfTab = iDataCur; + pParse->iSelfTab = iDataCur + 1; sqlite3ExprCachePush(pParse); for(k=pCheck->nExpr-1; k>0; k--){ sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0); @@ -114786,60 +115892,66 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, SQLITE_JUMPIFNULL); sqlite3VdbeResolveLabel(v, addrCkFault); + pParse->iSelfTab = 0; zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s", pTab->zName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); - integrityCheckResultRow(v, 3); + integrityCheckResultRow(v); sqlite3VdbeResolveLabel(v, addrCkOk); sqlite3ExprCachePop(pParse); } sqlite3ExprListDelete(db, pCheck); } - /* Validate index entries for the current row */ - for(j=0, pIdx=pTab->pIndex; pIdx && !isQuick; pIdx=pIdx->pNext, j++){ - int jmp2, jmp3, jmp4, jmp5; - int ckUniq = sqlite3VdbeMakeLabel(v); - if( pPk==pIdx ) continue; - r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, - pPrior, r1); - pPrior = pIdx; - sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */ - /* Verify that an index entry exists for the current table row */ - jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, - pIdx->nColumn); VdbeCoverage(v); - sqlite3VdbeLoadString(v, 3, "row "); - sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); - sqlite3VdbeLoadString(v, 4, " missing from index "); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); - jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); - jmp4 = integrityCheckResultRow(v, 3); - sqlite3VdbeJumpHere(v, jmp2); - /* For UNIQUE indexes, verify that only one entry exists with the - ** current key. The entry is unique if (1) any column is NULL - ** or (2) the next entry has a different key */ - if( IsUniqueIndex(pIdx) ){ - int uniqOk = sqlite3VdbeMakeLabel(v); - int jmp6; - int kk; - for(kk=0; kk<pIdx->nKeyCol; kk++){ - int iCol = pIdx->aiColumn[kk]; - assert( iCol!=XN_ROWID && iCol<pTab->nCol ); - if( iCol>=0 && pTab->aCol[iCol].notNull ) continue; - sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); - VdbeCoverage(v); + if( !isQuick ){ /* Omit the remaining tests for quick_check */ + /* Sanity check on record header decoding */ + sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + /* Validate index entries for the current row */ + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + int jmp2, jmp3, jmp4, jmp5; + int ckUniq = sqlite3VdbeMakeLabel(v); + if( pPk==pIdx ) continue; + r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, + pPrior, r1); + pPrior = pIdx; + sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */ + /* Verify that an index entry exists for the current table row */ + jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, + pIdx->nColumn); VdbeCoverage(v); + sqlite3VdbeLoadString(v, 3, "row "); + sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); + sqlite3VdbeLoadString(v, 4, " missing from index "); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); + jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); + jmp4 = integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, jmp2); + /* For UNIQUE indexes, verify that only one entry exists with the + ** current key. The entry is unique if (1) any column is NULL + ** or (2) the next entry has a different key */ + if( IsUniqueIndex(pIdx) ){ + int uniqOk = sqlite3VdbeMakeLabel(v); + int jmp6; + int kk; + for(kk=0; kk<pIdx->nKeyCol; kk++){ + int iCol = pIdx->aiColumn[kk]; + assert( iCol!=XN_ROWID && iCol<pTab->nCol ); + if( iCol>=0 && pTab->aCol[iCol].notNull ) continue; + sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); + VdbeCoverage(v); + } + jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); + sqlite3VdbeGoto(v, uniqOk); + sqlite3VdbeJumpHere(v, jmp6); + sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, + pIdx->nKeyCol); VdbeCoverage(v); + sqlite3VdbeLoadString(v, 3, "non-unique entry in index "); + sqlite3VdbeGoto(v, jmp5); + sqlite3VdbeResolveLabel(v, uniqOk); } - jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); - sqlite3VdbeGoto(v, uniqOk); - sqlite3VdbeJumpHere(v, jmp6); - sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, - pIdx->nKeyCol); VdbeCoverage(v); - sqlite3VdbeLoadString(v, 3, "non-unique entry in index "); - sqlite3VdbeGoto(v, jmp5); - sqlite3VdbeResolveLabel(v, uniqOk); + sqlite3VdbeJumpHere(v, jmp4); + sqlite3ResolvePartIdxLabel(pParse, jmp3); } - sqlite3VdbeJumpHere(v, jmp4); - sqlite3ResolvePartIdxLabel(pParse, jmp3); } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); @@ -114851,9 +115963,9 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3); addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); - sqlite3VdbeLoadString(v, 3, pIdx->zName); - sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7); - integrityCheckResultRow(v, 7); + sqlite3VdbeLoadString(v, 4, pIdx->zName); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3); + integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, addr); } } @@ -114867,6 +115979,9 @@ SQLITE_PRIVATE void sqlite3Pragma( { OP_IfNotZero, 1, 4, 0}, /* 1 */ { OP_String8, 0, 3, 0}, /* 2 */ { OP_ResultRow, 3, 1, 0}, /* 3 */ + { OP_Halt, 0, 0, 0}, /* 4 */ + { OP_String8, 0, 3, 0}, /* 5 */ + { OP_Goto, 0, 3, 0}, /* 6 */ }; VdbeOp *aOp; @@ -114875,7 +115990,10 @@ SQLITE_PRIVATE void sqlite3Pragma( aOp[0].p2 = 1-mxErr; aOp[2].p4type = P4_STATIC; aOp[2].p4.z = "ok"; + aOp[5].p4type = P4_STATIC; + aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT); } + sqlite3VdbeChangeP3(v, 0, sqlite3VdbeCurrentAddr(v)-2); } } break; @@ -115127,7 +116245,8 @@ SQLITE_PRIVATE void sqlite3Pragma( ** 0x0008 (Not yet implemented) Create indexes that might have ** been helpful to recent queries ** - ** The default MASK is and always shall be 0xfffe. 0xfffe means perform all ** of the optimizations listed above except Debug Mode, including new + ** The default MASK is and always shall be 0xfffe. 0xfffe means perform all + ** of the optimizations listed above except Debug Mode, including new ** optimizations that have not yet been invented. If new optimizations are ** ever added that should be off by default, those off-by-default ** optimizations will have bitmasks of 0x10000 or larger. @@ -115289,7 +116408,6 @@ SQLITE_PRIVATE void sqlite3Pragma( zState = azLockName[j]; } sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } break; } @@ -115555,10 +116673,14 @@ static int pragmaVtabFilter( pragmaVtabCursorClear(pCsr); j = (pTab->pName->mPragFlg & PragFlg_Result1)!=0 ? 0 : 1; for(i=0; i<argc; i++, j++){ + const char *zText = (const char*)sqlite3_value_text(argv[i]); assert( j<ArraySize(pCsr->azArg) ); - pCsr->azArg[j] = sqlite3_mprintf("%s", sqlite3_value_text(argv[i])); - if( pCsr->azArg[j]==0 ){ - return SQLITE_NOMEM; + assert( pCsr->azArg[j]==0 ); + if( zText ){ + pCsr->azArg[j] = sqlite3_mprintf("%s", zText); + if( pCsr->azArg[j]==0 ){ + return SQLITE_NOMEM; + } } } sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]); @@ -115691,7 +116813,7 @@ static void corruptSchema( const char *zExtra /* Error information */ ){ sqlite3 *db = pData->db; - if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){ + if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){ char *z; if( zObj==0 ) zObj = "?"; z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); @@ -115751,7 +116873,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; - assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 ); + assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); @@ -115816,6 +116938,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ assert( sqlite3_mutex_held(db->mutex) ); assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); + db->init.busy = 1; + /* Construct the in-memory representation schema tables (sqlite_master or ** sqlite_temp_master) by invoking the parser directly. The appropriate ** table name will be inserted automatically by the parser so we can just @@ -115824,7 +116948,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ azArg[0] = zMasterName = SCHEMA_TABLE(iDb); azArg[1] = "1"; azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text," - "rootpage integer,sql text)"; + "rootpage int,sql text)"; azArg[3] = 0; initData.db = db; initData.iDb = iDb; @@ -115840,10 +116964,10 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ */ pDb = &db->aDb[iDb]; if( pDb->pBt==0 ){ - if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){ - DbSetProperty(db, 1, DB_SchemaLoaded); - } - return SQLITE_OK; + assert( iDb==1 ); + DbSetProperty(db, 1, DB_SchemaLoaded); + rc = SQLITE_OK; + goto error_out; } /* If there is not already a read-only (or read-write) transaction opened @@ -115978,8 +117102,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); } - if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){ - /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider + if( rc==SQLITE_OK || (db->flags&SQLITE_WriteSchema)){ + /* Black magic: If the SQLITE_WriteSchema flag is set, then consider ** the schema loaded, even if errors occurred. In this situation the ** current sqlite3_prepare() operation will fail, but the following one ** will attempt to compile the supplied statement against whatever subset @@ -116002,9 +117126,13 @@ initone_error_out: sqlite3BtreeLeave(pDb->pBt); error_out: - if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ - sqlite3OomFault(db); + if( rc ){ + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ + sqlite3OomFault(db); + } + sqlite3ResetOneSchema(db, iDb); } + db->init.busy = 0; return rc; } @@ -116020,42 +117148,29 @@ error_out: */ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int i, rc; - int commit_internal = !(db->flags&SQLITE_InternChanges); + int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange); assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); assert( db->init.busy==0 ); - rc = SQLITE_OK; - db->init.busy = 1; ENC(db) = SCHEMA_ENC(db); - for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ - if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; - rc = sqlite3InitOne(db, i, pzErrMsg); - if( rc ){ - sqlite3ResetOneSchema(db, i); - } + assert( db->nDb>0 ); + /* Do the main schema first */ + if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){ + rc = sqlite3InitOne(db, 0, pzErrMsg); + if( rc ) return rc; } - - /* Once all the other databases have been initialized, load the schema - ** for the TEMP database. This is loaded last, as the TEMP database - ** schema may contain references to objects in other databases. - */ -#ifndef SQLITE_OMIT_TEMPDB - assert( db->nDb>1 ); - if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ - rc = sqlite3InitOne(db, 1, pzErrMsg); - if( rc ){ - sqlite3ResetOneSchema(db, 1); + /* All other schemas after the main schema. The "temp" schema must be last */ + for(i=db->nDb-1; i>0; i--){ + if( !DbHasProperty(db, i, DB_SchemaLoaded) ){ + rc = sqlite3InitOne(db, i, pzErrMsg); + if( rc ) return rc; } } -#endif - - db->init.busy = 0; - if( rc==SQLITE_OK && commit_internal ){ + if( commit_internal ){ sqlite3CommitInternalChanges(db); } - - return rc; + return SQLITE_OK; } /* @@ -116160,16 +117275,14 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ ** Free all memory allocations in the pParse object */ SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){ - if( pParse ){ - sqlite3 *db = pParse->db; - sqlite3DbFree(db, pParse->aLabel); - sqlite3ExprListDelete(db, pParse->pConstExpr); - if( db ){ - assert( db->lookaside.bDisable >= pParse->disableLookaside ); - db->lookaside.bDisable -= pParse->disableLookaside; - } - pParse->disableLookaside = 0; + sqlite3 *db = pParse->db; + sqlite3DbFree(db, pParse->aLabel); + sqlite3ExprListDelete(db, pParse->pConstExpr); + if( db ){ + assert( db->lookaside.bDisable >= pParse->disableLookaside ); + db->lookaside.bDisable -= pParse->disableLookaside; } + pParse->disableLookaside = 0; } /* @@ -116179,7 +117292,7 @@ static int sqlite3Prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ - int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ + u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pReprepare, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ @@ -116196,6 +117309,14 @@ static int sqlite3Prepare( /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */ assert( sqlite3_mutex_held(db->mutex) ); + /* For a long-term use prepared statement avoid the use of + ** lookaside memory. + */ + if( prepFlags & SQLITE_PREPARE_PERSISTENT ){ + sParse.disableLookaside++; + db->lookaside.bDisable++; + } + /* Check to verify that it is possible to get a read lock on all ** database schemas. The inability to get a read lock indicates that ** some other database connection is holding a write-lock, which in @@ -116227,7 +117348,7 @@ static int sqlite3Prepare( if( rc ){ const char *zDb = db->aDb[i].zDbSName; sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); - testcase( db->flags & SQLITE_ReadUncommitted ); + testcase( db->flags & SQLITE_ReadUncommit ); goto end_prepare; } } @@ -116295,8 +117416,7 @@ static int sqlite3Prepare( #endif if( db->init.busy==0 ){ - Vdbe *pVdbe = sParse.pVdbe; - sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag); + sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags); } if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){ sqlite3VdbeFinalize(sParse.pVdbe); @@ -116330,7 +117450,7 @@ static int sqlite3LockAndPrepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ - int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ + u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pOld, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ @@ -116346,10 +117466,11 @@ static int sqlite3LockAndPrepare( } sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); - rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); + rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); if( rc==SQLITE_SCHEMA ){ + sqlite3ResetOneSchema(db, -1); sqlite3_finalize(*ppStmt); - rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); + rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); } sqlite3BtreeLeaveAll(db); sqlite3_mutex_leave(db->mutex); @@ -116370,13 +117491,15 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){ sqlite3_stmt *pNew; const char *zSql; sqlite3 *db; + u8 prepFlags; assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) ); zSql = sqlite3_sql((sqlite3_stmt *)p); assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */ db = sqlite3VdbeDb(p); assert( sqlite3_mutex_held(db->mutex) ); - rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0); + prepFlags = sqlite3VdbePrepareFlags(p); + rc = sqlite3LockAndPrepare(db, zSql, -1, prepFlags, p, &pNew, 0); if( rc ){ if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); @@ -116422,8 +117545,36 @@ SQLITE_API int sqlite3_prepare_v2( const char **pzTail /* OUT: End of parsed string */ ){ int rc; - rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail); - assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ + /* EVIDENCE-OF: R-37923-12173 The sqlite3_prepare_v2() interface works + ** exactly the same as sqlite3_prepare_v3() with a zero prepFlags + ** parameter. + ** + ** Proof in that the 5th parameter to sqlite3LockAndPrepare is 0 */ + rc = sqlite3LockAndPrepare(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,0, + ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); + return rc; +} +SQLITE_API int sqlite3_prepare_v3( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char **pzTail /* OUT: End of parsed string */ +){ + int rc; + /* EVIDENCE-OF: R-56861-42673 sqlite3_prepare_v3() differs from + ** sqlite3_prepare_v2() only in having the extra prepFlags parameter, + ** which is a bit array consisting of zero or more of the + ** SQLITE_PREPARE_* flags. + ** + ** Proof by comparison to the implementation of sqlite3_prepare_v2() + ** directly above. */ + rc = sqlite3LockAndPrepare(db,zSql,nBytes, + SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK), + 0,ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); return rc; } @@ -116436,7 +117587,7 @@ static int sqlite3Prepare16( sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ - int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */ + u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const void **pzTail /* OUT: End of parsed string */ ){ @@ -116464,7 +117615,7 @@ static int sqlite3Prepare16( sqlite3_mutex_enter(db->mutex); zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE); if( zSql8 ){ - rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8); + rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8); } if( zTail8 && pzTail ){ @@ -116510,7 +117661,22 @@ SQLITE_API int sqlite3_prepare16_v2( const void **pzTail /* OUT: End of parsed string */ ){ int rc; - rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail); + rc = sqlite3Prepare16(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ + return rc; +} +SQLITE_API int sqlite3_prepare16_v3( + sqlite3 *db, /* Database handle. */ + const void *zSql, /* UTF-16 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const void **pzTail /* OUT: End of parsed string */ +){ + int rc; + rc = sqlite3Prepare16(db,zSql,nBytes, + SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK), + ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } @@ -116596,7 +117762,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){ sqlite3ExprListDelete(db, p->pOrderBy); sqlite3ExprDelete(db, p->pLimit); sqlite3ExprDelete(db, p->pOffset); - if( p->pWith ) sqlite3WithDelete(db, p->pWith); + if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith); if( bFree ) sqlite3DbFreeNN(db, p); p = pPrior; bFree = 1; @@ -116639,7 +117805,8 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( pNew = &standin; } if( pEList==0 ){ - pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0)); + pEList = sqlite3ExprListAppend(pParse, 0, + sqlite3Expr(pParse->db,TK_ASTERISK,0)); } pNew->pEList = pEList; pNew->op = TK_SELECT; @@ -116663,7 +117830,8 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( pNew->pLimit = pLimit; pNew->pOffset = pOffset; pNew->pWith = 0; - assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || pParse->db->mallocFailed!=0 ); + assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 + || pParse->db->mallocFailed!=0 ); if( pParse->db->mallocFailed ) { clearSelect(pParse->db, pNew, pNew!=&standin); pNew = 0; @@ -116690,7 +117858,7 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){ ** Delete the given Select structure and all of its substructures. */ SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){ - if( p ) clearSelect(db, p, 1); + if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1); } /* @@ -116931,11 +118099,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ pLeft = &pSrc->a[0]; pRight = &pLeft[1]; for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){ - Table *pLeftTab = pLeft->pTab; Table *pRightTab = pRight->pTab; int isOuter; - if( NEVER(pLeftTab==0 || pRightTab==0) ) continue; + if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; isOuter = (pRight->fg.jointype & JT_OUTER)!=0; /* When the NATURAL keyword is present, add WHERE clause terms for @@ -117083,11 +118250,11 @@ static void pushOntoSorter( if( pParse->db->mallocFailed ) return; pOp->p2 = nKey + nData; pKI = pOp->p4.pKeyInfo; - memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */ + memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */ sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); - testcase( pKI->nXField>2 ); + testcase( pKI->nAllField > pKI->nKeyField+2 ); pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, - pKI->nXField-1); + pKI->nAllField-pKI->nKeyField-1); addrJmp = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); pSort->labelBkOut = sqlite3VdbeMakeLabel(v); @@ -117185,16 +118352,15 @@ static void codeDistinct( ** This routine generates the code for the inside of the inner loop ** of a SELECT. ** -** If srcTab is negative, then the pEList expressions +** If srcTab is negative, then the p->pEList expressions ** are evaluated in order to get the data for this row. If srcTab is -** zero or more, then data is pulled from srcTab and pEList is used only +** zero or more, then data is pulled from srcTab and p->pEList is used only ** to get the number of columns and the collation sequence for each column. */ static void selectInnerLoop( Parse *pParse, /* The parser context */ Select *p, /* The complete select statement being coded */ - ExprList *pEList, /* List of values being extracted */ - int srcTab, /* Pull data from this table */ + int srcTab, /* Pull data from this table if non-negative */ SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */ DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */ SelectDest *pDest, /* How to dispose of the results */ @@ -117218,7 +118384,7 @@ static void selectInnerLoop( int regOrig; /* Start of memory holding full result (or 0) */ assert( v ); - assert( pEList!=0 ); + assert( p->pEList!=0 ); hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; if( pSort && pSort->pOrderBy==0 ) pSort = 0; if( pSort==0 && !hasDistinct ){ @@ -117228,7 +118394,7 @@ static void selectInnerLoop( /* Pull the requested columns. */ - nResultCol = pEList->nExpr; + nResultCol = p->pEList->nExpr; if( pDest->iSdst==0 ){ if( pSort ){ @@ -117251,7 +118417,7 @@ static void selectInnerLoop( if( srcTab>=0 ){ for(i=0; i<nResultCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i); - VdbeComment((v, "%s", pEList->a[i].zName)); + VdbeComment((v, "%s", p->pEList->a[i].zName)); } }else if( eDest!=SRT_Exists ){ /* If the destination is an EXISTS(...) expression, the actual @@ -117264,24 +118430,25 @@ static void selectInnerLoop( ecelFlags = 0; } if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){ - /* For each expression in pEList that is a copy of an expression in + /* For each expression in p->pEList that is a copy of an expression in ** the ORDER BY clause (pSort->pOrderBy), set the associated ** iOrderByCol value to one more than the index of the ORDER BY ** expression within the sort-key that pushOntoSorter() will generate. - ** This allows the pEList field to be omitted from the sorted record, + ** This allows the p->pEList field to be omitted from the sorted record, ** saving space and CPU cycles. */ ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF); for(i=pSort->nOBSat; i<pSort->pOrderBy->nExpr; i++){ int j; if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){ - pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat; + p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat; } } regOrig = 0; assert( eDest==SRT_Set || eDest==SRT_Mem || eDest==SRT_Coroutine || eDest==SRT_Output ); } - nResultCol = sqlite3ExprCodeExprList(pParse,pEList,regResult,0,ecelFlags); + nResultCol = sqlite3ExprCodeExprList(pParse,p->pEList,regResult, + 0,ecelFlags); } /* If the DISTINCT keyword was present on the SELECT statement @@ -117313,7 +118480,7 @@ static void selectInnerLoop( iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; for(i=0; i<nResultCol; i++){ - CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr); + CollSeq *pColl = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr); if( i<nResultCol-1 ){ sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i); VdbeCoverage(v); @@ -117552,12 +118719,12 @@ static void selectInnerLoop( ** X extra columns. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ - int nExtra = (N+X)*(sizeof(CollSeq*)+1); + int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*); KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra); if( p ){ p->aSortOrder = (u8*)&p->aColl[N+X]; - p->nField = (u16)N; - p->nXField = (u16)X; + p->nKeyField = (u16)N; + p->nAllField = (u16)(N+X); p->enc = ENC(db); p->db = db; p->nRef = 1; @@ -117631,10 +118798,7 @@ static KeyInfo *keyInfoFromExprList( if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){ - CollSeq *pColl; - pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr); - if( !pColl ) pColl = db->pDfltColl; - pInfo->aColl[i-iStart] = pColl; + pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr); pInfo->aSortOrder[i-iStart] = pItem->sortOrder; } } @@ -117884,23 +119048,23 @@ static void generateSortTail( ** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used. */ #ifdef SQLITE_ENABLE_COLUMN_METADATA -# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F) +# define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E) #else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */ -# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F) +# define columnType(A,B,C,D,E) columnTypeImpl(A,B) #endif static const char *columnTypeImpl( NameContext *pNC, +#ifndef SQLITE_ENABLE_COLUMN_METADATA + Expr *pExpr +#else Expr *pExpr, -#ifdef SQLITE_ENABLE_COLUMN_METADATA const char **pzOrigDb, const char **pzOrigTab, - const char **pzOrigCol, + const char **pzOrigCol #endif - u8 *pEstWidth ){ char const *zType = 0; int j; - u8 estWidth = 1; #ifdef SQLITE_ENABLE_COLUMN_METADATA char const *zOrigDb = 0; char const *zOrigTab = 0; @@ -117959,46 +119123,42 @@ static const char *columnTypeImpl( ** of the SELECT statement. Return the declaration type and origin ** data for the result-set column of the sub-select. */ - if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){ + if( iCol>=0 && iCol<pS->pEList->nExpr ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see ** test case misc2.2.2) - it always evaluates to NULL. - ** - ** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been - ** caught already by name resolution. */ NameContext sNC; Expr *p = pS->pEList->a[iCol].pExpr; sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; - zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth); + zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol); } - }else if( pTab->pSchema ){ - /* A real table */ + }else{ + /* A real table or a CTE table */ assert( !pS ); - if( iCol<0 ) iCol = pTab->iPKey; - assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); #ifdef SQLITE_ENABLE_COLUMN_METADATA + if( iCol<0 ) iCol = pTab->iPKey; + assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ zType = "INTEGER"; zOrigCol = "rowid"; }else{ zOrigCol = pTab->aCol[iCol].zName; zType = sqlite3ColumnType(&pTab->aCol[iCol],0); - estWidth = pTab->aCol[iCol].szEst; } zOrigTab = pTab->zName; - if( pNC->pParse ){ + if( pNC->pParse && pTab->pSchema ){ int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema); zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName; } #else + assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ zType = "INTEGER"; }else{ zType = sqlite3ColumnType(&pTab->aCol[iCol],0); - estWidth = pTab->aCol[iCol].szEst; } #endif } @@ -118017,7 +119177,7 @@ static const char *columnTypeImpl( sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; - zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth); + zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); break; } #endif @@ -118031,7 +119191,6 @@ static const char *columnTypeImpl( *pzOrigCol = zOrigCol; } #endif - if( pEstWidth ) *pEstWidth = estWidth; return zType; } @@ -118058,7 +119217,7 @@ static void generateColumnTypes( const char *zOrigDb = 0; const char *zOrigTab = 0; const char *zOrigCol = 0; - zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0); + zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); /* The vdbe must make its own copy of the column-type and other ** column specific strings, in case the schema is reset before this @@ -118068,41 +119227,56 @@ static void generateColumnTypes( sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT); sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT); #else - zType = columnType(&sNC, p, 0, 0, 0, 0); + zType = columnType(&sNC, p, 0, 0, 0); #endif sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT); } #endif /* !defined(SQLITE_OMIT_DECLTYPE) */ } -/* -** Return the Table objecct in the SrcList that has cursor iCursor. -** Or return NULL if no such Table object exists in the SrcList. -*/ -static Table *tableWithCursor(SrcList *pList, int iCursor){ - int j; - for(j=0; j<pList->nSrc; j++){ - if( pList->a[j].iCursor==iCursor ) return pList->a[j].pTab; - } - return 0; -} - /* -** Generate code that will tell the VDBE the names of columns -** in the result set. This information is used to provide the -** azCol[] values in the callback. +** Compute the column names for a SELECT statement. +** +** The only guarantee that SQLite makes about column names is that if the +** column has an AS clause assigning it a name, that will be the name used. +** That is the only documented guarantee. However, countless applications +** developed over the years have made baseless assumptions about column names +** and will break if those assumptions changes. Hence, use extreme caution +** when modifying this routine to avoid breaking legacy. +** +** See Also: sqlite3ColumnsFromExprList() +** +** The PRAGMA short_column_names and PRAGMA full_column_names settings are +** deprecated. The default setting is short=ON, full=OFF. 99.9% of all +** applications should operate this way. Nevertheless, we need to support the +** other modes for legacy: +** +** short=OFF, full=OFF: Column name is the text of the expression has it +** originally appears in the SELECT statement. In +** other words, the zSpan of the result expression. +** +** short=ON, full=OFF: (This is the default setting). If the result +** refers directly to a table column, then the +** result column name is just the table column +** name: COLUMN. Otherwise use zSpan. +** +** full=ON, short=ANY: If the result refers directly to a table column, +** then the result column name with the table name +** prefix, ex: TABLE.COLUMN. Otherwise use zSpan. */ static void generateColumnNames( Parse *pParse, /* Parser context */ - SrcList *pTabList, /* List of tables */ - ExprList *pEList /* Expressions defining the result set */ + Select *pSelect /* Generate column names for this SELECT statement */ ){ Vdbe *v = pParse->pVdbe; int i; Table *pTab; + SrcList *pTabList; + ExprList *pEList; sqlite3 *db = pParse->db; - int fullNames, shortNames; + int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */ + int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */ #ifndef SQLITE_OMIT_EXPLAIN /* If this is an EXPLAIN, skip this step */ @@ -118112,24 +119286,31 @@ static void generateColumnNames( #endif if( pParse->colNamesSet || db->mallocFailed ) return; + /* Column names are determined by the left-most term of a compound select */ + while( pSelect->pPrior ) pSelect = pSelect->pPrior; + pTabList = pSelect->pSrc; + pEList = pSelect->pEList; assert( v!=0 ); assert( pTabList!=0 ); pParse->colNamesSet = 1; - fullNames = (db->flags & SQLITE_FullColNames)!=0; - shortNames = (db->flags & SQLITE_ShortColNames)!=0; + fullName = (db->flags & SQLITE_FullColNames)!=0; + srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; i<pEList->nExpr; i++){ - Expr *p; - p = pEList->a[i].pExpr; - if( NEVER(p==0) ) continue; + Expr *p = pEList->a[i].pExpr; + + assert( p!=0 ); + assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ + assert( p->op!=TK_COLUMN || p->pTab!=0 ); /* Covering idx not yet coded */ if( pEList->a[i].zName ){ + /* An AS clause always takes first priority */ char *zName = pEList->a[i].zName; sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT); - }else if( (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN) - && (pTab = tableWithCursor(pTabList, p->iTable))!=0 - ){ + }else if( srcName && p->op==TK_COLUMN ){ char *zCol; int iCol = p->iColumn; + pTab = p->pTab; + assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ @@ -118137,10 +119318,7 @@ static void generateColumnNames( }else{ zCol = pTab->aCol[iCol].zName; } - if( !shortNames && !fullNames ){ - sqlite3VdbeSetColName(v, i, COLNAME_NAME, - sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC); - }else if( fullNames ){ + if( fullName ){ char *zName = 0; zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol); sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC); @@ -118168,6 +119346,15 @@ static void generateColumnNames( ** ** Return SQLITE_OK on success. If a memory allocation error occurs, ** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM. +** +** The only guarantee that SQLite makes about column names is that if the +** column has an AS clause assigning it a name, that will be the name used. +** That is the only documented guarantee. However, countless applications +** developed over the years have made baseless assumptions about column names +** and will break if those assumptions changes. Hence, use extreme caution +** when modifying this routine to avoid breaking legacy. +** +** See Also: generateColumnNames() */ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( Parse *pParse, /* Parsing context */ @@ -118180,7 +119367,6 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( u32 cnt; /* Index added to make the name unique */ Column *aCol, *pCol; /* For looping over result columns */ int nCol; /* Number of columns in the result set */ - Expr *p; /* Expression for a single result column */ char *zName; /* Column name */ int nName; /* Size of name in zName[] */ Hash ht; /* Hash table of column names */ @@ -118190,6 +119376,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( nCol = pEList->nExpr; aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol); testcase( aCol==0 ); + if( nCol>32767 ) nCol = 32767; }else{ nCol = 0; aCol = 0; @@ -118201,20 +119388,20 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){ /* Get an appropriate name for the column */ - p = sqlite3ExprSkipCollate(pEList->a[i].pExpr); if( (zName = pEList->a[i].zName)!=0 ){ /* If the column contains an "AS <name>" phrase, use <name> as the name */ }else{ - Expr *pColExpr = p; /* The expression that is the result column name */ - Table *pTab; /* Table associated with this expression */ + Expr *pColExpr = sqlite3ExprSkipCollate(pEList->a[i].pExpr); while( pColExpr->op==TK_DOT ){ pColExpr = pColExpr->pRight; assert( pColExpr!=0 ); } - if( pColExpr->op==TK_COLUMN && pColExpr->pTab!=0 ){ + if( (pColExpr->op==TK_COLUMN || pColExpr->op==TK_AGG_COLUMN) + && pColExpr->pTab!=0 + ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; - pTab = pColExpr->pTab; + Table *pTab = pColExpr->pTab; if( iCol<0 ) iCol = pTab->iPKey; zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; }else if( pColExpr->op==TK_ID ){ @@ -118225,7 +119412,11 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( zName = pEList->a[i].zSpan; } } - zName = sqlite3MPrintf(db, "%s", zName); + if( zName ){ + zName = sqlite3DbStrDup(db, zName); + }else{ + zName = sqlite3MPrintf(db,"column%d",i+1); + } /* Make sure the column name is unique. If the name is not unique, ** append an integer to the name so that it becomes unique. @@ -118282,7 +119473,6 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation( int i; Expr *p; struct ExprList_item *a; - u64 szAll = 0; assert( pSelect!=0 ); assert( (pSelect->selFlags & SF_Resolved)!=0 ); @@ -118295,10 +119485,11 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation( const char *zType; int n, m; p = a[i].pExpr; - zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst); - szAll += pCol->szEst; + zType = columnType(&sNC, p, 0, 0, 0); + /* pCol->szEst = ... // Column size est for SELECT tables never used */ pCol->affinity = sqlite3ExprAffinity(p); - if( zType && (m = sqlite3Strlen30(zType))>0 ){ + if( zType ){ + m = sqlite3Strlen30(zType); n = sqlite3Strlen30(pCol->zName); pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2); if( pCol->zName ){ @@ -118312,7 +119503,7 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation( pCol->zColl = sqlite3DbStrDup(db, pColl->zName); } } - pTab->szTabRow = sqlite3LogEst(szAll*4); + pTab->szTabRow = 1; /* Any non-zero value works */ } /* @@ -118355,19 +119546,16 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ ** Get a VDBE for the given parser context. Create a new one if necessary. ** If an error occurs, return NULL and leave a message in pParse. */ -static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){ - Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(pParse); - if( v ) sqlite3VdbeAddOp2(v, OP_Init, 0, 1); +SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){ + if( pParse->pVdbe ){ + return pParse->pVdbe; + } if( pParse->pToplevel==0 && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst) ){ pParse->okConstFactor = 1; } - return v; -} -SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){ - Vdbe *v = pParse->pVdbe; - return v ? v : allocVdbe(pParse); + return sqlite3VdbeCreate(pParse); } @@ -118640,7 +119828,7 @@ static void generateWithRecursiveQuery( /* Output the single row in Current */ addrCont = sqlite3VdbeMakeLabel(v); codeOffset(v, regOffset, addrCont); - selectInnerLoop(pParse, p, p->pEList, iCurrent, + selectInnerLoop(pParse, p, iCurrent, 0, 0, pDest, addrCont, addrBreak); if( regLimit ){ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak); @@ -118778,15 +119966,9 @@ static int multiSelect( db = pParse->db; pPrior = p->pPrior; dest = *pDest; - if( pPrior->pOrderBy ){ - sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before", - selectOpName(p->op)); - rc = 1; - goto multi_select_end; - } - if( pPrior->pLimit ){ - sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before", - selectOpName(p->op)); + if( pPrior->pOrderBy || pPrior->pLimit ){ + sqlite3ErrorMsg(pParse,"%s clause should come after %s not before", + pPrior->pOrderBy!=0 ? "ORDER BY" : "LIMIT", selectOpName(p->op)); rc = 1; goto multi_select_end; } @@ -118954,17 +120136,12 @@ static int multiSelect( if( dest.eDest!=priorOp ){ int iCont, iBreak, iStart; assert( p->pEList ); - if( dest.eDest==SRT_Output ){ - Select *pFirst = p; - while( pFirst->pPrior ) pFirst = pFirst->pPrior; - generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); - } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); iStart = sqlite3VdbeCurrentAddr(v); - selectInnerLoop(pParse, p, p->pEList, unionTab, + selectInnerLoop(pParse, p, unionTab, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); @@ -119029,11 +120206,6 @@ static int multiSelect( ** tables. */ assert( p->pEList ); - if( dest.eDest==SRT_Output ){ - Select *pFirst = p; - while( pFirst->pPrior ) pFirst = pFirst->pPrior; - generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); - } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); @@ -119042,7 +120214,7 @@ static int multiSelect( iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, r1); - selectInnerLoop(pParse, p, p->pEList, tab1, + selectInnerLoop(pParse, p, tab1, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); @@ -119641,14 +120813,6 @@ static int multiSelectOrderBy( */ sqlite3VdbeResolveLabel(v, labelEnd); - /* Set the number of output columns - */ - if( pDest->eDest==SRT_Output ){ - Select *pFirst = pPrior; - while( pFirst->pPrior ) pFirst = pFirst->pPrior; - generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); - } - /* Reassembly the compound query so that it will be freed correctly ** by the calling function */ if( p->pPrior ){ @@ -119702,7 +120866,9 @@ static Expr *substExpr( Expr *pExpr /* Expr in which substitution occurs */ ){ if( pExpr==0 ) return 0; - if( ExprHasProperty(pExpr, EP_FromJoin) && pExpr->iRightJoinTable==pSubst->iTable ){ + if( ExprHasProperty(pExpr, EP_FromJoin) + && pExpr->iRightJoinTable==pSubst->iTable + ){ pExpr->iRightJoinTable = pSubst->iNewTable; } if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){ @@ -119726,9 +120892,12 @@ static Expr *substExpr( pCopy = &ifNullRow; } pNew = sqlite3ExprDup(db, pCopy, 0); - if( pNew && (pExpr->flags & EP_FromJoin) ){ + if( pNew && pSubst->isLeftJoin ){ + ExprSetProperty(pNew, EP_CanBeNull); + } + if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){ pNew->iRightJoinTable = pExpr->iRightJoinTable; - pNew->flags |= EP_FromJoin; + ExprSetProperty(pNew, EP_FromJoin); } sqlite3ExprDelete(db, pExpr); pExpr = pNew; @@ -119812,67 +120981,74 @@ static void substSelect( ** exist on the table t1, a complete scan of the data might be ** avoided. ** -** Flattening is only attempted if all of the following are true: +** Flattening is subject to the following constraints: ** -** (1) The subquery and the outer query do not both use aggregates. +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** The subquery and the outer query cannot both be aggregates. ** -** (2) The subquery is not an aggregate or (2a) the outer query is not a join -** and (2b) the outer query does not use subqueries other than the one -** FROM-clause subquery that is a candidate for flattening. (2b is -** due to ticket [2f7170d73bf9abf80] from 2015-02-09.) +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** (2) If the subquery is an aggregate then +** (2a) the outer query must not be a join and +** (2b) the outer query must not use subqueries +** other than the one FROM-clause subquery that is a candidate +** for flattening. (This is due to ticket [2f7170d73bf9abf80] +** from 2015-02-09.) ** -** (3) The subquery is not the right operand of a LEFT JOIN -** or the subquery is not itself a join and the outer query is not -** an aggregate. +** (3) If the subquery is the right operand of a LEFT JOIN then +** (3a) the subquery may not be a join and +** (3b) the FROM clause of the subquery may not contain a virtual +** table and +** (3c) the outer query may not be an aggregate. ** -** (4) The subquery is not DISTINCT. +** (4) The subquery can not be DISTINCT. ** ** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT ** sub-queries that were excluded from this optimization. Restriction ** (4) has since been expanded to exclude all DISTINCT subqueries. ** -** (6) The subquery does not use aggregates or the outer query is not -** DISTINCT. +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** If the subquery is aggregate, the outer query may not be DISTINCT. ** -** (7) The subquery has a FROM clause. TODO: For subqueries without +** (7) The subquery must have a FROM clause. TODO: For subqueries without ** A FROM clause, consider adding a FROM clause with the special ** table sqlite_once that consists of a single row containing a ** single NULL. ** -** (8) The subquery does not use LIMIT or the outer query is not a join. +** (8) If the subquery uses LIMIT then the outer query may not be a join. ** -** (9) The subquery does not use LIMIT or the outer query does not use -** aggregates. +** (9) If the subquery uses LIMIT then the outer query may not be aggregate. ** ** (**) Restriction (10) was removed from the code on 2005-02-05 but we ** accidently carried the comment forward until 2014-09-15. Original -** text: "The subquery does not use aggregates or the outer query -** does not use LIMIT." +** constraint: "If the subquery is aggregate then the outer query +** may not use LIMIT." ** -** (11) The subquery and the outer query do not both have ORDER BY clauses. +** (11) The subquery and the outer query may not both have ORDER BY clauses. ** ** (**) Not implemented. Subsumed into restriction (3). Was previously ** a separate restriction deriving from ticket #350. ** -** (13) The subquery and outer query do not both use LIMIT. +** (13) The subquery and outer query may not both use LIMIT. ** -** (14) The subquery does not use OFFSET. +** (14) The subquery may not use OFFSET. ** -** (15) The outer query is not part of a compound select or the -** subquery does not have a LIMIT clause. +** (15) If the outer query is part of a compound select, then the +** subquery may not use LIMIT. ** (See ticket #2339 and ticket [02a8e81d44]). ** -** (16) The outer query is not an aggregate or the subquery does -** not contain ORDER BY. (Ticket #2942) This used to not matter +** (16) If the outer query is aggregate, then the subquery may not +** use ORDER BY. (Ticket #2942) This used to not matter ** until we introduced the group_concat() function. ** -** (17) The sub-query is not a compound select, or it is a UNION ALL -** compound clause made up entirely of non-aggregate queries, and -** the parent query: -** -** * is not itself part of a compound select, -** * is not an aggregate or DISTINCT query, and -** * is not a join +** (17) If the subquery is a compound select, then +** (17a) all compound operators must be a UNION ALL, and +** (17b) no terms within the subquery compound may be aggregate +** or DISTINCT, and +** (17c) every term within the subquery compound must have a FROM clause +** (17d) the outer query may not be +** (17d1) aggregate, or +** (17d2) DISTINCT, or +** (17d3) a join. ** ** The parent and sub-query may contain WHERE clauses. Subject to ** rules (11), (13) and (14), they may also contain ORDER BY, @@ -119888,29 +121064,32 @@ static void substSelect( ** syntax error and return a detailed message. ** ** (18) If the sub-query is a compound select, then all terms of the -** ORDER by clause of the parent must be simple references to +** ORDER BY clause of the parent must be simple references to ** columns of the sub-query. ** -** (19) The subquery does not use LIMIT or the outer query does not +** (19) If the subquery uses LIMIT then the outer query may not ** have a WHERE clause. ** -** (20) If the sub-query is a compound select, then it must not use -** an ORDER BY clause. Ticket #3773. We could relax this constraint -** somewhat by saying that the terms of the ORDER BY clause must -** appear as unmodified result columns in the outer query. But we -** have other optimizations in mind to deal with that case. +** (**) Subsumed into (17d3). Was: If the sub-query is a compound select, +** then it must not use an ORDER BY clause - Ticket #3773. Because +** of (17d3), then only way to have a compound subquery is if it is +** the only term in the FROM clause of the outer query. But if the +** only term in the FROM clause has an ORDER BY, then it will be +** implemented as a co-routine and the flattener will never be called. ** -** (21) The subquery does not use LIMIT or the outer query is not +** (21) If the subquery uses LIMIT then the outer query may not be ** DISTINCT. (See ticket [752e1646fc]). ** -** (22) The subquery is not a recursive CTE. +** (22) The subquery may not be a recursive CTE. ** -** (23) The parent is not a recursive CTE, or the sub-query is not a -** compound query. This restriction is because transforming the +** (**) Subsumed into restriction (17d3). Was: If the outer query is +** a recursive CTE, then the sub-query may not be a compound query. +** This restriction is because transforming the ** parent to a compound query confuses the code that handles ** recursive queries in multiSelect(). ** -** (24) The subquery is not an aggregate that uses the built-in min() or +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** The subquery may not be an aggregate that uses the built-in min() or ** or max() functions. (Without this restriction, a query like: ** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily ** return the value X for which Y was maximal.) @@ -119918,7 +121097,7 @@ static void substSelect( ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query -** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates. +** uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and returns 0. ** If flattening is attempted this routine returns 1. @@ -119930,8 +121109,7 @@ static int flattenSubquery( Parse *pParse, /* Parsing context */ Select *p, /* The parent or outer SELECT statement */ int iFrom, /* Index in p->pSrc->a[] of the inner subquery */ - int isAgg, /* True if outer SELECT uses aggregate functions */ - int subqueryIsAgg /* True if the subquery uses aggregate functions */ + int isAgg /* True if outer SELECT uses aggregate functions */ ){ const char *zSavedAuthContext = pParse->zAuthContext; Select *pParent; /* Current UNION ALL term of the other query */ @@ -119939,7 +121117,6 @@ static int flattenSubquery( Select *pSub1; /* Pointer to the rightmost select in sub-query */ SrcList *pSrc; /* The FROM clause of the outer query */ SrcList *pSubSrc; /* The FROM clause of the subquery */ - ExprList *pList; /* The result set of the outer query */ int iParent; /* VDBE cursor number of the pSub result set temp table */ int iNewParent = -1;/* Replacement table for iParent */ int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */ @@ -119951,7 +121128,7 @@ static int flattenSubquery( /* Check to see if flattening is permitted. Return 0 if not. */ assert( p!=0 ); - assert( p->pPrior==0 ); /* Unable to flatten compound queries */ + assert( p->pPrior==0 ); if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0; pSrc = p->pSrc; assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc ); @@ -119959,16 +121136,6 @@ static int flattenSubquery( iParent = pSubitem->iCursor; pSub = pSubitem->pSelect; assert( pSub!=0 ); - if( subqueryIsAgg ){ - if( isAgg ) return 0; /* Restriction (1) */ - if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */ - if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery)) - || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0 - || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0 - ){ - return 0; /* Restriction (2b) */ - } - } pSubSrc = pSub->pSrc; assert( pSubSrc ); @@ -119983,13 +121150,10 @@ static int flattenSubquery( return 0; /* Restriction (15) */ } if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */ - if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */ + if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (4) */ if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){ return 0; /* Restrictions (8)(9) */ } - if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){ - return 0; /* Restriction (6) */ - } if( p->pOrderBy && pSub->pOrderBy ){ return 0; /* Restriction (11) */ } @@ -119998,18 +121162,14 @@ static int flattenSubquery( if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){ return 0; /* Restriction (21) */ } - testcase( pSub->selFlags & SF_Recursive ); - testcase( pSub->selFlags & SF_MinMaxAgg ); - if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){ - return 0; /* Restrictions (22) and (24) */ - } - if( (p->selFlags & SF_Recursive) && pSub->pPrior ){ - return 0; /* Restriction (23) */ + if( pSub->selFlags & (SF_Recursive) ){ + return 0; /* Restrictions (22) */ } /* ** If the subquery is the right operand of a LEFT JOIN, then the - ** subquery may not be a join itself. Example of why this is not allowed: + ** subquery may not be a join itself (3a). Example of why this is not + ** allowed: ** ** t1 LEFT OUTER JOIN (t2 JOIN t3) ** @@ -120020,54 +121180,53 @@ static int flattenSubquery( ** which is not at all the same thing. ** ** If the subquery is the right operand of a LEFT JOIN, then the outer - ** query cannot be an aggregate. This is an artifact of the way aggregates - ** are processed - there is not mechanism to determine if the LEFT JOIN - ** table should be all-NULL. + ** query cannot be an aggregate. (3c) This is an artifact of the way + ** aggregates are processed - there is no mechanism to determine if + ** the LEFT JOIN table should be all-NULL. ** ** See also tickets #306, #350, and #3300. */ if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){ isLeftJoin = 1; - if( pSubSrc->nSrc>1 || isAgg ){ - return 0; /* Restriction (3) */ + if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){ + /* (3a) (3c) (3b) */ + return 0; } } #ifdef SQLITE_EXTRA_IFNULLROW else if( iFrom>0 && !isAgg ){ /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for - ** every reference to any result column from subquery in a join, even though - ** they are not necessary. This will stress-test the OP_IfNullRow opcode. */ + ** every reference to any result column from subquery in a join, even + ** though they are not necessary. This will stress-test the OP_IfNullRow + ** opcode. */ isLeftJoin = -1; } #endif - /* Restriction 17: If the sub-query is a compound SELECT, then it must + /* Restriction (17): If the sub-query is a compound SELECT, then it must ** use only the UNION ALL operator. And none of the simple select queries ** that make up the compound SELECT are allowed to be aggregate or distinct ** queries. */ if( pSub->pPrior ){ - if( pSub->pOrderBy ){ - return 0; /* Restriction 20 */ - } if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){ - return 0; + return 0; /* (17d1), (17d2), or (17d3) */ } for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){ testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate ); assert( pSub->pSrc!=0 ); assert( pSub->pEList->nExpr==pSub1->pEList->nExpr ); - if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 - || (pSub1->pPrior && pSub1->op!=TK_ALL) - || pSub1->pSrc->nSrc<1 + if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */ + || (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */ + || pSub1->pSrc->nSrc<1 /* (17c) */ ){ return 0; } testcase( pSub1->pSrc->nSrc>1 ); } - /* Restriction 18. */ + /* Restriction (18). */ if( p->pOrderBy ){ int ii; for(ii=0; ii<p->pOrderBy->nExpr; ii++){ @@ -120076,6 +121235,23 @@ static int flattenSubquery( } } + /* Ex-restriction (23): + ** The only way that the recursive part of a CTE can contain a compound + ** subquery is for the subquery to be one term of a join. But if the + ** subquery is a join, then the flattening has already been stopped by + ** restriction (17d3) + */ + assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 ); + + /* Ex-restriction (20): + ** A compound subquery must be the only term in the FROM clause of the + ** outer query by restriction (17d3). But if that term also has an + ** ORDER BY clause, then the subquery will be implemented by co-routine + ** and so the flattener will never be invoked. Hence, it is not possible + ** for the subquery to be a compound and have an ORDER BY clause. + */ + assert( pSub->pPrior==0 || pSub->pOrderBy==0 ); + /***** If we reach this point, flattening is permitted. *****/ SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n", pSub->zSelName, pSub, iFrom)); @@ -120264,14 +121440,6 @@ static int flattenSubquery( ** We look at every expression in the outer query and every place we see ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". */ - pList = pParent->pEList; - for(i=0; i<pList->nExpr; i++){ - if( pList->a[i].zName==0 ){ - char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan); - sqlite3Dequote(zName); - pList->a[i].zName = zName; - } - } if( pSub->pOrderBy ){ /* At this point, any non-zero iOrderByCol values indicate that the ** ORDER BY column expression is identical to the iOrderByCol'th @@ -120296,18 +121464,7 @@ static int flattenSubquery( if( isLeftJoin>0 ){ setJoinExpr(pWhere, iNewParent); } - if( subqueryIsAgg ){ - assert( pParent->pHaving==0 ); - pParent->pHaving = pParent->pWhere; - pParent->pWhere = pWhere; - pParent->pHaving = sqlite3ExprAnd(db, - sqlite3ExprDup(db, pSub->pHaving, 0), pParent->pHaving - ); - assert( pParent->pGroupBy==0 ); - pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0); - }else{ - pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere); - } + pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere); if( db->mallocFailed==0 ){ SubstContext x; x.pParse = pParse; @@ -120370,9 +121527,13 @@ static int flattenSubquery( ** ** Do not attempt this optimization if: ** -** (1) The inner query is an aggregate. (In that case, we'd really want -** to copy the outer WHERE-clause terms onto the HAVING clause of the -** inner query. But they probably won't help there so do not bother.) +** (1) (** This restriction was removed on 2017-09-29. We used to +** disallow this optimization for aggregate subqueries, but now +** it is allowed by putting the extra terms on the HAVING clause. +** The added HAVING clause is pointless if the subquery lacks +** a GROUP BY clause. But such a HAVING clause is also harmless +** so there does not appear to be any reason to add extra logic +** to suppress it. **) ** ** (2) The inner query is the recursive part of a common table expression. ** @@ -120397,16 +121558,22 @@ static int pushDownWhereTerms( ){ Expr *pNew; int nChng = 0; - Select *pX; /* For looping over compound SELECTs in pSubq */ if( pWhere==0 ) return 0; - for(pX=pSubq; pX; pX=pX->pPrior){ - if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){ - testcase( pX->selFlags & SF_Aggregate ); - testcase( pX->selFlags & SF_Recursive ); - testcase( pX!=pSubq ); - return 0; /* restrictions (1) and (2) */ + if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */ + +#ifdef SQLITE_DEBUG + /* Only the first term of a compound can have a WITH clause. But make + ** sure no other terms are marked SF_Recursive in case something changes + ** in the future. + */ + { + Select *pX; + for(pX=pSubq; pX; pX=pX->pPrior){ + assert( (pX->selFlags & (SF_Recursive))==0 ); } } +#endif + if( pSubq->pLimit!=0 ){ return 0; /* restriction (3) */ } @@ -120414,7 +121581,7 @@ static int pushDownWhereTerms( nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor); pWhere = pWhere->pLeft; } - if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */ + if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction (5) */ if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ nChng++; while( pSubq ){ @@ -120426,7 +121593,11 @@ static int pushDownWhereTerms( x.isLeftJoin = 0; x.pEList = pSubq->pEList; pNew = substExpr(&x, pNew); - pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew); + if( pSubq->selFlags & SF_Aggregate ){ + pSubq->pHaving = sqlite3ExprAnd(pParse->db, pSubq->pHaving, pNew); + }else{ + pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew); + } pSubq = pSubq->pPrior; } } @@ -120754,7 +121925,8 @@ static int withExpand( ); return SQLITE_ERROR; } - assert( pTab->nTabRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 )); + assert( pTab->nTabRef==1 || + ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 )); pCte->zCteErr = "circular reference: %s"; pSavedWith = pParse->pWith; @@ -120811,7 +121983,7 @@ static int withExpand( */ static void selectPopWith(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; - if( pParse->pWith && p->pPrior==0 ){ + if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){ With *pWith = findRightmost(p)->pWith; if( pWith!=0 ){ assert( pParse->pWith==pWith ); @@ -120866,7 +122038,7 @@ static int selectExpander(Walker *pWalker, Select *p){ } pTabList = p->pSrc; pEList = p->pEList; - if( p->pWith ){ + if( OK_IF_ALWAYS_TRUE(p->pWith) ){ sqlite3WithPush(pParse, p->pWith, 0); } @@ -120898,7 +122070,11 @@ static int selectExpander(Walker *pWalker, Select *p){ pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; pTab->nTabRef = 1; - pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab); + if( pFrom->zAlias ){ + pTab->zName = sqlite3DbStrDup(db, pFrom->zAlias); + }else{ + pTab->zName = sqlite3MPrintf(db, "subquery_%p", (void*)pTab); + } while( pSel->pPrior ){ pSel = pSel->pPrior; } sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; @@ -121108,12 +122284,10 @@ static int selectExpander(Walker *pWalker, Select *p){ sqlite3ExprListDelete(db, pEList); p->pEList = pNew; } -#if SQLITE_MAX_COLUMN if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns in result set"); return WRC_Abort; } -#endif return WRC_Continue; } @@ -121132,6 +122306,25 @@ SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ } /* +** No-op routine for the parse-tree walker for SELECT statements. +** subquery in the parser tree. +*/ +SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + return WRC_Continue; +} + +#if SQLITE_DEBUG +/* +** Always assert. This xSelectCallback2 implementation proves that the +** xSelectCallback2 is never invoked. +*/ +SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker *NotUsed, Select *NotUsed2){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + assert( 0 ); +} +#endif +/* ** This routine "expands" a SELECT statement and all of its subqueries. ** For additional information on what it means to "expand" a SELECT ** statement, see the comment on the selectExpand worker callback above. @@ -121146,11 +122339,11 @@ SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ */ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ Walker w; - memset(&w, 0, sizeof(w)); w.xExprCallback = sqlite3ExprWalkNoop; w.pParse = pParse; - if( pParse->hasCompound ){ + if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){ w.xSelectCallback = convertCompoundSelectToSubquery; + w.xSelectCallback2 = 0; sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; @@ -121210,7 +122403,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ #ifndef SQLITE_OMIT_SUBQUERY Walker w; - memset(&w, 0, sizeof(w)); + w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback2 = selectAddSubqueryTypeInfo; w.xExprCallback = sqlite3ExprWalkNoop; w.pParse = pParse; @@ -121236,15 +122429,13 @@ SQLITE_PRIVATE void sqlite3SelectPrep( Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for container */ ){ - sqlite3 *db; - if( NEVER(p==0) ) return; - db = pParse->db; - if( db->mallocFailed ) return; + assert( p!=0 || pParse->db->mallocFailed ); + if( pParse->db->mallocFailed ) return; if( p->selFlags & SF_HasTypeInfo ) return; sqlite3SelectExpand(pParse, p); - if( pParse->nErr || db->mallocFailed ) return; + if( pParse->nErr || pParse->db->mallocFailed ) return; sqlite3ResolveSelectNames(pParse, p, pOuterNC); - if( pParse->nErr || db->mallocFailed ) return; + if( pParse->nErr || pParse->db->mallocFailed ) return; sqlite3SelectAddTypeInfo(pParse, p); } @@ -121504,7 +122695,9 @@ static struct SrcList_item *isSelfJoinView( if( pItem->zName==0 ) continue; if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue; if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; - if( sqlite3ExprCompare(pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) ){ + if( sqlite3ExprCompare(0, + pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) + ){ /* The view was modified by some other optimization such as ** pushDownWhereTerms() */ continue; @@ -121514,6 +122707,88 @@ static struct SrcList_item *isSelfJoinView( return 0; } +#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION +/* +** Attempt to transform a query of the form +** +** SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2) +** +** Into this: +** +** SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2) +** +** The transformation only works if all of the following are true: +** +** * The subquery is a UNION ALL of two or more terms +** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries +** * The outer query is a simple count(*) +** +** Return TRUE if the optimization is undertaken. +*/ +static int countOfViewOptimization(Parse *pParse, Select *p){ + Select *pSub, *pPrior; + Expr *pExpr; + Expr *pCount; + sqlite3 *db; + if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ + if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ + pExpr = p->pEList->a[0].pExpr; + if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */ + if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */ + if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ + if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ + pSub = p->pSrc->a[0].pSelect; + if( pSub==0 ) return 0; /* The FROM is a subquery */ + if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */ + do{ + if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ + if( pSub->pWhere ) return 0; /* No WHERE clause */ + if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ + pSub = pSub->pPrior; /* Repeat over compound */ + }while( pSub ); + + /* If we reach this point then it is OK to perform the transformation */ + + db = pParse->db; + pCount = pExpr; + pExpr = 0; + pSub = p->pSrc->a[0].pSelect; + p->pSrc->a[0].pSelect = 0; + sqlite3SrcListDelete(db, p->pSrc); + p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); + while( pSub ){ + Expr *pTerm; + pPrior = pSub->pPrior; + pSub->pPrior = 0; + pSub->pNext = 0; + pSub->selFlags |= SF_Aggregate; + pSub->selFlags &= ~SF_Compound; + pSub->nSelectRow = 0; + sqlite3ExprListDelete(db, pSub->pEList); + pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount; + pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm); + pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, pTerm, pSub); + if( pExpr==0 ){ + pExpr = pTerm; + }else{ + pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr); + } + pSub = pPrior; + } + p->pEList->a[0].pExpr = pExpr; + p->selFlags &= ~SF_Aggregate; + +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + return 1; +} +#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */ + /* ** Generate code for the SELECT statement given in the p argument. ** @@ -121598,13 +122873,20 @@ SQLITE_PRIVATE int sqlite3Select( } #endif + /* Get a pointer the VDBE under construction, allocating a new VDBE if one + ** does not already exist */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto select_end; + if( pDest->eDest==SRT_Output ){ + generateColumnNames(pParse, p); + } + /* Try to flatten subqueries in the FROM clause up into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && i<pTabList->nSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; Select *pSub = pItem->pSelect; - int isAggSub; Table *pTab = pItem->pTab; if( pSub==0 ) continue; @@ -121616,13 +122898,36 @@ SQLITE_PRIVATE int sqlite3Select( goto select_end; } - isAggSub = (pSub->selFlags & SF_Aggregate)!=0; - if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ + /* Do not try to flatten an aggregate subquery. + ** + ** Flattening an aggregate subquery is only possible if the outer query + ** is not a join. But if the outer query is not a join, then the subquery + ** will be implemented as a co-routine and there is no advantage to + ** flattening in that case. + */ + if( (pSub->selFlags & SF_Aggregate)!=0 ) continue; + assert( pSub->pGroupBy==0 ); + + /* If the subquery contains an ORDER BY clause and if + ** it will be implemented as a co-routine, then do not flatten. This + ** restriction allows SQL constructs like this: + ** + ** SELECT expensive_function(x) + ** FROM (SELECT x FROM tab ORDER BY y LIMIT 10); + ** + ** The expensive_function() is only computed on the 10 rows that + ** are output, rather than every row of the table. + */ + if( pSub->pOrderBy!=0 + && i==0 + && (pTabList->nSrc==1 + || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) + ){ + continue; + } + + if( flattenSubquery(pParse, p, i, isAgg) ){ /* This subquery can be absorbed into its parent. */ - if( isAggSub ){ - isAgg = 1; - p->selFlags |= SF_Aggregate; - } i = -1; } pTabList = p->pSrc; @@ -121633,11 +122938,6 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - /* Get a pointer the VDBE under construction, allocating a new VDBE if one - ** does not already exist */ - v = sqlite3GetVdbe(pParse); - if( v==0 ) goto select_end; - #ifndef SQLITE_OMIT_COMPOUND_SELECT /* Handle compound SELECT statements using the separate multiSelect() ** procedure. @@ -121661,10 +122961,14 @@ SQLITE_PRIVATE int sqlite3Select( struct SrcList_item *pItem = &pTabList->a[i]; SelectDest dest; Select *pSub; +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + const char *zSavedAuthContext; +#endif - /* Issue SQLITE_READ authorizations with a fake column name for any tables that - ** are referenced but from which no values are extracted. Examples of where these - ** kinds of null SQLITE_READ authorizations would occur: + /* Issue SQLITE_READ authorizations with a fake column name for any + ** tables that are referenced but from which no values are extracted. + ** Examples of where these kinds of null SQLITE_READ authorizations + ** would occur: ** ** SELECT count(*) FROM t1; -- SQLITE_READ t1."" ** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2."" @@ -121672,10 +122976,10 @@ SQLITE_PRIVATE int sqlite3Select( ** The fake column name is an empty string. It is possible for a table to ** have a column named by the empty string, in which case there is no way to ** distinguish between an unreferenced table and an actual reference to the - ** "" column. The original design was for the fake column name to be a NULL, + ** "" column. The original design was for the fake column name to be a NULL, ** which would be unambiguous. But legacy authorization callbacks might - ** assume the column name is non-NULL and segfault. The use of an empty string - ** for the fake column name seems safer. + ** assume the column name is non-NULL and segfault. The use of an empty + ** string for the fake column name seems safer. */ if( pItem->colUsed==0 ){ sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); @@ -121727,16 +123031,14 @@ SQLITE_PRIVATE int sqlite3Select( #endif } + zSavedAuthContext = pParse->zAuthContext; + pParse->zAuthContext = pItem->zName; + /* Generate code to implement the subquery ** - ** The subquery is implemented as a co-routine if all of these are true: - ** (1) The subquery is guaranteed to be the outer loop (so that it - ** does not need to be computed more than once) - ** (2) The ALL keyword after SELECT is omitted. (Applications are - ** allowed to say "SELECT ALL" instead of just "SELECT" to disable - ** the use of co-routines.) - ** (3) Co-routines are not disabled using sqlite3_test_control() - ** with SQLITE_TESTCTRL_OPTIMIZATIONS. + ** The subquery is implemented as a co-routine if the subquery is + ** guaranteed to be the outer loop (so that it does not need to be + ** computed more than once) ** ** TODO: Are there other reasons beside (1) to use a co-routine ** implementation? @@ -121744,13 +123046,12 @@ SQLITE_PRIVATE int sqlite3Select( if( i==0 && (pTabList->nSrc==1 || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */ - && (p->selFlags & SF_All)==0 /* (2) */ - && OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */ ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. */ int addrTop = sqlite3VdbeCurrentAddr(v)+1; + pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%s", pItem->pTab->zName)); @@ -121791,6 +123092,9 @@ SQLITE_PRIVATE int sqlite3Select( pPrior = isSelfJoinView(pTabList, pItem); if( pPrior ){ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); + explainSetInteger(pItem->iSelectId, pPrior->iSelectId); + assert( pPrior->pSelect!=0 ); + pSub->nSelectRow = pPrior->pSelect->nSelectRow; }else{ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); @@ -121805,6 +123109,7 @@ SQLITE_PRIVATE int sqlite3Select( } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); + pParse->zAuthContext = zSavedAuthContext; #endif } @@ -121823,6 +123128,16 @@ SQLITE_PRIVATE int sqlite3Select( } #endif +#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION + if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) + && countOfViewOptimization(pParse, p) + ){ + if( db->mallocFailed ) goto select_end; + pEList = p->pEList; + pTabList = p->pSrc; + } +#endif + /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query ** can be rewritten as a GROUP BY. In other words, this: @@ -121942,7 +123257,8 @@ SQLITE_PRIVATE int sqlite3Select( } /* Use the standard inner loop. */ - selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest, + assert( p->pEList==pEList ); + selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, sqlite3WhereContinueLabel(pWInfo), sqlite3WhereBreakLabel(pWInfo)); @@ -122245,7 +123561,7 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); finalizeAggFunctions(pParse, &sAggInfo); sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); - selectInnerLoop(pParse, p, p->pEList, -1, &sSort, + selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, addrOutputRow+1, addrSetAbort); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); @@ -122389,7 +123705,7 @@ SQLITE_PRIVATE int sqlite3Select( sSort.pOrderBy = 0; sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); - selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, + selectInnerLoop(pParse, p, -1, 0, 0, pDest, addrEnd, addrEnd); sqlite3ExprListDelete(db, pDel); } @@ -122424,12 +123740,6 @@ SQLITE_PRIVATE int sqlite3Select( select_end: explainSetInteger(pParse->iSelectId, iRestoreSelectId); - /* Identify column names if results of the SELECT are to be output. - */ - if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){ - generateColumnNames(pParse, pTabList, pEList); - } - sqlite3DbFree(db, sAggInfo.aCol); sqlite3DbFree(db, sAggInfo.aFunc); #if SELECTTRACE_ENABLED @@ -122950,6 +124260,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); + testcase( z==0 ); sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db->aDb[iDb].zDbSName, MASTER_NAME, zName, @@ -123228,7 +124539,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const ch *pp = (*pp)->pNext; } sqlite3DeleteTrigger(db, pTrigger); - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; } } @@ -124549,12 +125860,6 @@ static void updateVirtualTable( if( pWInfo==0 ) return; /* Populate the argument registers. */ - sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg); - if( pRowid ){ - sqlite3ExprCode(pParse, pRowid, regArg+1); - }else{ - sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1); - } for(i=0; i<pTab->nCol; i++){ if( aXRef[i]>=0 ){ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); @@ -124562,6 +125867,23 @@ static void updateVirtualTable( sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); } } + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg); + if( pRowid ){ + sqlite3ExprCode(pParse, pRowid, regArg+1); + }else{ + sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1); + } + }else{ + Index *pPk; /* PRIMARY KEY index */ + i16 iPk; /* PRIMARY KEY column */ + pPk = sqlite3PrimaryKeyIndex(pTab); + assert( pPk!=0 ); + assert( pPk->nKeyCol==1 ); + iPk = pPk->aiColumn[0]; + sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg); + sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1); + } bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); @@ -124746,7 +126068,8 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ - int saved_flags; /* Saved value of the db->flags */ + u16 saved_mDbFlags; /* Saved value of db->mDbFlags */ + u32 saved_flags; /* Saved value of db->flags */ int saved_nChange; /* Saved value of db->nChange */ int saved_nTotalChange; /* Saved value of db->nTotalChange */ u8 saved_mTrace; /* Saved trace settings */ @@ -124769,11 +126092,12 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ ** restored before returning. Then set the writable-schema flag, and ** disable CHECK and foreign key constraints. */ saved_flags = db->flags; + saved_mDbFlags = db->mDbFlags; saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; saved_mTrace = db->mTrace; - db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks - | SQLITE_PreferBuiltin | SQLITE_Vacuum); + db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; + db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows); db->mTrace = 0; @@ -124817,7 +126141,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); int nKey; char *zKey; - sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); + sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey); if( nKey ) db->nextPagesize = 0; } #endif @@ -124884,8 +126208,8 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ "WHERE type='table'AND coalesce(rootpage,1)>0", zDbMain ); - assert( (db->flags & SQLITE_Vacuum)!=0 ); - db->flags &= ~SQLITE_Vacuum; + assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 ); + db->mDbFlags &= ~DBFLAG_Vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Copy the triggers, views, and virtual tables from the main database @@ -124953,6 +126277,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ end_of_vacuum: /* Restore the original value of db->flags */ db->init.iDb = 0; + db->mDbFlags = saved_mDbFlags; db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; @@ -125029,8 +126354,10 @@ SQLITE_PRIVATE Module *sqlite3VtabCreateModule( ){ Module *pMod; int nName = sqlite3Strlen30(zName); - pMod = (Module *)sqlite3DbMallocRawNN(db, sizeof(Module) + nName + 1); - if( pMod ){ + pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1); + if( pMod==0 ){ + sqlite3OomFault(db); + }else{ Module *pDel; char *zCopy = (char *)(&pMod[1]); memcpy(zCopy, zName, nName+1); @@ -125505,13 +126832,14 @@ static int vtabCallConstructor( } } - zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); + zModuleName = sqlite3DbStrDup(db, pTab->zName); if( !zModuleName ){ return SQLITE_NOMEM_BKPT; } - pVTable = sqlite3DbMallocZero(db, sizeof(VTable)); + pVTable = sqlite3MallocZero(sizeof(VTable)); if( !pVTable ){ + sqlite3OomFault(db); sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM_BKPT; } @@ -125631,6 +126959,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "%s", zErr); + pParse->rc = rc; } sqlite3DbFree(db, zErr); } @@ -125720,10 +127049,10 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, */ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ VtabCtx *pCtx; - Parse *pParse; int rc = SQLITE_OK; Table *pTab; char *zErr = 0; + Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){ @@ -125740,55 +127069,55 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ pTab = pCtx->pTab; assert( IsVirtual(pTab) ); - pParse = sqlite3StackAllocZero(db, sizeof(*pParse)); - if( pParse==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - pParse->declareVtab = 1; - pParse->db = db; - pParse->nQueryLoop = 1; - - if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr) - && pParse->pNewTable - && !db->mallocFailed - && !pParse->pNewTable->pSelect - && !IsVirtual(pParse->pNewTable) - ){ - if( !pTab->aCol ){ - Table *pNew = pParse->pNewTable; - Index *pIdx; - pTab->aCol = pNew->aCol; - pTab->nCol = pNew->nCol; - pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); - pNew->nCol = 0; - pNew->aCol = 0; - assert( pTab->pIndex==0 ); - if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){ - rc = SQLITE_ERROR; - } - pIdx = pNew->pIndex; - if( pIdx ){ - assert( pIdx->pNext==0 ); - pTab->pIndex = pIdx; - pNew->pIndex = 0; - pIdx->pTable = pTab; - } + memset(&sParse, 0, sizeof(sParse)); + sParse.declareVtab = 1; + sParse.db = db; + sParse.nQueryLoop = 1; + if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr) + && sParse.pNewTable + && !db->mallocFailed + && !sParse.pNewTable->pSelect + && !IsVirtual(sParse.pNewTable) + ){ + if( !pTab->aCol ){ + Table *pNew = sParse.pNewTable; + Index *pIdx; + pTab->aCol = pNew->aCol; + pTab->nCol = pNew->nCol; + pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); + pNew->nCol = 0; + pNew->aCol = 0; + assert( pTab->pIndex==0 ); + assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 ); + if( !HasRowid(pNew) + && pCtx->pVTable->pMod->pModule->xUpdate!=0 + && sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1 + ){ + /* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0) + ** or else must have a single-column PRIMARY KEY */ + rc = SQLITE_ERROR; + } + pIdx = pNew->pIndex; + if( pIdx ){ + assert( pIdx->pNext==0 ); + pTab->pIndex = pIdx; + pNew->pIndex = 0; + pIdx->pTable = pTab; } - pCtx->bDeclared = 1; - }else{ - sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); - sqlite3DbFree(db, zErr); - rc = SQLITE_ERROR; - } - pParse->declareVtab = 0; - - if( pParse->pVdbe ){ - sqlite3VdbeFinalize(pParse->pVdbe); } - sqlite3DeleteTable(db, pParse->pNewTable); - sqlite3ParserReset(pParse); - sqlite3StackFree(db, pParse); + pCtx->bDeclared = 1; + }else{ + sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); + sqlite3DbFree(db, zErr); + rc = SQLITE_ERROR; } + sParse.declareVtab = 0; + + if( sParse.pVdbe ){ + sqlite3VdbeFinalize(sParse.pVdbe); + } + sqlite3DeleteTable(db, sParse.pNewTable); + sqlite3ParserReset(&sParse); assert( (rc&0xff)==rc ); rc = sqlite3ApiExit(db, rc); @@ -126535,6 +127864,7 @@ struct WhereTerm { #define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */ #define TERM_LIKE 0x400 /* The original LIKE operator */ #define TERM_IS 0x800 /* Term.pExpr is an IS operator */ +#define TERM_VARSELECT 0x1000 /* Term.pExpr contains a correlated sub-query */ /* ** An instance of the WhereScan object is used as an iterator for locating @@ -126624,6 +127954,7 @@ struct WhereAndInfo { ** no gaps. */ struct WhereMaskSet { + int bVarSelect; /* Used by sqlite3WhereExprUsage() */ int n; /* Number of assigned cursor values */ int ix[BMS]; /* Cursor assigned to each bit */ }; @@ -126764,7 +128095,6 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC ** WO_LE == SQLITE_INDEX_CONSTRAINT_LE ** WO_GT == SQLITE_INDEX_CONSTRAINT_GT ** WO_GE == SQLITE_INDEX_CONSTRAINT_GE -** WO_MATCH == SQLITE_INDEX_CONSTRAINT_MATCH */ #define WO_IN 0x0001 #define WO_EQ 0x0002 @@ -126772,7 +128102,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC #define WO_LE (WO_EQ<<(TK_LE-TK_EQ)) #define WO_GT (WO_EQ<<(TK_GT-TK_EQ)) #define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) -#define WO_MATCH 0x0040 +#define WO_AUX 0x0040 /* Op useful to virtual tables only */ #define WO_IS 0x0080 #define WO_ISNULL 0x0100 #define WO_OR 0x0200 /* Two or more OR-connected terms */ @@ -127585,7 +128915,7 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){ pWalker->eCode = 1; }else if( pExpr->op==TK_FUNCTION ){ int d1; - char d2[3]; + char d2[4]; if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){ pWalker->eCode = 1; } @@ -127757,10 +129087,10 @@ static void codeCursorHint( ** ** Normally, this is just: ** -** OP_Seek $iCur $iRowid +** OP_DeferredSeek $iCur $iRowid ** ** However, if the scan currently being coded is a branch of an OR-loop and -** the statement currently being coded is a SELECT, then P3 of the OP_Seek +** the statement currently being coded is a SELECT, then P3 of OP_DeferredSeek ** is set to iIdxCur and P4 is set to point to an array of integers ** containing one entry for each column of the table cursor iCur is open ** on. For each table column, if the column is the i'th column of the @@ -127779,7 +129109,7 @@ static void codeDeferredSeek( assert( iIdxCur>0 ); assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); - sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur); + sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur); if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) ){ @@ -127808,7 +129138,7 @@ static void codeDeferredSeek( */ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ assert( nReg>0 ); - if( sqlite3ExprIsVector(p) ){ + if( p && sqlite3ExprIsVector(p) ){ #ifndef SQLITE_OMIT_SUBQUERY if( (p->flags & EP_xIsSelect) ){ Vdbe *v = pParse->pVdbe; @@ -127849,7 +129179,7 @@ typedef struct IdxExprTrans { */ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ IdxExprTrans *pX = p->u.pIdxTrans; - if( sqlite3ExprCompare(pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){ + if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){ pExpr->op = TK_COLUMN; pExpr->iTable = pX->iIdxCur; pExpr->iColumn = pX->iIdxCol; @@ -127861,9 +129191,9 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ } /* -** For an indexes on expression X, locate every instance of expression X in pExpr -** and change that subexpression into a reference to the appropriate column of -** the index. +** For an indexes on expression X, locate every instance of expression X +** in pExpr and change that subexpression into a reference to the appropriate +** column of the index. */ static void whereIndexExprTrans( Index *pIdx, /* The Index */ @@ -127921,7 +129251,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ int iReleaseReg = 0; /* Temp register to free before returning */ Index *pIdx = 0; /* Index used by loop (if any) */ - int loopAgain; /* True if constraint generator loop should repeat */ + int iLoop; /* Iteration of constraint generator loop */ pParse = pWInfo->pParse; v = pParse->pVdbe; @@ -128816,13 +130146,20 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. ** - ** This loop may run either once (pIdx==0) or twice (pIdx!=0). If - ** it is run twice, then the first iteration codes those sub-expressions - ** that can be computed using columns from pIdx only (without seeking - ** the main table cursor). + ** This loop may run between one and three times, depending on the + ** constraints to be generated. The value of stack variable iLoop + ** determines the constraints coded by each iteration, as follows: + ** + ** iLoop==1: Code only expressions that are entirely covered by pIdx. + ** iLoop==2: Code remaining expressions that do not contain correlated + ** sub-queries. + ** iLoop==3: Code all remaining expressions. + ** + ** An effort is made to skip unnecessary iterations of the loop. */ + iLoop = (pIdx ? 1 : 2); do{ - loopAgain = 0; + int iNext = 0; /* Next value for iLoop */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE; int skipLikeAddr = 0; @@ -128840,10 +130177,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ continue; } - if( pIdx && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){ - loopAgain = 1; + + if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){ + iNext = 2; continue; } + if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){ + if( iNext==0 ) iNext = 3; + continue; + } + if( pTerm->wtFlags & TERM_LIKECOND ){ /* If the TERM_LIKECOND flag is set, that means that the range search ** is sufficient to guarantee that the LIKE operator is true, so we @@ -128859,12 +130202,18 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeCoverage(v); #endif } +#ifdef WHERETRACE_ENABLED /* 0xffff */ + if( sqlite3WhereTrace ){ + VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d", + pWC->nTerm-j, pTerm, iLoop)); + } +#endif sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); pTerm->wtFlags |= TERM_CODED; } - pIdx = 0; - }while( loopAgain ); + iLoop = iNext; + }while( iLoop>0 ); /* Insert code to test for implied constraints based on transitivity ** of the "==" operator. @@ -129121,12 +130470,12 @@ static int isLikeOrGlob( int *pisComplete, /* True if the only wildcard is % in the last character */ int *pnoCase /* True if uppercase is equivalent to lowercase */ ){ - const char *z = 0; /* String on RHS of LIKE operator */ + const u8 *z = 0; /* String on RHS of LIKE operator */ Expr *pRight, *pLeft; /* Right and left size of LIKE operator */ ExprList *pList; /* List of operands to the LIKE operator */ int c; /* One character in z[] */ int cnt; /* Number of non-wildcard prefix characters */ - char wc[3]; /* Wildcard characters */ + char wc[4]; /* Wildcard characters */ sqlite3 *db = pParse->db; /* Database connection */ sqlite3_value *pVal = 0; int op; /* Opcode of pRight */ @@ -129143,17 +130492,17 @@ static int isLikeOrGlob( pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr); op = pRight->op; - if( op==TK_VARIABLE ){ + if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *pReprepare = pParse->pReprepare; int iCol = pRight->iColumn; pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB); if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ - z = (char *)sqlite3_value_text(pVal); + z = sqlite3_value_text(pVal); } sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ - z = pRight->u.zToken; + z = (u8*)pRight->u.zToken; } if( z ){ @@ -129173,16 +130522,42 @@ static int isLikeOrGlob( return 0; } } + + /* Count the number of prefix characters prior to the first wildcard */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; + if( c==wc[3] && z[cnt]!=0 ) cnt++; } + + /* The optimization is possible only if (1) the pattern does not begin + ** with a wildcard and if (2) the non-wildcard prefix does not end with + ** an (illegal 0xff) character. The second condition is necessary so + ** that we can increment the prefix key to find an upper bound for the + ** range search. + */ if( cnt!=0 && 255!=(u8)z[cnt-1] ){ Expr *pPrefix; + + /* A "complete" match if the pattern ends with "*" or "%" */ *pisComplete = c==wc[0] && z[cnt+1]==0; - pPrefix = sqlite3Expr(db, TK_STRING, z); - if( pPrefix ) pPrefix->u.zToken[cnt] = 0; + + /* Get the pattern prefix. Remove all escapes from the prefix. */ + pPrefix = sqlite3Expr(db, TK_STRING, (char*)z); + if( pPrefix ){ + int iFrom, iTo; + char *zNew = pPrefix->u.zToken; + zNew[cnt] = 0; + for(iFrom=iTo=0; iFrom<cnt; iFrom++){ + if( zNew[iFrom]==wc[3] ) iFrom++; + zNew[iTo++] = zNew[iFrom]; + } + zNew[iTo] = 0; + } *ppPrefix = pPrefix; + + /* If the RHS pattern is a bound parameter, make arrangements to + ** reprepare the statement when that parameter is rebound */ if( op==TK_VARIABLE ){ Vdbe *v = pParse->pVdbe; sqlite3VdbeSetVarmask(v, pRight->iColumn); @@ -129213,48 +130588,84 @@ static int isLikeOrGlob( #ifndef SQLITE_OMIT_VIRTUALTABLE /* -** Check to see if the given expression is of the form -** -** column OP expr -** -** where OP is one of MATCH, GLOB, LIKE or REGEXP and "column" is a -** column of a virtual table. -** -** If it is then return TRUE. If not, return FALSE. -*/ -static int isMatchOfColumn( +** Check to see if the pExpr expression is a form that needs to be passed +** to the xBestIndex method of virtual tables. Forms of interest include: +** +** Expression Virtual Table Operator +** ----------------------- --------------------------------- +** 1. column MATCH expr SQLITE_INDEX_CONSTRAINT_MATCH +** 2. column GLOB expr SQLITE_INDEX_CONSTRAINT_GLOB +** 3. column LIKE expr SQLITE_INDEX_CONSTRAINT_LIKE +** 4. column REGEXP expr SQLITE_INDEX_CONSTRAINT_REGEXP +** 5. column != expr SQLITE_INDEX_CONSTRAINT_NE +** 6. expr != column SQLITE_INDEX_CONSTRAINT_NE +** 7. column IS NOT expr SQLITE_INDEX_CONSTRAINT_ISNOT +** 8. expr IS NOT column SQLITE_INDEX_CONSTRAINT_ISNOT +** 9. column IS NOT NULL SQLITE_INDEX_CONSTRAINT_ISNOTNULL +** +** In every case, "column" must be a column of a virtual table. If there +** is a match, set *ppLeft to the "column" expression, set *ppRight to the +** "expr" expression (even though in forms (6) and (8) the column is on the +** right and the expression is on the left). Also set *peOp2 to the +** appropriate virtual table operator. The return value is 1 or 2 if there +** is a match. The usual return is 1, but if the RHS is also a column +** of virtual table in forms (5) or (7) then return 2. +** +** If the expression matches none of the patterns above, return 0. +*/ +static int isAuxiliaryVtabOperator( Expr *pExpr, /* Test this expression */ - unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */ -){ - static const struct Op2 { - const char *zOp; - unsigned char eOp2; - } aOp[] = { - { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, - { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, - { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, - { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } - }; - ExprList *pList; - Expr *pCol; /* Column reference */ - int i; + unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */ + Expr **ppLeft, /* Column expression to left of MATCH/op2 */ + Expr **ppRight /* Expression to left of MATCH/op2 */ +){ + if( pExpr->op==TK_FUNCTION ){ + static const struct Op2 { + const char *zOp; + unsigned char eOp2; + } aOp[] = { + { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, + { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, + { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, + { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } + }; + ExprList *pList; + Expr *pCol; /* Column reference */ + int i; - if( pExpr->op!=TK_FUNCTION ){ - return 0; - } - pList = pExpr->x.pList; - if( pList==0 || pList->nExpr!=2 ){ - return 0; - } - pCol = pList->a[1].pExpr; - if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){ - return 0; - } - for(i=0; i<ArraySize(aOp); i++){ - if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){ - *peOp2 = aOp[i].eOp2; - return 1; + pList = pExpr->x.pList; + if( pList==0 || pList->nExpr!=2 ){ + return 0; + } + pCol = pList->a[1].pExpr; + if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){ + return 0; + } + for(i=0; i<ArraySize(aOp); i++){ + if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){ + *peOp2 = aOp[i].eOp2; + *ppRight = pList->a[0].pExpr; + *ppLeft = pCol; + return 1; + } + } + }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){ + int res = 0; + Expr *pLeft = pExpr->pLeft; + Expr *pRight = pExpr->pRight; + if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->pTab) ){ + res++; } + if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->pTab) ){ + res++; + SWAP(Expr*, pLeft, pRight); + } + *ppLeft = pLeft; + *ppRight = pRight; + if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE; + if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT; + if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL; + return res; } return 0; } @@ -129333,8 +130744,8 @@ static void whereCombineDisjuncts( && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 ); - if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; - if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return; + if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; + if( sqlite3ExprCompare(0,pOne->pExpr->pRight, pTwo->pExpr->pRight,-1) )return; /* If we reach this point, it means the two subterms can be combined */ if( (eOp & (eOp-1))!=0 ){ if( eOp & (WO_LT|WO_LE) ){ @@ -129505,7 +130916,7 @@ static void exprAnalyzeOrTerm( for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); if( allowedOp(pAndTerm->pExpr->op) - || pAndTerm->eOperator==WO_MATCH + || pAndTerm->eOperator==WO_AUX ){ b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); } @@ -129707,7 +131118,6 @@ static void exprAnalyzeOrTerm( static int termIsEquivalence(Parse *pParse, Expr *pExpr){ char aff1, aff2; CollSeq *pColl; - const char *zColl1, *zColl2; if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; @@ -129720,11 +131130,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){ } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; - pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - zColl1 = pColl ? pColl->zName : 0; - pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); - zColl2 = pColl ? pColl->zName : 0; - return sqlite3_stricmp(zColl1, zColl2)==0; + return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight); } /* @@ -129878,7 +131284,9 @@ static void exprAnalyze( }else{ pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight); } + pMaskSet->bVarSelect = 0; prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr); + if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT; if( ExprHasProperty(pExpr, EP_FromJoin) ){ Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable); prereqAll |= x; @@ -130085,38 +131493,46 @@ static void exprAnalyze( #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ #ifndef SQLITE_OMIT_VIRTUALTABLE - /* Add a WO_MATCH auxiliary term to the constraint set if the - ** current expression is of the form: column MATCH expr. + /* Add a WO_AUX auxiliary term to the constraint set if the + ** current expression is of the form "column OP expr" where OP + ** is an operator that gets passed into virtual tables but which is + ** not normally optimized for ordinary tables. In other words, OP + ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL. ** This information is used by the xBestIndex methods of ** virtual tables. The native query optimizer does not attempt ** to do anything with MATCH functions. */ - if( pWC->op==TK_AND && isMatchOfColumn(pExpr, &eOp2) ){ - int idxNew; + if( pWC->op==TK_AND ){ Expr *pRight, *pLeft; - WhereTerm *pNewTerm; - Bitmask prereqColumn, prereqExpr; - - pRight = pExpr->x.pList->a[0].pExpr; - pLeft = pExpr->x.pList->a[1].pExpr; - prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight); - prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft); - if( (prereqExpr & prereqColumn)==0 ){ - Expr *pNewExpr; - pNewExpr = sqlite3PExpr(pParse, TK_MATCH, - 0, sqlite3ExprDup(db, pRight, 0)); - idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); - testcase( idxNew==0 ); - pNewTerm = &pWC->a[idxNew]; - pNewTerm->prereqRight = prereqExpr; - pNewTerm->leftCursor = pLeft->iTable; - pNewTerm->u.leftColumn = pLeft->iColumn; - pNewTerm->eOperator = WO_MATCH; - pNewTerm->eMatchOp = eOp2; - markTermAsChild(pWC, idxNew, idxTerm); - pTerm = &pWC->a[idxTerm]; - pTerm->wtFlags |= TERM_COPIED; - pNewTerm->prereqAll = pTerm->prereqAll; + int res = isAuxiliaryVtabOperator(pExpr, &eOp2, &pLeft, &pRight); + while( res-- > 0 ){ + int idxNew; + WhereTerm *pNewTerm; + Bitmask prereqColumn, prereqExpr; + + prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight); + prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft); + if( (prereqExpr & prereqColumn)==0 ){ + Expr *pNewExpr; + pNewExpr = sqlite3PExpr(pParse, TK_MATCH, + 0, sqlite3ExprDup(db, pRight, 0)); + if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){ + ExprSetProperty(pNewExpr, EP_FromJoin); + } + idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); + testcase( idxNew==0 ); + pNewTerm = &pWC->a[idxNew]; + pNewTerm->prereqRight = prereqExpr; + pNewTerm->leftCursor = pLeft->iTable; + pNewTerm->u.leftColumn = pLeft->iColumn; + pNewTerm->eOperator = WO_AUX; + pNewTerm->eMatchOp = eOp2; + markTermAsChild(pWC, idxNew, idxTerm); + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags |= TERM_COPIED; + pNewTerm->prereqAll = pTerm->prereqAll; + } + SWAP(Expr*, pLeft, pRight); } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -130306,9 +131722,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ } mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0; assert( !ExprHasProperty(p, EP_TokenOnly) ); - if( p->pRight ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight); if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft); - if( ExprHasProperty(p, EP_xIsSelect) ){ + if( p->pRight ){ + mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight); + assert( p->x.pList==0 ); + }else if( ExprHasProperty(p, EP_xIsSelect) ){ + if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1; mask |= exprSelectUsage(pMaskSet, p->x.pSelect); }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); @@ -130792,8 +132211,8 @@ static int findIndexCol( && p->iColumn==pIdx->aiColumn[iCol] && p->iTable==iBase ){ - CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); - if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){ + CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr); + if( 0==sqlite3StrICmp(pColl->zName, zColl) ){ return i; } } @@ -130997,6 +132416,15 @@ static int termCanDriveIndex( char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0; + if( (pSrc->fg.jointype & JT_LEFT) + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && (pTerm->eOperator & WO_IS) + ){ + /* Cannot use an IS term from the WHERE clause as an index driver for + ** the RHS of a LEFT JOIN. Such a term can only be used if it is from + ** the ON clause. */ + return 0; + } if( (pTerm->prereqRight & notReady)!=0 ) return 0; if( pTerm->u.leftColumn<0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; @@ -131248,7 +132676,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ALL ); - if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; + if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; assert( pTerm->u.leftColumn>=(-1) ); nTerm++; @@ -131296,7 +132724,7 @@ static sqlite3_index_info *allocateIndexInfo( pUsage; for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ - u8 op; + u16 op; if( pTerm->leftCursor != pSrc->iCursor ) continue; if( pTerm->prereqRight & mUnusable ) continue; assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); @@ -131304,34 +132732,40 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_ALL ); - if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; + if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; assert( pTerm->u.leftColumn>=(-1) ); pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; - op = (u8)pTerm->eOperator & WO_ALL; + op = pTerm->eOperator & WO_ALL; if( op==WO_IN ) op = WO_EQ; - if( op==WO_MATCH ){ - op = pTerm->eMatchOp; - } - pIdxCons[j].op = op; - /* The direct assignment in the previous line is possible only because - ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The - ** following asserts verify this fact. */ - assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); - assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); - assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); - assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); - assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); - assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH ); - assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); - - if( op & (WO_LT|WO_LE|WO_GT|WO_GE) - && sqlite3ExprIsVector(pTerm->pExpr->pRight) - ){ - if( i<16 ) mNoOmit |= (1 << i); - if( op==WO_LT ) pIdxCons[j].op = WO_LE; - if( op==WO_GT ) pIdxCons[j].op = WO_GE; + if( op==WO_AUX ){ + pIdxCons[j].op = pTerm->eMatchOp; + }else if( op & (WO_ISNULL|WO_IS) ){ + if( op==WO_ISNULL ){ + pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL; + }else{ + pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS; + } + }else{ + pIdxCons[j].op = (u8)op; + /* The direct assignment in the previous line is possible only because + ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The + ** following asserts verify this fact. */ + assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); + assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); + assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); + assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); + assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); + assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) ); + + if( op & (WO_LT|WO_LE|WO_GT|WO_GE) + && sqlite3ExprIsVector(pTerm->pExpr->pRight) + ){ + if( i<16 ) mNoOmit |= (1 << i); + if( op==WO_LT ) pIdxCons[j].op = WO_LE; + if( op==WO_GT ) pIdxCons[j].op = WO_GE; + } } j++; @@ -131581,7 +133015,7 @@ static int whereKeyStats( iGap = iGap/3; } aStat[0] = iLower + iGap; - aStat[1] = pIdx->aAvgEq[iCol]; + aStat[1] = pIdx->aAvgEq[nField-1]; } /* Restore the pRec->nField value before returning. */ @@ -132259,18 +133693,19 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** Return TRUE if all of the following are true: ** ** (1) X has the same or lower cost that Y -** (2) X is a proper subset of Y -** (3) X skips at least as many columns as Y -** -** By "proper subset" we mean that X uses fewer WHERE clause terms -** than Y and that every WHERE clause term used by X is also used -** by Y. +** (2) X uses fewer WHERE clause terms than Y +** (3) Every WHERE clause term used by X is also used by Y +** (4) X skips at least as many columns as Y +** (5) If X is a covering index, than Y is too ** +** Conditions (2) and (3) mean that X is a "proper subset" of Y. ** If X is a proper subset of Y then Y is a better choice and ought ** to have a lower cost. This routine returns TRUE when that cost -** relationship is inverted and needs to be adjusted. The third rule +** relationship is inverted and needs to be adjusted. Constraint (4) ** was added because if X uses skip-scan less than Y it still might -** deserve a lower cost even if it is a proper subset of Y. +** deserve a lower cost even if it is a proper subset of Y. Constraint (5) +** was added because a covering index probably deserves to have a lower cost +** than a non-covering index even if it is a proper subset. */ static int whereLoopCheaperProperSubset( const WhereLoop *pX, /* First WhereLoop to compare */ @@ -132292,6 +133727,10 @@ static int whereLoopCheaperProperSubset( } if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ } + if( (pX->wsFlags&WHERE_IDX_ONLY)!=0 + && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){ + return 0; /* Constraint (5) */ + } return 1; /* All conditions meet */ } @@ -132334,16 +133773,17 @@ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ /* ** Search the list of WhereLoops in *ppPrev looking for one that can be -** supplanted by pTemplate. +** replaced by pTemplate. ** -** Return NULL if the WhereLoop list contains an entry that can supplant -** pTemplate, in other words if pTemplate does not belong on the list. +** Return NULL if pTemplate does not belong on the WhereLoop list. +** In other words if pTemplate ought to be dropped from further consideration. ** -** If pX is a WhereLoop that pTemplate can supplant, then return the +** If pX is a WhereLoop that pTemplate can replace, then return the ** link that points to pX. ** -** If pTemplate cannot supplant any existing element of the list but needs -** to be added to the list, then return a pointer to the tail of the list. +** If pTemplate cannot replace any existing element of the list but needs +** to be added to the list as a new entry, then return a pointer to the +** tail of the list. */ static WhereLoop **whereLoopFindLesser( WhereLoop **ppPrev, @@ -132488,8 +133928,10 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ if( p!=0 ){ sqlite3DebugPrintf("replace: "); whereLoopPrint(p, pBuilder->pWC); + sqlite3DebugPrintf(" with: "); + }else{ + sqlite3DebugPrintf(" add: "); } - sqlite3DebugPrintf(" add: "); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif @@ -133040,7 +134482,7 @@ static int indexMightHelpWithOrderBy( }else if( (aColExpr = pIndex->aColExpr)!=0 ){ for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pIndex->aiColumn[jj]!=XN_EXPR ) continue; - if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ + if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ return 1; } } @@ -133073,14 +134515,16 @@ static Bitmask columnsInIndex(Index *pIdx){ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){ int i; WhereTerm *pTerm; + Parse *pParse = pWC->pWInfo->pParse; while( pWhere->op==TK_AND ){ if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0; pWhere = pWhere->pRight; } + if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0; for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ Expr *pExpr = pTerm->pExpr; - if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab) - && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab) + if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab) + && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) ){ return 1; } @@ -133948,14 +135392,10 @@ static i8 wherePathSatisfiesOrderBy( if( j>=pLoop->nLTerm ) continue; } if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ - const char *z1, *z2; - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); - if( !pColl ) pColl = db->pDfltColl; - z1 = pColl->zName; - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr); - if( !pColl ) pColl = db->pDfltColl; - z2 = pColl->zName; - if( sqlite3StrICmp(z1, z2)!=0 ) continue; + if( sqlite3ExprCollSeqMatch(pWInfo->pParse, + pOrderBy->a[i].pExpr, pTerm->pExpr)==0 ){ + continue; + } testcase( pTerm->pExpr->op==TK_IS ); } obSat |= MASKBIT(i); @@ -134027,7 +135467,7 @@ static i8 wherePathSatisfiesOrderBy( if( pIndex ){ iColumn = pIndex->aiColumn[j]; revIdx = pIndex->aSortOrder[j]; - if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; + if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID; }else{ iColumn = XN_ROWID; revIdx = 0; @@ -134054,18 +135494,18 @@ static i8 wherePathSatisfiesOrderBy( testcase( wctrlFlags & WHERE_GROUPBY ); testcase( wctrlFlags & WHERE_DISTINCTBY ); if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; - if( iColumn>=(-1) ){ + if( iColumn>=XN_ROWID ){ if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; }else{ - if( sqlite3ExprCompare(pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){ + Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr; + if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){ continue; } } - if( iColumn>=0 ){ - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); - if( !pColl ) pColl = db->pDfltColl; + if( iColumn!=XN_ROWID ){ + pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } pLoop->u.btree.nIdxCol = j+1; @@ -134358,6 +135798,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ rUnsorted, rCost)); }else{ rCost = rUnsorted; + rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */ } /* Check to see if pWLoop should be added to the set of @@ -134389,8 +135830,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** this candidate as not viable. */ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ - sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); } #endif @@ -134408,26 +135849,36 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pTo = &aTo[jj]; #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ - sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); } #endif }else{ /* Control reaches here if best-so-far path pTo=aTo[jj] covers the - ** same set of loops and has the sam isOrdered setting as the + ** same set of loops and has the same isOrdered setting as the ** candidate path. Check to see if the candidate should replace - ** pTo or if the candidate should be skipped */ - if( pTo->rCost<rCost || (pTo->rCost==rCost && pTo->nRow<=nOut) ){ + ** pTo or if the candidate should be skipped. + ** + ** The conditional is an expanded vector comparison equivalent to: + ** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted) + */ + if( pTo->rCost<rCost + || (pTo->rCost==rCost + && (pTo->nRow<nOut + || (pTo->nRow==nOut && pTo->rUnsorted<=rUnsorted) + ) + ) + ){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( - "Skip %s cost=%-3d,%3d order=%c", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + "Skip %s cost=%-3d,%3d,%3d order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); - sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n", + sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif /* Discard the candidate path from further consideration */ @@ -134440,12 +135891,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( - "Update %s cost=%-3d,%3d order=%c", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + "Update %s cost=%-3d,%3d,%3d order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); - sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n", + sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif } @@ -134671,6 +136122,32 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ } /* +** Helper function for exprIsDeterministic(). +*/ +static int exprNodeIsDeterministic(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_ConstFunc)==0 ){ + pWalker->eCode = 0; + return WRC_Abort; + } + return WRC_Continue; +} + +/* +** Return true if the expression contains no non-deterministic SQL +** functions. Do not consider non-deterministic SQL functions that are +** part of sub-select statements. +*/ +static int exprIsDeterministic(Expr *p){ + Walker w; + memset(&w, 0, sizeof(w)); + w.eCode = 1; + w.xExprCallback = exprNodeIsDeterministic; + w.xSelectCallback = sqlite3SelectWalkFail; + sqlite3WalkExpr(&w, p); + return w.eCode; +} + +/* ** Generate the beginning of the loop used for WHERE clause processing. ** The return value is a pointer to an opaque structure that contains ** information needed to terminate the loop. Later, the calling routine @@ -134868,17 +136345,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo); sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND); - /* Special case: a WHERE clause that is constant. Evaluate the - ** expression and either jump over all of the code or fall thru. - */ - for(ii=0; ii<sWLB.pWC->nTerm; ii++){ - if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){ - sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak, - SQLITE_JUMPIFNULL); - sWLB.pWC->a[ii].wtFlags |= TERM_CODED; - } - } - /* Special case: No FROM clause */ if( nTabList==0 ){ @@ -134886,36 +136352,60 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } + }else{ + /* Assign a bit from the bitmask to every term in the FROM clause. + ** + ** The N-th term of the FROM clause is assigned a bitmask of 1<<N. + ** + ** The rule of the previous sentence ensures thta if X is the bitmask for + ** a table T, then X-1 is the bitmask for all other tables to the left of T. + ** Knowing the bitmask for all tables to the left of a left join is + ** important. Ticket #3015. + ** + ** Note that bitmasks are created for all pTabList->nSrc tables in + ** pTabList, not just the first nTabList tables. nTabList is normally + ** equal to pTabList->nSrc but might be shortened to 1 if the + ** WHERE_OR_SUBCLAUSE flag is set. + */ + ii = 0; + do{ + createMask(pMaskSet, pTabList->a[ii].iCursor); + sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); + }while( (++ii)<pTabList->nSrc ); + #ifdef SQLITE_DEBUG + { + Bitmask mx = 0; + for(ii=0; ii<pTabList->nSrc; ii++){ + Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); + assert( m>=mx ); + mx = m; + } + } + #endif } + + /* Analyze all of the subexpressions. */ + sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC); + if( db->mallocFailed ) goto whereBeginError; - /* Assign a bit from the bitmask to every term in the FROM clause. + /* Special case: WHERE terms that do not refer to any tables in the join + ** (constant expressions). Evaluate each such term, and jump over all the + ** generated code if the result is not true. ** - ** The N-th term of the FROM clause is assigned a bitmask of 1<<N. + ** Do not do this if the expression contains non-deterministic functions + ** that are not within a sub-select. This is not strictly required, but + ** preserves SQLite's legacy behaviour in the following two cases: ** - ** The rule of the previous sentence ensures thta if X is the bitmask for - ** a table T, then X-1 is the bitmask for all other tables to the left of T. - ** Knowing the bitmask for all tables to the left of a left join is - ** important. Ticket #3015. - ** - ** Note that bitmasks are created for all pTabList->nSrc tables in - ** pTabList, not just the first nTabList tables. nTabList is normally - ** equal to pTabList->nSrc but might be shortened to 1 if the - ** WHERE_OR_SUBCLAUSE flag is set. + ** FROM ... WHERE random()>0; -- eval random() once per row + ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall */ - for(ii=0; ii<pTabList->nSrc; ii++){ - createMask(pMaskSet, pTabList->a[ii].iCursor); - sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); - } -#ifdef SQLITE_DEBUG - for(ii=0; ii<pTabList->nSrc; ii++){ - Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); - assert( m==MASKBIT(ii) ); + for(ii=0; ii<sWLB.pWC->nTerm; ii++){ + WhereTerm *pT = &sWLB.pWC->a[ii]; + if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ + sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL); + pT->wtFlags |= TERM_CODED; + } } -#endif - - /* Analyze all of the subexpressions. */ - sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC); - if( db->mallocFailed ) goto whereBeginError; if( wctrlFlags & WHERE_WANT_DISTINCT ){ if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ @@ -134953,7 +136443,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){ - p->cId = zLabel[i%sizeof(zLabel)]; + p->cId = zLabel[i%(sizeof(zLabel)-1)]; whereLoopPrint(p, sWLB.pWC); } } @@ -135116,7 +136606,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Index *pIx = pLoop->u.btree.pIndex; int iIndexCur; int op = OP_OpenRead; - /* iAuxArg is always set if to a positive value if ONEPASS is possible */ + /* iAuxArg is always set to a positive value if ONEPASS is possible */ assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 @@ -135697,7 +137187,8 @@ static void disableLookaside(Parse *pParse){ ** YY_MAX_SHIFT Maximum value for shift actions ** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions ** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions -** YY_MIN_REDUCE Maximum value for reduce actions +** YY_MIN_REDUCE Minimum value for reduce actions +** YY_MAX_REDUCE Maximum value for reduce actions ** YY_ERROR_ACTION The yy_action[] code for syntax error ** YY_ACCEPT_ACTION The yy_action[] code for accept ** YY_NO_ACTION The yy_action[] code for no-op @@ -135709,7 +137200,7 @@ static void disableLookaside(Parse *pParse){ #define YYCODETYPE unsigned char #define YYNOCODE 252 #define YYACTIONTYPE unsigned short int -#define YYWILDCARD 69 +#define YYWILDCARD 83 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; @@ -135735,16 +137226,16 @@ typedef union { #define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse #define sqlite3ParserARG_STORE yypParser->pParse = pParse #define YYFALLBACK 1 -#define YYNSTATE 456 -#define YYNRULE 332 -#define YY_MAX_SHIFT 455 -#define YY_MIN_SHIFTREDUCE 668 -#define YY_MAX_SHIFTREDUCE 999 -#define YY_MIN_REDUCE 1000 -#define YY_MAX_REDUCE 1331 -#define YY_ERROR_ACTION 1332 -#define YY_ACCEPT_ACTION 1333 -#define YY_NO_ACTION 1334 +#define YYNSTATE 455 +#define YYNRULE 329 +#define YY_MAX_SHIFT 454 +#define YY_MIN_SHIFTREDUCE 664 +#define YY_MAX_SHIFTREDUCE 992 +#define YY_MIN_REDUCE 993 +#define YY_MAX_REDUCE 1321 +#define YY_ERROR_ACTION 1322 +#define YY_ACCEPT_ACTION 1323 +#define YY_NO_ACTION 1324 /************* End control #defines *******************************************/ /* Define the yytestcase() macro to be a no-op if is not already defined @@ -135818,461 +137309,461 @@ typedef union { *********** Begin parsing tables **********************************************/ #define YY_ACTTAB_COUNT (1566) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 325, 411, 343, 752, 752, 203, 946, 354, 976, 98, - /* 10 */ 98, 98, 98, 91, 96, 96, 96, 96, 95, 95, - /* 20 */ 94, 94, 94, 93, 351, 1333, 155, 155, 2, 813, - /* 30 */ 978, 978, 98, 98, 98, 98, 20, 96, 96, 96, - /* 40 */ 96, 95, 95, 94, 94, 94, 93, 351, 92, 89, - /* 50 */ 178, 99, 100, 90, 853, 856, 845, 845, 97, 97, - /* 60 */ 98, 98, 98, 98, 351, 96, 96, 96, 96, 95, - /* 70 */ 95, 94, 94, 94, 93, 351, 325, 340, 976, 262, - /* 80 */ 365, 251, 212, 169, 287, 405, 282, 404, 199, 791, - /* 90 */ 242, 412, 21, 957, 379, 280, 93, 351, 792, 95, - /* 100 */ 95, 94, 94, 94, 93, 351, 978, 978, 96, 96, - /* 110 */ 96, 96, 95, 95, 94, 94, 94, 93, 351, 813, - /* 120 */ 329, 242, 412, 913, 832, 913, 132, 99, 100, 90, - /* 130 */ 853, 856, 845, 845, 97, 97, 98, 98, 98, 98, - /* 140 */ 450, 96, 96, 96, 96, 95, 95, 94, 94, 94, - /* 150 */ 93, 351, 325, 825, 349, 348, 120, 819, 120, 75, - /* 160 */ 52, 52, 957, 958, 959, 760, 984, 146, 361, 262, - /* 170 */ 370, 261, 957, 982, 961, 983, 92, 89, 178, 371, - /* 180 */ 230, 371, 978, 978, 817, 361, 360, 101, 824, 824, - /* 190 */ 826, 384, 24, 964, 381, 428, 413, 369, 985, 380, - /* 200 */ 985, 708, 325, 99, 100, 90, 853, 856, 845, 845, - /* 210 */ 97, 97, 98, 98, 98, 98, 373, 96, 96, 96, - /* 220 */ 96, 95, 95, 94, 94, 94, 93, 351, 957, 132, - /* 230 */ 897, 450, 978, 978, 896, 60, 94, 94, 94, 93, - /* 240 */ 351, 957, 958, 959, 961, 103, 361, 957, 385, 334, - /* 250 */ 702, 52, 52, 99, 100, 90, 853, 856, 845, 845, - /* 260 */ 97, 97, 98, 98, 98, 98, 698, 96, 96, 96, - /* 270 */ 96, 95, 95, 94, 94, 94, 93, 351, 325, 455, - /* 280 */ 670, 450, 227, 61, 157, 243, 344, 114, 701, 888, - /* 290 */ 147, 832, 957, 373, 747, 957, 320, 957, 958, 959, - /* 300 */ 194, 10, 10, 402, 399, 398, 888, 890, 978, 978, - /* 310 */ 762, 171, 170, 157, 397, 337, 957, 958, 959, 702, - /* 320 */ 825, 310, 153, 957, 819, 321, 82, 23, 80, 99, - /* 330 */ 100, 90, 853, 856, 845, 845, 97, 97, 98, 98, - /* 340 */ 98, 98, 894, 96, 96, 96, 96, 95, 95, 94, - /* 350 */ 94, 94, 93, 351, 325, 824, 824, 826, 277, 231, - /* 360 */ 300, 957, 958, 959, 957, 958, 959, 888, 194, 25, - /* 370 */ 450, 402, 399, 398, 957, 355, 300, 450, 957, 74, - /* 380 */ 450, 1, 397, 132, 978, 978, 957, 224, 224, 813, - /* 390 */ 10, 10, 957, 958, 959, 968, 132, 52, 52, 415, - /* 400 */ 52, 52, 739, 739, 339, 99, 100, 90, 853, 856, - /* 410 */ 845, 845, 97, 97, 98, 98, 98, 98, 790, 96, - /* 420 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351, - /* 430 */ 325, 789, 428, 418, 706, 428, 427, 1270, 1270, 262, - /* 440 */ 370, 261, 957, 957, 958, 959, 757, 957, 958, 959, - /* 450 */ 450, 756, 450, 734, 713, 957, 958, 959, 443, 711, - /* 460 */ 978, 978, 734, 394, 92, 89, 178, 447, 447, 447, - /* 470 */ 51, 51, 52, 52, 439, 778, 700, 92, 89, 178, - /* 480 */ 172, 99, 100, 90, 853, 856, 845, 845, 97, 97, - /* 490 */ 98, 98, 98, 98, 198, 96, 96, 96, 96, 95, - /* 500 */ 95, 94, 94, 94, 93, 351, 325, 428, 408, 916, - /* 510 */ 699, 957, 958, 959, 92, 89, 178, 224, 224, 157, - /* 520 */ 241, 221, 419, 299, 776, 917, 416, 375, 450, 415, - /* 530 */ 58, 324, 737, 737, 920, 379, 978, 978, 379, 777, - /* 540 */ 449, 918, 363, 740, 296, 686, 9, 9, 52, 52, - /* 550 */ 234, 330, 234, 256, 417, 741, 280, 99, 100, 90, - /* 560 */ 853, 856, 845, 845, 97, 97, 98, 98, 98, 98, - /* 570 */ 450, 96, 96, 96, 96, 95, 95, 94, 94, 94, - /* 580 */ 93, 351, 325, 423, 72, 450, 833, 120, 368, 450, - /* 590 */ 10, 10, 5, 301, 203, 450, 177, 976, 253, 420, - /* 600 */ 255, 776, 200, 175, 233, 10, 10, 842, 842, 36, - /* 610 */ 36, 1299, 978, 978, 729, 37, 37, 349, 348, 425, - /* 620 */ 203, 260, 776, 976, 232, 937, 1326, 876, 338, 1326, - /* 630 */ 422, 854, 857, 99, 100, 90, 853, 856, 845, 845, - /* 640 */ 97, 97, 98, 98, 98, 98, 268, 96, 96, 96, - /* 650 */ 96, 95, 95, 94, 94, 94, 93, 351, 325, 846, - /* 660 */ 450, 985, 818, 985, 1209, 450, 916, 976, 720, 350, - /* 670 */ 350, 350, 935, 177, 450, 937, 1327, 254, 198, 1327, - /* 680 */ 12, 12, 917, 403, 450, 27, 27, 250, 978, 978, - /* 690 */ 118, 721, 162, 976, 38, 38, 268, 176, 918, 776, - /* 700 */ 433, 1275, 946, 354, 39, 39, 317, 998, 325, 99, - /* 710 */ 100, 90, 853, 856, 845, 845, 97, 97, 98, 98, - /* 720 */ 98, 98, 935, 96, 96, 96, 96, 95, 95, 94, - /* 730 */ 94, 94, 93, 351, 450, 330, 450, 358, 978, 978, - /* 740 */ 717, 317, 936, 341, 900, 900, 387, 673, 674, 675, - /* 750 */ 275, 996, 318, 999, 40, 40, 41, 41, 268, 99, - /* 760 */ 100, 90, 853, 856, 845, 845, 97, 97, 98, 98, - /* 770 */ 98, 98, 450, 96, 96, 96, 96, 95, 95, 94, - /* 780 */ 94, 94, 93, 351, 325, 450, 356, 450, 999, 450, - /* 790 */ 692, 331, 42, 42, 791, 270, 450, 273, 450, 228, - /* 800 */ 450, 298, 450, 792, 450, 28, 28, 29, 29, 31, - /* 810 */ 31, 450, 817, 450, 978, 978, 43, 43, 44, 44, - /* 820 */ 45, 45, 11, 11, 46, 46, 893, 78, 893, 268, - /* 830 */ 268, 105, 105, 47, 47, 99, 100, 90, 853, 856, - /* 840 */ 845, 845, 97, 97, 98, 98, 98, 98, 450, 96, - /* 850 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351, - /* 860 */ 325, 450, 117, 450, 749, 158, 450, 696, 48, 48, - /* 870 */ 229, 919, 450, 928, 450, 415, 450, 335, 450, 245, - /* 880 */ 450, 33, 33, 49, 49, 450, 50, 50, 246, 817, - /* 890 */ 978, 978, 34, 34, 122, 122, 123, 123, 124, 124, - /* 900 */ 56, 56, 268, 81, 249, 35, 35, 197, 196, 195, - /* 910 */ 325, 99, 100, 90, 853, 856, 845, 845, 97, 97, - /* 920 */ 98, 98, 98, 98, 450, 96, 96, 96, 96, 95, - /* 930 */ 95, 94, 94, 94, 93, 351, 450, 696, 450, 817, - /* 940 */ 978, 978, 975, 884, 106, 106, 268, 886, 268, 944, - /* 950 */ 2, 892, 268, 892, 336, 716, 53, 53, 107, 107, - /* 960 */ 325, 99, 100, 90, 853, 856, 845, 845, 97, 97, - /* 970 */ 98, 98, 98, 98, 450, 96, 96, 96, 96, 95, - /* 980 */ 95, 94, 94, 94, 93, 351, 450, 746, 450, 742, - /* 990 */ 978, 978, 715, 267, 108, 108, 446, 331, 332, 133, - /* 1000 */ 223, 175, 301, 225, 386, 933, 104, 104, 121, 121, - /* 1010 */ 325, 99, 88, 90, 853, 856, 845, 845, 97, 97, - /* 1020 */ 98, 98, 98, 98, 817, 96, 96, 96, 96, 95, - /* 1030 */ 95, 94, 94, 94, 93, 351, 450, 347, 450, 167, - /* 1040 */ 978, 978, 932, 815, 372, 319, 202, 202, 374, 263, - /* 1050 */ 395, 202, 74, 208, 726, 727, 119, 119, 112, 112, - /* 1060 */ 325, 407, 100, 90, 853, 856, 845, 845, 97, 97, - /* 1070 */ 98, 98, 98, 98, 450, 96, 96, 96, 96, 95, - /* 1080 */ 95, 94, 94, 94, 93, 351, 450, 757, 450, 345, - /* 1090 */ 978, 978, 756, 278, 111, 111, 74, 719, 718, 709, - /* 1100 */ 286, 883, 754, 1289, 257, 77, 109, 109, 110, 110, - /* 1110 */ 908, 285, 810, 90, 853, 856, 845, 845, 97, 97, - /* 1120 */ 98, 98, 98, 98, 911, 96, 96, 96, 96, 95, - /* 1130 */ 95, 94, 94, 94, 93, 351, 86, 445, 450, 3, - /* 1140 */ 1202, 450, 745, 132, 352, 120, 689, 86, 445, 785, - /* 1150 */ 3, 767, 202, 377, 448, 352, 907, 120, 55, 55, - /* 1160 */ 450, 57, 57, 828, 879, 448, 450, 208, 450, 709, - /* 1170 */ 450, 883, 237, 434, 436, 120, 440, 429, 362, 120, - /* 1180 */ 54, 54, 132, 450, 434, 832, 52, 52, 26, 26, - /* 1190 */ 30, 30, 382, 132, 409, 444, 832, 694, 264, 390, - /* 1200 */ 116, 269, 272, 32, 32, 83, 84, 120, 274, 120, - /* 1210 */ 120, 276, 85, 352, 452, 451, 83, 84, 819, 730, - /* 1220 */ 714, 428, 430, 85, 352, 452, 451, 120, 120, 819, - /* 1230 */ 378, 218, 281, 828, 783, 816, 86, 445, 410, 3, - /* 1240 */ 763, 774, 431, 432, 352, 302, 303, 823, 697, 824, - /* 1250 */ 824, 826, 827, 19, 448, 691, 680, 679, 681, 951, - /* 1260 */ 824, 824, 826, 827, 19, 289, 159, 291, 293, 7, - /* 1270 */ 316, 173, 259, 434, 805, 364, 252, 910, 376, 713, - /* 1280 */ 295, 435, 168, 993, 400, 832, 284, 881, 880, 205, - /* 1290 */ 954, 308, 927, 86, 445, 990, 3, 925, 333, 144, - /* 1300 */ 130, 352, 72, 135, 59, 83, 84, 761, 137, 366, - /* 1310 */ 802, 448, 85, 352, 452, 451, 139, 226, 819, 140, - /* 1320 */ 156, 62, 315, 314, 313, 215, 311, 367, 393, 683, - /* 1330 */ 434, 185, 141, 912, 142, 160, 148, 812, 875, 383, - /* 1340 */ 189, 67, 832, 180, 389, 248, 895, 775, 219, 824, - /* 1350 */ 824, 826, 827, 19, 247, 190, 266, 154, 391, 271, - /* 1360 */ 191, 192, 83, 84, 682, 406, 733, 182, 322, 85, - /* 1370 */ 352, 452, 451, 732, 183, 819, 342, 132, 181, 711, - /* 1380 */ 731, 421, 76, 445, 705, 3, 323, 704, 283, 724, - /* 1390 */ 352, 771, 703, 966, 723, 71, 204, 6, 288, 290, - /* 1400 */ 448, 772, 770, 769, 79, 292, 824, 824, 826, 827, - /* 1410 */ 19, 294, 297, 438, 346, 442, 102, 861, 753, 434, - /* 1420 */ 238, 426, 73, 305, 239, 304, 326, 240, 424, 306, - /* 1430 */ 307, 832, 213, 688, 22, 952, 453, 214, 216, 217, - /* 1440 */ 454, 677, 115, 676, 671, 125, 126, 235, 127, 669, - /* 1450 */ 327, 83, 84, 359, 353, 244, 166, 328, 85, 352, - /* 1460 */ 452, 451, 134, 179, 819, 357, 113, 891, 811, 889, - /* 1470 */ 136, 128, 138, 743, 258, 184, 906, 143, 145, 63, - /* 1480 */ 64, 65, 66, 129, 909, 905, 187, 186, 8, 13, - /* 1490 */ 188, 265, 898, 149, 202, 824, 824, 826, 827, 19, - /* 1500 */ 388, 987, 150, 161, 285, 685, 392, 396, 151, 722, - /* 1510 */ 193, 68, 14, 401, 279, 15, 69, 236, 831, 830, - /* 1520 */ 131, 859, 751, 70, 16, 414, 755, 4, 784, 220, - /* 1530 */ 222, 174, 152, 437, 779, 201, 17, 77, 74, 18, - /* 1540 */ 874, 860, 858, 915, 863, 914, 207, 206, 941, 163, - /* 1550 */ 210, 942, 209, 164, 441, 862, 165, 211, 829, 695, - /* 1560 */ 87, 312, 309, 947, 1291, 1290, + /* 0 */ 324, 1323, 155, 155, 2, 203, 94, 94, 94, 93, + /* 10 */ 350, 98, 98, 98, 98, 91, 95, 95, 94, 94, + /* 20 */ 94, 93, 350, 268, 99, 100, 90, 971, 971, 847, + /* 30 */ 850, 839, 839, 97, 97, 98, 98, 98, 98, 350, + /* 40 */ 969, 96, 96, 96, 96, 95, 95, 94, 94, 94, + /* 50 */ 93, 350, 950, 96, 96, 96, 96, 95, 95, 94, + /* 60 */ 94, 94, 93, 350, 250, 96, 96, 96, 96, 95, + /* 70 */ 95, 94, 94, 94, 93, 350, 224, 224, 969, 132, + /* 80 */ 888, 348, 347, 415, 172, 324, 1286, 449, 414, 950, + /* 90 */ 951, 952, 808, 977, 1032, 950, 300, 786, 428, 132, + /* 100 */ 975, 362, 976, 9, 9, 787, 132, 52, 52, 99, + /* 110 */ 100, 90, 971, 971, 847, 850, 839, 839, 97, 97, + /* 120 */ 98, 98, 98, 98, 372, 978, 241, 978, 262, 369, + /* 130 */ 261, 120, 950, 951, 952, 194, 58, 324, 401, 398, + /* 140 */ 397, 808, 427, 429, 75, 808, 1260, 1260, 132, 396, + /* 150 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 160 */ 350, 99, 100, 90, 971, 971, 847, 850, 839, 839, + /* 170 */ 97, 97, 98, 98, 98, 98, 786, 262, 369, 261, + /* 180 */ 826, 262, 364, 251, 787, 1084, 101, 1114, 72, 324, + /* 190 */ 227, 1113, 242, 411, 442, 819, 92, 89, 178, 818, + /* 200 */ 1022, 268, 96, 96, 96, 96, 95, 95, 94, 94, + /* 210 */ 94, 93, 350, 99, 100, 90, 971, 971, 847, 850, + /* 220 */ 839, 839, 97, 97, 98, 98, 98, 98, 449, 372, + /* 230 */ 818, 818, 820, 92, 89, 178, 60, 92, 89, 178, + /* 240 */ 1025, 324, 357, 930, 1316, 300, 61, 1316, 52, 52, + /* 250 */ 836, 836, 848, 851, 96, 96, 96, 96, 95, 95, + /* 260 */ 94, 94, 94, 93, 350, 99, 100, 90, 971, 971, + /* 270 */ 847, 850, 839, 839, 97, 97, 98, 98, 98, 98, + /* 280 */ 92, 89, 178, 427, 412, 198, 930, 1317, 454, 995, + /* 290 */ 1317, 355, 1024, 324, 243, 231, 114, 277, 348, 347, + /* 300 */ 1242, 950, 416, 1071, 928, 840, 96, 96, 96, 96, + /* 310 */ 95, 95, 94, 94, 94, 93, 350, 99, 100, 90, + /* 320 */ 971, 971, 847, 850, 839, 839, 97, 97, 98, 98, + /* 330 */ 98, 98, 449, 328, 449, 120, 23, 256, 950, 951, + /* 340 */ 952, 968, 978, 438, 978, 324, 329, 928, 954, 701, + /* 350 */ 200, 175, 52, 52, 52, 52, 939, 353, 96, 96, + /* 360 */ 96, 96, 95, 95, 94, 94, 94, 93, 350, 99, + /* 370 */ 100, 90, 971, 971, 847, 850, 839, 839, 97, 97, + /* 380 */ 98, 98, 98, 98, 354, 449, 954, 427, 417, 427, + /* 390 */ 426, 1290, 92, 89, 178, 268, 253, 324, 255, 1058, + /* 400 */ 1037, 694, 93, 350, 383, 52, 52, 380, 1058, 374, + /* 410 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 420 */ 350, 99, 100, 90, 971, 971, 847, 850, 839, 839, + /* 430 */ 97, 97, 98, 98, 98, 98, 228, 449, 167, 449, + /* 440 */ 427, 407, 157, 446, 446, 446, 349, 349, 349, 324, + /* 450 */ 310, 316, 991, 827, 320, 242, 411, 51, 51, 36, + /* 460 */ 36, 254, 96, 96, 96, 96, 95, 95, 94, 94, + /* 470 */ 94, 93, 350, 99, 100, 90, 971, 971, 847, 850, + /* 480 */ 839, 839, 97, 97, 98, 98, 98, 98, 194, 316, + /* 490 */ 929, 401, 398, 397, 224, 224, 1265, 939, 353, 1318, + /* 500 */ 317, 324, 396, 1063, 1063, 813, 414, 1061, 1061, 950, + /* 510 */ 299, 448, 992, 268, 96, 96, 96, 96, 95, 95, + /* 520 */ 94, 94, 94, 93, 350, 99, 100, 90, 971, 971, + /* 530 */ 847, 850, 839, 839, 97, 97, 98, 98, 98, 98, + /* 540 */ 757, 1041, 449, 893, 893, 386, 950, 951, 952, 410, + /* 550 */ 992, 747, 747, 324, 229, 268, 221, 296, 268, 771, + /* 560 */ 890, 378, 52, 52, 890, 421, 96, 96, 96, 96, + /* 570 */ 95, 95, 94, 94, 94, 93, 350, 99, 100, 90, + /* 580 */ 971, 971, 847, 850, 839, 839, 97, 97, 98, 98, + /* 590 */ 98, 98, 103, 449, 275, 384, 1241, 343, 157, 1207, + /* 600 */ 909, 669, 670, 671, 176, 197, 196, 195, 324, 298, + /* 610 */ 319, 1266, 2, 37, 37, 910, 1134, 1040, 96, 96, + /* 620 */ 96, 96, 95, 95, 94, 94, 94, 93, 350, 697, + /* 630 */ 911, 177, 99, 100, 90, 971, 971, 847, 850, 839, + /* 640 */ 839, 97, 97, 98, 98, 98, 98, 230, 146, 120, + /* 650 */ 735, 1235, 826, 270, 1141, 273, 1141, 771, 171, 170, + /* 660 */ 736, 1141, 82, 324, 80, 268, 697, 819, 158, 268, + /* 670 */ 378, 818, 78, 96, 96, 96, 96, 95, 95, 94, + /* 680 */ 94, 94, 93, 350, 120, 950, 393, 99, 100, 90, + /* 690 */ 971, 971, 847, 850, 839, 839, 97, 97, 98, 98, + /* 700 */ 98, 98, 818, 818, 820, 1141, 1070, 370, 331, 133, + /* 710 */ 1066, 1141, 1250, 198, 268, 324, 1016, 330, 245, 333, + /* 720 */ 24, 334, 950, 951, 952, 368, 335, 81, 96, 96, + /* 730 */ 96, 96, 95, 95, 94, 94, 94, 93, 350, 99, + /* 740 */ 100, 90, 971, 971, 847, 850, 839, 839, 97, 97, + /* 750 */ 98, 98, 98, 98, 132, 267, 260, 445, 330, 223, + /* 760 */ 175, 1289, 925, 752, 724, 318, 1073, 324, 751, 246, + /* 770 */ 385, 301, 301, 378, 329, 361, 344, 414, 1233, 280, + /* 780 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 790 */ 350, 99, 88, 90, 971, 971, 847, 850, 839, 839, + /* 800 */ 97, 97, 98, 98, 98, 98, 337, 346, 721, 722, + /* 810 */ 449, 120, 118, 887, 162, 887, 810, 371, 324, 202, + /* 820 */ 202, 373, 249, 263, 202, 394, 74, 704, 208, 1069, + /* 830 */ 12, 12, 96, 96, 96, 96, 95, 95, 94, 94, + /* 840 */ 94, 93, 350, 100, 90, 971, 971, 847, 850, 839, + /* 850 */ 839, 97, 97, 98, 98, 98, 98, 449, 771, 232, + /* 860 */ 449, 278, 120, 286, 74, 704, 714, 713, 324, 342, + /* 870 */ 749, 877, 1209, 77, 285, 1255, 780, 52, 52, 202, + /* 880 */ 27, 27, 418, 96, 96, 96, 96, 95, 95, 94, + /* 890 */ 94, 94, 93, 350, 90, 971, 971, 847, 850, 839, + /* 900 */ 839, 97, 97, 98, 98, 98, 98, 86, 444, 877, + /* 910 */ 3, 1193, 422, 1013, 873, 435, 886, 208, 886, 689, + /* 920 */ 1091, 257, 116, 822, 447, 1230, 117, 1229, 86, 444, + /* 930 */ 177, 3, 381, 96, 96, 96, 96, 95, 95, 94, + /* 940 */ 94, 94, 93, 350, 339, 447, 120, 351, 120, 212, + /* 950 */ 169, 287, 404, 282, 403, 199, 771, 950, 433, 419, + /* 960 */ 439, 822, 280, 691, 1039, 264, 269, 132, 351, 153, + /* 970 */ 826, 376, 74, 272, 274, 276, 83, 84, 1054, 433, + /* 980 */ 147, 1038, 443, 85, 351, 451, 450, 281, 132, 818, + /* 990 */ 25, 826, 449, 120, 950, 951, 952, 83, 84, 86, + /* 1000 */ 444, 691, 3, 408, 85, 351, 451, 450, 449, 5, + /* 1010 */ 818, 203, 32, 32, 1107, 120, 447, 950, 225, 1140, + /* 1020 */ 818, 818, 820, 821, 19, 203, 226, 950, 38, 38, + /* 1030 */ 1087, 314, 314, 313, 215, 311, 120, 449, 678, 351, + /* 1040 */ 237, 818, 818, 820, 821, 19, 969, 409, 377, 1, + /* 1050 */ 433, 180, 706, 248, 950, 951, 952, 10, 10, 449, + /* 1060 */ 969, 247, 826, 1098, 950, 951, 952, 430, 83, 84, + /* 1070 */ 756, 336, 950, 20, 431, 85, 351, 451, 450, 10, + /* 1080 */ 10, 818, 86, 444, 969, 3, 950, 449, 302, 303, + /* 1090 */ 182, 950, 1146, 338, 1021, 1015, 1004, 183, 969, 447, + /* 1100 */ 132, 181, 76, 444, 21, 3, 449, 10, 10, 950, + /* 1110 */ 951, 952, 818, 818, 820, 821, 19, 715, 1279, 447, + /* 1120 */ 389, 233, 351, 950, 951, 952, 10, 10, 950, 951, + /* 1130 */ 952, 1003, 218, 433, 1005, 325, 1273, 773, 289, 291, + /* 1140 */ 424, 293, 351, 7, 159, 826, 363, 402, 315, 360, + /* 1150 */ 1129, 83, 84, 433, 1232, 716, 772, 259, 85, 351, + /* 1160 */ 451, 450, 358, 375, 818, 826, 360, 359, 399, 1211, + /* 1170 */ 157, 83, 84, 681, 98, 98, 98, 98, 85, 351, + /* 1180 */ 451, 450, 323, 252, 818, 295, 1211, 1213, 1235, 173, + /* 1190 */ 1037, 284, 434, 340, 1204, 818, 818, 820, 821, 19, + /* 1200 */ 308, 234, 449, 234, 96, 96, 96, 96, 95, 95, + /* 1210 */ 94, 94, 94, 93, 350, 818, 818, 820, 821, 19, + /* 1220 */ 909, 120, 39, 39, 1203, 449, 168, 360, 449, 1276, + /* 1230 */ 367, 449, 135, 449, 986, 910, 449, 1249, 449, 1247, + /* 1240 */ 449, 205, 983, 449, 370, 40, 40, 1211, 41, 41, + /* 1250 */ 911, 42, 42, 28, 28, 870, 29, 29, 31, 31, + /* 1260 */ 43, 43, 379, 44, 44, 449, 59, 449, 332, 449, + /* 1270 */ 432, 62, 144, 156, 449, 130, 449, 72, 449, 137, + /* 1280 */ 449, 365, 449, 392, 139, 45, 45, 11, 11, 46, + /* 1290 */ 46, 140, 1200, 449, 105, 105, 47, 47, 48, 48, + /* 1300 */ 33, 33, 49, 49, 1126, 449, 141, 366, 449, 185, + /* 1310 */ 142, 449, 1234, 50, 50, 449, 160, 449, 148, 449, + /* 1320 */ 1136, 382, 449, 67, 449, 34, 34, 449, 122, 122, + /* 1330 */ 449, 123, 123, 449, 1198, 124, 124, 56, 56, 35, + /* 1340 */ 35, 449, 106, 106, 53, 53, 449, 107, 107, 449, + /* 1350 */ 108, 108, 449, 104, 104, 449, 406, 449, 388, 449, + /* 1360 */ 189, 121, 121, 449, 190, 449, 119, 119, 449, 112, + /* 1370 */ 112, 449, 111, 111, 1218, 109, 109, 110, 110, 55, + /* 1380 */ 55, 266, 752, 57, 57, 54, 54, 751, 26, 26, + /* 1390 */ 1099, 30, 30, 219, 154, 390, 271, 191, 321, 1006, + /* 1400 */ 192, 405, 1057, 1056, 1055, 341, 1048, 706, 1047, 1029, + /* 1410 */ 322, 420, 1028, 71, 1095, 283, 288, 1027, 1288, 204, + /* 1420 */ 6, 297, 79, 1184, 437, 1096, 1094, 290, 345, 292, + /* 1430 */ 441, 1093, 294, 102, 425, 73, 423, 213, 1012, 22, + /* 1440 */ 452, 945, 214, 1077, 216, 217, 238, 453, 306, 304, + /* 1450 */ 307, 239, 240, 1001, 305, 125, 996, 126, 115, 235, + /* 1460 */ 127, 665, 352, 166, 244, 179, 356, 113, 885, 883, + /* 1470 */ 806, 136, 128, 738, 326, 138, 327, 258, 184, 899, + /* 1480 */ 143, 129, 145, 63, 64, 65, 66, 902, 186, 187, + /* 1490 */ 898, 8, 13, 188, 134, 265, 891, 202, 980, 387, + /* 1500 */ 150, 149, 680, 161, 391, 193, 285, 279, 395, 151, + /* 1510 */ 68, 717, 14, 15, 400, 69, 16, 131, 236, 825, + /* 1520 */ 824, 853, 746, 750, 4, 70, 174, 413, 220, 222, + /* 1530 */ 152, 779, 774, 77, 868, 74, 854, 201, 17, 852, + /* 1540 */ 908, 206, 907, 207, 18, 857, 934, 163, 436, 210, + /* 1550 */ 935, 164, 209, 165, 440, 856, 823, 312, 690, 87, + /* 1560 */ 211, 309, 1281, 940, 995, 1280, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 19, 115, 19, 117, 118, 24, 1, 2, 27, 79, - /* 10 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - /* 20 */ 90, 91, 92, 93, 94, 144, 145, 146, 147, 58, - /* 30 */ 49, 50, 79, 80, 81, 82, 22, 84, 85, 86, - /* 40 */ 87, 88, 89, 90, 91, 92, 93, 94, 221, 222, - /* 50 */ 223, 70, 71, 72, 73, 74, 75, 76, 77, 78, - /* 60 */ 79, 80, 81, 82, 94, 84, 85, 86, 87, 88, - /* 70 */ 89, 90, 91, 92, 93, 94, 19, 94, 97, 108, - /* 80 */ 109, 110, 99, 100, 101, 102, 103, 104, 105, 32, - /* 90 */ 119, 120, 78, 27, 152, 112, 93, 94, 41, 88, - /* 100 */ 89, 90, 91, 92, 93, 94, 49, 50, 84, 85, - /* 110 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 58, - /* 120 */ 157, 119, 120, 163, 68, 163, 65, 70, 71, 72, - /* 130 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - /* 140 */ 152, 84, 85, 86, 87, 88, 89, 90, 91, 92, - /* 150 */ 93, 94, 19, 97, 88, 89, 196, 101, 196, 26, - /* 160 */ 172, 173, 96, 97, 98, 210, 100, 22, 152, 108, - /* 170 */ 109, 110, 27, 107, 27, 109, 221, 222, 223, 219, - /* 180 */ 238, 219, 49, 50, 152, 169, 170, 54, 132, 133, - /* 190 */ 134, 228, 232, 171, 231, 207, 208, 237, 132, 237, - /* 200 */ 134, 179, 19, 70, 71, 72, 73, 74, 75, 76, - /* 210 */ 77, 78, 79, 80, 81, 82, 152, 84, 85, 86, - /* 220 */ 87, 88, 89, 90, 91, 92, 93, 94, 27, 65, - /* 230 */ 30, 152, 49, 50, 34, 52, 90, 91, 92, 93, - /* 240 */ 94, 96, 97, 98, 97, 22, 230, 27, 48, 217, - /* 250 */ 27, 172, 173, 70, 71, 72, 73, 74, 75, 76, - /* 260 */ 77, 78, 79, 80, 81, 82, 172, 84, 85, 86, - /* 270 */ 87, 88, 89, 90, 91, 92, 93, 94, 19, 148, - /* 280 */ 149, 152, 218, 24, 152, 154, 207, 156, 172, 152, - /* 290 */ 22, 68, 27, 152, 163, 27, 164, 96, 97, 98, - /* 300 */ 99, 172, 173, 102, 103, 104, 169, 170, 49, 50, - /* 310 */ 90, 88, 89, 152, 113, 186, 96, 97, 98, 96, - /* 320 */ 97, 160, 57, 27, 101, 164, 137, 196, 139, 70, - /* 330 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - /* 340 */ 81, 82, 11, 84, 85, 86, 87, 88, 89, 90, - /* 350 */ 91, 92, 93, 94, 19, 132, 133, 134, 23, 218, - /* 360 */ 152, 96, 97, 98, 96, 97, 98, 230, 99, 22, - /* 370 */ 152, 102, 103, 104, 27, 244, 152, 152, 27, 26, - /* 380 */ 152, 22, 113, 65, 49, 50, 27, 194, 195, 58, - /* 390 */ 172, 173, 96, 97, 98, 185, 65, 172, 173, 206, - /* 400 */ 172, 173, 190, 191, 186, 70, 71, 72, 73, 74, - /* 410 */ 75, 76, 77, 78, 79, 80, 81, 82, 175, 84, - /* 420 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - /* 430 */ 19, 175, 207, 208, 23, 207, 208, 119, 120, 108, - /* 440 */ 109, 110, 27, 96, 97, 98, 116, 96, 97, 98, - /* 450 */ 152, 121, 152, 179, 180, 96, 97, 98, 250, 106, - /* 460 */ 49, 50, 188, 19, 221, 222, 223, 168, 169, 170, - /* 470 */ 172, 173, 172, 173, 250, 124, 172, 221, 222, 223, - /* 480 */ 26, 70, 71, 72, 73, 74, 75, 76, 77, 78, - /* 490 */ 79, 80, 81, 82, 50, 84, 85, 86, 87, 88, - /* 500 */ 89, 90, 91, 92, 93, 94, 19, 207, 208, 12, - /* 510 */ 23, 96, 97, 98, 221, 222, 223, 194, 195, 152, - /* 520 */ 199, 23, 19, 225, 26, 28, 152, 152, 152, 206, - /* 530 */ 209, 164, 190, 191, 241, 152, 49, 50, 152, 124, - /* 540 */ 152, 44, 219, 46, 152, 21, 172, 173, 172, 173, - /* 550 */ 183, 107, 185, 16, 163, 58, 112, 70, 71, 72, - /* 560 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - /* 570 */ 152, 84, 85, 86, 87, 88, 89, 90, 91, 92, - /* 580 */ 93, 94, 19, 207, 130, 152, 23, 196, 64, 152, - /* 590 */ 172, 173, 22, 152, 24, 152, 98, 27, 61, 96, - /* 600 */ 63, 26, 211, 212, 186, 172, 173, 49, 50, 172, - /* 610 */ 173, 23, 49, 50, 26, 172, 173, 88, 89, 186, - /* 620 */ 24, 238, 124, 27, 238, 22, 23, 103, 187, 26, - /* 630 */ 152, 73, 74, 70, 71, 72, 73, 74, 75, 76, - /* 640 */ 77, 78, 79, 80, 81, 82, 152, 84, 85, 86, - /* 650 */ 87, 88, 89, 90, 91, 92, 93, 94, 19, 101, - /* 660 */ 152, 132, 23, 134, 140, 152, 12, 97, 36, 168, - /* 670 */ 169, 170, 69, 98, 152, 22, 23, 140, 50, 26, - /* 680 */ 172, 173, 28, 51, 152, 172, 173, 193, 49, 50, - /* 690 */ 22, 59, 24, 97, 172, 173, 152, 152, 44, 124, - /* 700 */ 46, 0, 1, 2, 172, 173, 22, 23, 19, 70, - /* 710 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - /* 720 */ 81, 82, 69, 84, 85, 86, 87, 88, 89, 90, - /* 730 */ 91, 92, 93, 94, 152, 107, 152, 193, 49, 50, - /* 740 */ 181, 22, 23, 111, 108, 109, 110, 7, 8, 9, - /* 750 */ 16, 247, 248, 69, 172, 173, 172, 173, 152, 70, - /* 760 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - /* 770 */ 81, 82, 152, 84, 85, 86, 87, 88, 89, 90, - /* 780 */ 91, 92, 93, 94, 19, 152, 242, 152, 69, 152, - /* 790 */ 166, 167, 172, 173, 32, 61, 152, 63, 152, 193, - /* 800 */ 152, 152, 152, 41, 152, 172, 173, 172, 173, 172, - /* 810 */ 173, 152, 152, 152, 49, 50, 172, 173, 172, 173, - /* 820 */ 172, 173, 172, 173, 172, 173, 132, 138, 134, 152, - /* 830 */ 152, 172, 173, 172, 173, 70, 71, 72, 73, 74, - /* 840 */ 75, 76, 77, 78, 79, 80, 81, 82, 152, 84, - /* 850 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - /* 860 */ 19, 152, 22, 152, 195, 24, 152, 27, 172, 173, - /* 870 */ 193, 193, 152, 152, 152, 206, 152, 217, 152, 152, - /* 880 */ 152, 172, 173, 172, 173, 152, 172, 173, 152, 152, - /* 890 */ 49, 50, 172, 173, 172, 173, 172, 173, 172, 173, - /* 900 */ 172, 173, 152, 138, 152, 172, 173, 108, 109, 110, - /* 910 */ 19, 70, 71, 72, 73, 74, 75, 76, 77, 78, - /* 920 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88, - /* 930 */ 89, 90, 91, 92, 93, 94, 152, 97, 152, 152, - /* 940 */ 49, 50, 26, 193, 172, 173, 152, 152, 152, 146, - /* 950 */ 147, 132, 152, 134, 217, 181, 172, 173, 172, 173, - /* 960 */ 19, 70, 71, 72, 73, 74, 75, 76, 77, 78, - /* 970 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88, - /* 980 */ 89, 90, 91, 92, 93, 94, 152, 193, 152, 193, - /* 990 */ 49, 50, 181, 193, 172, 173, 166, 167, 245, 246, - /* 1000 */ 211, 212, 152, 22, 217, 152, 172, 173, 172, 173, - /* 1010 */ 19, 70, 71, 72, 73, 74, 75, 76, 77, 78, - /* 1020 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88, - /* 1030 */ 89, 90, 91, 92, 93, 94, 152, 187, 152, 123, - /* 1040 */ 49, 50, 23, 23, 23, 26, 26, 26, 23, 23, - /* 1050 */ 23, 26, 26, 26, 7, 8, 172, 173, 172, 173, - /* 1060 */ 19, 90, 71, 72, 73, 74, 75, 76, 77, 78, - /* 1070 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88, - /* 1080 */ 89, 90, 91, 92, 93, 94, 152, 116, 152, 217, - /* 1090 */ 49, 50, 121, 23, 172, 173, 26, 100, 101, 27, - /* 1100 */ 101, 27, 23, 122, 152, 26, 172, 173, 172, 173, - /* 1110 */ 152, 112, 163, 72, 73, 74, 75, 76, 77, 78, - /* 1120 */ 79, 80, 81, 82, 163, 84, 85, 86, 87, 88, - /* 1130 */ 89, 90, 91, 92, 93, 94, 19, 20, 152, 22, - /* 1140 */ 23, 152, 163, 65, 27, 196, 163, 19, 20, 23, - /* 1150 */ 22, 213, 26, 19, 37, 27, 152, 196, 172, 173, - /* 1160 */ 152, 172, 173, 27, 23, 37, 152, 26, 152, 97, - /* 1170 */ 152, 97, 210, 56, 163, 196, 163, 163, 100, 196, - /* 1180 */ 172, 173, 65, 152, 56, 68, 172, 173, 172, 173, - /* 1190 */ 172, 173, 152, 65, 163, 163, 68, 23, 152, 234, - /* 1200 */ 26, 152, 152, 172, 173, 88, 89, 196, 152, 196, - /* 1210 */ 196, 152, 95, 96, 97, 98, 88, 89, 101, 152, - /* 1220 */ 152, 207, 208, 95, 96, 97, 98, 196, 196, 101, - /* 1230 */ 96, 233, 152, 97, 152, 152, 19, 20, 207, 22, - /* 1240 */ 152, 152, 152, 191, 27, 152, 152, 152, 152, 132, - /* 1250 */ 133, 134, 135, 136, 37, 152, 152, 152, 152, 152, - /* 1260 */ 132, 133, 134, 135, 136, 210, 197, 210, 210, 198, - /* 1270 */ 150, 184, 239, 56, 201, 214, 214, 201, 239, 180, - /* 1280 */ 214, 227, 198, 38, 176, 68, 175, 175, 175, 122, - /* 1290 */ 155, 200, 159, 19, 20, 40, 22, 159, 159, 22, - /* 1300 */ 70, 27, 130, 243, 240, 88, 89, 90, 189, 18, - /* 1310 */ 201, 37, 95, 96, 97, 98, 192, 5, 101, 192, - /* 1320 */ 220, 240, 10, 11, 12, 13, 14, 159, 18, 17, - /* 1330 */ 56, 158, 192, 201, 192, 220, 189, 189, 201, 159, - /* 1340 */ 158, 137, 68, 31, 45, 33, 236, 159, 159, 132, - /* 1350 */ 133, 134, 135, 136, 42, 158, 235, 22, 177, 159, - /* 1360 */ 158, 158, 88, 89, 159, 107, 174, 55, 177, 95, - /* 1370 */ 96, 97, 98, 174, 62, 101, 47, 65, 66, 106, - /* 1380 */ 174, 125, 19, 20, 174, 22, 177, 176, 174, 182, - /* 1390 */ 27, 216, 174, 174, 182, 107, 159, 22, 215, 215, - /* 1400 */ 37, 216, 216, 216, 137, 215, 132, 133, 134, 135, - /* 1410 */ 136, 215, 159, 177, 94, 177, 129, 224, 205, 56, - /* 1420 */ 226, 126, 128, 203, 229, 204, 114, 229, 127, 202, - /* 1430 */ 201, 68, 25, 162, 26, 13, 161, 153, 153, 6, - /* 1440 */ 151, 151, 178, 151, 151, 165, 165, 178, 165, 4, - /* 1450 */ 249, 88, 89, 141, 3, 142, 22, 249, 95, 96, - /* 1460 */ 97, 98, 246, 15, 101, 67, 16, 23, 120, 23, - /* 1470 */ 131, 111, 123, 20, 16, 125, 1, 123, 131, 78, - /* 1480 */ 78, 78, 78, 111, 96, 1, 122, 35, 5, 22, - /* 1490 */ 107, 140, 53, 53, 26, 132, 133, 134, 135, 136, - /* 1500 */ 43, 60, 107, 24, 112, 20, 19, 52, 22, 29, - /* 1510 */ 105, 22, 22, 52, 23, 22, 22, 52, 23, 23, - /* 1520 */ 39, 23, 116, 26, 22, 26, 23, 22, 96, 23, - /* 1530 */ 23, 122, 22, 24, 124, 35, 35, 26, 26, 35, - /* 1540 */ 23, 23, 23, 23, 11, 23, 22, 26, 23, 22, - /* 1550 */ 122, 23, 26, 22, 24, 23, 22, 122, 23, 23, - /* 1560 */ 22, 15, 23, 1, 122, 122, + /* 0 */ 19, 144, 145, 146, 147, 24, 90, 91, 92, 93, + /* 10 */ 94, 54, 55, 56, 57, 58, 88, 89, 90, 91, + /* 20 */ 92, 93, 94, 152, 43, 44, 45, 46, 47, 48, + /* 30 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 94, + /* 40 */ 59, 84, 85, 86, 87, 88, 89, 90, 91, 92, + /* 50 */ 93, 94, 59, 84, 85, 86, 87, 88, 89, 90, + /* 60 */ 91, 92, 93, 94, 193, 84, 85, 86, 87, 88, + /* 70 */ 89, 90, 91, 92, 93, 94, 194, 195, 97, 79, + /* 80 */ 11, 88, 89, 152, 26, 19, 171, 152, 206, 96, + /* 90 */ 97, 98, 72, 100, 179, 59, 152, 31, 163, 79, + /* 100 */ 107, 219, 109, 172, 173, 39, 79, 172, 173, 43, + /* 110 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 120 */ 54, 55, 56, 57, 152, 132, 199, 134, 108, 109, + /* 130 */ 110, 196, 96, 97, 98, 99, 209, 19, 102, 103, + /* 140 */ 104, 72, 207, 208, 26, 72, 119, 120, 79, 113, + /* 150 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 160 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 170 */ 52, 53, 54, 55, 56, 57, 31, 108, 109, 110, + /* 180 */ 82, 108, 109, 110, 39, 210, 68, 175, 130, 19, + /* 190 */ 218, 175, 119, 120, 250, 97, 221, 222, 223, 101, + /* 200 */ 172, 152, 84, 85, 86, 87, 88, 89, 90, 91, + /* 210 */ 92, 93, 94, 43, 44, 45, 46, 47, 48, 49, + /* 220 */ 50, 51, 52, 53, 54, 55, 56, 57, 152, 152, + /* 230 */ 132, 133, 134, 221, 222, 223, 66, 221, 222, 223, + /* 240 */ 172, 19, 193, 22, 23, 152, 24, 26, 172, 173, + /* 250 */ 46, 47, 48, 49, 84, 85, 86, 87, 88, 89, + /* 260 */ 90, 91, 92, 93, 94, 43, 44, 45, 46, 47, + /* 270 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 280 */ 221, 222, 223, 207, 208, 46, 22, 23, 148, 149, + /* 290 */ 26, 242, 172, 19, 154, 218, 156, 23, 88, 89, + /* 300 */ 241, 59, 163, 163, 83, 101, 84, 85, 86, 87, + /* 310 */ 88, 89, 90, 91, 92, 93, 94, 43, 44, 45, + /* 320 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 330 */ 56, 57, 152, 157, 152, 196, 196, 16, 96, 97, + /* 340 */ 98, 26, 132, 250, 134, 19, 107, 83, 59, 23, + /* 350 */ 211, 212, 172, 173, 172, 173, 1, 2, 84, 85, + /* 360 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 43, + /* 370 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 380 */ 54, 55, 56, 57, 244, 152, 97, 207, 208, 207, + /* 390 */ 208, 185, 221, 222, 223, 152, 75, 19, 77, 179, + /* 400 */ 180, 23, 93, 94, 228, 172, 173, 231, 188, 152, + /* 410 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 420 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 430 */ 52, 53, 54, 55, 56, 57, 193, 152, 123, 152, + /* 440 */ 207, 208, 152, 168, 169, 170, 168, 169, 170, 19, + /* 450 */ 160, 22, 23, 23, 164, 119, 120, 172, 173, 172, + /* 460 */ 173, 140, 84, 85, 86, 87, 88, 89, 90, 91, + /* 470 */ 92, 93, 94, 43, 44, 45, 46, 47, 48, 49, + /* 480 */ 50, 51, 52, 53, 54, 55, 56, 57, 99, 22, + /* 490 */ 23, 102, 103, 104, 194, 195, 0, 1, 2, 247, + /* 500 */ 248, 19, 113, 190, 191, 23, 206, 190, 191, 59, + /* 510 */ 225, 152, 83, 152, 84, 85, 86, 87, 88, 89, + /* 520 */ 90, 91, 92, 93, 94, 43, 44, 45, 46, 47, + /* 530 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 540 */ 90, 181, 152, 108, 109, 110, 96, 97, 98, 115, + /* 550 */ 83, 117, 118, 19, 193, 152, 23, 152, 152, 26, + /* 560 */ 29, 152, 172, 173, 33, 152, 84, 85, 86, 87, + /* 570 */ 88, 89, 90, 91, 92, 93, 94, 43, 44, 45, + /* 580 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 590 */ 56, 57, 22, 152, 16, 64, 193, 207, 152, 193, + /* 600 */ 12, 7, 8, 9, 152, 108, 109, 110, 19, 152, + /* 610 */ 164, 146, 147, 172, 173, 27, 163, 181, 84, 85, + /* 620 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 59, + /* 630 */ 42, 98, 43, 44, 45, 46, 47, 48, 49, 50, + /* 640 */ 51, 52, 53, 54, 55, 56, 57, 238, 22, 196, + /* 650 */ 62, 163, 82, 75, 152, 77, 152, 124, 88, 89, + /* 660 */ 72, 152, 137, 19, 139, 152, 96, 97, 24, 152, + /* 670 */ 152, 101, 138, 84, 85, 86, 87, 88, 89, 90, + /* 680 */ 91, 92, 93, 94, 196, 59, 19, 43, 44, 45, + /* 690 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 700 */ 56, 57, 132, 133, 134, 152, 193, 219, 245, 246, + /* 710 */ 193, 152, 152, 46, 152, 19, 166, 167, 152, 217, + /* 720 */ 232, 217, 96, 97, 98, 237, 217, 138, 84, 85, + /* 730 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 43, + /* 740 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 750 */ 54, 55, 56, 57, 79, 193, 238, 166, 167, 211, + /* 760 */ 212, 23, 23, 116, 26, 26, 195, 19, 121, 152, + /* 770 */ 217, 152, 152, 152, 107, 100, 217, 206, 163, 112, + /* 780 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 790 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 800 */ 52, 53, 54, 55, 56, 57, 187, 187, 7, 8, + /* 810 */ 152, 196, 22, 132, 24, 134, 23, 23, 19, 26, + /* 820 */ 26, 23, 152, 23, 26, 23, 26, 59, 26, 163, + /* 830 */ 172, 173, 84, 85, 86, 87, 88, 89, 90, 91, + /* 840 */ 92, 93, 94, 44, 45, 46, 47, 48, 49, 50, + /* 850 */ 51, 52, 53, 54, 55, 56, 57, 152, 26, 238, + /* 860 */ 152, 23, 196, 101, 26, 97, 100, 101, 19, 19, + /* 870 */ 23, 59, 152, 26, 112, 152, 23, 172, 173, 26, + /* 880 */ 172, 173, 19, 84, 85, 86, 87, 88, 89, 90, + /* 890 */ 91, 92, 93, 94, 45, 46, 47, 48, 49, 50, + /* 900 */ 51, 52, 53, 54, 55, 56, 57, 19, 20, 97, + /* 910 */ 22, 23, 207, 163, 23, 163, 132, 26, 134, 23, + /* 920 */ 213, 152, 26, 59, 36, 152, 22, 152, 19, 20, + /* 930 */ 98, 22, 152, 84, 85, 86, 87, 88, 89, 90, + /* 940 */ 91, 92, 93, 94, 94, 36, 196, 59, 196, 99, + /* 950 */ 100, 101, 102, 103, 104, 105, 124, 59, 70, 96, + /* 960 */ 163, 97, 112, 59, 181, 152, 152, 79, 59, 71, + /* 970 */ 82, 19, 26, 152, 152, 152, 88, 89, 152, 70, + /* 980 */ 22, 152, 163, 95, 96, 97, 98, 152, 79, 101, + /* 990 */ 22, 82, 152, 196, 96, 97, 98, 88, 89, 19, + /* 1000 */ 20, 97, 22, 163, 95, 96, 97, 98, 152, 22, + /* 1010 */ 101, 24, 172, 173, 152, 196, 36, 59, 22, 152, + /* 1020 */ 132, 133, 134, 135, 136, 24, 5, 59, 172, 173, + /* 1030 */ 152, 10, 11, 12, 13, 14, 196, 152, 17, 59, + /* 1040 */ 210, 132, 133, 134, 135, 136, 59, 207, 96, 22, + /* 1050 */ 70, 30, 106, 32, 96, 97, 98, 172, 173, 152, + /* 1060 */ 59, 40, 82, 152, 96, 97, 98, 152, 88, 89, + /* 1070 */ 90, 186, 59, 22, 191, 95, 96, 97, 98, 172, + /* 1080 */ 173, 101, 19, 20, 97, 22, 59, 152, 152, 152, + /* 1090 */ 69, 59, 152, 186, 152, 152, 152, 76, 97, 36, + /* 1100 */ 79, 80, 19, 20, 53, 22, 152, 172, 173, 96, + /* 1110 */ 97, 98, 132, 133, 134, 135, 136, 35, 122, 36, + /* 1120 */ 234, 186, 59, 96, 97, 98, 172, 173, 96, 97, + /* 1130 */ 98, 152, 233, 70, 152, 114, 152, 124, 210, 210, + /* 1140 */ 186, 210, 59, 198, 197, 82, 214, 65, 150, 152, + /* 1150 */ 201, 88, 89, 70, 201, 73, 124, 239, 95, 96, + /* 1160 */ 97, 98, 141, 239, 101, 82, 169, 170, 176, 152, + /* 1170 */ 152, 88, 89, 21, 54, 55, 56, 57, 95, 96, + /* 1180 */ 97, 98, 164, 214, 101, 214, 169, 170, 163, 184, + /* 1190 */ 180, 175, 227, 111, 175, 132, 133, 134, 135, 136, + /* 1200 */ 200, 183, 152, 185, 84, 85, 86, 87, 88, 89, + /* 1210 */ 90, 91, 92, 93, 94, 132, 133, 134, 135, 136, + /* 1220 */ 12, 196, 172, 173, 175, 152, 198, 230, 152, 155, + /* 1230 */ 78, 152, 243, 152, 60, 27, 152, 159, 152, 159, + /* 1240 */ 152, 122, 38, 152, 219, 172, 173, 230, 172, 173, + /* 1250 */ 42, 172, 173, 172, 173, 103, 172, 173, 172, 173, + /* 1260 */ 172, 173, 237, 172, 173, 152, 240, 152, 159, 152, + /* 1270 */ 62, 240, 22, 220, 152, 43, 152, 130, 152, 189, + /* 1280 */ 152, 18, 152, 18, 192, 172, 173, 172, 173, 172, + /* 1290 */ 173, 192, 140, 152, 172, 173, 172, 173, 172, 173, + /* 1300 */ 172, 173, 172, 173, 201, 152, 192, 159, 152, 158, + /* 1310 */ 192, 152, 201, 172, 173, 152, 220, 152, 189, 152, + /* 1320 */ 189, 159, 152, 137, 152, 172, 173, 152, 172, 173, + /* 1330 */ 152, 172, 173, 152, 201, 172, 173, 172, 173, 172, + /* 1340 */ 173, 152, 172, 173, 172, 173, 152, 172, 173, 152, + /* 1350 */ 172, 173, 152, 172, 173, 152, 90, 152, 61, 152, + /* 1360 */ 158, 172, 173, 152, 158, 152, 172, 173, 152, 172, + /* 1370 */ 173, 152, 172, 173, 236, 172, 173, 172, 173, 172, + /* 1380 */ 173, 235, 116, 172, 173, 172, 173, 121, 172, 173, + /* 1390 */ 159, 172, 173, 159, 22, 177, 159, 158, 177, 159, + /* 1400 */ 158, 107, 174, 174, 174, 63, 182, 106, 182, 174, + /* 1410 */ 177, 125, 176, 107, 216, 174, 215, 174, 174, 159, + /* 1420 */ 22, 159, 137, 224, 177, 216, 216, 215, 94, 215, + /* 1430 */ 177, 216, 215, 129, 126, 128, 127, 25, 162, 26, + /* 1440 */ 161, 13, 153, 205, 153, 6, 226, 151, 202, 204, + /* 1450 */ 201, 229, 229, 151, 203, 165, 151, 165, 178, 178, + /* 1460 */ 165, 4, 3, 22, 142, 15, 81, 16, 23, 23, + /* 1470 */ 120, 131, 111, 20, 249, 123, 249, 16, 125, 1, + /* 1480 */ 123, 111, 131, 53, 53, 53, 53, 96, 34, 122, + /* 1490 */ 1, 5, 22, 107, 246, 140, 67, 26, 74, 41, + /* 1500 */ 107, 67, 20, 24, 19, 105, 112, 23, 66, 22, + /* 1510 */ 22, 28, 22, 22, 66, 22, 22, 37, 66, 23, + /* 1520 */ 23, 23, 116, 23, 22, 26, 122, 26, 23, 23, + /* 1530 */ 22, 96, 124, 26, 23, 26, 23, 34, 34, 23, + /* 1540 */ 23, 26, 23, 22, 34, 11, 23, 22, 24, 122, + /* 1550 */ 23, 22, 26, 22, 24, 23, 23, 15, 23, 22, + /* 1560 */ 122, 23, 122, 1, 251, 122, }; #define YY_SHIFT_USE_DFLT (1566) -#define YY_SHIFT_COUNT (455) -#define YY_SHIFT_MIN (-114) +#define YY_SHIFT_COUNT (454) +#define YY_SHIFT_MIN (-84) #define YY_SHIFT_MAX (1562) static const short yy_shift_ofst[] = { - /* 0 */ 5, 1117, 1312, 1128, 1274, 1274, 1274, 1274, 61, -19, - /* 10 */ 57, 57, 183, 1274, 1274, 1274, 1274, 1274, 1274, 1274, - /* 20 */ 66, 66, 201, -29, 331, 318, 133, 259, 335, 411, - /* 30 */ 487, 563, 639, 689, 765, 841, 891, 891, 891, 891, - /* 40 */ 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, - /* 50 */ 891, 891, 891, 941, 891, 991, 1041, 1041, 1217, 1274, - /* 60 */ 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, - /* 70 */ 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, - /* 80 */ 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, - /* 90 */ 1363, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, - /* 100 */ 1274, 1274, 1274, 1274, -70, -47, -47, -47, -47, -47, - /* 110 */ 24, 11, 146, 296, 524, 444, 529, 529, 296, 3, - /* 120 */ 2, -30, 1566, 1566, 1566, -17, -17, -17, 145, 145, - /* 130 */ 497, 497, 265, 603, 653, 296, 296, 296, 296, 296, - /* 140 */ 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, - /* 150 */ 296, 296, 296, 296, 296, 701, 1078, 147, 147, 2, - /* 160 */ 164, 164, 164, 164, 164, 164, 1566, 1566, 1566, 223, - /* 170 */ 56, 56, 268, 269, 220, 347, 351, 415, 359, 296, - /* 180 */ 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, - /* 190 */ 296, 296, 296, 296, 296, 632, 632, 632, 296, 296, - /* 200 */ 498, 296, 296, 296, 570, 296, 296, 654, 296, 296, - /* 210 */ 296, 296, 296, 296, 296, 296, 296, 296, 636, 200, - /* 220 */ 596, 596, 596, 575, -114, 971, 740, 454, 503, 503, - /* 230 */ 1134, 454, 1134, 353, 588, 628, 762, 503, 189, 762, - /* 240 */ 762, 916, 330, 668, 1245, 1167, 1167, 1255, 1255, 1167, - /* 250 */ 1277, 1230, 1172, 1291, 1291, 1291, 1291, 1167, 1310, 1172, - /* 260 */ 1277, 1230, 1230, 1172, 1167, 1310, 1204, 1299, 1167, 1167, - /* 270 */ 1310, 1335, 1167, 1310, 1167, 1310, 1335, 1258, 1258, 1258, - /* 280 */ 1329, 1335, 1258, 1273, 1258, 1329, 1258, 1258, 1256, 1288, - /* 290 */ 1256, 1288, 1256, 1288, 1256, 1288, 1167, 1375, 1167, 1267, - /* 300 */ 1335, 1320, 1320, 1335, 1287, 1295, 1294, 1301, 1172, 1407, - /* 310 */ 1408, 1422, 1422, 1433, 1433, 1433, 1433, 1566, 1566, 1566, - /* 320 */ 1566, 1566, 1566, 1566, 1566, 558, 537, 684, 719, 734, - /* 330 */ 799, 840, 1019, 14, 1020, 1021, 1025, 1026, 1027, 1070, - /* 340 */ 1072, 997, 1047, 999, 1079, 1126, 1074, 1141, 694, 819, - /* 350 */ 1174, 1136, 981, 1445, 1451, 1434, 1313, 1448, 1398, 1450, - /* 360 */ 1444, 1446, 1348, 1339, 1360, 1349, 1453, 1350, 1458, 1475, - /* 370 */ 1354, 1347, 1401, 1402, 1403, 1404, 1372, 1388, 1452, 1364, - /* 380 */ 1484, 1483, 1467, 1383, 1351, 1439, 1468, 1440, 1441, 1457, - /* 390 */ 1395, 1479, 1485, 1487, 1392, 1405, 1486, 1455, 1489, 1490, - /* 400 */ 1491, 1493, 1461, 1480, 1494, 1465, 1481, 1495, 1496, 1498, - /* 410 */ 1497, 1406, 1502, 1503, 1505, 1499, 1409, 1506, 1507, 1432, - /* 420 */ 1500, 1510, 1410, 1511, 1501, 1512, 1504, 1517, 1511, 1518, - /* 430 */ 1519, 1520, 1521, 1522, 1524, 1533, 1525, 1527, 1509, 1526, - /* 440 */ 1528, 1531, 1530, 1526, 1532, 1534, 1535, 1536, 1538, 1428, - /* 450 */ 1435, 1442, 1443, 1539, 1546, 1562, + /* 0 */ 355, 888, 1021, 909, 1063, 1063, 1063, 1063, 20, -19, + /* 10 */ 66, 66, 170, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 20 */ -7, -7, 36, 73, 69, 27, 118, 222, 274, 326, + /* 30 */ 378, 430, 482, 534, 589, 644, 696, 696, 696, 696, + /* 40 */ 696, 696, 696, 696, 696, 696, 696, 696, 696, 696, + /* 50 */ 696, 696, 696, 748, 696, 799, 849, 849, 980, 1063, + /* 60 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 70 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 80 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 90 */ 1083, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 100 */ 1063, 1063, 1063, 1063, -43, 1120, 1120, 1120, 1120, 1120, + /* 110 */ -31, -72, -84, 242, 1152, 667, 210, 210, 242, 309, + /* 120 */ 336, -55, 1566, 1566, 1566, 850, 850, 850, 626, 626, + /* 130 */ 588, 588, 898, 221, 264, 242, 242, 242, 242, 242, + /* 140 */ 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, + /* 150 */ 242, 242, 242, 242, 242, 496, 675, 289, 289, 336, + /* 160 */ 0, 0, 0, 0, 0, 0, 1566, 1566, 1566, 570, + /* 170 */ 98, 98, 958, 389, 450, 968, 1013, 1032, 1027, 242, + /* 180 */ 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, + /* 190 */ 242, 242, 242, 242, 242, 1082, 1082, 1082, 242, 242, + /* 200 */ 533, 242, 242, 242, 987, 242, 242, 1208, 242, 242, + /* 210 */ 242, 242, 242, 242, 242, 242, 242, 242, 435, 531, + /* 220 */ 1001, 1001, 1001, 832, 434, 1266, 594, 58, 863, 863, + /* 230 */ 952, 58, 952, 946, 738, 239, 145, 863, 525, 145, + /* 240 */ 145, 315, 647, 790, 1174, 1119, 1119, 1204, 1204, 1119, + /* 250 */ 1250, 1232, 1147, 1263, 1263, 1263, 1263, 1119, 1265, 1147, + /* 260 */ 1250, 1232, 1232, 1147, 1119, 1265, 1186, 1297, 1119, 1119, + /* 270 */ 1265, 1372, 1119, 1265, 1119, 1265, 1372, 1294, 1294, 1294, + /* 280 */ 1342, 1372, 1294, 1301, 1294, 1342, 1294, 1294, 1286, 1306, + /* 290 */ 1286, 1306, 1286, 1306, 1286, 1306, 1119, 1398, 1119, 1285, + /* 300 */ 1372, 1334, 1334, 1372, 1304, 1308, 1307, 1309, 1147, 1412, + /* 310 */ 1413, 1428, 1428, 1439, 1439, 1439, 1566, 1566, 1566, 1566, + /* 320 */ 1566, 1566, 1566, 1566, 204, 321, 429, 467, 578, 497, + /* 330 */ 904, 739, 1051, 793, 794, 798, 800, 802, 838, 768, + /* 340 */ 766, 801, 762, 847, 853, 812, 891, 681, 784, 896, + /* 350 */ 864, 996, 1457, 1459, 1441, 1322, 1450, 1385, 1451, 1445, + /* 360 */ 1446, 1350, 1340, 1361, 1352, 1453, 1353, 1461, 1478, 1357, + /* 370 */ 1351, 1430, 1431, 1432, 1433, 1370, 1391, 1454, 1367, 1489, + /* 380 */ 1486, 1470, 1386, 1355, 1429, 1471, 1434, 1424, 1458, 1393, + /* 390 */ 1479, 1482, 1485, 1394, 1400, 1487, 1442, 1488, 1490, 1484, + /* 400 */ 1491, 1448, 1483, 1493, 1452, 1480, 1496, 1497, 1498, 1499, + /* 410 */ 1406, 1494, 1500, 1502, 1501, 1404, 1505, 1506, 1435, 1503, + /* 420 */ 1508, 1408, 1507, 1504, 1509, 1510, 1511, 1507, 1513, 1516, + /* 430 */ 1517, 1515, 1519, 1521, 1534, 1523, 1525, 1524, 1526, 1527, + /* 440 */ 1529, 1530, 1526, 1532, 1531, 1533, 1535, 1537, 1427, 1438, + /* 450 */ 1440, 1443, 1538, 1542, 1562, }; -#define YY_REDUCE_USE_DFLT (-174) -#define YY_REDUCE_COUNT (324) -#define YY_REDUCE_MIN (-173) -#define YY_REDUCE_MAX (1293) +#define YY_REDUCE_USE_DFLT (-144) +#define YY_REDUCE_COUNT (323) +#define YY_REDUCE_MIN (-143) +#define YY_REDUCE_MAX (1305) static const short yy_reduce_ofst[] = { - /* 0 */ -119, 1014, 131, 1031, -12, 225, 228, 300, -40, -45, - /* 10 */ 243, 256, 293, 129, 218, 418, 79, 376, 433, 298, - /* 20 */ 16, 137, 367, 323, -38, 391, -173, -173, -173, -173, - /* 30 */ -173, -173, -173, -173, -173, -173, -173, -173, -173, -173, - /* 40 */ -173, -173, -173, -173, -173, -173, -173, -173, -173, -173, - /* 50 */ -173, -173, -173, -173, -173, -173, -173, -173, 374, 437, - /* 60 */ 443, 508, 513, 522, 532, 582, 584, 620, 633, 635, - /* 70 */ 637, 644, 646, 648, 650, 652, 659, 661, 696, 709, - /* 80 */ 711, 714, 720, 722, 724, 726, 728, 733, 772, 784, - /* 90 */ 786, 822, 834, 836, 884, 886, 922, 934, 936, 986, - /* 100 */ 989, 1008, 1016, 1018, -173, -173, -173, -173, -173, -173, - /* 110 */ -173, -173, -173, 544, -37, 274, 299, 501, 161, -173, - /* 120 */ 193, -173, -173, -173, -173, 22, 22, 22, 64, 141, - /* 130 */ 212, 342, 208, 504, 504, 132, 494, 606, 677, 678, - /* 140 */ 750, 794, 796, -58, 32, 383, 660, 737, 386, 787, - /* 150 */ 800, 441, 872, 224, 850, 803, 949, 624, 830, 669, - /* 160 */ 961, 979, 983, 1011, 1013, 1032, 753, 789, 321, 94, - /* 170 */ 116, 304, 375, 210, 388, 392, 478, 545, 649, 721, - /* 180 */ 727, 736, 752, 795, 853, 952, 958, 1004, 1040, 1046, - /* 190 */ 1049, 1050, 1056, 1059, 1067, 559, 774, 811, 1068, 1080, - /* 200 */ 938, 1082, 1083, 1088, 962, 1089, 1090, 1052, 1093, 1094, - /* 210 */ 1095, 388, 1096, 1103, 1104, 1105, 1106, 1107, 965, 998, - /* 220 */ 1055, 1057, 1058, 938, 1069, 1071, 1120, 1073, 1061, 1062, - /* 230 */ 1033, 1076, 1039, 1108, 1087, 1099, 1111, 1066, 1054, 1112, - /* 240 */ 1113, 1091, 1084, 1135, 1060, 1133, 1138, 1064, 1081, 1139, - /* 250 */ 1100, 1119, 1109, 1124, 1127, 1140, 1142, 1168, 1173, 1132, - /* 260 */ 1115, 1147, 1148, 1137, 1180, 1182, 1110, 1121, 1188, 1189, - /* 270 */ 1197, 1181, 1200, 1202, 1205, 1203, 1191, 1192, 1199, 1206, - /* 280 */ 1207, 1209, 1210, 1211, 1214, 1212, 1218, 1219, 1175, 1183, - /* 290 */ 1185, 1184, 1186, 1190, 1187, 1196, 1237, 1193, 1253, 1194, - /* 300 */ 1236, 1195, 1198, 1238, 1213, 1221, 1220, 1227, 1229, 1271, - /* 310 */ 1275, 1284, 1285, 1289, 1290, 1292, 1293, 1201, 1208, 1216, - /* 320 */ 1280, 1281, 1264, 1269, 1283, + /* 0 */ -143, -65, 140, 840, 76, 180, 182, 233, 488, -25, + /* 10 */ 12, 16, 59, 885, 907, 935, 390, 705, 954, 285, + /* 20 */ 997, 1017, 1018, -118, 1025, 139, 171, 171, 171, 171, + /* 30 */ 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, + /* 40 */ 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, + /* 50 */ 171, 171, 171, 171, 171, 171, 171, 171, -69, 287, + /* 60 */ 441, 658, 708, 856, 1050, 1073, 1076, 1079, 1081, 1084, + /* 70 */ 1086, 1088, 1091, 1113, 1115, 1117, 1122, 1124, 1126, 1128, + /* 80 */ 1130, 1141, 1153, 1156, 1159, 1163, 1165, 1167, 1170, 1172, + /* 90 */ 1175, 1178, 1181, 1189, 1194, 1197, 1200, 1203, 1205, 1207, + /* 100 */ 1211, 1213, 1216, 1219, 171, 171, 171, 171, 171, 171, + /* 110 */ 171, 171, 171, 49, 176, 220, 275, 278, 290, 171, + /* 120 */ 300, 171, 171, 171, 171, -85, -85, -85, -28, 77, + /* 130 */ 313, 317, -56, 252, 252, 446, -129, 243, 361, 403, + /* 140 */ 406, 513, 517, 409, 502, 518, 504, 509, 621, 553, + /* 150 */ 562, 619, 559, 93, 620, 465, 453, 550, 591, 571, + /* 160 */ 615, 666, 750, 752, 797, 819, 463, 548, -73, 28, + /* 170 */ 68, 120, 257, 206, 359, 405, 413, 452, 457, 560, + /* 180 */ 566, 617, 670, 720, 723, 769, 773, 775, 780, 813, + /* 190 */ 814, 821, 822, 823, 826, 360, 436, 783, 829, 835, + /* 200 */ 707, 862, 867, 878, 830, 911, 915, 883, 936, 937, + /* 210 */ 940, 359, 942, 943, 944, 979, 982, 984, 886, 899, + /* 220 */ 928, 929, 931, 707, 947, 945, 998, 949, 932, 969, + /* 230 */ 918, 953, 924, 992, 1005, 1010, 1016, 971, 965, 1019, + /* 240 */ 1049, 1000, 1028, 1074, 989, 1078, 1080, 1026, 1031, 1109, + /* 250 */ 1053, 1090, 1103, 1092, 1099, 1114, 1118, 1148, 1151, 1111, + /* 260 */ 1096, 1129, 1131, 1133, 1162, 1202, 1138, 1146, 1231, 1234, + /* 270 */ 1206, 1218, 1237, 1239, 1240, 1242, 1221, 1228, 1229, 1230, + /* 280 */ 1224, 1233, 1235, 1236, 1241, 1226, 1243, 1244, 1198, 1201, + /* 290 */ 1209, 1212, 1210, 1214, 1215, 1217, 1260, 1199, 1262, 1220, + /* 300 */ 1247, 1222, 1223, 1253, 1238, 1245, 1251, 1246, 1249, 1276, + /* 310 */ 1279, 1289, 1291, 1296, 1302, 1305, 1225, 1227, 1248, 1290, + /* 320 */ 1292, 1280, 1281, 1295, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1280, 1270, 1270, 1270, 1202, 1202, 1202, 1202, 1270, 1096, - /* 10 */ 1125, 1125, 1254, 1332, 1332, 1332, 1332, 1332, 1332, 1201, - /* 20 */ 1332, 1332, 1332, 1332, 1270, 1100, 1131, 1332, 1332, 1332, - /* 30 */ 1332, 1203, 1204, 1332, 1332, 1332, 1253, 1255, 1141, 1140, - /* 40 */ 1139, 1138, 1236, 1112, 1136, 1129, 1133, 1203, 1197, 1198, - /* 50 */ 1196, 1200, 1204, 1332, 1132, 1167, 1181, 1166, 1332, 1332, - /* 60 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 70 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 80 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 90 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 100 */ 1332, 1332, 1332, 1332, 1175, 1180, 1187, 1179, 1176, 1169, - /* 110 */ 1168, 1170, 1171, 1332, 1019, 1067, 1332, 1332, 1332, 1172, - /* 120 */ 1332, 1173, 1184, 1183, 1182, 1261, 1288, 1287, 1332, 1332, - /* 130 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 140 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 150 */ 1332, 1332, 1332, 1332, 1332, 1280, 1270, 1025, 1025, 1332, - /* 160 */ 1270, 1270, 1270, 1270, 1270, 1270, 1266, 1100, 1091, 1332, - /* 170 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 180 */ 1258, 1256, 1332, 1217, 1332, 1332, 1332, 1332, 1332, 1332, - /* 190 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 200 */ 1332, 1332, 1332, 1332, 1096, 1332, 1332, 1332, 1332, 1332, - /* 210 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1282, 1332, 1231, - /* 220 */ 1096, 1096, 1096, 1098, 1080, 1090, 1004, 1135, 1114, 1114, - /* 230 */ 1321, 1135, 1321, 1042, 1302, 1039, 1125, 1114, 1199, 1125, - /* 240 */ 1125, 1097, 1090, 1332, 1324, 1105, 1105, 1323, 1323, 1105, - /* 250 */ 1146, 1070, 1135, 1076, 1076, 1076, 1076, 1105, 1016, 1135, - /* 260 */ 1146, 1070, 1070, 1135, 1105, 1016, 1235, 1318, 1105, 1105, - /* 270 */ 1016, 1210, 1105, 1016, 1105, 1016, 1210, 1068, 1068, 1068, - /* 280 */ 1057, 1210, 1068, 1042, 1068, 1057, 1068, 1068, 1118, 1113, - /* 290 */ 1118, 1113, 1118, 1113, 1118, 1113, 1105, 1205, 1105, 1332, - /* 300 */ 1210, 1214, 1214, 1210, 1130, 1119, 1128, 1126, 1135, 1022, - /* 310 */ 1060, 1285, 1285, 1281, 1281, 1281, 1281, 1329, 1329, 1266, - /* 320 */ 1297, 1297, 1044, 1044, 1297, 1332, 1332, 1332, 1332, 1332, - /* 330 */ 1332, 1292, 1332, 1219, 1332, 1332, 1332, 1332, 1332, 1332, - /* 340 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 350 */ 1332, 1332, 1152, 1332, 1000, 1263, 1332, 1332, 1262, 1332, - /* 360 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 370 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1320, - /* 380 */ 1332, 1332, 1332, 1332, 1332, 1332, 1234, 1233, 1332, 1332, - /* 390 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 400 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 410 */ 1332, 1082, 1332, 1332, 1332, 1306, 1332, 1332, 1332, 1332, - /* 420 */ 1332, 1332, 1332, 1127, 1332, 1120, 1332, 1332, 1311, 1332, - /* 430 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1272, - /* 440 */ 1332, 1332, 1332, 1271, 1332, 1332, 1332, 1332, 1332, 1154, - /* 450 */ 1332, 1153, 1157, 1332, 1010, 1332, + /* 0 */ 1270, 1260, 1260, 1260, 1193, 1193, 1193, 1193, 1260, 1088, + /* 10 */ 1117, 1117, 1244, 1322, 1322, 1322, 1322, 1322, 1322, 1192, + /* 20 */ 1322, 1322, 1322, 1322, 1260, 1092, 1123, 1322, 1322, 1322, + /* 30 */ 1322, 1194, 1195, 1322, 1322, 1322, 1243, 1245, 1133, 1132, + /* 40 */ 1131, 1130, 1226, 1104, 1128, 1121, 1125, 1194, 1188, 1189, + /* 50 */ 1187, 1191, 1195, 1322, 1124, 1158, 1172, 1157, 1322, 1322, + /* 60 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 70 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 80 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 90 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 100 */ 1322, 1322, 1322, 1322, 1166, 1171, 1178, 1170, 1167, 1160, + /* 110 */ 1159, 1161, 1162, 1322, 1011, 1059, 1322, 1322, 1322, 1163, + /* 120 */ 1322, 1164, 1175, 1174, 1173, 1251, 1278, 1277, 1322, 1322, + /* 130 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 140 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 150 */ 1322, 1322, 1322, 1322, 1322, 1270, 1260, 1017, 1017, 1322, + /* 160 */ 1260, 1260, 1260, 1260, 1260, 1260, 1256, 1092, 1083, 1322, + /* 170 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 180 */ 1248, 1246, 1322, 1208, 1322, 1322, 1322, 1322, 1322, 1322, + /* 190 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 200 */ 1322, 1322, 1322, 1322, 1088, 1322, 1322, 1322, 1322, 1322, + /* 210 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1272, 1322, 1221, + /* 220 */ 1088, 1088, 1088, 1090, 1072, 1082, 997, 1127, 1106, 1106, + /* 230 */ 1311, 1127, 1311, 1034, 1292, 1031, 1117, 1106, 1190, 1117, + /* 240 */ 1117, 1089, 1082, 1322, 1314, 1097, 1097, 1313, 1313, 1097, + /* 250 */ 1138, 1062, 1127, 1068, 1068, 1068, 1068, 1097, 1008, 1127, + /* 260 */ 1138, 1062, 1062, 1127, 1097, 1008, 1225, 1308, 1097, 1097, + /* 270 */ 1008, 1201, 1097, 1008, 1097, 1008, 1201, 1060, 1060, 1060, + /* 280 */ 1049, 1201, 1060, 1034, 1060, 1049, 1060, 1060, 1110, 1105, + /* 290 */ 1110, 1105, 1110, 1105, 1110, 1105, 1097, 1196, 1097, 1322, + /* 300 */ 1201, 1205, 1205, 1201, 1122, 1111, 1120, 1118, 1127, 1014, + /* 310 */ 1052, 1275, 1275, 1271, 1271, 1271, 1319, 1319, 1256, 1287, + /* 320 */ 1287, 1036, 1036, 1287, 1322, 1322, 1322, 1322, 1322, 1322, + /* 330 */ 1282, 1322, 1210, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 340 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 350 */ 1322, 1143, 1322, 993, 1253, 1322, 1322, 1252, 1322, 1322, + /* 360 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 370 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1310, 1322, + /* 380 */ 1322, 1322, 1322, 1322, 1322, 1224, 1223, 1322, 1322, 1322, + /* 390 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 400 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 410 */ 1074, 1322, 1322, 1322, 1296, 1322, 1322, 1322, 1322, 1322, + /* 420 */ 1322, 1322, 1119, 1322, 1112, 1322, 1322, 1301, 1322, 1322, + /* 430 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1262, 1322, + /* 440 */ 1322, 1322, 1261, 1322, 1322, 1322, 1322, 1322, 1145, 1322, + /* 450 */ 1144, 1148, 1322, 1002, 1322, }; /********** End of lemon-generated parsing tables *****************************/ @@ -136294,73 +137785,87 @@ static const YYACTIONTYPE yy_default[] = { static const YYCODETYPE yyFallback[] = { 0, /* $ => nothing */ 0, /* SEMI => nothing */ - 27, /* EXPLAIN => ID */ - 27, /* QUERY => ID */ - 27, /* PLAN => ID */ - 27, /* BEGIN => ID */ + 59, /* EXPLAIN => ID */ + 59, /* QUERY => ID */ + 59, /* PLAN => ID */ + 59, /* BEGIN => ID */ 0, /* TRANSACTION => nothing */ - 27, /* DEFERRED => ID */ - 27, /* IMMEDIATE => ID */ - 27, /* EXCLUSIVE => ID */ + 59, /* DEFERRED => ID */ + 59, /* IMMEDIATE => ID */ + 59, /* EXCLUSIVE => ID */ 0, /* COMMIT => nothing */ - 27, /* END => ID */ - 27, /* ROLLBACK => ID */ - 27, /* SAVEPOINT => ID */ - 27, /* RELEASE => ID */ + 59, /* END => ID */ + 59, /* ROLLBACK => ID */ + 59, /* SAVEPOINT => ID */ + 59, /* RELEASE => ID */ 0, /* TO => nothing */ 0, /* TABLE => nothing */ 0, /* CREATE => nothing */ - 27, /* IF => ID */ + 59, /* IF => ID */ 0, /* NOT => nothing */ 0, /* EXISTS => nothing */ - 27, /* TEMP => ID */ + 59, /* TEMP => ID */ 0, /* LP => nothing */ 0, /* RP => nothing */ 0, /* AS => nothing */ - 27, /* WITHOUT => ID */ + 59, /* WITHOUT => ID */ 0, /* COMMA => nothing */ + 59, /* ABORT => ID */ + 59, /* ACTION => ID */ + 59, /* AFTER => ID */ + 59, /* ANALYZE => ID */ + 59, /* ASC => ID */ + 59, /* ATTACH => ID */ + 59, /* BEFORE => ID */ + 59, /* BY => ID */ + 59, /* CASCADE => ID */ + 59, /* CAST => ID */ + 59, /* CONFLICT => ID */ + 59, /* DATABASE => ID */ + 59, /* DESC => ID */ + 59, /* DETACH => ID */ + 59, /* EACH => ID */ + 59, /* FAIL => ID */ + 0, /* OR => nothing */ + 0, /* AND => nothing */ + 0, /* IS => nothing */ + 59, /* MATCH => ID */ + 59, /* LIKE_KW => ID */ + 0, /* BETWEEN => nothing */ + 0, /* IN => nothing */ + 0, /* ISNULL => nothing */ + 0, /* NOTNULL => nothing */ + 0, /* NE => nothing */ + 0, /* EQ => nothing */ + 0, /* GT => nothing */ + 0, /* LE => nothing */ + 0, /* LT => nothing */ + 0, /* GE => nothing */ + 0, /* ESCAPE => nothing */ 0, /* ID => nothing */ - 27, /* ABORT => ID */ - 27, /* ACTION => ID */ - 27, /* AFTER => ID */ - 27, /* ANALYZE => ID */ - 27, /* ASC => ID */ - 27, /* ATTACH => ID */ - 27, /* BEFORE => ID */ - 27, /* BY => ID */ - 27, /* CASCADE => ID */ - 27, /* CAST => ID */ - 27, /* COLUMNKW => ID */ - 27, /* CONFLICT => ID */ - 27, /* DATABASE => ID */ - 27, /* DESC => ID */ - 27, /* DETACH => ID */ - 27, /* EACH => ID */ - 27, /* FAIL => ID */ - 27, /* FOR => ID */ - 27, /* IGNORE => ID */ - 27, /* INITIALLY => ID */ - 27, /* INSTEAD => ID */ - 27, /* LIKE_KW => ID */ - 27, /* MATCH => ID */ - 27, /* NO => ID */ - 27, /* KEY => ID */ - 27, /* OF => ID */ - 27, /* OFFSET => ID */ - 27, /* PRAGMA => ID */ - 27, /* RAISE => ID */ - 27, /* RECURSIVE => ID */ - 27, /* REPLACE => ID */ - 27, /* RESTRICT => ID */ - 27, /* ROW => ID */ - 27, /* TRIGGER => ID */ - 27, /* VACUUM => ID */ - 27, /* VIEW => ID */ - 27, /* VIRTUAL => ID */ - 27, /* WITH => ID */ - 27, /* REINDEX => ID */ - 27, /* RENAME => ID */ - 27, /* CTIME_KW => ID */ + 59, /* COLUMNKW => ID */ + 59, /* FOR => ID */ + 59, /* IGNORE => ID */ + 59, /* INITIALLY => ID */ + 59, /* INSTEAD => ID */ + 59, /* NO => ID */ + 59, /* KEY => ID */ + 59, /* OF => ID */ + 59, /* OFFSET => ID */ + 59, /* PRAGMA => ID */ + 59, /* RAISE => ID */ + 59, /* RECURSIVE => ID */ + 59, /* REPLACE => ID */ + 59, /* RESTRICT => ID */ + 59, /* ROW => ID */ + 59, /* TRIGGER => ID */ + 59, /* VACUUM => ID */ + 59, /* VIEW => ID */ + 59, /* VIRTUAL => ID */ + 59, /* WITH => ID */ + 59, /* REINDEX => ID */ + 59, /* RENAME => ID */ + 59, /* CTIME_KW => ID */ }; #endif /* YYFALLBACK */ @@ -136406,6 +137911,7 @@ struct yyParser { yyStackEntry yystk0; /* First stack entry */ #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ + yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; @@ -136452,21 +137958,21 @@ static const char *const yyTokenName[] = { "ROLLBACK", "SAVEPOINT", "RELEASE", "TO", "TABLE", "CREATE", "IF", "NOT", "EXISTS", "TEMP", "LP", "RP", - "AS", "WITHOUT", "COMMA", "ID", - "ABORT", "ACTION", "AFTER", "ANALYZE", - "ASC", "ATTACH", "BEFORE", "BY", - "CASCADE", "CAST", "COLUMNKW", "CONFLICT", - "DATABASE", "DESC", "DETACH", "EACH", - "FAIL", "FOR", "IGNORE", "INITIALLY", - "INSTEAD", "LIKE_KW", "MATCH", "NO", - "KEY", "OF", "OFFSET", "PRAGMA", - "RAISE", "RECURSIVE", "REPLACE", "RESTRICT", - "ROW", "TRIGGER", "VACUUM", "VIEW", - "VIRTUAL", "WITH", "REINDEX", "RENAME", - "CTIME_KW", "ANY", "OR", "AND", - "IS", "BETWEEN", "IN", "ISNULL", - "NOTNULL", "NE", "EQ", "GT", - "LE", "LT", "GE", "ESCAPE", + "AS", "WITHOUT", "COMMA", "ABORT", + "ACTION", "AFTER", "ANALYZE", "ASC", + "ATTACH", "BEFORE", "BY", "CASCADE", + "CAST", "CONFLICT", "DATABASE", "DESC", + "DETACH", "EACH", "FAIL", "OR", + "AND", "IS", "MATCH", "LIKE_KW", + "BETWEEN", "IN", "ISNULL", "NOTNULL", + "NE", "EQ", "GT", "LE", + "LT", "GE", "ESCAPE", "ID", + "COLUMNKW", "FOR", "IGNORE", "INITIALLY", + "INSTEAD", "NO", "KEY", "OF", + "OFFSET", "PRAGMA", "RAISE", "RECURSIVE", + "REPLACE", "RESTRICT", "ROW", "TRIGGER", + "VACUUM", "VIEW", "VIRTUAL", "WITH", + "REINDEX", "RENAME", "CTIME_KW", "ANY", "BITAND", "BITOR", "LSHIFT", "RSHIFT", "PLUS", "MINUS", "STAR", "SLASH", "REM", "CONCAT", "COLLATE", "BITNOT", @@ -136524,330 +138030,327 @@ static const char *const yyRuleName[] = { /* 5 */ "transtype ::= DEFERRED", /* 6 */ "transtype ::= IMMEDIATE", /* 7 */ "transtype ::= EXCLUSIVE", - /* 8 */ "cmd ::= COMMIT trans_opt", - /* 9 */ "cmd ::= END trans_opt", - /* 10 */ "cmd ::= ROLLBACK trans_opt", - /* 11 */ "cmd ::= SAVEPOINT nm", - /* 12 */ "cmd ::= RELEASE savepoint_opt nm", - /* 13 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", - /* 14 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", - /* 15 */ "createkw ::= CREATE", - /* 16 */ "ifnotexists ::=", - /* 17 */ "ifnotexists ::= IF NOT EXISTS", - /* 18 */ "temp ::= TEMP", - /* 19 */ "temp ::=", - /* 20 */ "create_table_args ::= LP columnlist conslist_opt RP table_options", - /* 21 */ "create_table_args ::= AS select", - /* 22 */ "table_options ::=", - /* 23 */ "table_options ::= WITHOUT nm", - /* 24 */ "columnname ::= nm typetoken", - /* 25 */ "typetoken ::=", - /* 26 */ "typetoken ::= typename LP signed RP", - /* 27 */ "typetoken ::= typename LP signed COMMA signed RP", - /* 28 */ "typename ::= typename ID|STRING", - /* 29 */ "ccons ::= CONSTRAINT nm", - /* 30 */ "ccons ::= DEFAULT term", - /* 31 */ "ccons ::= DEFAULT LP expr RP", - /* 32 */ "ccons ::= DEFAULT PLUS term", - /* 33 */ "ccons ::= DEFAULT MINUS term", - /* 34 */ "ccons ::= DEFAULT ID|INDEXED", - /* 35 */ "ccons ::= NOT NULL onconf", - /* 36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", - /* 37 */ "ccons ::= UNIQUE onconf", - /* 38 */ "ccons ::= CHECK LP expr RP", - /* 39 */ "ccons ::= REFERENCES nm eidlist_opt refargs", - /* 40 */ "ccons ::= defer_subclause", - /* 41 */ "ccons ::= COLLATE ID|STRING", - /* 42 */ "autoinc ::=", - /* 43 */ "autoinc ::= AUTOINCR", - /* 44 */ "refargs ::=", - /* 45 */ "refargs ::= refargs refarg", - /* 46 */ "refarg ::= MATCH nm", - /* 47 */ "refarg ::= ON INSERT refact", - /* 48 */ "refarg ::= ON DELETE refact", - /* 49 */ "refarg ::= ON UPDATE refact", - /* 50 */ "refact ::= SET NULL", - /* 51 */ "refact ::= SET DEFAULT", - /* 52 */ "refact ::= CASCADE", - /* 53 */ "refact ::= RESTRICT", - /* 54 */ "refact ::= NO ACTION", - /* 55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", - /* 56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", - /* 57 */ "init_deferred_pred_opt ::=", - /* 58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", - /* 59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", - /* 60 */ "conslist_opt ::=", - /* 61 */ "tconscomma ::= COMMA", - /* 62 */ "tcons ::= CONSTRAINT nm", - /* 63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", - /* 64 */ "tcons ::= UNIQUE LP sortlist RP onconf", - /* 65 */ "tcons ::= CHECK LP expr RP onconf", - /* 66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", - /* 67 */ "defer_subclause_opt ::=", - /* 68 */ "onconf ::=", - /* 69 */ "onconf ::= ON CONFLICT resolvetype", - /* 70 */ "orconf ::=", - /* 71 */ "orconf ::= OR resolvetype", - /* 72 */ "resolvetype ::= IGNORE", - /* 73 */ "resolvetype ::= REPLACE", - /* 74 */ "cmd ::= DROP TABLE ifexists fullname", - /* 75 */ "ifexists ::= IF EXISTS", - /* 76 */ "ifexists ::=", - /* 77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", - /* 78 */ "cmd ::= DROP VIEW ifexists fullname", - /* 79 */ "cmd ::= select", - /* 80 */ "select ::= with selectnowith", - /* 81 */ "selectnowith ::= selectnowith multiselect_op oneselect", - /* 82 */ "multiselect_op ::= UNION", - /* 83 */ "multiselect_op ::= UNION ALL", - /* 84 */ "multiselect_op ::= EXCEPT|INTERSECT", - /* 85 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 86 */ "values ::= VALUES LP nexprlist RP", - /* 87 */ "values ::= values COMMA LP exprlist RP", - /* 88 */ "distinct ::= DISTINCT", - /* 89 */ "distinct ::= ALL", - /* 90 */ "distinct ::=", - /* 91 */ "sclp ::=", - /* 92 */ "selcollist ::= sclp expr as", - /* 93 */ "selcollist ::= sclp STAR", - /* 94 */ "selcollist ::= sclp nm DOT STAR", - /* 95 */ "as ::= AS nm", - /* 96 */ "as ::=", - /* 97 */ "from ::=", - /* 98 */ "from ::= FROM seltablist", - /* 99 */ "stl_prefix ::= seltablist joinop", - /* 100 */ "stl_prefix ::=", - /* 101 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", - /* 102 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", - /* 103 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", - /* 104 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", - /* 105 */ "dbnm ::=", - /* 106 */ "dbnm ::= DOT nm", - /* 107 */ "fullname ::= nm dbnm", - /* 108 */ "joinop ::= COMMA|JOIN", - /* 109 */ "joinop ::= JOIN_KW JOIN", - /* 110 */ "joinop ::= JOIN_KW nm JOIN", - /* 111 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 112 */ "on_opt ::= ON expr", - /* 113 */ "on_opt ::=", - /* 114 */ "indexed_opt ::=", - /* 115 */ "indexed_opt ::= INDEXED BY nm", - /* 116 */ "indexed_opt ::= NOT INDEXED", - /* 117 */ "using_opt ::= USING LP idlist RP", - /* 118 */ "using_opt ::=", - /* 119 */ "orderby_opt ::=", - /* 120 */ "orderby_opt ::= ORDER BY sortlist", - /* 121 */ "sortlist ::= sortlist COMMA expr sortorder", - /* 122 */ "sortlist ::= expr sortorder", - /* 123 */ "sortorder ::= ASC", - /* 124 */ "sortorder ::= DESC", - /* 125 */ "sortorder ::=", - /* 126 */ "groupby_opt ::=", - /* 127 */ "groupby_opt ::= GROUP BY nexprlist", - /* 128 */ "having_opt ::=", - /* 129 */ "having_opt ::= HAVING expr", - /* 130 */ "limit_opt ::=", - /* 131 */ "limit_opt ::= LIMIT expr", - /* 132 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 133 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 134 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt", - /* 135 */ "where_opt ::=", - /* 136 */ "where_opt ::= WHERE expr", - /* 137 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", - /* 138 */ "setlist ::= setlist COMMA nm EQ expr", - /* 139 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", - /* 140 */ "setlist ::= nm EQ expr", - /* 141 */ "setlist ::= LP idlist RP EQ expr", - /* 142 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select", - /* 143 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES", - /* 144 */ "insert_cmd ::= INSERT orconf", - /* 145 */ "insert_cmd ::= REPLACE", - /* 146 */ "idlist_opt ::=", - /* 147 */ "idlist_opt ::= LP idlist RP", - /* 148 */ "idlist ::= idlist COMMA nm", - /* 149 */ "idlist ::= nm", - /* 150 */ "expr ::= LP expr RP", - /* 151 */ "term ::= NULL", - /* 152 */ "expr ::= ID|INDEXED", - /* 153 */ "expr ::= JOIN_KW", - /* 154 */ "expr ::= nm DOT nm", - /* 155 */ "expr ::= nm DOT nm DOT nm", - /* 156 */ "term ::= FLOAT|BLOB", - /* 157 */ "term ::= STRING", - /* 158 */ "term ::= INTEGER", - /* 159 */ "expr ::= VARIABLE", - /* 160 */ "expr ::= expr COLLATE ID|STRING", - /* 161 */ "expr ::= CAST LP expr AS typetoken RP", - /* 162 */ "expr ::= ID|INDEXED LP distinct exprlist RP", - /* 163 */ "expr ::= ID|INDEXED LP STAR RP", - /* 164 */ "term ::= CTIME_KW", - /* 165 */ "expr ::= LP nexprlist COMMA expr RP", - /* 166 */ "expr ::= expr AND expr", - /* 167 */ "expr ::= expr OR expr", - /* 168 */ "expr ::= expr LT|GT|GE|LE expr", - /* 169 */ "expr ::= expr EQ|NE expr", - /* 170 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 171 */ "expr ::= expr PLUS|MINUS expr", - /* 172 */ "expr ::= expr STAR|SLASH|REM expr", - /* 173 */ "expr ::= expr CONCAT expr", - /* 174 */ "likeop ::= NOT LIKE_KW|MATCH", - /* 175 */ "expr ::= expr likeop expr", - /* 176 */ "expr ::= expr likeop expr ESCAPE expr", - /* 177 */ "expr ::= expr ISNULL|NOTNULL", - /* 178 */ "expr ::= expr NOT NULL", - /* 179 */ "expr ::= expr IS expr", - /* 180 */ "expr ::= expr IS NOT expr", - /* 181 */ "expr ::= NOT expr", - /* 182 */ "expr ::= BITNOT expr", - /* 183 */ "expr ::= MINUS expr", - /* 184 */ "expr ::= PLUS expr", - /* 185 */ "between_op ::= BETWEEN", - /* 186 */ "between_op ::= NOT BETWEEN", - /* 187 */ "expr ::= expr between_op expr AND expr", - /* 188 */ "in_op ::= IN", - /* 189 */ "in_op ::= NOT IN", - /* 190 */ "expr ::= expr in_op LP exprlist RP", - /* 191 */ "expr ::= LP select RP", - /* 192 */ "expr ::= expr in_op LP select RP", - /* 193 */ "expr ::= expr in_op nm dbnm paren_exprlist", - /* 194 */ "expr ::= EXISTS LP select RP", - /* 195 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 196 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 197 */ "case_exprlist ::= WHEN expr THEN expr", - /* 198 */ "case_else ::= ELSE expr", - /* 199 */ "case_else ::=", - /* 200 */ "case_operand ::= expr", - /* 201 */ "case_operand ::=", - /* 202 */ "exprlist ::=", - /* 203 */ "nexprlist ::= nexprlist COMMA expr", - /* 204 */ "nexprlist ::= expr", - /* 205 */ "paren_exprlist ::=", - /* 206 */ "paren_exprlist ::= LP exprlist RP", - /* 207 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 208 */ "uniqueflag ::= UNIQUE", - /* 209 */ "uniqueflag ::=", - /* 210 */ "eidlist_opt ::=", - /* 211 */ "eidlist_opt ::= LP eidlist RP", - /* 212 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 213 */ "eidlist ::= nm collate sortorder", - /* 214 */ "collate ::=", - /* 215 */ "collate ::= COLLATE ID|STRING", - /* 216 */ "cmd ::= DROP INDEX ifexists fullname", - /* 217 */ "cmd ::= VACUUM", - /* 218 */ "cmd ::= VACUUM nm", - /* 219 */ "cmd ::= PRAGMA nm dbnm", - /* 220 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 221 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 222 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 223 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 224 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 225 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 226 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 227 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 228 */ "trigger_time ::= BEFORE", - /* 229 */ "trigger_time ::= AFTER", - /* 230 */ "trigger_time ::= INSTEAD OF", - /* 231 */ "trigger_time ::=", - /* 232 */ "trigger_event ::= DELETE|INSERT", - /* 233 */ "trigger_event ::= UPDATE", - /* 234 */ "trigger_event ::= UPDATE OF idlist", - /* 235 */ "when_clause ::=", - /* 236 */ "when_clause ::= WHEN expr", - /* 237 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 238 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 239 */ "trnm ::= nm DOT nm", - /* 240 */ "tridxby ::= INDEXED BY nm", - /* 241 */ "tridxby ::= NOT INDEXED", - /* 242 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", - /* 243 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select", - /* 244 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", - /* 245 */ "trigger_cmd ::= select", - /* 246 */ "expr ::= RAISE LP IGNORE RP", - /* 247 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 248 */ "raisetype ::= ROLLBACK", - /* 249 */ "raisetype ::= ABORT", - /* 250 */ "raisetype ::= FAIL", - /* 251 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 252 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 253 */ "cmd ::= DETACH database_kw_opt expr", - /* 254 */ "key_opt ::=", - /* 255 */ "key_opt ::= KEY expr", - /* 256 */ "cmd ::= REINDEX", - /* 257 */ "cmd ::= REINDEX nm dbnm", - /* 258 */ "cmd ::= ANALYZE", - /* 259 */ "cmd ::= ANALYZE nm dbnm", - /* 260 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 261 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", - /* 262 */ "add_column_fullname ::= fullname", - /* 263 */ "cmd ::= create_vtab", - /* 264 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 265 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 266 */ "vtabarg ::=", - /* 267 */ "vtabargtoken ::= ANY", - /* 268 */ "vtabargtoken ::= lp anylist RP", - /* 269 */ "lp ::= LP", - /* 270 */ "with ::=", - /* 271 */ "with ::= WITH wqlist", - /* 272 */ "with ::= WITH RECURSIVE wqlist", - /* 273 */ "wqlist ::= nm eidlist_opt AS LP select RP", - /* 274 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", - /* 275 */ "input ::= cmdlist", - /* 276 */ "cmdlist ::= cmdlist ecmd", - /* 277 */ "cmdlist ::= ecmd", - /* 278 */ "ecmd ::= SEMI", - /* 279 */ "ecmd ::= explain cmdx SEMI", - /* 280 */ "explain ::=", - /* 281 */ "trans_opt ::=", - /* 282 */ "trans_opt ::= TRANSACTION", - /* 283 */ "trans_opt ::= TRANSACTION nm", - /* 284 */ "savepoint_opt ::= SAVEPOINT", - /* 285 */ "savepoint_opt ::=", - /* 286 */ "cmd ::= create_table create_table_args", - /* 287 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 288 */ "columnlist ::= columnname carglist", - /* 289 */ "nm ::= ID|INDEXED", - /* 290 */ "nm ::= STRING", - /* 291 */ "nm ::= JOIN_KW", - /* 292 */ "typetoken ::= typename", - /* 293 */ "typename ::= ID|STRING", - /* 294 */ "signed ::= plus_num", - /* 295 */ "signed ::= minus_num", - /* 296 */ "carglist ::= carglist ccons", - /* 297 */ "carglist ::=", - /* 298 */ "ccons ::= NULL onconf", - /* 299 */ "conslist_opt ::= COMMA conslist", - /* 300 */ "conslist ::= conslist tconscomma tcons", - /* 301 */ "conslist ::= tcons", - /* 302 */ "tconscomma ::=", - /* 303 */ "defer_subclause_opt ::= defer_subclause", - /* 304 */ "resolvetype ::= raisetype", - /* 305 */ "selectnowith ::= oneselect", - /* 306 */ "oneselect ::= values", - /* 307 */ "sclp ::= selcollist COMMA", - /* 308 */ "as ::= ID|STRING", - /* 309 */ "expr ::= term", - /* 310 */ "likeop ::= LIKE_KW|MATCH", - /* 311 */ "exprlist ::= nexprlist", - /* 312 */ "nmnum ::= plus_num", - /* 313 */ "nmnum ::= nm", - /* 314 */ "nmnum ::= ON", - /* 315 */ "nmnum ::= DELETE", - /* 316 */ "nmnum ::= DEFAULT", - /* 317 */ "plus_num ::= INTEGER|FLOAT", - /* 318 */ "foreach_clause ::=", - /* 319 */ "foreach_clause ::= FOR EACH ROW", - /* 320 */ "trnm ::= nm", - /* 321 */ "tridxby ::=", - /* 322 */ "database_kw_opt ::= DATABASE", - /* 323 */ "database_kw_opt ::=", - /* 324 */ "kwcolumn_opt ::=", - /* 325 */ "kwcolumn_opt ::= COLUMNKW", - /* 326 */ "vtabarglist ::= vtabarg", - /* 327 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 328 */ "vtabarg ::= vtabarg vtabargtoken", - /* 329 */ "anylist ::=", - /* 330 */ "anylist ::= anylist LP anylist RP", - /* 331 */ "anylist ::= anylist ANY", + /* 8 */ "cmd ::= COMMIT|END trans_opt", + /* 9 */ "cmd ::= ROLLBACK trans_opt", + /* 10 */ "cmd ::= SAVEPOINT nm", + /* 11 */ "cmd ::= RELEASE savepoint_opt nm", + /* 12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", + /* 13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", + /* 14 */ "createkw ::= CREATE", + /* 15 */ "ifnotexists ::=", + /* 16 */ "ifnotexists ::= IF NOT EXISTS", + /* 17 */ "temp ::= TEMP", + /* 18 */ "temp ::=", + /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP table_options", + /* 20 */ "create_table_args ::= AS select", + /* 21 */ "table_options ::=", + /* 22 */ "table_options ::= WITHOUT nm", + /* 23 */ "columnname ::= nm typetoken", + /* 24 */ "typetoken ::=", + /* 25 */ "typetoken ::= typename LP signed RP", + /* 26 */ "typetoken ::= typename LP signed COMMA signed RP", + /* 27 */ "typename ::= typename ID|STRING", + /* 28 */ "ccons ::= CONSTRAINT nm", + /* 29 */ "ccons ::= DEFAULT term", + /* 30 */ "ccons ::= DEFAULT LP expr RP", + /* 31 */ "ccons ::= DEFAULT PLUS term", + /* 32 */ "ccons ::= DEFAULT MINUS term", + /* 33 */ "ccons ::= DEFAULT ID|INDEXED", + /* 34 */ "ccons ::= NOT NULL onconf", + /* 35 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 36 */ "ccons ::= UNIQUE onconf", + /* 37 */ "ccons ::= CHECK LP expr RP", + /* 38 */ "ccons ::= REFERENCES nm eidlist_opt refargs", + /* 39 */ "ccons ::= defer_subclause", + /* 40 */ "ccons ::= COLLATE ID|STRING", + /* 41 */ "autoinc ::=", + /* 42 */ "autoinc ::= AUTOINCR", + /* 43 */ "refargs ::=", + /* 44 */ "refargs ::= refargs refarg", + /* 45 */ "refarg ::= MATCH nm", + /* 46 */ "refarg ::= ON INSERT refact", + /* 47 */ "refarg ::= ON DELETE refact", + /* 48 */ "refarg ::= ON UPDATE refact", + /* 49 */ "refact ::= SET NULL", + /* 50 */ "refact ::= SET DEFAULT", + /* 51 */ "refact ::= CASCADE", + /* 52 */ "refact ::= RESTRICT", + /* 53 */ "refact ::= NO ACTION", + /* 54 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 55 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 56 */ "init_deferred_pred_opt ::=", + /* 57 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 58 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 59 */ "conslist_opt ::=", + /* 60 */ "tconscomma ::= COMMA", + /* 61 */ "tcons ::= CONSTRAINT nm", + /* 62 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", + /* 63 */ "tcons ::= UNIQUE LP sortlist RP onconf", + /* 64 */ "tcons ::= CHECK LP expr RP onconf", + /* 65 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", + /* 66 */ "defer_subclause_opt ::=", + /* 67 */ "onconf ::=", + /* 68 */ "onconf ::= ON CONFLICT resolvetype", + /* 69 */ "orconf ::=", + /* 70 */ "orconf ::= OR resolvetype", + /* 71 */ "resolvetype ::= IGNORE", + /* 72 */ "resolvetype ::= REPLACE", + /* 73 */ "cmd ::= DROP TABLE ifexists fullname", + /* 74 */ "ifexists ::= IF EXISTS", + /* 75 */ "ifexists ::=", + /* 76 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", + /* 77 */ "cmd ::= DROP VIEW ifexists fullname", + /* 78 */ "cmd ::= select", + /* 79 */ "select ::= with selectnowith", + /* 80 */ "selectnowith ::= selectnowith multiselect_op oneselect", + /* 81 */ "multiselect_op ::= UNION", + /* 82 */ "multiselect_op ::= UNION ALL", + /* 83 */ "multiselect_op ::= EXCEPT|INTERSECT", + /* 84 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 85 */ "values ::= VALUES LP nexprlist RP", + /* 86 */ "values ::= values COMMA LP exprlist RP", + /* 87 */ "distinct ::= DISTINCT", + /* 88 */ "distinct ::= ALL", + /* 89 */ "distinct ::=", + /* 90 */ "sclp ::=", + /* 91 */ "selcollist ::= sclp expr as", + /* 92 */ "selcollist ::= sclp STAR", + /* 93 */ "selcollist ::= sclp nm DOT STAR", + /* 94 */ "as ::= AS nm", + /* 95 */ "as ::=", + /* 96 */ "from ::=", + /* 97 */ "from ::= FROM seltablist", + /* 98 */ "stl_prefix ::= seltablist joinop", + /* 99 */ "stl_prefix ::=", + /* 100 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", + /* 101 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", + /* 102 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", + /* 103 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", + /* 104 */ "dbnm ::=", + /* 105 */ "dbnm ::= DOT nm", + /* 106 */ "fullname ::= nm dbnm", + /* 107 */ "joinop ::= COMMA|JOIN", + /* 108 */ "joinop ::= JOIN_KW JOIN", + /* 109 */ "joinop ::= JOIN_KW nm JOIN", + /* 110 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 111 */ "on_opt ::= ON expr", + /* 112 */ "on_opt ::=", + /* 113 */ "indexed_opt ::=", + /* 114 */ "indexed_opt ::= INDEXED BY nm", + /* 115 */ "indexed_opt ::= NOT INDEXED", + /* 116 */ "using_opt ::= USING LP idlist RP", + /* 117 */ "using_opt ::=", + /* 118 */ "orderby_opt ::=", + /* 119 */ "orderby_opt ::= ORDER BY sortlist", + /* 120 */ "sortlist ::= sortlist COMMA expr sortorder", + /* 121 */ "sortlist ::= expr sortorder", + /* 122 */ "sortorder ::= ASC", + /* 123 */ "sortorder ::= DESC", + /* 124 */ "sortorder ::=", + /* 125 */ "groupby_opt ::=", + /* 126 */ "groupby_opt ::= GROUP BY nexprlist", + /* 127 */ "having_opt ::=", + /* 128 */ "having_opt ::= HAVING expr", + /* 129 */ "limit_opt ::=", + /* 130 */ "limit_opt ::= LIMIT expr", + /* 131 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 132 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 133 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt", + /* 134 */ "where_opt ::=", + /* 135 */ "where_opt ::= WHERE expr", + /* 136 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", + /* 137 */ "setlist ::= setlist COMMA nm EQ expr", + /* 138 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 139 */ "setlist ::= nm EQ expr", + /* 140 */ "setlist ::= LP idlist RP EQ expr", + /* 141 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select", + /* 142 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES", + /* 143 */ "insert_cmd ::= INSERT orconf", + /* 144 */ "insert_cmd ::= REPLACE", + /* 145 */ "idlist_opt ::=", + /* 146 */ "idlist_opt ::= LP idlist RP", + /* 147 */ "idlist ::= idlist COMMA nm", + /* 148 */ "idlist ::= nm", + /* 149 */ "expr ::= LP expr RP", + /* 150 */ "expr ::= ID|INDEXED", + /* 151 */ "expr ::= JOIN_KW", + /* 152 */ "expr ::= nm DOT nm", + /* 153 */ "expr ::= nm DOT nm DOT nm", + /* 154 */ "term ::= NULL|FLOAT|BLOB", + /* 155 */ "term ::= STRING", + /* 156 */ "term ::= INTEGER", + /* 157 */ "expr ::= VARIABLE", + /* 158 */ "expr ::= expr COLLATE ID|STRING", + /* 159 */ "expr ::= CAST LP expr AS typetoken RP", + /* 160 */ "expr ::= ID|INDEXED LP distinct exprlist RP", + /* 161 */ "expr ::= ID|INDEXED LP STAR RP", + /* 162 */ "term ::= CTIME_KW", + /* 163 */ "expr ::= LP nexprlist COMMA expr RP", + /* 164 */ "expr ::= expr AND expr", + /* 165 */ "expr ::= expr OR expr", + /* 166 */ "expr ::= expr LT|GT|GE|LE expr", + /* 167 */ "expr ::= expr EQ|NE expr", + /* 168 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 169 */ "expr ::= expr PLUS|MINUS expr", + /* 170 */ "expr ::= expr STAR|SLASH|REM expr", + /* 171 */ "expr ::= expr CONCAT expr", + /* 172 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 173 */ "expr ::= expr likeop expr", + /* 174 */ "expr ::= expr likeop expr ESCAPE expr", + /* 175 */ "expr ::= expr ISNULL|NOTNULL", + /* 176 */ "expr ::= expr NOT NULL", + /* 177 */ "expr ::= expr IS expr", + /* 178 */ "expr ::= expr IS NOT expr", + /* 179 */ "expr ::= NOT expr", + /* 180 */ "expr ::= BITNOT expr", + /* 181 */ "expr ::= MINUS expr", + /* 182 */ "expr ::= PLUS expr", + /* 183 */ "between_op ::= BETWEEN", + /* 184 */ "between_op ::= NOT BETWEEN", + /* 185 */ "expr ::= expr between_op expr AND expr", + /* 186 */ "in_op ::= IN", + /* 187 */ "in_op ::= NOT IN", + /* 188 */ "expr ::= expr in_op LP exprlist RP", + /* 189 */ "expr ::= LP select RP", + /* 190 */ "expr ::= expr in_op LP select RP", + /* 191 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 192 */ "expr ::= EXISTS LP select RP", + /* 193 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 194 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 195 */ "case_exprlist ::= WHEN expr THEN expr", + /* 196 */ "case_else ::= ELSE expr", + /* 197 */ "case_else ::=", + /* 198 */ "case_operand ::= expr", + /* 199 */ "case_operand ::=", + /* 200 */ "exprlist ::=", + /* 201 */ "nexprlist ::= nexprlist COMMA expr", + /* 202 */ "nexprlist ::= expr", + /* 203 */ "paren_exprlist ::=", + /* 204 */ "paren_exprlist ::= LP exprlist RP", + /* 205 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 206 */ "uniqueflag ::= UNIQUE", + /* 207 */ "uniqueflag ::=", + /* 208 */ "eidlist_opt ::=", + /* 209 */ "eidlist_opt ::= LP eidlist RP", + /* 210 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 211 */ "eidlist ::= nm collate sortorder", + /* 212 */ "collate ::=", + /* 213 */ "collate ::= COLLATE ID|STRING", + /* 214 */ "cmd ::= DROP INDEX ifexists fullname", + /* 215 */ "cmd ::= VACUUM", + /* 216 */ "cmd ::= VACUUM nm", + /* 217 */ "cmd ::= PRAGMA nm dbnm", + /* 218 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 219 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 220 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 221 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 222 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 223 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 224 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 225 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 226 */ "trigger_time ::= BEFORE|AFTER", + /* 227 */ "trigger_time ::= INSTEAD OF", + /* 228 */ "trigger_time ::=", + /* 229 */ "trigger_event ::= DELETE|INSERT", + /* 230 */ "trigger_event ::= UPDATE", + /* 231 */ "trigger_event ::= UPDATE OF idlist", + /* 232 */ "when_clause ::=", + /* 233 */ "when_clause ::= WHEN expr", + /* 234 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 235 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 236 */ "trnm ::= nm DOT nm", + /* 237 */ "tridxby ::= INDEXED BY nm", + /* 238 */ "tridxby ::= NOT INDEXED", + /* 239 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", + /* 240 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select", + /* 241 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", + /* 242 */ "trigger_cmd ::= select", + /* 243 */ "expr ::= RAISE LP IGNORE RP", + /* 244 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 245 */ "raisetype ::= ROLLBACK", + /* 246 */ "raisetype ::= ABORT", + /* 247 */ "raisetype ::= FAIL", + /* 248 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 249 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 250 */ "cmd ::= DETACH database_kw_opt expr", + /* 251 */ "key_opt ::=", + /* 252 */ "key_opt ::= KEY expr", + /* 253 */ "cmd ::= REINDEX", + /* 254 */ "cmd ::= REINDEX nm dbnm", + /* 255 */ "cmd ::= ANALYZE", + /* 256 */ "cmd ::= ANALYZE nm dbnm", + /* 257 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 258 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 259 */ "add_column_fullname ::= fullname", + /* 260 */ "cmd ::= create_vtab", + /* 261 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 262 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 263 */ "vtabarg ::=", + /* 264 */ "vtabargtoken ::= ANY", + /* 265 */ "vtabargtoken ::= lp anylist RP", + /* 266 */ "lp ::= LP", + /* 267 */ "with ::=", + /* 268 */ "with ::= WITH wqlist", + /* 269 */ "with ::= WITH RECURSIVE wqlist", + /* 270 */ "wqlist ::= nm eidlist_opt AS LP select RP", + /* 271 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", + /* 272 */ "input ::= cmdlist", + /* 273 */ "cmdlist ::= cmdlist ecmd", + /* 274 */ "cmdlist ::= ecmd", + /* 275 */ "ecmd ::= SEMI", + /* 276 */ "ecmd ::= explain cmdx SEMI", + /* 277 */ "explain ::=", + /* 278 */ "trans_opt ::=", + /* 279 */ "trans_opt ::= TRANSACTION", + /* 280 */ "trans_opt ::= TRANSACTION nm", + /* 281 */ "savepoint_opt ::= SAVEPOINT", + /* 282 */ "savepoint_opt ::=", + /* 283 */ "cmd ::= create_table create_table_args", + /* 284 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 285 */ "columnlist ::= columnname carglist", + /* 286 */ "nm ::= ID|INDEXED", + /* 287 */ "nm ::= STRING", + /* 288 */ "nm ::= JOIN_KW", + /* 289 */ "typetoken ::= typename", + /* 290 */ "typename ::= ID|STRING", + /* 291 */ "signed ::= plus_num", + /* 292 */ "signed ::= minus_num", + /* 293 */ "carglist ::= carglist ccons", + /* 294 */ "carglist ::=", + /* 295 */ "ccons ::= NULL onconf", + /* 296 */ "conslist_opt ::= COMMA conslist", + /* 297 */ "conslist ::= conslist tconscomma tcons", + /* 298 */ "conslist ::= tcons", + /* 299 */ "tconscomma ::=", + /* 300 */ "defer_subclause_opt ::= defer_subclause", + /* 301 */ "resolvetype ::= raisetype", + /* 302 */ "selectnowith ::= oneselect", + /* 303 */ "oneselect ::= values", + /* 304 */ "sclp ::= selcollist COMMA", + /* 305 */ "as ::= ID|STRING", + /* 306 */ "expr ::= term", + /* 307 */ "likeop ::= LIKE_KW|MATCH", + /* 308 */ "exprlist ::= nexprlist", + /* 309 */ "nmnum ::= plus_num", + /* 310 */ "nmnum ::= nm", + /* 311 */ "nmnum ::= ON", + /* 312 */ "nmnum ::= DELETE", + /* 313 */ "nmnum ::= DEFAULT", + /* 314 */ "plus_num ::= INTEGER|FLOAT", + /* 315 */ "foreach_clause ::=", + /* 316 */ "foreach_clause ::= FOR EACH ROW", + /* 317 */ "trnm ::= nm", + /* 318 */ "tridxby ::=", + /* 319 */ "database_kw_opt ::= DATABASE", + /* 320 */ "database_kw_opt ::=", + /* 321 */ "kwcolumn_opt ::=", + /* 322 */ "kwcolumn_opt ::= COLUMNKW", + /* 323 */ "vtabarglist ::= vtabarg", + /* 324 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 325 */ "vtabarg ::= vtabarg vtabargtoken", + /* 326 */ "anylist ::=", + /* 327 */ "anylist ::= anylist LP anylist RP", + /* 328 */ "anylist ::= anylist ANY", }; #endif /* NDEBUG */ @@ -136916,6 +138419,9 @@ SQLITE_PRIVATE void sqlite3ParserInit(void *yypParser){ pParser->yytos = pParser->yystack; pParser->yystack[0].stateno = 0; pParser->yystack[0].major = 0; +#if YYSTACKDEPTH>0 + pParser->yystackEnd = &pParser->yystack[YYSTACKDEPTH-1]; +#endif } #ifndef sqlite3Parser_ENGINEALWAYSONSTACK @@ -137258,7 +138764,7 @@ static void yy_shift( } #endif #if YYSTACKDEPTH>0 - if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){ + if( yypParser->yytos>yypParser->yystackEnd ){ yypParser->yytos--; yyStackOverflow(yypParser); return; @@ -137286,341 +138792,338 @@ static void yy_shift( ** is used during the reduce. */ static const struct { - YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - unsigned char nrhs; /* Number of right-hand side symbols in the rule */ + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ + signed char nrhs; /* Negative of the number of RHS symbols in the rule */ } yyRuleInfo[] = { - { 147, 1 }, - { 147, 3 }, - { 148, 1 }, - { 149, 3 }, + { 147, -1 }, + { 147, -3 }, + { 148, -1 }, + { 149, -3 }, { 150, 0 }, - { 150, 1 }, - { 150, 1 }, - { 150, 1 }, - { 149, 2 }, - { 149, 2 }, - { 149, 2 }, - { 149, 2 }, - { 149, 3 }, - { 149, 5 }, - { 154, 6 }, - { 156, 1 }, + { 150, -1 }, + { 150, -1 }, + { 150, -1 }, + { 149, -2 }, + { 149, -2 }, + { 149, -2 }, + { 149, -3 }, + { 149, -5 }, + { 154, -6 }, + { 156, -1 }, { 158, 0 }, - { 158, 3 }, - { 157, 1 }, + { 158, -3 }, + { 157, -1 }, { 157, 0 }, - { 155, 5 }, - { 155, 2 }, + { 155, -5 }, + { 155, -2 }, { 162, 0 }, - { 162, 2 }, - { 164, 2 }, + { 162, -2 }, + { 164, -2 }, { 166, 0 }, - { 166, 4 }, - { 166, 6 }, - { 167, 2 }, - { 171, 2 }, - { 171, 2 }, - { 171, 4 }, - { 171, 3 }, - { 171, 3 }, - { 171, 2 }, - { 171, 3 }, - { 171, 5 }, - { 171, 2 }, - { 171, 4 }, - { 171, 4 }, - { 171, 1 }, - { 171, 2 }, + { 166, -4 }, + { 166, -6 }, + { 167, -2 }, + { 171, -2 }, + { 171, -2 }, + { 171, -4 }, + { 171, -3 }, + { 171, -3 }, + { 171, -2 }, + { 171, -3 }, + { 171, -5 }, + { 171, -2 }, + { 171, -4 }, + { 171, -4 }, + { 171, -1 }, + { 171, -2 }, { 176, 0 }, - { 176, 1 }, + { 176, -1 }, { 178, 0 }, - { 178, 2 }, - { 180, 2 }, - { 180, 3 }, - { 180, 3 }, - { 180, 3 }, - { 181, 2 }, - { 181, 2 }, - { 181, 1 }, - { 181, 1 }, - { 181, 2 }, - { 179, 3 }, - { 179, 2 }, + { 178, -2 }, + { 180, -2 }, + { 180, -3 }, + { 180, -3 }, + { 180, -3 }, + { 181, -2 }, + { 181, -2 }, + { 181, -1 }, + { 181, -1 }, + { 181, -2 }, + { 179, -3 }, + { 179, -2 }, { 182, 0 }, - { 182, 2 }, - { 182, 2 }, + { 182, -2 }, + { 182, -2 }, { 161, 0 }, - { 184, 1 }, - { 185, 2 }, - { 185, 7 }, - { 185, 5 }, - { 185, 5 }, - { 185, 10 }, + { 184, -1 }, + { 185, -2 }, + { 185, -7 }, + { 185, -5 }, + { 185, -5 }, + { 185, -10 }, { 188, 0 }, { 174, 0 }, - { 174, 3 }, + { 174, -3 }, { 189, 0 }, - { 189, 2 }, - { 190, 1 }, - { 190, 1 }, - { 149, 4 }, - { 192, 2 }, + { 189, -2 }, + { 190, -1 }, + { 190, -1 }, + { 149, -4 }, + { 192, -2 }, { 192, 0 }, - { 149, 9 }, - { 149, 4 }, - { 149, 1 }, - { 163, 2 }, - { 194, 3 }, - { 197, 1 }, - { 197, 2 }, - { 197, 1 }, - { 195, 9 }, - { 206, 4 }, - { 206, 5 }, - { 198, 1 }, - { 198, 1 }, + { 149, -9 }, + { 149, -4 }, + { 149, -1 }, + { 163, -2 }, + { 194, -3 }, + { 197, -1 }, + { 197, -2 }, + { 197, -1 }, + { 195, -9 }, + { 206, -4 }, + { 206, -5 }, + { 198, -1 }, + { 198, -1 }, { 198, 0 }, { 209, 0 }, - { 199, 3 }, - { 199, 2 }, - { 199, 4 }, - { 210, 2 }, + { 199, -3 }, + { 199, -2 }, + { 199, -4 }, + { 210, -2 }, { 210, 0 }, { 200, 0 }, - { 200, 2 }, - { 212, 2 }, + { 200, -2 }, + { 212, -2 }, { 212, 0 }, - { 211, 7 }, - { 211, 9 }, - { 211, 7 }, - { 211, 7 }, + { 211, -7 }, + { 211, -9 }, + { 211, -7 }, + { 211, -7 }, { 159, 0 }, - { 159, 2 }, - { 193, 2 }, - { 213, 1 }, - { 213, 2 }, - { 213, 3 }, - { 213, 4 }, - { 215, 2 }, + { 159, -2 }, + { 193, -2 }, + { 213, -1 }, + { 213, -2 }, + { 213, -3 }, + { 213, -4 }, + { 215, -2 }, { 215, 0 }, { 214, 0 }, - { 214, 3 }, - { 214, 2 }, - { 216, 4 }, + { 214, -3 }, + { 214, -2 }, + { 216, -4 }, { 216, 0 }, { 204, 0 }, - { 204, 3 }, - { 186, 4 }, - { 186, 2 }, - { 175, 1 }, - { 175, 1 }, + { 204, -3 }, + { 186, -4 }, + { 186, -2 }, + { 175, -1 }, + { 175, -1 }, { 175, 0 }, { 202, 0 }, - { 202, 3 }, + { 202, -3 }, { 203, 0 }, - { 203, 2 }, + { 203, -2 }, { 205, 0 }, - { 205, 2 }, - { 205, 4 }, - { 205, 4 }, - { 149, 6 }, + { 205, -2 }, + { 205, -4 }, + { 205, -4 }, + { 149, -6 }, { 201, 0 }, - { 201, 2 }, - { 149, 8 }, - { 218, 5 }, - { 218, 7 }, - { 218, 3 }, - { 218, 5 }, - { 149, 6 }, - { 149, 7 }, - { 219, 2 }, - { 219, 1 }, + { 201, -2 }, + { 149, -8 }, + { 218, -5 }, + { 218, -7 }, + { 218, -3 }, + { 218, -5 }, + { 149, -6 }, + { 149, -7 }, + { 219, -2 }, + { 219, -1 }, { 220, 0 }, - { 220, 3 }, - { 217, 3 }, - { 217, 1 }, - { 173, 3 }, - { 172, 1 }, - { 173, 1 }, - { 173, 1 }, - { 173, 3 }, - { 173, 5 }, - { 172, 1 }, - { 172, 1 }, - { 172, 1 }, - { 173, 1 }, - { 173, 3 }, - { 173, 6 }, - { 173, 5 }, - { 173, 4 }, - { 172, 1 }, - { 173, 5 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 221, 2 }, - { 173, 3 }, - { 173, 5 }, - { 173, 2 }, - { 173, 3 }, - { 173, 3 }, - { 173, 4 }, - { 173, 2 }, - { 173, 2 }, - { 173, 2 }, - { 173, 2 }, - { 222, 1 }, - { 222, 2 }, - { 173, 5 }, - { 223, 1 }, - { 223, 2 }, - { 173, 5 }, - { 173, 3 }, - { 173, 5 }, - { 173, 5 }, - { 173, 4 }, - { 173, 5 }, - { 226, 5 }, - { 226, 4 }, - { 227, 2 }, + { 220, -3 }, + { 217, -3 }, + { 217, -1 }, + { 173, -3 }, + { 173, -1 }, + { 173, -1 }, + { 173, -3 }, + { 173, -5 }, + { 172, -1 }, + { 172, -1 }, + { 172, -1 }, + { 173, -1 }, + { 173, -3 }, + { 173, -6 }, + { 173, -5 }, + { 173, -4 }, + { 172, -1 }, + { 173, -5 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 221, -2 }, + { 173, -3 }, + { 173, -5 }, + { 173, -2 }, + { 173, -3 }, + { 173, -3 }, + { 173, -4 }, + { 173, -2 }, + { 173, -2 }, + { 173, -2 }, + { 173, -2 }, + { 222, -1 }, + { 222, -2 }, + { 173, -5 }, + { 223, -1 }, + { 223, -2 }, + { 173, -5 }, + { 173, -3 }, + { 173, -5 }, + { 173, -5 }, + { 173, -4 }, + { 173, -5 }, + { 226, -5 }, + { 226, -4 }, + { 227, -2 }, { 227, 0 }, - { 225, 1 }, + { 225, -1 }, { 225, 0 }, { 208, 0 }, - { 207, 3 }, - { 207, 1 }, + { 207, -3 }, + { 207, -1 }, { 224, 0 }, - { 224, 3 }, - { 149, 12 }, - { 228, 1 }, + { 224, -3 }, + { 149, -12 }, + { 228, -1 }, { 228, 0 }, { 177, 0 }, - { 177, 3 }, - { 187, 5 }, - { 187, 3 }, + { 177, -3 }, + { 187, -5 }, + { 187, -3 }, { 229, 0 }, - { 229, 2 }, - { 149, 4 }, - { 149, 1 }, - { 149, 2 }, - { 149, 3 }, - { 149, 5 }, - { 149, 6 }, - { 149, 5 }, - { 149, 6 }, - { 169, 2 }, - { 170, 2 }, - { 149, 5 }, - { 231, 11 }, - { 233, 1 }, - { 233, 1 }, - { 233, 2 }, + { 229, -2 }, + { 149, -4 }, + { 149, -1 }, + { 149, -2 }, + { 149, -3 }, + { 149, -5 }, + { 149, -6 }, + { 149, -5 }, + { 149, -6 }, + { 169, -2 }, + { 170, -2 }, + { 149, -5 }, + { 231, -11 }, + { 233, -1 }, + { 233, -2 }, { 233, 0 }, - { 234, 1 }, - { 234, 1 }, - { 234, 3 }, + { 234, -1 }, + { 234, -1 }, + { 234, -3 }, { 236, 0 }, - { 236, 2 }, - { 232, 3 }, - { 232, 2 }, - { 238, 3 }, - { 239, 3 }, - { 239, 2 }, - { 237, 7 }, - { 237, 5 }, - { 237, 5 }, - { 237, 1 }, - { 173, 4 }, - { 173, 6 }, - { 191, 1 }, - { 191, 1 }, - { 191, 1 }, - { 149, 4 }, - { 149, 6 }, - { 149, 3 }, + { 236, -2 }, + { 232, -3 }, + { 232, -2 }, + { 238, -3 }, + { 239, -3 }, + { 239, -2 }, + { 237, -7 }, + { 237, -5 }, + { 237, -5 }, + { 237, -1 }, + { 173, -4 }, + { 173, -6 }, + { 191, -1 }, + { 191, -1 }, + { 191, -1 }, + { 149, -4 }, + { 149, -6 }, + { 149, -3 }, { 241, 0 }, - { 241, 2 }, - { 149, 1 }, - { 149, 3 }, - { 149, 1 }, - { 149, 3 }, - { 149, 6 }, - { 149, 7 }, - { 242, 1 }, - { 149, 1 }, - { 149, 4 }, - { 244, 8 }, + { 241, -2 }, + { 149, -1 }, + { 149, -3 }, + { 149, -1 }, + { 149, -3 }, + { 149, -6 }, + { 149, -7 }, + { 242, -1 }, + { 149, -1 }, + { 149, -4 }, + { 244, -8 }, { 246, 0 }, - { 247, 1 }, - { 247, 3 }, - { 248, 1 }, + { 247, -1 }, + { 247, -3 }, + { 248, -1 }, { 196, 0 }, - { 196, 2 }, - { 196, 3 }, - { 250, 6 }, - { 250, 8 }, - { 144, 1 }, - { 145, 2 }, - { 145, 1 }, - { 146, 1 }, - { 146, 3 }, + { 196, -2 }, + { 196, -3 }, + { 250, -6 }, + { 250, -8 }, + { 144, -1 }, + { 145, -2 }, + { 145, -1 }, + { 146, -1 }, + { 146, -3 }, { 147, 0 }, { 151, 0 }, - { 151, 1 }, - { 151, 2 }, - { 153, 1 }, + { 151, -1 }, + { 151, -2 }, + { 153, -1 }, { 153, 0 }, - { 149, 2 }, - { 160, 4 }, - { 160, 2 }, - { 152, 1 }, - { 152, 1 }, - { 152, 1 }, - { 166, 1 }, - { 167, 1 }, - { 168, 1 }, - { 168, 1 }, - { 165, 2 }, + { 149, -2 }, + { 160, -4 }, + { 160, -2 }, + { 152, -1 }, + { 152, -1 }, + { 152, -1 }, + { 166, -1 }, + { 167, -1 }, + { 168, -1 }, + { 168, -1 }, + { 165, -2 }, { 165, 0 }, - { 171, 2 }, - { 161, 2 }, - { 183, 3 }, - { 183, 1 }, + { 171, -2 }, + { 161, -2 }, + { 183, -3 }, + { 183, -1 }, { 184, 0 }, - { 188, 1 }, - { 190, 1 }, - { 194, 1 }, - { 195, 1 }, - { 209, 2 }, - { 210, 1 }, - { 173, 1 }, - { 221, 1 }, - { 208, 1 }, - { 230, 1 }, - { 230, 1 }, - { 230, 1 }, - { 230, 1 }, - { 230, 1 }, - { 169, 1 }, + { 188, -1 }, + { 190, -1 }, + { 194, -1 }, + { 195, -1 }, + { 209, -2 }, + { 210, -1 }, + { 173, -1 }, + { 221, -1 }, + { 208, -1 }, + { 230, -1 }, + { 230, -1 }, + { 230, -1 }, + { 230, -1 }, + { 230, -1 }, + { 169, -1 }, { 235, 0 }, - { 235, 3 }, - { 238, 1 }, + { 235, -3 }, + { 238, -1 }, { 239, 0 }, - { 240, 1 }, + { 240, -1 }, { 240, 0 }, { 243, 0 }, - { 243, 1 }, - { 245, 1 }, - { 245, 3 }, - { 246, 2 }, + { 243, -1 }, + { 245, -1 }, + { 245, -3 }, + { 246, -2 }, { 249, 0 }, - { 249, 4 }, - { 249, 2 }, + { 249, -4 }, + { 249, -2 }, }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -137643,7 +139146,7 @@ static void yy_reduce( if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ yysize = yyRuleInfo[yyruleno].nrhs; fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, - yyRuleName[yyruleno], yymsp[-yysize].stateno); + yyRuleName[yyruleno], yymsp[yysize].stateno); } #endif /* NDEBUG */ @@ -137658,7 +139161,7 @@ static void yy_reduce( } #endif #if YYSTACKDEPTH>0 - if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){ + if( yypParser->yytos>=yypParser->yystackEnd ){ yyStackOverflow(yypParser); return; } @@ -137704,66 +139207,63 @@ static void yy_reduce( case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); {yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-X*/} break; - case 8: /* cmd ::= COMMIT trans_opt */ - case 9: /* cmd ::= END trans_opt */ yytestcase(yyruleno==9); -{sqlite3CommitTransaction(pParse);} - break; - case 10: /* cmd ::= ROLLBACK trans_opt */ -{sqlite3RollbackTransaction(pParse);} + case 8: /* cmd ::= COMMIT|END trans_opt */ + case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); +{sqlite3EndTransaction(pParse,yymsp[-1].major);} break; - case 11: /* cmd ::= SAVEPOINT nm */ + case 10: /* cmd ::= SAVEPOINT nm */ { sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0); } break; - case 12: /* cmd ::= RELEASE savepoint_opt nm */ + case 11: /* cmd ::= RELEASE savepoint_opt nm */ { sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0); } break; - case 13: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ { sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); } break; - case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy194,0,0,yymsp[-2].minor.yy194); } break; - case 15: /* createkw ::= CREATE */ + case 14: /* createkw ::= CREATE */ {disableLookaside(pParse);} break; - case 16: /* ifnotexists ::= */ - case 19: /* temp ::= */ yytestcase(yyruleno==19); - case 22: /* table_options ::= */ yytestcase(yyruleno==22); - case 42: /* autoinc ::= */ yytestcase(yyruleno==42); - case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57); - case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67); - case 76: /* ifexists ::= */ yytestcase(yyruleno==76); - case 90: /* distinct ::= */ yytestcase(yyruleno==90); - case 214: /* collate ::= */ yytestcase(yyruleno==214); + case 15: /* ifnotexists ::= */ + case 18: /* temp ::= */ yytestcase(yyruleno==18); + case 21: /* table_options ::= */ yytestcase(yyruleno==21); + case 41: /* autoinc ::= */ yytestcase(yyruleno==41); + case 56: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==56); + case 66: /* defer_subclause_opt ::= */ yytestcase(yyruleno==66); + case 75: /* ifexists ::= */ yytestcase(yyruleno==75); + case 89: /* distinct ::= */ yytestcase(yyruleno==89); + case 212: /* collate ::= */ yytestcase(yyruleno==212); {yymsp[1].minor.yy194 = 0;} break; - case 17: /* ifnotexists ::= IF NOT EXISTS */ + case 16: /* ifnotexists ::= IF NOT EXISTS */ {yymsp[-2].minor.yy194 = 1;} break; - case 18: /* temp ::= TEMP */ - case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43); + case 17: /* temp ::= TEMP */ + case 42: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==42); {yymsp[0].minor.yy194 = 1;} break; - case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ + case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ { sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy194,0); } break; - case 21: /* create_table_args ::= AS select */ + case 20: /* create_table_args ::= AS select */ { sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy243); sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); } break; - case 23: /* table_options ::= WITHOUT nm */ + case 22: /* table_options ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ yymsp[-1].minor.yy194 = TF_WithoutRowid | TF_NoVisibleRowid; @@ -137773,39 +139273,39 @@ static void yy_reduce( } } break; - case 24: /* columnname ::= nm typetoken */ + case 23: /* columnname ::= nm typetoken */ {sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);} break; - case 25: /* typetoken ::= */ - case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60); - case 96: /* as ::= */ yytestcase(yyruleno==96); + case 24: /* typetoken ::= */ + case 59: /* conslist_opt ::= */ yytestcase(yyruleno==59); + case 95: /* as ::= */ yytestcase(yyruleno==95); {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} break; - case 26: /* typetoken ::= typename LP signed RP */ + case 25: /* typetoken ::= typename LP signed RP */ { yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); } break; - case 27: /* typetoken ::= typename LP signed COMMA signed RP */ + case 26: /* typetoken ::= typename LP signed COMMA signed RP */ { yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z); } break; - case 28: /* typename ::= typename ID|STRING */ + case 27: /* typename ::= typename ID|STRING */ {yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} break; - case 29: /* ccons ::= CONSTRAINT nm */ - case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62); + case 28: /* ccons ::= CONSTRAINT nm */ + case 61: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==61); {pParse->constraintName = yymsp[0].minor.yy0;} break; - case 30: /* ccons ::= DEFAULT term */ - case 32: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==32); + case 29: /* ccons ::= DEFAULT term */ + case 31: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==31); {sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy190);} break; - case 31: /* ccons ::= DEFAULT LP expr RP */ + case 30: /* ccons ::= DEFAULT LP expr RP */ {sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy190);} break; - case 33: /* ccons ::= DEFAULT MINUS term */ + case 32: /* ccons ::= DEFAULT MINUS term */ { ExprSpan v; v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy190.pExpr, 0); @@ -137814,142 +139314,142 @@ static void yy_reduce( sqlite3AddDefaultValue(pParse,&v); } break; - case 34: /* ccons ::= DEFAULT ID|INDEXED */ + case 33: /* ccons ::= DEFAULT ID|INDEXED */ { ExprSpan v; spanExpr(&v, pParse, TK_STRING, yymsp[0].minor.yy0); sqlite3AddDefaultValue(pParse,&v); } break; - case 35: /* ccons ::= NOT NULL onconf */ + case 34: /* ccons ::= NOT NULL onconf */ {sqlite3AddNotNull(pParse, yymsp[0].minor.yy194);} break; - case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ + case 35: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ {sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy194,yymsp[0].minor.yy194,yymsp[-2].minor.yy194);} break; - case 37: /* ccons ::= UNIQUE onconf */ + case 36: /* ccons ::= UNIQUE onconf */ {sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy194,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; - case 38: /* ccons ::= CHECK LP expr RP */ + case 37: /* ccons ::= CHECK LP expr RP */ {sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy190.pExpr);} break; - case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */ + case 38: /* ccons ::= REFERENCES nm eidlist_opt refargs */ {sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy148,yymsp[0].minor.yy194);} break; - case 40: /* ccons ::= defer_subclause */ + case 39: /* ccons ::= defer_subclause */ {sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy194);} break; - case 41: /* ccons ::= COLLATE ID|STRING */ + case 40: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; - case 44: /* refargs ::= */ + case 43: /* refargs ::= */ { yymsp[1].minor.yy194 = OE_None*0x0101; /* EV: R-19803-45884 */} break; - case 45: /* refargs ::= refargs refarg */ + case 44: /* refargs ::= refargs refarg */ { yymsp[-1].minor.yy194 = (yymsp[-1].minor.yy194 & ~yymsp[0].minor.yy497.mask) | yymsp[0].minor.yy497.value; } break; - case 46: /* refarg ::= MATCH nm */ + case 45: /* refarg ::= MATCH nm */ { yymsp[-1].minor.yy497.value = 0; yymsp[-1].minor.yy497.mask = 0x000000; } break; - case 47: /* refarg ::= ON INSERT refact */ + case 46: /* refarg ::= ON INSERT refact */ { yymsp[-2].minor.yy497.value = 0; yymsp[-2].minor.yy497.mask = 0x000000; } break; - case 48: /* refarg ::= ON DELETE refact */ + case 47: /* refarg ::= ON DELETE refact */ { yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194; yymsp[-2].minor.yy497.mask = 0x0000ff; } break; - case 49: /* refarg ::= ON UPDATE refact */ + case 48: /* refarg ::= ON UPDATE refact */ { yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194<<8; yymsp[-2].minor.yy497.mask = 0x00ff00; } break; - case 50: /* refact ::= SET NULL */ + case 49: /* refact ::= SET NULL */ { yymsp[-1].minor.yy194 = OE_SetNull; /* EV: R-33326-45252 */} break; - case 51: /* refact ::= SET DEFAULT */ + case 50: /* refact ::= SET DEFAULT */ { yymsp[-1].minor.yy194 = OE_SetDflt; /* EV: R-33326-45252 */} break; - case 52: /* refact ::= CASCADE */ + case 51: /* refact ::= CASCADE */ { yymsp[0].minor.yy194 = OE_Cascade; /* EV: R-33326-45252 */} break; - case 53: /* refact ::= RESTRICT */ + case 52: /* refact ::= RESTRICT */ { yymsp[0].minor.yy194 = OE_Restrict; /* EV: R-33326-45252 */} break; - case 54: /* refact ::= NO ACTION */ + case 53: /* refact ::= NO ACTION */ { yymsp[-1].minor.yy194 = OE_None; /* EV: R-33326-45252 */} break; - case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + case 54: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ {yymsp[-2].minor.yy194 = 0;} break; - case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71); - case 144: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==144); + case 55: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + case 70: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==70); + case 143: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==143); {yymsp[-1].minor.yy194 = yymsp[0].minor.yy194;} break; - case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ - case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75); - case 186: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==186); - case 189: /* in_op ::= NOT IN */ yytestcase(yyruleno==189); - case 215: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==215); + case 57: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ + case 74: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==74); + case 184: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==184); + case 187: /* in_op ::= NOT IN */ yytestcase(yyruleno==187); + case 213: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==213); {yymsp[-1].minor.yy194 = 1;} break; - case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + case 58: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ {yymsp[-1].minor.yy194 = 0;} break; - case 61: /* tconscomma ::= COMMA */ + case 60: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; - case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + case 62: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ {sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy148,yymsp[0].minor.yy194,yymsp[-2].minor.yy194,0);} break; - case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */ + case 63: /* tcons ::= UNIQUE LP sortlist RP onconf */ {sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy148,yymsp[0].minor.yy194,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; - case 65: /* tcons ::= CHECK LP expr RP onconf */ + case 64: /* tcons ::= CHECK LP expr RP onconf */ {sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy190.pExpr);} break; - case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + case 65: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy148, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[-1].minor.yy194); sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy194); } break; - case 68: /* onconf ::= */ - case 70: /* orconf ::= */ yytestcase(yyruleno==70); + case 67: /* onconf ::= */ + case 69: /* orconf ::= */ yytestcase(yyruleno==69); {yymsp[1].minor.yy194 = OE_Default;} break; - case 69: /* onconf ::= ON CONFLICT resolvetype */ + case 68: /* onconf ::= ON CONFLICT resolvetype */ {yymsp[-2].minor.yy194 = yymsp[0].minor.yy194;} break; - case 72: /* resolvetype ::= IGNORE */ + case 71: /* resolvetype ::= IGNORE */ {yymsp[0].minor.yy194 = OE_Ignore;} break; - case 73: /* resolvetype ::= REPLACE */ - case 145: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==145); + case 72: /* resolvetype ::= REPLACE */ + case 144: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==144); {yymsp[0].minor.yy194 = OE_Replace;} break; - case 74: /* cmd ::= DROP TABLE ifexists fullname */ + case 73: /* cmd ::= DROP TABLE ifexists fullname */ { sqlite3DropTable(pParse, yymsp[0].minor.yy185, 0, yymsp[-1].minor.yy194); } break; - case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + case 76: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[0].minor.yy243, yymsp[-7].minor.yy194, yymsp[-5].minor.yy194); } break; - case 78: /* cmd ::= DROP VIEW ifexists fullname */ + case 77: /* cmd ::= DROP VIEW ifexists fullname */ { sqlite3DropTable(pParse, yymsp[0].minor.yy185, 1, yymsp[-1].minor.yy194); } break; - case 79: /* cmd ::= select */ + case 78: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; sqlite3Select(pParse, yymsp[0].minor.yy243, &dest); sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); } break; - case 80: /* select ::= with selectnowith */ + case 79: /* select ::= with selectnowith */ { Select *p = yymsp[0].minor.yy243; if( p ){ @@ -137961,7 +139461,7 @@ static void yy_reduce( yymsp[-1].minor.yy243 = p; /*A-overwrites-W*/ } break; - case 81: /* selectnowith ::= selectnowith multiselect_op oneselect */ + case 80: /* selectnowith ::= selectnowith multiselect_op oneselect */ { Select *pRhs = yymsp[0].minor.yy243; Select *pLhs = yymsp[-2].minor.yy243; @@ -137985,14 +139485,14 @@ static void yy_reduce( yymsp[-2].minor.yy243 = pRhs; } break; - case 82: /* multiselect_op ::= UNION */ - case 84: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==84); + case 81: /* multiselect_op ::= UNION */ + case 83: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==83); {yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-OP*/} break; - case 83: /* multiselect_op ::= UNION ALL */ + case 82: /* multiselect_op ::= UNION ALL */ {yymsp[-1].minor.yy194 = TK_ALL;} break; - case 85: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + case 84: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { #if SELECTTRACE_ENABLED Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/ @@ -138024,12 +139524,12 @@ static void yy_reduce( #endif /* SELECTRACE_ENABLED */ } break; - case 86: /* values ::= VALUES LP nexprlist RP */ + case 85: /* values ::= VALUES LP nexprlist RP */ { yymsp[-3].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values,0,0); } break; - case 87: /* values ::= values COMMA LP exprlist RP */ + case 86: /* values ::= values COMMA LP exprlist RP */ { Select *pRight, *pLeft = yymsp[-4].minor.yy243; pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); @@ -138043,34 +139543,34 @@ static void yy_reduce( } } break; - case 88: /* distinct ::= DISTINCT */ + case 87: /* distinct ::= DISTINCT */ {yymsp[0].minor.yy194 = SF_Distinct;} break; - case 89: /* distinct ::= ALL */ + case 88: /* distinct ::= ALL */ {yymsp[0].minor.yy194 = SF_All;} break; - case 91: /* sclp ::= */ - case 119: /* orderby_opt ::= */ yytestcase(yyruleno==119); - case 126: /* groupby_opt ::= */ yytestcase(yyruleno==126); - case 202: /* exprlist ::= */ yytestcase(yyruleno==202); - case 205: /* paren_exprlist ::= */ yytestcase(yyruleno==205); - case 210: /* eidlist_opt ::= */ yytestcase(yyruleno==210); + case 90: /* sclp ::= */ + case 118: /* orderby_opt ::= */ yytestcase(yyruleno==118); + case 125: /* groupby_opt ::= */ yytestcase(yyruleno==125); + case 200: /* exprlist ::= */ yytestcase(yyruleno==200); + case 203: /* paren_exprlist ::= */ yytestcase(yyruleno==203); + case 208: /* eidlist_opt ::= */ yytestcase(yyruleno==208); {yymsp[1].minor.yy148 = 0;} break; - case 92: /* selcollist ::= sclp expr as */ + case 91: /* selcollist ::= sclp expr as */ { yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy148, yymsp[-1].minor.yy190.pExpr); if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy148, &yymsp[0].minor.yy0, 1); sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy148,&yymsp[-1].minor.yy190); } break; - case 93: /* selcollist ::= sclp STAR */ + case 92: /* selcollist ::= sclp STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy148, p); } break; - case 94: /* selcollist ::= sclp nm DOT STAR */ + case 93: /* selcollist ::= sclp nm DOT STAR */ { Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); @@ -138078,47 +139578,47 @@ static void yy_reduce( yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, pDot); } break; - case 95: /* as ::= AS nm */ - case 106: /* dbnm ::= DOT nm */ yytestcase(yyruleno==106); - case 224: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==224); - case 225: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==225); + case 94: /* as ::= AS nm */ + case 105: /* dbnm ::= DOT nm */ yytestcase(yyruleno==105); + case 222: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==222); + case 223: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==223); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; - case 97: /* from ::= */ + case 96: /* from ::= */ {yymsp[1].minor.yy185 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy185));} break; - case 98: /* from ::= FROM seltablist */ + case 97: /* from ::= FROM seltablist */ { yymsp[-1].minor.yy185 = yymsp[0].minor.yy185; sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy185); } break; - case 99: /* stl_prefix ::= seltablist joinop */ + case 98: /* stl_prefix ::= seltablist joinop */ { if( ALWAYS(yymsp[-1].minor.yy185 && yymsp[-1].minor.yy185->nSrc>0) ) yymsp[-1].minor.yy185->a[yymsp[-1].minor.yy185->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy194; } break; - case 100: /* stl_prefix ::= */ + case 99: /* stl_prefix ::= */ {yymsp[1].minor.yy185 = 0;} break; - case 101: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + case 100: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ { yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy185, &yymsp[-2].minor.yy0); } break; - case 102: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + case 101: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ { yymsp[-8].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy185,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy185, yymsp[-4].minor.yy148); } break; - case 103: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + case 102: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ { yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy243,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); } break; - case 104: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + case 103: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ { if( yymsp[-6].minor.yy185==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy72==0 && yymsp[0].minor.yy254==0 ){ yymsp[-6].minor.yy185 = yymsp[-4].minor.yy185; @@ -138142,96 +139642,96 @@ static void yy_reduce( } } break; - case 105: /* dbnm ::= */ - case 114: /* indexed_opt ::= */ yytestcase(yyruleno==114); + case 104: /* dbnm ::= */ + case 113: /* indexed_opt ::= */ yytestcase(yyruleno==113); {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; - case 107: /* fullname ::= nm dbnm */ + case 106: /* fullname ::= nm dbnm */ {yymsp[-1].minor.yy185 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 108: /* joinop ::= COMMA|JOIN */ + case 107: /* joinop ::= COMMA|JOIN */ { yymsp[0].minor.yy194 = JT_INNER; } break; - case 109: /* joinop ::= JOIN_KW JOIN */ + case 108: /* joinop ::= JOIN_KW JOIN */ {yymsp[-1].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; - case 110: /* joinop ::= JOIN_KW nm JOIN */ + case 109: /* joinop ::= JOIN_KW nm JOIN */ {yymsp[-2].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} break; - case 111: /* joinop ::= JOIN_KW nm nm JOIN */ + case 110: /* joinop ::= JOIN_KW nm nm JOIN */ {yymsp[-3].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} break; - case 112: /* on_opt ::= ON expr */ - case 129: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==129); - case 136: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==136); - case 198: /* case_else ::= ELSE expr */ yytestcase(yyruleno==198); + case 111: /* on_opt ::= ON expr */ + case 128: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==128); + case 135: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==135); + case 196: /* case_else ::= ELSE expr */ yytestcase(yyruleno==196); {yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr;} break; - case 113: /* on_opt ::= */ - case 128: /* having_opt ::= */ yytestcase(yyruleno==128); - case 135: /* where_opt ::= */ yytestcase(yyruleno==135); - case 199: /* case_else ::= */ yytestcase(yyruleno==199); - case 201: /* case_operand ::= */ yytestcase(yyruleno==201); + case 112: /* on_opt ::= */ + case 127: /* having_opt ::= */ yytestcase(yyruleno==127); + case 134: /* where_opt ::= */ yytestcase(yyruleno==134); + case 197: /* case_else ::= */ yytestcase(yyruleno==197); + case 199: /* case_operand ::= */ yytestcase(yyruleno==199); {yymsp[1].minor.yy72 = 0;} break; - case 115: /* indexed_opt ::= INDEXED BY nm */ + case 114: /* indexed_opt ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; - case 116: /* indexed_opt ::= NOT INDEXED */ + case 115: /* indexed_opt ::= NOT INDEXED */ {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; - case 117: /* using_opt ::= USING LP idlist RP */ + case 116: /* using_opt ::= USING LP idlist RP */ {yymsp[-3].minor.yy254 = yymsp[-1].minor.yy254;} break; - case 118: /* using_opt ::= */ - case 146: /* idlist_opt ::= */ yytestcase(yyruleno==146); + case 117: /* using_opt ::= */ + case 145: /* idlist_opt ::= */ yytestcase(yyruleno==145); {yymsp[1].minor.yy254 = 0;} break; - case 120: /* orderby_opt ::= ORDER BY sortlist */ - case 127: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==127); + case 119: /* orderby_opt ::= ORDER BY sortlist */ + case 126: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==126); {yymsp[-2].minor.yy148 = yymsp[0].minor.yy148;} break; - case 121: /* sortlist ::= sortlist COMMA expr sortorder */ + case 120: /* sortlist ::= sortlist COMMA expr sortorder */ { yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148,yymsp[-1].minor.yy190.pExpr); sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy148,yymsp[0].minor.yy194); } break; - case 122: /* sortlist ::= expr sortorder */ + case 121: /* sortlist ::= expr sortorder */ { yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy190.pExpr); /*A-overwrites-Y*/ sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy148,yymsp[0].minor.yy194); } break; - case 123: /* sortorder ::= ASC */ + case 122: /* sortorder ::= ASC */ {yymsp[0].minor.yy194 = SQLITE_SO_ASC;} break; - case 124: /* sortorder ::= DESC */ + case 123: /* sortorder ::= DESC */ {yymsp[0].minor.yy194 = SQLITE_SO_DESC;} break; - case 125: /* sortorder ::= */ + case 124: /* sortorder ::= */ {yymsp[1].minor.yy194 = SQLITE_SO_UNDEFINED;} break; - case 130: /* limit_opt ::= */ + case 129: /* limit_opt ::= */ {yymsp[1].minor.yy354.pLimit = 0; yymsp[1].minor.yy354.pOffset = 0;} break; - case 131: /* limit_opt ::= LIMIT expr */ + case 130: /* limit_opt ::= LIMIT expr */ {yymsp[-1].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr; yymsp[-1].minor.yy354.pOffset = 0;} break; - case 132: /* limit_opt ::= LIMIT expr OFFSET expr */ + case 131: /* limit_opt ::= LIMIT expr OFFSET expr */ {yymsp[-3].minor.yy354.pLimit = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pOffset = yymsp[0].minor.yy190.pExpr;} break; - case 133: /* limit_opt ::= LIMIT expr COMMA expr */ + case 132: /* limit_opt ::= LIMIT expr COMMA expr */ {yymsp[-3].minor.yy354.pOffset = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr;} break; - case 134: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */ + case 133: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */ { sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy185, &yymsp[-1].minor.yy0); sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy185,yymsp[0].minor.yy72); } break; - case 137: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ + case 136: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ { sqlite3WithPush(pParse, yymsp[-7].minor.yy285, 1); sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy185, &yymsp[-3].minor.yy0); @@ -138239,63 +139739,58 @@ static void yy_reduce( sqlite3Update(pParse,yymsp[-4].minor.yy185,yymsp[-1].minor.yy148,yymsp[0].minor.yy72,yymsp[-5].minor.yy194); } break; - case 138: /* setlist ::= setlist COMMA nm EQ expr */ + case 137: /* setlist ::= setlist COMMA nm EQ expr */ { yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, 1); } break; - case 139: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ + case 138: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { yymsp[-6].minor.yy148 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy148, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr); } break; - case 140: /* setlist ::= nm EQ expr */ + case 139: /* setlist ::= nm EQ expr */ { yylhsminor.yy148 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy190.pExpr); sqlite3ExprListSetName(pParse, yylhsminor.yy148, &yymsp[-2].minor.yy0, 1); } yymsp[-2].minor.yy148 = yylhsminor.yy148; break; - case 141: /* setlist ::= LP idlist RP EQ expr */ + case 140: /* setlist ::= LP idlist RP EQ expr */ { yymsp[-4].minor.yy148 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr); } break; - case 142: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */ + case 141: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */ { sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); sqlite3Insert(pParse, yymsp[-2].minor.yy185, yymsp[0].minor.yy243, yymsp[-1].minor.yy254, yymsp[-4].minor.yy194); } break; - case 143: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ + case 142: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ { sqlite3WithPush(pParse, yymsp[-6].minor.yy285, 1); sqlite3Insert(pParse, yymsp[-3].minor.yy185, 0, yymsp[-2].minor.yy254, yymsp[-5].minor.yy194); } break; - case 147: /* idlist_opt ::= LP idlist RP */ + case 146: /* idlist_opt ::= LP idlist RP */ {yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} break; - case 148: /* idlist ::= idlist COMMA nm */ + case 147: /* idlist ::= idlist COMMA nm */ {yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);} break; - case 149: /* idlist ::= nm */ + case 148: /* idlist ::= nm */ {yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} break; - case 150: /* expr ::= LP expr RP */ + case 149: /* expr ::= LP expr RP */ {spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy190.pExpr = yymsp[-1].minor.yy190.pExpr;} break; - case 151: /* term ::= NULL */ - case 156: /* term ::= FLOAT|BLOB */ yytestcase(yyruleno==156); - case 157: /* term ::= STRING */ yytestcase(yyruleno==157); -{spanExpr(&yymsp[0].minor.yy190,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/} - break; - case 152: /* expr ::= ID|INDEXED */ - case 153: /* expr ::= JOIN_KW */ yytestcase(yyruleno==153); + case 150: /* expr ::= ID|INDEXED */ + case 151: /* expr ::= JOIN_KW */ yytestcase(yyruleno==151); {spanExpr(&yymsp[0].minor.yy190,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 154: /* expr ::= nm DOT nm */ + case 152: /* expr ::= nm DOT nm */ { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); @@ -138303,7 +139798,7 @@ static void yy_reduce( yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } break; - case 155: /* expr ::= nm DOT nm DOT nm */ + case 153: /* expr ::= nm DOT nm DOT nm */ { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); @@ -138313,16 +139808,19 @@ static void yy_reduce( yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); } break; - case 158: /* term ::= INTEGER */ + case 154: /* term ::= NULL|FLOAT|BLOB */ + case 155: /* term ::= STRING */ yytestcase(yyruleno==155); +{spanExpr(&yymsp[0].minor.yy190,pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 156: /* term ::= INTEGER */ { yylhsminor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); yylhsminor.yy190.zStart = yymsp[0].minor.yy0.z; yylhsminor.yy190.zEnd = yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n; - if( yylhsminor.yy190.pExpr ) yylhsminor.yy190.pExpr->flags |= EP_Leaf|EP_Resolved; } yymsp[0].minor.yy190 = yylhsminor.yy190; break; - case 159: /* expr ::= VARIABLE */ + case 157: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; @@ -138345,20 +139843,20 @@ static void yy_reduce( } } break; - case 160: /* expr ::= expr COLLATE ID|STRING */ + case 158: /* expr ::= expr COLLATE ID|STRING */ { yymsp[-2].minor.yy190.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy190.pExpr, &yymsp[0].minor.yy0, 1); yymsp[-2].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; - case 161: /* expr ::= CAST LP expr AS typetoken RP */ + case 159: /* expr ::= CAST LP expr AS typetoken RP */ { spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ yymsp[-5].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, 0); } break; - case 162: /* expr ::= ID|INDEXED LP distinct exprlist RP */ + case 160: /* expr ::= ID|INDEXED LP distinct exprlist RP */ { if( yymsp[-1].minor.yy148 && yymsp[-1].minor.yy148->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); @@ -138371,21 +139869,21 @@ static void yy_reduce( } yymsp[-4].minor.yy190 = yylhsminor.yy190; break; - case 163: /* expr ::= ID|INDEXED LP STAR RP */ + case 161: /* expr ::= ID|INDEXED LP STAR RP */ { yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); spanSet(&yylhsminor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); } yymsp[-3].minor.yy190 = yylhsminor.yy190; break; - case 164: /* term ::= CTIME_KW */ + case 162: /* term ::= CTIME_KW */ { yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0); spanSet(&yylhsminor.yy190, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); } yymsp[0].minor.yy190 = yylhsminor.yy190; break; - case 165: /* expr ::= LP nexprlist COMMA expr RP */ + case 163: /* expr ::= LP nexprlist COMMA expr RP */ { ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy148, yymsp[-1].minor.yy190.pExpr); yylhsminor.yy190.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); @@ -138398,20 +139896,20 @@ static void yy_reduce( } yymsp[-4].minor.yy190 = yylhsminor.yy190; break; - case 166: /* expr ::= expr AND expr */ - case 167: /* expr ::= expr OR expr */ yytestcase(yyruleno==167); - case 168: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==168); - case 169: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==169); - case 170: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==170); - case 171: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==171); - case 172: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==172); - case 173: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==173); + case 164: /* expr ::= expr AND expr */ + case 165: /* expr ::= expr OR expr */ yytestcase(yyruleno==165); + case 166: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==166); + case 167: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==167); + case 168: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==168); + case 169: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==169); + case 170: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==170); + case 171: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==171); {spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190);} break; - case 174: /* likeop ::= NOT LIKE_KW|MATCH */ + case 172: /* likeop ::= NOT LIKE_KW|MATCH */ {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} break; - case 175: /* expr ::= expr likeop expr */ + case 173: /* expr ::= expr likeop expr */ { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; @@ -138424,7 +139922,7 @@ static void yy_reduce( if( yymsp[-2].minor.yy190.pExpr ) yymsp[-2].minor.yy190.pExpr->flags |= EP_InfixFunc; } break; - case 176: /* expr ::= expr likeop expr ESCAPE expr */ + case 174: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; @@ -138438,39 +139936,39 @@ static void yy_reduce( if( yymsp[-4].minor.yy190.pExpr ) yymsp[-4].minor.yy190.pExpr->flags |= EP_InfixFunc; } break; - case 177: /* expr ::= expr ISNULL|NOTNULL */ + case 175: /* expr ::= expr ISNULL|NOTNULL */ {spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy190,&yymsp[0].minor.yy0);} break; - case 178: /* expr ::= expr NOT NULL */ + case 176: /* expr ::= expr NOT NULL */ {spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy0);} break; - case 179: /* expr ::= expr IS expr */ + case 177: /* expr ::= expr IS expr */ { spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-2].minor.yy190.pExpr, TK_ISNULL); } break; - case 180: /* expr ::= expr IS NOT expr */ + case 178: /* expr ::= expr IS NOT expr */ { spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy190,&yymsp[0].minor.yy190); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, TK_NOTNULL); } break; - case 181: /* expr ::= NOT expr */ - case 182: /* expr ::= BITNOT expr */ yytestcase(yyruleno==182); + case 179: /* expr ::= NOT expr */ + case 180: /* expr ::= BITNOT expr */ yytestcase(yyruleno==180); {spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,yymsp[-1].major,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} break; - case 183: /* expr ::= MINUS expr */ + case 181: /* expr ::= MINUS expr */ {spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UMINUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} break; - case 184: /* expr ::= PLUS expr */ + case 182: /* expr ::= PLUS expr */ {spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UPLUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} break; - case 185: /* between_op ::= BETWEEN */ - case 188: /* in_op ::= IN */ yytestcase(yyruleno==188); + case 183: /* between_op ::= BETWEEN */ + case 186: /* in_op ::= IN */ yytestcase(yyruleno==186); {yymsp[0].minor.yy194 = 0;} break; - case 187: /* expr ::= expr between_op expr AND expr */ + case 185: /* expr ::= expr between_op expr AND expr */ { ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); @@ -138484,7 +139982,7 @@ static void yy_reduce( yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; } break; - case 190: /* expr ::= expr in_op LP exprlist RP */ + case 188: /* expr ::= expr in_op LP exprlist RP */ { if( yymsp[-1].minor.yy148==0 ){ /* Expressions of the form @@ -138537,14 +140035,14 @@ static void yy_reduce( yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; - case 191: /* expr ::= LP select RP */ + case 189: /* expr ::= LP select RP */ { spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0); sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy190.pExpr, yymsp[-1].minor.yy243); } break; - case 192: /* expr ::= expr in_op LP select RP */ + case 190: /* expr ::= expr in_op LP select RP */ { yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0); sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, yymsp[-1].minor.yy243); @@ -138552,7 +140050,7 @@ static void yy_reduce( yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; - case 193: /* expr ::= expr in_op nm dbnm paren_exprlist */ + case 191: /* expr ::= expr in_op nm dbnm paren_exprlist */ { SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); @@ -138563,7 +140061,7 @@ static void yy_reduce( yymsp[-4].minor.yy190.zEnd = yymsp[-1].minor.yy0.z ? &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n] : &yymsp[-2].minor.yy0.z[yymsp[-2].minor.yy0.n]; } break; - case 194: /* expr ::= EXISTS LP select RP */ + case 192: /* expr ::= EXISTS LP select RP */ { Expr *p; spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ @@ -138571,7 +140069,7 @@ static void yy_reduce( sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy243); } break; - case 195: /* expr ::= CASE case_operand case_exprlist case_else END */ + case 193: /* expr ::= CASE case_operand case_exprlist case_else END */ { spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/ yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy72, 0); @@ -138584,80 +140082,80 @@ static void yy_reduce( } } break; - case 196: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 194: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[-2].minor.yy190.pExpr); yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); } break; - case 197: /* case_exprlist ::= WHEN expr THEN expr */ + case 195: /* case_exprlist ::= WHEN expr THEN expr */ { yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, yymsp[0].minor.yy190.pExpr); } break; - case 200: /* case_operand ::= expr */ + case 198: /* case_operand ::= expr */ {yymsp[0].minor.yy72 = yymsp[0].minor.yy190.pExpr; /*A-overwrites-X*/} break; - case 203: /* nexprlist ::= nexprlist COMMA expr */ + case 201: /* nexprlist ::= nexprlist COMMA expr */ {yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[0].minor.yy190.pExpr);} break; - case 204: /* nexprlist ::= expr */ + case 202: /* nexprlist ::= expr */ {yymsp[0].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy190.pExpr); /*A-overwrites-Y*/} break; - case 206: /* paren_exprlist ::= LP exprlist RP */ - case 211: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==211); + case 204: /* paren_exprlist ::= LP exprlist RP */ + case 209: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==209); {yymsp[-2].minor.yy148 = yymsp[-1].minor.yy148;} break; - case 207: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 205: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy148, yymsp[-10].minor.yy194, &yymsp[-11].minor.yy0, yymsp[0].minor.yy72, SQLITE_SO_ASC, yymsp[-8].minor.yy194, SQLITE_IDXTYPE_APPDEF); } break; - case 208: /* uniqueflag ::= UNIQUE */ - case 249: /* raisetype ::= ABORT */ yytestcase(yyruleno==249); + case 206: /* uniqueflag ::= UNIQUE */ + case 246: /* raisetype ::= ABORT */ yytestcase(yyruleno==246); {yymsp[0].minor.yy194 = OE_Abort;} break; - case 209: /* uniqueflag ::= */ + case 207: /* uniqueflag ::= */ {yymsp[1].minor.yy194 = OE_None;} break; - case 212: /* eidlist ::= eidlist COMMA nm collate sortorder */ + case 210: /* eidlist ::= eidlist COMMA nm collate sortorder */ { yymsp[-4].minor.yy148 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); } break; - case 213: /* eidlist ::= nm collate sortorder */ + case 211: /* eidlist ::= nm collate sortorder */ { yymsp[-2].minor.yy148 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); /*A-overwrites-Y*/ } break; - case 216: /* cmd ::= DROP INDEX ifexists fullname */ + case 214: /* cmd ::= DROP INDEX ifexists fullname */ {sqlite3DropIndex(pParse, yymsp[0].minor.yy185, yymsp[-1].minor.yy194);} break; - case 217: /* cmd ::= VACUUM */ + case 215: /* cmd ::= VACUUM */ {sqlite3Vacuum(pParse,0);} break; - case 218: /* cmd ::= VACUUM nm */ + case 216: /* cmd ::= VACUUM nm */ {sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);} break; - case 219: /* cmd ::= PRAGMA nm dbnm */ + case 217: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 220: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 218: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 221: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 219: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 222: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 220: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 223: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 221: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; - case 226: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 224: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; @@ -138665,53 +140163,50 @@ static void yy_reduce( sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy145, &all); } break; - case 227: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 225: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy194, yymsp[-4].minor.yy332.a, yymsp[-4].minor.yy332.b, yymsp[-2].minor.yy185, yymsp[0].minor.yy72, yymsp[-10].minor.yy194, yymsp[-8].minor.yy194); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 228: /* trigger_time ::= BEFORE */ -{ yymsp[0].minor.yy194 = TK_BEFORE; } - break; - case 229: /* trigger_time ::= AFTER */ -{ yymsp[0].minor.yy194 = TK_AFTER; } + case 226: /* trigger_time ::= BEFORE|AFTER */ +{ yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-X*/ } break; - case 230: /* trigger_time ::= INSTEAD OF */ + case 227: /* trigger_time ::= INSTEAD OF */ { yymsp[-1].minor.yy194 = TK_INSTEAD;} break; - case 231: /* trigger_time ::= */ + case 228: /* trigger_time ::= */ { yymsp[1].minor.yy194 = TK_BEFORE; } break; - case 232: /* trigger_event ::= DELETE|INSERT */ - case 233: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==233); + case 229: /* trigger_event ::= DELETE|INSERT */ + case 230: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==230); {yymsp[0].minor.yy332.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy332.b = 0;} break; - case 234: /* trigger_event ::= UPDATE OF idlist */ + case 231: /* trigger_event ::= UPDATE OF idlist */ {yymsp[-2].minor.yy332.a = TK_UPDATE; yymsp[-2].minor.yy332.b = yymsp[0].minor.yy254;} break; - case 235: /* when_clause ::= */ - case 254: /* key_opt ::= */ yytestcase(yyruleno==254); + case 232: /* when_clause ::= */ + case 251: /* key_opt ::= */ yytestcase(yyruleno==251); { yymsp[1].minor.yy72 = 0; } break; - case 236: /* when_clause ::= WHEN expr */ - case 255: /* key_opt ::= KEY expr */ yytestcase(yyruleno==255); + case 233: /* when_clause ::= WHEN expr */ + case 252: /* key_opt ::= KEY expr */ yytestcase(yyruleno==252); { yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr; } break; - case 237: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 234: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { assert( yymsp[-2].minor.yy145!=0 ); yymsp[-2].minor.yy145->pLast->pNext = yymsp[-1].minor.yy145; yymsp[-2].minor.yy145->pLast = yymsp[-1].minor.yy145; } break; - case 238: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 235: /* trigger_cmd_list ::= trigger_cmd SEMI */ { assert( yymsp[-1].minor.yy145!=0 ); yymsp[-1].minor.yy145->pLast = yymsp[-1].minor.yy145; } break; - case 239: /* trnm ::= nm DOT nm */ + case 236: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, @@ -138719,33 +140214,33 @@ static void yy_reduce( "statements within triggers"); } break; - case 240: /* tridxby ::= INDEXED BY nm */ + case 237: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 241: /* tridxby ::= NOT INDEXED */ + case 238: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 242: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */ + case 239: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */ {yymsp[-6].minor.yy145 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy148, yymsp[0].minor.yy72, yymsp[-5].minor.yy194);} break; - case 243: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */ + case 240: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */ {yymsp[-4].minor.yy145 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy254, yymsp[0].minor.yy243, yymsp[-4].minor.yy194);/*A-overwrites-R*/} break; - case 244: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */ + case 241: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */ {yymsp[-4].minor.yy145 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy72);} break; - case 245: /* trigger_cmd ::= select */ + case 242: /* trigger_cmd ::= select */ {yymsp[0].minor.yy145 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy243); /*A-overwrites-X*/} break; - case 246: /* expr ::= RAISE LP IGNORE RP */ + case 243: /* expr ::= RAISE LP IGNORE RP */ { spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0); @@ -138754,7 +140249,7 @@ static void yy_reduce( } } break; - case 247: /* expr ::= RAISE LP raisetype COMMA nm RP */ + case 244: /* expr ::= RAISE LP raisetype COMMA nm RP */ { spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ yymsp[-5].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); @@ -138763,172 +140258,176 @@ static void yy_reduce( } } break; - case 248: /* raisetype ::= ROLLBACK */ + case 245: /* raisetype ::= ROLLBACK */ {yymsp[0].minor.yy194 = OE_Rollback;} break; - case 250: /* raisetype ::= FAIL */ + case 247: /* raisetype ::= FAIL */ {yymsp[0].minor.yy194 = OE_Fail;} break; - case 251: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 248: /* cmd ::= DROP TRIGGER ifexists fullname */ { sqlite3DropTrigger(pParse,yymsp[0].minor.yy185,yymsp[-1].minor.yy194); } break; - case 252: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 249: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { sqlite3Attach(pParse, yymsp[-3].minor.yy190.pExpr, yymsp[-1].minor.yy190.pExpr, yymsp[0].minor.yy72); } break; - case 253: /* cmd ::= DETACH database_kw_opt expr */ + case 250: /* cmd ::= DETACH database_kw_opt expr */ { sqlite3Detach(pParse, yymsp[0].minor.yy190.pExpr); } break; - case 256: /* cmd ::= REINDEX */ + case 253: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 257: /* cmd ::= REINDEX nm dbnm */ + case 254: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 258: /* cmd ::= ANALYZE */ + case 255: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 259: /* cmd ::= ANALYZE nm dbnm */ + case 256: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 260: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 257: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy185,&yymsp[0].minor.yy0); } break; - case 261: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 258: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 262: /* add_column_fullname ::= fullname */ + case 259: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy185); } break; - case 263: /* cmd ::= create_vtab */ + case 260: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 264: /* cmd ::= create_vtab LP vtabarglist RP */ + case 261: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 265: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 262: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy194); } break; - case 266: /* vtabarg ::= */ + case 263: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 267: /* vtabargtoken ::= ANY */ - case 268: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==268); - case 269: /* lp ::= LP */ yytestcase(yyruleno==269); + case 264: /* vtabargtoken ::= ANY */ + case 265: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==265); + case 266: /* lp ::= LP */ yytestcase(yyruleno==266); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 270: /* with ::= */ + case 267: /* with ::= */ {yymsp[1].minor.yy285 = 0;} break; - case 271: /* with ::= WITH wqlist */ + case 268: /* with ::= WITH wqlist */ { yymsp[-1].minor.yy285 = yymsp[0].minor.yy285; } break; - case 272: /* with ::= WITH RECURSIVE wqlist */ + case 269: /* with ::= WITH RECURSIVE wqlist */ { yymsp[-2].minor.yy285 = yymsp[0].minor.yy285; } break; - case 273: /* wqlist ::= nm eidlist_opt AS LP select RP */ + case 270: /* wqlist ::= nm eidlist_opt AS LP select RP */ { yymsp[-5].minor.yy285 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); /*A-overwrites-X*/ } break; - case 274: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ + case 271: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ { yymsp[-7].minor.yy285 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy285, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); } break; default: - /* (275) input ::= cmdlist */ yytestcase(yyruleno==275); - /* (276) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==276); - /* (277) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=277); - /* (278) ecmd ::= SEMI */ yytestcase(yyruleno==278); - /* (279) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==279); - /* (280) explain ::= */ yytestcase(yyruleno==280); - /* (281) trans_opt ::= */ yytestcase(yyruleno==281); - /* (282) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==282); - /* (283) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==283); - /* (284) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==284); - /* (285) savepoint_opt ::= */ yytestcase(yyruleno==285); - /* (286) cmd ::= create_table create_table_args */ yytestcase(yyruleno==286); - /* (287) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==287); - /* (288) columnlist ::= columnname carglist */ yytestcase(yyruleno==288); - /* (289) nm ::= ID|INDEXED */ yytestcase(yyruleno==289); - /* (290) nm ::= STRING */ yytestcase(yyruleno==290); - /* (291) nm ::= JOIN_KW */ yytestcase(yyruleno==291); - /* (292) typetoken ::= typename */ yytestcase(yyruleno==292); - /* (293) typename ::= ID|STRING */ yytestcase(yyruleno==293); - /* (294) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=294); - /* (295) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=295); - /* (296) carglist ::= carglist ccons */ yytestcase(yyruleno==296); - /* (297) carglist ::= */ yytestcase(yyruleno==297); - /* (298) ccons ::= NULL onconf */ yytestcase(yyruleno==298); - /* (299) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==299); - /* (300) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==300); - /* (301) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=301); - /* (302) tconscomma ::= */ yytestcase(yyruleno==302); - /* (303) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=303); - /* (304) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=304); - /* (305) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=305); - /* (306) oneselect ::= values */ yytestcase(yyruleno==306); - /* (307) sclp ::= selcollist COMMA */ yytestcase(yyruleno==307); - /* (308) as ::= ID|STRING */ yytestcase(yyruleno==308); - /* (309) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=309); - /* (310) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==310); - /* (311) exprlist ::= nexprlist */ yytestcase(yyruleno==311); - /* (312) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=312); - /* (313) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=313); - /* (314) nmnum ::= ON */ yytestcase(yyruleno==314); - /* (315) nmnum ::= DELETE */ yytestcase(yyruleno==315); - /* (316) nmnum ::= DEFAULT */ yytestcase(yyruleno==316); - /* (317) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==317); - /* (318) foreach_clause ::= */ yytestcase(yyruleno==318); - /* (319) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==319); - /* (320) trnm ::= nm */ yytestcase(yyruleno==320); - /* (321) tridxby ::= */ yytestcase(yyruleno==321); - /* (322) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==322); - /* (323) database_kw_opt ::= */ yytestcase(yyruleno==323); - /* (324) kwcolumn_opt ::= */ yytestcase(yyruleno==324); - /* (325) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==325); - /* (326) vtabarglist ::= vtabarg */ yytestcase(yyruleno==326); - /* (327) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==327); - /* (328) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==328); - /* (329) anylist ::= */ yytestcase(yyruleno==329); - /* (330) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==330); - /* (331) anylist ::= anylist ANY */ yytestcase(yyruleno==331); + /* (272) input ::= cmdlist */ yytestcase(yyruleno==272); + /* (273) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==273); + /* (274) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=274); + /* (275) ecmd ::= SEMI */ yytestcase(yyruleno==275); + /* (276) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==276); + /* (277) explain ::= */ yytestcase(yyruleno==277); + /* (278) trans_opt ::= */ yytestcase(yyruleno==278); + /* (279) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==279); + /* (280) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==280); + /* (281) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==281); + /* (282) savepoint_opt ::= */ yytestcase(yyruleno==282); + /* (283) cmd ::= create_table create_table_args */ yytestcase(yyruleno==283); + /* (284) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==284); + /* (285) columnlist ::= columnname carglist */ yytestcase(yyruleno==285); + /* (286) nm ::= ID|INDEXED */ yytestcase(yyruleno==286); + /* (287) nm ::= STRING */ yytestcase(yyruleno==287); + /* (288) nm ::= JOIN_KW */ yytestcase(yyruleno==288); + /* (289) typetoken ::= typename */ yytestcase(yyruleno==289); + /* (290) typename ::= ID|STRING */ yytestcase(yyruleno==290); + /* (291) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=291); + /* (292) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=292); + /* (293) carglist ::= carglist ccons */ yytestcase(yyruleno==293); + /* (294) carglist ::= */ yytestcase(yyruleno==294); + /* (295) ccons ::= NULL onconf */ yytestcase(yyruleno==295); + /* (296) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==296); + /* (297) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==297); + /* (298) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=298); + /* (299) tconscomma ::= */ yytestcase(yyruleno==299); + /* (300) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=300); + /* (301) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=301); + /* (302) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=302); + /* (303) oneselect ::= values */ yytestcase(yyruleno==303); + /* (304) sclp ::= selcollist COMMA */ yytestcase(yyruleno==304); + /* (305) as ::= ID|STRING */ yytestcase(yyruleno==305); + /* (306) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=306); + /* (307) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==307); + /* (308) exprlist ::= nexprlist */ yytestcase(yyruleno==308); + /* (309) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=309); + /* (310) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=310); + /* (311) nmnum ::= ON */ yytestcase(yyruleno==311); + /* (312) nmnum ::= DELETE */ yytestcase(yyruleno==312); + /* (313) nmnum ::= DEFAULT */ yytestcase(yyruleno==313); + /* (314) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==314); + /* (315) foreach_clause ::= */ yytestcase(yyruleno==315); + /* (316) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==316); + /* (317) trnm ::= nm */ yytestcase(yyruleno==317); + /* (318) tridxby ::= */ yytestcase(yyruleno==318); + /* (319) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==319); + /* (320) database_kw_opt ::= */ yytestcase(yyruleno==320); + /* (321) kwcolumn_opt ::= */ yytestcase(yyruleno==321); + /* (322) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==322); + /* (323) vtabarglist ::= vtabarg */ yytestcase(yyruleno==323); + /* (324) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==324); + /* (325) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==325); + /* (326) anylist ::= */ yytestcase(yyruleno==326); + /* (327) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==327); + /* (328) anylist ::= anylist ANY */ yytestcase(yyruleno==328); break; /********** End reduce actions ************************************************/ }; assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) ); yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; - yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); - if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yyact>YY_MAX_SHIFT ){ - yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - } - yymsp -= yysize-1; + yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto); + + /* There are no SHIFTREDUCE actions on nonterminals because the table + ** generator has simplified them to pure REDUCE actions. */ + assert( !(yyact>YY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) ); + + /* It is not possible for a REDUCE to be followed by an error */ + assert( yyact!=YY_ERROR_ACTION ); + + if( yyact==YY_ACCEPT_ACTION ){ + yypParser->yytos += yysize; + yy_accept(yypParser); + }else{ + yymsp += yysize+1; yypParser->yytos = yymsp; yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yyTraceShift(yypParser, yyact); - }else{ - assert( yyact == YY_ACCEPT_ACTION ); - yypParser->yytos -= yysize; - yy_accept(yypParser); } } @@ -139334,134 +140833,145 @@ const unsigned char ebcdicToAscii[] = { ** on platforms with limited memory. */ /* Hash score: 182 */ +/* zKWText[] encodes 834 bytes of keyword text in 554 bytes */ +/* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ +/* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */ +/* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */ +/* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE */ +/* BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ +/* IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN */ +/* WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT */ +/* CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL */ +/* FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING */ +/* VACUUMVIEWINITIALLY */ +static const char zKWText[553] = { + 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', + 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', + 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', + 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', + 'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N', + 'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I', + 'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E', + 'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E', + 'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T', + 'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q', + 'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S', + 'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A', + 'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E', + 'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A', + 'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A', + 'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A', + 'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J', + 'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L', + 'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E', + 'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H', + 'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E', + 'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E', + 'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M', + 'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R', + 'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A', + 'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D', + 'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O', + 'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T', + 'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R', + 'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M', + 'V','I','E','W','I','N','I','T','I','A','L','L','Y', +}; +/* aKWHash[i] is the hash value for the i-th keyword */ +static const unsigned char aKWHash[127] = { + 76, 105, 117, 74, 0, 45, 0, 0, 82, 0, 77, 0, 0, + 42, 12, 78, 15, 0, 116, 85, 54, 112, 0, 19, 0, 0, + 121, 0, 119, 115, 0, 22, 93, 0, 9, 0, 0, 70, 71, + 0, 69, 6, 0, 48, 90, 102, 0, 118, 101, 0, 0, 44, + 0, 103, 24, 0, 17, 0, 122, 53, 23, 0, 5, 110, 25, + 96, 0, 0, 124, 106, 60, 123, 57, 28, 55, 0, 91, 0, + 100, 26, 0, 99, 0, 0, 0, 95, 92, 97, 88, 109, 14, + 39, 108, 0, 81, 0, 18, 89, 111, 32, 0, 120, 80, 113, + 62, 46, 84, 0, 0, 94, 40, 59, 114, 0, 36, 0, 0, + 29, 0, 86, 63, 64, 0, 20, 61, 0, 56, +}; +/* aKWNext[] forms the hash collision chain. If aKWHash[i]==0 +** then the i-th keyword has no more hash collisions. Otherwise, +** the next keyword with the same hash is aKWHash[i]-1. */ +static const unsigned char aKWNext[124] = { + 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, + 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 0, 21, 0, 0, 0, 0, 0, 50, + 0, 43, 3, 47, 0, 0, 0, 0, 30, 0, 58, 0, 38, + 0, 0, 0, 1, 66, 0, 0, 67, 0, 41, 0, 0, 0, + 0, 0, 0, 49, 65, 0, 0, 0, 0, 31, 52, 16, 34, + 10, 0, 0, 0, 0, 0, 0, 0, 11, 72, 79, 0, 8, + 0, 104, 98, 0, 107, 0, 87, 0, 75, 51, 0, 27, 37, + 73, 83, 0, 35, 68, 0, 0, +}; +/* aKWLen[i] is the length (in bytes) of the i-th keyword */ +static const unsigned char aKWLen[124] = { + 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, + 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6, + 11, 6, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10, + 4, 6, 2, 3, 9, 4, 2, 6, 5, 7, 4, 5, 7, + 6, 6, 5, 6, 5, 5, 9, 7, 7, 3, 2, 4, 4, + 7, 3, 6, 4, 7, 6, 12, 6, 9, 4, 6, 5, 4, + 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7, + 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8, + 2, 4, 4, 4, 4, 4, 2, 2, 6, 5, 8, 5, 8, + 3, 5, 5, 6, 4, 9, 3, +}; +/* aKWOffset[i] is the index into zKWText[] of the start of +** the text for the i-th keyword. */ +static const unsigned short int aKWOffset[124] = { + 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, + 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, + 86, 91, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152, + 159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192, + 199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246, + 250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318, + 320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380, + 387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459, + 460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513, + 521, 524, 529, 534, 540, 544, 549, +}; +/* aKWCode[i] is the parser symbol code for the i-th keyword */ +static const unsigned char aKWCode[124] = { + TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, + TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, + TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, + TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, + TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, + TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, + TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_SAVEPOINT, + TK_INTERSECT, TK_TRIGGER, TK_REFERENCES, TK_CONSTRAINT, TK_INTO, + TK_OFFSET, TK_OF, TK_SET, TK_TEMP, TK_TEMP, + TK_OR, TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, + TK_JOIN_KW, TK_RELEASE, TK_ATTACH, TK_HAVING, TK_GROUP, + TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RECURSIVE, TK_BETWEEN, + TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, + TK_CASCADE, TK_ASC, TK_DELETE, TK_CASE, TK_COLLATE, + TK_CREATE, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE, TK_JOIN, + TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, + TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, + TK_WHERE, TK_RENAME, TK_AFTER, TK_REPLACE, TK_AND, + TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, + TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, + TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED, TK_DISTINCT, TK_IS, + TK_DROP, TK_FAIL, TK_FROM, TK_JOIN_KW, TK_LIKE_KW, + TK_BY, TK_IF, TK_ISNULL, TK_ORDER, TK_RESTRICT, + TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING, + TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL, +}; +/* Check to see if z[0..n-1] is a keyword. If it is, write the +** parser symbol code for that keyword into *pType. Always +** return the integer n (the length of the token). */ static int keywordCode(const char *z, int n, int *pType){ - /* zText[] encodes 834 bytes of keywords in 554 bytes */ - /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ - /* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */ - /* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */ - /* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE */ - /* BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ - /* IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN */ - /* WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT */ - /* CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL */ - /* FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING */ - /* VACUUMVIEWINITIALLY */ - static const char zText[553] = { - 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', - 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', - 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', - 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', - 'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N', - 'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I', - 'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E', - 'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E', - 'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T', - 'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q', - 'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S', - 'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A', - 'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E', - 'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A', - 'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A', - 'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A', - 'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J', - 'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L', - 'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E', - 'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H', - 'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E', - 'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E', - 'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M', - 'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R', - 'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A', - 'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D', - 'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O', - 'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T', - 'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R', - 'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M', - 'V','I','E','W','I','N','I','T','I','A','L','L','Y', - }; - static const unsigned char aHash[127] = { - 76, 105, 117, 74, 0, 45, 0, 0, 82, 0, 77, 0, 0, - 42, 12, 78, 15, 0, 116, 85, 54, 112, 0, 19, 0, 0, - 121, 0, 119, 115, 0, 22, 93, 0, 9, 0, 0, 70, 71, - 0, 69, 6, 0, 48, 90, 102, 0, 118, 101, 0, 0, 44, - 0, 103, 24, 0, 17, 0, 122, 53, 23, 0, 5, 110, 25, - 96, 0, 0, 124, 106, 60, 123, 57, 28, 55, 0, 91, 0, - 100, 26, 0, 99, 0, 0, 0, 95, 92, 97, 88, 109, 14, - 39, 108, 0, 81, 0, 18, 89, 111, 32, 0, 120, 80, 113, - 62, 46, 84, 0, 0, 94, 40, 59, 114, 0, 36, 0, 0, - 29, 0, 86, 63, 64, 0, 20, 61, 0, 56, - }; - static const unsigned char aNext[124] = { - 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, - 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 33, 0, 21, 0, 0, 0, 0, 0, 50, - 0, 43, 3, 47, 0, 0, 0, 0, 30, 0, 58, 0, 38, - 0, 0, 0, 1, 66, 0, 0, 67, 0, 41, 0, 0, 0, - 0, 0, 0, 49, 65, 0, 0, 0, 0, 31, 52, 16, 34, - 10, 0, 0, 0, 0, 0, 0, 0, 11, 72, 79, 0, 8, - 0, 104, 98, 0, 107, 0, 87, 0, 75, 51, 0, 27, 37, - 73, 83, 0, 35, 68, 0, 0, - }; - static const unsigned char aLen[124] = { - 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, - 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6, - 11, 6, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10, - 4, 6, 2, 3, 9, 4, 2, 6, 5, 7, 4, 5, 7, - 6, 6, 5, 6, 5, 5, 9, 7, 7, 3, 2, 4, 4, - 7, 3, 6, 4, 7, 6, 12, 6, 9, 4, 6, 5, 4, - 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7, - 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8, - 2, 4, 4, 4, 4, 4, 2, 2, 6, 5, 8, 5, 8, - 3, 5, 5, 6, 4, 9, 3, - }; - static const unsigned short int aOffset[124] = { - 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, - 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, - 86, 91, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152, - 159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192, - 199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246, - 250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318, - 320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380, - 387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459, - 460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513, - 521, 524, 529, 534, 540, 544, 549, - }; - static const unsigned char aCode[124] = { - TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, - TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, - TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, - TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, - TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, - TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, - TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_SAVEPOINT, - TK_INTERSECT, TK_TRIGGER, TK_REFERENCES, TK_CONSTRAINT, TK_INTO, - TK_OFFSET, TK_OF, TK_SET, TK_TEMP, TK_TEMP, - TK_OR, TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, - TK_JOIN_KW, TK_RELEASE, TK_ATTACH, TK_HAVING, TK_GROUP, - TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RECURSIVE, TK_BETWEEN, - TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, - TK_CASCADE, TK_ASC, TK_DELETE, TK_CASE, TK_COLLATE, - TK_CREATE, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE, TK_JOIN, - TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, - TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, - TK_WHERE, TK_RENAME, TK_AFTER, TK_REPLACE, TK_AND, - TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, - TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, - TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED, TK_DISTINCT, TK_IS, - TK_DROP, TK_FAIL, TK_FROM, TK_JOIN_KW, TK_LIKE_KW, - TK_BY, TK_IF, TK_ISNULL, TK_ORDER, TK_RESTRICT, - TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING, - TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL, - }; int i, j; const char *zKW; if( n>=2 ){ i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127; - for(i=((int)aHash[i])-1; i>=0; i=((int)aNext[i])-1){ - if( aLen[i]!=n ) continue; + for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){ + if( aKWLen[i]!=n ) continue; j = 0; - zKW = &zText[aOffset[i]]; + zKW = &zKWText[aKWOffset[i]]; #ifdef SQLITE_ASCII while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; } #endif @@ -139593,7 +141103,7 @@ static int keywordCode(const char *z, int n, int *pType){ testcase( i==121 ); /* VIEW */ testcase( i==122 ); /* INITIALLY */ testcase( i==123 ); /* ALL */ - *pType = aCode[i]; + *pType = aKWCode[i]; break; } } @@ -140496,6 +142006,9 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db); #ifdef SQLITE_ENABLE_JSON1 SQLITE_PRIVATE int sqlite3Json1Init(sqlite3*); #endif +#ifdef SQLITE_ENABLE_STMTVTAB +SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*); +#endif #ifdef SQLITE_ENABLE_FTS5 SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*); #endif @@ -140512,11 +142025,13 @@ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; */ SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; } -/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a +/* IMPLEMENTATION-OF: R-25063-23286 The sqlite3_sourceid() function returns a ** pointer to a string constant whose value is the same as the -** SQLITE_SOURCE_ID C preprocessor macro. +** SQLITE_SOURCE_ID C preprocessor macro. Except if SQLite is built using +** an edited copy of the amalgamation, then the last four characters of +** the hash might be different from SQLITE_SOURCE_ID. */ -SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } +/* SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } */ /* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function ** returns an integer equal to SQLITE_VERSION_NUMBER. @@ -140901,14 +142416,8 @@ SQLITE_API int sqlite3_config(int op, ...){ sqlite3GlobalConfig.bMemstat = va_arg(ap, int); break; } - case SQLITE_CONFIG_SCRATCH: { - /* EVIDENCE-OF: R-08404-60887 There are three arguments to - ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from - ** which the scratch allocations will be drawn, the size of each scratch - ** allocation (sz), and the maximum number of scratch allocations (N). */ - sqlite3GlobalConfig.pScratch = va_arg(ap, void*); - sqlite3GlobalConfig.szScratch = va_arg(ap, int); - sqlite3GlobalConfig.nScratch = va_arg(ap, int); + case SQLITE_CONFIG_SMALL_MALLOC: { + sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int); break; } case SQLITE_CONFIG_PAGECACHE: { @@ -141129,7 +142638,8 @@ SQLITE_API int sqlite3_config(int op, ...){ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ #ifndef SQLITE_OMIT_LOOKASIDE void *pStart; - if( db->lookaside.nOut ){ + + if( sqlite3LookasideUsed(db,0)>0 ){ return SQLITE_BUSY; } /* Free any existing lookaside buffer for this handle before @@ -141157,16 +142667,18 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ pStart = pBuf; } db->lookaside.pStart = pStart; + db->lookaside.pInit = 0; db->lookaside.pFree = 0; db->lookaside.sz = (u16)sz; if( pStart ){ int i; LookasideSlot *p; assert( sz > (int)sizeof(LookasideSlot*) ); + db->lookaside.nSlot = cnt; p = (LookasideSlot*)pStart; for(i=cnt-1; i>=0; i--){ - p->pNext = db->lookaside.pFree; - db->lookaside.pFree = p; + p->pNext = db->lookaside.pInit; + db->lookaside.pInit = p; p = (LookasideSlot*)&((u8*)p)[sz]; } db->lookaside.pEnd = p; @@ -141177,6 +142689,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ db->lookaside.pEnd = db; db->lookaside.bDisable = 1; db->lookaside.bMalloced = 0; + db->lookaside.nSlot = 0; } #endif /* SQLITE_OMIT_LOOKASIDE */ return SQLITE_OK; @@ -141258,6 +142771,8 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ va_start(ap, op); switch( op ){ case SQLITE_DBCONFIG_MAINDBNAME: { + /* IMP: R-06824-28531 */ + /* IMP: R-36257-52125 */ db->aDb[0].zDbSName = va_arg(ap,char*); rc = SQLITE_OK; break; @@ -141279,6 +142794,7 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer }, { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension }, { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, + { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ @@ -141286,7 +142802,7 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ if( aFlagOp[i].op==op ){ int onoff = va_arg(ap, int); int *pRes = va_arg(ap, int*); - int oldFlags = db->flags; + u32 oldFlags = db->flags; if( onoff>0 ){ db->flags |= aFlagOp[i].mask; }else if( onoff==0 ){ @@ -141335,6 +142851,7 @@ static int binCollFunc( /* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares ** strings byte by byte using the memcmp() function from the standard C ** library. */ + assert( pKey1 && pKey2 ); rc = memcmp(pKey1, pKey2, n); if( rc==0 ){ if( padFlag @@ -141692,7 +143209,7 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ sqlite3_mutex_leave(db->mutex); db->magic = SQLITE_MAGIC_CLOSED; sqlite3_mutex_free(db->mutex); - assert( db->lookaside.nOut==0 ); /* Fails on a lookaside memory leak */ + assert( sqlite3LookasideUsed(db,0)==0 ); if( db->lookaside.bMalloced ){ sqlite3_free(db->lookaside.pStart); } @@ -141720,7 +143237,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ ** the database rollback and schema reset, which can cause false ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); - schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0; + schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0; for(i=0; i<db->nDb; i++){ Btree *p = db->aDb[i].pBt; @@ -141734,7 +143251,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); - if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){ + if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); } @@ -141867,10 +143384,10 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ static const char* const aMsg[] = { /* SQLITE_OK */ "not an error", - /* SQLITE_ERROR */ "SQL logic error or missing database", + /* SQLITE_ERROR */ "SQL logic error", /* SQLITE_INTERNAL */ 0, /* SQLITE_PERM */ "access permission denied", - /* SQLITE_ABORT */ "callback requested query abort", + /* SQLITE_ABORT */ "query aborted", /* SQLITE_BUSY */ "database is locked", /* SQLITE_LOCKED */ "database table is locked", /* SQLITE_NOMEM */ "out of memory", @@ -141882,17 +143399,21 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ /* SQLITE_FULL */ "database or disk is full", /* SQLITE_CANTOPEN */ "unable to open database file", /* SQLITE_PROTOCOL */ "locking protocol", - /* SQLITE_EMPTY */ "table contains no data", + /* SQLITE_EMPTY */ 0, /* SQLITE_SCHEMA */ "database schema has changed", /* SQLITE_TOOBIG */ "string or blob too big", /* SQLITE_CONSTRAINT */ "constraint failed", /* SQLITE_MISMATCH */ "datatype mismatch", - /* SQLITE_MISUSE */ "library routine called out of sequence", + /* SQLITE_MISUSE */ "bad parameter or other API misuse", +#ifdef SQLITE_DISABLE_LFS /* SQLITE_NOLFS */ "large file support is disabled", +#else + /* SQLITE_NOLFS */ 0, +#endif /* SQLITE_AUTH */ "authorization denied", - /* SQLITE_FORMAT */ "auxiliary database format error", - /* SQLITE_RANGE */ "bind or column index out of range", - /* SQLITE_NOTADB */ "file is encrypted or is not a database", + /* SQLITE_FORMAT */ 0, + /* SQLITE_RANGE */ "column index out of range", + /* SQLITE_NOTADB */ "file is not a database", }; const char *zErr = "unknown error"; switch( rc ){ @@ -142632,7 +144153,8 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ ** checkpointed. If an error is encountered it is returned immediately - ** no attempt is made to checkpoint any remaining databases. ** -** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. +** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART +** or TRUNCATE. */ SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; /* Return code */ @@ -142732,12 +144254,9 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){ 'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0 }; static const u16 misuse[] = { - 'l', 'i', 'b', 'r', 'a', 'r', 'y', ' ', - 'r', 'o', 'u', 't', 'i', 'n', 'e', ' ', - 'c', 'a', 'l', 'l', 'e', 'd', ' ', - 'o', 'u', 't', ' ', - 'o', 'f', ' ', - 's', 'e', 'q', 'u', 'e', 'n', 'c', 'e', 0 + 'b', 'a', 'd', ' ', 'p', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', ' ', + 'o', 'r', ' ', 'o', 't', 'h', 'e', 'r', ' ', 'A', 'P', 'I', ' ', + 'm', 'i', 's', 'u', 's', 'e', 0 }; const void *z; @@ -143272,26 +144791,6 @@ static int openDatabase( if( rc ) return rc; #endif - /* Only allow sensible combinations of bits in the flags argument. - ** Throw an error if any non-sense combination is used. If we - ** do not block illegal combinations here, it could trigger - ** assert() statements in deeper layers. Sensible combinations - ** are: - ** - ** 1: SQLITE_OPEN_READONLY - ** 2: SQLITE_OPEN_READWRITE - ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE - */ - assert( SQLITE_OPEN_READONLY == 0x01 ); - assert( SQLITE_OPEN_READWRITE == 0x02 ); - assert( SQLITE_OPEN_CREATE == 0x04 ); - testcase( (1<<(flags&7))==0x02 ); /* READONLY */ - testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ - testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ - if( ((1<<(flags&7)) & 0x46)==0 ){ - return SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */ - } - if( sqlite3GlobalConfig.bCoreMutex==0 ){ isThreadsafe = 0; }else if( flags & SQLITE_OPEN_NOMUTEX ){ @@ -143383,6 +144882,9 @@ static int openDatabase( #if defined(SQLITE_ENABLE_FTS3_TOKENIZER) | SQLITE_Fts3Tokenizer #endif +#if defined(SQLITE_ENABLE_QPSG) + | SQLITE_EnableQPSG +#endif ; sqlite3HashInit(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -143410,9 +144912,30 @@ static int openDatabase( db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0); assert( db->pDfltColl!=0 ); - /* Parse the filename/URI argument. */ + /* Parse the filename/URI argument + ** + ** Only allow sensible combinations of bits in the flags argument. + ** Throw an error if any non-sense combination is used. If we + ** do not block illegal combinations here, it could trigger + ** assert() statements in deeper layers. Sensible combinations + ** are: + ** + ** 1: SQLITE_OPEN_READONLY + ** 2: SQLITE_OPEN_READWRITE + ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE + */ db->openFlags = flags; - rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); + assert( SQLITE_OPEN_READONLY == 0x01 ); + assert( SQLITE_OPEN_READWRITE == 0x02 ); + assert( SQLITE_OPEN_CREATE == 0x04 ); + testcase( (1<<(flags&7))==0x02 ); /* READONLY */ + testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ + testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ + if( ((1<<(flags&7)) & 0x46)==0 ){ + rc = SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */ + }else{ + rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); + } if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg); @@ -143509,6 +145032,12 @@ static int openDatabase( } #endif +#ifdef SQLITE_ENABLE_DBPAGE_VTAB + if( !db->mallocFailed && rc==SQLITE_OK){ + rc = sqlite3DbpageRegister(db); + } +#endif + #ifdef SQLITE_ENABLE_DBSTAT_VTAB if( !db->mallocFailed && rc==SQLITE_OK){ rc = sqlite3DbstatRegister(db); @@ -143521,6 +145050,12 @@ static int openDatabase( } #endif +#ifdef SQLITE_ENABLE_STMTVTAB + if( !db->mallocFailed && rc==SQLITE_OK){ + rc = sqlite3StmtVtabInit(db); + } +#endif + /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking ** mode. Doing nothing at all also makes NORMAL the default. @@ -143805,6 +145340,12 @@ SQLITE_PRIVATE int sqlite3CantopenError(int lineno){ return reportError(SQLITE_CANTOPEN, lineno, "cannot open file"); } #ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3CorruptPgnoError(int lineno, Pgno pgno){ + char zMsg[100]; + sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno); + testcase( sqlite3GlobalConfig.xLog!=0 ); + return reportError(SQLITE_CORRUPT, lineno, zMsg); +} SQLITE_PRIVATE int sqlite3NomemError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); return reportError(SQLITE_NOMEM, lineno, "OOM"); @@ -144156,7 +145697,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){ ** This action provides a run-time test to see how the ALWAYS and ** NEVER macros were defined at compile-time. ** - ** The return value is ALWAYS(X). + ** The return value is ALWAYS(X) if X is true, or 0 if X is false. ** ** The recommended test is X==2. If the return value is 2, that means ** ALWAYS() and NEVER() are both no-op pass-through macros, which is the @@ -144179,7 +145720,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){ */ case SQLITE_TESTCTRL_ALWAYS: { int x = va_arg(ap,int); - rc = ALWAYS(x); + rc = x ? ALWAYS(x) : 0; break; } @@ -144246,22 +145787,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){ } #endif - /* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree); - ** - ** Pass pFree into sqlite3ScratchFree(). - ** If sz>0 then allocate a scratch buffer into pNew. - */ - case SQLITE_TESTCTRL_SCRATCHMALLOC: { - void *pFree, **ppNew; - int sz; - sz = va_arg(ap, int); - ppNew = va_arg(ap, void**); - pFree = va_arg(ap, void*); - if( sz ) *ppNew = sqlite3ScratchMalloc(sz); - sqlite3ScratchFree(pFree); - break; - } - /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff); ** ** If parameter onoff is non-zero, configure the wrappers so that all @@ -144403,7 +145928,7 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64( ){ const char *z = sqlite3_uri_parameter(zFilename, zParam); sqlite3_int64 v; - if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){ + if( z && sqlite3DecOrHexToI64(z, &v)==0 ){ bDflt = v; } return bDflt; @@ -144564,6 +146089,58 @@ SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ } #endif /* SQLITE_ENABLE_SNAPSHOT */ +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +/* +** Given the name of a compile-time option, return true if that option +** was used and false if not. +** +** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix +** is not required for a match. +*/ +SQLITE_API int sqlite3_compileoption_used(const char *zOptName){ + int i, n; + int nOpt; + const char **azCompileOpt; + +#if SQLITE_ENABLE_API_ARMOR + if( zOptName==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + + azCompileOpt = sqlite3CompileOptions(&nOpt); + + if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; + n = sqlite3Strlen30(zOptName); + + /* Since nOpt is normally in single digits, a linear search is + ** adequate. No need for a binary search. */ + for(i=0; i<nOpt; i++){ + if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0 + && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0 + ){ + return 1; + } + } + return 0; +} + +/* +** Return the N-th compile-time option string. If N is out of range, +** return a NULL pointer. +*/ +SQLITE_API const char *sqlite3_compileoption_get(int N){ + int nOpt; + const char **azCompileOpt; + azCompileOpt = sqlite3CompileOptions(&nOpt); + if( N>=0 && N<nOpt ){ + return azCompileOpt[N]; + } + return 0; +} +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ + /************** End of main.c ************************************************/ /************** Begin file notify.c ******************************************/ /* @@ -147515,17 +149092,26 @@ static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){ } /* +** Free all resources currently held by the cursor passed as the only +** argument. +*/ +static void fts3ClearCursor(Fts3Cursor *pCsr){ + fts3CursorFinalizeStmt(pCsr); + sqlite3Fts3FreeDeferredTokens(pCsr); + sqlite3_free(pCsr->aDoclist); + sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); + sqlite3Fts3ExprFree(pCsr->pExpr); + memset(&(&pCsr->base)[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); +} + +/* ** Close the cursor. For additional information see the documentation ** on the xClose method of the virtual table interface. */ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){ Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); - fts3CursorFinalizeStmt(pCsr); - sqlite3Fts3ExprFree(pCsr->pExpr); - sqlite3Fts3FreeDeferredTokens(pCsr); - sqlite3_free(pCsr->aDoclist); - sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); + fts3ClearCursor(pCsr); assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); sqlite3_free(pCsr); return SQLITE_OK; @@ -147551,7 +149137,7 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){ }else{ zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); if( !zSql ) return SQLITE_NOMEM; - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); + rc = sqlite3_prepare_v3(p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0); sqlite3_free(zSql); } if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1; @@ -149026,11 +150612,7 @@ static int fts3FilterMethod( assert( iIdx==nVal ); /* In case the cursor has been used before, clear it now. */ - fts3CursorFinalizeStmt(pCsr); - sqlite3_free(pCsr->aDoclist); - sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); - sqlite3Fts3ExprFree(pCsr->pExpr); - memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); + fts3ClearCursor(pCsr); /* Set the lower and upper bounds on docids to return */ pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64); @@ -149088,7 +150670,7 @@ static int fts3FilterMethod( ); } if( zSql ){ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); + rc = sqlite3_prepare_v3(p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0); sqlite3_free(zSql); }else{ rc = SQLITE_NOMEM; @@ -149109,7 +150691,12 @@ static int fts3FilterMethod( ** routine to find out if it has reached the end of a result set. */ static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){ - return ((Fts3Cursor *)pCursor)->isEof; + Fts3Cursor *pCsr = (Fts3Cursor*)pCursor; + if( pCsr->isEof ){ + fts3ClearCursor(pCsr); + pCsr->isEof = 1; + } + return pCsr->isEof; } /* @@ -149150,8 +150737,7 @@ static int fts3ColumnMethod( switch( iCol-p->nColumn ){ case 0: /* The special 'table-name' column */ - sqlite3_result_blob(pCtx, &pCsr, sizeof(Fts3Cursor*), SQLITE_TRANSIENT); - sqlite3_result_subtype(pCtx, SQLITE_BLOB); + sqlite3_result_pointer(pCtx, pCsr, "fts3cursor", 0); break; case 1: @@ -149369,9 +150955,10 @@ static int fts3FunctionArg( sqlite3_value *pVal, /* argv[0] passed to function */ Fts3Cursor **ppCsr /* OUT: Store cursor handle here */ ){ - int rc = SQLITE_OK; - if( sqlite3_value_subtype(pVal)==SQLITE_BLOB ){ - *ppCsr = *(Fts3Cursor**)sqlite3_value_blob(pVal); + int rc; + *ppCsr = (Fts3Cursor*)sqlite3_value_pointer(pVal, "fts3cursor"); + if( (*ppCsr)!=0 ){ + rc = SQLITE_OK; }else{ char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc); sqlite3_result_error(pContext, zErr, -1); @@ -156295,7 +157882,8 @@ static int fts3SqlStmt( if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, NULL); + rc = sqlite3_prepare_v3(p->db, zSql, -1, SQLITE_PREPARE_PERSISTENT, + &pStmt, NULL); sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); p->aStmt[eStmt] = pStmt; @@ -164383,14 +165971,6 @@ struct RtreeGeomCallback { void *pContext; }; - -/* -** Value for the first field of every RtreeMatchArg object. The MATCH -** operator tests that the first field of a blob operand matches this -** value to avoid operating on invalid blobs (which could cause a segfault). -*/ -#define RTREE_GEOMETRY_MAGIC 0x891245AB - /* ** An instance of this structure (in the form of a BLOB) is returned by ** the SQL functions that sqlite3_rtree_geometry_callback() and @@ -164398,7 +165978,7 @@ struct RtreeGeomCallback { ** operand to the MATCH operator of an R-Tree. */ struct RtreeMatchArg { - u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ + u32 iSize; /* Size of this object */ RtreeGeomCallback cb; /* Info about the callback functions */ int nParam; /* Number of parameters to the SQL function */ sqlite3_value **apSqlParam; /* Original SQL parameter values */ @@ -165693,33 +167273,17 @@ static int findLeafNode( ** operator. */ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ - RtreeMatchArg *pBlob; /* BLOB returned by geometry function */ + RtreeMatchArg *pBlob, *pSrc; /* BLOB returned by geometry function */ sqlite3_rtree_query_info *pInfo; /* Callback information */ - int nBlob; /* Size of the geometry function blob */ - int nExpected; /* Expected size of the BLOB */ - /* Check that value is actually a blob. */ - if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR; - - /* Check that the blob is roughly the right size. */ - nBlob = sqlite3_value_bytes(pValue); - if( nBlob<(int)sizeof(RtreeMatchArg) ){ - return SQLITE_ERROR; - } - - pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob ); + pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg"); + if( pSrc==0 ) return SQLITE_ERROR; + pInfo = (sqlite3_rtree_query_info*) + sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize ); if( !pInfo ) return SQLITE_NOMEM; memset(pInfo, 0, sizeof(*pInfo)); pBlob = (RtreeMatchArg*)&pInfo[1]; - - memcpy(pBlob, sqlite3_value_blob(pValue), nBlob); - nExpected = (int)(sizeof(RtreeMatchArg) + - pBlob->nParam*sizeof(sqlite3_value*) + - (pBlob->nParam-1)*sizeof(RtreeDValue)); - if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){ - sqlite3_free(pInfo); - return SQLITE_ERROR; - } + memcpy(pBlob, pSrc, pSrc->iSize); pInfo->pContext = pBlob->cb.pContext; pInfo->nParam = pBlob->nParam; pInfo->aParam = pBlob->aParam; @@ -166921,7 +168485,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ int rc; /* Return code */ RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */ int iCell; /* Index of iDelete cell in pLeaf */ - RtreeNode *pRoot; /* Root node of rtree structure */ + RtreeNode *pRoot = 0; /* Root node of rtree structure */ /* Obtain a reference to the root node to initialize Rtree.iDepth */ @@ -167405,7 +168969,8 @@ static int rtreeSqlInit( for(i=0; i<N_STATEMENT && rc==SQLITE_OK; i++){ char *zSql = sqlite3_mprintf(azSql[i], zDb, zPrefix); if( zSql ){ - rc = sqlite3_prepare_v2(db, zSql, -1, appStmt[i], 0); + rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT, + appStmt[i], 0); }else{ rc = SQLITE_NOMEM; } @@ -167480,6 +169045,10 @@ static int getNodeSize( rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + }else if( pRtree->iNodeSize<(512-64) ){ + rc = SQLITE_CORRUPT_VTAB; + *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"", + pRtree->zName); } } @@ -167752,7 +169321,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ sqlite3_result_error_nomem(ctx); }else{ int i; - pBlob->magic = RTREE_GEOMETRY_MAGIC; + pBlob->iSize = nBlob; pBlob->cb = pGeomCtx[0]; pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg]; pBlob->nParam = nArg; @@ -167769,7 +169338,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ sqlite3_result_error_nomem(ctx); rtreeMatchArgFree(pBlob); }else{ - sqlite3_result_blob(ctx, pBlob, nBlob, rtreeMatchArgFree); + sqlite3_result_pointer(ctx, pBlob, "RtreeMatchArg", rtreeMatchArgFree); } } } @@ -167944,15 +169513,15 @@ static int icuLikeCompare( const uint8_t *zString, /* The UTF-8 string to compare against */ const UChar32 uEsc /* The escape character */ ){ - static const int MATCH_ONE = (UChar32)'_'; - static const int MATCH_ALL = (UChar32)'%'; + static const uint32_t MATCH_ONE = (uint32_t)'_'; + static const uint32_t MATCH_ALL = (uint32_t)'%'; int prevEscape = 0; /* True if the previous character was uEsc */ while( 1 ){ /* Read (and consume) the next character from the input pattern. */ - UChar32 uPattern; + uint32_t uPattern; SQLITE_ICU_READ_UTF8(zPattern, uPattern); if( uPattern==0 ) break; @@ -167994,16 +169563,16 @@ static int icuLikeCompare( if( *zString==0 ) return 0; SQLITE_ICU_SKIP_UTF8(zString); - }else if( !prevEscape && uPattern==uEsc){ + }else if( !prevEscape && uPattern==(uint32_t)uEsc){ /* Case 3. */ prevEscape = 1; }else{ /* Case 4. */ - UChar32 uString; + uint32_t uString; SQLITE_ICU_READ_UTF8(zString, uString); - uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT); - uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT); + uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); + uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); if( uString!=uPattern ){ return 0; } @@ -169100,6 +170669,28 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( ); /* +** Configure a limit for the amount of temp space that may be used by +** the RBU handle passed as the first argument. The new limit is specified +** in bytes by the second parameter. If it is positive, the limit is updated. +** If the second parameter to this function is passed zero, then the limit +** is removed entirely. If the second parameter is negative, the limit is +** not modified (this is useful for querying the current limit). +** +** In all cases the returned value is the current limit in bytes (zero +** indicates unlimited). +** +** If the temp space limit is exceeded during operation, an SQLITE_FULL +** error is returned. +*/ +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64); + +/* +** Return the current amount of temp file space, in bytes, currently used by +** the RBU handle passed as the only argument. +*/ +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*); + +/* ** Internally, each RBU connection uses a separate SQLite database ** connection to access the target and rbu update databases. This ** API allows the application direct access to these database handles. @@ -169167,10 +170758,10 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); ** ** If an error has already occurred as part of an sqlite3rbu_step() ** or sqlite3rbu_open() call, or if one occurs within this function, an -** SQLite error code is returned. Additionally, *pzErrmsg may be set to -** point to a buffer containing a utf-8 formatted English language error -** message. It is the responsibility of the caller to eventually free any -** such buffer using sqlite3_free(). +** SQLite error code is returned. Additionally, if pzErrmsg is not NULL, +** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted +** English language error message. It is the responsibility of the caller to +** eventually free any such buffer using sqlite3_free(). ** ** Otherwise, if no error occurs, this function returns SQLITE_OK if the ** update has been partially applied, or SQLITE_DONE if it has been @@ -169225,7 +170816,7 @@ SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu); ** table exists but is not correctly populated, the value of the *pnOne ** output variable during stage 1 is undefined. */ -SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo); +SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo); /* ** Obtain an indication as to the current stage of an RBU update or vacuum. @@ -169335,6 +170926,13 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName); /* Maximum number of prepared UPDATE statements held by this module */ #define SQLITE_RBU_UPDATE_CACHESIZE 16 +/* Delta checksums disabled by default. Compile with -DRBU_ENABLE_DELTA_CKSUM +** to enable checksum verification. +*/ +#ifndef RBU_ENABLE_DELTA_CKSUM +# define RBU_ENABLE_DELTA_CKSUM 0 +#endif + /* ** Swap two objects of type TYPE. */ @@ -169610,6 +171208,8 @@ struct sqlite3rbu { int pgsz; u8 *aBuf; i64 iWalCksum; + i64 szTemp; /* Current size of all temp files in use */ + i64 szTempLimit; /* Total size limit for temp files */ /* Used in RBU vacuum mode only */ int nRbu; /* Number of RBU VFS in the stack */ @@ -169618,23 +171218,33 @@ struct sqlite3rbu { /* ** An rbu VFS is implemented using an instance of this structure. +** +** Variable pRbu is only non-NULL for automatically created RBU VFS objects. +** It is NULL for RBU VFS objects created explicitly using +** sqlite3rbu_create_vfs(). It is used to track the total amount of temp +** space used by the RBU handle. */ struct rbu_vfs { sqlite3_vfs base; /* rbu VFS shim methods */ sqlite3_vfs *pRealVfs; /* Underlying VFS */ sqlite3_mutex *mutex; /* Mutex to protect pMain */ + sqlite3rbu *pRbu; /* Owner RBU object */ rbu_file *pMain; /* Linked list of main db files */ }; /* ** Each file opened by an rbu VFS is represented by an instance of ** the following structure. +** +** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable +** "sz" is set to the current size of the database file. */ struct rbu_file { sqlite3_file base; /* sqlite3_file methods */ sqlite3_file *pReal; /* Underlying file handle */ rbu_vfs *pRbuVfs; /* Pointer to the rbu_vfs object */ sqlite3rbu *pRbu; /* Pointer to rbu object (rbu target only) */ + i64 sz; /* Size of file in bytes (temp only) */ int openFlags; /* Flags this file was opened with */ u32 iCookie; /* Cookie value for main db files */ @@ -169697,6 +171307,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){ return v; } +#if RBU_ENABLE_DELTA_CKSUM /* ** Compute a 32-bit checksum on the N-byte buffer. Return the result. */ @@ -169731,6 +171342,7 @@ static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){ } return sum3; } +#endif /* ** Apply a delta. @@ -169761,7 +171373,7 @@ static int rbuDeltaApply( ){ unsigned int limit; unsigned int total = 0; -#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST +#if RBU_ENABLE_DELTA_CKSUM char *zOrigOut = zOut; #endif @@ -169816,7 +171428,7 @@ static int rbuDeltaApply( case ';': { zDelta++; lenDelta--; zOut[0] = 0; -#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST +#if RBU_ENABLE_DELTA_CKSUM if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){ /* ERROR: bad checksum */ return -1; @@ -172648,6 +174260,7 @@ static void rbuCreateVfs(sqlite3rbu *p){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd); assert( pVfs ); p->zVfsName = pVfs->zName; + ((rbu_vfs*)pVfs)->pRbu = p; } } @@ -173020,13 +174633,18 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){ /* Close the open database handle and VFS object. */ sqlite3_close(p->dbRbu); sqlite3_close(p->dbMain); + assert( p->szTemp==0 ); rbuDeleteVfs(p); sqlite3_free(p->aBuf); sqlite3_free(p->aFrame); rbuEditErrmsg(p); rc = p->rc; - *pzErrmsg = p->zErrmsg; + if( pzErrmsg ){ + *pzErrmsg = p->zErrmsg; + }else{ + sqlite3_free(p->zErrmsg); + } sqlite3_free(p->zState); sqlite3_free(p); }else{ @@ -173203,6 +174821,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ */ static void rbuUnlockShm(rbu_file *p){ + assert( p->openFlags & SQLITE_OPEN_MAIN_DB ); if( p->pRbu ){ int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock; int i; @@ -173216,6 +174835,18 @@ static void rbuUnlockShm(rbu_file *p){ } /* +*/ +static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){ + sqlite3rbu *pRbu = pFd->pRbu; + i64 nDiff = nNew - pFd->sz; + pRbu->szTemp += nDiff; + pFd->sz = nNew; + assert( pRbu->szTemp>=0 ); + if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL; + return SQLITE_OK; +} + +/* ** Close an rbu file. */ static int rbuVfsClose(sqlite3_file *pFile){ @@ -173240,6 +174871,9 @@ static int rbuVfsClose(sqlite3_file *pFile){ rbuUnlockShm(p); p->pReal->pMethods->xShmUnmap(p->pReal, 0); } + else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ + rbuUpdateTempSize(p, 0); + } /* Close the underlying file handle */ rc = p->pReal->pMethods->xClose(p->pReal); @@ -173357,11 +174991,19 @@ static int rbuVfsWrite( assert( p->openFlags & SQLITE_OPEN_MAIN_DB ); rc = rbuCaptureDbWrite(p->pRbu, iOfst); }else{ - if( pRbu && pRbu->eStage==RBU_STAGE_OAL - && (p->openFlags & SQLITE_OPEN_WAL) - && iOfst>=pRbu->iOalSz - ){ - pRbu->iOalSz = iAmt + iOfst; + if( pRbu ){ + if( pRbu->eStage==RBU_STAGE_OAL + && (p->openFlags & SQLITE_OPEN_WAL) + && iOfst>=pRbu->iOalSz + ){ + pRbu->iOalSz = iAmt + iOfst; + }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){ + i64 szNew = iAmt+iOfst; + if( szNew>p->sz ){ + rc = rbuUpdateTempSize(p, szNew); + if( rc!=SQLITE_OK ) return rc; + } + } } rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){ @@ -173380,6 +175022,10 @@ static int rbuVfsWrite( */ static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ rbu_file *p = (rbu_file*)pFile; + if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ + int rc = rbuUpdateTempSize(p, size); + if( rc!=SQLITE_OK ) return rc; + } return p->pReal->pMethods->xTruncate(p->pReal, size); } @@ -173769,6 +175415,8 @@ static int rbuVfsOpen( pDb->pWalFd = pFd; } } + }else{ + pFd->pRbu = pRbuVfs->pRbu; } if( oflags & SQLITE_OPEN_MAIN_DB @@ -173845,7 +175493,9 @@ static int rbuVfsAccess( if( *pResOut ){ rc = SQLITE_CANTOPEN; }else{ - *pResOut = 1; + sqlite3_int64 sz = 0; + rc = rbuVfsFileSize(&pDb->base, &sz); + *pResOut = (sz>0); } } } @@ -174034,6 +175684,20 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){ return rc; } +/* +** Configure the aggregate temp file size limit for this RBU handle. +*/ +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){ + if( n>=0 ){ + pRbu->szTempLimit = n; + } + return pRbu->szTempLimit; +} + +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){ + return pRbu->szTemp; +} + /**************************************************************************/ @@ -174737,6 +176401,9 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ }; return sqlite3_create_module(db, "dbstat", &dbstat_module, 0); } @@ -174745,6 +176412,338 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; } #endif /* SQLITE_ENABLE_DBSTAT_VTAB */ /************** End of dbstat.c **********************************************/ +/************** Begin file dbpage.c ******************************************/ +/* +** 2017-10-11 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains an implementation of the "sqlite_dbpage" virtual table. +** +** The sqlite_dbpage virtual table is used to read or write whole raw +** pages of the database file. The pager interface is used so that +** uncommitted changes and changes recorded in the WAL file are correctly +** retrieved. +** +** Usage example: +** +** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123; +** +** This is an eponymous virtual table so it does not need to be created before +** use. The optional argument to the sqlite_dbpage() table name is the +** schema for the database file that is to be read. The default schema is +** "main". +** +** The data field of sqlite_dbpage table can be updated. The new +** value must be a BLOB which is the correct page size, otherwise the +** update fails. Rows may not be deleted or inserted. +*/ + +/* #include "sqliteInt.h" ** Requires access to internal data structures ** */ +#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \ + && !defined(SQLITE_OMIT_VIRTUALTABLE) + +typedef struct DbpageTable DbpageTable; +typedef struct DbpageCursor DbpageCursor; + +struct DbpageCursor { + sqlite3_vtab_cursor base; /* Base class. Must be first */ + int pgno; /* Current page number */ + int mxPgno; /* Last page to visit on this scan */ +}; + +struct DbpageTable { + sqlite3_vtab base; /* Base class. Must be first */ + sqlite3 *db; /* The database */ + Pager *pPager; /* Pager being read/written */ + int iDb; /* Index of database to analyze */ + int szPage; /* Size of each page in bytes */ + int nPage; /* Number of pages in the file */ +}; + +/* +** Connect to or create a dbpagevfs virtual table. +*/ +static int dbpageConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + DbpageTable *pTab = 0; + int rc = SQLITE_OK; + int iDb; + + if( argc>=4 ){ + Token nm; + sqlite3TokenInit(&nm, (char*)argv[3]); + iDb = sqlite3FindDb(db, &nm); + if( iDb<0 ){ + *pzErr = sqlite3_mprintf("no such schema: %s", argv[3]); + return SQLITE_ERROR; + } + }else{ + iDb = 0; + } + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); + if( rc==SQLITE_OK ){ + pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable)); + if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; + } + + assert( rc==SQLITE_OK || pTab==0 ); + if( rc==SQLITE_OK ){ + Btree *pBt = db->aDb[iDb].pBt; + memset(pTab, 0, sizeof(DbpageTable)); + pTab->db = db; + pTab->iDb = iDb; + pTab->pPager = pBt ? sqlite3BtreePager(pBt) : 0; + } + + *ppVtab = (sqlite3_vtab*)pTab; + return rc; +} + +/* +** Disconnect from or destroy a dbpagevfs virtual table. +*/ +static int dbpageDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* +** idxNum: +** +** 0 full table scan +** 1 pgno=?1 +*/ +static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + int i; + pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */ + for(i=0; i<pIdxInfo->nConstraint; i++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; + if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + pIdxInfo->estimatedRows = 1; + pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; + pIdxInfo->estimatedCost = 1.0; + pIdxInfo->idxNum = 1; + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + pIdxInfo->aConstraintUsage[i].omit = 1; + break; + } + } + if( pIdxInfo->nOrderBy>=1 + && pIdxInfo->aOrderBy[0].iColumn<=0 + && pIdxInfo->aOrderBy[0].desc==0 + ){ + pIdxInfo->orderByConsumed = 1; + } + return SQLITE_OK; +} + +/* +** Open a new dbpagevfs cursor. +*/ +static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ + DbpageCursor *pCsr; + + pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor)); + if( pCsr==0 ){ + return SQLITE_NOMEM_BKPT; + }else{ + memset(pCsr, 0, sizeof(DbpageCursor)); + pCsr->base.pVtab = pVTab; + pCsr->pgno = -1; + } + + *ppCursor = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** Close a dbpagevfs cursor. +*/ +static int dbpageClose(sqlite3_vtab_cursor *pCursor){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** Move a dbpagevfs cursor to the next entry in the file. +*/ +static int dbpageNext(sqlite3_vtab_cursor *pCursor){ + int rc = SQLITE_OK; + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + pCsr->pgno++; + return rc; +} + +static int dbpageEof(sqlite3_vtab_cursor *pCursor){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + return pCsr->pgno > pCsr->mxPgno; +} + +static int dbpageFilter( + sqlite3_vtab_cursor *pCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; + int rc = SQLITE_OK; + Btree *pBt = pTab->db->aDb[pTab->iDb].pBt; + + pTab->szPage = sqlite3BtreeGetPageSize(pBt); + pTab->nPage = sqlite3BtreeLastPage(pBt); + if( idxNum==1 ){ + pCsr->pgno = sqlite3_value_int(argv[0]); + if( pCsr->pgno<1 || pCsr->pgno>pTab->nPage ){ + pCsr->pgno = 1; + pCsr->mxPgno = 0; + }else{ + pCsr->mxPgno = pCsr->pgno; + } + }else{ + pCsr->pgno = 1; + pCsr->mxPgno = pTab->nPage; + } + return rc; +} + +static int dbpageColumn( + sqlite3_vtab_cursor *pCursor, + sqlite3_context *ctx, + int i +){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; + int rc = SQLITE_OK; + switch( i ){ + case 0: { /* pgno */ + sqlite3_result_int(ctx, pCsr->pgno); + break; + } + case 1: { /* data */ + DbPage *pDbPage = 0; + rc = sqlite3PagerGet(pTab->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0); + if( rc==SQLITE_OK ){ + sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pTab->szPage, + SQLITE_TRANSIENT); + } + sqlite3PagerUnref(pDbPage); + break; + } + default: { /* schema */ + sqlite3 *db = sqlite3_context_db_handle(ctx); + sqlite3_result_text(ctx, db->aDb[pTab->iDb].zDbSName, -1, SQLITE_STATIC); + break; + } + } + return SQLITE_OK; +} + +static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + *pRowid = pCsr->pgno; + return SQLITE_OK; +} + +static int dbpageUpdate( + sqlite3_vtab *pVtab, + int argc, + sqlite3_value **argv, + sqlite_int64 *pRowid +){ + DbpageTable *pTab = (DbpageTable *)pVtab; + int pgno; + DbPage *pDbPage = 0; + int rc = SQLITE_OK; + char *zErr = 0; + + if( argc==1 ){ + zErr = "cannot delete"; + goto update_fail; + } + pgno = sqlite3_value_int(argv[0]); + if( pgno<1 || pgno>pTab->nPage ){ + zErr = "bad page number"; + goto update_fail; + } + if( sqlite3_value_int(argv[1])!=pgno ){ + zErr = "cannot insert"; + goto update_fail; + } + if( sqlite3_value_type(argv[3])!=SQLITE_BLOB + || sqlite3_value_bytes(argv[3])!=pTab->szPage + ){ + zErr = "bad page value"; + goto update_fail; + } + rc = sqlite3PagerGet(pTab->pPager, pgno, (DbPage**)&pDbPage, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerWrite(pDbPage); + if( rc==SQLITE_OK ){ + memcpy(sqlite3PagerGetData(pDbPage), + sqlite3_value_blob(argv[3]), + pTab->szPage); + } + } + sqlite3PagerUnref(pDbPage); + return rc; + +update_fail: + sqlite3_free(pVtab->zErrMsg); + pVtab->zErrMsg = sqlite3_mprintf("%s", zErr); + return SQLITE_ERROR; +} + +/* +** Invoke this routine to register the "dbpage" virtual table module +*/ +SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ + static sqlite3_module dbpage_module = { + 0, /* iVersion */ + dbpageConnect, /* xCreate */ + dbpageConnect, /* xConnect */ + dbpageBestIndex, /* xBestIndex */ + dbpageDisconnect, /* xDisconnect */ + dbpageDisconnect, /* xDestroy */ + dbpageOpen, /* xOpen - open a cursor */ + dbpageClose, /* xClose - close a cursor */ + dbpageFilter, /* xFilter - configure scan constraints */ + dbpageNext, /* xNext - advance a cursor */ + dbpageEof, /* xEof - check for end of scan */ + dbpageColumn, /* xColumn - read data */ + dbpageRowid, /* xRowid - read data */ + dbpageUpdate, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + }; + return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); +} +#elif defined(SQLITE_ENABLE_DBPAGE_VTAB) +SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; } +#endif /* SQLITE_ENABLE_DBSTAT_VTAB */ + +/************** End of dbpage.c **********************************************/ /************** Begin file sqlite3session.c **********************************/ #if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) @@ -177584,11 +179583,12 @@ static int sessionChangesetNext( p->in.iCurrent = p->in.iNext; op = p->in.aData[p->in.iNext++]; - if( op=='T' || op=='P' ){ + while( op=='T' || op=='P' ){ p->bPatchset = (op=='P'); if( sessionChangesetReadTblhdr(p) ) return p->rc; if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc; p->in.iCurrent = p->in.iNext; + if( p->in.iNext>=p->in.nData ) return SQLITE_DONE; op = p->in.aData[p->in.iNext++]; } @@ -183334,7 +185334,8 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); ** fts5YY_MAX_SHIFT Maximum value for shift actions ** fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions ** fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions -** fts5YY_MIN_REDUCE Maximum value for reduce actions +** fts5YY_MIN_REDUCE Minimum value for reduce actions +** fts5YY_MAX_REDUCE Maximum value for reduce actions ** fts5YY_ERROR_ACTION The fts5yy_action[] code for syntax error ** fts5YY_ACCEPT_ACTION The fts5yy_action[] code for accept ** fts5YY_NO_ACTION The fts5yy_action[] code for no-op @@ -183446,12 +185447,12 @@ typedef union { *********** Begin parsing tables **********************************************/ #define fts5YY_ACTTAB_COUNT (98) static const fts5YYACTIONTYPE fts5yy_action[] = { - /* 0 */ 105, 19, 63, 6, 26, 66, 65, 24, 24, 17, - /* 10 */ 63, 6, 26, 16, 65, 54, 24, 18, 63, 6, - /* 20 */ 26, 10, 65, 12, 24, 75, 59, 63, 6, 26, - /* 30 */ 13, 65, 75, 24, 20, 63, 6, 26, 74, 65, - /* 40 */ 56, 24, 27, 63, 6, 26, 73, 65, 21, 24, - /* 50 */ 23, 15, 30, 11, 1, 64, 22, 25, 9, 65, + /* 0 */ 105, 19, 90, 6, 26, 93, 92, 24, 24, 17, + /* 10 */ 90, 6, 26, 16, 92, 54, 24, 18, 90, 6, + /* 20 */ 26, 10, 92, 12, 24, 75, 86, 90, 6, 26, + /* 30 */ 13, 92, 75, 24, 20, 90, 6, 26, 101, 92, + /* 40 */ 56, 24, 27, 90, 6, 26, 100, 92, 21, 24, + /* 50 */ 23, 15, 30, 11, 1, 91, 22, 25, 9, 92, /* 60 */ 7, 24, 3, 4, 5, 3, 4, 5, 3, 77, /* 70 */ 4, 5, 3, 61, 23, 15, 60, 11, 80, 12, /* 80 */ 2, 13, 68, 10, 29, 52, 55, 75, 31, 32, @@ -183556,6 +185557,7 @@ struct fts5yyParser { fts5yyStackEntry fts5yystk0; /* First stack entry */ #else fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */ + fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */ #endif }; typedef struct fts5yyParser fts5yyParser; @@ -183705,6 +185707,9 @@ static void sqlite3Fts5ParserInit(void *fts5yypParser){ pParser->fts5yytos = pParser->fts5yystack; pParser->fts5yystack[0].stateno = 0; pParser->fts5yystack[0].major = 0; +#if fts5YYSTACKDEPTH>0 + pParser->fts5yystackEnd = &pParser->fts5yystack[fts5YYSTACKDEPTH-1]; +#endif } #ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK @@ -184003,7 +186008,7 @@ static void fts5yy_shift( } #endif #if fts5YYSTACKDEPTH>0 - if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH] ){ + if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){ fts5yypParser->fts5yytos--; fts5yyStackOverflow(fts5yypParser); return; @@ -184031,35 +186036,35 @@ static void fts5yy_shift( ** is used during the reduce. */ static const struct { - fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - unsigned char nrhs; /* Number of right-hand side symbols in the rule */ + fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ + signed char nrhs; /* Negative of the number of RHS symbols in the rule */ } fts5yyRuleInfo[] = { - { 16, 1 }, - { 20, 4 }, - { 20, 3 }, - { 20, 1 }, - { 20, 2 }, - { 21, 2 }, - { 21, 1 }, - { 17, 3 }, - { 17, 3 }, - { 17, 3 }, - { 17, 5 }, - { 17, 3 }, - { 17, 1 }, - { 19, 1 }, - { 19, 2 }, - { 18, 1 }, - { 18, 3 }, - { 22, 1 }, - { 22, 5 }, - { 23, 1 }, - { 23, 2 }, + { 16, -1 }, + { 20, -4 }, + { 20, -3 }, + { 20, -1 }, + { 20, -2 }, + { 21, -2 }, + { 21, -1 }, + { 17, -3 }, + { 17, -3 }, + { 17, -3 }, + { 17, -5 }, + { 17, -3 }, + { 17, -1 }, + { 19, -1 }, + { 19, -2 }, + { 18, -1 }, + { 18, -3 }, + { 22, -1 }, + { 22, -5 }, + { 23, -1 }, + { 23, -2 }, { 25, 0 }, - { 25, 2 }, - { 24, 4 }, - { 24, 2 }, - { 26, 1 }, + { 25, -2 }, + { 24, -4 }, + { 24, -2 }, + { 26, -1 }, { 26, 0 }, }; @@ -184083,7 +186088,7 @@ static void fts5yy_reduce( if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){ fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs; fprintf(fts5yyTraceFILE, "%sReduce [%s], go to state %d.\n", fts5yyTracePrompt, - fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno); + fts5yyRuleName[fts5yyruleno], fts5yymsp[fts5yysize].stateno); } #endif /* NDEBUG */ @@ -184098,7 +186103,7 @@ static void fts5yy_reduce( } #endif #if fts5YYSTACKDEPTH>0 - if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1] ){ + if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){ fts5yyStackOverflow(fts5yypParser); return; } @@ -184265,20 +186270,24 @@ static void fts5yy_reduce( assert( fts5yyruleno<sizeof(fts5yyRuleInfo)/sizeof(fts5yyRuleInfo[0]) ); fts5yygoto = fts5yyRuleInfo[fts5yyruleno].lhs; fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs; - fts5yyact = fts5yy_find_reduce_action(fts5yymsp[-fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto); - if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){ - if( fts5yyact>fts5YY_MAX_SHIFT ){ - fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; - } - fts5yymsp -= fts5yysize-1; + fts5yyact = fts5yy_find_reduce_action(fts5yymsp[fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto); + + /* There are no SHIFTREDUCE actions on nonterminals because the table + ** generator has simplified them to pure REDUCE actions. */ + assert( !(fts5yyact>fts5YY_MAX_SHIFT && fts5yyact<=fts5YY_MAX_SHIFTREDUCE) ); + + /* It is not possible for a REDUCE to be followed by an error */ + assert( fts5yyact!=fts5YY_ERROR_ACTION ); + + if( fts5yyact==fts5YY_ACCEPT_ACTION ){ + fts5yypParser->fts5yytos += fts5yysize; + fts5yy_accept(fts5yypParser); + }else{ + fts5yymsp += fts5yysize+1; fts5yypParser->fts5yytos = fts5yymsp; fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact; fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto; fts5yyTraceShift(fts5yypParser, fts5yyact); - }else{ - assert( fts5yyact == fts5YY_ACCEPT_ACTION ); - fts5yypParser->fts5yytos -= fts5yysize; - fts5yy_accept(fts5yypParser); } } @@ -189575,10 +191584,11 @@ static int fts5HashResize(Fts5Hash *pHash){ for(i=0; i<pHash->nSlot; i++){ while( apOld[i] ){ - int iHash; + unsigned int iHash; Fts5HashEntry *p = apOld[i]; apOld[i] = p->pHashNext; - iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), strlen(fts5EntryKey(p))); + iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), + (int)strlen(fts5EntryKey(p))); p->pHashNext = apNew[iHash]; apNew[iHash] = p; } @@ -189881,7 +191891,7 @@ static int sqlite3Fts5HashQuery( int *pnDoclist /* OUT: Size of doclist in bytes */ ){ unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); - char *zKey; + char *zKey = 0; Fts5HashEntry *p; for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ @@ -190669,7 +192679,8 @@ static int fts5IndexPrepareStmt( ){ if( p->rc==SQLITE_OK ){ if( zSql ){ - p->rc = sqlite3_prepare_v2(p->pConfig->db, zSql, -1, ppStmt, 0); + p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, ppStmt, 0); }else{ p->rc = SQLITE_NOMEM; } @@ -190718,7 +192729,8 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){ if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pDeleter, 0); + rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, &p->pDeleter, 0); sqlite3_free(zSql); } if( rc!=SQLITE_OK ){ @@ -197317,7 +199329,8 @@ static int fts5PrepareStatement( if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0); + rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, &pRet, 0); if( rc!=SQLITE_OK ){ *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); } @@ -197453,7 +199466,8 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){ char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs); if( zSql ){ sqlite3_stmt *pStmt = 0; - rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0); + rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, &pStmt, 0); sqlite3_free(zSql); assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 ); if( rc==SQLITE_OK ){ @@ -199041,15 +201055,14 @@ static void fts5ModuleDestroy(void *pCtx){ static void fts5Fts5Func( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ - sqlite3_value **apUnused /* Function arguments */ + sqlite3_value **apArg /* Function arguments */ ){ Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx); - char buf[8]; - UNUSED_PARAM2(nArg, apUnused); - assert( nArg==0 ); - assert( sizeof(buf)>=sizeof(pGlobal) ); - memcpy(buf, (void*)&pGlobal, sizeof(pGlobal)); - sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT); + fts5_api **ppApi; + UNUSED_PARAM(nArg); + assert( nArg==1 ); + ppApi = (fts5_api**)sqlite3_value_pointer(apArg[0], "fts5_api_ptr"); + if( ppApi ) *ppApi = &pGlobal->api; } /* @@ -199062,7 +201075,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2017-06-08 14:26:16 0ee482a1e0eae22e08edc8978c9733a96603d4509645f348ebf55b579e89636b", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de48827", -1, SQLITE_TRANSIENT); } static int fts5Init(sqlite3 *db){ @@ -199114,7 +201127,7 @@ static int fts5Init(sqlite3 *db){ if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db); if( rc==SQLITE_OK ){ rc = sqlite3_create_function( - db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0 + db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0 ); } if( rc==SQLITE_OK ){ @@ -199316,7 +201329,8 @@ static int fts5StorageGetStmt( if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0); + rc = sqlite3_prepare_v3(pC->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, &p->aStmt[eStmt], 0); sqlite3_free(zSql); if( rc!=SQLITE_OK && pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); @@ -202289,6 +204303,11 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){ ** the number of fts5 rows that contain at least one instance of term ** $term. Field $cnt is set to the total number of instances of term ** $term in the database. +** +** instance: +** CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY(<all-fields>)); +** +** One row for each term instance in the database. */ @@ -202304,7 +204323,7 @@ struct Fts5VocabTable { char *zFts5Db; /* Db containing fts5 table */ sqlite3 *db; /* Database handle */ Fts5Global *pGlobal; /* FTS5 global object for this database */ - int eType; /* FTS5_VOCAB_COL or ROW */ + int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */ }; struct Fts5VocabCursor { @@ -202324,16 +204343,22 @@ struct Fts5VocabCursor { i64 *aCnt; i64 *aDoc; - /* Output values used by 'row' and 'col' tables */ + /* Output values used by all tables. */ i64 rowid; /* This table's current rowid value */ Fts5Buffer term; /* Current value of 'term' column */ + + /* Output values Used by 'instance' tables only */ + i64 iInstPos; + int iInstOff; }; -#define FTS5_VOCAB_COL 0 -#define FTS5_VOCAB_ROW 1 +#define FTS5_VOCAB_COL 0 +#define FTS5_VOCAB_ROW 1 +#define FTS5_VOCAB_INSTANCE 2 #define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt" #define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt" +#define FTS5_VOCAB_INST_SCHEMA "term, doc, col, offset" /* ** Bits for the mask used as the idxNum value by xBestIndex/xFilter. @@ -202361,6 +204386,9 @@ static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){ if( sqlite3_stricmp(zCopy, "row")==0 ){ *peType = FTS5_VOCAB_ROW; }else + if( sqlite3_stricmp(zCopy, "instance")==0 ){ + *peType = FTS5_VOCAB_INSTANCE; + }else { *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy); rc = SQLITE_ERROR; @@ -202421,7 +204449,8 @@ static int fts5VocabInitVtab( ){ const char *azSchema[] = { "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")", - "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")" + "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")", + "CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")" }; Fts5VocabTable *pRet = 0; @@ -202495,6 +204524,15 @@ static int fts5VocabCreateMethod( /* ** Implementation of the xBestIndex method. +** +** Only constraints of the form: +** +** term <= ? +** term == ? +** term >= ? +** +** are interpreted. Less-than and less-than-or-equal are treated +** identically, as are greater-than and greater-than-or-equal. */ static int fts5VocabBestIndexMethod( sqlite3_vtab *pUnused, @@ -202638,6 +204676,54 @@ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){ return SQLITE_OK; } +static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){ + int rc = SQLITE_OK; + + if( sqlite3Fts5IterEof(pCsr->pIter) ){ + pCsr->bEof = 1; + }else{ + const char *zTerm; + int nTerm; + zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); + if( pCsr->nLeTerm>=0 ){ + int nCmp = MIN(nTerm, pCsr->nLeTerm); + int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp); + if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){ + pCsr->bEof = 1; + } + } + + sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm); + } + return rc; +} + +static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){ + int eDetail = pCsr->pConfig->eDetail; + int rc = SQLITE_OK; + Fts5IndexIter *pIter = pCsr->pIter; + i64 *pp = &pCsr->iInstPos; + int *po = &pCsr->iInstOff; + + while( eDetail==FTS5_DETAIL_NONE + || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp) + ){ + pCsr->iInstPos = 0; + pCsr->iInstOff = 0; + + rc = sqlite3Fts5IterNextScan(pCsr->pIter); + if( rc==SQLITE_OK ){ + rc = fts5VocabInstanceNewTerm(pCsr); + if( eDetail==FTS5_DETAIL_NONE ) break; + } + if( rc ){ + pCsr->bEof = 1; + break; + } + } + + return rc; +} /* ** Advance the cursor to the next row in the table. @@ -202650,13 +204736,17 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ pCsr->rowid++; + if( pTab->eType==FTS5_VOCAB_INSTANCE ){ + return fts5VocabInstanceNext(pCsr); + } + if( pTab->eType==FTS5_VOCAB_COL ){ for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){ if( pCsr->aDoc[pCsr->iCol] ) break; } } - if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){ + if( pTab->eType!=FTS5_VOCAB_COL || pCsr->iCol>=nCol ){ if( sqlite3Fts5IterEof(pCsr->pIter) ){ pCsr->bEof = 1; }else{ @@ -202680,22 +204770,26 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW ); while( rc==SQLITE_OK ){ + int eDetail = pCsr->pConfig->eDetail; const u8 *pPos; int nPos; /* Position list */ i64 iPos = 0; /* 64-bit position read from poslist */ int iOff = 0; /* Current offset within position list */ pPos = pCsr->pIter->pData; nPos = pCsr->pIter->nData; - switch( pCsr->pConfig->eDetail ){ - case FTS5_DETAIL_FULL: - pPos = pCsr->pIter->pData; - nPos = pCsr->pIter->nData; - if( pTab->eType==FTS5_VOCAB_ROW ){ + + switch( pTab->eType ){ + case FTS5_VOCAB_ROW: + if( eDetail==FTS5_DETAIL_FULL ){ while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ pCsr->aCnt[0]++; } - pCsr->aDoc[0]++; - }else{ + } + pCsr->aDoc[0]++; + break; + + case FTS5_VOCAB_COL: + if( eDetail==FTS5_DETAIL_FULL ){ int iCol = -1; while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ int ii = FTS5_POS2COLUMN(iPos); @@ -202709,13 +204803,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ iCol = ii; } } - } - break; - - case FTS5_DETAIL_COLUMNS: - if( pTab->eType==FTS5_VOCAB_ROW ){ - pCsr->aDoc[0]++; - }else{ + }else if( eDetail==FTS5_DETAIL_COLUMNS ){ while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){ assert_nc( iPos>=0 && iPos<nCol ); if( iPos>=nCol ){ @@ -202724,18 +204812,21 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ } pCsr->aDoc[iPos]++; } + }else{ + assert( eDetail==FTS5_DETAIL_NONE ); + pCsr->aDoc[0]++; } break; - default: - assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE ); - pCsr->aDoc[0]++; + default: + assert( pTab->eType==FTS5_VOCAB_INSTANCE ); break; } if( rc==SQLITE_OK ){ rc = sqlite3Fts5IterNextScan(pCsr->pIter); } + if( pTab->eType==FTS5_VOCAB_INSTANCE ) break; if( rc==SQLITE_OK ){ zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); @@ -202765,7 +204856,9 @@ static int fts5VocabFilterMethod( int nUnused, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ + Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + int eType = pTab->eType; int rc = SQLITE_OK; int iVal = 0; @@ -202805,11 +204898,16 @@ static int fts5VocabFilterMethod( } } - if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); } - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){ + rc = fts5VocabInstanceNewTerm(pCsr); + } + if( rc==SQLITE_OK + && !pCsr->bEof + && (eType!=FTS5_VOCAB_INSTANCE || pCsr->pConfig->eDetail!=FTS5_DETAIL_NONE) + ){ rc = fts5VocabNextMethod(pCursor); } @@ -202851,13 +204949,41 @@ static int fts5VocabColumnMethod( }else{ iVal = pCsr->aCnt[pCsr->iCol]; } - }else{ + }else if( eType==FTS5_VOCAB_ROW ){ assert( iCol==1 || iCol==2 ); if( iCol==1 ){ iVal = pCsr->aDoc[0]; }else{ iVal = pCsr->aCnt[0]; } + }else{ + assert( eType==FTS5_VOCAB_INSTANCE ); + switch( iCol ){ + case 1: + sqlite3_result_int64(pCtx, pCsr->pIter->iRowid); + break; + case 2: { + int ii = -1; + if( eDetail==FTS5_DETAIL_FULL ){ + ii = FTS5_POS2COLUMN(pCsr->iInstPos); + }else if( eDetail==FTS5_DETAIL_COLUMNS ){ + ii = (int)pCsr->iInstPos; + } + if( ii>=0 && ii<pCsr->pConfig->nCol ){ + const char *z = pCsr->pConfig->azCol[ii]; + sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); + } + break; + } + default: { + assert( iCol==3 ); + if( eDetail==FTS5_DETAIL_FULL ){ + int ii = FTS5_POS2OFFSET(pCsr->iInstPos); + sqlite3_result_int(pCtx, ii); + } + break; + } + } } if( iVal>0 ) sqlite3_result_int64(pCtx, iVal); @@ -202916,3 +205042,311 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ /************** End of fts5.c ************************************************/ +/************** Begin file stmt.c ********************************************/ +/* +** 2017-05-31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file demonstrates an eponymous virtual table that returns information +** about all prepared statements for the database connection. +** +** Usage example: +** +** .load ./stmt +** .mode line +** .header on +** SELECT * FROM stmt; +*/ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) +#if !defined(SQLITEINT_H) +/* #include "sqlite3ext.h" */ +#endif +SQLITE_EXTENSION_INIT1 +/* #include <assert.h> */ +/* #include <string.h> */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE + +/* stmt_vtab is a subclass of sqlite3_vtab which will +** serve as the underlying representation of a stmt virtual table +*/ +typedef struct stmt_vtab stmt_vtab; +struct stmt_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; /* Database connection for this stmt vtab */ +}; + +/* stmt_cursor is a subclass of sqlite3_vtab_cursor which will +** serve as the underlying representation of a cursor that scans +** over rows of the result +*/ +typedef struct stmt_cursor stmt_cursor; +struct stmt_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + sqlite3 *db; /* Database connection for this cursor */ + sqlite3_stmt *pStmt; /* Statement cursor is currently pointing at */ + sqlite3_int64 iRowid; /* The rowid */ +}; + +/* +** The stmtConnect() method is invoked to create a new +** stmt_vtab that describes the stmt virtual table. +** +** Think of this routine as the constructor for stmt_vtab objects. +** +** All this routine needs to do is: +** +** (1) Allocate the stmt_vtab object and initialize all fields. +** +** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the +** result set of queries against stmt will look like. +*/ +static int stmtConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + stmt_vtab *pNew; + int rc; + +/* Column numbers */ +#define STMT_COLUMN_SQL 0 /* SQL for the statement */ +#define STMT_COLUMN_NCOL 1 /* Number of result columns */ +#define STMT_COLUMN_RO 2 /* True if read-only */ +#define STMT_COLUMN_BUSY 3 /* True if currently busy */ +#define STMT_COLUMN_NSCAN 4 /* SQLITE_STMTSTATUS_FULLSCAN_STEP */ +#define STMT_COLUMN_NSORT 5 /* SQLITE_STMTSTATUS_SORT */ +#define STMT_COLUMN_NAIDX 6 /* SQLITE_STMTSTATUS_AUTOINDEX */ +#define STMT_COLUMN_NSTEP 7 /* SQLITE_STMTSTATUS_VM_STEP */ +#define STMT_COLUMN_REPREP 8 /* SQLITE_STMTSTATUS_REPREPARE */ +#define STMT_COLUMN_RUN 9 /* SQLITE_STMTSTATUS_RUN */ +#define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */ + + + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep," + "reprep,run,mem)"); + if( rc==SQLITE_OK ){ + pNew = sqlite3_malloc( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + pNew->db = db; + } + return rc; +} + +/* +** This method is the destructor for stmt_cursor objects. +*/ +static int stmtDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* +** Constructor for a new stmt_cursor object. +*/ +static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + stmt_cursor *pCur; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + pCur->db = ((stmt_vtab*)p)->db; + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Destructor for a stmt_cursor. +*/ +static int stmtClose(sqlite3_vtab_cursor *cur){ + sqlite3_free(cur); + return SQLITE_OK; +} + + +/* +** Advance a stmt_cursor to its next row of output. +*/ +static int stmtNext(sqlite3_vtab_cursor *cur){ + stmt_cursor *pCur = (stmt_cursor*)cur; + pCur->iRowid++; + pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt); + return SQLITE_OK; +} + +/* +** Return values of columns for the row at which the stmt_cursor +** is currently pointing. +*/ +static int stmtColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + stmt_cursor *pCur = (stmt_cursor*)cur; + switch( i ){ + case STMT_COLUMN_SQL: { + sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT); + break; + } + case STMT_COLUMN_NCOL: { + sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt)); + break; + } + case STMT_COLUMN_RO: { + sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt)); + break; + } + case STMT_COLUMN_BUSY: { + sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt)); + break; + } + case STMT_COLUMN_MEM: { + i = SQLITE_STMTSTATUS_MEMUSED + + STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP; + /* Fall thru */ + } + case STMT_COLUMN_NSCAN: + case STMT_COLUMN_NSORT: + case STMT_COLUMN_NAIDX: + case STMT_COLUMN_NSTEP: + case STMT_COLUMN_REPREP: + case STMT_COLUMN_RUN: { + sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt, + i-STMT_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 0)); + break; + } + } + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** rowid is the same as the output value. +*/ +static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + stmt_cursor *pCur = (stmt_cursor*)cur; + *pRowid = pCur->iRowid; + return SQLITE_OK; +} + +/* +** Return TRUE if the cursor has been moved off of the last +** row of output. +*/ +static int stmtEof(sqlite3_vtab_cursor *cur){ + stmt_cursor *pCur = (stmt_cursor*)cur; + return pCur->pStmt==0; +} + +/* +** This method is called to "rewind" the stmt_cursor object back +** to the first row of output. This method is always called at least +** once prior to any call to stmtColumn() or stmtRowid() or +** stmtEof(). +*/ +static int stmtFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + stmt_cursor *pCur = (stmt_cursor *)pVtabCursor; + pCur->pStmt = 0; + pCur->iRowid = 0; + return stmtNext(pVtabCursor); +} + +/* +** SQLite will invoke this method one or more times while planning a query +** that uses the stmt virtual table. This routine needs to create +** a query plan for each invocation and compute an estimated cost for that +** plan. +*/ +static int stmtBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + pIdxInfo->estimatedCost = (double)500; + pIdxInfo->estimatedRows = 500; + return SQLITE_OK; +} + +/* +** This following structure defines all the methods for the +** stmt virtual table. +*/ +static sqlite3_module stmtModule = { + 0, /* iVersion */ + 0, /* xCreate */ + stmtConnect, /* xConnect */ + stmtBestIndex, /* xBestIndex */ + stmtDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + stmtOpen, /* xOpen - open a cursor */ + stmtClose, /* xClose - close a cursor */ + stmtFilter, /* xFilter - configure scan constraints */ + stmtNext, /* xNext - advance a cursor */ + stmtEof, /* xEof - check for end of scan */ + stmtColumn, /* xColumn - read data */ + stmtRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ +}; + +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3 *db){ + int rc = SQLITE_OK; +#ifndef SQLITE_OMIT_VIRTUALTABLE + rc = sqlite3_create_module(db, "sqlite_stmt", &stmtModule, 0); +#endif + return rc; +} + +#ifndef SQLITE_CORE +#ifdef _WIN32 +__declspec(dllexport) +#endif +SQLITE_API int sqlite3_stmt_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); +#ifndef SQLITE_OMIT_VIRTUALTABLE + rc = sqlite3StmtVtabInit(db); +#endif + return rc; +} +#endif /* SQLITE_CORE */ +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ + +/************** End of stmt.c ************************************************/ +#if __LINE__!=205346 +#undef SQLITE_SOURCE_ID +#define SQLITE_SOURCE_ID "2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de4alt2" +#endif +/* Return the source-id for this library */ +SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } +/************************** End of sqlite3.c ******************************/ diff --git a/db/sqlite3/src/sqlite3.h b/db/sqlite3/src/sqlite3.h index 3deb9c79b..5f28e036b 100644 --- a/db/sqlite3/src/sqlite3.h +++ b/db/sqlite3/src/sqlite3.h @@ -1,5 +1,5 @@ /* -** 2001 September 15 +** 2001-09-15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -115,15 +115,17 @@ extern "C" { ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID ** string contains the date and time of the check-in (UTC) and a SHA1 -** or SHA3-256 hash of the entire source tree. +** or SHA3-256 hash of the entire source tree. If the source code has +** been edited in any way since it was last checked in, then the last +** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.19.3" -#define SQLITE_VERSION_NUMBER 3019003 -#define SQLITE_SOURCE_ID "2017-06-08 14:26:16 0ee482a1e0eae22e08edc8978c9733a96603d4509645f348ebf55b579e89636b" +#define SQLITE_VERSION "3.21.0" +#define SQLITE_VERSION_NUMBER 3021000 +#define SQLITE_SOURCE_ID "2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de48827" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -139,7 +141,7 @@ extern "C" { ** ** <blockquote><pre> ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER ); -** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 ); +** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 ); ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 ); ** </pre></blockquote>)^ ** @@ -149,9 +151,11 @@ extern "C" { ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to -** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns +** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns ** a pointer to a string constant whose value is the same as the -** [SQLITE_SOURCE_ID] C preprocessor macro. +** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built +** using an edited copy of [the amalgamation], then the last four characters +** of the hash might be different from [SQLITE_SOURCE_ID].)^ ** ** See also: [sqlite_version()] and [sqlite_source_id()]. */ @@ -417,7 +421,7 @@ SQLITE_API int sqlite3_exec( */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ -#define SQLITE_ERROR 1 /* SQL error or missing database */ +#define SQLITE_ERROR 1 /* Generic error */ #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ #define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */ @@ -432,7 +436,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Database is empty */ +#define SQLITE_EMPTY 16 /* Internal use only */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ @@ -440,7 +444,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_FORMAT 24 /* Not used */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ @@ -494,6 +498,9 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) +#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) +#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) +#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) @@ -580,6 +587,11 @@ SQLITE_API int sqlite3_exec( ** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on ** read-only media and cannot be changed even by processes with ** elevated privileges. +** +** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying +** filesystem supports doing multiple write operations atomically when those +** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and +** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -595,6 +607,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 +#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels @@ -729,6 +742,7 @@ struct sqlite3_file { ** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN] ** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE] ** <li> [SQLITE_IOCAP_IMMUTABLE] +** <li> [SQLITE_IOCAP_BATCH_ATOMIC] ** </ul> ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -1012,6 +1026,40 @@ struct sqlite3_io_methods { ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by ** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for ** this opcode. +** +** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]] +** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then +** the file descriptor is placed in "batch write mode", which +** means all subsequent write operations will be deferred and done +** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems +** that do not support batch atomic writes will return SQLITE_NOTFOUND. +** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to +** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or +** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make +** no VFS interface calls on the same [sqlite3_file] file descriptor +** except for calls to the xWrite method and the xFileControl method +** with [SQLITE_FCNTL_SIZE_HINT]. +** +** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically. +** This file control returns [SQLITE_OK] if and only if the writes were +** all performed successfully and have been committed to persistent storage. +** ^Regardless of whether or not it is successful, this file control takes +** the file descriptor out of batch write mode so that all subsequent +** write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. +** +** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back. +** ^This file control takes the file descriptor out of batch write mode +** so that all subsequent write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1043,6 +1091,9 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_JOURNAL_POINTER 28 #define SQLITE_FCNTL_WIN32_GET_HANDLE 29 #define SQLITE_FCNTL_PDB 30 +#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 +#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 +#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -1613,6 +1664,16 @@ struct sqlite3_mem_methods { ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example. </dd> ** +** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt> +** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of +** type int, interpreted as a boolean, which if true provides a hint to +** SQLite that it should avoid large memory allocations if possible. +** SQLite will run faster if it is free to make large memory allocations, +** but some application might prefer to run slower in exchange for +** guarantees about memory fragmentation that are possible if large +** allocations are avoided. This hint is normally off. +** </dd> +** ** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt> ** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, ** interpreted as a boolean, which enables or disables the collection of @@ -1630,25 +1691,7 @@ struct sqlite3_mem_methods { ** </dd> ** ** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt> -** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer -** that SQLite can use for scratch memory. ^(There are three arguments -** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte -** aligned memory buffer from which the scratch allocations will be -** drawn, the size of each scratch allocation (sz), -** and the maximum number of scratch allocations (N).)^ -** The first argument must be a pointer to an 8-byte aligned buffer -** of at least sz*N bytes of memory. -** ^SQLite will not use more than one scratch buffers per thread. -** ^SQLite will never request a scratch buffer that is more than 6 -** times the database page size. -** ^If SQLite needs needs additional -** scratch memory beyond what is provided by this configuration option, then -** [sqlite3_malloc()] will be used to obtain the memory needed.<p> -** ^When the application provides any amount of scratch memory using -** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large -** [sqlite3_malloc|heap allocations]. -** This can help [Robson proof|prevent memory allocation failures] due to heap -** fragmentation in low-memory embedded systems. +** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used. ** </dd> ** ** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt> @@ -1684,8 +1727,7 @@ struct sqlite3_mem_methods { ** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt> ** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer ** that SQLite will use for all of its dynamic memory allocation needs -** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and -** [SQLITE_CONFIG_PAGECACHE]. +** beyond those provided for by [SQLITE_CONFIG_PAGECACHE]. ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns ** [SQLITE_ERROR] if invoked otherwise. @@ -1878,7 +1920,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ -#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ +#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ @@ -1899,6 +1941,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ +#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ /* ** CAPI3REF: Database Connection Configuration Options @@ -2007,6 +2050,17 @@ struct sqlite3_mem_methods { ** have been disabled - 0 if they are not disabled, 1 if they are. ** </dd> ** +** <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt> +** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates +** the [query planner stability guarantee] (QPSG). When the QPSG is active, +** a single SQL query statement will always use the same algorithm regardless +** of values of [bound parameters].)^ The QPSG disables some query optimizations +** that look at the values of bound parameters, which can make some queries +** slower. But the QPSG has the advantage of more predictable behavior. With +** the QPSG active, SQLite will always use the same query plan in the field as +** was used during testing in the lab. +** </dd> +** ** </dl> */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -2016,6 +2070,7 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ /* @@ -2679,7 +2734,8 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** [database connection], supplied in the first argument. ** ^The authorizer callback is invoked as SQL statements are being compiled ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], -** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various +** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()], +** and [sqlite3_prepare16_v3()]. ^At various ** points during the compilation process, as logic is being created ** to perform various actions, the authorizer callback is invoked to ** see if those actions are allowed. ^The authorizer callback should @@ -3086,10 +3142,10 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** ^If [URI filename] interpretation is enabled, and the filename argument ** begins with "file:", then the filename is interpreted as a URI. ^URI ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is -** set in the fourth argument to sqlite3_open_v2(), or if it has +** set in the third argument to sqlite3_open_v2(), or if it has ** been enabled globally using the [SQLITE_CONFIG_URI] option with the ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. -** As of SQLite version 3.7.7, URI filename interpretation is turned off +** URI filename interpretation is turned off ** by default, but future releases of SQLite might enable URI filename ** interpretation by default. See "[URI filenames]" for additional ** information. @@ -3468,6 +3524,29 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +/* +** CAPI3REF: Prepare Flags +** +** These constants define various flags that can be passed into +** "prepFlags" parameter of the [sqlite3_prepare_v3()] and +** [sqlite3_prepare16_v3()] interfaces. +** +** New flags may be added in future releases of SQLite. +** +** <dl> +** [[SQLITE_PREPARE_PERSISTENT]] ^(<dt>SQLITE_PREPARE_PERSISTENT</dt> +** <dd>The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner +** that the prepared statement will be retained for a long time and +** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()] +** and [sqlite3_prepare16_v3()] assume that the prepared statement will +** be used just once or at most a few times and then destroyed using +** [sqlite3_finalize()] relatively soon. The current implementation acts +** on this hint by avoiding the use of [lookaside memory] so as not to +** deplete the limited store of lookaside memory. Future versions of +** SQLite may act on this hint differently. +** </dl> +*/ +#define SQLITE_PREPARE_PERSISTENT 0x01 /* ** CAPI3REF: Compiling An SQL Statement @@ -3475,17 +3554,29 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** METHOD: sqlite3 ** CONSTRUCTOR: sqlite3_stmt ** -** To execute an SQL query, it must first be compiled into a byte-code -** program using one of these routines. +** To execute an SQL statement, it must first be compiled into a byte-code +** program using one of these routines. Or, in other words, these routines +** are constructors for the [prepared statement] object. +** +** The preferred routine to use is [sqlite3_prepare_v2()]. The +** [sqlite3_prepare()] interface is legacy and should be avoided. +** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used +** for special purposes. +** +** The use of the UTF-8 interfaces is preferred, as SQLite currently +** does all parsing using UTF-8. The UTF-16 interfaces are provided +** as a convenience. The UTF-16 interfaces work by converting the +** input text into UTF-8, then invoking the corresponding UTF-8 interface. ** ** The first argument, "db", is a [database connection] obtained from a ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or ** [sqlite3_open16()]. The database connection must not have been closed. ** ** The second argument, "zSql", is the statement to be compiled, encoded -** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() -** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() -** use UTF-16. +** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(), +** and sqlite3_prepare_v3() +** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the ** first zero terminator. ^If nByte is positive, then it is the @@ -3512,10 +3603,11 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; ** otherwise an [error code] is returned. ** -** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are -** recommended for all new programs. The two older interfaces are retained -** for backwards compatibility, but their use is discouraged. -** ^In the "v2" interfaces, the prepared statement +** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() interfaces are recommended for all new programs. +** The older interfaces (sqlite3_prepare() and sqlite3_prepare16()) +** are retained for backwards compatibility, but their use is discouraged. +** ^In the "vX" interfaces, the prepared statement ** that is returned (the [sqlite3_stmt] object) contains a copy of the ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: @@ -3548,6 +3640,12 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. ** </li> +** +** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having +** the extra prepFlags parameter, which is a bit array consisting of zero or +** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The +** sqlite3_prepare_v2() interface works exactly the same as +** sqlite3_prepare_v3() with a zero prepFlags parameter. ** </ol> */ SQLITE_API int sqlite3_prepare( @@ -3564,6 +3662,14 @@ SQLITE_API int sqlite3_prepare_v2( sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); +SQLITE_API int sqlite3_prepare_v3( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); SQLITE_API int sqlite3_prepare16( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ @@ -3578,6 +3684,14 @@ SQLITE_API int sqlite3_prepare16_v2( sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); +SQLITE_API int sqlite3_prepare16_v3( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); /* ** CAPI3REF: Retrieving Statement SQL @@ -3585,7 +3699,8 @@ SQLITE_API int sqlite3_prepare16_v2( ** ** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 ** SQL text used to create [prepared statement] P if P was -** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], +** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. @@ -3704,8 +3819,9 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); ** implementation of [application-defined SQL functions] are protected. ** ^The sqlite3_value object returned by ** [sqlite3_column_value()] is unprotected. -** Unprotected sqlite3_value objects may only be used with -** [sqlite3_result_value()] and [sqlite3_bind_value()]. +** Unprotected sqlite3_value objects may only be used as arguments +** to [sqlite3_result_value()], [sqlite3_bind_value()], and +** [sqlite3_value_dup()]. ** The [sqlite3_value_blob | sqlite3_value_type()] family of ** interfaces require protected sqlite3_value objects. */ @@ -3811,6 +3927,15 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_blob_open | incremental BLOB I/O] routines. ** ^A negative value for the zeroblob results in a zero-length BLOB. ** +** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in +** [prepared statement] S to have an SQL value of NULL, but to also be +** associated with the pointer P of type T. ^D is either a NULL pointer or +** a pointer to a destructor function for P. ^SQLite will invoke the +** destructor D with a single argument of P when it is finished using +** P. The T parameter should be a static string, preferably a string +** literal. The sqlite3_bind_pointer() routine is part of the +** [pointer passing interface] added for SQLite 3.20.0. +** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which ** [sqlite3_step()] has been called more recently than [sqlite3_reset()], @@ -3844,6 +3969,7 @@ SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*) SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void(*)(void*), unsigned char encoding); SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); +SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); @@ -3887,8 +4013,8 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); ** ^If the value N is out of range or if the N-th parameter is ** nameless, then NULL is returned. ^The returned string is ** always in UTF-8 encoding even if the named parameter was -** originally specified as UTF-16 in [sqlite3_prepare16()] or -** [sqlite3_prepare16_v2()]. +** originally specified as UTF-16 in [sqlite3_prepare16()], +** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and @@ -3905,7 +4031,8 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); ** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero ** is returned if no matching parameter is found. ^The parameter ** name must be given in UTF-8 even if the original statement -** was prepared from UTF-16 text using [sqlite3_prepare16_v2()]. +** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or +** [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and @@ -4059,16 +4186,18 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** CAPI3REF: Evaluate An SQL Statement ** METHOD: sqlite3_stmt ** -** After a [prepared statement] has been prepared using either -** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy +** After a [prepared statement] has been prepared using any of +** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()], +** or [sqlite3_prepare16_v3()] or one of the legacy ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function ** must be called one or more times to evaluate the statement. ** ** The details of the behavior of the sqlite3_step() interface depend -** on whether the statement was prepared using the newer "v2" interface -** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy -** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the -** new "v2" interface is recommended for new applications but the legacy +** on whether the statement was prepared using the newer "vX" interfaces +** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()], +** [sqlite3_prepare16_v2()] or the older legacy +** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the +** new "vX" interface is recommended for new applications but the legacy ** interface will continue to be supported. ** ** ^In the legacy interface, the return value will be either [SQLITE_BUSY], @@ -4129,10 +4258,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** specific [error codes] that better describes the error. ** We admit that this is a goofy design. The problem has been fixed ** with the "v2" interface. If you prepare all of your SQL statements -** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead +** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()] +** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, ** then the more specific [error codes] are returned directly -** by sqlite3_step(). The use of the "v2" interface is recommended. +** by sqlite3_step(). The use of the "vX" interfaces is recommended. */ SQLITE_API int sqlite3_step(sqlite3_stmt*); @@ -4194,6 +4324,28 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** KEYWORDS: {column access functions} ** METHOD: sqlite3_stmt ** +** <b>Summary:</b> +** <blockquote><table border=0 cellpadding=0 cellspacing=0> +** <tr><td><b>sqlite3_column_blob</b><td>→<td>BLOB result +** <tr><td><b>sqlite3_column_double</b><td>→<td>REAL result +** <tr><td><b>sqlite3_column_int</b><td>→<td>32-bit INTEGER result +** <tr><td><b>sqlite3_column_int64</b><td>→<td>64-bit INTEGER result +** <tr><td><b>sqlite3_column_text</b><td>→<td>UTF-8 TEXT result +** <tr><td><b>sqlite3_column_text16</b><td>→<td>UTF-16 TEXT result +** <tr><td><b>sqlite3_column_value</b><td>→<td>The result as an +** [sqlite3_value|unprotected sqlite3_value] object. +** <tr><td> <td> <td> +** <tr><td><b>sqlite3_column_bytes</b><td>→<td>Size of a BLOB +** or a UTF-8 TEXT result in bytes +** <tr><td><b>sqlite3_column_bytes16 </b> +** <td>→ <td>Size of UTF-16 +** TEXT in bytes +** <tr><td><b>sqlite3_column_type</b><td>→<td>Default +** datatype of the result +** </table></blockquote> +** +** <b>Details:</b> +** ** ^These routines return information about a single column of the current ** result row of a query. ^In every case the first argument is a pointer ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] @@ -4215,16 +4367,29 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** are called from a different thread while any of these routines ** are pending, then the results are undefined. ** +** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16) +** each return the value of a result column in a specific data format. If +** the result column is not initially in the requested format (for example, +** if the query returns an integer but the sqlite3_column_text() interface +** is used to extract the value) then an automatic type conversion is performed. +** ** ^The sqlite3_column_type() routine returns the ** [SQLITE_INTEGER | datatype code] for the initial data type ** of the result column. ^The returned value is one of [SQLITE_INTEGER], -** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value -** returned by sqlite3_column_type() is only meaningful if no type -** conversions have occurred as described below. After a type conversion, -** the value returned by sqlite3_column_type() is undefined. Future +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. +** The return value of sqlite3_column_type() can be used to decide which +** of the first six interface should be used to extract the column value. +** The value returned by sqlite3_column_type() is only meaningful if no +** automatic type conversions have occurred for the value in question. +** After a type conversion, the result of calling sqlite3_column_type() +** is undefined, though harmless. Future ** versions of SQLite may change the behavior of sqlite3_column_type() ** following a type conversion. ** +** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes() +** or sqlite3_column_bytes16() interfaces can be used to determine the size +** of that BLOB or string. +** ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() ** routine returns the number of bytes in that BLOB or string. ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts @@ -4261,9 +4426,13 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** [sqlite3_column_value()] is used in any other way, including calls ** to routines like [sqlite3_value_int()], [sqlite3_value_text()], ** or [sqlite3_value_bytes()], the behavior is not threadsafe. +** Hence, the sqlite3_column_value() interface +** is normally only useful within the implementation of +** [application-defined SQL functions] or [virtual tables], not within +** top-level application code. ** -** These routines attempt to convert the value where appropriate. ^For -** example, if the internal representation is FLOAT and a text result +** The these routines may attempt to convert the datatype of the result. +** ^For example, if the internal representation is FLOAT and a text result ** is requested, [sqlite3_snprintf()] is used internally to perform the ** conversion automatically. ^(The following table details the conversions ** that are applied: @@ -4335,7 +4504,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings -** and BLOBs is freed automatically. Do <em>not</em> pass the pointers returned +** and BLOBs is freed automatically. Do not pass the pointers returned ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** @@ -4346,15 +4515,15 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** [SQLITE_NOMEM].)^ */ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); /* ** CAPI3REF: Destroy A Prepared Statement Object @@ -4588,21 +4757,40 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** CAPI3REF: Obtaining SQL Values ** METHOD: sqlite3_value ** -** The C-language implementation of SQL functions and aggregates uses -** this set of interface routines to access the parameter values on -** the function or aggregate. -** -** The xFunc (for scalar functions) or xStep (for aggregates) parameters -** to [sqlite3_create_function()] and [sqlite3_create_function16()] -** define callbacks that implement the SQL functions and aggregates. -** The 3rd parameter to these callbacks is an array of pointers to -** [protected sqlite3_value] objects. There is one [sqlite3_value] object for -** each parameter to the SQL function. These routines are used to -** extract values from the [sqlite3_value] objects. +** <b>Summary:</b> +** <blockquote><table border=0 cellpadding=0 cellspacing=0> +** <tr><td><b>sqlite3_value_blob</b><td>→<td>BLOB value +** <tr><td><b>sqlite3_value_double</b><td>→<td>REAL value +** <tr><td><b>sqlite3_value_int</b><td>→<td>32-bit INTEGER value +** <tr><td><b>sqlite3_value_int64</b><td>→<td>64-bit INTEGER value +** <tr><td><b>sqlite3_value_pointer</b><td>→<td>Pointer value +** <tr><td><b>sqlite3_value_text</b><td>→<td>UTF-8 TEXT value +** <tr><td><b>sqlite3_value_text16</b><td>→<td>UTF-16 TEXT value in +** the native byteorder +** <tr><td><b>sqlite3_value_text16be</b><td>→<td>UTF-16be TEXT value +** <tr><td><b>sqlite3_value_text16le</b><td>→<td>UTF-16le TEXT value +** <tr><td> <td> <td> +** <tr><td><b>sqlite3_value_bytes</b><td>→<td>Size of a BLOB +** or a UTF-8 TEXT in bytes +** <tr><td><b>sqlite3_value_bytes16 </b> +** <td>→ <td>Size of UTF-16 +** TEXT in bytes +** <tr><td><b>sqlite3_value_type</b><td>→<td>Default +** datatype of the value +** <tr><td><b>sqlite3_value_numeric_type </b> +** <td>→ <td>Best numeric datatype of the value +** </table></blockquote> +** +** <b>Details:</b> +** +** These routines extract type, size, and content information from +** [protected sqlite3_value] objects. Protected sqlite3_value objects +** are used to pass parameter information into implementation of +** [application-defined SQL functions] and [virtual tables]. ** ** These routines work only with [protected sqlite3_value] objects. ** Any attempt to use these routines on an [unprotected sqlite3_value] -** object results in undefined behavior. +** is not threadsafe. ** ** ^These routines work just like the corresponding [column access functions] ** except that these routines take a single [protected sqlite3_value] object @@ -4613,6 +4801,24 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces ** extract UTF-16 strings as big-endian and little-endian respectively. ** +** ^If [sqlite3_value] object V was initialized +** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)] +** and if X and Y are strings that compare equal according to strcmp(X,Y), +** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise, +** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** +** ^(The sqlite3_value_type(V) interface returns the +** [SQLITE_INTEGER | datatype code] for the initial datatype of the +** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER], +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ +** Other interfaces might change the datatype for an sqlite3_value object. +** For example, if the datatype is initially SQLITE_INTEGER and +** sqlite3_value_text(V) is called to extract a text value for that +** integer, then subsequent calls to sqlite3_value_type(V) might return +** SQLITE_TEXT. Whether or not a persistent internal datatype conversion +** occurs is undefined and may change from one release of SQLite to the next. +** ** ^(The sqlite3_value_numeric_type() interface attempts to apply ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If @@ -4631,15 +4837,16 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** the SQL function that supplied the [sqlite3_value*] parameters. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); -SQLITE_API int sqlite3_value_bytes(sqlite3_value*); -SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); SQLITE_API int sqlite3_value_int(sqlite3_value*); SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); +SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*); SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); @@ -4652,10 +4859,6 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. -** -** SQLite makes no use of subtype itself. It merely passes the subtype -** from the result of one [application-defined SQL function] into the -** input of another. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); @@ -4925,7 +5128,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** when it has finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT -** then SQLite makes a copy of the result into space obtained from +** then SQLite makes a copy of the result into space obtained ** from [sqlite3_malloc()] before it returns. ** ** ^The sqlite3_result_value() interface sets the result of @@ -4938,6 +5141,17 @@ typedef void (*sqlite3_destructor_type)(void*); ** [unprotected sqlite3_value] object is required, so either ** kind of [sqlite3_value] object can be used with this interface. ** +** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an +** SQL NULL value, just like [sqlite3_result_null(C)], except that it +** also associates the host-language pointer P or type T with that +** NULL value such that the pointer can be retrieved within an +** [application-defined SQL function] using [sqlite3_value_pointer()]. +** ^If the D parameter is not NULL, then it is a pointer to a destructor +** for the P parameter. ^SQLite invokes D with P as its only argument +** when SQLite is finished with P. The T parameter should be a static +** string and preferably a string literal. The sqlite3_result_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** ** If these routines are called from within the different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. @@ -4961,6 +5175,7 @@ SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(* SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); +SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*)); SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); @@ -5620,7 +5835,9 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** ^If the column-name parameter to sqlite3_table_column_metadata() is a ** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it -** does not. +** does not. If the table name parameter T in a call to +** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is +** undefined behavior. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^(The second parameter is either the name of the database @@ -6030,15 +6247,20 @@ struct sqlite3_index_info { ** an operator that is part of a constraint term in the wHERE clause of ** a query that uses a [virtual table]. */ -#define SQLITE_INDEX_CONSTRAINT_EQ 2 -#define SQLITE_INDEX_CONSTRAINT_GT 4 -#define SQLITE_INDEX_CONSTRAINT_LE 8 -#define SQLITE_INDEX_CONSTRAINT_LT 16 -#define SQLITE_INDEX_CONSTRAINT_GE 32 -#define SQLITE_INDEX_CONSTRAINT_MATCH 64 -#define SQLITE_INDEX_CONSTRAINT_LIKE 65 -#define SQLITE_INDEX_CONSTRAINT_GLOB 66 -#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 +#define SQLITE_INDEX_CONSTRAINT_EQ 2 +#define SQLITE_INDEX_CONSTRAINT_GT 4 +#define SQLITE_INDEX_CONSTRAINT_LE 8 +#define SQLITE_INDEX_CONSTRAINT_LT 16 +#define SQLITE_INDEX_CONSTRAINT_GE 32 +#define SQLITE_INDEX_CONSTRAINT_MATCH 64 +#define SQLITE_INDEX_CONSTRAINT_LIKE 65 +#define SQLITE_INDEX_CONSTRAINT_GLOB 66 +#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 +#define SQLITE_INDEX_CONSTRAINT_NE 68 +#define SQLITE_INDEX_CONSTRAINT_ISNOT 69 +#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 +#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 +#define SQLITE_INDEX_CONSTRAINT_IS 72 /* ** CAPI3REF: Register A Virtual Table Implementation @@ -6790,7 +7012,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_RESERVE 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 -#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 +#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 @@ -6849,8 +7071,7 @@ SQLITE_API int sqlite3_status64( ** <dd>This parameter is the current amount of memory checked out ** using [sqlite3_malloc()], either directly or indirectly. The ** figure includes calls made to [sqlite3_malloc()] by the application -** and internal memory usage by the SQLite library. Scratch memory -** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache +** and internal memory usage by the SQLite library. Auxiliary page-cache ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in ** this parameter. The amount returned is the sum of the allocation ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^ @@ -6888,29 +7109,14 @@ SQLITE_API int sqlite3_status64( ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.</dd>)^ ** -** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> -** <dd>This parameter returns the number of allocations used out of the -** [scratch memory allocator] configured using -** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not -** in bytes. Since a single thread may only have one scratch allocation -** outstanding at time, this parameter also reports the number of threads -** using scratch memory at the same time.</dd>)^ +** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt> +** <dd>No longer used.</dd> ** ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> -** <dd>This parameter returns the number of bytes of scratch memory -** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] -** buffer and where forced to overflow to [sqlite3_malloc()]. The values -** returned include overflows because the requested allocation was too -** larger (that is, because the requested allocation was larger than the -** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer -** slots were available. -** </dd>)^ -** -** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> -** <dd>This parameter records the largest memory allocation request -** handed to [scratch memory allocator]. Only the value returned in the -** *pHighwater parameter to [sqlite3_status()] is of interest. -** The value written into the *pCurrent parameter is undefined.</dd>)^ +** <dd>No longer used.</dd> +** +** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt> +** <dd>No longer used.</dd> ** ** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> ** <dd>The *pHighwater parameter records the deepest parser stack. @@ -6923,12 +7129,12 @@ SQLITE_API int sqlite3_status64( #define SQLITE_STATUS_MEMORY_USED 0 #define SQLITE_STATUS_PAGECACHE_USED 1 #define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 -#define SQLITE_STATUS_SCRATCH_USED 3 -#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 +#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */ +#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */ #define SQLITE_STATUS_MALLOC_SIZE 5 #define SQLITE_STATUS_PARSER_STACK 6 #define SQLITE_STATUS_PAGECACHE_SIZE 7 -#define SQLITE_STATUS_SCRATCH_SIZE 8 +#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */ #define SQLITE_STATUS_MALLOC_COUNT 9 /* @@ -7133,6 +7339,24 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 ** then the value returned by this statement status code is undefined. +** +** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt> +** <dd>^This is the number of times that the prepare statement has been +** automatically regenerated due to schema changes or change to +** [bound parameters] that might affect the query plan. +** +** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt> +** <dd>^This is the number of times that the prepared statement has +** been run. A single "run" for the purposes of this counter is one +** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. +** The counter is incremented on the first [sqlite3_step()] call of each +** cycle. +** +** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt> +** <dd>^This is the approximate number of bytes of heap memory +** used to store the prepared statement. ^This value is not actually +** a counter, and so the resetFlg parameter to sqlite3_stmt_status() +** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED. ** </dd> ** </dl> */ @@ -7140,6 +7364,9 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 #define SQLITE_STMTSTATUS_VM_STEP 4 +#define SQLITE_STMTSTATUS_REPREPARE 5 +#define SQLITE_STMTSTATUS_RUN 6 +#define SQLITE_STMTSTATUS_MEMUSED 99 /* ** CAPI3REF: Custom Page Cache Object @@ -9004,8 +9231,8 @@ SQLITE_API int sqlite3session_diff( */ SQLITE_API int sqlite3session_patchset( sqlite3_session *pSession, /* Session object */ - int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */ - void **ppPatchset /* OUT: Buffer containing changeset */ + int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */ + void **ppPatchset /* OUT: Buffer containing patchset */ ); /* @@ -9772,12 +9999,12 @@ SQLITE_API int sqlite3changeset_apply( ** ** <table border=1 style="margin-left:8ex;margin-right:8ex"> ** <tr><th>Streaming function<th>Non-streaming equivalent</th> -** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply] -** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat] -** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert] -** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start] -** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset] -** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset] +** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply] +** <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat] +** <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert] +** <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start] +** <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset] +** <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset] ** </table> ** ** Non-streaming functions that accept changesets (or patchsets) as input diff --git a/devtools/client/commandline/test/browser_cmd_csscoverage_startstop.js b/devtools/client/commandline/test/browser_cmd_csscoverage_startstop.js index 2bdb86d86..c48136989 100644 --- a/devtools/client/commandline/test/browser_cmd_csscoverage_startstop.js +++ b/devtools/client/commandline/test/browser_cmd_csscoverage_startstop.js @@ -4,6 +4,7 @@ // Tests that the addon commands works as they should const csscoverage = require("devtools/shared/fronts/csscoverage"); +const {gDevTools} = require("devtools/client/framework/devtools"); const PAGE_1 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page1.html"; const PAGE_2 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page2.html"; diff --git a/devtools/client/framework/browser-menus.js b/devtools/client/framework/browser-menus.js index 3d6c4def6..e62afddac 100644 --- a/devtools/client/framework/browser-menus.js +++ b/devtools/client/framework/browser-menus.js @@ -133,10 +133,11 @@ function attachKeybindingsToBrowser(doc, keys) { */ function createToolMenuElements(toolDefinition, doc) { let id = toolDefinition.id; + let appmenuId = "appmenuitem_" + id; let menuId = "menuitem_" + id; // Prevent multiple entries for the same tool. - if (doc.getElementById(menuId)) { + if (doc.getElementById(appmenuId) || doc.getElementById(menuId)) { return; } @@ -156,6 +157,13 @@ function createToolMenuElements(toolDefinition, doc) { }); } + let appmenuitem = createMenuItem({ + doc, + id: "appmenuitem_" + id, + label: toolDefinition.menuLabel || toolDefinition.label, + accesskey: null + }); + let menuitem = createMenuItem({ doc, id: "menuitem_" + id, @@ -166,10 +174,12 @@ function createToolMenuElements(toolDefinition, doc) { // Refer to the key in order to display the key shortcut at menu ends menuitem.setAttribute("key", key.id); } + appmenuitem.addEventListener("command", oncommand); menuitem.addEventListener("command", oncommand); return { key, + appmenuitem, menuitem }; } @@ -186,22 +196,34 @@ function createToolMenuElements(toolDefinition, doc) { * The tool definition after which the tool menu item is to be added. */ function insertToolMenuElements(doc, toolDefinition, prevDef) { - let { key, menuitem } = createToolMenuElements(toolDefinition, doc); + let { key, appmenuitem, menuitem } = createToolMenuElements(toolDefinition, doc); if (key) { attachKeybindingsToBrowser(doc, key); } - let ref; + let amp; + if (prevDef) { + let appmenuitem = doc.getElementById("appmenuitem_" + prevDef.id); + amp = appmenuitem && appmenuitem.nextSibling ? appmenuitem.nextSibling : null; + } else { + amp = doc.getElementById("appmenu_devtools_separator"); + } + + if (amp) { + amp.parentNode.insertBefore(appmenuitem, amp); + } + + let mp; if (prevDef) { let menuitem = doc.getElementById("menuitem_" + prevDef.id); - ref = menuitem && menuitem.nextSibling ? menuitem.nextSibling : null; + mp = menuitem && menuitem.nextSibling ? menuitem.nextSibling : null; } else { - ref = doc.getElementById("menu_devtools_separator"); + mp = doc.getElementById("menu_devtools_separator"); } - if (ref) { - ref.parentNode.insertBefore(menuitem, ref); + if (mp) { + mp.parentNode.insertBefore(menuitem, mp); } } exports.insertToolMenuElements = insertToolMenuElements; @@ -220,6 +242,11 @@ function removeToolFromMenu(toolId, doc) { key.remove(); } + let appmenuitem = doc.getElementById("appmenuitem_" + toolId); + if (appmenuitem) { + appmenuitem.remove(); + } + let menuitem = doc.getElementById("menuitem_" + toolId); if (menuitem) { menuitem.remove(); @@ -235,6 +262,7 @@ exports.removeToolFromMenu = removeToolFromMenu; */ function addAllToolsToMenu(doc) { let fragKeys = doc.createDocumentFragment(); + let fragAppMenuItems = doc.createDocumentFragment(); let fragMenuItems = doc.createDocumentFragment(); for (let toolDefinition of gDevTools.getToolDefinitionArray()) { @@ -251,11 +279,17 @@ function addAllToolsToMenu(doc) { if (elements.key) { fragKeys.appendChild(elements.key); } + fragAppMenuItems.appendChild(elements.appmenuitem); fragMenuItems.appendChild(elements.menuitem); } attachKeybindingsToBrowser(doc, fragKeys); + let amps = doc.getElementById("appmenu_devtools_separator"); + if (amps) { + amps.parentNode.insertBefore(fragAppMenuItems, amps); + } + let mps = doc.getElementById("menu_devtools_separator"); if (mps) { mps.parentNode.insertBefore(fragMenuItems, mps); @@ -270,18 +304,29 @@ function addAllToolsToMenu(doc) { */ function addTopLevelItems(doc) { let keys = doc.createDocumentFragment(); + let appmenuItems = doc.createDocumentFragment(); let menuItems = doc.createDocumentFragment(); let { menuitems } = require("../menus"); for (let item of menuitems) { if (item.separator) { + let appseparator = doc.createElement("menuseparator"); + appseparator.id = "app" + item.id; let separator = doc.createElement("menuseparator"); separator.id = item.id; + appmenuItems.appendChild(appseparator); menuItems.appendChild(separator); } else { let { id, l10nKey } = item; // Create a <menuitem> + let appmenuitem = createMenuItem({ + doc, + id: "app" + id, + label: l10n(l10nKey + ".label"), + accesskey: null, + isCheckbox: item.checkbox + }); let menuitem = createMenuItem({ doc, id, @@ -289,7 +334,9 @@ function addTopLevelItems(doc) { accesskey: l10n(l10nKey + ".accesskey"), isCheckbox: item.checkbox }); + appmenuitem.addEventListener("command", item.oncommand); menuitem.addEventListener("command", item.oncommand); + appmenuItems.appendChild(appmenuitem); menuItems.appendChild(menuitem); if (item.key && l10nKey) { @@ -330,6 +377,9 @@ function addTopLevelItems(doc) { for (let node of keys.children) { nodes.push(node); } + for (let node of appmenuItems.children) { + nodes.push(node); + } for (let node of menuItems.children) { nodes.push(node); } @@ -337,15 +387,33 @@ function addTopLevelItems(doc) { attachKeybindingsToBrowser(doc, keys); + // There are hardcoded menu items in the Web Developer menus plus it is a + // location of menu items via overlays from extensions so we want to make + // sure the last seperator and the "Get More Tools..." items are last. + // This will emulate the behavior when devtools menu items were actually + // physically present in browser.xul + + // Tools > Web Developer let menu = doc.getElementById("menuWebDeveloperPopup"); - menu.appendChild(menuItems); - - // There is still "Page Source" menuitem hardcoded into browser.xul. Instead - // of manually inserting everything around it, move it to the expected - // position. - let pageSource = doc.getElementById("menu_pageSource"); - let endSeparator = doc.getElementById("devToolsEndSeparator"); - menu.insertBefore(pageSource, endSeparator); + // Insert the Devtools Menu Items before everything else + menu.insertBefore(menuItems, menu.firstChild); + // Move the devtools last seperator and Get More Tools menu items to the bottom + let menu_endSeparator = doc.getElementById("menu_devToolsEndSeparator"); + let menu_getMoreDevtools = doc.getElementById("menu_getMoreDevtools"); + menu.insertBefore(menu_getMoreDevtools, null); + menu.insertBefore(menu_endSeparator, menu_getMoreDevtools); + + // Application Menu > Web Developer (If existant) + let appmenu = doc.getElementById("appmenu_webDeveloper_popup"); + if (appmenu) { + // Insert the Devtools Menu Items after the hardcoded idless seperator + appmenu.insertBefore(appmenuItems, appmenu.childNodes[2].nextSibling); + // Move the devtools last seperator and Get More Tools menu items to the bottom + let appmenu_endSeparator = doc.getElementById("appmenu_devToolsEndSeparator"); + let appmenu_getMoreDevtools = doc.getElementById("appmenu_getMoreDevtools"); + appmenu.insertBefore(appmenu_getMoreDevtools, null); + appmenu.insertBefore(appmenu_endSeparator, appmenu_getMoreDevtools); + } } /** diff --git a/devtools/client/framework/devtools-browser.js b/devtools/client/framework/devtools-browser.js index b9f4d92ba..f032f82aa 100644 --- a/devtools/client/framework/devtools-browser.js +++ b/devtools/client/framework/devtools-browser.js @@ -8,7 +8,7 @@ * This is the main module loaded in Firefox desktop that handles browser * windows and coordinates devtools around each window. * - * This module is loaded lazily by devtools-clhandler.js, once the first + * This module is loaded lazily by devtools-startup.js, once the first * browser window is ready (i.e. fired browser-delayed-startup-finished event) **/ @@ -27,8 +27,10 @@ loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true); loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true); loader.lazyRequireGetter(this, "BrowserMenus", "devtools/client/framework/browser-menus"); -loader.lazyImporter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm"); loader.lazyImporter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm"); +#ifdef MC_BASILISK +loader.lazyImporter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm"); +#endif const {LocalizationHelper} = require("devtools/shared/l10n"); const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties"); @@ -85,6 +87,9 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { function toggleMenuItem(id, isEnabled) { let cmd = doc.getElementById(id); + if (!cmd) { + return; + } if (isEnabled) { cmd.removeAttribute("disabled"); cmd.removeAttribute("hidden"); @@ -94,22 +99,39 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { } } + let idEls = []; + // Enable developer toolbar? let devToolbarEnabled = Services.prefs.getBoolPref("devtools.toolbar.enabled"); - toggleMenuItem("menu_devToolbar", devToolbarEnabled); - let focusEl = doc.getElementById("menu_devToolbar"); - if (devToolbarEnabled) { - focusEl.removeAttribute("disabled"); - } else { - focusEl.setAttribute("disabled", "true"); - } + idEls = [ + "appmenu_devToolbar", + "menu_devToolbar" + ]; + idEls.forEach(function (idEl) { + toggleMenuItem(idEl, devToolbarEnabled); + let focusEl = doc.getElementById(idEl); + if (!focusEl) { + return; + } + if (devToolbarEnabled) { + focusEl.removeAttribute("disabled"); + } else { + focusEl.setAttribute("disabled", "true"); + } + }); if (devToolbarEnabled && Services.prefs.getBoolPref("devtools.toolbar.visible")) { win.DeveloperToolbar.show(false).catch(console.error); } // Enable WebIDE? let webIDEEnabled = Services.prefs.getBoolPref("devtools.webide.enabled"); - toggleMenuItem("menu_webide", webIDEEnabled); + idEls = [ + "appmenu_webide", + "menu_webide" + ]; + idEls.forEach(function (idEl) { + toggleMenuItem(idEl, webIDEEnabled); + }); let showWebIDEWidget = Services.prefs.getBoolPref("devtools.webide.widget.enabled"); if (webIDEEnabled && showWebIDEWidget) { @@ -122,11 +144,29 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { let chromeEnabled = Services.prefs.getBoolPref("devtools.chrome.enabled"); let devtoolsRemoteEnabled = Services.prefs.getBoolPref("devtools.debugger.remote-enabled"); let remoteEnabled = chromeEnabled && devtoolsRemoteEnabled; - toggleMenuItem("menu_browserToolbox", remoteEnabled); - toggleMenuItem("menu_browserContentToolbox", remoteEnabled && win.gMultiProcessBrowser); + idEls = [ + "appmenu_browserToolbox", + "menu_browserToolbox" + ]; + idEls.forEach(function (idEl) { + toggleMenuItem(idEl, remoteEnabled); + }); + idEls = [ + "appmenu_browserContentToolbox", + "menu_browserContentToolbox" + ]; + idEls.forEach(function (idEl) { + toggleMenuItem(idEl, remoteEnabled && win.gMultiProcessBrowser); + }); // Enable DevTools connection screen, if the preference allows this. - toggleMenuItem("menu_devtools_connect", devtoolsRemoteEnabled); + idEls = [ + "appmenu_devtools_connect", + "menu_devtools_connect" + ]; + idEls.forEach(function (idEl) { + toggleMenuItem(idEl, devtoolsRemoteEnabled); + }); }, observe: function (subject, topic, prefName) { @@ -295,6 +335,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { * Install Developer widget */ installDeveloperWidget: function () { +#ifdef MC_BASILISK let id = "developer-button"; let widget = CustomizableUI.getWidget(id); if (widget && widget.provider == CustomizableUI.PROVIDER_API) { @@ -343,6 +384,9 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { doc.getElementById("PanelUI-multiView").appendChild(view); } }); +#else + return; +#endif }, /** @@ -350,6 +394,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { */ // Used by itself installWebIDEWidget: function () { +#ifdef MC_BASILISK if (this.isWebIDEWidgetInstalled()) { return; } @@ -371,11 +416,18 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { gDevToolsBrowser.openWebIDE(); } }); +#else + return; +#endif }, isWebIDEWidgetInstalled: function () { +#ifdef MC_BASILISK let widgetWrapper = CustomizableUI.getWidget("webide-button"); return !!(widgetWrapper && widgetWrapper.provider == CustomizableUI.PROVIDER_API); +#else + return false; +#endif }, /** @@ -387,10 +439,14 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { * Uninstall WebIDE widget */ uninstallWebIDEWidget: function () { +#ifdef MC_BASILISK if (this.isWebIDEWidgetInstalled()) { CustomizableUI.removeWidgetFromArea("webide-button"); } CustomizableUI.destroyWidget("webide-button"); +#else + return; +#endif }, /** @@ -398,7 +454,11 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { */ // Used by webide.js moveWebIDEWidgetInNavbar: function () { +#ifdef MC_BASILISK CustomizableUI.addWidgetToArea("webide-button", CustomizableUI.AREA_NAVBAR); +#else + return; +#endif }, /** @@ -591,12 +651,23 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { let hasToolbox = gDevToolsBrowser.hasToolboxOpened(win); - let menu = win.document.getElementById("menu_devToolbox"); - if (hasToolbox) { - menu.setAttribute("checked", "true"); - } else { - menu.removeAttribute("checked"); - } + let idEls = []; + + idEls = [ + "appmenu_devToolbox", + "menu_devToolbox" + ]; + idEls.forEach(function (idEl) { + let menu = win.document.getElementById(idEl); + if (!menu) { + return; + } + if (hasToolbox) { + menu.setAttribute("checked", "true"); + } else { + menu.removeAttribute("checked"); + } + }); } }, diff --git a/devtools/client/framework/moz.build b/devtools/client/framework/moz.build index 7b28b4b9e..407e21f8b 100644 --- a/devtools/client/framework/moz.build +++ b/devtools/client/framework/moz.build @@ -13,7 +13,6 @@ DevToolsModules( 'about-devtools-toolbox.js', 'attach-thread.js', 'browser-menus.js', - 'devtools-browser.js', 'devtools.js', 'gDevTools.jsm', 'location-store.js', @@ -31,3 +30,7 @@ DevToolsModules( 'toolbox.js', 'ToolboxProcess.jsm', ) + +FINAL_TARGET_PP_FILES.chrome.devtools.modules.devtools.client.framework += [ + 'devtools-browser.js', +] diff --git a/devtools/client/framework/test/browser_keybindings_01.js b/devtools/client/framework/test/browser_keybindings_01.js index 4e4effb07..134fb127c 100644 --- a/devtools/client/framework/test/browser_keybindings_01.js +++ b/devtools/client/framework/test/browser_keybindings_01.js @@ -8,6 +8,9 @@ const TEST_URL = "data:text/html,<html><head><title>Test for the " + "highlighter keybindings</title></head><body>" + "<h1>Keybindings!</h1></body></html>" + +const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser"); + function test() { waitForExplicitFinish(); diff --git a/devtools/client/menus.js b/devtools/client/menus.js index 7e36839da..1d2168967 100644 --- a/devtools/client/menus.js +++ b/devtools/client/menus.js @@ -183,9 +183,9 @@ exports.menuitems = [ } }, { separator: true, - id: "devToolsEndSeparator" + id: "menu_devToolsEndSeparator" }, - { id: "getMoreDevtools", + { id: "menu_getMoreDevtools", l10nKey: "getMoreDevtoolsCmd", oncommand(event) { let window = event.target.ownerDocument.defaultView; diff --git a/devtools/client/netmonitor/request-list-context-menu.js b/devtools/client/netmonitor/request-list-context-menu.js index 331a7bde3..bacb7dc33 100644 --- a/devtools/client/netmonitor/request-list-context-menu.js +++ b/devtools/client/netmonitor/request-list-context-menu.js @@ -186,7 +186,6 @@ RequestListContextMenu.prototype = { * Opens selected item in a new tab. */ openRequestInTab() { - let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType); openRequestInTab(this.selectedItem.attachment); }, diff --git a/devtools/client/scratchpad/test/head.js b/devtools/client/scratchpad/test/head.js index 15619a169..955c037d7 100644 --- a/devtools/client/scratchpad/test/head.js +++ b/devtools/client/scratchpad/test/head.js @@ -9,6 +9,7 @@ const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {}); const {console} = Cu.import("resource://gre/modules/Console.jsm", {}); const {ScratchpadManager} = Cu.import("resource://devtools/client/scratchpad/scratchpad-manager.jsm", {}); const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); +const {gDevTools} = require("devtools/client/framework/devtools"); const Services = require("Services"); const DevToolsUtils = require("devtools/shared/DevToolsUtils"); const flags = require("devtools/shared/flags"); diff --git a/devtools/client/shared/developer-toolbar.js b/devtools/client/shared/developer-toolbar.js index 2528591a6..d84402418 100644 --- a/devtools/client/shared/developer-toolbar.js +++ b/devtools/client/shared/developer-toolbar.js @@ -449,7 +449,15 @@ DeveloperToolbar.prototype.show = function (focus) { [ this.tooltipPanel, this.outputPanel ] = panels; - this._doc.getElementById("menu_devToolbar").setAttribute("checked", "true"); + let checkboxValue = "true"; + let appmenuEl = this._doc.getElementById("appmenu_devToolbar"); + let menuEl = this._doc.getElementById("menu_devToolbar"); + if (appmenuEl) { + appmenuEl.setAttribute("checked", checkboxValue); + } + if (menuEl) { + menuEl.setAttribute("checked", checkboxValue); + } this.target = TargetFactory.forTab(this._chromeWindow.gBrowser.selectedTab); const options = { @@ -569,7 +577,15 @@ DeveloperToolbar.prototype.hide = function () { Services.prefs.setBoolPref("devtools.toolbar.visible", false); - this._doc.getElementById("menu_devToolbar").setAttribute("checked", "false"); + let checkboxValue = "false"; + let appmenuEl = this._doc.getElementById("appmenu_devToolbar"); + let menuEl = this._doc.getElementById("menu_devToolbar"); + if (appmenuEl) { + appmenuEl.setAttribute("checked", checkboxValue); + } + if (menuEl) { + menuEl.setAttribute("checked", checkboxValue); + } this.destroy(); this._telemetry.toolClosed("developertoolbar"); diff --git a/devtools/client/webconsole/new-console-output/test/mochitest/head.js b/devtools/client/webconsole/new-console-output/test/mochitest/head.js index b71eaec4f..049f3d1ce 100644 --- a/devtools/client/webconsole/new-console-output/test/mochitest/head.js +++ b/devtools/client/webconsole/new-console-output/test/mochitest/head.js @@ -14,6 +14,7 @@ Services.scriptloader.loadSubScript( var {Utils: WebConsoleUtils} = require("devtools/client/webconsole/utils"); const WEBCONSOLE_STRINGS_URI = "devtools/client/locales/webconsole.properties"; +var {HUDService} = require("devtools/client/webconsole/hudservice"); var WCUL10n = new WebConsoleUtils.L10n(WEBCONSOLE_STRINGS_URI); Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", true); diff --git a/docshell/base/nsAboutRedirector.cpp b/docshell/base/nsAboutRedirector.cpp index e7d362864..e56447296 100644 --- a/docshell/base/nsAboutRedirector.cpp +++ b/docshell/base/nsAboutRedirector.cpp @@ -42,17 +42,14 @@ static RedirEntry kRedirMap[] = { { "buildconfig", "chrome://global/content/buildconfig.html", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::MAKE_LINKABLE + nsIAboutModule::MAKE_LINKABLE }, { "checkerboard", "chrome://global/content/aboutCheckerboard.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::ALLOW_SCRIPT + nsIAboutModule::ALLOW_SCRIPT }, { "config", "chrome://global/content/config.xul", 0 }, -#ifdef MOZ_CRASHREPORTER - { "crashes", "chrome://global/content/crashes.xhtml", 0 }, -#endif { "credits", "http://www.palemoon.org/Contributors.shtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | @@ -67,7 +64,7 @@ static RedirEntry kRedirMap[] = { { "license", "chrome://global/content/license.html", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::MAKE_LINKABLE + nsIAboutModule::MAKE_LINKABLE }, { "logo", "chrome://branding/content/about.png", @@ -75,6 +72,13 @@ static RedirEntry kRedirMap[] = { // Linkable for testing reasons. nsIAboutModule::MAKE_LINKABLE }, +#ifdef MOZ_PHOENIX + { + "logopage", "chrome://global/content/logopage.xhtml", + nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::HIDE_FROM_ABOUTABOUT + }, +#endif { "memory", "chrome://global/content/aboutMemory.xhtml", nsIAboutModule::ALLOW_SCRIPT @@ -86,9 +90,9 @@ static RedirEntry kRedirMap[] = { { "neterror", "chrome://global/content/netError.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::URI_CAN_LOAD_IN_CHILD | - nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT + nsIAboutModule::URI_CAN_LOAD_IN_CHILD | + nsIAboutModule::ALLOW_SCRIPT | + nsIAboutModule::HIDE_FROM_ABOUTABOUT }, { "networking", "chrome://global/content/aboutNetworking.xhtml", @@ -97,7 +101,7 @@ static RedirEntry kRedirMap[] = { { "newaddon", "chrome://mozapps/content/extensions/newaddon.xul", nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT + nsIAboutModule::HIDE_FROM_ABOUTABOUT }, { "performance", "chrome://global/content/aboutPerformance.xhtml", @@ -124,10 +128,10 @@ static RedirEntry kRedirMap[] = { { "srcdoc", "about:blank", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT | - // Needs to be linkable so content can touch its own srcdoc frames - nsIAboutModule::MAKE_LINKABLE | - nsIAboutModule::URI_CAN_LOAD_IN_CHILD + nsIAboutModule::HIDE_FROM_ABOUTABOUT | + // Needs to be linkable so content can touch its own srcdoc frames + nsIAboutModule::MAKE_LINKABLE | + nsIAboutModule::URI_CAN_LOAD_IN_CHILD }, { "support", "chrome://global/content/aboutSupport.xhtml", diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 50641508d..58c182cbb 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -2289,13 +2289,6 @@ nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs) NS_IMETHODIMP nsDocShell::SetRemoteTabs(bool aUseRemoteTabs) { -#ifdef MOZ_CRASHREPORTER - if (aUseRemoteTabs) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("DOMIPCEnabled"), - NS_LITERAL_CSTRING("1")); - } -#endif - mUseRemoteTabs = aUseRemoteTabs; return NS_OK; } diff --git a/docshell/build/nsDocShellModule.cpp b/docshell/build/nsDocShellModule.cpp index d43c305f9..872874012 100644 --- a/docshell/build/nsDocShellModule.cpp +++ b/docshell/build/nsDocShellModule.cpp @@ -165,15 +165,15 @@ const mozilla::Module::ContractIDEntry kDocShellContracts[] = { { NS_ABOUT_MODULE_CONTRACTID_PREFIX "buildconfig", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "checkerboard", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "config", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, -#ifdef MOZ_CRASHREPORTER - { NS_ABOUT_MODULE_CONTRACTID_PREFIX "crashes", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, -#endif { NS_ABOUT_MODULE_CONTRACTID_PREFIX "credits", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, #ifdef MOZ_DEVTOOLS { NS_ABOUT_MODULE_CONTRACTID_PREFIX "debugging", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, #endif { NS_ABOUT_MODULE_CONTRACTID_PREFIX "license", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "logo", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, +#ifdef MOZ_PHOENIX + { NS_ABOUT_MODULE_CONTRACTID_PREFIX "logopage", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, +#endif { NS_ABOUT_MODULE_CONTRACTID_PREFIX "memory", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "mozilla", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "neterror", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index a4bba4856..049bc0a1a 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -51,10 +51,6 @@ #include <algorithm> #include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - #ifdef ANDROID #include <android/log.h> #endif diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index ca4acf114..75678ca96 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -585,11 +585,6 @@ ContentChild::Init(MessageLoop* aIOLoop, SendBackUpXResources(FileDescriptor(xSocketFd)); #endif -#ifdef MOZ_CRASHREPORTER - SendPCrashReporterConstructor(CrashReporter::CurrentThreadId(), - XRE_GetProcessType()); -#endif - SendGetProcessAttributes(&mID, &mIsForApp, &mIsForBrowser); InitProcessAttributes(); @@ -1439,18 +1434,6 @@ ContentChild::RecvSetProcessSandbox(const MaybeFileDesc& aBroker) sandboxEnabled = StartMacOSContentSandbox(); #endif -#if defined(MOZ_CRASHREPORTER) - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxEnabled"), - sandboxEnabled? NS_LITERAL_CSTRING("1") : NS_LITERAL_CSTRING("0")); -#if defined(XP_LINUX) && !defined(OS_ANDROID) - nsAutoCString flagsString; - flagsString.AppendInt(SandboxInfo::Get().AsInteger()); - - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxCapabilities"), flagsString); -#endif /* XP_LINUX && !OS_ANDROID */ -#endif /* MOZ_CRASHREPORTER */ #endif /* MOZ_CONTENT_SANDBOX */ return true; @@ -1740,11 +1723,7 @@ PCrashReporterChild* ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id, const uint32_t& processType) { -#ifdef MOZ_CRASHREPORTER - return new CrashReporterChild(); -#else return nullptr; -#endif } bool @@ -2159,16 +2138,6 @@ ContentChild::ProcessingError(Result aCode, const char* aReason) NS_RUNTIMEABORT("not reached"); } -#if defined(MOZ_CRASHREPORTER) && !defined(MOZ_B2G) - if (PCrashReporterChild* c = LoneManagedOrNullAsserts(ManagedPCrashReporterChild())) { - CrashReporterChild* crashReporter = - static_cast<CrashReporterChild*>(c); - nsDependentCString reason(aReason); - crashReporter->SendAnnotateCrashReport( - NS_LITERAL_CSTRING("ipc_channel_error"), - reason); - } -#endif NS_RUNTIMEABORT("Content child abort due to IPC error"); } @@ -2872,10 +2841,6 @@ ContentChild::RecvShutdown() // to wait for that event loop to finish. Otherwise we could prematurely // terminate an "unload" or "pagehide" event handler (which might be doing a // sync XHR, for example). -#if defined(MOZ_CRASHREPORTER) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"), - NS_LITERAL_CSTRING("RecvShutdown")); -#endif nsCOMPtr<nsIThread> thread; nsresult rv = NS_GetMainThread(getter_AddRefs(thread)); if (NS_SUCCEEDED(rv) && thread) { @@ -2923,10 +2888,6 @@ ContentChild::RecvShutdown() // parent closes. StartForceKillTimer(); -#if defined(MOZ_CRASHREPORTER) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"), - NS_LITERAL_CSTRING("SendFinishShutdown")); -#endif // Ignore errors here. If this fails, the parent will kill us after a // timeout. Unused << SendFinishShutdown(); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index ff40db8d7..73621df22 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -249,10 +249,6 @@ using namespace mozilla::system; #include "mozilla/widget/AudioSession.h" #endif -#ifdef MOZ_CRASHREPORTER -#include "nsThread.h" -#endif - #ifdef ACCESSIBILITY #include "nsAccessibilityService.h" #endif @@ -273,9 +269,6 @@ using base::KillProcess; using mozilla::ProfileGatherer; #endif -#ifdef MOZ_CRASHREPORTER -using namespace CrashReporter; -#endif using namespace mozilla::dom::power; using namespace mozilla::media; using namespace mozilla::embedding; @@ -1847,36 +1840,6 @@ ContentParent::ActorDestroy(ActorDestroyReason why) NS_LITERAL_CSTRING("content"), 1); props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true); - -#ifdef MOZ_CRASHREPORTER - // There's a window in which child processes can crash - // after IPC is established, but before a crash reporter - // is created. - if (PCrashReporterParent* p = LoneManagedOrNullAsserts(ManagedPCrashReporterParent())) { - CrashReporterParent* crashReporter = - static_cast<CrashReporterParent*>(p); - - // If we're an app process, always stomp the latest URI - // loaded in the child process with our manifest URL. We - // would rather associate the crashes with apps than - // random child windows loaded in them. - // - // XXX would be nice if we could get both ... - if (!mAppManifestURL.IsEmpty()) { - crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), - NS_ConvertUTF16toUTF8(mAppManifestURL)); - } - - // if mCreatedPairedMinidumps is true, we've already generated - // parent/child dumps for dekstop crashes. - if (!mCreatedPairedMinidumps) { - crashReporter->GenerateCrashReport(this, nullptr); - } - - nsAutoString dumpID(crashReporter->ChildDumpID()); - props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID); - } -#endif } nsAutoString cpId; cpId.AppendInt(static_cast<uint64_t>(this->ChildID())); @@ -3090,33 +3053,6 @@ ContentParent::KillHard(const char* aReason) mCalledKillHard = true; mForceKillTimer = nullptr; -#if defined(MOZ_CRASHREPORTER) && !defined(MOZ_B2G) - // We're about to kill the child process associated with this content. - // Something has gone wrong to get us here, so we generate a minidump - // of the parent and child for submission to the crash server. - if (PCrashReporterParent* p = LoneManagedOrNullAsserts(ManagedPCrashReporterParent())) { - CrashReporterParent* crashReporter = - static_cast<CrashReporterParent*>(p); - // GeneratePairedMinidump creates two minidumps for us - the main - // one is for the content process we're about to kill, and the other - // one is for the main browser process. That second one is the extra - // minidump tagging along, so we have to tell the crash reporter that - // it exists and is being appended. - nsAutoCString additionalDumps("browser"); - crashReporter->AnnotateCrashReport( - NS_LITERAL_CSTRING("additional_minidumps"), - additionalDumps); - nsDependentCString reason(aReason); - crashReporter->AnnotateCrashReport( - NS_LITERAL_CSTRING("ipc_channel_error"), - reason); - - // Generate the report and insert into the queue for submittal. - mCreatedPairedMinidumps = crashReporter->GenerateCompleteMinidump(this); - - Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1); - } -#endif ProcessHandle otherProcessHandle; if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) { NS_ERROR("Failed to open child process when attempting kill."); @@ -3168,11 +3104,7 @@ PCrashReporterParent* ContentParent::AllocPCrashReporterParent(const NativeThreadId& tid, const uint32_t& processType) { -#ifdef MOZ_CRASHREPORTER - return new CrashReporterParent(); -#else return nullptr; -#endif } bool @@ -5001,9 +4933,6 @@ ContentParent::RecvNotifyPushSubscriptionModifiedObservers(const nsCString& aSco bool ContentParent::RecvNotifyLowMemory() { -#ifdef MOZ_CRASHREPORTER - nsThread::SaveMemoryReportNearOOM(nsThread::ShouldSaveMemoryReport::kForceReport); -#endif return true; } diff --git a/dom/ipc/CrashReporterParent.cpp b/dom/ipc/CrashReporterParent.cpp index fc627387f..677b29670 100644 --- a/dom/ipc/CrashReporterParent.cpp +++ b/dom/ipc/CrashReporterParent.cpp @@ -13,13 +13,6 @@ #include "mozilla/Telemetry.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#include "nsICrashService.h" -#include "mozilla/SyncRunnable.h" -#include "nsThreadUtils.h" -#endif - namespace mozilla { namespace dom { @@ -29,9 +22,6 @@ void CrashReporterParent::AnnotateCrashReport(const nsCString& key, const nsCString& data) { -#ifdef MOZ_CRASHREPORTER - mNotes.Put(key, data); -#endif } void @@ -49,9 +39,6 @@ CrashReporterParent::RecvAppendAppNotes(const nsCString& data) CrashReporterParent::CrashReporterParent() : -#ifdef MOZ_CRASHREPORTER - mNotes(4), -#endif mStartTime(::time(nullptr)) , mInitialized(false) { @@ -72,75 +59,5 @@ CrashReporterParent::SetChildData(const NativeThreadId& tid, mProcessType = GeckoProcessType(processType); } -#ifdef MOZ_CRASHREPORTER -bool -CrashReporterParent::GenerateCrashReportForMinidump(nsIFile* minidump, - const AnnotationTable* processNotes) -{ - if (!CrashReporter::GetIDFromMinidump(minidump, mChildDumpID)) { - return false; - } - - bool result = GenerateChildData(processNotes); - FinalizeChildData(); - return result; -} - -bool -CrashReporterParent::GenerateChildData(const AnnotationTable* processNotes) -{ - MOZ_ASSERT(mInitialized); - - if (mChildDumpID.IsEmpty()) { - NS_WARNING("problem with GenerateChildData: no child dump id yet!"); - return false; - } - - nsAutoCString type; - switch (mProcessType) { - case GeckoProcessType_Content: - type = NS_LITERAL_CSTRING("content"); - break; - case GeckoProcessType_Plugin: - case GeckoProcessType_GMPlugin: - type = NS_LITERAL_CSTRING("plugin"); - break; - default: - NS_ERROR("unknown process type"); - break; - } - mNotes.Put(NS_LITERAL_CSTRING("ProcessType"), type); - - char startTime[32]; - SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime)); - mNotes.Put(NS_LITERAL_CSTRING("StartupTime"), nsDependentCString(startTime)); - - if (!mAppNotes.IsEmpty()) { - mNotes.Put(NS_LITERAL_CSTRING("Notes"), mAppNotes); - } - - // Append these notes to the end of the extra file based on the current - // dump id we obtained from CreatePairedMinidumps. - bool ret = CrashReporter::AppendExtraData(mChildDumpID, mNotes); - if (ret && processNotes) { - ret = CrashReporter::AppendExtraData(mChildDumpID, *processNotes); - } - - if (!ret) { - NS_WARNING("problem appending child data to .extra"); - } - return ret; -} - -void -CrashReporterParent::FinalizeChildData() -{ - MOZ_ASSERT(mInitialized); - - CrashReporterHost::NotifyCrashService(mProcessType, mChildDumpID, &mNotes); - mNotes.Clear(); -} -#endif - } // namespace dom } // namespace mozilla diff --git a/dom/ipc/CrashReporterParent.h b/dom/ipc/CrashReporterParent.h index 25824f279..71896c5c1 100644 --- a/dom/ipc/CrashReporterParent.h +++ b/dom/ipc/CrashReporterParent.h @@ -10,122 +10,16 @@ #include "mozilla/dom/PCrashReporterParent.h" #include "mozilla/dom/TabMessageUtils.h" #include "nsIFile.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#include "nsDataHashtable.h" -#endif namespace mozilla { namespace dom { class CrashReporterParent : public PCrashReporterParent { -#ifdef MOZ_CRASHREPORTER - typedef CrashReporter::AnnotationTable AnnotationTable; -#endif public: CrashReporterParent(); virtual ~CrashReporterParent(); -#ifdef MOZ_CRASHREPORTER - - /* - * Attempt to create a bare-bones crash report, along with extra process- - * specific annotations present in the given AnnotationTable. Calls - * GenerateChildData and FinalizeChildData. - * - * @returns true if successful, false otherwise. - */ - template<class Toplevel> - bool - GenerateCrashReport(Toplevel* t, const AnnotationTable* processNotes); - - /* - * Attempt to generate a parent/child pair of minidumps from the given - * toplevel actor. This calls CrashReporter::CreateMinidumpsAndPair to - * generate the minidumps. Crash reporter annotations set prior to this - * call will be saved via PairedDumpCallbackExtra into an .extra file - * under the proper crash id. AnnotateCrashReport annotations are not - * set in this call and the report is not finalized. - * - * @returns true if successful, false otherwise. - */ - template<class Toplevel> - bool - GeneratePairedMinidump(Toplevel* t); - - /* - * Attempts to take a minidump of the current process and pair that with - * a named minidump handed in by the caller. - * - * @param aTopLevel - top level actor this reporter is associated with. - * @param aMinidump - the minidump to associate with. - * @param aPairName - the name of the additional minidump. - * @returns true if successful, false otherwise. - */ - template<class Toplevel> - bool - GenerateMinidumpAndPair(Toplevel* aTopLevel, nsIFile* aMinidump, - const nsACString& aPairName); - - /** - * Apply child process annotations to an existing paired mindump generated - * with GeneratePairedMinidump. - * - * Be careful about calling generate apis immediately after this call, - * see FinalizeChildData. - * - * @param processNotes (optional) - Additional notes to append. Annotations - * stored in mNotes will also be applied. processNotes can be null. - * @returns true if successful, false otherwise. - */ - bool - GenerateChildData(const AnnotationTable* processNotes); - - /** - * Handles main thread finalization tasks after a report has been - * generated. Does the following: - * - register the finished report with the crash service manager - * - records telemetry related data about crashes - * - * Be careful about calling generate apis immediately after this call, - * if this api is called on a non-main thread it will fire off a runnable - * to complete its work async. - */ - void - FinalizeChildData(); - - /* - * Attempt to generate a full paired dump complete with any child - * annoations, and finalizes the report. Note this call is only valid - * on the main thread. Calling on a background thread will fail. - * - * @returns true if successful, false otherwise. - */ - template<class Toplevel> - bool - GenerateCompleteMinidump(Toplevel* t); - - /** - * Submits a raw minidump handed in, calls GenerateChildData and - * FinalizeChildData. Used by content plugins and gmp. - * - * @returns true if successful, false otherwise. - */ - bool - GenerateCrashReportForMinidump(nsIFile* minidump, - const AnnotationTable* processNotes); - - /* - * Instantiate a new crash reporter actor from a given parent that manages - * the protocol. - * - * @returns true if successful, false otherwise. - */ - template<class Toplevel> - static bool CreateCrashReporter(Toplevel* actor); -#endif // MOZ_CRASHREPORTER - /* * Initialize this reporter with data from the child process. */ @@ -160,14 +54,6 @@ public: virtual bool RecvAppendAppNotes(const nsCString& aData) override; -#ifdef MOZ_CRASHREPORTER - void - NotifyCrashService(); -#endif - -#ifdef MOZ_CRASHREPORTER - AnnotationTable mNotes; -#endif nsCString mAppNotes; nsString mChildDumpID; // stores the child main thread id @@ -178,128 +64,6 @@ public: bool mInitialized; }; -#ifdef MOZ_CRASHREPORTER -template<class Toplevel> -inline bool -CrashReporterParent::GeneratePairedMinidump(Toplevel* t) -{ - mozilla::ipc::ScopedProcessHandle child; -#ifdef XP_MACOSX - child = t->Process()->GetChildTask(); -#else - if (!base::OpenPrivilegedProcessHandle(t->OtherPid(), &child.rwget())) { - NS_WARNING("Failed to open child process handle."); - return false; - } -#endif - nsCOMPtr<nsIFile> childDump; - if (CrashReporter::CreateMinidumpsAndPair(child, - mMainThread, - NS_LITERAL_CSTRING("browser"), - nullptr, // pair with a dump of this process and thread - getter_AddRefs(childDump)) && - CrashReporter::GetIDFromMinidump(childDump, mChildDumpID)) { - return true; - } - return false; -} - -template<class Toplevel> -inline bool -CrashReporterParent::GenerateMinidumpAndPair(Toplevel* aTopLevel, - nsIFile* aMinidumpToPair, - const nsACString& aPairName) -{ - mozilla::ipc::ScopedProcessHandle childHandle; -#ifdef XP_MACOSX - childHandle = aTopLevel->Process()->GetChildTask(); -#else - if (!base::OpenPrivilegedProcessHandle(aTopLevel->OtherPid(), - &childHandle.rwget())) { - NS_WARNING("Failed to open child process handle."); - return false; - } -#endif - nsCOMPtr<nsIFile> targetDump; - if (CrashReporter::CreateMinidumpsAndPair(childHandle, - mMainThread, // child thread id - aPairName, - aMinidumpToPair, - getter_AddRefs(targetDump)) && - CrashReporter::GetIDFromMinidump(targetDump, mChildDumpID)) { - return true; - } - return false; -} - -template<class Toplevel> -inline bool -CrashReporterParent::GenerateCrashReport(Toplevel* t, - const AnnotationTable* processNotes) -{ - nsCOMPtr<nsIFile> crashDump; - if (t->TakeMinidump(getter_AddRefs(crashDump), nullptr) && - CrashReporter::GetIDFromMinidump(crashDump, mChildDumpID)) { - bool result = GenerateChildData(processNotes); - FinalizeChildData(); - return result; - } - return false; -} - -template<class Toplevel> -inline bool -CrashReporterParent::GenerateCompleteMinidump(Toplevel* t) -{ - mozilla::ipc::ScopedProcessHandle child; - if (!NS_IsMainThread()) { - NS_WARNING("GenerateCompleteMinidump can't be called on non-main thread."); - return false; - } - -#ifdef XP_MACOSX - child = t->Process()->GetChildTask(); -#else - if (!base::OpenPrivilegedProcessHandle(t->OtherPid(), &child.rwget())) { - NS_WARNING("Failed to open child process handle."); - return false; - } -#endif - nsCOMPtr<nsIFile> childDump; - if (CrashReporter::CreateMinidumpsAndPair(child, - mMainThread, - NS_LITERAL_CSTRING("browser"), - nullptr, // pair with a dump of this process and thread - getter_AddRefs(childDump)) && - CrashReporter::GetIDFromMinidump(childDump, mChildDumpID)) { - bool result = GenerateChildData(nullptr); - FinalizeChildData(); - return result; - } - return false; -} - -template<class Toplevel> -/* static */ bool -CrashReporterParent::CreateCrashReporter(Toplevel* actor) -{ -#ifdef MOZ_CRASHREPORTER - NativeThreadId id; - uint32_t processType; - PCrashReporterParent* p = - actor->CallPCrashReporterConstructor(&id, &processType); - if (p) { - static_cast<CrashReporterParent*>(p)->SetChildData(id, processType); - } else { - NS_ERROR("Error creating crash reporter actor"); - } - return !!p; -#endif - return false; -} - -#endif - } // namespace dom } // namespace mozilla diff --git a/dom/ipc/ProcessHangMonitor.cpp b/dom/ipc/ProcessHangMonitor.cpp index b574be61f..d46a1f5d5 100644 --- a/dom/ipc/ProcessHangMonitor.cpp +++ b/dom/ipc/ProcessHangMonitor.cpp @@ -27,9 +27,6 @@ #include "nsITabParent.h" #include "nsPluginHost.h" #include "nsThreadUtils.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif #include "base/task.h" #include "base/thread.h" @@ -556,16 +553,6 @@ HangMonitorParent::HangMonitorParent(ProcessHangMonitor* aMonitor) HangMonitorParent::~HangMonitorParent() { -#ifdef MOZ_CRASHREPORTER - MutexAutoLock lock(mBrowserCrashDumpHashLock); - - for (auto iter = mBrowserCrashDumpIds.Iter(); !iter.Done(); iter.Next()) { - nsString crashId = iter.UserData(); - if (!crashId.IsEmpty()) { - CrashReporter::DeleteMinidumpFilesForID(crashId); - } - } -#endif } void @@ -698,24 +685,6 @@ bool HangMonitorParent::TakeBrowserMinidump(const PluginHangData& aPhd, nsString& aCrashId) { -#ifdef MOZ_CRASHREPORTER - MutexAutoLock lock(mBrowserCrashDumpHashLock); - if (!mBrowserCrashDumpIds.Get(aPhd.pluginId(), &aCrashId)) { - nsCOMPtr<nsIFile> browserDump; - if (CrashReporter::TakeMinidump(getter_AddRefs(browserDump), true)) { - if (!CrashReporter::GetIDFromMinidump(browserDump, aCrashId) - || aCrashId.IsEmpty()) { - browserDump->Remove(false); - NS_WARNING("Failed to generate timely browser stack, " - "this is bad for plugin hang analysis!"); - } else { - mBrowserCrashDumpIds.Put(aPhd.pluginId(), aCrashId); - return true; - } - } - } -#endif // MOZ_CRASHREPORTER - return false; } @@ -840,11 +809,6 @@ HangMonitorParent::CleanupPluginHang(uint32_t aPluginId, bool aRemoveFiles) return; } mBrowserCrashDumpIds.Remove(aPluginId); -#ifdef MOZ_CRASHREPORTER - if (aRemoveFiles && !crashId.IsEmpty()) { - CrashReporter::DeleteMinidumpFilesForID(crashId); - } -#endif } void diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index f46a917d5..c8a0c6e3f 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -52,9 +52,6 @@ #include "nsEmbedCID.h" #include "nsGlobalWindow.h" #include <algorithm> -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif #include "nsFilePickerProxy.h" #include "mozilla/dom/Element.h" #include "nsGlobalWindow.h" @@ -1261,10 +1258,6 @@ TabChild::RecvLoadURL(const nsCString& aURI, NS_WARNING("WebNavigation()->LoadURI failed. Eating exception, what else can I do?"); } -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), aURI); -#endif - return true; } diff --git a/dom/ipc/TabMessageUtils.h b/dom/ipc/TabMessageUtils.h index cdb76099d..2933173d7 100644 --- a/dom/ipc/TabMessageUtils.h +++ b/dom/ipc/TabMessageUtils.h @@ -13,10 +13,6 @@ #include "nsPIDOMWindow.h" #include "nsCOMPtr.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - namespace mozilla { namespace dom { struct RemoteDOMEvent @@ -28,12 +24,8 @@ struct RemoteDOMEvent bool ReadRemoteEvent(const IPC::Message* aMsg, PickleIterator* aIter, mozilla::dom::RemoteDOMEvent* aResult); -#ifdef MOZ_CRASHREPORTER -typedef CrashReporter::ThreadId NativeThreadId; -#else // unused in this case typedef int32_t NativeThreadId; -#endif } // namespace dom } // namespace mozilla diff --git a/dom/media/gmp/GMPChild.cpp b/dom/media/gmp/GMPChild.cpp index 953dae3c6..f8e75e299 100644 --- a/dom/media/gmp/GMPChild.cpp +++ b/dom/media/gmp/GMPChild.cpp @@ -257,10 +257,6 @@ GMPChild::Init(const nsAString& aPluginPath, return false; } -#ifdef MOZ_CRASHREPORTER - SendPCrashReporterConstructor(CrashReporter::CurrentThreadId()); -#endif - mPluginPath = aPluginPath; mSandboxVoucherPath = aVoucherPath; diff --git a/dom/media/gmp/GMPParent.cpp b/dom/media/gmp/GMPParent.cpp index 75468ea9a..00bc97777 100644 --- a/dom/media/gmp/GMPParent.cpp +++ b/dom/media/gmp/GMPParent.cpp @@ -29,12 +29,6 @@ using mozilla::dom::CrashReporterParent; using mozilla::ipc::GeckoChildProcessHost; -#ifdef MOZ_CRASHREPORTER -#include "nsPrintfCString.h" -using CrashReporter::AnnotationTable; -using CrashReporter::GetIDFromMinidump; -#endif - #include "mozilla/Telemetry.h" #ifdef XP_WIN @@ -224,10 +218,6 @@ GMPParent::AbortWaitingForGMPAsyncShutdown(nsITimer* aTimer, void* aClosure) NS_WARNING("Timed out waiting for GMP async shutdown!"); GMPParent* parent = reinterpret_cast<GMPParent*>(aClosure); MOZ_ASSERT(parent->mService); -#if defined(MOZ_CRASHREPORTER) - parent->mService->SetAsyncShutdownPluginState(parent, 'G', - NS_LITERAL_CSTRING("Timed out waiting for async shutdown")); -#endif parent->mService->AsyncShutdownComplete(parent); } @@ -270,22 +260,8 @@ GMPParent::RecvPGMPContentChildDestroyed() { --mGMPContentChildCount; if (!IsUsed()) { -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'E', - NS_LITERAL_CSTRING("Last content child destroyed")); - } -#endif CloseIfUnused(); } -#if defined(MOZ_CRASHREPORTER) - else { - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'F', - nsPrintfCString("Content child destroyed, remaining: %u", mGMPContentChildCount)); - } - } -#endif return true; } @@ -307,38 +283,14 @@ GMPParent::CloseIfUnused() if (mAsyncShutdownRequired) { if (!mAsyncShutdownInProgress) { LOGD("%s: sending async shutdown notification", __FUNCTION__); -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'H', - NS_LITERAL_CSTRING("Sent BeginAsyncShutdown")); - } -#endif mAsyncShutdownInProgress = true; if (!SendBeginAsyncShutdown()) { -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'I', - NS_LITERAL_CSTRING("Could not send BeginAsyncShutdown - Aborting async shutdown")); - } -#endif AbortAsyncShutdown(); } else if (NS_FAILED(EnsureAsyncShutdownTimeoutSet())) { -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'J', - NS_LITERAL_CSTRING("Could not start timer after sending BeginAsyncShutdown - Aborting async shutdown")); - } -#endif AbortAsyncShutdown(); } } } else { -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'K', - NS_LITERAL_CSTRING("No (more) async-shutdown required")); - } -#endif // No async-shutdown, kill async-shutdown timer started in CloseActive(). AbortAsyncShutdown(); // Any async shutdown must be complete. Shutdown GMPStorage. @@ -385,29 +337,11 @@ GMPParent::CloseActive(bool aDieWhenUnloaded) mState = GMPStateUnloading; } if (mState != GMPStateNotLoaded && IsUsed()) { -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'A', - nsPrintfCString("Sent CloseActive, content children to close: %u", mGMPContentChildCount)); - } -#endif if (!SendCloseActive()) { -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'B', - NS_LITERAL_CSTRING("Could not send CloseActive - Aborting async shutdown")); - } -#endif AbortAsyncShutdown(); } else if (IsUsed()) { // We're expecting RecvPGMPContentChildDestroyed's -> Start async-shutdown timer now if needed. if (mAsyncShutdownRequired && NS_FAILED(EnsureAsyncShutdownTimeoutSet())) { -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'C', - NS_LITERAL_CSTRING("Could not start timer after sending CloseActive - Aborting async shutdown")); - } -#endif AbortAsyncShutdown(); } } else { @@ -418,12 +352,6 @@ GMPParent::CloseActive(bool aDieWhenUnloaded) // that time, it might not have proceeded with shutdown; And calling it // again after shutdown is fine because after the first one we'll be in // GMPStateNotLoaded. -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'D', - NS_LITERAL_CSTRING("Content children already destroyed")); - } -#endif CloseIfUnused(); } } @@ -630,78 +558,10 @@ GMPParent::EnsureProcessLoaded() return NS_SUCCEEDED(rv); } -#ifdef MOZ_CRASHREPORTER -void -GMPParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes) -{ - notes.Put(NS_LITERAL_CSTRING("GMPPlugin"), NS_LITERAL_CSTRING("1")); - notes.Put(NS_LITERAL_CSTRING("PluginFilename"), - NS_ConvertUTF16toUTF8(mName)); - notes.Put(NS_LITERAL_CSTRING("PluginName"), mDisplayName); - notes.Put(NS_LITERAL_CSTRING("PluginVersion"), mVersion); -} - -void -GMPParent::GetCrashID(nsString& aResult) -{ - CrashReporterParent* cr = - static_cast<CrashReporterParent*>(LoneManagedOrNullAsserts(ManagedPCrashReporterParent())); - if (NS_WARN_IF(!cr)) { - return; - } - - AnnotationTable notes(4); - WriteExtraDataForMinidump(notes); - nsCOMPtr<nsIFile> dumpFile; - TakeMinidump(getter_AddRefs(dumpFile), nullptr); - if (!dumpFile) { - NS_WARNING("GMP crash without crash report"); - aResult = mName; - aResult += '-'; - AppendUTF8toUTF16(mVersion, aResult); - return; - } - GetIDFromMinidump(dumpFile, aResult); - cr->GenerateCrashReportForMinidump(dumpFile, ¬es); -} - -static void -GMPNotifyObservers(const uint32_t aPluginID, const nsACString& aPluginName, const nsAString& aPluginDumpID) -{ - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - nsCOMPtr<nsIWritablePropertyBag2> propbag = - do_CreateInstance("@mozilla.org/hash-property-bag;1"); - if (obs && propbag) { - propbag->SetPropertyAsUint32(NS_LITERAL_STRING("pluginID"), aPluginID); - propbag->SetPropertyAsACString(NS_LITERAL_STRING("pluginName"), aPluginName); - propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"), aPluginDumpID); - obs->NotifyObservers(propbag, "gmp-plugin-crash", nullptr); - } - - RefPtr<gmp::GeckoMediaPluginService> service = - gmp::GeckoMediaPluginService::GetGeckoMediaPluginService(); - if (service) { - service->RunPluginCrashCallbacks(aPluginID, aPluginName); - } -} -#endif void GMPParent::ActorDestroy(ActorDestroyReason aWhy) { LOGD("%s: (%d)", __FUNCTION__, (int)aWhy); -#ifdef MOZ_CRASHREPORTER - if (AbnormalShutdown == aWhy) { - Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, - NS_LITERAL_CSTRING("gmplugin"), 1); - nsString dumpID; - GetCrashID(dumpID); - - // NotifyObservers is mainthread-only - NS_DispatchToMainThread(WrapRunnableNM(&GMPNotifyObservers, - mPluginId, mDisplayName, dumpID), - NS_DISPATCH_NORMAL); - } -#endif // warn us off trying to close again mState = GMPStateClosing; mAbnormalShutdownInProgress = true; @@ -711,12 +571,6 @@ GMPParent::ActorDestroy(ActorDestroyReason aWhy) if (AbnormalShutdown == aWhy) { RefPtr<GMPParent> self(this); if (mAsyncShutdownRequired) { -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'M', - NS_LITERAL_CSTRING("Actor destroyed")); - } -#endif mService->AsyncShutdownComplete(this); mAsyncShutdownRequired = false; } @@ -732,9 +586,7 @@ GMPParent::ActorDestroy(ActorDestroyReason aWhy) mozilla::dom::PCrashReporterParent* GMPParent::AllocPCrashReporterParent(const NativeThreadId& aThread) { -#ifndef MOZ_CRASHREPORTER MOZ_ASSERT(false, "Should only be sent if crash reporting is enabled."); -#endif CrashReporterParent* cr = new CrashReporterParent(); cr->SetChildData(aThread, GeckoProcessType_GMPlugin); return cr; @@ -1043,12 +895,6 @@ GMPParent::RecvAsyncShutdownComplete() LOGD("%s", __FUNCTION__); MOZ_ASSERT(mAsyncShutdownRequired); -#if defined(MOZ_CRASHREPORTER) - if (mService) { - mService->SetAsyncShutdownPluginState(this, 'L', - NS_LITERAL_CSTRING("Received AsyncShutdownComplete")); - } -#endif AbortAsyncShutdown(); return true; } diff --git a/dom/media/gmp/GMPParent.h b/dom/media/gmp/GMPParent.h index 91a6fb429..4f91ec5ba 100644 --- a/dom/media/gmp/GMPParent.h +++ b/dom/media/gmp/GMPParent.h @@ -25,17 +25,6 @@ class nsIThread; -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" - -namespace mozilla { -namespace dom { -class PCrashReporterParent; -class CrashReporterParent; -} -} -#endif - namespace mozilla { namespace gmp { @@ -177,10 +166,6 @@ private: RefPtr<GenericPromise> ReadGMPInfoFile(nsIFile* aFile); RefPtr<GenericPromise> ParseChromiumManifest(nsString aJSON); // Main thread. RefPtr<GenericPromise> ReadChromiumManifestFile(nsIFile* aFile); // GMP thread. -#ifdef MOZ_CRASHREPORTER - void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes); - void GetCrashID(nsString& aResult); -#endif void ActorDestroy(ActorDestroyReason aWhy) override; PCrashReporterParent* AllocPCrashReporterParent(const NativeThreadId& aThread) override; diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp index 8741989e3..f25c36811 100644 --- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -36,10 +36,6 @@ #include "nsHashKeys.h" #include "nsIFile.h" #include "nsISimpleEnumerator.h" -#if defined(MOZ_CRASHREPORTER) -#include "nsExceptionHandler.h" -#include "nsPrintfCString.h" -#endif #include "nsIXULRuntime.h" #include "GMPDecoderModule.h" #include <limits> @@ -88,9 +84,6 @@ NS_IMPL_ISUPPORTS_INHERITED(GeckoMediaPluginServiceParent, GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent() : mShuttingDown(false) -#ifdef MOZ_CRASHREPORTER - , mAsyncShutdownPluginStatesMutex("GeckoMediaPluginService::mAsyncShutdownPluginStatesMutex") -#endif , mScannedPluginOnDisk(false) , mWaitingForPluginsSyncShutdown(false) , mInitPromiseMonitor("GeckoMediaPluginServiceParent::mInitPromiseMonitor") @@ -421,28 +414,16 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject, if (gmpThread) { LOGD(("%s::%s Starting to unload plugins, waiting for first sync shutdown..." , __CLASS__, __FUNCTION__)); -#ifdef MOZ_CRASHREPORTER - SetAsyncShutdownPluginState(nullptr, '0', - NS_LITERAL_CSTRING("Dispatching UnloadPlugins")); -#endif gmpThread->Dispatch( NewRunnableMethod(this, &GeckoMediaPluginServiceParent::UnloadPlugins), NS_DISPATCH_NORMAL); -#ifdef MOZ_CRASHREPORTER - SetAsyncShutdownPluginState(nullptr, '1', - NS_LITERAL_CSTRING("Waiting for sync shutdown")); -#endif // Wait for UnloadPlugins() to do initial sync shutdown... while (mWaitingForPluginsSyncShutdown) { NS_ProcessNextEvent(NS_GetCurrentThread(), true); } -#ifdef MOZ_CRASHREPORTER - SetAsyncShutdownPluginState(nullptr, '4', - NS_LITERAL_CSTRING("Waiting for async shutdown")); -#endif // Wait for other plugins (if any) to do async shutdown... auto syncShutdownPluginsRemaining = std::numeric_limits<decltype(mAsyncShutdownPlugins.Length())>::max(); @@ -452,10 +433,6 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject, if (mAsyncShutdownPlugins.IsEmpty()) { LOGD(("%s::%s Finished unloading all plugins" , __CLASS__, __FUNCTION__)); -#if defined(MOZ_CRASHREPORTER) - CrashReporter::RemoveCrashReportAnnotation( - NS_LITERAL_CSTRING("AsyncPluginShutdown")); -#endif break; } else if (mAsyncShutdownPlugins.Length() < syncShutdownPluginsRemaining) { // First time here, or number of pending plugins has decreased. @@ -463,24 +440,10 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject, syncShutdownPluginsRemaining = mAsyncShutdownPlugins.Length(); LOGD(("%s::%s Still waiting for %d plugins to shutdown..." , __CLASS__, __FUNCTION__, (int)syncShutdownPluginsRemaining)); -#if defined(MOZ_CRASHREPORTER) - nsAutoCString names; - for (const auto& plugin : mAsyncShutdownPlugins) { - if (!names.IsEmpty()) { names.Append(NS_LITERAL_CSTRING(", ")); } - names.Append(plugin->GetDisplayName()); - } - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("AsyncPluginShutdown"), - names); -#endif } } NS_ProcessNextEvent(NS_GetCurrentThread(), true); } -#ifdef MOZ_CRASHREPORTER - SetAsyncShutdownPluginState(nullptr, '5', - NS_LITERAL_CSTRING("Async shutdown complete")); -#endif } else { // GMP thread has already shutdown. MOZ_ASSERT(mPlugins.IsEmpty()); @@ -627,66 +590,6 @@ GeckoMediaPluginServiceParent::AsyncShutdownComplete(GMPParent* aParent) } } -#ifdef MOZ_CRASHREPORTER -void -GeckoMediaPluginServiceParent::SetAsyncShutdownPluginState(GMPParent* aGMPParent, - char aId, - const nsCString& aState) -{ - MutexAutoLock lock(mAsyncShutdownPluginStatesMutex); - if (!aGMPParent) { - mAsyncShutdownPluginStates.Update(NS_LITERAL_CSTRING("-"), - NS_LITERAL_CSTRING("-"), - aId, - aState); - return; - } - mAsyncShutdownPluginStates.Update(aGMPParent->GetDisplayName(), - nsPrintfCString("%p", aGMPParent), - aId, - aState); -} - -void -GeckoMediaPluginServiceParent::AsyncShutdownPluginStates::Update(const nsCString& aPlugin, - const nsCString& aInstance, - char aId, - const nsCString& aState) -{ - nsCString note; - StatesByInstance* instances = mStates.LookupOrAdd(aPlugin); - if (!instances) { return; } - State* state = instances->LookupOrAdd(aInstance); - if (!state) { return; } - state->mStateSequence += aId; - state->mLastStateDescription = aState; - note += '{'; - bool firstPlugin = true; - for (auto pluginIt = mStates.ConstIter(); !pluginIt.Done(); pluginIt.Next()) { - if (!firstPlugin) { note += ','; } else { firstPlugin = false; } - note += pluginIt.Key(); - note += ":{"; - bool firstInstance = true; - for (auto instanceIt = pluginIt.UserData()->ConstIter(); !instanceIt.Done(); instanceIt.Next()) { - if (!firstInstance) { note += ','; } else { firstInstance = false; } - note += instanceIt.Key(); - note += ":\""; - note += instanceIt.UserData()->mStateSequence; - note += '='; - note += instanceIt.UserData()->mLastStateDescription; - note += '"'; - } - note += '}'; - } - note += '}'; - LOGD(("%s::%s states[%s][%s]='%c'/'%s' -> %s", __CLASS__, __FUNCTION__, - aPlugin.get(), aInstance.get(), aId, aState.get(), note.get())); - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("AsyncPluginShutdownStates"), - note); -} -#endif // MOZ_CRASHREPORTER - void GeckoMediaPluginServiceParent::NotifyAsyncShutdownComplete() { @@ -714,10 +617,6 @@ GeckoMediaPluginServiceParent::UnloadPlugins() MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); MOZ_ASSERT(!mShuttingDownOnGMPThread); mShuttingDownOnGMPThread = true; -#ifdef MOZ_CRASHREPORTER - SetAsyncShutdownPluginState(nullptr, '2', - NS_LITERAL_CSTRING("Starting to unload plugins")); -#endif nsTArray<RefPtr<GMPParent>> plugins; { @@ -742,17 +641,9 @@ GeckoMediaPluginServiceParent::UnloadPlugins() // Note: CloseActive may be async; it could actually finish // shutting down when all the plugins have unloaded. for (const auto& plugin : plugins) { -#ifdef MOZ_CRASHREPORTER - SetAsyncShutdownPluginState(plugin, 'S', - NS_LITERAL_CSTRING("CloseActive")); -#endif plugin->CloseActive(true); } -#ifdef MOZ_CRASHREPORTER - SetAsyncShutdownPluginState(nullptr, '3', - NS_LITERAL_CSTRING("Dispatching sync-shutdown-complete")); -#endif nsCOMPtr<nsIRunnable> task(NewRunnableMethod( this, &GeckoMediaPluginServiceParent::NotifySyncShutdownComplete)); NS_DispatchToMainThread(task); diff --git a/dom/media/gmp/GMPServiceParent.h b/dom/media/gmp/GMPServiceParent.h index f3f43e215..49d81055b 100644 --- a/dom/media/gmp/GMPServiceParent.h +++ b/dom/media/gmp/GMPServiceParent.h @@ -54,9 +54,6 @@ public: void AsyncShutdownComplete(GMPParent* aParent); int32_t AsyncShutdownTimeoutMs(); -#ifdef MOZ_CRASHREPORTER - void SetAsyncShutdownPluginState(GMPParent* aGMPParent, char aId, const nsCString& aState); -#endif // MOZ_CRASHREPORTER RefPtr<GenericPromise> EnsureInitialized(); RefPtr<GenericPromise> AsyncAddPluginDirectory(const nsAString& aDirectory); @@ -169,21 +166,6 @@ private: bool mShuttingDown; nsTArray<RefPtr<GMPParent>> mAsyncShutdownPlugins; -#ifdef MOZ_CRASHREPORTER - Mutex mAsyncShutdownPluginStatesMutex; // Protects mAsyncShutdownPluginStates. - class AsyncShutdownPluginStates - { - public: - void Update(const nsCString& aPlugin, const nsCString& aInstance, - char aId, const nsCString& aState); - private: - struct State { nsCString mStateSequence; nsCString mLastStateDescription; }; - typedef nsClassHashtable<nsCStringHashKey, State> StatesByInstance; - typedef nsClassHashtable<nsCStringHashKey, StatesByInstance> StateInstancesByPlugin; - StateInstancesByPlugin mStates; - } mAsyncShutdownPluginStates; -#endif // MOZ_CRASHREPORTER - // True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any // plugins found there into mPlugins. Atomic<bool> mScannedPluginOnDisk; diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index bd71d6f65..916bdea0f 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -109,10 +109,6 @@ #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) #endif -#if MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - #include "npapi.h" using namespace mozilla; @@ -962,12 +958,6 @@ nsPluginHost::TrySetUpPluginInstance(const nsACString &aMimeType, plugin->GetLibrary()->SetHasLocalInstance(); -#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_CRASHREPORTER) - if (pluginTag->mIsFlashPlugin) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FlashVersion"), pluginTag->Version()); - } -#endif - RefPtr<nsNPAPIPluginInstance> instance = new nsNPAPIPluginInstance(); // This will create the owning reference. The connection must be made between the diff --git a/dom/plugins/base/nsPluginsDirDarwin.cpp b/dom/plugins/base/nsPluginsDirDarwin.cpp index 6edc4fd6a..0085eec0d 100644 --- a/dom/plugins/base/nsPluginsDirDarwin.cpp +++ b/dom/plugins/base/nsPluginsDirDarwin.cpp @@ -26,9 +26,6 @@ #include "mozilla/UniquePtr.h" #include "nsCocoaFeatures.h" -#if defined(MOZ_CRASHREPORTER) -#include "nsExceptionHandler.h" -#endif #include <string.h> #include <stdio.h> @@ -487,14 +484,6 @@ nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary) NS_WARNING(msg.get()); return NS_ERROR_FAILURE; } -#if defined(MOZ_CRASHREPORTER) - // The block above assumes that "fbplugin" is the filename of the plugin - // to be blocked, or that the filename starts with "fbplugin_". But we - // don't yet know for sure if this is always true. So for the time being - // record extra information in our crash logs. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Bug_1086977"), - fileName); -#endif } // It's possible that our plugin has 2 entry points that'll give us mime type @@ -504,14 +493,6 @@ nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary) // Sadly we have to load the library for this to work. rv = LoadPlugin(outLibrary); -#if defined(MOZ_CRASHREPORTER) - if (nsCocoaFeatures::OnYosemiteOrLater()) { - // If we didn't crash in LoadPlugin(), change the previous annotation so we - // don't sow confusion. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Bug_1086977"), - NS_LITERAL_CSTRING("Didn't crash, please ignore")); - } -#endif if (NS_FAILED(rv)) return rv; diff --git a/dom/plugins/ipc/PluginMessageUtils.h b/dom/plugins/ipc/PluginMessageUtils.h index 55be59d62..4532fac93 100644 --- a/dom/plugins/ipc/PluginMessageUtils.h +++ b/dom/plugins/ipc/PluginMessageUtils.h @@ -23,9 +23,6 @@ #include "nsTArray.h" #include "mozilla/Logging.h" #include "nsHashKeys.h" -#ifdef MOZ_CRASHREPORTER -# include "nsExceptionHandler.h" -#endif #ifdef XP_MACOSX #include "PluginInterposeOSX.h" #else diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index 84dc7c71f..7350a7fa7 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -753,10 +753,6 @@ PluginModuleChild::AnswerPCrashReporterConstructor( mozilla::dom::NativeThreadId* id, uint32_t* processType) { -#ifdef MOZ_CRASHREPORTER - *id = CrashReporter::CurrentThreadId(); - *processType = XRE_GetProcessType(); -#endif return true; } diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index b85a3e94b..73f9c1025 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -74,12 +74,6 @@ using namespace mozilla; using namespace mozilla::plugins; using namespace mozilla::plugins::parent; -#ifdef MOZ_CRASHREPORTER -#include "mozilla/dom/CrashReporterParent.h" - -using namespace CrashReporter; -#endif - static const char kContentTimeoutPref[] = "dom.ipc.plugins.contentTimeoutSecs"; static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs"; static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs"; @@ -134,66 +128,6 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId, return true; } -#ifdef MOZ_CRASHREPORTER_INJECTOR - -/** - * Use for executing CreateToolhelp32Snapshot off main thread - */ -class mozilla::plugins::FinishInjectorInitTask : public mozilla::CancelableRunnable -{ -public: - FinishInjectorInitTask() - : mMutex("FlashInjectorInitTask::mMutex") - , mParent(nullptr) - , mMainThreadMsgLoop(MessageLoop::current()) - { - MOZ_ASSERT(NS_IsMainThread()); - } - - void Init(PluginModuleChromeParent* aParent) - { - MOZ_ASSERT(aParent); - mParent = aParent; - } - - void PostToMainThread() - { - RefPtr<Runnable> self = this; - mSnapshot.own(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); - { // Scope for lock - mozilla::MutexAutoLock lock(mMutex); - if (mMainThreadMsgLoop) { - mMainThreadMsgLoop->PostTask(self.forget()); - } - } - } - - NS_IMETHOD Run() override - { - mParent->DoInjection(mSnapshot); - // We don't need to hold this lock during DoInjection, but we do need - // to obtain it before returning from Run() to ensure that - // PostToMainThread has completed before we return. - mozilla::MutexAutoLock lock(mMutex); - return NS_OK; - } - - nsresult Cancel() override - { - mozilla::MutexAutoLock lock(mMutex); - mMainThreadMsgLoop = nullptr; - return NS_OK; - } - -private: - mozilla::Mutex mMutex; - nsAutoHandle mSnapshot; - PluginModuleChromeParent* mParent; - MessageLoop* mMainThreadMsgLoop; -}; - -#endif // MOZ_CRASHREPORTER_INJECTOR - namespace { /** @@ -578,29 +512,6 @@ PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded) RegisterSettingsCallbacks(); -#ifdef MOZ_CRASHREPORTER - // If this fails, we're having IPC troubles, and we're doomed anyways. - if (!CrashReporterParent::CreateCrashReporter(this)) { - mShutdown = true; - Close(); - OnInitFailure(); - return; - } - CrashReporterParent* crashReporter = CrashReporter(); - if (crashReporter) { - crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"), - mIsStartingAsync ? - NS_LITERAL_CSTRING("1") : - NS_LITERAL_CSTRING("0")); - } -#ifdef XP_WIN - { // Scope for lock - mozilla::MutexAutoLock lock(mCrashReporterMutex); - mCrashReporter = CrashReporter(); - } -#endif -#endif - #if defined(XP_WIN) && defined(_X86_) // Protected mode only applies to Windows and only to x86. if (!mIsBlocklisted && mIsFlashPlugin && @@ -686,12 +597,6 @@ PluginModuleParent::PluginModuleParent(bool aIsChrome, bool aAllowAsyncInit) , mIsNPShutdownPending(false) , mAsyncNewRv(NS_ERROR_NOT_INITIALIZED) { -#if defined(MOZ_CRASHREPORTER) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"), - mIsStartingAsync ? - NS_LITERAL_CSTRING("1") : - NS_LITERAL_CSTRING("0")); -#endif } PluginModuleParent::~PluginModuleParent() @@ -734,15 +639,6 @@ PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, , mHangUIParent(nullptr) , mHangUIEnabled(true) , mIsTimerReset(true) -#ifdef MOZ_CRASHREPORTER - , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex") - , mCrashReporter(nullptr) -#endif -#endif -#ifdef MOZ_CRASHREPORTER_INJECTOR - , mFlashProcess1(0) - , mFlashProcess2(0) - , mFinishInitTask(nullptr) #endif , mInitOnAsyncConnect(false) , mAsyncInitRv(NS_ERROR_NOT_INITIALIZED) @@ -790,17 +686,6 @@ PluginModuleChromeParent::~PluginModuleChromeParent() mSubprocess = nullptr; } -#ifdef MOZ_CRASHREPORTER_INJECTOR - if (mFlashProcess1) - UnregisterInjectorCallback(mFlashProcess1); - if (mFlashProcess2) - UnregisterInjectorCallback(mFlashProcess2); - if (mFinishInitTask) { - // mFinishInitTask will be deleted by the main thread message_loop - mFinishInitTask->Cancel(); - } -#endif - UnregisterSettingsCallbacks(); Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this); @@ -818,52 +703,6 @@ PluginModuleChromeParent::~PluginModuleChromeParent() mozilla::HangMonitor::UnregisterAnnotator(*this); } -#ifdef MOZ_CRASHREPORTER -void -PluginModuleChromeParent::WriteExtraDataForMinidump(AnnotationTable& notes) -{ -#ifdef XP_WIN - // mCrashReporterMutex is already held by the caller - mCrashReporterMutex.AssertCurrentThreadOwns(); -#endif - typedef nsDependentCString CS; - - // Get the plugin filename, try to get just the file leafname - const std::string& pluginFile = mSubprocess->GetPluginFilePath(); - size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR); - if (filePos == std::string::npos) - filePos = 0; - else - filePos++; - notes.Put(NS_LITERAL_CSTRING("PluginFilename"), CS(pluginFile.substr(filePos).c_str())); - - notes.Put(NS_LITERAL_CSTRING("PluginName"), mPluginName); - notes.Put(NS_LITERAL_CSTRING("PluginVersion"), mPluginVersion); - - CrashReporterParent* crashReporter = CrashReporter(); - if (crashReporter) { -#ifdef XP_WIN - if (mPluginCpuUsageOnHang.Length() > 0) { - notes.Put(NS_LITERAL_CSTRING("NumberOfProcessors"), - nsPrintfCString("%d", PR_GetNumberOfProcessors())); - - nsCString cpuUsageStr; - cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100); - notes.Put(NS_LITERAL_CSTRING("PluginCpuUsage"), cpuUsageStr); - -#ifdef MOZ_CRASHREPORTER_INJECTOR - for (uint32_t i=1; i<mPluginCpuUsageOnHang.Length(); ++i) { - nsCString tempStr; - tempStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[i] * 100) / 100); - notes.Put(nsPrintfCString("CpuUsageFlashProcess%d", i), tempStr); - } -#endif - } -#endif - } -} -#endif // MOZ_CRASHREPORTER - void PluginModuleParent::SetChildTimeout(const int32_t aChildTimeout) { @@ -1123,20 +962,6 @@ PluginModuleChromeParent::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aA } } -#ifdef MOZ_CRASHREPORTER -static bool -CreatePluginMinidump(base::ProcessId processId, ThreadId childThread, - nsIFile* parentMinidump, const nsACString& name) -{ - mozilla::ipc::ScopedProcessHandle handle; - if (processId == 0 || - !base::OpenPrivilegedProcessHandle(processId, &handle.rwget())) { - return false; - } - return CreateAdditionalChildMinidump(handle, 0, parentMinidump, name); -} -#endif - bool PluginModuleChromeParent::ShouldContinueFromReplyTimeout() { @@ -1184,87 +1009,7 @@ PluginModuleChromeParent::TakeFullMinidump(base::ProcessId aContentPid, const nsAString& aBrowserDumpId, nsString& aDumpId) { -#ifdef MOZ_CRASHREPORTER -#ifdef XP_WIN - mozilla::MutexAutoLock lock(mCrashReporterMutex); -#endif // XP_WIN - - CrashReporterParent* crashReporter = CrashReporter(); - if (!crashReporter) { - return; - } - - bool reportsReady = false; - - // Check to see if we already have a browser dump id - with e10s plugin - // hangs we take this earlier (see ProcessHangMonitor) from a background - // thread. We do this before we message the main thread about the hang - // since the posted message will trash our browser stack state. - bool exists; - nsCOMPtr<nsIFile> browserDumpFile; - if (!aBrowserDumpId.IsEmpty() && - CrashReporter::GetMinidumpForID(aBrowserDumpId, getter_AddRefs(browserDumpFile)) && - browserDumpFile && - NS_SUCCEEDED(browserDumpFile->Exists(&exists)) && exists) - { - // We have a single browser report, generate a new plugin process parent - // report and pair it up with the browser report handed in. - reportsReady = crashReporter->GenerateMinidumpAndPair(this, browserDumpFile, - NS_LITERAL_CSTRING("browser")); - if (!reportsReady) { - browserDumpFile = nullptr; - CrashReporter::DeleteMinidumpFilesForID(aBrowserDumpId); - } - } - - // Generate crash report including plugin and browser process minidumps. - // The plugin process is the parent report with additional dumps including - // the browser process, content process when running under e10s, and - // various flash subprocesses if we're the flash module. - if (!reportsReady) { - reportsReady = crashReporter->GeneratePairedMinidump(this); - } - - if (reportsReady) { - // Important to set this here, it tells the ActorDestroy handler - // that we have an existing crash report that needs to be finalized. - mPluginDumpID = crashReporter->ChildDumpID(); - aDumpId = mPluginDumpID; - PLUGIN_LOG_DEBUG( - ("generated paired browser/plugin minidumps: %s)", - NS_ConvertUTF16toUTF8(mPluginDumpID).get())); - nsAutoCString additionalDumps("browser"); - nsCOMPtr<nsIFile> pluginDumpFile; - if (GetMinidumpForID(mPluginDumpID, getter_AddRefs(pluginDumpFile)) && - pluginDumpFile) { -#ifdef MOZ_CRASHREPORTER_INJECTOR - // If we have handles to the flash sandbox processes on Windows, - // include those minidumps as well. - if (CreatePluginMinidump(mFlashProcess1, 0, pluginDumpFile, - NS_LITERAL_CSTRING("flash1"))) { - additionalDumps.AppendLiteral(",flash1"); - } - if (CreatePluginMinidump(mFlashProcess2, 0, pluginDumpFile, - NS_LITERAL_CSTRING("flash2"))) { - additionalDumps.AppendLiteral(",flash2"); - } -#endif // MOZ_CRASHREPORTER_INJECTOR - if (aContentPid != mozilla::ipc::kInvalidProcessId) { - // Include the content process minidump - if (CreatePluginMinidump(aContentPid, 0, - pluginDumpFile, - NS_LITERAL_CSTRING("content"))) { - additionalDumps.AppendLiteral(",content"); - } - } - } - crashReporter->AnnotateCrashReport( - NS_LITERAL_CSTRING("additional_minidumps"), - additionalDumps); - } else { - NS_WARNING("failed to capture paired minidumps from hang"); - } -#endif // MOZ_CRASHREPORTER + /*** STUB ***/ } void @@ -1273,43 +1018,6 @@ PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop, const nsCString& aMonitorDescription, const nsAString& aDumpId) { -#ifdef MOZ_CRASHREPORTER - // Start by taking a full minidump if necessary, this is done early - // because it also needs to lock the mCrashReporterMutex and Mutex doesn't - // support recrusive locking. - nsAutoString dumpId; - if (aDumpId.IsEmpty()) { - TakeFullMinidump(aContentPid, EmptyString(), dumpId); - } - -#ifdef XP_WIN - mozilla::MutexAutoLock lock(mCrashReporterMutex); - CrashReporterParent* crashReporter = mCrashReporter; - if (!crashReporter) { - // If mCrashReporter is null then the hang has ended, the plugin module - // is shutting down. There's nothing to do here. - return; - } -#else - CrashReporterParent* crashReporter = CrashReporter(); -#endif // XP_WIN - crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("PluginHang"), - NS_LITERAL_CSTRING("1")); - crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("HangMonitorDescription"), - aMonitorDescription); -#ifdef XP_WIN - if (mHangUIParent) { - unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs(); - if (hangUIDuration) { - nsPrintfCString strHangUIDuration("%u", hangUIDuration); - crashReporter->AnnotateCrashReport( - NS_LITERAL_CSTRING("PluginHangUIDuration"), - strHangUIDuration); - } - } -#endif // XP_WIN -#endif // MOZ_CRASHREPORTER - mozilla::ipc::ScopedProcessHandle geckoChildProcess; bool childOpened = base::OpenProcessHandle(OtherPid(), &geckoChildProcess.rwget()); @@ -1323,19 +1031,6 @@ PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop, processHandles.AppendElement(geckoChildProcess); } -#ifdef MOZ_CRASHREPORTER_INJECTOR - mozilla::ipc::ScopedProcessHandle flashBrokerProcess; - if (mFlashProcess1 && - base::OpenProcessHandle(mFlashProcess1, &flashBrokerProcess.rwget())) { - processHandles.AppendElement(flashBrokerProcess); - } - mozilla::ipc::ScopedProcessHandle flashSandboxProcess; - if (mFlashProcess2 && - base::OpenProcessHandle(mFlashProcess2, &flashSandboxProcess.rwget())) { - processHandles.AppendElement(flashSandboxProcess); - } -#endif - if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) { mPluginCpuUsageOnHang.Clear(); } @@ -1482,108 +1177,6 @@ PluginModuleChromeParent::OnHangUIContinue() } #endif // XP_WIN -#ifdef MOZ_CRASHREPORTER -CrashReporterParent* -PluginModuleChromeParent::CrashReporter() -{ - return static_cast<CrashReporterParent*>(LoneManagedOrNullAsserts(ManagedPCrashReporterParent())); -} - -#ifdef MOZ_CRASHREPORTER_INJECTOR -static void -RemoveMinidump(nsIFile* minidump) -{ - if (!minidump) - return; - - minidump->Remove(false); - nsCOMPtr<nsIFile> extraFile; - if (GetExtraFileForMinidump(minidump, - getter_AddRefs(extraFile))) { - extraFile->Remove(true); - } -} -#endif // MOZ_CRASHREPORTER_INJECTOR - -void -PluginModuleChromeParent::ProcessFirstMinidump() -{ -#ifdef XP_WIN - mozilla::MutexAutoLock lock(mCrashReporterMutex); -#endif - CrashReporterParent* crashReporter = CrashReporter(); - if (!crashReporter) - return; - - AnnotationTable notes(4); - WriteExtraDataForMinidump(notes); - - if (!mPluginDumpID.IsEmpty()) { - // mPluginDumpID may be set in TerminateChildProcess, which means the - // process hang monitor has already collected a 3-way browser, plugin, - // content crash report. If so, update the existing report with our - // annotations and finalize it. If not, fall through for standard - // plugin crash report handling. - crashReporter->GenerateChildData(¬es); - crashReporter->FinalizeChildData(); - return; - } - - uint32_t sequence = UINT32_MAX; - nsCOMPtr<nsIFile> dumpFile; - nsAutoCString flashProcessType; - TakeMinidump(getter_AddRefs(dumpFile), &sequence); - -#ifdef MOZ_CRASHREPORTER_INJECTOR - nsCOMPtr<nsIFile> childDumpFile; - uint32_t childSequence; - - if (mFlashProcess1 && - TakeMinidumpForChild(mFlashProcess1, - getter_AddRefs(childDumpFile), - &childSequence)) { - if (childSequence < sequence) { - RemoveMinidump(dumpFile); - dumpFile = childDumpFile; - sequence = childSequence; - flashProcessType.AssignLiteral("Broker"); - } - else { - RemoveMinidump(childDumpFile); - } - } - if (mFlashProcess2 && - TakeMinidumpForChild(mFlashProcess2, - getter_AddRefs(childDumpFile), - &childSequence)) { - if (childSequence < sequence) { - RemoveMinidump(dumpFile); - dumpFile = childDumpFile; - sequence = childSequence; - flashProcessType.AssignLiteral("Sandbox"); - } - else { - RemoveMinidump(childDumpFile); - } - } -#endif - - if (!dumpFile) { - NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!"); - return; - } - - PLUGIN_LOG_DEBUG(("got child minidump: %s", - NS_ConvertUTF16toUTF8(mPluginDumpID).get())); - - GetIDFromMinidump(dumpFile, mPluginDumpID); - if (!flashProcessType.IsEmpty()) { - notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType); - } - crashReporter->GenerateCrashReportForMinidump(dumpFile, ¬es); -} -#endif - void PluginModuleParent::ActorDestroy(ActorDestroyReason why) { @@ -1621,9 +1214,6 @@ void PluginModuleChromeParent::ActorDestroy(ActorDestroyReason why) { if (why == AbnormalShutdown) { -#ifdef MOZ_CRASHREPORTER - ProcessFirstMinidump(); -#endif Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, NS_LITERAL_CSTRING("plugin"), 1); } @@ -2405,9 +1995,6 @@ PluginModuleChromeParent::RecvNP_InitializeResult(const NPError& aError) } #endif -#ifdef MOZ_CRASHREPORTER_INJECTOR - InitializeInjector(); -#endif } return PluginModuleParent::RecvNP_InitializeResult(aError) && ok; @@ -2955,24 +2542,12 @@ PCrashReporterParent* PluginModuleChromeParent::AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id, uint32_t* processType) { -#ifdef MOZ_CRASHREPORTER - return new CrashReporterParent(); -#else return nullptr; -#endif } bool PluginModuleChromeParent::DeallocPCrashReporterParent(PCrashReporterParent* actor) { -#ifdef MOZ_CRASHREPORTER -#ifdef XP_WIN - mozilla::MutexAutoLock lock(mCrashReporterMutex); - if (actor == static_cast<PCrashReporterParent*>(mCrashReporter)) { - mCrashReporter = nullptr; - } -#endif -#endif delete actor; return true; } @@ -3134,107 +2709,6 @@ PluginModuleParent::AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges( return true; } -#ifdef MOZ_CRASHREPORTER_INJECTOR - -// We only add the crash reporter to subprocess which have the filename -// FlashPlayerPlugin* -#define FLASH_PROCESS_PREFIX "FLASHPLAYERPLUGIN" - -static DWORD -GetFlashChildOfPID(DWORD pid, HANDLE snapshot) -{ - PROCESSENTRY32 entry = { - sizeof(entry) - }; - for (BOOL ok = Process32First(snapshot, &entry); - ok; - ok = Process32Next(snapshot, &entry)) { - if (entry.th32ParentProcessID == pid) { - nsString name(entry.szExeFile); - ToUpperCase(name); - if (StringBeginsWith(name, NS_LITERAL_STRING(FLASH_PROCESS_PREFIX))) { - return entry.th32ProcessID; - } - } - } - return 0; -} - -// We only look for child processes of the Flash plugin, NPSWF* -#define FLASH_PLUGIN_PREFIX "NPSWF" - -void -PluginModuleChromeParent::InitializeInjector() -{ - if (!Preferences::GetBool("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", false)) - return; - - nsCString path(Process()->GetPluginFilePath().c_str()); - ToUpperCase(path); - int32_t lastSlash = path.RFindCharInSet("\\/"); - if (kNotFound == lastSlash) - return; - - if (!StringBeginsWith(Substring(path, lastSlash + 1), - NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX))) - return; - - TimeStamp th32Start = TimeStamp::Now(); - mFinishInitTask = mChromeTaskFactory.NewTask<FinishInjectorInitTask>(); - mFinishInitTask->Init(this); - if (!::QueueUserWorkItem(&PluginModuleChromeParent::GetToolhelpSnapshot, - mFinishInitTask, WT_EXECUTEDEFAULT)) { - mFinishInitTask = nullptr; - return; - } - TimeStamp th32End = TimeStamp::Now(); - mTimeBlocked += (th32End - th32Start); -} - -void -PluginModuleChromeParent::DoInjection(const nsAutoHandle& aSnapshot) -{ - DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle()); - mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, aSnapshot); - if (mFlashProcess1) { - InjectCrashReporterIntoProcess(mFlashProcess1, this); - - mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, aSnapshot); - if (mFlashProcess2) { - InjectCrashReporterIntoProcess(mFlashProcess2, this); - } - } - mFinishInitTask = nullptr; -} - -DWORD WINAPI -PluginModuleChromeParent::GetToolhelpSnapshot(LPVOID aContext) -{ - FinishInjectorInitTask* task = static_cast<FinishInjectorInitTask*>(aContext); - MOZ_ASSERT(task); - task->PostToMainThread(); - return 0; -} - -void -PluginModuleChromeParent::OnCrash(DWORD processID) -{ - if (!mShutdown) { - GetIPCChannel()->CloseWithError(); - mozilla::ipc::ScopedProcessHandle geckoPluginChild; - if (base::OpenProcessHandle(OtherPid(), &geckoPluginChild.rwget())) { - if (!base::KillProcess(geckoPluginChild, - base::PROCESS_END_KILLED_BY_USER, false)) { - NS_ERROR("May have failed to kill child process."); - } - } else { - NS_ERROR("Failed to open child process when attempting kill."); - } - } -} - -#endif // MOZ_CRASHREPORTER_INJECTOR - #ifdef MOZ_ENABLE_PROFILER_SPS class PluginProfilerObserver final : public nsIObserver, public nsSupportsWeakReference diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h index cc24d6ed2..946d4c236 100644 --- a/dom/plugins/ipc/PluginModuleParent.h +++ b/dom/plugins/ipc/PluginModuleParent.h @@ -26,10 +26,6 @@ #include "nsWindowsHelpers.h" #endif -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - class nsIProfileSaveEvent; class nsPluginTag; @@ -56,9 +52,6 @@ class PluginInstanceParent; #ifdef XP_WIN class PluginHangUIParent; #endif -#ifdef MOZ_CRASHREPORTER_INJECTOR -class FinishInjectorInitTask; -#endif /** * PluginModuleParent @@ -80,9 +73,6 @@ class FinishInjectorInitTask; class PluginModuleParent : public PPluginModuleParent , public PluginLibrary -#ifdef MOZ_CRASHREPORTER_INJECTOR - , public CrashReporter::InjectorCrashCallback -#endif { protected: typedef mozilla::PluginLibrary PluginLibrary; @@ -395,10 +385,6 @@ class PluginModuleContentParent : public PluginModuleParent virtual bool ShouldContinueFromReplyTimeout() override; virtual void OnExitedSyncSend() override; -#ifdef MOZ_CRASHREPORTER_INJECTOR - void OnCrash(DWORD processID) override {} -#endif - static PluginModuleContentParent* sSavedModuleParent; uint32_t mPluginId; @@ -522,11 +508,6 @@ private: virtual bool ShouldContinueFromReplyTimeout() override; -#ifdef MOZ_CRASHREPORTER - void ProcessFirstMinidump(); - void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes); -#endif - virtual PCrashReporterParent* AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id, uint32_t* processType) override; @@ -594,17 +575,6 @@ private: PluginHangUIParent *mHangUIParent; bool mHangUIEnabled; bool mIsTimerReset; -#ifdef MOZ_CRASHREPORTER - /** - * This mutex protects the crash reporter when the Plugin Hang UI event - * handler is executing off main thread. It is intended to protect both - * the mCrashReporter variable in addition to the CrashReporterParent object - * that mCrashReporter refers to. - */ - mozilla::Mutex mCrashReporterMutex; - CrashReporterParent* mCrashReporter; -#endif // MOZ_CRASHREPORTER - /** * Launches the Plugin Hang UI. @@ -626,20 +596,6 @@ private: friend class mozilla::dom::CrashReporterParent; friend class mozilla::plugins::PluginAsyncSurrogate; -#ifdef MOZ_CRASHREPORTER_INJECTOR - friend class mozilla::plugins::FinishInjectorInitTask; - - void InitializeInjector(); - void DoInjection(const nsAutoHandle& aSnapshot); - static DWORD WINAPI GetToolhelpSnapshot(LPVOID aContext); - - void OnCrash(DWORD processID) override; - - DWORD mFlashProcess1; - DWORD mFlashProcess2; - RefPtr<mozilla::plugins::FinishInjectorInitTask> mFinishInitTask; -#endif - void OnProcessLaunched(const bool aSucceeded); class LaunchedTask : public LaunchCompleteTask diff --git a/dom/plugins/test/mochitest/test_crash_notify_no_report.xul b/dom/plugins/test/mochitest/test_crash_notify_no_report.xul index a1344bf0f..ac2b878fb 100644 --- a/dom/plugins/test/mochitest/test_crash_notify_no_report.xul +++ b/dom/plugins/test/mochitest/test_crash_notify_no_report.xul @@ -83,21 +83,10 @@ function onPluginCrashed(aEvent) { getService(Components.interfaces.nsIObserverService); os.removeObserver(testObserver, "plugin-crashed"); - // re-set MOZ_CRASHREPORTER_NO_REPORT - let env = Components.classes["@mozilla.org/process/environment;1"] - .getService(Components.interfaces.nsIEnvironment); - env.set("MOZ_CRASHREPORTER_NO_REPORT", "1"); SimpleTest.finish(); } function runTests() { - // the test harness will have set MOZ_CRASHREPORTER_NO_REPORT, - // ensure that we can change the setting and have our minidumps - // wind up in Crash Reports/pending - let env = Components.classes["@mozilla.org/process/environment;1"] - .getService(Components.interfaces.nsIEnvironment); - env.set("MOZ_CRASHREPORTER_NO_REPORT", ""); - var os = Components.classes["@mozilla.org/observer-service;1"]. getService(Components.interfaces.nsIObserverService); os.addObserver(testObserver, "plugin-crashed", true); diff --git a/dom/plugins/test/mochitest/test_crash_submit.xul b/dom/plugins/test/mochitest/test_crash_submit.xul index 22f39384b..53b42b25c 100644 --- a/dom/plugins/test/mochitest/test_crash_submit.xul +++ b/dom/plugins/test/mochitest/test_crash_submit.xul @@ -70,11 +70,6 @@ var testObserver = { getService(Components.interfaces.nsIObserverService); os.removeObserver(testObserver, "crash-report-status"); - // Then re-set MOZ_CRASHREPORTER_NO_REPORT - let env = Components.classes["@mozilla.org/process/environment;1"] - .getService(Components.interfaces.nsIEnvironment); - env.set("MOZ_CRASHREPORTER_NO_REPORT", "1"); - // Finally re-set crashreporter URL crashReporter.serverURL = oldServerURL; @@ -123,13 +118,6 @@ function onPluginCrashed(aEvent) { } function runTests() { - // the test harness will have set MOZ_CRASHREPORTER_NO_REPORT, - // ensure that we can change the setting and have our minidumps - // wind up in Crash Reports/pending - let env = Components.classes["@mozilla.org/process/environment;1"] - .getService(Components.interfaces.nsIEnvironment); - env.set("MOZ_CRASHREPORTER_NO_REPORT", ""); - // Override the crash reporter URL to send to our fake server crashReporter.serverURL = NetUtil.newURI(SERVER_URL); diff --git a/dom/plugins/test/mochitest/test_hang_submit.xul b/dom/plugins/test/mochitest/test_hang_submit.xul index 6c037ecd4..52ed78c6b 100644 --- a/dom/plugins/test/mochitest/test_hang_submit.xul +++ b/dom/plugins/test/mochitest/test_hang_submit.xul @@ -78,10 +78,6 @@ var testObserver = { // Next unregister our observer Services.obs.removeObserver(testObserver, "crash-report-status"); - // Then re-set MOZ_CRASHREPORTER_NO_REPORT - let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - env.set("MOZ_CRASHREPORTER_NO_REPORT", "1"); - // Finally re-set prefs crashReporter.serverURL = oldServerURL; Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", oldTimeoutPref); @@ -133,13 +129,6 @@ function runTests() { // Default plugin hang timeout is too high for mochitests Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", 1); - // the test harness will have set MOZ_CRASHREPORTER_NO_REPORT, - // ensure that we can change the setting and have our minidumps - // wind up in Crash Reports/pending - let env = Cc["@mozilla.org/process/environment;1"] - .getService(Ci.nsIEnvironment); - env.set("MOZ_CRASHREPORTER_NO_REPORT", ""); - // Override the crash reporter URL to send to our fake server crashReporter.serverURL = NetUtil.newURI(SERVER_URL); diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index bf1fa5f50..00b78143e 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -38,9 +38,6 @@ #include "WorkerRunnable.h" #include "WrapperFactory.h" #include "xpcpublic.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif namespace mozilla { namespace dom { diff --git a/dom/xhr/XMLHttpRequestWorker.cpp b/dom/xhr/XMLHttpRequestWorker.cpp index f61383baf..93b93a2b1 100644 --- a/dom/xhr/XMLHttpRequestWorker.cpp +++ b/dom/xhr/XMLHttpRequestWorker.cpp @@ -1148,8 +1148,8 @@ EventRunnable::PreDispatch(WorkerPrivate* /* unused */) } else { bool doClone = true; JS::Rooted<JS::Value> transferable(cx); - JS::Rooted<JSObject*> obj(cx, response.isObjectOrNull() ? - response.toObjectOrNull() : nullptr); + JS::Rooted<JSObject*> obj(cx, response.isObject() ? + &response.toObject() : nullptr); if (obj && JS_IsArrayBufferObject(obj)) { // Use cached response if the arraybuffer has been transfered. if (mProxy->mArrayBufferResponseWasTransferred) { diff --git a/gfx/gl/GfxTexturesReporter.cpp b/gfx/gl/GfxTexturesReporter.cpp index 8007fe6b1..d2ca70d27 100644 --- a/gfx/gl/GfxTexturesReporter.cpp +++ b/gfx/gl/GfxTexturesReporter.cpp @@ -9,10 +9,6 @@ #include "GfxTexturesReporter.h" #include "gfxPrefs.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - using namespace mozilla; using namespace mozilla::gl; @@ -75,8 +71,4 @@ GfxTexturesReporter::UpdateAmount(MemoryUse action, size_t amount) } } } - -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateTexturesSize(sAmount); -#endif } diff --git a/gfx/ipc/GPUChild.cpp b/gfx/ipc/GPUChild.cpp index 72328ac0b..3c2797683 100644 --- a/gfx/ipc/GPUChild.cpp +++ b/gfx/ipc/GPUChild.cpp @@ -121,9 +121,6 @@ GPUChild::RecvGraphicsError(const nsCString& aError) bool GPUChild::RecvInitCrashReporter(Shmem&& aShmem) { -#ifdef MOZ_CRASHREPORTER - mCrashReporter = MakeUnique<ipc::CrashReporterHost>(GeckoProcessType_GPU, aShmem); -#endif return true; } @@ -163,12 +160,6 @@ void GPUChild::ActorDestroy(ActorDestroyReason aWhy) { if (aWhy == AbnormalShutdown) { -#ifdef MOZ_CRASHREPORTER - if (mCrashReporter) { - mCrashReporter->GenerateCrashReport(OtherPid()); - mCrashReporter = nullptr; - } -#endif Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, nsDependentCString(XRE_ChildProcessTypeToString(GeckoProcessType_GPU), 1)); } diff --git a/gfx/ipc/GPUParent.cpp b/gfx/ipc/GPUParent.cpp index d63e17e2f..896c7b36b 100644 --- a/gfx/ipc/GPUParent.cpp +++ b/gfx/ipc/GPUParent.cpp @@ -82,11 +82,6 @@ GPUParent::Init(base::ProcessId aParentPid, nsDebugImpl::SetMultiprocessMode("GPU"); -#ifdef MOZ_CRASHREPORTER - // Init crash reporter support. - CrashReporterClient::InitSingleton(this); -#endif - // Ensure gfxPrefs are initialized. gfxPrefs::GetSingleton(); gfxConfig::Init(); @@ -380,9 +375,6 @@ GPUParent::ActorDestroy(ActorDestroyReason aWhy) gfxVars::Shutdown(); gfxConfig::Shutdown(); gfxPrefs::DestroySingleton(); -#ifdef MOZ_CRASHREPORTER - CrashReporterClient::DestroySingleton(); -#endif XRE_ShutdownChildProcess(); } diff --git a/gfx/src/DriverCrashGuard.cpp b/gfx/src/DriverCrashGuard.cpp index 36d08dcf3..4754c26ad 100644 --- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -7,9 +7,6 @@ #include "gfxPrefs.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
-#ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-#endif
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsXULAppAPI.h"
@@ -164,12 +161,6 @@ DriverCrashGuard::~DriverCrashGuard() } else {
dom::ContentChild::GetSingleton()->SendEndDriverCrashGuard(uint32_t(mType));
}
-
-#ifdef MOZ_CRASHREPORTER
- // Remove the crash report annotation.
- CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
- NS_LITERAL_CSTRING(""));
-#endif
}
bool
@@ -208,16 +199,6 @@ DriverCrashGuard::ActivateGuard() {
mGuardActivated = true;
-#ifdef MOZ_CRASHREPORTER
- // Anotate crash reports only if we're a real guard. Otherwise, we could
- // attribute a random parent process crash to a graphics problem in a child
- // process.
- if (mMode != Mode::Proxy) {
- CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"),
- NS_LITERAL_CSTRING("1"));
- }
-#endif
-
// If we're in the content process, the rest of the guarding is handled
// in the parent.
if (XRE_IsContentProcess()) {
diff --git a/gfx/src/gfxCrashReporterUtils.cpp b/gfx/src/gfxCrashReporterUtils.cpp index 42647ccc6..757c15527 100644 --- a/gfx/src/gfxCrashReporterUtils.cpp +++ b/gfx/src/gfxCrashReporterUtils.cpp @@ -5,10 +5,6 @@ #include "gfxCrashReporterUtils.h" -#if defined(MOZ_CRASHREPORTER) -#define MOZ_GFXFEATUREREPORTER 1 -#endif - #ifdef MOZ_GFXFEATUREREPORTER #include "gfxCrashReporterUtils.h" #include <string.h> // for strcmp diff --git a/gfx/tests/gtest/TestGfxPrefs.cpp b/gfx/tests/gtest/TestGfxPrefs.cpp index 72b698ed6..4e3b6037e 100644 --- a/gfx/tests/gtest/TestGfxPrefs.cpp +++ b/gfx/tests/gtest/TestGfxPrefs.cpp @@ -80,27 +80,3 @@ TEST(GfxPrefs, Set) { ASSERT_TRUE(gfxPrefs::APZMaxVelocity() == -1.0f); } -#ifdef MOZ_CRASHREPORTER -// Randomly test the function we use in nsExceptionHandler.cpp here: -extern bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength); -TEST(GfxPrefs, StringUtility) -{ - char testBuffer[64]; - double testVal[] = {13.4, - 3324243.42, - 0.332424342, - 864.0, - 86400 * 100000000.0 * 10000000000.0 * 10000000000.0 * 100.0, - 86400.0 * 366.0 * 100.0 + 14243.44332}; - for (size_t i=0; i<mozilla::ArrayLength(testVal); i++) { - ASSERT_TRUE(SimpleNoCLibDtoA(testVal[i], testBuffer, sizeof(testBuffer))); - ASSERT_TRUE(fabs(1.0 - atof(testBuffer)/testVal[i]) < 0.0001); - } - - // We do not like negative numbers (random limitation) - ASSERT_FALSE(SimpleNoCLibDtoA(-864.0, testBuffer, sizeof(testBuffer))); - - // It won't fit into 32: - ASSERT_FALSE(SimpleNoCLibDtoA(testVal[4], testBuffer, sizeof(testBuffer)/2)); -} -#endif diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 2e4ec990f..a468592fe 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -71,9 +71,6 @@ #include "nsIScreenManager.h" #include "FrameMetrics.h" #include "MainThreadUtils.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif #include "nsWeakReference.h" @@ -293,12 +290,7 @@ void CrashStatsLogForwarder::UpdateCrashReport() message << logAnnotation << Get<0>(*it) << "]" << Get<1>(*it) << " (t=" << Get<2>(*it) << ") "; } -#ifdef MOZ_CRASHREPORTER - nsCString reportString(message.str().c_str()); - nsresult annotated = CrashReporter::AnnotateCrashReport(mCrashCriticalKey, reportString); -#else nsresult annotated = NS_ERROR_NOT_IMPLEMENTED; -#endif if (annotated != NS_OK) { printf("Crash Annotation %s: %s", mCrashCriticalKey.get(), message.str().c_str()); diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp index 9d7f512f2..1fb3bc4fd 100644 --- a/gfx/thebes/gfxPlatformGtk.cpp +++ b/gfx/thebes/gfxPlatformGtk.cpp @@ -227,10 +227,10 @@ gfxPlatformGtk::UpdateFontList() // out a more general list static const char kFontDejaVuSans[] = "DejaVu Sans"; static const char kFontDejaVuSerif[] = "DejaVu Serif"; -static const char kFontEmojiOneMozilla[] = "EmojiOne Mozilla"; static const char kFontFreeSans[] = "FreeSans"; static const char kFontFreeSerif[] = "FreeSerif"; static const char kFontTakaoPGothic[] = "TakaoPGothic"; +static const char kFontTwemojiMozilla[] = "Twemoji Mozilla"; static const char kFontDroidSansFallback[] = "Droid Sans Fallback"; static const char kFontWenQuanYiMicroHei[] = "WenQuanYi Micro Hei"; static const char kFontNanumGothic[] = "NanumGothic"; @@ -242,7 +242,7 @@ gfxPlatformGtk::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh, { if (aNextCh == 0xfe0fu) { // if char is followed by VS16, try for a color emoji glyph - aFontList.AppendElement(kFontEmojiOneMozilla); + aFontList.AppendElement(kFontTwemojiMozilla); } aFontList.AppendElement(kFontDejaVuSerif); @@ -254,7 +254,7 @@ gfxPlatformGtk::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh, uint32_t p = aCh >> 16; if (p == 1) { // try color emoji font, unless VS15 (text style) present if (aNextCh != 0xfe0fu && aNextCh != 0xfe0eu) { - aFontList.AppendElement(kFontEmojiOneMozilla); + aFontList.AppendElement(kFontTwemojiMozilla); } } } diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 84199170b..af4d932a9 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -634,7 +634,6 @@ static const char kFontCambriaMath[] = "Cambria Math"; static const char kFontEbrima[] = "Ebrima"; static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa"; static const char kFontEuphemia[] = "Euphemia"; -static const char kFontEmojiOneMozilla[] = "EmojiOne Mozilla"; static const char kFontGabriola[] = "Gabriola"; static const char kFontJavaneseText[] = "Javanese Text"; static const char kFontKhmerUI[] = "Khmer UI"; @@ -661,6 +660,7 @@ static const char kFontSegoeUIEmoji[] = "Segoe UI Emoji"; static const char kFontSegoeUISymbol[] = "Segoe UI Symbol"; static const char kFontSylfaen[] = "Sylfaen"; static const char kFontTraditionalArabic[] = "Traditional Arabic"; +static const char kFontTwemojiMozilla[] = "Twemoji Mozilla"; static const char kFontUtsaah[] = "Utsaah"; static const char kFontYuGothic[] = "Yu Gothic"; @@ -671,7 +671,7 @@ gfxWindowsPlatform::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh, { if (aNextCh == 0xfe0fu) { aFontList.AppendElement(kFontSegoeUIEmoji); - aFontList.AppendElement(kFontEmojiOneMozilla); + aFontList.AppendElement(kFontTwemojiMozilla); } // Arial is used as the default fallback for system fallback @@ -683,11 +683,11 @@ gfxWindowsPlatform::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh, if (aNextCh == 0xfe0eu) { aFontList.AppendElement(kFontSegoeUISymbol); aFontList.AppendElement(kFontSegoeUIEmoji); - aFontList.AppendElement(kFontEmojiOneMozilla); + aFontList.AppendElement(kFontTwemojiMozilla); } else { if (aNextCh != 0xfe0fu) { aFontList.AppendElement(kFontSegoeUIEmoji); - aFontList.AppendElement(kFontEmojiOneMozilla); + aFontList.AppendElement(kFontTwemojiMozilla); } aFontList.AppendElement(kFontSegoeUISymbol); } diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index fd970e179..1e59b13fa 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -9,6 +9,7 @@ #include "gfxContext.h" #include "gfxDrawable.h" #include "gfxPlatform.h" +#include "gfxPrefs.h" // for surface cache size #include "gfxUtils.h" #include "imgFrame.h" #include "mozilla/AutoRestore.h" @@ -931,11 +932,14 @@ VectorImage::CreateSurfaceAndShow(const SVGDrawingParameters& aParams, BackendTy RefPtr<gfxDrawable> svgDrawable = new gfxCallbackDrawable(cb, aParams.size); - // We take an early exit without using the surface cache if - // x or y > maxDimension, because for vector images this can cause bad perf - // issues if large sizes are scaled repeatedly (a rather common scenario) - // that can quickly exhaust the cache. - int32_t maxDimension = 3000; + // We take an early exit without using the surface cache if too large, + // because for vector images this can cause bad perf issues if large sizes + // are scaled repeatedly (a rather common scenario) that can quickly exhaust + // the cache. + // Similar to max image size calculations, this has a max cap and size check. + // max cap = 8000 (pixels); size check = 5% of cache + int32_t maxDimension = 8000; + int32_t maxCacheElemSize = (gfxPrefs::ImageMemSurfaceCacheMaxSizeKB() * 1024) / 20; bool bypassCache = bool(aParams.flags & FLAG_BYPASS_SURFACE_CACHE) || // Refuse to cache animated images: @@ -946,6 +950,14 @@ VectorImage::CreateSurfaceAndShow(const SVGDrawingParameters& aParams, BackendTy // Image x or y is larger than our cache cap: aParams.size.width > maxDimension || aParams.size.height > maxDimension; + if (!bypassCache) { + // This is separated out to make sure width and height are sane at this point + // and the result can't overflow. Note: keep maxDimension low enough so that + // (maxDimension)^2 x 4 < INT32_MAX. + // Assuming surface size for any rendered vector image is RGBA, so 4Bpp. + bypassCache = (aParams.size.width * aParams.size.height * 4) > maxCacheElemSize; + } + if (bypassCache) { return Show(svgDrawable, aParams); } diff --git a/ipc/glue/CrashReporterHost.cpp b/ipc/glue/CrashReporterHost.cpp index 76052ae66..85552cba5 100644 --- a/ipc/glue/CrashReporterHost.cpp +++ b/ipc/glue/CrashReporterHost.cpp @@ -9,9 +9,6 @@ #include "mozilla/Sprintf.h" #include "mozilla/SyncRunnable.h" #include "mozilla/Telemetry.h" -#ifdef MOZ_CRASHREPORTER -# include "nsICrashService.h" -#endif namespace mozilla { namespace ipc { @@ -24,105 +21,5 @@ CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType, { } -#ifdef MOZ_CRASHREPORTER -void -CrashReporterHost::GenerateCrashReport(RefPtr<nsIFile> aCrashDump) -{ - nsString dumpID; - if (!CrashReporter::GetIDFromMinidump(aCrashDump, dumpID)) { - return; - } - - CrashReporter::AnnotationTable notes; - - nsAutoCString type; - switch (mProcessType) { - case GeckoProcessType_Content: - type = NS_LITERAL_CSTRING("content"); - break; - case GeckoProcessType_Plugin: - case GeckoProcessType_GMPlugin: - type = NS_LITERAL_CSTRING("plugin"); - break; - case GeckoProcessType_GPU: - type = NS_LITERAL_CSTRING("gpu"); - break; - default: - NS_ERROR("unknown process type"); - break; - } - notes.Put(NS_LITERAL_CSTRING("ProcessType"), type); - - char startTime[32]; - SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime)); - notes.Put(NS_LITERAL_CSTRING("StartupTime"), nsDependentCString(startTime)); - - CrashReporterMetadataShmem::ReadAppNotes(mShmem, ¬es); - - CrashReporter::AppendExtraData(dumpID, notes); - NotifyCrashService(mProcessType, dumpID, ¬es); -} - -/* static */ void -CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType, - const nsString& aChildDumpID, - const AnnotationTable* aNotes) -{ - if (!NS_IsMainThread()) { - RefPtr<Runnable> runnable = NS_NewRunnableFunction([=] () -> void { - CrashReporterHost::NotifyCrashService(aProcessType, aChildDumpID, aNotes); - }); - RefPtr<nsIThread> mainThread = do_GetMainThread(); - SyncRunnable::DispatchToThread(mainThread, runnable); - return; - } - - MOZ_ASSERT(!aChildDumpID.IsEmpty()); - - nsCOMPtr<nsICrashService> crashService = - do_GetService("@mozilla.org/crashservice;1"); - if (!crashService) { - return; - } - - int32_t processType; - int32_t crashType = nsICrashService::CRASH_TYPE_CRASH; - - nsCString telemetryKey; - - switch (aProcessType) { - case GeckoProcessType_Content: - processType = nsICrashService::PROCESS_TYPE_CONTENT; - telemetryKey.AssignLiteral("content"); - break; - case GeckoProcessType_Plugin: { - processType = nsICrashService::PROCESS_TYPE_PLUGIN; - telemetryKey.AssignLiteral("plugin"); - nsAutoCString val; - if (aNotes->Get(NS_LITERAL_CSTRING("PluginHang"), &val) && - val.Equals(NS_LITERAL_CSTRING("1"))) { - crashType = nsICrashService::CRASH_TYPE_HANG; - telemetryKey.AssignLiteral("pluginhang"); - } - break; - } - case GeckoProcessType_GMPlugin: - processType = nsICrashService::PROCESS_TYPE_GMPLUGIN; - telemetryKey.AssignLiteral("gmplugin"); - break; - case GeckoProcessType_GPU: - processType = nsICrashService::PROCESS_TYPE_GPU; - telemetryKey.AssignLiteral("gpu"); - break; - default: - NS_ERROR("unknown process type"); - return; - } - - crashService->AddCrash(processType, crashType, aChildDumpID); - Telemetry::Accumulate(Telemetry::SUBPROCESS_CRASHES_WITH_DUMP, telemetryKey, 1); -} -#endif - } // namespace ipc } // namespace mozilla diff --git a/ipc/glue/CrashReporterHost.h b/ipc/glue/CrashReporterHost.h index 36c5923c2..1089781c5 100644 --- a/ipc/glue/CrashReporterHost.h +++ b/ipc/glue/CrashReporterHost.h @@ -28,26 +28,6 @@ class CrashReporterHost public: CrashReporterHost(GeckoProcessType aProcessType, const Shmem& aShmem); -#ifdef MOZ_CRASHREPORTER - void GenerateCrashReport(base::ProcessId aPid) { - RefPtr<nsIFile> crashDump; - if (!XRE_TakeMinidumpForChild(aPid, getter_AddRefs(crashDump), nullptr)) { - return; - } - GenerateCrashReport(crashDump); - } - - // This is a static helper function to notify the crash service that a - // crash has occurred. When PCrashReporter is removed, we can make this - // a member function. This can be called from any thread, and if not - // called from the main thread, will post a synchronous message to the - // main thread. - static void NotifyCrashService( - GeckoProcessType aProcessType, - const nsString& aChildDumpID, - const AnnotationTable* aNotes); -#endif - private: void GenerateCrashReport(RefPtr<nsIFile> aCrashDump); diff --git a/ipc/glue/CrashReporterMetadataShmem.cpp b/ipc/glue/CrashReporterMetadataShmem.cpp index f579d5bb0..5b889948b 100644 --- a/ipc/glue/CrashReporterMetadataShmem.cpp +++ b/ipc/glue/CrashReporterMetadataShmem.cpp @@ -208,28 +208,5 @@ private: EntryType mEntryType; }; -#ifdef MOZ_CRASHREPORTER -void -CrashReporterMetadataShmem::ReadAppNotes(const Shmem& aShmem, CrashReporter::AnnotationTable* aNotes) -{ - for (MetadataShmemReader reader(aShmem); !reader.Done(); reader.Next()) { - switch (reader.Type()) { - case EntryType::Annotation: { - nsCString key, value; - if (!reader.Read(key) || !reader.Read(value)) { - return; - } - - aNotes->Put(key, value); - break; - } - default: - NS_ASSERTION(false, "Unknown metadata entry type"); - break; - } - } -} -#endif - } // namespace ipc } // namespace mozilla diff --git a/ipc/glue/CrashReporterMetadataShmem.h b/ipc/glue/CrashReporterMetadataShmem.h index d2d8670a2..ad67c6d75 100644 --- a/ipc/glue/CrashReporterMetadataShmem.h +++ b/ipc/glue/CrashReporterMetadataShmem.h @@ -28,10 +28,6 @@ public: void AnnotateCrashReport(const nsCString& aKey, const nsCString& aData); void AppendAppNotes(const nsCString& aData); -#ifdef MOZ_CRASHREPORTER - static void ReadAppNotes(const Shmem& aShmem, CrashReporter::AnnotationTable* aNotes); -#endif - private: void SyncNotesToShmem(); diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index 48051472a..db8ab3d0a 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -307,12 +307,6 @@ GeckoChildProcessHost::GetUniqueID() void GeckoChildProcessHost::PrepareLaunch() { -#ifdef MOZ_CRASHREPORTER - if (CrashReporter::GetEnabled()) { - CrashReporter::OOPInit(); - } -#endif - #ifdef XP_WIN if (mProcessType == GeckoProcessType_Plugin) { InitWindowsGroupID(); @@ -902,26 +896,6 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt childArgv.push_back(pidstring); -#if defined(MOZ_CRASHREPORTER) -# if defined(OS_LINUX) || defined(OS_BSD) - int childCrashFd, childCrashRemapFd; - if (!CrashReporter::CreateNotificationPipeForChild( - &childCrashFd, &childCrashRemapFd)) - return false; - if (0 <= childCrashFd) { - mFileMap.push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd)); - // "true" == crash reporting enabled - childArgv.push_back("true"); - } - else { - // "false" == crash reporting disabled - childArgv.push_back("false"); - } -# elif defined(MOZ_WIDGET_COCOA) - childArgv.push_back(CrashReporter::GetChildNotificationPipe()); -# endif // OS_LINUX -#endif - #ifdef MOZ_WIDGET_COCOA // Add a mach port to the command line so the child can communicate its // 'task_t' back to the parent. @@ -1139,11 +1113,6 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt // Process id cmdLine.AppendLooseValue(UTF8ToWide(pidstring)); -#if defined(MOZ_CRASHREPORTER) - cmdLine.AppendLooseValue( - UTF8ToWide(CrashReporter::GetChildNotificationPipe())); -#endif - // Process type cmdLine.AppendLooseValue(UTF8ToWide(childProcessType)); diff --git a/ipc/glue/IPCMessageUtils.h b/ipc/glue/IPCMessageUtils.h index 094aa978a..15834a854 100644 --- a/ipc/glue/IPCMessageUtils.h +++ b/ipc/glue/IPCMessageUtils.h @@ -25,9 +25,6 @@ #include <stdint.h> -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif #include "nsID.h" #include "nsIWidget.h" #include "nsMemory.h" @@ -127,16 +124,8 @@ struct EnumSerializer { static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) { uintParamType value; if (!ReadParam(aMsg, aIter, &value)) { -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCReadErrorReason"), - NS_LITERAL_CSTRING("Bad iter")); -#endif return false; } else if (!EnumValidator::IsLegalValue(paramType(value))) { -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCReadErrorReason"), - NS_LITERAL_CSTRING("Illegal value")); -#endif return false; } *aResult = paramType(value); diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index df70899df..4c9edf9dd 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -19,10 +19,6 @@ #include "mozilla/ipc/Neutering.h" #endif // defined(OS_WIN) #include "mozilla/ipc/Transport.h" -#if defined(MOZ_CRASHREPORTER) && defined(OS_WIN) -#include "mozilla/mozalloc_oom.h" -#include "nsExceptionHandler.h" -#endif #include "MessageLink.h" #include <deque> diff --git a/ipc/glue/MessageLink.cpp b/ipc/glue/MessageLink.cpp index 6a1bda02d..a66fbbb32 100644 --- a/ipc/glue/MessageLink.cpp +++ b/ipc/glue/MessageLink.cpp @@ -14,9 +14,6 @@ #include "mozilla/Assertions.h" #include "mozilla/DebugOnly.h" #include "nsDebug.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif #include "nsISupportsImpl.h" #include "nsXULAppAPI.h" @@ -135,10 +132,6 @@ void ProcessLink::SendMessage(Message *msg) { if (msg->size() > IPC::Channel::kMaximumMessageSize) { -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCMessageName"), nsDependentCString(msg->name())); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCMessageSize"), nsPrintfCString("%d", msg->size())); -#endif MOZ_CRASH("IPC message size is too large"); } diff --git a/ipc/glue/ProtocolUtils.cpp b/ipc/glue/ProtocolUtils.cpp index 1a022048f..4de131469 100644 --- a/ipc/glue/ProtocolUtils.cpp +++ b/ipc/glue/ProtocolUtils.cpp @@ -25,13 +25,6 @@ #include "mozilla/sandboxTarget.h" #endif -#if defined(MOZ_CRASHREPORTER) && defined(XP_WIN) -#include "aclapi.h" -#include "sddl.h" - -#include "mozilla/TypeTraits.h" -#endif - #include "nsAutoPtr.h" using namespace IPC; @@ -42,16 +35,6 @@ using base::ProcessId; namespace mozilla { -#if defined(MOZ_CRASHREPORTER) && defined(XP_WIN) -// Generate RAII classes for LPTSTR and PSECURITY_DESCRIPTOR. -MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedLPTStr, \ - RemovePointer<LPTSTR>::Type, \ - ::LocalFree) -MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPSecurityDescriptor, \ - RemovePointer<PSECURITY_DESCRIPTOR>::Type, \ - ::LocalFree) -#endif - namespace ipc { class ChannelOpened : public IPC::Message @@ -195,11 +178,6 @@ bool DuplicateHandle(HANDLE aSourceHandle, FALSE, aTargetProcessId)); if (!targetProcess) { -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("IPCTransportFailureReason"), - NS_LITERAL_CSTRING("Failed to open target process.")); -#endif return false; } @@ -209,34 +187,6 @@ bool DuplicateHandle(HANDLE aSourceHandle, } #endif -#ifdef MOZ_CRASHREPORTER -void -AnnotateSystemError() -{ - int64_t error = 0; -#if defined(XP_WIN) - error = ::GetLastError(); -#elif defined(OS_POSIX) - error = errno; -#endif - if (error) { - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("IPCSystemError"), - nsPrintfCString("%lld", error)); - } -} -#endif - -#if defined(MOZ_CRASHREPORTER) && defined(XP_MACOSX) -void -AnnotateCrashReportWithErrno(const char* tag, int error) -{ - CrashReporter::AnnotateCrashReport( - nsCString(tag), - nsPrintfCString("%d", error)); -} -#endif - void LogMessageForProtocol(const char* aTopLevelProtocol, base::ProcessId aOtherPid, const char* aContextDescription, @@ -274,18 +224,6 @@ FatalError(const char* aProtocolName, const char* aMsg, bool aIsParent) formattedMessage.AppendLiteral("]: \""); formattedMessage.AppendASCII(aMsg); if (aIsParent) { -#ifdef MOZ_CRASHREPORTER - // We're going to crash the parent process because at this time - // there's no other really nice way of getting a minidump out of - // this process if we're off the main thread. - formattedMessage.AppendLiteral("\". Intentionally crashing."); - NS_ERROR(formattedMessage.get()); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCFatalErrorProtocol"), - nsDependentCString(aProtocolName)); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCFatalErrorMsg"), - nsDependentCString(aMsg)); - AnnotateSystemError(); -#endif MOZ_CRASH("IPC FatalError in the parent process!"); } else { formattedMessage.AppendLiteral("\". abort()ing as a result."); @@ -540,12 +478,9 @@ IToplevelProtocol::SetOtherProcessId(base::ProcessId aOtherPid) bool IToplevelProtocol::TakeMinidump(nsIFile** aDump, uint32_t* aSequence) { + /*** STUB ***/ MOZ_RELEASE_ASSERT(GetSide() == ParentSide); -#ifdef MOZ_CRASHREPORTER - return XRE_TakeMinidumpForChild(OtherPid(), aDump, aSequence); -#else return false; -#endif } bool diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h index 9184aae54..83860d93a 100644 --- a/ipc/glue/ProtocolUtils.h +++ b/ipc/glue/ProtocolUtils.h @@ -472,14 +472,10 @@ DuplicateHandle(HANDLE aSourceHandle, #endif /** - * Annotate the crash reporter with the error code from the most recent system - * call. Returns the system error. + * Hist: Annotated the crash reporter with the error code from the most + * recent system call. Returned the system error. */ -#ifdef MOZ_CRASHREPORTER -void AnnotateSystemError(); -#else #define AnnotateSystemError() do { } while (0) -#endif /** * An endpoint represents one end of a partially initialized IPDL channel. To @@ -599,12 +595,8 @@ private: ProtocolId mProtocolId; }; -#if defined(MOZ_CRASHREPORTER) && defined(XP_MACOSX) -void AnnotateCrashReportWithErrno(const char* tag, int error); -#else static inline void AnnotateCrashReportWithErrno(const char* tag, int error) {} -#endif // This function is used internally to create a pair of Endpoints. See the // comment above Endpoint for a description of how it might be used. diff --git a/ipc/ipdl/ipdl/lower.py b/ipc/ipdl/ipdl/lower.py index f810cccb0..61855a7a9 100644 --- a/ipc/ipdl/ipdl/lower.py +++ b/ipc/ipdl/ipdl/lower.py @@ -2610,13 +2610,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): '"'+ _protocolHeaderName(self.protocol, self.side) +'.h"') ] + setToIncludes(self.externalIncludes)) - if self.protocol.decl.type.isToplevel(): - cf.addthings([ - CppDirective('ifdef', 'MOZ_CRASHREPORTER'), - CppDirective(' include', '"nsXULAppAPI.h"'), - CppDirective('endif') - ]) - cppheaders = [CppDirective('include', '"%s"' % filename) for filename in ipdl.builtin.CppIncludes] diff --git a/js/public/CallArgs.h b/js/public/CallArgs.h index 6e6164e55..a7774309a 100644 --- a/js/public/CallArgs.h +++ b/js/public/CallArgs.h @@ -290,7 +290,7 @@ class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsed args.constructing_ = constructing; #ifdef DEBUG for (unsigned i = 0; i < argc; ++i) - MOZ_ASSERT_IF(argv[i].isMarkable(), !GCThingIsMarkedGray(GCCellPtr(argv[i]))); + MOZ_ASSERT_IF(argv[i].isGCThing(), !GCThingIsMarkedGray(GCCellPtr(argv[i]))); #endif return args; } diff --git a/js/public/Proxy.h b/js/public/Proxy.h index 3e95538db..5acb91b26 100644 --- a/js/public/Proxy.h +++ b/js/public/Proxy.h @@ -456,7 +456,7 @@ SetProxyExtra(JSObject* obj, size_t n, const Value& extra) Value* vp = &detail::GetProxyDataLayout(obj)->values->extraSlots[n]; // Trigger a barrier before writing the slot. - if (vp->isMarkable() || extra.isMarkable()) + if (vp->isGCThing() || extra.isGCThing()) SetValueInProxy(vp, extra); else *vp = extra; @@ -482,7 +482,7 @@ SetReservedOrProxyPrivateSlot(JSObject* obj, size_t slot, const Value& value) MOZ_ASSERT(slot == 0); MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj)); shadow::Object* sobj = reinterpret_cast<shadow::Object*>(obj); - if (sobj->slotRef(slot).isMarkable() || value.isMarkable()) + if (sobj->slotRef(slot).isGCThing() || value.isGCThing()) SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value); else sobj->slotRef(slot) = value; diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h index 2eda9cb2c..3270966fc 100644 --- a/js/public/TraceKind.h +++ b/js/public/TraceKind.h @@ -40,9 +40,11 @@ enum class TraceKind // Note: The order here is determined by our Value packing. Other users // should sort alphabetically, for consistency. Object = 0x00, - String = 0x01, - Symbol = 0x02, - Script = 0x03, + String = 0x02, + Symbol = 0x03, + + // 0x1 is not used for any GCThing Value tag, so we use it for Script. + Script = 0x01, // Shape details are exposed through JS_TraceShapeCycleCollectorChildren. Shape = 0x04, diff --git a/js/public/Value.h b/js/public/Value.h index 00fdad586..a40e65c83 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -51,12 +51,12 @@ JS_ENUM_HEADER(JSValueType, uint8_t) JSVAL_TYPE_DOUBLE = 0x00, JSVAL_TYPE_INT32 = 0x01, JSVAL_TYPE_UNDEFINED = 0x02, - JSVAL_TYPE_BOOLEAN = 0x03, - JSVAL_TYPE_MAGIC = 0x04, - JSVAL_TYPE_STRING = 0x05, - JSVAL_TYPE_SYMBOL = 0x06, - JSVAL_TYPE_PRIVATE_GCTHING = 0x07, - JSVAL_TYPE_NULL = 0x08, + JSVAL_TYPE_NULL = 0x03, + JSVAL_TYPE_BOOLEAN = 0x04, + JSVAL_TYPE_MAGIC = 0x05, + JSVAL_TYPE_STRING = 0x06, + JSVAL_TYPE_SYMBOL = 0x07, + JSVAL_TYPE_PRIVATE_GCTHING = 0x08, JSVAL_TYPE_OBJECT = 0x0c, /* These never appear in a jsval; they are only provided as an out-of-band value. */ @@ -75,11 +75,11 @@ JS_ENUM_HEADER(JSValueTag, uint32_t) JSVAL_TAG_CLEAR = 0xFFFFFF80, JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL, JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, - JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT, JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING } JS_ENUM_FOOTER(JSValueTag); @@ -95,11 +95,11 @@ JS_ENUM_HEADER(JSValueTag, uint32_t) JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL, JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, - JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT, JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING } JS_ENUM_FOOTER(JSValueTag); @@ -112,11 +112,11 @@ JS_ENUM_HEADER(JSValueShiftedTag, uint64_t) JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT) } JS_ENUM_FOOTER(JSValueShiftedTag); @@ -140,7 +140,6 @@ static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t), #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) -#define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING @@ -152,12 +151,10 @@ static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t), #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) -#define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING -#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING @@ -537,12 +534,7 @@ class MOZ_NON_PARAM alignas(8) Value } bool isObjectOrNull() const { - MOZ_ASSERT(uint32_t(toTag()) <= uint32_t(JSVAL_TAG_OBJECT)); -#if defined(JS_NUNBOX32) - return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET); -#elif defined(JS_PUNBOX64) - return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; -#endif + return isObject() || isNull(); } bool isGCThing() const { @@ -575,12 +567,8 @@ class MOZ_NON_PARAM alignas(8) Value return isMagic(); } - bool isMarkable() const { - return isGCThing() && !isNull(); - } - JS::TraceKind traceKind() const { - MOZ_ASSERT(isMarkable()); + MOZ_ASSERT(isGCThing()); static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String), "Value type tags must correspond with JS::TraceKinds."); static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol), @@ -684,11 +672,6 @@ class MOZ_NON_PARAM alignas(8) Value #endif } - js::gc::Cell* toMarkablePointer() const { - MOZ_ASSERT(isMarkable()); - return toGCThing(); - } - GCCellPtr toGCCellPtr() const { return GCCellPtr(toGCThing(), traceKind()); } @@ -760,9 +743,9 @@ class MOZ_NON_PARAM alignas(8) Value * Private GC Thing API * * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit - * payload as private GC things. Such Values are considered isMarkable() - * and isGCThing(), and as such, automatically marked. Their traceKind() - * is gotten via their cells. + * payload as private GC things. Such Values are considered isGCThing(), and + * as such, automatically marked. Their traceKind() is gotten via their + * cells. */ void setPrivateGCThing(js::gc::Cell* cell) { @@ -980,7 +963,7 @@ IsOptimizedPlaceholderMagicValue(const Value& v) static MOZ_ALWAYS_INLINE void ExposeValueToActiveJS(const Value& v) { - if (v.isMarkable()) + if (v.isGCThing()) js::gc::ExposeGCThingToActiveJS(GCCellPtr(v)); } @@ -1298,7 +1281,7 @@ template <> struct BarrierMethods<JS::Value> { static gc::Cell* asGCThingOrNull(const JS::Value& v) { - return v.isMarkable() ? v.toGCThing() : nullptr; + return v.isGCThing() ? v.toGCThing() : nullptr; } static void postBarrier(JS::Value* v, const JS::Value& prev, const JS::Value& next) { JS::HeapValuePostBarrier(v, prev, next); @@ -1338,9 +1321,8 @@ class ValueOperations bool isObject() const { return value().isObject(); } bool isMagic() const { return value().isMagic(); } bool isMagic(JSWhyMagic why) const { return value().isMagic(why); } - bool isMarkable() const { return value().isMarkable(); } - bool isPrimitive() const { return value().isPrimitive(); } bool isGCThing() const { return value().isGCThing(); } + bool isPrimitive() const { return value().isPrimitive(); } bool isNullOrUndefined() const { return value().isNullOrUndefined(); } bool isObjectOrNull() const { return value().isObjectOrNull(); } @@ -1485,7 +1467,7 @@ DispatchTyped(F f, const JS::Value& val, Args&&... args) return f(val.toSymbol(), mozilla::Forward<Args>(args)...); if (MOZ_UNLIKELY(val.isPrivateGCThing())) return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...); - MOZ_ASSERT(!val.isMarkable()); + MOZ_ASSERT(!val.isGCThing()); return F::defaultValue(val); } diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 40fd008b9..710c7a76c 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -1159,7 +1159,7 @@ bool ModuleBuilder::processExport(frontend::ParseNode* pn) { MOZ_ASSERT(pn->isKind(PNK_EXPORT) || pn->isKind(PNK_EXPORT_DEFAULT)); - MOZ_ASSERT(pn->getArity() == pn->isKind(PNK_EXPORT) ? PN_UNARY : PN_BINARY); + MOZ_ASSERT(pn->getArity() == (pn->isKind(PNK_EXPORT) ? PN_UNARY : PN_BINARY)); bool isDefault = pn->getKind() == PNK_EXPORT_DEFAULT; ParseNode* kid = isDefault ? pn->pn_left : pn->pn_kid; diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index eef6fd7ec..beff58e13 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -2140,7 +2140,7 @@ ASTSerializer::exportDeclaration(ParseNode* pn, MutableHandleValue dst) MOZ_ASSERT(pn->isKind(PNK_EXPORT) || pn->isKind(PNK_EXPORT_FROM) || pn->isKind(PNK_EXPORT_DEFAULT)); - MOZ_ASSERT(pn->getArity() == pn->isKind(PNK_EXPORT) ? PN_UNARY : PN_BINARY); + MOZ_ASSERT(pn->getArity() == (pn->isKind(PNK_EXPORT) ? PN_UNARY : PN_BINARY)); MOZ_ASSERT_IF(pn->isKind(PNK_EXPORT_FROM), pn->pn_right->isKind(PNK_STRING)); RootedValue decl(cx, NullValue()); diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index acf449b7e..a14f9ba69 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -881,7 +881,7 @@ HasChild(JSContext* cx, unsigned argc, Value* vp) RootedValue parent(cx, args.get(0)); RootedValue child(cx, args.get(1)); - if (!parent.isMarkable() || !child.isMarkable()) { + if (!parent.isGCThing() || !child.isGCThing()) { args.rval().setBoolean(false); return true; } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index f4c02720a..623379f61 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -9617,8 +9617,9 @@ Parser<ParseHandler>::warnOnceAboutForEach() return true; if (!cx->compartment()->warnedAboutForEach) { - if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_FOR_EACH)) - return false; + // Disabled warning spew. + // if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_FOR_EACH)) + // return false; cx->compartment()->warnedAboutForEach = true; } return true; diff --git a/js/src/gc/Barrier.cpp b/js/src/gc/Barrier.cpp index f19f6f046..6dab8d25b 100644 --- a/js/src/gc/Barrier.cpp +++ b/js/src/gc/Barrier.cpp @@ -56,7 +56,7 @@ HeapSlot::preconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t bool isCorrectSlot = kind == Slot ? obj->getSlotAddressUnchecked(slot)->get() == target : static_cast<HeapSlot*>(obj->getDenseElements() + slot)->get() == target; - bool isBlackToGray = target.isMarkable() && + bool isBlackToGray = target.isGCThing() && IsMarkedBlack(obj) && JS::GCThingIsMarkedGray(JS::GCCellPtr(target)); return isCorrectSlot && !isBlackToGray; } diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 950c96314..effc9233e 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -282,7 +282,7 @@ template <typename S> struct ReadBarrierFunctor : public VoidDefaultAdaptor<S> { template <> struct InternalBarrierMethods<Value> { - static bool isMarkable(const Value& v) { return v.isMarkable(); } + static bool isMarkable(const Value& v) { return v.isGCThing(); } static bool isMarkableTaggedPointer(const Value& v) { return isMarkable(v); } static void preBarrier(const Value& v) { diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index d9235f9ac..b2c105999 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -328,7 +328,7 @@ ShouldMarkCrossCompartment(JSTracer* trc, JSObject* src, Cell* cell) static bool ShouldMarkCrossCompartment(JSTracer* trc, JSObject* src, const Value& val) { - return val.isMarkable() && ShouldMarkCrossCompartment(trc, src, (Cell*)val.toGCThing()); + return val.isGCThing() && ShouldMarkCrossCompartment(trc, src, val.toGCThing()); } static void @@ -1599,7 +1599,7 @@ ObjectDenseElementsMayBeMarkable(NativeObject* nobj) if (!mayBeMarkable) { const Value* elements = nobj->getDenseElementsAllowCopyOnWrite(); for (unsigned i = 0; i < nobj->getDenseInitializedLength(); i++) - MOZ_ASSERT(!elements[i].isMarkable()); + MOZ_ASSERT(!elements[i].isGCThing()); } #endif diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index ec4c69a2f..73f63d804 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -404,7 +404,7 @@ IsAboutToBeFinalizedDuringSweep(TenuredCell& tenured); inline Cell* ToMarkable(const Value& v) { - if (v.isMarkable()) + if (v.isGCThing()) return (Cell*)v.toGCThing(); return nullptr; } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index ccdc5fbfa..7b2f8214b 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8526,8 +8526,8 @@ StoreUnboxedPointer(MacroAssembler& masm, T address, MIRType type, const LAlloca masm.patchableCallPreBarrier(address, type); if (value->isConstant()) { Value v = value->toConstant()->toJSValue(); - if (v.isMarkable()) { - masm.storePtr(ImmGCPtr(v.toMarkablePointer()), address); + if (v.isGCThing()) { + masm.storePtr(ImmGCPtr(v.toGCThing()), address); } else { MOZ_ASSERT(v.isNull()); masm.storePtr(ImmWord(0), address); diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index 966d952d3..f11f17225 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -2062,7 +2062,7 @@ SnapshotIterator::traceAllocation(JSTracer* trc) return; Value v = allocationValue(alloc, RM_AlwaysDefault); - if (!v.isMarkable()) + if (!v.isGCThing()) return; Value copy = v; diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 7f28a9020..730697163 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2687,7 +2687,7 @@ IsNonNurseryConstant(MDefinition* def) if (!def->isConstant()) return false; Value v = def->toConstant()->toJSValue(); - return !v.isMarkable() || !IsInsideNursery(v.toMarkablePointer()); + return !v.isGCThing() || !IsInsideNursery(v.toGCThing()); } void diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index c6e627db6..d40578514 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -3286,8 +3286,8 @@ void MacroAssemblerARMCompat::moveValue(const Value& val, Register type, Register data) { ma_mov(Imm32(val.toNunboxTag()), type); - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), data); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), data); else ma_mov(Imm32(val.toNunboxPayload()), data); } @@ -3484,8 +3484,8 @@ MacroAssemblerARMCompat::storePayload(const Value& val, const BaseIndex& dest) ScratchRegisterScope scratch(asMasm()); SecondScratchRegisterScope scratch2(asMasm()); - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), scratch); else ma_mov(Imm32(val.toNunboxPayload()), scratch); @@ -5314,8 +5314,8 @@ MacroAssembler::branchTestValue(Condition cond, const ValueOperand& lhs, // equal, short circuit false (NotEqual). ScratchRegisterScope scratch(*this); - if (rhs.isMarkable()) - ma_cmp(lhs.payloadReg(), ImmGCPtr(rhs.toMarkablePointer()), scratch); + if (rhs.isGCThing()) + ma_cmp(lhs.payloadReg(), ImmGCPtr(rhs.toGCThing()), scratch); else ma_cmp(lhs.payloadReg(), Imm32(rhs.toNunboxPayload()), scratch); ma_cmp(lhs.typeReg(), Imm32(rhs.toNunboxTag()), scratch, Equal); diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index c011af3c3..c20a6c3e5 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -915,8 +915,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM ma_mov(Imm32(val.toNunboxTag()), scratch); ma_str(scratch, ToType(dest), scratch2); - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), scratch); else ma_mov(Imm32(val.toNunboxPayload()), scratch); ma_str(scratch, ToPayload(dest), scratch2); @@ -944,15 +944,15 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM // Store the payload, marking if necessary. if (payloadoffset < 4096 && payloadoffset > -4096) { - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch2); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), scratch2); else ma_mov(Imm32(val.toNunboxPayload()), scratch2); ma_str(scratch2, DTRAddr(scratch, DtrOffImm(payloadoffset))); } else { ma_add(Imm32(payloadoffset), scratch, scratch2); - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch2); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), scratch2); else ma_mov(Imm32(val.toNunboxPayload()), scratch2); ma_str(scratch2, DTRAddr(scratch, DtrOffImm(0))); @@ -977,8 +977,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void popValue(ValueOperand val); void pushValue(const Value& val) { push(Imm32(val.toNunboxTag())); - if (val.isMarkable()) - push(ImmGCPtr(val.toMarkablePointer())); + if (val.isGCThing()) + push(ImmGCPtr(val.toGCThing())); else push(Imm32(val.toNunboxPayload())); } diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index b95831443..c21e2fd66 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -306,7 +306,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void pushValue(const Value& val) { vixl::UseScratchRegisterScope temps(this); const Register scratch = temps.AcquireX().asUnsized(); - if (val.isMarkable()) { + if (val.isGCThing()) { BufferOffset load = movePatchablePtr(ImmPtr(val.bitsAsPunboxPointer()), scratch); writeDataRelocation(val, load); push(scratch); @@ -349,7 +349,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler } } void moveValue(const Value& val, Register dest) { - if (val.isMarkable()) { + if (val.isGCThing()) { BufferOffset load = movePatchablePtr(ImmPtr(val.bitsAsPunboxPointer()), dest); writeDataRelocation(val, load); } else { @@ -1835,8 +1835,8 @@ class MacroAssemblerCompat : public vixl::MacroAssembler dataRelocations_.writeUnsigned(load.getOffset()); } void writeDataRelocation(const Value& val, BufferOffset load) { - if (val.isMarkable()) { - gc::Cell* cell = val.toMarkablePointer(); + if (val.isGCThing()) { + gc::Cell* cell = val.toGCThing(); if (cell && gc::IsInsideNursery(cell)) embedsNurseryPointers_ = true; dataRelocations_.writeUnsigned(load.getOffset()); diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index 0d3e55e21..2b2fab92d 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1527,8 +1527,8 @@ MacroAssemblerMIPSCompat::getType(const Value& val) void MacroAssemblerMIPSCompat::moveData(const Value& val, Register data) { - if (val.isMarkable()) - ma_li(data, ImmGCPtr(val.toMarkablePointer())); + if (val.isGCThing()) + ma_li(data, ImmGCPtr(val.toGCThing())); else ma_li(data, Imm32(val.toNunboxPayload())); } diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 4c7618d08..adb626bb0 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -480,8 +480,8 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void popValue(ValueOperand val); void pushValue(const Value& val) { push(Imm32(val.toNunboxTag())); - if (val.isMarkable()) - push(ImmGCPtr(val.toMarkablePointer())); + if (val.isGCThing()) + push(ImmGCPtr(val.toGCThing())); else push(Imm32(val.toNunboxPayload())); } diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index 329fa83f8..f58184bca 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -1885,7 +1885,7 @@ MacroAssemblerMIPS64Compat::storeValue(JSValueType type, Register reg, Address d void MacroAssemblerMIPS64Compat::storeValue(const Value& val, Address dest) { - if (val.isMarkable()) { + if (val.isGCThing()) { writeDataRelocation(val); movWithPatch(ImmWord(val.asRawBits()), SecondScratchReg); } else { diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index 4cff87236..bfe452974 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -221,8 +221,8 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 } void writeDataRelocation(const Value& val) { - if (val.isMarkable()) { - gc::Cell* cell = val.toMarkablePointer(); + if (val.isGCThing()) { + gc::Cell* cell = val.toGCThing(); if (cell && gc::IsInsideNursery(cell)) embedsNurseryPointers_ = true; dataRelocations_.writeUnsigned(currentOffset()); @@ -498,7 +498,7 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 void pushValue(ValueOperand val); void popValue(ValueOperand val); void pushValue(const Value& val) { - if (val.isMarkable()) { + if (val.isGCThing()) { writeDataRelocation(val); movWithPatch(ImmWord(val.asRawBits()), ScratchRegister); push(ScratchRegister); diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index cb81bd7c1..be450767b 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -58,8 +58,8 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared // X64 helpers. ///////////////////////////////////////////////////////////////// void writeDataRelocation(const Value& val) { - if (val.isMarkable()) { - gc::Cell* cell = val.toMarkablePointer(); + if (val.isGCThing()) { + gc::Cell* cell = val.toGCThing(); if (cell && gc::IsInsideNursery(cell)) embedsNurseryPointers_ = true; dataRelocations_.writeUnsigned(masm.currentOffset()); @@ -132,7 +132,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared template <typename T> void storeValue(const Value& val, const T& dest) { ScratchRegisterScope scratch(asMasm()); - if (val.isMarkable()) { + if (val.isGCThing()) { movWithPatch(ImmWord(val.asRawBits()), scratch); writeDataRelocation(val); } else { @@ -171,7 +171,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared pop(val.valueReg()); } void pushValue(const Value& val) { - if (val.isMarkable()) { + if (val.isGCThing()) { ScratchRegisterScope scratch(asMasm()); movWithPatch(ImmWord(val.asRawBits()), scratch); writeDataRelocation(val); diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 754b29c2d..dc97b5b5b 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -499,8 +499,8 @@ MacroAssembler::branchTestValue(Condition cond, const ValueOperand& lhs, const Value& rhs, Label* label) { MOZ_ASSERT(cond == Equal || cond == NotEqual); - if (rhs.isMarkable()) - cmpPtr(lhs.payloadReg(), ImmGCPtr(rhs.toMarkablePointer())); + if (rhs.isGCThing()) + cmpPtr(lhs.payloadReg(), ImmGCPtr(rhs.toGCThing())); else cmpPtr(lhs.payloadReg(), ImmWord(rhs.toNunboxPayload())); diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 21cd63a0c..2b2507c77 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -94,8 +94,8 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } void moveValue(const Value& val, Register type, Register data) { movl(Imm32(val.toNunboxTag()), type); - if (val.isMarkable()) - movl(ImmGCPtr(val.toMarkablePointer()), data); + if (val.isGCThing()) + movl(ImmGCPtr(val.toGCThing()), data); else movl(Imm32(val.toNunboxPayload()), data); } @@ -213,8 +213,8 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } void pushValue(const Value& val) { push(Imm32(val.toNunboxTag())); - if (val.isMarkable()) - push(ImmGCPtr(val.toMarkablePointer())); + if (val.isGCThing()) + push(ImmGCPtr(val.toGCThing())); else push(Imm32(val.toNunboxPayload())); } @@ -235,8 +235,8 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared pop(dest.high); } void storePayload(const Value& val, Operand dest) { - if (val.isMarkable()) - movl(ImmGCPtr(val.toMarkablePointer()), ToPayload(dest)); + if (val.isGCThing()) + movl(ImmGCPtr(val.toGCThing()), ToPayload(dest)); else movl(Imm32(val.toNunboxPayload()), ToPayload(dest)); } diff --git a/js/src/jscompartmentinlines.h b/js/src/jscompartmentinlines.h index 08d315db0..6a54bc5a6 100644 --- a/js/src/jscompartmentinlines.h +++ b/js/src/jscompartmentinlines.h @@ -61,7 +61,7 @@ inline bool JSCompartment::wrap(JSContext* cx, JS::MutableHandleValue vp) { /* Only GC things have to be wrapped or copied. */ - if (!vp.isMarkable()) + if (!vp.isGCThing()) return true; /* diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index b1c7cb0dc..722085549 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -761,7 +761,7 @@ SetReservedSlot(JSObject* obj, size_t slot, const JS::Value& value) { MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); shadow::Object* sobj = reinterpret_cast<shadow::Object*>(obj); - if (sobj->slotRef(slot).isMarkable() || value.isMarkable()) + if (sobj->slotRef(slot).isGCThing() || value.isGCThing()) SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value); else sobj->slotRef(slot) = value; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index d45d112a5..7da831aa2 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -830,7 +830,7 @@ inline void JSFunction::setExtendedSlot(size_t which, const js::Value& val) { MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); - MOZ_ASSERT_IF(js::IsMarkedBlack(this) && val.isMarkable(), + MOZ_ASSERT_IF(js::IsMarkedBlack(this) && val.isGCThing(), !JS::GCThingIsMarkedGray(JS::GCCellPtr(val))); toExtended()->extendedSlots[which] = val; } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index e86ceab3d..9f914943e 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -3309,7 +3309,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst, GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector); dst->consts()->vector = vector; for (unsigned i = 0; i < nconsts; ++i) - MOZ_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom()); + MOZ_ASSERT_IF(vector[i].isGCThing(), vector[i].toString()->isAtom()); } if (nobjects != 0) { GCPtrObject* vector = Rebase<GCPtrObject>(dst, src, src->objects()->vector); diff --git a/js/src/vm/ProxyObject.cpp b/js/src/vm/ProxyObject.cpp index 49ed5a624..69b4cd952 100644 --- a/js/src/vm/ProxyObject.cpp +++ b/js/src/vm/ProxyObject.cpp @@ -45,7 +45,7 @@ ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler, HandleValue pri // wrappee. Prefer to allocate in the nursery, when possible. NewObjectKind newKind = NurseryAllocatedProxy; if (options.singleton()) { - MOZ_ASSERT(priv.isGCThing() && priv.toGCThing()->isTenured()); + MOZ_ASSERT(priv.isNull() || (priv.isGCThing() && priv.toGCThing()->isTenured())); newKind = SingletonObject; } else if ((priv.isGCThing() && priv.toGCThing()->isTenured()) || !handler->canNurseryAllocate() || diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index bedb7c650..f5f6a11bb 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -59,10 +59,6 @@ #include "nsIXULRuntime.h" #include "nsJSPrincipals.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - #if defined(MOZ_JEMALLOC4) #include "mozmemory.h" #endif @@ -709,11 +705,6 @@ XPCJSContext::GCSliceCallback(JSContext* cx, if (!self) return; -#ifdef MOZ_CRASHREPORTER - CrashReporter::SetGarbageCollecting(progress == JS::GC_CYCLE_BEGIN || - progress == JS::GC_SLICE_BEGIN); -#endif - if (self->mPrevGCSliceCallback) (*self->mPrevGCSliceCallback)(cx, progress, desc); } diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index d9629bfed..45d00d390 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -59,11 +59,6 @@ #include <unistd.h> /* for isatty() */ #endif -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#include "nsICrashReporter.h" -#endif - using namespace mozilla; using namespace JS; using mozilla::dom::AutoJSAPI; @@ -1372,18 +1367,6 @@ XRE_XPCShellMain(int argc, char** argv, char** envp, argv += 2; } -#ifdef MOZ_CRASHREPORTER - const char* val = getenv("MOZ_CRASHREPORTER"); - if (val && *val) { - rv = CrashReporter::SetExceptionHandler(greDir, true); - if (NS_FAILED(rv)) { - printf("CrashReporter::SetExceptionHandler failed!\n"); - return 1; - } - MOZ_ASSERT(CrashReporter::GetEnabled()); - } -#endif - { if (argc > 1 && !strcmp(argv[1], "--greomni")) { nsCOMPtr<nsIFile> greOmni; @@ -1603,12 +1586,6 @@ XRE_XPCShellMain(int argc, char** argv, char** envp, dirprovider.ClearPluginDir(); dirprovider.ClearAppFile(); -#ifdef MOZ_CRASHREPORTER - // Shut down the crashreporter service to prevent leaking some strings it holds. - if (CrashReporter::GetEnabled()) - CrashReporter::UnsetExceptionHandler(); -#endif - NS_LogTerm(); return result; diff --git a/js/xpconnect/src/XPCVariant.cpp b/js/xpconnect/src/XPCVariant.cpp index a3d2b88c5..4c1230172 100644 --- a/js/xpconnect/src/XPCVariant.cpp +++ b/js/xpconnect/src/XPCVariant.cpp @@ -55,7 +55,7 @@ XPCTraceableVariant::~XPCTraceableVariant() { Value val = GetJSValPreserveColor(); - MOZ_ASSERT(val.isGCThing(), "Must be traceable or unlinked"); + MOZ_ASSERT(val.isGCThing() || val.isNull(), "Must be traceable or unlinked"); mData.Cleanup(); @@ -65,7 +65,7 @@ XPCTraceableVariant::~XPCTraceableVariant() void XPCTraceableVariant::TraceJS(JSTracer* trc) { - MOZ_ASSERT(GetJSValPreserveColor().isMarkable()); + MOZ_ASSERT(GetJSValPreserveColor().isGCThing()); JS::TraceEdge(trc, &mJSVal, "XPCTraceableVariant::mJSVal"); } @@ -86,7 +86,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant) tmp->mData.Cleanup(); - if (val.isMarkable()) { + if (val.isGCThing()) { XPCTraceableVariant* v = static_cast<XPCTraceableVariant*>(tmp); v->RemoveFromRootSet(); } @@ -99,7 +99,7 @@ XPCVariant::newVariant(JSContext* cx, const Value& aJSVal) { RefPtr<XPCVariant> variant; - if (!aJSVal.isMarkable()) + if (!aJSVal.isGCThing()) variant = new XPCVariant(cx, aJSVal); else variant = new XPCTraceableVariant(cx, aJSVal); diff --git a/layout/style/nsLayoutStylesheetCache.cpp b/layout/style/nsLayoutStylesheetCache.cpp index f8aea5541..e8c6d09d7 100644 --- a/layout/style/nsLayoutStylesheetCache.cpp +++ b/layout/style/nsLayoutStylesheetCache.cpp @@ -23,19 +23,6 @@ #include "nsPrintfCString.h" #include "nsXULAppAPI.h" -// Includes for the crash report annotation in ErrorLoadingSheet. -#ifdef MOZ_CRASHREPORTER -#include "mozilla/Omnijar.h" -#include "nsDirectoryService.h" -#include "nsDirectoryServiceDefs.h" -#include "nsExceptionHandler.h" -#include "nsIChromeRegistry.h" -#include "nsISimpleEnumerator.h" -#include "nsISubstitutingProtocolHandler.h" -#include "zlib.h" -#include "nsZipArchive.h" -#endif - using namespace mozilla; using namespace mozilla::css; @@ -463,280 +450,6 @@ nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile, LoadSheet(uri, aSheet, aParsingMode, aFailureAction); } -#ifdef MOZ_CRASHREPORTER -static inline nsresult -ComputeCRC32(nsIFile* aFile, uint32_t* aResult) -{ - PRFileDesc* fd; - nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); - NS_ENSURE_SUCCESS(rv, rv); - - uint32_t crc = crc32(0, nullptr, 0); - - unsigned char buf[512]; - int32_t n; - while ((n = PR_Read(fd, buf, sizeof(buf))) > 0) { - crc = crc32(crc, buf, n); - } - PR_Close(fd); - - if (n < 0) { - return NS_ERROR_FAILURE; - } - - *aResult = crc; - return NS_OK; -} - -static void -ListInterestingFiles(nsString& aAnnotation, nsIFile* aFile, - const nsTArray<nsString>& aInterestingFilenames) -{ - nsString filename; - aFile->GetLeafName(filename); - for (const nsString& interestingFilename : aInterestingFilenames) { - if (interestingFilename == filename) { - nsString path; - aFile->GetPath(path); - aAnnotation.AppendLiteral(" "); - aAnnotation.Append(path); - aAnnotation.AppendLiteral(" ("); - int64_t size; - if (NS_SUCCEEDED(aFile->GetFileSize(&size))) { - aAnnotation.AppendPrintf("%ld", size); - } else { - aAnnotation.AppendLiteral("???"); - } - aAnnotation.AppendLiteral(" bytes, crc32 = "); - uint32_t crc; - nsresult rv = ComputeCRC32(aFile, &crc); - if (NS_SUCCEEDED(rv)) { - aAnnotation.AppendPrintf("0x%08x)\n", crc); - } else { - aAnnotation.AppendPrintf("error 0x%08x)\n", uint32_t(rv)); - } - return; - } - } - - bool isDir = false; - aFile->IsDirectory(&isDir); - - if (!isDir) { - return; - } - - nsCOMPtr<nsISimpleEnumerator> entries; - if (NS_FAILED(aFile->GetDirectoryEntries(getter_AddRefs(entries)))) { - aAnnotation.AppendLiteral(" (failed to enumerated directory)\n"); - return; - } - - for (;;) { - bool hasMore = false; - if (NS_FAILED(entries->HasMoreElements(&hasMore))) { - aAnnotation.AppendLiteral(" (failed during directory enumeration)\n"); - return; - } - if (!hasMore) { - break; - } - - nsCOMPtr<nsISupports> entry; - if (NS_FAILED(entries->GetNext(getter_AddRefs(entry)))) { - aAnnotation.AppendLiteral(" (failed during directory enumeration)\n"); - return; - } - - nsCOMPtr<nsIFile> file = do_QueryInterface(entry); - if (file) { - ListInterestingFiles(aAnnotation, file, aInterestingFilenames); - } - } -} - -// Generate a crash report annotation to help debug issues with style -// sheets failing to load (bug 1194856). -static void -AnnotateCrashReport(nsIURI* aURI) -{ - nsAutoCString spec; - nsAutoCString scheme; - nsDependentCSubstring filename; - if (aURI) { - spec = aURI->GetSpecOrDefault(); - aURI->GetScheme(scheme); - int32_t i = spec.RFindChar('/'); - if (i != -1) { - filename.Rebind(spec, i + 1); - } - } - - nsString annotation; - - // The URL of the sheet that failed to load. - annotation.AppendLiteral("Error loading sheet: "); - annotation.Append(NS_ConvertUTF8toUTF16(spec).get()); - annotation.Append('\n'); - - annotation.AppendLiteral("NS_ERROR_FILE_CORRUPTION reason: "); - if (nsZipArchive::sFileCorruptedReason) { - annotation.Append(NS_ConvertUTF8toUTF16(nsZipArchive::sFileCorruptedReason).get()); - annotation.Append('\n'); - } else { - annotation.AppendLiteral("(none)\n"); - } - - // The jar: or file: URL that the sheet's resource: or chrome: URL - // resolves to. - if (scheme.EqualsLiteral("resource")) { - annotation.AppendLiteral("Real location: "); - nsCOMPtr<nsISubstitutingProtocolHandler> handler; - nsCOMPtr<nsIIOService> io(do_GetIOService()); - if (io) { - nsCOMPtr<nsIProtocolHandler> ph; - io->GetProtocolHandler(scheme.get(), getter_AddRefs(ph)); - if (ph) { - handler = do_QueryInterface(ph); - } - } - if (!handler) { - annotation.AppendLiteral("(ResolveURI failed)\n"); - } else { - nsAutoCString resolvedSpec; - handler->ResolveURI(aURI, resolvedSpec); - annotation.Append(NS_ConvertUTF8toUTF16(resolvedSpec)); - annotation.Append('\n'); - } - } else if (scheme.EqualsLiteral("chrome")) { - annotation.AppendLiteral("Real location: "); - nsCOMPtr<nsIChromeRegistry> reg = - mozilla::services::GetChromeRegistryService(); - if (!reg) { - annotation.AppendLiteral("(no chrome registry)\n"); - } else { - nsCOMPtr<nsIURI> resolvedURI; - reg->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI)); - if (!resolvedURI) { - annotation.AppendLiteral("(ConvertChromeURL failed)\n"); - } else { - annotation.Append( - NS_ConvertUTF8toUTF16(resolvedURI->GetSpecOrDefault())); - annotation.Append('\n'); - } - } - } - - nsTArray<nsString> interestingFiles; - interestingFiles.AppendElement(NS_LITERAL_STRING("chrome.manifest")); - interestingFiles.AppendElement(NS_LITERAL_STRING("omni.ja")); - interestingFiles.AppendElement(NS_ConvertUTF8toUTF16(filename)); - - annotation.AppendLiteral("GRE directory: "); - nsCOMPtr<nsIFile> file; - nsDirectoryService::gService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), - getter_AddRefs(file)); - if (file) { - // The Firefox installation directory. - nsString path; - file->GetPath(path); - annotation.Append(path); - annotation.Append('\n'); - - // List interesting files -- any chrome.manifest or omni.ja file or any file - // whose name is the sheet's filename -- under the Firefox installation - // directory. - annotation.AppendLiteral("Interesting files in the GRE directory:\n"); - ListInterestingFiles(annotation, file, interestingFiles); - - // If the Firefox installation directory has a chrome.manifest file, let's - // see what's in it. - file->Append(NS_LITERAL_STRING("chrome.manifest")); - bool exists = false; - file->Exists(&exists); - if (exists) { - annotation.AppendLiteral("Contents of chrome.manifest:\n[[[\n"); - PRFileDesc* fd; - if (NS_SUCCEEDED(file->OpenNSPRFileDesc(PR_RDONLY, 0, &fd))) { - nsCString contents; - char buf[512]; - int32_t n; - while ((n = PR_Read(fd, buf, sizeof(buf))) > 0) { - contents.Append(buf, n); - } - if (n < 0) { - annotation.AppendLiteral(" (error while reading)\n"); - } else { - annotation.Append(NS_ConvertUTF8toUTF16(contents)); - } - PR_Close(fd); - } - annotation.AppendLiteral("]]]\n"); - } - } else { - annotation.AppendLiteral("(none)\n"); - } - - // The jar: or file: URL prefix that chrome: and resource: URLs get translated - // to. - annotation.AppendLiteral("GRE omnijar URI string: "); - nsCString uri; - nsresult rv = Omnijar::GetURIString(Omnijar::GRE, uri); - if (NS_FAILED(rv)) { - annotation.AppendLiteral("(failed)\n"); - } else { - annotation.Append(NS_ConvertUTF8toUTF16(uri)); - annotation.Append('\n'); - } - - RefPtr<nsZipArchive> zip = Omnijar::GetReader(Omnijar::GRE); - if (zip) { - // List interesting files in the GRE omnijar. - annotation.AppendLiteral("Interesting files in the GRE omnijar:\n"); - nsZipFind* find; - rv = zip->FindInit(nullptr, &find); - if (NS_FAILED(rv)) { - annotation.AppendPrintf(" (FindInit failed with 0x%08x)\n", rv); - } else if (!find) { - annotation.AppendLiteral(" (FindInit returned null)\n"); - } else { - const char* result; - uint16_t len; - while (NS_SUCCEEDED(find->FindNext(&result, &len))) { - nsCString itemPathname; - nsString itemFilename; - itemPathname.Append(result, len); - int32_t i = itemPathname.RFindChar('/'); - if (i != -1) { - itemFilename = NS_ConvertUTF8toUTF16(Substring(itemPathname, i + 1)); - } - for (const nsString& interestingFile : interestingFiles) { - if (interestingFile == itemFilename) { - annotation.AppendLiteral(" "); - annotation.Append(NS_ConvertUTF8toUTF16(itemPathname)); - nsZipItem* item = zip->GetItem(itemPathname.get()); - if (!item) { - annotation.AppendLiteral(" (GetItem failed)\n"); - } else { - annotation.AppendPrintf(" (%d bytes, crc32 = 0x%08x)\n", - item->RealSize(), - item->CRC32()); - } - break; - } - } - } - delete find; - } - } else { - annotation.AppendLiteral("No GRE omnijar\n"); - } - - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("SheetLoadFailure"), - NS_ConvertUTF16toUTF8(annotation)); -} -#endif - static void ErrorLoadingSheet(nsIURI* aURI, const char* aMsg, FailureAction aFailureAction) { @@ -751,9 +464,6 @@ ErrorLoadingSheet(nsIURI* aURI, const char* aMsg, FailureAction aFailureAction) } } -#ifdef MOZ_CRASHREPORTER - AnnotateCrashReport(aURI); -#endif NS_RUNTIMEABORT(errorMessage.get()); } @@ -780,9 +490,6 @@ nsLayoutStylesheetCache::LoadSheet(nsIURI* aURI, } } -#ifdef MOZ_CRASHREPORTER - nsZipArchive::sFileCorruptedReason = nullptr; -#endif nsresult rv = loader->LoadSheetSync(aURI, aParsingMode, true, aSheet); if (NS_FAILED(rv)) { ErrorLoadingSheet(aURI, diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index 18586cadb..724b955ef 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -100,9 +100,7 @@ android { srcDir "${topsrcdir}/mobile/android/stumbler/java" } - if (!mozconfig.substs.MOZ_CRASHREPORTER) { - exclude 'org/mozilla/gecko/CrashReporter.java' - } + exclude 'org/mozilla/gecko/CrashReporter.java' if (!mozconfig.substs.MOZ_NATIVE_DEVICES) { exclude 'org/mozilla/gecko/ChromeCastDisplay.java' diff --git a/mobile/android/base/AndroidManifest.xml.in b/mobile/android/base/AndroidManifest.xml.in index 2ec98c35a..0352c1ab6 100644 --- a/mobile/android/base/AndroidManifest.xml.in +++ b/mobile/android/base/AndroidManifest.xml.in @@ -263,20 +263,6 @@ #include ../search/manifests/SearchAndroidManifest_activities.xml.in #endif -#if MOZ_CRASHREPORTER - <activity android:name="org.mozilla.gecko.CrashReporter" - android:process="@ANDROID_PACKAGE_NAME@.CrashReporter" - android:label="@string/crash_reporter_title" - android:icon="@drawable/crash_reporter" - android:theme="@style/Gecko" - android:exported="false" - android:excludeFromRecents="true"> - <intent-filter> - <action android:name="org.mozilla.gecko.reportCrash" /> - </intent-filter> - </activity> -#endif - <activity android:name="org.mozilla.gecko.preferences.GeckoPreferences" android:theme="@style/Gecko.Preferences" android:configChanges="orientation|screenSize|locale|layoutDirection" diff --git a/mobile/android/base/AppConstants.java.in b/mobile/android/base/AppConstants.java.in index 25a6a456e..21748e73b 100644 --- a/mobile/android/base/AppConstants.java.in +++ b/mobile/android/base/AppConstants.java.in @@ -194,13 +194,6 @@ public class AppConstants { false; //#endif - public static final boolean MOZ_CRASHREPORTER = -//#if MOZ_CRASHREPORTER - true; -//#else - false; -//#endif - public static final boolean MOZ_DATA_REPORTING = //#ifdef MOZ_DATA_REPORTING true; diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java index 5ab1bc3fd..aab5be2de 100644 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java +++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java @@ -734,12 +734,6 @@ OnSharedPreferenceChangeListener i--; continue; } - } else if (PREFS_CRASHREPORTER_ENABLED.equals(key)) { - if (!AppConstants.MOZ_CRASHREPORTER || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) { - preferences.removePreference(pref); - i--; - continue; - } } else if (PREFS_GEO_REPORTING.equals(key) || PREFS_GEO_LEARN_MORE.equals(key)) { if (!AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) { diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 6c88464ab..eac831421 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -805,10 +805,6 @@ gbjar.extra_jars += [ CONFIG['ANDROID_SUPPORT_V4_AAR_INTERNAL_LIB'], 'constants.jar' ] -if CONFIG['MOZ_CRASHREPORTER']: - gbjar.sources += [ 'java/org/mozilla/gecko/CrashReporter.java' ] - ANDROID_RES_DIRS += [ 'crashreporter/res' ] - if CONFIG['MOZ_ANDROID_GCM']: gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [ 'gcm/GcmInstanceIDListenerService.java', @@ -1089,7 +1085,7 @@ for var in ('ANDROID_PACKAGE_NAME', 'ANDROID_CPU_ARCH', 'MOZ_APP_DISPLAYNAME', 'MOZ_APP_UA_NAME', 'MOZ_APP_ID', 'MOZ_APP_NAME', 'MOZ_APP_VENDOR', 'MOZ_APP_VERSION', 'MOZ_CHILD_PROCESS_NAME', 'MOZ_ANDROID_APPLICATION_CLASS', 'MOZ_ANDROID_BROWSER_INTENT_CLASS', 'MOZ_ANDROID_SEARCH_INTENT_CLASS', - 'MOZ_CRASHREPORTER', 'MOZ_UPDATE_CHANNEL', 'OMNIJAR_NAME', + 'MOZ_UPDATE_CHANNEL', 'OMNIJAR_NAME', 'OS_TARGET', 'TARGET_XPCOM_ABI'): DEFINES[var] = CONFIG[var] diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java index 15df27336..0c8eeff9e 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java @@ -467,10 +467,6 @@ public class CrashHandler implements Thread.UncaughtExceptionHandler { @Override public boolean reportException(final Thread thread, final Throwable exc) { - if (AppConstants.MOZ_CRASHREPORTER && AppConstants.MOZILLA_OFFICIAL) { - // Only use Java crash reporter if enabled on official build. - return super.reportException(thread, exc); - } return false; } }; diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java index a80212639..152981649 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -166,10 +166,6 @@ public class GeckoAppShell // reportJavaCrash should have caused us to hard crash. If we're still here, // it probably means Gecko is not loaded, and we should do something else. - if (AppConstants.MOZ_CRASHREPORTER && AppConstants.MOZILLA_OFFICIAL) { - // Only use Java crash reporter if enabled on official build. - return super.reportException(thread, exc); - } return false; } }; diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index a643ea243..086138d47 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -507,14 +507,6 @@ @BINPATH@/@DLL_PREFIX@mozsandbox@DLL_SUFFIX@ #endif -; [Crash Reporter] -; CrashService is not used on Android but the ini files are required for L10N -; strings, see bug 1191351. -#ifdef MOZ_CRASHREPORTER -@BINPATH@/crashreporter.ini -@BINPATH@/crashreporter-override.ini -#endif - [mobile] @BINPATH@/chrome/chrome@JAREXT@ @BINPATH@/chrome/chrome.manifest diff --git a/mobile/android/tests/browser/robocop/robocop_head.js b/mobile/android/tests/browser/robocop/robocop_head.js index 0fa7e56c8..c9e1383f2 100644 --- a/mobile/android/tests/browser/robocop/robocop_head.js +++ b/mobile/android/tests/browser/robocop/robocop_head.js @@ -69,25 +69,6 @@ try { } catch (e) { } -// Enable crash reporting, if possible -// We rely on the Python harness to set MOZ_CRASHREPORTER_NO_REPORT -// and handle checking for minidumps. -// Note that if we're in a child process, we don't want to init the -// crashreporter component. -try { // nsIXULRuntime is not available in some configurations. - if (runningInParent && - "@mozilla.org/toolkit/crash-reporter;1" in Components.classes) { - // Remember to update </toolkit/crashreporter/test/unit/test_crashreporter.js> - // too if you change this initial setting. - let crashReporter = - Components.classes["@mozilla.org/toolkit/crash-reporter;1"] - .getService(Components.interfaces.nsICrashReporter); - crashReporter.enabled = true; - crashReporter.minidumpPath = do_get_cwd(); - } -} -catch (e) { } - /** * Date.now() is not necessarily monotonically increasing (insert sob story * about times not being the right tool to use for measuring intervals of time, diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index ff47dc8e3..110f4384f 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -24,7 +24,7 @@ pref("general.useragent.locale", "chrome://global/locale/intl.properties"); pref("general.useragent.compatMode.gecko", false); pref("general.useragent.compatMode.firefox", false); pref("general.useragent.compatMode.version", "52.9"); -pref("general.useragent.appVersionIsBuildID", true); +pref("general.useragent.appVersionIsBuildID", false); // This pref exists only for testing purposes. In order to disable all // overrides by default, don't initialize UserAgentOverrides.jsm. diff --git a/modules/libpref/nsPrefBranch.cpp b/modules/libpref/nsPrefBranch.cpp index 2fd4992c8..98e06aaa4 100644 --- a/modules/libpref/nsPrefBranch.cpp +++ b/modules/libpref/nsPrefBranch.cpp @@ -26,10 +26,6 @@ #include "prefapi_private_data.h" -#ifdef MOZ_CRASHREPORTER -#include "nsICrashReporter.h" -#endif - #include "nsIConsoleService.h" #ifdef DEBUG @@ -335,16 +331,6 @@ NS_IMETHODIMP nsPrefBranch::GetComplexValue(const char *aPrefName, const nsIID & // some addons, see bug 836263. nsAutoString wdata; if (!AppendUTF8toUTF16(utf8String, wdata, mozilla::fallible)) { -#ifdef MOZ_CRASHREPORTER - nsCOMPtr<nsICrashReporter> cr = - do_GetService("@mozilla.org/toolkit/crash-reporter;1"); - if (cr) { - cr->AnnotateCrashReport(NS_LITERAL_CSTRING("bug836263-size"), - nsPrintfCString("%x", utf8String.Length())); - cr->RegisterAppMemory(uint64_t(utf8String.BeginReading()), - std::min(0x1000U, utf8String.Length())); - } -#endif NS_RUNTIMEABORT("bug836263"); } theString->SetData(wdata); diff --git a/netwerk/ipc/NeckoMessageUtils.h b/netwerk/ipc/NeckoMessageUtils.h index 778691369..1633b82b6 100644 --- a/netwerk/ipc/NeckoMessageUtils.h +++ b/netwerk/ipc/NeckoMessageUtils.h @@ -14,11 +14,6 @@ #include "mozilla/net/DNS.h" #include "TimingStruct.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#include "nsPrintfCString.h" -#endif - namespace IPC { // nsIPermissionManager utilities @@ -102,12 +97,6 @@ struct ParamTraits<mozilla::net::NetAddr> aMsg->WriteBytes(aParam.local.path, sizeof(aParam.local.path)); #endif } else { -#ifdef MOZ_CRASHREPORTER - if (XRE_IsParentProcess()) { - nsPrintfCString msg("%d", aParam.raw.family); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Unknown NetAddr socket family"), msg); - } -#endif NS_RUNTIMEABORT("Unknown socket family"); } } diff --git a/old-configure.in b/old-configure.in index 9eb213988..2a9e2c65f 100644 --- a/old-configure.in +++ b/old-configure.in @@ -68,7 +68,7 @@ GNOMEUI_VERSION=2.2.0 GCONF_VERSION=1.2.1 STARTUP_NOTIFICATION_VERSION=0.8 DBUS_VERSION=0.60 -SQLITE_VERSION=3.19.3 +SQLITE_VERSION=3.21.0 dnl Set various checks dnl ======================================================== @@ -2271,7 +2271,7 @@ MOZ_TREMOR= MOZ_SAMPLE_TYPE_FLOAT32= MOZ_SAMPLE_TYPE_S16= MOZ_DIRECTSHOW= -MOZ_WEBRTC=1 +MOZ_WEBRTC= MOZ_PEERCONNECTION= MOZ_SRTP= MOZ_WEBRTC_SIGNALING= @@ -2312,6 +2312,11 @@ MOZ_BINARY_EXTENSIONS= MOZ_JETPACK=1 MOZ_DEVTOOLS_SERVER=1 MOZ_DEVTOOLS= +MOZ_PLACES=1 +MOZ_SOCIAL=1 +MOZ_SERVICES_HEALTHREPORT=1 +MOZ_SERVICES_SYNC=1 +MOZ_SERVICES_CLOUDSYNC=1 case "$target_os" in mingw*) @@ -3482,68 +3487,6 @@ AC_SUBST(MOZ_GAMEPAD) AC_SUBST(MOZ_GAMEPAD_BACKEND) dnl ======================================================== -dnl = Breakpad crash reporting (on by default on supported platforms) -dnl ======================================================== - -case $target in -i?86-*-mingw*|x86_64-*-mingw*) - MOZ_CRASHREPORTER=1 - ;; -i?86-apple-darwin*|x86_64-apple-darwin*) - if test -z "$MOZ_IOS"; then - MOZ_CRASHREPORTER=1 - fi - ;; -i?86-*-linux*|x86_64-*-linux*|arm-*-linux*) - if test "$MOZ_ENABLE_GTK"; then - MOZ_CRASHREPORTER=1 - fi - ;; -*-android*|*-linuxandroid*) - MOZ_CRASHREPORTER=1 - ;; -esac - -MOZ_ARG_DISABLE_BOOL(crashreporter, -[ --disable-crashreporter Disable breakpad crash reporting], - [MOZ_CRASHREPORTER=], - [MOZ_CRASHREPORTER=F # Force enable breakpad]) - -if test "$OS_ARCH" != "$HOST_OS_ARCH" -a "$OS_ARCH" != "WINNT" -a "$OS_ARCH" != "Darwin"; then - if test "$MOZ_CRASHREPORTER" = F; then - AC_MSG_ERROR([Cannot --enable-crashreporter, as breakpad tools do not support compiling on $HOST_OS_ARCH while targeting $OS_ARCH.]) - fi - MOZ_CRASHREPORTER= -fi - -if test -n "$MOZ_CRASHREPORTER"; then - AC_DEFINE(MOZ_CRASHREPORTER) - - if test "$OS_TARGET" = "Linux" && \ - test -z "$SKIP_LIBRARY_CHECKS"; then - PKG_CHECK_MODULES(MOZ_GTHREAD, gthread-2.0) - fi - - if test "$OS_ARCH" = "WINNT"; then - if test -z "$HAVE_64BIT_BUILD" -a -n "$COMPILE_ENVIRONMENT"; then - MOZ_CRASHREPORTER_INJECTOR=1 - AC_DEFINE(MOZ_CRASHREPORTER_INJECTOR) - fi - fi -fi - -MOZ_ARG_WITH_STRING(crashreporter-enable-percent, -[ --with-crashreporter-enable-percent=NN - Enable sending crash reports by default on NN% of users. (default=100)], -[ val=`echo $withval | sed 's/[^0-9]//g'` - MOZ_CRASHREPORTER_ENABLE_PERCENT="$val"]) - -if test -z "$MOZ_CRASHREPORTER_ENABLE_PERCENT"; then - MOZ_CRASHREPORTER_ENABLE_PERCENT=100 -fi -AC_DEFINE_UNQUOTED(MOZ_CRASHREPORTER_ENABLE_PERCENT, $MOZ_CRASHREPORTER_ENABLE_PERCENT) - -dnl ======================================================== dnl = libjpeg-turbo configuration dnl ======================================================== MOZ_LIBJPEG_TURBO= @@ -5254,6 +5197,43 @@ if test "$ENABLE_MARIONETTE"; then fi dnl ======================================================== +dnl = +dnl = Miscellaneous (former toolkit/moz.configure) +dnl = +dnl ======================================================== + +dnl Build Places if required +AC_SUBST(MOZ_PLACES) +if test "$MOZ_PLACES"; then + AC_DEFINE(MOZ_PLACES) +fi + +dnl Build SocialAPI if required +AC_SUBST(MOZ_SOCIAL) +if test "$MOZ_SOCIAL"; then + AC_DEFINE(MOZ_SOCIAL) +fi + +dnl Build Firefox Health Reporter Service +AC_SUBST(MOZ_SERVICES_HEALTHREPORT) +if test -n "$MOZ_SERVICES_HEALTHREPORT"; then + AC_DEFINE(MOZ_SERVICES_HEALTHREPORT) +fi + +dnl Build Sync Services if required +AC_SUBST(MOZ_SERVICES_SYNC) +if test -n "$MOZ_SERVICES_SYNC"; then + AC_DEFINE(MOZ_SERVICES_SYNC) +fi + +dnl Build Services/CloudSync if required +AC_SUBST(MOZ_SERVICES_CLOUDSYNC) +if test -n "$MOZ_SERVICES_CLOUDSYNC"; then + AC_DEFINE(MOZ_SERVICES_CLOUDSYNC) +fi + + +dnl ======================================================== if test "$MOZ_DEBUG" -o "$MOZ_DMD"; then MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS= fi @@ -5291,8 +5271,6 @@ AC_SUBST(MOZ_UNIVERSALCHARDET) AC_SUBST(ACCESSIBILITY) AC_SUBST(MOZ_SPELLCHECK) AC_SUBST(MOZ_ANDROID_ANR_REPORTER) -AC_SUBST(MOZ_CRASHREPORTER) -AC_SUBST(MOZ_CRASHREPORTER_INJECTOR) AC_SUBST(MOZ_MAINTENANCE_SERVICE) AC_SUBST(MOZ_VERIFY_MAR_SIGNATURE) AC_SUBST(MOZ_ENABLE_SIGNMAR) @@ -5525,7 +5503,7 @@ fi dnl If we have any service that uploads data (and requires data submission dnl policy alert), set MOZ_DATA_REPORTING. dnl We need SUBST for build system and DEFINE for xul preprocessor. -if test -n "$MOZ_TELEMETRY_REPORTING" || test -n "$MOZ_SERVICES_HEALTHREPORT" || test -n "$MOZ_CRASHREPORTER"; then +if test -n "$MOZ_TELEMETRY_REPORTING" || test -n "$MOZ_SERVICES_HEALTHREPORT"; then MOZ_DATA_REPORTING=1 AC_DEFINE(MOZ_DATA_REPORTING) AC_SUBST(MOZ_DATA_REPORTING) @@ -5778,6 +5756,7 @@ MOZ_BRANDING_DIRECTORY=$MOZ_BRANDING_DIRECTORY MC_BASILISK=$MC_BASILISK MC_PALEMOON=$MC_PALEMOON MOZ_SANDBOX=$MOZ_SANDBOX +MOZ_EME=$MOZ_EME MOZ_WEBRTC=$MOZ_WEBRTC MOZ_SYSTEM_LIBEVENT=$MOZ_SYSTEM_LIBEVENT MOZ_SYSTEM_NSS=$MOZ_SYSTEM_NSS diff --git a/python/mozbuild/mozbuild/mach_commands.py b/python/mozbuild/mozbuild/mach_commands.py index ae71d0868..f654db769 100644 --- a/python/mozbuild/mozbuild/mach_commands.py +++ b/python/mozbuild/mozbuild/mach_commands.py @@ -536,10 +536,6 @@ class Build(MachCommandBase): # arguably make the build action useful for Fennec. Another day... if self.substs['MOZ_BUILD_APP'] != 'mobile/android': print('To take your build for a test drive, run: |mach run|') - app = self.substs['MOZ_BUILD_APP'] - if app in ('browser', 'mobile/android'): - print('For more information on what to do now, see ' - 'https://developer.mozilla.org/docs/Developer_Guide/So_You_Just_Built_Firefox') except Exception: # Ignore Exceptions in case we can't find config.status (such # as when doing OSX Universal builds) diff --git a/python/mozbuild/mozbuild/mozinfo.py b/python/mozbuild/mozbuild/mozinfo.py index 2c08c4e9f..712722d62 100755 --- a/python/mozbuild/mozbuild/mozinfo.py +++ b/python/mozbuild/mozbuild/mozinfo.py @@ -80,7 +80,6 @@ def build_dict(config, env=os.environ): d['nightly_build'] = substs.get('NIGHTLY_BUILD') == '1' d['release_or_beta'] = substs.get('RELEASE_OR_BETA') == '1' d['pgo'] = substs.get('MOZ_PGO') == '1' - d['crashreporter'] = bool(substs.get('MOZ_CRASHREPORTER')) d['datareporting'] = bool(substs.get('MOZ_DATA_REPORTING')) d['healthreport'] = substs.get('MOZ_SERVICES_HEALTHREPORT') == '1' d['sync'] = substs.get('MOZ_SERVICES_SYNC') == '1' diff --git a/python/mozbuild/mozbuild/test/test_mozinfo.py b/python/mozbuild/mozbuild/test/test_mozinfo.py index 1a4194cb5..6d0909b2d 100755 --- a/python/mozbuild/mozbuild/test/test_mozinfo.py +++ b/python/mozbuild/mozbuild/test/test_mozinfo.py @@ -215,7 +215,6 @@ class TestBuildDict(unittest.TestCase, Base): OS_TARGET='Linux', TARGET_CPU='i386', MOZ_WIDGET_TOOLKIT='gtk2', - MOZ_CRASHREPORTER='1', ))) self.assertEqual(True, d['crashreporter']) diff --git a/security/sandbox/linux/glue/SandboxCrash.cpp b/security/sandbox/linux/glue/SandboxCrash.cpp index 87a75e845..8ead16bdf 100644 --- a/security/sandbox/linux/glue/SandboxCrash.cpp +++ b/security/sandbox/linux/glue/SandboxCrash.cpp @@ -18,9 +18,6 @@ #include "mozilla/Unused.h" #include "mozilla/dom/Exceptions.h" #include "nsContentUtils.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif #include "mozilla/StackWalk.h" #include "nsString.h" #include "nsThreadUtils.h" @@ -109,9 +106,6 @@ SandboxCrash(int nr, siginfo_t *info, void *void_context) pid_t pid = getpid(), tid = syscall(__NR_gettid); bool dumped = false; -#ifdef MOZ_CRASHREPORTER - dumped = CrashReporter::WriteMinidumpForSigInfo(nr, info, void_context); -#endif if (!dumped) { SANDBOX_LOG_ERROR("crash reporter is disabled (or failed);" " trying stack trace:"); diff --git a/taskcluster/scripts/builder/build-l10n.sh b/taskcluster/scripts/builder/build-l10n.sh index be16955a5..d337bbfe3 100755 --- a/taskcluster/scripts/builder/build-l10n.sh +++ b/taskcluster/scripts/builder/build-l10n.sh @@ -32,7 +32,6 @@ fail() { exit 1 } -export MOZ_CRASHREPORTER_NO_REPORT=1 export MOZ_OBJDIR=obj-firefox export TINDERBOX_OUTPUT=1 diff --git a/taskcluster/scripts/builder/build-linux.sh b/taskcluster/scripts/builder/build-linux.sh index 8885abdec..d1e7e77cf 100755 --- a/taskcluster/scripts/builder/build-linux.sh +++ b/taskcluster/scripts/builder/build-linux.sh @@ -36,7 +36,6 @@ fail() { exit 1 } -export MOZ_CRASHREPORTER_NO_REPORT=1 export MOZ_OBJDIR=obj-firefox export TINDERBOX_OUTPUT=1 diff --git a/testing/gtest/mozilla/GTestRunner.cpp b/testing/gtest/mozilla/GTestRunner.cpp index 0864db8cb..544de81da 100644 --- a/testing/gtest/mozilla/GTestRunner.cpp +++ b/testing/gtest/mozilla/GTestRunner.cpp @@ -6,9 +6,6 @@ #include "GTestRunner.h" #include "gtest/gtest.h" #include "mozilla/Attributes.h" -#ifdef MOZ_CRASHREPORTER -#include "nsICrashReporter.h" -#endif #include "testing/TestHarness.h" #include "prenv.h" #ifdef XP_WIN @@ -92,28 +89,6 @@ int RunGTestFunc() #ifdef XP_WIN mozilla::ipc::windows::InitUIThread(); #endif -#ifdef MOZ_CRASHREPORTER - nsCOMPtr<nsICrashReporter> crashreporter; - char *crashreporterStr = PR_GetEnv("MOZ_CRASHREPORTER"); - if (crashreporterStr && !strcmp(crashreporterStr, "1")) { - //TODO: move this to an even-more-common location to use in all - // C++ unittests - crashreporter = do_GetService("@mozilla.org/toolkit/crash-reporter;1"); - if (crashreporter) { - std::cerr << "Setting up crash reporting" << std::endl; - - nsCOMPtr<nsIProperties> dirsvc = - do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); - nsCOMPtr<nsIFile> cwd; - nsresult rv = dirsvc->Get(NS_OS_CURRENT_WORKING_DIR, - NS_GET_IID(nsIFile), - getter_AddRefs(cwd)); - MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); - crashreporter->SetEnabled(true); - crashreporter->SetMinidumpPath(cwd); - } - } -#endif return RUN_ALL_TESTS(); } diff --git a/testing/gtest/rungtests.py b/testing/gtest/rungtests.py index e9e33cca2..499908680 100644 --- a/testing/gtest/rungtests.py +++ b/testing/gtest/rungtests.py @@ -89,7 +89,6 @@ class GTests(object): ) env["XPCOM_DEBUG_BREAK"] = "stack-and-abort" env["MOZ_CRASHREPORTER_NO_REPORT"] = "1" - env["MOZ_CRASHREPORTER"] = "1" env["MOZ_RUN_GTEST"] = "1" # Normally we run with GTest default output, override this to use the TBPL test format. env["MOZ_TBPL_PARSER"] = "1" diff --git a/testing/marionette/client/marionette_driver/geckoinstance.py b/testing/marionette/client/marionette_driver/geckoinstance.py index 7e2048187..174168ed2 100644 --- a/testing/marionette/client/marionette_driver/geckoinstance.py +++ b/testing/marionette/client/marionette_driver/geckoinstance.py @@ -226,8 +226,7 @@ class GeckoInstance(object): # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting - env.update({"MOZ_CRASHREPORTER": "1", - "MOZ_CRASHREPORTER_NO_REPORT": "1", + env.update({"MOZ_CRASHREPORTER_NO_REPORT": "1", "MOZ_CRASHREPORTER_SHUTDOWN": "1", }) diff --git a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm index eebcbb6bb..d6cd836e7 100644 --- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm +++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm @@ -851,9 +851,6 @@ this.BrowserTestUtils = { crashBrowser: Task.async(function*(browser, shouldShowTabCrashPage=true) { let extra = {}; let KeyValueParser = {}; - if (AppConstants.MOZ_CRASHREPORTER) { - Cu.import("resource://gre/modules/KeyValueParser.jsm", KeyValueParser); - } if (!browser.isRemoteBrowser) { throw new Error("<xul:browser> needs to be remote in order to crash"); @@ -938,11 +935,7 @@ this.BrowserTestUtils = { extrafile.append(dumpID + '.extra'); if (extrafile.exists()) { dump(`\nNo .extra file for dumpID: ${dumpID}\n`); - if (AppConstants.MOZ_CRASHREPORTER) { - extra = KeyValueParser.parseKeyValuePairsFromFile(extrafile); - } else { - dump('\nCrashReporter not enabled - will not return any extra data\n'); - } + dump('\nWill not return any extra data\n'); } removeFile(minidumpDirectory, dumpID + '.dmp'); diff --git a/testing/mozbase/mozrunner/mozrunner/base/browser.py b/testing/mozbase/mozrunner/mozrunner/base/browser.py index 998e4ccc5..6fc7348d5 100644 --- a/testing/mozbase/mozrunner/mozrunner/base/browser.py +++ b/testing/mozbase/mozrunner/mozrunner/base/browser.py @@ -75,6 +75,5 @@ class GeckoRuntimeRunner(BaseRunner): if not self.show_crash_reporter: # hide the crash reporter window self.env["MOZ_CRASHREPORTER_NO_REPORT"] = "1" - self.env["MOZ_CRASHREPORTER"] = "1" BaseRunner.start(self, *args, **kwargs) diff --git a/testing/mozbase/mozrunner/mozrunner/base/device.py b/testing/mozbase/mozrunner/mozrunner/base/device.py index 2252203d1..6eeef042f 100644 --- a/testing/mozbase/mozrunner/mozrunner/base/device.py +++ b/testing/mozbase/mozrunner/mozrunner/base/device.py @@ -22,8 +22,7 @@ class DeviceRunner(BaseRunner): The base runner class used for running gecko on remote devices (or emulators), such as B2G. """ - env = {'MOZ_CRASHREPORTER': '1', - 'MOZ_CRASHREPORTER_NO_REPORT': '1', + env = {'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_CRASHREPORTER_SHUTDOWN': '1', 'MOZ_HIDE_RESULTS_TABLE': '1', 'MOZ_LOG': 'signaling:3,mtransport:4,DataChannel:4,jsep:4,MediaPipelineFactory:4', diff --git a/testing/mozbase/mozrunner/mozrunner/utils.py b/testing/mozbase/mozrunner/mozrunner/utils.py index f96c94398..79f26b8f2 100755 --- a/testing/mozbase/mozrunner/mozrunner/utils.py +++ b/testing/mozbase/mozrunner/mozrunner/utils.py @@ -132,7 +132,6 @@ def test_environment(xrePath, env=None, crashreporter=True, debugger=False, if crashreporter and not debugger: env['MOZ_CRASHREPORTER_NO_REPORT'] = '1' - env['MOZ_CRASHREPORTER'] = '1' else: env['MOZ_CRASHREPORTER_DISABLE'] = '1' diff --git a/testing/runcppunittests.py b/testing/runcppunittests.py index d8b79f68f..fdd6abc1f 100755 --- a/testing/runcppunittests.py +++ b/testing/runcppunittests.py @@ -90,7 +90,6 @@ class CPPUnitTests(object): # been fixed to enable crash reporting env["XPCOM_DEBUG_BREAK"] = "stack-and-abort" env["MOZ_CRASHREPORTER_NO_REPORT"] = "1" - env["MOZ_CRASHREPORTER"] = "1" return env def build_environment(self): diff --git a/testing/talos/talos/ffsetup.py b/testing/talos/talos/ffsetup.py index 22a9dea07..14ff576d5 100644 --- a/testing/talos/talos/ffsetup.py +++ b/testing/talos/talos/ffsetup.py @@ -67,10 +67,7 @@ class FFSetup(object): # for winxp e10s logging: # https://bugzilla.mozilla.org/show_bug.cgi?id=1037445 self.env['MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA'] = '1' - if self.browser_config['symbols_path']: - self.env['MOZ_CRASHREPORTER'] = '1' - else: - self.env['MOZ_CRASHREPORTER_DISABLE'] = '1' + self.env['MOZ_CRASHREPORTER_DISABLE'] = '1' self.env['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] = '1' diff --git a/testing/xpcshell/head.js b/testing/xpcshell/head.js index 74fd482cf..e204a4512 100644 --- a/testing/xpcshell/head.js +++ b/testing/xpcshell/head.js @@ -95,23 +95,6 @@ try { } catch (e) { } -// Configure crash reporting, if possible -// We rely on the Python harness to set MOZ_CRASHREPORTER, -// MOZ_CRASHREPORTER_NO_REPORT, and handle checking for minidumps. -// Note that if we're in a child process, we don't want to init the -// crashreporter component. -try { - if (runningInParent && - "@mozilla.org/toolkit/crash-reporter;1" in Components.classes) { - let crashReporter = - Components.classes["@mozilla.org/toolkit/crash-reporter;1"] - .getService(Components.interfaces.nsICrashReporter); - crashReporter.UpdateCrashEventsDir(); - crashReporter.minidumpPath = do_get_minidumpdir(); - } -} -catch (e) { } - // Configure a console listener so messages sent to it are logged as part // of the test. try { diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py index 7c88343dc..34af6639f 100755 --- a/testing/xpcshell/runxpcshelltests.py +++ b/testing/xpcshell/runxpcshelltests.py @@ -910,9 +910,6 @@ class XPCShellTests(object): """ # Make assertions fatal self.env["XPCOM_DEBUG_BREAK"] = "stack-and-abort" - # Crash reporting interferes with debugging - if not self.debuggerInfo: - self.env["MOZ_CRASHREPORTER"] = "1" # Don't launch the crash reporter client self.env["MOZ_CRASHREPORTER_NO_REPORT"] = "1" # Don't permit remote connections by default. diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build index 12e1748e9..5dba09a32 100644 --- a/toolkit/components/moz.build +++ b/toolkit/components/moz.build @@ -79,9 +79,6 @@ if not CONFIG['MOZ_FENNEC']: if CONFIG['NS_PRINTING']: DIRS += ['printing'] -if CONFIG['MOZ_CRASHREPORTER']: - DIRS += ['crashes'] - if CONFIG['BUILD_CTYPES']: DIRS += ['ctypes'] diff --git a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js index b66489234..720e80446 100644 --- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js +++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js @@ -808,6 +808,9 @@ LoginManagerPrompter.prototype = { */ _showLoginCaptureDoorhanger(login, type) { let { browser } = this._getNotifyWindow(); + if (!browser) { + return; + } let saveMsgNames = { prompt: login.username === "" ? "rememberLoginMsgNoUser" @@ -1405,10 +1408,34 @@ LoginManagerPrompter.prototype = { * Given a content DOM window, returns the chrome window and browser it's in. */ _getChromeWindow: function (aWindow) { + // Handle non-e10s toolkit consumers. + if (!Cu.isCrossProcessWrapper(aWindow)) { + let chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .chromeEventHandler.ownerGlobal; + if (!chromeWin) { + return null; + } + + // gBrowser only exists on some apps, like Firefox. + let tabbrowser = chromeWin.gBrowser || + (typeof chromeWin.getBrowser == "function" ? chromeWin.getBrowser() : null); + // At least serve the chrome window if getBrowser() + // or getBrowserForContentWindow() are not supported. + if (!tabbrowser || typeof tabbrowser.getBrowserForContentWindow != "function") { + return { win: chromeWin }; + } + + let browser = tabbrowser.getBrowserForContentWindow(aWindow); + return { win: chromeWin, browser }; + } + let windows = Services.wm.getEnumerator(null); while (windows.hasMoreElements()) { let win = windows.getNext(); - let browser = win.gBrowser.getBrowserForContentWindow(aWindow); + let tabbrowser = win.gBrowser || win.getBrowser(); + let browser = tabbrowser.getBrowserForContentWindow(aWindow); if (browser) { return { win, browser }; } diff --git a/toolkit/components/places/tests/cpp/places_test_harness_tail.h b/toolkit/components/places/tests/cpp/places_test_harness_tail.h index 4bbd45ccb..9e57c3724 100644 --- a/toolkit/components/places/tests/cpp/places_test_harness_tail.h +++ b/toolkit/components/places/tests/cpp/places_test_harness_tail.h @@ -6,9 +6,6 @@ #include "nsWidgetsCID.h" #include "nsIComponentRegistrar.h" -#ifdef MOZ_CRASHREPORTER -#include "nsICrashReporter.h" -#endif #ifndef TEST_NAME #error "Must #define TEST_NAME before including places_test_harness_tail.h" @@ -94,32 +91,6 @@ main(int aArgc, return -1; } -#ifdef MOZ_CRASHREPORTER - char* enabled = PR_GetEnv("MOZ_CRASHREPORTER"); - if (enabled && !strcmp(enabled, "1")) { - // bug 787458: move this to an even-more-common location to use in all - // C++ unittests - nsCOMPtr<nsICrashReporter> crashreporter = - do_GetService("@mozilla.org/toolkit/crash-reporter;1"); - if (crashreporter) { - fprintf(stderr, "Setting up crash reporting\n"); - - nsCOMPtr<nsIProperties> dirsvc = - do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); - if (!dirsvc) - NS_RUNTIMEABORT("Couldn't get directory service"); - nsCOMPtr<nsIFile> cwd; - nsresult rv = dirsvc->Get(NS_OS_CURRENT_WORKING_DIR, - NS_GET_IID(nsIFile), - getter_AddRefs(cwd)); - if (NS_FAILED(rv)) - NS_RUNTIMEABORT("Couldn't get CWD"); - crashreporter->SetEnabled(true); - crashreporter->SetMinidumpPath(cwd); - } - } -#endif - RefPtr<WaitForConnectionClosed> spinClose = new WaitForConnectionClosed(); // Tinderboxes are constantly on idle. Since idle tasks can interact with diff --git a/toolkit/components/protobuf/moz.build b/toolkit/components/protobuf/moz.build index b5015eb67..8cca3514c 100644 --- a/toolkit/components/protobuf/moz.build +++ b/toolkit/components/protobuf/moz.build @@ -117,10 +117,13 @@ DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER'] = True # Suppress warnings in third-party code. if CONFIG['GNU_CXX']: CXXFLAGS += [ - '-Wno-null-conversion', '-Wno-return-type', '-Wno-sign-compare', ] + if CONFIG['CLANG_CXX']: + CXXFLAGS += [ + '-Wno-null-conversion', + ] elif CONFIG['_MSC_VER']: CXXFLAGS += [ '-wd4005', # 'WIN32_LEAN_AND_MEAN' : macro redefinition diff --git a/toolkit/components/telemetry/TelemetryEnvironment.jsm b/toolkit/components/telemetry/TelemetryEnvironment.jsm index 2f4ac81ba..910d804ae 100644 --- a/toolkit/components/telemetry/TelemetryEnvironment.jsm +++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm @@ -153,7 +153,6 @@ const DEFAULT_ENVIRONMENT_PREFS = new Map([ ["dom.ipc.plugins.enabled", {what: RECORD_PREF_VALUE}], ["dom.ipc.processCount", {what: RECORD_PREF_VALUE, requiresRestart: true}], ["dom.max_script_run_time", {what: RECORD_PREF_VALUE}], - ["experiments.manifest.uri", {what: RECORD_PREF_VALUE}], ["extensions.autoDisableScopes", {what: RECORD_PREF_VALUE}], ["extensions.enabledScopes", {what: RECORD_PREF_VALUE}], ["extensions.blocklist.enabled", {what: RECORD_PREF_VALUE}], @@ -209,7 +208,6 @@ const PREF_E10S_COHORT = "e10s.rollout.cohort"; const COMPOSITOR_CREATED_TOPIC = "compositor:created"; const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC = "distribution-customization-complete"; -const EXPERIMENTS_CHANGED_TOPIC = "experiments-changed"; const GFX_FEATURES_READY_TOPIC = "gfx-features-ready"; const SEARCH_ENGINE_MODIFIED_TOPIC = "browser-search-engine-modified"; const SEARCH_SERVICE_TOPIC = "browser-search-service"; @@ -465,7 +463,6 @@ EnvironmentAddonBuilder.prototype = { watchForChanges: function() { this._loaded = true; AddonManager.addAddonListener(this); - Services.obs.addObserver(this, EXPERIMENTS_CHANGED_TOPIC, false); }, // AddonListener @@ -490,7 +487,6 @@ EnvironmentAddonBuilder.prototype = { // nsIObserver observe: function (aSubject, aTopic, aData) { this._environment._log.trace("observe - Topic " + aTopic); - this._checkForChanges("experiment-changed"); }, _checkForChanges: function(changeReason) { @@ -515,7 +511,6 @@ EnvironmentAddonBuilder.prototype = { _shutdownBlocker: function() { if (this._loaded) { AddonManager.removeAddonListener(this); - Services.obs.removeObserver(this, EXPERIMENTS_CHANGED_TOPIC); } return this._pendingTask; }, @@ -545,7 +540,6 @@ EnvironmentAddonBuilder.prototype = { theme: yield this._getActiveTheme(), activePlugins: this._getActivePlugins(), activeGMPlugins: yield this._getActiveGMPlugins(), - activeExperiment: this._getActiveExperiment(), persona: personaId, }; @@ -718,29 +712,7 @@ EnvironmentAddonBuilder.prototype = { } return activeGMPlugins; - }), - - /** - * Get the active experiment data in object form. - * @return Object containing the active experiment data. - */ - _getActiveExperiment: function () { - let experimentInfo = {}; - try { - let scope = {}; - Cu.import("resource:///modules/experiments/Experiments.jsm", scope); - let experiments = scope.Experiments.instance(); - let activeExperiment = experiments.getActiveExperimentID(); - if (activeExperiment) { - experimentInfo.id = activeExperiment; - experimentInfo.branch = experiments.getActiveExperimentBranch(); - } - } catch (e) { - // If this is not Firefox, the import will fail. - } - - return experimentInfo; - }, + }) }; function EnvironmentCache() { diff --git a/toolkit/components/terminator/nsTerminator.cpp b/toolkit/components/terminator/nsTerminator.cpp index f9459cc5d..91e872821 100644 --- a/toolkit/components/terminator/nsTerminator.cpp +++ b/toolkit/components/terminator/nsTerminator.cpp @@ -29,9 +29,6 @@ #include "nsIObserverService.h" #include "nsIPrefService.h" -#if defined(MOZ_CRASHREPORTER) -#include "nsExceptionHandler.h" -#endif #if defined(XP_WIN) #include <windows.h> @@ -541,13 +538,7 @@ nsTerminator::UpdateTelemetry() void nsTerminator::UpdateCrashReport(const char* aTopic) { -#if defined(MOZ_CRASHREPORTER) - // In case of crash, we wish to know where in shutdown we are - nsAutoCString report(aTopic); - - Unused << CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ShutdownProgress"), - report); -#endif // defined(MOZ_CRASH_REPORTER) + /*** STUB ***/ } diff --git a/toolkit/content/aboutSupport.js b/toolkit/content/aboutSupport.js index 5daf6d189..e66095e20 100644 --- a/toolkit/content/aboutSupport.js +++ b/toolkit/content/aboutSupport.js @@ -75,69 +75,7 @@ var snapshotFormatters = { }, crashes: function crashes(data) { - if (!AppConstants.MOZ_CRASHREPORTER) - return; - - let strings = stringBundle(); - let daysRange = Troubleshoot.kMaxCrashAge / (24 * 60 * 60 * 1000); - $("crashes-title").textContent = - PluralForm.get(daysRange, strings.GetStringFromName("crashesTitle")) - .replace("#1", daysRange); - let reportURL; - try { - reportURL = Services.prefs.getCharPref("breakpad.reportURL"); - // Ignore any non http/https urls - if (!/^https?:/i.test(reportURL)) - reportURL = null; - } - catch (e) { } - if (!reportURL) { - $("crashes-noConfig").style.display = "block"; - $("crashes-noConfig").classList.remove("no-copy"); - return; - } - $("crashes-allReports").style.display = "block"; - $("crashes-allReports").classList.remove("no-copy"); - - if (data.pending > 0) { - $("crashes-allReportsWithPending").textContent = - PluralForm.get(data.pending, strings.GetStringFromName("pendingReports")) - .replace("#1", data.pending); - } - - let dateNow = new Date(); - $.append($("crashes-tbody"), data.submitted.map(function (crash) { - let date = new Date(crash.date); - let timePassed = dateNow - date; - let formattedDate; - if (timePassed >= 24 * 60 * 60 * 1000) - { - let daysPassed = Math.round(timePassed / (24 * 60 * 60 * 1000)); - let daysPassedString = strings.GetStringFromName("crashesTimeDays"); - formattedDate = PluralForm.get(daysPassed, daysPassedString) - .replace("#1", daysPassed); - } - else if (timePassed >= 60 * 60 * 1000) - { - let hoursPassed = Math.round(timePassed / (60 * 60 * 1000)); - let hoursPassedString = strings.GetStringFromName("crashesTimeHours"); - formattedDate = PluralForm.get(hoursPassed, hoursPassedString) - .replace("#1", hoursPassed); - } - else - { - let minutesPassed = Math.max(Math.round(timePassed / (60 * 1000)), 1); - let minutesPassedString = strings.GetStringFromName("crashesTimeMinutes"); - formattedDate = PluralForm.get(minutesPassed, minutesPassedString) - .replace("#1", minutesPassed); - } - return $.new("tr", [ - $.new("td", [ - $.new("a", crash.id, null, {href : reportURL + crash.id}) - ]), - $.new("td", formattedDate) - ]); - })); + return; }, extensions: function extensions(data) { @@ -151,22 +89,6 @@ var snapshotFormatters = { })); }, - experiments: function experiments(data) { - $.append($("experiments-tbody"), data.map(function (experiment) { - return $.new("tr", [ - $.new("td", experiment.name), - $.new("td", experiment.id), - $.new("td", experiment.description), - $.new("td", experiment.active), - $.new("td", experiment.endDate), - $.new("td", [ - $.new("a", experiment.detailURL, null, {href : experiment.detailURL, }) - ]), - $.new("td", experiment.branch), - ]); - })); - }, - modifiedPreferences: function modifiedPreferences(data) { $.append($("prefs-tbody"), sortedArrayFromObject(data).map( function ([name, value]) { diff --git a/toolkit/content/aboutSupport.xhtml b/toolkit/content/aboutSupport.xhtml index e2885c8b8..8464e014b 100644 --- a/toolkit/content/aboutSupport.xhtml +++ b/toolkit/content/aboutSupport.xhtml @@ -253,34 +253,6 @@ </table> <!-- - - - - - - - - - - - - - - - - - - - - --> -#ifdef MOZ_CRASHREPORTER - - <h2 class="major-section" id="crashes-title"> - &aboutSupport.crashes.title; - </h2> - - <table id="crashes-table"> - <thead> - <tr> - <th> - &aboutSupport.crashes.id; - </th> - <th> - &aboutSupport.crashes.sendDate; - </th> - </tr> - </thead> - <tbody id="crashes-tbody"> - </tbody> - </table> - <p id="crashes-allReports" class="hidden no-copy"> - <a href="about:crashes" id="crashes-allReportsWithPending" class="block">&aboutSupport.crashes.allReports;</a> - </p> - <p id="crashes-noConfig" class="hidden no-copy">&aboutSupport.crashes.noConfig;</p> - -#endif - <!-- - - - - - - - - - - - - - - - - - - - - --> - <h2 class="major-section"> &aboutSupport.extensionsTitle; </h2> @@ -504,39 +476,6 @@ </table> - <h2 class="major-section"> - &aboutSupport.experimentsTitle; - </h2> - - <table> - <thead> - <tr> - <th> - &aboutSupport.experimentName; - </th> - <th> - &aboutSupport.experimentId; - </th> - <th> - &aboutSupport.experimentDescription; - </th> - <th> - &aboutSupport.experimentActive; - </th> - <th> - &aboutSupport.experimentEndDate; - </th> - <th> - &aboutSupport.experimentHomepage; - </th> - <th> - &aboutSupport.experimentBranch; - </th> - </tr> - </thead> - <tbody id="experiments-tbody"> - </tbody> - </table> <!-- - - - - - - - - - - - - - - - - - - - - --> #if defined(MOZ_SANDBOX) diff --git a/toolkit/content/browser-child.js b/toolkit/content/browser-child.js index c819e3db6..7d0fe18c5 100644 --- a/toolkit/content/browser-child.js +++ b/toolkit/content/browser-child.js @@ -17,12 +17,6 @@ Cu.import("resource://gre/modules/Timer.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PageThumbUtils", "resource://gre/modules/PageThumbUtils.jsm"); -if (AppConstants.MOZ_CRASHREPORTER) { - XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", - "@mozilla.org/xre/app-info;1", - "nsICrashReporter"); -} - function makeInputStream(aString) { let stream = Cc["@mozilla.org/io/string-input-stream;1"]. createInstance(Ci.nsISupportsCString); @@ -174,15 +168,6 @@ var WebProgressListener = { json.principal = content.document.nodePrincipal; json.synthetic = content.document.mozSyntheticDocument; json.inLoadURI = WebNavigation.inLoadURI; - - if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) { - let uri = aLocationURI.clone(); - try { - // If the current URI contains a username/password, remove it. - uri.userPass = ""; - } catch (ex) { /* Ignore failures on about: URIs. */ } - CrashReporter.annotateCrashReport("URL", uri.spec); - } } this._send("Content:LocationChange", json, objects); @@ -310,17 +295,6 @@ var WebNavigation = { }, loadURI: function(uri, flags, referrer, referrerPolicy, postData, headers, baseURI) { - if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) { - let annotation = uri; - try { - let url = Services.io.newURI(uri, null, null); - // If the current URI contains a username/password, remove it. - url.userPass = ""; - annotation = url.spec; - } catch (ex) { /* Ignore failures to parse and failures - on about: URIs. */ } - CrashReporter.annotateCrashReport("URL", annotation); - } if (referrer) referrer = Services.io.newURI(referrer, null, null); if (postData) diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn index 0a0f0253b..f9ac19a24 100644 --- a/toolkit/content/jar.mn +++ b/toolkit/content/jar.mn @@ -28,7 +28,7 @@ toolkit.jar: content/global/aboutwebrtc/aboutWebrtc.css (aboutwebrtc/aboutWebrtc.css) content/global/aboutwebrtc/aboutWebrtc.js (aboutwebrtc/aboutWebrtc.js) content/global/aboutwebrtc/aboutWebrtc.html (aboutwebrtc/aboutWebrtc.html) - content/global/aboutSupport.js +* content/global/aboutSupport.js * content/global/aboutSupport.xhtml content/global/aboutTelemetry.js content/global/aboutTelemetry.xhtml @@ -54,7 +54,12 @@ toolkit.jar: #endif content/global/filepicker.properties content/global/globalOverlay.js + content/global/memoriam.xhtml +* content/global/mozilla.css content/global/mozilla.xhtml +#ifdef MOZ_PHOENIX + content/global/logopage.xhtml +#endif content/global/process-content.js content/global/resetProfile.css content/global/resetProfile.js diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 99ee42fde..45889a191 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -87,7 +87,7 @@ <li><a href="about:license#dtoa">dtoa License</a></li> <li><a href="about:license#hunspell-nl">Dutch Spellchecking Dictionary License</a></li> #if defined(XP_WIN) || defined(XP_LINUX) - <li><a href="about:license#emojione">EmojiOne License</a></li> + <li><a href="about:license#twemoji">Twemoji License</a></li> #endif <li><a href="about:license#hunspell-ee">Estonian Spellchecking Dictionary License</a></li> <li><a href="about:license#expat">Expat License</a></li> @@ -2911,14 +2911,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <hr> #if defined(XP_WIN) || defined(XP_LINUX) - <h1><a id="emojione"></a>EmojiOne License</h1> + <h1><a id="twemoji"></a>Twemoji License</h1> <p>This license applies to the emoji art contained within the bundled emoji font file.</p> <pre> -Copyright (c) 2016 Ranks.com Inc. -Copyright (c) 2014 Twitter, Inc and other contributors. +Copyright (c) 2018 Twitter, Inc and other contributors. Creative Commons Attribution 4.0 International (CC BY 4.0) diff --git a/toolkit/content/logopage.xhtml b/toolkit/content/logopage.xhtml new file mode 100644 index 000000000..bcf1da0f0 --- /dev/null +++ b/toolkit/content/logopage.xhtml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [ +]> + +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title></title> + <style type="text/css"> + body { + background: Menu; + color: MenuText; + } + + img { + text-align: center; + position: absolute; + margin: auto; + top: 0; + right: 0; + bottom: 0; + left: 0; + opacity: 0.2; + } + </style> +</head> + +<body> + <img src="about:logo" alt=""/> +</body> +</html> diff --git a/toolkit/content/memoriam.xhtml b/toolkit/content/memoriam.xhtml new file mode 100644 index 000000000..f1a1b474d --- /dev/null +++ b/toolkit/content/memoriam.xhtml @@ -0,0 +1,76 @@ +<!DOCTYPE html +[ + <!ENTITY % directionDTD SYSTEM "chrome://global/locale/global.dtd" > + %directionDTD; + <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> + %brandDTD; +]> + +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta charset='utf-8' /> + <title>Mozilla: In Memoriam</title> + +<style> +html { + background: maroon radial-gradient( circle, #a01010 0%, #800000 80%) center center / cover no-repeat; + color: white; + font-style: italic; + text-rendering: optimizeLegibility; + min-height: 100%; +} + +#moztext { + margin-top: 15%; + font-size: 1.1em; + font-family: serif; + text-align: center; + line-height: 1.5; +} + +#from { + font-size: 1.0em; + font-family: serif; + text-align: right; +} + +em { + font-size: 1.3em; + line-height: 0; +} + +a { + text-decoration: none; + color: white; +} +</style> +</head> + +<body dir="&locale.dir;"> + +<section> + <p id="moztext"> + <h1>Mozilla: In Memoriam</h1> + <br/> + Dedicated to the tireless developers who have come and gone.<br/> + To those who have put their heart and soul into Mozilla products.<br/> + To those who have seen their good intentions and hard work squandered.<br/> + To those who really cared about the user, and cared about usability.<br/> + To those who truly understood us and desired freedom, but were unheard.<br/> + To those who knew that change is inevitable, but loss of vision is not.<br/> + To those who were forced to give up the good fight.<br/> + <br/> + <em>Thank you.</em> &brandFullName; would not have been possible without you.<br/> + <br/> + </p> + + <p id="from"> + </p> +</section> + +</body> +</html>
\ No newline at end of file diff --git a/toolkit/content/mozilla.css b/toolkit/content/mozilla.css new file mode 100644 index 000000000..d5eae6415 --- /dev/null +++ b/toolkit/content/mozilla.css @@ -0,0 +1,36 @@ +html { +%ifdef MC_PALEMOON + background: #333399 radial-gradient( circle at 75% 25%, #6666b0 0%, #333399 40%, #111177 80%) center center / cover no-repeat; +%else + background: maroon radial-gradient( circle, #a01010 0%, #800000 80%) center center / cover no-repeat; +%endif + + color: white; + font-style: italic; + text-rendering: optimizeLegibility; + min-height: 100%; +} + +#moztext { + margin-top: 15%; + font-size: 1.1em; + font-family: serif; + text-align: center; + line-height: 1.5; +} + +#from { + font-size: 1.95em; + font-family: serif; + text-align: right; +} + +em { + font-size: 1.3em; + line-height: 0; +} + +a { + text-decoration: none; + color: white; +}
\ No newline at end of file diff --git a/toolkit/content/mozilla.xhtml b/toolkit/content/mozilla.xhtml index 2acfc9f5d..8c79b5ff9 100644 --- a/toolkit/content/mozilla.xhtml +++ b/toolkit/content/mozilla.xhtml @@ -15,39 +15,8 @@ <meta charset='utf-8' /> <title>&chronicles.title.55.2;</title> -<style> -html { - background: maroon radial-gradient( circle, #a01010 0%, #800000 80%) center center / cover no-repeat; - color: white; - font-style: italic; - text-rendering: optimizeLegibility; - min-height: 100%; -} - -#moztext { - margin-top: 15%; - font-size: 1.1em; - font-family: serif; - text-align: center; - line-height: 1.5; -} - -#from { - font-size: 1.95em; - font-family: serif; - text-align: right; -} - -em { - font-size: 1.3em; - line-height: 0; -} - -a { - text-decoration: none; - color: white; -} -</style> + <link rel="stylesheet" href="chrome://global/content/mozilla.css" + type="text/css"/> </head> <body dir="&locale.dir;"> diff --git a/toolkit/content/plugins.html b/toolkit/content/plugins.html index 84cbba596..d389f52dd 100644 --- a/toolkit/content/plugins.html +++ b/toolkit/content/plugins.html @@ -10,6 +10,7 @@ "use strict"; Components.utils.import("resource://gre/modules/Services.jsm"); + Components.utils.import("resource://gre/modules/AddonManager.jsm"); var Ci = Components.interfaces; var strBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService); @@ -57,7 +58,7 @@ */ navigator.plugins.refresh(false); - addMessageListener("PluginList", function({ data: aPlugins }) { + AddonManager.getAddonsByTypes(["plugin"], function (aPlugins) { var fragment = document.createDocumentFragment(); // "Installed plugins" @@ -209,8 +210,6 @@ document.getElementById("outside").appendChild(fragment); }); - - sendAsyncMessage("RequestPlugins"); </script> </div> </body> diff --git a/toolkit/locales/Makefile.in b/toolkit/locales/Makefile.in index e20128611..189e0b1b0 100644 --- a/toolkit/locales/Makefile.in +++ b/toolkit/locales/Makefile.in @@ -30,11 +30,3 @@ chrome-%: libs:: update.locale sed -e 's/%AB_CD%/$(AB_CD)/' $< > $(FINAL_TARGET)/update.locale -ifdef MOZ_CRASHREPORTER -libs:: crashreporter.ini -ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) - $(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/crashreporter.app/Contents/Resources -else - $(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET) -endif -endif diff --git a/toolkit/locales/l10n.mk b/toolkit/locales/l10n.mk index 34d78d33c..05bda0b56 100644 --- a/toolkit/locales/l10n.mk +++ b/toolkit/locales/l10n.mk @@ -120,14 +120,6 @@ ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) ifneq (en,$(LPROJ_ROOT)) mv $(STAGEDIST)/en.lproj $(STAGEDIST)/$(LPROJ_ROOT).lproj endif -ifdef MOZ_CRASHREPORTER -# On Mac OS X, the crashreporter.ini file needs to be moved from under the -# application bundle's Resources directory where all other l10n files are -# located to the crash reporter bundle's Resources directory. - mv $(STAGEDIST)/crashreporter.app/Contents/Resources/crashreporter.ini \ - $(STAGEDIST)/../MacOS/crashreporter.app/Contents/Resources/crashreporter.ini - $(RM) -rf $(STAGEDIST)/crashreporter.app -endif endif $(NSINSTALL) -D $(DIST)/l10n-stage/$(PKG_PATH) diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index ba5d82c01..93acea0ec 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -183,13 +183,6 @@ this.AppConstants = Object.freeze({ Services.vc.compare(platformVersion, version) <= 0; }, - MOZ_CRASHREPORTER: -#ifdef MOZ_CRASHREPORTER - true, -#else - false, -#endif - MOZ_VERIFY_MAR_SIGNATURE: #ifdef MOZ_VERIFY_MAR_SIGNATURE true, diff --git a/toolkit/modules/Services.jsm b/toolkit/modules/Services.jsm index 1bf1a89fe..58d87ffb1 100644 --- a/toolkit/modules/Services.jsm +++ b/toolkit/modules/Services.jsm @@ -39,15 +39,6 @@ XPCOMUtils.defineLazyGetter(Services, "dirsvc", function () { .QueryInterface(Ci.nsIProperties); }); -#ifdef MOZ_CRASHREPORTER -XPCOMUtils.defineLazyGetter(Services, "crashmanager", () => { - let ns = {}; - Components.utils.import("resource://gre/modules/CrashManager.jsm", ns); - - return ns.CrashManager.Singleton; -}); -#endif - XPCOMUtils.defineLazyGetter(Services, "mm", () => { return Cc["@mozilla.org/globalmessagemanager;1"] .getService(Ci.nsIMessageBroadcaster) diff --git a/toolkit/modules/Troubleshoot.jsm b/toolkit/modules/Troubleshoot.jsm index cc545b4c4..60f7e8666 100644 --- a/toolkit/modules/Troubleshoot.jsm +++ b/toolkit/modules/Troubleshoot.jsm @@ -12,13 +12,6 @@ Cu.import("resource://gre/modules/AddonManager.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/AppConstants.jsm"); -var Experiments; -try { - Experiments = Cu.import("resource:///modules/experiments/Experiments.jsm").Experiments; -} -catch (e) { -} - // We use a preferences whitelist to make sure we only show preferences that // are useful for support and won't compromise the user's privacy. Note that // entries are *prefixes*: for example, "accessibility." applies to all prefs @@ -263,18 +256,6 @@ var dataProviders = { }); }, - experiments: function experiments(done) { - if (Experiments === undefined) { - done([]); - return; - } - - // getExperiments promises experiment history - Experiments.instance().getExperiments().then( - experiments => done(experiments) - ); - }, - modifiedPreferences: function modifiedPreferences(done) { done(getPrefList(name => Services.prefs.prefHasUserValue(name))); }, @@ -549,19 +530,6 @@ var dataProviders = { } }; -if (AppConstants.MOZ_CRASHREPORTER) { - dataProviders.crashes = function crashes(done) { - let CrashReports = Cu.import("resource://gre/modules/CrashReports.jsm").CrashReports; - let reports = CrashReports.getReports(); - let now = new Date(); - let reportsNew = reports.filter(report => (now - report.date < Troubleshoot.kMaxCrashAge)); - let reportsSubmitted = reportsNew.filter(report => (!report.pending)); - let reportsPendingCount = reportsNew.length - reportsSubmitted.length; - let data = {submitted : reportsSubmitted, pending : reportsPendingCount}; - done(data); - } -} - if (AppConstants.MOZ_SANDBOX) { dataProviders.sandbox = function sandbox(done) { let data = {}; diff --git a/toolkit/moz.build b/toolkit/moz.build index d9becc9c6..778f1c0de 100644 --- a/toolkit/moz.build +++ b/toolkit/moz.build @@ -54,9 +54,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': DIRS += ['system/androidproxy'] -if CONFIG['MOZ_CRASHREPORTER']: - DIRS += ['crashreporter'] - TEST_HARNESS_FILES.testing.mochitest.browser.toolkit.crashreporter.test.browser += [ 'crashreporter/test/browser/crashreport.sjs', ] diff --git a/toolkit/moz.configure b/toolkit/moz.configure index 4717af022..c1e0880c9 100644 --- a/toolkit/moz.configure +++ b/toolkit/moz.configure @@ -444,34 +444,10 @@ def omnijar_name(toolkit): set_config('OMNIJAR_NAME', omnijar_name) -project_flag('MOZ_PLACES', - help='Build Places if required', - set_as_define=True) - -project_flag('MOZ_SOCIAL', - help='Build SocialAPI if required', - default=True) - -project_flag('MOZ_SERVICES_HEALTHREPORT', - help='Build Firefox Health Reporter Service', - set_for_old_configure=True, - set_as_define=True) - -project_flag('MOZ_SERVICES_SYNC', - help='Build Sync Services if required') - -project_flag('MOZ_SERVICES_CLOUDSYNC', - help='Build Services/CloudSync if required') - project_flag('MOZ_ANDROID_HISTORY', help='Enable Android History instead of Places', set_as_define=True) -@depends('MOZ_PLACES', 'MOZ_ANDROID_HISTORY') -def check_places_and_android_history(places, android_history): - if places and android_history: - die('Cannot use MOZ_ANDROID_HISTORY alongside MOZ_PLACES.') - # Permissions system # ============================================================== option(name='--disable-permissions', diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index a799eeebb..6f2a47482 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -19,11 +19,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm"); XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function () { - return Cu.import("resource://gre/modules/devtools/ToolboxProcess.jsm", {}). + return Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {}). BrowserToolboxProcess; }); -XPCOMUtils.defineLazyModuleGetter(this, "Experiments", - "resource:///modules/experiments/Experiments.jsm"); const PREF_DISCOVERURL = "extensions.webservice.discoverURL"; const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane"; @@ -216,23 +214,6 @@ function isDiscoverEnabled() { return true; } -function getExperimentEndDate(aAddon) { - if (!("@mozilla.org/browser/experiments-service;1" in Cc)) { - return 0; - } - - if (!aAddon.isActive) { - return aAddon.endDate; - } - - let experiment = Experiments.instance().getActiveExperiment(); - if (!experiment) { - return 0; - } - - return experiment.endDate; -} - /** * Obtain the main DOMWindow for the current context. */ @@ -1316,28 +1297,7 @@ var gViewController = { doCommand: function cmd_neverActivateItem_doCommand(aAddon) { aAddon.userDisabled = true; } - }, - - cmd_experimentsLearnMore: { - isEnabled: function cmd_experimentsLearnMore_isEnabled() { - let mainWindow = getMainWindow(); - return mainWindow && "switchToTabHavingURI" in mainWindow; - }, - doCommand: function cmd_experimentsLearnMore_doCommand() { - let url = Services.prefs.getCharPref("toolkit.telemetry.infoURL"); - openOptionsInTab(url); - }, - }, - - cmd_experimentsOpenTelemetryPreferences: { - isEnabled: function cmd_experimentsOpenTelemetryPreferences_isEnabled() { - return !!getMainWindowWithPreferencesPane(); - }, - doCommand: function cmd_experimentsOpenTelemetryPreferences_doCommand() { - let mainWindow = getMainWindowWithPreferencesPane(); - mainWindow.openAdvancedPreferences("dataChoicesTab"); - }, - }, + } }, supportsCommand: function gVC_supportsCommand(aCommand) { @@ -1468,10 +1428,6 @@ function createItem(aObj, aIsInstall, aIsRemote) { // the binding handles the rest item.setAttribute("value", aObj.id); - if (aObj.type == "experiment") { - item.endDate = getExperimentEndDate(aObj); - } - return item; } @@ -2679,13 +2635,6 @@ var gListView = { // the existing item if (aInstall.existingAddon) this.removeItem(aInstall, true); - - if (aInstall.addon.type == "experiment") { - let item = this.getListItemForID(aInstall.addon.id); - if (item) { - item.endDate = getExperimentEndDate(aInstall.addon); - } - } }, addItem: function gListView_addItem(aObj, aIsInstall) { @@ -2945,34 +2894,6 @@ var gDetailView = { } } - if (this._addon.type == "experiment") { - let prefix = "details.experiment."; - let active = this._addon.isActive; - - let stateKey = prefix + "state." + (active ? "active" : "complete"); - let node = document.getElementById("detail-experiment-state"); - node.value = gStrings.ext.GetStringFromName(stateKey); - - let now = Date.now(); - let end = getExperimentEndDate(this._addon); - let days = Math.abs(end - now) / (24 * 60 * 60 * 1000); - - let timeKey = prefix + "time."; - let timeMessage; - if (days < 1) { - timeKey += (active ? "endsToday" : "endedToday"); - timeMessage = gStrings.ext.GetStringFromName(timeKey); - } else { - timeKey += (active ? "daysRemaining" : "daysPassed"); - days = Math.round(days); - let timeString = gStrings.ext.GetStringFromName(timeKey); - timeMessage = PluralForm.get(days, timeString) - .replace("#1", days); - } - - document.getElementById("detail-experiment-time").value = timeMessage; - } - this.fillSettingsRows(aScrollToPreferences, (function updateView_fillSettingsRows() { this.updateState(); gViewController.notifyViewChanged(); diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 54b86edc4..d5f1ab5dd 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -37,9 +37,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task", XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "BrowserToolboxProcess", - "resource://gre/modules/devtools/ToolboxProcess.jsm"); + "resource://devtools/client/framework/ToolboxProcess.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPI", - "resource://gre/modules/devtools/Console.jsm"); + "resource://gre/modules/Console.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "Blocklist", "@mozilla.org/extensions/blocklist;1", @@ -2082,7 +2082,7 @@ this.XPIProvider = { Services.prefs.addObserver(PREF_EM_MIN_COMPAT_APP_VERSION, this, false); Services.prefs.addObserver(PREF_EM_MIN_COMPAT_PLATFORM_VERSION, this, false); Services.obs.addObserver(this, NOTIFICATION_FLUSH_PERMISSIONS, false); - if (Cu.isModuleLoaded("resource://gre/modules/devtools/ToolboxProcess.jsm")) { + if (Cu.isModuleLoaded("resource://devtools/client/framework/ToolboxProcess.jsm")) { // If BrowserToolboxProcess is already loaded, set the boolean to true // and do whatever is needed this._toolboxProcessLoaded = true; diff --git a/toolkit/mozapps/extensions/test/browser/browser_experiments.js b/toolkit/mozapps/extensions/test/browser/browser_experiments.js deleted file mode 100644 index 72d0ca83e..000000000 --- a/toolkit/mozapps/extensions/test/browser/browser_experiments.js +++ /dev/null @@ -1,645 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -Components.utils.import("resource://gre/modules/Promise.jsm", this); - -let {AddonTestUtils} = Components.utils.import("resource://testing-common/AddonManagerTesting.jsm", {}); -let {HttpServer} = Components.utils.import("resource://testing-common/httpd.js", {}); - -let gManagerWindow; -let gCategoryUtilities; -let gExperiments; -let gHttpServer; - -let gSavedManifestURI; -let gIsEnUsLocale; - -const SEC_IN_ONE_DAY = 24 * 60 * 60; -const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000; - -function getExperimentAddons() { - let deferred = Promise.defer(); - AddonManager.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons); - }); - return deferred.promise; -} - -function getInstallItem() { - let doc = gManagerWindow.document; - let view = doc.getElementById("view-port").selectedPanel; - let list = doc.getElementById("addon-list"); - - let node = list.firstChild; - while (node) { - if (node.getAttribute("status") == "installing") { - return node; - } - node = node.nextSibling; - } - - return null; -} - -function patchPolicy(policy, data) { - for (let key of Object.keys(data)) { - Object.defineProperty(policy, key, { - value: data[key], - writable: true, - }); - } -} - -function defineNow(policy, time) { - patchPolicy(policy, { now: () => new Date(time) }); -} - -function openDetailsView(aId) { - let item = get_addon_element(gManagerWindow, aId); - Assert.ok(item, "Should have got add-on element."); - is_element_visible(item, "Add-on element should be visible."); - - EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow); - EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow); - - let deferred = Promise.defer(); - wait_for_view_load(gManagerWindow, deferred.resolve); - return deferred.promise; -} - -function clickRemoveButton(addonElement) { - let btn = gManagerWindow.document.getAnonymousElementByAttribute(addonElement, "anonid", "remove-btn"); - if (!btn) { - return Promise.reject(); - } - - EventUtils.synthesizeMouseAtCenter(btn, { clickCount: 1 }, gManagerWindow); - let deferred = Promise.defer(); - setTimeout(deferred.resolve, 0); - return deferred; -} - -function clickUndoButton(addonElement) { - let btn = gManagerWindow.document.getAnonymousElementByAttribute(addonElement, "anonid", "undo-btn"); - if (!btn) { - return Promise.reject(); - } - - EventUtils.synthesizeMouseAtCenter(btn, { clickCount: 1 }, gManagerWindow); - let deferred = Promise.defer(); - setTimeout(deferred.resolve, 0); - return deferred; -} - -add_task(function* initializeState() { - gManagerWindow = yield open_manager(); - gCategoryUtilities = new CategoryUtilities(gManagerWindow); - - registerCleanupFunction(() => { - Services.prefs.clearUserPref("experiments.enabled"); - if (gHttpServer) { - gHttpServer.stop(() => {}); - if (gSavedManifestURI !== undefined) { - Services.prefs.setCharPref("experments.manifest.uri", gSavedManifestURI); - } - } - if (gExperiments) { - let tmp = {}; - Cu.import("resource:///modules/experiments/Experiments.jsm", tmp); - gExperiments._policy = new tmp.Experiments.Policy(); - } - }); - - let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); - gIsEnUsLocale = chrome.getSelectedLocale("global") == "en-US"; - - // The Experiments Manager will interfere with us by preventing installs - // of experiments it doesn't know about. We remove it from the equation - // because here we are only concerned with core Addon Manager operation, - // not the superset Experiments Manager has imposed. - if ("@mozilla.org/browser/experiments-service;1" in Components.classes) { - let tmp = {}; - Cu.import("resource:///modules/experiments/Experiments.jsm", tmp); - // There is a race condition between XPCOM service initialization and - // this test running. We have to initialize the instance first, then - // uninitialize it to prevent this. - gExperiments = tmp.Experiments.instance(); - yield gExperiments._mainTask; - yield gExperiments.uninit(); - } -}); - -// On an empty profile with no experiments, the experiment category -// should be hidden. -add_task(function* testInitialState() { - Assert.ok(gCategoryUtilities.get("experiment", false), "Experiment tab is defined."); - Assert.ok(!gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab hidden by default."); -}); - -add_task(function* testExperimentInfoNotVisible() { - yield gCategoryUtilities.openType("extension"); - let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0]; - is_element_hidden(el, "Experiment info not visible on other types."); -}); - -// If we have an active experiment, we should see the experiments tab -// and that tab should have some messages. -add_task(function* testActiveExperiment() { - let addon = yield install_addon("addons/browser_experiment1.xpi"); - - Assert.ok(addon.userDisabled, "Add-on is disabled upon initial install."); - Assert.equal(addon.isActive, false, "Add-on is not active."); - - Assert.ok(gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab visible."); - - yield gCategoryUtilities.openType("experiment"); - let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0]; - is_element_visible(el, "Experiment info is visible on experiment tab."); -}); - -add_task(function* testExperimentLearnMore() { - // Actual URL is irrelevant. - Services.prefs.setCharPref("toolkit.telemetry.infoURL", - "http://mochi.test:8888/server.js"); - - yield gCategoryUtilities.openType("experiment"); - let btn = gManagerWindow.document.getElementById("experiments-learn-more"); - - if (!gUseInContentUI) { - is_element_hidden(btn, "Learn more button hidden if not using in-content UI."); - Services.prefs.clearUserPref("toolkit.telemetry.infoURL"); - - return; - } - - is_element_visible(btn, "Learn more button visible."); - - let deferred = Promise.defer(); - window.addEventListener("DOMContentLoaded", function onLoad(event) { - info("Telemetry privacy policy window opened."); - window.removeEventListener("DOMContentLoaded", onLoad, false); - - let browser = gBrowser.selectedBrowser; - let expected = Services.prefs.getCharPref("toolkit.telemetry.infoURL"); - Assert.equal(browser.currentURI.spec, expected, "New tab should have loaded privacy policy."); - browser.contentWindow.close(); - - Services.prefs.clearUserPref("toolkit.telemetry.infoURL"); - - deferred.resolve(); - }, false); - - info("Opening telemetry privacy policy."); - EventUtils.synthesizeMouseAtCenter(btn, {}, gManagerWindow); - - yield deferred.promise; -}); - -add_task(function* testOpenPreferences() { - yield gCategoryUtilities.openType("experiment"); - let btn = gManagerWindow.document.getElementById("experiments-change-telemetry"); - if (!gUseInContentUI) { - is_element_hidden(btn, "Change telemetry button not enabled in out of window UI."); - info("Skipping preferences open test because not using in-content UI."); - return; - } - - is_element_visible(btn, "Change telemetry button visible in in-content UI."); - - let deferred = Promise.defer(); - Services.obs.addObserver(function observer(prefWin, topic, data) { - Services.obs.removeObserver(observer, "advanced-pane-loaded"); - info("Advanced preference pane opened."); - executeSoon(function() { - // We want this test to fail if the preferences pane changes. - let el = prefWin.document.getElementById("dataChoicesPanel"); - is_element_visible(el); - - prefWin.close(); - info("Closed preferences pane."); - - deferred.resolve(); - }); - }, "advanced-pane-loaded", false); - - info("Loading preferences pane."); - EventUtils.synthesizeMouseAtCenter(btn, {}, gManagerWindow); - - yield deferred.promise; -}); - -add_task(function* testButtonPresence() { - yield gCategoryUtilities.openType("experiment"); - let item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org"); - Assert.ok(item, "Got add-on element."); - item.parentNode.ensureElementIsVisible(item); - - let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn"); - // Corresponds to the uninstall permission. - is_element_visible(el, "Remove button is visible."); - // Corresponds to lack of disable permission. - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn"); - is_element_hidden(el, "Disable button not visible."); - // Corresponds to lack of enable permission. - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn"); - is_element_hidden(el, "Enable button not visible."); -}); - -// Remove the add-on we've been testing with. -add_task(function* testCleanup() { - yield AddonTestUtils.uninstallAddonByID("test-experiment1@experiments.mozilla.org"); - // Verify some conditions, just in case. - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "No experiment add-ons are installed."); -}); - -// The following tests should ideally live in browser/experiments/. However, -// they rely on some of the helper functions from head.js, which can't easily -// be consumed from other directories. So, they live here. - -add_task(function* testActivateExperiment() { - if (!gExperiments) { - info("Skipping experiments test because that feature isn't available."); - return; - } - - gHttpServer = new HttpServer(); - gHttpServer.start(-1); - let root = "http://localhost:" + gHttpServer.identity.primaryPort + "/"; - gHttpServer.registerPathHandler("/manifest", (request, response) => { - response.setStatusLine(null, 200, "OK"); - response.write(JSON.stringify({ - "version": 1, - "experiments": [ - { - id: "experiment-1", - xpiURL: TESTROOT + "addons/browser_experiment1.xpi", - xpiHash: "IRRELEVANT", - startTime: Date.now() / 1000 - 3600, - endTime: Date.now() / 1000 + 3600, - maxActiveSeconds: 600, - appName: [Services.appinfo.name], - channel: [gExperiments._policy.updatechannel()], - }, - ], - })); - response.processAsync(); - response.finish(); - }); - - gSavedManifestURI = Services.prefs.getCharPref("experiments.manifest.uri"); - Services.prefs.setCharPref("experiments.manifest.uri", root + "manifest"); - - // We need to remove the cache file to help ensure consistent state. - yield OS.File.remove(gExperiments._cacheFilePath); - - Services.prefs.setBoolPref("experiments.enabled", true); - - info("Initializing experiments service."); - yield gExperiments.init(); - info("Experiments service finished first run."); - - // Check conditions, just to be sure. - let experiments = yield gExperiments.getExperiments(); - Assert.equal(experiments.length, 0, "No experiments known to the service."); - - // This makes testing easier. - gExperiments._policy.ignoreHashes = true; - - info("Manually updating experiments manifest."); - yield gExperiments.updateManifest(); - info("Experiments update complete."); - - let deferred = Promise.defer(); - gHttpServer.stop(() => { - gHttpServer = null; - - info("getting experiment by ID"); - AddonManager.getAddonByID("test-experiment1@experiments.mozilla.org", (addon) => { - Assert.ok(addon, "Add-on installed via Experiments manager."); - - deferred.resolve(); - }); - }); - - yield deferred.promise; - - Assert.ok(gCategoryUtilities.isTypeVisible, "experiment", "Experiment tab visible."); - yield gCategoryUtilities.openType("experiment"); - let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0]; - is_element_visible(el, "Experiment info is visible on experiment tab."); -}); - -add_task(function testDeactivateExperiment() { - if (!gExperiments) { - return; - } - - // Fake an empty manifest to purge data from previous manifest. - yield gExperiments._updateExperiments({ - "version": 1, - "experiments": [], - }); - - yield gExperiments.disableExperiment("testing"); - - // We should have a record of the previously-active experiment. - let experiments = yield gExperiments.getExperiments(); - Assert.equal(experiments.length, 1, "1 experiment is known."); - Assert.equal(experiments[0].active, false, "Experiment is not active."); - - // We should have a previous experiment in the add-ons manager. - let deferred = Promise.defer(); - AddonManager.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons); - }); - let addons = yield deferred.promise; - Assert.equal(addons.length, 1, "1 experiment add-on known."); - Assert.ok(addons[0].appDisabled, "It is a previous experiment."); - Assert.equal(addons[0].id, "experiment-1", "Add-on ID matches expected."); - - // Verify the UI looks sane. - - Assert.ok(gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab visible."); - let item = get_addon_element(gManagerWindow, "experiment-1"); - Assert.ok(item, "Got add-on element."); - Assert.ok(!item.active, "Element should not be active."); - item.parentNode.ensureElementIsVisible(item); - - // User control buttons should not be present because previous experiments - // should have no permissions. - let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn"); - is_element_hidden(el, "Remove button is not visible."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn"); - is_element_hidden(el, "Disable button is not visible."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn"); - is_element_hidden(el, "Enable button is not visible."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "preferences-btn"); - is_element_hidden(el, "Preferences button is not visible."); -}); - -add_task(function testActivateRealExperiments() { - if (!gExperiments) { - info("Skipping experiments test because that feature isn't available."); - return; - } - - yield gExperiments._updateExperiments({ - "version": 1, - "experiments": [ - { - id: "experiment-2", - xpiURL: TESTROOT + "addons/browser_experiment1.xpi", - xpiHash: "IRRELEVANT", - startTime: Date.now() / 1000 - 3600, - endTime: Date.now() / 1000 + 3600, - maxActiveSeconds: 600, - appName: [Services.appinfo.name], - channel: [gExperiments._policy.updatechannel()], - }, - ], - }); - yield gExperiments._run(); - - // Check the active experiment. - - let item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org"); - Assert.ok(item, "Got add-on element."); - item.parentNode.ensureElementIsVisible(item); - - let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Active"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Less than a day remaining"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "error-container"); - is_element_hidden(el, "error-container should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning-container"); - is_element_hidden(el, "warning-container should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "pending-container"); - is_element_hidden(el, "pending-container should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "version"); - is_element_hidden(el, "version should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix"); - is_element_hidden(el, "disabled-postfix should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "update-postfix"); - is_element_hidden(el, "update-postfix should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "experiment-bullet"); - is_element_visible(el, "experiment-bullet should be visible."); - - // Check the previous experiment. - - item = get_addon_element(gManagerWindow, "experiment-1"); - Assert.ok(item, "Got add-on element."); - item.parentNode.ensureElementIsVisible(item); - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Complete"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Less than a day ago"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "error-container"); - is_element_hidden(el, "error-container should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning-container"); - is_element_hidden(el, "warning-container should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "pending-container"); - is_element_hidden(el, "pending-container should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "version"); - is_element_hidden(el, "version should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix"); - is_element_hidden(el, "disabled-postfix should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "update-postfix"); - is_element_hidden(el, "update-postfix should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "experiment-bullet"); - is_element_visible(el, "experiment-bullet should be visible."); - - // Install an "older" experiment. - - yield gExperiments.disableExperiment("experiment-2"); - - let now = Date.now(); - let fakeNow = now - 5 * MS_IN_ONE_DAY; - defineNow(gExperiments._policy, fakeNow); - - yield gExperiments._updateExperiments({ - "version": 1, - "experiments": [ - { - id: "experiment-3", - xpiURL: TESTROOT + "addons/browser_experiment1.xpi", - xpiHash: "IRRELEVANT", - startTime: fakeNow / 1000 - SEC_IN_ONE_DAY, - endTime: now / 1000 + 10 * SEC_IN_ONE_DAY, - maxActiveSeconds: 100 * SEC_IN_ONE_DAY, - appName: [Services.appinfo.name], - channel: [gExperiments._policy.updatechannel()], - }, - ], - }); - yield gExperiments._run(); - - // Check the active experiment. - - item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org"); - Assert.ok(item, "Got add-on element."); - item.parentNode.ensureElementIsVisible(item); - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Active"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "10 days remaining"); - } - - // Disable it and check it's previous experiment entry. - - yield gExperiments.disableExperiment("experiment-3"); - - item = get_addon_element(gManagerWindow, "experiment-3"); - Assert.ok(item, "Got add-on element."); - item.parentNode.ensureElementIsVisible(item); - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Complete"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "5 days ago"); - } -}); - -add_task(function testDetailView() { - if (!gExperiments) { - info("Skipping experiments test because that feature isn't available."); - return; - } - - defineNow(gExperiments._policy, Date.now()); - yield gExperiments._updateExperiments({ - "version": 1, - "experiments": [ - { - id: "experiment-4", - xpiURL: TESTROOT + "addons/browser_experiment1.xpi", - xpiHash: "IRRELEVANT", - startTime: Date.now() / 1000 - 3600, - endTime: Date.now() / 1000 + 3600, - maxActiveSeconds: 600, - appName: [Services.appinfo.name], - channel: [gExperiments._policy.updatechannel()], - }, - ], - }); - yield gExperiments._run(); - - // Check active experiment. - - yield openDetailsView("test-experiment1@experiments.mozilla.org"); - - let el = gManagerWindow.document.getElementById("detail-experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Active"); - } - - el = gManagerWindow.document.getElementById("detail-experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Less than a day remaining"); - } - - el = gManagerWindow.document.getElementById("detail-version"); - is_element_hidden(el, "detail-version should be hidden."); - el = gManagerWindow.document.getElementById("detail-creator"); - is_element_hidden(el, "detail-creator should be hidden."); - el = gManagerWindow.document.getElementById("detail-experiment-bullet"); - is_element_visible(el, "experiment-bullet should be visible."); - - // Check previous experiment. - - yield gCategoryUtilities.openType("experiment"); - yield openDetailsView("experiment-3"); - - el = gManagerWindow.document.getElementById("detail-experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Complete"); - } - - el = gManagerWindow.document.getElementById("detail-experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "5 days ago"); - } - - el = gManagerWindow.document.getElementById("detail-version"); - is_element_hidden(el, "detail-version should be hidden."); - el = gManagerWindow.document.getElementById("detail-creator"); - is_element_hidden(el, "detail-creator should be hidden."); - el = gManagerWindow.document.getElementById("detail-experiment-bullet"); - is_element_visible(el, "experiment-bullet should be visible."); -}); - -add_task(function* testRemoveAndUndo() { - if (!gExperiments) { - info("Skipping experiments test because that feature isn't available."); - return; - } - - yield gCategoryUtilities.openType("experiment"); - - let addon = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org"); - Assert.ok(addon, "Got add-on element."); - - yield clickRemoveButton(addon); - addon.parentNode.ensureElementIsVisible(addon); - - let el = gManagerWindow.document.getAnonymousElementByAttribute(addon, "class", "pending"); - is_element_visible(el, "Uninstall undo information should be visible."); - - yield clickUndoButton(addon); - addon = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org"); - Assert.ok(addon, "Got add-on element."); -}); - -add_task(function* testCleanup() { - if (gExperiments) { - Services.prefs.clearUserPref("experiments.enabled"); - Services.prefs.setCharPref("experiments.manifest.uri", gSavedManifestURI); - - // We perform the uninit/init cycle to purge any leftover state. - yield OS.File.remove(gExperiments._cacheFilePath); - yield gExperiments.uninit(); - yield gExperiments.init(); - } - - // Check post-conditions. - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "No experiment add-ons are installed."); - - yield close_manager(gManagerWindow); -}); diff --git a/toolkit/mozapps/webextensions/content/extensions.js b/toolkit/mozapps/webextensions/content/extensions.js index 5e428fe17..3159eb1e1 100644 --- a/toolkit/mozapps/webextensions/content/extensions.js +++ b/toolkit/mozapps/webextensions/content/extensions.js @@ -29,9 +29,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", XPCOMUtils.defineLazyModuleGetter(this, "Preferences", "resource://gre/modules/Preferences.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Experiments", - "resource:///modules/experiments/Experiments.jsm"); - const PREF_DISCOVERURL = "extensions.webservice.discoverURL"; const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane"; const PREF_XPI_ENABLED = "xpinstall.enabled"; @@ -297,23 +294,6 @@ function isDiscoverEnabled() { return true; } -function getExperimentEndDate(aAddon) { - if (!("@mozilla.org/browser/experiments-service;1" in Cc)) { - return 0; - } - - if (!aAddon.isActive) { - return aAddon.endDate; - } - - let experiment = Experiments.instance().getActiveExperiment(); - if (!experiment) { - return 0; - } - - return experiment.endDate; -} - /** * Obtain the main DOMWindow for the current context. */ @@ -1444,27 +1424,6 @@ var gViewController = { } }, - cmd_experimentsLearnMore: { - isEnabled: function() { - let mainWindow = getMainWindow(); - return mainWindow && "switchToTabHavingURI" in mainWindow; - }, - doCommand: function() { - let url = Services.prefs.getCharPref("toolkit.telemetry.infoURL"); - openOptionsInTab(url); - }, - }, - - cmd_experimentsOpenTelemetryPreferences: { - isEnabled: function() { - return !!getMainWindowWithPreferencesPane(); - }, - doCommand: function() { - let mainWindow = getMainWindowWithPreferencesPane(); - mainWindow.openAdvancedPreferences("dataChoicesTab"); - }, - }, - cmd_showUnsignedExtensions: { isEnabled: function() { return true; @@ -1577,10 +1536,6 @@ function shouldShowVersionNumber(aAddon) { if (!aAddon.version) return false; - // The version number is hidden for experiments. - if (aAddon.type == "experiment") - return false; - // The version number is hidden for lightweight themes. if (aAddon.type == "theme") return !/@personas\.mozilla\.org$/.test(aAddon.id); @@ -1614,10 +1569,6 @@ function createItem(aObj, aIsInstall, aIsRemote) { // the binding handles the rest item.setAttribute("value", aObj.id); - if (aObj.type == "experiment") { - item.endDate = getExperimentEndDate(aObj); - } - return item; } @@ -2861,13 +2812,6 @@ var gListView = { // the existing item if (aInstall.existingAddon) this.removeItem(aInstall, true); - - if (aInstall.addon.type == "experiment") { - let item = this.getListItemForID(aInstall.addon.id); - if (item) { - item.endDate = getExperimentEndDate(aInstall.addon); - } - } }, addItem: function(aObj, aIsInstall) { @@ -3126,34 +3070,6 @@ var gDetailView = { } } - if (this._addon.type == "experiment") { - let prefix = "details.experiment."; - let active = this._addon.isActive; - - let stateKey = prefix + "state." + (active ? "active" : "complete"); - let node = document.getElementById("detail-experiment-state"); - node.value = gStrings.ext.GetStringFromName(stateKey); - - let now = Date.now(); - let end = getExperimentEndDate(this._addon); - let days = Math.abs(end - now) / (24 * 60 * 60 * 1000); - - let timeKey = prefix + "time."; - let timeMessage; - if (days < 1) { - timeKey += (active ? "endsToday" : "endedToday"); - timeMessage = gStrings.ext.GetStringFromName(timeKey); - } else { - timeKey += (active ? "daysRemaining" : "daysPassed"); - days = Math.round(days); - let timeString = gStrings.ext.GetStringFromName(timeKey); - timeMessage = PluralForm.get(days, timeString) - .replace("#1", days); - } - - document.getElementById("detail-experiment-time").value = timeMessage; - } - this.fillSettingsRows(aScrollToPreferences, (function() { this.updateState(); gViewController.notifyViewChanged(); diff --git a/toolkit/mozapps/webextensions/internal/XPIProvider.jsm b/toolkit/mozapps/webextensions/internal/XPIProvider.jsm index 87e09cef1..7c3cb6763 100644 --- a/toolkit/mozapps/webextensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/webextensions/internal/XPIProvider.jsm @@ -175,6 +175,8 @@ const RDFURI_INSTALL_MANIFEST_ROOT = "urn:mozilla:install-manifest"; const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#"; const TOOLKIT_ID = "toolkit@mozilla.org"; +const WEBEXTENSIONS_ID = "webextensions@mozilla.org"; +const WEBEXTENSIONS_VERSION = "52.0"; const XPI_SIGNATURE_CHECK_PERIOD = 24 * 60 * 60; @@ -1037,7 +1039,7 @@ var loadManifestFromWebManifest = Task.async(function*(aUri) { delete addon.defaultLocale.locales; addon.targetApplications = [{ - id: TOOLKIT_ID, + id: WEBEXTENSIONS_ID, minVersion: bss.strict_min_version, maxVersion: bss.strict_max_version, }]; @@ -7228,6 +7230,8 @@ AddonInternal.prototype = { version = aAppVersion; else if (app.id == TOOLKIT_ID) version = aPlatformVersion + else if (app.id == WEBEXTENSIONS_ID) + version = WEBEXTENSIONS_VERSION // Only extensions and dictionaries can be compatible by default; themes // and language packs always use strict compatibility checking. @@ -7250,7 +7254,7 @@ AddonInternal.prototype = { let minCompatVersion; if (app.id == Services.appinfo.ID) minCompatVersion = XPIProvider.minCompatibleAppVersion; - else if (app.id == TOOLKIT_ID) + else if (app.id == TOOLKIT_ID || app.id == WEBEXTENSIONS_ID) minCompatVersion = XPIProvider.minCompatiblePlatformVersion; if (minCompatVersion && @@ -7269,7 +7273,7 @@ AddonInternal.prototype = { for (let targetApp of this.targetApplications) { if (targetApp.id == Services.appinfo.ID) return targetApp; - if (targetApp.id == TOOLKIT_ID) + if (targetApp.id == TOOLKIT_ID || targetApp.id == WEBEXTENSIONS_ID) app = targetApp; } return app; diff --git a/toolkit/mozapps/webextensions/test/browser/browser_experiments.js b/toolkit/mozapps/webextensions/test/browser/browser_experiments.js deleted file mode 100644 index 18a548de5..000000000 --- a/toolkit/mozapps/webextensions/test/browser/browser_experiments.js +++ /dev/null @@ -1,654 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -Components.utils.import("resource://gre/modules/Promise.jsm", this); - -var {AddonManagerTesting} = Components.utils.import("resource://testing-common/AddonManagerTesting.jsm", {}); -var {HttpServer} = Components.utils.import("resource://testing-common/httpd.js", {}); - -var gManagerWindow; -var gCategoryUtilities; -var gExperiments; -var gHttpServer; - -var gSavedManifestURI; -var gIsEnUsLocale; - -const SEC_IN_ONE_DAY = 24 * 60 * 60; -const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000; - -function getExperimentAddons() { - let deferred = Promise.defer(); - AddonManager.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons); - }); - return deferred.promise; -} - -function getInstallItem() { - let doc = gManagerWindow.document; - let view = get_current_view(gManagerWindow); - let list = doc.getElementById("addon-list"); - - let node = list.firstChild; - while (node) { - if (node.getAttribute("status") == "installing") { - return node; - } - node = node.nextSibling; - } - - return null; -} - -function patchPolicy(policy, data) { - for (let key of Object.keys(data)) { - Object.defineProperty(policy, key, { - value: data[key], - writable: true, - }); - } -} - -function defineNow(policy, time) { - patchPolicy(policy, { now: () => new Date(time) }); -} - -function openDetailsView(aId) { - let item = get_addon_element(gManagerWindow, aId); - Assert.ok(item, "Should have got add-on element."); - is_element_visible(item, "Add-on element should be visible."); - - EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow); - EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow); - - let deferred = Promise.defer(); - wait_for_view_load(gManagerWindow, deferred.resolve); - return deferred.promise; -} - -function clickRemoveButton(addonElement) { - let btn = gManagerWindow.document.getAnonymousElementByAttribute(addonElement, "anonid", "remove-btn"); - if (!btn) { - return Promise.reject(); - } - - EventUtils.synthesizeMouseAtCenter(btn, { clickCount: 1 }, gManagerWindow); - let deferred = Promise.defer(); - setTimeout(deferred.resolve, 0); - return deferred; -} - -function clickUndoButton(addonElement) { - let btn = gManagerWindow.document.getAnonymousElementByAttribute(addonElement, "anonid", "undo-btn"); - if (!btn) { - return Promise.reject(); - } - - EventUtils.synthesizeMouseAtCenter(btn, { clickCount: 1 }, gManagerWindow); - let deferred = Promise.defer(); - setTimeout(deferred.resolve, 0); - return deferred; -} - -add_task(function* initializeState() { - gManagerWindow = yield open_manager(); - gCategoryUtilities = new CategoryUtilities(gManagerWindow); - - registerCleanupFunction(() => { - Services.prefs.clearUserPref("experiments.enabled"); - Services.prefs.clearUserPref("toolkit.telemetry.enabled"); - if (gHttpServer) { - gHttpServer.stop(() => {}); - if (gSavedManifestURI !== undefined) { - Services.prefs.setCharPref("experments.manifest.uri", gSavedManifestURI); - } - } - if (gExperiments) { - let tmp = {}; - Cu.import("resource:///modules/experiments/Experiments.jsm", tmp); - gExperiments._policy = new tmp.Experiments.Policy(); - } - }); - - let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); - gIsEnUsLocale = chrome.getSelectedLocale("global") == "en-US"; - - // The Experiments Manager will interfere with us by preventing installs - // of experiments it doesn't know about. We remove it from the equation - // because here we are only concerned with core Addon Manager operation, - // not the superset Experiments Manager has imposed. - if ("@mozilla.org/browser/experiments-service;1" in Components.classes) { - let tmp = {}; - Cu.import("resource:///modules/experiments/Experiments.jsm", tmp); - // There is a race condition between XPCOM service initialization and - // this test running. We have to initialize the instance first, then - // uninitialize it to prevent this. - gExperiments = tmp.Experiments.instance(); - yield gExperiments._mainTask; - yield gExperiments.uninit(); - } -}); - -// On an empty profile with no experiments, the experiment category -// should be hidden. -add_task(function* testInitialState() { - Assert.ok(gCategoryUtilities.get("experiment", false), "Experiment tab is defined."); - Assert.ok(!gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab hidden by default."); -}); - -add_task(function* testExperimentInfoNotVisible() { - yield gCategoryUtilities.openType("extension"); - let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0]; - is_element_hidden(el, "Experiment info not visible on other types."); -}); - -// If we have an active experiment, we should see the experiments tab -// and that tab should have some messages. -add_task(function* testActiveExperiment() { - let addon = yield install_addon("addons/browser_experiment1.xpi"); - - Assert.ok(addon.userDisabled, "Add-on is disabled upon initial install."); - Assert.equal(addon.isActive, false, "Add-on is not active."); - - Assert.ok(gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab visible."); - - yield gCategoryUtilities.openType("experiment"); - let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0]; - is_element_visible(el, "Experiment info is visible on experiment tab."); -}); - -add_task(function* testExperimentLearnMore() { - // Actual URL is irrelevant. - Services.prefs.setCharPref("toolkit.telemetry.infoURL", - "http://mochi.test:8888/server.js"); - - yield gCategoryUtilities.openType("experiment"); - let btn = gManagerWindow.document.getElementById("experiments-learn-more"); - - if (!gUseInContentUI) { - is_element_hidden(btn, "Learn more button hidden if not using in-content UI."); - Services.prefs.clearUserPref("toolkit.telemetry.infoURL"); - - return; - } - - is_element_visible(btn, "Learn more button visible."); - - let deferred = Promise.defer(); - window.addEventListener("DOMContentLoaded", function onLoad(event) { - info("Telemetry privacy policy window opened."); - window.removeEventListener("DOMContentLoaded", onLoad, false); - - let browser = gBrowser.selectedBrowser; - let expected = Services.prefs.getCharPref("toolkit.telemetry.infoURL"); - Assert.equal(browser.currentURI.spec, expected, "New tab should have loaded privacy policy."); - browser.contentWindow.close(); - - Services.prefs.clearUserPref("toolkit.telemetry.infoURL"); - - deferred.resolve(); - }, false); - - info("Opening telemetry privacy policy."); - EventUtils.synthesizeMouseAtCenter(btn, {}, gManagerWindow); - - yield deferred.promise; -}); - -add_task(function* testOpenPreferences() { - yield gCategoryUtilities.openType("experiment"); - let btn = gManagerWindow.document.getElementById("experiments-change-telemetry"); - if (!gUseInContentUI) { - is_element_hidden(btn, "Change telemetry button not enabled in out of window UI."); - info("Skipping preferences open test because not using in-content UI."); - return; - } - - is_element_visible(btn, "Change telemetry button visible in in-content UI."); - - let deferred = Promise.defer(); - Services.obs.addObserver(function observer(prefWin, topic, data) { - Services.obs.removeObserver(observer, "advanced-pane-loaded"); - info("Advanced preference pane opened."); - executeSoon(function() { - // We want this test to fail if the preferences pane changes. - let el = prefWin.document.getElementById("dataChoicesPanel"); - is_element_visible(el); - - prefWin.close(); - info("Closed preferences pane."); - - deferred.resolve(); - }); - }, "advanced-pane-loaded", false); - - info("Loading preferences pane."); - // We need to focus before synthesizing the mouse event (bug 1240052) as - // synthesizeMouseAtCenter currently only synthesizes the mouse in the child process. - // This can cause some subtle differences if the child isn't focused. - yield SimpleTest.promiseFocus(); - yield BrowserTestUtils.synthesizeMouseAtCenter("#experiments-change-telemetry", {}, - gBrowser.selectedBrowser); - - yield deferred.promise; -}); - -add_task(function* testButtonPresence() { - yield gCategoryUtilities.openType("experiment"); - let item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org"); - Assert.ok(item, "Got add-on element."); - item.parentNode.ensureElementIsVisible(item); - - let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn"); - // Corresponds to the uninstall permission. - is_element_visible(el, "Remove button is visible."); - // Corresponds to lack of disable permission. - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn"); - is_element_hidden(el, "Disable button not visible."); - // Corresponds to lack of enable permission. - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn"); - is_element_hidden(el, "Enable button not visible."); -}); - -// Remove the add-on we've been testing with. -add_task(function* testCleanup() { - yield AddonManagerTesting.uninstallAddonByID("test-experiment1@experiments.mozilla.org"); - // Verify some conditions, just in case. - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "No experiment add-ons are installed."); -}); - -// The following tests should ideally live in browser/experiments/. However, -// they rely on some of the helper functions from head.js, which can't easily -// be consumed from other directories. So, they live here. - -add_task(function* testActivateExperiment() { - if (!gExperiments) { - info("Skipping experiments test because that feature isn't available."); - return; - } - - gHttpServer = new HttpServer(); - gHttpServer.start(-1); - let root = "http://localhost:" + gHttpServer.identity.primaryPort + "/"; - gHttpServer.registerPathHandler("/manifest", (request, response) => { - response.setStatusLine(null, 200, "OK"); - response.write(JSON.stringify({ - "version": 1, - "experiments": [ - { - id: "experiment-1", - xpiURL: TESTROOT + "addons/browser_experiment1.xpi", - xpiHash: "IRRELEVANT", - startTime: Date.now() / 1000 - 3600, - endTime: Date.now() / 1000 + 3600, - maxActiveSeconds: 600, - appName: [Services.appinfo.name], - channel: [gExperiments._policy.updatechannel()], - }, - ], - })); - response.processAsync(); - response.finish(); - }); - - gSavedManifestURI = Services.prefs.getCharPref("experiments.manifest.uri"); - Services.prefs.setCharPref("experiments.manifest.uri", root + "manifest"); - - // We need to remove the cache file to help ensure consistent state. - yield OS.File.remove(gExperiments._cacheFilePath); - - Services.prefs.setBoolPref("toolkit.telemetry.enabled", true); - Services.prefs.setBoolPref("experiments.enabled", true); - - info("Initializing experiments service."); - yield gExperiments.init(); - info("Experiments service finished first run."); - - // Check conditions, just to be sure. - let experiments = yield gExperiments.getExperiments(); - Assert.equal(experiments.length, 0, "No experiments known to the service."); - - // This makes testing easier. - gExperiments._policy.ignoreHashes = true; - - info("Manually updating experiments manifest."); - yield gExperiments.updateManifest(); - info("Experiments update complete."); - - let deferred = Promise.defer(); - gHttpServer.stop(() => { - gHttpServer = null; - - info("getting experiment by ID"); - AddonManager.getAddonByID("test-experiment1@experiments.mozilla.org", (addon) => { - Assert.ok(addon, "Add-on installed via Experiments manager."); - - deferred.resolve(); - }); - }); - - yield deferred.promise; - - Assert.ok(gCategoryUtilities.isTypeVisible, "experiment", "Experiment tab visible."); - yield gCategoryUtilities.openType("experiment"); - let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0]; - is_element_visible(el, "Experiment info is visible on experiment tab."); -}); - -add_task(function* testDeactivateExperiment() { - if (!gExperiments) { - return; - } - - // Fake an empty manifest to purge data from previous manifest. - yield gExperiments._updateExperiments({ - "version": 1, - "experiments": [], - }); - - yield gExperiments.disableExperiment("testing"); - - // We should have a record of the previously-active experiment. - let experiments = yield gExperiments.getExperiments(); - Assert.equal(experiments.length, 1, "1 experiment is known."); - Assert.equal(experiments[0].active, false, "Experiment is not active."); - - // We should have a previous experiment in the add-ons manager. - let deferred = Promise.defer(); - AddonManager.getAddonsByTypes(["experiment"], (addons) => { - deferred.resolve(addons); - }); - let addons = yield deferred.promise; - Assert.equal(addons.length, 1, "1 experiment add-on known."); - Assert.ok(addons[0].appDisabled, "It is a previous experiment."); - Assert.equal(addons[0].id, "experiment-1", "Add-on ID matches expected."); - - // Verify the UI looks sane. - - Assert.ok(gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab visible."); - let item = get_addon_element(gManagerWindow, "experiment-1"); - Assert.ok(item, "Got add-on element."); - Assert.ok(!item.active, "Element should not be active."); - item.parentNode.ensureElementIsVisible(item); - - // User control buttons should not be present because previous experiments - // should have no permissions. - let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn"); - is_element_hidden(el, "Remove button is not visible."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn"); - is_element_hidden(el, "Disable button is not visible."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn"); - is_element_hidden(el, "Enable button is not visible."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "preferences-btn"); - is_element_hidden(el, "Preferences button is not visible."); -}); - -add_task(function* testActivateRealExperiments() { - if (!gExperiments) { - info("Skipping experiments test because that feature isn't available."); - return; - } - - yield gExperiments._updateExperiments({ - "version": 1, - "experiments": [ - { - id: "experiment-2", - xpiURL: TESTROOT + "addons/browser_experiment1.xpi", - xpiHash: "IRRELEVANT", - startTime: Date.now() / 1000 - 3600, - endTime: Date.now() / 1000 + 3600, - maxActiveSeconds: 600, - appName: [Services.appinfo.name], - channel: [gExperiments._policy.updatechannel()], - }, - ], - }); - yield gExperiments._run(); - - // Check the active experiment. - - let item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org"); - Assert.ok(item, "Got add-on element."); - item.parentNode.ensureElementIsVisible(item); - - let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Active"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Less than a day remaining"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "error-container"); - is_element_hidden(el, "error-container should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning-container"); - is_element_hidden(el, "warning-container should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "pending-container"); - is_element_hidden(el, "pending-container should be hidden."); - let { version } = yield get_tooltip_info(item); - Assert.equal(version, undefined, "version should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix"); - is_element_hidden(el, "disabled-postfix should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "update-postfix"); - is_element_hidden(el, "update-postfix should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "experiment-bullet"); - is_element_visible(el, "experiment-bullet should be visible."); - - // Check the previous experiment. - - item = get_addon_element(gManagerWindow, "experiment-1"); - Assert.ok(item, "Got add-on element."); - item.parentNode.ensureElementIsVisible(item); - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Complete"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Less than a day ago"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "error-container"); - is_element_hidden(el, "error-container should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning-container"); - is_element_hidden(el, "warning-container should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "pending-container"); - is_element_hidden(el, "pending-container should be hidden."); - ({ version } = yield get_tooltip_info(item)); - Assert.equal(version, undefined, "version should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix"); - is_element_hidden(el, "disabled-postfix should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "update-postfix"); - is_element_hidden(el, "update-postfix should be hidden."); - el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "experiment-bullet"); - is_element_visible(el, "experiment-bullet should be visible."); - - // Install an "older" experiment. - - yield gExperiments.disableExperiment("experiment-2"); - - let now = Date.now(); - let fakeNow = now - 5 * MS_IN_ONE_DAY; - defineNow(gExperiments._policy, fakeNow); - - yield gExperiments._updateExperiments({ - "version": 1, - "experiments": [ - { - id: "experiment-3", - xpiURL: TESTROOT + "addons/browser_experiment1.xpi", - xpiHash: "IRRELEVANT", - startTime: fakeNow / 1000 - SEC_IN_ONE_DAY, - endTime: now / 1000 + 10 * SEC_IN_ONE_DAY, - maxActiveSeconds: 100 * SEC_IN_ONE_DAY, - appName: [Services.appinfo.name], - channel: [gExperiments._policy.updatechannel()], - }, - ], - }); - yield gExperiments._run(); - - // Check the active experiment. - - item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org"); - Assert.ok(item, "Got add-on element."); - item.parentNode.ensureElementIsVisible(item); - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Active"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "10 days remaining"); - } - - // Disable it and check it's previous experiment entry. - - yield gExperiments.disableExperiment("experiment-3"); - - item = get_addon_element(gManagerWindow, "experiment-3"); - Assert.ok(item, "Got add-on element."); - item.parentNode.ensureElementIsVisible(item); - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Complete"); - } - - el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "5 days ago"); - } -}); - -add_task(function* testDetailView() { - if (!gExperiments) { - info("Skipping experiments test because that feature isn't available."); - return; - } - - defineNow(gExperiments._policy, Date.now()); - yield gExperiments._updateExperiments({ - "version": 1, - "experiments": [ - { - id: "experiment-4", - xpiURL: TESTROOT + "addons/browser_experiment1.xpi", - xpiHash: "IRRELEVANT", - startTime: Date.now() / 1000 - 3600, - endTime: Date.now() / 1000 + 3600, - maxActiveSeconds: 600, - appName: [Services.appinfo.name], - channel: [gExperiments._policy.updatechannel()], - }, - ], - }); - yield gExperiments._run(); - - // Check active experiment. - - yield openDetailsView("test-experiment1@experiments.mozilla.org"); - - let el = gManagerWindow.document.getElementById("detail-experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Active"); - } - - el = gManagerWindow.document.getElementById("detail-experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Less than a day remaining"); - } - - el = gManagerWindow.document.getElementById("detail-version"); - is_element_hidden(el, "detail-version should be hidden."); - el = gManagerWindow.document.getElementById("detail-creator"); - is_element_hidden(el, "detail-creator should be hidden."); - el = gManagerWindow.document.getElementById("detail-experiment-bullet"); - is_element_visible(el, "experiment-bullet should be visible."); - - // Check previous experiment. - - yield gCategoryUtilities.openType("experiment"); - yield openDetailsView("experiment-3"); - - el = gManagerWindow.document.getElementById("detail-experiment-state"); - is_element_visible(el, "Experiment state label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "Complete"); - } - - el = gManagerWindow.document.getElementById("detail-experiment-time"); - is_element_visible(el, "Experiment time label should be visible."); - if (gIsEnUsLocale) { - Assert.equal(el.value, "5 days ago"); - } - - el = gManagerWindow.document.getElementById("detail-version"); - is_element_hidden(el, "detail-version should be hidden."); - el = gManagerWindow.document.getElementById("detail-creator"); - is_element_hidden(el, "detail-creator should be hidden."); - el = gManagerWindow.document.getElementById("detail-experiment-bullet"); - is_element_visible(el, "experiment-bullet should be visible."); -}); - -add_task(function* testRemoveAndUndo() { - if (!gExperiments) { - info("Skipping experiments test because that feature isn't available."); - return; - } - - yield gCategoryUtilities.openType("experiment"); - - let addon = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org"); - Assert.ok(addon, "Got add-on element."); - - yield clickRemoveButton(addon); - addon.parentNode.ensureElementIsVisible(addon); - - let el = gManagerWindow.document.getAnonymousElementByAttribute(addon, "class", "pending"); - is_element_visible(el, "Uninstall undo information should be visible."); - - yield clickUndoButton(addon); - addon = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org"); - Assert.ok(addon, "Got add-on element."); -}); - -add_task(function* testCleanup() { - if (gExperiments) { - Services.prefs.clearUserPref("experiments.enabled"); - Services.prefs.setCharPref("experiments.manifest.uri", gSavedManifestURI); - - // We perform the uninit/init cycle to purge any leftover state. - yield OS.File.remove(gExperiments._cacheFilePath); - yield gExperiments.uninit(); - yield gExperiments.init(); - - Services.prefs.clearUserPref("toolkit.telemetry.enabled"); - } - - // Check post-conditions. - let addons = yield getExperimentAddons(); - Assert.equal(addons.length, 0, "No experiment add-ons are installed."); - - yield close_manager(gManagerWindow); -}); diff --git a/toolkit/profile/nsProfileLock.cpp b/toolkit/profile/nsProfileLock.cpp index 08d109224..cc9ecb62e 100644 --- a/toolkit/profile/nsProfileLock.cpp +++ b/toolkit/profile/nsProfileLock.cpp @@ -30,7 +30,7 @@ #include "prenv.h" #endif -#if defined(MOZ_WIDGET_GONK) && !defined(MOZ_CRASHREPORTER) +#if defined(MOZ_WIDGET_GONK) #include <sys/syscall.h> #endif @@ -198,7 +198,6 @@ void nsProfileLock::FatalSignalHandler(int signo case SIGILL: case SIGABRT: case SIGSEGV: -#ifndef MOZ_CRASHREPORTER // Retrigger the signal for those that can generate a core dump signal(signo, SIG_DFL); if (info->si_code <= 0) { @@ -206,7 +205,6 @@ void nsProfileLock::FatalSignalHandler(int signo break; } } -#endif return; default: break; diff --git a/toolkit/themes/linux/mozapps/jar.mn b/toolkit/themes/linux/mozapps/jar.mn index d4997d36c..37325c0be 100644 --- a/toolkit/themes/linux/mozapps/jar.mn +++ b/toolkit/themes/linux/mozapps/jar.mn @@ -23,30 +23,33 @@ toolkit.jar: * skin/classic/mozapps/extensions/newaddon.css (webextensions/newaddon.css) skin/classic/mozapps/extensions/heart.png (webextensions/heart.png) #else -+ skin/classic/mozapps/extensions/extensions.css (extensions/extensions.css) -+ skin/classic/mozapps/extensions/category-search.png (extensions/category-search.png) -+ skin/classic/mozapps/extensions/category-discover.png (extensions/category-discover.png) -+ skin/classic/mozapps/extensions/category-languages.png (extensions/localeGeneric.png) -+ skin/classic/mozapps/extensions/category-extensions.png (extensions/extensionGeneric.png) -+ skin/classic/mozapps/extensions/category-themes.png (extensions/themeGeneric.png) -+ skin/classic/mozapps/extensions/category-plugins.png (extensions/category-plugins.png) -+ skin/classic/mozapps/extensions/category-service.png (extensions/category-service.png) -+ skin/classic/mozapps/extensions/category-dictionaries.png (extensions/category-dictionaries.png) -+ skin/classic/mozapps/extensions/category-experiments.png (extensions/category-experiments.png) -+ skin/classic/mozapps/extensions/category-recent.png (extensions/category-recent.png) -+ skin/classic/mozapps/extensions/category-available.png (extensions/category-available.png) -+ skin/classic/mozapps/extensions/extensionGeneric.png (extensions/extensionGeneric.png) -+ skin/classic/mozapps/extensions/extensionGeneric-16.png (extensions/extensionGeneric-16.png) -+ skin/classic/mozapps/extensions/dictionaryGeneric.png (extensions/dictionaryGeneric.png) -+ skin/classic/mozapps/extensions/dictionaryGeneric-16.png (extensions/dictionaryGeneric-16.png) -+ skin/classic/mozapps/extensions/experimentGeneric.png (extensions/experimentGeneric.png) -+ skin/classic/mozapps/extensions/themeGeneric.png (extensions/themeGeneric.png) -+ skin/classic/mozapps/extensions/themeGeneric-16.png (extensions/themeGeneric-16.png) -+ skin/classic/mozapps/extensions/localeGeneric.png (extensions/localeGeneric.png) -+ skin/classic/mozapps/extensions/newaddon.css (extensions/newaddon.css) -+ skin/classic/mozapps/extensions/selectAddons.css (extensions/selectAddons.css) -+ skin/classic/mozapps/xpinstall/xpinstallItemGeneric.png (extensions/extensionGeneric.png) + skin/classic/mozapps/extensions/extensions.css (extensions/extensions.css) + skin/classic/mozapps/extensions/category-search.png (extensions/category-search.png) + skin/classic/mozapps/extensions/category-discover.png (extensions/category-discover.png) + skin/classic/mozapps/extensions/category-languages.png (extensions/localeGeneric.png) + skin/classic/mozapps/extensions/category-extensions.png (extensions/extensionGeneric.png) + skin/classic/mozapps/extensions/category-themes.png (extensions/themeGeneric.png) + skin/classic/mozapps/extensions/category-plugins.png (extensions/category-plugins.png) + skin/classic/mozapps/extensions/category-service.png (extensions/category-service.png) + skin/classic/mozapps/extensions/category-dictionaries.png (extensions/category-dictionaries.png) + skin/classic/mozapps/extensions/category-experiments.png (extensions/category-experiments.png) + skin/classic/mozapps/extensions/category-recent.png (extensions/category-recent.png) + skin/classic/mozapps/extensions/category-available.png (extensions/category-available.png) + skin/classic/mozapps/extensions/extensionGeneric.png (extensions/extensionGeneric.png) + skin/classic/mozapps/extensions/extensionGeneric-16.png (extensions/extensionGeneric-16.png) + skin/classic/mozapps/extensions/dictionaryGeneric.png (extensions/dictionaryGeneric.png) + skin/classic/mozapps/extensions/dictionaryGeneric-16.png (extensions/dictionaryGeneric-16.png) + skin/classic/mozapps/extensions/experimentGeneric.png (extensions/experimentGeneric.png) + skin/classic/mozapps/extensions/themeGeneric.png (extensions/themeGeneric.png) + skin/classic/mozapps/extensions/themeGeneric-16.png (extensions/themeGeneric-16.png) + skin/classic/mozapps/extensions/localeGeneric.png (extensions/localeGeneric.png) + skin/classic/mozapps/extensions/newaddon.css (extensions/newaddon.css) + skin/classic/mozapps/extensions/selectAddons.css (extensions/selectAddons.css) + skin/classic/mozapps/xpinstall/xpinstallItemGeneric.png (extensions/extensionGeneric.png) #endif + skin/classic/mozapps/passwordmgr/key.png (passwordmgr/key.png) + skin/classic/mozapps/passwordmgr/key-16.png (passwordmgr/key-16.png) + skin/classic/mozapps/passwordmgr/key-64.png (passwordmgr/key-64.png) skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png) skin/classic/mozapps/plugins/pluginBlocked.png (plugins/pluginBlocked.png) skin/classic/mozapps/plugins/pluginGeneric-16.png (plugins/pluginGeneric-16.png) diff --git a/toolkit/themes/linux/mozapps/passwordmgr/key-16.png b/toolkit/themes/linux/mozapps/passwordmgr/key-16.png Binary files differnew file mode 100644 index 000000000..ac135b847 --- /dev/null +++ b/toolkit/themes/linux/mozapps/passwordmgr/key-16.png diff --git a/toolkit/themes/linux/mozapps/passwordmgr/key-64.png b/toolkit/themes/linux/mozapps/passwordmgr/key-64.png Binary files differnew file mode 100644 index 000000000..0fb69f382 --- /dev/null +++ b/toolkit/themes/linux/mozapps/passwordmgr/key-64.png diff --git a/toolkit/themes/linux/mozapps/passwordmgr/key.png b/toolkit/themes/linux/mozapps/passwordmgr/key.png Binary files differnew file mode 100644 index 000000000..b5e8afefc --- /dev/null +++ b/toolkit/themes/linux/mozapps/passwordmgr/key.png diff --git a/toolkit/themes/osx/mozapps/jar.mn b/toolkit/themes/osx/mozapps/jar.mn index 35927755b..f8ade11d9 100644 --- a/toolkit/themes/osx/mozapps/jar.mn +++ b/toolkit/themes/osx/mozapps/jar.mn @@ -83,6 +83,9 @@ toolkit.jar: skin/classic/mozapps/extensions/blocklist.css (extensions/blocklist.css) * skin/classic/mozapps/extensions/newaddon.css (extensions/newaddon.css) #endif + skin/classic/mozapps/passwordmgr/key.png (passwordmgr/key.png) + skin/classic/mozapps/passwordmgr/key-16.png (passwordmgr/key-16.png) + skin/classic/mozapps/passwordmgr/key-64.png (passwordmgr/key-64.png) skin/classic/mozapps/plugins/notifyPluginGeneric.png (plugins/notifyPluginGeneric.png) skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png) skin/classic/mozapps/plugins/pluginBlocked.png (plugins/pluginBlocked.png) diff --git a/toolkit/themes/osx/mozapps/passwordmgr/key-16.png b/toolkit/themes/osx/mozapps/passwordmgr/key-16.png Binary files differnew file mode 100644 index 000000000..ac135b847 --- /dev/null +++ b/toolkit/themes/osx/mozapps/passwordmgr/key-16.png diff --git a/toolkit/themes/osx/mozapps/passwordmgr/key-64.png b/toolkit/themes/osx/mozapps/passwordmgr/key-64.png Binary files differnew file mode 100644 index 000000000..0fb69f382 --- /dev/null +++ b/toolkit/themes/osx/mozapps/passwordmgr/key-64.png diff --git a/toolkit/themes/osx/mozapps/passwordmgr/key.png b/toolkit/themes/osx/mozapps/passwordmgr/key.png Binary files differnew file mode 100644 index 000000000..b5e8afefc --- /dev/null +++ b/toolkit/themes/osx/mozapps/passwordmgr/key.png diff --git a/toolkit/themes/shared/non-mac.jar.inc.mn b/toolkit/themes/shared/non-mac.jar.inc.mn index a783bbb3c..637537d9d 100644 --- a/toolkit/themes/shared/non-mac.jar.inc.mn +++ b/toolkit/themes/shared/non-mac.jar.inc.mn @@ -77,6 +77,8 @@ skin/classic/global/icons/Landscape.png (../../windows/global/icons/Landscape.png) skin/classic/global/icons/Question.png (../../windows/global/icons/Question.png) skin/classic/global/icons/question-16.png (../../windows/global/icons/question-16.png) + skin/classic/global/icons/question-32.png (../../windows/global/icons/question-32.png) + skin/classic/global/icons/question-48.png (../../windows/global/icons/question-48.png) skin/classic/global/icons/question-64.png (../../windows/global/icons/question-64.png) skin/classic/global/icons/resizer-rtl.png (../../windows/global/icons/resizer-rtl.png) skin/classic/global/icons/Restore.gif (../../windows/global/icons/Restore.gif) diff --git a/toolkit/themes/windows/global/icons/question-32.png b/toolkit/themes/windows/global/icons/question-32.png Binary files differnew file mode 100644 index 000000000..7c80831b0 --- /dev/null +++ b/toolkit/themes/windows/global/icons/question-32.png diff --git a/toolkit/themes/windows/global/icons/question-48.png b/toolkit/themes/windows/global/icons/question-48.png Binary files differnew file mode 100644 index 000000000..dd2b21874 --- /dev/null +++ b/toolkit/themes/windows/global/icons/question-48.png diff --git a/toolkit/themes/windows/mozapps/jar.mn b/toolkit/themes/windows/mozapps/jar.mn index 29203811f..842c8a138 100644 --- a/toolkit/themes/windows/mozapps/jar.mn +++ b/toolkit/themes/windows/mozapps/jar.mn @@ -15,6 +15,7 @@ toolkit.jar: skin/classic/mozapps/extensions/category-recent.png (webextensions/category-recent.png) skin/classic/mozapps/extensions/category-available.png (webextensions/category-available.png) skin/classic/mozapps/extensions/extensionGeneric-16.png (webextensions/extensionGeneric-16.png) + skin/classic/mozapps/extensions/extensionGeneric-48.png (webextensions/extensionGeneric-48.png) skin/classic/mozapps/extensions/themeGeneric.png (webextensions/themeGeneric.png) skin/classic/mozapps/extensions/themeGeneric-16.png (webextensions/themeGeneric-16.png) skin/classic/mozapps/extensions/dictionaryGeneric.png (webextensions/dictionaryGeneric.png) @@ -68,9 +69,13 @@ toolkit.jar: * skin/classic/mozapps/xpinstall/xpinstallConfirm.css (extensions/xpinstallConfirm.css) skin/classic/mozapps/xpinstall/xpinstallItemGeneric.png (extensions/extensionGeneric.png) #endif + skin/classic/mozapps/passwordmgr/key.png (passwordmgr/key.png) + skin/classic/mozapps/passwordmgr/key-16.png (passwordmgr/key-16.png) + skin/classic/mozapps/passwordmgr/key-64.png (passwordmgr/key-64.png) skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png) skin/classic/mozapps/plugins/pluginBlocked.png (plugins/pluginBlocked.png) skin/classic/mozapps/plugins/pluginGeneric-16.png (plugins/pluginGeneric-16.png) + skin/classic/mozapps/plugins/pluginGeneric-48.png (plugins/pluginGeneric-48.png) skin/classic/mozapps/profile/profileicon.png (profile/profileicon.png) skin/classic/mozapps/update/updates.css (update/updates.css) skin/classic/mozapps/viewsource/viewsource.css (viewsource/viewsource.css) diff --git a/toolkit/themes/windows/mozapps/passwordmgr/key-16.png b/toolkit/themes/windows/mozapps/passwordmgr/key-16.png Binary files differnew file mode 100644 index 000000000..ac135b847 --- /dev/null +++ b/toolkit/themes/windows/mozapps/passwordmgr/key-16.png diff --git a/toolkit/themes/windows/mozapps/passwordmgr/key-64.png b/toolkit/themes/windows/mozapps/passwordmgr/key-64.png Binary files differnew file mode 100644 index 000000000..0fb69f382 --- /dev/null +++ b/toolkit/themes/windows/mozapps/passwordmgr/key-64.png diff --git a/toolkit/themes/windows/mozapps/passwordmgr/key.png b/toolkit/themes/windows/mozapps/passwordmgr/key.png Binary files differnew file mode 100644 index 000000000..b5e8afefc --- /dev/null +++ b/toolkit/themes/windows/mozapps/passwordmgr/key.png diff --git a/toolkit/themes/windows/mozapps/plugins/pluginGeneric-16.png b/toolkit/themes/windows/mozapps/plugins/pluginGeneric-16.png Binary files differindex 5d796cc4c..080b0e502 100644 --- a/toolkit/themes/windows/mozapps/plugins/pluginGeneric-16.png +++ b/toolkit/themes/windows/mozapps/plugins/pluginGeneric-16.png diff --git a/toolkit/themes/windows/mozapps/plugins/pluginGeneric-48.png b/toolkit/themes/windows/mozapps/plugins/pluginGeneric-48.png Binary files differnew file mode 100644 index 000000000..173679448 --- /dev/null +++ b/toolkit/themes/windows/mozapps/plugins/pluginGeneric-48.png diff --git a/toolkit/themes/windows/mozapps/plugins/pluginGeneric.png b/toolkit/themes/windows/mozapps/plugins/pluginGeneric.png Binary files differindex d8b270ae5..1fcbf154e 100644 --- a/toolkit/themes/windows/mozapps/plugins/pluginGeneric.png +++ b/toolkit/themes/windows/mozapps/plugins/pluginGeneric.png diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild index a782acd3a..3b3bf80ae 100644 --- a/toolkit/toolkit.mozbuild +++ b/toolkit/toolkit.mozbuild @@ -181,10 +181,6 @@ if CONFIG['ENABLE_TESTS']: '/testing/web-platform', ] - # The file id utility requires breakpad libraries. - if CONFIG['MOZ_CRASHREPORTER']: - DIRS += ['/testing/tools/fileid'] - if CONFIG['MOZ_MEMORY']: DIRS += ['/memory/gtest'] diff --git a/toolkit/xre/nsAndroidStartup.cpp b/toolkit/xre/nsAndroidStartup.cpp index a88c58e5d..47b9ec6e5 100644 --- a/toolkit/xre/nsAndroidStartup.cpp +++ b/toolkit/xre/nsAndroidStartup.cpp @@ -26,15 +26,6 @@ GeckoStart(JNIEnv* env, char* data, const nsXREAppData* appData) { mozilla::jni::SetGeckoThreadEnv(env); -#ifdef MOZ_CRASHREPORTER - const struct mapping_info *info = getLibraryMapping(); - while (info->name) { - CrashReporter::AddLibraryMapping(info->name, info->base, - info->len, info->offset); - info++; - } -#endif - if (!data) { LOG("Failed to get arguments for GeckoStart\n"); return; diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 1b5c2ed75..b65a4093f 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -190,17 +190,6 @@ #include "jprof.h" #endif -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#include "nsICrashReporter.h" -#define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" -#include "nsIPrefService.h" -#include "nsIMemoryInfoDumper.h" -#if defined(XP_LINUX) && !defined(ANDROID) -#include "mozilla/widget/LSBUtils.h" -#endif -#endif - #include "base/command_line.h" #include "GTestRunner.h" @@ -646,10 +635,6 @@ class nsXULAppInfo : public nsIXULAppInfo, #ifdef XP_WIN public nsIWinAppHelper, #endif -#ifdef MOZ_CRASHREPORTER - public nsICrashReporter, - public nsIFinishDumpingCallback, -#endif public nsIXULRuntime { @@ -660,10 +645,6 @@ public: NS_DECL_NSIXULAPPINFO NS_DECL_NSIXULRUNTIME NS_DECL_NSIOBSERVER -#ifdef MOZ_CRASHREPORTER - NS_DECL_NSICRASHREPORTER - NS_DECL_NSIFINISHDUMPINGCALLBACK -#endif #ifdef XP_WIN NS_DECL_NSIWINAPPHELPER #endif @@ -676,10 +657,6 @@ NS_INTERFACE_MAP_BEGIN(nsXULAppInfo) #ifdef XP_WIN NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper) #endif -#ifdef MOZ_CRASHREPORTER - NS_INTERFACE_MAP_ENTRY(nsICrashReporter) - NS_INTERFACE_MAP_ENTRY(nsIFinishDumpingCallback) -#endif NS_INTERFACE_MAP_ENTRY(nsIPlatformInfo) NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData || XRE_IsContentProcess()) @@ -1004,12 +981,7 @@ nsXULAppInfo::GetReplacedLockTime(PRTime *aReplacedLockTime) NS_IMETHODIMP nsXULAppInfo::GetLastRunCrashID(nsAString &aLastRunCrashID) { -#ifdef MOZ_CRASHREPORTER - CrashReporter::GetLastRunCrashID(aLastRunCrashID); - return NS_OK; -#else return NS_ERROR_NOT_IMPLEMENTED; -#endif } NS_IMETHODIMP @@ -1117,219 +1089,6 @@ nsXULAppInfo::GetUserCanElevate(bool *aUserCanElevate) } #endif -#ifdef MOZ_CRASHREPORTER -NS_IMETHODIMP -nsXULAppInfo::GetEnabled(bool *aEnabled) -{ - *aEnabled = CrashReporter::GetEnabled(); - return NS_OK; -} - -NS_IMETHODIMP -nsXULAppInfo::SetEnabled(bool aEnabled) -{ - if (aEnabled) { - if (CrashReporter::GetEnabled()) { - // no point in erroring for double-enabling - return NS_OK; - } - - nsCOMPtr<nsIFile> greBinDir; - NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(greBinDir)); - if (!greBinDir) { - return NS_ERROR_FAILURE; - } - - nsCOMPtr<nsIFile> xreBinDirectory = do_QueryInterface(greBinDir); - if (!xreBinDirectory) { - return NS_ERROR_FAILURE; - } - - return CrashReporter::SetExceptionHandler(xreBinDirectory, true); - } - else { - if (!CrashReporter::GetEnabled()) { - // no point in erroring for double-disabling - return NS_OK; - } - - return CrashReporter::UnsetExceptionHandler(); - } -} - -NS_IMETHODIMP -nsXULAppInfo::GetServerURL(nsIURL** aServerURL) -{ - if (!CrashReporter::GetEnabled()) - return NS_ERROR_NOT_INITIALIZED; - - nsAutoCString data; - if (!CrashReporter::GetServerURL(data)) { - return NS_ERROR_FAILURE; - } - nsCOMPtr<nsIURI> uri; - NS_NewURI(getter_AddRefs(uri), data); - if (!uri) - return NS_ERROR_FAILURE; - - nsCOMPtr<nsIURL> url; - url = do_QueryInterface(uri); - NS_ADDREF(*aServerURL = url); - - return NS_OK; -} - -NS_IMETHODIMP -nsXULAppInfo::SetServerURL(nsIURL* aServerURL) -{ - bool schemeOk; - // only allow https or http URLs - nsresult rv = aServerURL->SchemeIs("https", &schemeOk); - NS_ENSURE_SUCCESS(rv, rv); - if (!schemeOk) { - rv = aServerURL->SchemeIs("http", &schemeOk); - NS_ENSURE_SUCCESS(rv, rv); - - if (!schemeOk) - return NS_ERROR_INVALID_ARG; - } - nsAutoCString spec; - rv = aServerURL->GetSpec(spec); - NS_ENSURE_SUCCESS(rv, rv); - - return CrashReporter::SetServerURL(spec); -} - -NS_IMETHODIMP -nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath) -{ - if (!CrashReporter::GetEnabled()) - return NS_ERROR_NOT_INITIALIZED; - - nsAutoString path; - if (!CrashReporter::GetMinidumpPath(path)) - return NS_ERROR_FAILURE; - - nsresult rv = NS_NewLocalFile(path, false, aMinidumpPath); - NS_ENSURE_SUCCESS(rv, rv); - return NS_OK; -} - -NS_IMETHODIMP -nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath) -{ - nsAutoString path; - nsresult rv = aMinidumpPath->GetPath(path); - NS_ENSURE_SUCCESS(rv, rv); - return CrashReporter::SetMinidumpPath(path); -} - -NS_IMETHODIMP -nsXULAppInfo::AnnotateCrashReport(const nsACString& key, - const nsACString& data) -{ - return CrashReporter::AnnotateCrashReport(key, data); -} - -NS_IMETHODIMP -nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data) -{ - return CrashReporter::AppendAppNotesToCrashReport(data); -} - -NS_IMETHODIMP -nsXULAppInfo::RegisterAppMemory(uint64_t pointer, - uint64_t len) -{ - return CrashReporter::RegisterAppMemory((void *)pointer, len); -} - -NS_IMETHODIMP -nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo) -{ -#ifdef XP_WIN32 - return CrashReporter::WriteMinidumpForException(static_cast<EXCEPTION_POINTERS*>(aExceptionInfo)); -#else - return NS_ERROR_NOT_IMPLEMENTED; -#endif -} - -NS_IMETHODIMP -nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException) -{ -#ifdef XP_MACOSX - return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException); -#else - return NS_ERROR_NOT_IMPLEMENTED; -#endif -} - -NS_IMETHODIMP -nsXULAppInfo::GetSubmitReports(bool* aEnabled) -{ - return CrashReporter::GetSubmitReports(aEnabled); -} - -NS_IMETHODIMP -nsXULAppInfo::SetSubmitReports(bool aEnabled) -{ - return CrashReporter::SetSubmitReports(aEnabled); -} - -NS_IMETHODIMP -nsXULAppInfo::UpdateCrashEventsDir() -{ - CrashReporter::UpdateCrashEventsDir(); - return NS_OK; -} - -NS_IMETHODIMP -nsXULAppInfo::SaveMemoryReport() -{ - if (!CrashReporter::GetEnabled()) { - return NS_ERROR_NOT_INITIALIZED; - } - nsCOMPtr<nsIFile> file; - nsresult rv = CrashReporter::GetDefaultMemoryReportFile(getter_AddRefs(file)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - nsString path; - file->GetPath(path); - - nsCOMPtr<nsIMemoryInfoDumper> dumper = - do_GetService("@mozilla.org/memory-info-dumper;1"); - if (NS_WARN_IF(!dumper)) { - return NS_ERROR_UNEXPECTED; - } - - rv = dumper->DumpMemoryReportsToNamedFile(path, this, file, true /* anonymize */); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return NS_OK; -} - -NS_IMETHODIMP -nsXULAppInfo::SetTelemetrySessionId(const nsACString& id) -{ - CrashReporter::SetTelemetrySessionId(id); - return NS_OK; -} - -// This method is from nsIFInishDumpingCallback. -NS_IMETHODIMP -nsXULAppInfo::Callback(nsISupports* aData) -{ - nsCOMPtr<nsIFile> file = do_QueryInterface(aData); - MOZ_ASSERT(file); - - CrashReporter::SetMemoryReportFile(file); - return NS_OK; -} -#endif - static const nsXULAppInfo kAppInfo; static nsresult AppInfoConstructor(nsISupports* aOuter, REFNSIID aIID, void **aResult) @@ -1434,9 +1193,6 @@ static const mozilla::Module::CIDEntry kXRECIDs[] = { static const mozilla::Module::ContractIDEntry kXREContracts[] = { { XULAPPINFO_SERVICE_CONTRACTID, &kAPPINFO_CID }, { XULRUNTIME_SERVICE_CONTRACTID, &kAPPINFO_CID }, -#ifdef MOZ_CRASHREPORTER - { NS_CRASHREPORTER_CONTRACTID, &kAPPINFO_CID }, -#endif { NS_PROFILESERVICE_CONTRACTID, &kProfileServiceCID }, { NS_NATIVEAPPSUPPORT_CONTRACTID, &kNativeAppSupportCID }, { nullptr } @@ -2763,33 +2519,6 @@ static void RestoreStateForAppInitiatedRestart() } } -#ifdef MOZ_CRASHREPORTER -// When we first initialize the crash reporter we don't have a profile, -// so we set the minidump path to $TEMP. Once we have a profile, -// we set it to $PROFILE/minidumps, creating the directory -// if needed. -static void MakeOrSetMinidumpPath(nsIFile* profD) -{ - nsCOMPtr<nsIFile> dumpD; - profD->Clone(getter_AddRefs(dumpD)); - - if (dumpD) { - bool fileExists; - //XXX: do some more error checking here - dumpD->Append(NS_LITERAL_STRING("minidumps")); - dumpD->Exists(&fileExists); - if (!fileExists) { - nsresult rv = dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700); - NS_ENSURE_SUCCESS_VOID(rv); - } - - nsAutoString pathStr; - if (NS_SUCCEEDED(dumpD->GetPath(pathStr))) - CrashReporter::SetMinidumpPath(pathStr); - } -} -#endif - const nsXREAppData* gAppData = nullptr; #ifdef MOZ_WIDGET_GTK @@ -3215,94 +2944,6 @@ XREMain::XRE_mainInit(bool* aExitFlag) if (NS_FAILED(rv)) return 1; -#ifdef MOZ_CRASHREPORTER - if (EnvHasValue("MOZ_CRASHREPORTER")) { - mAppData->flags |= NS_XRE_ENABLE_CRASH_REPORTER; - } - - nsCOMPtr<nsIFile> xreBinDirectory; - xreBinDirectory = mDirProvider.GetGREBinDir(); - - if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) && - NS_SUCCEEDED( - CrashReporter::SetExceptionHandler(xreBinDirectory))) { - nsCOMPtr<nsIFile> file; - rv = mDirProvider.GetUserAppDataDirectory(getter_AddRefs(file)); - if (NS_SUCCEEDED(rv)) { - CrashReporter::SetUserAppDataDirectory(file); - } - if (mAppData->crashReporterURL) - CrashReporter::SetServerURL(nsDependentCString(mAppData->crashReporterURL)); - - // We overwrite this once we finish starting up. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("StartupCrash"), - NS_LITERAL_CSTRING("1")); - - // pass some basic info from the app data - if (mAppData->vendor) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"), - nsDependentCString(mAppData->vendor)); - if (mAppData->name) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"), - nsDependentCString(mAppData->name)); - if (mAppData->ID) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductID"), - nsDependentCString(mAppData->ID)); - if (mAppData->version) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"), - nsDependentCString(mAppData->version)); - if (mAppData->buildID) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"), - nsDependentCString(mAppData->buildID)); - - nsDependentCString releaseChannel(NS_STRINGIFY(MOZ_UPDATE_CHANNEL)); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"), - releaseChannel); -#ifdef MOZ_LINKER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CrashAddressLikelyWrong"), - IsSignalHandlingBroken() ? NS_LITERAL_CSTRING("1") - : NS_LITERAL_CSTRING("0")); -#endif - -#ifdef XP_WIN - nsAutoString appInitDLLs; - if (widget::WinUtils::GetAppInitDLLs(appInitDLLs)) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AppInitDLLs"), - NS_ConvertUTF16toUTF8(appInitDLLs)); - } -#endif - - CrashReporter::SetRestartArgs(gArgc, gArgv); - - // annotate other data (user id etc) - nsCOMPtr<nsIFile> userAppDataDir; - if (NS_SUCCEEDED(mDirProvider.GetUserAppDataDirectory( - getter_AddRefs(userAppDataDir)))) { - CrashReporter::SetupExtraData(userAppDataDir, - nsDependentCString(mAppData->buildID)); - - // see if we have a crashreporter-override.ini in the application directory - nsCOMPtr<nsIFile> overrideini; - bool exists; - if (NS_SUCCEEDED(mDirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) && - NS_SUCCEEDED(overrideini->AppendNative(NS_LITERAL_CSTRING("crashreporter-override.ini"))) && - NS_SUCCEEDED(overrideini->Exists(&exists)) && - exists) { -#ifdef XP_WIN - nsAutoString overridePathW; - overrideini->GetPath(overridePathW); - NS_ConvertUTF16toUTF8 overridePath(overridePathW); -#else - nsAutoCString overridePath; - overrideini->GetNativePath(overridePath); -#endif - - SaveWordToEnv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE", overridePath); - } - } - } -#endif - #if defined(MOZ_SANDBOX) && defined(XP_WIN) if (mAppData->sandboxBrokerServices) { SandboxBroker::Initialize(mAppData->sandboxBrokerServices); @@ -3448,22 +3089,9 @@ XREMain::XRE_mainInit(bool* aExitFlag) } } -#ifdef MOZ_CRASHREPORTER - if (cpuUpdateRevision > 0) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CPUMicrocodeVersion"), - nsPrintfCString("0x%x", - cpuUpdateRevision)); - } -#endif } #endif -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("SafeMode"), - gSafeMode ? NS_LITERAL_CSTRING("1") : - NS_LITERAL_CSTRING("0")); -#endif - // Handle --no-remote and --new-instance command line arguments. Setup // the environment to better accommodate other components and various // restart scenarios. @@ -3523,102 +3151,6 @@ XREMain::XRE_mainInit(bool* aExitFlag) return 0; } -#ifdef MOZ_CRASHREPORTER -#ifdef XP_WIN -/** - * Uses WMI to read some manufacturer information that may be useful for - * diagnosing hardware-specific crashes. This function is best-effort; failures - * shouldn't burden the caller. COM must be initialized before calling. - */ -static void AnnotateSystemManufacturer() -{ - RefPtr<IWbemLocator> locator; - - HRESULT hr = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER, - IID_IWbemLocator, getter_AddRefs(locator)); - - if (FAILED(hr)) { - return; - } - - RefPtr<IWbemServices> services; - - hr = locator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), nullptr, nullptr, nullptr, - 0, nullptr, nullptr, getter_AddRefs(services)); - - if (FAILED(hr)) { - return; - } - - hr = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, - RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, - nullptr, EOAC_NONE); - - if (FAILED(hr)) { - return; - } - - RefPtr<IEnumWbemClassObject> enumerator; - - hr = services->ExecQuery(_bstr_t(L"WQL"), _bstr_t(L"SELECT * FROM Win32_BIOS"), - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - nullptr, getter_AddRefs(enumerator)); - - if (FAILED(hr) || !enumerator) { - return; - } - - RefPtr<IWbemClassObject> classObject; - ULONG results; - - hr = enumerator->Next(WBEM_INFINITE, 1, getter_AddRefs(classObject), &results); - - if (FAILED(hr) || results == 0) { - return; - } - - VARIANT value; - VariantInit(&value); - - hr = classObject->Get(L"Manufacturer", 0, &value, 0, 0); - - if (SUCCEEDED(hr) && V_VT(&value) == VT_BSTR) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BIOS_Manufacturer"), - NS_ConvertUTF16toUTF8(V_BSTR(&value))); - } - - VariantClear(&value); -} - -static void PR_CALLBACK AnnotateSystemManufacturer_ThreadStart(void*) -{ - HRESULT hr = CoInitialize(nullptr); - - if (FAILED(hr)) { - return; - } - - AnnotateSystemManufacturer(); - - CoUninitialize(); -} -#endif // XP_WIN - -#if defined(XP_LINUX) && !defined(ANDROID) - -static void -AnnotateLSBRelease(void*) -{ - nsCString dist, desc, release, codename; - if (widget::lsb::GetLSBRelease(dist, desc, release, codename)) { - CrashReporter::AppendAppNotesToCrashReport(desc); - } -} - -#endif // defined(XP_LINUX) && !defined(ANDROID) - -#endif - namespace mozilla { ShutdownChecksMode gShutdownChecks = SCM_NOTHING; } // namespace mozilla @@ -4007,13 +3539,6 @@ XREMain::XRE_mainStartup(bool* aExitFlag) mozilla::Telemetry::SetProfileDir(mProfD); -#ifdef MOZ_CRASHREPORTER - if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) - MakeOrSetMinidumpPath(mProfD); - - CrashReporter::SetProfileDirectory(mProfD); -#endif - nsAutoCString version; BuildVersion(version); @@ -4103,39 +3628,6 @@ XREMain::XRE_mainStartup(bool* aExitFlag) return 0; } -#if defined(MOZ_CRASHREPORTER) -#if defined(MOZ_CONTENT_SANDBOX) && !defined(MOZ_WIDGET_GONK) -void AddSandboxAnnotations() -{ - // Include the sandbox content level, regardless of platform - int level = Preferences::GetInt("security.sandbox.content.level"); - - nsAutoCString levelString; - levelString.AppendInt(level); - - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxLevel"), levelString); - - // Include whether or not this instance is capable of content sandboxing - bool sandboxCapable = false; - -#if defined(XP_WIN) - // All supported Windows versions support some level of content sandboxing - sandboxCapable = true; -#elif defined(XP_MACOSX) - // All supported OS X versions are capable - sandboxCapable = true; -#elif defined(XP_LINUX) - sandboxCapable = SandboxInfo::Get().CanSandboxContent(); -#endif - - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxCapable"), - sandboxCapable ? NS_LITERAL_CSTRING("1") : NS_LITERAL_CSTRING("0")); -} -#endif /* MOZ_CONTENT_SANDBOX && !MOZ_WIDGET_GONK */ -#endif /* MOZ_CRASHREPORTER */ - /* * XRE_mainRun - Command line startup, profile migration, and * the calling of appStartup->Run(). @@ -4169,40 +3661,6 @@ XREMain::XRE_mainRun() rv = mScopedXPCOM->SetWindowCreator(mNativeApp); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); -#ifdef MOZ_CRASHREPORTER - // tell the crash reporter to also send the release channel - nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr<nsIPrefBranch> defaultPrefBranch; - rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch)); - - if (NS_SUCCEEDED(rv)) { - nsXPIDLCString sval; - rv = defaultPrefBranch->GetCharPref("app.update.channel", getter_Copies(sval)); - if (NS_SUCCEEDED(rv)) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"), - sval); - } - } - } - // Needs to be set after xpcom initialization. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonBase"), - nsPrintfCString("%.16llx", uint64_t(gMozillaPoisonBase))); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonSize"), - nsPrintfCString("%lu", uint32_t(gMozillaPoisonSize))); - -#ifdef XP_WIN - PR_CreateThread(PR_USER_THREAD, AnnotateSystemManufacturer_ThreadStart, 0, - PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); -#endif - -#if defined(XP_LINUX) && !defined(ANDROID) - PR_CreateThread(PR_USER_THREAD, AnnotateLSBRelease, 0, PR_PRIORITY_LOW, - PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); -#endif - -#endif - if (mStartOffline) { nsCOMPtr<nsIIOService2> io (do_GetService("@mozilla.org/network/io-service;1")); NS_ENSURE_TRUE(io, NS_ERROR_FAILURE); @@ -4308,17 +3766,6 @@ XREMain::XRE_mainRun() OverrideDefaultLocaleIfNeeded(); -#ifdef MOZ_CRASHREPORTER - nsCString userAgentLocale; - // Try a localized string first. This pref is always a localized string in - // Fennec, and might be elsewhere, too. - if (NS_SUCCEEDED(Preferences::GetLocalizedCString("general.useragent.locale", &userAgentLocale))) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("useragent_locale"), userAgentLocale); - } else if (NS_SUCCEEDED(Preferences::GetCString("general.useragent.locale", &userAgentLocale))) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("useragent_locale"), userAgentLocale); - } -#endif - appStartup->GetShuttingDown(&mShuttingDown); nsCOMPtr<nsICommandLineRunner> cmdLine; @@ -4411,11 +3858,6 @@ XREMain::XRE_mainRun() (void)appStartup->DoneStartingUp(); -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("StartupCrash"), - NS_LITERAL_CSTRING("0")); -#endif - appStartup->GetShuttingDown(&mShuttingDown); } @@ -4466,21 +3908,8 @@ XREMain::XRE_mainRun() sandboxInfo.Test(SandboxInfo::kEnabledForContent)); Telemetry::Accumulate(Telemetry::SANDBOX_MEDIA_ENABLED, sandboxInfo.Test(SandboxInfo::kEnabledForMedia)); -#if defined(MOZ_CRASHREPORTER) - nsAutoCString flagsString; - flagsString.AppendInt(sandboxInfo.AsInteger()); - - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxCapabilities"), flagsString); -#endif /* MOZ_CRASHREPORTER */ #endif /* MOZ_SANDBOX && XP_LINUX && !MOZ_WIDGET_GONK */ -#if defined(MOZ_CRASHREPORTER) -#if defined(MOZ_CONTENT_SANDBOX) && !defined(MOZ_WIDGET_GONK) - AddSandboxAnnotations(); -#endif /* MOZ_CONTENT_SANDBOX && !MOZ_WIDGET_GONK */ -#endif /* MOZ_CRASHREPORTER */ - { rv = appStartup->Run(); if (NS_FAILED(rv)) { @@ -4673,10 +4102,6 @@ XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) rv = LaunchChild(mNativeApp, true); } -#ifdef MOZ_CRASHREPORTER - if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) - CrashReporter::UnsetExceptionHandler(); -#endif return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1; } @@ -4686,11 +4111,6 @@ XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) MOZ_gdk_display_close(mGdkDisplay); #endif -#ifdef MOZ_CRASHREPORTER - if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) - CrashReporter::UnsetExceptionHandler(); -#endif - XRE_DeinitCommandLine(); return NS_FAILED(rv) ? 1 : 0; @@ -4863,12 +4283,6 @@ MultiprocessBlockPolicy() { bool addonsCanDisable = Preferences::GetBool("extensions.e10sBlocksEnabling", false); bool disabledByAddons = Preferences::GetBool("extensions.e10sBlockedByAddons", false); -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AddonsShouldHaveBlockedE10s"), - disabledByAddons ? NS_LITERAL_CSTRING("1") - : NS_LITERAL_CSTRING("0")); -#endif - if (addonsCanDisable && disabledByAddons) { gMultiprocessBlockPolicy = kE10sDisabledForAddons; return gMultiprocessBlockPolicy; diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 1e67ea7ce..4a612e495 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -239,30 +239,6 @@ XRE_SetProcessType(const char* aProcessTypeString) } } -#if defined(MOZ_CRASHREPORTER) -// FIXME/bug 539522: this out-of-place function is stuck here because -// IPDL wants access to this crashreporter interface, and -// crashreporter is built in such a way to make that awkward -bool -XRE_TakeMinidumpForChild(uint32_t aChildPid, nsIFile** aDump, - uint32_t* aSequence) -{ - return CrashReporter::TakeMinidumpForChild(aChildPid, aDump, aSequence); -} - -bool -XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/) -{ -#if defined(XP_WIN) || defined(XP_MACOSX) - return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe)); -#elif defined(OS_LINUX) - return CrashReporter::SetRemoteExceptionHandler(); -#else -# error "OOP crash reporter unsupported on this platform" -#endif -} -#endif // if defined(MOZ_CRASHREPORTER) - #if defined(XP_WIN) void SetTaskbarGroupId(const nsString& aId) @@ -273,22 +249,6 @@ SetTaskbarGroupId(const nsString& aId) } #endif -#if defined(MOZ_CRASHREPORTER) -#if defined(MOZ_CONTENT_SANDBOX) && !defined(MOZ_WIDGET_GONK) -void -AddContentSandboxLevelAnnotation() -{ - if (XRE_GetProcessType() == GeckoProcessType_Content) { - int level = Preferences::GetInt("security.sandbox.content.level"); - nsAutoCString levelString; - levelString.AppendInt(level); - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxLevel"), levelString); - } -} -#endif /* MOZ_CONTENT_SANDBOX && !MOZ_WIDGET_GONK */ -#endif /* MOZ_CRASHREPORTER */ - nsresult XRE_InitChildProcess(int aArgc, char* aArgv[], @@ -442,33 +402,6 @@ XRE_InitChildProcess(int aArgc, SetupErrorHandling(aArgv[0]); -#if defined(MOZ_CRASHREPORTER) - if (aArgc < 1) - return NS_ERROR_FAILURE; - const char* const crashReporterArg = aArgv[--aArgc]; - -# if defined(XP_WIN) || defined(XP_MACOSX) - // on windows and mac, |crashReporterArg| is the named pipe on which the - // server is listening for requests, or "-" if crash reporting is - // disabled. - if (0 != strcmp("-", crashReporterArg) && - !XRE_SetRemoteExceptionHandler(crashReporterArg)) { - // Bug 684322 will add better visibility into this condition - NS_WARNING("Could not setup crash reporting\n"); - } -# elif defined(OS_LINUX) - // on POSIX, |crashReporterArg| is "true" if crash reporting is - // enabled, false otherwise - if (0 != strcmp("false", crashReporterArg) && - !XRE_SetRemoteExceptionHandler(nullptr)) { - // Bug 684322 will add better visibility into this condition - NS_WARNING("Could not setup crash reporting\n"); - } -# else -# error "OOP crash reporting unsupported on this platform" -# endif -#endif // if defined(MOZ_CRASHREPORTER) - gArgv = aArgv; gArgc = aArgc; @@ -647,12 +580,6 @@ XRE_InitChildProcess(int aArgc, return NS_ERROR_FAILURE; } -#ifdef MOZ_CRASHREPORTER -#if defined(XP_WIN) || defined(XP_MACOSX) - CrashReporter::InitChildProcessTmpDir(); -#endif -#endif - #if defined(XP_WIN) // Set child processes up such that they will get killed after the // chrome process is killed in cases where the user shuts the system @@ -668,12 +595,6 @@ XRE_InitChildProcess(int aArgc, OverrideDefaultLocaleIfNeeded(); -#if defined(MOZ_CRASHREPORTER) -#if defined(MOZ_CONTENT_SANDBOX) && !defined(MOZ_WIDGET_GONK) - AddContentSandboxLevelAnnotation(); -#endif -#endif - // Run the UI event loop on the main thread. uiMessageLoop.MessageLoop::Run(); diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp index 788d25a90..e282374cc 100644 --- a/toolkit/xre/nsWindowsWMain.cpp +++ b/toolkit/xre/nsWindowsWMain.cpp @@ -18,10 +18,6 @@ #include "nsSetDllDirectory.h" #endif -#if defined(__GNUC__) -#define XRE_DONT_SUPPORT_XPSP2 -#endif - #ifdef __MINGW32__ /* MingW currently does not implement a wide version of the diff --git a/toolkit/xre/nsX11ErrorHandler.cpp b/toolkit/xre/nsX11ErrorHandler.cpp index 0db24e58b..0fb0d29c5 100644 --- a/toolkit/xre/nsX11ErrorHandler.cpp +++ b/toolkit/xre/nsX11ErrorHandler.cpp @@ -117,18 +117,6 @@ X11Error(Display *display, XErrorEvent *event) { } } -#ifdef MOZ_CRASHREPORTER - switch (XRE_GetProcessType()) { - case GeckoProcessType_Default: - case GeckoProcessType_Plugin: - case GeckoProcessType_Content: - CrashReporter::AppendAppNotesToCrashReport(notes); - break; - default: - ; // crash report notes not supported. - } -#endif - #ifdef DEBUG // The resource id is unlikely to be useful in a crash report without // context of other ids, but add it to the debug console output. diff --git a/tools/profiler/moz.build b/tools/profiler/moz.build index e48ae8f94..08103f126 100644 --- a/tools/profiler/moz.build +++ b/tools/profiler/moz.build @@ -60,14 +60,13 @@ if CONFIG['MOZ_ENABLE_PROFILER_SPS']: 'core/platform-linux.cc', 'core/shared-libraries-linux.cc', ] - if not CONFIG['MOZ_CRASHREPORTER']: - SOURCES += [ - '/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc', - '/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc', - '/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.cc', - '/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc', - '/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc', - ] + SOURCES += [ + '/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc', + '/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc', + '/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.cc', + '/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc', + '/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc', + ] if CONFIG['CPU_ARCH'] == 'arm': SOURCES += [ 'core/EHABIStackWalk.cpp', @@ -100,7 +99,7 @@ if CONFIG['MOZ_ENABLE_PROFILER_SPS']: '/toolkit/crashreporter/google-breakpad/src/common/android/include', ] - if not CONFIG['MOZ_CRASHREPORTER'] and CONFIG['OS_TARGET'] == 'Android': + if CONFIG['OS_TARGET'] == 'Android': SOURCES += ['/toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext.S'] if CONFIG['ANDROID_CPU_ARCH'] == 'armeabi': diff --git a/widget/GfxInfoBase.cpp b/widget/GfxInfoBase.cpp index 5c8693957..c937f5099 100644 --- a/widget/GfxInfoBase.cpp +++ b/widget/GfxInfoBase.cpp @@ -37,10 +37,6 @@ #include "gfxConfig.h" #include "DriverCrashGuard.h" -#if defined(MOZ_CRASHREPORTER) -#include "nsExceptionHandler.h" -#endif - using namespace mozilla::widget; using namespace mozilla; using mozilla::MutexAutoLock; diff --git a/widget/GfxInfoX11.cpp b/widget/GfxInfoX11.cpp index f490bed52..4297aaa93 100644 --- a/widget/GfxInfoX11.cpp +++ b/widget/GfxInfoX11.cpp @@ -15,11 +15,6 @@ #include "GfxInfoX11.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#include "nsICrashReporter.h" -#endif - namespace mozilla { namespace widget { @@ -176,9 +171,6 @@ GfxInfo::GetData() mAdapterDescription.Append(nsDependentCString(buf)); mAdapterDescription.Append('\n'); } -#ifdef MOZ_CRASHREPORTER - CrashReporter::AppendAppNotesToCrashReport(mAdapterDescription); -#endif return; } @@ -194,9 +186,6 @@ GfxInfo::GetData() if (mHasTextureFromPixmap) note.AppendLiteral(" -- texture_from_pixmap"); note.Append('\n'); -#ifdef MOZ_CRASHREPORTER - CrashReporter::AppendAppNotesToCrashReport(note); -#endif // determine the major OpenGL version. That's the first integer in the version string. mGLMajorVersion = strtol(mVersion.get(), 0, 10); diff --git a/widget/android/GfxInfo.cpp b/widget/android/GfxInfo.cpp index af63184a7..181629e96 100644 --- a/widget/android/GfxInfo.cpp +++ b/widget/android/GfxInfo.cpp @@ -15,12 +15,6 @@ #include "nsIWindowWatcher.h" #include "nsServiceManagerUtils.h" -#if defined(MOZ_CRASHREPORTER) -#include "nsExceptionHandler.h" -#include "nsICrashReporter.h" -#define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" -#endif - namespace mozilla { namespace widget { @@ -351,21 +345,7 @@ GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) void GfxInfo::AddCrashReportAnnotations() { -#if defined(MOZ_CRASHREPORTER) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterVendorID"), - mGLStrings->Vendor()); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDeviceID"), - mGLStrings->Renderer()); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDriverVersion"), - mGLStrings->Version()); - - /* Add an App Note for now so that we get the data immediately. These - * can go away after we store the above in the socorro db */ - nsAutoCString note; - note.AppendPrintf("AdapterDescription: '%s'\n", mAdapterDescription.get()); - - CrashReporter::AppendAppNotesToCrashReport(note); -#endif + /*** STUB ***/ } const nsTArray<GfxDriverInfo>& diff --git a/widget/android/jni/Utils.cpp b/widget/android/jni/Utils.cpp index 145f7e9ea..919588851 100644 --- a/widget/android/jni/Utils.cpp +++ b/widget/android/jni/Utils.cpp @@ -9,10 +9,6 @@ #include "GeneratedJNIWrappers.h" #include "nsAppShell.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - namespace mozilla { namespace jni { @@ -192,12 +188,6 @@ bool ReportException(JNIEnv* aEnv, jthrowable aExc, jstring aStack) { bool result = true; -#ifdef MOZ_CRASHREPORTER - result &= NS_SUCCEEDED(CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("JavaStackTrace"), - String::Ref::From(aStack)->ToCString())); -#endif // MOZ_CRASHREPORTER - if (sOOMErrorClass && aEnv->IsInstanceOf(aExc, sOOMErrorClass)) { NS_ABORT_OOM(0); // Unknown OOM size } diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index fefd711d0..09548c27b 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -53,11 +53,6 @@ #include "mozilla/Logging.h" #endif -#ifdef MOZ_CRASHREPORTER -#include "nsICrashReporter.h" -#include "nsExceptionHandler.h" -#endif - #include "AndroidAlerts.h" #include "ANRReporter.h" #include "GeckoBatteryManager.h" diff --git a/widget/cocoa/GfxInfo.mm b/widget/cocoa/GfxInfo.mm index 6789ae8b2..74333c514 100644 --- a/widget/cocoa/GfxInfo.mm +++ b/widget/cocoa/GfxInfo.mm @@ -18,12 +18,6 @@ #import <IOKit/IOKitLib.h> #import <Cocoa/Cocoa.h> -#if defined(MOZ_CRASHREPORTER) -#include "nsExceptionHandler.h" -#include "nsICrashReporter.h" -#define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" -#endif - using namespace mozilla; using namespace mozilla::widget; @@ -273,33 +267,7 @@ GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) void GfxInfo::AddCrashReportAnnotations() { -#if defined(MOZ_CRASHREPORTER) - nsString deviceID, vendorID, driverVersion; - nsAutoCString narrowDeviceID, narrowVendorID, narrowDriverVersion; - - GetAdapterDeviceID(deviceID); - CopyUTF16toUTF8(deviceID, narrowDeviceID); - GetAdapterVendorID(vendorID); - CopyUTF16toUTF8(vendorID, narrowVendorID); - GetAdapterDriverVersion(driverVersion); - CopyUTF16toUTF8(driverVersion, narrowDriverVersion); - - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterVendorID"), - narrowVendorID); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDeviceID"), - narrowDeviceID); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDriverVersion"), - narrowDriverVersion); - /* Add an App Note for now so that we get the data immediately. These - * can go away after we store the above in the socorro db */ - nsAutoCString note; - /* AppendPrintf only supports 32 character strings, mrghh. */ - note.Append("AdapterVendorID: "); - note.Append(narrowVendorID); - note.Append(", AdapterDeviceID: "); - note.Append(narrowDeviceID); - CrashReporter::AppendAppNotesToCrashReport(note); -#endif + /*** STUB ***/ } // We don't support checking driver versions on Mac. diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 92ccd8b6c..8f72a81be 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -77,9 +77,6 @@ #include "nsAccessibilityService.h" #include "mozilla/a11y/Platform.h" #endif -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif #include "mozilla/Preferences.h" @@ -5373,31 +5370,14 @@ GetIntegerDeltaForEvent(NSEvent* aEvent) #if !defined(RELEASE_OR_BETA) || defined(DEBUG) if (!Preferences::GetBool("intl.allow-insecure-text-input", false) && mGeckoChild && mTextInputHandler && mTextInputHandler->IsFocused()) { -#ifdef MOZ_CRASHREPORTER - NSWindow* window = [self window]; - NSString* info = [NSString stringWithFormat:@"\nview [%@], window [%@], window is key %i, is fullscreen %i, app is active %i", - self, window, [window isKeyWindow], ([window styleMask] & (1 << 14)) != 0, - [NSApp isActive]]; - nsAutoCString additionalInfo([info UTF8String]); -#endif if (mGeckoChild->GetInputContext().IsPasswordEditor() && !TextInputHandler::IsSecureEventInputEnabled()) { #define CRASH_MESSAGE "A password editor has focus, but not in secure input mode" -#ifdef MOZ_CRASHREPORTER - CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("\nBug 893973: ") + - NS_LITERAL_CSTRING(CRASH_MESSAGE)); - CrashReporter::AppendAppNotesToCrashReport(additionalInfo); -#endif MOZ_CRASH(CRASH_MESSAGE); #undef CRASH_MESSAGE } else if (!mGeckoChild->GetInputContext().IsPasswordEditor() && TextInputHandler::IsSecureEventInputEnabled()) { #define CRASH_MESSAGE "A non-password editor has focus, but in secure input mode" -#ifdef MOZ_CRASHREPORTER - CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("\nBug 893973: ") + - NS_LITERAL_CSTRING(CRASH_MESSAGE)); - CrashReporter::AppendAppNotesToCrashReport(additionalInfo); -#endif MOZ_CRASH(CRASH_MESSAGE); #undef CRASH_MESSAGE } diff --git a/widget/nsBaseAppShell.cpp b/widget/nsBaseAppShell.cpp index 1557498b7..c6b88cba0 100644 --- a/widget/nsBaseAppShell.cpp +++ b/widget/nsBaseAppShell.cpp @@ -6,9 +6,6 @@ #include "base/message_loop.h" #include "nsBaseAppShell.h" -#if defined(MOZ_CRASHREPORTER) -#include "nsExceptionHandler.h" -#endif #include "nsThreadUtils.h" #include "nsIObserverService.h" #include "nsServiceManagerUtils.h" @@ -317,18 +314,12 @@ void nsBaseAppShell::IncrementEventloopNestingLevel() { ++mEventloopNestingLevel; -#if defined(MOZ_CRASHREPORTER) - CrashReporter::SetEventloopNestingLevel(mEventloopNestingLevel); -#endif } void nsBaseAppShell::DecrementEventloopNestingLevel() { --mEventloopNestingLevel; -#if defined(MOZ_CRASHREPORTER) - CrashReporter::SetEventloopNestingLevel(mEventloopNestingLevel); -#endif } // Called from the main thread diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp index bfea41851..8a429ad32 100644 --- a/widget/windows/GfxInfo.cpp +++ b/widget/windows/GfxInfo.cpp @@ -21,12 +21,6 @@ #include "nsPrintfCString.h" #include "jsapi.h" -#if defined(MOZ_CRASHREPORTER) -#include "nsExceptionHandler.h" -#include "nsICrashReporter.h" -#define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1" -#endif - using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::widget; @@ -721,102 +715,10 @@ GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) return NS_OK; } -#if defined(MOZ_CRASHREPORTER) -/* Cisco's VPN software can cause corruption of the floating point state. - * Make a note of this in our crash reports so that some weird crashes - * make more sense */ -static void -CheckForCiscoVPN() { - LONG result; - HKEY key; - /* This will give false positives, but hopefully no false negatives */ - result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Cisco Systems\\VPN Client", 0, KEY_QUERY_VALUE, &key); - if (result == ERROR_SUCCESS) { - RegCloseKey(key); - CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("Cisco VPN\n")); - } -} -#endif - void GfxInfo::AddCrashReportAnnotations() { -#if defined(MOZ_CRASHREPORTER) - CheckForCiscoVPN(); - - if (mHasDriverVersionMismatch) { - CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DriverVersionMismatch\n")); - } - - nsString deviceID, vendorID, driverVersion, subsysID; - nsCString narrowDeviceID, narrowVendorID, narrowDriverVersion, narrowSubsysID; - - GetAdapterDeviceID(deviceID); - CopyUTF16toUTF8(deviceID, narrowDeviceID); - GetAdapterVendorID(vendorID); - CopyUTF16toUTF8(vendorID, narrowVendorID); - GetAdapterDriverVersion(driverVersion); - CopyUTF16toUTF8(driverVersion, narrowDriverVersion); - GetAdapterSubsysID(subsysID); - CopyUTF16toUTF8(subsysID, narrowSubsysID); - - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterVendorID"), - narrowVendorID); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDeviceID"), - narrowDeviceID); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDriverVersion"), - narrowDriverVersion); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterSubsysID"), - narrowSubsysID); - - /* Add an App Note for now so that we get the data immediately. These - * can go away after we store the above in the socorro db */ - nsAutoCString note; - /* AppendPrintf only supports 32 character strings, mrghh. */ - note.AppendLiteral("AdapterVendorID: "); - note.Append(narrowVendorID); - note.AppendLiteral(", AdapterDeviceID: "); - note.Append(narrowDeviceID); - note.AppendLiteral(", AdapterSubsysID: "); - note.Append(narrowSubsysID); - note.AppendLiteral(", AdapterDriverVersion: "); - note.Append(NS_LossyConvertUTF16toASCII(driverVersion)); - - if (vendorID == GfxDriverInfo::GetDeviceVendor(VendorAll)) { - /* if we didn't find a valid vendorID lets append the mDeviceID string to try to find out why */ - note.AppendLiteral(", "); - LossyAppendUTF16toASCII(mDeviceID, note); - note.AppendLiteral(", "); - LossyAppendUTF16toASCII(mDeviceKeyDebug, note); - LossyAppendUTF16toASCII(mDeviceKeyDebug, note); - } - note.Append("\n"); - - if (mHasDualGPU) { - nsString deviceID2, vendorID2, subsysID2; - nsAutoString adapterDriverVersionString2; - nsCString narrowDeviceID2, narrowVendorID2, narrowSubsysID2; - - note.AppendLiteral("Has dual GPUs. GPU #2: "); - GetAdapterDeviceID2(deviceID2); - CopyUTF16toUTF8(deviceID2, narrowDeviceID2); - GetAdapterVendorID2(vendorID2); - CopyUTF16toUTF8(vendorID2, narrowVendorID2); - GetAdapterDriverVersion2(adapterDriverVersionString2); - GetAdapterSubsysID(subsysID2); - CopyUTF16toUTF8(subsysID2, narrowSubsysID2); - note.AppendLiteral("AdapterVendorID2: "); - note.Append(narrowVendorID2); - note.AppendLiteral(", AdapterDeviceID2: "); - note.Append(narrowDeviceID2); - note.AppendLiteral(", AdapterSubsysID2: "); - note.Append(narrowSubsysID2); - note.AppendLiteral(", AdapterDriverVersion2: "); - note.Append(NS_LossyConvertUTF16toASCII(adapterDriverVersionString2)); - } - CrashReporter::AppendAppNotesToCrashReport(note); - -#endif + /*** STUB ***/ } static OperatingSystem diff --git a/widget/windows/KeyboardLayout.cpp b/widget/windows/KeyboardLayout.cpp index 341a40c18..9166d97d7 100644 --- a/widget/windows/KeyboardLayout.cpp +++ b/widget/windows/KeyboardLayout.cpp @@ -13,9 +13,6 @@ #include "mozilla/WindowsVersion.h" #include "nsAlgorithm.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif #include "nsGkAtoms.h" #include "nsIDOMKeyEvent.h" #include "nsIIdleServiceInternal.h" @@ -2740,42 +2737,6 @@ NativeKey::NeedsToHandleWithoutFollowingCharMessages() const return mIsPrintableKey; } -#ifdef MOZ_CRASHREPORTER - -static nsCString -GetResultOfInSendMessageEx() -{ - DWORD ret = ::InSendMessageEx(nullptr); - if (!ret) { - return NS_LITERAL_CSTRING("ISMEX_NOSEND"); - } - nsAutoCString result; - if (ret & ISMEX_CALLBACK) { - result = "ISMEX_CALLBACK"; - } - if (ret & ISMEX_NOTIFY) { - if (!result.IsEmpty()) { - result += " | "; - } - result += "ISMEX_NOTIFY"; - } - if (ret & ISMEX_REPLIED) { - if (!result.IsEmpty()) { - result += " | "; - } - result += "ISMEX_REPLIED"; - } - if (ret & ISMEX_SEND) { - if (!result.IsEmpty()) { - result += " | "; - } - result += "ISMEX_SEND"; - } - return result; -} - -#endif // #ifdef MOZ_CRASHREPORTER - bool NativeKey::MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const @@ -3019,33 +2980,6 @@ NativeKey::GetFollowingCharMessage(MSG& aCharMsg) } if (doCrash) { -#ifdef MOZ_CRASHREPORTER - nsPrintfCString info("\nPeekMessage() failed to remove char message! " - "\nActive keyboard layout=0x%08X (%s), " - "\nHandling message: %s, InSendMessageEx()=%s, " - "\nFound message: %s, " - "\nWM_NULL has been removed: %d, " - "\nNext key message in all windows: %s, " - "time=%d, ", - KeyboardLayout::GetActiveLayout(), - KeyboardLayout::GetActiveLayoutName().get(), - ToString(mMsg).get(), - GetResultOfInSendMessageEx().get(), - ToString(kFoundCharMsg).get(), i, - ToString(nextKeyMsgInAllWindows).get(), - nextKeyMsgInAllWindows.time); - CrashReporter::AppendAppNotesToCrashReport(info); - MSG nextMsg; - if (WinUtils::PeekMessage(&nextMsg, 0, 0, 0, - PM_NOREMOVE | PM_NOYIELD)) { - nsPrintfCString info("\nNext message in all windows: %s, time=%d", - ToString(nextMsg).get(), nextMsg.time); - CrashReporter::AppendAppNotesToCrashReport(info); - } else { - CrashReporter::AppendAppNotesToCrashReport( - NS_LITERAL_CSTRING("\nThere is no message in any window")); - } -#endif // #ifdef MOZ_CRASHREPORTER MOZ_CRASH("We lost the following char message"); } @@ -3164,63 +3098,12 @@ NativeKey::GetFollowingCharMessage(MSG& aCharMsg) "nextKeyMsg=%s, kFoundCharMsg=%s", this, ToString(removedMsg).get(), ToString(nextKeyMsg).get(), ToString(kFoundCharMsg).get())); -#ifdef MOZ_CRASHREPORTER - nsPrintfCString info("\nPeekMessage() removed unexpcted char message! " - "\nActive keyboard layout=0x%08X (%s), " - "\nHandling message: %s, InSendMessageEx()=%s, " - "\nFound message: %s, " - "\nRemoved message: %s, ", - KeyboardLayout::GetActiveLayout(), - KeyboardLayout::GetActiveLayoutName().get(), - ToString(mMsg).get(), - GetResultOfInSendMessageEx().get(), - ToString(kFoundCharMsg).get(), - ToString(removedMsg).get()); - CrashReporter::AppendAppNotesToCrashReport(info); - // What's the next key message? - MSG nextKeyMsgAfter; - if (WinUtils::PeekMessage(&nextKeyMsgAfter, mMsg.hwnd, - WM_KEYFIRST, WM_KEYLAST, - PM_NOREMOVE | PM_NOYIELD)) { - nsPrintfCString info("\nNext key message after unexpected char message " - "removed: %s, ", - ToString(nextKeyMsgAfter).get()); - CrashReporter::AppendAppNotesToCrashReport(info); - } else { - CrashReporter::AppendAppNotesToCrashReport( - NS_LITERAL_CSTRING("\nThere is no key message after unexpected char " - "message removed, ")); - } - // Another window has a key message? - if (WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0, - WM_KEYFIRST, WM_KEYLAST, - PM_NOREMOVE | PM_NOYIELD)) { - nsPrintfCString info("\nNext key message in all windows: %s.", - ToString(nextKeyMsgInAllWindows).get()); - CrashReporter::AppendAppNotesToCrashReport(info); - } else { - CrashReporter::AppendAppNotesToCrashReport( - NS_LITERAL_CSTRING("\nThere is no key message in any windows.")); - } -#endif // #ifdef MOZ_CRASHREPORTER MOZ_CRASH("PeekMessage() removed unexpected message"); } MOZ_LOG(sNativeKeyLogger, LogLevel::Error, ("%p NativeKey::GetFollowingCharMessage(), FAILED, removed messages " "are all WM_NULL, nextKeyMsg=%s", this, ToString(nextKeyMsg).get())); -#ifdef MOZ_CRASHREPORTER - nsPrintfCString info("\nWe lost following char message! " - "\nActive keyboard layout=0x%08X (%s), " - "\nHandling message: %s, InSendMessageEx()=%s, \n" - "Found message: %s, removed a lot of WM_NULL", - KeyboardLayout::GetActiveLayout(), - KeyboardLayout::GetActiveLayoutName().get(), - ToString(mMsg).get(), - GetResultOfInSendMessageEx().get(), - ToString(kFoundCharMsg).get()); - CrashReporter::AppendAppNotesToCrashReport(info); -#endif // #ifdef MOZ_CRASHREPORTER MOZ_CRASH("We lost the following char message"); return false; } diff --git a/widget/windows/LSPAnnotator.cpp b/widget/windows/LSPAnnotator.cpp deleted file mode 100644 index 97f6e5b50..000000000 --- a/widget/windows/LSPAnnotator.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * LSPs are evil little bits of code that are allowed to inject into our - * networking stack by Windows. Once they have wormed into our process - * they gnaw at our innards until we crash. Here we force the buggers - * into the light by recording them in our crash information. - * We do the enumeration on a thread because I'm concerned about startup perf - * on machines with several LSPs. - */ - -#include "nsICrashReporter.h" -#include "nsISupportsImpl.h" -#include "nsServiceManagerUtils.h" -#include "nsThreadUtils.h" -#include "nsQueryObject.h" -#include "nsWindowsHelpers.h" -#include <windows.h> -#include <rpc.h> -#include <ws2spi.h> - -namespace mozilla { -namespace crashreporter { - -class LSPAnnotationGatherer : public Runnable -{ - ~LSPAnnotationGatherer() {} - -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIRUNNABLE - - void Annotate(); - nsCString mString; - nsCOMPtr<nsIThread> mThread; -}; - -NS_IMPL_ISUPPORTS(LSPAnnotationGatherer, nsIRunnable) - -void -LSPAnnotationGatherer::Annotate() -{ - nsCOMPtr<nsICrashReporter> cr = - do_GetService("@mozilla.org/toolkit/crash-reporter;1"); - bool enabled; - if (cr && NS_SUCCEEDED(cr->GetEnabled(&enabled)) && enabled) { - cr->AnnotateCrashReport(NS_LITERAL_CSTRING("Winsock_LSP"), mString); - } - mThread->AsyncShutdown(); -} - -NS_IMETHODIMP -LSPAnnotationGatherer::Run() -{ - PR_SetCurrentThreadName("LSP Annotator"); - - mThread = NS_GetCurrentThread(); - - DWORD size = 0; - int err; - // Get the size of the buffer we need - if (SOCKET_ERROR != WSCEnumProtocols(nullptr, nullptr, &size, &err) || - err != WSAENOBUFS) { - // Er, what? - NS_NOTREACHED("WSCEnumProtocols suceeded when it should have failed ..."); - return NS_ERROR_FAILURE; - } - - auto byteArray = MakeUnique<char[]>(size); - WSAPROTOCOL_INFOW* providers = - reinterpret_cast<WSAPROTOCOL_INFOW*>(byteArray.get()); - - int n = WSCEnumProtocols(nullptr, providers, &size, &err); - if (n == SOCKET_ERROR) { - // Lame. We provided the right size buffer; we'll just give up now. - NS_WARNING("Could not get LSP list"); - return NS_ERROR_FAILURE; - } - - nsCString str; - for (int i = 0; i < n; i++) { - AppendUTF16toUTF8(nsDependentString(providers[i].szProtocol), str); - str.AppendLiteral(" : "); - str.AppendInt(providers[i].iVersion); - str.AppendLiteral(" : "); - str.AppendInt(providers[i].iAddressFamily); - str.AppendLiteral(" : "); - str.AppendInt(providers[i].iSocketType); - str.AppendLiteral(" : "); - str.AppendInt(providers[i].iProtocol); - str.AppendLiteral(" : "); - str.AppendPrintf("0x%x", providers[i].dwServiceFlags1); - str.AppendLiteral(" : "); - str.AppendPrintf("0x%x", providers[i].dwProviderFlags); - str.AppendLiteral(" : "); - - wchar_t path[MAX_PATH]; - int pathLen = MAX_PATH; - if (!WSCGetProviderPath(&providers[i].ProviderId, path, &pathLen, &err)) { - AppendUTF16toUTF8(nsDependentString(path), str); - } - - str.AppendLiteral(" : "); - // If WSCGetProviderInfo is available, we should call it to obtain the - // category flags for this provider. When present, these flags inform - // Windows as to which order to chain the providers. - nsModuleHandle ws2_32(LoadLibraryW(L"ws2_32.dll")); - if (ws2_32) { - decltype(WSCGetProviderInfo)* pWSCGetProviderInfo = - reinterpret_cast<decltype(WSCGetProviderInfo)*>( - GetProcAddress(ws2_32, "WSCGetProviderInfo")); - if (pWSCGetProviderInfo) { - DWORD categoryInfo; - size_t categoryInfoSize = sizeof(categoryInfo); - if (!pWSCGetProviderInfo(&providers[i].ProviderId, - ProviderInfoLspCategories, - (PBYTE)&categoryInfo, &categoryInfoSize, 0, - &err)) { - str.AppendPrintf("0x%x", categoryInfo); - } - } - } - - str.AppendLiteral(" : "); - if (providers[i].ProtocolChain.ChainLen <= BASE_PROTOCOL) { - // If we're dealing with a catalog entry that identifies an individual - // base or layer provider, log its provider GUID. - RPC_CSTR provIdStr = nullptr; - if (UuidToStringA(&providers[i].ProviderId, &provIdStr) == RPC_S_OK) { - str.Append(reinterpret_cast<char*>(provIdStr)); - RpcStringFreeA(&provIdStr); - } - } - - if (i + 1 != n) { - str.AppendLiteral(" \n "); - } - } - - mString = str; - NS_DispatchToMainThread(NewRunnableMethod(this, &LSPAnnotationGatherer::Annotate)); - return NS_OK; -} - -void LSPAnnotate() -{ - nsCOMPtr<nsIThread> thread; - nsCOMPtr<nsIRunnable> runnable = - do_QueryObject(new LSPAnnotationGatherer()); - NS_NewThread(getter_AddRefs(thread), runnable); -} - -} // namespace crashreporter -} // namespace mozilla diff --git a/widget/windows/moz.build b/widget/windows/moz.build index d4f089eea..1e7fc4b02 100644 --- a/widget/windows/moz.build +++ b/widget/windows/moz.build @@ -79,11 +79,6 @@ SOURCES += [ 'WinMouseScrollHandler.cpp', ] -if CONFIG['MOZ_CRASHREPORTER']: - UNIFIED_SOURCES += [ - 'LSPAnnotator.cpp', - ] - if CONFIG['NS_PRINTING']: UNIFIED_SOURCES += [ 'nsDeviceContextSpecWin.cpp', diff --git a/widget/windows/nsAppShell.cpp b/widget/windows/nsAppShell.cpp index c8820e7d1..c3e99b2d3 100644 --- a/widget/windows/nsAppShell.cpp +++ b/widget/windows/nsAppShell.cpp @@ -213,10 +213,6 @@ nsAppShell::~nsAppShell() nsresult nsAppShell::Init() { -#ifdef MOZ_CRASHREPORTER - LSPAnnotate(); -#endif - mLastNativeEventScheduled = TimeStamp::NowLoRes(); mozilla::ipc::windows::InitUIThread(); diff --git a/xpcom/base/CycleCollectedJSContext.cpp b/xpcom/base/CycleCollectedJSContext.cpp index 87e123078..4af8fe4dd 100644 --- a/xpcom/base/CycleCollectedJSContext.cpp +++ b/xpcom/base/CycleCollectedJSContext.cpp @@ -82,10 +82,6 @@ #include "nsJSUtils.h" #include "nsWrapperCache.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - #include "nsIException.h" #include "nsIPlatformInfo.h" #include "nsThread.h" @@ -539,10 +535,6 @@ CycleCollectedJSContext::Initialize(JSContext* aParentContext, JS_SetSweepZoneCallback(mJSContext, XPCStringConvert::ClearZoneCache); JS::SetBuildIdOp(mJSContext, GetBuildId); JS::SetWarningReporter(mJSContext, MozCrashWarningReporter); -#ifdef MOZ_CRASHREPORTER - js::AutoEnterOOMUnsafeRegion::setAnnotateOOMAllocationSizeCallback( - CrashReporter::AnnotateOOMAllocationSize); -#endif static js::DOMCallbacks DOMcallbacks = { InstanceClassHasProtoAtDepth @@ -1607,16 +1599,6 @@ CycleCollectedJSContext::AnnotateAndSetOutOfMemory(OOMState* aStatePtr, MOZ_ASSERT(mJSContext); *aStatePtr = aNewState; -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(aStatePtr == &mOutOfMemoryState - ? NS_LITERAL_CSTRING("JSOutOfMemory") - : NS_LITERAL_CSTRING("JSLargeAllocationFailure"), - aNewState == OOMState::Reporting - ? NS_LITERAL_CSTRING("Reporting") - : aNewState == OOMState::Reported - ? NS_LITERAL_CSTRING("Reported") - : NS_LITERAL_CSTRING("Recovered")); -#endif } void @@ -1630,14 +1612,6 @@ CycleCollectedJSContext::OnGC(JSGCStatus aStatus) mZonesWaitingForGC.Clear(); break; case JSGC_END: { -#ifdef MOZ_CRASHREPORTER - if (mOutOfMemoryState == OOMState::Reported) { - AnnotateAndSetOutOfMemory(&mOutOfMemoryState, OOMState::Recovered); - } - if (mLargeAllocationFailureState == OOMState::Reported) { - AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Recovered); - } -#endif // Do any deferred finalization of native objects. FinalizeDeferredThings(JS::WasIncrementalGC(mJSContext) ? FinalizeIncrementally : diff --git a/xpcom/base/nsCrashOnException.cpp b/xpcom/base/nsCrashOnException.cpp index 0f8042531..06c48738f 100644 --- a/xpcom/base/nsCrashOnException.cpp +++ b/xpcom/base/nsCrashOnException.cpp @@ -8,22 +8,11 @@ #include "nsCOMPtr.h" #include "nsServiceManagerUtils.h" -#ifdef MOZ_CRASHREPORTER -#include "nsICrashReporter.h" -#endif - namespace mozilla { static int ReportException(EXCEPTION_POINTERS* aExceptionInfo) { -#ifdef MOZ_CRASHREPORTER - nsCOMPtr<nsICrashReporter> cr = - do_GetService("@mozilla.org/toolkit/crash-reporter;1"); - if (cr) { - cr->WriteMinidumpForException(aExceptionInfo); - } -#endif return EXCEPTION_EXECUTE_HANDLER; } diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index ca7057628..b2c15a1dd 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -188,10 +188,6 @@ #include "mozilla/Telemetry.h" #include "mozilla/ThreadLocal.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - using namespace mozilla; //#define COLLECT_TIME_DEBUG @@ -2690,7 +2686,7 @@ public: void* aClosure) const override { const JS::Value& val = aValue->unbarrieredGet(); - if (val.isMarkable() && ValueIsGrayCCThing(val)) { + if (val.isGCThing() && ValueIsGrayCCThing(val)) { MOZ_ASSERT(!js::gc::IsInsideNursery(val.toGCThing())); mCollector->GetJSPurpleBuffer()->mValues.InfallibleAppend(val); } @@ -3150,14 +3146,6 @@ nsCycleCollector::ScanWhiteNodes(bool aFullySynchGraphBuild) } if (pi->mInternalRefs > pi->mRefCount) { -#ifdef MOZ_CRASHREPORTER - const char* piName = "Unknown"; - if (pi->mParticipant) { - piName = pi->mParticipant->ClassName(); - } - nsPrintfCString msg("More references to an object than its refcount, for class %s", piName); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CycleCollector"), msg); -#endif MOZ_CRASH(); } diff --git a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp index eb06a389c..7c48002e3 100644 --- a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp +++ b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp @@ -36,7 +36,7 @@ void TraceCallbackFunc::Trace(JS::Heap<JS::Value>* aPtr, const char* aName, void* aClosure) const { - if (aPtr->unbarrieredGet().isMarkable()) { + if (aPtr->unbarrieredGet().isGCThing()) { mCallback(JS::GCCellPtr(aPtr->unbarrieredGet()), aName, aClosure); } } diff --git a/xpcom/base/nsDebugImpl.cpp b/xpcom/base/nsDebugImpl.cpp index 36288d203..96487acda 100644 --- a/xpcom/base/nsDebugImpl.cpp +++ b/xpcom/base/nsDebugImpl.cpp @@ -11,9 +11,6 @@ #include "nsDebugImpl.h" #include "nsDebug.h" -#ifdef MOZ_CRASHREPORTER -# include "nsExceptionHandler.h" -#endif #include "nsString.h" #include "nsXULAppAPI.h" #include "prprf.h" @@ -380,22 +377,6 @@ NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr, return; case NS_DEBUG_ABORT: { -#if defined(MOZ_CRASHREPORTER) - // Updating crash annotations in the child causes us to do IPC. This can - // really cause trouble if we're asserting from within IPC code. So we - // have to do without the annotations in that case. - if (XRE_IsParentProcess()) { - // Don't include the PID in the crash report annotation to - // allow faceting on crash-stats.mozilla.org. - nsCString note("xpcom_runtime_abort("); - note += nonPIDBuf.buffer; - note += ")"; - CrashReporter::AppendAppNotesToCrashReport(note); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AbortMessage"), - nsDependentCString(nonPIDBuf.buffer)); - } -#endif // MOZ_CRASHREPORTER - #if defined(DEBUG) && defined(_WIN32) RealBreak(); #endif @@ -600,8 +581,5 @@ NS_ErrorAccordingToNSPR() void NS_ABORT_OOM(size_t aSize) { -#if defined(MOZ_CRASHREPORTER) - CrashReporter::AnnotateOOMAllocationSize(aSize); -#endif MOZ_CRASH("OOM"); } diff --git a/xpcom/base/nsObjCExceptions.h b/xpcom/base/nsObjCExceptions.h index e63c92af5..b3ed532ec 100644 --- a/xpcom/base/nsObjCExceptions.h +++ b/xpcom/base/nsObjCExceptions.h @@ -17,12 +17,6 @@ #import <ExceptionHandling/NSExceptionHandler.h> #endif -#if defined(MOZ_CRASHREPORTER) && defined(__cplusplus) -#include "nsICrashReporter.h" -#include "nsCOMPtr.h" -#include "nsServiceManagerUtils.h" -#endif - #include <unistd.h> #include <signal.h> #include "nsError.h" @@ -47,15 +41,6 @@ nsObjCExceptionLog(NSException* aException) NSLog(@"Mozilla has caught an Obj-C exception [%@: %@]", [aException name], [aException reason]); -#if defined(MOZ_CRASHREPORTER) && defined(__cplusplus) - // Attach exception info to the crash report. - nsCOMPtr<nsICrashReporter> crashReporter = - do_GetService("@mozilla.org/toolkit/crash-reporter;1"); - if (crashReporter) { - crashReporter->AppendObjCExceptionInfoToAppNotes(static_cast<void*>(aException)); - } -#endif - #ifdef DEBUG @try { // Try to get stack information out of the exception. 10.5 returns the stack diff --git a/xpcom/build/nsXULAppAPI.h b/xpcom/build/nsXULAppAPI.h index 426a58f06..aae248ca1 100644 --- a/xpcom/build/nsXULAppAPI.h +++ b/xpcom/build/nsXULAppAPI.h @@ -426,17 +426,6 @@ XRE_API(const char*, XRE_API(void, XRE_SetProcessType, (const char* aProcessTypeString)) -#if defined(MOZ_CRASHREPORTER) -// Used in the "master" parent process hosting the crash server -XRE_API(bool, - XRE_TakeMinidumpForChild, (uint32_t aChildPid, nsIFile** aDump, - uint32_t* aSequence)) - -// Used in child processes. -XRE_API(bool, - XRE_SetRemoteExceptionHandler, (const char* aPipe)) -#endif - namespace mozilla { namespace gmp { class GMPLoader; diff --git a/xpcom/system/moz.build b/xpcom/system/moz.build index 8a4f88efe..1d8e7ea1f 100644 --- a/xpcom/system/moz.build +++ b/xpcom/system/moz.build @@ -18,9 +18,4 @@ XPIDL_SOURCES += [ 'nsIXULRuntime.idl', ] -if CONFIG['MOZ_CRASHREPORTER']: - XPIDL_SOURCES += [ - 'nsICrashReporter.idl', - ] - XPIDL_MODULE = 'xpcom_system' diff --git a/xpcom/tests/gtest/TestDeadlockDetector.cpp b/xpcom/tests/gtest/TestDeadlockDetector.cpp index 646ee3e1d..877c5f5c3 100644 --- a/xpcom/tests/gtest/TestDeadlockDetector.cpp +++ b/xpcom/tests/gtest/TestDeadlockDetector.cpp @@ -15,12 +15,6 @@ #include "mozilla/ReentrantMonitor.h" #include "mozilla/Mutex.h" -#ifdef MOZ_CRASHREPORTER -#include "nsCOMPtr.h" -#include "nsICrashReporter.h" -#include "nsServiceManagerUtils.h" -#endif - #include "gtest/gtest.h" using namespace mozilla; @@ -62,13 +56,7 @@ private: void DisableCrashReporter() { -#ifdef MOZ_CRASHREPORTER - nsCOMPtr<nsICrashReporter> crashreporter = - do_GetService("@mozilla.org/toolkit/crash-reporter;1"); - if (crashreporter) { - crashreporter->SetEnabled(false); - } -#endif + /*** STUB ***/ } //----------------------------------------------------------------------------- diff --git a/xpcom/tests/gtest/TestPLDHash.cpp b/xpcom/tests/gtest/TestPLDHash.cpp index e7a73ae1b..4405b102c 100644 --- a/xpcom/tests/gtest/TestPLDHash.cpp +++ b/xpcom/tests/gtest/TestPLDHash.cpp @@ -21,10 +21,6 @@ extern unsigned int _gdb_sleep_duration; #endif -#ifdef MOZ_CRASHREPORTER -#include "nsICrashReporter.h" -#endif - // We can test that certain operations cause expected aborts by forking // and then checking that the child aborted in the expected way (i.e. via // MOZ_CRASH). We skip this for the following configurations. @@ -46,17 +42,6 @@ TestCrashyOperation(void (*aCrashyOperation)()) ASSERT_NE(pid, -1); if (pid == 0) { - // Disable the crashreporter -- writing a crash dump in the child will - // prevent the parent from writing a subsequent dump. Crashes here are - // expected, so we don't want their stacks to show up in the log anyway. -#ifdef MOZ_CRASHREPORTER - nsCOMPtr<nsICrashReporter> crashreporter = - do_GetService("@mozilla.org/toolkit/crash-reporter;1"); - if (crashreporter) { - crashreporter->SetEnabled(false); - } -#endif - // Child: perform the crashy operation. fprintf(stderr, "TestCrashyOperation: The following crash is expected. Do not panic.\n"); aCrashyOperation(); diff --git a/xpcom/tests/gtest/TestSTLWrappers.cpp b/xpcom/tests/gtest/TestSTLWrappers.cpp index 9559548a3..295aa7434 100644 --- a/xpcom/tests/gtest/TestSTLWrappers.cpp +++ b/xpcom/tests/gtest/TestSTLWrappers.cpp @@ -10,12 +10,6 @@ # error "failed to wrap <vector>" #endif -#ifdef MOZ_CRASHREPORTER -#include "nsCOMPtr.h" -#include "nsICrashReporter.h" -#include "nsServiceManagerUtils.h" -#endif - // gcc errors out if we |try ... catch| with -fno-exceptions, but we // can still test on windows #ifdef _MSC_VER @@ -40,14 +34,6 @@ void ShouldAbort() _gdb_sleep_duration = 0; #endif -#ifdef MOZ_CRASHREPORTER - nsCOMPtr<nsICrashReporter> crashreporter = - do_GetService("@mozilla.org/toolkit/crash-reporter;1"); - if (crashreporter) { - crashreporter->SetEnabled(false); - } -#endif - std::vector<int> v; int rv = 1; diff --git a/xpcom/threads/HangMonitor.cpp b/xpcom/threads/HangMonitor.cpp index 71cc67ca4..bd415be50 100644 --- a/xpcom/threads/HangMonitor.cpp +++ b/xpcom/threads/HangMonitor.cpp @@ -22,10 +22,6 @@ #include "nsThreadUtils.h" #include "nsXULAppAPI.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - #ifdef XP_WIN #include <windows.h> #endif @@ -111,15 +107,6 @@ Crash() } #endif -#ifdef MOZ_CRASHREPORTER - // If you change this, you must also deal with the threadsafety of AnnotateCrashReport in - // non-chrome processes! - if (GeckoProcessType_Default == XRE_GetProcessType()) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Hang"), - NS_LITERAL_CSTRING("1")); - } -#endif - NS_RUNTIMEABORT("HangMonitor triggered"); } diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index 63bd28ca3..7c1af08f4 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -39,12 +39,6 @@ #include "nsThreadSyncDispatch.h" #include "LeakRefPtr.h" -#ifdef MOZ_CRASHREPORTER -#include "nsServiceManagerUtils.h" -#include "nsICrashReporter.h" -#include "mozilla/dom/ContentChild.h" -#endif - #ifdef XP_LINUX #include <sys/time.h> #include <sys/resource.h> @@ -520,73 +514,6 @@ nsThread::ThreadFunc(void* aArg) //----------------------------------------------------------------------------- -#ifdef MOZ_CRASHREPORTER -// Tell the crash reporter to save a memory report if our heuristics determine -// that an OOM failure is likely to occur soon. -// Memory usage will not be checked more than every 30 seconds or saved more -// than every 3 minutes -// If |aShouldSave == kForceReport|, a report will be saved regardless of -// whether the process is low on memory or not. However, it will still not be -// saved if a report was saved less than 3 minutes ago. -bool -nsThread::SaveMemoryReportNearOOM(ShouldSaveMemoryReport aShouldSave) -{ - // Keep an eye on memory usage (cheap, ~7ms) somewhat frequently, - // but save memory reports (expensive, ~75ms) less frequently. - const size_t kLowMemoryCheckSeconds = 30; - const size_t kLowMemorySaveSeconds = 3 * 60; - - static TimeStamp nextCheck = TimeStamp::NowLoRes() - + TimeDuration::FromSeconds(kLowMemoryCheckSeconds); - static bool recentlySavedReport = false; // Keeps track of whether a report - // was saved last time we checked - - // Are we checking again too soon? - TimeStamp now = TimeStamp::NowLoRes(); - if ((aShouldSave == ShouldSaveMemoryReport::kMaybeReport || - recentlySavedReport) && now < nextCheck) { - return false; - } - - bool needMemoryReport = (aShouldSave == ShouldSaveMemoryReport::kForceReport); -#ifdef XP_WIN // XXX implement on other platforms as needed - // If the report is forced there is no need to check whether it is necessary - if (aShouldSave != ShouldSaveMemoryReport::kForceReport) { - const size_t LOWMEM_THRESHOLD_VIRTUAL = 200 * 1024 * 1024; - MEMORYSTATUSEX statex; - statex.dwLength = sizeof(statex); - if (GlobalMemoryStatusEx(&statex)) { - if (statex.ullAvailVirtual < LOWMEM_THRESHOLD_VIRTUAL) { - needMemoryReport = true; - } - } - } -#endif - - if (needMemoryReport) { - if (XRE_IsContentProcess()) { - dom::ContentChild* cc = dom::ContentChild::GetSingleton(); - if (cc) { - cc->SendNotifyLowMemory(); - } - } else { - nsCOMPtr<nsICrashReporter> cr = - do_GetService("@mozilla.org/toolkit/crash-reporter;1"); - if (cr) { - cr->SaveMemoryReport(); - } - } - recentlySavedReport = true; - nextCheck = now + TimeDuration::FromSeconds(kLowMemorySaveSeconds); - } else { - recentlySavedReport = false; - nextCheck = now + TimeDuration::FromSeconds(kLowMemoryCheckSeconds); - } - - return recentlySavedReport; -} -#endif - #ifdef MOZ_CANARY int sCanaryOutputFD = -1; #endif @@ -1459,12 +1386,6 @@ nsThread::DoMainThreadSpecificProcessing(bool aReallyWait) } } } - -#ifdef MOZ_CRASHREPORTER - if (!ShuttingDown()) { - SaveMemoryReportNearOOM(ShouldSaveMemoryReport::kMaybeReport); - } -#endif } //----------------------------------------------------------------------------- diff --git a/xpcom/threads/nsThread.h b/xpcom/threads/nsThread.h index 836123747..037ef1952 100644 --- a/xpcom/threads/nsThread.h +++ b/xpcom/threads/nsThread.h @@ -83,16 +83,6 @@ public: void WaitForAllAsynchronousShutdowns(); -#ifdef MOZ_CRASHREPORTER - enum class ShouldSaveMemoryReport - { - kMaybeReport, - kForceReport - }; - - static bool SaveMemoryReportNearOOM(ShouldSaveMemoryReport aShouldSave); -#endif - private: void DoMainThreadSpecificProcessing(bool aReallyWait); |