author | Kyle Huey <khuey@kylehuey.com> |
Sun, 28 Aug 2011 06:00:17 -0400 | |
changeset 77313 | 0ac24f429e24d7f46731e9698d3f889bda63e2cb |
parent 77312 | 80155b29d8160f173be0d1ff8328cc8d474bc99f (current diff) |
parent 77292 | 6c8a909977d32284bbddd60a45e1780e824b5d7c (diff) |
child 77326 | ca5a3569462d7b03ba1da27ed161e1d506190912 |
push id | 78 |
push user | clegnitto@mozilla.com |
push date | Fri, 16 Dec 2011 17:32:24 +0000 |
treeherder | mozilla-release@79d24e644fdd [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 9.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/aclocal.m4 +++ b/aclocal.m4 @@ -10,16 +10,17 @@ builtin(include, build/autoconf/nss.m4)d builtin(include, build/autoconf/pkg.m4)dnl builtin(include, build/autoconf/freetype2.m4)dnl builtin(include, build/autoconf/codeset.m4)dnl builtin(include, build/autoconf/altoptions.m4)dnl builtin(include, build/autoconf/mozprog.m4)dnl builtin(include, build/autoconf/mozheader.m4)dnl builtin(include, build/autoconf/acwinpaths.m4)dnl builtin(include, build/autoconf/lto.m4)dnl +builtin(include, build/autoconf/gcc-pr49911.m4)dnl MOZ_PROG_CHECKMSYS() # Read the user's .mozconfig script. We can't do this in # configure.in: autoconf puts the argument parsing code above anything # expanded from configure.in, and we need to get the configure options # from .mozconfig in place before that argument parsing code. MOZ_READ_MOZCONFIG(.)
--- a/browser/base/content/aboutHome.css +++ b/browser/base/content/aboutHome.css @@ -95,17 +95,21 @@ a:hover { max-width: 1830px; margin: 0 auto; } @media all and (max-height: 700px) { #searchContainer { height: 20% } } -@media all and (max-height: 450px) { +@media all and (max-height: 500px) { + #searchContainer { height: 25% } +} + +@media all and (max-height: 370px) { #searchContainer { height: 30% } } #searchLogoContainer { display: table-cell; width: 30%; text-align: end; line-height: 32px; @@ -274,20 +278,20 @@ body[dir=rtl] #searchSubmit:active { content: url("chrome://browser/content/aboutHome-snippet2.png"); } #sessionRestoreContainer { padding-top: 1.5%; text-align: center; } -@media all and (max-height: 370px) { +@media all and (max-height: 500px) { #sessionRestoreContainer { position: relative; - top: -5px; + top: -15px; padding-top: 0; } } #restorePreviousSession { padding: 10px; border: 0; border-radius: 4px; @@ -355,8 +359,14 @@ body[dir=rtl] #restorePreviousSession::b #bottomSection { position: absolute; color: rgb(150,150,150); font-size: .8em; width: 100%; text-align: center; bottom: 2%; } + +@media all and (max-height: 370px) { + #bottomSection { + visibility: hidden; + } +}
--- a/browser/base/content/tabview/tabitems.js +++ b/browser/base/content/tabview/tabitems.js @@ -537,16 +537,18 @@ TabItem.prototype = Utils.extend(new Ite // don't allow zoom in if its group is hidden if (this.parent && this.parent.hidden) return; let self = this; let $tabEl = this.$container; let $canvas = this.$canvas; + hideSearch(); + UI.setActive(this); TabItems._update(this.tab, {force: true}); // Zoom in! let tab = this.tab; function onZoomDone() { $canvas.css({ '-moz-transform': null });
--- a/browser/base/content/tabview/ui.js +++ b/browser/base/content/tabview/ui.js @@ -708,26 +708,24 @@ let UI = { self._privateBrowsing.wasInTabView = self.isTabViewVisible(); if (self.isTabViewVisible()) self.goToTab(gBrowser.selectedTab); } } else if (topic == "private-browsing-change-granted") { if (data == "enter" || data == "exit") { hideSearch(); self._privateBrowsing.transitionMode = data; - self.storageBusy(); } } else if (topic == "private-browsing-transition-complete") { // We use .transitionMode here, as aData is empty. if (self._privateBrowsing.transitionMode == "exit" && self._privateBrowsing.wasInTabView) self.showTabView(false); self._privateBrowsing.transitionMode = ""; - self.storageReady(); } } Services.obs.addObserver(pbObserver, "private-browsing", false); Services.obs.addObserver(pbObserver, "private-browsing-change-granted", false); Services.obs.addObserver(pbObserver, "private-browsing-transition-complete", false); this._cleanupFunctions.push(function() { @@ -864,18 +862,22 @@ let UI = { // ---------- // Function: onTabSelect // Called when the user switches from one tab to another outside of the TabView UI. onTabSelect: function UI_onTabSelect(tab) { this._currentTab = tab; if (this.isTabViewVisible()) { - if (!this.restoredClosedTab && this._lastOpenedTab == tab && - tab._tabViewTabItem) { + // We want to zoom in if: + // 1) we didn't just restore a tab via Ctrl+Shift+T + // 2) we're not in the middle of switching from/to private browsing + // 3) the currently selected tab is the last created tab and has a tabItem + if (!this.restoredClosedTab && !this._privateBrowsing.transitionMode && + this._lastOpenedTab == tab && tab._tabViewTabItem) { tab._tabViewTabItem.zoomIn(true); this._lastOpenedTab = null; return; } if (this._closedLastVisibleTab || (this._closedSelectedTabInTabView && !this.closedLastTabInTabView) || this.restoredClosedTab) { if (this.restoredClosedTab) { @@ -1125,28 +1127,36 @@ let UI = { self.ignoreKeypressForSearch = false; processBrowserKeys(event); return; } function getClosestTabBy(norm) { if (!self.getActiveTab()) return null; - let centers = - [[item.bounds.center(), item] - for each(item in TabItems.getItems()) if (!item.parent || !item.parent.hidden)]; - let myCenter = self.getActiveTab().bounds.center(); - let matches = centers - .filter(function(item){return norm(item[0], myCenter)}) - .sort(function(a,b){ - return myCenter.distance(a[0]) - myCenter.distance(b[0]); - }); - if (matches.length > 0) - return matches[0][1]; - return null; + + let activeTab = self.getActiveTab(); + let activeTabGroup = activeTab.parent; + let myCenter = activeTab.bounds.center(); + let match; + + TabItems.getItems().forEach(function (item) { + if (!item.parent.hidden && + (!activeTabGroup.expanded || activeTabGroup.id == item.parent.id)) { + let itemCenter = item.bounds.center(); + + if (norm(itemCenter, myCenter)) { + let itemDist = myCenter.distance(itemCenter); + if (!match || match[0] > itemDist) + match = [itemDist, item]; + } + } + }); + + return match && match[1]; } let preventDefault = true; let activeTab; let norm = null; switch (event.keyCode) { case KeyEvent.DOM_VK_RIGHT: norm = function(a, me){return a.x > me.x}; @@ -1497,17 +1507,17 @@ let UI = { if (isSearchEnabled()) { let matcher = createSearchTabMacher(); let matches = matcher.matched(); if (matches.length > 0) { matches[0].zoomIn(); zoomedIn = true; } - hideSearch(null); + hideSearch(); } if (!zoomedIn) { let unhiddenGroups = GroupItems.groupItems.filter(function(groupItem) { return (!groupItem.hidden && groupItem.getChildren().length > 0); }); // no pinned tabs and no visible groups: open a new group. open a blank // tab and return @@ -1608,21 +1618,25 @@ let UI = { }, // ---------- // Function: getFavIconUrlForTab // Gets fav icon url for the given xul:tab. getFavIconUrlForTab: function UI_getFavIconUrlForTab(tab) { let url; - // use the tab image if it doesn't start with http e.g. data:image/png, chrome:// - if (tab.image && !(/^https?:/.test(tab.image))) - url = tab.image; - else + if (tab.image) { + // if starts with http/https, fetch icon from favicon service via the moz-anno protocal + if (/^https?:/.test(tab.image)) + url = gFavIconService.getFaviconLinkForIcon(gWindow.makeURI(tab.image)).spec; + else + url = tab.image; + } else { url = gFavIconService.getFaviconImageForPage(tab.linkedBrowser.currentURI).spec; + } return url; }, // ---------- // Function: notifySessionRestoreEnabled // Notify the user that session restore has been automatically enabled // by showing a banner that expects no user interaction. It fades out after
--- a/browser/base/content/test/tabview/Makefile.in +++ b/browser/base/content/test/tabview/Makefile.in @@ -115,16 +115,17 @@ include $(topsrcdir)/config/rules.mk browser_tabview_bug626525.js \ browser_tabview_bug626791.js \ browser_tabview_bug627239.js \ browser_tabview_bug627288.js \ browser_tabview_bug627736.js \ browser_tabview_bug628061.js \ browser_tabview_bug628165.js \ browser_tabview_bug628270.js \ + browser_tabview_bug628887.js \ browser_tabview_bug629189.js \ browser_tabview_bug629195.js \ browser_tabview_bug630102.js \ browser_tabview_bug630157.js \ browser_tabview_bug631662.js \ browser_tabview_bug631752.js \ browser_tabview_bug633788.js \ browser_tabview_bug634077.js \ @@ -149,16 +150,18 @@ include $(topsrcdir)/config/rules.mk browser_tabview_bug656778.js \ browser_tabview_bug656913.js \ browser_tabview_bug662266.js \ browser_tabview_bug663421.js \ browser_tabview_bug665502.js \ browser_tabview_bug669694.js \ browser_tabview_bug673196.js \ browser_tabview_bug673729.js \ + browser_tabview_bug679853.js \ + browser_tabview_bug681599.js \ browser_tabview_click_group.js \ browser_tabview_dragdrop.js \ browser_tabview_exit_button.js \ browser_tabview_expander.js \ browser_tabview_firstrun_pref.js \ browser_tabview_group.js \ browser_tabview_launch.js \ browser_tabview_multiwindow_search.js \
--- a/browser/base/content/test/tabview/browser_tabview_bug600645.js +++ b/browser/base/content/test/tabview/browser_tabview_bug600645.js @@ -35,18 +35,28 @@ function onTabViewWindowLoaded() { let errorHandler = function(event) { newTab.removeEventListener("error", errorHandler, false); // since the browser code and test code are invoked when an error event is // fired, a delay is used here to avoid the test code run before the browser // code. executeSoon(function() { - is($icon.attr("src"), fi.defaultFavicon.spec, - "The icon is showing the default fav icon"); + let iconSrc = $icon.attr("src"); + let hasData = true; + try { + fi.getFaviconDataAsDataURL(iconSrc); + } catch(e) { + hasData = false; + } + ok(!hasData, "The icon src doesn't return any data"); + // with moz-anno:favicon automatically redirects to the default favIcon + // if the given url is invalid + ok(/^moz-anno:favicon:/.test(iconSrc), + "The icon url starts with moz-anno:favicon so the default fav icon would be displayed"); // clean up gBrowser.removeTab(newTab); let endGame = function() { window.removeEventListener("tabviewhidden", endGame, false); ok(!TabView.isVisible(), "Tab View is hidden"); finish();
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/tabview/browser_tabview_bug628887.js @@ -0,0 +1,50 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function test() { + waitForExplicitFinish(); + + newWindowWithTabView(function(win) { + registerCleanupFunction(function() win.close()); + + let cw = win.TabView.getContentWindow(); + let groupItemOne = cw.GroupItems.groupItems[0]; + + let groupItemTwo = createGroupItemWithBlankTabs(win, 100, 100, 40, 2); + ok(groupItemTwo.isStacked(), "groupItem is now stacked"); + + is(win.gBrowser.tabs.length, 3, "There are three tabs"); + + // the focus should remain within the group after it's expanded + groupItemTwo.addSubscriber("expanded", function onExpanded() { + groupItemTwo.removeSubscriber("expanded", onExpanded); + + ok(groupItemTwo.expanded, "groupItemTwo is expanded"); + is(cw.UI.getActiveTab(), groupItemTwo.getChild(0), + "The first tab item in group item two is active in expanded mode"); + + EventUtils.synthesizeKey("VK_DOWN", {}, cw); + is(cw.UI.getActiveTab(), groupItemTwo.getChild(0), + "The first tab item is still active after pressing down key"); + + // the focus should goes to other group if the down arrow is pressed + groupItemTwo.addSubscriber("collapsed", function onExpanded() { + groupItemTwo.removeSubscriber("collapsed", onExpanded); + + ok(!groupItemTwo.expanded, "groupItemTwo is not expanded"); + is(cw.UI.getActiveTab(), groupItemTwo.getChild(0), + "The first tab item is active in group item two in collapsed mode"); + + EventUtils.synthesizeKey("VK_DOWN", {}, cw); + is(cw.UI.getActiveTab(), groupItemOne.getChild(0), + "The first tab item in group item one is active after pressing down key"); + + finish(); + }); + + groupItemTwo.collapse(); + }); + + groupItemTwo.expand(); + }); +}
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/tabview/browser_tabview_bug679853.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function test() { + waitForExplicitFinish(); + + // clean up after ourselves + registerCleanupFunction(function () { + while (gBrowser.tabs.length > 1) + gBrowser.removeTab(gBrowser.tabs[1]); + + hideTabView(); + }); + + // select the new tab + gBrowser.selectedTab = gBrowser.addTab(); + + showTabView(function () { + // enter private browsing mode + togglePrivateBrowsing(function () { + ok(!TabView.isVisible(), "tabview is hidden"); + + showTabView(function () { + // leave private browsing mode + togglePrivateBrowsing(function () { + ok(TabView.isVisible(), "tabview is visible"); + hideTabView(finish); + }); + }); + }); + }); +}
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/tabview/browser_tabview_bug681599.js @@ -0,0 +1,31 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function test() { + waitForExplicitFinish(); + + showTabView(function() { + let cw = TabView.getContentWindow(); + + registerCleanupFunction(function () { + while (gBrowser.tabs.length > 1) + gBrowser.removeTab(gBrowser.tabs[1]); + hideTabView(); + }) + + whenSearchIsEnabled(function() { + ok(cw.isSearchEnabled(), "The search is enabled before creating a new tab"); + + whenTabViewIsHidden(function() { + showTabView(function() { + ok(!cw.isSearchEnabled(), "The search is disabled when entering Tabview"); + + hideTabView(finish); + }) + }); + EventUtils.synthesizeKey("t", { accelKey: true }, cw); + }); + + EventUtils.synthesizeKey("VK_SLASH", {}, cw); + }); +}
new file mode 100644 --- /dev/null +++ b/build/autoconf/gcc-pr49911.m4 @@ -0,0 +1,67 @@ +dnl Check if the compiler is gcc and has PR49911. If so +dnl disable vrp. + +AC_DEFUN([MOZ_GCC_PR49911], +[ +if test "$GNU_CC"; then + +AC_MSG_CHECKING(for gcc PR49911) +ac_have_gcc_pr49911="no" +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + +_SAVE_CXXFLAGS=$CXXFLAGS +CXXFLAGS="-O2" +AC_TRY_RUN([ +extern "C" void abort(void); +typedef enum { +eax, ecx, edx, ebx, esp, ebp, +esi, edi } +RegisterID; +union StateRemat { + RegisterID reg_; + int offset_; +}; +static StateRemat FromRegister(RegisterID reg) { + StateRemat sr; + sr.reg_ = reg; + return sr; +} +static StateRemat FromAddress3(int address) { + StateRemat sr; + sr.offset_ = address; + if (address < 46 && address >= 0) { + abort(); + } + return sr; +} +struct FrameState { + StateRemat dataRematInfo2(bool y, int z) { + if (y) return FromRegister(RegisterID(1)); + return FromAddress3(z); + } +}; +FrameState frame; +StateRemat x; +__attribute__((noinline)) void jsop_setelem(bool y, int z) { + x = frame.dataRematInfo2(y, z); +} +int main(void) { + jsop_setelem(0, 47); +} +], true, + ac_have_gcc_pr49911="yes", + true) +CXXFLAGS="$_SAVE_CXXFLAGS" + +AC_LANG_RESTORE + +if test "$ac_have_gcc_pr49911" == "yes"; then + AC_MSG_RESULT(yes) + CFLAGS="$CFLAGS -fno-tree-vrp" + CXXFLAGS="$CXXFLAGS -fno-tree-vrp" +else + AC_MSG_RESULT(no) +fi +fi +])
--- a/build/mobile/devicemanagerADB.py +++ b/build/mobile/devicemanagerADB.py @@ -8,16 +8,17 @@ class DeviceManagerADB(DeviceManager): def __init__(self, host = None, port = 20701, retrylimit = 5, packageName = None): self.host = host self.port = port self.retrylimit = retrylimit self.retries = 0 self._sock = None self.useRunAs = False + self.packageName = None if packageName == None: if os.getenv('USER'): packageName = 'org.mozilla.fennec_' + os.getenv('USER') else: packageName = 'org.mozilla.fennec_' self.Init(packageName) def Init(self, packageName):
--- a/chrome/src/nsChromeProtocolHandler.cpp +++ b/chrome/src/nsChromeProtocolHandler.cpp @@ -64,24 +64,16 @@ #include "nsIServiceManager.h" #include "nsIStandardURL.h" #include "nsIStreamListener.h" #include "nsNetUtil.h" #include "nsXPIDLString.h" #include "nsString.h" #include "prlog.h" -#ifdef MOZ_XUL -#include "nsIXULPrototypeCache.h" -#endif - -//---------------------------------------------------------------------- - -static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID); - //////////////////////////////////////////////////////////////////////////////// NS_IMPL_THREADSAFE_ISUPPORTS2(nsChromeProtocolHandler, nsIProtocolHandler, nsISupportsWeakReference) //////////////////////////////////////////////////////////////////////////////// // nsIProtocolHandler methods:
--- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -624,17 +624,16 @@ MOZILLA_OFFICIAL = @MOZILLA_OFFICIAL@ # Win32 options MOZ_BROWSE_INFO = @MOZ_BROWSE_INFO@ MOZ_TOOLS_DIR = @MOZ_TOOLS_DIR@ MOZ_QUANTIFY = @MOZ_QUANTIFY@ MSMANIFEST_TOOL = @MSMANIFEST_TOOL@ WIN32_REDIST_DIR = @WIN32_REDIST_DIR@ MOZ_MEMORY_LDFLAGS = @MOZ_MEMORY_LDFLAGS@ WIN32_CRT_LIBS = @WIN32_CRT_LIBS@ -MOZ_CRT_CPU_ARCH = @MOZ_CRT_CPU_ARCH@ # This is for custom CRT building ifdef MOZ_MEMORY DLLFLAGS = @DLLFLAGS@ endif # Codesighs tools option, enables win32 mapfiles. MOZ_MAPINFO = @MOZ_MAPINFO@
--- a/config/rules.mk +++ b/config/rules.mk @@ -676,16 +676,22 @@ IFLAGS2 = -m 755 endif ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) OUTOPTION = -Fo# eol else OUTOPTION = -o # eol endif # WINNT && !GNU_CC +ifneq (,$(filter ml%,$(AS))) +ASOUTOPTION = -Fo# eol +else +ASOUTOPTION = -o # eol +endif + ifeq (,$(CROSS_COMPILE)) HOST_OUTOPTION = $(OUTOPTION) else HOST_OUTOPTION = -o # eol endif ################################################################################ # SUBMAKEFILES: List of Makefiles for next level down. @@ -1281,17 +1287,17 @@ moc_%.cpp: %.h $(GLOBAL_DEPS) moc_%.cc: %.cc $(GLOBAL_DEPS) $(REPORT_BUILD) $(ELOG) $(MOC) $(DEFINES) $(ACDEFINES) $(_VPATH_SRCS:.cc=.h) $(OUTOPTION)$@ ifdef ASFILES # The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept # a '-c' flag. %.$(OBJ_SUFFIX): %.$(ASM_SUFFIX) $(GLOBAL_DEPS) - $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS) + $(AS) $(ASOUTOPTION)$@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS) endif %.$(OBJ_SUFFIX): %.S $(GLOBAL_DEPS) $(AS) -o $@ $(ASFLAGS) -c $< %:: %.cpp $(GLOBAL_DEPS) @$(MAKE_DEPS_AUTO_CXX) $(CCC) $(OUTOPTION)$@ $(CXXFLAGS) $(_VPATH_SRCS) $(LDFLAGS)
--- a/configure.in +++ b/configure.in @@ -125,17 +125,17 @@ GTK2_VERSION=2.10.0 WINDRES_VERSION=2.14.90 W32API_VERSION=3.14 GNOMEVFS_VERSION=2.0 GNOMEUI_VERSION=2.2.0 GCONF_VERSION=1.2.1 GIO_VERSION=2.18 STARTUP_NOTIFICATION_VERSION=0.8 DBUS_VERSION=0.60 -SQLITE_VERSION=3.7.5 +SQLITE_VERSION=3.7.7.1 LIBNOTIFY_VERSION=0.4 MSMANIFEST_TOOL= dnl Set various checks dnl ======================================================== MISSING_X= AC_PROG_AWK @@ -2106,18 +2106,16 @@ case "$target" in AC_TRY_LINK(,[return 0;], ac_cv_have_framework_exceptionhandling="yes", ac_cv_have_framework_exceptionhandling="no") AC_MSG_RESULT([$ac_cv_have_framework_exceptionhandling]) if test "$ac_cv_have_framework_exceptionhandling" = "yes"; then MOZ_DEBUG_LDFLAGS="$MOZ_DEBUG_LDFLAGS -framework ExceptionHandling"; fi LDFLAGS=$_SAVE_LDFLAGS - # Debug builds should always have frame pointers - MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer" if test "x$lto_is_enabled" = "xyes"; then echo "Skipping -dead_strip because lto is enabled." dnl DTrace and -dead_strip don't interact well. See bug 403132. dnl =================================================================== elif test "x$enable_dtrace" = "xyes"; then echo "Skipping -dead_strip because DTrace is enabled. See bug 403132." else @@ -2194,18 +2192,16 @@ ia64*-hpux*) MOZ_GFX_OPTIMIZE_MOBILE=1 # If we're building with --enable-profiling, we need a frame pointer. if test -z "$MOZ_PROFILING"; then MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fomit-frame-pointer" else MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fno-omit-frame-pointer" fi - # Debug builds should always have frame pointers - MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer" ;; *-*linux*) # Note: both GNU_CC and INTEL_CC are set when using Intel's C compiler. # Similarly for GNU_CXX and INTEL_CXX. if test "$INTEL_CC" -o "$INTEL_CXX"; then # -Os has been broken on Intel's C/C++ compilers for quite a # while; Intel recommends against using it. @@ -2221,18 +2217,17 @@ ia64*-hpux*) # If we're building with --enable-profiling, we need a frame pointer. if test -z "$MOZ_PROFILING"; then MOZ_FRAMEPTR_FLAGS="-fomit-frame-pointer" else MOZ_FRAMEPTR_FLAGS="-fno-omit-frame-pointer" fi MOZ_PGO_OPTIMIZE_FLAGS="-O3 $MOZ_FRAMEPTR_FLAGS" MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks $MOZ_OPTIMIZE_SIZE_TWEAK $MOZ_FRAMEPTR_FLAGS" - # Debug builds should always have frame pointers - MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer" + MOZ_DEBUG_FLAGS="-g" fi TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"' MOZ_MEMORY=1 case "${target_cpu}" in alpha*) @@ -2315,18 +2310,17 @@ ia64*-hpux*) _DEFINES_CXXFLAGS='-FI $(DEPTH)/dist/include/mozilla-config.h -DMOZILLA_CLIENT' CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" CXXFLAGS="$CXXFLAGS -wd4800" # disable warning "forcing value to bool" # make 'foo == bar;' error out CFLAGS="$CFLAGS -we4553" CXXFLAGS="$CXXFLAGS -we4553" LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib" - # Debug builds should always have frame pointers - MOZ_DEBUG_FLAGS='-Zi -Oy-' + MOZ_DEBUG_FLAGS='-Zi' MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV' WARNINGS_AS_ERRORS='-WX' # If we're building with --enable-profiling, we need -Oy-, which forces a frame pointer. if test -z "$MOZ_PROFILING"; then MOZ_OPTIMIZE_FLAGS='-O1' else MOZ_OPTIMIZE_FLAGS='-O1 -Oy-' fi @@ -3172,16 +3166,18 @@ fi # GNU_CC # visibility hidden flag for Sun Studio on Solaris if test "$SOLARIS_SUNPRO_CC"; then VISIBILITY_FLAGS='-xldscope=hidden' fi # Sun Studio on Solaris AC_SUBST(WRAP_SYSTEM_INCLUDES) AC_SUBST(VISIBILITY_FLAGS) +MOZ_GCC_PR49911 + dnl Check for __force_align_arg_pointer__ for SSE2 on gcc dnl ======================================================== if test "$GNU_CC"; then CFLAGS_save="${CFLAGS}" CFLAGS="${CFLAGS} -Werror" AC_CACHE_CHECK(for __force_align_arg_pointer__ attribute, ac_cv_force_align_arg_pointer, [AC_TRY_COMPILE([__attribute__ ((__force_align_arg_pointer__)) void test() {}],
--- a/content/base/public/nsContentCID.h +++ b/content/base/public/nsContentCID.h @@ -181,20 +181,16 @@ // {1abdcc96-1dd2-11b2-b520-f8f59cdd67bc} #define NS_XULTREEBUILDER_CID \ { 0x1abdcc96, 0x1dd2, 0x11b2, { 0xb5, 0x20, 0xf8, 0xf5, 0x9c, 0xdd, 0x67, 0xbc } } // {541AFCB2-A9A3-11d2-8EC5-00805F29F370} #define NS_XULDOCUMENT_CID \ { 0x541afcb2, 0xa9a3, 0x11d2, { 0x8e, 0xc5, 0x0, 0x80, 0x5f, 0x29, 0xf3, 0x70 } } -// {3A0A0FC1-8349-11d3-BE47-00104BDE6048} -#define NS_XULPROTOTYPECACHE_CID \ -{ 0x3a0a0fc1, 0x8349, 0x11d3, { 0xbe, 0x47, 0x0, 0x10, 0x4b, 0xde, 0x60, 0x48 } } - // {a6cf9126-15b3-11d2-932e-00805f8add32} #define NS_RANGEUTILS_CID \ { 0xa6cf9126, 0x15b3, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32 } } #define NS_SVGDOCUMENT_CID \ { /* b7f44954-1dd1-11b2-8c2e-c2feab4186bc */ \ 0xb7f44954, 0x11d1, 0x11b2, \ {0x8c, 0x2e, 0xc2, 0xfe, 0xab, 0x41, 0x86, 0xbc}}
--- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -44,16 +44,17 @@ #include "nsTObserverArray.h" #include "nsINodeInfo.h" #include "nsCOMPtr.h" #include "nsWrapperCache.h" #include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT #include "nsDOMError.h" #include "nsDOMString.h" #include "jspubtd.h" +#include "nsDOMMemoryReporter.h" class nsIContent; class nsIDocument; class nsIDOMEvent; class nsIDOMNode; class nsIDOMNodeList; class nsINodeList; class nsIPresShell; @@ -276,33 +277,31 @@ private: #define DOM_USER_DATA 1 #define DOM_USER_DATA_HANDLER 2 #ifdef MOZ_SMIL #define SMIL_MAPPED_ATTR_ANIMVAL 3 #endif // MOZ_SMIL // IID for the nsINode interface #define NS_INODE_IID \ -{ 0xcdab747e, 0xa58f, 0x4b96, \ - { 0x8b, 0xae, 0x9d, 0x53, 0xe0, 0xa7, 0x8a, 0x74 } } +{ 0x5572c8a9, 0xbda9, 0x4b78, \ + { 0xb4, 0x1a, 0xdb, 0x1a, 0x83, 0xef, 0x53, 0x7e } } /** * An internal interface that abstracts some DOMNode-related parts that both * nsIContent and nsIDocument share. An instance of this interface has a list * of nsIContent children and provides access to them. */ class nsINode : public nsIDOMEventTarget, public nsWrapperCache { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODE_IID) - virtual PRInt64 SizeOf() const { - return sizeof(*this); - } + NS_DECL_DOM_MEMORY_REPORTER_SIZEOF friend class nsNodeUtils; friend class nsNodeWeakReference; friend class nsNodeSupportsWeakRefTearoff; friend class nsAttrAndChildArray; #ifdef MOZILLA_INTERNAL_API nsINode(already_AddRefed<nsINodeInfo> aNodeInfo) @@ -929,52 +928,16 @@ public: /** * Implementation is in nsIDocument.h, because it needs to cast from * nsIDocument* to nsINode*. */ nsIDocument* GetOwnerDocument() const; /** - * Iterator that can be used to easily iterate over the children. This has - * the same restrictions on its use as GetChildArray does. - */ - class ChildIterator { - public: - ChildIterator(const nsINode* aNode) { Init(aNode); } - ChildIterator(const nsINode* aNode, PRUint32 aOffset) { - Init(aNode); - Advance(aOffset); - } - ~ChildIterator() { - NS_ASSERTION(!mGuard.Mutated(0), "Unexpected mutations happened"); - } - - PRBool IsDone() const { return mCur == mEnd; } - operator nsIContent*() const { return *mCur; } - void Next() { NS_PRECONDITION(mCur != mEnd, "Check IsDone"); ++mCur; } - void Advance(PRUint32 aOffset) { - NS_ASSERTION(mCur + aOffset <= mEnd, "Unexpected offset"); - mCur += aOffset; - } - private: - void Init(const nsINode* aNode) { - NS_PRECONDITION(aNode, "Must have node here!"); - PRUint32 childCount; - mCur = aNode->GetChildArray(&childCount); - mEnd = mCur + childCount; - } -#ifdef DEBUG - nsMutationGuard mGuard; -#endif - nsIContent* const * mCur; - nsIContent* const * mEnd; - }; - - /** * The default script type (language) ID for this node. * All nodes must support fetching the default script language. */ virtual PRUint32 GetScriptTypeID() const { return nsIProgrammingLanguage::JAVASCRIPT; } /** * Not all nodes support setting a new default language.
--- a/content/base/src/nsContentAreaDragDrop.cpp +++ b/content/base/src/nsContentAreaDragDrop.cpp @@ -41,17 +41,16 @@ // Local Includes #include "nsContentAreaDragDrop.h" // Helper Classes #include "nsString.h" // Interfaces needed to be included #include "nsCopySupport.h" -#include "nsIDOMNSUIEvent.h" #include "nsIDOMUIEvent.h" #include "nsISelection.h" #include "nsIDOMNode.h" #include "nsIDOMNodeList.h" #include "nsIDOMEvent.h" #include "nsIDOMNSEvent.h" #include "nsIDOMDragEvent.h" #include "nsPIDOMWindow.h"
--- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -136,17 +136,16 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_ #include "nsContentCreatorFunctions.h" #include "nsGUIEvent.h" #include "nsMutationEvent.h" #include "nsIMEStateManager.h" #include "nsContentErrors.h" #include "nsUnicharUtilCIID.h" #include "nsCompressedCharMap.h" #include "nsINativeKeyBindings.h" -#include "nsIDOMNSUIEvent.h" #include "nsIDOMNSEvent.h" #include "nsIPrivateDOMEvent.h" #include "nsXULPopupManager.h" #include "nsIPermissionManager.h" #include "nsIContentPrefService.h" #include "nsIScriptObjectPrincipal.h" #include "nsIRunnable.h" #include "nsDOMJSUtils.h" @@ -4132,23 +4131,22 @@ nsContentUtils::GetNativeEvent(nsIDOMEve } //static PRBool nsContentUtils::DOMEventToNativeKeyEvent(nsIDOMKeyEvent* aKeyEvent, nsNativeKeyEvent* aNativeEvent, PRBool aGetCharCode) { - nsCOMPtr<nsIDOMNSUIEvent> uievent = do_QueryInterface(aKeyEvent); + nsCOMPtr<nsIDOMNSEvent> nsevent = do_QueryInterface(aKeyEvent); PRBool defaultPrevented; - uievent->GetPreventDefault(&defaultPrevented); + nsevent->GetPreventDefault(&defaultPrevented); if (defaultPrevented) return PR_FALSE; - nsCOMPtr<nsIDOMNSEvent> nsevent = do_QueryInterface(aKeyEvent); PRBool trusted = PR_FALSE; nsevent->GetIsTrusted(&trusted); if (!trusted) return PR_FALSE; if (aGetCharCode) { aKeyEvent->GetCharCode(&aNativeEvent->charCode); } else {
--- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -8450,17 +8450,17 @@ nsDocument::CaretPositionFromPoint(float *aCaretPos = new nsDOMCaretPosition(node, offset); NS_ADDREF(*aCaretPos); return NS_OK; } PRInt64 nsIDocument::SizeOf() const { - PRInt64 size = sizeof(*this); + PRInt64 size = MemoryReporter::GetBasicSize<nsIDocument, nsINode>(this); for (nsIContent* node = GetFirstChild(); node; node = node->GetNextNode(this)) { size += node->SizeOf(); } return size; }
--- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -3636,17 +3636,17 @@ nsGenericElement::DispatchClickEvent(nsP PRUint32 clickCount = 1; float pressure = 0; PRUint16 inputSource = 0; if (aSourceEvent->eventStructType == NS_MOUSE_EVENT) { clickCount = static_cast<nsMouseEvent*>(aSourceEvent)->clickCount; pressure = static_cast<nsMouseEvent*>(aSourceEvent)->pressure; inputSource = static_cast<nsMouseEvent*>(aSourceEvent)->inputSource; } else if (aSourceEvent->eventStructType == NS_KEY_EVENT) { - inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_KEYBOARD; + inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD; } event.pressure = pressure; event.clickCount = clickCount; event.inputSource = inputSource; event.isShift = aSourceEvent->isShift; event.isControl = aSourceEvent->isControl; event.isAlt = aSourceEvent->isAlt; event.isMeta = aSourceEvent->isMeta; @@ -5398,16 +5398,30 @@ nsNSElementTearoff::MozMatchesSelector(c nsresult rv; *aReturn = mContent->MozMatchesSelector(aSelector, &rv); return rv; } PRInt64 +nsINode::SizeOf() const +{ + PRInt64 size = sizeof(*this); + + nsEventListenerManager* elm = + const_cast<nsINode*>(this)->GetListenerManager(PR_FALSE); + if (elm) { + size += elm->SizeOf(); + } + + return size; +} + +PRInt64 nsGenericElement::SizeOf() const { PRInt64 size = MemoryReporter::GetBasicSize<nsGenericElement, Element>(this); size -= sizeof(mAttrsAndChildren); size += mAttrsAndChildren.SizeOf(); return size;
--- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -487,17 +487,19 @@ protected: PRBool ValidateFaceEnum(WebGLenum face, const char *info); PRBool ValidateBufferUsageEnum(WebGLenum target, const char *info); PRBool ValidateTexFormatAndType(WebGLenum format, WebGLenum type, int jsArrayType, PRUint32 *texelSize, const char *info); PRBool ValidateDrawModeEnum(WebGLenum mode, const char *info); PRBool ValidateAttribIndex(WebGLuint index, const char *info); PRBool ValidateStencilParamsForDrawCall(); - bool ValidateGLSLIdentifier(const nsAString& name, const char *info); + bool ValidateGLSLVariableName(const nsAString& name, const char *info); + bool ValidateGLSLCharacter(PRUnichar c); + bool ValidateGLSLString(const nsAString& string, const char *info); static PRUint32 GetTexelSize(WebGLenum format, WebGLenum type); void Invalidate(); void DestroyResourcesAndContext(); void MakeContextCurrent() { gl->MakeCurrent(); }
--- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -57,16 +57,17 @@ #include "jstypedarray.h" #if defined(USE_ANGLE) // shader translator #include "angle/ShaderLang.h" #endif #include "WebGLTexelConversions.h" +#include "WebGLValidateStrings.h" using namespace mozilla; static PRBool BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *unitSize); static WebGLenum InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2); /* Helper macros for when we're just wrapping a gl method, so that * we can avoid having to type this 500 times. Note that these MUST @@ -177,18 +178,18 @@ WebGLContext::AttachShader(nsIWebGLProgr NS_IMETHODIMP WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, const nsAString& name) { WebGLuint progname; if (!GetGLName<WebGLProgram>("bindAttribLocation: program", pobj, &progname)) return NS_OK; - if (name.IsEmpty()) - return ErrorInvalidValue("BindAttribLocation: name can't be null or empty"); + if (!ValidateGLSLVariableName(name, "bindAttribLocation")) + return NS_OK; if (!ValidateAttribIndex(location, "bindAttribLocation")) return NS_OK; MakeContextCurrent(); gl->fBindAttribLocation(progname, location, NS_LossyConvertUTF16toASCII(name).get()); @@ -1834,17 +1835,17 @@ WebGLContext::GetAttribLocation(nsIWebGL PRInt32 *retval) { *retval = 0; WebGLuint progname; if (!GetGLName<WebGLProgram>("getAttribLocation: program", pobj, &progname)) return NS_OK; - if (!ValidateGLSLIdentifier(name, "getAttribLocation")) + if (!ValidateGLSLVariableName(name, "getAttribLocation")) return NS_OK; MakeContextCurrent(); *retval = gl->fGetAttribLocation(progname, NS_LossyConvertUTF16toASCII(name).get()); return NS_OK; } NS_IMETHODIMP @@ -2659,17 +2660,17 @@ WebGLContext::GetUniformLocation(nsIWebG { *retval = nsnull; WebGLuint progname; WebGLProgram *prog; if (!GetConcreteObjectAndGLName("getUniformLocation: program", pobj, &prog, &progname)) return NS_OK; - if (!ValidateGLSLIdentifier(name, "getUniformLocation")) + if (!ValidateGLSLVariableName(name, "getUniformLocation")) return NS_OK; MakeContextCurrent(); GLint intlocation = gl->fGetUniformLocation(progname, NS_LossyConvertUTF16toASCII(name).get()); nsRefPtr<nsIWebGLUniformLocation> loc = prog->GetUniformLocationObject(intlocation); *retval = loc.forget().get(); @@ -3161,18 +3162,18 @@ WebGLContext::RenderbufferStorage(WebGLe { if (!mBoundRenderbuffer || !mBoundRenderbuffer->GLName()) return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0"); if (target != LOCAL_GL_RENDERBUFFER) return ErrorInvalidEnumInfo("renderbufferStorage: target", target); - if (width <= 0 || height <= 0) - return ErrorInvalidValue("renderbufferStorage: width and height must be > 0"); + if (width < 0 || height < 0) + return ErrorInvalidValue("renderbufferStorage: width and height must be >= 0"); if (!mBoundRenderbuffer || !mBoundRenderbuffer->GLName()) return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0"); // certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL WebGLenum internalformatForGL = internalformat; switch (internalformat) { @@ -4126,17 +4127,20 @@ WebGLContext::GetShaderSource(nsIWebGLSh NS_IMETHODIMP WebGLContext::ShaderSource(nsIWebGLShader *sobj, const nsAString& source) { WebGLShader *shader; WebGLuint shadername; if (!GetConcreteObjectAndGLName("shaderSource: shader", sobj, &shader, &shadername)) return NS_OK; - + + if (!ValidateGLSLString(source, "shaderSource")) + return NS_OK; + const nsPromiseFlatString& flatSource = PromiseFlatString(source); if (!NS_IsAscii(flatSource.get())) return ErrorInvalidValue("shaderSource: non-ascii characters found in source"); const nsCString& sourceCString = NS_LossyConvertUTF16toASCII(flatSource); const PRUint32 maxSourceLength = (PRUint32(1)<<18) - 1;
--- a/content/canvas/src/WebGLContextValidate.cpp +++ b/content/canvas/src/WebGLContextValidate.cpp @@ -323,24 +323,41 @@ PRBool WebGLContext::ValidateDrawModeEnu case LOCAL_GL_LINES: return PR_TRUE; default: ErrorInvalidEnumInfo(info, mode); return PR_FALSE; } } -bool WebGLContext::ValidateGLSLIdentifier(const nsAString& name, const char *info) +bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info) { - const PRUint32 maxSize = 4095; + const PRUint32 maxSize = 255; if (name.Length() > maxSize) { ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters", info, name.Length(), maxSize); return false; } + + if (!ValidateGLSLString(name, info)) { + return false; + } + + return true; +} + +bool WebGLContext::ValidateGLSLString(const nsAString& string, const char *info) +{ + for (PRUint32 i = 0; i < string.Length(); ++i) { + if (!ValidateGLSLCharacter(string.CharAt(i))) { + ErrorInvalidValue("%s: string contains the illegal character '%d'", info, string.CharAt(i)); + return false; + } + } + return true; } PRUint32 WebGLContext::GetTexelSize(WebGLenum format, WebGLenum type) { if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) { int multiplier = type == LOCAL_GL_FLOAT ? 4 : 1; switch (format) {
new file mode 100644 --- /dev/null +++ b/content/canvas/src/WebGLValidateStrings.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011 Mozilla Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WEBGLVALIDATESTRINGS_H_ +#define WEBGLVALIDATESTRINGS_H_ + +#include "WebGLContext.h" + +namespace mozilla { + +// The following function was taken from the WebKit WebGL implementation, +// which can be found here: +// http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp#L123 +/****** BEGIN CODE TAKEN FROM WEBKIT ******/ +bool WebGLContext::ValidateGLSLCharacter(PRUnichar c) +{ + // Printing characters are valid except " $ ` @ \ ' DEL. + if (c >= 32 && c <= 126 && + c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'') + { + return true; + } + + // Horizontal tab, line feed, vertical tab, form feed, carriage return are also valid. + if (c >= 9 && c <= 13) { + return true; + } + + return false; +} +/****** END CODE TAKEN FROM WEBKIT ******/ + +} // end namespace mozilla + +#endif // WEBGLVALIDATESTRINGS_H_
--- a/content/canvas/test/webgl/failing_tests_linux.txt +++ b/content/canvas/test/webgl/failing_tests_linux.txt @@ -8,17 +8,16 @@ conformance/shaders/glsl-features/../../ conformance/shaders/glsl-features/../../glsl-features.html?feature=abs-vert-vec4&refvs=shaders/glsl-features/abs-vec4-ref.vert&testvs=shaders/glsl-features/abs-vec4.vert conformance/shaders/glsl-features/../../glsl-features.html?feature=sign-frag-vec4&reffs=shaders/glsl-features/sign-vec4-ref.frag&testfs=shaders/glsl-features/sign-vec4.frag conformance/shaders/glsl-features/../../glsl-features.html?feature=sign-vert-vec4&refvs=shaders/glsl-features/sign-vec4-ref.vert&testvs=shaders/glsl-features/sign-vec4.vert conformance/gl-get-active-attribute.html conformance/gl-getshadersource.html conformance/gl-uniform-bool.html conformance/glsl-conformance.html conformance/glsl-long-variable-names.html -conformance/invalid-passed-params.html conformance/object-deletion-behaviour.html conformance/premultiplyalpha-test.html conformance/read-pixels-test.html conformance/uninitialized-test.html conformance/webgl-specific.html conformance/more/conformance/quickCheckAPI.html conformance/more/functions/copyTexImage2D.html conformance/more/functions/copyTexSubImage2D.html
--- a/content/canvas/test/webgl/failing_tests_mac.txt +++ b/content/canvas/test/webgl/failing_tests_mac.txt @@ -2,17 +2,16 @@ conformance/buffer-offscreen-test.html conformance/context-attributes-alpha-depth-stencil-antialias.html conformance/drawingbuffer-static-canvas-test.html conformance/drawingbuffer-test.html conformance/framebuffer-object-attachment.html conformance/gl-getshadersource.html conformance/gl-object-get-calls.html conformance/glsl-conformance.html conformance/glsl-long-variable-names.html -conformance/invalid-passed-params.html conformance/object-deletion-behaviour.html conformance/premultiplyalpha-test.html conformance/program-test.html conformance/read-pixels-test.html conformance/tex-input-validation.html conformance/texture-npot.html conformance/webgl-specific.html conformance/more/conformance/quickCheckAPI.html
--- a/content/canvas/test/webgl/failing_tests_windows.txt +++ b/content/canvas/test/webgl/failing_tests_windows.txt @@ -1,16 +1,15 @@ conformance/buffer-offscreen-test.html conformance/drawingbuffer-static-canvas-test.html conformance/drawingbuffer-test.html conformance/framebuffer-object-attachment.html conformance/gl-getshadersource.html conformance/glsl-conformance.html conformance/glsl-long-variable-names.html -conformance/invalid-passed-params.html conformance/object-deletion-behaviour.html conformance/premultiplyalpha-test.html conformance/read-pixels-test.html conformance/webgl-specific.html conformance/more/conformance/quickCheckAPI.html conformance/more/functions/copyTexImage2D.html conformance/more/functions/copyTexSubImage2D.html conformance/more/functions/deleteBufferBadArgs.html
--- a/content/events/src/nsDOMDragEvent.cpp +++ b/content/events/src/nsDOMDragEvent.cpp @@ -49,17 +49,17 @@ nsDOMDragEvent::nsDOMDragEvent(nsPresCon { if (aEvent) { mEventIsInternal = PR_FALSE; } else { mEventIsInternal = PR_TRUE; mEvent->time = PR_Now(); mEvent->refPoint.x = mEvent->refPoint.y = 0; - static_cast<nsMouseEvent*>(mEvent)->inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_UNKNOWN; + static_cast<nsMouseEvent*>(mEvent)->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN; } } nsDOMDragEvent::~nsDOMDragEvent() { if (mEventIsInternal) { if (mEvent->eventStructType == NS_DRAG_EVENT) delete static_cast<nsDragEvent*>(mEvent);
--- a/content/events/src/nsDOMKeyboardEvent.cpp +++ b/content/events/src/nsDOMKeyboardEvent.cpp @@ -139,18 +139,19 @@ nsDOMKeyboardEvent::GetKeyCode(PRUint32* default: *aKeyCode = 0; break; } return NS_OK; } -NS_IMETHODIMP -nsDOMKeyboardEvent::GetWhich(PRUint32* aWhich) +/* virtual */ +nsresult +nsDOMKeyboardEvent::Which(PRUint32* aWhich) { NS_ENSURE_ARG_POINTER(aWhich); switch (mEvent->message) { case NS_KEY_UP: case NS_KEY_DOWN: return GetKeyCode(aWhich); case NS_KEY_PRESS:
--- a/content/events/src/nsDOMKeyboardEvent.h +++ b/content/events/src/nsDOMKeyboardEvent.h @@ -52,14 +52,15 @@ public: NS_DECL_ISUPPORTS_INHERITED // nsIDOMKeyEvent Interface NS_DECL_NSIDOMKEYEVENT // Forward to base class NS_FORWARD_TO_NSDOMUIEVENT +protected: // Specific implementation for a keyboard event. - NS_IMETHOD GetWhich(PRUint32 *aWhich); + virtual nsresult Which(PRUint32* aWhich); }; #endif // nsDOMKeyboardEvent_h__
--- a/content/events/src/nsDOMMouseEvent.cpp +++ b/content/events/src/nsDOMMouseEvent.cpp @@ -54,17 +54,17 @@ nsDOMMouseEvent::nsDOMMouseEvent(nsPresC if (aEvent) { mEventIsInternal = PR_FALSE; } else { mEventIsInternal = PR_TRUE; mEvent->time = PR_Now(); mEvent->refPoint.x = mEvent->refPoint.y = 0; - static_cast<nsMouseEvent*>(mEvent)->inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_UNKNOWN; + static_cast<nsMouseEvent*>(mEvent)->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN; } switch (mEvent->eventStructType) { case NS_MOUSE_EVENT: NS_ASSERTION(static_cast<nsMouseEvent*>(mEvent)->reason != nsMouseEvent::eSynthesized, "Don't dispatch DOM events from synthesized mouse events"); @@ -93,17 +93,16 @@ nsDOMMouseEvent::~nsDOMMouseEvent() NS_IMPL_ADDREF_INHERITED(nsDOMMouseEvent, nsDOMUIEvent) NS_IMPL_RELEASE_INHERITED(nsDOMMouseEvent, nsDOMUIEvent) DOMCI_DATA(MouseEvent, nsDOMMouseEvent) NS_INTERFACE_MAP_BEGIN(nsDOMMouseEvent) NS_INTERFACE_MAP_ENTRY(nsIDOMMouseEvent) - NS_INTERFACE_MAP_ENTRY(nsIDOMNSMouseEvent) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MouseEvent) NS_INTERFACE_MAP_END_INHERITING(nsDOMUIEvent) NS_IMETHODIMP nsDOMMouseEvent::InitMouseEvent(const nsAString & aType, PRBool aCanBubble, PRBool aCancelable, nsIDOMWindow* aView, PRInt32 aDetail, PRInt32 aScreenX, PRInt32 aScreenY, PRInt32 aClientX, PRInt32 aClientY, PRBool aCtrlKey, PRBool aAltKey, PRBool aShiftKey, @@ -277,18 +276,19 @@ nsDOMMouseEvent::GetShiftKey(PRBool* aIs NS_IMETHODIMP nsDOMMouseEvent::GetMetaKey(PRBool* aIsDown) { NS_ENSURE_ARG_POINTER(aIsDown); *aIsDown = ((nsInputEvent*)mEvent)->isMeta; return NS_OK; } -NS_IMETHODIMP -nsDOMMouseEvent::GetWhich(PRUint32* aWhich) +/* virtual */ +nsresult +nsDOMMouseEvent::Which(PRUint32* aWhich) { NS_ENSURE_ARG_POINTER(aWhich); PRUint16 button; (void) GetButton(&button); *aWhich = button + 1; return NS_OK; }
--- a/content/events/src/nsDOMMouseEvent.h +++ b/content/events/src/nsDOMMouseEvent.h @@ -36,40 +36,37 @@ * * ***** END LICENSE BLOCK ***** */ #ifndef nsDOMMouseEvent_h__ #define nsDOMMouseEvent_h__ #include "nsIDOMMouseEvent.h" #include "nsDOMUIEvent.h" -#include "nsIDOMNSMouseEvent.h" class nsIContent; class nsEvent; class nsDOMMouseEvent : public nsDOMUIEvent, - public nsIDOMNSMouseEvent + public nsIDOMMouseEvent { public: nsDOMMouseEvent(nsPresContext* aPresContext, nsInputEvent* aEvent); virtual ~nsDOMMouseEvent(); NS_DECL_ISUPPORTS_INHERITED // nsIDOMMouseEvent Interface NS_DECL_NSIDOMMOUSEEVENT - // nsIDOMNSMouseEvent Interface - NS_DECL_NSIDOMNSMOUSEEVENT - // Forward to base class NS_FORWARD_TO_NSDOMUIEVENT +protected: // Specific implementation for a mouse event. - NS_IMETHOD GetWhich(PRUint32 *aWhich); + virtual nsresult Which(PRUint32* aWhich); }; #define NS_FORWARD_TO_NSDOMMOUSEEVENT \ NS_FORWARD_NSIDOMMOUSEEVENT(nsDOMMouseEvent::) \ NS_FORWARD_TO_NSDOMUIEVENT #endif // nsDOMMouseEvent_h__
--- a/content/events/src/nsDOMMouseScrollEvent.cpp +++ b/content/events/src/nsDOMMouseScrollEvent.cpp @@ -46,17 +46,17 @@ nsDOMMouseScrollEvent::nsDOMMouseScrollE new nsMouseScrollEvent(PR_FALSE, 0, nsnull)) { if (aEvent) { mEventIsInternal = PR_FALSE; } else { mEventIsInternal = PR_TRUE; mEvent->time = PR_Now(); mEvent->refPoint.x = mEvent->refPoint.y = 0; - static_cast<nsMouseEvent*>(mEvent)->inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_UNKNOWN; + static_cast<nsMouseEvent*>(mEvent)->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN; } if(mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) { nsMouseScrollEvent* mouseEvent = static_cast<nsMouseScrollEvent*>(mEvent); mDetail = mouseEvent->delta; } }
--- a/content/events/src/nsDOMSimpleGestureEvent.cpp +++ b/content/events/src/nsDOMSimpleGestureEvent.cpp @@ -46,17 +46,17 @@ nsDOMSimpleGestureEvent::nsDOMSimpleGest NS_ASSERTION(mEvent->eventStructType == NS_SIMPLE_GESTURE_EVENT, "event type mismatch"); if (aEvent) { mEventIsInternal = PR_FALSE; } else { mEventIsInternal = PR_TRUE; mEvent->time = PR_Now(); mEvent->refPoint.x = mEvent->refPoint.y = 0; - static_cast<nsMouseEvent*>(mEvent)->inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_UNKNOWN; + static_cast<nsMouseEvent*>(mEvent)->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN; } } nsDOMSimpleGestureEvent::~nsDOMSimpleGestureEvent() { if (mEventIsInternal) { delete static_cast<nsSimpleGestureEvent*>(mEvent); mEvent = nsnull;
--- a/content/events/src/nsDOMUIEvent.cpp +++ b/content/events/src/nsDOMUIEvent.cpp @@ -114,17 +114,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_ADDREF_INHERITED(nsDOMUIEvent, nsDOMEvent) NS_IMPL_RELEASE_INHERITED(nsDOMUIEvent, nsDOMEvent) DOMCI_DATA(UIEvent, nsDOMUIEvent) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMUIEvent) NS_INTERFACE_MAP_ENTRY(nsIDOMUIEvent) - NS_INTERFACE_MAP_ENTRY(nsIDOMNSUIEvent) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(UIEvent) NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent) nsIntPoint nsDOMUIEvent::GetScreenPoint() { if (!mEvent || (mEvent->eventStructType != NS_MOUSE_EVENT && @@ -244,20 +243,17 @@ nsDOMUIEvent::GetPageY(PRInt32* aPageY) NS_ENSURE_ARG_POINTER(aPageY); *aPageY = GetPagePoint().y; return NS_OK; } NS_IMETHODIMP nsDOMUIEvent::GetWhich(PRUint32* aWhich) { - NS_ENSURE_ARG_POINTER(aWhich); - // Usually we never reach here, as this is reimplemented for mouse and keyboard events. - *aWhich = 0; - return NS_OK; + return Which(aWhich); } NS_IMETHODIMP nsDOMUIEvent::GetRangeParent(nsIDOMNode** aRangeParent) { NS_ENSURE_ARG_POINTER(aRangeParent); nsIFrame* targetFrame = nsnull;
--- a/content/events/src/nsDOMUIEvent.h +++ b/content/events/src/nsDOMUIEvent.h @@ -35,53 +35,56 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef nsDOMUIEvent_h #define nsDOMUIEvent_h #include "nsIDOMUIEvent.h" -#include "nsIDOMNSUIEvent.h" #include "nsDOMEvent.h" class nsDOMUIEvent : public nsDOMEvent, - public nsIDOMUIEvent, - public nsIDOMNSUIEvent + public nsIDOMUIEvent { public: nsDOMUIEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMUIEvent, nsDOMEvent) // nsIDOMUIEvent Interface NS_DECL_NSIDOMUIEVENT - // nsIDOMNSUIEvent Interface - NS_DECL_NSIDOMNSUIEVENT - // nsIPrivateDOMEvent interface NS_IMETHOD DuplicatePrivateData(); virtual void Serialize(IPC::Message* aMsg, PRBool aSerializeInterfaceType); virtual PRBool Deserialize(const IPC::Message* aMsg, void** aIter); // Forward to nsDOMEvent NS_FORWARD_TO_NSDOMEVENT NS_FORWARD_NSIDOMNSEVENT(nsDOMEvent::) + protected: - // Internal helper functions nsIntPoint GetClientPoint(); nsIntPoint GetScreenPoint(); nsIntPoint GetLayerPoint(); nsIntPoint GetPagePoint(); - -protected: + + // Allow specializations. + virtual nsresult Which(PRUint32* aWhich) + { + NS_ENSURE_ARG_POINTER(aWhich); + // Usually we never reach here, as this is reimplemented for mouse and keyboard events. + *aWhich = 0; + return NS_OK; + } + nsCOMPtr<nsIDOMWindow> mView; PRInt32 mDetail; nsIntPoint mClientPoint; // Screenpoint is mEvent->refPoint. nsIntPoint mLayerPoint; nsIntPoint mPagePoint; };
--- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -977,8 +977,23 @@ nsEventListenerManager::GetJSEventListen if (ls->mHandlerIsString) { CompileEventHandlerInternal(ls, PR_TRUE, nsnull); } *vp = OBJECT_TO_JSVAL(static_cast<JSObject*>(listener->GetHandler())); } +PRInt64 +nsEventListenerManager::SizeOf() const +{ + PRInt64 size = sizeof(*this); + PRUint32 count = mListeners.Length(); + for (PRUint32 i = 0; i < count; ++i) { + const nsListenerStruct& ls = mListeners.ElementAt(i); + size += sizeof(ls); + nsIJSEventListener* jsl = ls.GetJSListener(); + if (jsl) { + size += jsl->SizeOf(); + } + } + return size; +}
--- a/content/events/src/nsEventListenerManager.h +++ b/content/events/src/nsEventListenerManager.h @@ -227,16 +227,17 @@ public: PRBool MayHaveAudioAvailableEventListener() { return mMayHaveAudioAvailableEventListener; } /** * Returns PR_TRUE if there may be a touch event listener registered, * PR_FALSE if there definitely isn't. */ PRBool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; } + PRInt64 SizeOf() const; protected: nsresult HandleEventSubType(nsListenerStruct* aListenerStruct, nsIDOMEventListener* aListener, nsIDOMEvent* aDOMEvent, nsIDOMEventTarget* aCurrentTarget, PRUint32 aPhaseFlags, nsCxPusher* aPusher);
--- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -94,17 +94,17 @@ #include "nsIDOMDocument.h" #include "nsIDOMKeyEvent.h" #include "nsIObserverService.h" #include "nsIDocShell.h" #include "nsIMarkupDocumentViewer.h" #include "nsIDOMMouseScrollEvent.h" #include "nsIDOMDragEvent.h" #include "nsIDOMEventTarget.h" -#include "nsIDOMNSUIEvent.h" +#include "nsIDOMUIEvent.h" #include "nsDOMDragEvent.h" #include "nsIDOMNSEditableElement.h" #include "nsCaret.h" #include "nsILookAndFeel.h" #include "nsWidgetsCID.h" #include "nsSubDocumentFrame.h" @@ -2640,18 +2640,18 @@ nsEventStateManager::ComputeWheelDeltaFo PRBool deltaUp = (delta < 0); if (swapDirs) { deltaUp = !deltaUp; } delta = deltaUp ? -userSize : userSize; } if (ComputeWheelActionFor(aMouseEvent, useSysNumLines) == MOUSE_SCROLL_PAGE) { - delta = (delta > 0) ? PRInt32(nsIDOMNSUIEvent::SCROLL_PAGE_DOWN) : - PRInt32(nsIDOMNSUIEvent::SCROLL_PAGE_UP); + delta = (delta > 0) ? PRInt32(nsIDOMUIEvent::SCROLL_PAGE_DOWN) : + PRInt32(nsIDOMUIEvent::SCROLL_PAGE_UP); } return delta; } PRInt32 nsEventStateManager::ComputeWheelActionFor(nsMouseScrollEvent* aMouseEvent, PRBool aUseSystemSettings)
--- a/content/events/test/test_bug547996-1.html +++ b/content/events/test/test_bug547996-1.html @@ -21,18 +21,18 @@ https://bugzilla.mozilla.org/show_bug.cg /* mouseEvent.mozInputSource attribute */ function prepareListener(eventName, expectedValue) { return function(event) { is(event.mozInputSource, expectedValue, "Correct .mozInputSource value in " + eventName); }; } -const INPUT_SOURCE_UNKNOWN = Components.interfaces.nsIDOMNSMouseEvent.MOZ_SOURCE_UNKNOWN; -const INPUT_SOURCE_KEYBOARD = Components.interfaces.nsIDOMNSMouseEvent.MOZ_SOURCE_KEYBOARD; +const INPUT_SOURCE_UNKNOWN = Components.interfaces.nsIDOMMouseEvent.MOZ_SOURCE_UNKNOWN; +const INPUT_SOURCE_KEYBOARD = Components.interfaces.nsIDOMMouseEvent.MOZ_SOURCE_KEYBOARD; function doTest() { var eventNames = [ "mousedown", "mouseup", "click", "dblclick", "contextmenu",
--- a/content/events/test/test_bug547996-2.xhtml +++ b/content/events/test/test_bug547996-2.xhtml @@ -24,23 +24,23 @@ var expectedInputSource = null; function check(event) { is(event.mozInputSource, expectedInputSource, ".mozInputSource"); } function doTest() { setup(); - expectedInputSource = Components.interfaces.nsIDOMNSMouseEvent.MOZ_SOURCE_KEYBOARD; + expectedInputSource = Components.interfaces.nsIDOMMouseEvent.MOZ_SOURCE_KEYBOARD; testKeyboard(); - expectedInputSource = Components.interfaces.nsIDOMNSMouseEvent.MOZ_SOURCE_MOUSE; + expectedInputSource = Components.interfaces.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE; testMouse(); - expectedInputSource = Components.interfaces.nsIDOMNSMouseEvent.MOZ_SOURCE_UNKNOWN; + expectedInputSource = Components.interfaces.nsIDOMMouseEvent.MOZ_SOURCE_UNKNOWN; testScriptedClicks(); cleanup(); SimpleTest.finish(); } function testKeyboard() {
--- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -728,18 +728,20 @@ nsGenericHTMLElement::FireMutationEvents // Fire mutation events. Optimize for the case when there are no listeners PRInt32 newChildCount = aDest->GetChildCount(); if (newChildCount && nsContentUtils:: HasMutationListeners(aDoc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) { nsAutoTArray<nsCOMPtr<nsIContent>, 50> childNodes; NS_ASSERTION(newChildCount - aOldChildCount >= 0, "What, some unexpected dom mutation has happened?"); childNodes.SetCapacity(newChildCount - aOldChildCount); - for (nsINode::ChildIterator iter(aDest); !iter.IsDone(); iter.Next()) { - childNodes.AppendElement(iter); + for (nsIContent* child = aDest->GetFirstChild(); + child; + child = child->GetNextSibling()) { + childNodes.AppendElement(child); } nsGenericElement::FireNodeInserted(aDoc, aDest, childNodes); } } nsresult nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML) { @@ -3396,17 +3398,17 @@ nsresult nsGenericHTMLElement::Click() SetFlags(NODE_HANDLING_CLICK); // Click() is never called from native code, but it may be // called from chrome JS. Mark this event trusted if Click() // is called from chrome code. nsMouseEvent event(nsContentUtils::IsCallerChrome(), NS_MOUSE_CLICK, nsnull, nsMouseEvent::eReal); - event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_UNKNOWN; + event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN; nsEventDispatcher::Dispatch(this, context, &event); UnsetFlags(NODE_HANDLING_CLICK); return NS_OK; } PRBool @@ -3502,17 +3504,17 @@ nsGenericHTMLElement::PerformAccesskey(P nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this); fm->SetFocus(elem, nsIFocusManager::FLAG_BYKEY); } if (aKeyCausesActivation) { // Click on it if the users prefs indicate to do so. nsMouseEvent event(aIsTrustedEvent, NS_MOUSE_CLICK, nsnull, nsMouseEvent::eReal); - event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_KEYBOARD; + event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD; nsAutoPopupStatePusher popupStatePusher(aIsTrustedEvent ? openAllowed : openAbused); nsEventDispatcher::Dispatch(this, presContext, &event); } }
--- a/content/html/content/src/nsHTMLButtonElement.cpp +++ b/content/html/content/src/nsHTMLButtonElement.cpp @@ -363,17 +363,17 @@ nsHTMLButtonElement::PostHandleEvent(nsE NS_KEY_PRESS == aVisitor.mEvent->message) || keyEvent->keyCode == NS_VK_SPACE && NS_KEY_UP == aVisitor.mEvent->message) { nsEventStatus status = nsEventStatus_eIgnore; nsMouseEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), NS_MOUSE_CLICK, nsnull, nsMouseEvent::eReal); - event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_KEYBOARD; + event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD; nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this), aVisitor.mPresContext, &event, nsnull, &status); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } break;// NS_KEY_PRESS
--- a/content/html/content/src/nsHTMLCanvasElement.cpp +++ b/content/html/content/src/nsHTMLCanvasElement.cpp @@ -223,16 +223,19 @@ nsHTMLCanvasElement::ExtractData(const n { // note that if we don't have a current context, the spec says we're // supposed to just return transparent black pixels of the canvas // dimensions. nsRefPtr<gfxImageSurface> emptyCanvas; nsIntSize size = GetWidthHeight(); if (!mCurrentContext) { emptyCanvas = new gfxImageSurface(gfxIntSize(size.width, size.height), gfxASurface::ImageFormatARGB32); + if (emptyCanvas->CairoStatus()) { + return NS_ERROR_INVALID_ARG; + } } nsresult rv; // get image bytes nsCOMPtr<nsIInputStream> imgStream; NS_ConvertUTF16toUTF8 encoderType(aType); @@ -308,19 +311,45 @@ nsHTMLCanvasElement::ToDataURLImpl(const if (NS_SUCCEEDED(aEncoderOptions->GetAsDouble(&quality)) && quality >= 0.0 && quality <= 1.0) { params.AppendLiteral("quality="); params.AppendInt(NS_lround(quality * 100.0)); } } } + // If we haven't parsed the params check for proprietary options. + // The proprietary option -moz-parse-options will take a image lib encoder + // parse options string as is and pass it to the encoder. + PRBool usingCustomParseOptions = PR_FALSE; + if (params.Length() == 0) { + NS_NAMED_LITERAL_STRING(mozParseOptions, "-moz-parse-options:"); + nsAutoString paramString; + if (NS_SUCCEEDED(aEncoderOptions->GetAsAString(paramString)) && + StringBeginsWith(paramString, mozParseOptions)) { + nsDependentSubstring parseOptions = Substring(paramString, + mozParseOptions.Length(), + paramString.Length() - + mozParseOptions.Length()); + params.Append(parseOptions); + usingCustomParseOptions = PR_TRUE; + } + } + nsCOMPtr<nsIInputStream> stream; nsresult rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG); + + // If there are unrecognized custom parse options, we should fall back to + // the default values for the encoder without any options at all. + if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) { + fallbackToPNG = false; + rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG); + } + NS_ENSURE_SUCCESS(rv, rv); // build data URL string if (fallbackToPNG) aDataURL = NS_LITERAL_STRING("data:image/png;base64,"); else aDataURL = NS_LITERAL_STRING("data:") + type + NS_LITERAL_STRING(";base64,");
--- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -2174,17 +2174,17 @@ nsHTMLInputElement::PostHandleEvent(nsEv } case NS_FORM_INPUT_BUTTON: case NS_FORM_INPUT_RESET: case NS_FORM_INPUT_SUBMIT: case NS_FORM_INPUT_IMAGE: // Bug 34418 { nsMouseEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), NS_MOUSE_CLICK, nsnull, nsMouseEvent::eReal); - event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_KEYBOARD; + event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD; nsEventStatus status = nsEventStatus_eIgnore; nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this), aVisitor.mPresContext, &event, nsnull, &status); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } // case } // switch @@ -2212,17 +2212,17 @@ nsHTMLInputElement::PostHandleEvent(nsEv do_QueryInterface(selectedRadioButton); if (radioContent) { rv = selectedRadioButton->Focus(); if (NS_SUCCEEDED(rv)) { nsEventStatus status = nsEventStatus_eIgnore; nsMouseEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), NS_MOUSE_CLICK, nsnull, nsMouseEvent::eReal); - event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_KEYBOARD; + event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD; rv = nsEventDispatcher::Dispatch(radioContent, aVisitor.mPresContext, &event, nsnull, &status); if (NS_SUCCEEDED(rv)) { aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } }
--- a/content/html/content/src/nsHTMLLabelElement.cpp +++ b/content/html/content/src/nsHTMLLabelElement.cpp @@ -309,17 +309,17 @@ nsHTMLLabelElement::PerformAccesskey(PRB } else { nsPresContext *presContext = GetPresContext(); if (!presContext) return; // Click on it if the users prefs indicate to do so. nsMouseEvent event(aIsTrustedEvent, NS_MOUSE_CLICK, nsnull, nsMouseEvent::eReal); - event.inputSource = nsIDOMNSMouseEvent::MOZ_SOURCE_KEYBOARD; + event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD; nsAutoPopupStatePusher popupStatePusher(aIsTrustedEvent ? openAllowed : openAbused); nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this), presContext, &event); } }
--- a/content/html/content/test/Makefile.in +++ b/content/html/content/test/Makefile.in @@ -208,17 +208,16 @@ include $(topsrcdir)/config/rules.mk test_bug588683-2.html \ test_bug588683-3.html \ test_bug588683-4.html \ test_bug590353-1.html \ test_bug590353-2.html \ test_bug593689.html \ test_bug561636.html \ test_bug590363.html \ - test_bug557628.html \ test_bug592802.html \ test_bug595429.html \ test_bug595447.html \ test_bug595449.html \ test_bug557087-1.html \ test_bug557087-2.html \ test_bug557087-3.html \ test_bug557087-4.html \
--- a/content/html/content/test/forms/Makefile.in +++ b/content/html/content/test/forms/Makefile.in @@ -58,13 +58,14 @@ include $(topsrcdir)/config/rules.mk test_formnovalidate_attribute.html \ test_label_control_attribute.html \ test_output_element.html \ test_button_attributes_reflection.html \ test_textarea_attributes_reflection.html \ test_validation.html \ test_maxlength_attribute.html \ test_datalist_element.html \ + test_form_attributes_reflection.html \ $(NULL) libs:: $(_TEST_FILES) $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644 --- /dev/null +++ b/content/html/content/test/forms/test_form_attributes_reflection.html @@ -0,0 +1,87 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLFormElement attributes reflection</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="../reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLFormElement attributes reflection **/ + +// .acceptCharset +reflectString({ + element: document.createElement("form"), + attribute: { idl: "acceptCharset", content: "accept-charset" }, + otherValues: [ "ISO-8859-1", "UTF-8" ], +}); + +// TODO: action (URL) + +// .autocomplete +reflectLimitedEnumerated({ + element: document.createElement("form"), + attribute: "autocomplete", + validValues: [ "on", "off" ], + invalidValues: [ "", "foo", "tulip", "default" ], + defaultValue: "on", +}); + +// .enctype +reflectLimitedEnumerated({ + element: document.createElement("form"), + attribute: "enctype", + validValues: [ "application/x-www-form-urlencoded", "multipart/form-data", + "text/plain" ], + invalidValues: [ "", "foo", "tulip", "multipart/foo" ], + defaultValue: "application/x-www-form-urlencoded" +}); + +// .encoding +reflectLimitedEnumerated({ + element: document.createElement("form"), + attribute: { idl: "encoding", content: "enctype" }, + validValues: [ "application/x-www-form-urlencoded", "multipart/form-data", + "text/plain" ], + invalidValues: [ "", "foo", "tulip", "multipart/foo" ], + defaultValue: "application/x-www-form-urlencoded" +}); + +// .method +reflectLimitedEnumerated({ + element: document.createElement("form"), + attribute: "method", + validValues: [ "get", "post" ], + invalidValues: [ "", "foo", "tulip" ], + defaultValue: "get" +}); + +// .name +reflectString({ + element: document.createElement("form"), + attribute: "name", +}); + +// .noValidate +reflectBoolean({ + element: document.createElement("form"), + attribute: "noValidate", +}); + +// .target +reflectString({ + element: document.createElement("form"), + attribute: "target", + otherValues: [ "_blank", "_self", "_parent", "_top" ], +}); + +</script> +</pre> +</body> +</html>
--- a/content/html/content/test/forms/test_novalidate_attribute.html +++ b/content/html/content/test/forms/test_novalidate_attribute.html @@ -26,45 +26,16 @@ https://bugzilla.mozilla.org/show_bug.cg <input id='c' required> </form> </div> <pre id="test"> <script type="application/javascript"> /** Test for Bug 556013 **/ -var form = document.createElement('form'); - -function checkNoValidateAttribute(aForm) -{ - ok("noValidate" in form, "noValidate should be a form element IDL attribute"); - - ok(!aForm.noValidate, "aForm novalidate attribute should be disabled"); - is(aForm.getAttribute('novalidate'), null, - "aForm novalidate attribute should be disabled"); - - aForm.noValidate = true; - ok(aForm.noValidate, "aForm novalidate attribute should be enabled"); - isnot(aForm.getAttribute('novalidate'), null, - "aForm novalidate attribute should be enabled"); - - aForm.removeAttribute('novalidate'); - aForm.setAttribute('novalidate', ''); - ok(aForm.noValidate, "aForm novalidate attribute should be enabled"); - isnot(aForm.getAttribute('novalidate'), null, - "aForm novalidate attribute should be enabled"); - - aForm.removeAttribute('novalidate'); - ok(!aForm.noValidate, "aForm novalidate attribute should be disabled"); - is(aForm.getAttribute('novalidate'), null, - "aForm novalidate attribute should be disabled"); -} - -checkNoValidateAttribute(form); - /** * novalidate should prevent form validation, thus not blocking form submission. * * NOTE: if there is no invalidformsubmit observer, the form submission will * never be blocked and this test might be a false-positive but that should not * be a problem. */ document.forms[0].addEventListener("submit", function(aEvent) {
--- a/content/html/content/test/reflect.js +++ b/content/html/content/test/reflect.js @@ -232,118 +232,123 @@ function reflectUnsignedInt(aParameters) /** * Checks that a given attribute is correctly reflected as limited to known * values enumerated attribute. * * @param aParameters Object object containing the parameters, which are: * - element Element node to test on * - attribute String name of the attribute + * OR + * attribute Object object containing two attributes, 'content' and 'idl' * - validValues Array valid values we support * - invalidValues Array invalid values * - defaultValue String [optional] default value when no valid value is set * - unsupportedValues Array [optional] valid values we do not support */ function reflectLimitedEnumerated(aParameters) { var element = aParameters.element; - var attr = aParameters.attribute; + var contentAttr = typeof aParameters.attribute === "string" + ? aParameters.attribute : aParameters.attribute.content; + var idlAttr = typeof aParameters.attribute === "string" + ? aParameters.attribute : aParameters.attribute.idl; var validValues = aParameters.validValues; var invalidValues = aParameters.invalidValues; var defaultValue = aParameters.defaultValue !== undefined - ? aParameters.defaultValue : ""; + ? aParameters.defaultValue : ""; var unsupportedValues = aParameters.unsupportedValues !== undefined - ? aParameters.unsupportedValues : []; + ? aParameters.unsupportedValues : []; - ok(attr in element, attr + " should be an IDL attribute of this element"); - is(typeof element[attr], "string", attr + " IDL attribute should be a string"); + ok(idlAttr in element, idlAttr + " should be an IDL attribute of this element"); + is(typeof element[idlAttr], "string", idlAttr + " IDL attribute should be a string"); // Explicitly check the default value. - element.removeAttribute(attr); - is(element[attr], defaultValue, + element.removeAttribute(contentAttr); + is(element[idlAttr], defaultValue, "When no attribute is set, the value should be the default value."); // Check valid values. validValues.forEach(function (v) { - element.setAttribute(attr, v); - is(element[attr], v, - v + " should be accepted as a valid value for " + attr); - is(element.getAttribute(attr), v, + element.setAttribute(contentAttr, v); + is(element[idlAttr], v, + v + " should be accepted as a valid value for " + idlAttr); + is(element.getAttribute(contentAttr), v, "Content attribute should return the value it has been set to."); - element.removeAttribute(attr); + element.removeAttribute(contentAttr); - element.setAttribute(attr, v.toUpperCase()); - is(element[attr], v, + element.setAttribute(contentAttr, v.toUpperCase()); + is(element[idlAttr], v, "Enumerated attributes should be case-insensitive."); - is(element.getAttribute(attr), v.toUpperCase(), + is(element.getAttribute(contentAttr), v.toUpperCase(), "Content attribute should not be lower-cased."); - element.removeAttribute(attr); + element.removeAttribute(contentAttr); - element[attr] = v; - is(element[attr], v, - v + " should be accepted as a valid value for " + attr); - is(element.getAttribute(attr), v, + element[idlAttr] = v; + is(element[idlAttr], v, + v + " should be accepted as a valid value for " + idlAttr); + is(element.getAttribute(contentAttr), v, "Content attribute should return the value it has been set to."); - element.removeAttribute(attr); + element.removeAttribute(contentAttr); - element[attr] = v.toUpperCase(); - is(element[attr], v, + element[idlAttr] = v.toUpperCase(); + is(element[idlAttr], v, "Enumerated attributes should be case-insensitive."); - is(element.getAttribute(attr), v.toUpperCase(), + is(element.getAttribute(contentAttr), v.toUpperCase(), "Content attribute should not be lower-cased."); - element.removeAttribute(attr); + element.removeAttribute(contentAttr); }); // Check invalid values. invalidValues.forEach(function (v) { - element.setAttribute(attr, v); - is(element[attr], defaultValue, + element.setAttribute(contentAttr, v); + is(element[idlAttr], defaultValue, "When the content attribute is set to an invalid value, the default value should be returned."); - is(element.getAttribute(attr), v, + is(element.getAttribute(contentAttr), v, "Content attribute should not have been changed."); - element.removeAttribute(attr); + element.removeAttribute(contentAttr); - element[attr] = v; - is(element[attr], defaultValue, + element[idlAttr] = v; + is(element[idlAttr], defaultValue, "When the value is set to an invalid value, the default value should be returned."); - is(element.getAttribute(attr), v, + is(element.getAttribute(contentAttr), v, "Content attribute should not have been changed."); - element.removeAttribute(attr); + element.removeAttribute(contentAttr); }); // Check valid values we currently do not support. // Basically, it's like the checks for the valid values but with some todo's. unsupportedValues.forEach(function (v) { - element.setAttribute(attr, v); - todo_is(element[attr], v, - v + " should be accepted as a valid value for " + attr); - is(element.getAttribute(attr), v, + element.setAttribute(contentAttr, v); + todo_is(element[idlAttr], v, + v + " should be accepted as a valid value for " + idlAttr); + is(element.getAttribute(contentAttr), v, "Content attribute should return the value it has been set to."); - element.removeAttribute(attr); + element.removeAttribute(contentAttr); - element.setAttribute(attr, v.toUpperCase()); - todo_is(element[attr], v, + element.setAttribute(contentAttr, v.toUpperCase()); + todo_is(element[idlAttr], v, "Enumerated attributes should be case-insensitive."); - is(element.getAttribute(attr), v.toUpperCase(), + is(element.getAttribute(contentAttr), v.toUpperCase(), "Content attribute should not be lower-cased."); - element.removeAttribute(attr); + element.removeAttribute(contentAttr); - element[attr] = v; - todo_is(element[attr], v, - v + " should be accepted as a valid value for " + attr); - is(element.getAttribute(attr), v, + element[idlAttr] = v; + todo_is(element[idlAttr], v, + v + " should be accepted as a valid value for " + idlAttr); + is(element.getAttribute(contentAttr), v, "Content attribute should return the value it has been set to."); - element.removeAttribute(attr); + element.removeAttribute(contentAttr); - element[attr] = v.toUpperCase(); - todo_is(element[attr], v, + element[idlAttr] = v.toUpperCase(); + todo_is(element[idlAttr], v, "Enumerated attributes should be case-insensitive."); - is(element.getAttribute(attr), v.toUpperCase(), + is(element.getAttribute(contentAttr), v.toUpperCase(), "Content attribute should not be lower-cased."); - element.removeAttribute(attr); + element.removeAttribute(contentAttr); }); } /** * Checks that a given attribute is correctly reflected as a boolean. * * @param aParameters Object object containing the parameters, which are: * - element Element node to test on
deleted file mode 100644 --- a/content/html/content/test/test_bug557628.html +++ /dev/null @@ -1,71 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=557628 ---> -<head> - <title>Test for Bug 557628</title> - <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557628">Mozilla Bug 557628</a> -<p id="display"></p> -<pre id="test"> -<script type="application/javascript"> - -/** Test for Bug 557628 **/ - -var formAutocompleteTestData = [ - // Default value. - [ "on" ], - // Valid values. - [ "on", "off" ], - // Invalid values. - [ "", " ", "foo", "default" ] -]; - -function checkAttribute(element, name, data) -{ - is(element.getAttribute(name), undefined, - "By default " + name + " content attribute should be undefined"); - is(element[name], data[0][0], - "By default " + name + " IDL attribute should be equal to " + - data[0][0]); - - // Valid values. - for (i in data[1]) { - element.setAttribute(name, data[1][i]); - is(element.getAttribute(name), data[1][i], - "getAttribute should return the content attribute"); - is(element[name], data[1][i], "When getting, " + name + " IDL attribute " + - "should be equal to the content attribute if the value is known"); - } - - // Invalid values. - for (i in data[2]) { - element.setAttribute(name, data[2][i]); - is(element.getAttribute(name), data[2][i], - "getAttribute should return the content attribute"); - is(element[name], data[0][0], "When getting, " + name + " IDL attribute " + - "should return the default value if the content attribute value isn't known"); - } - - // TODO values. - for (i in data[3]) { - element.setAttribute(name, data[3][i]); - is(element.getAttribute(name), data[3][i], - "getAttribute should return the content attribute"); - todo_is(element[name], data[3][i], "When getting, " + name + " IDL attribute " + - "should be equal to the content attribute if the value is known"); - } -} - -var form = document.createElement('form'); - -checkAttribute(form, 'autocomplete', formAutocompleteTestData); - -</script> -</pre> -</body> -</html>
--- a/content/html/content/test/test_bug585508.html +++ b/content/html/content/test/test_bug585508.html @@ -56,20 +56,17 @@ function checkAttribute(form, attrName, form.setAttribute(attrName, data[2][i]); is(form.getAttribute(attrName), data[2][i], "getAttribute should return the content attribute"); is(form[idlName], data[0][0], "When getting, " + idlName + " IDL attribute " + "should return the default value if the content attribute value isn't known"); } } -var form = document.createElement('form'); var button = document.createElement('button'); -checkAttribute(form, 'enctype', 'enctype', enctypeTestData); -checkAttribute(form, 'method', 'method', methodTestData); checkAttribute(button, 'formenctype', 'formEnctype', enctypeTestData); checkAttribute(button, 'formmethod', 'formMethod', methodTestData); </script> </pre> </body> </html>
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp +++ b/content/xbl/src/nsXBLPrototypeHandler.cpp @@ -47,17 +47,16 @@ #include "nsINameSpaceManager.h" #include "nsIScriptContext.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIJSEventListener.h" #include "nsIController.h" #include "nsIControllers.h" #include "nsIDOMXULElement.h" -#include "nsIDOMNSUIEvent.h" #include "nsIURI.h" #include "nsIDOMHTMLTextAreaElement.h" #include "nsIDOMHTMLInputElement.h" #include "nsFocusManager.h" #include "nsEventListenerManager.h" #include "nsIDOMEventTarget.h" #include "nsIDOMEventListener.h" #include "nsIPrivateDOMEvent.h" @@ -382,19 +381,20 @@ nsXBLPrototypeHandler::EnsureEventHandle nsresult nsXBLPrototypeHandler::DispatchXBLCommand(nsIDOMEventTarget* aTarget, nsIDOMEvent* aEvent) { // This is a special-case optimization to make command handling fast. // It isn't really a part of XBL, but it helps speed things up. // See if preventDefault has been set. If so, don't execute. PRBool preventDefault = PR_FALSE; - nsCOMPtr<nsIDOMNSUIEvent> nsUIEvent(do_QueryInterface(aEvent)); - if (nsUIEvent) - nsUIEvent->GetPreventDefault(&preventDefault); + nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aEvent); + if (domNSEvent) { + domNSEvent->GetPreventDefault(&preventDefault); + } if (preventDefault) return NS_OK; nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(aEvent); if (privateEvent) { PRBool dispatchStopped = privateEvent->IsDispatchStopped(); if (dispatchStopped)
--- a/content/xbl/src/nsXBLWindowKeyHandler.cpp +++ b/content/xbl/src/nsXBLWindowKeyHandler.cpp @@ -37,17 +37,16 @@ * * ***** END LICENSE BLOCK ***** */ #include "nsCOMPtr.h" #include "nsXBLPrototypeHandler.h" #include "nsXBLWindowKeyHandler.h" #include "nsIContent.h" #include "nsIAtom.h" -#include "nsIDOMNSUIEvent.h" #include "nsIDOMKeyEvent.h" #include "nsIDOMEventTarget.h" #include "nsIDOMNSEvent.h" #include "nsXBLService.h" #include "nsIServiceManager.h" #include "nsGkAtoms.h" #include "nsXBLDocumentInfo.h" #include "nsIDOMElement.h" @@ -314,42 +313,40 @@ DoCommandCallback(const char *aCommand, controller->DoCommand(aCommand); } } } nsresult nsXBLWindowKeyHandler::WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventType) { - nsCOMPtr<nsIDOMNSUIEvent> evt = do_QueryInterface(aKeyEvent); + nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent); PRBool prevent; - evt->GetPreventDefault(&prevent); + domNSEvent->GetPreventDefault(&prevent); if (prevent) return NS_OK; - nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent); PRBool trustedEvent = PR_FALSE; - if (domNSEvent) { //Don't process the event if it was not dispatched from a trusted source domNSEvent->GetIsTrusted(&trustedEvent); } if (!trustedEvent) return NS_OK; PRBool isEditor; nsresult rv = EnsureHandlers(&isEditor); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDOMElement> el = GetElement(); if (!el) { if (mUserHandler) { WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler); - evt->GetPreventDefault(&prevent); + domNSEvent->GetPreventDefault(&prevent); if (prevent) return NS_OK; // Handled by the user bindings. Our work here is done. } } nsCOMPtr<nsIContent> content = do_QueryInterface(el); // skip keysets that are disabled if (content && content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
--- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -689,17 +689,17 @@ nsXULElement::PerformAccesskey(PRBool aK else { element = do_QueryInterface(content); } if (element) fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY); } } if (aKeyCausesActivation && tag != nsGkAtoms::textbox && tag != nsGkAtoms::menulist) { - elm->ClickWithInputSource(nsIDOMNSMouseEvent::MOZ_SOURCE_KEYBOARD); + elm->ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD); } } else { content->PerformAccesskey(aKeyCausesActivation, aIsTrustedEvent); } } @@ -2072,17 +2072,17 @@ nsXULElement::Blur() if (win && fm) return fm->ClearFocus(win); return NS_OK; } NS_IMETHODIMP nsXULElement::Click() { - return ClickWithInputSource(nsIDOMNSMouseEvent::MOZ_SOURCE_UNKNOWN); + return ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN); } nsresult nsXULElement::ClickWithInputSource(PRUint16 aInputSource) { if (BoolAttrIsTrue(nsGkAtoms::disabled)) return NS_OK;
--- a/content/xul/content/src/nsXULPopupListener.cpp +++ b/content/xul/content/src/nsXULPopupListener.cpp @@ -55,17 +55,16 @@ #include "nsContentCID.h" #include "nsContentUtils.h" #include "nsXULPopupManager.h" #include "nsEventStateManager.h" #include "nsIScriptContext.h" #include "nsIDOMWindow.h" #include "nsIDOMXULDocument.h" #include "nsIDocument.h" -#include "nsIDOMNSUIEvent.h" #include "nsIDOMEventTarget.h" #include "nsIDOMNSEvent.h" #include "nsServiceManagerUtils.h" #include "nsIPrincipal.h" #include "nsIScriptSecurityManager.h" #include "nsLayoutUtils.h" #include "nsFrameManager.h" #include "nsHTMLReflowState.h" @@ -125,19 +124,18 @@ nsXULPopupListener::HandleEvent(nsIDOMEv nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent); if (!mouseEvent) { //non-ui event passed in. bad things. return NS_OK; } // check if someone has attempted to prevent this action. - nsCOMPtr<nsIDOMNSUIEvent> nsUIEvent; - nsUIEvent = do_QueryInterface(mouseEvent); - if (!nsUIEvent) { + nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(mouseEvent); + if (!domNSEvent) { return NS_OK; } // Get the node that was clicked on. nsCOMPtr<nsIDOMEventTarget> target; mouseEvent->GetTarget(getter_AddRefs(target)); nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(target); @@ -155,17 +153,17 @@ nsXULPopupListener::HandleEvent(nsIDOMEv if (doc) targetNode = do_QueryInterface(doc->GetRootElement()); if (!targetNode) { return NS_ERROR_FAILURE; } } PRBool preventDefault; - nsUIEvent->GetPreventDefault(&preventDefault); + domNSEvent->GetPreventDefault(&preventDefault); if (preventDefault && targetNode && mIsContext) { // Someone called preventDefault on a context menu. // Let's make sure they are allowed to do so. PRBool eventEnabled = Preferences::GetBool("dom.event.contextmenu.enabled", PR_TRUE); if (!eventEnabled) { // If the target node is for plug-in, we should not open XUL context // menu on windowless plug-ins.
--- a/content/xul/document/public/Makefile.in +++ b/content/xul/document/public/Makefile.in @@ -52,14 +52,13 @@ XPIDLSRCS = \ ifdef MOZ_XUL XPIDLSRCS += \ nsIXULOverlayProvider.idl \ $(NULL) EXPORTS = \ nsIXULDocument.h \ - nsIXULPrototypeCache.h \ $(NULL) endif include $(topsrcdir)/config/rules.mk
deleted file mode 100644 --- a/content/xul/document/public/nsIXULPrototypeCache.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Ben Goodger <ben@netscape.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef nsIXULPrototypeCache_h__ -#define nsIXULPrototypeCache_h__ - -#include "nsISupports.h" -class nsIURI; - -// {3A0A0FC1-8349-11d3-BE47-00104BDE6048} -#define NS_XULPROTOTYPECACHE_CID \ -{ 0x3a0a0fc1, 0x8349, 0x11d3, { 0xbe, 0x47, 0x0, 0x10, 0x4b, 0xde, 0x60, 0x48 } } - -// {f8bee3d7-4be8-46ae-92c2-60c25d5cd647} -#define NS_IXULPROTOTYPECACHE_IID \ -{ 0xf8bee3d7, 0x4be8, 0x46ae, \ - { 0x92, 0xc2, 0x60, 0xc2, 0x5d, 0x5c, 0xd6, 0x47 } } - -/** - * This interface lets code from outside gklayout access the prototype cache. - */ -class nsIXULPrototypeCache : public nsISupports -{ -public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXULPROTOTYPECACHE_IID) - - /** - * Whether the XUL document at the specified URI is in the cache. - */ - virtual PRBool IsCached(nsIURI* aURI) = 0; - - /** - * Stop the caching process abruptly, removing the cache file. - */ - virtual void AbortCaching() = 0; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsIXULPrototypeCache, NS_IXULPROTOTYPECACHE_IID) - -nsresult -NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult); - - -const char XUL_FASTLOAD_FILE_BASENAME[] = "XUL"; - -// Increase the subtractor when changing version, say when changing the -// (opaque to XPCOM FastLoad code) format of XUL-specific XDR serializations. -// See also JSXDR_BYTECODE_VERSION in jsxdrapi.h, which tracks incompatible JS -// bytecode version changes. -#define XUL_FASTLOAD_FILE_VERSION (0xfeedbeef - 25) - -#define XUL_SERIALIZATION_BUFFER_SIZE (64 * 1024) -#define XUL_DESERIALIZATION_BUFFER_SIZE (8 * 1024) - - -#endif // nsIXULPrototypeCache_h__
--- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -63,17 +63,16 @@ #include "nsDOMError.h" #include "nsIBoxObject.h" #include "nsIChromeRegistry.h" #include "nsIView.h" #include "nsIViewManager.h" #include "nsIContentViewer.h" #include "nsGUIEvent.h" -#include "nsIDOMNSUIEvent.h" #include "nsIDOMXULElement.h" #include "nsIPrivateDOMEvent.h" #include "nsIRDFNode.h" #include "nsIRDFRemoteDataSource.h" #include "nsIRDFService.h" #include "nsIStreamListener.h" #include "nsITimer.h" #include "nsIDocShell.h"
--- a/content/xul/document/src/nsXULDocument.h +++ b/content/xul/document/src/nsXULDocument.h @@ -55,17 +55,16 @@ #include "nsIURI.h" #include "nsIXULDocument.h" #include "nsScriptLoader.h" #include "nsIStreamListener.h" #include "nsICSSLoaderObserver.h" class nsIRDFResource; class nsIRDFService; -class nsIXULPrototypeCache; class nsPIWindowRoot; #if 0 // XXXbe save me, scc (need NSCAP_FORWARD_DECL(nsXULPrototypeScript)) class nsIObjectInputStream; class nsIObjectOutputStream; class nsIXULPrototypeScript; #else #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h"
--- a/content/xul/document/src/nsXULPrototypeCache.cpp +++ b/content/xul/document/src/nsXULPrototypeCache.cpp @@ -64,18 +64,16 @@ #include "mozilla/Preferences.h" #include "mozilla/scache/StartupCache.h" #include "mozilla/scache/StartupCacheUtils.h" using namespace mozilla; using namespace mozilla::scache; -static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID); - static PRBool gDisableXULCache = PR_FALSE; // enabled by default static const char kDisableXULCachePref[] = "nglayout.debug.disable_xul_cache"; static const char kXULCacheInfoKey[] = "nsXULPrototypeCache.startupCache"; static const char kXULCachePrefix[] = "xulcache"; //---------------------------------------------------------------------- static int @@ -104,75 +102,47 @@ nsXULPrototypeCache::nsXULPrototypeCache nsXULPrototypeCache::~nsXULPrototypeCache() { FlushScripts(); } -NS_IMPL_THREADSAFE_ISUPPORTS2(nsXULPrototypeCache, - nsIXULPrototypeCache, - nsIObserver) - - -nsresult -NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult) -{ - NS_PRECONDITION(! aOuter, "no aggregation"); - if (aOuter) - return NS_ERROR_NO_AGGREGATION; - - nsRefPtr<nsXULPrototypeCache> result = new nsXULPrototypeCache(); - if (! result) - return NS_ERROR_OUT_OF_MEMORY; - - if (!(result->mPrototypeTable.Init() && - result->mStyleSheetTable.Init() && - result->mScriptTable.Init() && - result->mXBLDocTable.Init())) { - return NS_ERROR_OUT_OF_MEMORY; - } - - if (!(result->mCacheURITable.Init() && - result->mInputStreamTable.Init() && - result->mOutputStreamTable.Init())) { - return NS_ERROR_OUT_OF_MEMORY; - } - - // XXX Ignore return values. - gDisableXULCache = - Preferences::GetBool(kDisableXULCachePref, gDisableXULCache); - Preferences::RegisterCallback(DisableXULCacheChangedCallback, - kDisableXULCachePref); - - nsresult rv = result->QueryInterface(aIID, aResult); - - nsCOMPtr<nsIObserverService> obsSvc = - mozilla::services::GetObserverService(); - if (obsSvc && NS_SUCCEEDED(rv)) { - nsXULPrototypeCache *p = result; - obsSvc->AddObserver(p, "chrome-flush-skin-caches", PR_FALSE); - obsSvc->AddObserver(p, "chrome-flush-caches", PR_FALSE); - obsSvc->AddObserver(p, "startupcache-invalidate", PR_FALSE); - } - - return rv; -} +NS_IMPL_THREADSAFE_ISUPPORTS1(nsXULPrototypeCache, nsIObserver) /* static */ nsXULPrototypeCache* nsXULPrototypeCache::GetInstance() { - // Theoretically this can return nsnull and callers should handle that. if (!sInstance) { - nsIXULPrototypeCache* cache; + NS_ADDREF(sInstance = new nsXULPrototypeCache()); + + sInstance->mPrototypeTable.Init(); + sInstance->mStyleSheetTable.Init(); + sInstance->mScriptTable.Init(); + sInstance->mXBLDocTable.Init(); + + sInstance->mCacheURITable.Init(); + sInstance->mInputStreamTable.Init(); + sInstance->mOutputStreamTable.Init(); - CallGetService(kXULPrototypeCacheCID, &cache); + gDisableXULCache = + Preferences::GetBool(kDisableXULCachePref, gDisableXULCache); + Preferences::RegisterCallback(DisableXULCacheChangedCallback, + kDisableXULCachePref); - sInstance = static_cast<nsXULPrototypeCache*>(cache); + nsCOMPtr<nsIObserverService> obsSvc = + mozilla::services::GetObserverService(); + if (obsSvc) { + nsXULPrototypeCache *p = sInstance; + obsSvc->AddObserver(p, "chrome-flush-skin-caches", PR_FALSE); + obsSvc->AddObserver(p, "chrome-flush-caches", PR_FALSE); + obsSvc->AddObserver(p, "startupcache-invalidate", PR_FALSE); + } + } return sInstance; } /* static */ StartupCache* nsXULPrototypeCache::GetStartupCache() { return gStartupCache; @@ -582,19 +552,17 @@ static int CachePrefChangedCallback(const char* aPref, void* aClosure) { PRBool wasEnabled = !gDisableXULDiskCache; gDisableXULDiskCache = Preferences::GetBool(kDisableXULCachePref, gDisableXULDiskCache); if (wasEnabled && gDisableXULDiskCache) { - static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID); - nsCOMPtr<nsIXULPrototypeCache> cache = - do_GetService(kXULPrototypeCacheCID); + nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance(); if (cache) cache->AbortCaching(); } return 0; } nsresult
--- a/content/xul/document/src/nsXULPrototypeCache.h +++ b/content/xul/document/src/nsXULPrototypeCache.h @@ -41,17 +41,16 @@ * ***** END LICENSE BLOCK ***** */ #ifndef nsXULPrototypeCache_h__ #define nsXULPrototypeCache_h__ #include "nsCOMPtr.h" #include "nsIObserver.h" #include "nsXBLDocumentInfo.h" -#include "nsIXULPrototypeCache.h" #include "nsDataHashtable.h" #include "nsInterfaceHashtable.h" #include "nsRefPtrHashtable.h" #include "nsURIHashKey.h" #include "nsXULPrototypeDocument.h" #include "nsIInputStream.h" #include "nsIStorageStream.h" #include "mozilla/scache/StartupCache.h" @@ -69,29 +68,27 @@ struct CacheScriptEntry /** * The XUL prototype cache can be used to store and retrieve shared data for * XUL documents, style sheets, XBL, and scripts. * * The cache has two levels: * 1. In-memory hashtables * 2. The on-disk cache file. */ -class nsXULPrototypeCache : public nsIXULPrototypeCache, - nsIObserver +class nsXULPrototypeCache : public nsIObserver { public: // nsISupports NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER - // nsIXULPrototypeCache - virtual PRBool IsCached(nsIURI* aURI) { + PRBool IsCached(nsIURI* aURI) { return GetPrototype(aURI) != nsnull; } - virtual void AbortCaching(); + void AbortCaching(); /** * Whether the prototype cache is enabled. */ PRBool IsEnabled(); /**
--- a/content/xul/templates/src/nsXULContentUtils.cpp +++ b/content/xul/templates/src/nsXULContentUtils.cpp @@ -66,17 +66,16 @@ #include "nsIDOMXULCommandDispatcher.h" #include "nsIDOMXULDocument.h" #include "nsIRDFNode.h" #include "nsINameSpaceManager.h" #include "nsIRDFService.h" #include "nsIServiceManager.h" #include "nsIURL.h" #include "nsXULContentUtils.h" -#include "nsIXULPrototypeCache.h" #include "nsLayoutCID.h" #include "nsNetUtil.h" #include "nsRDFCID.h" #include "nsString.h" #include "nsXPIDLString.h" #include "nsGkAtoms.h" #include "prlog.h" #include "prtime.h"
--- a/content/xul/templates/src/nsXULTemplateBuilder.cpp +++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp @@ -2122,19 +2122,20 @@ nsXULTemplateBuilder::CompileExtendedQue return NS_OK; } already_AddRefed<nsIAtom> nsXULTemplateBuilder::DetermineMemberVariable(nsIContent* aElement) { // recursively iterate over the children looking for an element // with uri="?..." - for (nsINode::ChildIterator iter(aElement); !iter.IsDone(); iter.Next()) { + for (nsIContent* child = aElement->GetFirstChild(); + child; + child = child->GetNextSibling()) { nsAutoString uri; - nsIContent *child = iter; child->GetAttr(kNameSpaceID_None, nsGkAtoms::uri, uri); if (!uri.IsEmpty() && uri[0] == PRUnichar('?')) { return NS_NewAtom(uri); } nsCOMPtr<nsIAtom> result = DetermineMemberVariable(child); if (result) { return result.forget();
--- a/db/sqlite3/README.MOZILLA +++ b/db/sqlite3/README.MOZILLA @@ -1,11 +1,11 @@ -This is sqlite 3.7.5 +This is sqlite 3.7.7.1 --- Shawn Wilsher <me@shawnwilsher.com>, 03/2011 +-- Marco Bonardo <mak77@bonardo.net>, 08/2011 See http://www.sqlite.org/ for more info. We have a mozilla-specific Makefile.in in src/ (normally no Makefile.in there) that we use to build. To move to a new version:
--- a/db/sqlite3/src/Makefile.in +++ b/db/sqlite3/src/Makefile.in @@ -93,25 +93,29 @@ CSRCS = \ # -DSQLITE_SECURE_DELETE=1 will cause SQLITE to 0-fill delete data so we # don't have to vacuum to make sure the data is not visible in the file. # -DSQLITE_ENABLE_FTS3=1 enables the full-text index module. # -DSQLITE_CORE=1 statically links that module into the SQLite library. # -DSQLITE_DEFAULT_PAGE_SIZE=32768 and SQLITE_MAX_DEFAULT_PAGE_SIZE=32768 # increases the page size from 1k, see bug 416330. The value must stay in sync # with mozIStorageConnection::DEFAULT_PAGE_SIZE. +# -DSQLITE_MAX_SCHEMA_RETRY increases the times SQLite may try to reparse +# statements when the schema changes. This is important when supporting lots of +# concurrent connections, especially when they use shared cache. # Note: Be sure to update the configure.in checks when these change! DEFINES = \ -DSQLITE_SECURE_DELETE=1 \ -DSQLITE_THREADSAFE=1 \ -DSQLITE_CORE=1 \ -DSQLITE_ENABLE_FTS3=1 \ -DSQLITE_ENABLE_UNLOCK_NOTIFY=1 \ -DSQLITE_DEFAULT_PAGE_SIZE=32768 \ -DSQLITE_MAX_DEFAULT_PAGE_SIZE=32768 \ + -DSQLITE_MAX_SCHEMA_RETRY=25 \ $(NULL) # -DSQLITE_ENABLE_LOCKING_STYLE=1 to help with AFP folders ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa) DEFINES += -DSQLITE_ENABLE_LOCKING_STYLE=1 endif # Turn on SQLite's assertions in debug builds. @@ -128,16 +132,18 @@ ifeq ($(OS_ARCH),OS2) ifdef MOZ_OS2_HIGH_MEMORY DEFINES += -DOS2_HIGH_MEMORY endif endif ifeq ($(OS_TARGET),Android) # default to user readable only to fit Android security model DEFINES += -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600 +# Force using fsync, since there is not fdatasync in ndk 5. +DEFINES += -Dfdatasync=fsync endif include $(topsrcdir)/config/rules.mk # next line allows use of MOZ_OBJDIR in .mozconfig with older gcc on BeOS, maybe others LOCAL_INCLUDES += -I$(srcdir) ifeq ($(OS_ARCH),OS2)
--- a/db/sqlite3/src/sqlite3.c +++ b/db/sqlite3/src/sqlite3.c @@ -1,12 +1,12 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.7.5. By combining all the individual C code files into this -** single large file, the entire code can be compiled as a one translation +** version 3.7.7.1. 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 ** of 5% or more are commonly seen when SQLite is compiled as a single ** translation unit. ** ** This file is all you need to compile SQLite. To use SQLite in other ** programs, you need this file and the "sqlite3.h" header file that defines ** the programming interface to the SQLite library. (If you do not have @@ -195,17 +195,17 @@ ** checkpointing the database in WAL mode. */ #ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT # define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000 #endif /* ** The maximum number of attached databases. This must be between 0 -** and 30. The upper bound on 30 is because a 32-bit integer bitmap +** and 62. The upper bound on 62 is because a 64-bit integer bitmap ** is used internally to track attached databases. */ #ifndef SQLITE_MAX_ATTACHED # define SQLITE_MAX_ATTACHED 10 #endif /* @@ -645,19 +645,19 @@ extern "C" { ** within its configuration management system. ^The SQLITE_SOURCE_ID ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.7.5" -#define SQLITE_VERSION_NUMBER 3007005 -#define SQLITE_SOURCE_ID "2011-01-28 17:03:50 ed759d5a9edb3bba5f48f243df47be29e3fe8cd7" +#define SQLITE_VERSION "3.7.7.1" +#define SQLITE_VERSION_NUMBER 3007007 +#define SQLITE_SOURCE_ID "2011-06-28 17:39:05 af0d91adf497f5f36ec3813f04235a6e195a605f" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros ** but are associated with the library instead of the header file. ^(Cautious @@ -848,17 +848,17 @@ typedef int (*sqlite3_callback)(void*,in ** without having to use a lot of C code. ** ** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, ** semicolon-separate SQL statements passed into its 2nd argument, ** in the context of the [database connection] passed in as its 1st ** argument. ^If the callback function of the 3rd argument to ** sqlite3_exec() is not NULL, then it is invoked for each result row ** coming out of the evaluated SQL statements. ^The 4th argument to -** to sqlite3_exec() is relayed through to the 1st argument of each +** sqlite3_exec() is relayed through to the 1st argument of each ** callback invocation. ^If the callback pointer to sqlite3_exec() ** is NULL, then no callback is ever invoked and result rows are ** ignored. ** ** ^If an error occurs while evaluating the SQL statements passed into ** sqlite3_exec(), then execution of the current statement stops and ** subsequent statements are skipped. ^If the 5th parameter to sqlite3_exec() ** is not NULL then any error message is written into memory obtained @@ -913,17 +913,18 @@ SQLITE_API int sqlite3_exec( ** KEYWORDS: SQLITE_OK {error code} {error codes} ** KEYWORDS: {result code} {result codes} ** ** Many SQLite functions return an integer result code from the set shown ** here in order to indicates success or failure. ** ** New error codes may be added in future versions of SQLite. ** -** See also: [SQLITE_IOERR_READ | extended result codes] +** See also: [SQLITE_IOERR_READ | extended result codes], +** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ #define SQLITE_ERROR 1 /* SQL error or missing database */ #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 */ #define SQLITE_BUSY 5 /* The database file is locked */ @@ -990,47 +991,54 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8)) #define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8)) #define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8)) #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) +#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) +#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) +#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) +#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) +#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and -** in the 4th parameter to the xOpen method of the -** [sqlite3_vfs] object. +** in the 4th parameter to the [sqlite3_vfs.xOpen] method. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ +#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ #define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ #define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ #define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ +/* Reserved: 0x00F00000 */ + /* ** CAPI3REF: Device Characteristics ** ** The xDeviceCharacteristics method of the [sqlite3_io_methods] ** object returns an integer which is a vector of the these ** bit values expressing I/O characteristics of the mass storage ** device that holds the file that the [sqlite3_io_methods] ** refers to. @@ -1116,27 +1124,28 @@ SQLITE_API int sqlite3_exec( typedef struct sqlite3_file sqlite3_file; struct sqlite3_file { const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ }; /* ** CAPI3REF: OS Interface File Virtual Methods Object ** -** Every file opened by the [sqlite3_vfs] xOpen method populates an +** Every file opened by the [sqlite3_vfs.xOpen] method populates an ** [sqlite3_file] object (or, more commonly, a subclass of the ** [sqlite3_file] object) with a pointer to an instance of this object. ** This object defines the methods used to perform various operations ** against the open file represented by the [sqlite3_file] object. ** -** If the xOpen method sets the sqlite3_file.pMethods element +** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method -** may be invoked even if the xOpen reported that it failed. The -** only way to prevent a call to xClose following a failed xOpen -** is for the xOpen to set the sqlite3_file.pMethods element to NULL. +** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The +** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] +** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element +** to NULL. ** ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). ** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] ** flag may be ORed in to indicate that only the data of the file ** and not its inode needs to be synced. ** ** The integer values to xLock() and xUnlock() are one of @@ -1268,17 +1277,17 @@ struct sqlite3_io_methods { ** ** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by ** SQLite and sent to all VFSes in place of a call to the xSync method ** when the database connection has [PRAGMA synchronous] set to OFF.)^ ** Some specialized VFSes need this signal in order to operate correctly ** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most ** VFSes do not need this signal and should silently ignore this opcode. ** Applications should not call [sqlite3_file_control()] with this -** opcode as doing so may disrupt the operation of the specilized VFSes +** opcode as doing so may disrupt the operation of the specialized VFSes ** that do require it. */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 @@ -1298,17 +1307,18 @@ struct sqlite3_io_methods { */ typedef struct sqlite3_mutex sqlite3_mutex; /* ** CAPI3REF: OS Interface Object ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" -** in the name of the object stands for "virtual file system". +** in the name of the object stands for "virtual file system". See +** the [VFS | VFS documentation] for further information. ** ** The value of the iVersion field is initially 1 but may be larger in ** future versions of SQLite. Additional fields may be appended to this ** object when the iVersion value is increased. Note that the structure ** of the sqlite3_vfs object changes in the transaction between ** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not ** modified. ** @@ -1327,16 +1337,17 @@ typedef struct sqlite3_mutex sqlite3_mut ** structure that SQLite will ever modify. SQLite will only access ** or modify this field while holding a particular static mutex. ** The application should never modify anything within the sqlite3_vfs ** object once the object has been registered. ** ** The zName field holds the name of the VFS module. The name must ** be unique across all VFS modules. ** +** [[sqlite3_vfs.xOpen]] ** ^SQLite guarantees that the zFilename parameter to xOpen ** is either a NULL pointer or string obtained ** from xFullPathname() with an optional suffix added. ** ^If a suffix is added to the zFilename parameter, it will ** consist of a single "-" character followed by no more than ** 10 alphanumeric and/or "-" characters. ** ^SQLite further guarantees that ** the string will be valid and unchanged until xClose() is @@ -1404,16 +1415,17 @@ typedef struct sqlite3_mutex sqlite3_mut ** argument to xOpen. The xOpen method does not have to ** allocate the structure; it should just fill it in. Note that ** the xOpen method must set the sqlite3_file.pMethods to either ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods ** element will be valid after xOpen returns regardless of the success ** or failure of the xOpen call. ** +** [[sqlite3_vfs.xAccess]] ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] ** to test whether a file is at least readable. The file can be a ** directory. ** ** ^SQLite will always allocate at least mxPathname+1 bytes for the ** output buffer xFullPathname. The exact size of the output buffer @@ -1428,26 +1440,39 @@ typedef struct sqlite3_mutex sqlite3_mut ** The xRandomness() function attempts to return nBytes bytes ** of good-quality randomness into zOut. The return value is ** the actual number of bytes of randomness obtained. ** The xSleep() method causes the calling thread to sleep for at ** least the number of microseconds given. ^The xCurrentTime() ** method returns a Julian Day Number for the current date and time as ** a floating point value. ** ^The xCurrentTimeInt64() method returns, as an integer, the Julian -** Day Number multipled by 86400000 (the number of milliseconds in +** Day Number multiplied by 86400000 (the number of milliseconds in ** a 24-hour day). ** ^SQLite will use the xCurrentTimeInt64() method to get the current ** date and time if that method is available (if iVersion is 2 or ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. +** +** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces +** are not used by the SQLite core. These optional interfaces are provided +** by some VFSes to facilitate testing of the VFS code. By overriding +** system calls with functions under its control, a test program can +** simulate faults and error conditions that would otherwise be difficult +** or impossible to induce. The set of system calls that can be overridden +** varies from one VFS to another, and from one version of the same VFS to the +** next. Applications that use these interfaces must be prepared for any +** or all of these interfaces to be NULL or for their behavior to change +** from one release to the next. Applications must not attempt to access +** any of these methods if the iVersion of the VFS is less than 3. */ typedef struct sqlite3_vfs sqlite3_vfs; +typedef void (*sqlite3_syscall_ptr)(void); struct sqlite3_vfs { - int iVersion; /* Structure version number (currently 2) */ + int iVersion; /* Structure version number (currently 3) */ int szOsFile; /* Size of subclassed sqlite3_file */ int mxPathname; /* Maximum file pathname length */ sqlite3_vfs *pNext; /* Next registered VFS */ const char *zName; /* Name of this virtual file system */ void *pAppData; /* Pointer to application-specific data */ int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, int flags, int *pOutFlags); int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); @@ -1463,16 +1488,23 @@ struct sqlite3_vfs { int (*xGetLastError)(sqlite3_vfs*, int, char *); /* ** The methods above are in version 1 of the sqlite_vfs object ** definition. Those that follow are added in version 2 or later */ int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); /* ** The methods above are in versions 1 and 2 of the sqlite_vfs object. + ** Those below are for version 3 and greater. + */ + int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); + sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); + const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); + /* + ** The methods above are in versions 1 through 3 of the sqlite_vfs object. ** New fields may be appended in figure versions. The iVersion ** value will increment whenever this happens. */ }; /* ** CAPI3REF: Flags for the xAccess VFS method ** @@ -1630,44 +1662,39 @@ SQLITE_API int sqlite3_os_end(void); ** may only be invoked prior to library initialization using ** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before ** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** ** The first argument to sqlite3_config() is an integer -** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines +** [configuration option] that determines ** what property of SQLite is to be configured. Subsequent arguments -** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option] +** vary depending on the [configuration option] ** in the first argument. ** ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. ** ^If the option is unknown or SQLite is unable to set the option ** then this routine returns a non-zero [error code]. */ SQLITE_API int sqlite3_config(int, ...); /* ** CAPI3REF: Configure database connections ** ** The sqlite3_db_config() interface is used to make configuration ** changes to a [database connection]. The interface is similar to ** [sqlite3_config()] except that the changes apply to a single -** [database connection] (specified in the first argument). The -** sqlite3_db_config() interface should only be used immediately after -** the database connection is created using [sqlite3_open()], -** [sqlite3_open16()], or [sqlite3_open_v2()]. +** [database connection] (specified in the first argument). ** ** The second argument to sqlite3_db_config(D,V,...) is the -** configuration verb - an integer code that indicates what -** aspect of the [database connection] is being configured. -** The only choice for this value is [SQLITE_DBCONFIG_LOOKASIDE]. -** New verbs are likely to be added in future releases of SQLite. -** Additional arguments depend on the verb. +** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code +** that indicates what aspect of the [database connection] is being configured. +** Subsequent arguments vary depending on the configuration verb. ** ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if ** the call is considered successful. */ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); /* ** CAPI3REF: Memory Allocation Routines @@ -1747,120 +1774,121 @@ struct sqlite3_mem_methods { int (*xRoundup)(int); /* Round up request size to allocation size */ int (*xInit)(void*); /* Initialize the memory allocator */ void (*xShutdown)(void*); /* Deinitialize the memory allocator */ void *pAppData; /* Argument to xInit() and xShutdown() */ }; /* ** CAPI3REF: Configuration Options +** KEYWORDS: {configuration option} ** ** These constants are the available integer configuration options that ** can be passed as the first argument to the [sqlite3_config()] interface. ** ** New configuration options may be added in future releases of SQLite. ** Existing configuration options might be discontinued. Applications ** should check the return code from [sqlite3_config()] to make sure that ** the call worked. The [sqlite3_config()] interface will return a ** non-zero [error code] if a discontinued or unsupported configuration option ** is invoked. ** ** <dl> -** <dt>SQLITE_CONFIG_SINGLETHREAD</dt> +** [[SQLITE_CONFIG_SINGLETHREAD]] <dt>SQLITE_CONFIG_SINGLETHREAD</dt> ** <dd>There are no arguments to this option. ^This option sets the ** [threading mode] to Single-thread. In other words, it disables ** all mutexing and puts SQLite into a mode where it can only be used ** by a single thread. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to change the [threading mode] from its default ** value of Single-thread and so [sqlite3_config()] will return ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD ** configuration option.</dd> ** -** <dt>SQLITE_CONFIG_MULTITHREAD</dt> +** [[SQLITE_CONFIG_MULTITHREAD]] <dt>SQLITE_CONFIG_MULTITHREAD</dt> ** <dd>There are no arguments to this option. ^This option sets the ** [threading mode] to Multi-thread. In other words, it disables ** mutexing on [database connection] and [prepared statement] objects. ** The application is responsible for serializing access to ** [database connections] and [prepared statements]. But other mutexes ** are enabled so that SQLite will be safe to use in a multi-threaded ** environment as long as no two threads attempt to use the same ** [database connection] at the same time. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to set the Multi-thread [threading mode] and ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_MULTITHREAD configuration option.</dd> ** -** <dt>SQLITE_CONFIG_SERIALIZED</dt> +** [[SQLITE_CONFIG_SERIALIZED]] <dt>SQLITE_CONFIG_SERIALIZED</dt> ** <dd>There are no arguments to this option. ^This option sets the ** [threading mode] to Serialized. In other words, this option enables ** all mutexes including the recursive ** mutexes on [database connection] and [prepared statement] objects. ** In this mode (which is the default when SQLite is compiled with ** [SQLITE_THREADSAFE=1]) the SQLite library will itself serialize access ** to [database connections] and [prepared statements] so that the ** application is free to use the same [database connection] or the ** same [prepared statement] in different threads at the same time. ** ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to set the Serialized [threading mode] and ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_SERIALIZED configuration option.</dd> ** -** <dt>SQLITE_CONFIG_MALLOC</dt> +** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt> ** <dd> ^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mem_methods] structure. The argument specifies ** alternative low-level memory allocation routines to be used in place of ** the memory allocation routines built into SQLite.)^ ^SQLite makes ** its own private copy of the content of the [sqlite3_mem_methods] structure ** before the [sqlite3_config()] call returns.</dd> ** -** <dt>SQLITE_CONFIG_GETMALLOC</dt> +** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt> ** <dd> ^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] ** structure is filled with the currently defined memory allocation routines.)^ ** This option can be used to overload the default memory allocation ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example. </dd> ** -** <dt>SQLITE_CONFIG_MEMSTATUS</dt> +** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt> ** <dd> ^This option takes single argument of type int, interpreted as a ** boolean, which enables or disables the collection of memory allocation ** statistics. ^(When memory allocation statistics are disabled, the ** following SQLite interfaces become non-operational: ** <ul> ** <li> [sqlite3_memory_used()] ** <li> [sqlite3_memory_highwater()] ** <li> [sqlite3_soft_heap_limit64()] ** <li> [sqlite3_status()] ** </ul>)^ ** ^Memory allocation statistics are enabled by default unless SQLite is ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory ** allocation statistics are disabled by default. ** </dd> ** -** <dt>SQLITE_CONFIG_SCRATCH</dt> +** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt> ** <dd> ^This option specifies a static memory buffer that SQLite can use for ** scratch memory. There are three arguments: A pointer an 8-byte -** aligned memory buffer from which the scrach allocations will be +** 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 sz ** argument must be a multiple of 16. ** The first argument must be a pointer to an 8-byte aligned buffer ** of at least sz*N bytes of memory. ** ^SQLite will use no more than two scratch buffers per thread. So ** N should be set to twice the expected maximum number of threads. ** ^SQLite will never require 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.</dd> ** -** <dt>SQLITE_CONFIG_PAGECACHE</dt> +** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt> ** <dd> ^This option specifies a static memory buffer that SQLite can use for -** the database page cache with the default page cache implemenation. +** the database page cache with the default page cache implementation. ** This configuration should not be used if an application-define page ** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option. ** There are three arguments to this option: A pointer to 8-byte aligned ** memory, the size of each page buffer (sz), and the number of pages (N). ** The sz argument should be the size of the largest database page ** (a power of two between 512 and 32768) plus a little extra for each ** page header. ^The page header size is 20 to 40 bytes depending on ** the host architecture. ^It is harmless, apart from the wasted memory, @@ -1869,78 +1897,80 @@ struct sqlite3_mem_methods { ** ^SQLite will use the memory provided by the first argument to satisfy its ** memory needs for the first N pages that it adds to cache. ^If additional ** page cache memory is needed beyond what is provided by this option, then ** SQLite goes to [sqlite3_malloc()] for the additional storage space. ** The pointer in the first argument must ** be aligned to an 8-byte boundary or subsequent behavior of SQLite ** will be undefined.</dd> ** -** <dt>SQLITE_CONFIG_HEAP</dt> +** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt> ** <dd> ^This 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]. ** There are three arguments: An 8-byte aligned pointer to the memory, ** the number of bytes in the memory buffer, and the minimum allocation size. ** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts ** to using its default memory allocator (the system malloc() implementation), ** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory ** allocator is engaged to handle all of SQLites memory allocation needs. ** The first pointer (the memory pointer) must be aligned to an 8-byte -** boundary or subsequent behavior of SQLite will be undefined.</dd> -** -** <dt>SQLITE_CONFIG_MUTEX</dt> +** boundary or subsequent behavior of SQLite will be undefined. +** The minimum allocation size is capped at 2^12. Reasonable values +** for the minimum allocation size are 2^5 through 2^8.</dd> +** +** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> ** <dd> ^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mutex_methods] structure. The argument specifies ** alternative low-level mutex routines to be used in place ** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the ** content of the [sqlite3_mutex_methods] structure before the call to ** [sqlite3_config()] returns. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** the entire mutexing subsystem is omitted from the build and hence calls to ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will ** return [SQLITE_ERROR].</dd> ** -** <dt>SQLITE_CONFIG_GETMUTEX</dt> +** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt> ** <dd> ^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mutex_methods] structure. The ** [sqlite3_mutex_methods] ** structure is filled with the currently defined mutex routines.)^ ** This option can be used to overload the default mutex allocation ** routines with a wrapper used to track mutex usage for performance ** profiling or testing, for example. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** the entire mutexing subsystem is omitted from the build and hence calls to ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will ** return [SQLITE_ERROR].</dd> ** -** <dt>SQLITE_CONFIG_LOOKASIDE</dt> +** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt> ** <dd> ^(This option takes two arguments that determine the default ** memory allocation for the lookaside memory allocator on each ** [database connection]. The first argument is the ** size of each lookaside buffer slot and the second is the number of ** slots allocated to each database connection.)^ ^(This option sets the ** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] ** verb to [sqlite3_db_config()] can be used to change the lookaside ** configuration on individual connections.)^ </dd> ** -** <dt>SQLITE_CONFIG_PCACHE</dt> +** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt> ** <dd> ^(This option takes a single argument which is a pointer to ** an [sqlite3_pcache_methods] object. This object specifies the interface ** to a custom page cache implementation.)^ ^SQLite makes a copy of the ** object and uses it for page cache memory allocations.</dd> ** -** <dt>SQLITE_CONFIG_GETPCACHE</dt> +** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt> ** <dd> ^(This option takes a single argument which is a pointer to an ** [sqlite3_pcache_methods] object. SQLite copies of the current ** page cache implementation into that object.)^ </dd> ** -** <dt>SQLITE_CONFIG_LOG</dt> +** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt> ** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a ** function with a call signature of void(*)(void*,int,const char*), ** and a pointer to void. ^If the function pointer is not NULL, it is ** invoked by [sqlite3_log()] to process each logging event. ^If the ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. ** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is ** passed through as the first parameter to the application-defined logger ** function whenever that function is invoked. ^The second parameter to @@ -1948,16 +1978,28 @@ struct sqlite3_mem_methods { ** [sqlite3_log()] call and is intended to be a [result code] or an ** [extended result code]. ^The third parameter passed to the logger is ** log message after formatting via [sqlite3_snprintf()]. ** The SQLite logging interface is not reentrant; the logger function ** supplied by the application must not invoke any SQLite interface. ** In a multi-threaded application, the application-defined logger ** function must be threadsafe. </dd> ** +** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI +** <dd> This option takes a single argument of type int. If non-zero, then +** URI handling is globally enabled. If the parameter is zero, then URI handling +** is globally disabled. If URI handling is globally enabled, all filenames +** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or +** specified as part of [ATTACH] commands are interpreted as URIs, regardless +** of whether or not the [SQLITE_OPEN_URI] flag is set when the database +** connection is opened. If it is globally disabled, filenames are +** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the +** database connection is opened. By default, URI handling is globally +** disabled. The default value may be changed by compiling with the +** [SQLITE_USE_URI] symbol defined. ** </dl> */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #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 */ @@ -1966,16 +2008,17 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ #define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ #define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ #define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */ #define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */ #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ +#define SQLITE_CONFIG_URI 17 /* int */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that ** can be passed as the second argument to the [sqlite3_db_config()] interface. ** ** New configuration options may be added in future releases of SQLite. @@ -1985,17 +2028,17 @@ struct sqlite3_mem_methods { ** non-zero [error code] if a discontinued or unsupported configuration option ** is invoked. ** ** <dl> ** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt> ** <dd> ^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. ** ^The first argument (the third parameter to [sqlite3_db_config()] is a -** pointer to an memory buffer to use for lookaside memory. +** pointer to a memory buffer to use for lookaside memory. ** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb ** may be NULL in which case SQLite will allocate the ** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the ** size of each lookaside buffer slot. ^The third argument is the number of ** slots. The size of the buffer in the first argument must be greater than ** or equal to the product of the second and third arguments. The buffer ** must be aligned to an 8-byte boundary. ^If the second argument to ** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally @@ -2003,19 +2046,41 @@ struct sqlite3_mem_methods { ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words ** when the "current value" returned by ** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^</dd> ** +** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt> +** <dd> ^This option is used to enable or disable the enforcement of +** [foreign key constraints]. There should be two additional arguments. +** The first argument is an integer which is 0 to disable FK enforcement, +** positive to enable FK enforcement or negative to leave FK enforcement +** unchanged. The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether FK enforcement is off or on +** following this call. The second parameter may be a NULL pointer, in +** which case the FK enforcement setting is not reported back. </dd> +** +** <dt>SQLITE_DBCONFIG_ENABLE_TRIGGER</dt> +** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers]. +** There should be two additional arguments. +** The first argument is an integer which is 0 to disable triggers, +** positive to enable triggers or negative to leave the setting unchanged. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether triggers are disabled or enabled +** following this call. The second parameter may be a NULL pointer, in +** which case the trigger setting is not reported back. </dd> +** ** </dl> */ -#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ +#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ +#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes ** ** ^The sqlite3_extended_result_codes() routine enables or disables the ** [extended result codes] feature of SQLite. ^The extended result ** codes are disabled by default for historical compatibility. @@ -2029,23 +2094,27 @@ SQLITE_API int sqlite3_extended_result_c ** integer key called the [ROWID | "rowid"]. ^The rowid is always available ** as an undeclared column named ROWID, OID, or _ROWID_ as long as those ** names are not also used by explicitly declared columns. ^If ** the table has a column of type [INTEGER PRIMARY KEY] then that column ** is another alias for the rowid. ** ** ^This routine returns the [rowid] of the most recent ** successful [INSERT] into the database from the [database connection] -** in the first argument. ^If no successful [INSERT]s +** in the first argument. ^As of SQLite version 3.7.7, this routines +** records the last insert rowid of both ordinary tables and [virtual tables]. +** ^If no successful [INSERT]s ** have ever occurred on that database connection, zero is returned. ** -** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted -** row is returned by this routine as long as the trigger is running. -** But once the trigger terminates, the value returned by this routine -** reverts to the last value inserted before the trigger fired.)^ +** ^(If an [INSERT] occurs within a trigger or within a [virtual table] +** method, then this routine will return the [rowid] of the inserted +** row as long as the trigger or virtual table method is running. +** But once the trigger or virtual table method ends, the value returned +** by this routine reverts to what it was before the trigger or virtual +** table method began.)^ ** ** ^An [INSERT] that fails due to a constraint violation is not a ** successful [INSERT] and does not change the value returned by this ** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, ** and INSERT OR ABORT make no changes to the return value of this ** routine when their insertion fails. ^(When INSERT OR REPLACE ** encounters a constraint violation, it does not fail. The ** INSERT continues to completion after deleting rows that caused @@ -2607,17 +2676,17 @@ SQLITE_API sqlite3_int64 sqlite3_memory_ ** internally and without recourse to the [sqlite3_vfs] xRandomness ** method. */ SQLITE_API void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks ** -** ^This routine registers a authorizer callback with a particular +** ^This routine registers an authorizer callback with a particular ** [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 ** 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 ** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the @@ -2698,16 +2767,19 @@ SQLITE_API int sqlite3_set_authorizer( /* ** CAPI3REF: Authorizer Return Codes ** ** The [sqlite3_set_authorizer | authorizer callback function] must ** return either [SQLITE_OK] or one of these two constants in order ** to signal SQLite whether or not the action is permitted. See the ** [sqlite3_set_authorizer | authorizer documentation] for additional ** information. +** +** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code] +** from the [sqlite3_vtab_on_conflict()] interface. */ #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ /* ** CAPI3REF: Authorizer Action Codes ** ** The [sqlite3_set_authorizer()] interface registers a callback function @@ -2820,17 +2892,17 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sql ** database connections for the meaning of "modify" in this paragraph. ** */ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); /* ** CAPI3REF: Opening A New Database Connection ** -** ^These routines open an SQLite database file whose name is given by the +** ^These routines open an SQLite database file as specified by the ** filename argument. ^The filename argument is interpreted as UTF-8 for ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte ** order for sqlite3_open16(). ^(A [database connection] handle is usually ** returned in *ppDb, even if an error occurs. The only exception is that ** if SQLite is unable to allocate memory to hold the [sqlite3] object, ** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] ** object.)^ ^(If the database is opened (and/or created) successfully, then ** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The @@ -2847,17 +2919,17 @@ SQLITE_API void sqlite3_progress_handler ** passing it to [sqlite3_close()] when it is no longer required. ** ** The sqlite3_open_v2() interface works like sqlite3_open() ** except that it accepts two additional parameters for additional control ** over the new database connection. ^(The flags parameter to ** sqlite3_open_v2() can take one of ** the following three values, optionally combined with the ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], -** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^ +** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ ** ** <dl> ** ^(<dt>[SQLITE_OPEN_READONLY]</dt> ** <dd>The database is opened in read-only mode. If the database does not ** already exist, an error is returned.</dd>)^ ** ** ^(<dt>[SQLITE_OPEN_READWRITE]</dt> ** <dd>The database is opened for reading and writing if possible, or reading @@ -2866,49 +2938,154 @@ SQLITE_API void sqlite3_progress_handler ** ** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt> ** <dd>The database is opened for reading and writing, and is created if ** it does not already exist. This is the behavior that is always used for ** sqlite3_open() and sqlite3_open16().</dd>)^ ** </dl> ** ** If the 3rd parameter to sqlite3_open_v2() is not one of the -** combinations shown above or one of the combinations shown above combined -** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], -** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags, +** combinations shown above optionally combined with other +** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] ** then the behavior is undefined. ** ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection ** opens in the multi-thread [threading mode] as long as the single-thread ** mode has not been set at compile-time or start-time. ^If the ** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens ** in the serialized [threading mode] unless single-thread was ** previously selected at compile-time or start-time. ** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be ** eligible to use [shared cache mode], regardless of whether or not shared ** cache is enabled using [sqlite3_enable_shared_cache()]. ^The ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not ** participate in [shared cache mode] even if it is enabled. ** +** ^The fourth parameter to sqlite3_open_v2() is the name of the +** [sqlite3_vfs] object that defines the operating system interface that +** the new database connection should use. ^If the fourth parameter is +** a NULL pointer then the default [sqlite3_vfs] object is used. +** ** ^If the filename is ":memory:", then a private, temporary in-memory database ** is created for the connection. ^This in-memory database will vanish when ** the database connection is closed. Future versions of SQLite might ** make use of additional special filenames that begin with the ":" character. ** It is recommended that when a database filename actually does begin with ** a ":" character you should prefix the filename with a pathname such as ** "./" to avoid ambiguity. ** ** ^If the filename is an empty string, then a private, temporary ** on-disk database will be created. ^This private database will be ** automatically deleted as soon as the database connection is closed. ** -** ^The fourth parameter to sqlite3_open_v2() is the name of the -** [sqlite3_vfs] object that defines the operating system interface that -** the new database connection should use. ^If the fourth parameter is -** a NULL pointer then the default [sqlite3_vfs] object is used. +** [[URI filenames in sqlite3_open()]] <h3>URI Filenames</h3> +** +** ^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 +** 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 +** by default, but future releases of SQLite might enable URI filename +** interpretation by default. See "[URI filenames]" for additional +** information. +** +** URI filenames are parsed according to RFC 3986. ^If the URI contains an +** authority, then it must be either an empty string or the string +** "localhost". ^If the authority is not an empty string or "localhost", an +** error is returned to the caller. ^The fragment component of a URI, if +** present, is ignored. +** +** ^SQLite uses the path component of the URI as the name of the disk file +** which contains the database. ^If the path begins with a '/' character, +** then it is interpreted as an absolute path. ^If the path does not begin +** with a '/' (meaning that the authority section is omitted from the URI) +** then the path is interpreted as a relative path. +** ^On windows, the first component of an absolute path +** is a drive specification (e.g. "C:"). +** +** [[core URI query parameters]] +** The query component of a URI may contain parameters that are interpreted +** either by SQLite itself, or by a [VFS | custom VFS implementation]. +** SQLite interprets the following three query parameters: +** +** <ul> +** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of +** a VFS object that provides the operating system interface that should +** be used to access the database file on disk. ^If this option is set to +** an empty string the default VFS object is used. ^Specifying an unknown +** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is +** present, then the VFS specified by the option takes precedence over +** the value passed as the fourth parameter to sqlite3_open_v2(). +** +** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw" or +** "rwc". Attempting to set it to any other value is an error)^. +** ^If "ro" is specified, then the database is opened for read-only +** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the +** third argument to sqlite3_prepare_v2(). ^If the mode option is set to +** "rw", then the database is opened for read-write (but not create) +** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had +** been set. ^Value "rwc" is equivalent to setting both +** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is +** used, it is an error to specify a value for the mode parameter that is +** less restrictive than that specified by the flags passed as the third +** parameter. +** +** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or +** "private". ^Setting it to "shared" is equivalent to setting the +** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to +** sqlite3_open_v2(). ^Setting the cache parameter to "private" is +** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. +** ^If sqlite3_open_v2() is used and the "cache" parameter is present in +** a URI filename, its value overrides any behaviour requested by setting +** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. +** </ul> +** +** ^Specifying an unknown parameter in the query component of a URI is not an +** error. Future versions of SQLite might understand additional query +** parameters. See "[query parameters with special meaning to SQLite]" for +** additional information. +** +** [[URI filename examples]] <h3>URI filename examples</h3> +** +** <table border="1" align=center cellpadding=5> +** <tr><th> URI filenames <th> Results +** <tr><td> file:data.db <td> +** Open the file "data.db" in the current directory. +** <tr><td> file:/home/fred/data.db<br> +** file:///home/fred/data.db <br> +** file://localhost/home/fred/data.db <br> <td> +** Open the database file "/home/fred/data.db". +** <tr><td> file://darkstar/home/fred/data.db <td> +** An error. "darkstar" is not a recognized authority. +** <tr><td style="white-space:nowrap"> +** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db +** <td> Windows only: Open the file "data.db" on fred's desktop on drive +** C:. Note that the %20 escaping in this example is not strictly +** necessary - space characters can be used literally +** in URI filenames. +** <tr><td> file:data.db?mode=ro&cache=private <td> +** Open file "data.db" in the current directory for read-only access. +** Regardless of whether or not shared-cache mode is enabled by +** default, use a private cache. +** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td> +** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". +** <tr><td> file:data.db?mode=readonly <td> +** An error. "readonly" is not a valid option for the "mode" parameter. +** </table> +** +** ^URI hexadecimal escape sequences (%HH) are supported within the path and +** query components of a URI. A hexadecimal escape sequence consists of a +** percent sign - "%" - followed by exactly two hexadecimal digits +** specifying an octet value. ^Before the path or query components of a +** URI filename are interpreted, they are encoded using UTF-8 and all +** hexadecimal escape sequences replaced by a single byte containing the +** corresponding octet. If this process generates an invalid UTF-8 encoding, +** the results are undefined. ** ** <b>Note to Windows users:</b> The encoding used for the filename argument ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever ** codepage is currently defined. Filenames containing international ** characters must be converted to UTF-8 prior to passing them into ** sqlite3_open() or sqlite3_open_v2(). */ SQLITE_API int sqlite3_open( @@ -2922,16 +3099,36 @@ SQLITE_API int sqlite3_open16( SQLITE_API int sqlite3_open_v2( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb, /* OUT: SQLite db handle */ int flags, /* Flags */ const char *zVfs /* Name of VFS module to use */ ); /* +** CAPI3REF: Obtain Values For URI Parameters +** +** This is a utility routine, useful to VFS implementations, that checks +** to see if a database file was a URI that contained a specific query +** parameter, and if so obtains the value of the query parameter. +** +** The zFilename argument is the filename pointer passed into the xOpen() +** method of a VFS implementation. The zParam argument is the name of the +** query parameter we seek. This routine returns the value of the zParam +** parameter if it exists. If the parameter does not exist, this routine +** returns a NULL pointer. +** +** If the zFilename argument to this function is not a pointer that SQLite +** passed into the xOpen VFS method, then the behavior of this routine +** is undefined and probably undesirable. +*/ +SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); + + +/* ** CAPI3REF: Error Codes And Messages ** ** ^The sqlite3_errcode() interface returns the numeric [result code] or ** [extended result code] for the most recent failed sqlite3_* API call ** associated with a [database connection]. If a prior API call failed ** but the most recent API call succeeded, the return value from ** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode() ** interface is the same except that it always returns the @@ -3036,53 +3233,55 @@ SQLITE_API int sqlite3_limit(sqlite3*, i ** KEYWORDS: {limit category} {*limit categories} ** ** These constants define various performance limits ** that can be lowered at run-time using [sqlite3_limit()]. ** The synopsis of the meanings of the various limits is shown below. ** Additional information is available at [limits | Limits in SQLite]. ** ** <dl> -** ^(<dt>SQLITE_LIMIT_LENGTH</dt> +** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt> ** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^ ** -** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt> +** [[SQLITE_LIMIT_SQL_LENGTH]] ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt> ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^ ** -** ^(<dt>SQLITE_LIMIT_COLUMN</dt> +** [[SQLITE_LIMIT_COLUMN]] ^(<dt>SQLITE_LIMIT_COLUMN</dt> ** <dd>The maximum number of columns in a table definition or in the ** result set of a [SELECT] or the maximum number of columns in an index ** or in an ORDER BY or GROUP BY clause.</dd>)^ ** -** ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> +** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> ** <dd>The maximum depth of the parse tree on any expression.</dd>)^ ** -** ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt> +** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt> ** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^ ** -** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt> +** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt> ** <dd>The maximum number of instructions in a virtual machine program ** used to implement an SQL statement. This limit is not currently ** enforced, though that might be added in some future release of ** SQLite.</dd>)^ ** -** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt> +** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt> ** <dd>The maximum number of arguments on a function.</dd>)^ ** -** ^(<dt>SQLITE_LIMIT_ATTACHED</dt> +** [[SQLITE_LIMIT_ATTACHED]] ^(<dt>SQLITE_LIMIT_ATTACHED</dt> ** <dd>The maximum number of [ATTACH | attached databases].)^</dd> ** +** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] ** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt> ** <dd>The maximum length of the pattern argument to the [LIKE] or ** [GLOB] operators.</dd>)^ ** +** [[SQLITE_LIMIT_VARIABLE_NUMBER]] ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> ** <dd>The maximum index number of any [parameter] in an SQL statement.)^ ** -** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> +** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> ** <dd>The maximum depth of recursion for triggers.</dd>)^ ** </dl> */ #define SQLITE_LIMIT_LENGTH 0 #define SQLITE_LIMIT_SQL_LENGTH 1 #define SQLITE_LIMIT_COLUMN 2 #define SQLITE_LIMIT_EXPR_DEPTH 3 #define SQLITE_LIMIT_COMPOUND_SELECT 4 @@ -3209,17 +3408,17 @@ SQLITE_API int sqlite3_prepare16_v2( ** SQL text used to create a [prepared statement] if that statement was ** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database ** -** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if +** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if ** and only if the [prepared statement] X makes no direct changes to ** the content of the database file. ** ** Note that [application-defined SQL functions] or ** [virtual tables] might change the database indirectly as a side effect. ** ^(For example, if an application defines a function "eval()" that ** calls [sqlite3_exec()], then the following SQL statement would ** change the database file through side-effects: @@ -3253,17 +3452,17 @@ SQLITE_API int sqlite3_stmt_readonly(sql ** ** An sqlite3_value object may be either "protected" or "unprotected". ** Some interfaces require a protected sqlite3_value. Other interfaces ** will accept either a protected or an unprotected sqlite3_value. ** Every interface that accepts sqlite3_value arguments specifies ** whether or not it requires a protected sqlite3_value. ** ** The terms "protected" and "unprotected" refer to whether or not -** a mutex is held. A internal mutex is held for a protected +** a mutex is held. An internal mutex is held for a protected ** sqlite3_value object but no mutex is held for an unprotected ** sqlite3_value object. If SQLite is compiled to be single-threaded ** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) ** or if SQLite is run in one of reduced mutex modes ** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD] ** then there is no distinction between protected and unprotected ** sqlite3_value objects and they can be used interchangeably. However, ** for maximum code portability it is recommended that applications @@ -3477,17 +3676,19 @@ SQLITE_API int sqlite3_column_count(sqli ** in the result set of a [SELECT] statement. ^The sqlite3_column_name() ** interface returns a pointer to a zero-terminated UTF-8 string ** and sqlite3_column_name16() returns a pointer to a zero-terminated ** UTF-16 string. ^The first parameter is the [prepared statement] ** that implements the [SELECT] statement. ^The second parameter is the ** column number. ^The leftmost column is number 0. ** ** ^The returned string pointer is valid until either the [prepared statement] -** is destroyed by [sqlite3_finalize()] or until the next call to +** is destroyed by [sqlite3_finalize()] or until the statement is automatically +** reprepared by the first call to [sqlite3_step()] for a particular run +** or until the next call to ** sqlite3_column_name() or sqlite3_column_name16() on the same column. ** ** ^If sqlite3_malloc() fails during the processing of either routine ** (for example during a conversion from UTF-8 to UTF-16) then a ** NULL pointer is returned. ** ** ^The name of a result column is the value of the "AS" clause for ** that column, if there is an AS clause. If there is no AS clause @@ -3503,17 +3704,19 @@ SQLITE_API const void *sqlite3_column_na ** ^These routines provide a means to determine the database, table, and ** table column that is the origin of a particular result column in ** [SELECT] statement. ** ^The name of the database or table or column can be returned as ** either a UTF-8 or UTF-16 string. ^The _database_ routines return ** the database name, the _table_ routines return the table name, and ** the origin_ routines return the column name. ** ^The returned string is valid until the [prepared statement] is destroyed -** using [sqlite3_finalize()] or until the same information is requested +** using [sqlite3_finalize()] or until the statement is automatically +** reprepared by the first call to [sqlite3_step()] for a particular run +** or until the same information is requested ** again in a different encoding. ** ** ^The names returned are the original un-aliased names of the ** database, table, and column. ** ** ^The first argument to these interfaces is a [prepared statement]. ** ^These functions return information about the Nth result column returned by ** the statement, where N is the second function argument. @@ -3597,17 +3800,17 @@ SQLITE_API const void *sqlite3_column_de ** ^In the legacy interface, the return value will be either [SQLITE_BUSY], ** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE]. ** ^With the "v2" interface, any of the other [result codes] or ** [extended result codes] might be returned as well. ** ** ^[SQLITE_BUSY] means that the database engine was unable to acquire the ** database locks it needs to do its job. ^If the statement is a [COMMIT] ** or occurs outside of an explicit transaction, then you can retry the -** statement. If the statement is not a [COMMIT] and occurs within a +** statement. If the statement is not a [COMMIT] and occurs within an ** explicit transaction then you should rollback the transaction before ** continuing. ** ** ^[SQLITE_DONE] means that the statement has finished executing ** successfully. sqlite3_step() should not be called again on this virtual ** machine without first calling [sqlite3_reset()] to reset the virtual ** machine back to its initial state. ** @@ -3876,17 +4079,17 @@ SQLITE_API const unsigned char *sqlite3_ 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); /* ** CAPI3REF: Destroy A Prepared Statement Object ** ** ^The sqlite3_finalize() function is called to delete a [prepared statement]. -** ^If the most recent evaluation of the statement encountered no errors or +** ^If the most recent evaluation of the statement encountered no errors ** or if the statement is never been evaluated, then sqlite3_finalize() returns ** SQLITE_OK. ^If the most recent evaluation of statement S failed, then ** sqlite3_finalize(S) returns the appropriate [error code] or ** [extended error code]. ** ** ^The sqlite3_finalize(S) routine can be called at any point during ** the life cycle of [prepared statement] S: ** before statement S is ever evaluated, after @@ -3935,17 +4138,17 @@ SQLITE_API int sqlite3_reset(sqlite3_stm ** KEYWORDS: {function creation routines} ** KEYWORDS: {application-defined SQL function} ** KEYWORDS: {application-defined SQL functions} ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior ** of existing SQL functions or aggregates. The only differences between ** these routines are the text encoding expected for -** the the second parameter (the name of the function being created) +** the second parameter (the name of the function being created) ** and the presence or absence of a destructor callback for ** the application data pointer. ** ** ^The first parameter is the [database connection] to which the SQL ** function is to be added. ^If an application uses more than one database ** connection then application-defined SQL functions must be added ** to each database connection separately. ** @@ -3980,17 +4183,17 @@ SQLITE_API int sqlite3_reset(sqlite3_stm ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** ** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or ** aggregate. ^A scalar SQL function requires an implementation of the xFunc ** callback only; NULL pointers must be passed as the xStep and xFinal ** parameters. ^An aggregate SQL function requires an implementation of xStep ** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing -** SQL function or aggregate, pass NULL poiners for all three function +** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** ** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL, ** then it is destructor for the application data pointer. ** The destructor is invoked when the function is deleted, either by being ** overloaded or when the database connection closes.)^ ** ^The destructor is also invoked if the call to ** sqlite3_create_function_v2() fails. @@ -4414,33 +4617,33 @@ SQLITE_API void sqlite3_result_zeroblob( ** </ul>)^ ** ^The eTextRep argument determines the encoding of strings passed ** to the collating function callback, xCallback. ** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep ** force strings to be UTF16 with native byte order. ** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin ** on an even byte address. ** -** ^The fourth argument, pArg, is a application data pointer that is passed +** ^The fourth argument, pArg, is an application data pointer that is passed ** through as the first argument to the collating function callback. ** ** ^The fifth argument, xCallback, is a pointer to the collating function. ** ^Multiple collating functions can be registered using the same name but ** with different eTextRep parameters and SQLite will use whichever ** function requires the least amount of data transformation. ** ^If the xCallback argument is NULL then the collating function is ** deleted. ^When all collating functions having the same name are deleted, ** that collation is no longer usable. ** ** ^The collating function callback is invoked with a copy of the pArg ** application data pointer and with two strings in the encoding specified ** by the eTextRep argument. The collating function must return an ** integer that is negative, zero, or positive ** if the first string is less than, equal to, or greater than the second, -** respectively. A collating function must alway return the same answer +** respectively. A collating function must always return the same answer ** given the same inputs. If two or more collating functions are registered ** to the same collation name (using different eTextRep values) then all ** must give an equivalent answer when invoked with equivalent strings. ** The collating function must obey the following properties for all ** strings A, B, and C: ** ** <ol> ** <li> If A==B then B==A. @@ -4842,17 +5045,17 @@ SQLITE_API int sqlite3_release_memory(in ** ^(The soft heap limit is not enforced in the current implementation ** if one or more of following conditions are true: ** ** <ul> ** <li> The soft heap limit is set to zero. ** <li> Memory accounting is disabled using a combination of the ** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and ** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. -** <li> An alternative page cache implementation is specifed using +** <li> An alternative page cache implementation is specified using ** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...). ** <li> The page cache allocates from its own memory pool supplied ** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than ** from the heap. ** </ul>)^ ** ** Beginning with SQLite version 3.7.3, the soft heap limit is enforced ** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] @@ -5063,17 +5266,17 @@ typedef struct sqlite3_vtab sqlite3_vtab typedef struct sqlite3_index_info sqlite3_index_info; typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; typedef struct sqlite3_module sqlite3_module; /* ** CAPI3REF: Virtual Table Object ** KEYWORDS: sqlite3_module {virtual table module} ** -** This structure, sometimes called a a "virtual table module", +** This structure, sometimes called a "virtual table module", ** defines the implementation of a [virtual tables]. ** This structure consists mostly of methods for the module. ** ** ^A virtual table module is created by filling in a persistent ** instance of this structure and passing a pointer to that instance ** to [sqlite3_create_module()] or [sqlite3_create_module_v2()]. ** ^The registration remains valid until it is replaced by a different ** module or until the [database connection] closes. The content @@ -5103,16 +5306,21 @@ struct sqlite3_module { int (*xBegin)(sqlite3_vtab *pVTab); int (*xSync)(sqlite3_vtab *pVTab); int (*xCommit)(sqlite3_vtab *pVTab); int (*xRollback)(sqlite3_vtab *pVTab); int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg); int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); + /* The methods above are in version 1 of the sqlite_module object. Those + ** below are for version 2 and greater. */ + int (*xSavepoint)(sqlite3_vtab *pVTab, int); + int (*xRelease)(sqlite3_vtab *pVTab, int); + int (*xRollbackTo)(sqlite3_vtab *pVTab, int); }; /* ** CAPI3REF: Virtual Table Indexing Information ** KEYWORDS: sqlite3_index_info ** ** The sqlite3_index_info structure and its substructures is used as part ** of the [virtual table] interface to @@ -5375,17 +5583,17 @@ typedef struct sqlite3_blob sqlite3_blob ** regardless of the success or failure of this routine. ** ** ^(If the row that a BLOB handle points to is modified by an ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects ** then the BLOB handle is marked as "expired". ** This is true if any column of the row is changed, even a column ** other than the one the BLOB handle is open on.)^ ** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for -** a expired BLOB handle fail with an return code of [SQLITE_ABORT]. +** an expired BLOB handle fail with a return code of [SQLITE_ABORT]. ** ^(Changes written into a BLOB prior to the BLOB expiring are not ** rolled back by the expiration of the BLOB. Such changes will eventually ** commit if the transaction continues to completion.)^ ** ** ^Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. ^The size of a blob may not be changed by this ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. @@ -5785,17 +5993,17 @@ struct sqlite3_mutex_methods { ** ** ^The implementation is not required to provided versions of these ** routines that actually work. If the implementation does not provide working ** versions of these routines, it should at least provide stubs that always ** return true so that one does not get spurious assertion failures. ** ** ^If the argument to sqlite3_mutex_held() is a NULL pointer then ** the routine should return 1. This seems counter-intuitive since -** clearly the mutex cannot be held if it does not exist. But the +** clearly the mutex cannot be held if it does not exist. But ** the reason the mutex does not exist is because the build is not ** using mutexes. And we do not want the assert() containing the ** call to sqlite3_mutex_held() to fail, so a non-zero return is ** the appropriate thing to do. ^The sqlite3_mutex_notheld() ** interface should also return 1 when given a NULL pointer. */ #ifndef NDEBUG SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); @@ -5908,26 +6116,27 @@ SQLITE_API int sqlite3_test_control(int #define SQLITE_TESTCTRL_PENDING_BYTE 11 #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_PGHDRSZ 17 #define SQLITE_TESTCTRL_SCRATCHMALLOC 18 -#define SQLITE_TESTCTRL_LAST 18 +#define SQLITE_TESTCTRL_LOCALTIME_FAULT 19 +#define SQLITE_TESTCTRL_LAST 19 /* ** CAPI3REF: SQLite Runtime Status ** ** ^This interface is used to retrieve runtime status information ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for ** the specific parameter to measure. ^(Recognized integer codes -** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^ +** are of the form [status parameters | SQLITE_STATUS_...].)^ ** ^The current value of the parameter is returned into *pCurrent. ** ^The highest recorded value is returned in *pHighwater. ^If the ** resetFlag is true, then the highest record value is reset after ** *pHighwater is written. ^(Some parameters do not record the highest ** value. For those parameters ** nothing is written into *pHighwater and the resetFlag is ignored.)^ ** ^(Other parameters record only the highwater mark and not the current ** value. For these latter parameters nothing is written into *pCurrent.)^ @@ -5944,88 +6153,90 @@ SQLITE_API int sqlite3_test_control(int ** ** See also: [sqlite3_db_status()] */ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); /* ** CAPI3REF: Status Parameters +** KEYWORDS: {status parameters} ** ** These integer constants designate various run-time status parameters ** that can be returned by [sqlite3_status()]. ** ** <dl> -** ^(<dt>SQLITE_STATUS_MEMORY_USED</dt> +** [[SQLITE_STATUS_MEMORY_USED]] ^(<dt>SQLITE_STATUS_MEMORY_USED</dt> ** <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 ** 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>)^ ** -** ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt> +** [[SQLITE_STATUS_MALLOC_SIZE]] ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt> ** <dd>This parameter records the largest memory allocation request ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their ** internal equivalents). Only the value returned in the ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.</dd>)^ ** -** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt> +** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt> ** <dd>This parameter records the number of separate memory allocations ** currently checked out.</dd>)^ ** -** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt> +** [[SQLITE_STATUS_PAGECACHE_USED]] ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt> ** <dd>This parameter returns the number of pages used out of the ** [pagecache memory allocator] that was configured using ** [SQLITE_CONFIG_PAGECACHE]. The ** value returned is in pages, not in bytes.</dd>)^ ** +** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt> ** <dd>This parameter returns the number of bytes of page cache ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] ** buffer and where forced to overflow to [sqlite3_malloc()]. The ** returned value includes allocations that overflowed because they ** where too large (they were larger than the "sz" parameter to ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because ** no space was left in the page cache.</dd>)^ ** -** ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> +** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> ** <dd>This parameter records the largest memory allocation request ** handed to [pagecache 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>)^ ** -** ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> +** [[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>)^ ** -** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> +** [[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>)^ ** -** ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> +** [[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>)^ ** -** ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> +** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> ** <dd>This parameter records the deepest parser stack. It is only ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^ ** </dl> ** ** New status parameters may be added from time to time. */ #define SQLITE_STATUS_MEMORY_USED 0 #define SQLITE_STATUS_PAGECACHE_USED 1 @@ -6040,87 +6251,87 @@ SQLITE_API int sqlite3_status(int op, in /* ** CAPI3REF: Database Connection Status ** ** ^This interface is used to retrieve runtime status information ** about a single [database connection]. ^The first argument is the ** database connection object to be interrogated. ^The second argument ** is an integer constant, taken from the set of -** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that +** [SQLITE_DBSTATUS options], that ** determines the parameter to interrogate. The set of -** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely +** [SQLITE_DBSTATUS options] is likely ** to grow in future releases of SQLite. ** ** ^The current value of the requested parameter is written into *pCur ** and the highest instantaneous value is written into *pHiwtr. ^If ** the resetFlg is true, then the highest instantaneous value is ** reset back down to the current value. ** ** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a ** non-zero [error code] on failure. ** ** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. */ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); /* ** CAPI3REF: Status Parameters for database connections +** KEYWORDS: {SQLITE_DBSTATUS options} ** ** These constants are the available integer "verbs" that can be passed as ** the second argument to the [sqlite3_db_status()] interface. ** ** New verbs may be added in future releases of SQLite. Existing verbs ** might be discontinued. Applications should check the return code from ** [sqlite3_db_status()] to make sure that the call worked. ** The [sqlite3_db_status()] interface will return a non-zero error code ** if a discontinued or unsupported verb is invoked. ** ** <dl> -** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> +** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> ** <dd>This parameter returns the number of lookaside memory slots currently ** checked out.</dd>)^ ** -** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> +** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> ** <dd>This parameter returns the number malloc attempts that were ** satisfied using lookaside memory. Only the high-water value is meaningful; -** the current value is always zero. -** checked out.</dd>)^ -** +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt> ** <dd>This parameter returns the number malloc attempts that might have ** been satisfied using lookaside memory but failed due to the amount of ** memory requested being larger than the lookaside slot size. ** Only the high-water value is meaningful; -** the current value is always zero. -** checked out.</dd>)^ -** +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt> ** <dd>This parameter returns the number malloc attempts that might have ** been satisfied using lookaside memory but failed due to all lookaside ** memory already being in use. ** Only the high-water value is meaningful; -** the current value is always zero. -** checked out.</dd>)^ -** -** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> ** <dd>This parameter returns the approximate number of of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** -** ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> +** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> ** <dd>This parameter returns the approximate number of of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the ** schema memory is shared with other database connections due to ** [shared cache mode] being enabled. ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. ** -** ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> +** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> ** <dd>This parameter returns the approximate number of of bytes of heap ** and lookaside memory used by all prepared statements associated with ** the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. ** </dd> ** </dl> */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 @@ -6132,57 +6343,58 @@ SQLITE_API int sqlite3_db_status(sqlite3 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_MAX 6 /* Largest defined DBSTATUS */ /* ** CAPI3REF: Prepared Statement Status ** ** ^(Each prepared statement maintains various -** [SQLITE_STMTSTATUS_SORT | counters] that measure the number +** [SQLITE_STMTSTATUS counters] that measure the number ** of times it has performed specific operations.)^ These counters can ** be used to monitor the performance characteristics of the prepared ** statements. For example, if the number of table steps greatly exceeds ** the number of table searches or result rows, that would tend to indicate ** that the prepared statement is using a full table scan rather than ** an index. ** ** ^(This interface is used to retrieve and reset counter values from ** a [prepared statement]. The first argument is the prepared statement ** object to be interrogated. The second argument -** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter] +** is an integer code for a specific [SQLITE_STMTSTATUS counter] ** to be interrogated.)^ ** ^The current value of the requested counter is returned. ** ^If the resetFlg is true, then the counter is reset to zero after this ** interface call returns. ** ** See also: [sqlite3_status()] and [sqlite3_db_status()]. */ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); /* ** CAPI3REF: Status Parameters for prepared statements +** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} ** ** These preprocessor macros define integer codes that name counter ** values associated with the [sqlite3_stmt_status()] interface. ** The meanings of the various counters are as follows: ** ** <dl> -** <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt> +** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt> ** <dd>^This is the number of times that SQLite has stepped forward in ** a table as part of a full table scan. Large numbers for this counter ** may indicate opportunities for performance improvement through ** careful use of indices.</dd> ** -** <dt>SQLITE_STMTSTATUS_SORT</dt> +** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt> ** <dd>^This is the number of sort operations that have occurred. ** A non-zero value in this counter may indicate an opportunity to ** improvement performance through careful use of indices.</dd> ** -** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> +** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> ** <dd>^This is the number of rows inserted into transient indices that ** were created automatically in order to help joins run faster. ** A non-zero value in this counter may indicate an opportunity to ** improvement performance by adding permanent indices that do not ** need to be reinitialized each time the statement is run.</dd> ** ** </dl> */ @@ -6223,40 +6435,43 @@ typedef struct sqlite3_pcache sqlite3_pc ** extreme measure that is only needed by the most demanding applications. ** The built-in page cache is recommended for most uses. ** ** ^(The contents of the sqlite3_pcache_methods structure are copied to an ** internal buffer by SQLite within the call to [sqlite3_config]. Hence ** the application may discard the parameter after the call to ** [sqlite3_config()] returns.)^ ** +** [[the xInit() page cache method]] ** ^(The xInit() method is called once for each effective ** call to [sqlite3_initialize()])^ ** (usually only once during the lifetime of the process). ^(The xInit() ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^ ** The intent of the xInit() method is to set up global data structures ** required by the custom page cache implementation. ** ^(If the xInit() method is NULL, then the ** built-in default page cache is used instead of the application defined ** page cache.)^ ** +** [[the xShutdown() page cache method]] ** ^The xShutdown() method is called by [sqlite3_shutdown()]. ** It can be used to clean up ** any outstanding resources before process shutdown, if required. ** ^The xShutdown() method may be NULL. ** ** ^SQLite automatically serializes calls to the xInit method, ** so the xInit method need not be threadsafe. ^The ** xShutdown method is only called from [sqlite3_shutdown()] so it does ** not need to be threadsafe either. All other methods must be threadsafe ** in multithreaded applications. ** ** ^SQLite will never invoke xInit() more than once without an intervening ** call to xShutdown(). ** +** [[the xCreate() page cache methods]] ** ^SQLite invokes the xCreate() method to construct a new cache instance. ** SQLite will typically create one cache instance for each open database file, ** though this is not guaranteed. ^The ** first parameter, szPage, is the size in bytes of the pages that must ** be allocated by the cache. ^szPage will not be a power of two. ^szPage ** will the page size of the database file that is to be cached plus an ** increment (here called "R") of less than 250. SQLite will use the ** extra R bytes on each page to store metadata about the underlying @@ -6271,31 +6486,34 @@ typedef struct sqlite3_pcache sqlite3_pc ** does not have to do anything special based with the value of bPurgeable; ** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will ** never invoke xUnpin() except to deliberately delete a page. ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to ** false will always have the "discard" flag set to true. ** ^Hence, a cache created with bPurgeable false will ** never contain any unpinned pages. ** +** [[the xCachesize() page cache method]] ** ^(The xCachesize() method may be called at any time by SQLite to set the ** suggested maximum cache-size (number of pages stored by) the cache ** instance passed as the first argument. This is the value configured using ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable ** parameter, the implementation is not required to do anything with this ** value; it is advisory only. ** +** [[the xPagecount() page cache methods]] ** The xPagecount() method must return the number of pages currently ** stored in the cache, both pinned and unpinned. ** +** [[the xFetch() page cache methods]] ** The xFetch() method locates a page in the cache and returns a pointer to ** the page, or a NULL pointer. ** A "page", in this context, means a buffer of szPage bytes aligned at an ** 8-byte boundary. The page to be fetched is determined by the key. ^The -** mimimum key value is 1. After it has been retrieved using xFetch, the page +** minimum key value is 1. After it has been retrieved using xFetch, the page ** is considered to be "pinned". ** ** If the requested page is already in the page cache, then the page cache ** implementation must return a pointer to the page buffer with its content ** intact. If the requested page is not already in the cache, then the ** cache implementation should use the value of the createFlag ** parameter to help it determined what action to take: ** @@ -6309,40 +6527,43 @@ typedef struct sqlite3_pcache sqlite3_pc ** </table> ** ** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite ** will only use a createFlag of 2 after a prior call with a createFlag of 1 ** failed.)^ In between the to xFetch() calls, SQLite may ** attempt to unpin one or more cache pages by spilling the content of ** pinned pages to disk and synching the operating system disk cache. ** +** [[the xUnpin() page cache method]] ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page ** as its second argument. If the third parameter, discard, is non-zero, ** then the page must be evicted from the cache. ** ^If the discard parameter is ** zero, then the page may be discarded or retained at the discretion of ** page cache implementation. ^The page cache implementation ** may choose to evict unpinned pages at any time. ** ** The cache must not perform any reference counting. A single ** call to xUnpin() unpins the page regardless of the number of prior calls ** to xFetch(). ** +** [[the xRekey() page cache methods]] ** The xRekey() method is used to change the key value associated with the ** page passed as the second argument. If the cache ** previously contains an entry associated with newKey, it must be ** discarded. ^Any prior cache entry associated with newKey is guaranteed not ** to be pinned. ** ** When SQLite calls the xTruncate() method, the cache must discard all ** existing cache entries with page numbers (keys) greater than or equal ** to the value of the iLimit parameter passed to xTruncate(). If any ** of these pages are pinned, they are implicitly unpinned, meaning that ** they can be safely discarded. ** +** [[the xDestroy() page cache method]] ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). ** All resources associated with the specified cache should be freed. ^After ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] ** handle invalid, and will not use it with any other sqlite3_pcache_methods ** functions. */ typedef struct sqlite3_pcache_methods sqlite3_pcache_methods; struct sqlite3_pcache_methods { @@ -6395,17 +6616,17 @@ typedef struct sqlite3_backup sqlite3_ba ** <li><b>sqlite3_backup_step()</b> is called one or more times to transfer ** the data between the two databases, and finally ** <li><b>sqlite3_backup_finish()</b> is called to release all resources ** associated with the backup operation. ** </ol>)^ ** There should be exactly one call to sqlite3_backup_finish() for each ** successful call to sqlite3_backup_init(). ** -** <b>sqlite3_backup_init()</b> +** [[sqlite3_backup_init()]] <b>sqlite3_backup_init()</b> ** ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the ** [database connection] associated with the destination database ** and the database name, respectively. ** ^The database name is "main" for the main database, "temp" for the ** temporary database, or the name specified after the AS keyword in ** an [ATTACH] statement for an attached database. ** ^The S and M arguments passed to @@ -6422,17 +6643,17 @@ typedef struct sqlite3_backup sqlite3_ba ** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or ** [sqlite3_errmsg16()] functions. ** ^A successful call to sqlite3_backup_init() returns a pointer to an ** [sqlite3_backup] object. ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and ** sqlite3_backup_finish() functions to perform the specified backup ** operation. ** -** <b>sqlite3_backup_step()</b> +** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b> ** ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between ** the source and destination databases specified by [sqlite3_backup] object B. ** ^If N is negative, all remaining source pages are copied. ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there ** are still more pages to be copied, then the function returns [SQLITE_OK]. ** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages ** from source to destination, then it returns [SQLITE_DONE]. @@ -6479,17 +6700,17 @@ typedef struct sqlite3_backup sqlite3_ba ** through the backup process. ^If the source database is modified by an ** external process or via a database connection other than the one being ** used by the backup operation, then the backup will be automatically ** restarted by the next call to sqlite3_backup_step(). ^If the source ** database is modified by the using the same database connection as is used ** by the backup operation, then the backup database is automatically ** updated at the same time. ** -** <b>sqlite3_backup_finish()</b> +** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b> ** ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the ** application wishes to abandon the backup operation, the application ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). ** ^The sqlite3_backup_finish() interfaces releases all ** resources associated with the [sqlite3_backup] object. ** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any ** active write-transaction on the destination database is rolled back. @@ -6502,17 +6723,18 @@ typedef struct sqlite3_backup sqlite3_ba ** ^If an out-of-memory condition or IO error occurred during any prior ** sqlite3_backup_step() call on the same [sqlite3_backup] object, then ** sqlite3_backup_finish() returns the corresponding [error code]. ** ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() ** is not a permanent error and does not affect the return value of ** sqlite3_backup_finish(). ** -** <b>sqlite3_backup_remaining(), sqlite3_backup_pagecount()</b> +** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] +** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> ** ** ^Each call to sqlite3_backup_step() sets two values inside ** the [sqlite3_backup] object: the number of pages still to be backed ** up and the total number of pages in the source database file. ** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces ** retrieve these two values, respectively. ** ** ^The values returned by these functions are only updated by @@ -6793,20 +7015,200 @@ SQLITE_API int sqlite3_wal_autocheckpoin ** empty string, then a checkpoint is run on all databases of ** connection D. ^If the database connection D is not in ** [WAL | write-ahead log mode] then this interface is a harmless no-op. ** ** ^The [wal_checkpoint pragma] can be used to invoke this interface ** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] can be used to cause this interface to be ** run whenever the WAL reaches a certain size threshold. +** +** See also: [sqlite3_wal_checkpoint_v2()] */ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); /* +** CAPI3REF: Checkpoint a database +** +** Run a checkpoint operation on WAL database zDb attached to database +** handle db. The specific operation is determined by the value of the +** eMode parameter: +** +** <dl> +** <dt>SQLITE_CHECKPOINT_PASSIVE<dd> +** Checkpoint as many frames as possible without waiting for any database +** readers or writers to finish. Sync the db file if all frames in the log +** are checkpointed. This mode is the same as calling +** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked. +** +** <dt>SQLITE_CHECKPOINT_FULL<dd> +** This mode blocks (calls the busy-handler callback) until there is no +** database writer and all readers are reading from the most recent database +** snapshot. It then checkpoints all frames in the log file and syncs the +** database file. This call blocks database writers while it is running, +** but not database readers. +** +** <dt>SQLITE_CHECKPOINT_RESTART<dd> +** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after +** checkpointing the log file it blocks (calls the busy-handler callback) +** until all readers are reading from the database file only. This ensures +** that the next client to write to the database file restarts the log file +** from the beginning. This call blocks database writers while it is running, +** but not database readers. +** </dl> +** +** If pnLog is not NULL, then *pnLog is set to the total number of frames in +** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to +** the total number of checkpointed frames (including any that were already +** checkpointed when this function is called). *pnLog and *pnCkpt may be +** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK. +** If no values are available because of an error, they are both set to -1 +** before returning to communicate this to the caller. +** +** All calls obtain an exclusive "checkpoint" lock on the database file. If +** any other process is running a checkpoint operation at the same time, the +** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a +** busy-handler configured, it will not be invoked in this case. +** +** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive +** "writer" lock on the database file. If the writer lock cannot be obtained +** immediately, and a busy-handler is configured, it is invoked and the writer +** lock retried until either the busy-handler returns 0 or the lock is +** successfully obtained. The busy-handler is also invoked while waiting for +** database readers as described above. If the busy-handler returns 0 before +** the writer lock is obtained or while waiting for database readers, the +** checkpoint operation proceeds from that point in the same way as +** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible +** without blocking any further. SQLITE_BUSY is returned in this case. +** +** If parameter zDb is NULL or points to a zero length string, then the +** specified operation is attempted on all WAL databases. In this case the +** values written to output parameters *pnLog and *pnCkpt are undefined. If +** an SQLITE_BUSY error is encountered when processing one or more of the +** attached WAL databases, the operation is still attempted on any remaining +** attached databases and SQLITE_BUSY is returned to the caller. If any other +** error occurs while processing an attached database, processing is abandoned +** and the error code returned to the caller immediately. If no error +** (SQLITE_BUSY or otherwise) is encountered while processing the attached +** databases, SQLITE_OK is returned. +** +** If database zDb is the name of an attached database that is not in WAL +** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If +** zDb is not NULL (or a zero length string) and is not the name of any +** attached database, SQLITE_ERROR is returned to the caller. +*/ +SQLITE_API int sqlite3_wal_checkpoint_v2( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int *pnLog, /* OUT: Size of WAL log in frames */ + int *pnCkpt /* OUT: Total number of frames checkpointed */ +); + +/* +** CAPI3REF: Checkpoint operation parameters +** +** These constants can be used as the 3rd parameter to +** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()] +** documentation for additional information about the meaning and use of +** each of these values. +*/ +#define SQLITE_CHECKPOINT_PASSIVE 0 +#define SQLITE_CHECKPOINT_FULL 1 +#define SQLITE_CHECKPOINT_RESTART 2 + +/* +** CAPI3REF: Virtual Table Interface Configuration +** +** This function may be called by either the [xConnect] or [xCreate] method +** of a [virtual table] implementation to configure +** various facets of the virtual table interface. +** +** If this interface is invoked outside the context of an xConnect or +** xCreate virtual table method then the behavior is undefined. +** +** At present, there is only one option that may be configured using +** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options +** may be added in the future. +*/ +SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); + +/* +** CAPI3REF: Virtual Table Configuration Options +** +** These macros define the various options to the +** [sqlite3_vtab_config()] interface that [virtual table] implementations +** can use to customize and optimize their behavior. +** +** <dl> +** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT +** <dd>Calls of the form +** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, +** where X is an integer. If X is zero, then the [virtual table] whose +** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not +** support constraints. In this configuration (which is the default) if +** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire +** statement is rolled back as if [ON CONFLICT | OR ABORT] had been +** specified as part of the users SQL statement, regardless of the actual +** ON CONFLICT mode specified. +** +** If X is non-zero, then the virtual table implementation guarantees +** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before +** any modifications to internal or persistent data structures have been made. +** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite +** is able to roll back a statement or database transaction, and abandon +** or continue processing the current SQL statement as appropriate. +** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns +** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode +** had been ABORT. +** +** Virtual table implementations that are required to handle OR REPLACE +** must do so within the [xUpdate] method. If a call to the +** [sqlite3_vtab_on_conflict()] function indicates that the current ON +** CONFLICT policy is REPLACE, the virtual table implementation should +** silently replace the appropriate rows within the xUpdate callback and +** return SQLITE_OK. Or, if this is not possible, it may return +** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT +** constraint handling. +** </dl> +*/ +#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 + +/* +** CAPI3REF: Determine The Virtual Table Conflict Policy +** +** This function may only be called from within a call to the [xUpdate] method +** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The +** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], +** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode +** of the SQL statement that triggered the call to the [xUpdate] method of the +** [virtual table]. +*/ +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); + +/* +** CAPI3REF: Conflict resolution modes +** +** These constants are returned by [sqlite3_vtab_on_conflict()] to +** inform a [virtual table] implementation what the [ON CONFLICT] mode +** is for the SQL statement being evaluated. +** +** Note that the [SQLITE_IGNORE] constant is also used as a potential +** return value from the [sqlite3_set_authorizer()] callback and that +** [SQLITE_ABORT] is also a [result code]. +*/ +#define SQLITE_ROLLBACK 1 +/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ +#define SQLITE_FAIL 3 +/* #define SQLITE_ABORT 4 // Also an error code */ +#define SQLITE_REPLACE 5 + + + +/* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #if 0 @@ -7461,16 +7863,17 @@ typedef struct StrAccum StrAccum; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; typedef struct Trigger Trigger; typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; typedef struct UnpackedRecord UnpackedRecord; typedef struct VTable VTable; +typedef struct VtabCtx VtabCtx; typedef struct Walker Walker; typedef struct WherePlan WherePlan; typedef struct WhereInfo WhereInfo; typedef struct WhereLevel WhereLevel; /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque @@ -7514,31 +7917,20 @@ typedef struct WhereLevel WhereLevel; #define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */ /* ** Forward declarations of structure */ typedef struct Btree Btree; typedef struct BtCursor BtCursor; typedef struct BtShared BtShared; -typedef struct BtreeMutexArray BtreeMutexArray; - -/* -** This structure records all of the Btrees that need to hold -** a mutex before we enter sqlite3VdbeExec(). The Btrees are -** are placed in aBtree[] in order of aBtree[]->pBt. That way, -** we can always lock and unlock them all quickly. -*/ -struct BtreeMutexArray { - int nMutex; - Btree *aBtree[SQLITE_MAX_ATTACHED+1]; -}; SQLITE_PRIVATE int sqlite3BtreeOpen( + sqlite3_vfs *pVfs, /* VFS to use with this b-tree */ const char *zFilename, /* Name of database file to open */ sqlite3 *db, /* Associated database connection */ Btree **ppBtree, /* Return open Btree* here */ int flags, /* Flags */ int vfsFlags /* Flags passed through to VFS open */ ); /* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the @@ -7562,17 +7954,17 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSi SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int); SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*); SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int); SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *); SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); -SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*); +SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int); SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*); SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*); SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags); SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*); SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*); SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*); SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); @@ -7682,57 +8074,55 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtC #endif #ifdef SQLITE_TEST SQLITE_PRIVATE int sqlite3BtreeCursorInfo(BtCursor*, int*, int); SQLITE_PRIVATE void sqlite3BtreeCursorList(Btree*); #endif #ifndef SQLITE_OMIT_WAL -SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*); +SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif /* ** If we are not using shared cache, then there is no need to ** use mutexes to access the BtShared structures. So make the ** Enter and Leave procedures no-ops. */ #ifndef SQLITE_OMIT_SHARED_CACHE SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*); SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*); #else # define sqlite3BtreeEnter(X) # define sqlite3BtreeEnterAll(X) #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE +SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*); SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*); SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*); -SQLITE_PRIVATE void sqlite3BtreeMutexArrayEnter(BtreeMutexArray*); -SQLITE_PRIVATE void sqlite3BtreeMutexArrayLeave(BtreeMutexArray*); -SQLITE_PRIVATE void sqlite3BtreeMutexArrayInsert(BtreeMutexArray*, Btree*); #ifndef NDEBUG /* These routines are used inside assert() statements only. */ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree*); SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*); -#endif -#else - +SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); +#endif +#else + +# define sqlite3BtreeSharable(X) 0 # define sqlite3BtreeLeave(X) # define sqlite3BtreeEnterCursor(X) # define sqlite3BtreeLeaveCursor(X) # define sqlite3BtreeLeaveAll(X) -# define sqlite3BtreeMutexArrayEnter(X) -# define sqlite3BtreeMutexArrayLeave(X) -# define sqlite3BtreeMutexArrayInsert(X,Y) # define sqlite3BtreeHoldsMutex(X) 1 # define sqlite3BtreeHoldsAllMutexes(X) 1 +# define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif #endif /* _BTREE_H_ */ /************** End of btree.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include vdbe.h in the middle of sqliteInt.h ******************/ @@ -7841,17 +8231,17 @@ typedef struct VdbeOpList VdbeOpList; #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 (-4) /* P4 is a pointer to a CollSeq structure */ #define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */ #define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */ #define P4_VDBEFUNC (-7) /* P4 is a pointer to a VdbeFunc structure */ #define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */ -#define P4_TRANSIENT (-9) /* P4 is a pointer to a transient string */ +#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ #define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */ @@ -8091,38 +8481,40 @@ typedef struct VdbeOpList VdbeOpList; SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3*); SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp); +SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3); SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5); SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N); SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*); -SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int); +SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*); SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int); SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *, int); SQLITE_PRIVATE void sqlite3VdbeTrace(Vdbe*,FILE*); #endif SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe*); 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 void sqlite3VdbeSwap(Vdbe*,Vdbe*); SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); @@ -8292,17 +8684,17 @@ SQLITE_PRIVATE int sqlite3PagerCommitPha SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*); SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*); SQLITE_PRIVATE int sqlite3PagerRollback(Pager*); SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n); SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager); -SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager); +SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*); SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager); /* Functions used to query pager state and configuration. */ SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*); SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*); @@ -8876,19 +9268,34 @@ struct Db { Btree *pBt; /* The B*Tree structure for this database file */ u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */ u8 safety_level; /* How aggressive at syncing data to disk */ Schema *pSchema; /* Pointer to database schema (possibly shared) */ }; /* ** An instance of the following structure stores a database schema. +** +** Most Schema objects are associated with a Btree. The exception is +** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing. +** In shared cache mode, a single Schema object can be shared by multiple +** Btrees that refer to the same underlying BtShared object. +** +** Schema objects are automatically deallocated when the last Btree that +** references them is destroyed. The TEMP Schema is manually freed by +** sqlite3_close(). +* +** A thread must be holding a mutex on the corresponding Btree in order +** to access Schema content. This implies that the thread must also be +** holding a mutex on the sqlite3 connection pointer that owns the Btree. +** For a TEMP Schema, only the connection mutex is required. */ struct Schema { int schema_cookie; /* Database schema version number for this file */ + int iGeneration; /* Generation counter. Incremented with each change */ Hash tblHash; /* All tables indexed by name */ Hash idxHash; /* All (named) indices indexed by name */ Hash trigHash; /* All triggers indexed by name */ Hash fkeyHash; /* All foreign keys by referenced table name */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ u16 flags; /* Flags associated with this schema */ @@ -8995,25 +9402,26 @@ struct FuncDefHash { ** internal function sqlite3Error() is used to set these variables ** consistently. */ struct sqlite3 { sqlite3_vfs *pVfs; /* OS Interface */ int nDb; /* Number of backends currently in use */ Db *aDb; /* All backends */ int flags; /* Miscellaneous flags. See below */ - int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ + unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ u8 suppressErr; /* Do not issue error messages if true */ + u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ int nextPagesize; /* Pagesize after VACUUM if >0 */ int nTable; /* Number of tables in the database */ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ i64 lastRowid; /* ROWID of most recent insert (see above) */ u32 magic; /* Magic number for detect library misuse */ int nChange; /* Value returned by sqlite3_changes() */ int nTotalChange; /* Value returned by sqlite3_total_changes() */ sqlite3_mutex *mutex; /* Connection mutex */ @@ -9062,17 +9470,17 @@ struct sqlite3 { #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ - Table *pVTab; /* vtab with active Connect/Create method */ + VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ VTable **aVTrans; /* Virtual tables with open transactions */ int nVTrans; /* Allocated size of aVTrans */ VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ #endif FuncDefHash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ int busyTimeout; /* Busy handler timeout, in msec */ @@ -9132,29 +9540,31 @@ struct sqlite3 { #define SQLITE_CkptFullFSync 0x00400000 /* Use full fsync for checkpoint */ #define SQLITE_RecoveryMode 0x00800000 /* Ignore schema errors */ #define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */ #define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */ #define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */ #define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */ #define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */ #define SQLITE_LoadExtension 0x20000000 /* Enable load_extension */ +#define SQLITE_EnableTrigger 0x40000000 /* True to enable triggers */ /* ** Bits of the sqlite3.flags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface. ** These must be the low-order bits of the flags field. */ #define SQLITE_QueryFlattener 0x01 /* Disable query flattening */ #define SQLITE_ColumnCache 0x02 /* Disable the column cache */ #define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */ #define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */ #define SQLITE_IndexCover 0x10 /* Disable index covering table */ #define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x40 /* Disable factoring out constants */ +#define SQLITE_IdxRealAsInt 0x80 /* Store REAL as INT in indices */ #define SQLITE_OptMask 0xff /* Mask of all disablable opts */ /* ** Possible values for the sqlite.magic field. ** The numbers are obtained at random and have no special meaning, other ** than being distinct from one another. */ #define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ @@ -9390,17 +9800,17 @@ struct CollSeq { ** structure for each database connection (sqlite3*) that uses the shared ** schema. This is because each database connection requires its own unique ** instance of the sqlite3_vtab* handle used to access the virtual table ** implementation. sqlite3_vtab* handles can not be shared between ** database connections, even when the rest of the in-memory database ** schema is shared, as the implementation often stores the database ** connection handle passed to it via the xConnect() or xCreate() method ** during initialization internally. This database connection handle may -** then used by the virtual table implementation to access real tables +** then be used by the virtual table implementation to access real tables ** within the database. So that they appear as part of the callers ** transaction, these accesses need to be made via the same database ** connection as that used to execute SQL operations on the virtual table. ** ** All VTable objects that correspond to a single table in a shared ** database schema are initially stored in a linked-list pointed to by ** the Table.pVTable member variable of the corresponding Table object. ** When an sqlite3_prepare() operation is required to access the virtual @@ -9424,16 +9834,18 @@ struct CollSeq { ** sqlite3DbMalloc(), using the connection handle stored in VTable.db as ** the first argument. */ struct VTable { sqlite3 *db; /* Database connection associated with this table */ Module *pMod; /* Pointer to module implementation */ sqlite3_vtab *pVtab; /* Pointer to vtab instance */ int nRef; /* Number of pointers to this structure */ + u8 bConstraint; /* True if constraints are supported */ + int iSavepoint; /* Depth of the SAVEPOINT stack */ VTable *pNext; /* Next in linked list (see above) */ }; /* ** Each SQL table is represented in memory by an instance of the ** following structure. ** ** Table.zName is the name of the table. The case of the original @@ -9668,16 +10080,17 @@ struct Index { char *zName; /* Name of this index */ int nColumn; /* Number of columns in the table used by this index */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */ unsigned *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ int tnum; /* Page containing root of this index in database file */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ + u8 bUnordered; /* Use this index for == or IN queries only */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ Schema *pSchema; /* Schema containing this index */ u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ IndexSample *aSample; /* Array of SQLITE_INDEX_SAMPLES samples */ }; @@ -9831,17 +10244,17 @@ typedef int ynVar; ** allocated, regardless of whether or not EP_Reduced is set. */ struct Expr { u8 op; /* Operation performed by this node */ char affinity; /* The affinity of the column or 0 if not a column */ u16 flags; /* Various flags. EP_* See below */ union { char *zToken; /* Token value. Zero terminated and dequoted */ - int iValue; /* Integer value if EP_IntValue */ + int iValue; /* Non-negative integer value if EP_IntValue */ } u; /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no ** space is allocated for the fields below this point. An attempt to ** access them will result in a segfault or malfunction. *********************************************************************/ Expr *pLeft; /* Left subnode */ @@ -10332,16 +10745,25 @@ struct TriggerPrg { Trigger *pTrigger; /* Trigger this program was coded from */ int orconf; /* Default ON CONFLICT policy */ SubProgram *pProgram; /* Program implementing pTrigger/orconf */ u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */ TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */ }; /* +** The yDbMask datatype for the bitmask of all attached databases. +*/ +#if SQLITE_MAX_ATTACHED>30 + typedef sqlite3_uint64 yDbMask; +#else + typedef unsigned int yDbMask; +#endif + +/* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to ** carry around information that is global to the entire parse. ** ** The structure is divided into two parts. When the parser and code ** generate call themselves recursively, the first part of the structure ** is constant but the second part is reset at the beginning and end of ** each recursion. @@ -10379,18 +10801,18 @@ struct Parse { struct yColCache { int iTable; /* Table cursor number */ int iColumn; /* Table column number */ u8 tempReg; /* iReg is a temp register that needs to be freed */ int iLevel; /* Nesting level */ int iReg; /* Reg with value of this column. 0 means none. */ int lru; /* Least recently used entry has the smallest value */ } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */ - u32 writeMask; /* Start a write transaction on these databases */ - u32 cookieMask; /* Bitmask of schema verified databases */ + yDbMask writeMask; /* Start a write transaction on these databases */ + yDbMask cookieMask; /* Bitmask of schema verified databases */ u8 isMultiWrite; /* True if statement may affect/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */ int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */ #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ #endif @@ -10408,19 +10830,18 @@ struct Parse { u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ u8 disableTriggers; /* True to disable triggers */ double nQueryLoop; /* Estimated number of iterations of a query */ /* Above is constant between recursions. Below is reset before and after ** each recursion */ int nVar; /* Number of '?' variables seen in the SQL so far */ - int nVarExpr; /* Number of used slots in apVarExpr[] */ - int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */ - Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */ + int nzVar; /* Number of available slots in azVar[] */ + char **azVar; /* Pointers to names of parameters */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ int nAlias; /* Number of aliased result set columns */ int nAliasAlloc; /* Number of allocated slots for aAlias[] */ int *aAlias; /* Register used to hold aliased result */ u8 explain; /* True if the EXPLAIN flag is found on the query */ Token sNameToken; /* Token with unqualified schema object name */ Token sLastToken; /* The last token parsed */ const char *zTail; /* All SQL text past the last semicolon parsed */ @@ -10602,16 +11023,17 @@ typedef struct { ** Structure containing global configuration data for the SQLite library. ** ** This structure also contains some state information. */ struct Sqlite3Config { int bMemstat; /* True to enable memory status */ int bCoreMutex; /* True to enable core mutexing */ int bFullMutex; /* True to enable full mutexing */ + int bOpenUri; /* True to interpret filenames as URIs */ int mxStrlen; /* Maximum string length */ int szLookaside; /* Default lookaside buffer size */ int nLookaside; /* Default lookaside buffer count */ sqlite3_mem_methods m; /* Low-level memory allocation interface */ sqlite3_mutex_methods mutex; /* Low-level mutex interface */ sqlite3_pcache_methods pcache; /* Low-level page-cache interface */ void *pHeap; /* Heap storage space */ int nHeap; /* Size of pHeap[] */ @@ -10630,16 +11052,17 @@ struct Sqlite3Config { int inProgress; /* True while initialization in progress */ int isMutexInit; /* True after mutexes are initialized */ int isMallocInit; /* True after malloc is initialized */ int isPCacheInit; /* True after malloc is initialized */ sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ int nRefInitMutex; /* Number of users of pInitMutex */ void (*xLog)(void*,int,const char*); /* Function for logging */ void *pLogArg; /* First argument to xLog() */ + int bLocaltimeFault; /* True to fail localtime() calls */ }; /* ** Context pointer passed down through the tree-walk. */ struct Walker { int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ @@ -10851,16 +11274,18 @@ SQLITE_PRIVATE void sqlite3StartTable(Pa SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*); SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int); SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*); SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*); SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*); SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*); SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,Select*); +SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, + sqlite3_vfs**,char**,char **); SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32); SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32); SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32); SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*); SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*); SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*); SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*); @@ -10950,16 +11375,17 @@ SQLITE_PRIVATE int sqlite3ExprListCompar SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); SQLITE_PRIVATE void sqlite3PrngSaveState(void); SQLITE_PRIVATE void sqlite3PrngRestoreState(void); SQLITE_PRIVATE void sqlite3PrngResetState(void); SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*); 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 sqlite3Savepoint(Parse*, int, Token*); SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*); @@ -11054,17 +11480,17 @@ SQLITE_PRIVATE int sqlite3FixSelect(DbFi SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*); 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*); SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); -SQLITE_PRIVATE int sqlite3Utf8Read(const u8*, const u8**); +SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8*, const u8**); /* ** Routines to read and write variable-length integers. These used to ** be defined locally, but now we use the varint routines in the util.c ** file. Code should use the MACRO forms below, as the Varint32 versions ** are coded to assume the single byte case is already handled (which ** the MACRO form does). */ @@ -11100,27 +11526,38 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *); SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *, Table *); SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); +SQLITE_PRIVATE u8 sqlite3HexToInt(int h); SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); SQLITE_PRIVATE const char *sqlite3ErrStr(int); 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 Expr *sqlite3ExprSetColl(Expr*, CollSeq*); SQLITE_PRIVATE Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr*, Token*); SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *); SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); +SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); +SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64); +SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64); +SQLITE_PRIVATE int sqlite3AbsInt32(int); +#ifdef SQLITE_ENABLE_8_3_NAMES +SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*); +#else +# define sqlite3FileSuffix3(X,Y) +#endif +SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z); SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); @@ -11135,17 +11572,17 @@ SQLITE_PRIVATE const unsigned char sqlit SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[]; SQLITE_PRIVATE const Token sqlite3IntTokens[]; SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config; SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions; #ifndef SQLITE_OMIT_WSD SQLITE_PRIVATE int sqlite3PendingByte; #endif #endif -SQLITE_PRIVATE void sqlite3RootPageMoved(Db*, int, int); +SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, int, int); SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*); SQLITE_PRIVATE void sqlite3AlterFunctions(void); SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *); SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*); SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int); SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*); @@ -11162,17 +11599,17 @@ SQLITE_PRIVATE int sqlite3InvokeBusyHand SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*); SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *); SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB); SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*); SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*); SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3*, int); SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse*, int, int); -SQLITE_PRIVATE void sqlite3SchemaFree(void *); +SQLITE_PRIVATE void sqlite3SchemaClear(void *); SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *, Btree *); SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *); SQLITE_PRIVATE KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *); SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*), FuncDestructor *pDestructor ); @@ -11220,24 +11657,26 @@ SQLITE_PRIVATE int sqlite3Utf8To8(unsi # define sqlite3VtabClear(Y) # define sqlite3VtabSync(X,Y) SQLITE_OK # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) # define sqlite3VtabInSync(db) 0 # define sqlite3VtabLock(X) # define sqlite3VtabUnlock(X) # define sqlite3VtabUnlockList(X) +# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK #else SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table*); SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, char **); SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db); SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db); SQLITE_PRIVATE void sqlite3VtabLock(VTable *); SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *); SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*); +SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*); SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*); SQLITE_PRIVATE void sqlite3VtabArgInit(Parse*); SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse*, Token*); SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); @@ -11249,17 +11688,17 @@ SQLITE_PRIVATE void sqlite3InvalidFuncti SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*); SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*); SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*); SQLITE_PRIVATE const char *sqlite3JournalModename(int); -SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int); +SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int, int, int*, int*); SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); /* Declarations for functions in fkey.c. All of these are replaced by ** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign ** key functionality is available. If OMIT_TRIGGER is defined but ** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In ** this case foreign keys are parsed, but no other functionality is ** provided (enforcement of FK constraints requires the triggers sub-system). @@ -11534,26 +11973,29 @@ SQLITE_PRIVATE const unsigned char sqlit 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ }; #endif - +#ifndef SQLITE_USE_URI +# define SQLITE_USE_URI 0 +#endif /* ** The following singleton contains the global configuration for ** the SQLite library. */ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */ 1, /* bCoreMutex */ SQLITE_THREADSAFE==1, /* bFullMutex */ + SQLITE_USE_URI, /* bOpenUri */ 0x7ffffffe, /* mxStrlen */ 100, /* szLookaside */ 500, /* nLookaside */ {0,0,0,0,0,0,0,0}, /* m */ {0,0,0,0,0,0,0,0,0}, /* mutex */ {0,0,0,0,0,0,0,0,0,0,0}, /* pcache */ (void*)0, /* pHeap */ 0, /* nHeap */ @@ -11571,16 +12013,17 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3 0, /* inProgress */ 0, /* isMutexInit */ 0, /* isMallocInit */ 0, /* isPCacheInit */ 0, /* pInitMutex */ 0, /* nRefInitMutex */ 0, /* xLog */ 0, /* pLogArg */ + 0, /* bLocaltimeFault */ }; /* ** Hash table for global functions - functions common to all ** database connections. After initialization, this table is ** read-only. */ @@ -12323,35 +12766,35 @@ struct Vdbe { u16 nCursor; /* Number of slots in apCsr[] */ u32 magic; /* Magic number for sanity checking */ char *zErrMsg; /* Error message written here */ Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ Mem *aVar; /* Values for the OP_Variable opcode. */ char **azVar; /* Name of variables */ ynVar nVar; /* Number of entries in aVar[] */ + ynVar nzVar; /* Number of entries in azVar[] */ u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ u8 errorAction; /* Recovery action to do in case of an error */ - u8 okVar; /* True if azVar[] has been initialized */ u8 explain; /* True if EXPLAIN present on SQL command */ u8 changeCntOn; /* True to update the change-counter */ u8 expired; /* True if the VM needs to be recompiled */ u8 runOnlyOnce; /* Automatically expire on reset */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 inVtabMethod; /* See comments above */ u8 usesStmtJournal; /* True if uses a statement journal */ u8 readOnly; /* True for read-only statements */ u8 isPrepareV2; /* True if prepared with prepare_v2() */ int nChange; /* Number of db changes made since last reset */ - int btreeMask; /* Bitmask of db->aDb[] entries referenced */ + yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ + yDbMask lockMask; /* Subset of btreeMask that requires a lock */ int iStatement; /* Statement number (or 0 if has not opened stmt) */ int aCounter[3]; /* Counters used by sqlite3_stmt_status() */ - BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */ #ifndef SQLITE_OMIT_TRACE i64 startTime; /* Time when query started - used for profiling */ #endif i64 nFkConstraint; /* Number of imm. FK constraints this VM */ i64 nStmtDefCons; /* Number of def. constraints when stmt started */ char *zSql; /* Text of the SQL statement that generated this */ void *pFree; /* Free this when deleting the vdbe */ #ifdef SQLITE_DEBUG @@ -12424,32 +12867,34 @@ SQLITE_PRIVATE void sqlite3VdbeMemReleas SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); SQLITE_PRIVATE const char *sqlite3OpcodeName(int); SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem); +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 +SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*); +#else +# define sqlite3VdbeEnter(X) +# define sqlite3VdbeLeave(X) +#endif + #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*); #endif #ifndef SQLITE_OMIT_FOREIGN_KEY SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int); #else # define sqlite3VdbeCheckFk(p,i) 0 #endif -#ifndef SQLITE_OMIT_SHARED_CACHE -SQLITE_PRIVATE void sqlite3VdbeMutexArrayEnter(Vdbe *p); -#else -# define sqlite3VdbeMutexArrayEnter(p) -#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_INCRBLOB @@ -12605,16 +13050,17 @@ SQLITE_API int sqlite3_db_status( ** *pCurrent gets an accurate estimate of the amount of memory used ** to store the schema for all databases (main, temp, and any ATTACHed ** databases. *pHighwater is set to zero. */ case SQLITE_DBSTATUS_SCHEMA_USED: { int i; /* Used to iterate through schemas */ int nByte = 0; /* Used to accumulate return value */ + sqlite3BtreeEnterAll(db); db->pnBytesFreed = &nByte; for(i=0; i<db->nDb; i++){ Schema *pSchema = db->aDb[i].pSchema; if( ALWAYS(pSchema!=0) ){ HashElem *p; nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( pSchema->tblHash.count @@ -12631,16 +13077,17 @@ SQLITE_API int sqlite3_db_status( sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); } for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); } } } db->pnBytesFreed = 0; + sqlite3BtreeLeaveAll(db); *pHighwater = 0; *pCurrent = nByte; break; } /* ** *pCurrent gets an accurate estimate of the amount of memory used @@ -12717,32 +13164,16 @@ SQLITE_API int sqlite3_db_status( ** ISBM 0-943396-61-1 ** Willmann-Bell, Inc ** Richmond, Virginia (USA) */ #include <time.h> #ifndef SQLITE_OMIT_DATETIME_FUNCS -/* -** On recent Windows platforms, the localtime_s() function is available -** as part of the "Secure CRT". It is essentially equivalent to -** localtime_r() available under most POSIX platforms, except that the -** order of the parameters is reversed. -** -** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx. -** -** If the user has not indicated to use localtime_r() or localtime_s() -** already, check for an MSVC build environment that provides -** localtime_s(). -*/ -#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \ - defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE) -#define HAVE_LOCALTIME_S 1 -#endif /* ** A structure for holding a single date and time. */ typedef struct DateTime DateTime; struct DateTime { sqlite3_int64 iJD; /* The julian day number times 86400000 */ int Y, M, D; /* Year, month, and day */ @@ -13078,25 +13509,93 @@ static void computeYMD_HMS(DateTime *p){ ** Clear the YMD and HMS and the TZ */ static void clearYMD_HMS_TZ(DateTime *p){ p->validYMD = 0; p->validHMS = 0; p->validTZ = 0; } +/* +** On recent Windows platforms, the localtime_s() function is available +** as part of the "Secure CRT". It is essentially equivalent to +** localtime_r() available under most POSIX platforms, except that the +** order of the parameters is reversed. +** +** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx. +** +** If the user has not indicated to use localtime_r() or localtime_s() +** already, check for an MSVC build environment that provides +** localtime_s(). +*/ +#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \ + defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE) +#define HAVE_LOCALTIME_S 1 +#endif + #ifndef SQLITE_OMIT_LOCALTIME /* -** Compute the difference (in milliseconds) -** between localtime and UTC (a.k.a. GMT) -** for the time value p where p is in UTC. -*/ -static sqlite3_int64 localtimeOffset(DateTime *p){ +** The following routine implements the rough equivalent of localtime_r() +** using whatever operating-system specific localtime facility that +** is available. This routine returns 0 on success and +** non-zero on any kind of error. +** +** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this +** routine will always fail. +*/ +static int osLocaltime(time_t *t, struct tm *pTm){ + int rc; +#if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \ + && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S) + struct tm *pX; + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex_enter(mutex); + pX = localtime(t); +#ifndef SQLITE_OMIT_BUILTIN_TEST + if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0; +#endif + if( pX ) *pTm = *pX; + sqlite3_mutex_leave(mutex); + rc = pX==0; +#else +#ifndef SQLITE_OMIT_BUILTIN_TEST + if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; +#endif +#if defined(HAVE_LOCALTIME_R) && HAVE_LOCALTIME_R + rc = localtime_r(t, pTm)==0; +#else + rc = localtime_s(pTm, t); +#endif /* HAVE_LOCALTIME_R */ +#endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */ + return rc; +} +#endif /* SQLITE_OMIT_LOCALTIME */ + + +#ifndef SQLITE_OMIT_LOCALTIME +/* +** Compute the difference (in milliseconds) between localtime and UTC +** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs, +** return this value and set *pRc to SQLITE_OK. +** +** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value +** is undefined in this case. +*/ +static sqlite3_int64 localtimeOffset( + DateTime *p, /* Date at which to calculate offset */ + sqlite3_context *pCtx, /* Write error here if one occurs */ + int *pRc /* OUT: Error code. SQLITE_OK or ERROR */ +){ DateTime x, y; time_t t; + struct tm sLocal; + + /* Initialize the contents of sLocal to avoid a compiler warning. */ + memset(&sLocal, 0, sizeof(sLocal)); + x = *p; computeYMD_HMS(&x); if( x.Y<1971 || x.Y>=2038 ){ x.Y = 2000; x.M = 1; x.D = 1; x.h = 0; x.m = 0; @@ -13104,57 +13603,33 @@ static sqlite3_int64 localtimeOffset(Dat } else { int s = (int)(x.s + 0.5); x.s = s; } x.tz = 0; x.validJD = 0; computeJD(&x); t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); -#ifdef HAVE_LOCALTIME_R - { - struct tm sLocal; - localtime_r(&t, &sLocal); - y.Y = sLocal.tm_year + 1900; - y.M = sLocal.tm_mon + 1; - y.D = sLocal.tm_mday; - y.h = sLocal.tm_hour; - y.m = sLocal.tm_min; - y.s = sLocal.tm_sec; - } -#elif defined(HAVE_LOCALTIME_S) && HAVE_LOCALTIME_S - { - struct tm sLocal; - localtime_s(&sLocal, &t); - y.Y = sLocal.tm_year + 1900; - y.M = sLocal.tm_mon + 1; - y.D = sLocal.tm_mday; - y.h = sLocal.tm_hour; - y.m = sLocal.tm_min; - y.s = sLocal.tm_sec; - } -#else - { - struct tm *pTm; - sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); - pTm = localtime(&t); - y.Y = pTm->tm_year + 1900; - y.M = pTm->tm_mon + 1; - y.D = pTm->tm_mday; - y.h = pTm->tm_hour; - y.m = pTm->tm_min; - y.s = pTm->tm_sec; - sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); - } -#endif + if( osLocaltime(&t, &sLocal) ){ + sqlite3_result_error(pCtx, "local time unavailable", -1); + *pRc = SQLITE_ERROR; + return 0; + } + y.Y = sLocal.tm_year + 1900; + y.M = sLocal.tm_mon + 1; + y.D = sLocal.tm_mday; + y.h = sLocal.tm_hour; + y.m = sLocal.tm_min; + y.s = sLocal.tm_sec; y.validYMD = 1; y.validHMS = 1; y.validJD = 0; y.validTZ = 0; computeJD(&y); + *pRc = SQLITE_OK; return y.iJD - x.iJD; } #endif /* SQLITE_OMIT_LOCALTIME */ /* ** Process a modifier to a date-time stamp. The modifiers are ** as follows: ** @@ -13168,19 +13643,22 @@ static sqlite3_int64 localtimeOffset(Dat ** start of year ** start of week ** start of day ** weekday N ** unixepoch ** localtime ** utc ** -** Return 0 on success and 1 if there is any kind of error. -*/ -static int parseModifier(const char *zMod, DateTime *p){ +** Return 0 on success and 1 if there is any kind of error. If the error +** is in a system call (i.e. localtime()), then an error message is written +** to context pCtx. If the error is an unrecognized modifier, no error is +** written to pCtx. +*/ +static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){ int rc = 1; int n; double r; char *z, zBuf[30]; z = zBuf; for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){ z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]]; } @@ -13190,19 +13668,18 @@ static int parseModifier(const char *zMo case 'l': { /* localtime ** ** Assuming the current time value is UTC (a.k.a. GMT), shift it to ** show local time. */ if( strcmp(z, "localtime")==0 ){ computeJD(p); - p->iJD += localtimeOffset(p); + p->iJD += localtimeOffset(p, pCtx, &rc); clearYMD_HMS_TZ(p); - rc = 0; } break; } #endif case 'u': { /* ** unixepoch ** @@ -13213,21 +13690,22 @@ static int parseModifier(const char *zMo p->iJD = (p->iJD + 43200)/86400 + 21086676*(i64)10000000; clearYMD_HMS_TZ(p); rc = 0; } #ifndef SQLITE_OMIT_LOCALTIME else if( strcmp(z, "utc")==0 ){ sqlite3_int64 c1; computeJD(p); - c1 = localtimeOffset(p); - p->iJD -= c1; - clearYMD_HMS_TZ(p); - p->iJD += c1 - localtimeOffset(p); - rc = 0; + c1 = localtimeOffset(p, pCtx, &rc); + if( rc==SQLITE_OK ){ + p->iJD -= c1; + clearYMD_HMS_TZ(p); + p->iJD += c1 - localtimeOffset(p, pCtx, &rc); + } } #endif break; } case 'w': { /* ** weekday N ** @@ -13398,19 +13876,18 @@ static int isDate( p->validJD = 1; }else{ z = sqlite3_value_text(argv[0]); if( !z || parseDateOrTime(context, (char*)z, p) ){ return 1; } } for(i=1; i<argc; i++){ - if( (z = sqlite3_value_text(argv[i]))==0 || parseModifier((char*)z, p) ){ - return 1; - } + z = sqlite3_value_text(argv[i]); + if( z==0 || parseModifier(context, (char*)z, p) ) return 1; } return 0; } /* ** The following routines implement the various date and time functions ** of SQLite. @@ -15742,17 +16219,17 @@ static SQLITE_WSD struct Mem5Global { int aiFreelist[LOGMAX+1]; /* ** Space for tracking which blocks are checked out and the size ** of each block. One byte per block. */ u8 *aCtrl; -} mem5 = { 0 }; +} mem5; /* ** Access the static variable through a macro for SQLITE_OMIT_WSD */ #define mem5 GLOBAL(struct Mem5Global, mem5) /* ** Assuming mem5.zPool is divided up into an array of Mem5Link @@ -16057,17 +16534,17 @@ static int memsys5Roundup(int n){ ** memsys5Log(2) -> 1 ** memsys5Log(4) -> 2 ** memsys5Log(5) -> 3 ** memsys5Log(8) -> 3 ** memsys5Log(9) -> 4 */ static int memsys5Log(int iValue){ int iLog; - for(iLog=0; (1<<iLog)<iValue; iLog++); + for(iLog=0; (iLog<(int)((sizeof(int)*8)-1)) && (1<<iLog)<iValue; iLog++); return iLog; } /* ** Initialize the memory allocator. ** ** This routine is not threadsafe. The caller must be holding a mutex ** to prevent multiple threads from entering at the same time. @@ -16088,16 +16565,17 @@ static int memsys5Init(void *NotUsed){ ** this is case. */ assert( (sizeof(Mem5Link)&(sizeof(Mem5Link)-1))==0 ); nByte = sqlite3GlobalConfig.nHeap; zByte = (u8*)sqlite3GlobalConfig.pHeap; assert( zByte!=0 ); /* sqlite3_config() does not allow otherwise */ + /* boundaries on sqlite3GlobalConfig.mnReq are enforced in sqlite3_config() */ nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq); mem5.szAtom = (1<<nMinLog); while( (int)sizeof(Mem5Link)>mem5.szAtom ){ mem5.szAtom = mem5.szAtom << 1; } mem5.nBlock = (nByte / (mem5.szAtom+sizeof(u8))); mem5.zPool = zByte; @@ -16591,55 +17069,63 @@ SQLITE_PRIVATE sqlite3_mutex_methods con /* ** The mutex object ** Each recursive mutex is an instance of the following structure. */ struct sqlite3_mutex { HMTX mutex; /* Mutex controlling the lock */ int id; /* Mutex type */ - int nRef; /* Number of references */ - TID owner; /* Thread holding this mutex */ -}; - -#define OS2_MUTEX_INITIALIZER 0,0,0,0 +#ifdef SQLITE_DEBUG + int trace; /* True to trace changes */ +#endif +}; + +#ifdef SQLITE_DEBUG +#define SQLITE3_MUTEX_INITIALIZER { 0, 0, 0 } +#else +#define SQLITE3_MUTEX_INITIALIZER { 0, 0 } +#endif /* ** Initialize and deinitialize the mutex subsystem. */ static int os2MutexInit(void){ return SQLITE_OK; } static int os2MutexEnd(void){ return SQLITE_OK; } /* ** The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. If it returns NULL ** that means that a mutex could not be allocated. ** SQLite will unwind its stack and return an error. The argument ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> -** <li> SQLITE_MUTEX_FAST 0 -** <li> SQLITE_MUTEX_RECURSIVE 1 -** <li> SQLITE_MUTEX_STATIC_MASTER 2 -** <li> SQLITE_MUTEX_STATIC_MEM 3 -** <li> SQLITE_MUTEX_STATIC_PRNG 4 +** <li> SQLITE_MUTEX_FAST +** <li> SQLITE_MUTEX_RECURSIVE +** <li> SQLITE_MUTEX_STATIC_MASTER +** <li> SQLITE_MUTEX_STATIC_MEM +** <li> SQLITE_MUTEX_STATIC_MEM2 +** <li> SQLITE_MUTEX_STATIC_PRNG +** <li> SQLITE_MUTEX_STATIC_LRU +** <li> SQLITE_MUTEX_STATIC_LRU2 ** </ul> ** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does ** not want to. But SQLite will only request a recursive mutex in ** cases where it really needs one. If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** The other allowed parameters to sqlite3_mutex_alloc() each return -** a pointer to a static preexisting mutex. Three static mutexes are +** a pointer to a static preexisting mutex. Six static mutexes are ** used by the current version of SQLite. Future versions of SQLite ** may add additional static mutexes. Static mutexes are for internal ** use by SQLite only. Applications that use SQLite mutexes should ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or ** SQLITE_MUTEX_RECURSIVE. ** ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() @@ -16659,23 +17145,23 @@ static sqlite3_mutex *os2MutexAlloc(int sqlite3_free( p ); p = NULL; } } break; } default: { static volatile int isInit = 0; - static sqlite3_mutex staticMutexes[] = { - { OS2_MUTEX_INITIALIZER, }, - { OS2_MUTEX_INITIALIZER, }, - { OS2_MUTEX_INITIALIZER, }, - { OS2_MUTEX_INITIALIZER, }, - { OS2_MUTEX_INITIALIZER, }, - { OS2_MUTEX_INITIALIZER, }, + static sqlite3_mutex staticMutexes[6] = { + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, }; if ( !isInit ){ APIRET rc; PTIB ptib; PPIB ppib; HMTX mutex; char name[32]; DosGetInfoBlocks( &ptib, &ppib ); @@ -16711,128 +17197,123 @@ static sqlite3_mutex *os2MutexAlloc(int } /* ** This routine deallocates a previously allocated mutex. ** SQLite is careful to deallocate every mutex that it allocates. */ static void os2MutexFree(sqlite3_mutex *p){ - if( p==0 ) return; - assert( p->nRef==0 ); +#ifdef SQLITE_DEBUG + TID tid; + PID pid; + ULONG ulCount; + DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); + assert( ulCount==0 ); assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); +#endif DosCloseMutexSem( p->mutex ); sqlite3_free( p ); } #ifdef SQLITE_DEBUG /* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use inside assert() statements. */ static int os2MutexHeld(sqlite3_mutex *p){ TID tid; PID pid; ULONG ulCount; PTIB ptib; - if( p!=0 ) { - DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); - } else { - DosGetInfoBlocks(&ptib, NULL); - tid = ptib->tib_ptib2->tib2_ultid; - } - return p==0 || (p->nRef!=0 && p->owner==tid); + DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); + if( ulCount==0 || ( ulCount>1 && p->id!=SQLITE_MUTEX_RECURSIVE ) ) + return 0; + DosGetInfoBlocks(&ptib, NULL); + return tid==ptib->tib_ptib2->tib2_ultid; } static int os2MutexNotheld(sqlite3_mutex *p){ TID tid; PID pid; ULONG ulCount; PTIB ptib; - if( p!= 0 ) { - DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); - } else { - DosGetInfoBlocks(&ptib, NULL); - tid = ptib->tib_ptib2->tib2_ultid; - } - return p==0 || p->nRef==0 || p->owner!=tid; + DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); + if( ulCount==0 ) + return 1; + DosGetInfoBlocks(&ptib, NULL); + return tid!=ptib->tib_ptib2->tib2_ultid; +} +static void os2MutexTrace(sqlite3_mutex *p, char *pAction){ + TID tid; + PID pid; + ULONG ulCount; + DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); + printf("%s mutex %p (%d) with nRef=%ld\n", pAction, (void*)p, p->trace, ulCount); } #endif /* ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt ** to enter a mutex. If another thread is already within the mutex, ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can ** be entered multiple times by the same thread. In such cases the, ** mutex must be exited an equal number of times before another thread ** can enter. If the same thread tries to enter any other kind of mutex ** more than once, the behavior is undefined. */ static void os2MutexEnter(sqlite3_mutex *p){ - TID tid; - PID holder1; - ULONG holder2; - if( p==0 ) return; assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) ); DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT); - DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2); - p->owner = tid; - p->nRef++; +#ifdef SQLITE_DEBUG + if( p->trace ) os2MutexTrace(p, "enter"); +#endif } static int os2MutexTry(sqlite3_mutex *p){ - int rc; - TID tid; - PID holder1; - ULONG holder2; - if( p==0 ) return SQLITE_OK; + int rc = SQLITE_BUSY; assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) ); - if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR) { - DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2); - p->owner = tid; - p->nRef++; + if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR ) { rc = SQLITE_OK; - } else { - rc = SQLITE_BUSY; - } - +#ifdef SQLITE_DEBUG + if( p->trace ) os2MutexTrace(p, "try"); +#endif + } return rc; } /* ** The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. The behavior ** is undefined if the mutex is not currently entered or ** is not currently allocated. SQLite will never do either. */ static void os2MutexLeave(sqlite3_mutex *p){ - TID tid; - PID holder1; - ULONG holder2; - if( p==0 ) return; - assert( p->nRef>0 ); - DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2); - assert( p->owner==tid ); - p->nRef--; - assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); + assert( os2MutexHeld(p) ); DosReleaseMutexSem(p->mutex); +#ifdef SQLITE_DEBUG + if( p->trace ) os2MutexTrace(p, "leave"); +#endif } SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ static const sqlite3_mutex_methods sMutex = { os2MutexInit, os2MutexEnd, os2MutexAlloc, os2MutexFree, os2MutexEnter, os2MutexTry, os2MutexLeave, #ifdef SQLITE_DEBUG os2MutexHeld, os2MutexNotheld +#else + 0, + 0 #endif }; return &sMutex; } #endif /* SQLITE_MUTEX_OS2 */ /************** End of mutex_os2.c *******************************************/ @@ -17466,17 +17947,17 @@ static int winMutexTry(sqlite3_mutex *p) p->nRef++; rc = SQLITE_OK; } #else UNUSED_PARAMETER(p); #endif #ifdef SQLITE_DEBUG if( rc==SQLITE_OK && p->trace ){ - printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); } #endif return rc; } /* ** The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. The behavior @@ -17785,17 +18266,17 @@ static void sqlite3MallocAlarm(int nByte static int mallocWithAlarm(int n, void **pp){ int nFull; void *p; assert( sqlite3_mutex_held(mem0.mutex) ); nFull = sqlite3GlobalConfig.m.xRoundup(n); sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n); if( mem0.alarmCallback!=0 ){ int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); - if( nUsed+nFull >= mem0.alarmThreshold ){ + if( nUsed >= mem0.alarmThreshold - nFull ){ mem0.nearlyFull = 1; sqlite3MallocAlarm(nFull); }else{ mem0.nearlyFull = 0; } } p = sqlite3GlobalConfig.m.xMalloc(nFull); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT @@ -17923,17 +18404,17 @@ SQLITE_PRIVATE void sqlite3ScratchFree(v if( p>=sqlite3GlobalConfig.pScratch && p<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<=sqlite3GlobalConfig.nScratch ); + assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch ); sqlite3StatusAdd(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, ~MEMTYPE_SCRATCH) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); if( sqlite3GlobalConfig.bMemstat ){ @@ -18026,17 +18507,17 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); } /* ** Change the size of an existing memory allocation */ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){ - int nOld, nNew; + int nOld, nNew, nDiff; void *pNew; if( pOld==0 ){ return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */ } if( nBytes<=0 ){ sqlite3_free(pOld); /* IMP: R-31593-10574 */ return 0; } @@ -18049,19 +18530,20 @@ SQLITE_PRIVATE void *sqlite3Realloc(void ** argument to xRealloc is always a value returned by a prior call to ** xRoundup. */ nNew = sqlite3GlobalConfig.m.xRoundup(nBytes); if( nOld==nNew ){ pNew = pOld; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes); - if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >= - mem0.alarmThreshold ){ - sqlite3MallocAlarm(nNew-nOld); + nDiff = nNew - nOld; + if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= + mem0.alarmThreshold-nDiff ){ + sqlite3MallocAlarm(nDiff); } assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); if( pNew==0 && mem0.alarmCallback ){ sqlite3MallocAlarm(nBytes); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } @@ -18697,17 +19179,21 @@ SQLITE_PRIVATE void sqlite3VXPrintf( if( flag_longlong ){ v = va_arg(ap,i64); }else if( flag_long ){ v = va_arg(ap,long int); }else{ v = va_arg(ap,int); } if( v<0 ){ - longvalue = -v; + if( v==SMALLEST_INT64 ){ + longvalue = ((u64)1)<<63; + }else{ + longvalue = -v; + } prefix = '-'; }else{ longvalue = v; if( flag_plussign ) prefix = '+'; else if( flag_blanksign ) prefix = ' '; else prefix = 0; } }else{ @@ -19632,21 +20118,21 @@ static const unsigned char sqlite3Utf8Tr c = sqlite3Utf8Trans1[c-0xc0]; \ while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ c = (c<<6) + (0x3f & *(zIn++)); \ } \ if( c<0x80 \ || (c&0xFFFFF800)==0xD800 \ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ } -SQLITE_PRIVATE int sqlite3Utf8Read( +SQLITE_PRIVATE u32 sqlite3Utf8Read( const unsigned char *zIn, /* First byte of UTF-8 character */ const unsigned char **pzNext /* Write first byte past UTF-8 char here */ ){ - int c; + unsigned int c; /* Same as READ_UTF8() above but without the zTerm parameter. ** For this routine, we assume the UTF8 string is always zero-terminated. */ c = *(zIn++); if( c>=0xc0 ){ c = sqlite3Utf8Trans1[c-0xc0]; while( (*zIn & 0xc0)==0x80 ){ @@ -19879,25 +20365,25 @@ SQLITE_PRIVATE int sqlite3Utf8CharLen(co */ #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) /* ** Translate UTF-8 to UTF-8. ** ** This has the effect of making sure that the string is well-formed ** UTF-8. Miscoded characters are removed. ** -** The translation is done in-place (since it is impossible for the -** correct UTF-8 encoding to be longer than a malformed encoding). +** The translation is done in-place and aborted if the output +** overruns the input. */ SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char *zIn){ unsigned char *zOut = zIn; unsigned char *zStart = zIn; u32 c; - while( zIn[0] ){ + while( zIn[0] && zOut<=zIn ){ c = sqlite3Utf8Read(zIn, (const u8**)&zIn); if( c!=0xfffd ){ WRITE_UTF8(zOut, c); } } *zOut = 0; return (int)(zOut - zStart); } @@ -20056,18 +20542,18 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(v # include <math.h> #endif /* ** Routine needed to support the testcase() macro. */ #ifdef SQLITE_COVERAGE_TEST SQLITE_PRIVATE void sqlite3Coverage(int x){ - static int dummy = 0; - dummy += x; + static unsigned dummy = 0; + dummy += (unsigned)x; } #endif #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Return true if the floating point value is Not a Number (NaN). ** ** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN. @@ -20471,70 +20957,90 @@ static int compare2pow63(const char *zNu testcase( c==0 ); testcase( c==(+1) ); } return c; } /* -** Convert zNum to a 64-bit signed integer and write -** the value of the integer into *pNum. -** If zNum is exactly 9223372036854665808, return 2. -** This is a special case as the context will determine -** if it is too big (used as a negative). -** If zNum is not an integer or is an integer that -** is too large to be expressed with 64 bits, -** then return 1. Otherwise return 0. +** Convert zNum to a 64-bit signed integer. +** +** 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 9223372036854665808, return 2. This special +** case is broken out because while 9223372036854665808 cannot be a +** signed 64-bit integer, its negative -9223372036854665808 can be. +** +** If zNum is too big for a 64-bit integer and is not +** 9223372036854665808 then return 1. ** ** length is the number of bytes in the string (bytes, not characters). ** The string is not necessarily zero-terminated. The encoding is ** given by enc. */ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ int incr = (enc==SQLITE_UTF8?1:2); - i64 v = 0; + u64 u = 0; int neg = 0; /* assume positive */ int i; int c = 0; const char *zStart; const char *zEnd = zNum + length; if( enc==SQLITE_UTF16BE ) zNum++; while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr; - if( zNum>=zEnd ) goto do_atoi_calc; - if( *zNum=='-' ){ - neg = 1; - zNum+=incr; - }else if( *zNum=='+' ){ - zNum+=incr; - } -do_atoi_calc: + if( zNum<zEnd ){ + if( *zNum=='-' ){ + neg = 1; + zNum+=incr; + }else if( *zNum=='+' ){ + zNum+=incr; + } + } zStart = zNum; while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */ for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){ - v = v*10 + c - '0'; - } - *pNum = neg ? -v : v; + u = u*10 + c - '0'; + } + if( u>LARGEST_INT64 ){ + *pNum = SMALLEST_INT64; + }else if( neg ){ + *pNum = -(i64)u; + }else{ + *pNum = (i64)u; + } testcase( i==18 ); testcase( i==19 ); testcase( i==20 ); if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){ /* zNum is empty or contains non-numeric text or is longer ** than 19 digits (thus guaranteeing that it is too large) */ return 1; }else if( i<19*incr ){ /* Less than 19 digits, so we know that it fits in 64 bits */ + assert( u<=LARGEST_INT64 ); return 0; }else{ - /* 19-digit numbers must be no larger than 9223372036854775807 if positive - ** or 9223372036854775808 if negative. Note that 9223372036854665808 - ** is 2^63. Return 1 if to large */ - c=compare2pow63(zNum, incr); - if( c==0 && neg==0 ) return 2; /* too big, exactly 9223372036854665808 */ - return c<neg ? 0 : 1; + /* 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; + }else if( c>0 ){ + /* zNum is greater than 9223372036854775808 so it overflows */ + return 1; + }else{ + /* zNum is exactly 9223372036854775808. Fits if negative. The + ** special case 2 overflow if positive */ + assert( u-1==LARGEST_INT64 ); + assert( (*pNum)==SMALLEST_INT64 ); + return neg ? 0 : 2; + } } } /* ** If zNum represents an integer that will fit in 32-bits, then set ** *pValue to that integer and return true. Otherwise return false. ** ** Any non-numeric characters that following zNum are ignored. @@ -20993,50 +21499,48 @@ SQLITE_PRIVATE void sqlite3Put4byte(unsi p[0] = (u8)(v>>24); p[1] = (u8)(v>>16); p[2] = (u8)(v>>8); p[3] = (u8)v; } -#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) /* ** Translate a single byte of Hex into an integer. ** This routine only works if h really is a valid hexadecimal ** character: 0..9a..fA..F */ -static u8 hexToInt(int h){ +SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); #ifdef SQLITE_ASCII h += 9*(1&(h>>6)); #endif #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); #endif return (u8)(h & 0xf); } -#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */ #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) /* ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary ** value. Return a pointer to its binary value. Space to hold the ** binary value has been obtained from malloc and must be freed by ** the calling routine. */ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ char *zBlob; int i; zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1); n--; if( zBlob ){ for(i=0; i<n; i+=2){ - zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]); + zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]); } zBlob[i/2] = 0; } return zBlob; } #endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */ /* @@ -21091,16 +21595,110 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSic testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("invalid"); return 0; }else{ return 1; } } +/* +** Attempt to add, substract, or multiply the 64-bit signed value iB against +** the other 64-bit signed integer at *pA and store the result in *pA. +** Return 0 on success. Or if the operation would have resulted in an +** overflow, leave *pA unchanged and return 1. +*/ +SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){ + i64 iA = *pA; + testcase( iA==0 ); testcase( iA==1 ); + testcase( iB==-1 ); testcase( iB==0 ); + if( iB>=0 ){ + testcase( iA>0 && LARGEST_INT64 - iA == iB ); + testcase( iA>0 && LARGEST_INT64 - iA == iB - 1 ); + if( iA>0 && LARGEST_INT64 - iA < iB ) return 1; + *pA += iB; + }else{ + testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 1 ); + testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 2 ); + if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1; + *pA += iB; + } + return 0; +} +SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ + testcase( iB==SMALLEST_INT64+1 ); + if( iB==SMALLEST_INT64 ){ + testcase( (*pA)==(-1) ); testcase( (*pA)==0 ); + if( (*pA)>=0 ) return 1; + *pA -= iB; + return 0; + }else{ + return sqlite3AddInt64(pA, -iB); + } +} +#define TWOPOWER32 (((i64)1)<<32) +#define TWOPOWER31 (((i64)1)<<31) +SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ + i64 iA = *pA; + i64 iA1, iA0, iB1, iB0, r; + + iA1 = iA/TWOPOWER32; + iA0 = iA % TWOPOWER32; + iB1 = iB/TWOPOWER32; + iB0 = iB % TWOPOWER32; + if( iA1*iB1 != 0 ) return 1; + assert( iA1*iB0==0 || iA0*iB1==0 ); + r = iA1*iB0 + iA0*iB1; + testcase( r==(-TWOPOWER31)-1 ); + testcase( r==(-TWOPOWER31) ); + testcase( r==TWOPOWER31 ); + testcase( r==TWOPOWER31-1 ); + if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1; + r *= TWOPOWER32; + if( sqlite3AddInt64(&r, iA0*iB0) ) return 1; + *pA = r; + return 0; +} + +/* +** Compute the absolute value of a 32-bit signed integer, of possible. Or +** if the integer has a value of -2147483648, return +2147483647 +*/ +SQLITE_PRIVATE int sqlite3AbsInt32(int x){ + if( x>=0 ) return x; + if( x==(int)0x80000000 ) return 0x7fffffff; + return -x; +} + +#ifdef SQLITE_ENABLE_8_3_NAMES +/* +** If SQLITE_ENABLE_8_3_NAME is set at compile-time and if the database +** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and +** if filename in z[] has a suffix (a.k.a. "extension") that is longer than +** three characters, then shorten the suffix on z[] to be the last three +** characters of the original suffix. +** +** Examples: +** +** test.db-journal => test.nal +** test.db-wal => test.wal +** test.db-shm => test.shm +*/ +SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ + const char *zOk; + zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names"); + if( zOk && sqlite3GetBoolean(zOk) ){ + int i, sz; + sz = sqlite3Strlen30(z); + for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} + if( z[i]=='.' && ALWAYS(sz>i+4) ) memcpy(&z[i+1], &z[sz-3], 4); + } +} +#endif + /************** End of util.c ************************************************/ /************** Begin file hash.c ********************************************/ /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** @@ -21789,54 +22387,72 @@ SQLITE_API int sqlite3_open_file_count = #define OpenCounter(X) #endif #endif /* !defined(_OS_COMMON_H_) */ /************** End of os_common.h *******************************************/ /************** Continuing where we left off in os_os2.c *********************/ +/* Forward references */ +typedef struct os2File os2File; /* The file structure */ +typedef struct os2ShmNode os2ShmNode; /* A shared descritive memory node */ +typedef struct os2ShmLink os2ShmLink; /* A connection to shared-memory */ + /* ** The os2File structure is subclass of sqlite3_file specific for the OS/2 ** protability layer. */ -typedef struct os2File os2File; struct os2File { const sqlite3_io_methods *pMethod; /* Always the first entry */ HFILE h; /* Handle for accessing the file */ - char* pathToDel; /* Name of file to delete on close, NULL if not */ - unsigned char locktype; /* Type of lock currently held on this file */ + int flags; /* Flags provided to os2Open() */ + int locktype; /* Type of lock currently held on this file */ + int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ + char *zFullPathCp; /* Full path name of this file */ + os2ShmLink *pShmLink; /* Instance of shared memory on this file */ }; #define LOCK_TIMEOUT 10L /* the default locking timeout */ +/* +** Missing from some versions of the OS/2 toolkit - +** used to allocate from high memory if possible +*/ +#ifndef OBJ_ANY +# define OBJ_ANY 0x00000400 +#endif + /***************************************************************************** ** The next group of routines implement the I/O methods specified ** by the sqlite3_io_methods object. ******************************************************************************/ /* ** Close a file. */ static int os2Close( sqlite3_file *id ){ - APIRET rc = NO_ERROR; - os2File *pFile; - if( id && (pFile = (os2File*)id) != 0 ){ - OSTRACE(( "CLOSE %d\n", pFile->h )); - rc = DosClose( pFile->h ); - pFile->locktype = NO_LOCK; - if( pFile->pathToDel != NULL ){ - rc = DosForceDelete( (PSZ)pFile->pathToDel ); - free( pFile->pathToDel ); - pFile->pathToDel = NULL; - } - id = 0; - OpenCounter( -1 ); - } - + APIRET rc; + os2File *pFile = (os2File*)id; + + assert( id!=0 ); + OSTRACE(( "CLOSE %d (%s)\n", pFile->h, pFile->zFullPathCp )); + + rc = DosClose( pFile->h ); + + if( pFile->flags & SQLITE_OPEN_DELETEONCLOSE ) + DosForceDelete( (PSZ)pFile->zFullPathCp ); + + free( pFile->zFullPathCp ); + pFile->zFullPathCp = NULL; + pFile->locktype = NO_LOCK; + pFile->h = (HFILE)-1; + pFile->flags = 0; + + OpenCounter( -1 ); return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; } /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ @@ -21899,20 +22515,31 @@ static int os2Write( return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK; } /* ** Truncate an open file to a specified size */ static int os2Truncate( sqlite3_file *id, i64 nByte ){ - APIRET rc = NO_ERROR; + APIRET rc; os2File *pFile = (os2File*)id; + assert( id!=0 ); OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte )); SimulateIOError( return SQLITE_IOERR_TRUNCATE ); + + /* If the user has configured a chunk-size for this file, truncate the + ** file so that it consists of an integer number of chunks (i.e. the + ** actual file size after the operation may be larger than the requested + ** size). + */ + if( pFile->szChunk ){ + nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; + } + rc = DosSetFileSize( pFile->h, nByte ); return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE; } #ifdef SQLITE_TEST /* ** Count the number of fullsyncs and normal syncs. This is used to test ** that syncs and fullsyncs are occuring at the right times. @@ -22266,39 +22893,55 @@ static int os2Unlock( sqlite3_file *id, static int os2FileControl(sqlite3_file *id, int op, void *pArg){ switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = ((os2File*)id)->locktype; OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype )); return SQLITE_OK; } + case SQLITE_FCNTL_CHUNK_SIZE: { + ((os2File*)id)->szChunk = *(int*)pArg; + return SQLITE_OK; + } + case SQLITE_FCNTL_SIZE_HINT: { + sqlite3_int64 sz = *(sqlite3_int64*)pArg; + SimulateIOErrorBenign(1); + os2Truncate(id, sz); + SimulateIOErrorBenign(0); + return SQLITE_OK; + } + case SQLITE_FCNTL_SYNC_OMITTED: { + return SQLITE_OK; + } } return SQLITE_NOTFOUND; } /* ** 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 os2SectorSize(sqlite3_file *id){ + UNUSED_PARAMETER(id); return SQLITE_DEFAULT_SECTOR_SIZE; } /* ** Return a vector of device characteristics. */ static int os2DeviceCharacteristics(sqlite3_file *id){ - return 0; + UNUSED_PARAMETER(id); + return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; } /* ** Character set conversion objects used by conversion routines. */ static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */ static UconvObject uclCp = NULL; /* convert between local codepage and UCS-2 */ @@ -22375,91 +23018,754 @@ char *convertCpPathToUtf8( const char *i return out; /* if conversion fails, return the empty string */ /* determine string for the conversion of UTF-8 which is CP1208 */ UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH ); return out; } + +#ifndef SQLITE_OMIT_WAL + +/* +** Use main database file for interprocess locking. If un-defined +** a separate file is created for this purpose. The file will be +** used only to set file locks. There will be no data written to it. +*/ +#define SQLITE_OS2_NO_WAL_LOCK_FILE + +#if 0 +static void _ERR_TRACE( const char *fmt, ... ) { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fflush(stderr); +} +#define ERR_TRACE(rc, msg) \ + if( (rc) != SQLITE_OK ) _ERR_TRACE msg; +#else +#define ERR_TRACE(rc, msg) +#endif + +/* +** Helper functions to obtain and relinquish the global mutex. The +** global mutex is used to protect os2ShmNodeList. +** +** Function os2ShmMutexHeld() is used to assert() that the global mutex +** is held when required. This function is only used as part of assert() +** statements. e.g. +** +** os2ShmEnterMutex() +** assert( os2ShmMutexHeld() ); +** os2ShmLeaveMutex() +*/ +static void os2ShmEnterMutex(void){ + sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); +} +static void os2ShmLeaveMutex(void){ + sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); +} +#ifdef SQLITE_DEBUG +static int os2ShmMutexHeld(void) { + return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); +} +int GetCurrentProcessId(void) { + PPIB pib; + DosGetInfoBlocks(NULL, &pib); + return (int)pib->pib_ulpid; +} +#endif + +/* +** Object used to represent a the shared memory area for a single log file. +** When multiple threads all reference the same log-summary, each thread has +** its own os2File object, but they all point to a single instance of this +** object. In other words, each log-summary is opened only once per process. +** +** os2ShmMutexHeld() must be true when creating or destroying +** this object or while reading or writing the following fields: +** +** nRef +** pNext +** +** The following fields are read-only after the object is created: +** +** szRegion +** hLockFile +** shmBaseName +** +** Either os2ShmNode.mutex must be held or os2ShmNode.nRef==0 and +** os2ShmMutexHeld() is true when reading or writing any other field +** in this structure. +** +*/ +struct os2ShmNode { + sqlite3_mutex *mutex; /* Mutex to access this object */ + os2ShmNode *pNext; /* Next in list of all os2ShmNode objects */ + + int szRegion; /* Size of shared-memory regions */ + + int nRegion; /* Size of array apRegion */ + void **apRegion; /* Array of pointers to shared-memory regions */ + + int nRef; /* Number of os2ShmLink objects pointing to this */ + os2ShmLink *pFirst; /* First os2ShmLink object pointing to this */ + + HFILE hLockFile; /* File used for inter-process memory locking */ + char shmBaseName[1]; /* Name of the memory object !!! must last !!! */ +}; + + +/* +** Structure used internally by this VFS to record the state of an +** open shared memory connection. +** +** The following fields are initialized when this object is created and +** are read-only thereafter: +** +** os2Shm.pShmNode +** os2Shm.id +** +** All other fields are read/write. The os2Shm.pShmNode->mutex must be held +** while accessing any read/write fields. +*/ +struct os2ShmLink { + os2ShmNode *pShmNode; /* The underlying os2ShmNode object */ + os2ShmLink *pNext; /* Next os2Shm with the same os2ShmNode */ + u32 sharedMask; /* Mask of shared locks held */ + u32 exclMask; /* Mask of exclusive locks held */ +#ifdef SQLITE_DEBUG + u8 id; /* Id of this connection with its os2ShmNode */ +#endif +}; + + +/* +** A global list of all os2ShmNode objects. +** +** The os2ShmMutexHeld() must be true while reading or writing this list. +*/ +static os2ShmNode *os2ShmNodeList = NULL; + +/* +** Constants used for locking +*/ +#ifdef SQLITE_OS2_NO_WAL_LOCK_FILE +#define OS2_SHM_BASE (PENDING_BYTE + 0x10000) /* first lock byte */ +#else +#define OS2_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ +#endif + +#define OS2_SHM_DMS (OS2_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ + +/* +** Apply advisory locks for all n bytes beginning at ofst. +*/ +#define _SHM_UNLCK 1 /* no lock */ +#define _SHM_RDLCK 2 /* shared lock, no wait */ +#define _SHM_WRLCK 3 /* exlusive lock, no wait */ +#define _SHM_WRLCK_WAIT 4 /* exclusive lock, wait */ +static int os2ShmSystemLock( + os2ShmNode *pNode, /* Apply locks to this open shared-memory segment */ + int lockType, /* _SHM_UNLCK, _SHM_RDLCK, _SHM_WRLCK or _SHM_WRLCK_WAIT */ + int ofst, /* Offset to first byte to be locked/unlocked */ + int nByte /* Number of bytes to lock or unlock */ +){ + APIRET rc; + FILELOCK area; + ULONG mode, timeout; + + /* Access to the os2ShmNode object is serialized by the caller */ + assert( sqlite3_mutex_held(pNode->mutex) || pNode->nRef==0 ); + + mode = 1; /* shared lock */ + timeout = 0; /* no wait */ + area.lOffset = ofst; + area.lRange = nByte; + + switch( lockType ) { + case _SHM_WRLCK_WAIT: + timeout = (ULONG)-1; /* wait forever */ + case _SHM_WRLCK: + mode = 0; /* exclusive lock */ + case _SHM_RDLCK: + rc = DosSetFileLocks(pNode->hLockFile, + NULL, &area, timeout, mode); + break; + /* case _SHM_UNLCK: */ + default: + rc = DosSetFileLocks(pNode->hLockFile, + &area, NULL, 0, 0); + break; + } + + OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n", + pNode->hLockFile, + rc==SQLITE_OK ? "ok" : "failed", + lockType==_SHM_UNLCK ? "Unlock" : "Lock", + rc)); + + ERR_TRACE(rc, ("os2ShmSystemLock: %d %s\n", rc, pNode->shmBaseName)) + + return ( rc == 0 ) ? SQLITE_OK : SQLITE_BUSY; +} + +/* +** Find an os2ShmNode in global list or allocate a new one, if not found. +** +** This is not a VFS shared-memory method; it is a utility function called +** by VFS shared-memory methods. +*/ +static int os2OpenSharedMemory( os2File *fd, int szRegion ) { + os2ShmLink *pLink; + os2ShmNode *pNode; + int cbShmName, rc = SQLITE_OK; + char shmName[CCHMAXPATH + 30]; +#ifndef SQLITE_OS2_NO_WAL_LOCK_FILE + ULONG action; +#endif + + /* We need some additional space at the end to append the region number */ + cbShmName = sprintf(shmName, "\\SHAREMEM\\%s", fd->zFullPathCp ); + if( cbShmName >= CCHMAXPATH-8 ) + return SQLITE_IOERR_SHMOPEN; + + /* Replace colon in file name to form a valid shared memory name */ + shmName[10+1] = '!'; + + /* Allocate link object (we free it later in case of failure) */ + pLink = sqlite3_malloc( sizeof(*pLink) ); + if( !pLink ) + return SQLITE_NOMEM; + + /* Access node list */ + os2ShmEnterMutex(); + + /* Find node by it's shared memory base name */ + for( pNode = os2ShmNodeList; + pNode && stricmp(shmName, pNode->shmBaseName) != 0; + pNode = pNode->pNext ) ; + + /* Not found: allocate a new node */ + if( !pNode ) { + pNode = sqlite3_malloc( sizeof(*pNode) + cbShmName ); + if( pNode ) { + memset(pNode, 0, sizeof(*pNode) ); + pNode->szRegion = szRegion; + pNode->hLockFile = (HFILE)-1; + strcpy(pNode->shmBaseName, shmName); + +#ifdef SQLITE_OS2_NO_WAL_LOCK_FILE + if( DosDupHandle(fd->h, &pNode->hLockFile) != 0 ) { +#else + sprintf(shmName, "%s-lck", fd->zFullPathCp); + if( DosOpen((PSZ)shmName, &pNode->hLockFile, &action, 0, FILE_NORMAL, + OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW, + OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE | + OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR, + NULL) != 0 ) { +#endif + sqlite3_free(pNode); + rc = SQLITE_IOERR; + } else { + pNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( !pNode->mutex ) { + sqlite3_free(pNode); + rc = SQLITE_NOMEM; + } + } + } else { + rc = SQLITE_NOMEM; + } + + if( rc == SQLITE_OK ) { + pNode->pNext = os2ShmNodeList; + os2ShmNodeList = pNode; + } else { + pNode = NULL; + } + } else if( pNode->szRegion != szRegion ) { + rc = SQLITE_IOERR_SHMSIZE; + pNode = NULL; + } + + if( pNode ) { + sqlite3_mutex_enter(pNode->mutex); + + memset(pLink, 0, sizeof(*pLink)); + + pLink->pShmNode = pNode; + pLink->pNext = pNode->pFirst; + pNode->pFirst = pLink; + pNode->nRef++; + + fd->pShmLink = pLink; + + sqlite3_mutex_leave(pNode->mutex); + + } else { + /* Error occured. Free our link object. */ + sqlite3_free(pLink); + } + + os2ShmLeaveMutex(); + + ERR_TRACE(rc, ("os2OpenSharedMemory: %d %s\n", rc, fd->zFullPathCp)) + + return rc; +} + +/* +** Purge the os2ShmNodeList list of all entries with nRef==0. +** +** This is not a VFS shared-memory method; it is a utility function called +** by VFS shared-memory methods. +*/ +static void os2PurgeShmNodes( int deleteFlag ) { + os2ShmNode *pNode; + os2ShmNode **ppNode; + + os2ShmEnterMutex(); + + ppNode = &os2ShmNodeList; + + while( *ppNode ) { + pNode = *ppNode; + + if( pNode->nRef == 0 ) { + *ppNode = pNode->pNext; + + if( pNode->apRegion ) { + /* Prevent other processes from resizing the shared memory */ + os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1); + + while( pNode->nRegion-- ) { +#ifdef SQLITE_DEBUG + int rc = +#endif + DosFreeMem(pNode->apRegion[pNode->nRegion]); + + OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n", + (int)GetCurrentProcessId(), pNode->nRegion, + rc == 0 ? "ok" : "failed")); + } + + /* Allow other processes to resize the shared memory */ + os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1); + + sqlite3_free(pNode->apRegion); + } + + DosClose(pNode->hLockFile); + +#ifndef SQLITE_OS2_NO_WAL_LOCK_FILE + if( deleteFlag ) { + char fileName[CCHMAXPATH]; + /* Skip "\\SHAREMEM\\" */ + sprintf(fileName, "%s-lck", pNode->shmBaseName + 10); + /* restore colon */ + fileName[1] = ':'; + + DosForceDelete(fileName); + } +#endif + + sqlite3_mutex_free(pNode->mutex); + + sqlite3_free(pNode); + + } else { + ppNode = &pNode->pNext; + } + } + + os2ShmLeaveMutex(); +} + +/* +** This function is called to obtain a pointer to region iRegion of the +** shared-memory associated with the database file id. Shared-memory regions +** are numbered starting from zero. Each shared-memory region is szRegion +** bytes in size. +** +** If an error occurs, an error code is returned and *pp is set to NULL. +** +** Otherwise, if the bExtend parameter is 0 and the requested shared-memory +** region has not been allocated (by any client, including one running in a +** separate process), then *pp is set to NULL and SQLITE_OK returned. If +** bExtend is non-zero and the requested shared-memory region has not yet +** been allocated, it is allocated by this function. +** +** If the shared-memory region has already been allocated or is allocated by +** this call as described above, then it is mapped into this processes +** address space (if it is not already), *pp is set to point to the mapped +** memory and SQLITE_OK returned. +*/ +static int os2ShmMap( + sqlite3_file *id, /* Handle open on database file */ + int iRegion, /* Region to retrieve */ + int szRegion, /* Size of regions */ + int bExtend, /* True to extend block if necessary */ + void volatile **pp /* OUT: Mapped memory */ +){ + PVOID pvTemp; + void **apRegion; + os2ShmNode *pNode; + int n, rc = SQLITE_OK; + char shmName[CCHMAXPATH]; + os2File *pFile = (os2File*)id; + + *pp = NULL; + + if( !pFile->pShmLink ) + rc = os2OpenSharedMemory( pFile, szRegion ); + + if( rc == SQLITE_OK ) { + pNode = pFile->pShmLink->pShmNode ; + + sqlite3_mutex_enter(pNode->mutex); + + assert( szRegion==pNode->szRegion ); + + /* Unmapped region ? */ + if( iRegion >= pNode->nRegion ) { + /* Prevent other processes from resizing the shared memory */ + os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1); + + apRegion = sqlite3_realloc( + pNode->apRegion, (iRegion + 1) * sizeof(apRegion[0])); + + if( apRegion ) { + pNode->apRegion = apRegion; + + while( pNode->nRegion <= iRegion ) { + sprintf(shmName, "%s-%u", + pNode->shmBaseName, pNode->nRegion); + + if( DosGetNamedSharedMem(&pvTemp, (PSZ)shmName, + PAG_READ | PAG_WRITE) != NO_ERROR ) { + if( !bExtend ) + break; + + if( DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion, + PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_ANY) != NO_ERROR && + DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion, + PAG_READ | PAG_WRITE | PAG_COMMIT) != NO_ERROR ) { + rc = SQLITE_NOMEM; + break; + } + } + + apRegion[pNode->nRegion++] = pvTemp; + } + + /* zero out remaining entries */ + for( n = pNode->nRegion; n <= iRegion; n++ ) + pNode->apRegion[n] = NULL; + + /* Return this region (maybe zero) */ + *pp = pNode->apRegion[iRegion]; + } else { + rc = SQLITE_NOMEM; + } + + /* Allow other processes to resize the shared memory */ + os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1); + + } else { + /* Region has been mapped previously */ + *pp = pNode->apRegion[iRegion]; + } + + sqlite3_mutex_leave(pNode->mutex); + } + + ERR_TRACE(rc, ("os2ShmMap: %s iRgn = %d, szRgn = %d, bExt = %d : %d\n", + pFile->zFullPathCp, iRegion, szRegion, bExtend, rc)) + + return rc; +} + +/* +** Close a connection to shared-memory. Delete the underlying +** storage if deleteFlag is true. +** +** If there is no shared memory associated with the connection then this +** routine is a harmless no-op. +*/ +static int os2ShmUnmap( + sqlite3_file *id, /* The underlying database file */ + int deleteFlag /* Delete shared-memory if true */ +){ + os2File *pFile = (os2File*)id; + os2ShmLink *pLink = pFile->pShmLink; + + if( pLink ) { + int nRef = -1; + os2ShmLink **ppLink; + os2ShmNode *pNode = pLink->pShmNode; + + sqlite3_mutex_enter(pNode->mutex); + + for( ppLink = &pNode->pFirst; + *ppLink && *ppLink != pLink; + ppLink = &(*ppLink)->pNext ) ; + + assert(*ppLink); + + if( *ppLink ) { + *ppLink = pLink->pNext; + nRef = --pNode->nRef; + } else { + ERR_TRACE(1, ("os2ShmUnmap: link not found ! %s\n", + pNode->shmBaseName)) + } + + pFile->pShmLink = NULL; + sqlite3_free(pLink); + + sqlite3_mutex_leave(pNode->mutex); + + if( nRef == 0 ) + os2PurgeShmNodes( deleteFlag ); + } + + return SQLITE_OK; +} + +/* +** Change the lock state for a shared-memory segment. +** +** Note that the relationship between SHAREd and EXCLUSIVE locks is a little +** different here than in posix. In xShmLock(), one can go from unlocked +** to shared and back or from unlocked to exclusive and back. But one may +** not go from shared to exclusive or from exclusive to shared. +*/ +static int os2ShmLock( + sqlite3_file *id, /* Database file holding the shared memory */ + int ofst, /* First lock to acquire or release */ + int n, /* Number of locks to acquire or release */ + int flags /* What to do with the lock */ +){ + u32 mask; /* Mask of locks to take or release */ + int rc = SQLITE_OK; /* Result code */ + os2File *pFile = (os2File*)id; + os2ShmLink *p = pFile->pShmLink; /* The shared memory being locked */ + os2ShmLink *pX; /* For looping over all siblings */ + os2ShmNode *pShmNode = p->pShmNode; /* Our node */ + + assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); + assert( n>=1 ); + assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) + || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE) + || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) + || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); + assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); + + mask = (u32)((1U<<(ofst+n)) - (1U<<ofst)); + assert( n>1 || mask==(1<<ofst) ); + + + sqlite3_mutex_enter(pShmNode->mutex); + + if( flags & SQLITE_SHM_UNLOCK ){ + u32 allMask = 0; /* Mask of locks held by siblings */ + + /* See if any siblings hold this same lock */ + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + if( pX==p ) continue; + assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); + allMask |= pX->sharedMask; + } + + /* Unlock the system-level locks */ + if( (mask & allMask)==0 ){ + rc = os2ShmSystemLock(pShmNode, _SHM_UNLCK, ofst+OS2_SHM_BASE, n); + }else{ + rc = SQLITE_OK; + } + + /* Undo the local locks */ + if( rc==SQLITE_OK ){ + p->exclMask &= ~mask; + p->sharedMask &= ~mask; + } + }else if( flags & SQLITE_SHM_SHARED ){ + u32 allShared = 0; /* Union of locks held by connections other than "p" */ + + /* Find out which shared locks are already held by sibling connections. + ** If any sibling already holds an exclusive lock, go ahead and return + ** SQLITE_BUSY. + */ + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + if( (pX->exclMask & mask)!=0 ){ + rc = SQLITE_BUSY; + break; + } + allShared |= pX->sharedMask; + } + + /* Get shared locks at the system level, if necessary */ + if( rc==SQLITE_OK ){ + if( (allShared & mask)==0 ){ + rc = os2ShmSystemLock(pShmNode, _SHM_RDLCK, ofst+OS2_SHM_BASE, n); + }else{ + rc = SQLITE_OK; + } + } + + /* Get the local shared locks */ + if( rc==SQLITE_OK ){ + p->sharedMask |= mask; + } + }else{ + /* Make sure no sibling connections hold locks that will block this + ** lock. If any do, return SQLITE_BUSY right away. + */ + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ + rc = SQLITE_BUSY; + break; + } + } + + /* Get the exclusive locks at the system level. Then if successful + ** also mark the local connection as being locked. + */ + if( rc==SQLITE_OK ){ + rc = os2ShmSystemLock(pShmNode, _SHM_WRLCK, ofst+OS2_SHM_BASE, n); + if( rc==SQLITE_OK ){ + assert( (p->sharedMask & mask)==0 ); + p->exclMask |= mask; + } + } + } + + sqlite3_mutex_leave(pShmNode->mutex); + + OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n", + p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask, + rc ? "failed" : "ok")); + + ERR_TRACE(rc, ("os2ShmLock: ofst = %d, n = %d, flags = 0x%x -> %d \n", + ofst, n, flags, rc)) + + return rc; +} + +/* +** Implement a memory barrier or memory fence on shared memory. +** +** All loads and stores begun before the barrier must complete before +** any load or store begun after the barrier. +*/ +static void os2ShmBarrier( + sqlite3_file *id /* Database file holding the shared memory */ +){ + UNUSED_PARAMETER(id); + os2ShmEnterMutex(); + os2ShmLeaveMutex(); +} + +#else +# define os2ShmMap 0 +# define os2ShmLock 0 +# define os2ShmBarrier 0 +# define os2ShmUnmap 0 +#endif /* #ifndef SQLITE_OMIT_WAL */ + + /* ** This vector defines all the methods that can operate on an ** sqlite3_file for os2. */ static const sqlite3_io_methods os2IoMethod = { - 1, /* iVersion */ - os2Close, - os2Read, - os2Write, - os2Truncate, - os2Sync, - os2FileSize, - os2Lock, - os2Unlock, - os2CheckReservedLock, - os2FileControl, - os2SectorSize, - os2DeviceCharacteristics -}; + 2, /* iVersion */ + os2Close, /* xClose */ + os2Read, /* xRead */ + os2Write, /* xWrite */ + os2Truncate, /* xTruncate */ + os2Sync, /* xSync */ + os2FileSize, /* xFileSize */ + os2Lock, /* xLock */ + os2Unlock, /* xUnlock */ + os2CheckReservedLock, /* xCheckReservedLock */ + os2FileControl, /* xFileControl */ + os2SectorSize, /* xSectorSize */ + os2DeviceCharacteristics, /* xDeviceCharacteristics */ + os2ShmMap, /* xShmMap */ + os2ShmLock, /* xShmLock */ + os2ShmBarrier, /* xShmBarrier */ + os2ShmUnmap /* xShmUnmap */ +}; + /*************************************************************************** ** Here ends the I/O methods that form the sqlite3_io_methods object. ** ** The next block of code implements the VFS methods. ****************************************************************************/ /* ** Create a temporary file name in zBuf. zBuf must be big enough to ** hold at pVfs->mxPathname characters. */ static int getTempname(int nBuf, char *zBuf ){ - static const unsigned char zChars[] = + static const char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; int i, j; - char zTempPathBuf[3]; - PSZ zTempPath = (PSZ)&zTempPathBuf; - if( sqlite3_temp_directory ){ - zTempPath = sqlite3_temp_directory; - }else{ - if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){ - if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){ - if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){ - ULONG ulDriveNum = 0, ulDriveMap = 0; - DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); - sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) ); - } - } - } - } + PSZ zTempPathCp; + char zTempPath[CCHMAXPATH]; + ULONG ulDriveNum, ulDriveMap; + + /* It's odd to simulate an io-error here, but really this is just + ** using the io-error infrastructure to test that SQLite handles this + ** function failing. + */ + SimulateIOError( return SQLITE_IOERR ); + + if( sqlite3_temp_directory ) { + sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", sqlite3_temp_directory); + } else if( DosScanEnv( (PSZ)"TEMP", &zTempPathCp ) == NO_ERROR || + DosScanEnv( (PSZ)"TMP", &zTempPathCp ) == NO_ERROR || + DosScanEnv( (PSZ)"TMPDIR", &zTempPathCp ) == NO_ERROR ) { + char *zTempPathUTF = convertCpPathToUtf8( (char *)zTempPathCp ); + sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", zTempPathUTF); + free( zTempPathUTF ); + } else if( DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ) == NO_ERROR ) { + zTempPath[0] = (char)('A' + ulDriveNum - 1); + zTempPath[1] = ':'; + zTempPath[2] = '\0'; + } else { + zTempPath[0] = '\0'; + } + /* Strip off a trailing slashes or backslashes, otherwise we would get * * multiple (back)slashes which causes DosOpen() to fail. * * Trailing spaces are not allowed, either. */ j = sqlite3Strlen30(zTempPath); - while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' - || zTempPath[j-1] == ' ' ) ){ + while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' || + zTempPath[j-1] == ' ' ) ){ j--; } zTempPath[j] = '\0'; - if( !sqlite3_temp_directory ){ - char *zTempPathUTF = convertCpPathToUtf8( zTempPath ); - sqlite3_snprintf( nBuf-30, zBuf, - "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPathUTF ); - free( zTempPathUTF ); - }else{ - sqlite3_snprintf( nBuf-30, zBuf, - "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath ); - } - j = sqlite3Strlen30( zBuf ); + + /* We use 20 bytes to randomize the name */ + sqlite3_snprintf(nBuf-22, zBuf, + "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); + j = sqlite3Strlen30(zBuf); sqlite3_randomness( 20, &zBuf[j] ); for( i = 0; i < 20; i++, j++ ){ - zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; + zBuf[j] = zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; } zBuf[j] = 0; + OSTRACE(( "TEMP FILENAME: %s\n", zBuf )); return SQLITE_OK; } /* ** Turn a relative pathname into a full pathname. Write the full ** pathname into zFull[]. zFull[] will be at least pVfs->mxPathname @@ -22469,234 +23775,279 @@ static int os2FullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zRelative, /* Possibly relative input path */ int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ char *zRelativeCp = convertUtf8PathToCp( zRelative ); char zFullCp[CCHMAXPATH] = "\0"; char *zFullUTF; - APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp, - CCHMAXPATH ); + APIRET rc = DosQueryPathInfo( (PSZ)zRelativeCp, FIL_QUERYFULLNAME, + zFullCp, CCHMAXPATH ); free( zRelativeCp ); zFullUTF = convertCpPathToUtf8( zFullCp ); sqlite3_snprintf( nFull, zFull, zFullUTF ); free( zFullUTF ); return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; } /* ** Open a file. */ static int os2Open( sqlite3_vfs *pVfs, /* Not used */ - const char *zName, /* Name of the file */ + const char *zName, /* Name of the file (UTF-8) */ sqlite3_file *id, /* Write the SQLite file handle here */ int flags, /* Open mode flags */ int *pOutFlags /* Status return flags */ ){ HFILE h; - ULONG ulFileAttribute = FILE_NORMAL; ULONG ulOpenFlags = 0; ULONG ulOpenMode = 0; + ULONG ulAction = 0; + ULONG rc; os2File *pFile = (os2File*)id; - APIRET rc = NO_ERROR; - ULONG ulAction; + const char *zUtf8Name = zName; char *zNameCp; - char zTmpname[CCHMAXPATH+1]; /* Buffer to hold name of temp file */ + char zTmpname[CCHMAXPATH]; + + int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); + int isCreate = (flags & SQLITE_OPEN_CREATE); + int isReadWrite = (flags & SQLITE_OPEN_READWRITE); +#ifndef NDEBUG + int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); + int isReadonly = (flags & SQLITE_OPEN_READONLY); + int eType = (flags & 0xFFFFFF00); + int isOpenJournal = (isCreate && ( + eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_MAIN_JOURNAL + || eType==SQLITE_OPEN_WAL + )); +#endif + + UNUSED_PARAMETER(pVfs); + assert( id!=0 ); + + /* Check the following statements are true: + ** + ** (a) Exactly one of the READWRITE and READONLY flags must be set, and + ** (b) if CREATE is set, then READWRITE must also be set, and + ** (c) if EXCLUSIVE is set, then CREATE must also be set. + ** (d) if DELETEONCLOSE is set, then CREATE must also be set. + */ + assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); + assert(isCreate==0 || isReadWrite); + assert(isExclusive==0 || isCreate); + assert(isDelete==0 || isCreate); + + /* The main DB, main journal, WAL file and master journal are never + ** automatically deleted. Nor are they ever temporary files. */ + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); + + /* Assert that the upper layer has set one of the "file-type" flags. */ + assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL + || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL + ); + + memset( pFile, 0, sizeof(*pFile) ); + pFile->h = (HFILE)-1; /* If the second argument to this function is NULL, generate a ** temporary file name to use */ - if( !zName ){ - int rc = getTempname(CCHMAXPATH+1, zTmpname); + if( !zUtf8Name ){ + assert(isDelete && !isOpenJournal); + rc = getTempname(CCHMAXPATH, zTmpname); if( rc!=SQLITE_OK ){ return rc; } - zName = zTmpname; - } - - - memset( pFile, 0, sizeof(*pFile) ); - - OSTRACE(( "OPEN want %d\n", flags )); - - if( flags & SQLITE_OPEN_READWRITE ){ + zUtf8Name = zTmpname; + } + + if( isReadWrite ){ ulOpenMode |= OPEN_ACCESS_READWRITE; - OSTRACE(( "OPEN read/write\n" )); }else{ ulOpenMode |= OPEN_ACCESS_READONLY; - OSTRACE(( "OPEN read only\n" )); - } - - if( flags & SQLITE_OPEN_CREATE ){ - ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW; - OSTRACE(( "OPEN open new/create\n" )); - }else{ - ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW; - OSTRACE(( "OPEN open existing\n" )); - } - - if( flags & SQLITE_OPEN_MAIN_DB ){ - ulOpenMode |= OPEN_SHARE_DENYNONE; - OSTRACE(( "OPEN share read/write\n" )); - }else{ - ulOpenMode |= OPEN_SHARE_DENYWRITE; - OSTRACE(( "OPEN share read only\n" )); - } - - if( flags & SQLITE_OPEN_DELETEONCLOSE ){ - char pathUtf8[CCHMAXPATH]; -#ifdef NDEBUG /* when debugging we want to make sure it is deleted */ - ulFileAttribute = FILE_HIDDEN; -#endif - os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 ); - pFile->pathToDel = convertUtf8PathToCp( pathUtf8 ); - OSTRACE(( "OPEN hidden/delete on close file attributes\n" )); - }else{ - pFile->pathToDel = NULL; - OSTRACE(( "OPEN normal file attribute\n" )); - } - - /* always open in random access mode for possibly better speed */ - ulOpenMode |= OPEN_FLAGS_RANDOM; - ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR; - ulOpenMode |= OPEN_FLAGS_NOINHERIT; - - zNameCp = convertUtf8PathToCp( zName ); + } + + /* Open in random access mode for possibly better speed. Allow full + ** sharing because file locks will provide exclusive access when needed. + ** The handle should not be inherited by child processes and we don't + ** want popups from the critical error handler. + */ + ulOpenMode |= OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYNONE | + OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR; + + /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is + ** created. SQLite doesn't use it to indicate "exclusive access" + ** as it is usually understood. + */ + if( isExclusive ){ + /* Creates a new file, only if it does not already exist. */ + /* If the file exists, it fails. */ + ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS; + }else if( isCreate ){ + /* Open existing file, or create if it doesn't exist */ + ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; + }else{ + /* Opens a file, only if it exists. */ + ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; + } + + zNameCp = convertUtf8PathToCp( zUtf8Name ); rc = DosOpen( (PSZ)zNameCp, &h, &ulAction, 0L, - ulFileAttribute, + FILE_NORMAL, ulOpenFlags, ulOpenMode, (PEAOP2)NULL ); free( zNameCp ); + if( rc != NO_ERROR ){ - OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n", - rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode )); - if( pFile->pathToDel ) - free( pFile->pathToDel ); - pFile->pathToDel = NULL; - if( flags & SQLITE_OPEN_READWRITE ){ - OSTRACE(( "OPEN %d Invalid handle\n", - ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) )); + OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n", + rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode )); + + if( isReadWrite ){ return os2Open( pVfs, zName, id, - ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE), + ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags ); }else{ return SQLITE_CANTOPEN; } } if( pOutFlags ){ - *pOutFlags = flags & SQLITE_OPEN_READWRITE ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; - } - + *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; + } + + os2FullPathname( pVfs, zUtf8Name, sizeof( zTmpname ), zTmpname ); + pFile->zFullPathCp = convertUtf8PathToCp( zTmpname ); pFile->pMethod = &os2IoMethod; + pFile->flags = flags; pFile->h = h; + OpenCounter(+1); OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags )); return SQLITE_OK; } /* ** Delete the named file. */ static int os2Delete( sqlite3_vfs *pVfs, /* Not used on os2 */ const char *zFilename, /* Name of file to delete */ int syncDir /* Not used on os2 */ ){ - APIRET rc = NO_ERROR; - char *zFilenameCp = convertUtf8PathToCp( zFilename ); + APIRET rc; + char *zFilenameCp; SimulateIOError( return SQLITE_IOERR_DELETE ); + zFilenameCp = convertUtf8PathToCp( zFilename ); rc = DosDelete( (PSZ)zFilenameCp ); free( zFilenameCp ); OSTRACE(( "DELETE \"%s\"\n", zFilename )); - return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE; + return (rc == NO_ERROR || + rc == ERROR_FILE_NOT_FOUND || + rc == ERROR_PATH_NOT_FOUND ) ? SQLITE_OK : SQLITE_IOERR_DELETE; } /* ** Check the existance and status of a file. */ static int os2Access( sqlite3_vfs *pVfs, /* Not used on os2 */ const char *zFilename, /* Name of file to check */ int flags, /* Type of test to make on this file */ int *pOut /* Write results here */ ){ + APIRET rc; FILESTATUS3 fsts3ConfigInfo; - APIRET rc = NO_ERROR; - char *zFilenameCp = convertUtf8PathToCp( zFilename ); - - memset( &fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo) ); + char *zFilenameCp; + + UNUSED_PARAMETER(pVfs); + SimulateIOError( return SQLITE_IOERR_ACCESS; ); + + zFilenameCp = convertUtf8PathToCp( zFilename ); rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD, &fsts3ConfigInfo, sizeof(FILESTATUS3) ); free( zFilenameCp ); OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n", fsts3ConfigInfo.attrFile, flags, rc )); + switch( flags ){ - case SQLITE_ACCESS_READ: case SQLITE_ACCESS_EXISTS: - rc = (rc == NO_ERROR); - OSTRACE(( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc)); + /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file + ** as if it does not exist. + */ + if( fsts3ConfigInfo.cbFile == 0 ) + rc = ERROR_FILE_NOT_FOUND; + break; + case SQLITE_ACCESS_READ: break; case SQLITE_ACCESS_READWRITE: - rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 ); - OSTRACE(( "ACCESS %s access of read/write rc=%d\n", zFilename, rc )); + if( fsts3ConfigInfo.attrFile & FILE_READONLY ) + rc = ERROR_ACCESS_DENIED; break; default: + rc = ERROR_FILE_NOT_FOUND; assert( !"Invalid flags argument" ); } - *pOut = rc; + + *pOut = (rc == NO_ERROR); + OSTRACE(( "ACCESS %s flags %d: rc=%d\n", zFilename, flags, *pOut )); + return SQLITE_OK; } #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Interfaces for opening a shared library, finding entry points ** within the shared library, and closing the shared library. */ /* ** Interfaces for opening a shared library, finding entry points ** within the shared library, and closing the shared library. */ static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){ - UCHAR loadErr[256]; HMODULE hmod; APIRET rc; char *zFilenameCp = convertUtf8PathToCp(zFilename); - rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilenameCp, &hmod); + rc = DosLoadModule(NULL, 0, (PSZ)zFilenameCp, &hmod); free(zFilenameCp); return rc != NO_ERROR ? 0 : (void*)hmod; } /* ** A no-op since the error code is returned on the DosLoadModule call. ** os2Dlopen returns zero if DosLoadModule is not successful. */ static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ /* no-op */ } -static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ +static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){ PFN pfn; APIRET rc; - rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn); + rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)zSymbol, &pfn); if( rc != NO_ERROR ){ /* if the symbol itself was not found, search again for the same * symbol with an extra underscore, that might be needed depending * on the calling convention */ char _zSymbol[256] = "_"; - strncat(_zSymbol, zSymbol, 255); - rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn); - } - return rc != NO_ERROR ? 0 : (void*)pfn; + strncat(_zSymbol, zSymbol, 254); + rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)_zSymbol, &pfn); + } + return rc != NO_ERROR ? 0 : (void(*)(void))pfn; } static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){ DosFreeModule((HMODULE)pHandle); } #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ #define os2DlOpen 0 #define os2DlError 0 #define os2DlSym 0 @@ -22708,64 +24059,49 @@ static void os2DlClose(sqlite3_vfs *pVfs ** Write up to nBuf bytes of randomness into zBuf. */ static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){ int n = 0; #if defined(SQLITE_TEST) n = nBuf; memset(zBuf, 0, nBuf); #else - int sizeofULong = sizeof(ULONG); - if( (int)sizeof(DATETIME) <= nBuf - n ){ - DATETIME x; - DosGetDateTime(&x); - memcpy(&zBuf[n], &x, sizeof(x)); - n += sizeof(x); - } - - if( sizeofULong <= nBuf - n ){ - PPIB ppib; - DosGetInfoBlocks(NULL, &ppib); - memcpy(&zBuf[n], &ppib->pib_ulpid, sizeofULong); - n += sizeofULong; - } - - if( sizeofULong <= nBuf - n ){ - PTIB ptib; - DosGetInfoBlocks(&ptib, NULL); - memcpy(&zBuf[n], &ptib->tib_ptib2->tib2_ultid, sizeofULong); - n += sizeofULong; - } - - /* if we still haven't filled the buffer yet the following will */ - /* grab everything once instead of making several calls for a single item */ - if( sizeofULong <= nBuf - n ){ - ULONG ulSysInfo[QSV_MAX]; - DosQuerySysInfo(1L, QSV_MAX, ulSysInfo, sizeofULong * QSV_MAX); - - memcpy(&zBuf[n], &ulSysInfo[QSV_MS_COUNT - 1], sizeofULong); - n += sizeofULong; - - if( sizeofULong <= nBuf - n ){ - memcpy(&zBuf[n], &ulSysInfo[QSV_TIMER_INTERVAL - 1], sizeofULong); - n += sizeofULong; - } - if( sizeofULong <= nBuf - n ){ - memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_LOW - 1], sizeofULong); - n += sizeofULong; - } - if( sizeofULong <= nBuf - n ){ - memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_HIGH - 1], sizeofULong); - n += sizeofULong; - } - if( sizeofULong <= nBuf - n ){ - memcpy(&zBuf[n], &ulSysInfo[QSV_TOTAVAILMEM - 1], sizeofULong); - n += sizeofULong; - } - } + int i; + PPIB ppib; + PTIB ptib; + DATETIME dt; + static unsigned c = 0; + /* Ordered by variation probability */ + static ULONG svIdx[6] = { QSV_MS_COUNT, QSV_TIME_LOW, + QSV_MAXPRMEM, QSV_MAXSHMEM, + QSV_TOTAVAILMEM, QSV_TOTRESMEM }; + + /* 8 bytes; timezone and weekday don't increase the randomness much */ + if( (int)sizeof(dt)-3 <= nBuf - n ){ + c += 0x0100; + DosGetDateTime(&dt); + dt.year = (USHORT)((dt.year - 1900) | c); + memcpy(&zBuf[n], &dt, sizeof(dt)-3); + n += sizeof(dt)-3; + } + + /* 4 bytes; PIDs and TIDs are 16 bit internally, so combine them */ + if( (int)sizeof(ULONG) <= nBuf - n ){ + DosGetInfoBlocks(&ptib, &ppib); + *(PULONG)&zBuf[n] = MAKELONG(ppib->pib_ulpid, + ptib->tib_ptib2->tib2_ultid); + n += sizeof(ULONG); + } + + /* Up to 6 * 4 bytes; variables depend on the system state */ + for( i = 0; i < 6 && (int)sizeof(ULONG) <= nBuf - n; i++ ){ + DosQuerySysInfo(svIdx[i], svIdx[i], + (PULONG)&zBuf[n], sizeof(ULONG)); + n += sizeof(ULONG); + } #endif return n; } /* ** Sleep for a little while. Return the amount of time slept. ** The argument is the number of microseconds we want to sleep. @@ -22783,65 +24119,117 @@ static int os2Sleep( sqlite3_vfs *pVfs, ** The following variable, if set to a non-zero value, becomes the result ** returned from sqlite3OsCurrentTime(). This is used for testing. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_current_time = 0; #endif /* +** Find the current time (in Universal Coordinated Time). Write into *piNow +** the current time and date as a Julian Day number times 86_400_000. In +** other words, write into *piNow the number of milliseconds since the Julian +** epoch of noon in Greenwich on November 24, 4714 B.C according to the +** proleptic Gregorian calendar. +** +** On success, return 0. Return 1 if the time and date cannot be found. +*/ +static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ +#ifdef SQLITE_TEST + static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; +#endif + int year, month, datepart, timepart; + + DATETIME dt; + DosGetDateTime( &dt ); + + year = dt.year; + month = dt.month; + + /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html + ** http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c + ** Calculate the Julian days + */ + datepart = (int)dt.day - 32076 + + 1461*(year + 4800 + (month - 14)/12)/4 + + 367*(month - 2 - (month - 14)/12*12)/12 - + 3*((year + 4900 + (month - 14)/12)/100)/4; + + /* Time in milliseconds, hours to noon added */ + timepart = 12*3600*1000 + dt.hundredths*10 + dt.seconds*1000 + + ((int)dt.minutes + dt.timezone)*60*1000 + dt.hours*3600*1000; + + *piNow = (sqlite3_int64)datepart*86400*1000 + timepart; + +#ifdef SQLITE_TEST + if( sqlite3_current_time ){ + *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch; + } +#endif + + UNUSED_PARAMETER(pVfs); + return 0; +} + +/* ** Find the current time (in Universal Coordinated Time). Write the ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ -int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){ - double now; - SHORT minute; /* needs to be able to cope with negative timezone offset */ - USHORT second, hour, - day, month, year; - DATETIME dt; - DosGetDateTime( &dt ); - second = (USHORT)dt.seconds; - minute = (SHORT)dt.minutes + dt.timezone; - hour = (USHORT)dt.hours; - day = (USHORT)dt.day; - month = (USHORT)dt.month; - year = (USHORT)dt.year; - - /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html - http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */ - /* Calculate the Julian days */ - now = day - 32076 + - 1461*(year + 4800 + (month - 14)/12)/4 + - 367*(month - 2 - (month - 14)/12*12)/12 - - 3*((year + 4900 + (month - 14)/12)/100)/4; - - /* Add the fractional hours, mins and seconds */ - now += (hour + 12.0)/24.0; - now += minute/1440.0; - now += second/86400.0; - *prNow = now; -#ifdef SQLITE_TEST - if( sqlite3_current_time ){ - *prNow = sqlite3_current_time/86400.0 + 2440587.5; - } -#endif - return 0; -} - +static int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){ + int rc; + sqlite3_int64 i; + rc = os2CurrentTimeInt64(pVfs, &i); + if( !rc ){ + *prNow = i/86400000.0; + } + return rc; +} + +/* +** The idea is that this function works like a combination of +** GetLastError() and FormatMessage() on windows (or errno and +** strerror_r() on unix). After an error is returned by an OS +** function, SQLite calls this function with zBuf pointing to +** a buffer of nBuf bytes. The OS layer should populate the +** buffer with a nul-terminated UTF-8 encoded error message +** describing the last IO error to have occurred within the calling +** thread. +** +** If the error message is too large for the supplied buffer, +** it should be truncated. The return value of xGetLastError +** is zero if the error message fits in the buffer, or non-zero +** otherwise (if the message was truncated). If non-zero is returned, +** then it is not necessary to include the nul-terminator character +** in the output buffer. +** +** Not supplying an error message will have no adverse effect +** on SQLite. It is fine to have an implementation that never +** returns an error message: +** +** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ +** assert(zBuf[0]=='\0'); +** return 0; +** } +** +** However if an error message is supplied, it will be incorporated +** by sqlite into the error message available to the user using +** sqlite3_errmsg(), possibly making IO errors easier to debug. +*/ static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + assert(zBuf[0]=='\0'); return 0; } /* ** Initialize and deinitialize the operating system interface. */ SQLITE_API int sqlite3_os_init(void){ static sqlite3_vfs os2Vfs = { - 1, /* iVersion */ + 3, /* iVersion */ sizeof(os2File), /* szOsFile */ CCHMAXPATH, /* mxPathname */ 0, /* pNext */ "os2", /* zName */ 0, /* pAppData */ os2Open, /* xOpen */ os2Delete, /* xDelete */ @@ -22850,19 +24238,24 @@ SQLITE_API int sqlite3_os_init(void){ os2DlOpen, /* xDlOpen */ os2DlError, /* xDlError */ os2DlSym, /* xDlSym */ os2DlClose, /* xDlClose */ os2Randomness, /* xRandomness */ os2Sleep, /* xSleep */ os2CurrentTime, /* xCurrentTime */ os2GetLastError, /* xGetLastError */ + os2CurrentTimeInt64, /* xCurrentTimeInt64 */ + 0, /* xSetSystemCall */ + 0, /* xGetSystemCall */ + 0 /* xNextSystemCall */ }; sqlite3_vfs_register(&os2Vfs, 1); initUconvObjects(); +/* sqlite3OSTrace = 1; */ return SQLITE_OK; } SQLITE_API int sqlite3_os_end(void){ freeUconvObjects(); return SQLITE_OK; } #endif /* SQLITE_OS_OS2 */ @@ -23002,16 +24395,20 @@ SQLITE_API int sqlite3_os_end(void){ # include <sys/param.h> # endif #endif /* SQLITE_ENABLE_LOCKING_STYLE */ #if defined(__APPLE__) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) # include <sys/mount.h> #endif +#ifdef HAVE_UTIME +# include <utime.h> +#endif + /* ** Allowed values of unixFile.fsFlags */ #define SQLITE_FSFLAGS_IS_MSDOS 0x1 /* ** If we are to be thread-safe, include the pthreads header and define ** the SQLITE_UNIX_THREADS macro. @@ -23069,20 +24466,20 @@ struct UnixUnusedFd { */ typedef struct unixFile unixFile; struct unixFile { sqlite3_io_methods const *pMethod; /* Always the first entry */ unixInodeInfo *pInode; /* Info about locks on this inode */ int h; /* The file descriptor */ int dirfd; /* File descriptor for the directory */ unsigned char eFileLock; /* The type of lock held on this fd */ + unsigned char 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 */ - int fileFlags; /* Miscellanous flags */ const char *zPath; /* Name of the file */ unixShm *pShm; /* Shared memory segment information */ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif #if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__) unsigned fsFlags; /* cached details from statfs() */ @@ -23107,19 +24504,20 @@ struct unixFile { /* In test mode, increase the size of this structure a bit so that ** it is larger than the struct CrashFile defined in test6.c. */ char aPadding[32]; #endif }; /* -** The following macros define bits in unixFile.fileFlags -*/ -#define SQLITE_WHOLE_FILE_LOCKING 0x0001 /* Use whole-file locking */ +** Allowed values for the unixFile.ctrlFlags bitmask: +*/ +#define UNIXFILE_EXCL 0x01 /* Connections from one process only */ +#define UNIXFILE_RDONLY 0x02 /* Connection is read only */ /* ** Include code that is common to all os_*.c files */ /************** Include os_common.h in the middle of os_unix.c ***************/ /************** Begin file os_common.h ***************************************/ /* ** 2004 May 22 @@ -23339,35 +24737,226 @@ SQLITE_API int sqlite3_open_file_count = #ifndef O_NOFOLLOW # define O_NOFOLLOW 0 #endif #ifndef O_BINARY # define O_BINARY 0 #endif /* -** The DJGPP compiler environment looks mostly like Unix, but it -** lacks the fcntl() system call. So redefine fcntl() to be something -** that always succeeds. This means that locking does not occur under -** DJGPP. But it is DOS - what did you expect? -*/ -#ifdef __DJGPP__ -# define fcntl(A,B,C) 0 -#endif - -/* ** The threadid macro resolves to the thread-id or to 0. Used for ** testing and debugging only. */ #if SQLITE_THREADSAFE #define threadid pthread_self() #else #define threadid 0 #endif +/* +** Different Unix systems declare open() in different ways. Same use +** open(const char*,int,mode_t). Others use open(const char*,int,...). +** The difference is important when using a pointer to the function. +** +** The safest way to deal with the problem is to always use this wrapper +** which always has the same well-defined interface. +*/ +static int posixOpen(const char *zFile, int flags, int mode){ + return open(zFile, flags, mode); +} + +/* +** Many system calls are accessed through pointer-to-functions so that +** they may be overridden at runtime to facilitate fault injection during +** testing and sandboxing. The following array holds the names and pointers +** to all overrideable system calls. +*/ +static struct unix_syscall { + const char *zName; /* Name of the sytem call */ + sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ + sqlite3_syscall_ptr pDefault; /* Default value */ +} aSyscall[] = { + { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, +#define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) + + { "close", (sqlite3_syscall_ptr)close, 0 }, +#define osClose ((int(*)(int))aSyscall[1].pCurrent) + + { "access", (sqlite3_syscall_ptr)access, 0 }, +#define osAccess ((int(*)(const char*,int))aSyscall[2].pCurrent) + + { "getcwd", (sqlite3_syscall_ptr)getcwd, 0 }, +#define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent) + + { "stat", (sqlite3_syscall_ptr)stat, 0 }, +#define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent) + +/* +** The DJGPP compiler environment looks mostly like Unix, but it +** lacks the fcntl() system call. So redefine fcntl() to be something +** that always succeeds. This means that locking does not occur under +** DJGPP. But it is DOS - what did you expect? +*/ +#ifdef __DJGPP__ + { "fstat", 0, 0 }, +#define osFstat(a,b,c) 0 +#else + { "fstat", (sqlite3_syscall_ptr)fstat, 0 }, +#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent) +#endif + + { "ftruncate", (sqlite3_syscall_ptr)ftruncate, 0 }, +#define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent) + + { "fcntl", (sqlite3_syscall_ptr)fcntl, 0 }, +#define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent) + + { "read", (sqlite3_syscall_ptr)read, 0 }, +#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) + +#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE + { "pread", (sqlite3_syscall_ptr)pread, 0 }, +#else + { "pread", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent) + +#if defined(USE_PREAD64) + { "pread64", (sqlite3_syscall_ptr)pread64, 0 }, +#else + { "pread64", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) + + { "write", (sqlite3_syscall_ptr)write, 0 }, +#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) + +#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE + { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, +#else + { "pwrite", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ + aSyscall[12].pCurrent) + +#if defined(USE_PREAD64) + { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 }, +#else + { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ + aSyscall[13].pCurrent) + +#if SQLITE_ENABLE_LOCKING_STYLE + { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, +#else + { "fchmod", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) + +#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE + { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, +#else + { "fallocate", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent) + +}; /* End of the overrideable system calls */ + +/* +** This is the xSetSystemCall() method of sqlite3_vfs for all of the +** "unix" VFSes. Return SQLITE_OK opon successfully updating the +** system call pointer, or SQLITE_NOTFOUND if there is no configurable +** system call named zName. +*/ +static int unixSetSystemCall( + sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */ + const char *zName, /* Name of system call to override */ + sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */ +){ + unsigned int i; + int rc = SQLITE_NOTFOUND; + + UNUSED_PARAMETER(pNotUsed); + if( zName==0 ){ + /* If no zName is given, restore all system calls to their default + ** settings and return NULL + */ + rc = SQLITE_OK; + for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){ + if( aSyscall[i].pDefault ){ + aSyscall[i].pCurrent = aSyscall[i].pDefault; + } + } + }else{ + /* If zName is specified, operate on only the one system call + ** specified. + */ + for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){ + if( strcmp(zName, aSyscall[i].zName)==0 ){ + if( aSyscall[i].pDefault==0 ){ + aSyscall[i].pDefault = aSyscall[i].pCurrent; + } + rc = SQLITE_OK; + if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault; + aSyscall[i].pCurrent = pNewFunc; + break; + } + } + } + return rc; +} + +/* +** Return the value of a system call. Return NULL if zName is not a +** recognized system call name. NULL is also returned if the system call +** is currently undefined. +*/ +static sqlite3_syscall_ptr unixGetSystemCall( + sqlite3_vfs *pNotUsed, + const char *zName +){ + unsigned int i; + + UNUSED_PARAMETER(pNotUsed); + for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){ + if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent; + } + return 0; +} + +/* +** Return the name of the first system call after zName. If zName==NULL +** then return the name of the first system call. Return NULL if zName +** is the last system call or if zName is not the name of a valid +** system call. +*/ +static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){ + int i = -1; + + UNUSED_PARAMETER(p); + if( zName ){ + for(i=0; i<ArraySize(aSyscall)-1; i++){ + if( strcmp(zName, aSyscall[i].zName)==0 ) break; + } + } + for(i++; i<ArraySize(aSyscall); i++){ + if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName; + } + return 0; +} + +/* +** Retry open() calls that fail due to EINTR +*/ +static int robust_open(const char *z, int f, int m){ + int rc; + do{ rc = osOpen(z,f,m); }while( rc<0 && errno==EINTR ); + return rc; +} /* ** Helper functions to obtain and relinquish the global mutex. The ** global mutex is used to protect the unixInodeInfo and ** vxworksFileId objects used by this file, all of which may be ** shared by multiple threads. ** ** Function unixMutexHeld() is used to assert() that the global mutex @@ -23422,74 +25011,95 @@ static int lockTrace(int fd, int op, str char *zOpName, *zType; int s; int savedErrno; if( op==F_GETLK ){ zOpName = "GETLK"; }else if( op==F_SETLK ){ zOpName = "SETLK"; }else{ - s = fcntl(fd, op, p); + s = osFcntl(fd, op, p); sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s); return s; } if( p->l_type==F_RDLCK ){ zType = "RDLCK"; }else if( p->l_type==F_WRLCK ){ zType = "WRLCK"; }else if( p->l_type==F_UNLCK ){ zType = "UNLCK"; }else{ assert( 0 ); } assert( p->l_whence==SEEK_SET ); - s = fcntl(fd, op, p); + s = osFcntl(fd, op, p); savedErrno = errno; sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n", threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len, (int)p->l_pid, s); if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ struct flock l2; l2 = *p; - fcntl(fd, F_GETLK, &l2); + osFcntl(fd, F_GETLK, &l2); if( l2.l_type==F_RDLCK ){ zType = "RDLCK"; }else if( l2.l_type==F_WRLCK ){ zType = "WRLCK"; }else if( l2.l_type==F_UNLCK ){ zType = "UNLCK"; }else{ assert( 0 ); } sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n", zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid); } errno = savedErrno; return s; } -#define fcntl lockTrace +#undef osFcntl +#define osFcntl lockTrace #endif /* SQLITE_LOCK_TRACE */ - +/* +** Retry ftruncate() calls that fail due to EINTR +*/ +static int robust_ftruncate(int h, sqlite3_int64 sz){ + int rc; + do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR ); + return rc; +} /* ** This routine translates a standard POSIX errno code into something ** useful to the clients of the sqlite3 functions. Specifically, it is ** intended to translate a variety of "try again" errors into SQLITE_BUSY ** and a variety of "please close the file descriptor NOW" errors into ** SQLITE_IOERR ** ** Errors during initialization of locks, or file system support for locks, ** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately. */ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { switch (posixError) { +#if 0 + /* At one point this code was not commented out. In theory, this branch + ** should never be hit, as this function should only be called after + ** a locking-related function (i.e. fcntl()) has returned non-zero with + ** the value of errno as the first argument. Since a system call has failed, + ** errno should be non-zero. + ** + ** Despite this, if errno really is zero, we still don't want to return + ** SQLITE_OK. The system call failed, and *some* SQLite error should be + ** propagated back to the caller. Commenting this branch out means errno==0 + ** will be handled by the "default:" case below. + */ case 0: return SQLITE_OK; - +#endif + case EAGAIN: case ETIMEDOUT: case EBUSY: case EINTR: case ENOLCK: /* random NFS retry error, unless during file system support * introspection, in which it actually means what it says */ return SQLITE_BUSY; @@ -23501,18 +25111,25 @@ static int sqliteErrorFromPosixError(int (sqliteIOErr == SQLITE_IOERR_RDLOCK) || (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){ return SQLITE_BUSY; } /* else fall through */ case EPERM: return SQLITE_PERM; + /* EDEADLK is only possible if a call to fcntl(F_SETLKW) is made. And + ** this module never makes such a call. And the code in SQLite itself + ** asserts that SQLITE_IOERR_BLOCKED is never returned. For these reasons + ** this case is also commented out. If the system does set errno to EDEADLK, + ** the default SQLITE_IOERR_XXX code will be returned. */ +#if 0 case EDEADLK: return SQLITE_IOERR_BLOCKED; +#endif #if EOPNOTSUPP!=ENOTSUP case EOPNOTSUPP: /* something went terribly awry, unless during file system support * introspection, in which it actually means what it says */ #endif #ifdef ENOTSUP case ENOTSUP: @@ -23785,77 +25402,153 @@ struct unixFileId { ** ** A single inode can have multiple file descriptors, so each unixFile ** structure contains a pointer to an instance of this object and this ** object keeps a count of the number of unixFile pointing to it. */ struct unixInodeInfo { struct unixFileId fileId; /* The lookup key */ int nShared; /* Number of SHARED locks held */ - int eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ + unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ + unsigned char bProcessLock; /* An exclusive process lock is held */ int nRef; /* Number of pointers to this structure */ unixShmNode *pShmNode; /* Shared memory associated with this inode */ int nLock; /* Number of outstanding file locks */ UnixUnusedFd *pUnused; /* Unused file descriptors to close */ unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ unixInodeInfo *pPrev; /* .... doubly linked */ -#if defined(SQLITE_ENABLE_LOCKING_STYLE) +#if SQLITE_ENABLE_LOCKING_STYLE unsigned long long sharedByte; /* for AFP simulated shared lock */ #endif #if OS_VXWORKS sem_t *pSem; /* Named POSIX semaphore */ char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */ #endif }; /* ** A lists of all unixInodeInfo objects. */ static unixInodeInfo *inodeList = 0; /* +** +** This function - unixLogError_x(), is only ever called via the macro +** unixLogError(). +** +** It is invoked after an error occurs in an OS function and errno has been +** set. It logs a message using sqlite3_log() containing the current value of +** errno and, if possible, the human-readable equivalent from strerror() or +** strerror_r(). +** +** The first argument passed to the macro should be the error code that +** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). +** The two subsequent arguments should be the name of the OS function that +** failed (e.g. "unlink", "open") and the the associated file-system path, +** if any. +*/ +#define unixLogError(a,b,c) unixLogErrorAtLine(a,b,c,__LINE__) +static int unixLogErrorAtLine( + int errcode, /* SQLite error code */ + const char *zFunc, /* Name of OS function that failed */ + const char *zPath, /* File path associated with error */ + int iLine /* Source line number where error occurred */ +){ + char *zErr; /* Message from strerror() or equivalent */ + int iErrno = errno; /* Saved syscall error number */ + + /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use + ** the strerror() function to obtain the human-readable error message + ** equivalent to errno. Otherwise, use strerror_r(). + */ +#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R) + char aErr[80]; + memset(aErr, 0, sizeof(aErr)); + zErr = aErr; + + /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined, + ** assume that the system provides the the GNU version of strerror_r() that + ** returns a pointer to a buffer containing the error message. That pointer + ** may point to aErr[], or it may point to some static storage somewhere. + ** Otherwise, assume that the system provides the POSIX version of + ** strerror_r(), which always writes an error message into aErr[]. + ** + ** If the code incorrectly assumes that it is the POSIX version that is + ** available, the error message will often be an empty string. Not a + ** huge problem. Incorrectly concluding that the GNU version is available + ** could lead to a segfault though. + */ +#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU) + zErr = +# endif + strerror_r(iErrno, aErr, sizeof(aErr)-1); + +#elif SQLITE_THREADSAFE + /* This is a threadsafe build, but strerror_r() is not available. */ + zErr = ""; +#else + /* Non-threadsafe build, use strerror(). */ + zErr = strerror(iErrno); +#endif + + assert( errcode!=SQLITE_OK ); + if( zPath==0 ) zPath = ""; + sqlite3_log(errcode, + "os_unix.c:%d: (%d) %s(%s) - %s", + iLine, iErrno, zFunc, zPath, zErr + ); + + return errcode; +} + +/* +** Close a file descriptor. +** +** We assume that close() almost always works, since it is only in a +** very sick application or on a very sick platform that it might fail. +** If it does fail, simply leak the file descriptor, but do log the +** error. +** +** Note that it is not safe to retry close() after EINTR since the +** file descriptor might have already been reused by another thread. +** So we don't even try to recover from an EINTR. Just log the error +** and move on. +*/ +static void robust_close(unixFile *pFile, int h, int lineno){ + if( osClose(h) ){ + unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close", + pFile ? pFile->zPath : 0, lineno); + } +} + +/* ** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. -** If all such file descriptors are closed without error, the list is -** cleared and SQLITE_OK returned. -** -** Otherwise, if an error occurs, then successfully closed file descriptor -** entries are removed from the list, and SQLITE_IOERR_CLOSE returned. -** not deleted and SQLITE_IOERR_CLOSE returned. */ -static int closePendingFds(unixFile *pFile){ - int rc = SQLITE_OK; +static void closePendingFds(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; - UnixUnusedFd *pError = 0; UnixUnusedFd *p; UnixUnusedFd *pNext; for(p=pInode->pUnused; p; p=pNext){ pNext = p->pNext; - if( close(p->fd) ){ - pFile->lastErrno = errno; - rc = SQLITE_IOERR_CLOSE; - p->pNext = pError; - pError = p; - }else{ - sqlite3_free(p); - } - } - pInode->pUnused = pError; - return rc; + robust_close(pFile, p->fd, __LINE__); + sqlite3_free(p); + } + pInode->pUnused = 0; } /* ** Release a unixInodeInfo structure previously allocated by findInodeInfo(). ** ** The mutex entered using the unixEnterMutex() function must be held ** when this function is called. */ static void releaseInodeInfo(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); - if( pInode ){ + if( ALWAYS(pInode) ){ pInode->nRef--; if( pInode->nRef==0 ){ assert( pInode->pShmNode==0 ); closePendingFds(pFile); if( pInode->pPrev ){ assert( pInode->pPrev->pNext==pInode ); pInode->pPrev->pNext = pInode->pNext; }else{ @@ -23892,17 +25585,17 @@ static int findInodeInfo( unixInodeInfo *pInode = 0; /* Candidate unixInodeInfo object */ assert( unixMutexHeld() ); /* Get low-level information about the file that we can used to ** create a unique name for the file. */ fd = pFile->h; - rc = fstat(fd, &statbuf); + rc = osFstat(fd, &statbuf); if( rc!=0 ){ pFile->lastErrno = errno; #ifdef EOVERFLOW if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; #endif return SQLITE_IOERR; } @@ -23913,22 +25606,22 @@ static int findInodeInfo( ** we always increase the file size to 1 by writing a single byte ** prior to accessing the inode number. The one byte written is ** an ASCII 'S' character which also happens to be the first byte ** in the header of every SQLite database. In this way, if there ** is a race condition such that another thread has already populated ** the first page of the database, no damage is done. */ if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){ - rc = write(fd, "S", 1); + do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); if( rc!=1 ){ pFile->lastErrno = errno; return SQLITE_IOERR; } - rc = fstat(fd, &statbuf); + rc = osFstat(fd, &statbuf); if( rc!=0 ){ pFile->lastErrno = errno; return SQLITE_IOERR; } } #endif memset(&fileId, 0, sizeof(fileId)); @@ -23981,40 +25674,86 @@ static int unixCheckReservedLock(sqlite3 /* Check if a thread in this process holds such a lock */ if( pFile->pInode->eFileLock>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ #ifndef __DJGPP__ - if( !reserved ){ + if( !reserved && !pFile->pInode->bProcessLock ){ struct flock lock; lock.l_whence = SEEK_SET; lock.l_start = RESERVED_BYTE; lock.l_len = 1; lock.l_type = F_WRLCK; - if (-1 == fcntl(pFile->h, F_GETLK, &lock)) { - int tErrno = errno; - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK); - pFile->lastErrno = tErrno; + if( osFcntl(pFile->h, F_GETLK, &lock) ){ + rc = SQLITE_IOERR_CHECKRESERVEDLOCK; + pFile->lastErrno = errno; } else if( lock.l_type!=F_UNLCK ){ reserved = 1; } } #endif unixLeaveMutex(); OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* +** Attempt to set a system-lock on the file pFile. The lock is +** described by pLock. +** +** If the pFile was opened read/write from unix-excl, then the only lock +** ever obtained is an exclusive lock, and it is obtained exactly once +** the first time any lock is attempted. All subsequent system locking +** operations become no-ops. Locking operations still happen internally, +** in order to coordinate access between separate database connections +** within this process, but all of that is handled in memory and the +** operating system does not participate. +** +** This function is a pass-through to fcntl(F_SETLK) if pFile is using +** any VFS other than "unix-excl" or if pFile is opened on "unix-excl" +** and is read-only. +** +** Zero is returned if the call completes successfully, or -1 if a call +** to fcntl() fails. In this case, errno is set appropriately (by fcntl()). +*/ +static int unixFileLock(unixFile *pFile, struct flock *pLock){ + int rc; + unixInodeInfo *pInode = pFile->pInode; + assert( unixMutexHeld() ); + assert( pInode!=0 ); + if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock) + && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0) + ){ + if( pInode->bProcessLock==0 ){ + struct flock lock; + assert( pInode->nLock==0 ); + lock.l_whence = SEEK_SET; + lock.l_start = SHARED_FIRST; + lock.l_len = SHARED_SIZE; + lock.l_type = F_WRLCK; + rc = osFcntl(pFile->h, F_SETLK, &lock); + if( rc<0 ) return rc; + pInode->bProcessLock = 1; + pInode->nLock++; + }else{ + rc = 0; + } + }else{ + rc = osFcntl(pFile->h, F_SETLK, pLock); + } + return rc; +} + +/* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK ** (3) PENDING_LOCK ** (4) EXCLUSIVE_LOCK ** @@ -24071,17 +25810,16 @@ static int unixLock(sqlite3_file *id, in ** range' is that some versions of windows do not support read-locks. By ** locking a random byte from a range, concurrent SHARED locks may exist ** even if the locking primitive used is always a write-lock. */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode = pFile->pInode; struct flock lock; - int s = 0; int tErrno = 0; assert( pFile ); OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, azFileLock(eFileLock), azFileLock(pFile->eFileLock), azFileLock(pInode->eFileLock), pInode->nShared , getpid())); /* If there is already a lock of this type or more restrictive on the @@ -24140,93 +25878,88 @@ static int unixLock(sqlite3_file *id, in */ lock.l_len = 1L; lock.l_whence = SEEK_SET; if( eFileLock==SHARED_LOCK || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK) ){ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK); lock.l_start = PENDING_BYTE; - s = fcntl(pFile->h, F_SETLK, &lock); - if( s==(-1) ){ + if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); - if( IS_LOCK_ERROR(rc) ){ + if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } goto end_lock; } } /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ if( eFileLock==SHARED_LOCK ){ assert( pInode->nShared==0 ); assert( pInode->eFileLock==0 ); + assert( rc==SQLITE_OK ); /* Now get the read-lock */ lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - if( (s = fcntl(pFile->h, F_SETLK, &lock))==(-1) ){ + if( unixFileLock(pFile, &lock) ){ tErrno = errno; - } + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + } + /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; lock.l_type = F_UNLCK; - if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){ - if( s != -1 ){ - /* This could happen with a network mount */ - tErrno = errno; - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - goto end_lock; - } - } - if( s==(-1) ){ - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); - if( IS_LOCK_ERROR(rc) ){ + if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){ + /* This could happen with a network mount */ + tErrno = errno; + rc = SQLITE_IOERR_UNLOCK; + } + + if( rc ){ + if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } + goto end_lock; }else{ pFile->eFileLock = SHARED_LOCK; pInode->nLock++; pInode->nShared = 1; } }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file ** already. */ assert( 0!=pFile->eFileLock ); lock.l_type = F_WRLCK; - switch( eFileLock ){ - case RESERVED_LOCK: - lock.l_start = RESERVED_BYTE; - break; - case EXCLUSIVE_LOCK: - lock.l_start = SHARED_FIRST; - lock.l_len = SHARED_SIZE; - break; - default: - assert(0); - } - s = fcntl(pFile->h, F_SETLK, &lock); - if( s==(-1) ){ + + assert( eFileLock==RESERVED_LOCK || eFileLock==EXCLUSIVE_LOCK ); + if( eFileLock==RESERVED_LOCK ){ + lock.l_start = RESERVED_BYTE; + lock.l_len = 1L; + }else{ + lock.l_start = SHARED_FIRST; + lock.l_len = SHARED_SIZE; + } + + if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); - if( IS_LOCK_ERROR(rc) ){ + if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } } } #ifndef NDEBUG /* Set up the transaction-counter change checking flags when @@ -24281,23 +26014,22 @@ static void setPendingFd(unixFile *pFile ** the requested locking level, this routine is a no-op. ** ** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED ** the byte range is divided into 2 parts and the first part is unlocked then ** set to a read lock, then the other part is simply unlocked. This works ** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to ** remove the write lock on a region when a read lock is set. */ -static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ +static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode; struct flock lock; int rc = SQLITE_OK; int h; - int tErrno; /* Error code from system call errors */ assert( pFile ); OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock, pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, getpid())); assert( eFileLock<=SHARED_LOCK ); if( pFile->eFileLock<=eFileLock ){ @@ -24335,122 +26067,125 @@ static int _posixUnlock(sqlite3_file *id ** the lock in 2 blocks, so that part of the range will be covered by a ** write lock until the rest is covered by a read lock: ** 1: [WWWWW] ** 2: [....W] ** 3: [RRRRW] ** 4: [RRRR.] */ if( eFileLock==SHARED_LOCK ){ + +#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE + (void)handleNFSUnlock; + assert( handleNFSUnlock==0 ); +#endif +#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE if( handleNFSUnlock ){ + int tErrno; /* Error code from system call errors */ off_t divSize = SHARED_SIZE - 1; lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = divSize; - if( fcntl(h, F_SETLK, &lock)==(-1) ){ + if( unixFileLock(pFile, &lock)==(-1) ){ tErrno = errno; - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); + rc = SQLITE_IOERR_UNLOCK; if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } goto end_unlock; } lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = divSize; - if( fcntl(h, F_SETLK, &lock)==(-1) ){ + if( unixFileLock(pFile, &lock)==(-1) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } goto end_unlock; } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST+divSize; lock.l_len = SHARED_SIZE-divSize; - if( fcntl(h, F_SETLK, &lock)==(-1) ){ + if( unixFileLock(pFile, &lock)==(-1) ){ tErrno = errno; - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); + rc = SQLITE_IOERR_UNLOCK; if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } goto end_unlock; } - }else{ + }else +#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ + { lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - if( fcntl(h, F_SETLK, &lock)==(-1) ){ - tErrno = errno; - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } + if( unixFileLock(pFile, &lock) ){ + /* In theory, the call to unixFileLock() cannot fail because another + ** process is holding an incompatible lock. If it does, this + ** indicates that the other process is not following the locking + ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning + ** SQLITE_BUSY would confuse the upper layer (in practice it causes + ** an assert to fail). */ + rc = SQLITE_IOERR_RDLOCK; + pFile->lastErrno = errno; goto end_unlock; } } } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); - if( fcntl(h, F_SETLK, &lock)!=(-1) ){ + if( unixFileLock(pFile, &lock)==0 ){ pInode->eFileLock = SHARED_LOCK; }else{ - tErrno = errno; - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } + rc = SQLITE_IOERR_UNLOCK; + pFile->lastErrno = errno; goto end_unlock; } } if( eFileLock==NO_LOCK ){ /* Decrement the shared lock counter. Release the lock using an ** OS call only when all threads in this same process have released ** the lock. */ pInode->nShared--; if( pInode->nShared==0 ){ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; SimulateIOErrorBenign(1); SimulateIOError( h=(-1) ) SimulateIOErrorBenign(0); - if( fcntl(h, F_SETLK, &lock)!=(-1) ){ + if( unixFileLock(pFile, &lock)==0 ){ pInode->eFileLock = NO_LOCK; }else{ - tErrno = errno; - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } + rc = SQLITE_IOERR_UNLOCK; + pFile->lastErrno = errno; pInode->eFileLock = NO_LOCK; pFile->eFileLock = NO_LOCK; } } /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. */ pInode->nLock--; assert( pInode->nLock>=0 ); if( pInode->nLock==0 ){ - int rc2 = closePendingFds(pFile); - if( rc==SQLITE_OK ){ - rc = rc2; - } + closePendingFds(pFile); } } end_unlock: unixLeaveMutex(); if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; return rc; } @@ -24458,86 +26193,79 @@ end_unlock: /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int unixUnlock(sqlite3_file *id, int eFileLock){ - return _posixUnlock(id, eFileLock, 0); + return posixUnlock(id, eFileLock, 0); } /* ** This function performs the parts of the "close file" operation ** common to all locking schemes. It closes the directory and file ** handles, if they are valid, and sets all fields of the unixFile ** structure to 0. ** ** It is *not* necessary to hold the mutex when this routine is called, ** even on VxWorks. A mutex will be acquired on VxWorks by the ** vxworksReleaseFileId() routine. */ static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; - if( pFile ){ - if( pFile->dirfd>=0 ){ - int err = close(pFile->dirfd); - if( err ){ - pFile->lastErrno = errno; - return SQLITE_IOERR_DIR_CLOSE; - }else{ - pFile->dirfd=-1; - } - } - if( pFile->h>=0 ){ - int err = close(pFile->h); - if( err ){ - pFile->lastErrno = errno; - return SQLITE_IOERR_CLOSE; - } - } + if( pFile->dirfd>=0 ){ + robust_close(pFile, pFile->dirfd, __LINE__); + pFile->dirfd=-1; + } + if( pFile->h>=0 ){ + robust_close(pFile, pFile->h, __LINE__); + pFile->h = -1; + } #if OS_VXWORKS - if( pFile->pId ){ - if( pFile->isDelete ){ - unlink(pFile->pId->zCanonicalName); - } - vxworksReleaseFileId(pFile->pId); - pFile->pId = 0; - } -#endif - OSTRACE(("CLOSE %-3d\n", pFile->h)); - OpenCounter(-1); - sqlite3_free(pFile->pUnused); - memset(pFile, 0, sizeof(unixFile)); - } + if( pFile->pId ){ + if( pFile->isDelete ){ + unlink(pFile->pId->zCanonicalName); + } + vxworksReleaseFileId(pFile->pId); + pFile->pId = 0; + } +#endif + OSTRACE(("CLOSE %-3d\n", pFile->h)); + OpenCounter(-1); + sqlite3_free(pFile->pUnused); + memset(pFile, 0, sizeof(unixFile)); return SQLITE_OK; } /* ** Close a file. */ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; - if( id ){ - unixFile *pFile = (unixFile *)id; - unixUnlock(id, NO_LOCK); - unixEnterMutex(); - if( pFile->pInode && pFile->pInode->nLock ){ - /* If there are outstanding locks, do not actually close the file just - ** yet because that would clear those locks. Instead, add the file - ** descriptor to pInode->pUnused list. It will be automatically closed - ** when the last lock is cleared. - */ - setPendingFd(pFile); - } - releaseInodeInfo(pFile); - rc = closeUnixFile(id); - unixLeaveMutex(); - } + unixFile *pFile = (unixFile *)id; + unixUnlock(id, NO_LOCK); + unixEnterMutex(); + + /* unixFile.pInode is always valid here. Otherwise, a different close + ** routine (e.g. nolockClose()) would be called instead. + */ + assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); + if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){ + /* If there are outstanding locks, do not actually close the file just + ** yet because that would clear those locks. Instead, add the file + ** descriptor to pInode->pUnused list. It will be automatically closed + ** when the last lock is cleared. + */ + setPendingFd(pFile); + } + releaseInodeInfo(pFile); + rc = closeUnixFile(id); + unixLeaveMutex(); return rc; } /************** End of the posix advisory lock implementation ***************** ******************************************************************************/ /****************************************************************************** ****************************** No-op Locking ********************************** @@ -24630,17 +26358,17 @@ static int dotlockCheckReservedLock(sqli /* Check if a thread in this process holds such a lock */ if( pFile->eFileLock>SHARED_LOCK ){ /* Either this connection or some other connection in the same process ** holds a lock on the file. No need to check further. */ reserved = 1; }else{ /* The lock is held if and only if the lockfile exists */ const char *zLockFile = (const char*)pFile->lockingContext; - reserved = access(zLockFile, 0)==0; + reserved = osAccess(zLockFile, 0)==0; } OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* ** Lock the file with the lock specified by parameter eFileLock - one @@ -24676,42 +26404,41 @@ static int dotlockLock(sqlite3_file *id, int rc = SQLITE_OK; /* If we have any lock, then the lock file already exists. All we have ** to do is adjust our internal record of the lock level. */ if( pFile->eFileLock > NO_LOCK ){ pFile->eFileLock = eFileLock; -#if !OS_VXWORKS /* Always update the timestamp on the old file */ +#ifdef HAVE_UTIME + utime(zLockFile, NULL); +#else utimes(zLockFile, NULL); #endif return SQLITE_OK; } /* grab an exclusive lock */ - fd = open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600); + fd = robust_open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600); if( fd<0 ){ /* failed to open/create the file, someone else may have stolen the lock */ int tErrno = errno; if( EEXIST == tErrno ){ rc = SQLITE_BUSY; } else { rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } } return rc; } - if( close(fd) ){ - pFile->lastErrno = errno; - rc = SQLITE_IOERR_CLOSE; - } + robust_close(pFile, fd, __LINE__); /* got it, set the type and return ok */ pFile->eFileLock = eFileLock; return rc; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock @@ -24745,17 +26472,17 @@ static int dotlockUnlock(sqlite3_file *i } /* To fully unlock the database, delete the lock file */ assert( eFileLock==NO_LOCK ); if( unlink(zLockFile) ){ int rc = 0; int tErrno = errno; if( ENOENT != tErrno ){ - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); + rc = SQLITE_IOERR_UNLOCK; } if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } return rc; } pFile->eFileLock = NO_LOCK; return SQLITE_OK; @@ -24790,16 +26517,30 @@ static int dotlockClose(sqlite3_file *id ** only a single process can be reading the database at a time. ** ** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if ** compiling for VXWORKS. */ #if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS /* +** Retry flock() calls that fail with EINTR +*/ +#ifdef EINTR +static int robust_flock(int fd, int op){ + int rc; + do{ rc = flock(fd,op); }while( rc<0 && errno==EINTR ); + return rc; +} +#else +# define robust_flock(a,b) flock(a,b) +#endif + + +/* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; @@ -24812,24 +26553,24 @@ static int flockCheckReservedLock(sqlite /* Check if a thread in this process holds such a lock */ if( pFile->eFileLock>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ if( !reserved ){ /* attempt to get the lock */ - int lrc = flock(pFile->h, LOCK_EX | LOCK_NB); + int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB); if( !lrc ){ /* got the lock, unlock it */ - lrc = flock(pFile->h, LOCK_UN); + lrc = robust_flock(pFile->h, LOCK_UN); if ( lrc ) { int tErrno = errno; /* unlock failed with an error */ - lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); + lrc = SQLITE_IOERR_UNLOCK; if( IS_LOCK_ERROR(lrc) ){ pFile->lastErrno = tErrno; rc = lrc; } } } else { int tErrno = errno; reserved = 1; @@ -24892,17 +26633,17 @@ static int flockLock(sqlite3_file *id, i ** Just adjust level and punt on outta here. */ if (pFile->eFileLock > NO_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } /* grab an exclusive lock */ - if (flock(pFile->h, LOCK_EX | LOCK_NB)) { + if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) { int tErrno = errno; /* didn't get, must be busy */ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } } else { /* got it, set the type and return ok */ @@ -24941,31 +26682,22 @@ static int flockUnlock(sqlite3_file *id, /* shared can just be set because we always have an exclusive */ if (eFileLock==SHARED_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } /* no, really, unlock. */ - int rc = flock(pFile->h, LOCK_UN); - if (rc) { - int r, tErrno = errno; - r = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); - if( IS_LOCK_ERROR(r) ){ - pFile->lastErrno = tErrno; - } + if( robust_flock(pFile->h, LOCK_UN) ){ #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS - if( (r & SQLITE_IOERR) == SQLITE_IOERR ){ - r = SQLITE_BUSY; - } + return SQLITE_OK; #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ - - return r; - } else { + return SQLITE_IOERR_UNLOCK; + }else{ pFile->eFileLock = NO_LOCK; return SQLITE_OK; } } /* ** Close a file. */ @@ -25579,17 +27311,17 @@ static int afpUnlock(sqlite3_file *id, i pInode->eFileLock = NO_LOCK; pFile->eFileLock = NO_LOCK; } } if( rc==SQLITE_OK ){ pInode->nLock--; assert( pInode->nLock>=0 ); if( pInode->nLock==0 ){ - rc = closePendingFds(pFile); + closePendingFds(pFile); } } } unixLeaveMutex(); if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; return rc; } @@ -25636,17 +27368,17 @@ static int afpClose(sqlite3_file *id) { /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int nfsUnlock(sqlite3_file *id, int eFileLock){ - return _posixUnlock(id, eFileLock, 1); + return posixUnlock(id, eFileLock, 1); } #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ /* ** The code above is the NFS lock implementation. The code is specific ** to MacOSX and does not work on other unix platforms. No alternative ** is available. ** @@ -25678,33 +27410,33 @@ static int nfsUnlock(sqlite3_file *id, i */ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ int got; #if (!defined(USE_PREAD) && !defined(USE_PREAD64)) i64 newOffset; #endif TIMER_START; #if defined(USE_PREAD) - got = pread(id->h, pBuf, cnt, offset); + do{ got = osPread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); SimulateIOError( got = -1 ); #elif defined(USE_PREAD64) - got = pread64(id->h, pBuf, cnt, offset); + do{ got = osPread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR); SimulateIOError( got = -1 ); #else newOffset = lseek(id->h, offset, SEEK_SET); SimulateIOError( newOffset-- ); if( newOffset!=offset ){ if( newOffset == -1 ){ ((unixFile*)id)->lastErrno = errno; }else{ ((unixFile*)id)->lastErrno = 0; } return -1; } - got = read(id->h, pBuf, cnt); + do{ got = osRead(id->h, pBuf, cnt); }while( got<0 && errno==EINTR ); #endif TIMER_END; if( got<0 ){ ((unixFile*)id)->lastErrno = errno; } OSTRACE(("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED)); return got; } @@ -25756,30 +27488,31 @@ static int unixRead( */ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ int got; #if (!defined(USE_PREAD) && !defined(USE_PREAD64)) i64 newOffset; #endif TIMER_START; #if defined(USE_PREAD) - got = pwrite(id->h, pBuf, cnt, offset); + do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); #elif defined(USE_PREAD64) - got = pwrite64(id->h, pBuf, cnt, offset); + do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR); #else newOffset = lseek(id->h, offset, SEEK_SET); + SimulateIOError( newOffset-- ); if( newOffset!=offset ){ if( newOffset == -1 ){ ((unixFile*)id)->lastErrno = errno; }else{ ((unixFile*)id)->lastErrno = 0; } return -1; } - g