diff options
author | 2016-09-23 09:21:58 +0000 | |
---|---|---|
committer | 2016-09-23 09:21:58 +0000 | |
commit | 25e4f8ab5acd0ef40feec6767a572bebbbe294b3 (patch) | |
tree | 20197c0e46bb6d260f4a310b6d5dd73b8d826f01 /lib/libsqlite3/tool | |
parent | remove usr.bin/sqlite3, it has moved back to ports (diff) | |
download | wireguard-openbsd-25e4f8ab5acd0ef40feec6767a572bebbbe294b3.tar.xz wireguard-openbsd-25e4f8ab5acd0ef40feec6767a572bebbbe294b3.zip |
remove lib/libsqlite3, it has moved back to ports
Diffstat (limited to 'lib/libsqlite3/tool')
56 files changed, 0 insertions, 20539 deletions
diff --git a/lib/libsqlite3/tool/build-all-msvc.bat b/lib/libsqlite3/tool/build-all-msvc.bat deleted file mode 100755 index 4842dc40744..00000000000 --- a/lib/libsqlite3/tool/build-all-msvc.bat +++ /dev/null @@ -1,771 +0,0 @@ -@ECHO OFF
-
-::
-:: build-all-msvc.bat --
-::
-:: Multi-Platform Build Tool for MSVC
-::
-
-REM
-REM This batch script is used to build the SQLite DLL for multiple platforms
-REM and configurations using MSVC. The built SQLite DLLs, their associated
-REM import libraries, and optionally their symbols files, are placed within
-REM the directory specified on the command line, in sub-directories named for
-REM their respective platforms and configurations. This batch script must be
-REM run from inside a Visual Studio Command Prompt for the desired version of
-REM Visual Studio ^(the initial platform configured for the command prompt does
-REM not really matter^). Exactly one command line argument is required, the
-REM name of an existing directory to be used as the final destination directory
-REM for the generated output files, which will be placed in sub-directories
-REM created therein. Ideally, the directory specified should be empty.
-REM
-REM Example:
-REM
-REM CD /D C:\dev\sqlite\core
-REM tool\build-all-msvc.bat C:\Temp
-REM
-REM In the example above, "C:\dev\sqlite\core" represents the root of the
-REM source tree for SQLite and "C:\Temp" represents the final destination
-REM directory for the generated output files.
-REM
-REM Please note that the SQLite build process performed by the Makefile
-REM associated with this batch script requires both Gawk ^(gawk.exe^) and Tcl
-REM 8.5 ^(tclsh85.exe^) to be present in a directory contained in the PATH
-REM environment variable unless a pre-existing amalgamation file is used.
-REM
-REM There are several environment variables that may be set to modify the
-REM behavior of this batch script and its associated Makefile. The list of
-REM platforms to build may be overriden by using the PLATFORMS environment
-REM variable, which should contain a list of platforms ^(e.g. x86 x86_amd64
-REM x86_arm^). All platforms must be supported by the version of Visual Studio
-REM being used. The list of configurations to build may be overridden by
-REM setting the CONFIGURATIONS environment variable, which should contain a
-REM list of configurations to build ^(e.g. Debug Retail^). Neither of these
-REM variable values may contain any double quotes, surrounding or embedded.
-REM
-REM Finally, the NCRTLIBPATH, NUCRTLIBPATH, and NSDKLIBPATH environment
-REM variables may be set to specify the location of the CRT, Universal CRT, and
-REM Windows SDK, respectively, that may be needed to compile executables native
-REM to the architecture of the build machine during any cross-compilation that
-REM may be necessary, depending on the platforms to be built. These values in
-REM these three variables should be surrounded by double quotes if they contain
-REM spaces.
-REM
-REM There are a few other environment variables that impact the build process
-REM when set ^(to anything^), they are:
-REM
-REM NOCLEAN
-REM
-REM When set, the "clean" target will not be used during each build iteration.
-REM However, the target binaries, if any, will still be deleted manually prior
-REM to being rebuilt. Setting this environment variable is only rarely needed
-REM and could cause issues in some circumstances; therefore, setting it is not
-REM recommended.
-REM
-REM NOSYMBOLS
-REM
-REM When set, copying of symbol files ^(*.pdb^) created during the build will
-REM be skipped and they will not appear in the final destination directory.
-REM Setting this environment variable is never strictly needed and could cause
-REM issues in some circumstances; therefore, setting it is not recommended.
-REM
-REM BUILD_ALL_SHELL
-REM
-REM When set, the command line shell will be built for each selected platform
-REM and configuration as well. In addition, the command line shell binaries
-REM will be copied, with their symbols, to the final destination directory.
-REM
-REM USE_WINV63_NSDKLIBPATH
-REM
-REM When set, modifies how the NSDKLIBPATH environment variable is built, based
-REM on the WindowsSdkDir environment variable. It forces this batch script to
-REM assume the Windows 8.1 SDK location should be used.
-REM
-REM USE_WINV100_NSDKLIBPATH
-REM
-REM When set, modifies how the NSDKLIBPATH environment variable is built, based
-REM on the WindowsSdkDir environment variable. It causes this batch script to
-REM assume the Windows 10.0 SDK location should be used.
-REM
-REM NMAKE_ARGS
-REM
-REM When set, the value is expanded and passed to the NMAKE command line, after
-REM its other arguments. This is used to specify additional NMAKE options, for
-REM example:
-REM
-REM SET NMAKE_ARGS=FOR_WINRT=1
-REM
-SETLOCAL
-
-REM SET __ECHO=ECHO
-REM SET __ECHO2=ECHO
-REM SET __ECHO3=ECHO
-IF NOT DEFINED _AECHO (SET _AECHO=REM)
-IF NOT DEFINED _CECHO (SET _CECHO=REM)
-IF NOT DEFINED _VECHO (SET _VECHO=REM)
-
-SET REDIRECT=^>
-IF DEFINED __ECHO SET REDIRECT=^^^>
-
-%_AECHO% Running %0 %*
-
-REM SET DFLAGS=/L
-
-%_VECHO% DFlags = '%DFLAGS%'
-
-SET FFLAGS=/V /F /G /H /I /R /Y /Z
-
-%_VECHO% FFlags = '%FFLAGS%'
-
-SET ROOT=%~dp0\..
-SET ROOT=%ROOT:\\=\%
-
-%_VECHO% Root = '%ROOT%'
-
-REM
-REM NOTE: The first and only argument to this batch file should be the output
-REM directory where the platform-specific binary directories should be
-REM created.
-REM
-SET BINARYDIRECTORY=%1
-
-IF NOT DEFINED BINARYDIRECTORY (
- GOTO usage
-)
-
-%_VECHO% BinaryDirectory = '%BINARYDIRECTORY%'
-
-SET DUMMY=%2
-
-IF DEFINED DUMMY (
- GOTO usage
-)
-
-REM
-REM NOTE: From this point, we need a clean error level. Reset it now.
-REM
-CALL :fn_ResetErrorLevel
-
-REM
-REM NOTE: Change the current directory to the root of the source tree, saving
-REM the current directory on the directory stack.
-REM
-%__ECHO2% PUSHD "%ROOT%"
-
-IF ERRORLEVEL 1 (
- ECHO Could not change directory to "%ROOT%".
- GOTO errors
-)
-
-REM
-REM NOTE: This batch file requires the ComSpec environment variable to be set,
-REM typically to something like "C:\Windows\System32\cmd.exe".
-REM
-IF NOT DEFINED ComSpec (
- ECHO The ComSpec environment variable must be defined.
- GOTO errors
-)
-
-REM
-REM NOTE: This batch file requires the VcInstallDir environment variable to be
-REM set. Tyipcally, this means this batch file needs to be run from an
-REM MSVC command prompt.
-REM
-IF NOT DEFINED VCINSTALLDIR (
- ECHO The VCINSTALLDIR environment variable must be defined.
- GOTO errors
-)
-
-REM
-REM NOTE: If the list of platforms is not already set, use the default list.
-REM
-IF NOT DEFINED PLATFORMS (
- SET PLATFORMS=x86 x86_amd64 x86_arm
-)
-
-%_VECHO% Platforms = '%PLATFORMS%'
-
-REM
-REM NOTE: If the list of configurations is not already set, use the default
-REM list.
-REM
-IF NOT DEFINED CONFIGURATIONS (
- SET CONFIGURATIONS=Debug Retail
-)
-
-%_VECHO% Configurations = '%CONFIGURATIONS%'
-
-REM
-REM NOTE: If the command used to invoke NMAKE is not already set, use the
-REM default.
-REM
-IF NOT DEFINED NMAKE_CMD (
- SET NMAKE_CMD=nmake -B -f Makefile.msc
-)
-
-%_VECHO% NmakeCmd = '%NMAKE_CMD%'
-%_VECHO% NmakeArgs = '%NMAKE_ARGS%'
-
-REM
-REM NOTE: Setup environment variables to translate between the MSVC platform
-REM names and the names to be used for the platform-specific binary
-REM directories.
-REM
-SET amd64_NAME=x64
-SET arm_NAME=ARM
-SET x64_NAME=x64
-SET x86_NAME=x86
-SET x86_amd64_NAME=x64
-SET x86_arm_NAME=ARM
-SET x86_x64_NAME=x64
-
-%_VECHO% amd64_Name = '%amd64_NAME%'
-%_VECHO% arm_Name = '%arm_NAME%'
-%_VECHO% x64_Name = '%x64_NAME%'
-%_VECHO% x86_Name = '%x86_NAME%'
-%_VECHO% x86_amd64_Name = '%x86_amd64_NAME%'
-%_VECHO% x86_arm_Name = '%x86_arm_NAME%'
-%_VECHO% x86_x64_Name = '%x86_x64_NAME%'
-
-REM
-REM NOTE: Check for the external tools needed during the build process ^(i.e.
-REM those that do not get compiled as part of the build process itself^)
-REM along the PATH.
-REM
-FOR %%T IN (gawk.exe tclsh85.exe) DO (
- SET %%T_PATH=%%~dp$PATH:T
-)
-
-REM
-REM NOTE: The Gawk executable "gawk.exe" is required during the SQLite build
-REM process unless a pre-existing amalgamation file is used.
-REM
-IF NOT DEFINED gawk.exe_PATH (
- ECHO The Gawk executable "gawk.exe" is required to be in the PATH.
- GOTO errors
-)
-
-REM
-REM NOTE: The Tcl 8.5 executable "tclsh85.exe" is required during the SQLite
-REM build process unless a pre-existing amalgamation file is used.
-REM
-IF NOT DEFINED tclsh85.exe_PATH (
- ECHO The Tcl 8.5 executable "tclsh85.exe" is required to be in the PATH.
- GOTO errors
-)
-
-REM
-REM NOTE: Set the TOOLPATH variable to contain all the directories where the
-REM external tools were found in the search above.
-REM
-SET TOOLPATH=%gawk.exe_PATH%;%tclsh85.exe_PATH%
-
-%_VECHO% ToolPath = '%TOOLPATH%'
-
-REM
-REM NOTE: Setting the Windows SDK library path is only required for MSVC
-REM 2012, 2013, and 2015.
-REM
-CALL :fn_UnsetVariable SET_NSDKLIBPATH
-
-REM
-REM NOTE: Setting the Universal CRT library path is only required for MSVC
-REM 2015.
-REM
-CALL :fn_UnsetVariable SET_NUCRTLIBPATH
-
-REM
-REM NOTE: Check for MSVC 2012, 2013, and 2015 specially because the Windows
-REM SDK directory handling is slightly different for those versions.
-REM
-IF "%VisualStudioVersion%" == "11.0" (
- REM
- REM NOTE: If the Windows SDK library path has already been set, do not set
- REM it to something else later on.
- REM
- IF NOT DEFINED NSDKLIBPATH (
- SET SET_NSDKLIBPATH=1
- )
-) ELSE IF "%VisualStudioVersion%" == "12.0" (
- REM
- REM NOTE: If the Windows SDK library path has already been set, do not set
- REM it to something else later on.
- REM
- IF NOT DEFINED NSDKLIBPATH (
- SET SET_NSDKLIBPATH=1
- )
-) ELSE IF "%VisualStudioVersion%" == "14.0" (
- REM
- REM NOTE: If the Windows SDK library path has already been set, do not set
- REM it to something else later on.
- REM
- IF NOT DEFINED NSDKLIBPATH (
- SET SET_NSDKLIBPATH=1
- )
-
- REM
- REM NOTE: If the Universal CRT library path has already been set, do not set
- REM it to something else later on.
- REM
- IF NOT DEFINED NUCRTLIBPATH (
- SET SET_NUCRTLIBPATH=1
- )
-)
-
-REM
-REM NOTE: This is the name of the sub-directory where the UCRT libraries may
-REM be found. It is only used when compiling against the UCRT.
-REM
-IF DEFINED UCRTVersion (
- SET NUCRTVER=%UCRTVersion%
-) ELSE (
- SET NUCRTVER=10.0.10240.0
-)
-
-REM
-REM NOTE: This is the name of the sub-directory where the Windows 10.0 SDK
-REM libraries may be found. It is only used when compiling with the
-REM Windows 10.0 SDK.
-REM
-IF DEFINED WindowsSDKLibVersion (
- SET WIN10SDKVER=%WindowsSDKLibVersion:\=%
-) ELSE (
- SET WIN10SDKVER=%NUCRTVER%
-)
-
-REM
-REM NOTE: Check if this is the Windows Phone SDK. If so, a different batch
-REM file is necessary to setup the build environment. Since the variable
-REM values involved here may contain parenthesis, using GOTO instead of
-REM an IF block is required.
-REM
-IF DEFINED WindowsPhoneKitDir GOTO set_vcvarsall_phone
-SET VCVARSALL=%VCINSTALLDIR%\vcvarsall.bat
-GOTO set_vcvarsall_done
-:set_vcvarsall_phone
-SET VCVARSALL=%VCINSTALLDIR%\WPSDK\WP80\vcvarsphoneall.bat
-:set_vcvarsall_done
-SET VCVARSALL=%VCVARSALL:\\=\%
-
-REM
-REM NOTE: This is the outer loop. There should be exactly one iteration per
-REM platform.
-REM
-FOR %%P IN (%PLATFORMS%) DO (
- REM
- REM NOTE: Using the MSVC platform name, lookup the simpler platform name to
- REM be used for the name of the platform-specific binary directory via
- REM the environment variables setup earlier.
- REM
- CALL :fn_CopyVariable %%P_NAME PLATFORMNAME
-
- REM
- REM NOTE: This is the second loop. There should be exactly one iteration.
- REM This loop is necessary because the PlatformName environment
- REM variable was set above and that value is needed by some of the
- REM commands contained in the inner loop. If these commands were
- REM directly contained in the outer loop, the PlatformName environment
- REM variable would be stuck with its initial empty value instead.
- REM
- FOR /F "tokens=2* delims==" %%D IN ('SET PLATFORMNAME') DO (
- REM
- REM NOTE: Attempt to clean the environment of all variables used by MSVC
- REM and/or Visual Studio. This block may need to be updated in the
- REM future to account for additional environment variables.
- REM
- CALL :fn_UnsetVariable CommandPromptType
- CALL :fn_UnsetVariable DevEnvDir
- CALL :fn_UnsetVariable DNX_HOME
- CALL :fn_UnsetVariable ExtensionSdkDir
- CALL :fn_UnsetVariable Framework35Version
- CALL :fn_UnsetVariable Framework40Version
- CALL :fn_UnsetVariable FrameworkDir
- CALL :fn_UnsetVariable FrameworkDir32
- CALL :fn_UnsetVariable FrameworkVersion
- CALL :fn_UnsetVariable FrameworkVersion32
- CALL :fn_UnsetVariable FSHARPINSTALLDIR
- CALL :fn_UnsetVariable INCLUDE
- CALL :fn_UnsetVariable LIB
- CALL :fn_UnsetVariable LIBPATH
- CALL :fn_UnsetVariable NETFXSDKDir
- CALL :fn_UnsetVariable Platform
- CALL :fn_UnsetVariable UCRTVersion
- CALL :fn_UnsetVariable UniversalCRTSdkDir
- REM CALL :fn_UnsetVariable VCINSTALLDIR
- CALL :fn_UnsetVariable VSINSTALLDIR
- CALL :fn_UnsetVariable WindowsLibPath
- CALL :fn_UnsetVariable WindowsPhoneKitDir
- CALL :fn_UnsetVariable WindowsSdkDir
- CALL :fn_UnsetVariable WindowsSdkDir_35
- CALL :fn_UnsetVariable WindowsSdkDir_old
- CALL :fn_UnsetVariable WindowsSDKLibVersion
- CALL :fn_UnsetVariable WindowsSDKVersion
- CALL :fn_UnsetVariable WindowsSDK_ExecutablePath_x86
- CALL :fn_UnsetVariable WindowsSDK_ExecutablePath_x64
-
- REM
- REM NOTE: Reset the PATH here to the absolute bare minimum required.
- REM
- SET PATH=%TOOLPATH%;%SystemRoot%\System32;%SystemRoot%
-
- REM
- REM NOTE: This is the inner loop. There are normally two iterations, one
- REM for each supported build configuration, e.g. Debug or Retail.
- REM
- FOR %%B IN (%CONFIGURATIONS%) DO (
- REM
- REM NOTE: When preparing the debug build, set the DEBUG and MEMDEBUG
- REM environment variables to be picked up by the MSVC makefile
- REM itself.
- REM
- %_AECHO% Building the %%B configuration for platform %%P with name %%D...
-
- IF /I "%%B" == "Debug" (
- REM
- REM NOTE: Using this level for the DEBUG environment variable should
- REM disable all compiler optimizations and prevent use of the
- REM NDEBUG define. Additionally, both SQLITE_ENABLE_API_ARMOR
- REM and SQLITE_DEBUG defines should be enabled.
- REM
- SET DEBUG=3
-
- REM
- REM NOTE: Setting this to non-zero should enable the SQLITE_MEMDEBUG
- REM define.
- REM
- SET MEMDEBUG=1
- ) ELSE (
- CALL :fn_UnsetVariable DEBUG
- CALL :fn_UnsetVariable MEMDEBUG
- )
-
- REM
- REM NOTE: Launch a nested command shell to perform the following steps:
- REM
- REM 1. Setup the MSVC environment for this platform using the
- REM official batch file.
- REM
- REM 2. Make sure that no stale build output files are present.
- REM
- REM 3. Build the "sqlite3.dll" and "sqlite3.lib" binaries for this
- REM platform.
- REM
- REM 4. Copy the "sqlite3.dll" and "sqlite3.lib" binaries for this
- REM platform to the platform-specific directory beneath the
- REM binary directory.
- REM
- REM 5. Unless prevented from doing so, copy the "sqlite3.pdb"
- REM symbols file for this platform to the platform-specific
- REM directory beneath the binary directory.
- REM
- "%ComSpec%" /C (
- REM
- REM NOTE: Attempt to setup the MSVC environment for this platform.
- REM
- %__ECHO3% CALL "%VCVARSALL%" %%P
-
- IF ERRORLEVEL 1 (
- ECHO Failed to call "%VCVARSALL%" for platform %%P.
- GOTO errors
- )
-
- REM
- REM NOTE: If this batch file is not running in "what-if" mode, check to
- REM be sure we were actually able to setup the MSVC environment
- REM as current versions of their official batch file do not set
- REM the exit code upon failure.
- REM
- IF NOT DEFINED __ECHO3 (
- IF NOT DEFINED WindowsPhoneKitDir (
- IF NOT DEFINED WindowsSdkDir (
- ECHO Cannot build, Windows SDK not found for platform %%P.
- GOTO errors
- )
- )
- )
-
- REM
- REM NOTE: When using MSVC 2012, 2013, or 2015, the native SDK path
- REM cannot simply be the "lib" sub-directory beneath the location
- REM specified in the WindowsSdkDir environment variable because
- REM that location does not actually contain the necessary library
- REM files for x86. This must be done for each iteration because
- REM it relies upon the WindowsSdkDir environment variable being
- REM set by the batch file used to setup the MSVC environment.
- REM
- IF DEFINED SET_NSDKLIBPATH (
- REM
- REM NOTE: The Windows Phone SDK has a slightly different directory
- REM structure and must be handled specially here.
- REM
- IF DEFINED WindowsPhoneKitDir (
- CALL :fn_CopyVariable WindowsPhoneKitDir NSDKLIBPATH
- CALL :fn_AppendVariable NSDKLIBPATH \lib\x86
- ) ELSE IF DEFINED WindowsSdkDir (
- CALL :fn_CopyVariable WindowsSdkDir NSDKLIBPATH
-
- REM
- REM NOTE: The Windows 8.x and Windows 10.0 SDKs have a slightly
- REM different directory naming conventions.
- REM
- IF DEFINED USE_WINV100_NSDKLIBPATH (
- CALL :fn_AppendVariable NSDKLIBPATH \..\10\lib\%WIN10SDKVER%\um\x86
- CALL :fn_CopyVariable WindowsSdkDir PSDKLIBPATH
- CALL :fn_AppendVariable PSDKLIBPATH lib\%WIN10SDKVER%\um\%%D
- ) ELSE IF DEFINED USE_WINV63_NSDKLIBPATH (
- CALL :fn_AppendVariable NSDKLIBPATH \lib\winv6.3\um\x86
- ) ELSE IF "%VisualStudioVersion%" == "12.0" (
- CALL :fn_AppendVariable NSDKLIBPATH \..\8.0\lib\win8\um\x86
- ) ELSE IF "%VisualStudioVersion%" == "14.0" (
- CALL :fn_AppendVariable NSDKLIBPATH \..\8.0\lib\win8\um\x86
- ) ELSE (
- CALL :fn_AppendVariable NSDKLIBPATH \lib\win8\um\x86
- )
- )
- )
-
- REM
- REM NOTE: When using MSVC 2015, setting the Universal CRT library path
- REM for x86 may be required as well. This must also be done for
- REM each iteration because it relies upon the UniversalCRTSdkDir
- REM environment variable being set by the batch file used to
- REM setup the MSVC environment.
- REM
- IF DEFINED SET_NUCRTLIBPATH (
- IF DEFINED UniversalCRTSdkDir (
- CALL :fn_CopyVariable UniversalCRTSdkDir NUCRTLIBPATH
- CALL :fn_AppendVariable NUCRTLIBPATH \lib\%NUCRTVER%\ucrt\x86
- )
- )
-
- REM
- REM NOTE: Unless prevented from doing so, invoke NMAKE with the MSVC
- REM makefile to clean any stale build output from previous
- REM iterations of this loop and/or previous runs of this batch
- REM file, etc.
- REM
- IF NOT DEFINED NOCLEAN (
- %__ECHO% %NMAKE_CMD% clean
-
- IF ERRORLEVEL 1 (
- ECHO Failed to clean for platform %%P.
- GOTO errors
- )
- ) ELSE (
- REM
- REM NOTE: Even when the cleaning step has been disabled, we still
- REM need to remove the build output for all the files we are
- REM specifically wanting to build for each platform.
- REM
- %_AECHO% Cleaning final core library output files only...
- %__ECHO% DEL /Q *.lo sqlite3.dll sqlite3.lib sqlite3.pdb 2%REDIRECT% NUL
- )
-
- REM
- REM NOTE: Call NMAKE with the MSVC makefile to build the "sqlite3.dll"
- REM binary. The x86 compiler will be used to compile the native
- REM command line tools needed during the build process itself.
- REM Also, disable looking for and/or linking to the native Tcl
- REM runtime library.
- REM
- %__ECHO% %NMAKE_CMD% sqlite3.dll XCOMPILE=1 USE_NATIVE_LIBPATHS=1 NO_TCL=1 %NMAKE_ARGS%
-
- IF ERRORLEVEL 1 (
- ECHO Failed to build %%B "sqlite3.dll" for platform %%P.
- GOTO errors
- )
-
- REM
- REM NOTE: Copy the "sqlite3.dll" file to the appropriate directory for
- REM the build and platform beneath the binary directory.
- REM
- %__ECHO% XCOPY sqlite3.dll "%BINARYDIRECTORY%\%%B\%%D\" %FFLAGS% %DFLAGS%
-
- IF ERRORLEVEL 1 (
- ECHO Failed to copy "sqlite3.dll" to "%BINARYDIRECTORY%\%%B\%%D\".
- GOTO errors
- )
-
- REM
- REM NOTE: Copy the "sqlite3.lib" file to the appropriate directory for
- REM the build and platform beneath the binary directory.
- REM
- %__ECHO% XCOPY sqlite3.lib "%BINARYDIRECTORY%\%%B\%%D\" %FFLAGS% %DFLAGS%
-
- IF ERRORLEVEL 1 (
- ECHO Failed to copy "sqlite3.lib" to "%BINARYDIRECTORY%\%%B\%%D\".
- GOTO errors
- )
-
- REM
- REM NOTE: Copy the "sqlite3.pdb" file to the appropriate directory for
- REM the build and platform beneath the binary directory unless we
- REM are prevented from doing so.
- REM
- IF NOT DEFINED NOSYMBOLS (
- %__ECHO% XCOPY sqlite3.pdb "%BINARYDIRECTORY%\%%B\%%D\" %FFLAGS% %DFLAGS%
-
- IF ERRORLEVEL 1 (
- ECHO Failed to copy "sqlite3.pdb" to "%BINARYDIRECTORY%\%%B\%%D\".
- GOTO errors
- )
- )
-
- REM
- REM NOTE: If requested, also build the shell executable.
- REM
- IF DEFINED BUILD_ALL_SHELL (
- REM
- REM NOTE: If necessary, make sure any previous build output for the
- REM shell executable is deleted.
- REM
- IF DEFINED NOCLEAN (
- REM
- REM NOTE: Even when the cleaning step has been disabled, we still
- REM need to remove the build output for all the files we are
- REM specifically wanting to build for each platform.
- REM
- %_AECHO% Cleaning final shell executable output files only...
- %__ECHO% DEL /Q sqlite3.exe sqlite3sh.pdb 2%REDIRECT% NUL
- )
-
- REM
- REM NOTE: Call NMAKE with the MSVC makefile to build the "sqlite3.exe"
- REM binary. The x86 compiler will be used to compile the native
- REM command line tools needed during the build process itself.
- REM Also, disable looking for and/or linking to the native Tcl
- REM runtime library.
- REM
- %__ECHO% %NMAKE_CMD% sqlite3.exe XCOMPILE=1 USE_NATIVE_LIBPATHS=1 NO_TCL=1 %NMAKE_ARGS%
-
- IF ERRORLEVEL 1 (
- ECHO Failed to build %%B "sqlite3.exe" for platform %%P.
- GOTO errors
- )
-
- REM
- REM NOTE: Copy the "sqlite3.exe" file to the appropriate directory
- REM for the build and platform beneath the binary directory.
- REM
- %__ECHO% XCOPY sqlite3.exe "%BINARYDIRECTORY%\%%B\%%D\" %FFLAGS% %DFLAGS%
-
- IF ERRORLEVEL 1 (
- ECHO Failed to copy "sqlite3.exe" to "%BINARYDIRECTORY%\%%B\%%D\".
- GOTO errors
- )
-
- REM
- REM NOTE: Copy the "sqlite3sh.pdb" file to the appropriate directory
- REM for the build and platform beneath the binary directory
- REM unless we are prevented from doing so.
- REM
- IF NOT DEFINED NOSYMBOLS (
- %__ECHO% XCOPY sqlite3sh.pdb "%BINARYDIRECTORY%\%%B\%%D\" %FFLAGS% %DFLAGS%
-
- IF ERRORLEVEL 1 (
- ECHO Failed to copy "sqlite3sh.pdb" to "%BINARYDIRECTORY%\%%B\%%D\".
- GOTO errors
- )
- )
- )
- )
- )
- )
-
- REM
- REM NOTE: Handle any errors generated during the nested command shell.
- REM
- IF ERRORLEVEL 1 (
- GOTO errors
- )
-)
-
-REM
-REM NOTE: Restore the saved current directory from the directory stack.
-REM
-%__ECHO2% POPD
-
-IF ERRORLEVEL 1 (
- ECHO Could not restore directory.
- GOTO errors
-)
-
-REM
-REM NOTE: If we get to this point, we have succeeded.
-REM
-GOTO no_errors
-
-:fn_ShowVariable
- SETLOCAL
- SET __ECHO_CMD=ECHO %%%2%%
- FOR /F "delims=" %%V IN ('%__ECHO_CMD%') DO (
- IF NOT "%%V" == "" (
- IF NOT "%%V" == "%%%2%%" (
- %_VECHO% %1 = '%%V'
- )
- )
- )
- ENDLOCAL
- GOTO :EOF
-
-:fn_ResetErrorLevel
- VERIFY > NUL
- GOTO :EOF
-
-:fn_SetErrorLevel
- VERIFY MAYBE 2> NUL
- GOTO :EOF
-
-:fn_CopyVariable
- IF NOT DEFINED %1 GOTO :EOF
- IF "%2" == "" GOTO :EOF
- SETLOCAL
- SET __ECHO_CMD=ECHO %%%1%%
- FOR /F "delims=" %%V IN ('%__ECHO_CMD%') DO (
- SET VALUE=%%V
- )
- ENDLOCAL && SET %2=%VALUE%
- GOTO :EOF
-
-:fn_UnsetVariable
- IF NOT "%1" == "" (
- SET %1=
- CALL :fn_ResetErrorLevel
- )
- GOTO :EOF
-
-:fn_AppendVariable
- SET __ECHO_CMD=ECHO %%%1%%
- IF DEFINED %1 (
- FOR /F "delims=" %%V IN ('%__ECHO_CMD%') DO (
- SET %1=%%V%~2
- )
- ) ELSE (
- SET %1=%~2
- )
- SET __ECHO_CMD=
- CALL :fn_ResetErrorLevel
- GOTO :EOF
-
-:usage
- ECHO.
- ECHO Usage: %~nx0 ^<binaryDirectory^>
- ECHO.
- GOTO errors
-
-:errors
- CALL :fn_SetErrorLevel
- ENDLOCAL
- ECHO.
- ECHO Failure, errors were encountered.
- GOTO end_of_file
-
-:no_errors
- CALL :fn_ResetErrorLevel
- ENDLOCAL
- ECHO.
- ECHO Success, no errors were encountered.
- GOTO end_of_file
-
-:end_of_file
-%__ECHO% EXIT /B %ERRORLEVEL%
diff --git a/lib/libsqlite3/tool/build-shell.sh b/lib/libsqlite3/tool/build-shell.sh deleted file mode 100644 index 6a48299d73b..00000000000 --- a/lib/libsqlite3/tool/build-shell.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -# -# This script demonstrates how to do a full-featured build of the sqlite3 -# command-line shell on Linux. -# -# SQLite source code should be in a sibling directory named "sqlite". For -# example, put SQLite sources in ~/sqlite/sqlite and run this script from -# ~/sqlite/bld. There should be an appropriate Makefile in the current -# directory as well. -# -make sqlite3.c -gcc -o sqlite3 -g -Os -I. \ - -DSQLITE_THREADSAFE=0 \ - -DSQLITE_ENABLE_VFSTRACE \ - -DSQLITE_ENABLE_STAT3 \ - -DSQLITE_ENABLE_FTS4 \ - -DSQLITE_ENABLE_RTREE \ - -DHAVE_READLINE \ - -DHAVE_USLEEP=1 \ - ../sqlite/src/shell.c \ - ../sqlite/src/test_vfstrace.c \ - sqlite3.c -ldl -lreadline -lncurses diff --git a/lib/libsqlite3/tool/checkSpacing.c b/lib/libsqlite3/tool/checkSpacing.c deleted file mode 100644 index ce38b08ce4c..00000000000 --- a/lib/libsqlite3/tool/checkSpacing.c +++ /dev/null @@ -1,84 +0,0 @@ -/* -** This program checks for formatting problems in source code: -** -** * Any use of tab characters -** * White space at the end of a line -** * Blank lines at the end of a file -** -** Any violations are reported. -*/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define CR_OK 0x001 -#define WSEOL_OK 0x002 - -static void checkSpacing(const char *zFile, unsigned flags){ - FILE *in = fopen(zFile, "rb"); - int i; - int seenSpace; - int seenTab; - int ln = 0; - int lastNonspace = 0; - char zLine[2000]; - if( in==0 ){ - printf("cannot open %s\n", zFile); - return; - } - while( fgets(zLine, sizeof(zLine), in) ){ - seenSpace = 0; - seenTab = 0; - ln++; - for(i=0; zLine[i]; i++){ - if( zLine[i]=='\t' && seenTab==0 ){ - printf("%s:%d: tab (\\t) character\n", zFile, ln); - seenTab = 1; - }else if( zLine[i]=='\r' ){ - if( (flags & CR_OK)==0 ){ - printf("%s:%d: carriage-return (\\r) character\n", zFile, ln); - } - }else if( zLine[i]==' ' ){ - seenSpace = 1; - }else if( zLine[i]!='\n' ){ - lastNonspace = ln; - seenSpace = 0; - } - } - if( seenSpace && (flags & WSEOL_OK)==0 ){ - printf("%s:%d: whitespace at end-of-line\n", zFile, ln); - } - } - fclose(in); - if( lastNonspace<ln ){ - printf("%s:%d: blank lines at end of file (%d)\n", - zFile, ln, ln - lastNonspace); - } -} - -int main(int argc, char **argv){ - int i; - unsigned flags = WSEOL_OK; - for(i=1; i<argc; i++){ - const char *z = argv[i]; - if( z[0]=='-' ){ - while( z[0]=='-' ) z++; - if( strcmp(z,"crok")==0 ){ - flags |= CR_OK; - }else if( strcmp(z, "wseol")==0 ){ - flags &= ~WSEOL_OK; - }else if( strcmp(z, "help")==0 ){ - printf("Usage: %s [options] FILE ...\n", argv[0]); - printf(" --crok Do not report on carriage-returns\n"); - printf(" --wseol Complain about whitespace at end-of-line\n"); - printf(" --help This message\n"); - }else{ - printf("unknown command-line option: [%s]\n", argv[i]); - printf("use --help for additional information\n"); - } - }else{ - checkSpacing(argv[i], flags); - } - } - return 0; -} diff --git a/lib/libsqlite3/tool/diffdb.c b/lib/libsqlite3/tool/diffdb.c deleted file mode 100644 index 0537d38723e..00000000000 --- a/lib/libsqlite3/tool/diffdb.c +++ /dev/null @@ -1,44 +0,0 @@ -/* -** A utility for printing the differences between two SQLite database files. -*/ -#include <stdio.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> - - -#define PAGESIZE 1024 -static int db1 = -1; -static int db2 = -1; - -int main(int argc, char **argv){ - int iPg; - unsigned char a1[PAGESIZE], a2[PAGESIZE]; - if( argc!=3 ){ - fprintf(stderr,"Usage: %s FILENAME FILENAME\n", argv[0]); - exit(1); - } - db1 = open(argv[1], O_RDONLY); - if( db1<0 ){ - fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]); - exit(1); - } - db2 = open(argv[2], O_RDONLY); - if( db2<0 ){ - fprintf(stderr,"%s: can't open %s\n", argv[0], argv[2]); - exit(1); - } - iPg = 1; - while( read(db1, a1, PAGESIZE)==PAGESIZE && read(db2,a2,PAGESIZE)==PAGESIZE ){ - if( memcmp(a1,a2,PAGESIZE) ){ - printf("Page %d\n", iPg); - } - iPg++; - } - printf("%d pages checked\n", iPg-1); - close(db1); - close(db2); -} diff --git a/lib/libsqlite3/tool/extract.c b/lib/libsqlite3/tool/extract.c deleted file mode 100644 index 5bf5caa31c9..00000000000 --- a/lib/libsqlite3/tool/extract.c +++ /dev/null @@ -1,46 +0,0 @@ -/* -** Extract a range of bytes from a file. -** -** Usage: -** -** extract FILENAME OFFSET AMOUNT -** -** The bytes are written to standard output. -*/ -#include <stdio.h> -#include <stdlib.h> - -int main(int argc, char **argv){ - FILE *f; - char *zBuf; - int ofst; - int n; - size_t got; - - if( argc!=4 ){ - fprintf(stderr, "Usage: %s FILENAME OFFSET AMOUNT\n", *argv); - return 1; - } - f = fopen(argv[1], "rb"); - if( f==0 ){ - fprintf(stderr, "cannot open \"%s\"\n", argv[1]); - return 1; - } - ofst = atoi(argv[2]); - n = atoi(argv[3]); - zBuf = malloc( n ); - if( zBuf==0 ){ - fprintf(stderr, "out of memory\n"); - return 1; - } - fseek(f, ofst, SEEK_SET); - got = fread(zBuf, 1, n, f); - fclose(f); - if( got<n ){ - fprintf(stderr, "got only %d of %d bytes\n", got, n); - return 1; - }else{ - fwrite(zBuf, 1, n, stdout); - } - return 0; -} diff --git a/lib/libsqlite3/tool/fast_vacuum.c b/lib/libsqlite3/tool/fast_vacuum.c deleted file mode 100644 index 6a50dcc6805..00000000000 --- a/lib/libsqlite3/tool/fast_vacuum.c +++ /dev/null @@ -1,234 +0,0 @@ -/* -** 2013-10-01 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This program implements a high-speed version of the VACUUM command. -** It repacks an SQLite database to remove as much unused space as -** possible and to relocate content sequentially in the file. -** -** This program runs faster and uses less temporary disk space than the -** built-in VACUUM command. On the other hand, this program has a number -** of important restrictions relative to the built-in VACUUM command. -** -** (1) The caller must ensure that no other processes are accessing the -** database file while the vacuum is taking place. The usual SQLite -** file locking is insufficient for this. The caller must use -** external means to make sure only this one routine is reading and -** writing the database. -** -** (2) Database reconfiguration such as page size or auto_vacuum changes -** are not supported by this utility. -** -** (3) The database file might be renamed if a power loss or crash -** occurs at just the wrong moment. Recovery must be prepared to -** to deal with the possibly changed filename. -** -** This program is intended as a *Demonstration Only*. The intent of this -** program is to provide example code that application developers can use -** when creating similar functionality in their applications. -** -** To compile this program: -** -** cc fast_vacuum.c sqlite3.c -** -** Add whatever linker options are required. (Example: "-ldl -lpthread"). -** Then to run the program: -** -** ./a.out file-to-vacuum -** -*/ -#include "sqlite3.h" -#include <stdio.h> -#include <stdlib.h> - -/* -** Finalize a prepared statement. If an error has occurred, print the -** error message and exit. -*/ -static void vacuumFinalize(sqlite3_stmt *pStmt){ - sqlite3 *db = sqlite3_db_handle(pStmt); - int rc = sqlite3_finalize(pStmt); - if( rc ){ - fprintf(stderr, "finalize error: %s\n", sqlite3_errmsg(db)); - exit(1); - } -} - -/* -** Execute zSql on database db. The SQL text is printed to standard -** output. If an error occurs, print an error message and exit the -** process. -*/ -static void execSql(sqlite3 *db, const char *zSql){ - sqlite3_stmt *pStmt; - if( !zSql ){ - fprintf(stderr, "out of memory!\n"); - exit(1); - } - printf("%s;\n", zSql); - if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){ - fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); - exit(1); - } - sqlite3_step(pStmt); - vacuumFinalize(pStmt); -} - -/* -** Execute zSql on database db. The zSql statement returns exactly -** one column. Execute this return value as SQL on the same database. -** -** The zSql statement is printed on standard output prior to being -** run. If any errors occur, an error is printed and the process -** exits. -*/ -static void execExecSql(sqlite3 *db, const char *zSql){ - sqlite3_stmt *pStmt; - int rc; - - printf("%s;\n", zSql); - rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); - if( rc!=SQLITE_OK ){ - fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); - exit(1); - } - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - execSql(db, (char*)sqlite3_column_text(pStmt, 0)); - } - vacuumFinalize(pStmt); -} - - -int main(int argc, char **argv){ - sqlite3 *db; /* Connection to the database file */ - int rc; /* Return code from SQLite interface calls */ - sqlite3_uint64 r; /* A random number */ - const char *zDbToVacuum; /* Database to be vacuumed */ - char *zBackupDb; /* Backup copy of the original database */ - char *zTempDb; /* Temporary database */ - char *zSql; /* An SQL statement */ - - if( argc!=2 ){ - fprintf(stderr, "Usage: %s DATABASE\n", argv[0]); - return 1; - } - - /* Identify the database file to be vacuumed and open it. - */ - zDbToVacuum = argv[1]; - printf("-- open database file \"%s\"\n", zDbToVacuum); - rc = sqlite3_open(zDbToVacuum, &db); - if( rc ){ - fprintf(stderr, "%s: %s\n", zDbToVacuum, sqlite3_errstr(rc)); - return 1; - } - - /* Create names for two other files. zTempDb will be a new database - ** into which we construct a vacuumed copy of zDbToVacuum. zBackupDb - ** will be a new name for zDbToVacuum after it is vacuumed. - */ - sqlite3_randomness(sizeof(r), &r); - zTempDb = sqlite3_mprintf("%s-vacuum-%016llx", zDbToVacuum, r); - zBackupDb = sqlite3_mprintf("%s-backup-%016llx", zDbToVacuum, r); - - /* Attach the zTempDb database to the database connection. - */ - zSql = sqlite3_mprintf("ATTACH '%q' AS vacuum_db;", zTempDb); - execSql(db, zSql); - sqlite3_free(zSql); - - /* TODO: - ** Set the page_size and auto_vacuum mode for zTempDb here, if desired. - */ - - /* The vacuum will occur inside of a transaction. Set writable_schema - ** to ON so that we can directly update the sqlite_master table in the - ** zTempDb database. - */ - execSql(db, "PRAGMA writable_schema=ON"); - execSql(db, "BEGIN"); - - - /* Query the schema of the main database. Create a mirror schema - ** in the temporary database. - */ - execExecSql(db, - "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) " - " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'" - " AND rootpage>0" - ); - execExecSql(db, - "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)" - " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %'" - ); - execExecSql(db, - "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) " - " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'" - ); - - /* Loop through the tables in the main database. For each, do - ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy - ** the contents to the temporary database. - */ - execExecSql(db, - "SELECT 'INSERT INTO vacuum_db.' || quote(name) " - "|| ' SELECT * FROM main.' || quote(name) " - "FROM main.sqlite_master " - "WHERE type = 'table' AND name!='sqlite_sequence' " - " AND rootpage>0" - ); - - /* Copy over the sequence table - */ - execExecSql(db, - "SELECT 'DELETE FROM vacuum_db.' || quote(name) " - "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence'" - ); - execExecSql(db, - "SELECT 'INSERT INTO vacuum_db.' || quote(name) " - "|| ' SELECT * FROM main.' || quote(name) " - "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence'" - ); - - /* Copy the triggers, views, and virtual tables from the main database - ** over to the temporary database. None of these objects has any - ** associated storage, so all we have to do is copy their entries - ** from the SQLITE_MASTER table. - */ - execSql(db, - "INSERT INTO vacuum_db.sqlite_master " - " SELECT type, name, tbl_name, rootpage, sql" - " FROM main.sqlite_master" - " WHERE type='view' OR type='trigger'" - " OR (type='table' AND rootpage=0)" - ); - - /* Commit the transaction and close the database - */ - execSql(db, "COMMIT"); - printf("-- close database\n"); - sqlite3_close(db); - - - /* At this point, zDbToVacuum is unchanged. zTempDb contains a - ** vacuumed copy of zDbToVacuum. Rearrange filenames so that - ** zTempDb becomes thenew zDbToVacuum. - */ - printf("-- rename \"%s\" to \"%s\"\n", zDbToVacuum, zBackupDb); - rename(zDbToVacuum, zBackupDb); - printf("-- rename \"%s\" to \"%s\"\n", zTempDb, zDbToVacuum); - rename(zTempDb, zDbToVacuum); - - /* Release allocated memory */ - sqlite3_free(zTempDb); - sqlite3_free(zBackupDb); - return 0; -} diff --git a/lib/libsqlite3/tool/fragck.tcl b/lib/libsqlite3/tool/fragck.tcl deleted file mode 100644 index 35e76f482b6..00000000000 --- a/lib/libsqlite3/tool/fragck.tcl +++ /dev/null @@ -1,149 +0,0 @@ -# Run this TCL script using "testfixture" to get a report that shows -# the sequence of database pages used by a particular table or index. -# This information is used for fragmentation analysis. -# - -# Get the name of the database to analyze -# - -if {[llength $argv]!=2} { - puts stderr "Usage: $argv0 database-name table-or-index-name" - exit 1 -} -set file_to_analyze [lindex $argv 0] -if {![file exists $file_to_analyze]} { - puts stderr "No such file: $file_to_analyze" - exit 1 -} -if {![file readable $file_to_analyze]} { - puts stderr "File is not readable: $file_to_analyze" - exit 1 -} -if {[file size $file_to_analyze]<512} { - puts stderr "Empty or malformed database: $file_to_analyze" - exit 1 -} -set objname [lindex $argv 1] - -# Open the database -# -sqlite3 db [lindex $argv 0] -set DB [btree_open [lindex $argv 0] 1000 0] - -# This proc is a wrapper around the btree_cursor_info command. The -# second argument is an open btree cursor returned by [btree_cursor]. -# The first argument is the name of an array variable that exists in -# the scope of the caller. If the third argument is non-zero, then -# info is returned for the page that lies $up entries upwards in the -# tree-structure. (i.e. $up==1 returns the parent page, $up==2 the -# grandparent etc.) -# -# The following entries in that array are filled in with information retrieved -# using [btree_cursor_info]: -# -# $arrayvar(page_no) = The page number -# $arrayvar(entry_no) = The entry number -# $arrayvar(page_entries) = Total number of entries on this page -# $arrayvar(cell_size) = Cell size (local payload + header) -# $arrayvar(page_freebytes) = Number of free bytes on this page -# $arrayvar(page_freeblocks) = Number of free blocks on the page -# $arrayvar(payload_bytes) = Total payload size (local + overflow) -# $arrayvar(header_bytes) = Header size in bytes -# $arrayvar(local_payload_bytes) = Local payload size -# $arrayvar(parent) = Parent page number -# -proc cursor_info {arrayvar csr {up 0}} { - upvar $arrayvar a - foreach [list a(page_no) \ - a(entry_no) \ - a(page_entries) \ - a(cell_size) \ - a(page_freebytes) \ - a(page_freeblocks) \ - a(payload_bytes) \ - a(header_bytes) \ - a(local_payload_bytes) \ - a(parent) \ - a(first_ovfl) ] [btree_cursor_info $csr $up] break -} - -# Determine the page-size of the database. This global variable is used -# throughout the script. -# -set pageSize [db eval {PRAGMA page_size}] - -# Find the root page of table or index to be analyzed. Also find out -# if the object is a table or an index. -# -if {$objname=="sqlite_master"} { - set rootpage 1 - set type table -} else { - db eval { - SELECT rootpage, type FROM sqlite_master - WHERE name=$objname - } break - if {![info exists rootpage]} { - puts stderr "no such table or index: $objname" - exit 1 - } - if {$type!="table" && $type!="index"} { - puts stderr "$objname is something other than a table or index" - exit 1 - } - if {![string is integer -strict $rootpage]} { - puts stderr "invalid root page for $objname: $rootpage" - exit 1 - } -} - -# The cursor $csr is pointing to an entry. Print out information -# about the page that $up levels above that page that contains -# the entry. If $up==0 use the page that contains the entry. -# -# If information about the page has been printed already, then -# this is a no-op. -# -proc page_info {csr up} { - global seen - cursor_info ci $csr $up - set pg $ci(page_no) - if {[info exists seen($pg)]} return - set seen($pg) 1 - - # Do parent pages first - # - if {$ci(parent)} { - page_info $csr [expr {$up+1}] - } - - # Find the depth of this page - # - set depth 1 - set i $up - while {$ci(parent)} { - incr i - incr depth - cursor_info ci $csr $i - } - - # print the results - # - puts [format {LEVEL %d: %6d} $depth $pg] -} - - - - -# Loop through the object and print out page numbers -# -set csr [btree_cursor $DB $rootpage 0] -for {btree_first $csr} {![btree_eof $csr]} {btree_next $csr} { - page_info $csr 0 - set i 1 - foreach pg [btree_ovfl_info $DB $csr] { - puts [format {OVFL %3d: %6d} $i $pg] - incr i - } -} -exit 0 diff --git a/lib/libsqlite3/tool/fuzzershell.c b/lib/libsqlite3/tool/fuzzershell.c deleted file mode 100644 index 6754a071e37..00000000000 --- a/lib/libsqlite3/tool/fuzzershell.c +++ /dev/null @@ -1,866 +0,0 @@ -/* -** 2015-04-17 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This is a utility program designed to aid running the SQLite library -** against an external fuzzer, such as American Fuzzy Lop (AFL) -** (http://lcamtuf.coredump.cx/afl/). Basically, this program reads -** SQL text from standard input and passes it through to SQLite for evaluation, -** just like the "sqlite3" command-line shell. Differences from the -** command-line shell: -** -** (1) The complex "dot-command" extensions are omitted. This -** prevents the fuzzer from discovering that it can run things -** like ".shell rm -rf ~" -** -** (2) The database is opened with the SQLITE_OPEN_MEMORY flag so that -** no disk I/O from the database is permitted. The ATTACH command -** with a filename still uses an in-memory database. -** -** (3) The main in-memory database can be initialized from a template -** disk database so that the fuzzer starts with a database containing -** content. -** -** (4) The eval() SQL function is added, allowing the fuzzer to do -** interesting recursive operations. -** -** (5) An error is raised if there is a memory leak. -** -** The input text can be divided into separate test cases using comments -** of the form: -** -** |****<...>****| -** -** where the "..." is arbitrary text. (Except the "|" should really be "/". -** "|" is used here to avoid compiler errors about nested comments.) -** A separate in-memory SQLite database is created to run each test case. -** This feature allows the "queue" of AFL to be captured into a single big -** file using a command like this: -** -** (for i in id:*; do echo '|****<'$i'>****|'; cat $i; done) >~/all-queue.txt -** -** (Once again, change the "|" to "/") Then all elements of the AFL queue -** can be run in a single go (for regression testing, for example) by typing: -** -** fuzzershell -f ~/all-queue.txt -** -** After running each chunk of SQL, the database connection is closed. The -** program aborts if the close fails or if there is any unfreed memory after -** the close. -** -** New test cases can be appended to all-queue.txt at any time. If redundant -** test cases are added, they can be eliminated by running: -** -** fuzzershell -f ~/all-queue.txt --unique-cases ~/unique-cases.txt -*/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <ctype.h> -#include "sqlite3.h" - -/* -** All global variables are gathered into the "g" singleton. -*/ -struct GlobalVars { - const char *zArgv0; /* Name of program */ - sqlite3_mem_methods sOrigMem; /* Original memory methods */ - sqlite3_mem_methods sOomMem; /* Memory methods with OOM simulator */ - int iOomCntdown; /* Memory fails on 1 to 0 transition */ - int nOomFault; /* Increments for each OOM fault */ - int bOomOnce; /* Fail just once if true */ - int bOomEnable; /* True to enable OOM simulation */ - int nOomBrkpt; /* Number of calls to oomFault() */ - char zTestName[100]; /* Name of current test */ -} g; - -/* -** Maximum number of iterations for an OOM test -*/ -#ifndef OOM_MAX -# define OOM_MAX 625 -#endif - -/* -** This routine is called when a simulated OOM occurs. It exists as a -** convenient place to set a debugger breakpoint. -*/ -static void oomFault(void){ - g.nOomBrkpt++; /* Prevent oomFault() from being optimized out */ -} - - -/* Versions of malloc() and realloc() that simulate OOM conditions */ -static void *oomMalloc(int nByte){ - if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){ - g.iOomCntdown--; - if( g.iOomCntdown==0 ){ - if( g.nOomFault==0 ) oomFault(); - g.nOomFault++; - if( !g.bOomOnce ) g.iOomCntdown = 1; - return 0; - } - } - return g.sOrigMem.xMalloc(nByte); -} -static void *oomRealloc(void *pOld, int nByte){ - if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){ - g.iOomCntdown--; - if( g.iOomCntdown==0 ){ - if( g.nOomFault==0 ) oomFault(); - g.nOomFault++; - if( !g.bOomOnce ) g.iOomCntdown = 1; - return 0; - } - } - return g.sOrigMem.xRealloc(pOld, nByte); -} - -/* -** Print an error message and abort in such a way to indicate to the -** fuzzer that this counts as a crash. -*/ -static void abendError(const char *zFormat, ...){ - va_list ap; - if( g.zTestName[0] ){ - fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName); - }else{ - fprintf(stderr, "%s: ", g.zArgv0); - } - va_start(ap, zFormat); - vfprintf(stderr, zFormat, ap); - va_end(ap); - fprintf(stderr, "\n"); - abort(); -} -/* -** Print an error message and quit, but not in a way that would look -** like a crash. -*/ -static void fatalError(const char *zFormat, ...){ - va_list ap; - if( g.zTestName[0] ){ - fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName); - }else{ - fprintf(stderr, "%s: ", g.zArgv0); - } - va_start(ap, zFormat); - vfprintf(stderr, zFormat, ap); - va_end(ap); - fprintf(stderr, "\n"); - exit(1); -} - -/* -** Evaluate some SQL. Abort if unable. -*/ -static void sqlexec(sqlite3 *db, const char *zFormat, ...){ - va_list ap; - char *zSql; - char *zErrMsg = 0; - int rc; - va_start(ap, zFormat); - zSql = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg); - if( rc ) abendError("failed sql [%s]: %s", zSql, zErrMsg); - sqlite3_free(zSql); -} - -/* -** This callback is invoked by sqlite3_log(). -*/ -static void shellLog(void *pNotUsed, int iErrCode, const char *zMsg){ - printf("LOG: (%d) %s\n", iErrCode, zMsg); - fflush(stdout); -} -static void shellLogNoop(void *pNotUsed, int iErrCode, const char *zMsg){ - return; -} - -/* -** This callback is invoked by sqlite3_exec() to return query results. -*/ -static int execCallback(void *NotUsed, int argc, char **argv, char **colv){ - int i; - static unsigned cnt = 0; - printf("ROW #%u:\n", ++cnt); - for(i=0; i<argc; i++){ - printf(" %s=", colv[i]); - if( argv[i] ){ - printf("[%s]\n", argv[i]); - }else{ - printf("NULL\n"); - } - } - fflush(stdout); - return 0; -} -static int execNoop(void *NotUsed, int argc, char **argv, char **colv){ - return 0; -} - -#ifndef SQLITE_OMIT_TRACE -/* -** This callback is invoked by sqlite3_trace() as each SQL statement -** starts. -*/ -static void traceCallback(void *NotUsed, const char *zMsg){ - printf("TRACE: %s\n", zMsg); - fflush(stdout); -} -static void traceNoop(void *NotUsed, const char *zMsg){ - return; -} -#endif - -/*************************************************************************** -** eval() implementation copied from ../ext/misc/eval.c -*/ -/* -** Structure used to accumulate the output -*/ -struct EvalResult { - char *z; /* Accumulated output */ - const char *zSep; /* Separator */ - int szSep; /* Size of the separator string */ - sqlite3_int64 nAlloc; /* Number of bytes allocated for z[] */ - sqlite3_int64 nUsed; /* Number of bytes of z[] actually used */ -}; - -/* -** Callback from sqlite_exec() for the eval() function. -*/ -static int callback(void *pCtx, int argc, char **argv, char **colnames){ - struct EvalResult *p = (struct EvalResult*)pCtx; - int i; - for(i=0; i<argc; i++){ - const char *z = argv[i] ? argv[i] : ""; - size_t sz = strlen(z); - if( (sqlite3_int64)sz+p->nUsed+p->szSep+1 > p->nAlloc ){ - char *zNew; - p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; - /* Using sqlite3_realloc64() would be better, but it is a recent - ** addition and will cause a segfault if loaded by an older version - ** of SQLite. */ - zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0; - if( zNew==0 ){ - sqlite3_free(p->z); - memset(p, 0, sizeof(*p)); - return 1; - } - p->z = zNew; - } - if( p->nUsed>0 ){ - memcpy(&p->z[p->nUsed], p->zSep, p->szSep); - p->nUsed += p->szSep; - } - memcpy(&p->z[p->nUsed], z, sz); - p->nUsed += sz; - } - return 0; -} - -/* -** Implementation of the eval(X) and eval(X,Y) SQL functions. -** -** Evaluate the SQL text in X. Return the results, using string -** Y as the separator. If Y is omitted, use a single space character. -*/ -static void sqlEvalFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const char *zSql; - sqlite3 *db; - char *zErr = 0; - int rc; - struct EvalResult x; - - memset(&x, 0, sizeof(x)); - x.zSep = " "; - zSql = (const char*)sqlite3_value_text(argv[0]); - if( zSql==0 ) return; - if( argc>1 ){ - x.zSep = (const char*)sqlite3_value_text(argv[1]); - if( x.zSep==0 ) return; - } - x.szSep = (int)strlen(x.zSep); - db = sqlite3_context_db_handle(context); - rc = sqlite3_exec(db, zSql, callback, &x, &zErr); - if( rc!=SQLITE_OK ){ - sqlite3_result_error(context, zErr, -1); - sqlite3_free(zErr); - }else if( x.zSep==0 ){ - sqlite3_result_error_nomem(context); - sqlite3_free(x.z); - }else{ - sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free); - } -} -/* End of the eval() implementation -******************************************************************************/ - -/* -** Print sketchy documentation for this utility program -*/ -static void showHelp(void){ - printf("Usage: %s [options] ?FILE...?\n", g.zArgv0); - printf( -"Read SQL text from FILE... (or from standard input if FILE... is omitted)\n" -"and then evaluate each block of SQL contained therein.\n" -"Options:\n" -" --autovacuum Enable AUTOVACUUM mode\n" -" --database FILE Use database FILE instead of an in-memory database\n" -" --disable-lookaside Turn off lookaside memory\n" -" --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n" -" --help Show this help text\n" -" --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n" -" --oom Run each test multiple times in a simulated OOM loop\n" -" --pagesize N Set the page size to N\n" -" --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n" -" -q Reduced output\n" -" --quiet Reduced output\n" -" --scratch N SZ Configure scratch memory for N slots of SZ bytes each\n" -" --unique-cases FILE Write all unique test cases to FILE\n" -" --utf16be Set text encoding to UTF-16BE\n" -" --utf16le Set text encoding to UTF-16LE\n" -" -v Increased output\n" -" --verbose Increased output\n" - ); -} - -/* -** Return the value of a hexadecimal digit. Return -1 if the input -** is not a hex digit. -*/ -static int hexDigitValue(char c){ - if( c>='0' && c<='9' ) return c - '0'; - if( c>='a' && c<='f' ) return c - 'a' + 10; - if( c>='A' && c<='F' ) return c - 'A' + 10; - return -1; -} - -/* -** Interpret zArg as an integer value, possibly with suffixes. -*/ -static int integerValue(const char *zArg){ - sqlite3_int64 v = 0; - static const struct { char *zSuffix; int iMult; } aMult[] = { - { "KiB", 1024 }, - { "MiB", 1024*1024 }, - { "GiB", 1024*1024*1024 }, - { "KB", 1000 }, - { "MB", 1000000 }, - { "GB", 1000000000 }, - { "K", 1000 }, - { "M", 1000000 }, - { "G", 1000000000 }, - }; - int i; - int isNeg = 0; - if( zArg[0]=='-' ){ - isNeg = 1; - zArg++; - }else if( zArg[0]=='+' ){ - zArg++; - } - if( zArg[0]=='0' && zArg[1]=='x' ){ - int x; - zArg += 2; - while( (x = hexDigitValue(zArg[0]))>=0 ){ - v = (v<<4) + x; - zArg++; - } - }else{ - while( isdigit(zArg[0]) ){ - v = v*10 + zArg[0] - '0'; - zArg++; - } - } - for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){ - if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){ - v *= aMult[i].iMult; - break; - } - } - if( v>0x7fffffff ) abendError("parameter too large - max 2147483648"); - return (int)(isNeg? -v : v); -} - -/* Return the current wall-clock time */ -static sqlite3_int64 timeOfDay(void){ - static sqlite3_vfs *clockVfs = 0; - sqlite3_int64 t; - if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); - if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){ - clockVfs->xCurrentTimeInt64(clockVfs, &t); - }else{ - double r; - clockVfs->xCurrentTime(clockVfs, &r); - t = (sqlite3_int64)(r*86400000.0); - } - return t; -} - -int main(int argc, char **argv){ - char *zIn = 0; /* Input text */ - int nAlloc = 0; /* Number of bytes allocated for zIn[] */ - int nIn = 0; /* Number of bytes of zIn[] used */ - size_t got; /* Bytes read from input */ - int rc = SQLITE_OK; /* Result codes from API functions */ - int i; /* Loop counter */ - int iNext; /* Next block of SQL */ - sqlite3 *db; /* Open database */ - char *zErrMsg = 0; /* Error message returned from sqlite3_exec() */ - const char *zEncoding = 0; /* --utf16be or --utf16le */ - int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ - int nLook = 0, szLook = 0; /* --lookaside configuration */ - int nPCache = 0, szPCache = 0;/* --pcache configuration */ - int nScratch = 0, szScratch=0;/* --scratch configuration */ - int pageSize = 0; /* Desired page size. 0 means default */ - void *pHeap = 0; /* Allocated heap space */ - void *pLook = 0; /* Allocated lookaside space */ - void *pPCache = 0; /* Allocated storage for pcache */ - void *pScratch = 0; /* Allocated storage for scratch */ - int doAutovac = 0; /* True for --autovacuum */ - char *zSql; /* SQL to run */ - char *zToFree = 0; /* Call sqlite3_free() on this afte running zSql */ - int verboseFlag = 0; /* --verbose or -v flag */ - int quietFlag = 0; /* --quiet or -q flag */ - int nTest = 0; /* Number of test cases run */ - int multiTest = 0; /* True if there will be multiple test cases */ - int lastPct = -1; /* Previous percentage done output */ - sqlite3 *dataDb = 0; /* Database holding compacted input data */ - sqlite3_stmt *pStmt = 0; /* Statement to insert testcase into dataDb */ - const char *zDataOut = 0; /* Write compacted data to this output file */ - int nHeader = 0; /* Bytes of header comment text on input file */ - int oomFlag = 0; /* --oom */ - int oomCnt = 0; /* Counter for the OOM loop */ - char zErrBuf[200]; /* Space for the error message */ - const char *zFailCode; /* Value of the TEST_FAILURE environment var */ - const char *zPrompt; /* Initial prompt when large-file fuzzing */ - int nInFile = 0; /* Number of input files to read */ - char **azInFile = 0; /* Array of input file names */ - int jj; /* Loop counter for azInFile[] */ - sqlite3_int64 iBegin; /* Start time for the whole program */ - sqlite3_int64 iStart, iEnd; /* Start and end-times for a test case */ - const char *zDbName = 0; /* Name of an on-disk database file to open */ - - iBegin = timeOfDay(); - sqlite3_shutdown(); - zFailCode = getenv("TEST_FAILURE"); - g.zArgv0 = argv[0]; - zPrompt = "<stdin>"; - for(i=1; i<argc; i++){ - const char *z = argv[i]; - if( z[0]=='-' ){ - z++; - if( z[0]=='-' ) z++; - if( strcmp(z,"autovacuum")==0 ){ - doAutovac = 1; - }else - if( strcmp(z,"database")==0 ){ - if( i>=argc-1 ) abendError("missing argument on %s\n", argv[i]); - zDbName = argv[i+1]; - i += 1; - }else - if( strcmp(z,"disable-lookaside")==0 ){ - nLook = 1; - szLook = 0; - }else - if( strcmp(z, "f")==0 && i+1<argc ){ - i++; - goto addNewInFile; - }else - if( strcmp(z,"heap")==0 ){ - if( i>=argc-2 ) abendError("missing arguments on %s\n", argv[i]); - nHeap = integerValue(argv[i+1]); - mnHeap = integerValue(argv[i+2]); - i += 2; - }else - if( strcmp(z,"help")==0 ){ - showHelp(); - return 0; - }else - if( strcmp(z,"lookaside")==0 ){ - if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); - nLook = integerValue(argv[i+1]); - szLook = integerValue(argv[i+2]); - i += 2; - }else - if( strcmp(z,"oom")==0 ){ - oomFlag = 1; - }else - if( strcmp(z,"pagesize")==0 ){ - if( i>=argc-1 ) abendError("missing argument on %s", argv[i]); - pageSize = integerValue(argv[++i]); - }else - if( strcmp(z,"pcache")==0 ){ - if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); - nPCache = integerValue(argv[i+1]); - szPCache = integerValue(argv[i+2]); - i += 2; - }else - if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){ - quietFlag = 1; - verboseFlag = 0; - }else - if( strcmp(z,"scratch")==0 ){ - if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); - nScratch = integerValue(argv[i+1]); - szScratch = integerValue(argv[i+2]); - i += 2; - }else - if( strcmp(z, "unique-cases")==0 ){ - if( i>=argc-1 ) abendError("missing arguments on %s", argv[i]); - if( zDataOut ) abendError("only one --minimize allowed"); - zDataOut = argv[++i]; - }else - if( strcmp(z,"utf16le")==0 ){ - zEncoding = "utf16le"; - }else - if( strcmp(z,"utf16be")==0 ){ - zEncoding = "utf16be"; - }else - if( strcmp(z,"verbose")==0 || strcmp(z,"v")==0 ){ - quietFlag = 0; - verboseFlag = 1; - }else - { - abendError("unknown option: %s", argv[i]); - } - }else{ - addNewInFile: - nInFile++; - azInFile = realloc(azInFile, sizeof(azInFile[0])*nInFile); - if( azInFile==0 ) abendError("out of memory"); - azInFile[nInFile-1] = argv[i]; - } - } - - /* Do global SQLite initialization */ - sqlite3_config(SQLITE_CONFIG_LOG, verboseFlag ? shellLog : shellLogNoop, 0); - if( nHeap>0 ){ - pHeap = malloc( nHeap ); - if( pHeap==0 ) fatalError("cannot allocate %d-byte heap\n", nHeap); - rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap); - if( rc ) abendError("heap configuration failed: %d\n", rc); - } - if( oomFlag ){ - sqlite3_config(SQLITE_CONFIG_GETMALLOC, &g.sOrigMem); - g.sOomMem = g.sOrigMem; - g.sOomMem.xMalloc = oomMalloc; - g.sOomMem.xRealloc = oomRealloc; - sqlite3_config(SQLITE_CONFIG_MALLOC, &g.sOomMem); - } - if( nLook>0 ){ - sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0); - if( szLook>0 ){ - pLook = malloc( nLook*szLook ); - if( pLook==0 ) fatalError("out of memory"); - } - } - if( nScratch>0 && szScratch>0 ){ - pScratch = malloc( nScratch*(sqlite3_int64)szScratch ); - if( pScratch==0 ) fatalError("cannot allocate %lld-byte scratch", - nScratch*(sqlite3_int64)szScratch); - rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, pScratch, szScratch, nScratch); - if( rc ) abendError("scratch configuration failed: %d\n", rc); - } - if( nPCache>0 && szPCache>0 ){ - pPCache = malloc( nPCache*(sqlite3_int64)szPCache ); - if( pPCache==0 ) fatalError("cannot allocate %lld-byte pcache", - nPCache*(sqlite3_int64)szPCache); - rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache); - if( rc ) abendError("pcache configuration failed: %d", rc); - } - - /* If the --unique-cases option was supplied, open the database that will - ** be used to gather unique test cases. - */ - if( zDataOut ){ - rc = sqlite3_open(":memory:", &dataDb); - if( rc ) abendError("cannot open :memory: database"); - rc = sqlite3_exec(dataDb, - "CREATE TABLE testcase(sql BLOB PRIMARY KEY, tm) WITHOUT ROWID;",0,0,0); - if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); - rc = sqlite3_prepare_v2(dataDb, - "INSERT OR IGNORE INTO testcase(sql,tm)VALUES(?1,?2)", - -1, &pStmt, 0); - if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); - } - - /* Initialize the input buffer used to hold SQL text */ - if( nInFile==0 ) nInFile = 1; - nAlloc = 1000; - zIn = malloc(nAlloc); - if( zIn==0 ) fatalError("out of memory"); - - /* Loop over all input files */ - for(jj=0; jj<nInFile; jj++){ - - /* Read the complete content of the next input file into zIn[] */ - FILE *in; - if( azInFile ){ - int j, k; - in = fopen(azInFile[jj],"rb"); - if( in==0 ){ - abendError("cannot open %s for reading", azInFile[jj]); - } - zPrompt = azInFile[jj]; - for(j=k=0; zPrompt[j]; j++) if( zPrompt[j]=='/' ) k = j+1; - zPrompt += k; - }else{ - in = stdin; - zPrompt = "<stdin>"; - } - while( !feof(in) ){ - got = fread(zIn+nIn, 1, nAlloc-nIn-1, in); - nIn += (int)got; - zIn[nIn] = 0; - if( got==0 ) break; - if( nAlloc - nIn - 1 < 100 ){ - nAlloc += nAlloc+1000; - zIn = realloc(zIn, nAlloc); - if( zIn==0 ) fatalError("out of memory"); - } - } - if( in!=stdin ) fclose(in); - lastPct = -1; - - /* Skip initial lines of the input file that begin with "#" */ - for(i=0; i<nIn; i=iNext+1){ - if( zIn[i]!='#' ) break; - for(iNext=i+1; iNext<nIn && zIn[iNext]!='\n'; iNext++){} - } - nHeader = i; - - /* Process all test cases contained within the input file. - */ - for(; i<nIn; i=iNext, nTest++, g.zTestName[0]=0){ - char cSaved; - if( strncmp(&zIn[i], "/****<",6)==0 ){ - char *z = strstr(&zIn[i], ">****/"); - if( z ){ - z += 6; - sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "%.*s", - (int)(z-&zIn[i]) - 12, &zIn[i+6]); - if( verboseFlag ){ - printf("%.*s\n", (int)(z-&zIn[i]), &zIn[i]); - fflush(stdout); - } - i += (int)(z-&zIn[i]); - multiTest = 1; - } - } - for(iNext=i; iNext<nIn && strncmp(&zIn[iNext],"/****<",6)!=0; iNext++){} - cSaved = zIn[iNext]; - zIn[iNext] = 0; - - - /* Print out the SQL of the next test case is --verbose is enabled - */ - zSql = &zIn[i]; - if( verboseFlag ){ - printf("INPUT (offset: %d, size: %d): [%s]\n", - i, (int)strlen(&zIn[i]), &zIn[i]); - }else if( multiTest && !quietFlag ){ - if( oomFlag ){ - printf("%s\n", g.zTestName); - }else{ - int pct = (10*iNext)/nIn; - if( pct!=lastPct ){ - if( lastPct<0 ) printf("%s:", zPrompt); - printf(" %d%%", pct*10); - lastPct = pct; - } - } - }else if( nInFile>1 ){ - printf("%s\n", zPrompt); - } - fflush(stdout); - - /* Run the next test case. Run it multiple times in --oom mode - */ - if( oomFlag ){ - oomCnt = g.iOomCntdown = 1; - g.nOomFault = 0; - g.bOomOnce = 1; - if( verboseFlag ){ - printf("Once.%d\n", oomCnt); - fflush(stdout); - } - }else{ - oomCnt = 0; - } - do{ - if( zDbName ){ - rc = sqlite3_open_v2(zDbName, &db, SQLITE_OPEN_READWRITE, 0); - if( rc!=SQLITE_OK ){ - abendError("Cannot open database file %s", zDbName); - } - }else{ - rc = sqlite3_open_v2( - "main.db", &db, - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY, - 0); - if( rc!=SQLITE_OK ){ - abendError("Unable to open the in-memory database"); - } - } - if( pLook ){ - rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE,pLook,szLook,nLook); - if( rc!=SQLITE_OK ) abendError("lookaside configuration filed: %d", rc); - } - #ifndef SQLITE_OMIT_TRACE - sqlite3_trace(db, verboseFlag ? traceCallback : traceNoop, 0); - #endif - sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0); - sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0); - sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 1000000); - if( zEncoding ) sqlexec(db, "PRAGMA encoding=%s", zEncoding); - if( pageSize ) sqlexec(db, "PRAGMA pagesize=%d", pageSize); - if( doAutovac ) sqlexec(db, "PRAGMA auto_vacuum=FULL"); - iStart = timeOfDay(); - g.bOomEnable = 1; - if( verboseFlag ){ - zErrMsg = 0; - rc = sqlite3_exec(db, zSql, execCallback, 0, &zErrMsg); - if( zErrMsg ){ - sqlite3_snprintf(sizeof(zErrBuf),zErrBuf,"%z", zErrMsg); - zErrMsg = 0; - } - }else { - rc = sqlite3_exec(db, zSql, execNoop, 0, 0); - } - g.bOomEnable = 0; - iEnd = timeOfDay(); - rc = sqlite3_close(db); - if( rc ){ - abendError("sqlite3_close() failed with rc=%d", rc); - } - if( !zDataOut && sqlite3_memory_used()>0 ){ - abendError("memory in use after close: %lld bytes",sqlite3_memory_used()); - } - if( oomFlag ){ - /* Limit the number of iterations of the OOM loop to OOM_MAX. If the - ** first pass (single failure) exceeds 2/3rds of OOM_MAX this skip the - ** second pass (continuous failure after first) completely. */ - if( g.nOomFault==0 || oomCnt>OOM_MAX ){ - if( g.bOomOnce && oomCnt<=(OOM_MAX*2/3) ){ - oomCnt = g.iOomCntdown = 1; - g.bOomOnce = 0; - }else{ - oomCnt = 0; - } - }else{ - g.iOomCntdown = ++oomCnt; - g.nOomFault = 0; - } - if( oomCnt ){ - if( verboseFlag ){ - printf("%s.%d\n", g.bOomOnce ? "Once" : "Multi", oomCnt); - fflush(stdout); - } - nTest++; - } - } - }while( oomCnt>0 ); - - /* Store unique test cases in the in the dataDb database if the - ** --unique-cases flag is present - */ - if( zDataOut ){ - sqlite3_bind_blob(pStmt, 1, &zIn[i], iNext-i, SQLITE_STATIC); - sqlite3_bind_int64(pStmt, 2, iEnd - iStart); - rc = sqlite3_step(pStmt); - if( rc!=SQLITE_DONE ) abendError("%s", sqlite3_errmsg(dataDb)); - sqlite3_reset(pStmt); - } - - /* Free the SQL from the current test case - */ - if( zToFree ){ - sqlite3_free(zToFree); - zToFree = 0; - } - zIn[iNext] = cSaved; - - /* Show test-case results in --verbose mode - */ - if( verboseFlag ){ - printf("RESULT-CODE: %d\n", rc); - if( zErrMsg ){ - printf("ERROR-MSG: [%s]\n", zErrBuf); - } - fflush(stdout); - } - - /* Simulate an error if the TEST_FAILURE environment variable is "5". - ** This is used to verify that automated test script really do spot - ** errors that occur in this test program. - */ - if( zFailCode ){ - if( zFailCode[0]=='5' && zFailCode[1]==0 ){ - abendError("simulated failure"); - }else if( zFailCode[0]!=0 ){ - /* If TEST_FAILURE is something other than 5, just exit the test - ** early */ - printf("\nExit early due to TEST_FAILURE being set"); - break; - } - } - } - if( !verboseFlag && multiTest && !quietFlag && !oomFlag ) printf("\n"); - } - - /* Report total number of tests run - */ - if( nTest>1 && !quietFlag ){ - sqlite3_int64 iElapse = timeOfDay() - iBegin; - printf("%s: 0 errors out of %d tests in %d.%03d seconds\nSQLite %s %s\n", - g.zArgv0, nTest, (int)(iElapse/1000), (int)(iElapse%1000), - sqlite3_libversion(), sqlite3_sourceid()); - } - - /* Write the unique test cases if the --unique-cases flag was used - */ - if( zDataOut ){ - int n = 0; - FILE *out = fopen(zDataOut, "wb"); - if( out==0 ) abendError("cannot open %s for writing", zDataOut); - if( nHeader>0 ) fwrite(zIn, nHeader, 1, out); - sqlite3_finalize(pStmt); - rc = sqlite3_prepare_v2(dataDb, "SELECT sql, tm FROM testcase ORDER BY tm, sql", - -1, &pStmt, 0); - if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - fprintf(out,"/****<%d:%dms>****/", ++n, sqlite3_column_int(pStmt,1)); - fwrite(sqlite3_column_blob(pStmt,0),sqlite3_column_bytes(pStmt,0),1,out); - } - fclose(out); - sqlite3_finalize(pStmt); - sqlite3_close(dataDb); - } - - /* Clean up and exit. - */ - free(azInFile); - free(zIn); - free(pHeap); - free(pLook); - free(pScratch); - free(pPCache); - return 0; -} diff --git a/lib/libsqlite3/tool/genfkey.README b/lib/libsqlite3/tool/genfkey.README deleted file mode 100644 index 57cdff87f8b..00000000000 --- a/lib/libsqlite3/tool/genfkey.README +++ /dev/null @@ -1,137 +0,0 @@ - -OVERVIEW - - The SQLite library is capable of parsing SQL foreign key constraints - supplied as part of CREATE TABLE statements, but it does not actually - implement them. However, most of the features of foreign keys may be - implemented using SQL triggers, which SQLite does support. This text - file describes a feature of the SQLite shell tool (sqlite3) that - extracts foreign key definitions from an existing SQLite database and - creates the set of CREATE TRIGGER statements required to implement - the foreign key constraints. - -CAPABILITIES - - An SQL foreign key is a constraint that requires that each row in - the "child" table corresponds to a row in the "parent" table. For - example, the following schema: - - CREATE TABLE parent(a, b, c, PRIMARY KEY(a, b)); - CREATE TABLE child(d, e, f, FOREIGN KEY(d, e) REFERENCES parent(a, b)); - - implies that for each row in table "child", there must be a row in - "parent" for which the expression (child.d==parent.a AND child.e==parent.b) - is true. The columns in the parent table are required to be either the - primary key columns or subject to a UNIQUE constraint. There is no such - requirement for the columns of the child table. - - At this time, all foreign keys are implemented as if they were - "MATCH NONE", even if the declaration specified "MATCH PARTIAL" or - "MATCH FULL". "MATCH NONE" means that if any of the key columns in - the child table are NULL, then there is no requirement for a corresponding - row in the parent table. So, taking this into account, the expression that - must be true for every row of the child table in the above example is - actually: - - (child.d IS NULL) OR - (child.e IS NULL) OR - (child.d==parent.a AND child.e==parent.b) - - Attempting to insert or update a row in the child table so that the - affected row violates this constraint results in an exception being - thrown. - - The effect of attempting to delete or update a row in the parent table - so that the constraint becomes untrue for one or more rows in the child - table depends on the "ON DELETE" or "ON UPDATE" actions specified as - part of the foreign key definition, respectively. Three different actions - are supported: "RESTRICT" (the default), "CASCADE" and "SET NULL". SQLite - will also parse the "SET DEFAULT" action, but this is not implemented - and "RESTRICT" is used instead. - - RESTRICT: Attempting to update or delete a row in the parent table so - that the constraint becomes untrue for one or more rows in - the child table is not allowed. An exception is thrown. - - CASCADE: Instead of throwing an exception, all corresponding child table - rows are either deleted (if the parent row is being deleted) - or updated to match the new parent key values (if the parent - row is being updated). - - SET NULL: Instead of throwing an exception, the foreign key fields of - all corresponding child table rows are set to NULL. - -LIMITATIONS - - Apart from those limitiations described above: - - * Implicit mapping to composite primary keys is not supported. If - a parent table has a composite primary key, then any child table - that refers to it must explicitly map each column. For example, given - the following definition of table "parent": - - CREATE TABLE parent(a, b, c, PRIMARY KEY(a, b)); - - only the first of the following two definitions of table "child" - is supported: - - CREATE TABLE child(d, e, f, FOREIGN KEY(d, e) REFERENCES parent(a, b)); - CREATE TABLE child(d, e, f, FOREIGN KEY(d, e) REFERENCES parent); - - An implicit reference to a composite primary key is detected as an - error when the program is run (see below). - - * SQLite does not support recursive triggers, and therefore this program - does not support recursive CASCADE or SET NULL foreign key - relationships. If the parent and the child tables of a CASCADE or - SET NULL foreign key are the same table, the generated triggers will - malfunction. This is also true if the recursive foreign key constraint - is indirect (for example if table A references table B which references - table A with a CASCADE or SET NULL foreign key constraint). - - Recursive CASCADE or SET NULL foreign key relationships are *not* - detected as errors when the program is run. Buyer beware. - -USAGE - - The functionality is accessed through an sqlite3 shell tool "dot-command": - - .genfkey ?--no-drop? ?--ignore-errors? ?--exec? - - When this command is run, it first checks the schema of the open SQLite - database for foreign key related errors or inconsistencies. For example, - a foreign key that refers to a parent table that does not exist, or - a foreign key that refers to columns in a parent table that are not - guaranteed to be unique. If such errors are found and the --ignore-errors - option was not present, a message for each one is printed to stderr and - no further processing takes place. - - If errors are found and the --ignore-errors option is passed, then - no error messages are printed. No "CREATE TRIGGER" statements are generated - for foriegn-key definitions that contained errors, they are silently - ignored by subsequent processing. - - All triggers generated by this command have names that match the pattern - "genfkey*". Unless the --no-drop option is specified, then the program - also generates a "DROP TRIGGER" statement for each trigger that exists - in the database with a name that matches this pattern. This allows the - program to be used to upgrade a database schema for which foreign key - triggers have already been installed (i.e. after new tables are created - or existing tables dropped). - - Finally, a series of SQL trigger definitions (CREATE TRIGGER statements) - that implement the foreign key constraints found in the database schema are - generated. - - If the --exec option was passed, then all generated SQL is immediately - executed on the database. Otherwise, the generated SQL strings are output - in the same way as the results of SELECT queries are. Normally, this means - they will be printed to stdout, but this can be configured using other - dot-commands (i.e. ".output"). - - The simplest way to activate the foriegn key definitions in a database - is simply to open it using the shell tool and enter the command - ".genfkey --exec": - - sqlite> .genfkey --exec - diff --git a/lib/libsqlite3/tool/genfkey.test b/lib/libsqlite3/tool/genfkey.test deleted file mode 100644 index 3c0073e953d..00000000000 --- a/lib/libsqlite3/tool/genfkey.test +++ /dev/null @@ -1,354 +0,0 @@ - -package require sqlite3 - -proc do_test {name cmd expected} { - puts -nonewline "$name ..." - set res [uplevel $cmd] - if {$res eq $expected} { - puts Ok - } else { - puts Error - puts " Got: $res" - puts " Expected: $expected" - exit - } -} - -proc execsql {sql} { - uplevel [list db eval $sql] -} - -proc catchsql {sql} { - set rc [catch {uplevel [list db eval $sql]} msg] - list $rc $msg -} - -file delete -force test.db test.db.journal -sqlite3 db test.db - -# The following tests - genfkey-1.* - test RESTRICT foreign keys. -# -do_test genfkey-1.1 { - execsql { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c)); - CREATE TABLE t2(e REFERENCES t1, f); - CREATE TABLE t3(g, h, i, FOREIGN KEY (h, i) REFERENCES t1(b, c)); - } -} {} -do_test genfkey-1.2 { - execsql [exec ./sqlite3 test.db .genfkey] -} {} -do_test genfkey-1.3 { - catchsql { INSERT INTO t2 VALUES(1, 2) } -} {1 {constraint failed}} -do_test genfkey-1.4 { - execsql { - INSERT INTO t1 VALUES(1, 2, 3); - INSERT INTO t2 VALUES(1, 2); - } -} {} -do_test genfkey-1.5 { - execsql { INSERT INTO t2 VALUES(NULL, 3) } -} {} -do_test genfkey-1.6 { - catchsql { UPDATE t2 SET e = 5 WHERE e IS NULL } -} {1 {constraint failed}} -do_test genfkey-1.7 { - execsql { UPDATE t2 SET e = 1 WHERE e IS NULL } -} {} -do_test genfkey-1.8 { - execsql { UPDATE t2 SET e = NULL WHERE f = 3 } -} {} -do_test genfkey-1.9 { - catchsql { UPDATE t1 SET a = 10 } -} {1 {constraint failed}} -do_test genfkey-1.9a { - catchsql { UPDATE t1 SET a = NULL } -} {1 {datatype mismatch}} -do_test genfkey-1.10 { - catchsql { DELETE FROM t1 } -} {1 {constraint failed}} -do_test genfkey-1.11 { - execsql { UPDATE t2 SET e = NULL } -} {} -do_test genfkey-1.12 { - execsql { - UPDATE t1 SET a = 10 ; - DELETE FROM t1; - DELETE FROM t2; - } -} {} - -do_test genfkey-1.13 { - execsql { - INSERT INTO t3 VALUES(1, NULL, NULL); - INSERT INTO t3 VALUES(1, 2, NULL); - INSERT INTO t3 VALUES(1, NULL, 3); - } -} {} -do_test genfkey-1.14 { - catchsql { INSERT INTO t3 VALUES(3, 1, 4) } -} {1 {constraint failed}} -do_test genfkey-1.15 { - execsql { - INSERT INTO t1 VALUES(1, 1, 4); - INSERT INTO t3 VALUES(3, 1, 4); - } -} {} -do_test genfkey-1.16 { - catchsql { DELETE FROM t1 } -} {1 {constraint failed}} -do_test genfkey-1.17 { - catchsql { UPDATE t1 SET b = 10} -} {1 {constraint failed}} -do_test genfkey-1.18 { - execsql { UPDATE t1 SET a = 10} -} {} -do_test genfkey-1.19 { - catchsql { UPDATE t3 SET h = 'hello' WHERE i = 3} -} {1 {constraint failed}} - -do_test genfkey-1.X { - execsql { - DROP TABLE t1; - DROP TABLE t2; - DROP TABLE t3; - } -} {} - -# The following tests - genfkey-2.* - test CASCADE foreign keys. -# -do_test genfkey-2.1 { - execsql { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c)); - CREATE TABLE t2(e REFERENCES t1 ON UPDATE CASCADE ON DELETE CASCADE, f); - CREATE TABLE t3(g, h, i, - FOREIGN KEY (h, i) - REFERENCES t1(b, c) ON UPDATE CASCADE ON DELETE CASCADE - ); - } -} {} -do_test genfkey-2.2 { - execsql [exec ./sqlite3 test.db .genfkey] -} {} -do_test genfkey-2.3 { - execsql { - INSERT INTO t1 VALUES(1, 2, 3); - INSERT INTO t1 VALUES(4, 5, 6); - INSERT INTO t2 VALUES(1, 'one'); - INSERT INTO t2 VALUES(4, 'four'); - } -} {} -do_test genfkey-2.4 { - execsql { - UPDATE t1 SET a = 2 WHERE a = 1; - SELECT * FROM t2; - } -} {2 one 4 four} -do_test genfkey-2.5 { - execsql { - DELETE FROM t1 WHERE a = 4; - SELECT * FROM t2; - } -} {2 one} -do_test genfkey-2.6 { - execsql { - INSERT INTO t3 VALUES('hello', 2, 3); - UPDATE t1 SET c = 2; - SELECT * FROM t3; - } -} {hello 2 2} -do_test genfkey-2.7 { - execsql { - DELETE FROM t1; - SELECT * FROM t3; - } -} {} -do_test genfkey-2.X { - execsql { - DROP TABLE t1; - DROP TABLE t2; - DROP TABLE t3; - } -} {} - - -# The following tests - genfkey-3.* - test SET NULL foreign keys. -# -do_test genfkey-3.1 { - execsql { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(c, b)); - CREATE TABLE t2(e REFERENCES t1 ON UPDATE SET NULL ON DELETE SET NULL, f); - CREATE TABLE t3(g, h, i, - FOREIGN KEY (h, i) - REFERENCES t1(b, c) ON UPDATE SET NULL ON DELETE SET NULL - ); - } -} {} -do_test genfkey-3.2 { - execsql [exec ./sqlite3 test.db .genfkey] -} {} -do_test genfkey-3.3 { - execsql { - INSERT INTO t1 VALUES(1, 2, 3); - INSERT INTO t1 VALUES(4, 5, 6); - INSERT INTO t2 VALUES(1, 'one'); - INSERT INTO t2 VALUES(4, 'four'); - } -} {} -do_test genfkey-3.4 { - execsql { - UPDATE t1 SET a = 2 WHERE a = 1; - SELECT * FROM t2; - } -} {{} one 4 four} -do_test genfkey-3.5 { - execsql { - DELETE FROM t1 WHERE a = 4; - SELECT * FROM t2; - } -} {{} one {} four} -do_test genfkey-3.6 { - execsql { - INSERT INTO t3 VALUES('hello', 2, 3); - UPDATE t1 SET c = 2; - SELECT * FROM t3; - } -} {hello {} {}} -do_test genfkey-2.7 { - execsql { - UPDATE t3 SET h = 2, i = 2; - DELETE FROM t1; - SELECT * FROM t3; - } -} {hello {} {}} -do_test genfkey-3.X { - execsql { - DROP TABLE t1; - DROP TABLE t2; - DROP TABLE t3; - } -} {} - -# The following tests - genfkey-4.* - test that errors in the schema -# are detected correctly. -# -do_test genfkey-4.1 { - execsql { - CREATE TABLE t1(a REFERENCES nosuchtable, b); - CREATE TABLE t2(a REFERENCES t1, b); - - CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b)); - CREATE TABLE t4(a, b, c, FOREIGN KEY(c, b) REFERENCES t3); - - CREATE TABLE t5(a REFERENCES t4(d), b, c); - CREATE TABLE t6(a REFERENCES t4(a), b, c); - CREATE TABLE t7(a REFERENCES t3(a), b, c); - CREATE TABLE t8(a REFERENCES nosuchtable(a), b, c); - } -} {} - -do_test genfkey-4.X { - set rc [catch {exec ./sqlite3 test.db .genfkey} msg] - list $rc $msg -} "1 {[string trim { -Error in table t5: foreign key columns do not exist -Error in table t8: foreign key columns do not exist -Error in table t4: implicit mapping to composite primary key -Error in table t1: implicit mapping to non-existant primary key -Error in table t2: implicit mapping to non-existant primary key -Error in table t6: foreign key is not unique -Error in table t7: foreign key is not unique -}]}" - -# Test that ticket #3800 has been resolved. -# -do_test genfkey-5.1 { - execsql { - DROP TABLE t1; DROP TABLE t2; DROP TABLE t3; - DROP TABLE t4; DROP TABLE t5; DROP TABLE t6; - DROP TABLE t7; DROP TABLE t8; - } -} {} -do_test genfkey-5.2 { - execsql { - CREATE TABLE "t.3" (c1 PRIMARY KEY); - CREATE TABLE t13 (c1, foreign key(c1) references "t.3"(c1)); - } -} {} -do_test genfkey-5.3 { - set rc [catch {exec ./sqlite3 test.db .genfkey} msg] -} {0} -do_test genfkey-5.4 { - db eval $msg -} {} -do_test genfkey-5.5 { - catchsql { INSERT INTO t13 VALUES(1) } -} {1 {constraint failed}} -do_test genfkey-5.5 { - catchsql { - INSERT INTO "t.3" VALUES(1); - INSERT INTO t13 VALUES(1); - } -} {0 {}} - -# Test also column names that require quoting. -do_test genfkey-6.1 { - execsql { - DROP TABLE "t.3"; - DROP TABLE t13; - CREATE TABLE p( - "a.1 first", "b.2 second", - UNIQUE("a.1 first", "b.2 second") - ); - CREATE TABLE c( - "c.1 I", "d.2 II", - FOREIGN KEY("c.1 I", "d.2 II") - REFERENCES p("a.1 first", "b.2 second") - ON UPDATE CASCADE ON DELETE CASCADE - ); - } -} {} -do_test genfkey-6.2 { - set rc [catch {exec ./sqlite3 test.db .genfkey} msg] -} {0} -do_test genfkey-6.3 { - execsql $msg - execsql { - INSERT INTO p VALUES('A', 'B'); - INSERT INTO p VALUES('C', 'D'); - INSERT INTO c VALUES('A', 'B'); - INSERT INTO c VALUES('C', 'D'); - UPDATE p SET "a.1 first" = 'X' WHERE rowid = 1; - DELETE FROM p WHERE rowid = 2; - } - execsql { SELECT * FROM c } -} {X B} - -do_test genfkey-6.4 { - execsql { - DROP TABLE p; - DROP TABLE c; - CREATE TABLE parent("a.1", PRIMARY KEY("a.1")); - CREATE TABLE child("b.2", FOREIGN KEY("b.2") REFERENCES parent("a.1")); - } - set rc [catch {exec ./sqlite3 test.db .genfkey} msg] -} {0} -do_test genfkey-6.5 { - execsql $msg - execsql { - INSERT INTO parent VALUES(1); - INSERT INTO child VALUES(1); - } - catchsql { UPDATE parent SET "a.1"=0 } -} {1 {constraint failed}} -do_test genfkey-6.6 { - catchsql { UPDATE child SET "b.2"=7 } -} {1 {constraint failed}} -do_test genfkey-6.7 { - execsql { - SELECT * FROM parent; - SELECT * FROM child; - } -} {1 1} - diff --git a/lib/libsqlite3/tool/getlock.c b/lib/libsqlite3/tool/getlock.c deleted file mode 100644 index 7eff04d7f97..00000000000 --- a/lib/libsqlite3/tool/getlock.c +++ /dev/null @@ -1,134 +0,0 @@ -/* -** This utility program looks at an SQLite database and determines whether -** or not it is locked, the kind of lock, and who is holding this lock. -** -** This only works on unix when the posix advisory locking method is used -** (which is the default on unix) and when the PENDING_BYTE is in its -** usual place. -*/ -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> - -static void usage(const char *argv0){ - fprintf(stderr, "Usage: %s database\n", argv0); - exit(1); -} - -/* Check for a conflicting lock. If one is found, print an this -** on standard output using the format string given and return 1. -** If there are no conflicting locks, return 0. -*/ -static int isLocked( - int h, /* File descriptor to check */ - int type, /* F_RDLCK or F_WRLCK */ - unsigned int iOfst, /* First byte of the lock */ - unsigned int iCnt, /* Number of bytes in the lock range */ - const char *zType /* Type of lock */ -){ - struct flock lk; - - memset(&lk, 0, sizeof(lk)); - lk.l_type = type; - lk.l_whence = SEEK_SET; - lk.l_start = iOfst; - lk.l_len = iCnt; - if( fcntl(h, F_GETLK, &lk)==(-1) ){ - fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno); - exit(1); - } - if( lk.l_type==F_UNLCK ) return 0; - printf("%s lock held by %d\n", zType, (int)lk.l_pid); - return 1; -} - -/* -** Location of locking bytes in the database file -*/ -#define PENDING_BYTE (0x40000000) -#define RESERVED_BYTE (PENDING_BYTE+1) -#define SHARED_FIRST (PENDING_BYTE+2) -#define SHARED_SIZE 510 - -/* -** Lock locations for shared-memory locks used by WAL mode. -*/ -#define SHM_BASE 120 -#define SHM_WRITE SHM_BASE -#define SHM_CHECKPOINT (SHM_BASE+1) -#define SHM_RECOVER (SHM_BASE+2) -#define SHM_READ_FIRST (SHM_BASE+3) -#define SHM_READ_SIZE 5 - - -int main(int argc, char **argv){ - int hDb; /* File descriptor for the open database file */ - int hShm; /* File descriptor for WAL shared-memory file */ - char *zShm; /* Name of the shared-memory file for WAL mode */ - ssize_t got; /* Bytes read from header */ - int isWal; /* True if in WAL mode */ - int nName; /* Length of filename */ - unsigned char aHdr[100]; /* Database header */ - int nLock = 0; /* Number of locks held */ - int i; /* Loop counter */ - - if( argc!=2 ) usage(argv[0]); - hDb = open(argv[1], O_RDONLY, 0); - if( hDb<0 ){ - fprintf(stderr, "cannot open %s\n", argv[1]); - return 1; - } - - /* Make sure we are dealing with an database file */ - got = read(hDb, aHdr, 100); - if( got!=100 || memcmp(aHdr, "SQLite format 3",16)!=0 ){ - fprintf(stderr, "not an SQLite database: %s\n", argv[1]); - exit(1); - } - - /* First check for an exclusive lock */ - if( isLocked(hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE") ){ - return 0; - } - isWal = aHdr[18]==2; - if( isWal==0 ){ - /* Rollback mode */ - if( isLocked(hDb, F_RDLCK, PENDING_BYTE, 1, "PENDING") ) return 0; - if( isLocked(hDb, F_RDLCK, RESERVED_BYTE, 1, "RESERVED") ) return 0; - if( isLocked(hDb, F_WRLCK, SHARED_FIRST, SHARED_SIZE, "SHARED") ){ - return 0; - } - }else{ - /* WAL mode */ - nName = (int)strlen(argv[1]); - zShm = malloc( nName + 100 ); - if( zShm==0 ){ - fprintf(stderr, "out of memory\n"); - exit(1); - } - memcpy(zShm, argv[1], nName); - memcpy(&zShm[nName], "-shm", 5); - hShm = open(zShm, O_RDONLY, 0); - if( hShm<0 ){ - fprintf(stderr, "cannot open %s\n", zShm); - return 1; - } - if( isLocked(hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ){ - return 0; - } - nLock += isLocked(hShm, F_RDLCK, SHM_CHECKPOINT, 1, "WAL-CHECKPOINT"); - nLock += isLocked(hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE"); - for(i=0; i<SHM_READ_SIZE; i++){ - nLock += isLocked(hShm, F_WRLCK, SHM_READ_FIRST+i, 1, "WAL-READ"); - } - } - if( nLock==0 ){ - printf("file is not locked\n"); - } - return 0; -} diff --git a/lib/libsqlite3/tool/lemon.c b/lib/libsqlite3/tool/lemon.c deleted file mode 100644 index 2e8054b5ccb..00000000000 --- a/lib/libsqlite3/tool/lemon.c +++ /dev/null @@ -1,5171 +0,0 @@ -/* -** This file contains all sources (including headers) to the LEMON -** LALR(1) parser generator. The sources have been combined into a -** single file to make it easy to include LEMON in the source tree -** and Makefile of another program. -** -** The author of this program disclaims copyright. -*/ -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <ctype.h> -#include <stdlib.h> -#include <assert.h> - -#ifndef __WIN32__ -# if defined(_WIN32) || defined(WIN32) -# define __WIN32__ -# endif -#endif - -#ifdef __WIN32__ -#ifdef __cplusplus -extern "C" { -#endif -extern int access(const char *path, int mode); -#ifdef __cplusplus -} -#endif -#else -#include <unistd.h> -#endif - -/* #define PRIVATE static */ -#define PRIVATE - -#ifdef TEST -#define MAXRHS 5 /* Set low to exercise exception code */ -#else -#define MAXRHS 1000 -#endif - -static int showPrecedenceConflict = 0; -static char *msort(char*,char**,int(*)(const char*,const char*)); - -/* -** Compilers are getting increasingly pedantic about type conversions -** as C evolves ever closer to Ada.... To work around the latest problems -** we have to define the following variant of strlen(). -*/ -#define lemonStrlen(X) ((int)strlen(X)) - -/* -** Compilers are starting to complain about the use of sprintf() and strcpy(), -** saying they are unsafe. So we define our own versions of those routines too. -** -** There are three routines here: lemon_sprintf(), lemon_vsprintf(), and -** lemon_addtext(). The first two are replacements for sprintf() and vsprintf(). -** The third is a helper routine for vsnprintf() that adds texts to the end of a -** buffer, making sure the buffer is always zero-terminated. -** -** The string formatter is a minimal subset of stdlib sprintf() supporting only -** a few simply conversions: -** -** %d -** %s -** %.*s -** -*/ -static void lemon_addtext( - char *zBuf, /* The buffer to which text is added */ - int *pnUsed, /* Slots of the buffer used so far */ - const char *zIn, /* Text to add */ - int nIn, /* Bytes of text to add. -1 to use strlen() */ - int iWidth /* Field width. Negative to left justify */ -){ - if( nIn<0 ) for(nIn=0; zIn[nIn]; nIn++){} - while( iWidth>nIn ){ zBuf[(*pnUsed)++] = ' '; iWidth--; } - if( nIn==0 ) return; - memcpy(&zBuf[*pnUsed], zIn, nIn); - *pnUsed += nIn; - while( (-iWidth)>nIn ){ zBuf[(*pnUsed)++] = ' '; iWidth++; } - zBuf[*pnUsed] = 0; -} -static int lemon_vsprintf(char *str, const char *zFormat, va_list ap){ - int i, j, k, c; - int nUsed = 0; - const char *z; - char zTemp[50]; - str[0] = 0; - for(i=j=0; (c = zFormat[i])!=0; i++){ - if( c=='%' ){ - int iWidth = 0; - lemon_addtext(str, &nUsed, &zFormat[j], i-j, 0); - c = zFormat[++i]; - if( isdigit(c) || (c=='-' && isdigit(zFormat[i+1])) ){ - if( c=='-' ) i++; - while( isdigit(zFormat[i]) ) iWidth = iWidth*10 + zFormat[i++] - '0'; - if( c=='-' ) iWidth = -iWidth; - c = zFormat[i]; - } - if( c=='d' ){ - int v = va_arg(ap, int); - if( v<0 ){ - lemon_addtext(str, &nUsed, "-", 1, iWidth); - v = -v; - }else if( v==0 ){ - lemon_addtext(str, &nUsed, "0", 1, iWidth); - } - k = 0; - while( v>0 ){ - k++; - zTemp[sizeof(zTemp)-k] = (v%10) + '0'; - v /= 10; - } - lemon_addtext(str, &nUsed, &zTemp[sizeof(zTemp)-k], k, iWidth); - }else if( c=='s' ){ - z = va_arg(ap, const char*); - lemon_addtext(str, &nUsed, z, -1, iWidth); - }else if( c=='.' && memcmp(&zFormat[i], ".*s", 3)==0 ){ - i += 2; - k = va_arg(ap, int); - z = va_arg(ap, const char*); - lemon_addtext(str, &nUsed, z, k, iWidth); - }else if( c=='%' ){ - lemon_addtext(str, &nUsed, "%", 1, 0); - }else{ - fprintf(stderr, "illegal format\n"); - exit(1); - } - j = i+1; - } - } - lemon_addtext(str, &nUsed, &zFormat[j], i-j, 0); - return nUsed; -} -static int lemon_sprintf(char *str, const char *format, ...){ - va_list ap; - int rc; - va_start(ap, format); - rc = lemon_vsprintf(str, format, ap); - va_end(ap); - return rc; -} -static void lemon_strcpy(char *dest, const char *src){ - while( (*(dest++) = *(src++))!=0 ){} -} -static void lemon_strcat(char *dest, const char *src){ - while( *dest ) dest++; - lemon_strcpy(dest, src); -} - - -/* a few forward declarations... */ -struct rule; -struct lemon; -struct action; - -static struct action *Action_new(void); -static struct action *Action_sort(struct action *); - -/********** From the file "build.h" ************************************/ -void FindRulePrecedences(); -void FindFirstSets(); -void FindStates(); -void FindLinks(); -void FindFollowSets(); -void FindActions(); - -/********* From the file "configlist.h" *********************************/ -void Configlist_init(void); -struct config *Configlist_add(struct rule *, int); -struct config *Configlist_addbasis(struct rule *, int); -void Configlist_closure(struct lemon *); -void Configlist_sort(void); -void Configlist_sortbasis(void); -struct config *Configlist_return(void); -struct config *Configlist_basis(void); -void Configlist_eat(struct config *); -void Configlist_reset(void); - -/********* From the file "error.h" ***************************************/ -void ErrorMsg(const char *, int,const char *, ...); - -/****** From the file "option.h" ******************************************/ -enum option_type { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR, - OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR}; -struct s_options { - enum option_type type; - const char *label; - char *arg; - const char *message; -}; -int OptInit(char**,struct s_options*,FILE*); -int OptNArgs(void); -char *OptArg(int); -void OptErr(int); -void OptPrint(void); - -/******** From the file "parse.h" *****************************************/ -void Parse(struct lemon *lemp); - -/********* From the file "plink.h" ***************************************/ -struct plink *Plink_new(void); -void Plink_add(struct plink **, struct config *); -void Plink_copy(struct plink **, struct plink *); -void Plink_delete(struct plink *); - -/********** From the file "report.h" *************************************/ -void Reprint(struct lemon *); -void ReportOutput(struct lemon *); -void ReportTable(struct lemon *, int); -void ReportHeader(struct lemon *); -void CompressTables(struct lemon *); -void ResortStates(struct lemon *); - -/********** From the file "set.h" ****************************************/ -void SetSize(int); /* All sets will be of size N */ -char *SetNew(void); /* A new set for element 0..N */ -void SetFree(char*); /* Deallocate a set */ -int SetAdd(char*,int); /* Add element to a set */ -int SetUnion(char *,char *); /* A <- A U B, thru element N */ -#define SetFind(X,Y) (X[Y]) /* True if Y is in set X */ - -/********** From the file "struct.h" *************************************/ -/* -** Principal data structures for the LEMON parser generator. -*/ - -typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean; - -/* Symbols (terminals and nonterminals) of the grammar are stored -** in the following: */ -enum symbol_type { - TERMINAL, - NONTERMINAL, - MULTITERMINAL -}; -enum e_assoc { - LEFT, - RIGHT, - NONE, - UNK -}; -struct symbol { - const char *name; /* Name of the symbol */ - int index; /* Index number for this symbol */ - enum symbol_type type; /* Symbols are all either TERMINALS or NTs */ - struct rule *rule; /* Linked list of rules of this (if an NT) */ - struct symbol *fallback; /* fallback token in case this token doesn't parse */ - int prec; /* Precedence if defined (-1 otherwise) */ - enum e_assoc assoc; /* Associativity if precedence is defined */ - char *firstset; /* First-set for all rules of this symbol */ - Boolean lambda; /* True if NT and can generate an empty string */ - int useCnt; /* Number of times used */ - char *destructor; /* Code which executes whenever this symbol is - ** popped from the stack during error processing */ - int destLineno; /* Line number for start of destructor */ - char *datatype; /* The data type of information held by this - ** object. Only used if type==NONTERMINAL */ - int dtnum; /* The data type number. In the parser, the value - ** stack is a union. The .yy%d element of this - ** union is the correct data type for this object */ - /* The following fields are used by MULTITERMINALs only */ - int nsubsym; /* Number of constituent symbols in the MULTI */ - struct symbol **subsym; /* Array of constituent symbols */ -}; - -/* Each production rule in the grammar is stored in the following -** structure. */ -struct rule { - struct symbol *lhs; /* Left-hand side of the rule */ - const char *lhsalias; /* Alias for the LHS (NULL if none) */ - int lhsStart; /* True if left-hand side is the start symbol */ - int ruleline; /* Line number for the rule */ - int nrhs; /* Number of RHS symbols */ - struct symbol **rhs; /* The RHS symbols */ - const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ - int line; /* Line number at which code begins */ - const char *code; /* The code executed when this rule is reduced */ - struct symbol *precsym; /* Precedence symbol for this rule */ - int index; /* An index number for this rule */ - Boolean canReduce; /* True if this rule is ever reduced */ - struct rule *nextlhs; /* Next rule with the same LHS */ - struct rule *next; /* Next rule in the global list */ -}; - -/* A configuration is a production rule of the grammar together with -** a mark (dot) showing how much of that rule has been processed so far. -** Configurations also contain a follow-set which is a list of terminal -** symbols which are allowed to immediately follow the end of the rule. -** Every configuration is recorded as an instance of the following: */ -enum cfgstatus { - COMPLETE, - INCOMPLETE -}; -struct config { - struct rule *rp; /* The rule upon which the configuration is based */ - int dot; /* The parse point */ - char *fws; /* Follow-set for this configuration only */ - struct plink *fplp; /* Follow-set forward propagation links */ - struct plink *bplp; /* Follow-set backwards propagation links */ - struct state *stp; /* Pointer to state which contains this */ - enum cfgstatus status; /* used during followset and shift computations */ - struct config *next; /* Next configuration in the state */ - struct config *bp; /* The next basis configuration */ -}; - -enum e_action { - SHIFT, - ACCEPT, - REDUCE, - ERROR, - SSCONFLICT, /* A shift/shift conflict */ - SRCONFLICT, /* Was a reduce, but part of a conflict */ - RRCONFLICT, /* Was a reduce, but part of a conflict */ - SH_RESOLVED, /* Was a shift. Precedence resolved conflict */ - RD_RESOLVED, /* Was reduce. Precedence resolved conflict */ - NOT_USED, /* Deleted by compression */ - SHIFTREDUCE /* Shift first, then reduce */ -}; - -/* Every shift or reduce operation is stored as one of the following */ -struct action { - struct symbol *sp; /* The look-ahead symbol */ - enum e_action type; - union { - struct state *stp; /* The new state, if a shift */ - struct rule *rp; /* The rule, if a reduce */ - } x; - struct action *next; /* Next action for this state */ - struct action *collide; /* Next action with the same hash */ -}; - -/* Each state of the generated parser's finite state machine -** is encoded as an instance of the following structure. */ -struct state { - struct config *bp; /* The basis configurations for this state */ - struct config *cfp; /* All configurations in this set */ - int statenum; /* Sequential number for this state */ - struct action *ap; /* Array of actions for this state */ - int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ - int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ - int iDfltReduce; /* Default action is to REDUCE by this rule */ - struct rule *pDfltReduce;/* The default REDUCE rule. */ - int autoReduce; /* True if this is an auto-reduce state */ -}; -#define NO_OFFSET (-2147483647) - -/* A followset propagation link indicates that the contents of one -** configuration followset should be propagated to another whenever -** the first changes. */ -struct plink { - struct config *cfp; /* The configuration to which linked */ - struct plink *next; /* The next propagate link */ -}; - -/* The state vector for the entire parser generator is recorded as -** follows. (LEMON uses no global variables and makes little use of -** static variables. Fields in the following structure can be thought -** of as begin global variables in the program.) */ -struct lemon { - struct state **sorted; /* Table of states sorted by state number */ - struct rule *rule; /* List of all rules */ - int nstate; /* Number of states */ - int nxstate; /* nstate with tail degenerate states removed */ - int nrule; /* Number of rules */ - int nsymbol; /* Number of terminal and nonterminal symbols */ - int nterminal; /* Number of terminal symbols */ - struct symbol **symbols; /* Sorted array of pointers to symbols */ - int errorcnt; /* Number of errors */ - struct symbol *errsym; /* The error symbol */ - struct symbol *wildcard; /* Token that matches anything */ - char *name; /* Name of the generated parser */ - char *arg; /* Declaration of the 3th argument to parser */ - char *tokentype; /* Type of terminal symbols in the parser stack */ - char *vartype; /* The default type of non-terminal symbols */ - char *start; /* Name of the start symbol for the grammar */ - char *stacksize; /* Size of the parser stack */ - char *include; /* Code to put at the start of the C file */ - char *error; /* Code to execute when an error is seen */ - char *overflow; /* Code to execute on a stack overflow */ - char *failure; /* Code to execute on parser failure */ - char *accept; /* Code to execute when the parser excepts */ - char *extracode; /* Code appended to the generated file */ - char *tokendest; /* Code to execute to destroy token data */ - char *vardest; /* Code for the default non-terminal destructor */ - char *filename; /* Name of the input file */ - char *outname; /* Name of the current output file */ - char *tokenprefix; /* A prefix added to token names in the .h file */ - int nconflict; /* Number of parsing conflicts */ - int nactiontab; /* Number of entries in the yy_action[] table */ - int tablesize; /* Total table size of all tables in bytes */ - int basisflag; /* Print only basis configurations */ - int has_fallback; /* True if any %fallback is seen in the grammar */ - int nolinenosflag; /* True if #line statements should not be printed */ - char *argv0; /* Name of the program */ -}; - -#define MemoryCheck(X) if((X)==0){ \ - extern void memory_error(); \ - memory_error(); \ -} - -/**************** From the file "table.h" *********************************/ -/* -** All code in this file has been automatically generated -** from a specification in the file -** "table.q" -** by the associative array code building program "aagen". -** Do not edit this file! Instead, edit the specification -** file, then rerun aagen. -*/ -/* -** Code for processing tables in the LEMON parser generator. -*/ -/* Routines for handling a strings */ - -const char *Strsafe(const char *); - -void Strsafe_init(void); -int Strsafe_insert(const char *); -const char *Strsafe_find(const char *); - -/* Routines for handling symbols of the grammar */ - -struct symbol *Symbol_new(const char *); -int Symbolcmpp(const void *, const void *); -void Symbol_init(void); -int Symbol_insert(struct symbol *, const char *); -struct symbol *Symbol_find(const char *); -struct symbol *Symbol_Nth(int); -int Symbol_count(void); -struct symbol **Symbol_arrayof(void); - -/* Routines to manage the state table */ - -int Configcmp(const char *, const char *); -struct state *State_new(void); -void State_init(void); -int State_insert(struct state *, struct config *); -struct state *State_find(struct config *); -struct state **State_arrayof(/* */); - -/* Routines used for efficiency in Configlist_add */ - -void Configtable_init(void); -int Configtable_insert(struct config *); -struct config *Configtable_find(struct config *); -void Configtable_clear(int(*)(struct config *)); - -/****************** From the file "action.c" *******************************/ -/* -** Routines processing parser actions in the LEMON parser generator. -*/ - -/* Allocate a new parser action */ -static struct action *Action_new(void){ - static struct action *freelist = 0; - struct action *newaction; - - if( freelist==0 ){ - int i; - int amt = 100; - freelist = (struct action *)calloc(amt, sizeof(struct action)); - if( freelist==0 ){ - fprintf(stderr,"Unable to allocate memory for a new parser action."); - exit(1); - } - for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1]; - freelist[amt-1].next = 0; - } - newaction = freelist; - freelist = freelist->next; - return newaction; -} - -/* Compare two actions for sorting purposes. Return negative, zero, or -** positive if the first action is less than, equal to, or greater than -** the first -*/ -static int actioncmp( - struct action *ap1, - struct action *ap2 -){ - int rc; - rc = ap1->sp->index - ap2->sp->index; - if( rc==0 ){ - rc = (int)ap1->type - (int)ap2->type; - } - if( rc==0 && (ap1->type==REDUCE || ap1->type==SHIFTREDUCE) ){ - rc = ap1->x.rp->index - ap2->x.rp->index; - } - if( rc==0 ){ - rc = (int) (ap2 - ap1); - } - return rc; -} - -/* Sort parser actions */ -static struct action *Action_sort( - struct action *ap -){ - ap = (struct action *)msort((char *)ap,(char **)&ap->next, - (int(*)(const char*,const char*))actioncmp); - return ap; -} - -void Action_add( - struct action **app, - enum e_action type, - struct symbol *sp, - char *arg -){ - struct action *newaction; - newaction = Action_new(); - newaction->next = *app; - *app = newaction; - newaction->type = type; - newaction->sp = sp; - if( type==SHIFT ){ - newaction->x.stp = (struct state *)arg; - }else{ - newaction->x.rp = (struct rule *)arg; - } -} -/********************** New code to implement the "acttab" module ***********/ -/* -** This module implements routines use to construct the yy_action[] table. -*/ - -/* -** The state of the yy_action table under construction is an instance of -** the following structure. -** -** The yy_action table maps the pair (state_number, lookahead) into an -** action_number. The table is an array of integers pairs. The state_number -** determines an initial offset into the yy_action array. The lookahead -** value is then added to this initial offset to get an index X into the -** yy_action array. If the aAction[X].lookahead equals the value of the -** of the lookahead input, then the value of the action_number output is -** aAction[X].action. If the lookaheads do not match then the -** default action for the state_number is returned. -** -** All actions associated with a single state_number are first entered -** into aLookahead[] using multiple calls to acttab_action(). Then the -** actions for that single state_number are placed into the aAction[] -** array with a single call to acttab_insert(). The acttab_insert() call -** also resets the aLookahead[] array in preparation for the next -** state number. -*/ -struct lookahead_action { - int lookahead; /* Value of the lookahead token */ - int action; /* Action to take on the given lookahead */ -}; -typedef struct acttab acttab; -struct acttab { - int nAction; /* Number of used slots in aAction[] */ - int nActionAlloc; /* Slots allocated for aAction[] */ - struct lookahead_action - *aAction, /* The yy_action[] table under construction */ - *aLookahead; /* A single new transaction set */ - int mnLookahead; /* Minimum aLookahead[].lookahead */ - int mnAction; /* Action associated with mnLookahead */ - int mxLookahead; /* Maximum aLookahead[].lookahead */ - int nLookahead; /* Used slots in aLookahead[] */ - int nLookaheadAlloc; /* Slots allocated in aLookahead[] */ -}; - -/* Return the number of entries in the yy_action table */ -#define acttab_size(X) ((X)->nAction) - -/* The value for the N-th entry in yy_action */ -#define acttab_yyaction(X,N) ((X)->aAction[N].action) - -/* The value for the N-th entry in yy_lookahead */ -#define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead) - -/* Free all memory associated with the given acttab */ -void acttab_free(acttab *p){ - free( p->aAction ); - free( p->aLookahead ); - free( p ); -} - -/* Allocate a new acttab structure */ -acttab *acttab_alloc(void){ - acttab *p = (acttab *) calloc( 1, sizeof(*p) ); - if( p==0 ){ - fprintf(stderr,"Unable to allocate memory for a new acttab."); - exit(1); - } - memset(p, 0, sizeof(*p)); - return p; -} - -/* Add a new action to the current transaction set. -** -** This routine is called once for each lookahead for a particular -** state. -*/ -void acttab_action(acttab *p, int lookahead, int action){ - if( p->nLookahead>=p->nLookaheadAlloc ){ - p->nLookaheadAlloc += 25; - p->aLookahead = (struct lookahead_action *) realloc( p->aLookahead, - sizeof(p->aLookahead[0])*p->nLookaheadAlloc ); - if( p->aLookahead==0 ){ - fprintf(stderr,"malloc failed\n"); - exit(1); - } - } - if( p->nLookahead==0 ){ - p->mxLookahead = lookahead; - p->mnLookahead = lookahead; - p->mnAction = action; - }else{ - if( p->mxLookahead<lookahead ) p->mxLookahead = lookahead; - if( p->mnLookahead>lookahead ){ - p->mnLookahead = lookahead; - p->mnAction = action; - } - } - p->aLookahead[p->nLookahead].lookahead = lookahead; - p->aLookahead[p->nLookahead].action = action; - p->nLookahead++; -} - -/* -** Add the transaction set built up with prior calls to acttab_action() -** into the current action table. Then reset the transaction set back -** to an empty set in preparation for a new round of acttab_action() calls. -** -** Return the offset into the action table of the new transaction. -*/ -int acttab_insert(acttab *p){ - int i, j, k, n; - assert( p->nLookahead>0 ); - - /* Make sure we have enough space to hold the expanded action table - ** in the worst case. The worst case occurs if the transaction set - ** must be appended to the current action table - */ - n = p->mxLookahead + 1; - if( p->nAction + n >= p->nActionAlloc ){ - int oldAlloc = p->nActionAlloc; - p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20; - p->aAction = (struct lookahead_action *) realloc( p->aAction, - sizeof(p->aAction[0])*p->nActionAlloc); - if( p->aAction==0 ){ - fprintf(stderr,"malloc failed\n"); - exit(1); - } - for(i=oldAlloc; i<p->nActionAlloc; i++){ - p->aAction[i].lookahead = -1; - p->aAction[i].action = -1; - } - } - - /* Scan the existing action table looking for an offset that is a - ** duplicate of the current transaction set. Fall out of the loop - ** if and when the duplicate is found. - ** - ** i is the index in p->aAction[] where p->mnLookahead is inserted. - */ - for(i=p->nAction-1; i>=0; i--){ - if( p->aAction[i].lookahead==p->mnLookahead ){ - /* All lookaheads and actions in the aLookahead[] transaction - ** must match against the candidate aAction[i] entry. */ - if( p->aAction[i].action!=p->mnAction ) continue; - for(j=0; j<p->nLookahead; j++){ - k = p->aLookahead[j].lookahead - p->mnLookahead + i; - if( k<0 || k>=p->nAction ) break; - if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break; - if( p->aLookahead[j].action!=p->aAction[k].action ) break; - } - if( j<p->nLookahead ) continue; - - /* No possible lookahead value that is not in the aLookahead[] - ** transaction is allowed to match aAction[i] */ - n = 0; - for(j=0; j<p->nAction; j++){ - if( p->aAction[j].lookahead<0 ) continue; - if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++; - } - if( n==p->nLookahead ){ - break; /* An exact match is found at offset i */ - } - } - } - - /* If no existing offsets exactly match the current transaction, find an - ** an empty offset in the aAction[] table in which we can add the - ** aLookahead[] transaction. - */ - if( i<0 ){ - /* Look for holes in the aAction[] table that fit the current - ** aLookahead[] transaction. Leave i set to the offset of the hole. - ** If no holes are found, i is left at p->nAction, which means the - ** transaction will be appended. */ - for(i=0; i<p->nActionAlloc - p->mxLookahead; i++){ - if( p->aAction[i].lookahead<0 ){ - for(j=0; j<p->nLookahead; j++){ - k = p->aLookahead[j].lookahead - p->mnLookahead + i; - if( k<0 ) break; - if( p->aAction[k].lookahead>=0 ) break; - } - if( j<p->nLookahead ) continue; - for(j=0; j<p->nAction; j++){ - if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break; - } - if( j==p->nAction ){ - break; /* Fits in empty slots */ - } - } - } - } - /* Insert transaction set at index i. */ - for(j=0; j<p->nLookahead; j++){ - k = p->aLookahead[j].lookahead - p->mnLookahead + i; - p->aAction[k] = p->aLookahead[j]; - if( k>=p->nAction ) p->nAction = k+1; - } - p->nLookahead = 0; - - /* Return the offset that is added to the lookahead in order to get the - ** index into yy_action of the action */ - return i - p->mnLookahead; -} - -/********************** From the file "build.c" *****************************/ -/* -** Routines to construction the finite state machine for the LEMON -** parser generator. -*/ - -/* Find a precedence symbol of every rule in the grammar. -** -** Those rules which have a precedence symbol coded in the input -** grammar using the "[symbol]" construct will already have the -** rp->precsym field filled. Other rules take as their precedence -** symbol the first RHS symbol with a defined precedence. If there -** are not RHS symbols with a defined precedence, the precedence -** symbol field is left blank. -*/ -void FindRulePrecedences(struct lemon *xp) -{ - struct rule *rp; - for(rp=xp->rule; rp; rp=rp->next){ - if( rp->precsym==0 ){ - int i, j; - for(i=0; i<rp->nrhs && rp->precsym==0; i++){ - struct symbol *sp = rp->rhs[i]; - if( sp->type==MULTITERMINAL ){ - for(j=0; j<sp->nsubsym; j++){ - if( sp->subsym[j]->prec>=0 ){ - rp->precsym = sp->subsym[j]; - break; - } - } - }else if( sp->prec>=0 ){ - rp->precsym = rp->rhs[i]; - } - } - } - } - return; -} - -/* Find all nonterminals which will generate the empty string. -** Then go back and compute the first sets of every nonterminal. -** The first set is the set of all terminal symbols which can begin -** a string generated by that nonterminal. -*/ -void FindFirstSets(struct lemon *lemp) -{ - int i, j; - struct rule *rp; - int progress; - - for(i=0; i<lemp->nsymbol; i++){ - lemp->symbols[i]->lambda = LEMON_FALSE; - } - for(i=lemp->nterminal; i<lemp->nsymbol; i++){ - lemp->symbols[i]->firstset = SetNew(); - } - - /* First compute all lambdas */ - do{ - progress = 0; - for(rp=lemp->rule; rp; rp=rp->next){ - if( rp->lhs->lambda ) continue; - for(i=0; i<rp->nrhs; i++){ - struct symbol *sp = rp->rhs[i]; - assert( sp->type==NONTERMINAL || sp->lambda==LEMON_FALSE ); - if( sp->lambda==LEMON_FALSE ) break; - } - if( i==rp->nrhs ){ - rp->lhs->lambda = LEMON_TRUE; - progress = 1; - } - } - }while( progress ); - - /* Now compute all first sets */ - do{ - struct symbol *s1, *s2; - progress = 0; - for(rp=lemp->rule; rp; rp=rp->next){ - s1 = rp->lhs; - for(i=0; i<rp->nrhs; i++){ - s2 = rp->rhs[i]; - if( s2->type==TERMINAL ){ - progress += SetAdd(s1->firstset,s2->index); - break; - }else if( s2->type==MULTITERMINAL ){ - for(j=0; j<s2->nsubsym; j++){ - progress += SetAdd(s1->firstset,s2->subsym[j]->index); - } - break; - }else if( s1==s2 ){ - if( s1->lambda==LEMON_FALSE ) break; - }else{ - progress += SetUnion(s1->firstset,s2->firstset); - if( s2->lambda==LEMON_FALSE ) break; - } - } - } - }while( progress ); - return; -} - -/* Compute all LR(0) states for the grammar. Links -** are added to between some states so that the LR(1) follow sets -** can be computed later. -*/ -PRIVATE struct state *getstate(struct lemon *); /* forward reference */ -void FindStates(struct lemon *lemp) -{ - struct symbol *sp; - struct rule *rp; - - Configlist_init(); - - /* Find the start symbol */ - if( lemp->start ){ - sp = Symbol_find(lemp->start); - if( sp==0 ){ - ErrorMsg(lemp->filename,0, -"The specified start symbol \"%s\" is not \ -in a nonterminal of the grammar. \"%s\" will be used as the start \ -symbol instead.",lemp->start,lemp->rule->lhs->name); - lemp->errorcnt++; - sp = lemp->rule->lhs; - } - }else{ - sp = lemp->rule->lhs; - } - - /* Make sure the start symbol doesn't occur on the right-hand side of - ** any rule. Report an error if it does. (YACC would generate a new - ** start symbol in this case.) */ - for(rp=lemp->rule; rp; rp=rp->next){ - int i; - for(i=0; i<rp->nrhs; i++){ - if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */ - ErrorMsg(lemp->filename,0, -"The start symbol \"%s\" occurs on the \ -right-hand side of a rule. This will result in a parser which \ -does not work properly.",sp->name); - lemp->errorcnt++; - } - } - } - - /* The basis configuration set for the first state - ** is all rules which have the start symbol as their - ** left-hand side */ - for(rp=sp->rule; rp; rp=rp->nextlhs){ - struct config *newcfp; - rp->lhsStart = 1; - newcfp = Configlist_addbasis(rp,0); - SetAdd(newcfp->fws,0); - } - - /* Compute the first state. All other states will be - ** computed automatically during the computation of the first one. - ** The returned pointer to the first state is not used. */ - (void)getstate(lemp); - return; -} - -/* Return a pointer to a state which is described by the configuration -** list which has been built from calls to Configlist_add. -*/ -PRIVATE void buildshifts(struct lemon *, struct state *); /* Forwd ref */ -PRIVATE struct state *getstate(struct lemon *lemp) -{ - struct config *cfp, *bp; - struct state *stp; - - /* Extract the sorted basis of the new state. The basis was constructed - ** by prior calls to "Configlist_addbasis()". */ - Configlist_sortbasis(); - bp = Configlist_basis(); - - /* Get a state with the same basis */ - stp = State_find(bp); - if( stp ){ - /* A state with the same basis already exists! Copy all the follow-set - ** propagation links from the state under construction into the - ** preexisting state, then return a pointer to the preexisting state */ - struct config *x, *y; - for(x=bp, y=stp->bp; x && y; x=x->bp, y=y->bp){ - Plink_copy(&y->bplp,x->bplp); - Plink_delete(x->fplp); - x->fplp = x->bplp = 0; - } - cfp = Configlist_return(); - Configlist_eat(cfp); - }else{ - /* This really is a new state. Construct all the details */ - Configlist_closure(lemp); /* Compute the configuration closure */ - Configlist_sort(); /* Sort the configuration closure */ - cfp = Configlist_return(); /* Get a pointer to the config list */ - stp = State_new(); /* A new state structure */ - MemoryCheck(stp); - stp->bp = bp; /* Remember the configuration basis */ - stp->cfp = cfp; /* Remember the configuration closure */ - stp->statenum = lemp->nstate++; /* Every state gets a sequence number */ - stp->ap = 0; /* No actions, yet. */ - State_insert(stp,stp->bp); /* Add to the state table */ - buildshifts(lemp,stp); /* Recursively compute successor states */ - } - return stp; -} - -/* -** Return true if two symbols are the same. -*/ -int same_symbol(struct symbol *a, struct symbol *b) -{ - int i; - if( a==b ) return 1; - if( a->type!=MULTITERMINAL ) return 0; - if( b->type!=MULTITERMINAL ) return 0; - if( a->nsubsym!=b->nsubsym ) return 0; - for(i=0; i<a->nsubsym; i++){ - if( a->subsym[i]!=b->subsym[i] ) return 0; - } - return 1; -} - -/* Construct all successor states to the given state. A "successor" -** state is any state which can be reached by a shift action. -*/ -PRIVATE void buildshifts(struct lemon *lemp, struct state *stp) -{ - struct config *cfp; /* For looping thru the config closure of "stp" */ - struct config *bcfp; /* For the inner loop on config closure of "stp" */ - struct config *newcfg; /* */ - struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ - struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ - struct state *newstp; /* A pointer to a successor state */ - - /* Each configuration becomes complete after it contibutes to a successor - ** state. Initially, all configurations are incomplete */ - for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE; - - /* Loop through all configurations of the state "stp" */ - for(cfp=stp->cfp; cfp; cfp=cfp->next){ - if( cfp->status==COMPLETE ) continue; /* Already used by inner loop */ - if( cfp->dot>=cfp->rp->nrhs ) continue; /* Can't shift this config */ - Configlist_reset(); /* Reset the new config set */ - sp = cfp->rp->rhs[cfp->dot]; /* Symbol after the dot */ - - /* For every configuration in the state "stp" which has the symbol "sp" - ** following its dot, add the same configuration to the basis set under - ** construction but with the dot shifted one symbol to the right. */ - for(bcfp=cfp; bcfp; bcfp=bcfp->next){ - if( bcfp->status==COMPLETE ) continue; /* Already used */ - if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */ - bsp = bcfp->rp->rhs[bcfp->dot]; /* Get symbol after dot */ - if( !same_symbol(bsp,sp) ) continue; /* Must be same as for "cfp" */ - bcfp->status = COMPLETE; /* Mark this config as used */ - newcfg = Configlist_addbasis(bcfp->rp,bcfp->dot+1); - Plink_add(&newcfg->bplp,bcfp); - } - - /* Get a pointer to the state described by the basis configuration set - ** constructed in the preceding loop */ - newstp = getstate(lemp); - - /* The state "newstp" is reached from the state "stp" by a shift action - ** on the symbol "sp" */ - if( sp->type==MULTITERMINAL ){ - int i; - for(i=0; i<sp->nsubsym; i++){ - Action_add(&stp->ap,SHIFT,sp->subsym[i],(char*)newstp); - } - }else{ - Action_add(&stp->ap,SHIFT,sp,(char *)newstp); - } - } -} - -/* -** Construct the propagation links -*/ -void FindLinks(struct lemon *lemp) -{ - int i; - struct config *cfp, *other; - struct state *stp; - struct plink *plp; - - /* Housekeeping detail: - ** Add to every propagate link a pointer back to the state to - ** which the link is attached. */ - for(i=0; i<lemp->nstate; i++){ - stp = lemp->sorted[i]; - for(cfp=stp->cfp; cfp; cfp=cfp->next){ - cfp->stp = stp; - } - } - - /* Convert all backlinks into forward links. Only the forward - ** links are used in the follow-set computation. */ - for(i=0; i<lemp->nstate; i++){ - stp = lemp->sorted[i]; - for(cfp=stp->cfp; cfp; cfp=cfp->next){ - for(plp=cfp->bplp; plp; plp=plp->next){ - other = plp->cfp; - Plink_add(&other->fplp,cfp); - } - } - } -} - -/* Compute all followsets. -** -** A followset is the set of all symbols which can come immediately -** after a configuration. -*/ -void FindFollowSets(struct lemon *lemp) -{ - int i; - struct config *cfp; - struct plink *plp; - int progress; - int change; - - for(i=0; i<lemp->nstate; i++){ - for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ - cfp->status = INCOMPLETE; - } - } - - do{ - progress = 0; - for(i=0; i<lemp->nstate; i++){ - for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ - if( cfp->status==COMPLETE ) continue; - for(plp=cfp->fplp; plp; plp=plp->next){ - change = SetUnion(plp->cfp->fws,cfp->fws); - if( change ){ - plp->cfp->status = INCOMPLETE; - progress = 1; - } - } - cfp->status = COMPLETE; - } - } - }while( progress ); -} - -static int resolve_conflict(struct action *,struct action *); - -/* Compute the reduce actions, and resolve conflicts. -*/ -void FindActions(struct lemon *lemp) -{ - int i,j; - struct config *cfp; - struct state *stp; - struct symbol *sp; - struct rule *rp; - - /* Add all of the reduce actions - ** A reduce action is added for each element of the followset of - ** a configuration which has its dot at the extreme right. - */ - for(i=0; i<lemp->nstate; i++){ /* Loop over all states */ - stp = lemp->sorted[i]; - for(cfp=stp->cfp; cfp; cfp=cfp->next){ /* Loop over all configurations */ - if( cfp->rp->nrhs==cfp->dot ){ /* Is dot at extreme right? */ - for(j=0; j<lemp->nterminal; j++){ - if( SetFind(cfp->fws,j) ){ - /* Add a reduce action to the state "stp" which will reduce by the - ** rule "cfp->rp" if the lookahead symbol is "lemp->symbols[j]" */ - Action_add(&stp->ap,REDUCE,lemp->symbols[j],(char *)cfp->rp); - } - } - } - } - } - - /* Add the accepting token */ - if( lemp->start ){ - sp = Symbol_find(lemp->start); - if( sp==0 ) sp = lemp->rule->lhs; - }else{ - sp = lemp->rule->lhs; - } - /* Add to the first state (which is always the starting state of the - ** finite state machine) an action to ACCEPT if the lookahead is the - ** start nonterminal. */ - Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0); - - /* Resolve conflicts */ - for(i=0; i<lemp->nstate; i++){ - struct action *ap, *nap; - stp = lemp->sorted[i]; - /* assert( stp->ap ); */ - stp->ap = Action_sort(stp->ap); - for(ap=stp->ap; ap && ap->next; ap=ap->next){ - for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){ - /* The two actions "ap" and "nap" have the same lookahead. - ** Figure out which one should be used */ - lemp->nconflict += resolve_conflict(ap,nap); - } - } - } - - /* Report an error for each rule that can never be reduced. */ - for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE; - for(i=0; i<lemp->nstate; i++){ - struct action *ap; - for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){ - if( ap->type==REDUCE ) ap->x.rp->canReduce = LEMON_TRUE; - } - } - for(rp=lemp->rule; rp; rp=rp->next){ - if( rp->canReduce ) continue; - ErrorMsg(lemp->filename,rp->ruleline,"This rule can not be reduced.\n"); - lemp->errorcnt++; - } -} - -/* Resolve a conflict between the two given actions. If the -** conflict can't be resolved, return non-zero. -** -** NO LONGER TRUE: -** To resolve a conflict, first look to see if either action -** is on an error rule. In that case, take the action which -** is not associated with the error rule. If neither or both -** actions are associated with an error rule, then try to -** use precedence to resolve the conflict. -** -** If either action is a SHIFT, then it must be apx. This -** function won't work if apx->type==REDUCE and apy->type==SHIFT. -*/ -static int resolve_conflict( - struct action *apx, - struct action *apy -){ - struct symbol *spx, *spy; - int errcnt = 0; - assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */ - if( apx->type==SHIFT && apy->type==SHIFT ){ - apy->type = SSCONFLICT; - errcnt++; - } - if( apx->type==SHIFT && apy->type==REDUCE ){ - spx = apx->sp; - spy = apy->x.rp->precsym; - if( spy==0 || spx->prec<0 || spy->prec<0 ){ - /* Not enough precedence information. */ - apy->type = SRCONFLICT; - errcnt++; - }else if( spx->prec>spy->prec ){ /* higher precedence wins */ - apy->type = RD_RESOLVED; - }else if( spx->prec<spy->prec ){ - apx->type = SH_RESOLVED; - }else if( spx->prec==spy->prec && spx->assoc==RIGHT ){ /* Use operator */ - apy->type = RD_RESOLVED; /* associativity */ - }else if( spx->prec==spy->prec && spx->assoc==LEFT ){ /* to break tie */ - apx->type = SH_RESOLVED; - }else{ - assert( spx->prec==spy->prec && spx->assoc==NONE ); - apx->type = ERROR; - } - }else if( apx->type==REDUCE && apy->type==REDUCE ){ - spx = apx->x.rp->precsym; - spy = apy->x.rp->precsym; - if( spx==0 || spy==0 || spx->prec<0 || - spy->prec<0 || spx->prec==spy->prec ){ - apy->type = RRCONFLICT; - errcnt++; - }else if( spx->prec>spy->prec ){ - apy->type = RD_RESOLVED; - }else if( spx->prec<spy->prec ){ - apx->type = RD_RESOLVED; - } - }else{ - assert( - apx->type==SH_RESOLVED || - apx->type==RD_RESOLVED || - apx->type==SSCONFLICT || - apx->type==SRCONFLICT || - apx->type==RRCONFLICT || - apy->type==SH_RESOLVED || - apy->type==RD_RESOLVED || - apy->type==SSCONFLICT || - apy->type==SRCONFLICT || - apy->type==RRCONFLICT - ); - /* The REDUCE/SHIFT case cannot happen because SHIFTs come before - ** REDUCEs on the list. If we reach this point it must be because - ** the parser conflict had already been resolved. */ - } - return errcnt; -} -/********************* From the file "configlist.c" *************************/ -/* -** Routines to processing a configuration list and building a state -** in the LEMON parser generator. -*/ - -static struct config *freelist = 0; /* List of free configurations */ -static struct config *current = 0; /* Top of list of configurations */ -static struct config **currentend = 0; /* Last on list of configs */ -static struct config *basis = 0; /* Top of list of basis configs */ -static struct config **basisend = 0; /* End of list of basis configs */ - -/* Return a pointer to a new configuration */ -PRIVATE struct config *newconfig(){ - struct config *newcfg; - if( freelist==0 ){ - int i; - int amt = 3; - freelist = (struct config *)calloc( amt, sizeof(struct config) ); - if( freelist==0 ){ - fprintf(stderr,"Unable to allocate memory for a new configuration."); - exit(1); - } - for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1]; - freelist[amt-1].next = 0; - } - newcfg = freelist; - freelist = freelist->next; - return newcfg; -} - -/* The configuration "old" is no longer used */ -PRIVATE void deleteconfig(struct config *old) -{ - old->next = freelist; - freelist = old; -} - -/* Initialized the configuration list builder */ -void Configlist_init(){ - current = 0; - currentend = ¤t; - basis = 0; - basisend = &basis; - Configtable_init(); - return; -} - -/* Initialized the configuration list builder */ -void Configlist_reset(){ - current = 0; - currentend = ¤t; - basis = 0; - basisend = &basis; - Configtable_clear(0); - return; -} - -/* Add another configuration to the configuration list */ -struct config *Configlist_add( - struct rule *rp, /* The rule */ - int dot /* Index into the RHS of the rule where the dot goes */ -){ - struct config *cfp, model; - - assert( currentend!=0 ); - model.rp = rp; - model.dot = dot; - cfp = Configtable_find(&model); - if( cfp==0 ){ - cfp = newconfig(); - cfp->rp = rp; - cfp->dot = dot; - cfp->fws = SetNew(); - cfp->stp = 0; - cfp->fplp = cfp->bplp = 0; - cfp->next = 0; - cfp->bp = 0; - *currentend = cfp; - currentend = &cfp->next; - Configtable_insert(cfp); - } - return cfp; -} - -/* Add a basis configuration to the configuration list */ -struct config *Configlist_addbasis(struct rule *rp, int dot) -{ - struct config *cfp, model; - - assert( basisend!=0 ); - assert( currentend!=0 ); - model.rp = rp; - model.dot = dot; - cfp = Configtable_find(&model); - if( cfp==0 ){ - cfp = newconfig(); - cfp->rp = rp; - cfp->dot = dot; - cfp->fws = SetNew(); - cfp->stp = 0; - cfp->fplp = cfp->bplp = 0; - cfp->next = 0; - cfp->bp = 0; - *currentend = cfp; - currentend = &cfp->next; - *basisend = cfp; - basisend = &cfp->bp; - Configtable_insert(cfp); - } - return cfp; -} - -/* Compute the closure of the configuration list */ -void Configlist_closure(struct lemon *lemp) -{ - struct config *cfp, *newcfp; - struct rule *rp, *newrp; - struct symbol *sp, *xsp; - int i, dot; - - assert( currentend!=0 ); - for(cfp=current; cfp; cfp=cfp->next){ - rp = cfp->rp; - dot = cfp->dot; - if( dot>=rp->nrhs ) continue; - sp = rp->rhs[dot]; - if( sp->type==NONTERMINAL ){ - if( sp->rule==0 && sp!=lemp->errsym ){ - ErrorMsg(lemp->filename,rp->line,"Nonterminal \"%s\" has no rules.", - sp->name); - lemp->errorcnt++; - } - for(newrp=sp->rule; newrp; newrp=newrp->nextlhs){ - newcfp = Configlist_add(newrp,0); - for(i=dot+1; i<rp->nrhs; i++){ - xsp = rp->rhs[i]; - if( xsp->type==TERMINAL ){ - SetAdd(newcfp->fws,xsp->index); - break; - }else if( xsp->type==MULTITERMINAL ){ - int k; - for(k=0; k<xsp->nsubsym; k++){ - SetAdd(newcfp->fws, xsp->subsym[k]->index); - } - break; - }else{ - SetUnion(newcfp->fws,xsp->firstset); - if( xsp->lambda==LEMON_FALSE ) break; - } - } - if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp); - } - } - } - return; -} - -/* Sort the configuration list */ -void Configlist_sort(){ - current = (struct config*)msort((char*)current,(char**)&(current->next), - Configcmp); - currentend = 0; - return; -} - -/* Sort the basis configuration list */ -void Configlist_sortbasis(){ - basis = (struct config*)msort((char*)current,(char**)&(current->bp), - Configcmp); - basisend = 0; - return; -} - -/* Return a pointer to the head of the configuration list and -** reset the list */ -struct config *Configlist_return(){ - struct config *old; - old = current; - current = 0; - currentend = 0; - return old; -} - -/* Return a pointer to the head of the configuration list and -** reset the list */ -struct config *Configlist_basis(){ - struct config *old; - old = basis; - basis = 0; - basisend = 0; - return old; -} - -/* Free all elements of the given configuration list */ -void Configlist_eat(struct config *cfp) -{ - struct config *nextcfp; - for(; cfp; cfp=nextcfp){ - nextcfp = cfp->next; - assert( cfp->fplp==0 ); - assert( cfp->bplp==0 ); - if( cfp->fws ) SetFree(cfp->fws); - deleteconfig(cfp); - } - return; -} -/***************** From the file "error.c" *********************************/ -/* -** Code for printing error message. -*/ - -void ErrorMsg(const char *filename, int lineno, const char *format, ...){ - va_list ap; - fprintf(stderr, "%s:%d: ", filename, lineno); - va_start(ap, format); - vfprintf(stderr,format,ap); - va_end(ap); - fprintf(stderr, "\n"); -} -/**************** From the file "main.c" ************************************/ -/* -** Main program file for the LEMON parser generator. -*/ - -/* Report an out-of-memory condition and abort. This function -** is used mostly by the "MemoryCheck" macro in struct.h -*/ -void memory_error(){ - fprintf(stderr,"Out of memory. Aborting...\n"); - exit(1); -} - -static int nDefine = 0; /* Number of -D options on the command line */ -static char **azDefine = 0; /* Name of the -D macros */ - -/* This routine is called with the argument to each -D command-line option. -** Add the macro defined to the azDefine array. -*/ -static void handle_D_option(char *z){ - char **paz; - nDefine++; - azDefine = (char **) realloc(azDefine, sizeof(azDefine[0])*nDefine); - if( azDefine==0 ){ - fprintf(stderr,"out of memory\n"); - exit(1); - } - paz = &azDefine[nDefine-1]; - *paz = (char *) malloc( lemonStrlen(z)+1 ); - if( *paz==0 ){ - fprintf(stderr,"out of memory\n"); - exit(1); - } - lemon_strcpy(*paz, z); - for(z=*paz; *z && *z!='='; z++){} - *z = 0; -} - -static char *user_templatename = NULL; -static void handle_T_option(char *z){ - user_templatename = (char *) malloc( lemonStrlen(z)+1 ); - if( user_templatename==0 ){ - memory_error(); - } - lemon_strcpy(user_templatename, z); -} - -/* forward reference */ -static const char *minimum_size_type(int lwr, int upr, int *pnByte); - -/* Print a single line of the "Parser Stats" output -*/ -static void stats_line(const char *zLabel, int iValue){ - int nLabel = lemonStrlen(zLabel); - printf(" %s%.*s %5d\n", zLabel, - 35-nLabel, "................................", - iValue); -} - -/* The main program. Parse the command line and do it... */ -int main(int argc, char **argv) -{ - static int version = 0; - static int rpflag = 0; - static int basisflag = 0; - static int compress = 0; - static int quiet = 0; - static int statistics = 0; - static int mhflag = 0; - static int nolinenosflag = 0; - static int noResort = 0; - static struct s_options options[] = { - {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, - {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, - {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, - {OPT_FSTR, "f", 0, "Ignored. (Placeholder for -f compiler options.)"}, - {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, - {OPT_FSTR, "I", 0, "Ignored. (Placeholder for '-I' compiler options.)"}, - {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, - {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, - {OPT_FSTR, "O", 0, "Ignored. (Placeholder for '-O' compiler options.)"}, - {OPT_FLAG, "p", (char*)&showPrecedenceConflict, - "Show conflicts resolved by precedence rules"}, - {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, - {OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"}, - {OPT_FLAG, "s", (char*)&statistics, - "Print parser stats to standard output."}, - {OPT_FLAG, "x", (char*)&version, "Print the version number."}, - {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."}, - {OPT_FSTR, "W", 0, "Ignored. (Placeholder for '-W' compiler options.)"}, - {OPT_FLAG,0,0,0} - }; - int i; - int exitcode; - struct lemon lem; - - OptInit(argv,options,stderr); - if( version ){ - printf("Lemon version 1.0\n"); - exit(0); - } - if( OptNArgs()!=1 ){ - fprintf(stderr,"Exactly one filename argument is required.\n"); - exit(1); - } - memset(&lem, 0, sizeof(lem)); - lem.errorcnt = 0; - - /* Initialize the machine */ - Strsafe_init(); - Symbol_init(); - State_init(); - lem.argv0 = argv[0]; - lem.filename = OptArg(0); - lem.basisflag = basisflag; - lem.nolinenosflag = nolinenosflag; - Symbol_new("$"); - lem.errsym = Symbol_new("error"); - lem.errsym->useCnt = 0; - - /* Parse the input file */ - Parse(&lem); - if( lem.errorcnt ) exit(lem.errorcnt); - if( lem.nrule==0 ){ - fprintf(stderr,"Empty grammar.\n"); - exit(1); - } - - /* Count and index the symbols of the grammar */ - Symbol_new("{default}"); - lem.nsymbol = Symbol_count(); - lem.symbols = Symbol_arrayof(); - for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i; - qsort(lem.symbols,lem.nsymbol,sizeof(struct symbol*), Symbolcmpp); - for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i; - while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; } - assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 ); - lem.nsymbol = i - 1; - for(i=1; isupper(lem.symbols[i]->name[0]); i++); - lem.nterminal = i; - - /* Generate a reprint of the grammar, if requested on the command line */ - if( rpflag ){ - Reprint(&lem); - }else{ - /* Initialize the size for all follow and first sets */ - SetSize(lem.nterminal+1); - - /* Find the precedence for every production rule (that has one) */ - FindRulePrecedences(&lem); - - /* Compute the lambda-nonterminals and the first-sets for every - ** nonterminal */ - FindFirstSets(&lem); - - /* Compute all LR(0) states. Also record follow-set propagation - ** links so that the follow-set can be computed later */ - lem.nstate = 0; - FindStates(&lem); - lem.sorted = State_arrayof(); - - /* Tie up loose ends on the propagation links */ - FindLinks(&lem); - - /* Compute the follow set of every reducible configuration */ - FindFollowSets(&lem); - - /* Compute the action tables */ - FindActions(&lem); - - /* Compress the action tables */ - if( compress==0 ) CompressTables(&lem); - - /* Reorder and renumber the states so that states with fewer choices - ** occur at the end. This is an optimization that helps make the - ** generated parser tables smaller. */ - if( noResort==0 ) ResortStates(&lem); - - /* Generate a report of the parser generated. (the "y.output" file) */ - if( !quiet ) ReportOutput(&lem); - - /* Generate the source code for the parser */ - ReportTable(&lem, mhflag); - - /* Produce a header file for use by the scanner. (This step is - ** omitted if the "-m" option is used because makeheaders will - ** generate the file for us.) */ - if( !mhflag ) ReportHeader(&lem); - } - if( statistics ){ - printf("Parser statistics:\n"); - stats_line("terminal symbols", lem.nterminal); - stats_line("non-terminal symbols", lem.nsymbol - lem.nterminal); - stats_line("total symbols", lem.nsymbol); - stats_line("rules", lem.nrule); - stats_line("states", lem.nxstate); - stats_line("conflicts", lem.nconflict); - stats_line("action table entries", lem.nactiontab); - stats_line("total table size (bytes)", lem.tablesize); - } - if( lem.nconflict > 0 ){ - fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict); - } - - /* return 0 on success, 1 on failure. */ - exitcode = ((lem.errorcnt > 0) || (lem.nconflict > 0)) ? 1 : 0; - exit(exitcode); - return (exitcode); -} -/******************** From the file "msort.c" *******************************/ -/* -** A generic merge-sort program. -** -** USAGE: -** Let "ptr" be a pointer to some structure which is at the head of -** a null-terminated list. Then to sort the list call: -** -** ptr = msort(ptr,&(ptr->next),cmpfnc); -** -** In the above, "cmpfnc" is a pointer to a function which compares -** two instances of the structure and returns an integer, as in -** strcmp. The second argument is a pointer to the pointer to the -** second element of the linked list. This address is used to compute -** the offset to the "next" field within the structure. The offset to -** the "next" field must be constant for all structures in the list. -** -** The function returns a new pointer which is the head of the list -** after sorting. -** -** ALGORITHM: -** Merge-sort. -*/ - -/* -** Return a pointer to the next structure in the linked list. -*/ -#define NEXT(A) (*(char**)(((char*)A)+offset)) - -/* -** Inputs: -** a: A sorted, null-terminated linked list. (May be null). -** b: A sorted, null-terminated linked list. (May be null). -** cmp: A pointer to the comparison function. -** offset: Offset in the structure to the "next" field. -** -** Return Value: -** A pointer to the head of a sorted list containing the elements -** of both a and b. -** -** Side effects: -** The "next" pointers for elements in the lists a and b are -** changed. -*/ -static char *merge( - char *a, - char *b, - int (*cmp)(const char*,const char*), - int offset -){ - char *ptr, *head; - - if( a==0 ){ - head = b; - }else if( b==0 ){ - head = a; - }else{ - if( (*cmp)(a,b)<=0 ){ - ptr = a; - a = NEXT(a); - }else{ - ptr = b; - b = NEXT(b); - } - head = ptr; - while( a && b ){ - if( (*cmp)(a,b)<=0 ){ - NEXT(ptr) = a; - ptr = a; - a = NEXT(a); - }else{ - NEXT(ptr) = b; - ptr = b; - b = NEXT(b); - } - } - if( a ) NEXT(ptr) = a; - else NEXT(ptr) = b; - } - return head; -} - -/* -** Inputs: -** list: Pointer to a singly-linked list of structures. -** next: Pointer to pointer to the second element of the list. -** cmp: A comparison function. -** -** Return Value: -** A pointer to the head of a sorted list containing the elements -** orginally in list. -** -** Side effects: -** The "next" pointers for elements in list are changed. -*/ -#define LISTSIZE 30 -static char *msort( - char *list, - char **next, - int (*cmp)(const char*,const char*) -){ - unsigned long offset; - char *ep; - char *set[LISTSIZE]; - int i; - offset = (unsigned long)((char*)next - (char*)list); - for(i=0; i<LISTSIZE; i++) set[i] = 0; - while( list ){ - ep = list; - list = NEXT(list); - NEXT(ep) = 0; - for(i=0; i<LISTSIZE-1 && set[i]!=0; i++){ - ep = merge(ep,set[i],cmp,offset); - set[i] = 0; - } - set[i] = ep; - } - ep = 0; - for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(set[i],ep,cmp,offset); - return ep; -} -/************************ From the file "option.c" **************************/ -static char **argv; -static struct s_options *op; -static FILE *errstream; - -#define ISOPT(X) ((X)[0]=='-'||(X)[0]=='+'||strchr((X),'=')!=0) - -/* -** Print the command line with a carrot pointing to the k-th character -** of the n-th field. -*/ -static void errline(int n, int k, FILE *err) -{ - int spcnt, i; - if( argv[0] ) fprintf(err,"%s",argv[0]); - spcnt = lemonStrlen(argv[0]) + 1; - for(i=1; i<n && argv[i]; i++){ - fprintf(err," %s",argv[i]); - spcnt += lemonStrlen(argv[i])+1; - } - spcnt += k; - for(; argv[i]; i++) fprintf(err," %s",argv[i]); - if( spcnt<20 ){ - fprintf(err,"\n%*s^-- here\n",spcnt,""); - }else{ - fprintf(err,"\n%*shere --^\n",spcnt-7,""); - } -} - -/* -** Return the index of the N-th non-switch argument. Return -1 -** if N is out of range. -*/ -static int argindex(int n) -{ - int i; - int dashdash = 0; - if( argv!=0 && *argv!=0 ){ - for(i=1; argv[i]; i++){ - if( dashdash || !ISOPT(argv[i]) ){ - if( n==0 ) return i; - n--; - } - if( strcmp(argv[i],"--")==0 ) dashdash = 1; - } - } - return -1; -} - -static char emsg[] = "Command line syntax error: "; - -/* -** Process a flag command line argument. -*/ -static int handleflags(int i, FILE *err) -{ - int v; - int errcnt = 0; - int j; - for(j=0; op[j].label; j++){ - if( strncmp(&argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break; - } - v = argv[i][0]=='-' ? 1 : 0; - if( op[j].label==0 ){ - if( err ){ - fprintf(err,"%sundefined option.\n",emsg); - errline(i,1,err); - } - errcnt++; - }else if( op[j].arg==0 ){ - /* Ignore this option */ - }else if( op[j].type==OPT_FLAG ){ - *((int*)op[j].arg) = v; - }else if( op[j].type==OPT_FFLAG ){ - (*(void(*)(int))(op[j].arg))(v); - }else if( op[j].type==OPT_FSTR ){ - (*(void(*)(char *))(op[j].arg))(&argv[i][2]); - }else{ - if( err ){ - fprintf(err,"%smissing argument on switch.\n",emsg); - errline(i,1,err); - } - errcnt++; - } - return errcnt; -} - -/* -** Process a command line switch which has an argument. -*/ -static int handleswitch(int i, FILE *err) -{ - int lv = 0; - double dv = 0.0; - char *sv = 0, *end; - char *cp; - int j; - int errcnt = 0; - cp = strchr(argv[i],'='); - assert( cp!=0 ); - *cp = 0; - for(j=0; op[j].label; j++){ - if( strcmp(argv[i],op[j].label)==0 ) break; - } - *cp = '='; - if( op[j].label==0 ){ - if( err ){ - fprintf(err,"%sundefined option.\n",emsg); - errline(i,0,err); - } - errcnt++; - }else{ - cp++; - switch( op[j].type ){ - case OPT_FLAG: - case OPT_FFLAG: - if( err ){ - fprintf(err,"%soption requires an argument.\n",emsg); - errline(i,0,err); - } - errcnt++; - break; - case OPT_DBL: - case OPT_FDBL: - dv = strtod(cp,&end); - if( *end ){ - if( err ){ - fprintf(err, - "%sillegal character in floating-point argument.\n",emsg); - errline(i,(int)((char*)end-(char*)argv[i]),err); - } - errcnt++; - } - break; - case OPT_INT: - case OPT_FINT: - lv = strtol(cp,&end,0); - if( *end ){ - if( err ){ - fprintf(err,"%sillegal character in integer argument.\n",emsg); - errline(i,(int)((char*)end-(char*)argv[i]),err); - } - errcnt++; - } - break; - case OPT_STR: - case OPT_FSTR: - sv = cp; - break; - } - switch( op[j].type ){ - case OPT_FLAG: - case OPT_FFLAG: - break; - case OPT_DBL: - *(double*)(op[j].arg) = dv; - break; - case OPT_FDBL: - (*(void(*)(double))(op[j].arg))(dv); - break; - case OPT_INT: - *(int*)(op[j].arg) = lv; - break; - case OPT_FINT: - (*(void(*)(int))(op[j].arg))((int)lv); - break; - case OPT_STR: - *(char**)(op[j].arg) = sv; - break; - case OPT_FSTR: - (*(void(*)(char *))(op[j].arg))(sv); - break; - } - } - return errcnt; -} - -int OptInit(char **a, struct s_options *o, FILE *err) -{ - int errcnt = 0; - argv = a; - op = o; - errstream = err; - if( argv && *argv && op ){ - int i; - for(i=1; argv[i]; i++){ - if( argv[i][0]=='+' || argv[i][0]=='-' ){ - errcnt += handleflags(i,err); - }else if( strchr(argv[i],'=') ){ - errcnt += handleswitch(i,err); - } - } - } - if( errcnt>0 ){ - fprintf(err,"Valid command line options for \"%s\" are:\n",*a); - OptPrint(); - exit(1); - } - return 0; -} - -int OptNArgs(){ - int cnt = 0; - int dashdash = 0; - int i; - if( argv!=0 && argv[0]!=0 ){ - for(i=1; argv[i]; i++){ - if( dashdash || !ISOPT(argv[i]) ) cnt++; - if( strcmp(argv[i],"--")==0 ) dashdash = 1; - } - } - return cnt; -} - -char *OptArg(int n) -{ - int i; - i = argindex(n); - return i>=0 ? argv[i] : 0; -} - -void OptErr(int n) -{ - int i; - i = argindex(n); - if( i>=0 ) errline(i,0,errstream); -} - -void OptPrint(){ - int i; - int max, len; - max = 0; - for(i=0; op[i].label; i++){ - len = lemonStrlen(op[i].label) + 1; - switch( op[i].type ){ - case OPT_FLAG: - case OPT_FFLAG: - break; - case OPT_INT: - case OPT_FINT: - len += 9; /* length of "<integer>" */ - break; - case OPT_DBL: - case OPT_FDBL: - len += 6; /* length of "<real>" */ - break; - case OPT_STR: - case OPT_FSTR: - len += 8; /* length of "<string>" */ - break; - } - if( len>max ) max = len; - } - for(i=0; op[i].label; i++){ - switch( op[i].type ){ - case OPT_FLAG: - case OPT_FFLAG: - fprintf(errstream," -%-*s %s\n",max,op[i].label,op[i].message); - break; - case OPT_INT: - case OPT_FINT: - fprintf(errstream," -%s<integer>%*s %s\n",op[i].label, - (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message); - break; - case OPT_DBL: - case OPT_FDBL: - fprintf(errstream," -%s<real>%*s %s\n",op[i].label, - (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message); - break; - case OPT_STR: - case OPT_FSTR: - fprintf(errstream," -%s<string>%*s %s\n",op[i].label, - (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); - break; - } - } -} -/*********************** From the file "parse.c" ****************************/ -/* -** Input file parser for the LEMON parser generator. -*/ - -/* The state of the parser */ -enum e_state { - INITIALIZE, - WAITING_FOR_DECL_OR_RULE, - WAITING_FOR_DECL_KEYWORD, - WAITING_FOR_DECL_ARG, - WAITING_FOR_PRECEDENCE_SYMBOL, - WAITING_FOR_ARROW, - IN_RHS, - LHS_ALIAS_1, - LHS_ALIAS_2, - LHS_ALIAS_3, - RHS_ALIAS_1, - RHS_ALIAS_2, - PRECEDENCE_MARK_1, - PRECEDENCE_MARK_2, - RESYNC_AFTER_RULE_ERROR, - RESYNC_AFTER_DECL_ERROR, - WAITING_FOR_DESTRUCTOR_SYMBOL, - WAITING_FOR_DATATYPE_SYMBOL, - WAITING_FOR_FALLBACK_ID, - WAITING_FOR_WILDCARD_ID, - WAITING_FOR_CLASS_ID, - WAITING_FOR_CLASS_TOKEN -}; -struct pstate { - char *filename; /* Name of the input file */ - int tokenlineno; /* Linenumber at which current token starts */ - int errorcnt; /* Number of errors so far */ - char *tokenstart; /* Text of current token */ - struct lemon *gp; /* Global state vector */ - enum e_state state; /* The state of the parser */ - struct symbol *fallback; /* The fallback token */ - struct symbol *tkclass; /* Token class symbol */ - struct symbol *lhs; /* Left-hand side of current rule */ - const char *lhsalias; /* Alias for the LHS */ - int nrhs; /* Number of right-hand side symbols seen */ - struct symbol *rhs[MAXRHS]; /* RHS symbols */ - const char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */ - struct rule *prevrule; /* Previous rule parsed */ - const char *declkeyword; /* Keyword of a declaration */ - char **declargslot; /* Where the declaration argument should be put */ - int insertLineMacro; /* Add #line before declaration insert */ - int *decllinenoslot; /* Where to write declaration line number */ - enum e_assoc declassoc; /* Assign this association to decl arguments */ - int preccounter; /* Assign this precedence to decl arguments */ - struct rule *firstrule; /* Pointer to first rule in the grammar */ - struct rule *lastrule; /* Pointer to the most recently parsed rule */ -}; - -/* Parse a single token */ -static void parseonetoken(struct pstate *psp) -{ - const char *x; - x = Strsafe(psp->tokenstart); /* Save the token permanently */ -#if 0 - printf("%s:%d: Token=[%s] state=%d\n",psp->filename,psp->tokenlineno, - x,psp->state); -#endif - switch( psp->state ){ - case INITIALIZE: - psp->prevrule = 0; - psp->preccounter = 0; - psp->firstrule = psp->lastrule = 0; - psp->gp->nrule = 0; - /* Fall thru to next case */ - case WAITING_FOR_DECL_OR_RULE: - if( x[0]=='%' ){ - psp->state = WAITING_FOR_DECL_KEYWORD; - }else if( islower(x[0]) ){ - psp->lhs = Symbol_new(x); - psp->nrhs = 0; - psp->lhsalias = 0; - psp->state = WAITING_FOR_ARROW; - }else if( x[0]=='{' ){ - if( psp->prevrule==0 ){ - ErrorMsg(psp->filename,psp->tokenlineno, -"There is no prior rule upon which to attach the code \ -fragment which begins on this line."); - psp->errorcnt++; - }else if( psp->prevrule->code!=0 ){ - ErrorMsg(psp->filename,psp->tokenlineno, -"Code fragment beginning on this line is not the first \ -to follow the previous rule."); - psp->errorcnt++; - }else{ - psp->prevrule->line = psp->tokenlineno; - psp->prevrule->code = &x[1]; - } - }else if( x[0]=='[' ){ - psp->state = PRECEDENCE_MARK_1; - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "Token \"%s\" should be either \"%%\" or a nonterminal name.", - x); - psp->errorcnt++; - } - break; - case PRECEDENCE_MARK_1: - if( !isupper(x[0]) ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "The precedence symbol must be a terminal."); - psp->errorcnt++; - }else if( psp->prevrule==0 ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "There is no prior rule to assign precedence \"[%s]\".",x); - psp->errorcnt++; - }else if( psp->prevrule->precsym!=0 ){ - ErrorMsg(psp->filename,psp->tokenlineno, -"Precedence mark on this line is not the first \ -to follow the previous rule."); - psp->errorcnt++; - }else{ - psp->prevrule->precsym = Symbol_new(x); - } - psp->state = PRECEDENCE_MARK_2; - break; - case PRECEDENCE_MARK_2: - if( x[0]!=']' ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "Missing \"]\" on precedence mark."); - psp->errorcnt++; - } - psp->state = WAITING_FOR_DECL_OR_RULE; - break; - case WAITING_FOR_ARROW: - if( x[0]==':' && x[1]==':' && x[2]=='=' ){ - psp->state = IN_RHS; - }else if( x[0]=='(' ){ - psp->state = LHS_ALIAS_1; - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "Expected to see a \":\" following the LHS symbol \"%s\".", - psp->lhs->name); - psp->errorcnt++; - psp->state = RESYNC_AFTER_RULE_ERROR; - } - break; - case LHS_ALIAS_1: - if( isalpha(x[0]) ){ - psp->lhsalias = x; - psp->state = LHS_ALIAS_2; - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "\"%s\" is not a valid alias for the LHS \"%s\"\n", - x,psp->lhs->name); - psp->errorcnt++; - psp->state = RESYNC_AFTER_RULE_ERROR; - } - break; - case LHS_ALIAS_2: - if( x[0]==')' ){ - psp->state = LHS_ALIAS_3; - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); - psp->errorcnt++; - psp->state = RESYNC_AFTER_RULE_ERROR; - } - break; - case LHS_ALIAS_3: - if( x[0]==':' && x[1]==':' && x[2]=='=' ){ - psp->state = IN_RHS; - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "Missing \"->\" following: \"%s(%s)\".", - psp->lhs->name,psp->lhsalias); - psp->errorcnt++; - psp->state = RESYNC_AFTER_RULE_ERROR; - } - break; - case IN_RHS: - if( x[0]=='.' ){ - struct rule *rp; - rp = (struct rule *)calloc( sizeof(struct rule) + - sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1); - if( rp==0 ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "Can't allocate enough memory for this rule."); - psp->errorcnt++; - psp->prevrule = 0; - }else{ - int i; - rp->ruleline = psp->tokenlineno; - rp->rhs = (struct symbol**)&rp[1]; - rp->rhsalias = (const char**)&(rp->rhs[psp->nrhs]); - for(i=0; i<psp->nrhs; i++){ - rp->rhs[i] = psp->rhs[i]; - rp->rhsalias[i] = psp->alias[i]; - } - rp->lhs = psp->lhs; - rp->lhsalias = psp->lhsalias; - rp->nrhs = psp->nrhs; - rp->code = 0; - rp->precsym = 0; - rp->index = psp->gp->nrule++; - rp->nextlhs = rp->lhs->rule; - rp->lhs->rule = rp; - rp->next = 0; - if( psp->firstrule==0 ){ - psp->firstrule = psp->lastrule = rp; - }else{ - psp->lastrule->next = rp; - psp->lastrule = rp; - } - psp->prevrule = rp; - } - psp->state = WAITING_FOR_DECL_OR_RULE; - }else if( isalpha(x[0]) ){ - if( psp->nrhs>=MAXRHS ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "Too many symbols on RHS of rule beginning at \"%s\".", - x); - psp->errorcnt++; - psp->state = RESYNC_AFTER_RULE_ERROR; - }else{ - psp->rhs[psp->nrhs] = Symbol_new(x); - psp->alias[psp->nrhs] = 0; - psp->nrhs++; - } - }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){ - struct symbol *msp = psp->rhs[psp->nrhs-1]; - if( msp->type!=MULTITERMINAL ){ - struct symbol *origsp = msp; - msp = (struct symbol *) calloc(1,sizeof(*msp)); - memset(msp, 0, sizeof(*msp)); - msp->type = MULTITERMINAL; - msp->nsubsym = 1; - msp->subsym = (struct symbol **) calloc(1,sizeof(struct symbol*)); - msp->subsym[0] = origsp; - msp->name = origsp->name; - psp->rhs[psp->nrhs-1] = msp; - } - msp->nsubsym++; - msp->subsym = (struct symbol **) realloc(msp->subsym, - sizeof(struct symbol*)*msp->nsubsym); - msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]); - if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "Cannot form a compound containing a non-terminal"); - psp->errorcnt++; - } - }else if( x[0]=='(' && psp->nrhs>0 ){ - psp->state = RHS_ALIAS_1; - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "Illegal character on RHS of rule: \"%s\".",x); - psp->errorcnt++; - psp->state = RESYNC_AFTER_RULE_ERROR; - } - break; - case RHS_ALIAS_1: - if( isalpha(x[0]) ){ - psp->alias[psp->nrhs-1] = x; - psp->state = RHS_ALIAS_2; - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n", - x,psp->rhs[psp->nrhs-1]->name); - psp->errorcnt++; - psp->state = RESYNC_AFTER_RULE_ERROR; - } - break; - case RHS_ALIAS_2: - if( x[0]==')' ){ - psp->state = IN_RHS; - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); - psp->errorcnt++; - psp->state = RESYNC_AFTER_RULE_ERROR; - } - break; - case WAITING_FOR_DECL_KEYWORD: - if( isalpha(x[0]) ){ - psp->declkeyword = x; - psp->declargslot = 0; - psp->decllinenoslot = 0; - psp->insertLineMacro = 1; - psp->state = WAITING_FOR_DECL_ARG; - if( strcmp(x,"name")==0 ){ - psp->declargslot = &(psp->gp->name); - psp->insertLineMacro = 0; - }else if( strcmp(x,"include")==0 ){ - psp->declargslot = &(psp->gp->include); - }else if( strcmp(x,"code")==0 ){ - psp->declargslot = &(psp->gp->extracode); - }else if( strcmp(x,"token_destructor")==0 ){ - psp->declargslot = &psp->gp->tokendest; - }else if( strcmp(x,"default_destructor")==0 ){ - psp->declargslot = &psp->gp->vardest; - }else if( strcmp(x,"token_prefix")==0 ){ - psp->declargslot = &psp->gp->tokenprefix; - psp->insertLineMacro = 0; - }else if( strcmp(x,"syntax_error")==0 ){ - psp->declargslot = &(psp->gp->error); - }else if( strcmp(x,"parse_accept")==0 ){ - psp->declargslot = &(psp->gp->accept); - }else if( strcmp(x,"parse_failure")==0 ){ - psp->declargslot = &(psp->gp->failure); - }else if( strcmp(x,"stack_overflow")==0 ){ - psp->declargslot = &(psp->gp->overflow); - }else if( strcmp(x,"extra_argument")==0 ){ - psp->declargslot = &(psp->gp->arg); - psp->insertLineMacro = 0; - }else if( strcmp(x,"token_type")==0 ){ - psp->declargslot = &(psp->gp->tokentype); - psp->insertLineMacro = 0; - }else if( strcmp(x,"default_type")==0 ){ - psp->declargslot = &(psp->gp->vartype); - psp->insertLineMacro = 0; - }else if( strcmp(x,"stack_size")==0 ){ - psp->declargslot = &(psp->gp->stacksize); - psp->insertLineMacro = 0; - }else if( strcmp(x,"start_symbol")==0 ){ - psp->declargslot = &(psp->gp->start); - psp->insertLineMacro = 0; - }else if( strcmp(x,"left")==0 ){ - psp->preccounter++; - psp->declassoc = LEFT; - psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; - }else if( strcmp(x,"right")==0 ){ - psp->preccounter++; - psp->declassoc = RIGHT; - psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; - }else if( strcmp(x,"nonassoc")==0 ){ - psp->preccounter++; - psp->declassoc = NONE; - psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; - }else if( strcmp(x,"destructor")==0 ){ - psp->state = WAITING_FOR_DESTRUCTOR_SYMBOL; - }else if( strcmp(x,"type")==0 ){ - psp->state = WAITING_FOR_DATATYPE_SYMBOL; - }else if( strcmp(x,"fallback")==0 ){ - psp->fallback = 0; - psp->state = WAITING_FOR_FALLBACK_ID; - }else if( strcmp(x,"wildcard")==0 ){ - psp->state = WAITING_FOR_WILDCARD_ID; - }else if( strcmp(x,"token_class")==0 ){ - psp->state = WAITING_FOR_CLASS_ID; - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "Unknown declaration keyword: \"%%%s\".",x); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - } - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "Illegal declaration keyword: \"%s\".",x); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - } - break; - case WAITING_FOR_DESTRUCTOR_SYMBOL: - if( !isalpha(x[0]) ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "Symbol name missing after %%destructor keyword"); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - }else{ - struct symbol *sp = Symbol_new(x); - psp->declargslot = &sp->destructor; - psp->decllinenoslot = &sp->destLineno; - psp->insertLineMacro = 1; - psp->state = WAITING_FOR_DECL_ARG; - } - break; - case WAITING_FOR_DATATYPE_SYMBOL: - if( !isalpha(x[0]) ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "Symbol name missing after %%type keyword"); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - }else{ - struct symbol *sp = Symbol_find(x); - if((sp) && (sp->datatype)){ - ErrorMsg(psp->filename,psp->tokenlineno, - "Symbol %%type \"%s\" already defined", x); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - }else{ - if (!sp){ - sp = Symbol_new(x); - } - psp->declargslot = &sp->datatype; - psp->insertLineMacro = 0; - psp->state = WAITING_FOR_DECL_ARG; - } - } - break; - case WAITING_FOR_PRECEDENCE_SYMBOL: - if( x[0]=='.' ){ - psp->state = WAITING_FOR_DECL_OR_RULE; - }else if( isupper(x[0]) ){ - struct symbol *sp; - sp = Symbol_new(x); - if( sp->prec>=0 ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "Symbol \"%s\" has already be given a precedence.",x); - psp->errorcnt++; - }else{ - sp->prec = psp->preccounter; - sp->assoc = psp->declassoc; - } - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "Can't assign a precedence to \"%s\".",x); - psp->errorcnt++; - } - break; - case WAITING_FOR_DECL_ARG: - if( x[0]=='{' || x[0]=='\"' || isalnum(x[0]) ){ - const char *zOld, *zNew; - char *zBuf, *z; - int nOld, n, nLine = 0, nNew, nBack; - int addLineMacro; - char zLine[50]; - zNew = x; - if( zNew[0]=='"' || zNew[0]=='{' ) zNew++; - nNew = lemonStrlen(zNew); - if( *psp->declargslot ){ - zOld = *psp->declargslot; - }else{ - zOld = ""; - } - nOld = lemonStrlen(zOld); - n = nOld + nNew + 20; - addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && - (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0); - if( addLineMacro ){ - for(z=psp->filename, nBack=0; *z; z++){ - if( *z=='\\' ) nBack++; - } - lemon_sprintf(zLine, "#line %d ", psp->tokenlineno); - nLine = lemonStrlen(zLine); - n += nLine + lemonStrlen(psp->filename) + nBack; - } - *psp->declargslot = (char *) realloc(*psp->declargslot, n); - zBuf = *psp->declargslot + nOld; - if( addLineMacro ){ - if( nOld && zBuf[-1]!='\n' ){ - *(zBuf++) = '\n'; - } - memcpy(zBuf, zLine, nLine); - zBuf += nLine; - *(zBuf++) = '"'; - for(z=psp->filename; *z; z++){ - if( *z=='\\' ){ - *(zBuf++) = '\\'; - } - *(zBuf++) = *z; - } - *(zBuf++) = '"'; - *(zBuf++) = '\n'; - } - if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){ - psp->decllinenoslot[0] = psp->tokenlineno; - } - memcpy(zBuf, zNew, nNew); - zBuf += nNew; - *zBuf = 0; - psp->state = WAITING_FOR_DECL_OR_RULE; - }else{ - ErrorMsg(psp->filename,psp->tokenlineno, - "Illegal argument to %%%s: %s",psp->declkeyword,x); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - } - break; - case WAITING_FOR_FALLBACK_ID: - if( x[0]=='.' ){ - psp->state = WAITING_FOR_DECL_OR_RULE; - }else if( !isupper(x[0]) ){ - ErrorMsg(psp->filename, psp->tokenlineno, - "%%fallback argument \"%s\" should be a token", x); - psp->errorcnt++; - }else{ - struct symbol *sp = Symbol_new(x); - if( psp->fallback==0 ){ - psp->fallback = sp; - }else if( sp->fallback ){ - ErrorMsg(psp->filename, psp->tokenlineno, - "More than one fallback assigned to token %s", x); - psp->errorcnt++; - }else{ - sp->fallback = psp->fallback; - psp->gp->has_fallback = 1; - } - } - break; - case WAITING_FOR_WILDCARD_ID: - if( x[0]=='.' ){ - psp->state = WAITING_FOR_DECL_OR_RULE; - }else if( !isupper(x[0]) ){ - ErrorMsg(psp->filename, psp->tokenlineno, - "%%wildcard argument \"%s\" should be a token", x); - psp->errorcnt++; - }else{ - struct symbol *sp = Symbol_new(x); - if( psp->gp->wildcard==0 ){ - psp->gp->wildcard = sp; - }else{ - ErrorMsg(psp->filename, psp->tokenlineno, - "Extra wildcard to token: %s", x); - psp->errorcnt++; - } - } - break; - case WAITING_FOR_CLASS_ID: - if( !islower(x[0]) ){ - ErrorMsg(psp->filename, psp->tokenlineno, - "%%token_class must be followed by an identifier: ", x); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - }else if( Symbol_find(x) ){ - ErrorMsg(psp->filename, psp->tokenlineno, - "Symbol \"%s\" already used", x); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - }else{ - psp->tkclass = Symbol_new(x); - psp->tkclass->type = MULTITERMINAL; - psp->state = WAITING_FOR_CLASS_TOKEN; - } - break; - case WAITING_FOR_CLASS_TOKEN: - if( x[0]=='.' ){ - psp->state = WAITING_FOR_DECL_OR_RULE; - }else if( isupper(x[0]) || ((x[0]=='|' || x[0]=='/') && isupper(x[1])) ){ - struct symbol *msp = psp->tkclass; - msp->nsubsym++; - msp->subsym = (struct symbol **) realloc(msp->subsym, - sizeof(struct symbol*)*msp->nsubsym); - if( !isupper(x[0]) ) x++; - msp->subsym[msp->nsubsym-1] = Symbol_new(x); - }else{ - ErrorMsg(psp->filename, psp->tokenlineno, - "%%token_class argument \"%s\" should be a token", x); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - } - break; - case RESYNC_AFTER_RULE_ERROR: -/* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; -** break; */ - case RESYNC_AFTER_DECL_ERROR: - if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; - if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD; - break; - } -} - -/* Run the preprocessor over the input file text. The global variables -** azDefine[0] through azDefine[nDefine-1] contains the names of all defined -** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and -** comments them out. Text in between is also commented out as appropriate. -*/ -static void preprocess_input(char *z){ - int i, j, k, n; - int exclude = 0; - int start = 0; - int lineno = 1; - int start_lineno = 1; - for(i=0; z[i]; i++){ - if( z[i]=='\n' ) lineno++; - if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue; - if( strncmp(&z[i],"%endif",6)==0 && isspace(z[i+6]) ){ - if( exclude ){ - exclude--; - if( exclude==0 ){ - for(j=start; j<i; j++) if( z[j]!='\n' ) z[j] = ' '; - } - } - for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; - }else if( (strncmp(&z[i],"%ifdef",6)==0 && isspace(z[i+6])) - || (strncmp(&z[i],"%ifndef",7)==0 && isspace(z[i+7])) ){ - if( exclude ){ - exclude++; - }else{ - for(j=i+7; isspace(z[j]); j++){} - for(n=0; z[j+n] && !isspace(z[j+n]); n++){} - exclude = 1; - for(k=0; k<nDefine; k++){ - if( strncmp(azDefine[k],&z[j],n)==0 && lemonStrlen(azDefine[k])==n ){ - exclude = 0; - break; - } - } - if( z[i+3]=='n' ) exclude = !exclude; - if( exclude ){ - start = i; - start_lineno = lineno; - } - } - for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; - } - } - if( exclude ){ - fprintf(stderr,"unterminated %%ifdef starting on line %d\n", start_lineno); - exit(1); - } -} - -/* In spite of its name, this function is really a scanner. It read -** in the entire input file (all at once) then tokenizes it. Each -** token is passed to the function "parseonetoken" which builds all -** the appropriate data structures in the global state vector "gp". -*/ -void Parse(struct lemon *gp) -{ - struct pstate ps; - FILE *fp; - char *filebuf; - unsigned int filesize; - int lineno; - int c; - char *cp, *nextcp; - int startline = 0; - - memset(&ps, '\0', sizeof(ps)); - ps.gp = gp; - ps.filename = gp->filename; - ps.errorcnt = 0; - ps.state = INITIALIZE; - - /* Begin by reading the input file */ - fp = fopen(ps.filename,"rb"); - if( fp==0 ){ - ErrorMsg(ps.filename,0,"Can't open this file for reading."); - gp->errorcnt++; - return; - } - fseek(fp,0,2); - filesize = ftell(fp); - rewind(fp); - filebuf = (char *)malloc( filesize+1 ); - if( filesize>100000000 || filebuf==0 ){ - ErrorMsg(ps.filename,0,"Input file too large."); - gp->errorcnt++; - fclose(fp); - return; - } - if( fread(filebuf,1,filesize,fp)!=filesize ){ - ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.", - filesize); - free(filebuf); - gp->errorcnt++; - fclose(fp); - return; - } - fclose(fp); - filebuf[filesize] = 0; - - /* Make an initial pass through the file to handle %ifdef and %ifndef */ - preprocess_input(filebuf); - - /* Now scan the text of the input file */ - lineno = 1; - for(cp=filebuf; (c= *cp)!=0; ){ - if( c=='\n' ) lineno++; /* Keep track of the line number */ - if( isspace(c) ){ cp++; continue; } /* Skip all white space */ - if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */ - cp+=2; - while( (c= *cp)!=0 && c!='\n' ) cp++; - continue; - } - if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */ - cp+=2; - while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){ - if( c=='\n' ) lineno++; - cp++; - } - if( c ) cp++; - continue; - } - ps.tokenstart = cp; /* Mark the beginning of the token */ - ps.tokenlineno = lineno; /* Linenumber on which token begins */ - if( c=='\"' ){ /* String literals */ - cp++; - while( (c= *cp)!=0 && c!='\"' ){ - if( c=='\n' ) lineno++; - cp++; - } - if( c==0 ){ - ErrorMsg(ps.filename,startline, -"String starting on this line is not terminated before the end of the file."); - ps.errorcnt++; - nextcp = cp; - }else{ - nextcp = cp+1; - } - }else if( c=='{' ){ /* A block of C code */ - int level; - cp++; - for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){ - if( c=='\n' ) lineno++; - else if( c=='{' ) level++; - else if( c=='}' ) level--; - else if( c=='/' && cp[1]=='*' ){ /* Skip comments */ - int prevc; - cp = &cp[2]; - prevc = 0; - while( (c= *cp)!=0 && (c!='/' || prevc!='*') ){ - if( c=='\n' ) lineno++; - prevc = c; - cp++; - } - }else if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments too */ - cp = &cp[2]; - while( (c= *cp)!=0 && c!='\n' ) cp++; - if( c ) lineno++; - }else if( c=='\'' || c=='\"' ){ /* String a character literals */ - int startchar, prevc; - startchar = c; - prevc = 0; - for(cp++; (c= *cp)!=0 && (c!=startchar || prevc=='\\'); cp++){ - if( c=='\n' ) lineno++; - if( prevc=='\\' ) prevc = 0; - else prevc = c; - } - } - } - if( c==0 ){ - ErrorMsg(ps.filename,ps.tokenlineno, -"C code starting on this line is not terminated before the end of the file."); - ps.errorcnt++; - nextcp = cp; - }else{ - nextcp = cp+1; - } - }else if( isalnum(c) ){ /* Identifiers */ - while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++; - nextcp = cp; - }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */ - cp += 3; - nextcp = cp; - }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){ - cp += 2; - while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++; - nextcp = cp; - }else{ /* All other (one character) operators */ - cp++; - nextcp = cp; - } - c = *cp; - *cp = 0; /* Null terminate the token */ - parseonetoken(&ps); /* Parse the token */ - *cp = (char)c; /* Restore the buffer */ - cp = nextcp; - } - free(filebuf); /* Release the buffer after parsing */ - gp->rule = ps.firstrule; - gp->errorcnt = ps.errorcnt; -} -/*************************** From the file "plink.c" *********************/ -/* -** Routines processing configuration follow-set propagation links -** in the LEMON parser generator. -*/ -static struct plink *plink_freelist = 0; - -/* Allocate a new plink */ -struct plink *Plink_new(){ - struct plink *newlink; - - if( plink_freelist==0 ){ - int i; - int amt = 100; - plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) ); - if( plink_freelist==0 ){ - fprintf(stderr, - "Unable to allocate memory for a new follow-set propagation link.\n"); - exit(1); - } - for(i=0; i<amt-1; i++) plink_freelist[i].next = &plink_freelist[i+1]; - plink_freelist[amt-1].next = 0; - } - newlink = plink_freelist; - plink_freelist = plink_freelist->next; - return newlink; -} - -/* Add a plink to a plink list */ -void Plink_add(struct plink **plpp, struct config *cfp) -{ - struct plink *newlink; - newlink = Plink_new(); - newlink->next = *plpp; - *plpp = newlink; - newlink->cfp = cfp; -} - -/* Transfer every plink on the list "from" to the list "to" */ -void Plink_copy(struct plink **to, struct plink *from) -{ - struct plink *nextpl; - while( from ){ - nextpl = from->next; - from->next = *to; - *to = from; - from = nextpl; - } -} - -/* Delete every plink on the list */ -void Plink_delete(struct plink *plp) -{ - struct plink *nextpl; - - while( plp ){ - nextpl = plp->next; - plp->next = plink_freelist; - plink_freelist = plp; - plp = nextpl; - } -} -/*********************** From the file "report.c" **************************/ -/* -** Procedures for generating reports and tables in the LEMON parser generator. -*/ - -/* Generate a filename with the given suffix. Space to hold the -** name comes from malloc() and must be freed by the calling -** function. -*/ -PRIVATE char *file_makename(struct lemon *lemp, const char *suffix) -{ - char *name; - char *cp; - - name = (char*)malloc( lemonStrlen(lemp->filename) + lemonStrlen(suffix) + 5 ); - if( name==0 ){ - fprintf(stderr,"Can't allocate space for a filename.\n"); - exit(1); - } - lemon_strcpy(name,lemp->filename); - cp = strrchr(name,'.'); - if( cp ) *cp = 0; - lemon_strcat(name,suffix); - return name; -} - -/* Open a file with a name based on the name of the input file, -** but with a different (specified) suffix, and return a pointer -** to the stream */ -PRIVATE FILE *file_open( - struct lemon *lemp, - const char *suffix, - const char *mode -){ - FILE *fp; - - if( lemp->outname ) free(lemp->outname); - lemp->outname = file_makename(lemp, suffix); - fp = fopen(lemp->outname,mode); - if( fp==0 && *mode=='w' ){ - fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname); - lemp->errorcnt++; - return 0; - } - return fp; -} - -/* Duplicate the input file without comments and without actions -** on rules */ -void Reprint(struct lemon *lemp) -{ - struct rule *rp; - struct symbol *sp; - int i, j, maxlen, len, ncolumns, skip; - printf("// Reprint of input file \"%s\".\n// Symbols:\n",lemp->filename); - maxlen = 10; - for(i=0; i<lemp->nsymbol; i++){ - sp = lemp->symbols[i]; - len = lemonStrlen(sp->name); - if( len>maxlen ) maxlen = len; - } - ncolumns = 76/(maxlen+5); - if( ncolumns<1 ) ncolumns = 1; - skip = (lemp->nsymbol + ncolumns - 1)/ncolumns; - for(i=0; i<skip; i++){ - printf("//"); - for(j=i; j<lemp->nsymbol; j+=skip){ - sp = lemp->symbols[j]; - assert( sp->index==j ); - printf(" %3d %-*.*s",j,maxlen,maxlen,sp->name); - } - printf("\n"); - } - for(rp=lemp->rule; rp; rp=rp->next){ - printf("%s",rp->lhs->name); - /* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */ - printf(" ::="); - for(i=0; i<rp->nrhs; i++){ - sp = rp->rhs[i]; - if( sp->type==MULTITERMINAL ){ - printf(" %s", sp->subsym[0]->name); - for(j=1; j<sp->nsubsym; j++){ - printf("|%s", sp->subsym[j]->name); - } - }else{ - printf(" %s", sp->name); - } - /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */ - } - printf("."); - if( rp->precsym ) printf(" [%s]",rp->precsym->name); - /* if( rp->code ) printf("\n %s",rp->code); */ - printf("\n"); - } -} - -/* Print a single rule. -*/ -void RulePrint(FILE *fp, struct rule *rp, int iCursor){ - struct symbol *sp; - int i, j; - fprintf(fp,"%s ::=",rp->lhs->name); - for(i=0; i<=rp->nrhs; i++){ - if( i==iCursor ) fprintf(fp," *"); - if( i==rp->nrhs ) break; - sp = rp->rhs[i]; - if( sp->type==MULTITERMINAL ){ - fprintf(fp," %s", sp->subsym[0]->name); - for(j=1; j<sp->nsubsym; j++){ - fprintf(fp,"|%s",sp->subsym[j]->name); - } - }else{ - fprintf(fp," %s", sp->name); - } - } -} - -/* Print the rule for a configuration. -*/ -void ConfigPrint(FILE *fp, struct config *cfp){ - RulePrint(fp, cfp->rp, cfp->dot); -} - -/* #define TEST */ -#if 0 -/* Print a set */ -PRIVATE void SetPrint(out,set,lemp) -FILE *out; -char *set; -struct lemon *lemp; -{ - int i; - char *spacer; - spacer = ""; - fprintf(out,"%12s[",""); - for(i=0; i<lemp->nterminal; i++){ - if( SetFind(set,i) ){ - fprintf(out,"%s%s",spacer,lemp->symbols[i]->name); - spacer = " "; - } - } - fprintf(out,"]\n"); -} - -/* Print a plink chain */ -PRIVATE void PlinkPrint(out,plp,tag) -FILE *out; -struct plink *plp; -char *tag; -{ - while( plp ){ - fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->statenum); - ConfigPrint(out,plp->cfp); - fprintf(out,"\n"); - plp = plp->next; - } -} -#endif - -/* Print an action to the given file descriptor. Return FALSE if -** nothing was actually printed. -*/ -int PrintAction( - struct action *ap, /* The action to print */ - FILE *fp, /* Print the action here */ - int indent /* Indent by this amount */ -){ - int result = 1; - switch( ap->type ){ - case SHIFT: { - struct state *stp = ap->x.stp; - fprintf(fp,"%*s shift %-7d",indent,ap->sp->name,stp->statenum); - break; - } - case REDUCE: { - struct rule *rp = ap->x.rp; - fprintf(fp,"%*s reduce %-7d",indent,ap->sp->name,rp->index); - RulePrint(fp, rp, -1); - break; - } - case SHIFTREDUCE: { - struct rule *rp = ap->x.rp; - fprintf(fp,"%*s shift-reduce %-7d",indent,ap->sp->name,rp->index); - RulePrint(fp, rp, -1); - break; - } - case ACCEPT: - fprintf(fp,"%*s accept",indent,ap->sp->name); - break; - case ERROR: - fprintf(fp,"%*s error",indent,ap->sp->name); - break; - case SRCONFLICT: - case RRCONFLICT: - fprintf(fp,"%*s reduce %-7d ** Parsing conflict **", - indent,ap->sp->name,ap->x.rp->index); - break; - case SSCONFLICT: - fprintf(fp,"%*s shift %-7d ** Parsing conflict **", - indent,ap->sp->name,ap->x.stp->statenum); - break; - case SH_RESOLVED: - if( showPrecedenceConflict ){ - fprintf(fp,"%*s shift %-7d -- dropped by precedence", - indent,ap->sp->name,ap->x.stp->statenum); - }else{ - result = 0; - } - break; - case RD_RESOLVED: - if( showPrecedenceConflict ){ - fprintf(fp,"%*s reduce %-7d -- dropped by precedence", - indent,ap->sp->name,ap->x.rp->index); - }else{ - result = 0; - } - break; - case NOT_USED: - result = 0; - break; - } - return result; -} - -/* Generate the "*.out" log file */ -void ReportOutput(struct lemon *lemp) -{ - int i; - struct state *stp; - struct config *cfp; - struct action *ap; - FILE *fp; - - fp = file_open(lemp,".out","wb"); - if( fp==0 ) return; - for(i=0; i<lemp->nxstate; i++){ - stp = lemp->sorted[i]; - fprintf(fp,"State %d:\n",stp->statenum); - if( lemp->basisflag ) cfp=stp->bp; - else cfp=stp->cfp; - while( cfp ){ - char buf[20]; - if( cfp->dot==cfp->rp->nrhs ){ - lemon_sprintf(buf,"(%d)",cfp->rp->index); - fprintf(fp," %5s ",buf); - }else{ - fprintf(fp," "); - } - ConfigPrint(fp,cfp); - fprintf(fp,"\n"); -#if 0 - SetPrint(fp,cfp->fws,lemp); - PlinkPrint(fp,cfp->fplp,"To "); - PlinkPrint(fp,cfp->bplp,"From"); -#endif - if( lemp->basisflag ) cfp=cfp->bp; - else cfp=cfp->next; - } - fprintf(fp,"\n"); - for(ap=stp->ap; ap; ap=ap->next){ - if( PrintAction(ap,fp,30) ) fprintf(fp,"\n"); - } - fprintf(fp,"\n"); - } - fprintf(fp, "----------------------------------------------------\n"); - fprintf(fp, "Symbols:\n"); - for(i=0; i<lemp->nsymbol; i++){ - int j; - struct symbol *sp; - - sp = lemp->symbols[i]; - fprintf(fp, " %3d: %s", i, sp->name); - if( sp->type==NONTERMINAL ){ - fprintf(fp, ":"); - if( sp->lambda ){ - fprintf(fp, " <lambda>"); - } - for(j=0; j<lemp->nterminal; j++){ - if( sp->firstset && SetFind(sp->firstset, j) ){ - fprintf(fp, " %s", lemp->symbols[j]->name); - } - } - } - fprintf(fp, "\n"); - } - fclose(fp); - return; -} - -/* Search for the file "name" which is in the same directory as -** the exacutable */ -PRIVATE char *pathsearch(char *argv0, char *name, int modemask) -{ - const char *pathlist; - char *pathbufptr; - char *pathbuf; - char *path,*cp; - char c; - -#ifdef __WIN32__ - cp = strrchr(argv0,'\\'); -#else - cp = strrchr(argv0,'/'); -#endif - if( cp ){ - c = *cp; - *cp = 0; - path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 ); - if( path ) lemon_sprintf(path,"%s/%s",argv0,name); - *cp = c; - }else{ - pathlist = getenv("PATH"); - if( pathlist==0 ) pathlist = ".:/bin:/usr/bin"; - pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 ); - path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 ); - if( (pathbuf != 0) && (path!=0) ){ - pathbufptr = pathbuf; - lemon_strcpy(pathbuf, pathlist); - while( *pathbuf ){ - cp = strchr(pathbuf,':'); - if( cp==0 ) cp = &pathbuf[lemonStrlen(pathbuf)]; - c = *cp; - *cp = 0; - lemon_sprintf(path,"%s/%s",pathbuf,name); - *cp = c; - if( c==0 ) pathbuf[0] = 0; - else pathbuf = &cp[1]; - if( access(path,modemask)==0 ) break; - } - free(pathbufptr); - } - } - return path; -} - -/* Given an action, compute the integer value for that action -** which is to be put in the action table of the generated machine. -** Return negative if no action should be generated. -*/ -PRIVATE int compute_action(struct lemon *lemp, struct action *ap) -{ - int act; - switch( ap->type ){ - case SHIFT: act = ap->x.stp->statenum; break; - case SHIFTREDUCE: act = ap->x.rp->index + lemp->nstate; break; - case REDUCE: act = ap->x.rp->index + lemp->nstate+lemp->nrule; break; - case ERROR: act = lemp->nstate + lemp->nrule*2; break; - case ACCEPT: act = lemp->nstate + lemp->nrule*2 + 1; break; - default: act = -1; break; - } - return act; -} - -#define LINESIZE 1000 -/* The next cluster of routines are for reading the template file -** and writing the results to the generated parser */ -/* The first function transfers data from "in" to "out" until -** a line is seen which begins with "%%". The line number is -** tracked. -** -** if name!=0, then any word that begin with "Parse" is changed to -** begin with *name instead. -*/ -PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno) -{ - int i, iStart; - char line[LINESIZE]; - while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){ - (*lineno)++; - iStart = 0; - if( name ){ - for(i=0; line[i]; i++){ - if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0 - && (i==0 || !isalpha(line[i-1])) - ){ - if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]); - fprintf(out,"%s",name); - i += 4; - iStart = i+1; - } - } - } - fprintf(out,"%s",&line[iStart]); - } -} - -/* The next function finds the template file and opens it, returning -** a pointer to the opened file. */ -PRIVATE FILE *tplt_open(struct lemon *lemp) -{ - static char templatename[] = "lempar.c"; - char buf[1000]; - FILE *in; - char *tpltname; - char *cp; - - /* first, see if user specified a template filename on the command line. */ - if (user_templatename != 0) { - if( access(user_templatename,004)==-1 ){ - fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", - user_templatename); - lemp->errorcnt++; - return 0; - } - in = fopen(user_templatename,"rb"); - if( in==0 ){ - fprintf(stderr,"Can't open the template file \"%s\".\n", - user_templatename); - lemp->errorcnt++; - return 0; - } - return in; - } - - cp = strrchr(lemp->filename,'.'); - if( cp ){ - lemon_sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename); - }else{ - lemon_sprintf(buf,"%s.lt",lemp->filename); - } - if( access(buf,004)==0 ){ - tpltname = buf; - }else if( access(templatename,004)==0 ){ - tpltname = templatename; - }else{ - tpltname = pathsearch(lemp->argv0,templatename,0); - } - if( tpltname==0 ){ - fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", - templatename); - lemp->errorcnt++; - return 0; - } - in = fopen(tpltname,"rb"); - if( in==0 ){ - fprintf(stderr,"Can't open the template file \"%s\".\n",templatename); - lemp->errorcnt++; - return 0; - } - return in; -} - -/* Print a #line directive line to the output file. */ -PRIVATE void tplt_linedir(FILE *out, int lineno, char *filename) -{ - fprintf(out,"#line %d \"",lineno); - while( *filename ){ - if( *filename == '\\' ) putc('\\',out); - putc(*filename,out); - filename++; - } - fprintf(out,"\"\n"); -} - -/* Print a string to the file and keep the linenumber up to date */ -PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int *lineno) -{ - if( str==0 ) return; - while( *str ){ - putc(*str,out); - if( *str=='\n' ) (*lineno)++; - str++; - } - if( str[-1]!='\n' ){ - putc('\n',out); - (*lineno)++; - } - if (!lemp->nolinenosflag) { - (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); - } - return; -} - -/* -** The following routine emits code for the destructor for the -** symbol sp -*/ -void emit_destructor_code( - FILE *out, - struct symbol *sp, - struct lemon *lemp, - int *lineno -){ - char *cp = 0; - - if( sp->type==TERMINAL ){ - cp = lemp->tokendest; - if( cp==0 ) return; - fprintf(out,"{\n"); (*lineno)++; - }else if( sp->destructor ){ - cp = sp->destructor; - fprintf(out,"{\n"); (*lineno)++; - if( !lemp->nolinenosflag ){ - (*lineno)++; - tplt_linedir(out,sp->destLineno,lemp->filename); - } - }else if( lemp->vardest ){ - cp = lemp->vardest; - if( cp==0 ) return; - fprintf(out,"{\n"); (*lineno)++; - }else{ - assert( 0 ); /* Cannot happen */ - } - for(; *cp; cp++){ - if( *cp=='$' && cp[1]=='$' ){ - fprintf(out,"(yypminor->yy%d)",sp->dtnum); - cp++; - continue; - } - if( *cp=='\n' ) (*lineno)++; - fputc(*cp,out); - } - fprintf(out,"\n"); (*lineno)++; - if (!lemp->nolinenosflag) { - (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); - } - fprintf(out,"}\n"); (*lineno)++; - return; -} - -/* -** Return TRUE (non-zero) if the given symbol has a destructor. -*/ -int has_destructor(struct symbol *sp, struct lemon *lemp) -{ - int ret; - if( sp->type==TERMINAL ){ - ret = lemp->tokendest!=0; - }else{ - ret = lemp->vardest!=0 || sp->destructor!=0; - } - return ret; -} - -/* -** Append text to a dynamically allocated string. If zText is 0 then -** reset the string to be empty again. Always return the complete text -** of the string (which is overwritten with each call). -** -** n bytes of zText are stored. If n==0 then all of zText up to the first -** \000 terminator is stored. zText can contain up to two instances of -** %d. The values of p1 and p2 are written into the first and second -** %d. -** -** If n==-1, then the previous character is overwritten. -*/ -PRIVATE char *append_str(const char *zText, int n, int p1, int p2){ - static char empty[1] = { 0 }; - static char *z = 0; - static int alloced = 0; - static int used = 0; - int c; - char zInt[40]; - if( zText==0 ){ - used = 0; - return z; - } - if( n<=0 ){ - if( n<0 ){ - used += n; - assert( used>=0 ); - } - n = lemonStrlen(zText); - } - if( (int) (n+sizeof(zInt)*2+used) >= alloced ){ - alloced = n + sizeof(zInt)*2 + used + 200; - z = (char *) realloc(z, alloced); - } - if( z==0 ) return empty; - while( n-- > 0 ){ - c = *(zText++); - if( c=='%' && n>0 && zText[0]=='d' ){ - lemon_sprintf(zInt, "%d", p1); - p1 = p2; - lemon_strcpy(&z[used], zInt); - used += lemonStrlen(&z[used]); - zText++; - n--; - }else{ - z[used++] = (char)c; - } - } - z[used] = 0; - return z; -} - -/* -** zCode is a string that is the action associated with a rule. Expand -** the symbols in this string so that the refer to elements of the parser -** stack. -*/ -PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ - char *cp, *xp; - int i; - char lhsused = 0; /* True if the LHS element has been used */ - char used[MAXRHS]; /* True for each RHS element which is used */ - - for(i=0; i<rp->nrhs; i++) used[i] = 0; - lhsused = 0; - - if( rp->code==0 ){ - static char newlinestr[2] = { '\n', '\0' }; - rp->code = newlinestr; - rp->line = rp->ruleline; - } - - append_str(0,0,0,0); - - /* This const cast is wrong but harmless, if we're careful. */ - for(cp=(char *)rp->code; *cp; cp++){ - if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){ - char saved; - for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++); - saved = *xp; - *xp = 0; - if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){ - append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0); - cp = xp; - lhsused = 1; - }else{ - for(i=0; i<rp->nrhs; i++){ - if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){ - if( cp!=rp->code && cp[-1]=='@' ){ - /* If the argument is of the form @X then substituted - ** the token number of X, not the value of X */ - append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0); - }else{ - struct symbol *sp = rp->rhs[i]; - int dtnum; - if( sp->type==MULTITERMINAL ){ - dtnum = sp->subsym[0]->dtnum; - }else{ - dtnum = sp->dtnum; - } - append_str("yymsp[%d].minor.yy%d",0,i-rp->nrhs+1, dtnum); - } - cp = xp; - used[i] = 1; - break; - } - } - } - *xp = saved; - } - append_str(cp, 1, 0, 0); - } /* End loop */ - - /* Check to make sure the LHS has been used */ - if( rp->lhsalias && !lhsused ){ - ErrorMsg(lemp->filename,rp->ruleline, - "Label \"%s\" for \"%s(%s)\" is never used.", - rp->lhsalias,rp->lhs->name,rp->lhsalias); - lemp->errorcnt++; - } - - /* Generate destructor code for RHS symbols which are not used in the - ** reduce code */ - for(i=0; i<rp->nrhs; i++){ - if( rp->rhsalias[i] && !used[i] ){ - ErrorMsg(lemp->filename,rp->ruleline, - "Label %s for \"%s(%s)\" is never used.", - rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]); - lemp->errorcnt++; - }else if( rp->rhsalias[i]==0 ){ - if( has_destructor(rp->rhs[i],lemp) ){ - append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, - rp->rhs[i]->index,i-rp->nrhs+1); - }else{ - /* No destructor defined for this term */ - } - } - } - if( rp->code ){ - cp = append_str(0,0,0,0); - rp->code = Strsafe(cp?cp:""); - } -} - -/* -** Generate code which executes when the rule "rp" is reduced. Write -** the code to "out". Make sure lineno stays up-to-date. -*/ -PRIVATE void emit_code( - FILE *out, - struct rule *rp, - struct lemon *lemp, - int *lineno -){ - const char *cp; - - /* Generate code to do the reduce action */ - if( rp->code ){ - if( !lemp->nolinenosflag ){ - (*lineno)++; - tplt_linedir(out,rp->line,lemp->filename); - } - fprintf(out,"{%s",rp->code); - for(cp=rp->code; *cp; cp++){ - if( *cp=='\n' ) (*lineno)++; - } /* End loop */ - fprintf(out,"}\n"); (*lineno)++; - if( !lemp->nolinenosflag ){ - (*lineno)++; - tplt_linedir(out,*lineno,lemp->outname); - } - } /* End if( rp->code ) */ - - return; -} - -/* -** Print the definition of the union used for the parser's data stack. -** This union contains fields for every possible data type for tokens -** and nonterminals. In the process of computing and printing this -** union, also set the ".dtnum" field of every terminal and nonterminal -** symbol. -*/ -void print_stack_union( - FILE *out, /* The output stream */ - struct lemon *lemp, /* The main info structure for this parser */ - int *plineno, /* Pointer to the line number */ - int mhflag /* True if generating makeheaders output */ -){ - int lineno = *plineno; /* The line number of the output */ - char **types; /* A hash table of datatypes */ - int arraysize; /* Size of the "types" array */ - int maxdtlength; /* Maximum length of any ".datatype" field. */ - char *stddt; /* Standardized name for a datatype */ - int i,j; /* Loop counters */ - unsigned hash; /* For hashing the name of a type */ - const char *name; /* Name of the parser */ - - /* Allocate and initialize types[] and allocate stddt[] */ - arraysize = lemp->nsymbol * 2; - types = (char**)calloc( arraysize, sizeof(char*) ); - if( types==0 ){ - fprintf(stderr,"Out of memory.\n"); - exit(1); - } - for(i=0; i<arraysize; i++) types[i] = 0; - maxdtlength = 0; - if( lemp->vartype ){ - maxdtlength = lemonStrlen(lemp->vartype); - } - for(i=0; i<lemp->nsymbol; i++){ - int len; - struct symbol *sp = lemp->symbols[i]; - if( sp->datatype==0 ) continue; - len = lemonStrlen(sp->datatype); - if( len>maxdtlength ) maxdtlength = len; - } - stddt = (char*)malloc( maxdtlength*2 + 1 ); - if( stddt==0 ){ - fprintf(stderr,"Out of memory.\n"); - exit(1); - } - - /* Build a hash table of datatypes. The ".dtnum" field of each symbol - ** is filled in with the hash index plus 1. A ".dtnum" value of 0 is - ** used for terminal symbols. If there is no %default_type defined then - ** 0 is also used as the .dtnum value for nonterminals which do not specify - ** a datatype using the %type directive. - */ - for(i=0; i<lemp->nsymbol; i++){ - struct symbol *sp = lemp->symbols[i]; - char *cp; - if( sp==lemp->errsym ){ - sp->dtnum = arraysize+1; - continue; - } - if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){ - sp->dtnum = 0; - continue; - } - cp = sp->datatype; - if( cp==0 ) cp = lemp->vartype; - j = 0; - while( isspace(*cp) ) cp++; - while( *cp ) stddt[j++] = *cp++; - while( j>0 && isspace(stddt[j-1]) ) j--; - stddt[j] = 0; - if( lemp->tokentype && strcmp(stddt, lemp->tokentype)==0 ){ - sp->dtnum = 0; - continue; - } - hash = 0; - for(j=0; stddt[j]; j++){ - hash = hash*53 + stddt[j]; - } - hash = (hash & 0x7fffffff)%arraysize; - while( types[hash] ){ - if( strcmp(types[hash],stddt)==0 ){ - sp->dtnum = hash + 1; - break; - } - hash++; - if( hash>=(unsigned)arraysize ) hash = 0; - } - if( types[hash]==0 ){ - sp->dtnum = hash + 1; - types[hash] = (char*)malloc( lemonStrlen(stddt)+1 ); - if( types[hash]==0 ){ - fprintf(stderr,"Out of memory.\n"); - exit(1); - } - lemon_strcpy(types[hash],stddt); - } - } - - /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */ - name = lemp->name ? lemp->name : "Parse"; - lineno = *plineno; - if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; } - fprintf(out,"#define %sTOKENTYPE %s\n",name, - lemp->tokentype?lemp->tokentype:"void*"); lineno++; - if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } - fprintf(out,"typedef union {\n"); lineno++; - fprintf(out," int yyinit;\n"); lineno++; - fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++; - for(i=0; i<arraysize; i++){ - if( types[i]==0 ) continue; - fprintf(out," %s yy%d;\n",types[i],i+1); lineno++; - free(types[i]); - } - if( lemp->errsym->useCnt ){ - fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++; - } - free(stddt); - free(types); - fprintf(out,"} YYMINORTYPE;\n"); lineno++; - *plineno = lineno; -} - -/* -** Return the name of a C datatype able to represent values between -** lwr and upr, inclusive. If pnByte!=NULL then also write the sizeof -** for that type (1, 2, or 4) into *pnByte. -*/ -static const char *minimum_size_type(int lwr, int upr, int *pnByte){ - const char *zType = "int"; - int nByte = 4; - if( lwr>=0 ){ - if( upr<=255 ){ - zType = "unsigned char"; - nByte = 1; - }else if( upr<65535 ){ - zType = "unsigned short int"; - nByte = 2; - }else{ - zType = "unsigned int"; - nByte = 4; - } - }else if( lwr>=-127 && upr<=127 ){ - zType = "signed char"; - nByte = 1; - }else if( lwr>=-32767 && upr<32767 ){ - zType = "short"; - nByte = 2; - } - if( pnByte ) *pnByte = nByte; - return zType; -} - -/* -** Each state contains a set of token transaction and a set of -** nonterminal transactions. Each of these sets makes an instance -** of the following structure. An array of these structures is used -** to order the creation of entries in the yy_action[] table. -*/ -struct axset { - struct state *stp; /* A pointer to a state */ - int isTkn; /* True to use tokens. False for non-terminals */ - int nAction; /* Number of actions */ - int iOrder; /* Original order of action sets */ -}; - -/* -** Compare to axset structures for sorting purposes -*/ -static int axset_compare(const void *a, const void *b){ - struct axset *p1 = (struct axset*)a; - struct axset *p2 = (struct axset*)b; - int c; - c = p2->nAction - p1->nAction; - if( c==0 ){ - c = p1->iOrder - p2->iOrder; - } - assert( c!=0 || p1==p2 ); - return c; -} - -/* -** Write text on "out" that describes the rule "rp". -*/ -static void writeRuleText(FILE *out, struct rule *rp){ - int j; - fprintf(out,"%s ::=", rp->lhs->name); - for(j=0; j<rp->nrhs; j++){ - struct symbol *sp = rp->rhs[j]; - if( sp->type!=MULTITERMINAL ){ - fprintf(out," %s", sp->name); - }else{ - int k; - fprintf(out," %s", sp->subsym[0]->name); - for(k=1; k<sp->nsubsym; k++){ - fprintf(out,"|%s",sp->subsym[k]->name); - } - } - } -} - - -/* Generate C source code for the parser */ -void ReportTable( - struct lemon *lemp, - int mhflag /* Output in makeheaders format if true */ -){ - FILE *out, *in; - char line[LINESIZE]; - int lineno; - struct state *stp; - struct action *ap; - struct rule *rp; - struct acttab *pActtab; - int i, j, n, sz; - int szActionType; /* sizeof(YYACTIONTYPE) */ - int szCodeType; /* sizeof(YYCODETYPE) */ - const char *name; - int mnTknOfst, mxTknOfst; - int mnNtOfst, mxNtOfst; - struct axset *ax; - - in = tplt_open(lemp); - if( in==0 ) return; - out = file_open(lemp,".c","wb"); - if( out==0 ){ - fclose(in); - return; - } - lineno = 1; - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate the include code, if any */ - tplt_print(out,lemp,lemp->include,&lineno); - if( mhflag ){ - char *incName = file_makename(lemp, ".h"); - fprintf(out,"#include \"%s\"\n", incName); lineno++; - free(incName); - } - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate #defines for all tokens */ - if( mhflag ){ - const char *prefix; - fprintf(out,"#if INTERFACE\n"); lineno++; - if( lemp->tokenprefix ) prefix = lemp->tokenprefix; - else prefix = ""; - for(i=1; i<lemp->nterminal; i++){ - fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); - lineno++; - } - fprintf(out,"#endif\n"); lineno++; - } - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate the defines */ - fprintf(out,"#define YYCODETYPE %s\n", - minimum_size_type(0, lemp->nsymbol+1, &szCodeType)); lineno++; - fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; - fprintf(out,"#define YYACTIONTYPE %s\n", - minimum_size_type(0,lemp->nstate+lemp->nrule*2+5,&szActionType)); lineno++; - if( lemp->wildcard ){ - fprintf(out,"#define YYWILDCARD %d\n", - lemp->wildcard->index); lineno++; - } - print_stack_union(out,lemp,&lineno,mhflag); - fprintf(out, "#ifndef YYSTACKDEPTH\n"); lineno++; - if( lemp->stacksize ){ - fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize); lineno++; - }else{ - fprintf(out,"#define YYSTACKDEPTH 100\n"); lineno++; - } - fprintf(out, "#endif\n"); lineno++; - if( mhflag ){ - fprintf(out,"#if INTERFACE\n"); lineno++; - } - name = lemp->name ? lemp->name : "Parse"; - if( lemp->arg && lemp->arg[0] ){ - i = lemonStrlen(lemp->arg); - while( i>=1 && isspace(lemp->arg[i-1]) ) i--; - while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; - fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++; - fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg); lineno++; - fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n", - name,lemp->arg,&lemp->arg[i]); lineno++; - fprintf(out,"#define %sARG_STORE yypParser->%s = %s\n", - name,&lemp->arg[i],&lemp->arg[i]); lineno++; - }else{ - fprintf(out,"#define %sARG_SDECL\n",name); lineno++; - fprintf(out,"#define %sARG_PDECL\n",name); lineno++; - fprintf(out,"#define %sARG_FETCH\n",name); lineno++; - fprintf(out,"#define %sARG_STORE\n",name); lineno++; - } - if( mhflag ){ - fprintf(out,"#endif\n"); lineno++; - } - if( lemp->errsym->useCnt ){ - fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; - fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; - } - if( lemp->has_fallback ){ - fprintf(out,"#define YYFALLBACK 1\n"); lineno++; - } - - /* Compute the action table, but do not output it yet. The action - ** table must be computed before generating the YYNSTATE macro because - ** we need to know how many states can be eliminated. - */ - ax = (struct axset *) calloc(lemp->nxstate*2, sizeof(ax[0])); - if( ax==0 ){ - fprintf(stderr,"malloc failed\n"); - exit(1); - } - for(i=0; i<lemp->nxstate; i++){ - stp = lemp->sorted[i]; - ax[i*2].stp = stp; - ax[i*2].isTkn = 1; - ax[i*2].nAction = stp->nTknAct; - ax[i*2+1].stp = stp; - ax[i*2+1].isTkn = 0; - ax[i*2+1].nAction = stp->nNtAct; - } - mxTknOfst = mnTknOfst = 0; - mxNtOfst = mnNtOfst = 0; - /* In an effort to minimize the action table size, use the heuristic - ** of placing the largest action sets first */ - for(i=0; i<lemp->nxstate*2; i++) ax[i].iOrder = i; - qsort(ax, lemp->nxstate*2, sizeof(ax[0]), axset_compare); - pActtab = acttab_alloc(); - for(i=0; i<lemp->nxstate*2 && ax[i].nAction>0; i++){ - stp = ax[i].stp; - if( ax[i].isTkn ){ - for(ap=stp->ap; ap; ap=ap->next){ - int action; - if( ap->sp->index>=lemp->nterminal ) continue; - action = compute_action(lemp, ap); - if( action<0 ) continue; - acttab_action(pActtab, ap->sp->index, action); - } - stp->iTknOfst = acttab_insert(pActtab); - if( stp->iTknOfst<mnTknOfst ) mnTknOfst = stp->iTknOfst; - if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst; - }else{ - for(ap=stp->ap; ap; ap=ap->next){ - int action; - if( ap->sp->index<lemp->nterminal ) continue; - if( ap->sp->index==lemp->nsymbol ) continue; - action = compute_action(lemp, ap); - if( action<0 ) continue; - acttab_action(pActtab, ap->sp->index, action); - } - stp->iNtOfst = acttab_insert(pActtab); - if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst; - if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst; - } -#if 0 /* Uncomment for a trace of how the yy_action[] table fills out */ - { int jj, nn; - for(jj=nn=0; jj<pActtab->nAction; jj++){ - if( pActtab->aAction[jj].action<0 ) nn++; - } - printf("%4d: State %3d %s n: %2d size: %5d freespace: %d\n", - i, stp->statenum, ax[i].isTkn ? "Token" : "Var ", - ax[i].nAction, pActtab->nAction, nn); - } -#endif - } - free(ax); - - /* Finish rendering the constants now that the action table has - ** been computed */ - fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++; - fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; - fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++; - fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",lemp->nstate); lineno++; - i = lemp->nstate + lemp->nrule; - fprintf(out,"#define YY_MAX_SHIFTREDUCE %d\n", i-1); lineno++; - fprintf(out,"#define YY_MIN_REDUCE %d\n", i); lineno++; - i = lemp->nstate + lemp->nrule*2; - fprintf(out,"#define YY_MAX_REDUCE %d\n", i-1); lineno++; - fprintf(out,"#define YY_ERROR_ACTION %d\n", i); lineno++; - fprintf(out,"#define YY_ACCEPT_ACTION %d\n", i+1); lineno++; - fprintf(out,"#define YY_NO_ACTION %d\n", i+2); lineno++; - tplt_xfer(lemp->name,in,out,&lineno); - - /* Now output the action table and its associates: - ** - ** yy_action[] A single table containing all actions. - ** yy_lookahead[] A table containing the lookahead for each entry in - ** yy_action. Used to detect hash collisions. - ** yy_shift_ofst[] For each state, the offset into yy_action for - ** shifting terminals. - ** yy_reduce_ofst[] For each state, the offset into yy_action for - ** shifting non-terminals after a reduce. - ** yy_default[] Default action for each state. - */ - - /* Output the yy_action table */ - lemp->nactiontab = n = acttab_size(pActtab); - lemp->tablesize += n*szActionType; - fprintf(out,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++; - fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++; - for(i=j=0; i<n; i++){ - int action = acttab_yyaction(pActtab, i); - if( action<0 ) action = lemp->nstate + lemp->nrule + 2; - if( j==0 ) fprintf(out," /* %5d */ ", i); - fprintf(out, " %4d,", action); - if( j==9 || i==n-1 ){ - fprintf(out, "\n"); lineno++; - j = 0; - }else{ - j++; - } - } - fprintf(out, "};\n"); lineno++; - - /* Output the yy_lookahead table */ - lemp->tablesize += n*szCodeType; - fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; - for(i=j=0; i<n; i++){ - int la = acttab_yylookahead(pActtab, i); - if( la<0 ) la = lemp->nsymbol; - if( j==0 ) fprintf(out," /* %5d */ ", i); - fprintf(out, " %4d,", la); - if( j==9 || i==n-1 ){ - fprintf(out, "\n"); lineno++; - j = 0; - }else{ - j++; - } - } - fprintf(out, "};\n"); lineno++; - - /* Output the yy_shift_ofst[] table */ - fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; - n = lemp->nxstate; - while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; - fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; - fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; - fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; - fprintf(out, "static const %s yy_shift_ofst[] = {\n", - minimum_size_type(mnTknOfst-1, mxTknOfst, &sz)); lineno++; - lemp->tablesize += n*sz; - for(i=j=0; i<n; i++){ - int ofst; - stp = lemp->sorted[i]; - ofst = stp->iTknOfst; - if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1; - if( j==0 ) fprintf(out," /* %5d */ ", i); - fprintf(out, " %4d,", ofst); - if( j==9 || i==n-1 ){ - fprintf(out, "\n"); lineno++; - j = 0; - }else{ - j++; - } - } - fprintf(out, "};\n"); lineno++; - - /* Output the yy_reduce_ofst[] table */ - fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; - n = lemp->nxstate; - while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; - fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++; - fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++; - fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++; - fprintf(out, "static const %s yy_reduce_ofst[] = {\n", - minimum_size_type(mnNtOfst-1, mxNtOfst, &sz)); lineno++; - lemp->tablesize += n*sz; - for(i=j=0; i<n; i++){ - int ofst; - stp = lemp->sorted[i]; - ofst = stp->iNtOfst; - if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1; - if( j==0 ) fprintf(out," /* %5d */ ", i); - fprintf(out, " %4d,", ofst); - if( j==9 || i==n-1 ){ - fprintf(out, "\n"); lineno++; - j = 0; - }else{ - j++; - } - } - fprintf(out, "};\n"); lineno++; - - /* Output the default action table */ - fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; - n = lemp->nxstate; - lemp->tablesize += n*szActionType; - for(i=j=0; i<n; i++){ - stp = lemp->sorted[i]; - if( j==0 ) fprintf(out," /* %5d */ ", i); - fprintf(out, " %4d,", stp->iDfltReduce+lemp->nstate+lemp->nrule); - if( j==9 || i==n-1 ){ - fprintf(out, "\n"); lineno++; - j = 0; - }else{ - j++; - } - } - fprintf(out, "};\n"); lineno++; - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate the table of fallback tokens. - */ - if( lemp->has_fallback ){ - int mx = lemp->nterminal - 1; - while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } - lemp->tablesize += (mx+1)*szCodeType; - for(i=0; i<=mx; i++){ - struct symbol *p = lemp->symbols[i]; - if( p->fallback==0 ){ - fprintf(out, " 0, /* %10s => nothing */\n", p->name); - }else{ - fprintf(out, " %3d, /* %10s => %s */\n", p->fallback->index, - p->name, p->fallback->name); - } - lineno++; - } - } - tplt_xfer(lemp->name, in, out, &lineno); - - /* Generate a table containing the symbolic name of every symbol - */ - for(i=0; i<lemp->nsymbol; i++){ - lemon_sprintf(line,"\"%s\",",lemp->symbols[i]->name); - fprintf(out," %-15s",line); - if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; } - } - if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; } - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate a table containing a text string that describes every - ** rule in the rule set of the grammar. This information is used - ** when tracing REDUCE actions. - */ - for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ - assert( rp->index==i ); - fprintf(out," /* %3d */ \"", i); - writeRuleText(out, rp); - fprintf(out,"\",\n"); lineno++; - } - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate code which executes every time a symbol is popped from - ** the stack while processing errors or while destroying the parser. - ** (In other words, generate the %destructor actions) - */ - if( lemp->tokendest ){ - int once = 1; - for(i=0; i<lemp->nsymbol; i++){ - struct symbol *sp = lemp->symbols[i]; - if( sp==0 || sp->type!=TERMINAL ) continue; - if( once ){ - fprintf(out, " /* TERMINAL Destructor */\n"); lineno++; - once = 0; - } - fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; - } - for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++); - if( i<lemp->nsymbol ){ - emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); - fprintf(out," break;\n"); lineno++; - } - } - if( lemp->vardest ){ - struct symbol *dflt_sp = 0; - int once = 1; - for(i=0; i<lemp->nsymbol; i++){ - struct symbol *sp = lemp->symbols[i]; - if( sp==0 || sp->type==TERMINAL || - sp->index<=0 || sp->destructor!=0 ) continue; - if( once ){ - fprintf(out, " /* Default NON-TERMINAL Destructor */\n"); lineno++; - once = 0; - } - fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; - dflt_sp = sp; - } - if( dflt_sp!=0 ){ - emit_destructor_code(out,dflt_sp,lemp,&lineno); - } - fprintf(out," break;\n"); lineno++; - } - for(i=0; i<lemp->nsymbol; i++){ - struct symbol *sp = lemp->symbols[i]; - if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; - fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; - - /* Combine duplicate destructors into a single case */ - for(j=i+1; j<lemp->nsymbol; j++){ - struct symbol *sp2 = lemp->symbols[j]; - if( sp2 && sp2->type!=TERMINAL && sp2->destructor - && sp2->dtnum==sp->dtnum - && strcmp(sp->destructor,sp2->destructor)==0 ){ - fprintf(out," case %d: /* %s */\n", - sp2->index, sp2->name); lineno++; - sp2->destructor = 0; - } - } - - emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); - fprintf(out," break;\n"); lineno++; - } - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate code which executes whenever the parser stack overflows */ - tplt_print(out,lemp,lemp->overflow,&lineno); - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate the table of rule information - ** - ** Note: This code depends on the fact that rules are number - ** sequentually beginning with 0. - */ - for(rp=lemp->rule; rp; rp=rp->next){ - fprintf(out," { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++; - } - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate code which execution during each REDUCE action */ - for(rp=lemp->rule; rp; rp=rp->next){ - translate_code(lemp, rp); - } - /* First output rules other than the default: rule */ - for(rp=lemp->rule; rp; rp=rp->next){ - struct rule *rp2; /* Other rules with the same action */ - if( rp->code==0 ) continue; - if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */ - fprintf(out," case %d: /* ", rp->index); - writeRuleText(out, rp); - fprintf(out, " */\n"); lineno++; - for(rp2=rp->next; rp2; rp2=rp2->next){ - if( rp2->code==rp->code ){ - fprintf(out," case %d: /* ", rp2->index); - writeRuleText(out, rp2); - fprintf(out," */ yytestcase(yyruleno==%d);\n", rp2->index); lineno++; - rp2->code = 0; - } - } - emit_code(out,rp,lemp,&lineno); - fprintf(out," break;\n"); lineno++; - rp->code = 0; - } - /* Finally, output the default: rule. We choose as the default: all - ** empty actions. */ - fprintf(out," default:\n"); lineno++; - for(rp=lemp->rule; rp; rp=rp->next){ - if( rp->code==0 ) continue; - assert( rp->code[0]=='\n' && rp->code[1]==0 ); - fprintf(out," /* (%d) ", rp->index); - writeRuleText(out, rp); - fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->index); lineno++; - } - fprintf(out," break;\n"); lineno++; - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate code which executes if a parse fails */ - tplt_print(out,lemp,lemp->failure,&lineno); - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate code which executes when a syntax error occurs */ - tplt_print(out,lemp,lemp->error,&lineno); - tplt_xfer(lemp->name,in,out,&lineno); - - /* Generate code which executes when the parser accepts its input */ - tplt_print(out,lemp,lemp->accept,&lineno); - tplt_xfer(lemp->name,in,out,&lineno); - - /* Append any addition code the user desires */ - tplt_print(out,lemp,lemp->extracode,&lineno); - - fclose(in); - fclose(out); - return; -} - -/* Generate a header file for the parser */ -void ReportHeader(struct lemon *lemp) -{ - FILE *out, *in; - const char *prefix; - char line[LINESIZE]; - char pattern[LINESIZE]; - int i; - - if( lemp->tokenprefix ) prefix = lemp->tokenprefix; - else prefix = ""; - in = file_open(lemp,".h","rb"); - if( in ){ - int nextChar; - for(i=1; i<lemp->nterminal && fgets(line,LINESIZE,in); i++){ - lemon_sprintf(pattern,"#define %s%-30s %3d\n", - prefix,lemp->symbols[i]->name,i); - if( strcmp(line,pattern) ) break; - } - nextChar = fgetc(in); - fclose(in); - if( i==lemp->nterminal && nextChar==EOF ){ - /* No change in the file. Don't rewrite it. */ - return; - } - } - out = file_open(lemp,".h","wb"); - if( out ){ - for(i=1; i<lemp->nterminal; i++){ - fprintf(out,"#define %s%-30s %3d\n",prefix,lemp->symbols[i]->name,i); - } - fclose(out); - } - return; -} - -/* Reduce the size of the action tables, if possible, by making use -** of defaults. -** -** In this version, we take the most frequent REDUCE action and make -** it the default. Except, there is no default if the wildcard token -** is a possible look-ahead. -*/ -void CompressTables(struct lemon *lemp) -{ - struct state *stp; - struct action *ap, *ap2; - struct rule *rp, *rp2, *rbest; - int nbest, n; - int i; - int usesWildcard; - - for(i=0; i<lemp->nstate; i++){ - stp = lemp->sorted[i]; - nbest = 0; - rbest = 0; - usesWildcard = 0; - - for(ap=stp->ap; ap; ap=ap->next){ - if( ap->type==SHIFT && ap->sp==lemp->wildcard ){ - usesWildcard = 1; - } - if( ap->type!=REDUCE ) continue; - rp = ap->x.rp; - if( rp->lhsStart ) continue; - if( rp==rbest ) continue; - n = 1; - for(ap2=ap->next; ap2; ap2=ap2->next){ - if( ap2->type!=REDUCE ) continue; - rp2 = ap2->x.rp; - if( rp2==rbest ) continue; - if( rp2==rp ) n++; - } - if( n>nbest ){ - nbest = n; - rbest = rp; - } - } - - /* Do not make a default if the number of rules to default - ** is not at least 1 or if the wildcard token is a possible - ** lookahead. - */ - if( nbest<1 || usesWildcard ) continue; - - - /* Combine matching REDUCE actions into a single default */ - for(ap=stp->ap; ap; ap=ap->next){ - if( ap->type==REDUCE && ap->x.rp==rbest ) break; - } - assert( ap ); - ap->sp = Symbol_new("{default}"); - for(ap=ap->next; ap; ap=ap->next){ - if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED; - } - stp->ap = Action_sort(stp->ap); - - for(ap=stp->ap; ap; ap=ap->next){ - if( ap->type==SHIFT ) break; - if( ap->type==REDUCE && ap->x.rp!=rbest ) break; - } - if( ap==0 ){ - stp->autoReduce = 1; - stp->pDfltReduce = rbest; - } - } - - /* Make a second pass over all states and actions. Convert - ** every action that is a SHIFT to an autoReduce state into - ** a SHIFTREDUCE action. - */ - for(i=0; i<lemp->nstate; i++){ - stp = lemp->sorted[i]; - for(ap=stp->ap; ap; ap=ap->next){ - struct state *pNextState; - if( ap->type!=SHIFT ) continue; - pNextState = ap->x.stp; - if( pNextState->autoReduce && pNextState->pDfltReduce!=0 ){ - ap->type = SHIFTREDUCE; - ap->x.rp = pNextState->pDfltReduce; - } - } - } -} - - -/* -** Compare two states for sorting purposes. The smaller state is the -** one with the most non-terminal actions. If they have the same number -** of non-terminal actions, then the smaller is the one with the most -** token actions. -*/ -static int stateResortCompare(const void *a, const void *b){ - const struct state *pA = *(const struct state**)a; - const struct state *pB = *(const struct state**)b; - int n; - - n = pB->nNtAct - pA->nNtAct; - if( n==0 ){ - n = pB->nTknAct - pA->nTknAct; - if( n==0 ){ - n = pB->statenum - pA->statenum; - } - } - assert( n!=0 ); - return n; -} - - -/* -** Renumber and resort states so that states with fewer choices -** occur at the end. Except, keep state 0 as the first state. -*/ -void ResortStates(struct lemon *lemp) -{ - int i; - struct state *stp; - struct action *ap; - - for(i=0; i<lemp->nstate; i++){ - stp = lemp->sorted[i]; - stp->nTknAct = stp->nNtAct = 0; - stp->iDfltReduce = lemp->nrule; /* Init dflt action to "syntax error" */ - stp->iTknOfst = NO_OFFSET; - stp->iNtOfst = NO_OFFSET; - for(ap=stp->ap; ap; ap=ap->next){ - int iAction = compute_action(lemp,ap); - if( iAction>=0 ){ - if( ap->sp->index<lemp->nterminal ){ - stp->nTknAct++; - }else if( ap->sp->index<lemp->nsymbol ){ - stp->nNtAct++; - }else{ - assert( stp->autoReduce==0 || stp->pDfltReduce==ap->x.rp ); - stp->iDfltReduce = iAction - lemp->nstate - lemp->nrule; - } - } - } - } - qsort(&lemp->sorted[1], lemp->nstate-1, sizeof(lemp->sorted[0]), - stateResortCompare); - for(i=0; i<lemp->nstate; i++){ - lemp->sorted[i]->statenum = i; - } - lemp->nxstate = lemp->nstate; - while( lemp->nxstate>1 && lemp->sorted[lemp->nxstate-1]->autoReduce ){ - lemp->nxstate--; - } -} - - -/***************** From the file "set.c" ************************************/ -/* -** Set manipulation routines for the LEMON parser generator. -*/ - -static int size = 0; - -/* Set the set size */ -void SetSize(int n) -{ - size = n+1; -} - -/* Allocate a new set */ -char *SetNew(){ - char *s; - s = (char*)calloc( size, 1); - if( s==0 ){ - extern void memory_error(); - memory_error(); - } - return s; -} - -/* Deallocate a set */ -void SetFree(char *s) -{ - free(s); -} - -/* Add a new element to the set. Return TRUE if the element was added -** and FALSE if it was already there. */ -int SetAdd(char *s, int e) -{ - int rv; - assert( e>=0 && e<size ); - rv = s[e]; - s[e] = 1; - return !rv; -} - -/* Add every element of s2 to s1. Return TRUE if s1 changes. */ -int SetUnion(char *s1, char *s2) -{ - int i, progress; - progress = 0; - for(i=0; i<size; i++){ - if( s2[i]==0 ) continue; - if( s1[i]==0 ){ - progress = 1; - s1[i] = 1; - } - } - return progress; -} -/********************** From the file "table.c" ****************************/ -/* -** All code in this file has been automatically generated -** from a specification in the file -** "table.q" -** by the associative array code building program "aagen". -** Do not edit this file! Instead, edit the specification -** file, then rerun aagen. -*/ -/* -** Code for processing tables in the LEMON parser generator. -*/ - -PRIVATE unsigned strhash(const char *x) -{ - unsigned h = 0; - while( *x ) h = h*13 + *(x++); - return h; -} - -/* Works like strdup, sort of. Save a string in malloced memory, but -** keep strings in a table so that the same string is not in more -** than one place. -*/ -const char *Strsafe(const char *y) -{ - const char *z; - char *cpy; - - if( y==0 ) return 0; - z = Strsafe_find(y); - if( z==0 && (cpy=(char *)malloc( lemonStrlen(y)+1 ))!=0 ){ - lemon_strcpy(cpy,y); - z = cpy; - Strsafe_insert(z); - } - MemoryCheck(z); - return z; -} - -/* There is one instance of the following structure for each -** associative array of type "x1". -*/ -struct s_x1 { - int size; /* The number of available slots. */ - /* Must be a power of 2 greater than or */ - /* equal to 1 */ - int count; /* Number of currently slots filled */ - struct s_x1node *tbl; /* The data stored here */ - struct s_x1node **ht; /* Hash table for lookups */ -}; - -/* There is one instance of this structure for every data element -** in an associative array of type "x1". -*/ -typedef struct s_x1node { - const char *data; /* The data */ - struct s_x1node *next; /* Next entry with the same hash */ - struct s_x1node **from; /* Previous link */ -} x1node; - -/* There is only one instance of the array, which is the following */ -static struct s_x1 *x1a; - -/* Allocate a new associative array */ -void Strsafe_init(){ - if( x1a ) return; - x1a = (struct s_x1*)malloc( sizeof(struct s_x1) ); - if( x1a ){ - x1a->size = 1024; - x1a->count = 0; - x1a->tbl = (x1node*)calloc(1024, sizeof(x1node) + sizeof(x1node*)); - if( x1a->tbl==0 ){ - free(x1a); - x1a = 0; - }else{ - int i; - x1a->ht = (x1node**)&(x1a->tbl[1024]); - for(i=0; i<1024; i++) x1a->ht[i] = 0; - } - } -} -/* Insert a new record into the array. Return TRUE if successful. -** Prior data with the same key is NOT overwritten */ -int Strsafe_insert(const char *data) -{ - x1node *np; - unsigned h; - unsigned ph; - - if( x1a==0 ) return 0; - ph = strhash(data); - h = ph & (x1a->size-1); - np = x1a->ht[h]; - while( np ){ - if( strcmp(np->data,data)==0 ){ - /* An existing entry with the same key is found. */ - /* Fail because overwrite is not allows. */ - return 0; - } - np = np->next; - } - if( x1a->count>=x1a->size ){ - /* Need to make the hash table bigger */ - int i,arrSize; - struct s_x1 array; - array.size = arrSize = x1a->size*2; - array.count = x1a->count; - array.tbl = (x1node*)calloc(arrSize, sizeof(x1node) + sizeof(x1node*)); - if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ - array.ht = (x1node**)&(array.tbl[arrSize]); - for(i=0; i<arrSize; i++) array.ht[i] = 0; - for(i=0; i<x1a->count; i++){ - x1node *oldnp, *newnp; - oldnp = &(x1a->tbl[i]); - h = strhash(oldnp->data) & (arrSize-1); - newnp = &(array.tbl[i]); - if( array.ht[h] ) array.ht[h]->from = &(newnp->next); - newnp->next = array.ht[h]; - newnp->data = oldnp->data; - newnp->from = &(array.ht[h]); - array.ht[h] = newnp; - } - free(x1a->tbl); - *x1a = array; - } - /* Insert the new data */ - h = ph & (x1a->size-1); - np = &(x1a->tbl[x1a->count++]); - np->data = data; - if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next); - np->next = x1a->ht[h]; - x1a->ht[h] = np; - np->from = &(x1a->ht[h]); - return 1; -} - -/* Return a pointer to data assigned to the given key. Return NULL -** if no such key. */ -const char *Strsafe_find(const char *key) -{ - unsigned h; - x1node *np; - - if( x1a==0 ) return 0; - h = strhash(key) & (x1a->size-1); - np = x1a->ht[h]; - while( np ){ - if( strcmp(np->data,key)==0 ) break; - np = np->next; - } - return np ? np->data : 0; -} - -/* Return a pointer to the (terminal or nonterminal) symbol "x". -** Create a new symbol if this is the first time "x" has been seen. -*/ -struct symbol *Symbol_new(const char *x) -{ - struct symbol *sp; - - sp = Symbol_find(x); - if( sp==0 ){ - sp = (struct symbol *)calloc(1, sizeof(struct symbol) ); - MemoryCheck(sp); - sp->name = Strsafe(x); - sp->type = isupper(*x) ? TERMINAL : NONTERMINAL; - sp->rule = 0; - sp->fallback = 0; - sp->prec = -1; - sp->assoc = UNK; - sp->firstset = 0; - sp->lambda = LEMON_FALSE; - sp->destructor = 0; - sp->destLineno = 0; - sp->datatype = 0; - sp->useCnt = 0; - Symbol_insert(sp,sp->name); - } - sp->useCnt++; - return sp; -} - -/* Compare two symbols for sorting purposes. Return negative, -** zero, or positive if a is less then, equal to, or greater -** than b. -** -** Symbols that begin with upper case letters (terminals or tokens) -** must sort before symbols that begin with lower case letters -** (non-terminals). And MULTITERMINAL symbols (created using the -** %token_class directive) must sort at the very end. Other than -** that, the order does not matter. -** -** We find experimentally that leaving the symbols in their original -** order (the order they appeared in the grammar file) gives the -** smallest parser tables in SQLite. -*/ -int Symbolcmpp(const void *_a, const void *_b) -{ - const struct symbol *a = *(const struct symbol **) _a; - const struct symbol *b = *(const struct symbol **) _b; - int i1 = a->type==MULTITERMINAL ? 3 : a->name[0]>'Z' ? 2 : 1; - int i2 = b->type==MULTITERMINAL ? 3 : b->name[0]>'Z' ? 2 : 1; - return i1==i2 ? a->index - b->index : i1 - i2; -} - -/* There is one instance of the following structure for each -** associative array of type "x2". -*/ -struct s_x2 { - int size; /* The number of available slots. */ - /* Must be a power of 2 greater than or */ - /* equal to 1 */ - int count; /* Number of currently slots filled */ - struct s_x2node *tbl; /* The data stored here */ - struct s_x2node **ht; /* Hash table for lookups */ -}; - -/* There is one instance of this structure for every data element -** in an associative array of type "x2". -*/ -typedef struct s_x2node { - struct symbol *data; /* The data */ - const char *key; /* The key */ - struct s_x2node *next; /* Next entry with the same hash */ - struct s_x2node **from; /* Previous link */ -} x2node; - -/* There is only one instance of the array, which is the following */ -static struct s_x2 *x2a; - -/* Allocate a new associative array */ -void Symbol_init(){ - if( x2a ) return; - x2a = (struct s_x2*)malloc( sizeof(struct s_x2) ); - if( x2a ){ - x2a->size = 128; - x2a->count = 0; - x2a->tbl = (x2node*)calloc(128, sizeof(x2node) + sizeof(x2node*)); - if( x2a->tbl==0 ){ - free(x2a); - x2a = 0; - }else{ - int i; - x2a->ht = (x2node**)&(x2a->tbl[128]); - for(i=0; i<128; i++) x2a->ht[i] = 0; - } - } -} -/* Insert a new record into the array. Return TRUE if successful. -** Prior data with the same key is NOT overwritten */ -int Symbol_insert(struct symbol *data, const char *key) -{ - x2node *np; - unsigned h; - unsigned ph; - - if( x2a==0 ) return 0; - ph = strhash(key); - h = ph & (x2a->size-1); - np = x2a->ht[h]; - while( np ){ - if( strcmp(np->key,key)==0 ){ - /* An existing entry with the same key is found. */ - /* Fail because overwrite is not allows. */ - return 0; - } - np = np->next; - } - if( x2a->count>=x2a->size ){ - /* Need to make the hash table bigger */ - int i,arrSize; - struct s_x2 array; - array.size = arrSize = x2a->size*2; - array.count = x2a->count; - array.tbl = (x2node*)calloc(arrSize, sizeof(x2node) + sizeof(x2node*)); - if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ - array.ht = (x2node**)&(array.tbl[arrSize]); - for(i=0; i<arrSize; i++) array.ht[i] = 0; - for(i=0; i<x2a->count; i++){ - x2node *oldnp, *newnp; - oldnp = &(x2a->tbl[i]); - h = strhash(oldnp->key) & (arrSize-1); - newnp = &(array.tbl[i]); - if( array.ht[h] ) array.ht[h]->from = &(newnp->next); - newnp->next = array.ht[h]; - newnp->key = oldnp->key; - newnp->data = oldnp->data; - newnp->from = &(array.ht[h]); - array.ht[h] = newnp; - } - free(x2a->tbl); - *x2a = array; - } - /* Insert the new data */ - h = ph & (x2a->size-1); - np = &(x2a->tbl[x2a->count++]); - np->key = key; - np->data = data; - if( x2a->ht[h] ) x2a->ht[h]->from = &(np->next); - np->next = x2a->ht[h]; - x2a->ht[h] = np; - np->from = &(x2a->ht[h]); - return 1; -} - -/* Return a pointer to data assigned to the given key. Return NULL -** if no such key. */ -struct symbol *Symbol_find(const char *key) -{ - unsigned h; - x2node *np; - - if( x2a==0 ) return 0; - h = strhash(key) & (x2a->size-1); - np = x2a->ht[h]; - while( np ){ - if( strcmp(np->key,key)==0 ) break; - np = np->next; - } - return np ? np->data : 0; -} - -/* Return the n-th data. Return NULL if n is out of range. */ -struct symbol *Symbol_Nth(int n) -{ - struct symbol *data; - if( x2a && n>0 && n<=x2a->count ){ - data = x2a->tbl[n-1].data; - }else{ - data = 0; - } - return data; -} - -/* Return the size of the array */ -int Symbol_count() -{ - return x2a ? x2a->count : 0; -} - -/* Return an array of pointers to all data in the table. -** The array is obtained from malloc. Return NULL if memory allocation -** problems, or if the array is empty. */ -struct symbol **Symbol_arrayof() -{ - struct symbol **array; - int i,arrSize; - if( x2a==0 ) return 0; - arrSize = x2a->count; - array = (struct symbol **)calloc(arrSize, sizeof(struct symbol *)); - if( array ){ - for(i=0; i<arrSize; i++) array[i] = x2a->tbl[i].data; - } - return array; -} - -/* Compare two configurations */ -int Configcmp(const char *_a,const char *_b) -{ - const struct config *a = (struct config *) _a; - const struct config *b = (struct config *) _b; - int x; - x = a->rp->index - b->rp->index; - if( x==0 ) x = a->dot - b->dot; - return x; -} - -/* Compare two states */ -PRIVATE int statecmp(struct config *a, struct config *b) -{ - int rc; - for(rc=0; rc==0 && a && b; a=a->bp, b=b->bp){ - rc = a->rp->index - b->rp->index; - if( rc==0 ) rc = a->dot - b->dot; - } - if( rc==0 ){ - if( a ) rc = 1; - if( b ) rc = -1; - } - return rc; -} - -/* Hash a state */ -PRIVATE unsigned statehash(struct config *a) -{ - unsigned h=0; - while( a ){ - h = h*571 + a->rp->index*37 + a->dot; - a = a->bp; - } - return h; -} - -/* Allocate a new state structure */ -struct state *State_new() -{ - struct state *newstate; - newstate = (struct state *)calloc(1, sizeof(struct state) ); - MemoryCheck(newstate); - return newstate; -} - -/* There is one instance of the following structure for each -** associative array of type "x3". -*/ -struct s_x3 { - int size; /* The number of available slots. */ - /* Must be a power of 2 greater than or */ - /* equal to 1 */ - int count; /* Number of currently slots filled */ - struct s_x3node *tbl; /* The data stored here */ - struct s_x3node **ht; /* Hash table for lookups */ -}; - -/* There is one instance of this structure for every data element -** in an associative array of type "x3". -*/ -typedef struct s_x3node { - struct state *data; /* The data */ - struct config *key; /* The key */ - struct s_x3node *next; /* Next entry with the same hash */ - struct s_x3node **from; /* Previous link */ -} x3node; - -/* There is only one instance of the array, which is the following */ -static struct s_x3 *x3a; - -/* Allocate a new associative array */ -void State_init(){ - if( x3a ) return; - x3a = (struct s_x3*)malloc( sizeof(struct s_x3) ); - if( x3a ){ - x3a->size = 128; - x3a->count = 0; - x3a->tbl = (x3node*)calloc(128, sizeof(x3node) + sizeof(x3node*)); - if( x3a->tbl==0 ){ - free(x3a); - x3a = 0; - }else{ - int i; - x3a->ht = (x3node**)&(x3a->tbl[128]); - for(i=0; i<128; i++) x3a->ht[i] = 0; - } - } -} -/* Insert a new record into the array. Return TRUE if successful. -** Prior data with the same key is NOT overwritten */ -int State_insert(struct state *data, struct config *key) -{ - x3node *np; - unsigned h; - unsigned ph; - - if( x3a==0 ) return 0; - ph = statehash(key); - h = ph & (x3a->size-1); - np = x3a->ht[h]; - while( np ){ - if( statecmp(np->key,key)==0 ){ - /* An existing entry with the same key is found. */ - /* Fail because overwrite is not allows. */ - return 0; - } - np = np->next; - } - if( x3a->count>=x3a->size ){ - /* Need to make the hash table bigger */ - int i,arrSize; - struct s_x3 array; - array.size = arrSize = x3a->size*2; - array.count = x3a->count; - array.tbl = (x3node*)calloc(arrSize, sizeof(x3node) + sizeof(x3node*)); - if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ - array.ht = (x3node**)&(array.tbl[arrSize]); - for(i=0; i<arrSize; i++) array.ht[i] = 0; - for(i=0; i<x3a->count; i++){ - x3node *oldnp, *newnp; - oldnp = &(x3a->tbl[i]); - h = statehash(oldnp->key) & (arrSize-1); - newnp = &(array.tbl[i]); - if( array.ht[h] ) array.ht[h]->from = &(newnp->next); - newnp->next = array.ht[h]; - newnp->key = oldnp->key; - newnp->data = oldnp->data; - newnp->from = &(array.ht[h]); - array.ht[h] = newnp; - } - free(x3a->tbl); - *x3a = array; - } - /* Insert the new data */ - h = ph & (x3a->size-1); - np = &(x3a->tbl[x3a->count++]); - np->key = key; - np->data = data; - if( x3a->ht[h] ) x3a->ht[h]->from = &(np->next); - np->next = x3a->ht[h]; - x3a->ht[h] = np; - np->from = &(x3a->ht[h]); - return 1; -} - -/* Return a pointer to data assigned to the given key. Return NULL -** if no such key. */ -struct state *State_find(struct config *key) -{ - unsigned h; - x3node *np; - - if( x3a==0 ) return 0; - h = statehash(key) & (x3a->size-1); - np = x3a->ht[h]; - while( np ){ - if( statecmp(np->key,key)==0 ) break; - np = np->next; - } - return np ? np->data : 0; -} - -/* Return an array of pointers to all data in the table. -** The array is obtained from malloc. Return NULL if memory allocation -** problems, or if the array is empty. */ -struct state **State_arrayof() -{ - struct state **array; - int i,arrSize; - if( x3a==0 ) return 0; - arrSize = x3a->count; - array = (struct state **)calloc(arrSize, sizeof(struct state *)); - if( array ){ - for(i=0; i<arrSize; i++) array[i] = x3a->tbl[i].data; - } - return array; -} - -/* Hash a configuration */ -PRIVATE unsigned confighash(struct config *a) -{ - unsigned h=0; - h = h*571 + a->rp->index*37 + a->dot; - return h; -} - -/* There is one instance of the following structure for each -** associative array of type "x4". -*/ -struct s_x4 { - int size; /* The number of available slots. */ - /* Must be a power of 2 greater than or */ - /* equal to 1 */ - int count; /* Number of currently slots filled */ - struct s_x4node *tbl; /* The data stored here */ - struct s_x4node **ht; /* Hash table for lookups */ -}; - -/* There is one instance of this structure for every data element -** in an associative array of type "x4". -*/ -typedef struct s_x4node { - struct config *data; /* The data */ - struct s_x4node *next; /* Next entry with the same hash */ - struct s_x4node **from; /* Previous link */ -} x4node; - -/* There is only one instance of the array, which is the following */ -static struct s_x4 *x4a; - -/* Allocate a new associative array */ -void Configtable_init(){ - if( x4a ) return; - x4a = (struct s_x4*)malloc( sizeof(struct s_x4) ); - if( x4a ){ - x4a->size = 64; - x4a->count = 0; - x4a->tbl = (x4node*)calloc(64, sizeof(x4node) + sizeof(x4node*)); - if( x4a->tbl==0 ){ - free(x4a); - x4a = 0; - }else{ - int i; - x4a->ht = (x4node**)&(x4a->tbl[64]); - for(i=0; i<64; i++) x4a->ht[i] = 0; - } - } -} -/* Insert a new record into the array. Return TRUE if successful. -** Prior data with the same key is NOT overwritten */ -int Configtable_insert(struct config *data) -{ - x4node *np; - unsigned h; - unsigned ph; - - if( x4a==0 ) return 0; - ph = confighash(data); - h = ph & (x4a->size-1); - np = x4a->ht[h]; - while( np ){ - if( Configcmp((const char *) np->data,(const char *) data)==0 ){ - /* An existing entry with the same key is found. */ - /* Fail because overwrite is not allows. */ - return 0; - } - np = np->next; - } - if( x4a->count>=x4a->size ){ - /* Need to make the hash table bigger */ - int i,arrSize; - struct s_x4 array; - array.size = arrSize = x4a->size*2; - array.count = x4a->count; - array.tbl = (x4node*)calloc(arrSize, sizeof(x4node) + sizeof(x4node*)); - if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ - array.ht = (x4node**)&(array.tbl[arrSize]); - for(i=0; i<arrSize; i++) array.ht[i] = 0; - for(i=0; i<x4a->count; i++){ - x4node *oldnp, *newnp; - oldnp = &(x4a->tbl[i]); - h = confighash(oldnp->data) & (arrSize-1); - newnp = &(array.tbl[i]); - if( array.ht[h] ) array.ht[h]->from = &(newnp->next); - newnp->next = array.ht[h]; - newnp->data = oldnp->data; - newnp->from = &(array.ht[h]); - array.ht[h] = newnp; - } - free(x4a->tbl); - *x4a = array; - } - /* Insert the new data */ - h = ph & (x4a->size-1); - np = &(x4a->tbl[x4a->count++]); - np->data = data; - if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next); - np->next = x4a->ht[h]; - x4a->ht[h] = np; - np->from = &(x4a->ht[h]); - return 1; -} - -/* Return a pointer to data assigned to the given key. Return NULL -** if no such key. */ -struct config *Configtable_find(struct config *key) -{ - int h; - x4node *np; - - if( x4a==0 ) return 0; - h = confighash(key) & (x4a->size-1); - np = x4a->ht[h]; - while( np ){ - if( Configcmp((const char *) np->data,(const char *) key)==0 ) break; - np = np->next; - } - return np ? np->data : 0; -} - -/* Remove all data from the table. Pass each data to the function "f" -** as it is removed. ("f" may be null to avoid this step.) */ -void Configtable_clear(int(*f)(struct config *)) -{ - int i; - if( x4a==0 || x4a->count==0 ) return; - if( f ) for(i=0; i<x4a->count; i++) (*f)(x4a->tbl[i].data); - for(i=0; i<x4a->size; i++) x4a->ht[i] = 0; - x4a->count = 0; - return; -} diff --git a/lib/libsqlite3/tool/lempar.c b/lib/libsqlite3/tool/lempar.c deleted file mode 100644 index cdf4ca5a1a5..00000000000 --- a/lib/libsqlite3/tool/lempar.c +++ /dev/null @@ -1,880 +0,0 @@ -/* Driver template for the LEMON parser generator. -** The author disclaims copyright to this source code. -*/ -/* First off, code is included that follows the "include" declaration -** in the input grammar file. */ -#include <stdio.h> -%% -/* Next is all token values, in a form suitable for use by makeheaders. -** This section will be null unless lemon is run with the -m switch. -*/ -/* -** These constants (all generated automatically by the parser generator) -** specify the various kinds of tokens (terminals) that the parser -** understands. -** -** Each symbol here is a terminal symbol in the grammar. -*/ -%% -/* Make sure the INTERFACE macro is defined. -*/ -#ifndef INTERFACE -# define INTERFACE 1 -#endif -/* The next thing included is series of defines which control -** various aspects of the generated parser. -** YYCODETYPE is the data type used for storing terminal -** and nonterminal numbers. "unsigned char" is -** used if there are fewer than 250 terminals -** and nonterminals. "int" is used otherwise. -** YYNOCODE is a number of type YYCODETYPE which corresponds -** to no legal terminal or nonterminal number. This -** number is used to fill in empty slots of the hash -** table. -** YYFALLBACK If defined, this indicates that one or more tokens -** have fall-back values which should be used if the -** original value of the token will not parse. -** YYACTIONTYPE is the data type used for storing terminal -** and nonterminal numbers. "unsigned char" is -** used if there are fewer than 250 rules and -** states combined. "int" is used otherwise. -** ParseTOKENTYPE is the data type used for minor tokens given -** directly to the parser from the tokenizer. -** YYMINORTYPE is the data type used for all minor tokens. -** This is typically a union of many types, one of -** which is ParseTOKENTYPE. The entry in the union -** for base tokens is called "yy0". -** YYSTACKDEPTH is the maximum depth of the parser's stack. If -** zero the stack is dynamically sized using realloc() -** ParseARG_SDECL A static variable declaration for the %extra_argument -** ParseARG_PDECL A parameter declaration for the %extra_argument -** ParseARG_STORE Code to store %extra_argument into yypParser -** ParseARG_FETCH Code to extract %extra_argument from yypParser -** YYERRORSYMBOL is the code number of the error symbol. If not -** defined, then do no error processing. -** YYNSTATE the combined number of states. -** YYNRULE the number of rules in the grammar -** YY_MAX_SHIFT Maximum value for shift actions -** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions -** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions -** YY_MIN_REDUCE Maximum value for reduce actions -** YY_ERROR_ACTION The yy_action[] code for syntax error -** YY_ACCEPT_ACTION The yy_action[] code for accept -** YY_NO_ACTION The yy_action[] code for no-op -*/ -%% - -/* The yyzerominor constant is used to initialize instances of -** YYMINORTYPE objects to zero. */ -static const YYMINORTYPE yyzerominor = { 0 }; - -/* Define the yytestcase() macro to be a no-op if is not already defined -** otherwise. -** -** Applications can choose to define yytestcase() in the %include section -** to a macro that can assist in verifying code coverage. For production -** code the yytestcase() macro should be turned off. But it is useful -** for testing. -*/ -#ifndef yytestcase -# define yytestcase(X) -#endif - - -/* Next are the tables used to determine what action to take based on the -** current state and lookahead token. These tables are used to implement -** functions that take a state number and lookahead value and return an -** action integer. -** -** Suppose the action integer is N. Then the action is determined as -** follows -** -** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead -** token onto the stack and goto state N. -** -** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then -** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. -** -** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE -** and YY_MAX_REDUCE - -** N == YY_ERROR_ACTION A syntax error has occurred. -** -** N == YY_ACCEPT_ACTION The parser accepts its input. -** -** N == YY_NO_ACTION No such action. Denotes unused -** slots in the yy_action[] table. -** -** The action table is constructed as a single large table named yy_action[]. -** Given state S and lookahead X, the action is computed as -** -** yy_action[ yy_shift_ofst[S] + X ] -** -** If the index value yy_shift_ofst[S]+X is out of range or if the value -** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] -** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table -** and that yy_default[S] should be used instead. -** -** The formula above is for computing the action when the lookahead is -** a terminal symbol. If the lookahead is a non-terminal (as occurs after -** a reduce action) then the yy_reduce_ofst[] array is used in place of -** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of -** YY_SHIFT_USE_DFLT. -** -** The following are the tables generated in this section: -** -** yy_action[] A single table containing all actions. -** yy_lookahead[] A table containing the lookahead for each entry in -** yy_action. Used to detect hash collisions. -** yy_shift_ofst[] For each state, the offset into yy_action for -** shifting terminals. -** yy_reduce_ofst[] For each state, the offset into yy_action for -** shifting non-terminals after a reduce. -** yy_default[] Default action for each state. -*/ -%% - -/* The next table maps tokens into fallback tokens. If a construct -** like the following: -** -** %fallback ID X Y Z. -** -** appears in the grammar, then ID becomes a fallback token for X, Y, -** and Z. Whenever one of the tokens X, Y, or Z is input to the parser -** but it does not parse, the type of the token is changed to ID and -** the parse is retried before an error is thrown. -*/ -#ifdef YYFALLBACK -static const YYCODETYPE yyFallback[] = { -%% -}; -#endif /* YYFALLBACK */ - -/* The following structure represents a single element of the -** parser's stack. Information stored includes: -** -** + The state number for the parser at this level of the stack. -** -** + The value of the token stored at this level of the stack. -** (In other words, the "major" token.) -** -** + The semantic value stored at this level of the stack. This is -** the information used by the action routines in the grammar. -** It is sometimes called the "minor" token. -** -** After the "shift" half of a SHIFTREDUCE action, the stateno field -** actually contains the reduce action for the second half of the -** SHIFTREDUCE. -*/ -struct yyStackEntry { - YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ - YYCODETYPE major; /* The major token value. This is the code - ** number for the token at this stack level */ - YYMINORTYPE minor; /* The user-supplied minor token value. This - ** is the value of the token */ -}; -typedef struct yyStackEntry yyStackEntry; - -/* The state of the parser is completely contained in an instance of -** the following structure */ -struct yyParser { - int yyidx; /* Index of top element in stack */ -#ifdef YYTRACKMAXSTACKDEPTH - int yyidxMax; /* Maximum value of yyidx */ -#endif - int yyerrcnt; /* Shifts left before out of the error */ - ParseARG_SDECL /* A place to hold %extra_argument */ -#if YYSTACKDEPTH<=0 - int yystksz; /* Current side of the stack */ - yyStackEntry *yystack; /* The parser's stack */ -#else - yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ -#endif -}; -typedef struct yyParser yyParser; - -#ifndef NDEBUG -#include <stdio.h> -static FILE *yyTraceFILE = 0; -static char *yyTracePrompt = 0; -#endif /* NDEBUG */ - -#ifndef NDEBUG -/* -** Turn parser tracing on by giving a stream to which to write the trace -** and a prompt to preface each trace message. Tracing is turned off -** by making either argument NULL -** -** Inputs: -** <ul> -** <li> A FILE* to which trace output should be written. -** If NULL, then tracing is turned off. -** <li> A prefix string written at the beginning of every -** line of trace output. If NULL, then tracing is -** turned off. -** </ul> -** -** Outputs: -** None. -*/ -void ParseTrace(FILE *TraceFILE, char *zTracePrompt){ - yyTraceFILE = TraceFILE; - yyTracePrompt = zTracePrompt; - if( yyTraceFILE==0 ) yyTracePrompt = 0; - else if( yyTracePrompt==0 ) yyTraceFILE = 0; -} -#endif /* NDEBUG */ - -#ifndef NDEBUG -/* For tracing shifts, the names of all terminals and nonterminals -** are required. The following table supplies these names */ -static const char *const yyTokenName[] = { -%% -}; -#endif /* NDEBUG */ - -#ifndef NDEBUG -/* For tracing reduce actions, the names of all rules are required. -*/ -static const char *const yyRuleName[] = { -%% -}; -#endif /* NDEBUG */ - - -#if YYSTACKDEPTH<=0 -/* -** Try to increase the size of the parser stack. -*/ -static void yyGrowStack(yyParser *p){ - int newSize; - yyStackEntry *pNew; - - newSize = p->yystksz*2 + 100; - pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); - if( pNew ){ - p->yystack = pNew; - p->yystksz = newSize; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", - yyTracePrompt, p->yystksz); - } -#endif - } -} -#endif - -/* -** This function allocates a new parser. -** The only argument is a pointer to a function which works like -** malloc. -** -** Inputs: -** A pointer to the function used to allocate memory. -** -** Outputs: -** A pointer to a parser. This pointer is used in subsequent calls -** to Parse and ParseFree. -*/ -void *ParseAlloc(void *(*mallocProc)(size_t)){ - yyParser *pParser; - pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); - if( pParser ){ - pParser->yyidx = -1; -#ifdef YYTRACKMAXSTACKDEPTH - pParser->yyidxMax = 0; -#endif -#if YYSTACKDEPTH<=0 - pParser->yystack = NULL; - pParser->yystksz = 0; - yyGrowStack(pParser); -#endif - } - return pParser; -} - -/* The following function deletes the value associated with a -** symbol. The symbol can be either a terminal or nonterminal. -** "yymajor" is the symbol code, and "yypminor" is a pointer to -** the value. -*/ -static void yy_destructor( - yyParser *yypParser, /* The parser */ - YYCODETYPE yymajor, /* Type code for object to destroy */ - YYMINORTYPE *yypminor /* The object to be destroyed */ -){ - ParseARG_FETCH; - switch( yymajor ){ - /* Here is inserted the actions which take place when a - ** terminal or non-terminal is destroyed. This can happen - ** when the symbol is popped from the stack during a - ** reduce or during error processing or when a parser is - ** being destroyed before it is finished parsing. - ** - ** Note: during a reduce, the only symbols destroyed are those - ** which appear on the RHS of the rule, but which are not used - ** inside the C code. - */ -%% - default: break; /* If no destructor action specified: do nothing */ - } -} - -/* -** Pop the parser's stack once. -** -** If there is a destructor routine associated with the token which -** is popped from the stack, then call it. -** -** Return the major token number for the symbol popped. -*/ -static int yy_pop_parser_stack(yyParser *pParser){ - YYCODETYPE yymajor; - yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; - - if( pParser->yyidx<0 ) return 0; -#ifndef NDEBUG - if( yyTraceFILE && pParser->yyidx>=0 ){ - fprintf(yyTraceFILE,"%sPopping %s\n", - yyTracePrompt, - yyTokenName[yytos->major]); - } -#endif - yymajor = yytos->major; - yy_destructor(pParser, yymajor, &yytos->minor); - pParser->yyidx--; - return yymajor; -} - -/* -** Deallocate and destroy a parser. Destructors are all called for -** all stack elements before shutting the parser down. -** -** Inputs: -** <ul> -** <li> A pointer to the parser. This should be a pointer -** obtained from ParseAlloc. -** <li> A pointer to a function used to reclaim memory obtained -** from malloc. -** </ul> -*/ -void ParseFree( - void *p, /* The parser to be deleted */ - void (*freeProc)(void*) /* Function used to reclaim memory */ -){ - yyParser *pParser = (yyParser*)p; - if( pParser==0 ) return; - while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); -#if YYSTACKDEPTH<=0 - free(pParser->yystack); -#endif - (*freeProc)((void*)pParser); -} - -/* -** Return the peak depth of the stack for a parser. -*/ -#ifdef YYTRACKMAXSTACKDEPTH -int ParseStackPeak(void *p){ - yyParser *pParser = (yyParser*)p; - return pParser->yyidxMax; -} -#endif - -/* -** Find the appropriate action for a parser given the terminal -** look-ahead token iLookAhead. -** -** If the look-ahead token is YYNOCODE, then check to see if the action is -** independent of the look-ahead. If it is, return the action, otherwise -** return YY_NO_ACTION. -*/ -static int yy_find_shift_action( - yyParser *pParser, /* The parser */ - YYCODETYPE iLookAhead /* The look-ahead token */ -){ - int i; - int stateno = pParser->yystack[pParser->yyidx].stateno; - - if( stateno>=YY_MIN_REDUCE ) return stateno; - assert( stateno <= YY_SHIFT_COUNT ); - i = yy_shift_ofst[stateno]; - if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; - assert( iLookAhead!=YYNOCODE ); - i += iLookAhead; - if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ - if( iLookAhead>0 ){ -#ifdef YYFALLBACK - YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) - && (iFallback = yyFallback[iLookAhead])!=0 ){ -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); - } -#endif - return yy_find_shift_action(pParser, iFallback); - } -#endif -#ifdef YYWILDCARD - { - int j = i - iLookAhead + YYWILDCARD; - if( -#if YY_SHIFT_MIN+YYWILDCARD<0 - j>=0 && -#endif -#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT - j<YY_ACTTAB_COUNT && -#endif - yy_lookahead[j]==YYWILDCARD - ){ -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); - } -#endif /* NDEBUG */ - return yy_action[j]; - } - } -#endif /* YYWILDCARD */ - } - return yy_default[stateno]; - }else{ - return yy_action[i]; - } -} - -/* -** Find the appropriate action for a parser given the non-terminal -** look-ahead token iLookAhead. -** -** If the look-ahead token is YYNOCODE, then check to see if the action is -** independent of the look-ahead. If it is, return the action, otherwise -** return YY_NO_ACTION. -*/ -static int yy_find_reduce_action( - int stateno, /* Current state number */ - YYCODETYPE iLookAhead /* The look-ahead token */ -){ - int i; -#ifdef YYERRORSYMBOL - if( stateno>YY_REDUCE_COUNT ){ - return yy_default[stateno]; - } -#else - assert( stateno<=YY_REDUCE_COUNT ); -#endif - i = yy_reduce_ofst[stateno]; - assert( i!=YY_REDUCE_USE_DFLT ); - assert( iLookAhead!=YYNOCODE ); - i += iLookAhead; -#ifdef YYERRORSYMBOL - if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ - return yy_default[stateno]; - } -#else - assert( i>=0 && i<YY_ACTTAB_COUNT ); - assert( yy_lookahead[i]==iLookAhead ); -#endif - return yy_action[i]; -} - -/* -** The following routine is called if the stack overflows. -*/ -static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ - ParseARG_FETCH; - yypParser->yyidx--; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); - } -#endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); - /* Here code is inserted which will execute if the parser - ** stack every overflows */ -%% - ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ -} - -/* -** Print tracing information for a SHIFT action -*/ -#ifndef NDEBUG -static void yyTraceShift(yyParser *yypParser, int yyNewState){ - if( yyTraceFILE ){ - int i; - if( yyNewState<YYNSTATE ){ - fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); - fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); - for(i=1; i<=yypParser->yyidx; i++) - fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); - fprintf(yyTraceFILE,"\n"); - }else{ - fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt); - } - } -} -#else -# define yyTraceShift(X,Y) -#endif - -/* -** Perform a shift action. Return the number of errors. -*/ -static void yy_shift( - yyParser *yypParser, /* The parser to be shifted */ - int yyNewState, /* The new state to shift in */ - int yyMajor, /* The major token to shift in */ - YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ -){ - yyStackEntry *yytos; - yypParser->yyidx++; -#ifdef YYTRACKMAXSTACKDEPTH - if( yypParser->yyidx>yypParser->yyidxMax ){ - yypParser->yyidxMax = yypParser->yyidx; - } -#endif -#if YYSTACKDEPTH>0 - if( yypParser->yyidx>=YYSTACKDEPTH ){ - yyStackOverflow(yypParser, yypMinor); - return; - } -#else - if( yypParser->yyidx>=yypParser->yystksz ){ - yyGrowStack(yypParser); - if( yypParser->yyidx>=yypParser->yystksz ){ - yyStackOverflow(yypParser, yypMinor); - return; - } - } -#endif - yytos = &yypParser->yystack[yypParser->yyidx]; - yytos->stateno = (YYACTIONTYPE)yyNewState; - yytos->major = (YYCODETYPE)yyMajor; - yytos->minor = *yypMinor; - yyTraceShift(yypParser, yyNewState); -} - -/* The following table contains information about every rule that -** is used during the reduce. -*/ -static const struct { - YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - unsigned char nrhs; /* Number of right-hand side symbols in the rule */ -} yyRuleInfo[] = { -%% -}; - -static void yy_accept(yyParser*); /* Forward Declaration */ - -/* -** Perform a reduce action and the shift that must immediately -** follow the reduce. -*/ -static void yy_reduce( - yyParser *yypParser, /* The parser */ - int yyruleno /* Number of the rule by which to reduce */ -){ - int yygoto; /* The next state */ - int yyact; /* The next action */ - YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ - yyStackEntry *yymsp; /* The top of the parser's stack */ - int yysize; /* Amount to pop the stack */ - ParseARG_FETCH; - yymsp = &yypParser->yystack[yypParser->yyidx]; -#ifndef NDEBUG - if( yyTraceFILE && yyruleno>=0 - && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ - yysize = yyRuleInfo[yyruleno].nrhs; - fprintf(yyTraceFILE, "%sReduce [%s] -> state %d.\n", yyTracePrompt, - yyRuleName[yyruleno], yymsp[-yysize].stateno); - } -#endif /* NDEBUG */ - - /* Silence complaints from purify about yygotominor being uninitialized - ** in some cases when it is copied into the stack after the following - ** switch. yygotominor is uninitialized when a rule reduces that does - ** not set the value of its left-hand side nonterminal. Leaving the - ** value of the nonterminal uninitialized is utterly harmless as long - ** as the value is never used. So really the only thing this code - ** accomplishes is to quieten purify. - ** - ** 2007-01-16: The wireshark project (www.wireshark.org) reports that - ** without this code, their parser segfaults. I'm not sure what there - ** parser is doing to make this happen. This is the second bug report - ** from wireshark this week. Clearly they are stressing Lemon in ways - ** that it has not been previously stressed... (SQLite ticket #2172) - */ - /*memset(&yygotominor, 0, sizeof(yygotominor));*/ - yygotominor = yyzerominor; - - - switch( yyruleno ){ - /* Beginning here are the reduction cases. A typical example - ** follows: - ** case 0: - ** #line <lineno> <grammarfile> - ** { ... } // User supplied code - ** #line <lineno> <thisfile> - ** break; - */ -%% - }; - yygoto = yyRuleInfo[yyruleno].lhs; - yysize = yyRuleInfo[yyruleno].nrhs; - yypParser->yyidx -= yysize; - yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); - if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - /* If the reduce action popped at least - ** one element off the stack, then we can push the new element back - ** onto the stack here, and skip the stack overflow test in yy_shift(). - ** That gives a significant speed improvement. */ - if( yysize ){ - yypParser->yyidx++; - yymsp -= yysize-1; - yymsp->stateno = (YYACTIONTYPE)yyact; - yymsp->major = (YYCODETYPE)yygoto; - yymsp->minor = yygotominor; - yyTraceShift(yypParser, yyact); - }else{ - yy_shift(yypParser,yyact,yygoto,&yygotominor); - } - }else{ - assert( yyact == YY_ACCEPT_ACTION ); - yy_accept(yypParser); - } -} - -/* -** The following code executes when the parse fails -*/ -#ifndef YYNOERRORRECOVERY -static void yy_parse_failed( - yyParser *yypParser /* The parser */ -){ - ParseARG_FETCH; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); - } -#endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); - /* Here code is inserted which will be executed whenever the - ** parser fails */ -%% - ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ -} -#endif /* YYNOERRORRECOVERY */ - -/* -** The following code executes when a syntax error first occurs. -*/ -static void yy_syntax_error( - yyParser *yypParser, /* The parser */ - int yymajor, /* The major type of the error token */ - YYMINORTYPE yyminor /* The minor type of the error token */ -){ - ParseARG_FETCH; -#define TOKEN (yyminor.yy0) -%% - ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ -} - -/* -** The following is executed when the parser accepts -*/ -static void yy_accept( - yyParser *yypParser /* The parser */ -){ - ParseARG_FETCH; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); - } -#endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); - /* Here code is inserted which will be executed whenever the - ** parser accepts */ -%% - ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ -} - -/* The main parser program. -** The first argument is a pointer to a structure obtained from -** "ParseAlloc" which describes the current state of the parser. -** The second argument is the major token number. The third is -** the minor token. The fourth optional argument is whatever the -** user wants (and specified in the grammar) and is available for -** use by the action routines. -** -** Inputs: -** <ul> -** <li> A pointer to the parser (an opaque structure.) -** <li> The major token number. -** <li> The minor token number. -** <li> An option argument of a grammar-specified type. -** </ul> -** -** Outputs: -** None. -*/ -void Parse( - void *yyp, /* The parser */ - int yymajor, /* The major token code number */ - ParseTOKENTYPE yyminor /* The value for the token */ - ParseARG_PDECL /* Optional %extra_argument parameter */ -){ - YYMINORTYPE yyminorunion; - int yyact; /* The parser action. */ - int yyendofinput; /* True if we are at the end of input */ -#ifdef YYERRORSYMBOL - int yyerrorhit = 0; /* True if yymajor has invoked an error */ -#endif - yyParser *yypParser; /* The parser */ - - /* (re)initialize the parser, if necessary */ - yypParser = (yyParser*)yyp; - if( yypParser->yyidx<0 ){ -#if YYSTACKDEPTH<=0 - if( yypParser->yystksz <=0 ){ - /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ - yyminorunion = yyzerominor; - yyStackOverflow(yypParser, &yyminorunion); - return; - } -#endif - yypParser->yyidx = 0; - yypParser->yyerrcnt = -1; - yypParser->yystack[0].stateno = 0; - yypParser->yystack[0].major = 0; - } - yyminorunion.yy0 = yyminor; - yyendofinput = (yymajor==0); - ParseARG_STORE; - -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); - } -#endif - - do{ - yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); - if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - yy_shift(yypParser,yyact,yymajor,&yyminorunion); - yypParser->yyerrcnt--; - yymajor = YYNOCODE; - }else if( yyact <= YY_MAX_REDUCE ){ - yy_reduce(yypParser,yyact-YY_MIN_REDUCE); - }else{ - assert( yyact == YY_ERROR_ACTION ); -#ifdef YYERRORSYMBOL - int yymx; -#endif -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); - } -#endif -#ifdef YYERRORSYMBOL - /* A syntax error has occurred. - ** The response to an error depends upon whether or not the - ** grammar defines an error token "ERROR". - ** - ** This is what we do if the grammar does define ERROR: - ** - ** * Call the %syntax_error function. - ** - ** * Begin popping the stack until we enter a state where - ** it is legal to shift the error symbol, then shift - ** the error symbol. - ** - ** * Set the error count to three. - ** - ** * Begin accepting and shifting new tokens. No new error - ** processing will occur until three tokens have been - ** shifted successfully. - ** - */ - if( yypParser->yyerrcnt<0 ){ - yy_syntax_error(yypParser,yymajor,yyminorunion); - } - yymx = yypParser->yystack[yypParser->yyidx].major; - if( yymx==YYERRORSYMBOL || yyerrorhit ){ -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sDiscard input token %s\n", - yyTracePrompt,yyTokenName[yymajor]); - } -#endif - yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion); - yymajor = YYNOCODE; - }else{ - while( - yypParser->yyidx >= 0 && - yymx != YYERRORSYMBOL && - (yyact = yy_find_reduce_action( - yypParser->yystack[yypParser->yyidx].stateno, - YYERRORSYMBOL)) >= YY_MIN_REDUCE - ){ - yy_pop_parser_stack(yypParser); - } - if( yypParser->yyidx < 0 || yymajor==0 ){ - yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); - yy_parse_failed(yypParser); - yymajor = YYNOCODE; - }else if( yymx!=YYERRORSYMBOL ){ - YYMINORTYPE u2; - u2.YYERRSYMDT = 0; - yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); - } - } - yypParser->yyerrcnt = 3; - yyerrorhit = 1; -#elif defined(YYNOERRORRECOVERY) - /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to - ** do any kind of error recovery. Instead, simply invoke the syntax - ** error routine and continue going as if nothing had happened. - ** - ** Applications can set this macro (for example inside %include) if - ** they intend to abandon the parse upon the first syntax error seen. - */ - yy_syntax_error(yypParser,yymajor,yyminorunion); - yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); - yymajor = YYNOCODE; - -#else /* YYERRORSYMBOL is not defined */ - /* This is what we do if the grammar does not define ERROR: - ** - ** * Report an error message, and throw away the input token. - ** - ** * If the input token is $, then fail the parse. - ** - ** As before, subsequent error messages are suppressed until - ** three input tokens have been successfully shifted. - */ - if( yypParser->yyerrcnt<=0 ){ - yy_syntax_error(yypParser,yymajor,yyminorunion); - } - yypParser->yyerrcnt = 3; - yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); - if( yyendofinput ){ - yy_parse_failed(yypParser); - } - yymajor = YYNOCODE; -#endif - } - }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt); - } -#endif - return; -} diff --git a/lib/libsqlite3/tool/loadfts.c b/lib/libsqlite3/tool/loadfts.c deleted file mode 100644 index 0000797b887..00000000000 --- a/lib/libsqlite3/tool/loadfts.c +++ /dev/null @@ -1,242 +0,0 @@ -/* -** 2014-07-28 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This file implements a utility program that will load many disk -** files (all files under a given directory) into a FTS table. This is -** used for performance testing of FTS3, FTS4, and FTS5. -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <assert.h> -#include <string.h> -#include <errno.h> -#include <dirent.h> -#include "sqlite3.h" - -/* -** Implementation of the "readtext(X)" SQL function. The entire content -** of the file named X is read and returned as a TEXT value. It is assumed -** the file contains UTF-8 text. NULL is returned if the file does not -** exist or is unreadable. -*/ -static void readfileFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const char *zName; - FILE *in; - long nIn; - void *pBuf; - - zName = (const char*)sqlite3_value_text(argv[0]); - if( zName==0 ) return; - in = fopen(zName, "rb"); - if( in==0 ) return; - fseek(in, 0, SEEK_END); - nIn = ftell(in); - rewind(in); - pBuf = sqlite3_malloc( nIn ); - if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ - sqlite3_result_text(context, pBuf, nIn, sqlite3_free); - }else{ - sqlite3_free(pBuf); - } - fclose(in); -} - -/* -** Print usage text for this program and exit. -*/ -static void showHelp(const char *zArgv0){ - printf("\n" -"Usage: %s SWITCHES... DB\n" -"\n" -" This program opens the database named on the command line and attempts to\n" -" create an FTS table named \"fts\" with a single column. If successful, it\n" -" recursively traverses the directory named by the -dir option and inserts\n" -" the contents of each file into the fts table. All files are assumed to\n" -" contain UTF-8 text.\n" -"\n" -"Switches are:\n" -" -fts [345] FTS version to use (default=5)\n" -" -idx [01] Create a mapping from filename to rowid (default=0)\n" -" -dir <path> Root of directory tree to load data from (default=.)\n" -" -trans <integer> Number of inserts per transaction (default=1)\n" -, zArgv0 -); - exit(1); -} - -/* -** Exit with a message based on the argument and the current value of errno. -*/ -static void error_out(const char *zText){ - fprintf(stderr, "%s: %s\n", zText, strerror(errno)); - exit(-1); -} - -/* -** Exit with a message based on the first argument and the error message -** currently stored in database handle db. -*/ -static void sqlite_error_out(const char *zText, sqlite3 *db){ - fprintf(stderr, "%s: %s\n", zText, sqlite3_errmsg(db)); - exit(-1); -} - -/* -** Context object for visit_file(). -*/ -typedef struct VisitContext VisitContext; -struct VisitContext { - int nRowPerTrans; - sqlite3 *db; /* Database handle */ - sqlite3_stmt *pInsert; /* INSERT INTO fts VALUES(readtext(:1)) */ -}; - -/* -** Callback used with traverse(). The first argument points to an object -** of type VisitContext. This function inserts the contents of the text -** file zPath into the FTS table. -*/ -void visit_file(void *pCtx, const char *zPath){ - int rc; - VisitContext *p = (VisitContext*)pCtx; - /* printf("%s\n", zPath); */ - sqlite3_bind_text(p->pInsert, 1, zPath, -1, SQLITE_STATIC); - sqlite3_step(p->pInsert); - rc = sqlite3_reset(p->pInsert); - if( rc!=SQLITE_OK ){ - sqlite_error_out("insert", p->db); - }else if( p->nRowPerTrans>0 - && (sqlite3_last_insert_rowid(p->db) % p->nRowPerTrans)==0 - ){ - sqlite3_exec(p->db, "COMMIT ; BEGIN", 0, 0, 0); - } -} - -/* -** Recursively traverse directory zDir. For each file that is not a -** directory, invoke the supplied callback with its path. -*/ -static void traverse( - const char *zDir, /* Directory to traverse */ - void *pCtx, /* First argument passed to callback */ - void (*xCallback)(void*, const char *zPath) -){ - DIR *d; - struct dirent *e; - - d = opendir(zDir); - if( d==0 ) error_out("opendir()"); - - for(e=readdir(d); e; e=readdir(d)){ - if( strcmp(e->d_name, ".")==0 || strcmp(e->d_name, "..")==0 ) continue; - char *zPath = sqlite3_mprintf("%s/%s", zDir, e->d_name); - if (e->d_type & DT_DIR) { - traverse(zPath, pCtx, xCallback); - }else{ - xCallback(pCtx, zPath); - } - sqlite3_free(zPath); - } - - closedir(d); -} - -int main(int argc, char **argv){ - int iFts = 5; /* Value of -fts option */ - int bMap = 0; /* True to create mapping table */ - const char *zDir = "."; /* Directory to scan */ - int i; - int rc; - int nRowPerTrans = 0; - sqlite3 *db; - char *zSql; - VisitContext sCtx; - - int nCmd = 0; - char **aCmd = 0; - - if( argc % 2 ) showHelp(argv[0]); - - for(i=1; i<(argc-1); i+=2){ - char *zOpt = argv[i]; - char *zArg = argv[i+1]; - if( strcmp(zOpt, "-fts")==0 ){ - iFts = atoi(zArg); - if( iFts!=3 && iFts!=4 && iFts!= 5) showHelp(argv[0]); - } - else if( strcmp(zOpt, "-trans")==0 ){ - nRowPerTrans = atoi(zArg); - } - else if( strcmp(zOpt, "-idx")==0 ){ - bMap = atoi(zArg); - if( bMap!=0 && bMap!=1 ) showHelp(argv[0]); - } - else if( strcmp(zOpt, "-dir")==0 ){ - zDir = zArg; - } - else if( strcmp(zOpt, "-special")==0 ){ - nCmd++; - aCmd = sqlite3_realloc(aCmd, sizeof(char*) * nCmd); - aCmd[nCmd-1] = zArg; - } - else{ - showHelp(argv[0]); - } - } - - /* Open the database file */ - rc = sqlite3_open(argv[argc-1], &db); - if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_open()", db); - - rc = sqlite3_create_function(db, "readtext", 1, SQLITE_UTF8, 0, - readfileFunc, 0, 0); - if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_create_function()", db); - - /* Create the FTS table */ - zSql = sqlite3_mprintf("CREATE VIRTUAL TABLE fts USING fts%d(content)", iFts); - rc = sqlite3_exec(db, zSql, 0, 0, 0); - if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_exec(1)", db); - sqlite3_free(zSql); - - for(i=0; i<nCmd; i++){ - zSql = sqlite3_mprintf("INSERT INTO fts(fts) VALUES(%Q)", aCmd[i]); - rc = sqlite3_exec(db, zSql, 0, 0, 0); - if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_exec(1)", db); - sqlite3_free(zSql); - } - - /* Compile the INSERT statement to write data to the FTS table. */ - memset(&sCtx, 0, sizeof(VisitContext)); - sCtx.db = db; - sCtx.nRowPerTrans = nRowPerTrans; - rc = sqlite3_prepare_v2(db, - "INSERT INTO fts VALUES(readtext(?))", -1, &sCtx.pInsert, 0 - ); - if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_prepare_v2(1)", db); - - /* Load all files in the directory hierarchy into the FTS table. */ - if( sCtx.nRowPerTrans>0 ) sqlite3_exec(db, "BEGIN", 0, 0, 0); - traverse(zDir, (void*)&sCtx, visit_file); - if( sCtx.nRowPerTrans>0 ) sqlite3_exec(db, "COMMIT", 0, 0, 0); - - /* Clean up and exit. */ - sqlite3_finalize(sCtx.pInsert); - sqlite3_close(db); - sqlite3_free(aCmd); - return 0; -} diff --git a/lib/libsqlite3/tool/logest.c b/lib/libsqlite3/tool/logest.c deleted file mode 100644 index 347fa68a4f4..00000000000 --- a/lib/libsqlite3/tool/logest.c +++ /dev/null @@ -1,170 +0,0 @@ -/* -** 2013-06-10 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file contains a simple command-line utility for converting from -** integers and LogEst values and back again and for doing simple -** arithmetic operations (multiple and add) on LogEst values. -** -** Usage: -** -** ./LogEst ARGS -** -** See the showHelp() routine for a description of valid arguments. -** Examples: -** -** To convert 123 from LogEst to integer: -** -** ./LogEst ^123 -** -** To convert 123456 from integer to LogEst: -** -** ./LogEst 123456 -** -*/ -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <assert.h> -#include <string.h> -#include "sqlite3.h" - -typedef short int LogEst; /* 10 times log2() */ - -LogEst logEstMultiply(LogEst a, LogEst b){ return a+b; } -LogEst logEstAdd(LogEst a, LogEst b){ - static const unsigned char x[] = { - 10, 10, /* 0,1 */ - 9, 9, /* 2,3 */ - 8, 8, /* 4,5 */ - 7, 7, 7, /* 6,7,8 */ - 6, 6, 6, /* 9,10,11 */ - 5, 5, 5, /* 12-14 */ - 4, 4, 4, 4, /* 15-18 */ - 3, 3, 3, 3, 3, 3, /* 19-24 */ - 2, 2, 2, 2, 2, 2, 2, /* 25-31 */ - }; - if( a<b ){ LogEst t = a; a = b; b = t; } - if( a>b+49 ) return a; - if( a>b+31 ) return a+1; - return a+x[a-b]; -} -LogEst logEstFromInteger(sqlite3_uint64 x){ - static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; - LogEst y = 40; - if( x<8 ){ - if( x<2 ) return 0; - while( x<8 ){ y -= 10; x <<= 1; } - }else{ - while( x>255 ){ y += 40; x >>= 4; } - while( x>15 ){ y += 10; x >>= 1; } - } - return a[x&7] + y - 10; -} -static sqlite3_uint64 logEstToInt(LogEst x){ - sqlite3_uint64 n; - if( x<10 ) return 1; - n = x%10; - x /= 10; - if( n>=5 ) n -= 2; - else if( n>=1 ) n -= 1; - if( x>=3 ) return (n+8)<<(x-3); - return (n+8)>>(3-x); -} -static LogEst logEstFromDouble(double x){ - sqlite3_uint64 a; - LogEst e; - assert( sizeof(x)==8 && sizeof(a)==8 ); - if( x<=0.0 ) return -32768; - if( x<0.01 ) return -logEstFromDouble(1.0/x); - if( x<1.0 ) return logEstFromDouble(100.0*x) - 66; - if( x<1024.0 ) return logEstFromInteger((sqlite3_uint64)(1024.0*x)) - 100; - if( x<=2000000000.0 ) return logEstFromInteger((sqlite3_uint64)x); - memcpy(&a, &x, 8); - e = (a>>52) - 1022; - return e*10; -} - -int isInteger(const char *z){ - while( z[0]>='0' && z[0]<='9' ) z++; - return z[0]==0; -} - -int isFloat(const char *z){ - char c; - while( ((c=z[0])>='0' && c<='9') || c=='.' || c=='E' || c=='e' - || c=='+' || c=='-' ) z++; - return z[0]==0; -} - -static void showHelp(const char *zArgv0){ - printf("Usage: %s ARGS...\n", zArgv0); - printf("Arguments:\n" - " NUM Convert NUM from integer to LogEst and push onto the stack\n" - " ^NUM Interpret NUM as a LogEst and push onto stack\n" - " x Multiple the top two elements of the stack\n" - " + Add the top two elements of the stack\n" - " dup Dupliate the top element on the stack\n" - " inv Take the reciprocal of the top of stack. N = 1/N.\n" - " log Find the LogEst of the number on top of stack\n" - " nlogn Compute NlogN where N is the top of stack\n" - ); - exit(1); -} - -int main(int argc, char **argv){ - int i; - int n = 0; - LogEst a[100]; - for(i=1; i<argc; i++){ - const char *z = argv[i]; - if( strcmp(z,"+")==0 ){ - if( n>=2 ){ - a[n-2] = logEstAdd(a[n-2],a[n-1]); - n--; - } - }else if( strcmp(z,"x")==0 ){ - if( n>=2 ){ - a[n-2] = logEstMultiply(a[n-2],a[n-1]); - n--; - } - }else if( strcmp(z,"dup")==0 ){ - if( n>0 ){ - a[n] = a[n-1]; - n++; - } - }else if( strcmp(z,"log")==0 ){ - if( n>0 ) a[n-1] = logEstFromInteger(a[n-1]) - 33; - }else if( strcmp(z,"nlogn")==0 ){ - if( n>0 ) a[n-1] += logEstFromInteger(a[n-1]) - 33; - }else if( strcmp(z,"inv")==0 ){ - if( n>0 ) a[n-1] = -a[n-1]; - }else if( z[0]=='^' ){ - a[n++] = atoi(z+1); - }else if( isInteger(z) ){ - a[n++] = logEstFromInteger(atoi(z)); - }else if( isFloat(z) && z[0]!='-' ){ - a[n++] = logEstFromDouble(atof(z)); - }else{ - showHelp(argv[0]); - } - } - for(i=n-1; i>=0; i--){ - if( a[i]<-40 ){ - printf("%5d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i])); - }else if( a[i]<10 ){ - printf("%5d (%f)\n", a[i], logEstToInt(a[i]+100)/1024.0); - }else{ - sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024; - printf("%5d (%lld.%02lld)\n", a[i], x/100, x%100); - } - } - return 0; -} diff --git a/lib/libsqlite3/tool/mkautoconfamal.sh b/lib/libsqlite3/tool/mkautoconfamal.sh deleted file mode 100644 index 0c2668c8b7e..00000000000 --- a/lib/libsqlite3/tool/mkautoconfamal.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/sh -# This script is used to build the amalgamation autoconf package. -# It assumes the following: -# -# 1. The files "sqlite3.c", "sqlite3.h" and "sqlite3ext.h" -# are available in the current directory. -# -# 2. Variable $TOP is set to the full path of the root directory -# of the SQLite source tree. -# -# 3. There is nothing of value in the ./mkpkg_tmp_dir directory. -# This is important, as the script executes "rm -rf ./mkpkg_tmp_dir". -# - - -# Bail out of the script if any command returns a non-zero exit -# status. Or if the script tries to use an unset variable. These -# may fail for old /bin/sh interpreters. -# -set -e -set -u - -TMPSPACE=./mkpkg_tmp_dir -VERSION=`cat $TOP/VERSION` - -# Set global variable $ARTIFACT to the "3xxyyzz" string incorporated -# into artifact filenames. And $VERSION2 to the "3.x.y[.z]" form. -xx=`echo $VERSION|sed 's/3\.\([0-9]*\)\..*/\1/'` -yy=`echo $VERSION|sed 's/3\.[^.]*\.\([0-9]*\).*/\1/'` -zz=0 -set +e - zz=`echo $VERSION|sed 's/3\.[^.]*\.[^.]*\.\([0-9]*\).*/\1/'|grep -v '\.'` -set -e -ARTIFACT=`printf "3%.2d%.2d%.2d" $xx $yy $zz` - -rm -rf $TMPSPACE -cp -R $TOP/autoconf $TMPSPACE - -cp sqlite3.c $TMPSPACE -cp sqlite3.h $TMPSPACE -cp sqlite3ext.h $TMPSPACE -cp $TOP/sqlite3.1 $TMPSPACE -cp $TOP/sqlite3.pc.in $TMPSPACE -cp $TOP/src/shell.c $TMPSPACE - -chmod 755 $TMPSPACE/install-sh -chmod 755 $TMPSPACE/missing -chmod 755 $TMPSPACE/depcomp -chmod 755 $TMPSPACE/config.sub -chmod 755 $TMPSPACE/config.guess - -cat $TMPSPACE/configure.ac | -sed "s/AC_INIT(sqlite, .*, http:\/\/www.sqlite.org)/AC_INIT(sqlite, $VERSION, http:\/\/www.sqlite.org)/" > $TMPSPACE/tmp -mv $TMPSPACE/tmp $TMPSPACE/configure.ac - -cd $TMPSPACE -aclocal -autoconf -automake - -mkdir -p tea/generic -echo "#ifdef USE_SYSTEM_SQLITE" > tea/generic/tclsqlite3.c -echo "# include <sqlite3.h>" >> tea/generic/tclsqlite3.c -echo "#else" >> tea/generic/tclsqlite3.c -echo "#include \"sqlite3.c\"" >> tea/generic/tclsqlite3.c -echo "#endif" >> tea/generic/tclsqlite3.c -cat $TOP/src/tclsqlite.c >> tea/generic/tclsqlite3.c - -cat tea/configure.ac | - sed "s/AC_INIT(\[sqlite\], .*)/AC_INIT([sqlite], [$VERSION])/" > tmp -mv tmp tea/configure.ac - -cd tea -autoconf -rm -rf autom4te.cache - -cd ../ -./configure && make dist -tar -xzf sqlite-$VERSION.tar.gz -mv sqlite-$VERSION sqlite-autoconf-$ARTIFACT -tar -czf sqlite-autoconf-$ARTIFACT.tar.gz sqlite-autoconf-$ARTIFACT -mv sqlite-autoconf-$ARTIFACT.tar.gz .. diff --git a/lib/libsqlite3/tool/mkkeywordhash.c b/lib/libsqlite3/tool/mkkeywordhash.c deleted file mode 100644 index 721611f5a36..00000000000 --- a/lib/libsqlite3/tool/mkkeywordhash.c +++ /dev/null @@ -1,610 +0,0 @@ -/* -** Compile and run this standalone program in order to generate code that -** implements a function that will translate alphabetic identifiers into -** parser token codes. -*/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <assert.h> - -/* -** A header comment placed at the beginning of generated code. -*/ -static const char zHdr[] = - "/***** This file contains automatically generated code ******\n" - "**\n" - "** The code in this file has been automatically generated by\n" - "**\n" - "** sqlite/tool/mkkeywordhash.c\n" - "**\n" - "** The code in this file implements a function that determines whether\n" - "** or not a given identifier is really an SQL keyword. The same thing\n" - "** might be implemented more directly using a hand-written hash table.\n" - "** But by using this automatically generated code, the size of the code\n" - "** is substantially reduced. This is important for embedded applications\n" - "** on platforms with limited memory.\n" - "*/\n" -; - -/* -** All the keywords of the SQL language are stored in a hash -** table composed of instances of the following structure. -*/ -typedef struct Keyword Keyword; -struct Keyword { - char *zName; /* The keyword name */ - char *zTokenType; /* Token value for this keyword */ - int mask; /* Code this keyword if non-zero */ - int id; /* Unique ID for this record */ - int hash; /* Hash on the keyword */ - int offset; /* Offset to start of name string */ - int len; /* Length of this keyword, not counting final \000 */ - int prefix; /* Number of characters in prefix */ - int longestSuffix; /* Longest suffix that is a prefix on another word */ - int iNext; /* Index in aKeywordTable[] of next with same hash */ - int substrId; /* Id to another keyword this keyword is embedded in */ - int substrOffset; /* Offset into substrId for start of this keyword */ - char zOrigName[20]; /* Original keyword name before processing */ -}; - -/* -** Define masks used to determine which keywords are allowed -*/ -#ifdef SQLITE_OMIT_ALTERTABLE -# define ALTER 0 -#else -# define ALTER 0x00000001 -#endif -#define ALWAYS 0x00000002 -#ifdef SQLITE_OMIT_ANALYZE -# define ANALYZE 0 -#else -# define ANALYZE 0x00000004 -#endif -#ifdef SQLITE_OMIT_ATTACH -# define ATTACH 0 -#else -# define ATTACH 0x00000008 -#endif -#ifdef SQLITE_OMIT_AUTOINCREMENT -# define AUTOINCR 0 -#else -# define AUTOINCR 0x00000010 -#endif -#ifdef SQLITE_OMIT_CAST -# define CAST 0 -#else -# define CAST 0x00000020 -#endif -#ifdef SQLITE_OMIT_COMPOUND_SELECT -# define COMPOUND 0 -#else -# define COMPOUND 0x00000040 -#endif -#ifdef SQLITE_OMIT_CONFLICT_CLAUSE -# define CONFLICT 0 -#else -# define CONFLICT 0x00000080 -#endif -#ifdef SQLITE_OMIT_EXPLAIN -# define EXPLAIN 0 -#else -# define EXPLAIN 0x00000100 -#endif -#ifdef SQLITE_OMIT_FOREIGN_KEY -# define FKEY 0 -#else -# define FKEY 0x00000200 -#endif -#ifdef SQLITE_OMIT_PRAGMA -# define PRAGMA 0 -#else -# define PRAGMA 0x00000400 -#endif -#ifdef SQLITE_OMIT_REINDEX -# define REINDEX 0 -#else -# define REINDEX 0x00000800 -#endif -#ifdef SQLITE_OMIT_SUBQUERY -# define SUBQUERY 0 -#else -# define SUBQUERY 0x00001000 -#endif -#ifdef SQLITE_OMIT_TRIGGER -# define TRIGGER 0 -#else -# define TRIGGER 0x00002000 -#endif -#if defined(SQLITE_OMIT_AUTOVACUUM) && \ - (defined(SQLITE_OMIT_VACUUM) || defined(SQLITE_OMIT_ATTACH)) -# define VACUUM 0 -#else -# define VACUUM 0x00004000 -#endif -#ifdef SQLITE_OMIT_VIEW -# define VIEW 0 -#else -# define VIEW 0x00008000 -#endif -#ifdef SQLITE_OMIT_VIRTUALTABLE -# define VTAB 0 -#else -# define VTAB 0x00010000 -#endif -#ifdef SQLITE_OMIT_AUTOVACUUM -# define AUTOVACUUM 0 -#else -# define AUTOVACUUM 0x00020000 -#endif -#ifdef SQLITE_OMIT_CTE -# define CTE 0 -#else -# define CTE 0x00040000 -#endif - -/* -** These are the keywords -*/ -static Keyword aKeywordTable[] = { - { "ABORT", "TK_ABORT", CONFLICT|TRIGGER }, - { "ACTION", "TK_ACTION", FKEY }, - { "ADD", "TK_ADD", ALTER }, - { "AFTER", "TK_AFTER", TRIGGER }, - { "ALL", "TK_ALL", ALWAYS }, - { "ALTER", "TK_ALTER", ALTER }, - { "ANALYZE", "TK_ANALYZE", ANALYZE }, - { "AND", "TK_AND", ALWAYS }, - { "AS", "TK_AS", ALWAYS }, - { "ASC", "TK_ASC", ALWAYS }, - { "ATTACH", "TK_ATTACH", ATTACH }, - { "AUTOINCREMENT", "TK_AUTOINCR", AUTOINCR }, - { "BEFORE", "TK_BEFORE", TRIGGER }, - { "BEGIN", "TK_BEGIN", ALWAYS }, - { "BETWEEN", "TK_BETWEEN", ALWAYS }, - { "BY", "TK_BY", ALWAYS }, - { "CASCADE", "TK_CASCADE", FKEY }, - { "CASE", "TK_CASE", ALWAYS }, - { "CAST", "TK_CAST", CAST }, - { "CHECK", "TK_CHECK", ALWAYS }, - { "COLLATE", "TK_COLLATE", ALWAYS }, - { "COLUMN", "TK_COLUMNKW", ALTER }, - { "COMMIT", "TK_COMMIT", ALWAYS }, - { "CONFLICT", "TK_CONFLICT", CONFLICT }, - { "CONSTRAINT", "TK_CONSTRAINT", ALWAYS }, - { "CREATE", "TK_CREATE", ALWAYS }, - { "CROSS", "TK_JOIN_KW", ALWAYS }, - { "CURRENT_DATE", "TK_CTIME_KW", ALWAYS }, - { "CURRENT_TIME", "TK_CTIME_KW", ALWAYS }, - { "CURRENT_TIMESTAMP","TK_CTIME_KW", ALWAYS }, - { "DATABASE", "TK_DATABASE", ATTACH }, - { "DEFAULT", "TK_DEFAULT", ALWAYS }, - { "DEFERRED", "TK_DEFERRED", ALWAYS }, - { "DEFERRABLE", "TK_DEFERRABLE", FKEY }, - { "DELETE", "TK_DELETE", ALWAYS }, - { "DESC", "TK_DESC", ALWAYS }, - { "DETACH", "TK_DETACH", ATTACH }, - { "DISTINCT", "TK_DISTINCT", ALWAYS }, - { "DROP", "TK_DROP", ALWAYS }, - { "END", "TK_END", ALWAYS }, - { "EACH", "TK_EACH", TRIGGER }, - { "ELSE", "TK_ELSE", ALWAYS }, - { "ESCAPE", "TK_ESCAPE", ALWAYS }, - { "EXCEPT", "TK_EXCEPT", COMPOUND }, - { "EXCLUSIVE", "TK_EXCLUSIVE", ALWAYS }, - { "EXISTS", "TK_EXISTS", ALWAYS }, - { "EXPLAIN", "TK_EXPLAIN", EXPLAIN }, - { "FAIL", "TK_FAIL", CONFLICT|TRIGGER }, - { "FOR", "TK_FOR", TRIGGER }, - { "FOREIGN", "TK_FOREIGN", FKEY }, - { "FROM", "TK_FROM", ALWAYS }, - { "FULL", "TK_JOIN_KW", ALWAYS }, - { "GLOB", "TK_LIKE_KW", ALWAYS }, - { "GROUP", "TK_GROUP", ALWAYS }, - { "HAVING", "TK_HAVING", ALWAYS }, - { "IF", "TK_IF", ALWAYS }, - { "IGNORE", "TK_IGNORE", CONFLICT|TRIGGER }, - { "IMMEDIATE", "TK_IMMEDIATE", ALWAYS }, - { "IN", "TK_IN", ALWAYS }, - { "INDEX", "TK_INDEX", ALWAYS }, - { "INDEXED", "TK_INDEXED", ALWAYS }, - { "INITIALLY", "TK_INITIALLY", FKEY }, - { "INNER", "TK_JOIN_KW", ALWAYS }, - { "INSERT", "TK_INSERT", ALWAYS }, - { "INSTEAD", "TK_INSTEAD", TRIGGER }, - { "INTERSECT", "TK_INTERSECT", COMPOUND }, - { "INTO", "TK_INTO", ALWAYS }, - { "IS", "TK_IS", ALWAYS }, - { "ISNULL", "TK_ISNULL", ALWAYS }, - { "JOIN", "TK_JOIN", ALWAYS }, - { "KEY", "TK_KEY", ALWAYS }, - { "LEFT", "TK_JOIN_KW", ALWAYS }, - { "LIKE", "TK_LIKE_KW", ALWAYS }, - { "LIMIT", "TK_LIMIT", ALWAYS }, - { "MATCH", "TK_MATCH", ALWAYS }, - { "NATURAL", "TK_JOIN_KW", ALWAYS }, - { "NO", "TK_NO", FKEY }, - { "NOT", "TK_NOT", ALWAYS }, - { "NOTNULL", "TK_NOTNULL", ALWAYS }, - { "NULL", "TK_NULL", ALWAYS }, - { "OF", "TK_OF", ALWAYS }, - { "OFFSET", "TK_OFFSET", ALWAYS }, - { "ON", "TK_ON", ALWAYS }, - { "OR", "TK_OR", ALWAYS }, - { "ORDER", "TK_ORDER", ALWAYS }, - { "OUTER", "TK_JOIN_KW", ALWAYS }, - { "PLAN", "TK_PLAN", EXPLAIN }, - { "PRAGMA", "TK_PRAGMA", PRAGMA }, - { "PRIMARY", "TK_PRIMARY", ALWAYS }, - { "QUERY", "TK_QUERY", EXPLAIN }, - { "RAISE", "TK_RAISE", TRIGGER }, - { "RECURSIVE", "TK_RECURSIVE", CTE }, - { "REFERENCES", "TK_REFERENCES", FKEY }, - { "REGEXP", "TK_LIKE_KW", ALWAYS }, - { "REINDEX", "TK_REINDEX", REINDEX }, - { "RELEASE", "TK_RELEASE", ALWAYS }, - { "RENAME", "TK_RENAME", ALTER }, - { "REPLACE", "TK_REPLACE", CONFLICT }, - { "RESTRICT", "TK_RESTRICT", FKEY }, - { "RIGHT", "TK_JOIN_KW", ALWAYS }, - { "ROLLBACK", "TK_ROLLBACK", ALWAYS }, - { "ROW", "TK_ROW", TRIGGER }, - { "SAVEPOINT", "TK_SAVEPOINT", ALWAYS }, - { "SELECT", "TK_SELECT", ALWAYS }, - { "SET", "TK_SET", ALWAYS }, - { "TABLE", "TK_TABLE", ALWAYS }, - { "TEMP", "TK_TEMP", ALWAYS }, - { "TEMPORARY", "TK_TEMP", ALWAYS }, - { "THEN", "TK_THEN", ALWAYS }, - { "TO", "TK_TO", ALWAYS }, - { "TRANSACTION", "TK_TRANSACTION", ALWAYS }, - { "TRIGGER", "TK_TRIGGER", TRIGGER }, - { "UNION", "TK_UNION", COMPOUND }, - { "UNIQUE", "TK_UNIQUE", ALWAYS }, - { "UPDATE", "TK_UPDATE", ALWAYS }, - { "USING", "TK_USING", ALWAYS }, - { "VACUUM", "TK_VACUUM", VACUUM }, - { "VALUES", "TK_VALUES", ALWAYS }, - { "VIEW", "TK_VIEW", VIEW }, - { "VIRTUAL", "TK_VIRTUAL", VTAB }, - { "WITH", "TK_WITH", CTE }, - { "WITHOUT", "TK_WITHOUT", ALWAYS }, - { "WHEN", "TK_WHEN", ALWAYS }, - { "WHERE", "TK_WHERE", ALWAYS }, -}; - -/* Number of keywords */ -static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0])); - -/* An array to map all upper-case characters into their corresponding -** lower-case character. -*/ -const unsigned char sqlite3UpperToLower[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, - 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, - 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107, - 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, - 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, - 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, - 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, - 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, - 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, - 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, - 252,253,254,255 -}; -#define UpperToLower sqlite3UpperToLower - -/* -** Comparision function for two Keyword records -*/ -static int keywordCompare1(const void *a, const void *b){ - const Keyword *pA = (Keyword*)a; - const Keyword *pB = (Keyword*)b; - int n = pA->len - pB->len; - if( n==0 ){ - n = strcmp(pA->zName, pB->zName); - } - assert( n!=0 ); - return n; -} -static int keywordCompare2(const void *a, const void *b){ - const Keyword *pA = (Keyword*)a; - const Keyword *pB = (Keyword*)b; - int n = pB->longestSuffix - pA->longestSuffix; - if( n==0 ){ - n = strcmp(pA->zName, pB->zName); - } - assert( n!=0 ); - return n; -} -static int keywordCompare3(const void *a, const void *b){ - const Keyword *pA = (Keyword*)a; - const Keyword *pB = (Keyword*)b; - int n = pA->offset - pB->offset; - if( n==0 ) n = pB->id - pA->id; - assert( n!=0 ); - return n; -} - -/* -** Return a KeywordTable entry with the given id -*/ -static Keyword *findById(int id){ - int i; - for(i=0; i<nKeyword; i++){ - if( aKeywordTable[i].id==id ) break; - } - return &aKeywordTable[i]; -} - -/* -** This routine does the work. The generated code is printed on standard -** output. -*/ -int main(int argc, char **argv){ - int i, j, k, h; - int bestSize, bestCount; - int count; - int nChar; - int totalLen = 0; - int aHash[1000]; /* 1000 is much bigger than nKeyword */ - char zText[2000]; - - /* Remove entries from the list of keywords that have mask==0 */ - for(i=j=0; i<nKeyword; i++){ - if( aKeywordTable[i].mask==0 ) continue; - if( j<i ){ - aKeywordTable[j] = aKeywordTable[i]; - } - j++; - } - nKeyword = j; - - /* Fill in the lengths of strings and hashes for all entries. */ - for(i=0; i<nKeyword; i++){ - Keyword *p = &aKeywordTable[i]; - p->len = (int)strlen(p->zName); - assert( p->len<sizeof(p->zOrigName) ); - memcpy(p->zOrigName, p->zName, p->len+1); - totalLen += p->len; - p->hash = (UpperToLower[(int)p->zName[0]]*4) ^ - (UpperToLower[(int)p->zName[p->len-1]]*3) ^ p->len; - p->id = i+1; - } - - /* Sort the table from shortest to longest keyword */ - qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare1); - - /* Look for short keywords embedded in longer keywords */ - for(i=nKeyword-2; i>=0; i--){ - Keyword *p = &aKeywordTable[i]; - for(j=nKeyword-1; j>i && p->substrId==0; j--){ - Keyword *pOther = &aKeywordTable[j]; - if( pOther->substrId ) continue; - if( pOther->len<=p->len ) continue; - for(k=0; k<=pOther->len-p->len; k++){ - if( memcmp(p->zName, &pOther->zName[k], p->len)==0 ){ - p->substrId = pOther->id; - p->substrOffset = k; - break; - } - } - } - } - - /* Compute the longestSuffix value for every word */ - for(i=0; i<nKeyword; i++){ - Keyword *p = &aKeywordTable[i]; - if( p->substrId ) continue; - for(j=0; j<nKeyword; j++){ - Keyword *pOther; - if( j==i ) continue; - pOther = &aKeywordTable[j]; - if( pOther->substrId ) continue; - for(k=p->longestSuffix+1; k<p->len && k<pOther->len; k++){ - if( memcmp(&p->zName[p->len-k], pOther->zName, k)==0 ){ - p->longestSuffix = k; - } - } - } - } - - /* Sort the table into reverse order by length */ - qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare2); - - /* Fill in the offset for all entries */ - nChar = 0; - for(i=0; i<nKeyword; i++){ - Keyword *p = &aKeywordTable[i]; - if( p->offset>0 || p->substrId ) continue; - p->offset = nChar; - nChar += p->len; - for(k=p->len-1; k>=1; k--){ - for(j=i+1; j<nKeyword; j++){ - Keyword *pOther = &aKeywordTable[j]; - if( pOther->offset>0 || pOther->substrId ) continue; - if( pOther->len<=k ) continue; - if( memcmp(&p->zName[p->len-k], pOther->zName, k)==0 ){ - p = pOther; - p->offset = nChar - k; - nChar = p->offset + p->len; - p->zName += k; - p->len -= k; - p->prefix = k; - j = i; - k = p->len; - } - } - } - } - for(i=0; i<nKeyword; i++){ - Keyword *p = &aKeywordTable[i]; - if( p->substrId ){ - p->offset = findById(p->substrId)->offset + p->substrOffset; - } - } - - /* Sort the table by offset */ - qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare3); - - /* Figure out how big to make the hash table in order to minimize the - ** number of collisions */ - bestSize = nKeyword; - bestCount = nKeyword*nKeyword; - for(i=nKeyword/2; i<=2*nKeyword; i++){ - for(j=0; j<i; j++) aHash[j] = 0; - for(j=0; j<nKeyword; j++){ - h = aKeywordTable[j].hash % i; - aHash[h] *= 2; - aHash[h]++; - } - for(j=count=0; j<i; j++) count += aHash[j]; - if( count<bestCount ){ - bestCount = count; - bestSize = i; - } - } - - /* Compute the hash */ - for(i=0; i<bestSize; i++) aHash[i] = 0; - for(i=0; i<nKeyword; i++){ - h = aKeywordTable[i].hash % bestSize; - aKeywordTable[i].iNext = aHash[h]; - aHash[h] = i+1; - } - - /* Begin generating code */ - printf("%s", zHdr); - printf("/* Hash score: %d */\n", bestCount); - printf("static int keywordCode(const char *z, int n){\n"); - printf(" /* zText[] encodes %d bytes of keywords in %d bytes */\n", - totalLen + nKeyword, nChar+1 ); - for(i=j=k=0; i<nKeyword; i++){ - Keyword *p = &aKeywordTable[i]; - if( p->substrId ) continue; - memcpy(&zText[k], p->zName, p->len); - k += p->len; - if( j+p->len>70 ){ - printf("%*s */\n", 74-j, ""); - j = 0; - } - if( j==0 ){ - printf(" /* "); - j = 8; - } - printf("%s", p->zName); - j += p->len; - } - if( j>0 ){ - printf("%*s */\n", 74-j, ""); - } - printf(" static const char zText[%d] = {\n", nChar); - zText[nChar] = 0; - for(i=j=0; i<k; i++){ - if( j==0 ){ - printf(" "); - } - if( zText[i]==0 ){ - printf("0"); - }else{ - printf("'%c',", zText[i]); - } - j += 4; - if( j>68 ){ - printf("\n"); - j = 0; - } - } - if( j>0 ) printf("\n"); - printf(" };\n"); - - printf(" static const unsigned char aHash[%d] = {\n", bestSize); - for(i=j=0; i<bestSize; i++){ - if( j==0 ) printf(" "); - printf(" %3d,", aHash[i]); - j++; - if( j>12 ){ - printf("\n"); - j = 0; - } - } - printf("%s };\n", j==0 ? "" : "\n"); - - printf(" static const unsigned char aNext[%d] = {\n", nKeyword); - for(i=j=0; i<nKeyword; i++){ - if( j==0 ) printf(" "); - printf(" %3d,", aKeywordTable[i].iNext); - j++; - if( j>12 ){ - printf("\n"); - j = 0; - } - } - printf("%s };\n", j==0 ? "" : "\n"); - - printf(" static const unsigned char aLen[%d] = {\n", nKeyword); - for(i=j=0; i<nKeyword; i++){ - if( j==0 ) printf(" "); - printf(" %3d,", aKeywordTable[i].len+aKeywordTable[i].prefix); - j++; - if( j>12 ){ - printf("\n"); - j = 0; - } - } - printf("%s };\n", j==0 ? "" : "\n"); - - printf(" static const unsigned short int aOffset[%d] = {\n", nKeyword); - for(i=j=0; i<nKeyword; i++){ - if( j==0 ) printf(" "); - printf(" %3d,", aKeywordTable[i].offset); - j++; - if( j>12 ){ - printf("\n"); - j = 0; - } - } - printf("%s };\n", j==0 ? "" : "\n"); - - printf(" static const unsigned char aCode[%d] = {\n", nKeyword); - for(i=j=0; i<nKeyword; i++){ - char *zToken = aKeywordTable[i].zTokenType; - if( j==0 ) printf(" "); - printf("%s,%*s", zToken, (int)(14-strlen(zToken)), ""); - j++; - if( j>=5 ){ - printf("\n"); - j = 0; - } - } - printf("%s };\n", j==0 ? "" : "\n"); - - printf(" int h, i;\n"); - printf(" if( n<2 ) return TK_ID;\n"); - printf(" h = ((charMap(z[0])*4) ^\n" - " (charMap(z[n-1])*3) ^\n" - " n) %% %d;\n", bestSize); - printf(" for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){\n"); - printf(" if( aLen[i]==n &&" - " sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){\n"); - for(i=0; i<nKeyword; i++){ - printf(" testcase( i==%d ); /* %s */\n", - i, aKeywordTable[i].zOrigName); - } - printf(" return aCode[i];\n"); - printf(" }\n"); - printf(" }\n"); - printf(" return TK_ID;\n"); - printf("}\n"); - printf("int sqlite3KeywordCode(const unsigned char *z, int n){\n"); - printf(" return keywordCode((char*)z, n);\n"); - printf("}\n"); - printf("#define SQLITE_N_KEYWORD %d\n", nKeyword); - - return 0; -} diff --git a/lib/libsqlite3/tool/mkopts.tcl b/lib/libsqlite3/tool/mkopts.tcl deleted file mode 100644 index e3ddcb9eeb3..00000000000 --- a/lib/libsqlite3/tool/mkopts.tcl +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/tclsh -# -# This script is used to generate the array of strings and the enum -# that appear at the beginning of the C code implementation of a -# a TCL command and that define the available subcommands for that -# TCL command. - -set prefix {} -while {![eof stdin]} { - set line [gets stdin] - if {$line==""} continue - regsub -all "\[ \t\n,\]+" [string trim $line] { } line - foreach token [split $line { }] { - if {![regexp {(([a-zA-Z]+)_)?([_a-zA-Z]+)} $token all px p2 name]} continue - lappend namelist [string tolower $name] - if {$px!=""} {set prefix $p2} - } -} - -puts " static const char *${prefix}_strs\[\] = \173" -set col 0 -proc put_item x { - global col - if {$col==0} {puts -nonewline " "} - if {$col<2} { - puts -nonewline [format " %-21s" $x] - incr col - } else { - puts $x - set col 0 - } -} -proc finalize {} { - global col - if {$col>0} {puts {}} - set col 0 -} - -foreach name [lsort $namelist] { - put_item \"$name\", -} -put_item 0 -finalize -puts " \175;" -puts " enum ${prefix}_enum \173" -foreach name [lsort $namelist] { - regsub -all {@} $name {} name - put_item ${prefix}_[string toupper $name], -} -finalize -puts " \175;" diff --git a/lib/libsqlite3/tool/mkpragmatab.tcl b/lib/libsqlite3/tool/mkpragmatab.tcl deleted file mode 100644 index bbdf9da754a..00000000000 --- a/lib/libsqlite3/tool/mkpragmatab.tcl +++ /dev/null @@ -1,471 +0,0 @@ -#!/usr/bin/tclsh -# -# Run this script to generate the pragma name lookup table C code. -# -# To add new pragmas, first add the name and other relevant attributes -# of the pragma to the "pragma_def" object below. Then run this script -# to generate the ../src/pragma.h header file that contains macros and -# the lookup table needed for pragma name lookup in the pragma.c module. -# Then add the extra "case PragTyp_XXXXX:" and subsequent code for the -# new pragma in ../src/pragma.c. -# - -set pragma_def { - NAME: full_column_names - TYPE: FLAG - ARG: SQLITE_FullColNames - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: short_column_names - TYPE: FLAG - ARG: SQLITE_ShortColNames - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: count_changes - TYPE: FLAG - ARG: SQLITE_CountRows - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: empty_result_callbacks - TYPE: FLAG - ARG: SQLITE_NullCallback - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: legacy_file_format - TYPE: FLAG - ARG: SQLITE_LegacyFileFmt - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: fullfsync - TYPE: FLAG - ARG: SQLITE_FullFSync - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: checkpoint_fullfsync - TYPE: FLAG - ARG: SQLITE_CkptFullFSync - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: cache_spill - TYPE: FLAG - ARG: SQLITE_CacheSpill - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: reverse_unordered_selects - TYPE: FLAG - ARG: SQLITE_ReverseOrder - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: query_only - TYPE: FLAG - ARG: SQLITE_QueryOnly - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: automatic_index - TYPE: FLAG - ARG: SQLITE_AutoIndex - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - IF: !defined(SQLITE_OMIT_AUTOMATIC_INDEX) - - NAME: sql_trace - TYPE: FLAG - ARG: SQLITE_SqlTrace - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - IF: defined(SQLITE_DEBUG) - - NAME: vdbe_listing - TYPE: FLAG - ARG: SQLITE_VdbeListing - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - IF: defined(SQLITE_DEBUG) - - NAME: vdbe_trace - TYPE: FLAG - ARG: SQLITE_VdbeTrace - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - IF: defined(SQLITE_DEBUG) - - NAME: vdbe_addoptrace - TYPE: FLAG - ARG: SQLITE_VdbeAddopTrace - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - IF: defined(SQLITE_DEBUG) - - NAME: vdbe_debug - TYPE: FLAG - ARG: SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - IF: defined(SQLITE_DEBUG) - - NAME: vdbe_eqp - TYPE: FLAG - ARG: SQLITE_VdbeEQP - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - IF: defined(SQLITE_DEBUG) - - NAME: ignore_check_constraints - TYPE: FLAG - ARG: SQLITE_IgnoreChecks - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - IF: !defined(SQLITE_OMIT_CHECK) - - NAME: writable_schema - TYPE: FLAG - ARG: SQLITE_WriteSchema|SQLITE_RecoveryMode - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: read_uncommitted - TYPE: FLAG - ARG: SQLITE_ReadUncommitted - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: recursive_triggers - TYPE: FLAG - ARG: SQLITE_RecTriggers - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - - NAME: foreign_keys - TYPE: FLAG - ARG: SQLITE_ForeignKeys - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - - NAME: defer_foreign_keys - TYPE: FLAG - ARG: SQLITE_DeferFKs - IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) - IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - - NAME: cell_size_check - TYPE: FLAG - ARG: SQLITE_CellSizeCk - - NAME: default_cache_size - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) - - NAME: page_size - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: secure_delete - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: page_count - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: max_page_count - TYPE: PAGE_COUNT - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: locking_mode - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: journal_mode - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: journal_size_limit - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: cache_size - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: mmap_size - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: auto_vacuum - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_AUTOVACUUM) - - NAME: incremental_vacuum - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_AUTOVACUUM) - - NAME: temp_store - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: temp_store_directory - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: data_store_directory - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN - - NAME: lock_proxy_file - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE - - NAME: synchronous - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) - - NAME: table_info - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - - NAME: stats - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - - NAME: index_info - TYPE: INDEX_INFO - ARG: 0 - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - - NAME: index_xinfo - TYPE: INDEX_INFO - ARG: 1 - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - - NAME: index_list - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - - NAME: database_list - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - - NAME: collation_list - IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - - NAME: foreign_key_list - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_FOREIGN_KEY) - - NAME: foreign_key_check - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - - NAME: parser_trace - IF: defined(SQLITE_DEBUG) - - NAME: case_sensitive_like - - NAME: integrity_check - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK) - - NAME: quick_check - TYPE: INTEGRITY_CHECK - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK) - - NAME: encoding - IF: !defined(SQLITE_OMIT_UTF16) - - NAME: schema_version - TYPE: HEADER_VALUE - ARG: BTREE_SCHEMA_VERSION - IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - - NAME: user_version - TYPE: HEADER_VALUE - ARG: BTREE_USER_VERSION - IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - - NAME: data_version - TYPE: HEADER_VALUE - ARG: BTREE_DATA_VERSION - FLAG: ReadOnly - IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - - NAME: freelist_count - TYPE: HEADER_VALUE - ARG: BTREE_FREE_PAGE_COUNT - FLAG: ReadOnly - IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - - NAME: application_id - TYPE: HEADER_VALUE - ARG: BTREE_APPLICATION_ID - IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - - NAME: compile_options - IF: !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) - - NAME: wal_checkpoint - FLAG: NeedSchema - IF: !defined(SQLITE_OMIT_WAL) - - NAME: wal_autocheckpoint - IF: !defined(SQLITE_OMIT_WAL) - - NAME: shrink_memory - - NAME: busy_timeout - - NAME: lock_status - IF: defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - - NAME: key - IF: defined(SQLITE_HAS_CODEC) - - NAME: rekey - IF: defined(SQLITE_HAS_CODEC) - - NAME: hexkey - IF: defined(SQLITE_HAS_CODEC) - - NAME: hexrekey - TYPE: HEXKEY - IF: defined(SQLITE_HAS_CODEC) - - NAME: activate_extensions - IF: defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) - - NAME: soft_heap_limit - - NAME: threads -} - -# Open the output file -# -set destfile "[file dir [file dir [file normal $argv0]]]/src/pragma.h" -puts "Overwriting $destfile with new pragma table..." -set fd [open $destfile wb] -puts $fd {/* DO NOT EDIT! -** This file is automatically generated by the script at -** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit -** that script and rerun it. -*/} - -# Parse the PRAGMA table above. -# -set name {} -set type {} -set if {} -set flags {} -set arg 0 -proc record_one {} { - global name type if arg allbyname typebyif flags - if {$name==""} return - set allbyname($name) [list $type $arg $if $flags] - set name {} - set type {} - set if {} - set flags {} - set arg 0 -} -foreach line [split $pragma_def \n] { - set line [string trim $line] - if {$line==""} continue - foreach {id val} [split $line :] break - set val [string trim $val] - if {$id=="NAME"} { - record_one - set name $val - set type [string toupper $val] - } elseif {$id=="TYPE"} { - set type $val - } elseif {$id=="ARG"} { - set arg $val - } elseif {$id=="IF"} { - lappend if $val - } elseif {$id=="FLAG"} { - foreach term [split $val] { - lappend flags $term - set allflags($term) 1 - } - } else { - error "bad pragma_def line: $line" - } -} -record_one -set allnames [lsort [array names allbyname]] - -# Generate #defines for all pragma type names. Group the pragmas that are -# omit in default builds (defined(SQLITE_DEBUG) and defined(SQLITE_HAS_CODEC)) -# at the end. -# -set pnum 0 -foreach name $allnames { - set type [lindex $allbyname($name) 0] - if {[info exists seentype($type)]} continue - set if [lindex $allbyname($name) 2] - if {[regexp SQLITE_DEBUG $if] || [regexp SQLITE_HAS_CODEC $if]} continue - set seentype($type) 1 - puts $fd [format {#define %-35s %4d} PragTyp_$type $pnum] - incr pnum -} -foreach name $allnames { - set type [lindex $allbyname($name) 0] - if {[info exists seentype($type)]} continue - set if [lindex $allbyname($name) 2] - if {[regexp SQLITE_DEBUG $if]} continue - set seentype($type) 1 - puts $fd [format {#define %-35s %4d} PragTyp_$type $pnum] - incr pnum -} -foreach name $allnames { - set type [lindex $allbyname($name) 0] - if {[info exists seentype($type)]} continue - set seentype($type) 1 - puts $fd [format {#define %-35s %4d} PragTyp_$type $pnum] - incr pnum -} - -# Generate #defines for flags -# -set fv 1 -foreach f [lsort [array names allflags]] { - puts $fd [format {#define PragFlag_%-20s 0x%02x} $f $fv] - set fv [expr {$fv*2}] -} - -# Generate the lookup table -# -puts $fd "static const struct sPragmaNames \173" -puts $fd " const char *const zName; /* Name of pragma */" -puts $fd " u8 ePragTyp; /* PragTyp_XXX value */" -puts $fd " u8 mPragFlag; /* Zero or more PragFlag_XXX values */" -puts $fd " u32 iArg; /* Extra argument */" -puts $fd "\175 aPragmaNames\[\] = \173" - -set current_if {} -set spacer [format { %26s } {}] -foreach name $allnames { - foreach {type arg if flag} $allbyname($name) break - if {$if!=$current_if} { - if {$current_if!=""} { - foreach this_if $current_if { - puts $fd "#endif" - } - } - set current_if $if - if {$current_if!=""} { - foreach this_if $current_if { - puts $fd "#if $this_if" - } - } - } - set typex [format PragTyp_%-23s $type,] - if {$flag==""} { - set flagx "0" - } else { - set flagx PragFlag_[join $flag {|PragFlag_}] - } - puts $fd " \173 /* zName: */ \"$name\"," - puts $fd " /* ePragTyp: */ PragTyp_$type," - puts $fd " /* ePragFlag: */ $flagx," - puts $fd " /* iArg: */ $arg \175," -} -if {$current_if!=""} { - foreach this_if $current_if { - puts $fd "#endif" - } -} -puts $fd "\175;" - -# count the number of pragmas, for information purposes -# -set allcnt 0 -set dfltcnt 0 -foreach name $allnames { - incr allcnt - set if [lindex $allbyname($name) 2] - if {[regexp {^defined} $if] || [regexp {[^!]defined} $if]} continue - incr dfltcnt -} -puts $fd "/* Number of pragmas: $dfltcnt on by default, $allcnt total. */" diff --git a/lib/libsqlite3/tool/mkspeedsql.tcl b/lib/libsqlite3/tool/mkspeedsql.tcl deleted file mode 100644 index 65f8d3f0574..00000000000 --- a/lib/libsqlite3/tool/mkspeedsql.tcl +++ /dev/null @@ -1,237 +0,0 @@ -# 2008 October 9 -# -# The author disclaims copyright to this source code. In place of -# a legal notice, here is a blessing: -# -# May you do good and not evil. -# May you find forgiveness for yourself and forgive others. -# May you share freely, never taking more than you give. -# -#************************************************************************* -# This file generates SQL text used for performance testing. -# -# $Id: mkspeedsql.tcl,v 1.1.1.1 2012/04/14 13:13:17 espie Exp $ -# - -# Set a uniform random seed -expr srand(0) - -# The number_name procedure below converts its argment (an integer) -# into a string which is the English-language name for that number. -# -# Example: -# -# puts [number_name 123] -> "one hundred twenty three" -# -set ones {zero one two three four five six seven eight nine - ten eleven twelve thirteen fourteen fifteen sixteen seventeen - eighteen nineteen} -set tens {{} ten twenty thirty forty fifty sixty seventy eighty ninety} -proc number_name {n} { - if {$n>=1000} { - set txt "[number_name [expr {$n/1000}]] thousand" - set n [expr {$n%1000}] - } else { - set txt {} - } - if {$n>=100} { - append txt " [lindex $::ones [expr {$n/100}]] hundred" - set n [expr {$n%100}] - } - if {$n>=20} { - append txt " [lindex $::tens [expr {$n/10}]]" - set n [expr {$n%10}] - } - if {$n>0} { - append txt " [lindex $::ones $n]" - } - set txt [string trim $txt] - if {$txt==""} {set txt zero} - return $txt -} - -# Create a database schema. -# -puts { - PRAGMA page_size=1024; - PRAGMA cache_size=8192; - PRAGMA locking_mode=EXCLUSIVE; - CREATE TABLE t1(a INTEGER, b INTEGER, c TEXT); - CREATE TABLE t2(a INTEGER, b INTEGER, c TEXT); - CREATE INDEX i2a ON t2(a); - CREATE INDEX i2b ON t2(b); - SELECT name FROM sqlite_master ORDER BY 1; -} - - -# 50000 INSERTs on an unindexed table -# -set t1c_list {} -puts {BEGIN;} -for {set i 1} {$i<=50000} {incr i} { - set r [expr {int(rand()*500000)}] - set x [number_name $r] - lappend t1c_list $x - puts "INSERT INTO t1 VALUES($i,$r,'$x');" -} -puts {COMMIT;} - -# 50000 INSERTs on an indexed table -# -puts {BEGIN;} -for {set i 1} {$i<=50000} {incr i} { - set r [expr {int(rand()*500000)}] - puts "INSERT INTO t2 VALUES($i,$r,'[number_name $r]');" -} -puts {COMMIT;} - - -# 50 SELECTs on an integer comparison. There is no index so -# a full table scan is required. -# -for {set i 0} {$i<50} {incr i} { - set lwr [expr {$i*100}] - set upr [expr {($i+10)*100}] - puts "SELECT count(*), avg(b) FROM t1 WHERE b>=$lwr AND b<$upr;" -} - -# 50 SELECTs on an LIKE comparison. There is no index so a full -# table scan is required. -# -for {set i 0} {$i<50} {incr i} { - puts "SELECT count(*), avg(b) FROM t1 WHERE c LIKE '%[number_name $i]%';" -} - -# Create indices -# -puts {BEGIN;} -puts { - CREATE INDEX i1a ON t1(a); - CREATE INDEX i1b ON t1(b); - CREATE INDEX i1c ON t1(c); -} -puts {COMMIT;} - -# 5000 SELECTs on an integer comparison where the integer is -# indexed. -# -set sql {} -for {set i 0} {$i<5000} {incr i} { - set lwr [expr {$i*100}] - set upr [expr {($i+10)*100}] - puts "SELECT count(*), avg(b) FROM t1 WHERE b>=$lwr AND b<$upr;" -} - -# 100000 random SELECTs against rowid. -# -for {set i 1} {$i<=100000} {incr i} { - set id [expr {int(rand()*50000)+1}] - puts "SELECT c FROM t1 WHERE rowid=$id;" -} - -# 100000 random SELECTs against a unique indexed column. -# -for {set i 1} {$i<=100000} {incr i} { - set id [expr {int(rand()*50000)+1}] - puts "SELECT c FROM t1 WHERE a=$id;" -} - -# 50000 random SELECTs against an indexed column text column -# -set nt1c [llength $t1c_list] -for {set i 0} {$i<50000} {incr i} { - set r [expr {int(rand()*$nt1c)}] - set c [lindex $t1c_list $i] - puts "SELECT c FROM t1 WHERE c='$c';" -} - - -# Vacuum -puts {VACUUM;} - -# 5000 updates of ranges where the field being compared is indexed. -# -puts {BEGIN;} -for {set i 0} {$i<5000} {incr i} { - set lwr [expr {$i*2}] - set upr [expr {($i+1)*2}] - puts "UPDATE t1 SET b=b*2 WHERE a>=$lwr AND a<$upr;" -} -puts {COMMIT;} - -# 50000 single-row updates. An index is used to find the row quickly. -# -puts {BEGIN;} -for {set i 0} {$i<50000} {incr i} { - set r [expr {int(rand()*500000)}] - puts "UPDATE t1 SET b=$r WHERE a=$i;" -} -puts {COMMIT;} - -# 1 big text update that touches every row in the table. -# -puts { - UPDATE t1 SET c=a; -} - -# Many individual text updates. Each row in the table is -# touched through an index. -# -puts {BEGIN;} -for {set i 1} {$i<=50000} {incr i} { - set r [expr {int(rand()*500000)}] - puts "UPDATE t1 SET c='[number_name $r]' WHERE a=$i;" -} -puts {COMMIT;} - -# Delete all content in a table. -# -puts {DELETE FROM t1;} - -# Copy one table into another -# -puts {INSERT INTO t1 SELECT * FROM t2;} - -# Delete all content in a table, one row at a time. -# -puts {DELETE FROM t1 WHERE 1;} - -# Refill the table yet again -# -puts {INSERT INTO t1 SELECT * FROM t2;} - -# Drop the table and recreate it without its indices. -# -puts {BEGIN;} -puts { - DROP TABLE t1; - CREATE TABLE t1(a INTEGER, b INTEGER, c TEXT); -} -puts {COMMIT;} - -# Refill the table yet again. This copy should be faster because -# there are no indices to deal with. -# -puts {INSERT INTO t1 SELECT * FROM t2;} - -# Select 20000 rows from the table at random. -# -puts { - SELECT rowid FROM t1 ORDER BY random() LIMIT 20000; -} - -# Delete 20000 random rows from the table. -# -puts { - DELETE FROM t1 WHERE rowid IN - (SELECT rowid FROM t1 ORDER BY random() LIMIT 20000); -} -puts {SELECT count(*) FROM t1;} - -# Delete 20000 more rows at random from the table. -# -puts { - DELETE FROM t1 WHERE rowid IN - (SELECT rowid FROM t1 ORDER BY random() LIMIT 20000); -} -puts {SELECT count(*) FROM t1;} diff --git a/lib/libsqlite3/tool/mksqlite3c-noext.tcl b/lib/libsqlite3/tool/mksqlite3c-noext.tcl deleted file mode 100644 index 601b8cce8c3..00000000000 --- a/lib/libsqlite3/tool/mksqlite3c-noext.tcl +++ /dev/null @@ -1,355 +0,0 @@ -#!/usr/bin/tclsh -# -# To build a single huge source file holding all of SQLite (or at -# least the core components - the test harness, shell, and TCL -# interface are omitted.) first do -# -# make target_source -# -# The make target above moves all of the source code files into -# a subdirectory named "tsrc". (This script expects to find the files -# there and will not work if they are not found.) There are a few -# generated C code files that are also added to the tsrc directory. -# For example, the "parse.c" and "parse.h" files to implement the -# the parser are derived from "parse.y" using lemon. And the -# "keywordhash.h" files is generated by a program named "mkkeywordhash". -# -# After the "tsrc" directory has been created and populated, run -# this script: -# -# tclsh mksqlite3c-noext.tcl -# -# The amalgamated SQLite code will be written into sqlite3.c -# - -# Begin by reading the "sqlite3.h" header file. Extract the version number -# from in this file. The version number is needed to generate the header -# comment of the amalgamation. -# -if {[lsearch $argv --nostatic]>=0} { - set addstatic 0 -} else { - set addstatic 1 -} -if {[lsearch $argv --linemacros]>=0} { - set linemacros 1 -} else { - set linemacros 0 -} -set in [open tsrc/sqlite3.h] -set cnt 0 -set VERSION ????? -while {![eof $in]} { - set line [gets $in] - if {$line=="" && [eof $in]} break - incr cnt - regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION -} -close $in - -# Open the output file and write a header comment at the beginning -# of the file. -# -set out [open sqlite3.c w] -# Force the output to use unix line endings, even on Windows. -fconfigure $out -translation lf -set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1] -puts $out [subst \ -{/****************************************************************************** -** This file is an amalgamation of many separate C source files from SQLite -** version $VERSION. 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 -** the "sqlite3.h" header file at hand, you will find a copy embedded within -** the text of this file. Search for "Begin file sqlite3.h" to find the start -** of the embedded sqlite3.h header file.) Additional code files may be needed -** if you want a wrapper to interface SQLite with your choice of programming -** language. The code for the "sqlite3" command-line shell is also in a -** separate file. This file contains only code for the core SQLite library. -*/ -#define SQLITE_CORE 1 -#define SQLITE_AMALGAMATION 1}] -if {$addstatic} { - puts $out \ -{#ifndef SQLITE_PRIVATE -# define SQLITE_PRIVATE static -#endif} -} - -# These are the header files used by SQLite. The first time any of these -# files are seen in a #include statement in the C code, include the complete -# text of the file in-line. The file only needs to be included once. -# -foreach hdr { - btree.h - btreeInt.h - hash.h - hwtime.h - keywordhash.h - msvc.h - mutex.h - opcodes.h - os_common.h - os_setup.h - os_win.h - os.h - pager.h - parse.h - pcache.h - pragma.h - sqlite3ext.h - sqlite3.h - sqliteicu.h - sqliteInt.h - sqliteLimit.h - vdbe.h - vdbeInt.h - vxworks.h - wal.h - whereInt.h -} { - set available_hdr($hdr) 1 -} -set available_hdr(sqliteInt.h) 0 - -# These headers should be copied into the amalgamation without modifying any -# of their function declarations or definitions. -set varonly_hdr(sqlite3.h) 1 - -# These are the functions that accept a variable number of arguments. They -# always need to use the "cdecl" calling convention even when another calling -# convention (e.g. "stcall") is being used for the rest of the library. -set cdecllist { - sqlite3_config - sqlite3_db_config - sqlite3_log - sqlite3_mprintf - sqlite3_snprintf - sqlite3_test_control - sqlite3_vtab_config -} - -# 78 stars used for comment formatting. -set s78 \ -{*****************************************************************************} - -# Insert a comment into the code -# -proc section_comment {text} { - global out s78 - set n [string length $text] - set nstar [expr {60 - $n}] - set stars [string range $s78 0 $nstar] - puts $out "/************** $text $stars/" -} - -# Read the source file named $filename and write it into the -# sqlite3.c output file. If any #include statements are seen, -# process them appropriately. -# -proc copy_file {filename} { - global seen_hdr available_hdr varonly_hdr cdecllist out addstatic linemacros - set ln 0 - set tail [file tail $filename] - section_comment "Begin file $tail" - if {$linemacros} {puts $out "#line 1 \"$filename\""} - set in [open $filename r] - set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)} - set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)} - if {[file extension $filename]==".h"} { - set declpattern " *$declpattern" - } - set declpattern ^$declpattern\$ - while {![eof $in]} { - set line [gets $in] - incr ln - if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} { - if {[info exists available_hdr($hdr)]} { - if {$available_hdr($hdr)} { - if {$hdr!="os_common.h" && $hdr!="hwtime.h"} { - set available_hdr($hdr) 0 - } - section_comment "Include $hdr in the middle of $tail" - copy_file tsrc/$hdr - section_comment "Continuing where we left off in $tail" - if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""} - } else { - # Comment out the entire line, replacing any nested comment - # begin/end markers with the harmless substring "**". - puts $out "/* [string map [list /* ** */ **] $line] */" - } - } elseif {![info exists seen_hdr($hdr)]} { - if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} { - set seen_hdr($hdr) 1 - } - puts $out $line - } elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} { - # This include file must be kept because there was a "keep" - # directive inside of a line comment. - puts $out $line - } else { - # Comment out the entire line, replacing any nested comment - # begin/end markers with the harmless substring "**". - puts $out "/* [string map [list /* ** */ **] $line] */" - } - } elseif {[regexp {^#ifdef __cplusplus} $line]} { - puts $out "#if 0" - } elseif {!$linemacros && [regexp {^#line} $line]} { - # Skip #line directives. - } elseif {$addstatic && ![regexp {^(static|typedef)} $line]} { - # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before - # functions if this header file does not need it. - if {![info exists varonly_hdr($tail)] - && [regexp $declpattern $line all rettype funcname rest]} { - regsub {^SQLITE_API } $line {} line - # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions. - # so that linkage can be modified at compile-time. - if {[regexp {^sqlite3_} $funcname]} { - set line SQLITE_API - append line " " [string trim $rettype] - if {[string index $rettype end] ne "*"} { - append line " " - } - if {[lsearch -exact $cdecllist $funcname] >= 0} { - append line SQLITE_CDECL - } else { - append line SQLITE_STDCALL - } - append line " " $funcname $rest - puts $out $line - } else { - puts $out "SQLITE_PRIVATE $line" - } - } elseif {[regexp $varpattern $line all varname]} { - # Add the SQLITE_PRIVATE before variable declarations or - # definitions for internal use - regsub {^SQLITE_API } $line {} line - if {![regexp {^sqlite3_} $varname]} { - regsub {^extern } $line {} line - puts $out "SQLITE_PRIVATE $line" - } else { - if {[regexp {const char sqlite3_version\[\];} $line]} { - set line {const char sqlite3_version[] = SQLITE_VERSION;} - } - regsub {^SQLITE_EXTERN } $line {} line - puts $out "SQLITE_API $line" - } - } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} { - regsub {^SQLITE_API } $line {} line - regsub {^SQLITE_EXTERN } $line {} line - puts $out $line - } elseif {[regexp {^void \(\*sqlite3Os} $line]} { - regsub {^SQLITE_API } $line {} line - puts $out "SQLITE_PRIVATE $line" - } else { - puts $out $line - } - } else { - puts $out $line - } - } - close $in - section_comment "End of $tail" -} - - -# Process the source files. Process files containing commonly -# used subroutines first in order to help the compiler find -# inlining opportunities. -# -foreach file { - sqliteInt.h - - global.c - ctime.c - status.c - date.c - os.c - - fault.c - mem0.c - mem1.c - mem2.c - mem3.c - mem5.c - mutex.c - mutex_noop.c - mutex_unix.c - mutex_w32.c - malloc.c - printf.c - random.c - threads.c - utf.c - util.c - hash.c - opcodes.c - - os_unix.c - os_win.c - - bitvec.c - pcache.c - pcache1.c - rowset.c - pager.c - wal.c - - btmutex.c - btree.c - backup.c - - vdbemem.c - vdbeaux.c - vdbeapi.c - vdbetrace.c - vdbe.c - vdbeblob.c - vdbesort.c - journal.c - memjournal.c - - walker.c - resolve.c - expr.c - alter.c - analyze.c - attach.c - auth.c - build.c - callback.c - delete.c - func.c - fkey.c - insert.c - legacy.c - loadext.c - pragma.c - prepare.c - select.c - table.c - trigger.c - update.c - vacuum.c - vtab.c - where.c - - parse.c - - tokenize.c - complete.c - - main.c - notify.c -} { - copy_file tsrc/$file -} - -close $out diff --git a/lib/libsqlite3/tool/mksqlite3c.tcl b/lib/libsqlite3/tool/mksqlite3c.tcl deleted file mode 100644 index 23241e27a6e..00000000000 --- a/lib/libsqlite3/tool/mksqlite3c.tcl +++ /dev/null @@ -1,388 +0,0 @@ -#!/usr/bin/tclsh -# -# To build a single huge source file holding all of SQLite (or at -# least the core components - the test harness, shell, and TCL -# interface are omitted.) first do -# -# make target_source -# -# The make target above moves all of the source code files into -# a subdirectory named "tsrc". (This script expects to find the files -# there and will not work if they are not found.) There are a few -# generated C code files that are also added to the tsrc directory. -# For example, the "parse.c" and "parse.h" files to implement the -# the parser are derived from "parse.y" using lemon. And the -# "keywordhash.h" files is generated by a program named "mkkeywordhash". -# -# After the "tsrc" directory has been created and populated, run -# this script: -# -# tclsh mksqlite3c.tcl --srcdir $SRC -# -# The amalgamated SQLite code will be written into sqlite3.c -# - -# Begin by reading the "sqlite3.h" header file. Extract the version number -# from in this file. The version number is needed to generate the header -# comment of the amalgamation. -# -set addstatic 1 -set linemacros 0 -for {set i 0} {$i<[llength $argv]} {incr i} { - set x [lindex $argv $i] - if {[regexp {^-+nostatic$} $x]} { - set addstatic 0 - } elseif {[regexp {^-+linemacros} $x]} { - set linemacros 1 - } else { - error "unknown command-line option: $x" - } -} -set in [open tsrc/sqlite3.h] -set cnt 0 -set VERSION ????? -while {![eof $in]} { - set line [gets $in] - if {$line=="" && [eof $in]} break - incr cnt - regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION -} -close $in - -# Open the output file and write a header comment at the beginning -# of the file. -# -set out [open sqlite3.c w] -# Force the output to use unix line endings, even on Windows. -fconfigure $out -translation lf -set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1] -puts $out [subst \ -{/****************************************************************************** -** This file is an amalgamation of many separate C source files from SQLite -** version $VERSION. 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 -** the "sqlite3.h" header file at hand, you will find a copy embedded within -** the text of this file. Search for "Begin file sqlite3.h" to find the start -** of the embedded sqlite3.h header file.) Additional code files may be needed -** if you want a wrapper to interface SQLite with your choice of programming -** language. The code for the "sqlite3" command-line shell is also in a -** separate file. This file contains only code for the core SQLite library. -*/ -#define SQLITE_CORE 1 -#define SQLITE_AMALGAMATION 1}] -if {$addstatic} { - puts $out \ -{#ifndef SQLITE_PRIVATE -# define SQLITE_PRIVATE static -#endif} -} - -# These are the header files used by SQLite. The first time any of these -# files are seen in a #include statement in the C code, include the complete -# text of the file in-line. The file only needs to be included once. -# -foreach hdr { - btree.h - btreeInt.h - fts3.h - fts3Int.h - fts3_hash.h - fts3_tokenizer.h - hash.h - hwtime.h - keywordhash.h - msvc.h - mutex.h - opcodes.h - os_common.h - os_setup.h - os_win.h - os.h - pager.h - parse.h - pcache.h - pragma.h - rtree.h - sqlite3.h - sqlite3ext.h - sqlite3rbu.h - sqliteicu.h - sqliteInt.h - sqliteLimit.h - vdbe.h - vdbeInt.h - vxworks.h - wal.h - whereInt.h -} { - set available_hdr($hdr) 1 -} -set available_hdr(sqliteInt.h) 0 - -# These headers should be copied into the amalgamation without modifying any -# of their function declarations or definitions. -set varonly_hdr(sqlite3.h) 1 - -# These are the functions that accept a variable number of arguments. They -# always need to use the "cdecl" calling convention even when another calling -# convention (e.g. "stcall") is being used for the rest of the library. -set cdecllist { - sqlite3_config - sqlite3_db_config - sqlite3_log - sqlite3_mprintf - sqlite3_snprintf - sqlite3_test_control - sqlite3_vtab_config -} - -# 78 stars used for comment formatting. -set s78 \ -{*****************************************************************************} - -# Insert a comment into the code -# -proc section_comment {text} { - global out s78 - set n [string length $text] - set nstar [expr {60 - $n}] - set stars [string range $s78 0 $nstar] - puts $out "/************** $text $stars/" -} - -# Read the source file named $filename and write it into the -# sqlite3.c output file. If any #include statements are seen, -# process them appropriately. -# -proc copy_file {filename} { - global seen_hdr available_hdr varonly_hdr cdecllist out addstatic linemacros - set ln 0 - set tail [file tail $filename] - section_comment "Begin file $tail" - if {$linemacros} {puts $out "#line 1 \"$filename\""} - set in [open $filename r] - set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)} - set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)} - if {[file extension $filename]==".h"} { - set declpattern " *$declpattern" - } - set declpattern ^$declpattern\$ - while {![eof $in]} { - set line [gets $in] - incr ln - if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} { - if {[info exists available_hdr($hdr)]} { - if {$available_hdr($hdr)} { - if {$hdr!="os_common.h" && $hdr!="hwtime.h"} { - set available_hdr($hdr) 0 - } - section_comment "Include $hdr in the middle of $tail" - copy_file tsrc/$hdr - section_comment "Continuing where we left off in $tail" - if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""} - } else { - # Comment out the entire line, replacing any nested comment - # begin/end markers with the harmless substring "**". - puts $out "/* [string map [list /* ** */ **] $line] */" - } - } elseif {![info exists seen_hdr($hdr)]} { - if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} { - set seen_hdr($hdr) 1 - } - puts $out $line - } elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} { - # This include file must be kept because there was a "keep" - # directive inside of a line comment. - puts $out $line - } else { - # Comment out the entire line, replacing any nested comment - # begin/end markers with the harmless substring "**". - puts $out "/* [string map [list /* ** */ **] $line] */" - } - } elseif {[regexp {^#ifdef __cplusplus} $line]} { - puts $out "#if 0" - } elseif {!$linemacros && [regexp {^#line} $line]} { - # Skip #line directives. - } elseif {$addstatic - && ![regexp {^(static|typedef|SQLITE_PRIVATE)} $line]} { - # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before - # functions if this header file does not need it. - if {![info exists varonly_hdr($tail)] - && [regexp $declpattern $line all rettype funcname rest]} { - regsub {^SQLITE_API } $line {} line - # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions. - # so that linkage can be modified at compile-time. - if {[regexp {^sqlite3(_|rbu_)} $funcname]} { - set line SQLITE_API - append line " " [string trim $rettype] - if {[string index $rettype end] ne "*"} { - append line " " - } - if {[lsearch -exact $cdecllist $funcname] >= 0} { - append line SQLITE_CDECL - } else { - append line SQLITE_STDCALL - } - append line " " $funcname $rest - puts $out $line - } else { - puts $out "SQLITE_PRIVATE $line" - } - } elseif {[regexp $varpattern $line all varname]} { - # Add the SQLITE_PRIVATE before variable declarations or - # definitions for internal use - regsub {^SQLITE_API } $line {} line - if {![regexp {^sqlite3_} $varname]} { - regsub {^extern } $line {} line - puts $out "SQLITE_PRIVATE $line" - } else { - if {[regexp {const char sqlite3_version\[\];} $line]} { - set line {const char sqlite3_version[] = SQLITE_VERSION;} - } - regsub {^SQLITE_EXTERN } $line {} line - puts $out "SQLITE_API $line" - } - } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} { - regsub {^SQLITE_API } $line {} line - regsub {^SQLITE_EXTERN } $line {} line - puts $out $line - } elseif {[regexp {^void \(\*sqlite3Os} $line]} { - regsub {^SQLITE_API } $line {} line - puts $out "SQLITE_PRIVATE $line" - } else { - puts $out $line - } - } else { - puts $out $line - } - } - close $in - section_comment "End of $tail" -} - - -# Process the source files. Process files containing commonly -# used subroutines first in order to help the compiler find -# inlining opportunities. -# -foreach file { - sqliteInt.h - - global.c - ctime.c - status.c - date.c - os.c - - fault.c - mem0.c - mem1.c - mem2.c - mem3.c - mem5.c - mutex.c - mutex_noop.c - mutex_unix.c - mutex_w32.c - malloc.c - printf.c - treeview.c - random.c - threads.c - utf.c - util.c - hash.c - opcodes.c - - os_unix.c - os_win.c - - bitvec.c - pcache.c - pcache1.c - rowset.c - pager.c - wal.c - - btmutex.c - btree.c - backup.c - - vdbemem.c - vdbeaux.c - vdbeapi.c - vdbetrace.c - vdbe.c - vdbeblob.c - vdbesort.c - journal.c - memjournal.c - - walker.c - resolve.c - expr.c - alter.c - analyze.c - attach.c - auth.c - build.c - callback.c - delete.c - func.c - fkey.c - insert.c - legacy.c - loadext.c - pragma.c - prepare.c - select.c - table.c - trigger.c - update.c - vacuum.c - vtab.c - wherecode.c - whereexpr.c - where.c - - parse.c - - tokenize.c - complete.c - - main.c - notify.c - - fts3.c - fts3_aux.c - fts3_expr.c - fts3_hash.c - fts3_porter.c - fts3_tokenizer.c - fts3_tokenizer1.c - fts3_tokenize_vtab.c - fts3_write.c - fts3_snippet.c - fts3_unicode.c - fts3_unicode2.c - - rtree.c - icu.c - fts3_icu.c - sqlite3rbu.c - dbstat.c - json1.c - fts5.c -} { - copy_file tsrc/$file -} - -close $out diff --git a/lib/libsqlite3/tool/mksqlite3h.tcl b/lib/libsqlite3/tool/mksqlite3h.tcl deleted file mode 100644 index 3f59aef4675..00000000000 --- a/lib/libsqlite3/tool/mksqlite3h.tcl +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/tclsh -# -# This script constructs the "sqlite3.h" header file from the following -# sources: -# -# 1) The src/sqlite.h.in source file. This is the template for sqlite3.h. -# 2) The VERSION file containing the current SQLite version number. -# 3) The manifest file from the fossil SCM. This gives use the date. -# 4) The manifest.uuid file from the fossil SCM. This gives the SHA1 hash. -# -# Run this script by specifying the root directory of the source tree -# on the command-line. -# -# This script performs processing on src/sqlite.h.in. It: -# -# 1) Adds SQLITE_EXTERN in front of the declaration of global variables, -# 2) Adds SQLITE_API in front of the declaration of API functions, -# 3) Replaces the string --VERS-- with the current library version, -# formatted as a string (e.g. "3.6.17"), and -# 4) Replaces the string --VERSION-NUMBER-- with current library version, -# formatted as an integer (e.g. "3006017"). -# 5) Replaces the string --SOURCE-ID-- with the date and time and sha1 -# hash of the fossil-scm manifest for the source tree. -# -# This script outputs to stdout. -# -# Example usage: -# -# tclsh mksqlite3h.tcl ../sqlite >sqlite3.h -# - - -# Get the source tree root directory from the command-line -# -set TOP [lindex $argv 0] - -# Get the SQLite version number (ex: 3.6.18) from the $TOP/VERSION file. -# -set in [open $TOP/VERSION] -set zVersion [string trim [read $in]] -close $in -set nVersion [eval format "%d%03d%03d" [split $zVersion .]] - -# Get the fossil-scm version number from $TOP/manifest.uuid. -# -set in [open $TOP/manifest.uuid] -set zUuid [string trim [read $in]] -close $in - -# Get the fossil-scm check-in date from the "D" card of $TOP/manifest. -# -set in [open $TOP/manifest] -set zDate {} -while {![eof $in]} { - set line [gets $in] - if {[regexp {^D (2[-0-9T:]+)} $line all date]} { - set zDate [string map {T { }} $date] - break - } -} -close $in - -# Set up patterns for recognizing API declarations. -# -set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+sqlite3_[_a-zA-Z0-9]+(\[|;| =)} -set declpattern {^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3_[_a-zA-Z0-9]+)(\(.*)$} - -# Force the output to use unix line endings, even on Windows. -fconfigure stdout -translation lf - -set filelist [subst { - $TOP/src/sqlite.h.in - $TOP/ext/rtree/sqlite3rtree.h - $TOP/ext/fts5/fts5.h -}] - -# These are the functions that accept a variable number of arguments. They -# always need to use the "cdecl" calling convention even when another calling -# convention (e.g. "stcall") is being used for the rest of the library. -set cdecllist { - sqlite3_config - sqlite3_db_config - sqlite3_log - sqlite3_mprintf - sqlite3_snprintf - sqlite3_test_control - sqlite3_vtab_config -} - -# Process the source files. -# -foreach file $filelist { - set in [open $file] - while {![eof $in]} { - - set line [gets $in] - - # File sqlite3rtree.h contains a line "#include <sqlite3.h>". Omit this - # line when copying sqlite3rtree.h into sqlite3.h. - # - if {[string match {*#include*[<"]sqlite3.h[>"]*} $line]} continue - - regsub -- --VERS-- $line $zVersion line - regsub -- --VERSION-NUMBER-- $line $nVersion line - regsub -- --SOURCE-ID-- $line "$zDate $zUuid" line - - if {[regexp $varpattern $line] && ![regexp {^ *typedef} $line]} { - set line "SQLITE_API $line" - } else { - if {[regexp $declpattern $line all rettype funcname rest]} { - set line SQLITE_API - append line " " [string trim $rettype] - if {[string index $rettype end] ne "*"} { - append line " " - } - if {[lsearch -exact $cdecllist $funcname] >= 0} { - append line SQLITE_CDECL - } else { - append line SQLITE_STDCALL - } - append line " " $funcname $rest - } - } - puts $line - } - close $in -} diff --git a/lib/libsqlite3/tool/mksqlite3internalh.tcl b/lib/libsqlite3/tool/mksqlite3internalh.tcl deleted file mode 100644 index 8db593fe756..00000000000 --- a/lib/libsqlite3/tool/mksqlite3internalh.tcl +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/tclsh -# -# To build a single huge source file holding all of SQLite (or at -# least the core components - the test harness, shell, and TCL -# interface are omitted.) first do -# -# make target_source -# -# The make target above moves all of the source code files into -# a subdirectory named "tsrc". (This script expects to find the files -# there and will not work if they are not found.) There are a few -# generated C code files that are also added to the tsrc directory. -# For example, the "parse.c" and "parse.h" files to implement the -# the parser are derived from "parse.y" using lemon. And the -# "keywordhash.h" files is generated by a program named "mkkeywordhash". -# -# After the "tsrc" directory has been created and populated, run -# this script: -# -# tclsh mksqlite3c.tcl -# -# The amalgamated SQLite code will be written into sqlite3.c -# - -# Begin by reading the "sqlite3.h" header file. Count the number of lines -# in this file and extract the version number. That information will be -# needed in order to generate the header of the amalgamation. -# -set in [open tsrc/sqlite3.h] -set cnt 0 -set VERSION ????? -while {![eof $in]} { - set line [gets $in] - if {$line=="" && [eof $in]} break - incr cnt - regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION -} -close $in - -# Open the output file and write a header comment at the beginning -# of the file. -# -set out [open sqlite3internal.h w] -set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1] -puts $out [subst \ -{/****************************************************************************** -** This file is an amalgamation of many private header files from SQLite -** version $VERSION. -*/}] - -# These are the header files used by SQLite. The first time any of these -# files are seen in a #include statement in the C code, include the complete -# text of the file in-line. The file only needs to be included once. -# -foreach hdr { - btree.h - btreeInt.h - hash.h - hwtime.h - keywordhash.h - msvc.h - opcodes.h - os_common.h - os_setup.h - os_win.h - os.h - pager.h - parse.h - sqlite3ext.h - sqlite3.h - sqliteInt.h - sqliteLimit.h - vdbe.h - vdbeInt.h -} { - set available_hdr($hdr) 1 -} - -# 78 stars used for comment formatting. -set s78 \ -{*****************************************************************************} - -# Insert a comment into the code -# -proc section_comment {text} { - global out s78 - set n [string length $text] - set nstar [expr {60 - $n}] - set stars [string range $s78 0 $nstar] - puts $out "/************** $text $stars/" -} - -# Read the source file named $filename and write it into the -# sqlite3.c output file. If any #include statements are seen, -# process them approprately. -# -proc copy_file {filename} { - global seen_hdr available_hdr out - set tail [file tail $filename] - section_comment "Begin file $tail" - set in [open $filename r] - while {![eof $in]} { - set line [gets $in] - if {[regexp {^#\s*include\s+["<]([^">]+)[">]} $line all hdr]} { - if {[info exists available_hdr($hdr)]} { - if {$available_hdr($hdr)} { - section_comment "Include $hdr in the middle of $tail" - copy_file tsrc/$hdr - section_comment "Continuing where we left off in $tail" - } - } elseif {![info exists seen_hdr($hdr)]} { - set seen_hdr($hdr) 1 - puts $out $line - } - } elseif {[regexp {^#ifdef __cplusplus} $line]} { - puts $out "#if 0" - } elseif {[regexp {^#line} $line]} { - # Skip #line directives. - } else { - puts $out $line - } - } - close $in - section_comment "End of $tail" -} - - -# Process the source files. Process files containing commonly -# used subroutines first in order to help the compiler find -# inlining opportunities. -# -foreach file { - sqliteInt.h - sqlite3.h - btree.h - hash.h - os.h - pager.h - parse.h - sqlite3ext.h - vdbe.h -} { - if {$available_hdr($file)} { - copy_file tsrc/$file - } -} - -close $out diff --git a/lib/libsqlite3/tool/mkvsix.tcl b/lib/libsqlite3/tool/mkvsix.tcl deleted file mode 100644 index b7c5983dbe2..00000000000 --- a/lib/libsqlite3/tool/mkvsix.tcl +++ /dev/null @@ -1,840 +0,0 @@ -#!/usr/bin/tclsh -# -# This script is used to generate a VSIX (Visual Studio Extension) file for -# SQLite usable by Visual Studio. -# -# PREREQUISITES -# -# 1. Tcl 8.4 and later are supported, earlier versions have not been tested. -# -# 2. The "sqlite3.h" file is assumed to exist in the parent directory of the -# directory containing this script. The [optional] second command line -# argument to this script may be used to specify an alternate location. -# This script also assumes that the "sqlite3.h" file corresponds with the -# version of the binaries to be packaged. This assumption is not verified -# by this script. -# -# 3. The temporary directory specified in the TEMP or TMP environment variables -# must refer to an existing directory writable by the current user. -# -# 4. The "zip" and "unzip" command line tools must be located either in a -# directory contained in the PATH environment variable or specified as the -# exact file names to execute in the "ZipTool" and "UnZipTool" environment -# variables, respectively. -# -# 5. The template VSIX file (which is basically a zip file) must be located in -# a "win" directory inside the directory containing this script. It should -# not contain any executable binaries. It should only contain dynamic -# textual content files to be processed using [subst] and/or static content -# files to be copied verbatim. -# -# 6. The executable and other compiled binary files to be packaged into the -# final VSIX file (e.g. DLLs, LIBs, and PDBs) must be located in a single -# directory tree. The top-level directory of the tree must be specified as -# the first command line argument to this script. The second level -# sub-directory names must match those of the build configuration (e.g. -# "Debug" or "Retail"). The third level sub-directory names must match -# those of the platform (e.g. "x86", "x64", and "ARM"). For example, the -# binary files to be packaged would need to be organized as follows when -# packaging the "Debug" and "Retail" build configurations for the "x86" and -# "x64" platforms (in this example, "C:\temp" is the top-level directory as -# specified in the first command line argument): -# -# C:\Temp\Debug\x86\sqlite3.lib -# C:\Temp\Debug\x86\sqlite3.dll -# C:\Temp\Debug\x86\sqlite3.pdb -# C:\Temp\Debug\x64\sqlite3.lib -# C:\Temp\Debug\x64\sqlite3.dll -# C:\Temp\Debug\x64\sqlite3.pdb -# C:\Temp\Retail\x86\sqlite3.lib -# C:\Temp\Retail\x86\sqlite3.dll -# C:\Temp\Retail\x86\sqlite3.pdb -# C:\Temp\Retail\x64\sqlite3.lib -# C:\Temp\Retail\x64\sqlite3.dll -# C:\Temp\Retail\x64\sqlite3.pdb -# -# The above directory tree organization is performed automatically if the -# "tool\build-all-msvc.bat" batch script is used to build the binary files -# to be packaged. -# -# USAGE -# -# The first argument to this script is required and must be the name of the -# top-level directory containing the directories and files organized into a -# tree as described in item 6 of the PREREQUISITES section, above. The second -# argument is optional and if present must contain the name of the directory -# containing the root of the source tree for SQLite. The third argument is -# optional and if present must contain the flavor the VSIX package to build. -# Currently, the only supported package flavors are "WinRT", "WinRT81", "WP80", -# "WP81", and "Win32". The fourth argument is optional and if present must be -# a string containing a list of platforms to include in the VSIX package. The -# platform list is "platform1,platform2,platform3". The fifth argument is -# optional and if present must contain the version of Visual Studio required by -# the package. Currently, the only supported versions are "2012" and "2013". -# The package flavors "WinRT81" and "WP81" are only supported when the Visual -# Studio version is "2013". Typically, when on Windows, this script is -# executed using commands similar to the following from a normal Windows -# command prompt: -# -# CD /D C:\dev\sqlite\core -# tclsh85 tool\mkvsix.tcl C:\Temp -# -# In the example above, "C:\dev\sqlite\core" represents the root of the source -# tree for SQLite and "C:\Temp" represents the top-level directory containing -# the executable and other compiled binary files, organized into a directory -# tree as described in item 6 of the PREREQUISITES section, above. -# -# This script should work on non-Windows platforms as well, provided that all -# the requirements listed in the PREREQUISITES section are met. -# -# NOTES -# -# The temporary directory is used as a staging area for the final VSIX file. -# The template VSIX file is extracted, its contents processed, and then the -# resulting files are packaged into the final VSIX file. -# -package require Tcl 8.4 - -proc fail { {error ""} {usage false} } { - if {[string length $error] > 0} then { - puts stdout $error - if {!$usage} then {exit 1} - } - - puts stdout "usage:\ -[file tail [info nameofexecutable]]\ -[file tail [info script]] <binaryDirectory> \[sourceDirectory\]\ -\[packageFlavor\] \[platformNames\] \[vsVersion\]" - - exit 1 -} - -proc getEnvironmentVariable { name } { - # - # NOTE: Returns the value of the specified environment variable or an empty - # string for environment variables that do not exist in the current - # process environment. - # - return [expr {[info exists ::env($name)] ? $::env($name) : ""}] -} - -proc getTemporaryPath {} { - # - # NOTE: Returns the normalized path to the first temporary directory found - # in the typical set of environment variables used for that purpose - # or an empty string to signal a failure to locate such a directory. - # - set names [list] - - foreach name [list TEMP TMP] { - lappend names [string toupper $name] [string tolower $name] \ - [string totitle $name] - } - - foreach name $names { - set value [getEnvironmentVariable $name] - - if {[string length $value] > 0} then { - return [file normalize $value] - } - } - - return "" -} - -proc appendArgs { args } { - # - # NOTE: Returns all passed arguments joined together as a single string with - # no intervening spaces between arguments. - # - eval append result $args -} - -proc readFile { fileName } { - # - # NOTE: Reads and returns the entire contents of the specified file, which - # may contain binary data. - # - set file_id [open $fileName RDONLY] - fconfigure $file_id -encoding binary -translation binary - set result [read $file_id] - close $file_id - return $result -} - -proc writeFile { fileName data } { - # - # NOTE: Writes the entire contents of the specified file, which may contain - # binary data. - # - set file_id [open $fileName {WRONLY CREAT TRUNC}] - fconfigure $file_id -encoding binary -translation binary - puts -nonewline $file_id $data - close $file_id - return "" -} - -# -# TODO: Modify this procedure when a new version of Visual Studio is released. -# -proc getMinVsVersionXmlChunk { vsVersion } { - switch -exact $vsVersion { - 2012 { - return [appendArgs \ - "\r\n " {MinVSVersion="11.0"}] - } - 2013 { - return [appendArgs \ - "\r\n " {MinVSVersion="12.0"}] - } - 2015 { - return [appendArgs \ - "\r\n " {MinVSVersion="14.0"}] - } - default { - return "" - } - } -} - -# -# TODO: Modify this procedure when a new version of Visual Studio is released. -# -proc getMaxPlatformVersionXmlChunk { packageFlavor vsVersion } { - # - # NOTE: Only Visual Studio 2013 and later support this attribute within the - # SDK manifest. - # - if {![string equal $vsVersion 2013] && \ - ![string equal $vsVersion 2015]} then { - return "" - } - - switch -exact $packageFlavor { - WinRT { - return [appendArgs \ - "\r\n " {MaxPlatformVersion="8.0"}] - } - WinRT81 { - return [appendArgs \ - "\r\n " {MaxPlatformVersion="8.1"}] - } - WP80 { - return [appendArgs \ - "\r\n " {MaxPlatformVersion="8.0"}] - } - WP81 { - return [appendArgs \ - "\r\n " {MaxPlatformVersion="8.1"}] - } - default { - return "" - } - } -} - -# -# TODO: Modify this procedure when a new version of Visual Studio is released. -# -proc getExtraFileListXmlChunk { packageFlavor vsVersion } { - # - # NOTE: Windows Phone 8.0 does not require any extra attributes in its VSIX - # package SDK manifests; however, it appears that Windows Phone 8.1 - # does. - # - if {[string equal $packageFlavor WP80]} then { - return "" - } - - set appliesTo [expr {[string equal $packageFlavor Win32] ? \ - "VisualC" : "WindowsAppContainer"}] - - switch -exact $vsVersion { - 2012 { - return [appendArgs \ - "\r\n " AppliesTo=\" $appliesTo \" \ - "\r\n " {DependsOn="Microsoft.VCLibs, version=11.0"}] - } - 2013 { - return [appendArgs \ - "\r\n " AppliesTo=\" $appliesTo \" \ - "\r\n " {DependsOn="Microsoft.VCLibs, version=12.0"}] - } - 2015 { - return [appendArgs \ - "\r\n " AppliesTo=\" $appliesTo \" \ - "\r\n " {DependsOn="Microsoft.VCLibs, version=14.0"}] - } - default { - return "" - } - } -} - -proc replaceFileNameTokens { fileName name buildName platformName } { - # - # NOTE: Returns the specified file name containing the platform name instead - # of platform placeholder tokens. - # - return [string map [list <build> $buildName <platform> $platformName \ - <name> $name] $fileName] -} - -proc substFile { fileName } { - # - # NOTE: Performs all Tcl command, variable, and backslash substitutions in - # the specified file and then rewrites the contents of that same file - # with the substituted data. - # - return [writeFile $fileName [uplevel 1 [list subst [readFile $fileName]]]] -} - -# -# NOTE: This is the entry point for this script. -# -set script [file normalize [info script]] - -if {[string length $script] == 0} then { - fail "script file currently being evaluated is unknown" true -} - -set path [file dirname $script] -set rootName [file rootname [file tail $script]] - -############################################################################### - -# -# NOTE: Process and verify all the command line arguments. -# -set argc [llength $argv] -if {$argc < 1 || $argc > 5} then {fail} - -set binaryDirectory [lindex $argv 0] - -if {[string length $binaryDirectory] == 0} then { - fail "invalid binary directory" -} - -if {![file exists $binaryDirectory] || \ - ![file isdirectory $binaryDirectory]} then { - fail "binary directory does not exist" -} - -if {$argc >= 2} then { - set sourceDirectory [lindex $argv 1] -} else { - # - # NOTE: Assume that the source directory is the parent directory of the one - # that contains this script file. - # - set sourceDirectory [file dirname $path] -} - -if {[string length $sourceDirectory] == 0} then { - fail "invalid source directory" -} - -if {![file exists $sourceDirectory] || \ - ![file isdirectory $sourceDirectory]} then { - fail "source directory does not exist" -} - -if {$argc >= 3} then { - set packageFlavor [lindex $argv 2] -} else { - # - # NOTE: Assume the package flavor is WinRT. - # - set packageFlavor WinRT -} - -if {[string length $packageFlavor] == 0} then { - fail "invalid package flavor" -} - -if {$argc >= 4} then { - set platformNames [list] - - foreach platformName [split [lindex $argv 3] ", "] { - set platformName [string trim $platformName] - - if {[string length $platformName] > 0} then { - lappend platformNames $platformName - } - } -} - -if {$argc >= 5} then { - set vsVersion [lindex $argv 4] -} else { - set vsVersion 2012 -} - -if {[string length $vsVersion] == 0} then { - fail "invalid Visual Studio version" -} - -if {![string equal $vsVersion 2012] && ![string equal $vsVersion 2013] && \ - ![string equal $vsVersion 2015]} then { - fail [appendArgs \ - "unsupported Visual Studio version, must be one of: " \ - [list 2012 2013 2015]] -} - -set shortNames(WinRT,2012) SQLite.WinRT -set shortNames(WinRT,2013) SQLite.WinRT.2013 -set shortNames(WinRT81,2013) SQLite.WinRT81 -set shortNames(WP80,2012) SQLite.WP80 -set shortNames(WP80,2013) SQLite.WP80.2013 -set shortNames(WP81,2013) SQLite.WP81 -set shortNames(Win32,2012) SQLite.Win32 -set shortNames(Win32,2013) SQLite.Win32.2013 -set shortNames(UAP,2015) SQLite.UAP.2015 - -set displayNames(WinRT,2012) "SQLite for Windows Runtime" -set displayNames(WinRT,2013) "SQLite for Windows Runtime" -set displayNames(WinRT81,2013) "SQLite for Windows Runtime (Windows 8.1)" -set displayNames(WP80,2012) "SQLite for Windows Phone" -set displayNames(WP80,2013) "SQLite for Windows Phone" -set displayNames(WP81,2013) "SQLite for Windows Phone 8.1" -set displayNames(Win32,2012) "SQLite for Windows" -set displayNames(Win32,2013) "SQLite for Windows" -set displayNames(UAP,2015) "SQLite for Universal App Platform" - -if {[string equal $packageFlavor WinRT]} then { - set shortName $shortNames($packageFlavor,$vsVersion) - set displayName $displayNames($packageFlavor,$vsVersion) - set targetPlatformIdentifier Windows - set targetPlatformVersion v8.0 - set minVsVersion [getMinVsVersionXmlChunk $vsVersion] - set maxPlatformVersion \ - [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] - set extraSdkPath "" - set extraFileListAttributes \ - [getExtraFileListXmlChunk $packageFlavor $vsVersion] -} elseif {[string equal $packageFlavor WinRT81]} then { - if {$vsVersion ne "2013"} then { - fail [appendArgs \ - "unsupported combination, package flavor " $packageFlavor \ - " is only supported with Visual Studio 2013"] - } - set shortName $shortNames($packageFlavor,$vsVersion) - set displayName $displayNames($packageFlavor,$vsVersion) - set targetPlatformIdentifier Windows - set targetPlatformVersion v8.1 - set minVsVersion [getMinVsVersionXmlChunk $vsVersion] - set maxPlatformVersion \ - [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] - set extraSdkPath "" - set extraFileListAttributes \ - [getExtraFileListXmlChunk $packageFlavor $vsVersion] -} elseif {[string equal $packageFlavor WP80]} then { - set shortName $shortNames($packageFlavor,$vsVersion) - set displayName $displayNames($packageFlavor,$vsVersion) - set targetPlatformIdentifier "Windows Phone" - set targetPlatformVersion v8.0 - set minVsVersion [getMinVsVersionXmlChunk $vsVersion] - set maxPlatformVersion \ - [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] - set extraSdkPath "\\..\\$targetPlatformIdentifier" - set extraFileListAttributes \ - [getExtraFileListXmlChunk $packageFlavor $vsVersion] -} elseif {[string equal $packageFlavor WP81]} then { - if {$vsVersion ne "2013"} then { - fail [appendArgs \ - "unsupported combination, package flavor " $packageFlavor \ - " is only supported with Visual Studio 2013"] - } - set shortName $shortNames($packageFlavor,$vsVersion) - set displayName $displayNames($packageFlavor,$vsVersion) - set targetPlatformIdentifier WindowsPhoneApp - set targetPlatformVersion v8.1 - set minVsVersion [getMinVsVersionXmlChunk $vsVersion] - set maxPlatformVersion \ - [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] - set extraSdkPath "\\..\\$targetPlatformIdentifier" - set extraFileListAttributes \ - [getExtraFileListXmlChunk $packageFlavor $vsVersion] -} elseif {[string equal $packageFlavor UAP]} then { - if {$vsVersion ne "2015"} then { - fail [appendArgs \ - "unsupported combination, package flavor " $packageFlavor \ - " is only supported with Visual Studio 2015"] - } - set shortName $shortNames($packageFlavor,$vsVersion) - set displayName $displayNames($packageFlavor,$vsVersion) - set targetPlatformIdentifier UAP - set targetPlatformVersion v0.8.0.0 - set minVsVersion [getMinVsVersionXmlChunk $vsVersion] - set maxPlatformVersion \ - [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] - set extraSdkPath "\\..\\$targetPlatformIdentifier" - set extraFileListAttributes \ - [getExtraFileListXmlChunk $packageFlavor $vsVersion] -} elseif {[string equal $packageFlavor Win32]} then { - set shortName $shortNames($packageFlavor,$vsVersion) - set displayName $displayNames($packageFlavor,$vsVersion) - set targetPlatformIdentifier Windows - set targetPlatformVersion v8.0 - set minVsVersion [getMinVsVersionXmlChunk $vsVersion] - set maxPlatformVersion \ - [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] - set extraSdkPath "" - set extraFileListAttributes \ - [getExtraFileListXmlChunk $packageFlavor $vsVersion] -} else { - fail [appendArgs \ - "unsupported package flavor, must be one of: " \ - [list WinRT WinRT81 WP80 WP81 UAP Win32]] -} - -############################################################################### - -# -# NOTE: Evaluate the user-specific customizations file, if it exists. -# -set userFile [file join $path [appendArgs \ - $rootName . $tcl_platform(user) .tcl]] - -if {[file exists $userFile] && \ - [file isfile $userFile]} then { - source $userFile -} - -############################################################################### - -set templateFile [file join $path win sqlite.vsix] - -if {![file exists $templateFile] || \ - ![file isfile $templateFile]} then { - fail [appendArgs "template file \"" $templateFile "\" does not exist"] -} - -set currentDirectory [pwd] -set outputFile [file join $currentDirectory [appendArgs sqlite- \ - $packageFlavor -output.vsix]] - -if {[file exists $outputFile]} then { - fail [appendArgs "output file \"" $outputFile "\" already exists"] -} - -############################################################################### - -# -# NOTE: Make sure that a valid temporary directory exists. -# -set temporaryDirectory [getTemporaryPath] - -if {[string length $temporaryDirectory] == 0 || \ - ![file exists $temporaryDirectory] || \ - ![file isdirectory $temporaryDirectory]} then { - fail "cannot locate a usable temporary directory" -} - -# -# NOTE: Setup the staging directory to have a unique name inside of the -# configured temporary directory. -# -set stagingDirectory [file normalize [file join $temporaryDirectory \ - [appendArgs $rootName . [pid]]]] - -############################################################################### - -# -# NOTE: Configure the external zipping tool. First, see if it has already -# been pre-configured. If not, try to query it from the environment. -# Finally, fallback on the default of simply "zip", which will then -# be assumed to exist somewhere along the PATH. -# -if {![info exists zip]} then { - if {[info exists env(ZipTool)]} then { - set zip $env(ZipTool) - } - if {![info exists zip] || ![file exists $zip]} then { - set zip zip - } -} - -# -# NOTE: Configure the external unzipping tool. First, see if it has already -# been pre-configured. If not, try to query it from the environment. -# Finally, fallback on the default of simply "unzip", which will then -# be assumed to exist somewhere along the PATH. -# -if {![info exists unzip]} then { - if {[info exists env(UnZipTool)]} then { - set unzip $env(UnZipTool) - } - if {![info exists unzip] || ![file exists $unzip]} then { - set unzip unzip - } -} - -############################################################################### - -# -# NOTE: Attempt to extract the SQLite version from the "sqlite3.h" header file -# in the source directory. This script assumes that the header file has -# already been generated by the build process. -# -set pattern {^#define\s+SQLITE_VERSION\s+"(.*)"$} -set data [readFile [file join $sourceDirectory sqlite3.h]] - -if {![regexp -line -- $pattern $data dummy version]} then { - fail [appendArgs "cannot locate SQLITE_VERSION value in \"" \ - [file join $sourceDirectory sqlite3.h] \"] -} - -############################################################################### - -# -# NOTE: Setup all the master file list data. This includes the source file -# names, the destination file names, and the file processing flags. The -# possible file processing flags are: -# -# "buildNeutral" -- This flag indicates the file location and content do -# not depend on the build configuration. -# -# "platformNeutral" -- This flag indicates the file location and content -# do not depend on the build platform. -# -# "subst" -- This flag indicates that the file contains dynamic textual -# content that needs to be processed using [subst] prior to -# packaging the file into the final VSIX package. The primary -# use of this flag is to insert the name of the VSIX package, -# some package flavor-specific value, or the SQLite version -# into a file. -# -# "noDebug" -- This flag indicates that the file should be skipped when -# processing the debug build. -# -# "noRetail" -- This flag indicates that the file should be skipped when -# processing the retail build. -# -# "move" -- This flag indicates that the file should be moved from the -# source to the destination instead of being copied. -# -# This file metadata may be overridden, either in whole or in part, via -# the user-specific customizations file. -# -if {![info exists fileNames(source)]} then { - set fileNames(source) [list "" "" \ - [file join $stagingDirectory DesignTime <build> <platform> sqlite3.props] \ - [file join $sourceDirectory sqlite3.h] \ - [file join $binaryDirectory <build> <platform> sqlite3.lib] \ - [file join $binaryDirectory <build> <platform> sqlite3.dll]] - - if {![info exists no(symbols)]} then { - lappend fileNames(source) \ - [file join $binaryDirectory <build> <platform> sqlite3.pdb] - } -} - -if {![info exists fileNames(destination)]} then { - set fileNames(destination) [list \ - [file join $stagingDirectory extension.vsixmanifest] \ - [file join $stagingDirectory SDKManifest.xml] \ - [file join $stagingDirectory DesignTime <build> <platform> <name>.props] \ - [file join $stagingDirectory DesignTime <build> <platform> sqlite3.h] \ - [file join $stagingDirectory DesignTime <build> <platform> sqlite3.lib] \ - [file join $stagingDirectory Redist <build> <platform> sqlite3.dll]] - - if {![info exists no(symbols)]} then { - lappend fileNames(destination) \ - [file join $stagingDirectory Redist <build> <platform> sqlite3.pdb] - } -} - -if {![info exists fileNames(flags)]} then { - set fileNames(flags) [list \ - [list buildNeutral platformNeutral subst] \ - [list buildNeutral platformNeutral subst] \ - [list buildNeutral platformNeutral subst move] \ - [list buildNeutral platformNeutral] \ - [list] [list] [list noRetail]] - - if {![info exists no(symbols)]} then { - lappend fileNames(flags) [list noRetail] - } -} - -############################################################################### - -# -# NOTE: Setup the list of builds supported by this script. These may be -# overridden via the user-specific customizations file. -# -if {![info exists buildNames]} then { - set buildNames [list Debug Retail] -} - -############################################################################### - -# -# NOTE: Setup the list of platforms supported by this script. These may be -# overridden via the command line or the user-specific customizations -# file. -# -if {![info exists platformNames] || [llength $platformNames] == 0} then { - set platformNames [list x86 x64 ARM] -} - -############################################################################### - -# -# NOTE: Make sure the staging directory exists, creating it if necessary. -# -file mkdir $stagingDirectory - -# -# NOTE: Build the Tcl command used to extract the template VSIX package to -# the staging directory. -# -set extractCommand [list exec -- $unzip $templateFile -d $stagingDirectory] - -# -# NOTE: Extract the template VSIX package to the staging directory. -# -eval $extractCommand - -############################################################################### - -# -# NOTE: Process each file in the master file list. There are actually three -# parallel lists that contain the source file names, the destination file -# names, and the file processing flags. If the "buildNeutral" flag is -# present, the file location and content do not depend on the build -# configuration and "CommonConfiguration" will be used in place of the -# build configuration name. If the "platformNeutral" flag is present, -# the file location and content do not depend on the build platform and -# "neutral" will be used in place of the build platform name. If the -# "subst" flag is present, the file is assumed to be a text file that may -# contain Tcl variable, command, and backslash replacements, to be -# dynamically replaced during processing using the Tcl [subst] command. -# If the "noDebug" flag is present, the file will be skipped when -# processing for the debug build. If the "noRetail" flag is present, the -# file will be skipped when processing for the retail build. If the -# "move" flag is present, the source file will be deleted after it is -# copied to the destination file. If the source file name is an empty -# string, the destination file name will be assumed to already exist in -# the staging directory and will not be copied; however, Tcl variable, -# command, and backslash replacements may still be performed on the -# destination file prior to the final VSIX package being built if the -# "subst" flag is present. -# -foreach sourceFileName $fileNames(source) \ - destinationFileName $fileNames(destination) \ - fileFlags $fileNames(flags) { - # - # NOTE: Process the file flags into separate boolean variables that may be - # used within the loop. - # - set isBuildNeutral [expr {[lsearch $fileFlags buildNeutral] != -1}] - set isPlatformNeutral [expr {[lsearch $fileFlags platformNeutral] != -1}] - set isMove [expr {[lsearch $fileFlags move] != -1}] - set useSubst [expr {[lsearch $fileFlags subst] != -1}] - - # - # NOTE: If the current file is build-neutral, then only one build will - # be processed for it, namely "CommonConfiguration"; otherwise, each - # supported build will be processed for it individually. - # - foreach buildName \ - [expr {$isBuildNeutral ? [list CommonConfiguration] : $buildNames}] { - # - # NOTE: Should the current file be skipped for this build? - # - if {[lsearch $fileFlags no${buildName}] != -1} then { - continue - } - - # - # NOTE: If the current file is platform-neutral, then only one platform - # will be processed for it, namely "neutral"; otherwise, each - # supported platform will be processed for it individually. - # - foreach platformName \ - [expr {$isPlatformNeutral ? [list neutral] : $platformNames}] { - # - # NOTE: Use the actual platform name in the destination file name. - # - set newDestinationFileName [replaceFileNameTokens $destinationFileName \ - $shortName $buildName $platformName] - - # - # NOTE: Does the source file need to be copied to the destination file? - # - if {[string length $sourceFileName] > 0} then { - # - # NOTE: First, make sure the destination directory exists. - # - file mkdir [file dirname $newDestinationFileName] - - # - # NOTE: Then, copy the source file to the destination file verbatim. - # - set newSourceFileName [replaceFileNameTokens $sourceFileName \ - $shortName $buildName $platformName] - - file copy $newSourceFileName $newDestinationFileName - - # - # NOTE: If this is a move instead of a copy, delete the source file - # now. - # - if {$isMove} then { - file delete $newSourceFileName - } - } - - # - # NOTE: Does the destination file contain dynamic replacements that must - # be processed now? - # - if {$useSubst} then { - # - # NOTE: Perform any dynamic replacements contained in the destination - # file and then re-write it in-place. - # - substFile $newDestinationFileName - } - } - } -} - -############################################################################### - -# -# NOTE: Change the current directory to the staging directory so that the -# external archive building tool can pickup the necessary files using -# relative paths. -# -cd $stagingDirectory - -# -# NOTE: Build the Tcl command used to archive the final VSIX package in the -# output directory. -# -set archiveCommand [list exec -- $zip -r $outputFile *] - -# -# NOTE: Build the final VSIX package archive in the output directory. -# -eval $archiveCommand - -# -# NOTE: Change back to the previously saved current directory. -# -cd $currentDirectory - -# -# NOTE: Cleanup the temporary staging directory. -# -file delete -force $stagingDirectory - -############################################################################### - -# -# NOTE: Success, emit the fully qualified path of the generated VSIX file. -# -puts stdout $outputFile diff --git a/lib/libsqlite3/tool/offsets.c b/lib/libsqlite3/tool/offsets.c deleted file mode 100644 index 8e098e71cb9..00000000000 --- a/lib/libsqlite3/tool/offsets.c +++ /dev/null @@ -1,329 +0,0 @@ -/* -** This program searches an SQLite database file for the lengths and -** offsets for all TEXT or BLOB entries for a particular column of a -** particular table. The rowid, size and offset for the column are -** written to standard output. There are three arguments, which are the -** name of the database file, the table, and the column. -*/ -#include "sqlite3.h" -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> - -typedef unsigned char u8; -typedef struct GState GState; - -#define ArraySize(X) (sizeof(X)/sizeof(X[0])) - -/* -** Global state information for this program. -*/ -struct GState { - char *zErr; /* Error message text */ - FILE *f; /* Open database file */ - int szPg; /* Page size for the database file */ - int iRoot; /* Root page of the table */ - int iCol; /* Column number for the column */ - int pgno; /* Current page number */ - u8 *aPage; /* Current page content */ - u8 *aStack[20]; /* Page stack */ - int aPgno[20]; /* Page number stack */ - int nStack; /* Depth of stack */ - int bTrace; /* True for tracing output */ -}; - -/* -** Write an error. -*/ -static void ofstError(GState *p, const char *zFormat, ...){ - va_list ap; - sqlite3_free(p->zErr); - va_start(ap, zFormat); - p->zErr = sqlite3_vmprintf(zFormat, ap); - va_end(ap); -} - -/* -** Write a trace message -*/ -static void ofstTrace(GState *p, const char *zFormat, ...){ - va_list ap; - if( p->bTrace ){ - va_start(ap, zFormat); - vprintf(zFormat, ap); - va_end(ap); - } -} - -/* -** Find the root page of the table and the column number of the column. -*/ -static void ofstRootAndColumn( - GState *p, /* Global state */ - const char *zFile, /* Name of the database file */ - const char *zTable, /* Name of the table */ - const char *zColumn /* Name of the column */ -){ - sqlite3 *db = 0; - sqlite3_stmt *pStmt = 0; - char *zSql = 0; - int rc; - if( p->zErr ) return; - rc = sqlite3_open(zFile, &db); - if( rc ){ - ofstError(p, "cannot open database file \"%s\"", zFile); - goto rootAndColumn_exit; - } - zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master WHERE name=%Q", - zTable); - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - if( rc ) ofstError(p, "%s: [%s]", sqlite3_errmsg(db), zSql); - sqlite3_free(zSql); - if( p->zErr ) goto rootAndColumn_exit; - if( sqlite3_step(pStmt)!=SQLITE_ROW ){ - ofstError(p, "cannot find table [%s]\n", zTable); - sqlite3_finalize(pStmt); - goto rootAndColumn_exit; - } - p->iRoot = sqlite3_column_int(pStmt , 0); - sqlite3_finalize(pStmt); - - p->iCol = -1; - zSql = sqlite3_mprintf("PRAGMA table_info(%Q)", zTable); - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - if( rc ) ofstError(p, "%s: [%s}", sqlite3_errmsg(db), zSql); - sqlite3_free(zSql); - if( p->zErr ) goto rootAndColumn_exit; - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - const char *zCol = sqlite3_column_text(pStmt, 1); - if( strlen(zCol)==strlen(zColumn) - && sqlite3_strnicmp(zCol, zColumn, strlen(zCol))==0 - ){ - p->iCol = sqlite3_column_int(pStmt, 0); - break; - } - } - sqlite3_finalize(pStmt); - if( p->iCol<0 ){ - ofstError(p, "no such column: %s.%s", zTable, zColumn); - goto rootAndColumn_exit; - } - - zSql = sqlite3_mprintf("PRAGMA page_size"); - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - if( rc ) ofstError(p, "%s: [%s]", sqlite3_errmsg(db), zSql); - sqlite3_free(zSql); - if( p->zErr ) goto rootAndColumn_exit; - if( sqlite3_step(pStmt)!=SQLITE_ROW ){ - ofstError(p, "cannot find page size"); - }else{ - p->szPg = sqlite3_column_int(pStmt, 0); - } - sqlite3_finalize(pStmt); - -rootAndColumn_exit: - sqlite3_close(db); - return; -} - -/* -** Pop a page from the stack -*/ -static void ofstPopPage(GState *p){ - if( p->nStack<=0 ) return; - p->nStack--; - sqlite3_free(p->aStack[p->nStack]); - p->pgno = p->aPgno[p->nStack-1]; - p->aPage = p->aStack[p->nStack-1]; -} - - -/* -** Push a new page onto the stack. -*/ -static void ofstPushPage(GState *p, int pgno){ - u8 *pPage; - size_t got; - if( p->zErr ) return; - if( p->nStack >= ArraySize(p->aStack) ){ - ofstError(p, "page stack overflow"); - return; - } - p->aPgno[p->nStack] = pgno; - p->aStack[p->nStack] = pPage = sqlite3_malloc( p->szPg ); - if( pPage==0 ){ - fprintf(stderr, "out of memory\n"); - exit(1); - } - p->nStack++; - p->aPage = pPage; - p->pgno = pgno; - fseek(p->f, (pgno-1)*p->szPg, SEEK_SET); - got = fread(pPage, 1, p->szPg, p->f); - if( got!=p->szPg ){ - ofstError(p, "unable to read page %d", pgno); - ofstPopPage(p); - } -} - -/* Read a two-byte integer at the given offset into the current page */ -static int ofst2byte(GState *p, int ofst){ - int x = p->aPage[ofst]; - return (x<<8) + p->aPage[ofst+1]; -} - -/* Read a four-byte integer at the given offset into the current page */ -static int ofst4byte(GState *p, int ofst){ - int x = p->aPage[ofst]; - x = (x<<8) + p->aPage[ofst+1]; - x = (x<<8) + p->aPage[ofst+2]; - x = (x<<8) + p->aPage[ofst+3]; - return x; -} - -/* Read a variable-length integer. Update the offset */ -static sqlite3_int64 ofstVarint(GState *p, int *pOfst){ - sqlite3_int64 x = 0; - u8 *a = &p->aPage[*pOfst]; - int n = 0; - while( n<8 && (a[0] & 0x80)!=0 ){ - x = (x<<7) + (a[0] & 0x7f); - n++; - a++; - } - if( n==8 ){ - x = (x<<8) + a[0]; - }else{ - x = (x<<7) + a[0]; - } - *pOfst += (n+1); - return x; -} - -/* Return the absolute offset into a file for the given offset -** into the current page */ -static int ofstInFile(GState *p, int ofst){ - return p->szPg*(p->pgno-1) + ofst; -} - -/* Return the size (in bytes) of the data corresponding to the -** given serial code */ -static int ofstSerialSize(int scode){ - if( scode<5 ) return scode; - if( scode==5 ) return 6; - if( scode<8 ) return 8; - if( scode<12 ) return 0; - return (scode-12)/2; -} - -/* Forward reference */ -static void ofstWalkPage(GState*, int); - -/* Walk an interior btree page */ -static void ofstWalkInteriorPage(GState *p){ - int nCell; - int i; - int ofst; - int iChild; - - nCell = ofst2byte(p, 3); - for(i=0; i<nCell; i++){ - ofst = ofst2byte(p, 12+i*2); - iChild = ofst4byte(p, ofst); - ofstWalkPage(p, iChild); - if( p->zErr ) return; - } - ofstWalkPage(p, ofst4byte(p, 8)); -} - -/* Walk a leaf btree page */ -static void ofstWalkLeafPage(GState *p){ - int nCell; - int i; - int ofst; - int nPayload; - sqlite3_int64 rowid; - int nHdr; - int j; - int scode; - int sz; - int dataOfst; - char zMsg[200]; - - nCell = ofst2byte(p, 3); - for(i=0; i<nCell; i++){ - ofst = ofst2byte(p, 8+i*2); - nPayload = ofstVarint(p, &ofst); - rowid = ofstVarint(p, &ofst); - if( nPayload > p->szPg-35 ){ - sqlite3_snprintf(sizeof(zMsg), zMsg, - "# overflow rowid %lld", rowid); - printf("%s\n", zMsg); - continue; - } - dataOfst = ofst; - nHdr = ofstVarint(p, &ofst); - dataOfst += nHdr; - for(j=0; j<p->iCol; j++){ - scode = ofstVarint(p, &ofst); - dataOfst += ofstSerialSize(scode); - } - scode = ofstVarint(p, &ofst); - sz = ofstSerialSize(scode); - sqlite3_snprintf(sizeof(zMsg), zMsg, - "rowid %12lld size %5d offset %8d", - rowid, sz, ofstInFile(p, dataOfst)); - printf("%s\n", zMsg); - } -} - -/* -** Output results from a single page. -*/ -static void ofstWalkPage(GState *p, int pgno){ - if( p->zErr ) return; - ofstPushPage(p, pgno); - if( p->zErr ) return; - if( p->aPage[0]==5 ){ - ofstWalkInteriorPage(p); - }else if( p->aPage[0]==13 ){ - ofstWalkLeafPage(p); - }else{ - ofstError(p, "page %d has a faulty type byte: %d", pgno, p->aPage[0]); - } - ofstPopPage(p); -} - -int main(int argc, char **argv){ - GState g; - memset(&g, 0, sizeof(g)); - if( argc>2 && strcmp(argv[1],"--trace")==0 ){ - g.bTrace = 1; - argc--; - argv++; - } - if( argc!=4 ){ - fprintf(stderr, "Usage: %s DATABASE TABLE COLUMN\n", *argv); - exit(1); - } - ofstRootAndColumn(&g, argv[1], argv[2], argv[3]); - if( g.zErr ){ - fprintf(stderr, "%s\n", g.zErr); - exit(1); - } - ofstTrace(&g, "# szPg = %d\n", g.szPg); - ofstTrace(&g, "# iRoot = %d\n", g.iRoot); - ofstTrace(&g, "# iCol = %d\n", g.iCol); - g.f = fopen(argv[1], "rb"); - if( g.f==0 ){ - fprintf(stderr, "cannot open \"%s\"\n", argv[1]); - exit(1); - } - ofstWalkPage(&g, g.iRoot); - if( g.zErr ){ - fprintf(stderr, "%s\n", g.zErr); - exit(1); - } - return 0; -} diff --git a/lib/libsqlite3/tool/omittest.tcl b/lib/libsqlite3/tool/omittest.tcl deleted file mode 100644 index d03c5b49e70..00000000000 --- a/lib/libsqlite3/tool/omittest.tcl +++ /dev/null @@ -1,299 +0,0 @@ - -set rcsid {$Id: omittest.tcl,v 1.1.1.3 2014/03/24 01:37:45 jturner Exp $} - -# Documentation for this script. This may be output to stderr -# if the script is invoked incorrectly. -set ::USAGE_MESSAGE { -This Tcl script is used to test the various compile time options -available for omitting code (the SQLITE_OMIT_xxx options). It -should be invoked as follows: - - <script> ?test-symbol? ?-makefile PATH-TO-MAKEFILE? ?-skip_run? - -The default value for ::MAKEFILE is "../Makefile.linux.gcc". - -If -skip_run option is given then only the compile part is attempted. - -This script builds the testfixture program and runs the SQLite test suite -once with each SQLITE_OMIT_ option defined and then once with all options -defined together. Each run is performed in a seperate directory created -as a sub-directory of the current directory by the script. The output -of the build is saved in <sub-directory>/build.log. The output of the -test-suite is saved in <sub-directory>/test.log. - -Almost any SQLite makefile (except those generated by configure - see below) -should work. The following properties are required: - - * The makefile should support the "testfixture" target. - * The makefile should support the "test" target. - * The makefile should support the variable "OPTS" as a way to pass - options from the make command line to lemon and the C compiler. - -More precisely, the following two invocations must be supported: - - $::MAKEBIN -f $::MAKEFILE testfixture OPTS="-DSQLITE_OMIT_ALTERTABLE=1" - $::MAKEBIN -f $::MAKEFILE test - -Makefiles generated by the sqlite configure program cannot be used as -they do not respect the OPTS variable. -} - - -# Build a testfixture executable and run quick.test using it. The first -# parameter is the name of the directory to create and use to run the -# test in. The second parameter is a list of OMIT symbols to define -# when doing so. For example: -# -# run_quick_test /tmp/testdir {SQLITE_OMIT_TRIGGER SQLITE_OMIT_VIEW} -# -# -proc run_quick_test {dir omit_symbol_list} { - # Compile the value of the OPTS Makefile variable. - set opts "" - if {$::tcl_platform(platform)=="windows"} { - append opts "OPTS += -DSQLITE_OS_WIN=1\n" - set target "testfixture.exe" - } else { - append opts "OPTS += -DSQLITE_OS_UNIX=1\n" - } - foreach sym $omit_symbol_list { - append opts "OPTS += -D${sym}=1\n" - } - - # Create the directory and do the build. If an error occurs return - # early without attempting to run the test suite. - file mkdir $dir - puts -nonewline "Building $dir..." - flush stdout - catch { - file copy -force ./config.h $dir - file copy -force ./libtool $dir - } - set fd [open $::MAKEFILE] - set mkfile [read $fd] - close $fd - regsub {\ninclude} $mkfile "\n$opts\ninclude" mkfile - set fd [open $dir/makefile w] - puts $fd $mkfile - close $fd - - set rc [catch { - exec $::MAKEBIN -C $dir -f makefile clean $::TARGET >& $dir/build.log - }] - if {$rc} { - puts "No good. See $dir/build.log." - return - } else { - puts "Ok" - } - - # Create an empty file "$dir/sqlite3". This is to trick the makefile out - # of trying to build the sqlite shell. The sqlite shell won't build - # with some of the OMIT options (i.e OMIT_COMPLETE). - set sqlite3_dummy $dir/sqlite3 - if {$::tcl_platform(platform)=="windows"} { - append sqlite3_dummy ".exe" - } - if {![file exists $sqlite3_dummy]} { - set wr [open $sqlite3_dummy w] - puts $wr "dummy" - close $wr - } - - if {$::SKIP_RUN} { - puts "Skip testing $dir." - } else { - # Run the test suite. - puts -nonewline "Testing $dir..." - flush stdout - set rc [catch { - exec $::MAKEBIN -C $dir -f makefile test >& $dir/test.log - }] - if {$rc} { - puts "No good. See $dir/test.log." - } else { - puts "Ok" - } - } -} - - -# This proc processes the command line options passed to this script. -# Currently the only option supported is "-makefile", default -# "../Makefile.linux-gcc". Set the ::MAKEFILE variable to the value of this -# option. -# -proc process_options {argv} { - set ::MAKEBIN make ;# Default value - if {$::tcl_platform(platform)=="windows"} { - set ::MAKEFILE ./Makefile ;# Default value on Windows - } else { - set ::MAKEFILE ./Makefile.linux-gcc ;# Default value - } - set ::SKIP_RUN 0 ;# Default to attempt test - set ::TARGET testfixture ;# Default thing to build - - for {set i 0} {$i < [llength $argv]} {incr i} { - switch -- [lindex $argv $i] { - -makefile { - incr i - set ::MAKEFILE [lindex $argv $i] - } - - -nmake { - set ::MAKEBIN nmake - set ::MAKEFILE ./Makefile.msc - } - - -target { - incr i - set ::TARGET [lindex $argv $i] - } - - -skip_run { - set ::SKIP_RUN 1 - } - - default { - if {[info exists ::SYMBOL]} { - puts stderr [string trim $::USAGE_MESSAGE] - exit -1 - } - set ::SYMBOL [lindex $argv $i] - } - } - set ::MAKEFILE [file normalize $::MAKEFILE] - } -} - -# Main routine. -# - -proc main {argv} { - # List of SQLITE_OMIT_XXX symbols supported by SQLite. - set ::OMIT_SYMBOLS [list \ - SQLITE_OMIT_ALTERTABLE \ - SQLITE_OMIT_ANALYZE \ - SQLITE_OMIT_ATTACH \ - SQLITE_OMIT_AUTHORIZATION \ - SQLITE_OMIT_AUTOINCREMENT \ - SQLITE_OMIT_AUTOINIT \ - SQLITE_OMIT_AUTOMATIC_INDEX \ - SQLITE_OMIT_AUTORESET \ - SQLITE_OMIT_AUTOVACUUM \ - SQLITE_OMIT_BETWEEN_OPTIMIZATION \ - SQLITE_OMIT_BLOB_LITERAL \ - SQLITE_OMIT_BTREECOUNT \ - SQLITE_OMIT_BUILTIN_TEST \ - SQLITE_OMIT_CAST \ - SQLITE_OMIT_CHECK \ - SQLITE_OMIT_COMPILEOPTION_DIAGS \ - SQLITE_OMIT_COMPLETE \ - SQLITE_OMIT_COMPOUND_SELECT \ - SQLITE_OMIT_CTE \ - SQLITE_OMIT_DATETIME_FUNCS \ - SQLITE_OMIT_DECLTYPE \ - SQLITE_OMIT_DEPRECATED \ - SQLITE_OMIT_EXPLAIN \ - SQLITE_OMIT_FLAG_PRAGMAS \ - SQLITE_OMIT_FLOATING_POINT \ - SQLITE_OMIT_FOREIGN_KEY \ - SQLITE_OMIT_GET_TABLE \ - SQLITE_OMIT_INCRBLOB \ - SQLITE_OMIT_INTEGRITY_CHECK \ - SQLITE_OMIT_LIKE_OPTIMIZATION \ - SQLITE_OMIT_LOAD_EXTENSION \ - SQLITE_OMIT_LOCALTIME \ - SQLITE_OMIT_LOOKASIDE \ - SQLITE_OMIT_MEMORYDB \ - SQLITE_OMIT_OR_OPTIMIZATION \ - SQLITE_OMIT_PAGER_PRAGMAS \ - SQLITE_OMIT_PRAGMA \ - SQLITE_OMIT_PROGRESS_CALLBACK \ - SQLITE_OMIT_QUICKBALANCE \ - SQLITE_OMIT_REINDEX \ - SQLITE_OMIT_SCHEMA_PRAGMAS \ - SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS \ - SQLITE_OMIT_SHARED_CACHE \ - SQLITE_OMIT_SUBQUERY \ - SQLITE_OMIT_TCL_VARIABLE \ - SQLITE_OMIT_TEMPDB \ - SQLITE_OMIT_TRACE \ - SQLITE_OMIT_TRIGGER \ - SQLITE_OMIT_TRUNCATE_OPTIMIZATION \ - SQLITE_OMIT_UNIQUE_ENFORCEMENT \ - SQLITE_OMIT_UTF16 \ - SQLITE_OMIT_VACUUM \ - SQLITE_OMIT_VIEW \ - SQLITE_OMIT_VIRTUALTABLE \ - SQLITE_OMIT_WAL \ - SQLITE_OMIT_WSD \ - SQLITE_OMIT_XFER_OPT \ - ] - - set ::ENABLE_SYMBOLS [list \ - SQLITE_DISABLE_DIRSYNC \ - SQLITE_DISABLE_LFS \ - SQLITE_ENABLE_ATOMIC_WRITE \ - SQLITE_ENABLE_COLUMN_METADATA \ - SQLITE_ENABLE_EXPENSIVE_ASSERT \ - SQLITE_ENABLE_FTS3 \ - SQLITE_ENABLE_FTS3_PARENTHESIS \ - SQLITE_ENABLE_FTS4 \ - SQLITE_ENABLE_IOTRACE \ - SQLITE_ENABLE_LOAD_EXTENSION \ - SQLITE_ENABLE_LOCKING_STYLE \ - SQLITE_ENABLE_MEMORY_MANAGEMENT \ - SQLITE_ENABLE_MEMSYS3 \ - SQLITE_ENABLE_MEMSYS5 \ - SQLITE_ENABLE_OVERSIZE_CELL_CHECK \ - SQLITE_ENABLE_RTREE \ - SQLITE_ENABLE_STAT3 \ - SQLITE_ENABLE_UNLOCK_NOTIFY \ - SQLITE_ENABLE_UPDATE_DELETE_LIMIT \ - ] - - # Process any command line options. - process_options $argv - - if {[info exists ::SYMBOL] } { - set sym $::SYMBOL - - if {[lsearch $::OMIT_SYMBOLS $sym]<0 && [lsearch $::ENABLE_SYMBOLS $sym]<0} { - puts stderr "No such symbol: $sym" - exit -1 - } - - set dirname "test_[regsub -nocase {^x*SQLITE_} $sym {}]" - run_quick_test $dirname $sym - } else { - # First try a test with all OMIT symbols except SQLITE_OMIT_FLOATING_POINT - # and SQLITE_OMIT_PRAGMA defined. The former doesn't work (causes segfaults) - # and the latter is currently incompatible with the test suite (this should - # be fixed, but it will be a lot of work). - set allsyms [list] - foreach s $::OMIT_SYMBOLS { - if {$s!="SQLITE_OMIT_FLOATING_POINT" && $s!="SQLITE_OMIT_PRAGMA"} { - lappend allsyms $s - } - } - run_quick_test test_OMIT_EVERYTHING $allsyms - - # Now try one quick.test with each of the OMIT symbols defined. Included - # are the OMIT_FLOATING_POINT and OMIT_PRAGMA symbols, even though we - # know they will fail. It's good to be reminded of this from time to time. - foreach sym $::OMIT_SYMBOLS { - set dirname "test_[regsub -nocase {^x*SQLITE_} $sym {}]" - run_quick_test $dirname $sym - } - - # Try the ENABLE/DISABLE symbols one at a time. - # We don't do them all at once since some are conflicting. - foreach sym $::ENABLE_SYMBOLS { - set dirname "test_[regsub -nocase {^x*SQLITE_} $sym {}]" - run_quick_test $dirname $sym - } - } -} - -main $argv diff --git a/lib/libsqlite3/tool/opcodeDoc.awk b/lib/libsqlite3/tool/opcodeDoc.awk deleted file mode 100644 index 492010624fd..00000000000 --- a/lib/libsqlite3/tool/opcodeDoc.awk +++ /dev/null @@ -1,23 +0,0 @@ -# -# Extract opcode documentation for sqliteVdbe.c and generate HTML -# -BEGIN { - print "<html><body bgcolor=white>" - print "<h1>SQLite Virtual Database Engine Opcodes</h1>" - print "<table>" -} -/ Opcode: /,/\*\// { - if( $2=="Opcode:" ){ - printf "<tr><td>%s %s %s %s</td>\n<td>\n", $3, $4, $5, $6 - }else if( $1=="*/" ){ - printf "</td></tr>\n" - }else if( NF>1 ){ - sub(/^ *\*\* /,"") - gsub(/</,"<") - gsub(/&/,"&") - print - } -} -END { - print "</table></body></html>" -} diff --git a/lib/libsqlite3/tool/pagesig.c b/lib/libsqlite3/tool/pagesig.c deleted file mode 100644 index 540c9d72266..00000000000 --- a/lib/libsqlite3/tool/pagesig.c +++ /dev/null @@ -1,92 +0,0 @@ -/* -** 2013-10-01 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** Compute hash signatures for every page of a database file. This utility -** program is useful for analyzing the output logs generated by the -** ext/misc/vfslog.c extension. -*/ -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <stdlib.h> - -/* -** Compute signature for a block of content. -** -** For blocks of 16 or fewer bytes, the signature is just a hex dump of -** the entire block. -** -** For blocks of more than 16 bytes, the signature is a hex dump of the -** first 8 bytes followed by a 64-bit has of the entire block. -*/ -static void vlogSignature(unsigned char *p, int n, char *zCksum){ - unsigned int s0 = 0, s1 = 0; - unsigned int *pI; - int i; - if( n<=16 ){ - for(i=0; i<n; i++) sprintf(zCksum+i*2, "%02x", p[i]); - }else{ - pI = (unsigned int*)p; - for(i=0; i<n-7; i+=8){ - s0 += pI[0] + s1; - s1 += pI[1] + s0; - pI += 2; - } - for(i=0; i<8; i++) sprintf(zCksum+i*2, "%02x", p[i]); - sprintf(zCksum+i*2, "-%08x%08x", s0, s1); - } -} - -/* -** Open a file. Find its page size. Read each page, and compute and -** display the page signature. -*/ -static void computeSigs(const char *zFilename){ - FILE *in = fopen(zFilename, "rb"); - unsigned pgsz; - size_t got; - unsigned n; - unsigned char aBuf[50]; - unsigned char aPage[65536]; - - if( in==0 ){ - fprintf(stderr, "cannot open \"%s\"\n", zFilename); - return; - } - got = fread(aBuf, 1, sizeof(aBuf), in); - if( got!=sizeof(aBuf) ){ - goto endComputeSigs; - } - pgsz = aBuf[16]*256 + aBuf[17]; - if( pgsz==1 ) pgsz = 65536; - if( (pgsz & (pgsz-1))!=0 ){ - fprintf(stderr, "invalid page size: %02x%02x\n", aBuf[16], aBuf[17]); - goto endComputeSigs; - } - rewind(in); - for(n=1; (got=fread(aPage, 1, pgsz, in))==pgsz; n++){ - vlogSignature(aPage, pgsz, aBuf); - printf("%4d: %s\n", n, aBuf); - } - -endComputeSigs: - fclose(in); -} - -/* -** Find page signatures for all named files. -*/ -int main(int argc, char **argv){ - int i; - for(i=1; i<argc; i++) computeSigs(argv[i]); - return 0; -} diff --git a/lib/libsqlite3/tool/restore_jrnl.tcl b/lib/libsqlite3/tool/restore_jrnl.tcl deleted file mode 100644 index 05af4f9a2a8..00000000000 --- a/lib/libsqlite3/tool/restore_jrnl.tcl +++ /dev/null @@ -1,233 +0,0 @@ -# 2010 January 7 -# -# The author disclaims copyright to this source code. In place of -# a legal notice, here is a blessing: -# -# May you do good and not evil. -# May you find forgiveness for yourself and forgive others. -# May you share freely, never taking more than you give. -# -#*********************************************************************** -# This file implements utility functions for SQLite library. -# -# This file attempts to restore the header of a journal. -# This may be useful for rolling-back the last committed -# transaction from a recovered journal. -# - -package require sqlite3 - -set parm_error 0 -set fix_chksums 0 -set dump_pages 0 -set db_name "" - -for {set i 0} {$i<$argc} {incr i} { - if {[lindex $argv $i] == "-fix_chksums"} { - set fix_chksums -1 - } elseif {[lindex $argv $i] == "-dump_pages"} { - set dump_pages -1 - } elseif {$db_name == ""} { - set db_name [lindex $argv $i] - set jrnl_name $db_name-journal - } else { - set parm_error -1 - } -} -if {$parm_error || $db_name == ""} { - puts "USAGE: restore_jrnl.tcl \[-fix_chksums\] \[-dump_pages\] db_name" - puts "Example: restore_jrnl.tcl foo.sqlite" - return -} - -# is there a way to determine this? -set sectsz 512 - -# Copy file $from into $to -# -proc copy_file {from to} { - file copy -force $from $to -} - -# Execute some SQL -# -proc catchsql {sql} { - set rc [catch {uplevel [list db eval $sql]} msg] - list $rc $msg -} - -# Perform a test -# -proc do_test {name cmd expected} { - puts -nonewline "$name ..." - set res [uplevel $cmd] - if {$res eq $expected} { - puts Ok - } else { - puts Error - puts " Got: $res" - puts " Expected: $expected" - } -} - -# Calc checksum nonce from journal page data. -# -proc calc_nonce {jrnl_pgno} { - global sectsz - global db_pgsz - global jrnl_name - set jrnl_pg_offset [expr $sectsz+((4+$db_pgsz+4)*$jrnl_pgno)] - set nonce [hexio_get_int [hexio_read $jrnl_name [expr $jrnl_pg_offset+4+$db_pgsz] 4]] - for {set i [expr $db_pgsz-200]} {$i>0} {set i [expr $i-200]} { - set byte [hexio_get_int [hexio_read $jrnl_name [expr $jrnl_pg_offset+4+$i] 1]] - set nonce [expr $nonce-$byte] - } - return $nonce -} - -# Calc checksum from journal page data. -# -proc calc_chksum {jrnl_pgno} { - global sectsz - global db_pgsz - global jrnl_name - global nonce - set jrnl_pg_offset [expr $sectsz+((4+$db_pgsz+4)*$jrnl_pgno)] - set chksum $nonce - for {set i [expr $db_pgsz-200]} {$i>0} {set i [expr $i-200]} { - set byte [hexio_get_int [hexio_read $jrnl_name [expr $jrnl_pg_offset+4+$i] 1]] - set chksum [expr $chksum+$byte] - } - return $chksum -} - -# Print journal page data in hex dump form -# -proc dump_jrnl_page {jrnl_pgno} { - global sectsz - global db_pgsz - global jrnl_name - - # print a header block for the page - puts [string repeat "-" 79] - set jrnl_pg_offset [expr $sectsz+((4+$db_pgsz+4)*$jrnl_pgno)] - set db_pgno [hexio_get_int [hexio_read $jrnl_name [expr $jrnl_pg_offset] 4]] - set chksum [hexio_get_int [hexio_read $jrnl_name [expr $jrnl_pg_offset+4+$db_pgsz] 4]] - set nonce [calc_nonce $jrnl_pgno] - puts [ format {jrnl_pg_offset: %08x (%d) jrnl_pgno: %d db_pgno: %d} \
- $jrnl_pg_offset $jrnl_pg_offset \
- $jrnl_pgno $db_pgno]
- puts [ format {nonce: %08x chksum: %08x} \
- $nonce $chksum]
- - # now hex dump the data - # This is derived from the Tcler's WIKI
- set fid [open $jrnl_name r]
- fconfigure $fid -translation binary -encoding binary
- seek $fid [expr $jrnl_pg_offset+4]
- set data [read $fid $db_pgsz]
- close $fid
- for {set addr 0} {$addr<$db_pgsz} {set addr [expr $addr+16]} { - # get 16 bytes of data
- set s [string range $data $addr [expr $addr+16]]
-
- # Convert the data to hex and to characters.
- binary scan $s H*@0a* hex ascii
-
- # Replace non-printing characters in the data.
- regsub -all -- {[^[:graph:] ]} $ascii {.} ascii
-
- # Split the 16 bytes into two 8-byte chunks
- regexp -- {(.{16})(.{0,16})} $hex -> hex1 hex2
-
- # Convert the hex to pairs of hex digits
- regsub -all -- {..} $hex1 {& } hex1
- regsub -all -- {..} $hex2 {& } hex2
-
- # Print the hex and ascii data
- puts [ format {%08x %-24s %-24s %-16s} \
- $addr $hex1 $hex2 $ascii ]
- }
-} - -# Setup for the tests. Make a backup copy of the files. -# -if [file exist $db_name.org] { - puts "ERROR: during back-up: $db_name.org exists already." - return; -} -if [file exist $jrnl_name.org] { - puts "ERROR: during back-up: $jrnl_name.org exists already." - return -} -copy_file $db_name $db_name.org -copy_file $jrnl_name $jrnl_name.org - -set db_fsize [file size $db_name] -set db_pgsz [hexio_get_int [hexio_read $db_name 16 2]] -set db_npage [expr {$db_fsize / $db_pgsz}] - -set jrnl_fsize [file size $jrnl_name] -set jrnl_npage [expr {($jrnl_fsize - $sectsz) / (4 + $db_pgsz + 4)}] - -# calculate checksum nonce for first page -set nonce [calc_nonce 0] - -# verify all the pages in the journal use the same nonce -for {set i 1} {$i<$jrnl_npage} {incr i} { - set tnonce [calc_nonce $i] - if {$tnonce != $nonce} { - puts "WARNING: different nonces: 0=$nonce $i=$tnonce" - if {$fix_chksums } { - set jrnl_pg_offset [expr $sectsz+((4+$db_pgsz+4)*$i)] - set tchksum [calc_chksum $i] - hexio_write $jrnl_name [expr $jrnl_pg_offset+4+$db_pgsz] [format %08x $tchksum] - puts "INFO: fixing chksum: $i=$tchksum" - } - } -} - -# verify all the page numbers in the journal -for {set i 0} {$i<$jrnl_npage} {incr i} { - set jrnl_pg_offset [expr $sectsz+((4+$db_pgsz+4)*$i)] - set db_pgno [hexio_get_int [hexio_read $jrnl_name $jrnl_pg_offset 4]] - if {$db_pgno < 1} { - puts "WARNING: page number < 1: $i=$db_pgno" - } - if {$db_pgno >= $db_npage} { - puts "WARNING: page number >= $db_npage: $i=$db_pgno" - } -} - -# dump page data -if {$dump_pages} { - for {set i 0} {$i<$jrnl_npage} {incr i} { - dump_jrnl_page $i - } -} - -# write the 8 byte magic string -hexio_write $jrnl_name 0 d9d505f920a163d7 - -# write -1 for number of records -hexio_write $jrnl_name 8 ffffffff - -# write 00 for checksum nonce -hexio_write $jrnl_name 12 [format %08x $nonce] - -# write page count -hexio_write $jrnl_name 16 [format %08x $db_npage] - -# write sector size -hexio_write $jrnl_name 20 [format %08x $sectsz] - -# write page size -hexio_write $jrnl_name 24 [format %08x $db_pgsz] - -# check the integrity of the database with the patched journal -sqlite3 db $db_name -do_test restore_jrnl-1.0 { - catchsql {PRAGMA integrity_check} -} {0 ok} -db close - diff --git a/lib/libsqlite3/tool/rollback-test.c b/lib/libsqlite3/tool/rollback-test.c deleted file mode 100644 index 915d9d203da..00000000000 --- a/lib/libsqlite3/tool/rollback-test.c +++ /dev/null @@ -1,155 +0,0 @@ -/* -** This program is used to generate and verify databases with hot journals. -** Use this program to generate a hot journal on one machine and verify -** that it rolls back correctly on another machine with a different -** architecture. -** -** Usage: -** -** rollback-test new [-utf8] [-utf16le] [-utf16be] [-pagesize=N] DATABASE -** rollback-test check DATABASE -** rollback-test crash [-wal] [-rollback] DATABASE -*/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "sqlite3.h" - -static void usage(char *argv0){ - fprintf(stderr, - "Usage: %s new [-utf8] [-utf16le] [-utf16be] [-pagesize=N] DATABASE\n" - " %s check DATABASE\n" - " %s crash [-wal] DATABASE\n", - argv0, argv0, argv0 - ); - exit(1); -} - -static sqlite3 *openDb(const char *zFilename){ - int rc; - sqlite3 *db; - rc = sqlite3_open(zFilename, &db); - if( rc ){ - fprintf(stderr, "Cannot open \"%s\": %s\n", - zFilename, sqlite3_errmsg(db)); - sqlite3_close(db); - exit(1); - } - return db; -} - -static int nReply = 0; -static char zReply[1000]; - -static int execCallback(void *NotUsed, int nArg, char **azArg, char **azCol){ - int i, n; - char *z; - for(i=0; i<nArg; i++){ - z = azArg[i]; - if( z==0 ) z = "NULL"; - if( nReply>0 && nReply<sizeof(zReply)-1 ) zReply[nReply++] = ' '; - n = strlen(z); - if( nReply+n>=sizeof(zReply)-1 ) n = sizeof(zReply) - nReply - 1; - memcpy(&zReply[nReply], z, n); - nReply += n; - zReply[nReply] = 0; - } - return 0; -} - -static void runSql(sqlite3 *db, const char *zSql){ - char *zErr = 0; - int rc; - nReply = 0; - rc = sqlite3_exec(db, zSql, execCallback, 0, &zErr); - if( zErr ){ - fprintf(stderr, "SQL error: %s\n", zErr); - exit(1); - } - if( rc ){ - fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); - exit(1); - } -} - -int main(int argc, char **argv){ - sqlite3 *db; - int i; - - if( argc<3 ) usage(argv[0]); - if( strcmp(argv[1], "new")==0 ){ - db = openDb(argv[argc-1]); - for(i=2; i<argc-1; i++){ - if( strcmp(argv[i],"-utf8")==0 ){ - runSql(db, "PRAGMA encoding=UTF8"); - }else if( strcmp(argv[i], "-utf16le")==0 ){ - runSql(db, "PRAGMA encoding=UTF16LE"); - }else if( strcmp(argv[i], "-utf16be")==0 ){ - runSql(db, "PRAGMA encoding=UTF16BE"); - }else if( strncmp(argv[i], "-pagesize=", 10)==0 ){ - int szPg = atoi(&argv[i][10]); - char zBuf[100]; - sprintf(zBuf, "PRAGMA pagesize=%d", szPg); - runSql(db, zBuf); - }else{ - fprintf(stderr, "unknown option %s\n", argv[i]); - usage(argv[0]); - } - } - runSql(db, - "BEGIN;" - "CREATE TABLE t1(x INTEGER PRIMARY KEY, y);" - "INSERT INTO t1(y) VALUES('abcdefghijklmnopqrstuvwxyz');" - "INSERT INTO t1(y) VALUES('abcdefghijklmnopqrstuvwxyz');" - "INSERT INTO t1(y) SELECT y FROM t1;" /* 4 */ - "INSERT INTO t1(y) SELECT y FROM t1;" /* 8 */ - "INSERT INTO t1(y) SELECT y FROM t1;" /* 16 */ - "INSERT INTO t1(y) SELECT y FROM t1;" /* 32 */ - "INSERT INTO t1(y) SELECT y FROM t1;" /* 64 */ - "INSERT INTO t1(y) SELECT y FROM t1;" /* 128 */ - "INSERT INTO t1(y) SELECT y FROM t1;" /* 256 */ - "INSERT INTO t1(y) SELECT y FROM t1;" /* 512 */ - "INSERT INTO t1(y) SELECT y FROM t1;" /* 1024 */ - "UPDATE t1 SET y=(y || x);" - "CREATE INDEX t1y ON t1(y);" - "COMMIT;" - ); - sqlite3_close(db); - }else if( strcmp(argv[1], "check")==0 ){ - db = openDb(argv[argc-1]); - runSql(db, "PRAGMA integrity_check"); - if( strcmp(zReply, "ok")!=0 ){ - fprintf(stderr, "Integrity check: %s\n", zReply); - exit(1); - } - runSql(db, - "SELECT count(*) FROM t1 WHERE y<>('abcdefghijklmnopqrstuvwxyz' || x)" - ); - if( strcmp(zReply, "0")!=0 ){ - fprintf(stderr, "Wrong content\n"); - exit(1); - } - printf("Ok\n"); - }else if( strcmp(argv[1], "crash")==0 ){ - db = openDb(argv[argc-1]); - for(i=2; i<argc-1; i++){ - if( strcmp(argv[i],"-wal")==0 ){ - runSql(db, "PRAGMA journal_mode=WAL"); - }else if( strcmp(argv[i], "-rollback")==0 ){ - runSql(db, "PRAGMA journal_mode=DELETE"); - }else{ - fprintf(stderr, "unknown option %s\n", argv[i]); - usage(argv[0]); - } - } - runSql(db, - "PRAGMA cache_size=10;" - "BEGIN;" - "UPDATE t1 SET y=(y || -x)" - ); - exit(0); - }else{ - usage(argv[0]); - } - return 0; -} diff --git a/lib/libsqlite3/tool/showdb.c b/lib/libsqlite3/tool/showdb.c deleted file mode 100644 index 892cacd5520..00000000000 --- a/lib/libsqlite3/tool/showdb.c +++ /dev/null @@ -1,1177 +0,0 @@ -/* -** A utility for printing all or part of an SQLite database file. -*/ -#include <stdio.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#if !defined(_MSC_VER) -#include <unistd.h> -#else -#include <io.h> -#endif - -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include "sqlite3.h" - - -static struct GlobalData { - int pagesize; /* Size of a database page */ - int dbfd; /* File descriptor for reading the DB */ - int mxPage; /* Last page number */ - int perLine; /* HEX elements to print per line */ - int bRaw; /* True to access db file via OS APIs */ - sqlite3_file *pFd; /* File descriptor for non-raw mode */ - sqlite3 *pDb; /* Database handle that owns pFd */ -} g = {1024, -1, 0, 16, 0, 0, 0}; - - -typedef long long int i64; /* Datatype for 64-bit integers */ - - -/* -** Convert the var-int format into i64. Return the number of bytes -** in the var-int. Write the var-int value into *pVal. -*/ -static int decodeVarint(const unsigned char *z, i64 *pVal){ - i64 v = 0; - int i; - for(i=0; i<8; i++){ - v = (v<<7) + (z[i]&0x7f); - if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } - } - v = (v<<8) + (z[i]&0xff); - *pVal = v; - return 9; -} - -/* -** Extract a big-endian 32-bit integer -*/ -static unsigned int decodeInt32(const unsigned char *z){ - return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3]; -} - -/* Report an out-of-memory error and die. -*/ -static void out_of_memory(void){ - fprintf(stderr,"Out of memory...\n"); - exit(1); -} - -/* -** Open a database connection. -*/ -static sqlite3 *openDatabase(const char *zPrg, const char *zName){ - sqlite3 *db = 0; - int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI; - int rc = sqlite3_open_v2(zName, &db, flags, 0); - if( rc!=SQLITE_OK ){ - const char *zErr = sqlite3_errmsg(db); - fprintf(stderr, "%s: can't open %s (%s)\n", zPrg, zName, zErr); - sqlite3_close(db); - exit(1); - } - return db; -} - -/************************************************************************** -** Beginning of low-level file access functions. -** -** All low-level access to the database file read by this program is -** performed using the following four functions: -** -** fileOpen() - open the db file -** fileClose() - close the db file -** fileRead() - read raw data from the db file -** fileGetsize() - return the size of the db file in bytes -*/ - -/* -** Open the database file. -*/ -static void fileOpen(const char *zPrg, const char *zName){ - assert( g.dbfd<0 ); - if( g.bRaw==0 ){ - int rc; - void *pArg = (void *)(&g.pFd); - g.pDb = openDatabase(zPrg, zName); - rc = sqlite3_file_control(g.pDb, "main", SQLITE_FCNTL_FILE_POINTER, pArg); - if( rc!=SQLITE_OK ){ - fprintf(stderr, - "%s: failed to obtain fd for %s (SQLite too old?)\n", zPrg, zName - ); - exit(1); - } - }else{ - g.dbfd = open(zName, O_RDONLY); - if( g.dbfd<0 ){ - fprintf(stderr,"%s: can't open %s\n", zPrg, zName); - exit(1); - } - } -} - -/* -** Close the database file opened by fileOpen() -*/ -static void fileClose(){ - if( g.bRaw==0 ){ - sqlite3_close(g.pDb); - g.pDb = 0; - g.pFd = 0; - }else{ - close(g.dbfd); - g.dbfd = -1; - } -} - -/* -** Read content from the file. -** -** Space to hold the content is obtained from sqlite3_malloc() and needs -** to be freed by the caller. -*/ -static unsigned char *fileRead(sqlite3_int64 ofst, int nByte){ - unsigned char *aData; - int got; - aData = sqlite3_malloc(nByte+32); - if( aData==0 ) out_of_memory(); - memset(aData, 0, nByte+32); - if( g.bRaw==0 ){ - int rc = g.pFd->pMethods->xRead(g.pFd, (void*)aData, nByte, ofst); - if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ - fprintf(stderr, "error in xRead() - %d\n", rc); - exit(1); - } - }else{ - lseek(g.dbfd, ofst, SEEK_SET); - got = read(g.dbfd, aData, nByte); - if( got>0 && got<nByte ) memset(aData+got, 0, nByte-got); - } - return aData; -} - -/* -** Return the size of the file in byte. -*/ -static sqlite3_int64 fileGetsize(void){ - sqlite3_int64 res = 0; - if( g.bRaw==0 ){ - int rc = g.pFd->pMethods->xFileSize(g.pFd, &res); - if( rc!=SQLITE_OK ){ - fprintf(stderr, "error in xFileSize() - %d\n", rc); - exit(1); - } - }else{ - struct stat sbuf; - fstat(g.dbfd, &sbuf); - res = (sqlite3_int64)(sbuf.st_size); - } - return res; -} - -/* -** End of low-level file access functions. -**************************************************************************/ - -/* -** Print a range of bytes as hex and as ascii. -*/ -static unsigned char *print_byte_range( - int ofst, /* First byte in the range of bytes to print */ - int nByte, /* Number of bytes to print */ - int printOfst /* Add this amount to the index on the left column */ -){ - unsigned char *aData; - int i, j; - const char *zOfstFmt; - - if( ((printOfst+nByte)&~0xfff)==0 ){ - zOfstFmt = " %03x: "; - }else if( ((printOfst+nByte)&~0xffff)==0 ){ - zOfstFmt = " %04x: "; - }else if( ((printOfst+nByte)&~0xfffff)==0 ){ - zOfstFmt = " %05x: "; - }else if( ((printOfst+nByte)&~0xffffff)==0 ){ - zOfstFmt = " %06x: "; - }else{ - zOfstFmt = " %08x: "; - } - - aData = fileRead(ofst, nByte); - for(i=0; i<nByte; i += g.perLine){ - fprintf(stdout, zOfstFmt, i+printOfst); - for(j=0; j<g.perLine; j++){ - if( i+j>nByte ){ - fprintf(stdout, " "); - }else{ - fprintf(stdout,"%02x ", aData[i+j]); - } - } - for(j=0; j<g.perLine; j++){ - if( i+j>nByte ){ - fprintf(stdout, " "); - }else{ - fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.'); - } - } - fprintf(stdout,"\n"); - } - return aData; -} - -/* -** Print an entire page of content as hex -*/ -static void print_page(int iPg){ - int iStart; - unsigned char *aData; - iStart = (iPg-1)*g.pagesize; - fprintf(stdout, "Page %d: (offsets 0x%x..0x%x)\n", - iPg, iStart, iStart+g.pagesize-1); - aData = print_byte_range(iStart, g.pagesize, 0); - sqlite3_free(aData); -} - - -/* Print a line of decode output showing a 4-byte integer. -*/ -static void print_decode_line( - unsigned char *aData, /* Content being decoded */ - int ofst, int nByte, /* Start and size of decode */ - const char *zMsg /* Message to append */ -){ - int i, j; - int val = aData[ofst]; - char zBuf[100]; - sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]); - i = (int)strlen(zBuf); - for(j=1; j<4; j++){ - if( j>=nByte ){ - sprintf(&zBuf[i], " "); - }else{ - sprintf(&zBuf[i], " %02x", aData[ofst+j]); - val = val*256 + aData[ofst+j]; - } - i += (int)strlen(&zBuf[i]); - } - sprintf(&zBuf[i], " %9d", val); - printf("%s %s\n", zBuf, zMsg); -} - -/* -** Decode the database header. -*/ -static void print_db_header(void){ - unsigned char *aData; - aData = print_byte_range(0, 100, 0); - printf("Decoded:\n"); - print_decode_line(aData, 16, 2, "Database page size"); - print_decode_line(aData, 18, 1, "File format write version"); - print_decode_line(aData, 19, 1, "File format read version"); - print_decode_line(aData, 20, 1, "Reserved space at end of page"); - print_decode_line(aData, 24, 4, "File change counter"); - print_decode_line(aData, 28, 4, "Size of database in pages"); - print_decode_line(aData, 32, 4, "Page number of first freelist page"); - print_decode_line(aData, 36, 4, "Number of freelist pages"); - print_decode_line(aData, 40, 4, "Schema cookie"); - print_decode_line(aData, 44, 4, "Schema format version"); - print_decode_line(aData, 48, 4, "Default page cache size"); - print_decode_line(aData, 52, 4, "Largest auto-vac root page"); - print_decode_line(aData, 56, 4, "Text encoding"); - print_decode_line(aData, 60, 4, "User version"); - print_decode_line(aData, 64, 4, "Incremental-vacuum mode"); - print_decode_line(aData, 68, 4, "Application ID"); - print_decode_line(aData, 72, 4, "meta[8]"); - print_decode_line(aData, 76, 4, "meta[9]"); - print_decode_line(aData, 80, 4, "meta[10]"); - print_decode_line(aData, 84, 4, "meta[11]"); - print_decode_line(aData, 88, 4, "meta[12]"); - print_decode_line(aData, 92, 4, "Change counter for version number"); - print_decode_line(aData, 96, 4, "SQLite version number"); -} - -/* -** Describe cell content. -*/ -static i64 describeContent( - unsigned char *a, /* Cell content */ - i64 nLocal, /* Bytes in a[] */ - char *zDesc /* Write description here */ -){ - i64 nDesc = 0; - int n, j; - i64 i, x, v; - const unsigned char *pData; - const unsigned char *pLimit; - char sep = ' '; - - pLimit = &a[nLocal]; - n = decodeVarint(a, &x); - pData = &a[x]; - a += n; - i = x - n; - while( i>0 && pData<=pLimit ){ - n = decodeVarint(a, &x); - a += n; - i -= n; - nLocal -= n; - zDesc[0] = sep; - sep = ','; - nDesc++; - zDesc++; - if( x==0 ){ - sprintf(zDesc, "*"); /* NULL is a "*" */ - }else if( x>=1 && x<=6 ){ - v = (signed char)pData[0]; - pData++; - switch( x ){ - case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; - case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; - case 4: v = (v<<8) + pData[0]; pData++; - case 3: v = (v<<8) + pData[0]; pData++; - case 2: v = (v<<8) + pData[0]; pData++; - } - sprintf(zDesc, "%lld", v); - }else if( x==7 ){ - sprintf(zDesc, "real"); - pData += 8; - }else if( x==8 ){ - sprintf(zDesc, "0"); - }else if( x==9 ){ - sprintf(zDesc, "1"); - }else if( x>=12 ){ - i64 size = (x-12)/2; - if( (x&1)==0 ){ - sprintf(zDesc, "blob(%lld)", size); - }else{ - sprintf(zDesc, "txt(%lld)", size); - } - pData += size; - } - j = (int)strlen(zDesc); - zDesc += j; - nDesc += j; - } - return nDesc; -} - -/* -** Compute the local payload size given the total payload size and -** the page size. -*/ -static i64 localPayload(i64 nPayload, char cType){ - i64 maxLocal; - i64 minLocal; - i64 surplus; - i64 nLocal; - if( cType==13 ){ - /* Table leaf */ - maxLocal = g.pagesize-35; - minLocal = (g.pagesize-12)*32/255-23; - }else{ - maxLocal = (g.pagesize-12)*64/255-23; - minLocal = (g.pagesize-12)*32/255-23; - } - if( nPayload>maxLocal ){ - surplus = minLocal + (nPayload-minLocal)%(g.pagesize-4); - if( surplus<=maxLocal ){ - nLocal = surplus; - }else{ - nLocal = minLocal; - } - }else{ - nLocal = nPayload; - } - return nLocal; -} - - -/* -** Create a description for a single cell. -** -** The return value is the local cell size. -*/ -static i64 describeCell( - unsigned char cType, /* Page type */ - unsigned char *a, /* Cell content */ - int showCellContent, /* Show cell content if true */ - char **pzDesc /* Store description here */ -){ - int i; - i64 nDesc = 0; - int n = 0; - int leftChild; - i64 nPayload; - i64 rowid; - i64 nLocal; - static char zDesc[1000]; - i = 0; - if( cType<=5 ){ - leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3]; - a += 4; - n += 4; - sprintf(zDesc, "lx: %d ", leftChild); - nDesc = strlen(zDesc); - } - if( cType!=5 ){ - i = decodeVarint(a, &nPayload); - a += i; - n += i; - sprintf(&zDesc[nDesc], "n: %lld ", nPayload); - nDesc += strlen(&zDesc[nDesc]); - nLocal = localPayload(nPayload, cType); - }else{ - nPayload = nLocal = 0; - } - if( cType==5 || cType==13 ){ - i = decodeVarint(a, &rowid); - a += i; - n += i; - sprintf(&zDesc[nDesc], "r: %lld ", rowid); - nDesc += strlen(&zDesc[nDesc]); - } - if( nLocal<nPayload ){ - int ovfl; - unsigned char *b = &a[nLocal]; - ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3]; - sprintf(&zDesc[nDesc], "ov: %d ", ovfl); - nDesc += strlen(&zDesc[nDesc]); - n += 4; - } - if( showCellContent && cType!=5 ){ - nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]); - } - *pzDesc = zDesc; - return nLocal+n; -} - -/* Print an offset followed by nByte bytes. Add extra white-space -** at the end so that subsequent text is aligned. -*/ -static void printBytes( - unsigned char *aData, /* Content being decoded */ - unsigned char *aStart, /* Start of content to be printed */ - int nByte /* Number of bytes to print */ -){ - int j; - printf(" %03x: ", (int)(aStart-aData)); - for(j=0; j<9; j++){ - if( j>=nByte ){ - printf(" "); - }else{ - printf("%02x ", aStart[j]); - } - } -} - - -/* -** Write a full decode on stdout for the cell at a[ofst]. -** Assume the page contains a header of size szPgHdr bytes. -*/ -static void decodeCell( - unsigned char *a, /* Page content (without the page-1 header) */ - unsigned pgno, /* Page number */ - int iCell, /* Cell index */ - int szPgHdr, /* Size of the page header. 0 or 100 */ - int ofst /* Cell begins at a[ofst] */ -){ - int i, j = 0; - int leftChild; - i64 k; - i64 nPayload; - i64 rowid; - i64 nHdr; - i64 iType; - i64 nLocal; - unsigned char *x = a + ofst; - unsigned char *end; - unsigned char cType = a[0]; - int nCol = 0; - int szCol[2000]; - int ofstCol[2000]; - int typeCol[2000]; - - printf("Cell[%d]:\n", iCell); - if( cType<=5 ){ - leftChild = ((x[0]*256 + x[1])*256 + x[2])*256 + x[3]; - printBytes(a, x, 4); - printf("left child page:: %d\n", leftChild); - x += 4; - } - if( cType!=5 ){ - i = decodeVarint(x, &nPayload); - printBytes(a, x, i); - nLocal = localPayload(nPayload, cType); - if( nLocal==nPayload ){ - printf("payload-size: %lld\n", nPayload); - }else{ - printf("payload-size: %lld (%lld local, %lld overflow)\n", - nPayload, nLocal, nPayload-nLocal); - } - x += i; - }else{ - nPayload = nLocal = 0; - } - end = x + nLocal; - if( cType==5 || cType==13 ){ - i = decodeVarint(x, &rowid); - printBytes(a, x, i); - printf("rowid: %lld\n", rowid); - x += i; - } - if( nLocal>0 ){ - i = decodeVarint(x, &nHdr); - printBytes(a, x, i); - printf("record-header-size: %d\n", (int)nHdr); - j = i; - nCol = 0; - k = nHdr; - while( x+j<end && j<nHdr ){ - const char *zTypeName; - int sz = 0; - char zNm[30]; - i = decodeVarint(x+j, &iType); - printBytes(a, x+j, i); - printf("typecode[%d]: %d - ", nCol, (int)iType); - switch( iType ){ - case 0: zTypeName = "NULL"; sz = 0; break; - case 1: zTypeName = "int8"; sz = 1; break; - case 2: zTypeName = "int16"; sz = 2; break; - case 3: zTypeName = "int24"; sz = 3; break; - case 4: zTypeName = "int32"; sz = 4; break; - case 5: zTypeName = "int48"; sz = 6; break; - case 6: zTypeName = "int64"; sz = 8; break; - case 7: zTypeName = "double"; sz = 8; break; - case 8: zTypeName = "zero"; sz = 0; break; - case 9: zTypeName = "one"; sz = 0; break; - case 10: - case 11: zTypeName = "error"; sz = 0; break; - default: { - sz = (int)(iType-12)/2; - sprintf(zNm, (iType&1)==0 ? "blob(%d)" : "text(%d)", sz); - zTypeName = zNm; - break; - } - } - printf("%s\n", zTypeName); - szCol[nCol] = sz; - ofstCol[nCol] = (int)k; - typeCol[nCol] = (int)iType; - k += sz; - nCol++; - j += i; - } - for(i=0; i<nCol && ofstCol[i]+szCol[i]<=nLocal; i++){ - int s = ofstCol[i]; - i64 v; - const unsigned char *pData; - if( szCol[i]==0 ) continue; - printBytes(a, x+s, szCol[i]); - printf("data[%d]: ", i); - pData = x+s; - if( typeCol[i]<=7 ){ - v = (signed char)pData[0]; - for(k=1; k<szCol[i]; k++){ - v = (v<<8) + pData[k]; - } - if( typeCol[i]==7 ){ - double r; - memcpy(&r, &v, sizeof(r)); - printf("%#g\n", r); - }else{ - printf("%lld\n", v); - } - }else{ - int ii, jj; - char zConst[32]; - if( (typeCol[i]&1)==0 ){ - zConst[0] = 'x'; - zConst[1] = '\''; - for(ii=2, jj=0; jj<szCol[i] && ii<24; jj++, ii+=2){ - sprintf(zConst+ii, "%02x", pData[jj]); - } - }else{ - zConst[0] = '\''; - for(ii=1, jj=0; jj<szCol[i] && ii<24; jj++, ii++){ - zConst[ii] = isprint(pData[jj]) ? pData[jj] : '.'; - } - zConst[ii] = 0; - } - if( jj<szCol[i] ){ - memcpy(zConst+ii, "...'", 5); - }else{ - memcpy(zConst+ii, "'", 2); - } - printf("%s\n", zConst); - } - j = ofstCol[i] + szCol[i]; - } - } - if( j<nLocal ){ - printBytes(a, x+j, 0); - printf("... %lld bytes of content ...\n", nLocal-j); - } - if( nLocal<nPayload ){ - printBytes(a, x+nLocal, 4); - printf("overflow-page: %d\n", decodeInt32(x+nLocal)); - } -} - - -/* -** Decode a btree page -*/ -static void decode_btree_page( - unsigned char *a, /* Page content */ - int pgno, /* Page number */ - int hdrSize, /* Size of the page header. 0 or 100 */ - char *zArgs /* Flags to control formatting */ -){ - const char *zType = "unknown"; - int nCell; - int i, j; - int iCellPtr; - int showCellContent = 0; - int showMap = 0; - int cellToDecode = -2; - char *zMap = 0; - switch( a[0] ){ - case 2: zType = "index interior node"; break; - case 5: zType = "table interior node"; break; - case 10: zType = "index leaf"; break; - case 13: zType = "table leaf"; break; - } - while( zArgs[0] ){ - switch( zArgs[0] ){ - case 'c': showCellContent = 1; break; - case 'm': showMap = 1; break; - case 'd': { - if( !isdigit(zArgs[1]) ){ - cellToDecode = -1; - }else{ - cellToDecode = 0; - while( isdigit(zArgs[1]) ){ - zArgs++; - cellToDecode = cellToDecode*10 + zArgs[0] - '0'; - } - } - break; - } - } - zArgs++; - } - nCell = a[3]*256 + a[4]; - iCellPtr = (a[0]==2 || a[0]==5) ? 12 : 8; - if( cellToDecode>=nCell ){ - printf("Page %d has only %d cells\n", pgno, nCell); - return; - } - printf("Header on btree page %d:\n", pgno); - print_decode_line(a, 0, 1, zType); - print_decode_line(a, 1, 2, "Offset to first freeblock"); - print_decode_line(a, 3, 2, "Number of cells on this page"); - print_decode_line(a, 5, 2, "Offset to cell content area"); - print_decode_line(a, 7, 1, "Fragmented byte count"); - if( a[0]==2 || a[0]==5 ){ - print_decode_line(a, 8, 4, "Right child"); - } - if( cellToDecode==(-2) && nCell>0 ){ - printf(" key: lx=left-child n=payload-size r=rowid\n"); - } - if( showMap ){ - zMap = sqlite3_malloc(g.pagesize); - memset(zMap, '.', g.pagesize); - memset(zMap, '1', hdrSize); - memset(&zMap[hdrSize], 'H', iCellPtr); - memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell); - } - for(i=0; i<nCell; i++){ - int cofst = iCellPtr + i*2; - char *zDesc; - i64 n; - - cofst = a[cofst]*256 + a[cofst+1]; - n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc); - if( showMap ){ - char zBuf[30]; - memset(&zMap[cofst], '*', (size_t)n); - zMap[cofst] = '['; - zMap[cofst+n-1] = ']'; - sprintf(zBuf, "%d", i); - j = (int)strlen(zBuf); - if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j); - } - if( cellToDecode==(-2) ){ - printf(" %03x: cell[%d] %s\n", cofst, i, zDesc); - }else if( cellToDecode==(-1) || cellToDecode==i ){ - decodeCell(a, pgno, i, hdrSize, cofst-hdrSize); - } - } - if( showMap ){ - printf("Page map: (H=header P=cell-index 1=page-1-header .=free-space)\n"); - for(i=0; i<g.pagesize; i+=64){ - printf(" %03x: %.64s\n", i, &zMap[i]); - } - sqlite3_free(zMap); - } -} - -/* -** Decode a freelist trunk page. -*/ -static void decode_trunk_page( - int pgno, /* The page number */ - int detail, /* Show leaf pages if true */ - int recursive /* Follow the trunk change if true */ -){ - int n, i; - unsigned char *a; - while( pgno>0 ){ - a = fileRead((pgno-1)*g.pagesize, g.pagesize); - printf("Decode of freelist trunk page %d:\n", pgno); - print_decode_line(a, 0, 4, "Next freelist trunk page"); - print_decode_line(a, 4, 4, "Number of entries on this page"); - if( detail ){ - n = (int)decodeInt32(&a[4]); - for(i=0; i<n; i++){ - unsigned int x = decodeInt32(&a[8+4*i]); - char zIdx[10]; - sprintf(zIdx, "[%d]", i); - printf(" %5s %7u", zIdx, x); - if( i%5==4 ) printf("\n"); - } - if( i%5!=0 ) printf("\n"); - } - if( !recursive ){ - pgno = 0; - }else{ - pgno = (int)decodeInt32(&a[0]); - } - sqlite3_free(a); - } -} - -/* -** A short text comment on the use of each page. -*/ -static char **zPageUse; - -/* -** Add a comment on the use of a page. -*/ -static void page_usage_msg(int pgno, const char *zFormat, ...){ - va_list ap; - char *zMsg; - - va_start(ap, zFormat); - zMsg = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - if( pgno<=0 || pgno>g.mxPage ){ - printf("ERROR: page %d out of range 1..%d: %s\n", - pgno, g.mxPage, zMsg); - sqlite3_free(zMsg); - return; - } - if( zPageUse[pgno]!=0 ){ - printf("ERROR: page %d used multiple times:\n", pgno); - printf("ERROR: previous: %s\n", zPageUse[pgno]); - printf("ERROR: current: %s\n", zMsg); - sqlite3_free(zPageUse[pgno]); - } - zPageUse[pgno] = zMsg; -} - -/* -** Find overflow pages of a cell and describe their usage. -*/ -static void page_usage_cell( - unsigned char cType, /* Page type */ - unsigned char *a, /* Cell content */ - int pgno, /* page containing the cell */ - int cellno /* Index of the cell on the page */ -){ - int i; - int n = 0; - i64 nPayload; - i64 rowid; - i64 nLocal; - i = 0; - if( cType<=5 ){ - a += 4; - n += 4; - } - if( cType!=5 ){ - i = decodeVarint(a, &nPayload); - a += i; - n += i; - nLocal = localPayload(nPayload, cType); - }else{ - nPayload = nLocal = 0; - } - if( cType==5 || cType==13 ){ - i = decodeVarint(a, &rowid); - a += i; - n += i; - } - if( nLocal<nPayload ){ - int ovfl = decodeInt32(a+nLocal); - int cnt = 0; - while( ovfl && (cnt++)<g.mxPage ){ - page_usage_msg(ovfl, "overflow %d from cell %d of page %d", - cnt, cellno, pgno); - a = fileRead((ovfl-1)*g.pagesize, 4); - ovfl = decodeInt32(a); - sqlite3_free(a); - } - } -} - - -/* -** Describe the usages of a b-tree page -*/ -static void page_usage_btree( - int pgno, /* Page to describe */ - int parent, /* Parent of this page. 0 for root pages */ - int idx, /* Which child of the parent */ - const char *zName /* Name of the table */ -){ - unsigned char *a; - const char *zType = "corrupt node"; - int nCell; - int i; - int hdr = pgno==1 ? 100 : 0; - - if( pgno<=0 || pgno>g.mxPage ) return; - a = fileRead((pgno-1)*g.pagesize, g.pagesize); - switch( a[hdr] ){ - case 2: zType = "interior node of index"; break; - case 5: zType = "interior node of table"; break; - case 10: zType = "leaf of index"; break; - case 13: zType = "leaf of table"; break; - } - if( parent ){ - page_usage_msg(pgno, "%s [%s], child %d of page %d", - zType, zName, idx, parent); - }else{ - page_usage_msg(pgno, "root %s [%s]", zType, zName); - } - nCell = a[hdr+3]*256 + a[hdr+4]; - if( a[hdr]==2 || a[hdr]==5 ){ - int cellstart = hdr+12; - unsigned int child; - for(i=0; i<nCell; i++){ - int ofst; - - ofst = cellstart + i*2; - ofst = a[ofst]*256 + a[ofst+1]; - child = decodeInt32(a+ofst); - page_usage_btree(child, pgno, i, zName); - } - child = decodeInt32(a+cellstart-4); - page_usage_btree(child, pgno, i, zName); - } - if( a[hdr]==2 || a[hdr]==10 || a[hdr]==13 ){ - int cellstart = hdr + 8 + 4*(a[hdr]<=5); - for(i=0; i<nCell; i++){ - int ofst; - ofst = cellstart + i*2; - ofst = a[ofst]*256 + a[ofst+1]; - page_usage_cell(a[hdr], a+ofst, pgno, i); - } - } - sqlite3_free(a); -} - -/* -** Determine page usage by the freelist -*/ -static void page_usage_freelist(int pgno){ - unsigned char *a; - int cnt = 0; - int i; - int n; - int iNext; - int parent = 1; - - while( pgno>0 && pgno<=g.mxPage && (cnt++)<g.mxPage ){ - page_usage_msg(pgno, "freelist trunk #%d child of %d", cnt, parent); - a = fileRead((pgno-1)*g.pagesize, g.pagesize); - iNext = decodeInt32(a); - n = decodeInt32(a+4); - for(i=0; i<n; i++){ - int child = decodeInt32(a + (i*4+8)); - page_usage_msg(child, "freelist leaf, child %d of trunk page %d", - i, pgno); - } - sqlite3_free(a); - parent = pgno; - pgno = iNext; - } -} - -/* -** Determine pages used as PTRMAP pages -*/ -static void page_usage_ptrmap(unsigned char *a){ - if( a[55] ){ - int usable = g.pagesize - a[20]; - int pgno = 2; - int perPage = usable/5; - while( pgno<=g.mxPage ){ - page_usage_msg(pgno, "PTRMAP page covering %d..%d", - pgno+1, pgno+perPage); - pgno += perPage + 1; - } - } -} - -/* -** Try to figure out how every page in the database file is being used. -*/ -static void page_usage_report(const char *zPrg, const char *zDbName){ - int i, j; - int rc; - sqlite3 *db; - sqlite3_stmt *pStmt; - unsigned char *a; - char zQuery[200]; - - /* Avoid the pathological case */ - if( g.mxPage<1 ){ - printf("empty database\n"); - return; - } - - /* Open the database file */ - db = openDatabase(zPrg, zDbName); - - /* Set up global variables zPageUse[] and g.mxPage to record page - ** usages */ - zPageUse = sqlite3_malloc( sizeof(zPageUse[0])*(g.mxPage+1) ); - if( zPageUse==0 ) out_of_memory(); - memset(zPageUse, 0, sizeof(zPageUse[0])*(g.mxPage+1)); - - /* Discover the usage of each page */ - a = fileRead(0, 100); - page_usage_freelist(decodeInt32(a+32)); - page_usage_ptrmap(a); - sqlite3_free(a); - page_usage_btree(1, 0, 0, "sqlite_master"); - sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0); - for(j=0; j<2; j++){ - sqlite3_snprintf(sizeof(zQuery), zQuery, - "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage" - " ORDER BY rowid %s", j?"DESC":""); - rc = sqlite3_prepare_v2(db, zQuery, -1, &pStmt, 0); - if( rc==SQLITE_OK ){ - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - int pgno = sqlite3_column_int(pStmt, 2); - page_usage_btree(pgno, 0, 0, (const char*)sqlite3_column_text(pStmt,1)); - } - }else{ - printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db)); - } - rc = sqlite3_finalize(pStmt); - if( rc==SQLITE_OK ) break; - } - sqlite3_close(db); - - /* Print the report and free memory used */ - for(i=1; i<=g.mxPage; i++){ - printf("%5d: %s\n", i, zPageUse[i] ? zPageUse[i] : "???"); - sqlite3_free(zPageUse[i]); - } - sqlite3_free(zPageUse); - zPageUse = 0; -} - -/* -** Try to figure out how every page in the database file is being used. -*/ -static void ptrmap_coverage_report(const char *zDbName){ - int pgno; - unsigned char *aHdr; - unsigned char *a; - int usable; - int perPage; - int i; - - /* Avoid the pathological case */ - if( g.mxPage<1 ){ - printf("empty database\n"); - return; - } - - /* Make sure PTRMAPs are used in this database */ - aHdr = fileRead(0, 100); - if( aHdr[55]==0 ){ - printf("database does not use PTRMAP pages\n"); - return; - } - usable = g.pagesize - aHdr[20]; - perPage = usable/5; - sqlite3_free(aHdr); - printf("%5d: root of sqlite_master\n", 1); - for(pgno=2; pgno<=g.mxPage; pgno += perPage+1){ - printf("%5d: PTRMAP page covering %d..%d\n", pgno, - pgno+1, pgno+perPage); - a = fileRead((pgno-1)*g.pagesize, usable); - for(i=0; i+5<=usable && pgno+1+i/5<=g.mxPage; i+=5){ - const char *zType = "???"; - unsigned int iFrom = decodeInt32(&a[i+1]); - switch( a[i] ){ - case 1: zType = "b-tree root page"; break; - case 2: zType = "freelist page"; break; - case 3: zType = "first page of overflow"; break; - case 4: zType = "later page of overflow"; break; - case 5: zType = "b-tree non-root page"; break; - } - printf("%5d: %s, parent=%u\n", pgno+1+i/5, zType, iFrom); - } - sqlite3_free(a); - } -} - -/* -** Print a usage comment -*/ -static void usage(const char *argv0){ - fprintf(stderr, "Usage %s ?--uri? FILENAME ?args...?\n\n", argv0); - fprintf(stderr, - "switches:\n" - " --raw Read db file directly, bypassing SQLite VFS\n" - "args:\n" - " dbheader Show database header\n" - " pgidx Index of how each page is used\n" - " ptrmap Show all PTRMAP page content\n" - " NNN..MMM Show hex of pages NNN through MMM\n" - " NNN..end Show hex of pages NNN through end of file\n" - " NNNb Decode btree page NNN\n" - " NNNbc Decode btree page NNN and show content\n" - " NNNbm Decode btree page NNN and show a layout map\n" - " NNNbdCCC Decode cell CCC on btree page NNN\n" - " NNNt Decode freelist trunk page NNN\n" - " NNNtd Show leaf freelist pages on the decode\n" - " NNNtr Recursively decode freelist starting at NNN\n" - ); -} - -int main(int argc, char **argv){ - sqlite3_int64 szFile; - unsigned char *zPgSz; - const char *zPrg = argv[0]; /* Name of this executable */ - char **azArg = argv; - int nArg = argc; - - /* Check for the "--uri" or "-uri" switch. */ - if( nArg>1 ){ - if( sqlite3_stricmp("-raw", azArg[1])==0 - || sqlite3_stricmp("--raw", azArg[1])==0 - ){ - g.bRaw = 1; - azArg++; - nArg--; - } - } - - if( nArg<2 ){ - usage(zPrg); - exit(1); - } - - fileOpen(zPrg, azArg[1]); - szFile = fileGetsize(); - - zPgSz = fileRead(16, 2); - g.pagesize = zPgSz[0]*256 + zPgSz[1]*65536; - if( g.pagesize==0 ) g.pagesize = 1024; - sqlite3_free(zPgSz); - - printf("Pagesize: %d\n", g.pagesize); - g.mxPage = (szFile+g.pagesize-1)/g.pagesize; - - printf("Available pages: 1..%d\n", g.mxPage); - if( nArg==2 ){ - int i; - for(i=1; i<=g.mxPage; i++) print_page(i); - }else{ - int i; - for(i=2; i<nArg; i++){ - int iStart, iEnd; - char *zLeft; - if( strcmp(azArg[i], "dbheader")==0 ){ - print_db_header(); - continue; - } - if( strcmp(azArg[i], "pgidx")==0 ){ - page_usage_report(zPrg, azArg[1]); - continue; - } - if( strcmp(azArg[i], "ptrmap")==0 ){ - ptrmap_coverage_report(azArg[1]); - continue; - } - if( strcmp(azArg[i], "help")==0 ){ - usage(zPrg); - continue; - } - if( !isdigit(azArg[i][0]) ){ - fprintf(stderr, "%s: unknown option: [%s]\n", zPrg, azArg[i]); - continue; - } - iStart = strtol(azArg[i], &zLeft, 0); - if( zLeft && strcmp(zLeft,"..end")==0 ){ - iEnd = g.mxPage; - }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){ - iEnd = strtol(&zLeft[2], 0, 0); - }else if( zLeft && zLeft[0]=='b' ){ - int ofst, nByte, hdrSize; - unsigned char *a; - if( iStart==1 ){ - ofst = hdrSize = 100; - nByte = g.pagesize-100; - }else{ - hdrSize = 0; - ofst = (iStart-1)*g.pagesize; - nByte = g.pagesize; - } - a = fileRead(ofst, nByte); - decode_btree_page(a, iStart, hdrSize, &zLeft[1]); - sqlite3_free(a); - continue; - }else if( zLeft && zLeft[0]=='t' ){ - int detail = 0; - int recursive = 0; - int i; - for(i=1; zLeft[i]; i++){ - if( zLeft[i]=='r' ) recursive = 1; - if( zLeft[i]=='d' ) detail = 1; - } - decode_trunk_page(iStart, detail, recursive); - continue; - }else{ - iEnd = iStart; - } - if( iStart<1 || iEnd<iStart || iEnd>g.mxPage ){ - fprintf(stderr, - "Page argument should be LOWER?..UPPER?. Range 1 to %d\n", - g.mxPage); - exit(1); - } - while( iStart<=iEnd ){ - print_page(iStart); - iStart++; - } - } - } - fileClose(); - return 0; -} diff --git a/lib/libsqlite3/tool/showjournal.c b/lib/libsqlite3/tool/showjournal.c deleted file mode 100644 index 19220f5196a..00000000000 --- a/lib/libsqlite3/tool/showjournal.c +++ /dev/null @@ -1,138 +0,0 @@ -/* -** A utility for printing an SQLite database journal. -*/ -#include <stdio.h> -#include <ctype.h> -#include <stdlib.h> -#include <string.h> - -/* -** state information -*/ -static int pageSize = 1024; -static int sectorSize = 512; -static FILE *db = 0; -static int fileSize = 0; -static unsigned cksumNonce = 0; - -/* Report a memory allocation error */ -static void out_of_memory(void){ - fprintf(stderr,"Out of memory...\n"); - exit(1); -} - -/* -** Read N bytes of memory starting at iOfst into space obtained -** from malloc(). -*/ -static unsigned char *read_content(int N, int iOfst){ - int got; - unsigned char *pBuf = malloc(N); - if( pBuf==0 ) out_of_memory(); - fseek(db, iOfst, SEEK_SET); - got = fread(pBuf, 1, N, db); - if( got<0 ){ - fprintf(stderr, "I/O error reading %d bytes from %d\n", N, iOfst); - memset(pBuf, 0, N); - }else if( got<N ){ - fprintf(stderr, "Short read: got only %d of %d bytes from %d\n", - got, N, iOfst); - memset(&pBuf[got], 0, N-got); - } - return pBuf; -} - -/* Print a line of decode output showing a 4-byte integer. -*/ -static unsigned print_decode_line( - const unsigned char *aData, /* Content being decoded */ - int ofst, int nByte, /* Start and size of decode */ - const char *zMsg /* Message to append */ -){ - int i, j; - unsigned val = aData[ofst]; - char zBuf[100]; - sprintf(zBuf, " %05x: %02x", ofst, aData[ofst]); - i = strlen(zBuf); - for(j=1; j<4; j++){ - if( j>=nByte ){ - sprintf(&zBuf[i], " "); - }else{ - sprintf(&zBuf[i], " %02x", aData[ofst+j]); - val = val*256 + aData[ofst+j]; - } - i += strlen(&zBuf[i]); - } - sprintf(&zBuf[i], " %10u", val); - printf("%s %s\n", zBuf, zMsg); - return val; -} - -/* -** Read and print a journal header. Store key information (page size, etc) -** in global variables. -*/ -static unsigned decode_journal_header(int iOfst){ - unsigned char *pHdr = read_content(64, iOfst); - unsigned nPage; - printf("Header at offset %d:\n", iOfst); - print_decode_line(pHdr, 0, 4, "Header part 1 (3654616569)"); - print_decode_line(pHdr, 4, 4, "Header part 2 (547447767)"); - nPage = - print_decode_line(pHdr, 8, 4, "page count"); - cksumNonce = - print_decode_line(pHdr, 12, 4, "chksum nonce"); - print_decode_line(pHdr, 16, 4, "initial database size in pages"); - sectorSize = - print_decode_line(pHdr, 20, 4, "sector size"); - pageSize = - print_decode_line(pHdr, 24, 4, "page size"); - print_decode_line(pHdr, 28, 4, "zero"); - print_decode_line(pHdr, 32, 4, "zero"); - print_decode_line(pHdr, 36, 4, "zero"); - print_decode_line(pHdr, 40, 4, "zero"); - free(pHdr); - return nPage; -} - -static void print_page(int iOfst){ - unsigned char *aData; - char zTitle[50]; - aData = read_content(pageSize+8, iOfst); - sprintf(zTitle, "page number for page at offset %d", iOfst); - print_decode_line(aData-iOfst, iOfst, 4, zTitle); - free(aData); -} - -int main(int argc, char **argv){ - int nPage, cnt; - int iOfst; - if( argc!=2 ){ - fprintf(stderr,"Usage: %s FILENAME\n", argv[0]); - exit(1); - } - db = fopen(argv[1], "rb"); - if( db==0 ){ - fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]); - exit(1); - } - fseek(db, 0, SEEK_END); - fileSize = ftell(db); - printf("journal file size: %d bytes\n", fileSize); - fseek(db, 0, SEEK_SET); - iOfst = 0; - while( iOfst<fileSize ){ - cnt = nPage = (int)decode_journal_header(iOfst); - if( cnt==0 ){ - cnt = (fileSize - sectorSize)/(pageSize+8); - } - iOfst += sectorSize; - while( cnt && iOfst<fileSize ){ - print_page(iOfst); - iOfst += pageSize+8; - } - iOfst = (iOfst/sectorSize + 1)*sectorSize; - } - fclose(db); - return 0; -} diff --git a/lib/libsqlite3/tool/showlocks.c b/lib/libsqlite3/tool/showlocks.c deleted file mode 100644 index 752c535cc37..00000000000 --- a/lib/libsqlite3/tool/showlocks.c +++ /dev/null @@ -1,64 +0,0 @@ -/* -** This file implements a simple command-line utility that shows all of the -** Posix Advisory Locks on a file. -** -** Usage: -** -** showlocks FILENAME -** -** To compile: gcc -o showlocks showlocks.c -*/ -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> - -/* This utility only looks for locks in the first 2 billion bytes */ -#define MX_LCK 2147483647 - -/* -** Print all locks on the inode of "fd" that occur in between -** lwr and upr, inclusive. -*/ -static int showLocksInRange(int fd, off_t lwr, off_t upr){ - int cnt = 0; - struct flock x; - - x.l_type = F_WRLCK; - x.l_whence = SEEK_SET; - x.l_start = lwr; - x.l_len = upr-lwr; - fcntl(fd, F_GETLK, &x); - if( x.l_type==F_UNLCK ) return 0; - printf("start: %-12d len: %-5d pid: %-5d type: %s\n", - (int)x.l_start, (int)x.l_len, - x.l_pid, x.l_type==F_WRLCK ? "WRLCK" : "RDLCK"); - cnt++; - if( x.l_start>lwr ){ - cnt += showLocksInRange(fd, lwr, x.l_start-1); - } - if( x.l_start+x.l_len<upr ){ - cnt += showLocksInRange(fd, x.l_start+x.l_len+1, upr); - } - return cnt; -} - -int main(int argc, char **argv){ - int fd; - int cnt; - - if( argc!=2 ){ - fprintf(stderr, "Usage: %s FILENAME\n", argv[0]); - return 1; - } - fd = open(argv[1], O_RDWR, 0); - if( fd<0 ){ - fprintf(stderr, "%s: cannot open %s\n", argv[0], argv[1]); - return 1; - } - cnt = showLocksInRange(fd, 0, MX_LCK); - if( cnt==0 ) printf("no locks\n"); - close(fd); - return 0; -} diff --git a/lib/libsqlite3/tool/showstat4.c b/lib/libsqlite3/tool/showstat4.c deleted file mode 100644 index 215962919ed..00000000000 --- a/lib/libsqlite3/tool/showstat4.c +++ /dev/null @@ -1,158 +0,0 @@ -/* -** This utility program decodes and displays the content of the -** sqlite_stat4 table in the database file named on the command -** line. -*/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include "sqlite3.h" - -typedef sqlite3_int64 i64; /* 64-bit signed integer type */ - - -/* -** Convert the var-int format into i64. Return the number of bytes -** in the var-int. Write the var-int value into *pVal. -*/ -static int decodeVarint(const unsigned char *z, i64 *pVal){ - i64 v = 0; - int i; - for(i=0; i<8; i++){ - v = (v<<7) + (z[i]&0x7f); - if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } - } - v = (v<<8) + (z[i]&0xff); - *pVal = v; - return 9; -} - - - -int main(int argc, char **argv){ - sqlite3 *db; - sqlite3_stmt *pStmt; - char *zIdx = 0; - int rc, j, x, y, mxHdr; - const unsigned char *aSample; - int nSample; - i64 iVal; - const char *zSep; - int iRow = 0; - - if( argc!=2 ){ - fprintf(stderr, "Usage: %s DATABASE-FILE\n", argv[0]); - exit(1); - } - rc = sqlite3_open(argv[1], &db); - if( rc!=SQLITE_OK || db==0 ){ - fprintf(stderr, "Cannot open database file [%s]\n", argv[1]); - exit(1); - } - rc = sqlite3_prepare_v2(db, - "SELECT tbl||'.'||idx, nEq, nLT, nDLt, sample " - "FROM sqlite_stat4 ORDER BY 1", -1, - &pStmt, 0); - if( rc!=SQLITE_OK || pStmt==0 ){ - fprintf(stderr, "%s\n", sqlite3_errmsg(db)); - sqlite3_close(db); - exit(1); - } - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - if( zIdx==0 || strcmp(zIdx, (const char*)sqlite3_column_text(pStmt,0))!=0 ){ - if( zIdx ) printf("\n**************************************" - "**************\n\n"); - sqlite3_free(zIdx); - zIdx = sqlite3_mprintf("%s", sqlite3_column_text(pStmt,0)); - iRow = 0; - } - printf("%s sample %d ------------------------------------\n", zIdx, ++iRow); - printf(" nEq = %s\n", sqlite3_column_text(pStmt,1)); - printf(" nLt = %s\n", sqlite3_column_text(pStmt,2)); - printf(" nDLt = %s\n", sqlite3_column_text(pStmt,3)); - printf(" sample = x'"); - aSample = sqlite3_column_blob(pStmt,4); - nSample = sqlite3_column_bytes(pStmt,4); - for(j=0; j<nSample; j++) printf("%02x", aSample[j]); - printf("'\n "); - zSep = " "; - x = decodeVarint(aSample, &iVal); - if( iVal<x || iVal>nSample ){ - printf(" <error>\n"); - continue; - } - y = mxHdr = (int)iVal; - while( x<mxHdr ){ - int sz; - i64 v; - x += decodeVarint(aSample+x, &iVal); - if( x>mxHdr ) break; - if( iVal<0 ) break; - switch( iVal ){ - case 0: sz = 0; break; - case 1: sz = 1; break; - case 2: sz = 2; break; - case 3: sz = 3; break; - case 4: sz = 4; break; - case 5: sz = 6; break; - case 6: sz = 8; break; - case 7: sz = 8; break; - case 8: sz = 0; break; - case 9: sz = 0; break; - case 10: - case 11: sz = 0; break; - default: sz = (int)(iVal-12)/2; break; - } - if( y+sz>nSample ) break; - if( iVal==0 ){ - printf("%sNULL", zSep); - }else if( iVal==8 || iVal==9 ){ - printf("%s%d", zSep, ((int)iVal)-8); - }else if( iVal<=7 ){ - v = (signed char)aSample[y]; - for(j=1; j<sz; j++){ - v = (v<<8) + aSample[y+j]; - } - if( iVal==7 ){ - double r; - memcpy(&r, &v, sizeof(r)); - printf("%s%#g", zSep, r); - }else{ - printf("%s%lld", zSep, v); - } - }else if( (iVal&1)==0 ){ - printf("%sx'", zSep); - for(j=0; j<sz; j++){ - printf("%02x", aSample[y+j]); - } - printf("'"); - }else{ - printf("%s\"", zSep); - for(j=0; j<sz; j++){ - char c = (char)aSample[y+j]; - if( isprint(c) ){ - if( c=='"' || c=='\\' ) putchar('\\'); - putchar(c); - }else if( c=='\n' ){ - printf("\\n"); - }else if( c=='\t' ){ - printf("\\t"); - }else if( c=='\r' ){ - printf("\\r"); - }else{ - printf("\\%03o", c); - } - } - printf("\""); - } - zSep = ","; - y += sz; - } - printf("\n"); - } - sqlite3_free(zIdx); - sqlite3_finalize(pStmt); - sqlite3_close(db); - return 0; -} diff --git a/lib/libsqlite3/tool/showwal.c b/lib/libsqlite3/tool/showwal.c deleted file mode 100644 index 35810c66a96..00000000000 --- a/lib/libsqlite3/tool/showwal.c +++ /dev/null @@ -1,596 +0,0 @@ -/* -** A utility for printing content from a write-ahead log file. -*/ -#include <stdio.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#if !defined(_MSC_VER) -#include <unistd.h> -#else -#include <io.h> -#endif - -#include <stdlib.h> -#include <string.h> - - -static int pagesize = 1024; /* Size of a database page */ -static int fd = -1; /* File descriptor for reading the WAL file */ -static int mxFrame = 0; /* Last frame */ -static int perLine = 16; /* HEX elements to print per line */ - -typedef long long int i64; /* Datatype for 64-bit integers */ - -/* Information for computing the checksum */ -typedef struct Cksum Cksum; -struct Cksum { - int bSwap; /* True to do byte swapping on 32-bit words */ - unsigned s0, s1; /* Current checksum value */ -}; - -/* -** extract a 32-bit big-endian integer -*/ -static unsigned int getInt32(const unsigned char *a){ - unsigned int x = (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; - return x; -} - -/* -** Swap bytes on a 32-bit unsigned integer -*/ -static unsigned int swab32(unsigned int x){ - return (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) - + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24); -} - -/* Extend the checksum. Reinitialize the checksum if bInit is true. -*/ -static void extendCksum( - Cksum *pCksum, - unsigned char *aData, - unsigned int nByte, - int bInit -){ - unsigned int *a32; - if( bInit ){ - int a = 0; - *((char*)&a) = 1; - if( a==1 ){ - /* Host is little-endian */ - pCksum->bSwap = getInt32(aData)!=0x377f0682; - }else{ - /* Host is big-endian */ - pCksum->bSwap = getInt32(aData)!=0x377f0683; - } - pCksum->s0 = 0; - pCksum->s1 = 0; - } - a32 = (unsigned int*)aData; - while( nByte>0 ){ - unsigned int x0 = a32[0]; - unsigned int x1 = a32[1]; - if( pCksum->bSwap ){ - x0 = swab32(x0); - x1 = swab32(x1); - } - pCksum->s0 += x0 + pCksum->s1; - pCksum->s1 += x1 + pCksum->s0; - nByte -= 8; - a32 += 2; - } -} - -/* -** Convert the var-int format into i64. Return the number of bytes -** in the var-int. Write the var-int value into *pVal. -*/ -static int decodeVarint(const unsigned char *z, i64 *pVal){ - i64 v = 0; - int i; - for(i=0; i<8; i++){ - v = (v<<7) + (z[i]&0x7f); - if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } - } - v = (v<<8) + (z[i]&0xff); - *pVal = v; - return 9; -} - -/* Report an out-of-memory error and die. -*/ -static void out_of_memory(void){ - fprintf(stderr,"Out of memory...\n"); - exit(1); -} - -/* -** Read content from the file. -** -** Space to hold the content is obtained from malloc() and needs to be -** freed by the caller. -*/ -static unsigned char *getContent(int ofst, int nByte){ - unsigned char *aData; - aData = malloc(nByte); - if( aData==0 ) out_of_memory(); - lseek(fd, ofst, SEEK_SET); - read(fd, aData, nByte); - return aData; -} - -/* -** Print a range of bytes as hex and as ascii. -*/ -static void print_byte_range( - int ofst, /* First byte in the range of bytes to print */ - int nByte, /* Number of bytes to print */ - unsigned char *aData, /* Content to print */ - int printOfst /* Add this amount to the index on the left column */ -){ - int i, j; - const char *zOfstFmt; - - if( ((printOfst+nByte)&~0xfff)==0 ){ - zOfstFmt = " %03x: "; - }else if( ((printOfst+nByte)&~0xffff)==0 ){ - zOfstFmt = " %04x: "; - }else if( ((printOfst+nByte)&~0xfffff)==0 ){ - zOfstFmt = " %05x: "; - }else if( ((printOfst+nByte)&~0xffffff)==0 ){ - zOfstFmt = " %06x: "; - }else{ - zOfstFmt = " %08x: "; - } - - for(i=0; i<nByte; i += perLine){ - fprintf(stdout, zOfstFmt, i+printOfst); - for(j=0; j<perLine; j++){ - if( i+j>nByte ){ - fprintf(stdout, " "); - }else{ - fprintf(stdout,"%02x ", aData[i+j]); - } - } - for(j=0; j<perLine; j++){ - if( i+j>nByte ){ - fprintf(stdout, " "); - }else{ - fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.'); - } - } - fprintf(stdout,"\n"); - } -} - -/* Print a line of decode output showing a 4-byte integer. -*/ -static void print_decode_line( - unsigned char *aData, /* Content being decoded */ - int ofst, int nByte, /* Start and size of decode */ - int asHex, /* If true, output value as hex */ - const char *zMsg /* Message to append */ -){ - int i, j; - int val = aData[ofst]; - char zBuf[100]; - sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]); - i = (int)strlen(zBuf); - for(j=1; j<4; j++){ - if( j>=nByte ){ - sprintf(&zBuf[i], " "); - }else{ - sprintf(&zBuf[i], " %02x", aData[ofst+j]); - val = val*256 + aData[ofst+j]; - } - i += (int)strlen(&zBuf[i]); - } - if( asHex ){ - sprintf(&zBuf[i], " 0x%08x", val); - }else{ - sprintf(&zBuf[i], " %9d", val); - } - printf("%s %s\n", zBuf, zMsg); -} - -/* -** Print an entire page of content as hex -*/ -static void print_frame(int iFrame){ - int iStart; - unsigned char *aData; - iStart = 32 + (iFrame-1)*(pagesize+24); - fprintf(stdout, "Frame %d: (offsets 0x%x..0x%x)\n", - iFrame, iStart, iStart+pagesize+24); - aData = getContent(iStart, pagesize+24); - print_decode_line(aData, 0, 4, 0, "Page number"); - print_decode_line(aData, 4, 4, 0, "DB size, or 0 for non-commit"); - print_decode_line(aData, 8, 4, 1, "Salt-1"); - print_decode_line(aData,12, 4, 1, "Salt-2"); - print_decode_line(aData,16, 4, 1, "Checksum-1"); - print_decode_line(aData,20, 4, 1, "Checksum-2"); - print_byte_range(iStart+24, pagesize, aData+24, 0); - free(aData); -} - -/* -** Summarize a single frame on a single line. -*/ -static void print_oneline_frame(int iFrame, Cksum *pCksum){ - int iStart; - unsigned char *aData; - unsigned int s0, s1; - iStart = 32 + (iFrame-1)*(pagesize+24); - aData = getContent(iStart, 24); - extendCksum(pCksum, aData, 8, 0); - extendCksum(pCksum, getContent(iStart+24, pagesize), pagesize, 0); - s0 = getInt32(aData+16); - s1 = getInt32(aData+20); - fprintf(stdout, "Frame %4d: %6d %6d 0x%08x,%08x 0x%08x,%08x %s\n", - iFrame, - getInt32(aData), - getInt32(aData+4), - getInt32(aData+8), - getInt32(aData+12), - s0, - s1, - (s0==pCksum->s0 && s1==pCksum->s1) ? "" : "cksum-fail" - ); - - /* Reset the checksum so that a single frame checksum failure will not - ** cause all subsequent frames to also show a failure. */ - pCksum->s0 = s0; - pCksum->s1 = s1; - free(aData); -} - -/* -** Decode the WAL header. -*/ -static void print_wal_header(Cksum *pCksum){ - unsigned char *aData; - aData = getContent(0, 32); - if( pCksum ){ - extendCksum(pCksum, aData, 24, 1); - printf("Checksum byte order: %s\n", pCksum->bSwap ? "swapped" : "native"); - } - printf("WAL Header:\n"); - print_decode_line(aData, 0, 4,1,"Magic. 0x377f0682 (le) or 0x377f0683 (be)"); - print_decode_line(aData, 4, 4, 0, "File format"); - print_decode_line(aData, 8, 4, 0, "Database page size"); - print_decode_line(aData, 12,4, 0, "Checkpoint sequence number"); - print_decode_line(aData, 16,4, 1, "Salt-1"); - print_decode_line(aData, 20,4, 1, "Salt-2"); - print_decode_line(aData, 24,4, 1, "Checksum-1"); - print_decode_line(aData, 28,4, 1, "Checksum-2"); - if( pCksum ){ - if( pCksum->s0!=getInt32(aData+24) ){ - printf("**** cksum-1 mismatch: 0x%08x\n", pCksum->s0); - } - if( pCksum->s1!=getInt32(aData+28) ){ - printf("**** cksum-2 mismatch: 0x%08x\n", pCksum->s1); - } - } - free(aData); -} -/* -** Describe cell content. -*/ -static i64 describeContent( - unsigned char *a, /* Cell content */ - i64 nLocal, /* Bytes in a[] */ - char *zDesc /* Write description here */ -){ - int nDesc = 0; - int n, j; - i64 i, x, v; - const unsigned char *pData; - const unsigned char *pLimit; - char sep = ' '; - - pLimit = &a[nLocal]; - n = decodeVarint(a, &x); - pData = &a[x]; - a += n; - i = x - n; - while( i>0 && pData<=pLimit ){ - n = decodeVarint(a, &x); - a += n; - i -= n; - nLocal -= n; - zDesc[0] = sep; - sep = ','; - nDesc++; - zDesc++; - if( x==0 ){ - sprintf(zDesc, "*"); /* NULL is a "*" */ - }else if( x>=1 && x<=6 ){ - v = (signed char)pData[0]; - pData++; - switch( x ){ - case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; - case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; - case 4: v = (v<<8) + pData[0]; pData++; - case 3: v = (v<<8) + pData[0]; pData++; - case 2: v = (v<<8) + pData[0]; pData++; - } - sprintf(zDesc, "%lld", v); - }else if( x==7 ){ - sprintf(zDesc, "real"); - pData += 8; - }else if( x==8 ){ - sprintf(zDesc, "0"); - }else if( x==9 ){ - sprintf(zDesc, "1"); - }else if( x>=12 ){ - i64 size = (x-12)/2; - if( (x&1)==0 ){ - sprintf(zDesc, "blob(%lld)", size); - }else{ - sprintf(zDesc, "txt(%lld)", size); - } - pData += size; - } - j = (int)strlen(zDesc); - zDesc += j; - nDesc += j; - } - return nDesc; -} - -/* -** Compute the local payload size given the total payload size and -** the page size. -*/ -static i64 localPayload(i64 nPayload, char cType){ - i64 maxLocal; - i64 minLocal; - i64 surplus; - i64 nLocal; - if( cType==13 ){ - /* Table leaf */ - maxLocal = pagesize-35; - minLocal = (pagesize-12)*32/255-23; - }else{ - maxLocal = (pagesize-12)*64/255-23; - minLocal = (pagesize-12)*32/255-23; - } - if( nPayload>maxLocal ){ - surplus = minLocal + (nPayload-minLocal)%(pagesize-4); - if( surplus<=maxLocal ){ - nLocal = surplus; - }else{ - nLocal = minLocal; - } - }else{ - nLocal = nPayload; - } - return nLocal; -} - -/* -** Create a description for a single cell. -** -** The return value is the local cell size. -*/ -static i64 describeCell( - unsigned char cType, /* Page type */ - unsigned char *a, /* Cell content */ - int showCellContent, /* Show cell content if true */ - char **pzDesc /* Store description here */ -){ - int i; - i64 nDesc = 0; - int n = 0; - int leftChild; - i64 nPayload; - i64 rowid; - i64 nLocal; - static char zDesc[1000]; - i = 0; - if( cType<=5 ){ - leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3]; - a += 4; - n += 4; - sprintf(zDesc, "lx: %d ", leftChild); - nDesc = strlen(zDesc); - } - if( cType!=5 ){ - i = decodeVarint(a, &nPayload); - a += i; - n += i; - sprintf(&zDesc[nDesc], "n: %lld ", nPayload); - nDesc += strlen(&zDesc[nDesc]); - nLocal = localPayload(nPayload, cType); - }else{ - nPayload = nLocal = 0; - } - if( cType==5 || cType==13 ){ - i = decodeVarint(a, &rowid); - a += i; - n += i; - sprintf(&zDesc[nDesc], "r: %lld ", rowid); - nDesc += strlen(&zDesc[nDesc]); - } - if( nLocal<nPayload ){ - int ovfl; - unsigned char *b = &a[nLocal]; - ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3]; - sprintf(&zDesc[nDesc], "ov: %d ", ovfl); - nDesc += strlen(&zDesc[nDesc]); - n += 4; - } - if( showCellContent && cType!=5 ){ - nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]); - } - *pzDesc = zDesc; - return nLocal+n; -} - -/* -** Decode a btree page -*/ -static void decode_btree_page( - unsigned char *a, /* Content of the btree page to be decoded */ - int pgno, /* Page number */ - int hdrSize, /* Size of the page1-header in bytes */ - const char *zArgs /* Flags to control formatting */ -){ - const char *zType = "unknown"; - int nCell; - int i, j; - int iCellPtr; - int showCellContent = 0; - int showMap = 0; - char *zMap = 0; - switch( a[0] ){ - case 2: zType = "index interior node"; break; - case 5: zType = "table interior node"; break; - case 10: zType = "index leaf"; break; - case 13: zType = "table leaf"; break; - } - while( zArgs[0] ){ - switch( zArgs[0] ){ - case 'c': showCellContent = 1; break; - case 'm': showMap = 1; break; - } - zArgs++; - } - printf("Decode of btree page %d:\n", pgno); - print_decode_line(a, 0, 1, 0, zType); - print_decode_line(a, 1, 2, 0, "Offset to first freeblock"); - print_decode_line(a, 3, 2, 0, "Number of cells on this page"); - nCell = a[3]*256 + a[4]; - print_decode_line(a, 5, 2, 0, "Offset to cell content area"); - print_decode_line(a, 7, 1, 0, "Fragmented byte count"); - if( a[0]==2 || a[0]==5 ){ - print_decode_line(a, 8, 4, 0, "Right child"); - iCellPtr = 12; - }else{ - iCellPtr = 8; - } - if( nCell>0 ){ - printf(" key: lx=left-child n=payload-size r=rowid\n"); - } - if( showMap ){ - zMap = malloc(pagesize); - memset(zMap, '.', pagesize); - memset(zMap, '1', hdrSize); - memset(&zMap[hdrSize], 'H', iCellPtr); - memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell); - } - for(i=0; i<nCell; i++){ - int cofst = iCellPtr + i*2; - char *zDesc; - i64 n; - - cofst = a[cofst]*256 + a[cofst+1]; - n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc); - if( showMap ){ - char zBuf[30]; - memset(&zMap[cofst], '*', (size_t)n); - zMap[cofst] = '['; - zMap[cofst+n-1] = ']'; - sprintf(zBuf, "%d", i); - j = (int)strlen(zBuf); - if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j); - } - printf(" %03x: cell[%d] %s\n", cofst, i, zDesc); - } - if( showMap ){ - for(i=0; i<pagesize; i+=64){ - printf(" %03x: %.64s\n", i, &zMap[i]); - } - free(zMap); - } -} - -int main(int argc, char **argv){ - struct stat sbuf; - unsigned char zPgSz[4]; - if( argc<2 ){ - fprintf(stderr,"Usage: %s FILENAME ?PAGE? ...\n", argv[0]); - exit(1); - } - fd = open(argv[1], O_RDONLY); - if( fd<0 ){ - fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]); - exit(1); - } - zPgSz[0] = 0; - zPgSz[1] = 0; - lseek(fd, 8, SEEK_SET); - read(fd, zPgSz, 4); - pagesize = zPgSz[1]*65536 + zPgSz[2]*256 + zPgSz[3]; - if( pagesize==0 ) pagesize = 1024; - printf("Pagesize: %d\n", pagesize); - fstat(fd, &sbuf); - if( sbuf.st_size<32 ){ - printf("file too small to be a WAL\n"); - return 0; - } - mxFrame = (sbuf.st_size - 32)/(pagesize + 24); - printf("Available pages: 1..%d\n", mxFrame); - if( argc==2 ){ - int i; - Cksum x; - print_wal_header(&x); - for(i=1; i<=mxFrame; i++){ - print_oneline_frame(i, &x); - } - }else{ - int i; - for(i=2; i<argc; i++){ - int iStart, iEnd; - char *zLeft; - if( strcmp(argv[i], "header")==0 ){ - print_wal_header(0); - continue; - } - if( !isdigit(argv[i][0]) ){ - fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]); - continue; - } - iStart = strtol(argv[i], &zLeft, 0); - if( zLeft && strcmp(zLeft,"..end")==0 ){ - iEnd = mxFrame; - }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){ - iEnd = strtol(&zLeft[2], 0, 0); - }else if( zLeft && zLeft[0]=='b' ){ - int ofst, nByte, hdrSize; - unsigned char *a; - if( iStart==1 ){ - hdrSize = 100; - ofst = hdrSize = 100; - nByte = pagesize-100; - }else{ - hdrSize = 0; - ofst = (iStart-1)*pagesize; - nByte = pagesize; - } - ofst = 32 + hdrSize + (iStart-1)*(pagesize+24) + 24; - a = getContent(ofst, nByte); - decode_btree_page(a, iStart, hdrSize, zLeft+1); - free(a); - continue; - }else{ - iEnd = iStart; - } - if( iStart<1 || iEnd<iStart || iEnd>mxFrame ){ - fprintf(stderr, - "Page argument should be LOWER?..UPPER?. Range 1 to %d\n", - mxFrame); - exit(1); - } - while( iStart<=iEnd ){ - print_frame(iStart); - iStart++; - } - } - } - close(fd); - return 0; -} diff --git a/lib/libsqlite3/tool/soak1.tcl b/lib/libsqlite3/tool/soak1.tcl deleted file mode 100644 index 846f905935c..00000000000 --- a/lib/libsqlite3/tool/soak1.tcl +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/tclsh -# -# Usage: -# -# tclsh soak1.tcl local-makefile.mk ?target? ?scenario? -# -# This generates many variations on local-makefile.mk (by modifing -# the OPT = lines) and runs them will fulltest, one by one. The -# constructed makefiles are named "soak1.mk". -# -# If ?target? is provided, that is the makefile target that is run. -# The default is "fulltest" -# -# If ?scenario? is provided, it is the name of a single scenario to -# be run. All other scenarios are skipped. -# -set localmake [lindex $argv 0] -set target [lindex $argv 1] -set scene [lindex $argv 2] -if {$target==""} {set target fulltest} -if {$scene==""} {set scene all} - -set in [open $localmake] -set maketxt [read $in] -close $in -regsub -all {\\\n} $maketxt {} maketxt -#set makefilename "soak1-[expr {int(rand()*1000000000)}].mk" -set makefilename "soak1.mk" - -# Generate a makefile -# -proc generate_makefile {pattern} { - global makefilename maketxt - set out [open $makefilename w] - set seen_opt 0 - foreach line [split $maketxt \n] { - if {[regexp {^ *#? *OPTS[ =+]} $line]} { - if {!$seen_opt} { - puts $out "OPTS += -DSQLITE_NO_SYNC=1" - foreach x $pattern { - puts $out "OPTS += -D$x" - } - set seen_opt 1 - } - } else { - puts $out $line - } - } - close $out -} - -# Run a test -# -proc scenario {id title pattern} { - global makefilename target scene - if {$scene!="all" && $scene!=$id && $scene!=$title} return - puts "**************** $title ***************" - generate_makefile $pattern - exec make -f $makefilename clean >@stdout 2>@stdout - exec make -f $makefilename $target >@stdout 2>@stdout -} - -############################################################################### -# Add new scenarios here -# -scenario 0 {Default} {} -scenario 1 {Debug} { - SQLITE_DEBUG=1 - SQLITE_MEMDEBUG=1 -} -scenario 2 {Everything} { - SQLITE_DEBUG=1 - SQLITE_MEMDEBUG=1 - SQLITE_ENABLE_MEMORY_MANAGEMENT=1 - SQLITE_ENABLE_COLUMN_METADATA=1 - SQLITE_ENABLE_LOAD_EXTENSION=1 HAVE_DLOPEN=1 - SQLITE_ENABLE_MEMORY_MANAGEMENT=1 -} -scenario 3 {Customer-1} { - SQLITE_DEBUG=1 SQLITE_MEMDEBUG=1 - SQLITE_THREADSAFE=1 SQLITE_OS_UNIX=1 - SQLITE_DISABLE_LFS=1 - SQLITE_DEFAULT_AUTOVACUUM=1 - SQLITE_DEFAULT_PAGE_SIZE=1024 - SQLITE_MAX_PAGE_SIZE=4096 - SQLITE_DEFAULT_CACHE_SIZE=64 - SQLITE_DEFAULT_TEMP_CACHE_SIZE=32 - SQLITE_TEMP_STORE=3 - SQLITE_OMIT_PROGRESS_CALLBACK=1 - SQLITE_OMIT_LOAD_EXTENSION=1 - SQLITE_OMIT_VIRTUALTABLE=1 - SQLITE_ENABLE_IOTRACE=1 -} -scenario 4 {Small-Cache} { - SQLITE_DEBUG=1 SQLITE_MEMDEBUG=1 - SQLITE_THREADSAFE=1 SQLITE_OS_UNIX=1 - SQLITE_DEFAULT_AUTOVACUUM=1 - SQLITE_DEFAULT_PAGE_SIZE=1024 - SQLITE_MAX_PAGE_SIZE=2048 - SQLITE_DEFAULT_CACHE_SIZE=13 - SQLITE_DEFAULT_TEMP_CACHE_SIZE=11 - SQLITE_TEMP_STORE=1 -} diff --git a/lib/libsqlite3/tool/space_used.tcl b/lib/libsqlite3/tool/space_used.tcl deleted file mode 100644 index 2044aa38c5e..00000000000 --- a/lib/libsqlite3/tool/space_used.tcl +++ /dev/null @@ -1,111 +0,0 @@ -# Run this TCL script using "testfixture" in order get a report that shows -# how much disk space is used by a particular data to actually store data -# versus how much space is unused. -# - -# Get the name of the database to analyze -# -if {[llength $argv]!=1} { - puts stderr "Usage: $argv0 database-name" - exit 1 -} -set file_to_analyze [lindex $argv 0] - -# Open the database -# -sqlite db [lindex $argv 0] -set DB [btree_open [lindex $argv 0]] - -# Output the schema for the generated report -# -puts \ -{BEGIN; -CREATE TABLE space_used( - name clob, -- Name of a table or index in the database file - is_index boolean, -- TRUE if it is an index, false for a table - payload int, -- Total amount of data stored in this table or index - pri_pages int, -- Number of primary pages used - ovfl_pages int, -- Number of overflow pages used - pri_unused int, -- Number of unused bytes on primary pages - ovfl_unused int -- Number of unused bytes on overflow pages -);} - -# This query will be used to find the root page number for every index and -# table in the database. -# -set sql { - SELECT name, type, rootpage FROM sqlite_master - UNION ALL - SELECT 'sqlite_master', 'table', 2 - ORDER BY 1 -} - -# Initialize variables used for summary statistics. -# -set total_size 0 -set total_primary 0 -set total_overflow 0 -set total_unused_primary 0 -set total_unused_ovfl 0 - -# Analyze every table in the database, one at a time. -# -foreach {name type rootpage} [db eval $sql] { - set cursor [btree_cursor $DB $rootpage 0] - set go [btree_first $cursor] - set size 0 - catch {unset pg_used} - set unused_ovfl 0 - set n_overflow 0 - while {$go==0} { - set payload [btree_payload_size $cursor] - incr size $payload - set stat [btree_cursor_dump $cursor] - set pgno [lindex $stat 0] - set freebytes [lindex $stat 4] - set pg_used($pgno) $freebytes - if {$payload>238} { - set n [expr {($payload-238+1019)/1020}] - incr n_overflow $n - incr unused_ovfl [expr {$n*1020+238-$payload}] - } - set go [btree_next $cursor] - } - btree_close_cursor $cursor - set n_primary [llength [array names pg_used]] - set unused_primary 0 - foreach x [array names pg_used] {incr unused_primary $pg_used($x)} - regsub -all ' $name '' name - puts -nonewline "INSERT INTO space_used VALUES('$name'" - puts -nonewline ",[expr {$type=="index"}]" - puts ",$size,$n_primary,$n_overflow,$unused_primary,$unused_ovfl);" - incr total_size $size - incr total_primary $n_primary - incr total_overflow $n_overflow - incr total_unused_primary $unused_primary - incr total_unused_ovfl $unused_ovfl -} - -# Output summary statistics: -# -puts "-- Total payload size: $total_size" -puts "-- Total pages used: $total_primary primary and $total_overflow overflow" -set file_pgcnt [expr {[file size [lindex $argv 0]]/1024}] -puts -nonewline "-- Total unused bytes on primary pages: $total_unused_primary" -if {$total_primary>0} { - set upp [expr {$total_unused_primary/$total_primary}] - puts " (avg $upp bytes/page)" -} else { - puts "" -} -puts -nonewline "-- Total unused bytes on overflow pages: $total_unused_ovfl" -if {$total_overflow>0} { - set upp [expr {$total_unused_ovfl/$total_overflow}] - puts " (avg $upp bytes/page)" -} else { - puts "" -} -set n_free [expr {$file_pgcnt-$total_primary-$total_overflow}] -if {$n_free>0} {incr n_free -1} -puts "-- Total pages on freelist: $n_free" -puts "COMMIT;" diff --git a/lib/libsqlite3/tool/spaceanal.tcl b/lib/libsqlite3/tool/spaceanal.tcl deleted file mode 100644 index 38d954162e4..00000000000 --- a/lib/libsqlite3/tool/spaceanal.tcl +++ /dev/null @@ -1,805 +0,0 @@ -# Run this TCL script using "testfixture" in order get a report that shows -# how much disk space is used by a particular data to actually store data -# versus how much space is unused. -# - -if {[catch { - -# Argument $tname is the name of a table within the database opened by -# database handle [db]. Return true if it is a WITHOUT ROWID table, or -# false otherwise. -# -proc is_without_rowid {tname} { - set t [string map {' ''} $tname] - db eval "PRAGMA index_list = '$t'" o { - if {$o(origin) == "pk"} { - set n $o(name) - if {0==[db one { SELECT count(*) FROM sqlite_master WHERE name=$n }]} { - return 1 - } - } - } - return 0 -} - -# Get the name of the database to analyze -# -proc usage {} { - set argv0 [file rootname [file tail [info nameofexecutable]]] - puts stderr "Usage: $argv0 ?--pageinfo? ?--stats? database-filename" - puts stderr { -Analyze the SQLite3 database file specified by the "database-filename" -argument and output a report detailing size and storage efficiency -information for the database and its constituent tables and indexes. - -Options: - - --stats Output SQL text that creates a new database containing - statistics about the database that was analyzed - - --pageinfo Show how each page of the database-file is used -} - exit 1 -} -set file_to_analyze {} -set flags(-pageinfo) 0 -set flags(-stats) 0 -append argv {} -foreach arg $argv { - if {[regexp {^-+pageinfo$} $arg]} { - set flags(-pageinfo) 1 - } elseif {[regexp {^-+stats$} $arg]} { - set flags(-stats) 1 - } elseif {[regexp {^-} $arg]} { - puts stderr "Unknown option: $arg" - usage - } elseif {$file_to_analyze!=""} { - usage - } else { - set file_to_analyze $arg - } -} -if {$file_to_analyze==""} usage -set root_filename $file_to_analyze -regexp {^file:(//)?([^?]*)} $file_to_analyze all x1 root_filename -if {![file exists $root_filename]} { - puts stderr "No such file: $root_filename" - exit 1 -} -if {![file readable $root_filename]} { - puts stderr "File is not readable: $root_filename" - exit 1 -} -set true_file_size [file size $root_filename] -if {$true_file_size<512} { - puts stderr "Empty or malformed database: $root_filename" - exit 1 -} - -# Compute the total file size assuming test_multiplexor is being used. -# Assume that SQLITE_ENABLE_8_3_NAMES might be enabled -# -set extension [file extension $root_filename] -set pattern $root_filename -append pattern {[0-3][0-9][0-9]} -foreach f [glob -nocomplain $pattern] { - incr true_file_size [file size $f] - set extension {} -} -if {[string length $extension]>=2 && [string length $extension]<=4} { - set pattern [file rootname $root_filename] - append pattern {.[0-3][0-9][0-9]} - foreach f [glob -nocomplain $pattern] { - incr true_file_size [file size $f] - } -} - -# Open the database -# -if {[catch {sqlite3 db $file_to_analyze -uri 1} msg]} { - puts stderr "error trying to open $file_to_analyze: $msg" - exit 1 -} - -db eval {SELECT count(*) FROM sqlite_master} -set pageSize [expr {wide([db one {PRAGMA page_size}])}] - -if {$flags(-pageinfo)} { - db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat} - db eval {SELECT name, path, pageno FROM temp.stat ORDER BY pageno} { - puts "$pageno $name $path" - } - exit 0 -} -if {$flags(-stats)} { - db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat} - puts "BEGIN;" - puts "CREATE TABLE stats(" - puts " name STRING, /* Name of table or index */" - puts " path INTEGER, /* Path to page from root */" - puts " pageno INTEGER, /* Page number */" - puts " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" - puts " ncell INTEGER, /* Cells on page (0 for overflow) */" - puts " payload INTEGER, /* Bytes of payload on this page */" - puts " unused INTEGER, /* Bytes of unused space on this page */" - puts " mx_payload INTEGER, /* Largest payload size of all cells */" - puts " pgoffset INTEGER, /* Offset of page in file */" - puts " pgsize INTEGER /* Size of the page */" - puts ");" - db eval {SELECT quote(name) || ',' || - quote(path) || ',' || - quote(pageno) || ',' || - quote(pagetype) || ',' || - quote(ncell) || ',' || - quote(payload) || ',' || - quote(unused) || ',' || - quote(mx_payload) || ',' || - quote(pgoffset) || ',' || - quote(pgsize) AS x FROM stat} { - puts "INSERT INTO stats VALUES($x);" - } - puts "COMMIT;" - exit 0 -} - -# In-memory database for collecting statistics. This script loops through -# the tables and indices in the database being analyzed, adding a row for each -# to an in-memory database (for which the schema is shown below). It then -# queries the in-memory db to produce the space-analysis report. -# -sqlite3 mem :memory: -set tabledef {CREATE TABLE space_used( - name clob, -- Name of a table or index in the database file - tblname clob, -- Name of associated table - is_index boolean, -- TRUE if it is an index, false for a table - nentry int, -- Number of entries in the BTree - leaf_entries int, -- Number of leaf entries - depth int, -- Depth of the b-tree - payload int, -- Total amount of data stored in this table or index - ovfl_payload int, -- Total amount of data stored on overflow pages - ovfl_cnt int, -- Number of entries that use overflow - mx_payload int, -- Maximum payload size - int_pages int, -- Number of interior pages used - leaf_pages int, -- Number of leaf pages used - ovfl_pages int, -- Number of overflow pages used - int_unused int, -- Number of unused bytes on interior pages - leaf_unused int, -- Number of unused bytes on primary pages - ovfl_unused int, -- Number of unused bytes on overflow pages - gap_cnt int, -- Number of gaps in the page layout - compressed_size int -- Total bytes stored on disk -);} -mem eval $tabledef - -# Create a temporary "dbstat" virtual table. -# -db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat} -db eval {CREATE TEMP TABLE dbstat AS SELECT * FROM temp.stat - ORDER BY name, path} -db eval {DROP TABLE temp.stat} - -set isCompressed 0 -set compressOverhead 0 -set depth 0 -set sql { SELECT name, tbl_name FROM sqlite_master WHERE rootpage>0 } -foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] { - - set is_index [expr {$name!=$tblname}] - set idx_btree [expr {$is_index || [is_without_rowid $name]}] - db eval { - SELECT - sum(ncell) AS nentry, - sum((pagetype=='leaf')*ncell) AS leaf_entries, - sum(payload) AS payload, - sum((pagetype=='overflow') * payload) AS ovfl_payload, - sum(path LIKE '%+000000') AS ovfl_cnt, - max(mx_payload) AS mx_payload, - sum(pagetype=='internal') AS int_pages, - sum(pagetype=='leaf') AS leaf_pages, - sum(pagetype=='overflow') AS ovfl_pages, - sum((pagetype=='internal') * unused) AS int_unused, - sum((pagetype=='leaf') * unused) AS leaf_unused, - sum((pagetype=='overflow') * unused) AS ovfl_unused, - sum(pgsize) AS compressed_size, - max((length(CASE WHEN path LIKE '%+%' THEN '' ELSE path END)+3)/4) - AS depth - FROM temp.dbstat WHERE name = $name - } break - - set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}] - set storage [expr {$total_pages*$pageSize}] - if {!$isCompressed && $storage>$compressed_size} { - set isCompressed 1 - set compressOverhead 14 - } - - # Column 'gap_cnt' is set to the number of non-contiguous entries in the - # list of pages visited if the b-tree structure is traversed in a top-down - # fashion (each node visited before its child-tree is passed). Any overflow - # chains present are traversed from start to finish before any child-tree - # is. - # - set gap_cnt 0 - set prev 0 - db eval { - SELECT pageno, pagetype FROM temp.dbstat - WHERE name=$name - ORDER BY pageno - } { - if {$prev>0 && $pagetype=="leaf" && $pageno!=$prev+1} { - incr gap_cnt - } - set prev $pageno - } - mem eval { - INSERT INTO space_used VALUES( - $name, - $tblname, - $is_index, - $nentry, - $leaf_entries, - $depth, - $payload, - $ovfl_payload, - $ovfl_cnt, - $mx_payload, - $int_pages, - $leaf_pages, - $ovfl_pages, - $int_unused, - $leaf_unused, - $ovfl_unused, - $gap_cnt, - $compressed_size - ); - } -} - -proc integerify {real} { - if {[string is double -strict $real]} { - return [expr {wide($real)}] - } else { - return 0 - } -} -mem function int integerify - -# Quote a string for use in an SQL query. Examples: -# -# [quote {hello world}] == {'hello world'} -# [quote {hello world's}] == {'hello world''s'} -# -proc quote {txt} { - return [string map {' ''} $txt] -} - -# Output a title line -# -proc titleline {title} { - if {$title==""} { - puts [string repeat * 79] - } else { - set len [string length $title] - set stars [string repeat * [expr 79-$len-5]] - puts "*** $title $stars" - } -} - -# Generate a single line of output in the statistics section of the -# report. -# -proc statline {title value {extra {}}} { - set len [string length $title] - set dots [string repeat . [expr 50-$len]] - set len [string length $value] - set sp2 [string range { } $len end] - if {$extra ne ""} { - set extra " $extra" - } - puts "$title$dots $value$sp2$extra" -} - -# Generate a formatted percentage value for $num/$denom -# -proc percent {num denom {of {}}} { - if {$denom==0.0} {return ""} - set v [expr {$num*100.0/$denom}] - set of {} - if {$v==100.0 || $v<0.001 || ($v>1.0 && $v<99.0)} { - return [format {%5.1f%% %s} $v $of] - } elseif {$v<0.1 || $v>99.9} { - return [format {%7.3f%% %s} $v $of] - } else { - return [format {%6.2f%% %s} $v $of] - } -} - -proc divide {num denom} { - if {$denom==0} {return 0.0} - return [format %.2f [expr double($num)/double($denom)]] -} - -# Generate a subreport that covers some subset of the database. -# the $where clause determines which subset to analyze. -# -proc subreport {title where showFrag} { - global pageSize file_pgcnt compressOverhead - - # Query the in-memory database for the sum of various statistics - # for the subset of tables/indices identified by the WHERE clause in - # $where. Note that even if the WHERE clause matches no rows, the - # following query returns exactly one row (because it is an aggregate). - # - # The results of the query are stored directly by SQLite into local - # variables (i.e. $nentry, $nleaf etc.). - # - mem eval " - SELECT - int(sum(nentry)) AS nentry, - int(sum(leaf_entries)) AS nleaf, - int(sum(payload)) AS payload, - int(sum(ovfl_payload)) AS ovfl_payload, - max(mx_payload) AS mx_payload, - int(sum(ovfl_cnt)) as ovfl_cnt, - int(sum(leaf_pages)) AS leaf_pages, - int(sum(int_pages)) AS int_pages, - int(sum(ovfl_pages)) AS ovfl_pages, - int(sum(leaf_unused)) AS leaf_unused, - int(sum(int_unused)) AS int_unused, - int(sum(ovfl_unused)) AS ovfl_unused, - int(sum(gap_cnt)) AS gap_cnt, - int(sum(compressed_size)) AS compressed_size, - int(max(depth)) AS depth, - count(*) AS cnt - FROM space_used WHERE $where" {} {} - - # Output the sub-report title, nicely decorated with * characters. - # - puts "" - titleline $title - puts "" - - # Calculate statistics and store the results in TCL variables, as follows: - # - # total_pages: Database pages consumed. - # total_pages_percent: Pages consumed as a percentage of the file. - # storage: Bytes consumed. - # payload_percent: Payload bytes used as a percentage of $storage. - # total_unused: Unused bytes on pages. - # avg_payload: Average payload per btree entry. - # avg_fanout: Average fanout for internal pages. - # avg_unused: Average unused bytes per btree entry. - # ovfl_cnt_percent: Percentage of btree entries that use overflow pages. - # - set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}] - set total_pages_percent [percent $total_pages $file_pgcnt] - set storage [expr {$total_pages*$pageSize}] - set payload_percent [percent $payload $storage {of storage consumed}] - set total_unused [expr {$ovfl_unused+$int_unused+$leaf_unused}] - set avg_payload [divide $payload $nleaf] - set avg_unused [divide $total_unused $nleaf] - if {$int_pages>0} { - # TODO: Is this formula correct? - set nTab [mem eval " - SELECT count(*) FROM ( - SELECT DISTINCT tblname FROM space_used WHERE $where AND is_index=0 - ) - "] - set avg_fanout [mem eval " - SELECT (sum(leaf_pages+int_pages)-$nTab)/sum(int_pages) FROM space_used - WHERE $where - "] - set avg_fanout [format %.2f $avg_fanout] - } - set ovfl_cnt_percent [percent $ovfl_cnt $nleaf {of all entries}] - - # Print out the sub-report statistics. - # - statline {Percentage of total database} $total_pages_percent - statline {Number of entries} $nleaf - statline {Bytes of storage consumed} $storage - if {$compressed_size!=$storage} { - set compressed_size [expr {$compressed_size+$compressOverhead*$total_pages}] - set pct [expr {$compressed_size*100.0/$storage}] - set pct [format {%5.1f%%} $pct] - statline {Bytes used after compression} $compressed_size $pct - } - statline {Bytes of payload} $payload $payload_percent - if {$cnt==1} {statline {B-tree depth} $depth} - statline {Average payload per entry} $avg_payload - statline {Average unused bytes per entry} $avg_unused - if {[info exists avg_fanout]} { - statline {Average fanout} $avg_fanout - } - if {$showFrag && $total_pages>1} { - set fragmentation [percent $gap_cnt [expr {$total_pages-1}]] - statline {Non-sequential pages} $gap_cnt $fragmentation - } - statline {Maximum payload per entry} $mx_payload - statline {Entries that use overflow} $ovfl_cnt $ovfl_cnt_percent - if {$int_pages>0} { - statline {Index pages used} $int_pages - } - statline {Primary pages used} $leaf_pages - statline {Overflow pages used} $ovfl_pages - statline {Total pages used} $total_pages - if {$int_unused>0} { - set int_unused_percent [ - percent $int_unused [expr {$int_pages*$pageSize}] {of index space}] - statline "Unused bytes on index pages" $int_unused $int_unused_percent - } - statline "Unused bytes on primary pages" $leaf_unused [ - percent $leaf_unused [expr {$leaf_pages*$pageSize}] {of primary space}] - statline "Unused bytes on overflow pages" $ovfl_unused [ - percent $ovfl_unused [expr {$ovfl_pages*$pageSize}] {of overflow space}] - statline "Unused bytes on all pages" $total_unused [ - percent $total_unused $storage {of all space}] - return 1 -} - -# Calculate the overhead in pages caused by auto-vacuum. -# -# This procedure calculates and returns the number of pages used by the -# auto-vacuum 'pointer-map'. If the database does not support auto-vacuum, -# then 0 is returned. The two arguments are the size of the database file in -# pages and the page size used by the database (in bytes). -proc autovacuum_overhead {filePages pageSize} { - - # Set $autovacuum to non-zero for databases that support auto-vacuum. - set autovacuum [db one {PRAGMA auto_vacuum}] - - # If the database is not an auto-vacuum database or the file consists - # of one page only then there is no overhead for auto-vacuum. Return zero. - if {0==$autovacuum || $filePages==1} { - return 0 - } - - # The number of entries on each pointer map page. The layout of the - # database file is one pointer-map page, followed by $ptrsPerPage other - # pages, followed by a pointer-map page etc. The first pointer-map page - # is the second page of the file overall. - set ptrsPerPage [expr double($pageSize/5)] - - # Return the number of pointer map pages in the database. - return [expr wide(ceil( ($filePages-1.0)/($ptrsPerPage+1.0) ))] -} - - -# Calculate the summary statistics for the database and store the results -# in TCL variables. They are output below. Variables are as follows: -# -# pageSize: Size of each page in bytes. -# file_bytes: File size in bytes. -# file_pgcnt: Number of pages in the file. -# file_pgcnt2: Number of pages in the file (calculated). -# av_pgcnt: Pages consumed by the auto-vacuum pointer-map. -# av_percent: Percentage of the file consumed by auto-vacuum pointer-map. -# inuse_pgcnt: Data pages in the file. -# inuse_percent: Percentage of pages used to store data. -# free_pgcnt: Free pages calculated as (<total pages> - <in-use pages>) -# free_pgcnt2: Free pages in the file according to the file header. -# free_percent: Percentage of file consumed by free pages (calculated). -# free_percent2: Percentage of file consumed by free pages (header). -# ntable: Number of tables in the db. -# nindex: Number of indices in the db. -# nautoindex: Number of indices created automatically. -# nmanindex: Number of indices created manually. -# user_payload: Number of bytes of payload in table btrees -# (not including sqlite_master) -# user_percent: $user_payload as a percentage of total file size. - -### The following, setting $file_bytes based on the actual size of the file -### on disk, causes this tool to choke on zipvfs databases. So set it based -### on the return of [PRAGMA page_count] instead. -if 0 { - set file_bytes [file size $file_to_analyze] - set file_pgcnt [expr {$file_bytes/$pageSize}] -} -set file_pgcnt [db one {PRAGMA page_count}] -set file_bytes [expr {$file_pgcnt * $pageSize}] - -set av_pgcnt [autovacuum_overhead $file_pgcnt $pageSize] -set av_percent [percent $av_pgcnt $file_pgcnt] - -set sql {SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM space_used} -set inuse_pgcnt [expr wide([mem eval $sql])] -set inuse_percent [percent $inuse_pgcnt $file_pgcnt] - -set free_pgcnt [expr {$file_pgcnt-$inuse_pgcnt-$av_pgcnt}] -set free_percent [percent $free_pgcnt $file_pgcnt] -set free_pgcnt2 [db one {PRAGMA freelist_count}] -set free_percent2 [percent $free_pgcnt2 $file_pgcnt] - -set file_pgcnt2 [expr {$inuse_pgcnt+$free_pgcnt2+$av_pgcnt}] - -set ntable [db eval {SELECT count(*)+1 FROM sqlite_master WHERE type='table'}] -set nindex [db eval {SELECT count(*) FROM sqlite_master WHERE type='index'}] -set sql {SELECT count(*) FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'} -set nautoindex [db eval $sql] -set nmanindex [expr {$nindex-$nautoindex}] - -# set total_payload [mem eval "SELECT sum(payload) FROM space_used"] -set user_payload [mem one {SELECT int(sum(payload)) FROM space_used - WHERE NOT is_index AND name NOT LIKE 'sqlite_master'}] -set user_percent [percent $user_payload $file_bytes] - -# Output the summary statistics calculated above. -# -puts "/** Disk-Space Utilization Report For $root_filename" -puts "" -statline {Page size in bytes} $pageSize -statline {Pages in the whole file (measured)} $file_pgcnt -statline {Pages in the whole file (calculated)} $file_pgcnt2 -statline {Pages that store data} $inuse_pgcnt $inuse_percent -statline {Pages on the freelist (per header)} $free_pgcnt2 $free_percent2 -statline {Pages on the freelist (calculated)} $free_pgcnt $free_percent -statline {Pages of auto-vacuum overhead} $av_pgcnt $av_percent -statline {Number of tables in the database} $ntable -statline {Number of indices} $nindex -statline {Number of defined indices} $nmanindex -statline {Number of implied indices} $nautoindex -if {$isCompressed} { - statline {Size of uncompressed content in bytes} $file_bytes - set efficiency [percent $true_file_size $file_bytes] - statline {Size of compressed file on disk} $true_file_size $efficiency -} else { - statline {Size of the file in bytes} $file_bytes -} -statline {Bytes of user payload stored} $user_payload $user_percent - -# Output table rankings -# -puts "" -titleline "Page counts for all tables with their indices" -puts "" -mem eval {SELECT tblname, count(*) AS cnt, - int(sum(int_pages+leaf_pages+ovfl_pages)) AS size - FROM space_used GROUP BY tblname ORDER BY size+0 DESC, tblname} {} { - statline [string toupper $tblname] $size [percent $size $file_pgcnt] -} -puts "" -titleline "Page counts for all tables and indices separately" -puts "" -mem eval { - SELECT - upper(name) AS nm, - int(int_pages+leaf_pages+ovfl_pages) AS size - FROM space_used - ORDER BY size+0 DESC, name} {} { - statline $nm $size [percent $size $file_pgcnt] -} -if {$isCompressed} { - puts "" - titleline "Bytes of disk space used after compression" - puts "" - set csum 0 - mem eval {SELECT tblname, - int(sum(compressed_size)) + - $compressOverhead*sum(int_pages+leaf_pages+ovfl_pages) - AS csize - FROM space_used GROUP BY tblname ORDER BY csize+0 DESC, tblname} {} { - incr csum $csize - statline [string toupper $tblname] $csize [percent $csize $true_file_size] - } - set overhead [expr {$true_file_size - $csum}] - if {$overhead>0} { - statline {Header and free space} $overhead [percent $overhead $true_file_size] - } -} - -# Output subreports -# -if {$nindex>0} { - subreport {All tables and indices} 1 0 -} -subreport {All tables} {NOT is_index} 0 -if {$nindex>0} { - subreport {All indices} {is_index} 0 -} -foreach tbl [mem eval {SELECT DISTINCT tblname name FROM space_used - ORDER BY name}] { - set qn [quote $tbl] - set name [string toupper $tbl] - set n [mem eval {SELECT count(*) FROM space_used WHERE tblname=$tbl}] - if {$n>1} { - set idxlist [mem eval "SELECT name FROM space_used - WHERE tblname='$qn' AND is_index - ORDER BY 1"] - subreport "Table $name and all its indices" "tblname='$qn'" 0 - subreport "Table $name w/o any indices" "name='$qn'" 1 - if {[llength $idxlist]>1} { - subreport "Indices of table $name" "tblname='$qn' AND is_index" 0 - } - foreach idx $idxlist { - set qidx [quote $idx] - subreport "Index [string toupper $idx] of table $name" "name='$qidx'" 1 - } - } else { - subreport "Table $name" "name='$qn'" 1 - } -} - -# Output instructions on what the numbers above mean. -# -puts "" -titleline Definitions -puts { -Page size in bytes - - The number of bytes in a single page of the database file. - Usually 1024. - -Number of pages in the whole file -} -puts " The number of $pageSize-byte pages that go into forming the complete - database" -puts { -Pages that store data - - The number of pages that store data, either as primary B*Tree pages or - as overflow pages. The number at the right is the data pages divided by - the total number of pages in the file. - -Pages on the freelist - - The number of pages that are not currently in use but are reserved for - future use. The percentage at the right is the number of freelist pages - divided by the total number of pages in the file. - -Pages of auto-vacuum overhead - - The number of pages that store data used by the database to facilitate - auto-vacuum. This is zero for databases that do not support auto-vacuum. - -Number of tables in the database - - The number of tables in the database, including the SQLITE_MASTER table - used to store schema information. - -Number of indices - - The total number of indices in the database. - -Number of defined indices - - The number of indices created using an explicit CREATE INDEX statement. - -Number of implied indices - - The number of indices used to implement PRIMARY KEY or UNIQUE constraints - on tables. - -Size of the file in bytes - - The total amount of disk space used by the entire database files. - -Bytes of user payload stored - - The total number of bytes of user payload stored in the database. The - schema information in the SQLITE_MASTER table is not counted when - computing this number. The percentage at the right shows the payload - divided by the total file size. - -Percentage of total database - - The amount of the complete database file that is devoted to storing - information described by this category. - -Number of entries - - The total number of B-Tree key/value pairs stored under this category. - -Bytes of storage consumed - - The total amount of disk space required to store all B-Tree entries - under this category. The is the total number of pages used times - the pages size. - -Bytes of payload - - The amount of payload stored under this category. Payload is the data - part of table entries and the key part of index entries. The percentage - at the right is the bytes of payload divided by the bytes of storage - consumed. - -Average payload per entry - - The average amount of payload on each entry. This is just the bytes of - payload divided by the number of entries. - -Average unused bytes per entry - - The average amount of free space remaining on all pages under this - category on a per-entry basis. This is the number of unused bytes on - all pages divided by the number of entries. - -Non-sequential pages - - The number of pages in the table or index that are out of sequence. - Many filesystems are optimized for sequential file access so a small - number of non-sequential pages might result in faster queries, - especially for larger database files that do not fit in the disk cache. - Note that after running VACUUM, the root page of each table or index is - at the beginning of the database file and all other pages are in a - separate part of the database file, resulting in a single non- - sequential page. - -Maximum payload per entry - - The largest payload size of any entry. - -Entries that use overflow - - The number of entries that user one or more overflow pages. - -Total pages used - - This is the number of pages used to hold all information in the current - category. This is the sum of index, primary, and overflow pages. - -Index pages used - - This is the number of pages in a table B-tree that hold only key (rowid) - information and no data. - -Primary pages used - - This is the number of B-tree pages that hold both key and data. - -Overflow pages used - - The total number of overflow pages used for this category. - -Unused bytes on index pages - - The total number of bytes of unused space on all index pages. The - percentage at the right is the number of unused bytes divided by the - total number of bytes on index pages. - -Unused bytes on primary pages - - The total number of bytes of unused space on all primary pages. The - percentage at the right is the number of unused bytes divided by the - total number of bytes on primary pages. - -Unused bytes on overflow pages - - The total number of bytes of unused space on all overflow pages. The - percentage at the right is the number of unused bytes divided by the - total number of bytes on overflow pages. - -Unused bytes on all pages - - The total number of bytes of unused space on all primary and overflow - pages. The percentage at the right is the number of unused bytes - divided by the total number of bytes. -} - -# Output a dump of the in-memory database. This can be used for more -# complex offline analysis. -# -titleline {} -puts "The entire text of this report can be sourced into any SQL database" -puts "engine for further analysis. All of the text above is an SQL comment." -puts "The data used to generate this report follows:" -puts "*/" -puts "BEGIN;" -puts $tabledef -unset -nocomplain x -mem eval {SELECT * FROM space_used} x { - puts -nonewline "INSERT INTO space_used VALUES" - set sep ( - foreach col $x(*) { - set v $x($col) - if {$v=="" || ![string is double $v]} {set v '[quote $v]'} - puts -nonewline $sep$v - set sep , - } - puts ");" -} -puts "COMMIT;" - -} err]} { - puts "ERROR: $err" - puts $errorInfo - exit 1 -} diff --git a/lib/libsqlite3/tool/speedtest.tcl b/lib/libsqlite3/tool/speedtest.tcl deleted file mode 100644 index ef39dc5461d..00000000000 --- a/lib/libsqlite3/tool/speedtest.tcl +++ /dev/null @@ -1,275 +0,0 @@ -#!/usr/bin/tclsh -# -# Run this script using TCLSH to do a speed comparison between -# various versions of SQLite and PostgreSQL and MySQL -# - -# Run a test -# -set cnt 1 -proc runtest {title} { - global cnt - set sqlfile test$cnt.sql - puts "<h2>Test $cnt: $title</h2>" - incr cnt - set fd [open $sqlfile r] - set sql [string trim [read $fd [file size $sqlfile]]] - close $fd - set sx [split $sql \n] - set n [llength $sx] - if {$n>8} { - set sql {} - for {set i 0} {$i<3} {incr i} {append sql [lindex $sx $i]<br>\n} - append sql "<i>... [expr {$n-6}] lines omitted</i><br>\n" - for {set i [expr {$n-3}]} {$i<$n} {incr i} { - append sql [lindex $sx $i]<br>\n - } - } else { - regsub -all \n [string trim $sql] <br> sql - } - puts "<blockquote>" - puts "$sql" - puts "</blockquote><table border=0 cellpadding=0 cellspacing=0>" - set format {<tr><td>%s</td><td align="right"> %.3f</td></tr>} - set delay 1000 -# exec sync; after $delay; -# set t [time "exec psql drh <$sqlfile" 1] -# set t [expr {[lindex $t 0]/1000000.0}] -# puts [format $format PostgreSQL: $t] - exec sync; after $delay; - set t [time "exec mysql -f drh <$sqlfile" 1] - set t [expr {[lindex $t 0]/1000000.0}] - puts [format $format MySQL: $t] -# set t [time "exec ./sqlite232 s232.db <$sqlfile" 1] -# set t [expr {[lindex $t 0]/1000000.0}] -# puts [format $format {SQLite 2.3.2:} $t] -# set t [time "exec ./sqlite-100 s100.db <$sqlfile" 1] -# set t [expr {[lindex $t 0]/1000000.0}] -# puts [format $format {SQLite 2.4 (cache=100):} $t] - exec sync; after $delay; - set t [time "exec ./sqlite248 s2k.db <$sqlfile" 1] - set t [expr {[lindex $t 0]/1000000.0}] - puts [format $format {SQLite 2.4.8:} $t] - exec sync; after $delay; - set t [time "exec ./sqlite248 sns.db <$sqlfile" 1] - set t [expr {[lindex $t 0]/1000000.0}] - puts [format $format {SQLite 2.4.8 (nosync):} $t] - exec sync; after $delay; - set t [time "exec ./sqlite2412 s2kb.db <$sqlfile" 1] - set t [expr {[lindex $t 0]/1000000.0}] - puts [format $format {SQLite 2.4.12:} $t] - exec sync; after $delay; - set t [time "exec ./sqlite2412 snsb.db <$sqlfile" 1] - set t [expr {[lindex $t 0]/1000000.0}] - puts [format $format {SQLite 2.4.12 (nosync):} $t] -# set t [time "exec ./sqlite-t1 st1.db <$sqlfile" 1] -# set t [expr {[lindex $t 0]/1000000.0}] -# puts [format $format {SQLite 2.4 (test):} $t] - puts "</table>" -} - -# Initialize the environment -# -expr srand(1) -catch {exec /bin/sh -c {rm -f s*.db}} -set fd [open clear.sql w] -puts $fd { - drop table t1; - drop table t2; -} -close $fd -catch {exec psql drh <clear.sql} -catch {exec mysql drh <clear.sql} -set fd [open 2kinit.sql w] -puts $fd { - PRAGMA default_cache_size=2000; - PRAGMA default_synchronous=on; -} -close $fd -exec ./sqlite248 s2k.db <2kinit.sql -exec ./sqlite2412 s2kb.db <2kinit.sql -set fd [open nosync-init.sql w] -puts $fd { - PRAGMA default_cache_size=2000; - PRAGMA default_synchronous=off; -} -close $fd -exec ./sqlite248 sns.db <nosync-init.sql -exec ./sqlite2412 snsb.db <nosync-init.sql -set ones {zero one two three four five six seven eight nine - ten eleven twelve thirteen fourteen fifteen sixteen seventeen - eighteen nineteen} -set tens {{} ten twenty thirty forty fifty sixty seventy eighty ninety} -proc number_name {n} { - if {$n>=1000} { - set txt "[number_name [expr {$n/1000}]] thousand" - set n [expr {$n%1000}] - } else { - set txt {} - } - if {$n>=100} { - append txt " [lindex $::ones [expr {$n/100}]] hundred" - set n [expr {$n%100}] - } - if {$n>=20} { - append txt " [lindex $::tens [expr {$n/10}]]" - set n [expr {$n%10}] - } - if {$n>0} { - append txt " [lindex $::ones $n]" - } - set txt [string trim $txt] - if {$txt==""} {set txt zero} - return $txt -} - - - -set fd [open test$cnt.sql w] -puts $fd "CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));" -for {set i 1} {$i<=1000} {incr i} { - set r [expr {int(rand()*100000)}] - puts $fd "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');" -} -close $fd -runtest {1000 INSERTs} - - - -set fd [open test$cnt.sql w] -puts $fd "BEGIN;" -puts $fd "CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100));" -for {set i 1} {$i<=25000} {incr i} { - set r [expr {int(rand()*500000)}] - puts $fd "INSERT INTO t2 VALUES($i,$r,'[number_name $r]');" -} -puts $fd "COMMIT;" -close $fd -runtest {25000 INSERTs in a transaction} - - - -set fd [open test$cnt.sql w] -for {set i 0} {$i<100} {incr i} { - set lwr [expr {$i*100}] - set upr [expr {($i+10)*100}] - puts $fd "SELECT count(*), avg(b) FROM t2 WHERE b>=$lwr AND b<$upr;" -} -close $fd -runtest {100 SELECTs without an index} - - - -set fd [open test$cnt.sql w] -for {set i 1} {$i<=100} {incr i} { - puts $fd "SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%[number_name $i]%';" -} -close $fd -runtest {100 SELECTs on a string comparison} - - - -set fd [open test$cnt.sql w] -puts $fd {CREATE INDEX i2a ON t2(a);} -puts $fd {CREATE INDEX i2b ON t2(b);} -close $fd -runtest {Creating an index} - - - -set fd [open test$cnt.sql w] -for {set i 0} {$i<5000} {incr i} { - set lwr [expr {$i*100}] - set upr [expr {($i+1)*100}] - puts $fd "SELECT count(*), avg(b) FROM t2 WHERE b>=$lwr AND b<$upr;" -} -close $fd -runtest {5000 SELECTs with an index} - - - -set fd [open test$cnt.sql w] -puts $fd "BEGIN;" -for {set i 0} {$i<1000} {incr i} { - set lwr [expr {$i*10}] - set upr [expr {($i+1)*10}] - puts $fd "UPDATE t1 SET b=b*2 WHERE a>=$lwr AND a<$upr;" -} -puts $fd "COMMIT;" -close $fd -runtest {1000 UPDATEs without an index} - - - -set fd [open test$cnt.sql w] -puts $fd "BEGIN;" -for {set i 1} {$i<=25000} {incr i} { - set r [expr {int(rand()*500000)}] - puts $fd "UPDATE t2 SET b=$r WHERE a=$i;" -} -puts $fd "COMMIT;" -close $fd -runtest {25000 UPDATEs with an index} - - -set fd [open test$cnt.sql w] -puts $fd "BEGIN;" -for {set i 1} {$i<=25000} {incr i} { - set r [expr {int(rand()*500000)}] - puts $fd "UPDATE t2 SET c='[number_name $r]' WHERE a=$i;" -} -puts $fd "COMMIT;" -close $fd -runtest {25000 text UPDATEs with an index} - - - -set fd [open test$cnt.sql w] -puts $fd "BEGIN;" -puts $fd "INSERT INTO t1 SELECT * FROM t2;" -puts $fd "INSERT INTO t2 SELECT * FROM t1;" -puts $fd "COMMIT;" -close $fd -runtest {INSERTs from a SELECT} - - - -set fd [open test$cnt.sql w] -puts $fd {DELETE FROM t2 WHERE c LIKE '%fifty%';} -close $fd -runtest {DELETE without an index} - - - -set fd [open test$cnt.sql w] -puts $fd {DELETE FROM t2 WHERE a>10 AND a<20000;} -close $fd -runtest {DELETE with an index} - - - -set fd [open test$cnt.sql w] -puts $fd {INSERT INTO t2 SELECT * FROM t1;} -close $fd -runtest {A big INSERT after a big DELETE} - - - -set fd [open test$cnt.sql w] -puts $fd {BEGIN;} -puts $fd {DELETE FROM t1;} -for {set i 1} {$i<=3000} {incr i} { - set r [expr {int(rand()*100000)}] - puts $fd "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');" -} -puts $fd {COMMIT;} -close $fd -runtest {A big DELETE followed by many small INSERTs} - - - -set fd [open test$cnt.sql w] -puts $fd {DROP TABLE t1;} -puts $fd {DROP TABLE t2;} -close $fd -runtest {DROP TABLE} diff --git a/lib/libsqlite3/tool/speedtest16.c b/lib/libsqlite3/tool/speedtest16.c deleted file mode 100644 index e81f1a6dba0..00000000000 --- a/lib/libsqlite3/tool/speedtest16.c +++ /dev/null @@ -1,169 +0,0 @@ -/* -** Performance test for SQLite. -** -** This program reads ASCII text from a file named on the command-line. -** It converts each SQL statement into UTF16 and submits it to SQLite -** for evaluation. A new UTF16 database is created at the beginning of -** the program. All statements are timed using the high-resolution timer -** built into Intel-class processors. -** -** To compile this program, first compile the SQLite library separately -** will full optimizations. For example: -** -** gcc -c -O6 -DSQLITE_THREADSAFE=0 sqlite3.c -** -** Then link against this program. But to do optimize this program -** because that defeats the hi-res timer. -** -** gcc speedtest16.c sqlite3.o -ldl -I../src -** -** Then run this program with a single argument which is the name of -** a file containing SQL script that you want to test: -** -** ./a.out database.db test.sql -*/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <unistd.h> -#include "sqlite3.h" - -/* -** hwtime.h contains inline assembler code for implementing -** high-performance timing routines. -*/ -#include "hwtime.h" - -/* -** Convert a zero-terminated ASCII string into a zero-terminated -** UTF-16le string. Memory to hold the returned string comes -** from malloc() and should be freed by the caller. -*/ -static void *asciiToUtf16le(const char *z){ - int n = strlen(z); - char *z16; - int i, j; - - z16 = malloc( n*2 + 2 ); - for(i=j=0; i<=n; i++){ - z16[j++] = z[i]; - z16[j++] = 0; - } - return (void*)z16; -} - -/* -** Timers -*/ -static sqlite_uint64 prepTime = 0; -static sqlite_uint64 runTime = 0; -static sqlite_uint64 finalizeTime = 0; - -/* -** Prepare and run a single statement of SQL. -*/ -static void prepareAndRun(sqlite3 *db, const char *zSql){ - void *utf16; - sqlite3_stmt *pStmt; - const void *stmtTail; - sqlite_uint64 iStart, iElapse; - int rc; - - printf("****************************************************************\n"); - printf("SQL statement: [%s]\n", zSql); - utf16 = asciiToUtf16le(zSql); - iStart = sqlite3Hwtime(); - rc = sqlite3_prepare16_v2(db, utf16, -1, &pStmt, &stmtTail); - iElapse = sqlite3Hwtime() - iStart; - prepTime += iElapse; - printf("sqlite3_prepare16_v2() returns %d in %llu cycles\n", rc, iElapse); - if( rc==SQLITE_OK ){ - int nRow = 0; - iStart = sqlite3Hwtime(); - while( (rc=sqlite3_step(pStmt))==SQLITE_ROW ){ nRow++; } - iElapse = sqlite3Hwtime() - iStart; - runTime += iElapse; - printf("sqlite3_step() returns %d after %d rows in %llu cycles\n", - rc, nRow, iElapse); - iStart = sqlite3Hwtime(); - rc = sqlite3_finalize(pStmt); - iElapse = sqlite3Hwtime() - iStart; - finalizeTime += iElapse; - printf("sqlite3_finalize() returns %d in %llu cycles\n", rc, iElapse); - } - free(utf16); -} - -int main(int argc, char **argv){ - void *utf16; - sqlite3 *db; - int rc; - int nSql; - char *zSql; - int i, j; - FILE *in; - sqlite_uint64 iStart, iElapse; - sqlite_uint64 iSetup = 0; - int nStmt = 0; - int nByte = 0; - - if( argc!=3 ){ - fprintf(stderr, "Usage: %s FILENAME SQL-SCRIPT\n" - "Runs SQL-SCRIPT as UTF16 against a UTF16 database\n", - argv[0]); - exit(1); - } - in = fopen(argv[2], "r"); - fseek(in, 0L, SEEK_END); - nSql = ftell(in); - zSql = malloc( nSql+1 ); - fseek(in, 0L, SEEK_SET); - nSql = fread(zSql, 1, nSql, in); - zSql[nSql] = 0; - - printf("SQLite version: %d\n", sqlite3_libversion_number()); - unlink(argv[1]); - utf16 = asciiToUtf16le(argv[1]); - iStart = sqlite3Hwtime(); - rc = sqlite3_open16(utf16, &db); - iElapse = sqlite3Hwtime() - iStart; - iSetup = iElapse; - printf("sqlite3_open16() returns %d in %llu cycles\n", rc, iElapse); - free(utf16); - for(i=j=0; j<nSql; j++){ - if( zSql[j]==';' ){ - int isComplete; - char c = zSql[j+1]; - zSql[j+1] = 0; - isComplete = sqlite3_complete(&zSql[i]); - zSql[j+1] = c; - if( isComplete ){ - zSql[j] = 0; - while( i<j && isspace(zSql[i]) ){ i++; } - if( i<j ){ - nStmt++; - nByte += j-i; - prepareAndRun(db, &zSql[i]); - } - zSql[j] = ';'; - i = j+1; - } - } - } - iStart = sqlite3Hwtime(); - sqlite3_close(db); - iElapse = sqlite3Hwtime() - iStart; - iSetup += iElapse; - printf("sqlite3_close() returns in %llu cycles\n", iElapse); - printf("\n"); - printf("Statements run: %15d\n", nStmt); - printf("Bytes of SQL text: %15d\n", nByte); - printf("Total prepare time: %15llu cycles\n", prepTime); - printf("Total run time: %15llu cycles\n", runTime); - printf("Total finalize time: %15llu cycles\n", finalizeTime); - printf("Open/Close time: %15llu cycles\n", iSetup); - printf("Total Time: %15llu cycles\n", - prepTime + runTime + finalizeTime + iSetup); - return 0; -} diff --git a/lib/libsqlite3/tool/speedtest2.tcl b/lib/libsqlite3/tool/speedtest2.tcl deleted file mode 100644 index 4fd632d4c7c..00000000000 --- a/lib/libsqlite3/tool/speedtest2.tcl +++ /dev/null @@ -1,207 +0,0 @@ -#!/usr/bin/tclsh -# -# Run this script using TCLSH to do a speed comparison between -# various versions of SQLite and PostgreSQL and MySQL -# - -# Run a test -# -set cnt 1 -proc runtest {title} { - global cnt - set sqlfile test$cnt.sql - puts "<h2>Test $cnt: $title</h2>" - incr cnt - set fd [open $sqlfile r] - set sql [string trim [read $fd [file size $sqlfile]]] - close $fd - set sx [split $sql \n] - set n [llength $sx] - if {$n>8} { - set sql {} - for {set i 0} {$i<3} {incr i} {append sql [lindex $sx $i]<br>\n} - append sql "<i>... [expr {$n-6}] lines omitted</i><br>\n" - for {set i [expr {$n-3}]} {$i<$n} {incr i} { - append sql [lindex $sx $i]<br>\n - } - } else { - regsub -all \n [string trim $sql] <br> sql - } - puts "<blockquote>" - puts "$sql" - puts "</blockquote><table border=0 cellpadding=0 cellspacing=0>" - set format {<tr><td>%s</td><td align="right"> %.3f</td></tr>} - set delay 1000 - exec sync; after $delay; - set t [time "exec psql drh <$sqlfile" 1] - set t [expr {[lindex $t 0]/1000000.0}] - puts [format $format PostgreSQL: $t] - exec sync; after $delay; - set t [time "exec mysql -f drh <$sqlfile" 1] - set t [expr {[lindex $t 0]/1000000.0}] - puts [format $format MySQL: $t] -# set t [time "exec ./sqlite232 s232.db <$sqlfile" 1] -# set t [expr {[lindex $t 0]/1000000.0}] -# puts [format $format {SQLite 2.3.2:} $t] -# set t [time "exec ./sqlite-100 s100.db <$sqlfile" 1] -# set t [expr {[lindex $t 0]/1000000.0}] -# puts [format $format {SQLite 2.4 (cache=100):} $t] - exec sync; after $delay; - set t [time "exec ./sqlite240 s2k.db <$sqlfile" 1] - set t [expr {[lindex $t 0]/1000000.0}] - puts [format $format {SQLite 2.4:} $t] - exec sync; after $delay; - set t [time "exec ./sqlite240 sns.db <$sqlfile" 1] - set t [expr {[lindex $t 0]/1000000.0}] - puts [format $format {SQLite 2.4 (nosync):} $t] -# set t [time "exec ./sqlite-t1 st1.db <$sqlfile" 1] -# set t [expr {[lindex $t 0]/1000000.0}] -# puts [format $format {SQLite 2.4 (test):} $t] - puts "</table>" -} - -# Initialize the environment -# -expr srand(1) -catch {exec /bin/sh -c {rm -f s*.db}} -set fd [open clear.sql w] -puts $fd { - drop table t1; - drop table t2; -} -close $fd -catch {exec psql drh <clear.sql} -catch {exec mysql drh <clear.sql} -set fd [open 2kinit.sql w] -puts $fd { - PRAGMA default_cache_size=2000; - PRAGMA default_synchronous=on; -} -close $fd -exec ./sqlite240 s2k.db <2kinit.sql -exec ./sqlite-t1 st1.db <2kinit.sql -set fd [open nosync-init.sql w] -puts $fd { - PRAGMA default_cache_size=2000; - PRAGMA default_synchronous=off; -} -close $fd -exec ./sqlite240 sns.db <nosync-init.sql -set ones {zero one two three four five six seven eight nine - ten eleven twelve thirteen fourteen fifteen sixteen seventeen - eighteen nineteen} -set tens {{} ten twenty thirty forty fifty sixty seventy eighty ninety} -proc number_name {n} { - if {$n>=1000} { - set txt "[number_name [expr {$n/1000}]] thousand" - set n [expr {$n%1000}] - } else { - set txt {} - } - if {$n>=100} { - append txt " [lindex $::ones [expr {$n/100}]] hundred" - set n [expr {$n%100}] - } - if {$n>=20} { - append txt " [lindex $::tens [expr {$n/10}]]" - set n [expr {$n%10}] - } - if {$n>0} { - append txt " [lindex $::ones $n]" - } - set txt [string trim $txt] - if {$txt==""} {set txt zero} - return $txt -} - - -set fd [open test$cnt.sql w] -puts $fd "BEGIN;" -puts $fd "CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));" -for {set i 1} {$i<=25000} {incr i} { - set r [expr {int(rand()*500000)}] - puts $fd "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');" -} -puts $fd "COMMIT;" -close $fd -runtest {25000 INSERTs in a transaction} - - -set fd [open test$cnt.sql w] -puts $fd "DELETE FROM t1;" -close $fd -runtest {DELETE everything} - - -set fd [open test$cnt.sql w] -puts $fd "BEGIN;" -for {set i 1} {$i<=25000} {incr i} { - set r [expr {int(rand()*500000)}] - puts $fd "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');" -} -puts $fd "COMMIT;" -close $fd -runtest {25000 INSERTs in a transaction} - - -set fd [open test$cnt.sql w] -puts $fd "DELETE FROM t1;" -close $fd -runtest {DELETE everything} - - -set fd [open test$cnt.sql w] -puts $fd "BEGIN;" -for {set i 1} {$i<=25000} {incr i} { - set r [expr {int(rand()*500000)}] - puts $fd "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');" -} -puts $fd "COMMIT;" -close $fd -runtest {25000 INSERTs in a transaction} - - -set fd [open test$cnt.sql w] -puts $fd "DELETE FROM t1;" -close $fd -runtest {DELETE everything} - - -set fd [open test$cnt.sql w] -puts $fd "BEGIN;" -for {set i 1} {$i<=25000} {incr i} { - set r [expr {int(rand()*500000)}] - puts $fd "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');" -} -puts $fd "COMMIT;" -close $fd -runtest {25000 INSERTs in a transaction} - - -set fd [open test$cnt.sql w] -puts $fd "DELETE FROM t1;" -close $fd -runtest {DELETE everything} - - -set fd [open test$cnt.sql w] -puts $fd "BEGIN;" -for {set i 1} {$i<=25000} {incr i} { - set r [expr {int(rand()*500000)}] - puts $fd "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');" -} -puts $fd "COMMIT;" -close $fd -runtest {25000 INSERTs in a transaction} - - -set fd [open test$cnt.sql w] -puts $fd "DELETE FROM t1;" -close $fd -runtest {DELETE everything} - - -set fd [open test$cnt.sql w] -puts $fd {DROP TABLE t1;} -close $fd -runtest {DROP TABLE} diff --git a/lib/libsqlite3/tool/speedtest8.c b/lib/libsqlite3/tool/speedtest8.c deleted file mode 100644 index 051fc898196..00000000000 --- a/lib/libsqlite3/tool/speedtest8.c +++ /dev/null @@ -1,260 +0,0 @@ -/* -** Performance test for SQLite. -** -** This program reads ASCII text from a file named on the command-line -** and submits that text to SQLite for evaluation. A new database -** is created at the beginning of the program. All statements are -** timed using the high-resolution timer built into Intel-class processors. -** -** To compile this program, first compile the SQLite library separately -** will full optimizations. For example: -** -** gcc -c -O6 -DSQLITE_THREADSAFE=0 sqlite3.c -** -** Then link against this program. But to do optimize this program -** because that defeats the hi-res timer. -** -** gcc speedtest8.c sqlite3.o -ldl -I../src -** -** Then run this program with a single argument which is the name of -** a file containing SQL script that you want to test: -** -** ./a.out test.db test.sql -*/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <time.h> - -#if defined(_MSC_VER) -#include <windows.h> -#else -#include <unistd.h> -#include <sys/times.h> -#include <sched.h> -#endif - -#include "sqlite3.h" - -/* -** hwtime.h contains inline assembler code for implementing -** high-performance timing routines. -*/ -#include "hwtime.h" - -/* -** Timers -*/ -static sqlite_uint64 prepTime = 0; -static sqlite_uint64 runTime = 0; -static sqlite_uint64 finalizeTime = 0; - -/* -** Prepare and run a single statement of SQL. -*/ -static void prepareAndRun(sqlite3 *db, const char *zSql, int bQuiet){ - sqlite3_stmt *pStmt; - const char *stmtTail; - sqlite_uint64 iStart, iElapse; - int rc; - - if (!bQuiet){ - printf("***************************************************************\n"); - } - if (!bQuiet) printf("SQL statement: [%s]\n", zSql); - iStart = sqlite3Hwtime(); - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &stmtTail); - iElapse = sqlite3Hwtime() - iStart; - prepTime += iElapse; - if (!bQuiet){ - printf("sqlite3_prepare_v2() returns %d in %llu cycles\n", rc, iElapse); - } - if( rc==SQLITE_OK ){ - int nRow = 0; - iStart = sqlite3Hwtime(); - while( (rc=sqlite3_step(pStmt))==SQLITE_ROW ){ nRow++; } - iElapse = sqlite3Hwtime() - iStart; - runTime += iElapse; - if (!bQuiet){ - printf("sqlite3_step() returns %d after %d rows in %llu cycles\n", - rc, nRow, iElapse); - } - iStart = sqlite3Hwtime(); - rc = sqlite3_finalize(pStmt); - iElapse = sqlite3Hwtime() - iStart; - finalizeTime += iElapse; - if (!bQuiet){ - printf("sqlite3_finalize() returns %d in %llu cycles\n", rc, iElapse); - } - } -} - -int main(int argc, char **argv){ - sqlite3 *db; - int rc; - int nSql; - char *zSql; - int i, j; - FILE *in; - sqlite_uint64 iStart, iElapse; - sqlite_uint64 iSetup = 0; - int nStmt = 0; - int nByte = 0; - const char *zArgv0 = argv[0]; - int bQuiet = 0; -#if !defined(_MSC_VER) - struct tms tmsStart, tmsEnd; - clock_t clkStart, clkEnd; -#endif - -#ifdef HAVE_OSINST - extern sqlite3_vfs *sqlite3_instvfs_binarylog(char *, char *, char *); - extern void sqlite3_instvfs_destroy(sqlite3_vfs *); - sqlite3_vfs *pVfs = 0; -#endif - - while (argc>3) - { -#ifdef HAVE_OSINST - if( argc>4 && (strcmp(argv[1], "-log")==0) ){ - pVfs = sqlite3_instvfs_binarylog("oslog", 0, argv[2]); - sqlite3_vfs_register(pVfs, 1); - argv += 2; - argc -= 2; - continue; - } -#endif - - /* - ** Increasing the priority slightly above normal can help with - ** repeatability of testing. Note that with Cygwin, -5 equates - ** to "High", +5 equates to "Low", and anything in between - ** equates to "Normal". - */ - if( argc>4 && (strcmp(argv[1], "-priority")==0) ){ -#if defined(_MSC_VER) - int new_priority = atoi(argv[2]); - if(!SetPriorityClass(GetCurrentProcess(), - (new_priority<=-5) ? HIGH_PRIORITY_CLASS : - (new_priority<=0) ? ABOVE_NORMAL_PRIORITY_CLASS : - (new_priority==0) ? NORMAL_PRIORITY_CLASS : - (new_priority<5) ? BELOW_NORMAL_PRIORITY_CLASS : - IDLE_PRIORITY_CLASS)){ - printf ("error setting priority\n"); - exit(2); - } -#else - struct sched_param myParam; - sched_getparam(0, &myParam); - printf ("Current process priority is %d.\n", (int)myParam.sched_priority); - myParam.sched_priority = atoi(argv[2]); - printf ("Setting process priority to %d.\n", (int)myParam.sched_priority); - if (sched_setparam (0, &myParam) != 0){ - printf ("error setting priority\n"); - exit(2); - } -#endif - argv += 2; - argc -= 2; - continue; - } - - if( argc>3 && strcmp(argv[1], "-quiet")==0 ){ - bQuiet = -1; - argv++; - argc--; - continue; - } - - break; - } - - if( argc!=3 ){ - fprintf(stderr, "Usage: %s [options] FILENAME SQL-SCRIPT\n" - "Runs SQL-SCRIPT against a UTF8 database\n" - "\toptions:\n" -#ifdef HAVE_OSINST - "\t-log <log>\n" -#endif - "\t-priority <value> : set priority of task\n" - "\t-quiet : only display summary results\n", - zArgv0); - exit(1); - } - - in = fopen(argv[2], "r"); - fseek(in, 0L, SEEK_END); - nSql = ftell(in); - zSql = malloc( nSql+1 ); - fseek(in, 0L, SEEK_SET); - nSql = fread(zSql, 1, nSql, in); - zSql[nSql] = 0; - - printf("SQLite version: %d\n", sqlite3_libversion_number()); - unlink(argv[1]); -#if !defined(_MSC_VER) - clkStart = times(&tmsStart); -#endif - iStart = sqlite3Hwtime(); - rc = sqlite3_open(argv[1], &db); - iElapse = sqlite3Hwtime() - iStart; - iSetup = iElapse; - if (!bQuiet) printf("sqlite3_open() returns %d in %llu cycles\n", rc, iElapse); - for(i=j=0; j<nSql; j++){ - if( zSql[j]==';' ){ - int isComplete; - char c = zSql[j+1]; - zSql[j+1] = 0; - isComplete = sqlite3_complete(&zSql[i]); - zSql[j+1] = c; - if( isComplete ){ - zSql[j] = 0; - while( i<j && isspace(zSql[i]) ){ i++; } - if( i<j ){ - int n = j - i; - if( n>=6 && memcmp(&zSql[i], ".crash",6)==0 ) exit(1); - nStmt++; - nByte += n; - prepareAndRun(db, &zSql[i], bQuiet); - } - zSql[j] = ';'; - i = j+1; - } - } - } - iStart = sqlite3Hwtime(); - sqlite3_close(db); - iElapse = sqlite3Hwtime() - iStart; -#if !defined(_MSC_VER) - clkEnd = times(&tmsEnd); -#endif - iSetup += iElapse; - if (!bQuiet) printf("sqlite3_close() returns in %llu cycles\n", iElapse); - - printf("\n"); - printf("Statements run: %15d stmts\n", nStmt); - printf("Bytes of SQL text: %15d bytes\n", nByte); - printf("Total prepare time: %15llu cycles\n", prepTime); - printf("Total run time: %15llu cycles\n", runTime); - printf("Total finalize time: %15llu cycles\n", finalizeTime); - printf("Open/Close time: %15llu cycles\n", iSetup); - printf("Total time: %15llu cycles\n", - prepTime + runTime + finalizeTime + iSetup); - -#if !defined(_MSC_VER) - printf("\n"); - printf("Total user CPU time: %15.3g secs\n", (tmsEnd.tms_utime - tmsStart.tms_utime)/(double)CLOCKS_PER_SEC ); - printf("Total system CPU time: %15.3g secs\n", (tmsEnd.tms_stime - tmsStart.tms_stime)/(double)CLOCKS_PER_SEC ); - printf("Total real time: %15.3g secs\n", (clkEnd -clkStart)/(double)CLOCKS_PER_SEC ); -#endif - -#ifdef HAVE_OSINST - if( pVfs ){ - sqlite3_instvfs_destroy(pVfs); - printf("vfs log written to %s\n", argv[0]); - } -#endif - - return 0; -} diff --git a/lib/libsqlite3/tool/speedtest8inst1.c b/lib/libsqlite3/tool/speedtest8inst1.c deleted file mode 100644 index f0cb544c81e..00000000000 --- a/lib/libsqlite3/tool/speedtest8inst1.c +++ /dev/null @@ -1,216 +0,0 @@ -/* -** Performance test for SQLite. -** -** This program reads ASCII text from a file named on the command-line -** and submits that text to SQLite for evaluation. A new database -** is created at the beginning of the program. All statements are -** timed using the high-resolution timer built into Intel-class processors. -** -** To compile this program, first compile the SQLite library separately -** will full optimizations. For example: -** -** gcc -c -O6 -DSQLITE_THREADSAFE=0 sqlite3.c -** -** Then link against this program. But to do optimize this program -** because that defeats the hi-res timer. -** -** gcc speedtest8.c sqlite3.o -ldl -I../src -** -** Then run this program with a single argument which is the name of -** a file containing SQL script that you want to test: -** -** ./a.out test.db test.sql -*/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <unistd.h> -#include <stdarg.h> -#include "sqlite3.h" - -#include "test_osinst.c" - -/* -** Prepare and run a single statement of SQL. -*/ -static void prepareAndRun(sqlite3_vfs *pInstVfs, sqlite3 *db, const char *zSql){ - sqlite3_stmt *pStmt; - const char *stmtTail; - int rc; - char zMessage[1024]; - zMessage[1023] = '\0'; - - sqlite3_uint64 iTime; - - sqlite3_snprintf(1023, zMessage, "sqlite3_prepare_v2: %s", zSql); - sqlite3_instvfs_binarylog_marker(pInstVfs, zMessage); - - iTime = sqlite3Hwtime(); - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &stmtTail); - iTime = sqlite3Hwtime() - iTime; - sqlite3_instvfs_binarylog_call(pInstVfs,BINARYLOG_PREPARE_V2,iTime,rc,zSql); - - if( rc==SQLITE_OK ){ - int nRow = 0; - - sqlite3_snprintf(1023, zMessage, "sqlite3_step loop: %s", zSql); - sqlite3_instvfs_binarylog_marker(pInstVfs, zMessage); - iTime = sqlite3Hwtime(); - while( (rc=sqlite3_step(pStmt))==SQLITE_ROW ){ nRow++; } - iTime = sqlite3Hwtime() - iTime; - sqlite3_instvfs_binarylog_call(pInstVfs, BINARYLOG_STEP, iTime, rc, zSql); - - sqlite3_snprintf(1023, zMessage, "sqlite3_finalize: %s", zSql); - sqlite3_instvfs_binarylog_marker(pInstVfs, zMessage); - iTime = sqlite3Hwtime(); - rc = sqlite3_finalize(pStmt); - iTime = sqlite3Hwtime() - iTime; - sqlite3_instvfs_binarylog_call(pInstVfs, BINARYLOG_FINALIZE, iTime, rc, zSql); - } -} - -static int stringcompare(const char *zLeft, const char *zRight){ - int ii; - for(ii=0; zLeft[ii] && zRight[ii]; ii++){ - if( zLeft[ii]!=zRight[ii] ) return 0; - } - return( zLeft[ii]==zRight[ii] ); -} - -static char *readScriptFile(const char *zFile, int *pnScript){ - sqlite3_vfs *pVfs = sqlite3_vfs_find(0); - sqlite3_file *p; - int rc; - sqlite3_int64 nByte; - char *zData = 0; - int flags = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_DB; - - p = (sqlite3_file *)malloc(pVfs->szOsFile); - rc = pVfs->xOpen(pVfs, zFile, p, flags, &flags); - if( rc!=SQLITE_OK ){ - goto error_out; - } - - rc = p->pMethods->xFileSize(p, &nByte); - if( rc!=SQLITE_OK ){ - goto close_out; - } - - zData = (char *)malloc(nByte+1); - rc = p->pMethods->xRead(p, zData, nByte, 0); - if( rc!=SQLITE_OK ){ - goto close_out; - } - zData[nByte] = '\0'; - - p->pMethods->xClose(p); - free(p); - *pnScript = nByte; - return zData; - -close_out: - p->pMethods->xClose(p); - -error_out: - free(p); - free(zData); - return 0; -} - -int main(int argc, char **argv){ - - const char zUsageMsg[] = - "Usage: %s options...\n" - " where available options are:\n" - "\n" - " -db DATABASE-FILE (database file to operate on)\n" - " -script SCRIPT-FILE (script file to read sql from)\n" - " -log LOG-FILE (log file to create)\n" - " -logdata (log all data to log file)\n" - "\n" - " Options -db, -script and -log are compulsory\n" - "\n" - ; - - const char *zDb = 0; - const char *zScript = 0; - const char *zLog = 0; - int logdata = 0; - - int ii; - int i, j; - int rc; - - sqlite3_vfs *pInstVfs; /* Instrumentation VFS */ - - char *zSql = 0; - int nSql; - - sqlite3 *db; - - for(ii=1; ii<argc; ii++){ - if( stringcompare("-db", argv[ii]) && (ii+1)<argc ){ - zDb = argv[++ii]; - } - - else if( stringcompare("-script", argv[ii]) && (ii+1)<argc ){ - zScript = argv[++ii]; - } - - else if( stringcompare("-log", argv[ii]) && (ii+1)<argc ){ - zLog = argv[++ii]; - } - - else if( stringcompare("-logdata", argv[ii]) ){ - logdata = 1; - } - - else { - goto usage; - } - } - if( !zDb || !zScript || !zLog ) goto usage; - - zSql = readScriptFile(zScript, &nSql); - if( !zSql ){ - fprintf(stderr, "Failed to read script file\n"); - return -1; - } - - pInstVfs = sqlite3_instvfs_binarylog("logging", 0, zLog, logdata); - - rc = sqlite3_open_v2( - zDb, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "logging" - ); - if( rc!=SQLITE_OK ){ - fprintf(stderr, "Failed to open db: %s\n", sqlite3_errmsg(db)); - return -2; - } - - for(i=j=0; j<nSql; j++){ - if( zSql[j]==';' ){ - int isComplete; - char c = zSql[j+1]; - zSql[j+1] = 0; - isComplete = sqlite3_complete(&zSql[i]); - zSql[j+1] = c; - if( isComplete ){ - zSql[j] = 0; - while( i<j && isspace(zSql[i]) ){ i++; } - if( i<j ){ - prepareAndRun(pInstVfs, db, &zSql[i]); - } - zSql[j] = ';'; - i = j+1; - } - } - } - - sqlite3_instvfs_destroy(pInstVfs); - return 0; - -usage: - fprintf(stderr, zUsageMsg, argv[0]); - return -3; -} diff --git a/lib/libsqlite3/tool/split-sqlite3c.tcl b/lib/libsqlite3/tool/split-sqlite3c.tcl deleted file mode 100644 index 287b752828f..00000000000 --- a/lib/libsqlite3/tool/split-sqlite3c.tcl +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/tclsh -# -# This script splits the sqlite3.c amalgamated source code files into -# several smaller files such that no single files is more than a fixed -# number of lines in length (32k or 64k). Each of the split out files -# is #include-ed by the master file. -# -# Splitting files up this way allows them to be used with older compilers -# that cannot handle really long source files. -# -set MAX 32768 ;# Maximum number of lines per file. - -set BEGIN {^/\*+ Begin file ([a-zA-Z0-9_.]+) \*+/} -set END {^/\*+ End of %s \*+/} - -set in [open sqlite3.c] -set out1 [open sqlite3-all.c w] - -# Copy the header from sqlite3.c into sqlite3-all.c -# -while {[gets $in line]} { - if {[regexp $BEGIN $line]} break - puts $out1 $line -} - -# Gather the complete content of a file into memory. Store the -# content in $bufout. Store the number of lines is $nout -# -proc gather_one_file {firstline bufout nout} { - regexp $::BEGIN $firstline all filename - set end [format $::END $filename] - upvar $bufout buf $nout n - set buf $firstline\n - global in - set n 0 - while {[gets $in line]>=0} { - incr n - append buf $line\n - if {[regexp $end $line]} break - } -} - -# Write a big chunk of text in to an auxiliary file "sqlite3-NNN.c". -# Also add an appropriate #include to sqlite3-all.c -# -set filecnt 0 -proc write_one_file {content} { - global filecnt - incr filecnt - set out [open sqlite3-$filecnt.c w] - puts -nonewline $out $content - close $out - puts $::out1 "#include \"sqlite3-$filecnt.c\"" -} - -# Continue reading input. Store chunks in separate files and add -# the #includes to the main sqlite3-all.c file as necessary to reference -# the extra chunks. -# -set all {} -set N 0 -while {[regexp $BEGIN $line]} { - set buf {} - set n 0 - gather_one_file $line buf n - if {$n+$N>=$MAX} { - write_one_file $all - set all {} - set N 0 - } - append all $buf - incr N $n - while {[gets $in line]>=0} { - if {[regexp $BEGIN $line]} break - puts $out1 $line - } -} -if {$N>0} { - write_one_file $all -} -close $out1 -close $in diff --git a/lib/libsqlite3/tool/sqldiff.c b/lib/libsqlite3/tool/sqldiff.c deleted file mode 100644 index 9f0b705c40a..00000000000 --- a/lib/libsqlite3/tool/sqldiff.c +++ /dev/null @@ -1,1857 +0,0 @@ -/* -** 2015-04-06 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This is a utility program that computes the differences in content -** between two SQLite databases. -** -** To compile, simply link against SQLite. -** -** See the showHelp() routine below for a brief description of how to -** run the utility. -*/ -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> -#include <string.h> -#include <assert.h> -#include "sqlite3.h" - -/* -** All global variables are gathered into the "g" singleton. -*/ -struct GlobalVars { - const char *zArgv0; /* Name of program */ - int bSchemaOnly; /* Only show schema differences */ - int bSchemaPK; /* Use the schema-defined PK, not the true PK */ - unsigned fDebug; /* Debug flags */ - sqlite3 *db; /* The database connection */ -} g; - -/* -** Allowed values for g.fDebug -*/ -#define DEBUG_COLUMN_NAMES 0x000001 -#define DEBUG_DIFF_SQL 0x000002 - -/* -** Dynamic string object -*/ -typedef struct Str Str; -struct Str { - char *z; /* Text of the string */ - int nAlloc; /* Bytes allocated in z[] */ - int nUsed; /* Bytes actually used in z[] */ -}; - -/* -** Initialize a Str object -*/ -static void strInit(Str *p){ - p->z = 0; - p->nAlloc = 0; - p->nUsed = 0; -} - -/* -** Print an error resulting from faulting command-line arguments and -** abort the program. -*/ -static void cmdlineError(const char *zFormat, ...){ - va_list ap; - fprintf(stderr, "%s: ", g.zArgv0); - va_start(ap, zFormat); - vfprintf(stderr, zFormat, ap); - va_end(ap); - fprintf(stderr, "\n\"%s --help\" for more help\n", g.zArgv0); - exit(1); -} - -/* -** Print an error message for an error that occurs at runtime, then -** abort the program. -*/ -static void runtimeError(const char *zFormat, ...){ - va_list ap; - fprintf(stderr, "%s: ", g.zArgv0); - va_start(ap, zFormat); - vfprintf(stderr, zFormat, ap); - va_end(ap); - fprintf(stderr, "\n"); - exit(1); -} - -/* -** Free all memory held by a Str object -*/ -static void strFree(Str *p){ - sqlite3_free(p->z); - strInit(p); -} - -/* -** Add formatted text to the end of a Str object -*/ -static void strPrintf(Str *p, const char *zFormat, ...){ - int nNew; - for(;;){ - if( p->z ){ - va_list ap; - va_start(ap, zFormat); - sqlite3_vsnprintf(p->nAlloc-p->nUsed, p->z+p->nUsed, zFormat, ap); - va_end(ap); - nNew = (int)strlen(p->z + p->nUsed); - }else{ - nNew = p->nAlloc; - } - if( p->nUsed+nNew < p->nAlloc-1 ){ - p->nUsed += nNew; - break; - } - p->nAlloc = p->nAlloc*2 + 1000; - p->z = sqlite3_realloc(p->z, p->nAlloc); - if( p->z==0 ) runtimeError("out of memory"); - } -} - - - -/* Safely quote an SQL identifier. Use the minimum amount of transformation -** necessary to allow the string to be used with %s. -** -** Space to hold the returned string is obtained from sqlite3_malloc(). The -** caller is responsible for ensuring this space is freed when no longer -** needed. -*/ -static char *safeId(const char *zId){ - /* All SQLite keywords, in alphabetical order */ - static const char *azKeywords[] = { - "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS", - "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY", - "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT", - "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE", - "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE", - "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH", - "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN", - "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF", - "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER", - "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", - "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL", - "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA", - "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP", - "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT", - "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP", - "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE", - "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE", - "WITH", "WITHOUT", - }; - int lwr, upr, mid, c, i, x; - for(i=x=0; (c = zId[i])!=0; i++){ - if( !isalpha(c) && c!='_' ){ - if( i>0 && isdigit(c) ){ - x++; - }else{ - return sqlite3_mprintf("\"%w\"", zId); - } - } - } - if( x ) return sqlite3_mprintf("%s", zId); - lwr = 0; - upr = sizeof(azKeywords)/sizeof(azKeywords[0]) - 1; - while( lwr<=upr ){ - mid = (lwr+upr)/2; - c = sqlite3_stricmp(azKeywords[mid], zId); - if( c==0 ) return sqlite3_mprintf("\"%w\"", zId); - if( c<0 ){ - lwr = mid+1; - }else{ - upr = mid-1; - } - } - return sqlite3_mprintf("%s", zId); -} - -/* -** Prepare a new SQL statement. Print an error and abort if anything -** goes wrong. -*/ -static sqlite3_stmt *db_vprepare(const char *zFormat, va_list ap){ - char *zSql; - int rc; - sqlite3_stmt *pStmt; - - zSql = sqlite3_vmprintf(zFormat, ap); - if( zSql==0 ) runtimeError("out of memory"); - rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0); - if( rc ){ - runtimeError("SQL statement error: %s\n\"%s\"", sqlite3_errmsg(g.db), - zSql); - } - sqlite3_free(zSql); - return pStmt; -} -static sqlite3_stmt *db_prepare(const char *zFormat, ...){ - va_list ap; - sqlite3_stmt *pStmt; - va_start(ap, zFormat); - pStmt = db_vprepare(zFormat, ap); - va_end(ap); - return pStmt; -} - -/* -** Free a list of strings -*/ -static void namelistFree(char **az){ - if( az ){ - int i; - for(i=0; az[i]; i++) sqlite3_free(az[i]); - sqlite3_free(az); - } -} - -/* -** Return a list of column names for the table zDb.zTab. Space to -** hold the list is obtained from sqlite3_malloc() and should released -** using namelistFree() when no longer needed. -** -** Primary key columns are listed first, followed by data columns. -** The number of columns in the primary key is returned in *pnPkey. -** -** Normally, the "primary key" in the previous sentence is the true -** primary key - the rowid or INTEGER PRIMARY KEY for ordinary tables -** or the declared PRIMARY KEY for WITHOUT ROWID tables. However, if -** the g.bSchemaPK flag is set, then the schema-defined PRIMARY KEY is -** used in all cases. In that case, entries that have NULL values in -** any of their primary key fields will be excluded from the analysis. -** -** If the primary key for a table is the rowid but rowid is inaccessible, -** then this routine returns a NULL pointer. -** -** Examples: -** CREATE TABLE t1(a INT UNIQUE, b INTEGER, c TEXT, PRIMARY KEY(c)); -** *pnPKey = 1; -** az = { "rowid", "a", "b", "c", 0 } // Normal case -** az = { "c", "a", "b", 0 } // g.bSchemaPK==1 -** -** CREATE TABLE t2(a INT UNIQUE, b INTEGER, c TEXT, PRIMARY KEY(b)); -** *pnPKey = 1; -** az = { "b", "a", "c", 0 } -** -** CREATE TABLE t3(x,y,z,PRIMARY KEY(y,z)); -** *pnPKey = 1 // Normal case -** az = { "rowid", "x", "y", "z", 0 } // Normal case -** *pnPKey = 2 // g.bSchemaPK==1 -** az = { "y", "x", "z", 0 } // g.bSchemaPK==1 -** -** CREATE TABLE t4(x,y,z,PRIMARY KEY(y,z)) WITHOUT ROWID; -** *pnPKey = 2 -** az = { "y", "z", "x", 0 } -** -** CREATE TABLE t5(rowid,_rowid_,oid); -** az = 0 // The rowid is not accessible -*/ -static char **columnNames( - const char *zDb, /* Database ("main" or "aux") to query */ - const char *zTab, /* Name of table to return details of */ - int *pnPKey, /* OUT: Number of PK columns */ - int *pbRowid /* OUT: True if PK is an implicit rowid */ -){ - char **az = 0; /* List of column names to be returned */ - int naz = 0; /* Number of entries in az[] */ - sqlite3_stmt *pStmt; /* SQL statement being run */ - char *zPkIdxName = 0; /* Name of the PRIMARY KEY index */ - int truePk = 0; /* PRAGMA table_info indentifies the PK to use */ - int nPK = 0; /* Number of PRIMARY KEY columns */ - int i, j; /* Loop counters */ - - if( g.bSchemaPK==0 ){ - /* Normal case: Figure out what the true primary key is for the table. - ** * For WITHOUT ROWID tables, the true primary key is the same as - ** the schema PRIMARY KEY, which is guaranteed to be present. - ** * For rowid tables with an INTEGER PRIMARY KEY, the true primary - ** key is the INTEGER PRIMARY KEY. - ** * For all other rowid tables, the rowid is the true primary key. - */ - pStmt = db_prepare("PRAGMA %s.index_list=%Q", zDb, zTab); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - if( sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,3),"pk")==0 ){ - zPkIdxName = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); - break; - } - } - sqlite3_finalize(pStmt); - if( zPkIdxName ){ - int nKey = 0; - int nCol = 0; - truePk = 0; - pStmt = db_prepare("PRAGMA %s.index_xinfo=%Q", zDb, zPkIdxName); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - nCol++; - if( sqlite3_column_int(pStmt,5) ){ nKey++; continue; } - if( sqlite3_column_int(pStmt,1)>=0 ) truePk = 1; - } - if( nCol==nKey ) truePk = 1; - if( truePk ){ - nPK = nKey; - }else{ - nPK = 1; - } - sqlite3_finalize(pStmt); - sqlite3_free(zPkIdxName); - }else{ - truePk = 1; - nPK = 1; - } - pStmt = db_prepare("PRAGMA %s.table_info=%Q", zDb, zTab); - }else{ - /* The g.bSchemaPK==1 case: Use whatever primary key is declared - ** in the schema. The "rowid" will still be used as the primary key - ** if the table definition does not contain a PRIMARY KEY. - */ - nPK = 0; - pStmt = db_prepare("PRAGMA %s.table_info=%Q", zDb, zTab); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - if( sqlite3_column_int(pStmt,5)>0 ) nPK++; - } - sqlite3_reset(pStmt); - if( nPK==0 ) nPK = 1; - truePk = 1; - } - *pnPKey = nPK; - naz = nPK; - az = sqlite3_malloc( sizeof(char*)*(nPK+1) ); - if( az==0 ) runtimeError("out of memory"); - memset(az, 0, sizeof(char*)*(nPK+1)); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - int iPKey; - if( truePk && (iPKey = sqlite3_column_int(pStmt,5))>0 ){ - az[iPKey-1] = safeId((char*)sqlite3_column_text(pStmt,1)); - }else{ - az = sqlite3_realloc(az, sizeof(char*)*(naz+2) ); - if( az==0 ) runtimeError("out of memory"); - az[naz++] = safeId((char*)sqlite3_column_text(pStmt,1)); - } - } - sqlite3_finalize(pStmt); - if( az ) az[naz] = 0; - - /* If it is non-NULL, set *pbRowid to indicate whether or not the PK of - ** this table is an implicit rowid (*pbRowid==1) or not (*pbRowid==0). */ - if( pbRowid ) *pbRowid = (az[0]==0); - - /* If this table has an implicit rowid for a PK, figure out how to refer - ** to it. There are three options - "rowid", "_rowid_" and "oid". Any - ** of these will work, unless the table has an explicit column of the - ** same name. */ - if( az[0]==0 ){ - const char *azRowid[] = { "rowid", "_rowid_", "oid" }; - for(i=0; i<sizeof(azRowid)/sizeof(azRowid[0]); i++){ - for(j=1; j<naz; j++){ - if( sqlite3_stricmp(az[j], azRowid[i])==0 ) break; - } - if( j>=naz ){ - az[0] = sqlite3_mprintf("%s", azRowid[i]); - break; - } - } - if( az[0]==0 ){ - for(i=1; i<naz; i++) sqlite3_free(az[i]); - sqlite3_free(az); - az = 0; - } - } - return az; -} - -/* -** Print the sqlite3_value X as an SQL literal. -*/ -static void printQuoted(FILE *out, sqlite3_value *X){ - switch( sqlite3_value_type(X) ){ - case SQLITE_FLOAT: { - double r1; - char zBuf[50]; - r1 = sqlite3_value_double(X); - sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.15g", r1); - fprintf(out, "%s", zBuf); - break; - } - case SQLITE_INTEGER: { - fprintf(out, "%lld", sqlite3_value_int64(X)); - break; - } - case SQLITE_BLOB: { - const unsigned char *zBlob = sqlite3_value_blob(X); - int nBlob = sqlite3_value_bytes(X); - if( zBlob ){ - int i; - fprintf(out, "x'"); - for(i=0; i<nBlob; i++){ - fprintf(out, "%02x", zBlob[i]); - } - fprintf(out, "'"); - }else{ - fprintf(out, "NULL"); - } - break; - } - case SQLITE_TEXT: { - const unsigned char *zArg = sqlite3_value_text(X); - int i, j; - - if( zArg==0 ){ - fprintf(out, "NULL"); - }else{ - fprintf(out, "'"); - for(i=j=0; zArg[i]; i++){ - if( zArg[i]=='\'' ){ - fprintf(out, "%.*s'", i-j+1, &zArg[j]); - j = i+1; - } - } - fprintf(out, "%s'", &zArg[j]); - } - break; - } - case SQLITE_NULL: { - fprintf(out, "NULL"); - break; - } - } -} - -/* -** Output SQL that will recreate the aux.zTab table. -*/ -static void dump_table(const char *zTab, FILE *out){ - char *zId = safeId(zTab); /* Name of the table */ - char **az = 0; /* List of columns */ - int nPk; /* Number of true primary key columns */ - int nCol; /* Number of data columns */ - int i; /* Loop counter */ - sqlite3_stmt *pStmt; /* SQL statement */ - const char *zSep; /* Separator string */ - Str ins; /* Beginning of the INSERT statement */ - - pStmt = db_prepare("SELECT sql FROM aux.sqlite_master WHERE name=%Q", zTab); - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0)); - } - sqlite3_finalize(pStmt); - if( !g.bSchemaOnly ){ - az = columnNames("aux", zTab, &nPk, 0); - strInit(&ins); - if( az==0 ){ - pStmt = db_prepare("SELECT * FROM aux.%s", zId); - strPrintf(&ins,"INSERT INTO %s VALUES", zId); - }else{ - Str sql; - strInit(&sql); - zSep = "SELECT"; - for(i=0; az[i]; i++){ - strPrintf(&sql, "%s %s", zSep, az[i]); - zSep = ","; - } - strPrintf(&sql," FROM aux.%s", zId); - zSep = " ORDER BY"; - for(i=1; i<=nPk; i++){ - strPrintf(&sql, "%s %d", zSep, i); - zSep = ","; - } - pStmt = db_prepare("%s", sql.z); - strFree(&sql); - strPrintf(&ins, "INSERT INTO %s", zId); - zSep = "("; - for(i=0; az[i]; i++){ - strPrintf(&ins, "%s%s", zSep, az[i]); - zSep = ","; - } - strPrintf(&ins,") VALUES"); - namelistFree(az); - } - nCol = sqlite3_column_count(pStmt); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - fprintf(out, "%s",ins.z); - zSep = "("; - for(i=0; i<nCol; i++){ - fprintf(out, "%s",zSep); - printQuoted(out, sqlite3_column_value(pStmt,i)); - zSep = ","; - } - fprintf(out, ");\n"); - } - sqlite3_finalize(pStmt); - strFree(&ins); - } /* endif !g.bSchemaOnly */ - pStmt = db_prepare("SELECT sql FROM aux.sqlite_master" - " WHERE type='index' AND tbl_name=%Q AND sql IS NOT NULL", - zTab); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0)); - } - sqlite3_finalize(pStmt); -} - - -/* -** Compute all differences for a single table. -*/ -static void diff_one_table(const char *zTab, FILE *out){ - char *zId = safeId(zTab); /* Name of table (translated for us in SQL) */ - char **az = 0; /* Columns in main */ - char **az2 = 0; /* Columns in aux */ - int nPk; /* Primary key columns in main */ - int nPk2; /* Primary key columns in aux */ - int n = 0; /* Number of columns in main */ - int n2; /* Number of columns in aux */ - int nQ; /* Number of output columns in the diff query */ - int i; /* Loop counter */ - const char *zSep; /* Separator string */ - Str sql; /* Comparison query */ - sqlite3_stmt *pStmt; /* Query statement to do the diff */ - - strInit(&sql); - if( g.fDebug==DEBUG_COLUMN_NAMES ){ - /* Simply run columnNames() on all tables of the origin - ** database and show the results. This is used for testing - ** and debugging of the columnNames() function. - */ - az = columnNames("aux",zTab, &nPk, 0); - if( az==0 ){ - printf("Rowid not accessible for %s\n", zId); - }else{ - printf("%s:", zId); - for(i=0; az[i]; i++){ - printf(" %s", az[i]); - if( i+1==nPk ) printf(" *"); - } - printf("\n"); - } - goto end_diff_one_table; - } - - - if( sqlite3_table_column_metadata(g.db,"aux",zTab,0,0,0,0,0,0) ){ - if( !sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){ - /* Table missing from second database. */ - fprintf(out, "DROP TABLE %s;\n", zId); - } - goto end_diff_one_table; - } - - if( sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){ - /* Table missing from source */ - dump_table(zTab, out); - goto end_diff_one_table; - } - - az = columnNames("main", zTab, &nPk, 0); - az2 = columnNames("aux", zTab, &nPk2, 0); - if( az && az2 ){ - for(n=0; az[n]; n++){ - if( sqlite3_stricmp(az[n],az2[n])!=0 ) break; - } - } - if( az==0 - || az2==0 - || nPk!=nPk2 - || az[n] - ){ - /* Schema mismatch */ - fprintf(out, "DROP TABLE %s;\n", zId); - dump_table(zTab, out); - goto end_diff_one_table; - } - - /* Build the comparison query */ - for(n2=n; az[n2]; n2++){} - nQ = nPk2+1+2*(n2-nPk2); - if( n2>nPk2 ){ - zSep = "SELECT "; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%sB.%s", zSep, az[i]); - zSep = ", "; - } - strPrintf(&sql, ", 1%s -- changed row\n", nPk==n ? "" : ","); - while( az[i] ){ - strPrintf(&sql, " A.%s IS NOT B.%s, B.%s%s\n", - az[i], az[i], az[i], i==n2-1 ? "" : ","); - i++; - } - strPrintf(&sql, " FROM main.%s A, aux.%s B\n", zId, zId); - zSep = " WHERE"; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]); - zSep = " AND"; - } - zSep = "\n AND ("; - while( az[i] ){ - strPrintf(&sql, "%sA.%s IS NOT B.%s%s\n", - zSep, az[i], az[i], i==n2-1 ? ")" : ""); - zSep = " OR "; - i++; - } - strPrintf(&sql, " UNION ALL\n"); - } - zSep = "SELECT "; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%sA.%s", zSep, az[i]); - zSep = ", "; - } - strPrintf(&sql, ", 2%s -- deleted row\n", nPk==n ? "" : ","); - while( az[i] ){ - strPrintf(&sql, " NULL, NULL%s\n", i==n2-1 ? "" : ","); - i++; - } - strPrintf(&sql, " FROM main.%s A\n", zId); - strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B\n", zId); - zSep = " WHERE"; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]); - zSep = " AND"; - } - strPrintf(&sql, ")\n"); - zSep = " UNION ALL\nSELECT "; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%sB.%s", zSep, az[i]); - zSep = ", "; - } - strPrintf(&sql, ", 3%s -- inserted row\n", nPk==n ? "" : ","); - while( az2[i] ){ - strPrintf(&sql, " 1, B.%s%s\n", az[i], i==n2-1 ? "" : ","); - i++; - } - strPrintf(&sql, " FROM aux.%s B\n", zId); - strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A\n", zId); - zSep = " WHERE"; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]); - zSep = " AND"; - } - strPrintf(&sql, ")\n ORDER BY"); - zSep = " "; - for(i=1; i<=nPk; i++){ - strPrintf(&sql, "%s%d", zSep, i); - zSep = ", "; - } - strPrintf(&sql, ";\n"); - - if( g.fDebug & DEBUG_DIFF_SQL ){ - printf("SQL for %s:\n%s\n", zId, sql.z); - goto end_diff_one_table; - } - - /* Drop indexes that are missing in the destination */ - pStmt = db_prepare( - "SELECT name FROM main.sqlite_master" - " WHERE type='index' AND tbl_name=%Q" - " AND sql IS NOT NULL" - " AND sql NOT IN (SELECT sql FROM aux.sqlite_master" - " WHERE type='index' AND tbl_name=%Q" - " AND sql IS NOT NULL)", - zTab, zTab); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - char *z = safeId((const char*)sqlite3_column_text(pStmt,0)); - fprintf(out, "DROP INDEX %s;\n", z); - sqlite3_free(z); - } - sqlite3_finalize(pStmt); - - /* Run the query and output differences */ - if( !g.bSchemaOnly ){ - pStmt = db_prepare(sql.z); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - int iType = sqlite3_column_int(pStmt, nPk); - if( iType==1 || iType==2 ){ - if( iType==1 ){ /* Change the content of a row */ - fprintf(out, "UPDATE %s", zId); - zSep = " SET"; - for(i=nPk+1; i<nQ; i+=2){ - if( sqlite3_column_int(pStmt,i)==0 ) continue; - fprintf(out, "%s %s=", zSep, az2[(i+nPk-1)/2]); - zSep = ","; - printQuoted(out, sqlite3_column_value(pStmt,i+1)); - } - }else{ /* Delete a row */ - fprintf(out, "DELETE FROM %s", zId); - } - zSep = " WHERE"; - for(i=0; i<nPk; i++){ - fprintf(out, "%s %s=", zSep, az2[i]); - printQuoted(out, sqlite3_column_value(pStmt,i)); - zSep = ","; - } - fprintf(out, ";\n"); - }else{ /* Insert a row */ - fprintf(out, "INSERT INTO %s(%s", zId, az2[0]); - for(i=1; az2[i]; i++) fprintf(out, ",%s", az2[i]); - fprintf(out, ") VALUES"); - zSep = "("; - for(i=0; i<nPk2; i++){ - fprintf(out, "%s", zSep); - zSep = ","; - printQuoted(out, sqlite3_column_value(pStmt,i)); - } - for(i=nPk2+2; i<nQ; i+=2){ - fprintf(out, ","); - printQuoted(out, sqlite3_column_value(pStmt,i)); - } - fprintf(out, ");\n"); - } - } - sqlite3_finalize(pStmt); - } /* endif !g.bSchemaOnly */ - - /* Create indexes that are missing in the source */ - pStmt = db_prepare( - "SELECT sql FROM aux.sqlite_master" - " WHERE type='index' AND tbl_name=%Q" - " AND sql IS NOT NULL" - " AND sql NOT IN (SELECT sql FROM main.sqlite_master" - " WHERE type='index' AND tbl_name=%Q" - " AND sql IS NOT NULL)", - zTab, zTab); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0)); - } - sqlite3_finalize(pStmt); - -end_diff_one_table: - strFree(&sql); - sqlite3_free(zId); - namelistFree(az); - namelistFree(az2); - return; -} - -/* -** Check that table zTab exists and has the same schema in both the "main" -** and "aux" databases currently opened by the global db handle. If they -** do not, output an error message on stderr and exit(1). Otherwise, if -** the schemas do match, return control to the caller. -*/ -static void checkSchemasMatch(const char *zTab){ - sqlite3_stmt *pStmt = db_prepare( - "SELECT A.sql=B.sql FROM main.sqlite_master A, aux.sqlite_master B" - " WHERE A.name=%Q AND B.name=%Q", zTab, zTab - ); - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - if( sqlite3_column_int(pStmt,0)==0 ){ - runtimeError("schema changes for table %s", safeId(zTab)); - } - }else{ - runtimeError("table %s missing from one or both databases", safeId(zTab)); - } - sqlite3_finalize(pStmt); -} - -/************************************************************************** -** The following code is copied from fossil. It is used to generate the -** fossil delta blobs sometimes used in RBU update records. -*/ - -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned char u8; - -/* -** The width of a hash window in bytes. The algorithm only works if this -** is a power of 2. -*/ -#define NHASH 16 - -/* -** The current state of the rolling hash. -** -** z[] holds the values that have been hashed. z[] is a circular buffer. -** z[i] is the first entry and z[(i+NHASH-1)%NHASH] is the last entry of -** the window. -** -** Hash.a is the sum of all elements of hash.z[]. Hash.b is a weighted -** sum. Hash.b is z[i]*NHASH + z[i+1]*(NHASH-1) + ... + z[i+NHASH-1]*1. -** (Each index for z[] should be module NHASH, of course. The %NHASH operator -** is omitted in the prior expression for brevity.) -*/ -typedef struct hash hash; -struct hash { - u16 a, b; /* Hash values */ - u16 i; /* Start of the hash window */ - char z[NHASH]; /* The values that have been hashed */ -}; - -/* -** Initialize the rolling hash using the first NHASH characters of z[] -*/ -static void hash_init(hash *pHash, const char *z){ - u16 a, b, i; - a = b = 0; - for(i=0; i<NHASH; i++){ - a += z[i]; - b += (NHASH-i)*z[i]; - pHash->z[i] = z[i]; - } - pHash->a = a & 0xffff; - pHash->b = b & 0xffff; - pHash->i = 0; -} - -/* -** Advance the rolling hash by a single character "c" -*/ -static void hash_next(hash *pHash, int c){ - u16 old = pHash->z[pHash->i]; - pHash->z[pHash->i] = (char)c; - pHash->i = (pHash->i+1)&(NHASH-1); - pHash->a = pHash->a - old + (char)c; - pHash->b = pHash->b - NHASH*old + pHash->a; -} - -/* -** Return a 32-bit hash value -*/ -static u32 hash_32bit(hash *pHash){ - return (pHash->a & 0xffff) | (((u32)(pHash->b & 0xffff))<<16); -} - -/* -** Write an base-64 integer into the given buffer. -*/ -static void putInt(unsigned int v, char **pz){ - static const char zDigits[] = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; - /* 123456789 123456789 123456789 123456789 123456789 123456789 123 */ - int i, j; - char zBuf[20]; - if( v==0 ){ - *(*pz)++ = '0'; - return; - } - for(i=0; v>0; i++, v>>=6){ - zBuf[i] = zDigits[v&0x3f]; - } - for(j=i-1; j>=0; j--){ - *(*pz)++ = zBuf[j]; - } -} - -/* -** Return the number digits in the base-64 representation of a positive integer -*/ -static int digit_count(int v){ - unsigned int i, x; - for(i=1, x=64; (unsigned int)v>=x; i++, x <<= 6){} - return i; -} - -/* -** Compute a 32-bit checksum on the N-byte buffer. Return the result. -*/ -static unsigned int checksum(const char *zIn, size_t N){ - const unsigned char *z = (const unsigned char *)zIn; - unsigned sum0 = 0; - unsigned sum1 = 0; - unsigned sum2 = 0; - unsigned sum3 = 0; - while(N >= 16){ - sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]); - sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]); - sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]); - sum3 += ((unsigned)z[3] + z[7] + z[11]+ z[15]); - z += 16; - N -= 16; - } - while(N >= 4){ - sum0 += z[0]; - sum1 += z[1]; - sum2 += z[2]; - sum3 += z[3]; - z += 4; - N -= 4; - } - sum3 += (sum2 << 8) + (sum1 << 16) + (sum0 << 24); - switch(N){ - case 3: sum3 += (z[2] << 8); - case 2: sum3 += (z[1] << 16); - case 1: sum3 += (z[0] << 24); - default: ; - } - return sum3; -} - -/* -** Create a new delta. -** -** The delta is written into a preallocated buffer, zDelta, which -** should be at least 60 bytes longer than the target file, zOut. -** The delta string will be NUL-terminated, but it might also contain -** embedded NUL characters if either the zSrc or zOut files are -** binary. This function returns the length of the delta string -** in bytes, excluding the final NUL terminator character. -** -** Output Format: -** -** The delta begins with a base64 number followed by a newline. This -** number is the number of bytes in the TARGET file. Thus, given a -** delta file z, a program can compute the size of the output file -** simply by reading the first line and decoding the base-64 number -** found there. The delta_output_size() routine does exactly this. -** -** After the initial size number, the delta consists of a series of -** literal text segments and commands to copy from the SOURCE file. -** A copy command looks like this: -** -** NNN@MMM, -** -** where NNN is the number of bytes to be copied and MMM is the offset -** into the source file of the first byte (both base-64). If NNN is 0 -** it means copy the rest of the input file. Literal text is like this: -** -** NNN:TTTTT -** -** where NNN is the number of bytes of text (base-64) and TTTTT is the text. -** -** The last term is of the form -** -** NNN; -** -** In this case, NNN is a 32-bit bigendian checksum of the output file -** that can be used to verify that the delta applied correctly. All -** numbers are in base-64. -** -** Pure text files generate a pure text delta. Binary files generate a -** delta that may contain some binary data. -** -** Algorithm: -** -** The encoder first builds a hash table to help it find matching -** patterns in the source file. 16-byte chunks of the source file -** sampled at evenly spaced intervals are used to populate the hash -** table. -** -** Next we begin scanning the target file using a sliding 16-byte -** window. The hash of the 16-byte window in the target is used to -** search for a matching section in the source file. When a match -** is found, a copy command is added to the delta. An effort is -** made to extend the matching section to regions that come before -** and after the 16-byte hash window. A copy command is only issued -** if the result would use less space that just quoting the text -** literally. Literal text is added to the delta for sections that -** do not match or which can not be encoded efficiently using copy -** commands. -*/ -static int rbuDeltaCreate( - const char *zSrc, /* The source or pattern file */ - unsigned int lenSrc, /* Length of the source file */ - const char *zOut, /* The target file */ - unsigned int lenOut, /* Length of the target file */ - char *zDelta /* Write the delta into this buffer */ -){ - unsigned int i, base; - char *zOrigDelta = zDelta; - hash h; - int nHash; /* Number of hash table entries */ - int *landmark; /* Primary hash table */ - int *collide; /* Collision chain */ - int lastRead = -1; /* Last byte of zSrc read by a COPY command */ - - /* Add the target file size to the beginning of the delta - */ - putInt(lenOut, &zDelta); - *(zDelta++) = '\n'; - - /* If the source file is very small, it means that we have no - ** chance of ever doing a copy command. Just output a single - ** literal segment for the entire target and exit. - */ - if( lenSrc<=NHASH ){ - putInt(lenOut, &zDelta); - *(zDelta++) = ':'; - memcpy(zDelta, zOut, lenOut); - zDelta += lenOut; - putInt(checksum(zOut, lenOut), &zDelta); - *(zDelta++) = ';'; - return zDelta - zOrigDelta; - } - - /* Compute the hash table used to locate matching sections in the - ** source file. - */ - nHash = lenSrc/NHASH; - collide = sqlite3_malloc( nHash*2*sizeof(int) ); - landmark = &collide[nHash]; - memset(landmark, -1, nHash*sizeof(int)); - memset(collide, -1, nHash*sizeof(int)); - for(i=0; i<lenSrc-NHASH; i+=NHASH){ - int hv; - hash_init(&h, &zSrc[i]); - hv = hash_32bit(&h) % nHash; - collide[i/NHASH] = landmark[hv]; - landmark[hv] = i/NHASH; - } - - /* Begin scanning the target file and generating copy commands and - ** literal sections of the delta. - */ - base = 0; /* We have already generated everything before zOut[base] */ - while( base+NHASH<lenOut ){ - int iSrc, iBlock; - int bestCnt, bestOfst=0, bestLitsz=0; - hash_init(&h, &zOut[base]); - i = 0; /* Trying to match a landmark against zOut[base+i] */ - bestCnt = 0; - while( 1 ){ - int hv; - int limit = 250; - - hv = hash_32bit(&h) % nHash; - iBlock = landmark[hv]; - while( iBlock>=0 && (limit--)>0 ){ - /* - ** The hash window has identified a potential match against - ** landmark block iBlock. But we need to investigate further. - ** - ** Look for a region in zOut that matches zSrc. Anchor the search - ** at zSrc[iSrc] and zOut[base+i]. Do not include anything prior to - ** zOut[base] or after zOut[outLen] nor anything after zSrc[srcLen]. - ** - ** Set cnt equal to the length of the match and set ofst so that - ** zSrc[ofst] is the first element of the match. litsz is the number - ** of characters between zOut[base] and the beginning of the match. - ** sz will be the overhead (in bytes) needed to encode the copy - ** command. Only generate copy command if the overhead of the - ** copy command is less than the amount of literal text to be copied. - */ - int cnt, ofst, litsz; - int j, k, x, y; - int sz; - - /* Beginning at iSrc, match forwards as far as we can. j counts - ** the number of characters that match */ - iSrc = iBlock*NHASH; - for( - j=0, x=iSrc, y=base+i; - (unsigned int)x<lenSrc && (unsigned int)y<lenOut; - j++, x++, y++ - ){ - if( zSrc[x]!=zOut[y] ) break; - } - j--; - - /* Beginning at iSrc-1, match backwards as far as we can. k counts - ** the number of characters that match */ - for(k=1; k<iSrc && (unsigned int)k<=i; k++){ - if( zSrc[iSrc-k]!=zOut[base+i-k] ) break; - } - k--; - - /* Compute the offset and size of the matching region */ - ofst = iSrc-k; - cnt = j+k+1; - litsz = i-k; /* Number of bytes of literal text before the copy */ - /* sz will hold the number of bytes needed to encode the "insert" - ** command and the copy command, not counting the "insert" text */ - sz = digit_count(i-k)+digit_count(cnt)+digit_count(ofst)+3; - if( cnt>=sz && cnt>bestCnt ){ - /* Remember this match only if it is the best so far and it - ** does not increase the file size */ - bestCnt = cnt; - bestOfst = iSrc-k; - bestLitsz = litsz; - } - - /* Check the next matching block */ - iBlock = collide[iBlock]; - } - - /* We have a copy command that does not cause the delta to be larger - ** than a literal insert. So add the copy command to the delta. - */ - if( bestCnt>0 ){ - if( bestLitsz>0 ){ - /* Add an insert command before the copy */ - putInt(bestLitsz,&zDelta); - *(zDelta++) = ':'; - memcpy(zDelta, &zOut[base], bestLitsz); - zDelta += bestLitsz; - base += bestLitsz; - } - base += bestCnt; - putInt(bestCnt, &zDelta); - *(zDelta++) = '@'; - putInt(bestOfst, &zDelta); - *(zDelta++) = ','; - if( bestOfst + bestCnt -1 > lastRead ){ - lastRead = bestOfst + bestCnt - 1; - } - bestCnt = 0; - break; - } - - /* If we reach this point, it means no match is found so far */ - if( base+i+NHASH>=lenOut ){ - /* We have reached the end of the file and have not found any - ** matches. Do an "insert" for everything that does not match */ - putInt(lenOut-base, &zDelta); - *(zDelta++) = ':'; - memcpy(zDelta, &zOut[base], lenOut-base); - zDelta += lenOut-base; - base = lenOut; - break; - } - - /* Advance the hash by one character. Keep looking for a match */ - hash_next(&h, zOut[base+i+NHASH]); - i++; - } - } - /* Output a final "insert" record to get all the text at the end of - ** the file that does not match anything in the source file. - */ - if( base<lenOut ){ - putInt(lenOut-base, &zDelta); - *(zDelta++) = ':'; - memcpy(zDelta, &zOut[base], lenOut-base); - zDelta += lenOut-base; - } - /* Output the final checksum record. */ - putInt(checksum(zOut, lenOut), &zDelta); - *(zDelta++) = ';'; - sqlite3_free(collide); - return zDelta - zOrigDelta; -} - -/* -** End of code copied from fossil. -**************************************************************************/ - -static void strPrintfArray( - Str *pStr, /* String object to append to */ - const char *zSep, /* Separator string */ - const char *zFmt, /* Format for each entry */ - char **az, int n /* Array of strings & its size (or -1) */ -){ - int i; - for(i=0; az[i] && (i<n || n<0); i++){ - if( i!=0 ) strPrintf(pStr, "%s", zSep); - strPrintf(pStr, zFmt, az[i], az[i], az[i]); - } -} - -static void getRbudiffQuery( - const char *zTab, - char **azCol, - int nPK, - int bOtaRowid, - Str *pSql -){ - int i; - - /* First the newly inserted rows: **/ - strPrintf(pSql, "SELECT "); - strPrintfArray(pSql, ", ", "%s", azCol, -1); - strPrintf(pSql, ", 0, "); /* Set ota_control to 0 for an insert */ - strPrintfArray(pSql, ", ", "NULL", azCol, -1); - strPrintf(pSql, " FROM aux.%Q AS n WHERE NOT EXISTS (\n", zTab); - strPrintf(pSql, " SELECT 1 FROM ", zTab); - strPrintf(pSql, " main.%Q AS o WHERE ", zTab); - strPrintfArray(pSql, " AND ", "(n.%Q IS o.%Q)", azCol, nPK); - strPrintf(pSql, "\n)"); - - /* Deleted rows: */ - strPrintf(pSql, "\nUNION ALL\nSELECT "); - strPrintfArray(pSql, ", ", "%s", azCol, nPK); - if( azCol[nPK] ){ - strPrintf(pSql, ", "); - strPrintfArray(pSql, ", ", "NULL", &azCol[nPK], -1); - } - strPrintf(pSql, ", 1, "); /* Set ota_control to 1 for a delete */ - strPrintfArray(pSql, ", ", "NULL", azCol, -1); - strPrintf(pSql, " FROM main.%Q AS n WHERE NOT EXISTS (\n", zTab); - strPrintf(pSql, " SELECT 1 FROM ", zTab); - strPrintf(pSql, " aux.%Q AS o WHERE ", zTab); - strPrintfArray(pSql, " AND ", "(n.%Q IS o.%Q)", azCol, nPK); - strPrintf(pSql, "\n) "); - - /* Updated rows. If all table columns are part of the primary key, there - ** can be no updates. In this case this part of the compound SELECT can - ** be omitted altogether. */ - if( azCol[nPK] ){ - strPrintf(pSql, "\nUNION ALL\nSELECT "); - strPrintfArray(pSql, ", ", "n.%s", azCol, nPK); - strPrintf(pSql, ",\n"); - strPrintfArray(pSql, " ,\n", - " CASE WHEN n.%s IS o.%s THEN NULL ELSE n.%s END", &azCol[nPK], -1 - ); - - if( bOtaRowid==0 ){ - strPrintf(pSql, ", '"); - strPrintfArray(pSql, "", ".", azCol, nPK); - strPrintf(pSql, "' ||\n"); - }else{ - strPrintf(pSql, ",\n"); - } - strPrintfArray(pSql, " ||\n", - " CASE WHEN n.%s IS o.%s THEN '.' ELSE 'x' END", &azCol[nPK], -1 - ); - strPrintf(pSql, "\nAS ota_control, "); - strPrintfArray(pSql, ", ", "NULL", azCol, nPK); - strPrintf(pSql, ",\n"); - strPrintfArray(pSql, " ,\n", - " CASE WHEN n.%s IS o.%s THEN NULL ELSE o.%s END", &azCol[nPK], -1 - ); - - strPrintf(pSql, "\nFROM main.%Q AS o, aux.%Q AS n\nWHERE ", zTab, zTab); - strPrintfArray(pSql, " AND ", "(n.%Q IS o.%Q)", azCol, nPK); - strPrintf(pSql, " AND ota_control LIKE '%%x%%'"); - } - - /* Now add an ORDER BY clause to sort everything by PK. */ - strPrintf(pSql, "\nORDER BY "); - for(i=1; i<=nPK; i++) strPrintf(pSql, "%s%d", ((i>1)?", ":""), i); -} - -static void rbudiff_one_table(const char *zTab, FILE *out){ - int bOtaRowid; /* True to use an ota_rowid column */ - int nPK; /* Number of primary key columns in table */ - char **azCol; /* NULL terminated array of col names */ - int i; - int nCol; - Str ct = {0, 0, 0}; /* The "CREATE TABLE data_xxx" statement */ - Str sql = {0, 0, 0}; /* Query to find differences */ - Str insert = {0, 0, 0}; /* First part of output INSERT statement */ - sqlite3_stmt *pStmt = 0; - - /* --rbu mode must use real primary keys. */ - g.bSchemaPK = 1; - - /* Check that the schemas of the two tables match. Exit early otherwise. */ - checkSchemasMatch(zTab); - - /* Grab the column names and PK details for the table(s). If no usable PK - ** columns are found, bail out early. */ - azCol = columnNames("main", zTab, &nPK, &bOtaRowid); - if( azCol==0 ){ - runtimeError("table %s has no usable PK columns", zTab); - } - for(nCol=0; azCol[nCol]; nCol++); - - /* Build and output the CREATE TABLE statement for the data_xxx table */ - strPrintf(&ct, "CREATE TABLE IF NOT EXISTS 'data_%q'(", zTab); - if( bOtaRowid ) strPrintf(&ct, "rbu_rowid, "); - strPrintfArray(&ct, ", ", "%s", &azCol[bOtaRowid], -1); - strPrintf(&ct, ", rbu_control);"); - - /* Get the SQL for the query to retrieve data from the two databases */ - getRbudiffQuery(zTab, azCol, nPK, bOtaRowid, &sql); - - /* Build the first part of the INSERT statement output for each row - ** in the data_xxx table. */ - strPrintf(&insert, "INSERT INTO 'data_%q' (", zTab); - if( bOtaRowid ) strPrintf(&insert, "rbu_rowid, "); - strPrintfArray(&insert, ", ", "%s", &azCol[bOtaRowid], -1); - strPrintf(&insert, ", rbu_control) VALUES("); - - pStmt = db_prepare("%s", sql.z); - - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - - /* If this is the first row output, print out the CREATE TABLE - ** statement first. And then set ct.z to NULL so that it is not - ** printed again. */ - if( ct.z ){ - fprintf(out, "%s\n", ct.z); - strFree(&ct); - } - - /* Output the first part of the INSERT statement */ - fprintf(out, "%s", insert.z); - - if( sqlite3_column_type(pStmt, nCol)==SQLITE_INTEGER ){ - for(i=0; i<=nCol; i++){ - if( i>0 ) fprintf(out, ", "); - printQuoted(out, sqlite3_column_value(pStmt, i)); - } - }else{ - char *zOtaControl; - int nOtaControl = sqlite3_column_bytes(pStmt, nCol); - - zOtaControl = (char*)sqlite3_malloc(nOtaControl); - memcpy(zOtaControl, sqlite3_column_text(pStmt, nCol), nOtaControl+1); - - for(i=0; i<nCol; i++){ - int bDone = 0; - if( i>=nPK - && sqlite3_column_type(pStmt, i)==SQLITE_BLOB - && sqlite3_column_type(pStmt, nCol+1+i)==SQLITE_BLOB - ){ - const char *aSrc = sqlite3_column_blob(pStmt, nCol+1+i); - int nSrc = sqlite3_column_bytes(pStmt, nCol+1+i); - const char *aFinal = sqlite3_column_blob(pStmt, i); - int nFinal = sqlite3_column_bytes(pStmt, i); - char *aDelta; - int nDelta; - - aDelta = sqlite3_malloc(nFinal + 60); - nDelta = rbuDeltaCreate(aSrc, nSrc, aFinal, nFinal, aDelta); - if( nDelta<nFinal ){ - int j; - fprintf(out, "x'"); - for(j=0; j<nDelta; j++) fprintf(out, "%02x", (u8)aDelta[j]); - fprintf(out, "'"); - zOtaControl[i-bOtaRowid] = 'f'; - bDone = 1; - } - sqlite3_free(aDelta); - } - - if( bDone==0 ){ - printQuoted(out, sqlite3_column_value(pStmt, i)); - } - fprintf(out, ", "); - } - fprintf(out, "'%s'", zOtaControl); - sqlite3_free(zOtaControl); - } - - /* And the closing bracket of the insert statement */ - fprintf(out, ");\n"); - } - - sqlite3_finalize(pStmt); - - strFree(&ct); - strFree(&sql); - strFree(&insert); -} - -/* -** Display a summary of differences between two versions of the same -** table table. -** -** * Number of rows changed -** * Number of rows added -** * Number of rows deleted -** * Number of identical rows -*/ -static void summarize_one_table(const char *zTab, FILE *out){ - char *zId = safeId(zTab); /* Name of table (translated for us in SQL) */ - char **az = 0; /* Columns in main */ - char **az2 = 0; /* Columns in aux */ - int nPk; /* Primary key columns in main */ - int nPk2; /* Primary key columns in aux */ - int n = 0; /* Number of columns in main */ - int n2; /* Number of columns in aux */ - int i; /* Loop counter */ - const char *zSep; /* Separator string */ - Str sql; /* Comparison query */ - sqlite3_stmt *pStmt; /* Query statement to do the diff */ - sqlite3_int64 nUpdate; /* Number of updated rows */ - sqlite3_int64 nUnchanged; /* Number of unmodified rows */ - sqlite3_int64 nDelete; /* Number of deleted rows */ - sqlite3_int64 nInsert; /* Number of inserted rows */ - - strInit(&sql); - if( sqlite3_table_column_metadata(g.db,"aux",zTab,0,0,0,0,0,0) ){ - if( !sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){ - /* Table missing from second database. */ - fprintf(out, "%s: missing from second database\n", zTab); - } - goto end_summarize_one_table; - } - - if( sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){ - /* Table missing from source */ - fprintf(out, "%s: missing from first database\n", zTab); - goto end_summarize_one_table; - } - - az = columnNames("main", zTab, &nPk, 0); - az2 = columnNames("aux", zTab, &nPk2, 0); - if( az && az2 ){ - for(n=0; az[n]; n++){ - if( sqlite3_stricmp(az[n],az2[n])!=0 ) break; - } - } - if( az==0 - || az2==0 - || nPk!=nPk2 - || az[n] - ){ - /* Schema mismatch */ - fprintf(out, "%s: incompatible schema\n", zTab); - goto end_summarize_one_table; - } - - /* Build the comparison query */ - for(n2=n; az[n2]; n2++){} - strPrintf(&sql, "SELECT 1, count(*)"); - if( n2==nPk2 ){ - strPrintf(&sql, ", 0\n"); - }else{ - zSep = ", sum("; - for(i=nPk; az[i]; i++){ - strPrintf(&sql, "%sA.%s IS NOT B.%s", zSep, az[i], az[i]); - zSep = " OR "; - } - strPrintf(&sql, ")\n"); - } - strPrintf(&sql, " FROM main.%s A, aux.%s B\n", zId, zId); - zSep = " WHERE"; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]); - zSep = " AND"; - } - strPrintf(&sql, " UNION ALL\n"); - strPrintf(&sql, "SELECT 2, count(*), 0\n"); - strPrintf(&sql, " FROM main.%s A\n", zId); - strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B ", zId); - zSep = "WHERE"; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]); - zSep = " AND"; - } - strPrintf(&sql, ")\n"); - strPrintf(&sql, " UNION ALL\n"); - strPrintf(&sql, "SELECT 3, count(*), 0\n"); - strPrintf(&sql, " FROM aux.%s B\n", zId); - strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A ", zId); - zSep = "WHERE"; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%s A.%s=B.%s", zSep, az[i], az[i]); - zSep = " AND"; - } - strPrintf(&sql, ")\n ORDER BY 1;\n"); - - if( (g.fDebug & DEBUG_DIFF_SQL)!=0 ){ - printf("SQL for %s:\n%s\n", zId, sql.z); - goto end_summarize_one_table; - } - - /* Run the query and output difference summary */ - pStmt = db_prepare(sql.z); - nUpdate = 0; - nInsert = 0; - nDelete = 0; - nUnchanged = 0; - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - switch( sqlite3_column_int(pStmt,0) ){ - case 1: - nUpdate = sqlite3_column_int64(pStmt,2); - nUnchanged = sqlite3_column_int64(pStmt,1) - nUpdate; - break; - case 2: - nDelete = sqlite3_column_int64(pStmt,1); - break; - case 3: - nInsert = sqlite3_column_int64(pStmt,1); - break; - } - } - sqlite3_finalize(pStmt); - fprintf(out, "%s: %lld changes, %lld inserts, %lld deletes, %lld unchanged\n", - zTab, nUpdate, nInsert, nDelete, nUnchanged); - -end_summarize_one_table: - strFree(&sql); - sqlite3_free(zId); - namelistFree(az); - namelistFree(az2); - return; -} - -/* -** Write a 64-bit signed integer as a varint onto out -*/ -static void putsVarint(FILE *out, sqlite3_uint64 v){ - int i, n; - unsigned char p[12]; - if( v & (((sqlite3_uint64)0xff000000)<<32) ){ - p[8] = (unsigned char)v; - v >>= 8; - for(i=7; i>=0; i--){ - p[i] = (unsigned char)((v & 0x7f) | 0x80); - v >>= 7; - } - fwrite(p, 8, 1, out); - }else{ - n = 9; - do{ - p[n--] = (unsigned char)((v & 0x7f) | 0x80); - v >>= 7; - }while( v!=0 ); - p[9] &= 0x7f; - fwrite(p+n+1, 9-n, 1, out); - } -} - -/* -** Write an SQLite value onto out. -*/ -static void putValue(FILE *out, sqlite3_value *pVal){ - int iDType = sqlite3_value_type(pVal); - sqlite3_int64 iX; - double rX; - sqlite3_uint64 uX; - int j; - - putc(iDType, out); - switch( iDType ){ - case SQLITE_INTEGER: - iX = sqlite3_value_int64(pVal); - memcpy(&uX, &iX, 8); - for(j=56; j>=0; j-=8) putc((uX>>j)&0xff, out); - break; - case SQLITE_FLOAT: - rX = sqlite3_value_double(pVal); - memcpy(&uX, &rX, 8); - for(j=56; j>=0; j-=8) putc((uX>>j)&0xff, out); - break; - case SQLITE_TEXT: - iX = sqlite3_value_bytes(pVal); - putsVarint(out, (sqlite3_uint64)iX); - fwrite(sqlite3_value_text(pVal),1,(size_t)iX,out); - break; - case SQLITE_BLOB: - iX = sqlite3_value_bytes(pVal); - putsVarint(out, (sqlite3_uint64)iX); - fwrite(sqlite3_value_blob(pVal),1,(size_t)iX,out); - break; - case SQLITE_NULL: - break; - } -} - -/* -** Generate a CHANGESET for all differences from main.zTab to aux.zTab. -*/ -static void changeset_one_table(const char *zTab, FILE *out){ - sqlite3_stmt *pStmt; /* SQL statment */ - char *zId = safeId(zTab); /* Escaped name of the table */ - char **azCol = 0; /* List of escaped column names */ - int nCol = 0; /* Number of columns */ - int *aiFlg = 0; /* 0 if column is not part of PK */ - int *aiPk = 0; /* Column numbers for each PK column */ - int nPk = 0; /* Number of PRIMARY KEY columns */ - Str sql; /* SQL for the diff query */ - int i, k; /* Loop counters */ - const char *zSep; /* List separator */ - - /* Check that the schemas of the two tables match. Exit early otherwise. */ - checkSchemasMatch(zTab); - - pStmt = db_prepare("PRAGMA main.table_info=%Q", zTab); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - nCol++; - azCol = sqlite3_realloc(azCol, sizeof(char*)*nCol); - if( azCol==0 ) runtimeError("out of memory"); - aiFlg = sqlite3_realloc(aiFlg, sizeof(int)*nCol); - if( aiFlg==0 ) runtimeError("out of memory"); - azCol[nCol-1] = safeId((const char*)sqlite3_column_text(pStmt,1)); - aiFlg[nCol-1] = i = sqlite3_column_int(pStmt,5); - if( i>0 ){ - if( i>nPk ){ - nPk = i; - aiPk = sqlite3_realloc(aiPk, sizeof(int)*nPk); - if( aiPk==0 ) runtimeError("out of memory"); - } - aiPk[i-1] = nCol-1; - } - } - sqlite3_finalize(pStmt); - if( nPk==0 ) goto end_changeset_one_table; - strInit(&sql); - if( nCol>nPk ){ - strPrintf(&sql, "SELECT %d", SQLITE_UPDATE); - for(i=0; i<nCol; i++){ - if( aiFlg[i] ){ - strPrintf(&sql, ",\n A.%s", azCol[i]); - }else{ - strPrintf(&sql, ",\n A.%s IS NOT B.%s, A.%s, B.%s", - azCol[i], azCol[i], azCol[i], azCol[i]); - } - } - strPrintf(&sql,"\n FROM main.%s A, aux.%s B\n", zId, zId); - zSep = " WHERE"; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]); - zSep = " AND"; - } - zSep = "\n AND ("; - for(i=0; i<nCol; i++){ - if( aiFlg[i] ) continue; - strPrintf(&sql, "%sA.%s IS NOT B.%s", zSep, azCol[i], azCol[i]); - zSep = " OR\n "; - } - strPrintf(&sql,")\n UNION ALL\n"); - } - strPrintf(&sql, "SELECT %d", SQLITE_DELETE); - for(i=0; i<nCol; i++){ - if( aiFlg[i] ){ - strPrintf(&sql, ",\n A.%s", azCol[i]); - }else{ - strPrintf(&sql, ",\n 1, A.%s, NULL", azCol[i]); - } - } - strPrintf(&sql, "\n FROM main.%s A\n", zId); - strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B\n", zId); - zSep = " WHERE"; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]); - zSep = " AND"; - } - strPrintf(&sql, ")\n UNION ALL\n"); - strPrintf(&sql, "SELECT %d", SQLITE_INSERT); - for(i=0; i<nCol; i++){ - if( aiFlg[i] ){ - strPrintf(&sql, ",\n B.%s", azCol[i]); - }else{ - strPrintf(&sql, ",\n 1, NULL, B.%s", azCol[i]); - } - } - strPrintf(&sql, "\n FROM aux.%s B\n", zId); - strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A\n", zId); - zSep = " WHERE"; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]); - zSep = " AND"; - } - strPrintf(&sql, ")\n"); - strPrintf(&sql, " ORDER BY"); - zSep = " "; - for(i=0; i<nPk; i++){ - strPrintf(&sql, "%s %d", zSep, aiPk[i]+2); - zSep = ","; - } - strPrintf(&sql, ";\n"); - - if( g.fDebug & DEBUG_DIFF_SQL ){ - printf("SQL for %s:\n%s\n", zId, sql.z); - goto end_changeset_one_table; - } - - putc('T', out); - putsVarint(out, (sqlite3_uint64)nCol); - for(i=0; i<nCol; i++) putc(aiFlg[i]!=0, out); - fwrite(zTab, 1, strlen(zTab), out); - putc(0, out); - - pStmt = db_prepare("%s", sql.z); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - int iType = sqlite3_column_int(pStmt,0); - putc(iType, out); - putc(0, out); - switch( sqlite3_column_int(pStmt,0) ){ - case SQLITE_UPDATE: { - for(k=1, i=0; i<nCol; i++){ - if( aiFlg[i] ){ - putValue(out, sqlite3_column_value(pStmt,k)); - k++; - }else if( sqlite3_column_int(pStmt,k) ){ - putValue(out, sqlite3_column_value(pStmt,k+1)); - k += 3; - }else{ - putc(0, out); - k += 3; - } - } - for(k=1, i=0; i<nCol; i++){ - if( aiFlg[i] ){ - putc(0, out); - k++; - }else if( sqlite3_column_int(pStmt,k) ){ - putValue(out, sqlite3_column_value(pStmt,k+2)); - k += 3; - }else{ - putc(0, out); - k += 3; - } - } - break; - } - case SQLITE_INSERT: { - for(k=1, i=0; i<nCol; i++){ - if( aiFlg[i] ){ - putValue(out, sqlite3_column_value(pStmt,k)); - k++; - }else{ - putValue(out, sqlite3_column_value(pStmt,k+2)); - k += 3; - } - } - break; - } - case SQLITE_DELETE: { - for(k=1, i=0; i<nCol; i++){ - if( aiFlg[i] ){ - putValue(out, sqlite3_column_value(pStmt,k)); - k++; - }else{ - putValue(out, sqlite3_column_value(pStmt,k+1)); - k += 3; - } - } - break; - } - } - } - sqlite3_finalize(pStmt); - -end_changeset_one_table: - while( nCol>0 ) sqlite3_free(azCol[--nCol]); - sqlite3_free(azCol); - sqlite3_free(aiPk); - sqlite3_free(zId); -} - -/* -** Print sketchy documentation for this utility program -*/ -static void showHelp(void){ - printf("Usage: %s [options] DB1 DB2\n", g.zArgv0); - printf( -"Output SQL text that would transform DB1 into DB2.\n" -"Options:\n" -" --changeset FILE Write a CHANGESET into FILE\n" -" -L|--lib LIBRARY Load an SQLite extension library\n" -" --primarykey Use schema-defined PRIMARY KEYs\n" -" --rbu Output SQL to create/populate RBU table(s)\n" -" --schema Show only differences in the schema\n" -" --summary Show only a summary of the differences\n" -" --table TAB Show only differences in table TAB\n" - ); -} - -int main(int argc, char **argv){ - const char *zDb1 = 0; - const char *zDb2 = 0; - int i; - int rc; - char *zErrMsg = 0; - char *zSql; - sqlite3_stmt *pStmt; - char *zTab = 0; - FILE *out = stdout; - void (*xDiff)(const char*,FILE*) = diff_one_table; - int nExt = 0; - char **azExt = 0; - - g.zArgv0 = argv[0]; - sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); - for(i=1; i<argc; i++){ - const char *z = argv[i]; - if( z[0]=='-' ){ - z++; - if( z[0]=='-' ) z++; - if( strcmp(z,"changeset")==0 ){ - if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); - out = fopen(argv[++i], "wb"); - if( out==0 ) cmdlineError("cannot open: %s", argv[i]); - xDiff = changeset_one_table; - }else - if( strcmp(z,"debug")==0 ){ - if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); - g.fDebug = strtol(argv[++i], 0, 0); - }else - if( strcmp(z,"help")==0 ){ - showHelp(); - return 0; - }else -#ifndef SQLITE_OMIT_LOAD_EXTENSION - if( strcmp(z,"lib")==0 || strcmp(z,"L")==0 ){ - if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); - azExt = realloc(azExt, sizeof(azExt[0])*(nExt+1)); - if( azExt==0 ) cmdlineError("out of memory"); - azExt[nExt++] = argv[++i]; - }else -#endif - if( strcmp(z,"primarykey")==0 ){ - g.bSchemaPK = 1; - }else - if( strcmp(z,"rbu")==0 ){ - xDiff = rbudiff_one_table; - }else - if( strcmp(z,"schema")==0 ){ - g.bSchemaOnly = 1; - }else - if( strcmp(z,"summary")==0 ){ - xDiff = summarize_one_table; - }else - if( strcmp(z,"table")==0 ){ - if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); - zTab = argv[++i]; - }else - { - cmdlineError("unknown option: %s", argv[i]); - } - }else if( zDb1==0 ){ - zDb1 = argv[i]; - }else if( zDb2==0 ){ - zDb2 = argv[i]; - }else{ - cmdlineError("unknown argument: %s", argv[i]); - } - } - if( zDb2==0 ){ - cmdlineError("two database arguments required"); - } - rc = sqlite3_open(zDb1, &g.db); - if( rc ){ - cmdlineError("cannot open database file \"%s\"", zDb1); - } - rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, &zErrMsg); - if( rc || zErrMsg ){ - cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb1); - } -#ifndef SQLITE_OMIT_LOAD_EXTENSION - sqlite3_enable_load_extension(g.db, 1); - for(i=0; i<nExt; i++){ - rc = sqlite3_load_extension(g.db, azExt[i], 0, &zErrMsg); - if( rc || zErrMsg ){ - cmdlineError("error loading %s: %s", azExt[i], zErrMsg); - } - } -#endif - free(azExt); - zSql = sqlite3_mprintf("ATTACH %Q as aux;", zDb2); - rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg); - if( rc || zErrMsg ){ - cmdlineError("cannot attach database \"%s\"", zDb2); - } - rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_master", 0, 0, &zErrMsg); - if( rc || zErrMsg ){ - cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb2); - } - - if( zTab ){ - xDiff(zTab, out); - }else{ - /* Handle tables one by one */ - pStmt = db_prepare( - "SELECT name FROM main.sqlite_master\n" - " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" - " UNION\n" - "SELECT name FROM aux.sqlite_master\n" - " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" - " ORDER BY name" - ); - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - xDiff((const char*)sqlite3_column_text(pStmt,0), out); - } - sqlite3_finalize(pStmt); - } - - /* TBD: Handle trigger differences */ - /* TBD: Handle view differences */ - sqlite3_close(g.db); - return 0; -} diff --git a/lib/libsqlite3/tool/stack_usage.tcl b/lib/libsqlite3/tool/stack_usage.tcl deleted file mode 100644 index b3574f026e0..00000000000 --- a/lib/libsqlite3/tool/stack_usage.tcl +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/tclsh -# -# Parse the output of -# -# objdump -d sqlite3.o -# -# for x64 and generate a report showing: -# -# (1) Stack used by each function -# (2) Recursion paths and their aggregate stack depth -# -set getStack 0 -while {![eof stdin]} { - set line [gets stdin] - if {[regexp {^[0-9a-f]+ <([^>]+)>:\s*$} $line all procname]} { - set curfunc $procname - set root($curfunc) 1 - set calls($curfunc) {} - set calledby($curfunc) {} - set recursive($curfunc) {} - set stkdepth($curfunc) 0 - set getStack 1 - continue - } - if {[regexp {callq? +[0-9a-z]+ <([^>]+)>} $line all other]} { - set key [list $curfunc $other] - set callpair($key) 1 - unset -nocomplain root($curfunc) - continue - } - if {[regexp {sub +\$(0x[0-9a-z]+),%[er]sp} $line all xdepth]} { - if {$getStack} { - scan $xdepth %x depth - set stkdepth($curfunc) $depth - set getStack 0 - } - continue - } -} - -puts "****************** Stack Usage By Function ********************" -set sdlist {} -foreach f [array names stkdepth] { - lappend sdlist [list $stkdepth($f) $f] -} -foreach sd [lsort -integer -decr -index 0 $sdlist] { - foreach {depth fname} $sd break - puts [format {%6d %s} $depth $fname] -} - -puts "****************** Stack Usage By Recursion *******************" -foreach key [array names callpair] { - foreach {from to} $key break - lappend calls($from) $to - # lappend calledby($to) $from -} -proc all_descendents {root} { - global calls recursive - set todo($root) $root - set go 1 - while {$go} { - set go 0 - foreach f [array names todo] { - set path $todo($f) - unset todo($f) - if {![info exists calls($f)]} continue - foreach x $calls($f) { - if {$x==$root} { - lappend recursive($root) [concat $path $root] - } elseif {![info exists d($x)]} { - set go 1 - set todo($x) [concat $path $x] - set d($x) 1 - } - } - } - } - return [array names d] -} -set pathlist {} -foreach f [array names recursive] { - all_descendents $f - foreach m $recursive($f) { - set depth 0 - foreach b [lrange $m 0 end-1] { - set depth [expr {$depth+$stkdepth($b)}] - } - lappend pathlist [list $depth $m] - } -} -foreach path [lsort -integer -decr -index 0 $pathlist] { - foreach {depth m} $path break - set first [lindex $m 0] - puts [format {%6d %s %d} $depth $first $stkdepth($first)] - foreach b [lrange $m 1 end] { - puts " $b $stkdepth($b)" - } -} diff --git a/lib/libsqlite3/tool/symbols-mingw.sh b/lib/libsqlite3/tool/symbols-mingw.sh deleted file mode 100644 index bf93eec7c6b..00000000000 --- a/lib/libsqlite3/tool/symbols-mingw.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -# -# Run this script in a directory that contains a valid SQLite makefile in -# order to verify that unintentionally exported symbols. -# -make sqlite3.c - -echo '****** Exported symbols from a build including RTREE && FTS4 ******' -gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \ - -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ - -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ - -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ - sqlite3.c -nm sqlite3.o | grep " [TD] " - -echo '****** Surplus symbols from a build including RTREE & FTS4 ******' -nm sqlite3.o | grep " [TD] " | grep -v " .*sqlite3_" - -echo '****** Dependencies of the core. No extensions. No OS interface *******' -gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ - -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ - -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ - -DSQLITE_OS_OTHER -DSQLITE_THREADSAFE=0 \ - sqlite3.c -nm sqlite3.o | grep " U " - -echo '****** Dependencies including RTREE & FTS4 *******' -gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \ - -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ - -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ - -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ - sqlite3.c -nm sqlite3.o | grep " U " diff --git a/lib/libsqlite3/tool/symbols.sh b/lib/libsqlite3/tool/symbols.sh deleted file mode 100644 index befffce5c4c..00000000000 --- a/lib/libsqlite3/tool/symbols.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# Run this script in a directory that contains a valid SQLite makefile in -# order to verify that unintentionally exported symbols. -# -make sqlite3.c - -echo '****** Exported symbols from a build including RTREE, FTS4 & ICU ******' -gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \ - -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ - -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ - -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ - -DSQLITE_ENABLE_ICU \ - sqlite3.c -nm sqlite3.o | grep ' [TD] ' | sort -k 3 - -echo '****** Surplus symbols from a build including RTREE, FTS4 & ICU ******' -nm sqlite3.o | grep ' [TD] ' | grep -v ' .*sqlite3_' - -echo '****** Dependencies of the core. No extensions. No OS interface *******' -gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ - -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ - -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ - -DSQLITE_OS_OTHER -DSQLITE_THREADSAFE=0 \ - sqlite3.c -nm sqlite3.o | grep ' U ' | sort -k 3 - -echo '****** Dependencies including RTREE & FTS4 *******' -gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \ - -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ - -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ - -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ - sqlite3.c -nm sqlite3.o | grep ' U ' | sort -k 3 diff --git a/lib/libsqlite3/tool/tostr.awk b/lib/libsqlite3/tool/tostr.awk deleted file mode 100644 index 83c6cc1a50a..00000000000 --- a/lib/libsqlite3/tool/tostr.awk +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/awk -# -# Convert input text into a C string -# -{ - gsub(/\\/,"\\\\"); - gsub(/\"/,"\\\""); - print "\"" $0 "\\n\""; -} diff --git a/lib/libsqlite3/tool/varint.c b/lib/libsqlite3/tool/varint.c deleted file mode 100644 index f4a51118b4d..00000000000 --- a/lib/libsqlite3/tool/varint.c +++ /dev/null @@ -1,123 +0,0 @@ -/* -** A utility program to translate SQLite varints into decimal and decimal -** integers into varints. -*/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#if defined(_MSC_VER) || defined(__BORLANDC__) - typedef __int64 i64; - typedef unsigned __int64 u64; -#else - typedef long long int i64; - typedef unsigned long long int u64; -#endif - -static int hexValue(char c){ - if( c>='0' && c<='9' ) return c - '0'; - if( c>='a' && c<='f' ) return c - 'a' + 10; - if( c>='A' && c<='F' ) return c - 'A' + 10; - return -1; -} - -static char toHex(unsigned char c){ - return "0123456789abcdef"[c&0xf]; -} - -static int putVarint(unsigned char *p, u64 v){ - int i, j, n; - unsigned char buf[10]; - if( v & (((u64)0xff000000)<<32) ){ - p[8] = (unsigned char)v; - v >>= 8; - for(i=7; i>=0; i--){ - p[i] = (unsigned char)((v & 0x7f) | 0x80); - v >>= 7; - } - return 9; - } - n = 0; - do{ - buf[n++] = (unsigned char)((v & 0x7f) | 0x80); - v >>= 7; - }while( v!=0 ); - buf[0] &= 0x7f; - for(i=0, j=n-1; j>=0; j--, i++){ - p[i] = buf[j]; - } - return n; -} - - -int main(int argc, char **argv){ - int i; - u64 x; - u64 uX = 0; - i64 iX; - int n; - unsigned char zHex[20]; - - if( argc==1 ){ - fprintf(stderr, - "Usage:\n" - " %s HH HH HH ... Convert varint to decimal\n" - " %s DDDDD Convert decimal to varint\n" - " Add '+' or '-' before DDDDD to disambiguate.\n", - argv[0], argv[0]); - exit(1); - } - if( argc>2 - || (strlen(argv[1])==2 && hexValue(argv[1][0])>=0 && hexValue(argv[1][1])>=0) - ){ - /* Hex to decimal */ - for(i=1; i<argc && i<9; i++){ - if( strlen(argv[i])!=2 ){ - fprintf(stderr, "Not a hex byte: %s\n", argv[i]); - exit(1); - } - x = (hexValue(argv[i][0])<<4) + hexValue(argv[i][1]); - uX = (uX<<7) + (x&0x7f); - if( (x&0x80)==0 ) break; - } - if( i==9 && i<argc ){ - if( strlen(argv[i])!=2 ){ - fprintf(stderr, "Not a hex byte: %s\n", argv[i]); - exit(1); - } - x = (hexValue(argv[i][0])<<4) + hexValue(argv[i][1]); - uX = (uX<<8) + x; - } - i++; - if( i<argc ){ - fprintf(stderr, "Extra arguments: %s...\n", argv[i]); - exit(1); - } - }else{ - char *z = argv[1]; - int sign = 1; - if( z[0]=='+' ) z++; - else if( z[0]=='-' ){ z++; sign = -1; } - uX = 0; - while( z[0] ){ - if( z[0]<'0' || z[0]>'9' ){ - fprintf(stderr, "Not a decimal number: %s", argv[1]); - exit(1); - } - uX = uX*10 + z[0] - '0'; - z++; - } - if( sign<0 ){ - memcpy(&iX, &uX, 8); - iX = -iX; - memcpy(&uX, &iX, 8); - } - } - n = putVarint(zHex, uX); - printf("%lld =", (i64)uX); - for(i=0; i<n; i++){ - printf(" %c%c", toHex(zHex[i]>>4), toHex(zHex[i]&0x0f)); - } - printf("\n"); - return 0; -} diff --git a/lib/libsqlite3/tool/vdbe-compress.tcl b/lib/libsqlite3/tool/vdbe-compress.tcl deleted file mode 100644 index 9477f4afe62..00000000000 --- a/lib/libsqlite3/tool/vdbe-compress.tcl +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/tcl -# -# This script makes modifications to the vdbe.c source file which reduce -# the amount of stack space required by the sqlite3VdbeExec() routine. -# -# The modifications performed by this script are optional. The vdbe.c -# source file will compile correctly with and without the modifications -# performed by this script. And all routines within vdbe.c will compute -# the same result. The modifications made by this script merely help -# the C compiler to generate code for sqlite3VdbeExec() that uses less -# stack space. -# -# Script usage: -# -# mv vdbe.c vdbe.c.template -# tclsh vdbe-compress.tcl $CFLAGS <vdbe.c.template >vdbe.c -# -# Modifications made: -# -# All modifications are within the sqlite3VdbeExec() function. The -# modifications seek to reduce the amount of stack space allocated by -# this routine by moving local variable declarations out of individual -# opcode implementations and into a single large union. The union contains -# a separate structure for each opcode and that structure contains the -# local variables used by that opcode. In this way, the total amount -# of stack space required by sqlite3VdbeExec() is reduced from the -# sum of all local variables to the maximum of the local variable space -# required for any single opcode. -# -# In order to be recognized by this script, local variables must appear -# on the first line after the open curly-brace that begins a new opcode -# implementation. Local variables must not have initializers, though they -# may be commented. -# -# The union definition is inserted in place of a special marker comment -# in the preamble to the sqlite3VdbeExec() implementation. -# -############################################################################# -# -set beforeUnion {} ;# C code before union -set unionDef {} ;# C code of the union -set afterUnion {} ;# C code after the union -set sCtr 0 ;# Context counter - -# If the SQLITE_SMALL_STACK compile-time option is missing, then -# this transformation becomes a no-op. -# -if {![regexp {SQLITE_SMALL_STACK} $argv]} { - while {![eof stdin]} { - puts [gets stdin] - } - exit -} - -# Read program text up to the spot where the union should be -# inserted. -# -while {![eof stdin]} { - set line [gets stdin] - if {[regexp {INSERT STACK UNION HERE} $line]} break - append beforeUnion $line\n -} - -# Process the remaining text. Build up the union definition as we go. -# -set vlist {} -set seenDecl 0 -set namechars {abcdefghijklmnopqrstuvwxyz} -set nnc [string length $namechars] -while {![eof stdin]} { - set line [gets stdin] - if {[regexp "^case (OP_\\w+): \173" $line all operator]} { - append afterUnion $line\n - set vlist {} - while {![eof stdin]} { - set line [gets stdin] - if {[regexp {^ +(const )?\w+ \**(\w+)(\[.*\])?;} $line \ - all constKeyword vname notused1]} { - if {!$seenDecl} { - set sname {} - append sname [string index $namechars [expr {$sCtr/$nnc}]] - append sname [string index $namechars [expr {$sCtr%$nnc}]] - incr sCtr - append unionDef " struct ${operator}_stack_vars \173\n" - append afterUnion \ - "#if 0 /* local variables moved into u.$sname */\n" - set seenDecl 1 - } - append unionDef " $line\n" - append afterUnion $line\n - lappend vlist $vname - } elseif {[regexp {^#(if|endif)} $line] && [llength $vlist]>0} { - append unionDef "$line\n" - append afterUnion $line\n - } else { - break - } - } - if {$seenDecl} { - append unionDef " \175 $sname;\n" - append afterUnion "#endif /* local variables moved into u.$sname */\n" - } - set seenDecl 0 - } - if {[regexp "^\175" $line]} { - append afterUnion $line\n - set vlist {} - } elseif {[llength $vlist]>0} { - append line " " - foreach v $vlist { - regsub -all "(\[^a-zA-Z0-9>.\])${v}(\\W)" $line "\\1u.$sname.$v\\2" line - regsub -all "(\[^a-zA-Z0-9>.\])${v}(\\W)" $line "\\1u.$sname.$v\\2" line - - # The expressions above fail to catch instance of variable "abc" in - # expressions like (32>abc). The following expression makes those - # substitutions. - regsub -all "(\[^-\])>${v}(\\W)" $line "\\1>u.$sname.$v\\2" line - } - append afterUnion [string trimright $line]\n - } elseif {$line=="" && [eof stdin]} { - # no-op - } else { - append afterUnion $line\n - } -} - -# Output the resulting text. -# -puts -nonewline $beforeUnion -puts " /********************************************************************" -puts " ** Automatically generated code" -puts " **" -puts " ** The following union is automatically generated by the" -puts " ** vdbe-compress.tcl script. The purpose of this union is to" -puts " ** reduce the amount of stack space required by this function." -puts " ** See comments in the vdbe-compress.tcl script for details." -puts " */" -puts " union vdbeExecUnion \173" -puts -nonewline $unionDef -puts " \175 u;" -puts " /* End automatically generated code" -puts " ********************************************************************/" -puts -nonewline $afterUnion diff --git a/lib/libsqlite3/tool/vdbe_profile.tcl b/lib/libsqlite3/tool/vdbe_profile.tcl deleted file mode 100644 index fb1f955391a..00000000000 --- a/lib/libsqlite3/tool/vdbe_profile.tcl +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/tclsh -# -# Run this script in the same directory as the "vdbe_profile.out" file. -# This script summarizes the results contained in that file. -# -if {![file readable vdbe_profile.out]} { - error "run this script in the same directory as the vdbe_profile.out file" -} -set in [open vdbe_profile.out r] -set stmt {} -set allstmt {} -while {![eof $in]} { - set line [gets $in] - if {$line==""} continue - if {[regexp {^---- } $line]} { - set stmt [lindex $line 1] - if {[info exists cnt($stmt)]} { - incr cnt($stmt) - set firsttime 0 - } else { - set cnt($stmt) 1 - set sql($stmt) {} - set firsttime 1 - lappend allstmt $stmt - } - continue; - } - if {[regexp {^-- } $line]} { - if {$firsttime} { - append sql($stmt) [string range $line 3 end]\n - } - continue - } - if {![regexp {^ *\d+ *\d+ *\d+ *\d+ ([A-Z].*)} $line all detail]} continue - set c [lindex $line 0] - set t [lindex $line 1] - set addr [lindex $line 3] - set op [lindex $line 4] - if {[info exists opcnt($op)]} { - incr opcnt($op) $c - incr opcycle($op) $t - } else { - set opcnt($op) $c - set opcycle($op) $t - } - if {[info exists stat($stmt,$addr)]} { - foreach {cx tx detail} $stat($stmt,$addr) break - incr cx $c - incr tx $t - set stat($stmt,$addr) [list $cx $tx $detail] - } else { - set stat($stmt,$addr) [list $c $t $detail] - } -} -close $in - -foreach stmt $allstmt { - puts "********************************************************************" - puts [string trim $sql($stmt)] - puts "Execution count: $cnt($stmt)" - for {set i 0} {[info exists stat($stmt,$i)]} {incr i} { - foreach {cx tx detail} $stat($stmt,$i) break - if {$cx==0} { - set ax 0 - } else { - set ax [expr {$tx/$cx}] - } - puts [format {%8d %12d %12d %4d %s} $cx $tx $ax $i $detail] - } -} -puts "********************************************************************" -puts "OPCODES:" -foreach op [lsort [array names opcnt]] { - set cx $opcnt($op) - set tx $opcycle($op) - if {$cx==0} { - set ax 0 - } else { - set ax [expr {$tx/$cx}] - } - puts [format {%8d %12d %12d %s} $cx $tx $ax $op] -} diff --git a/lib/libsqlite3/tool/warnings-clang.sh b/lib/libsqlite3/tool/warnings-clang.sh deleted file mode 100644 index 7a0aa4bce7f..00000000000 --- a/lib/libsqlite3/tool/warnings-clang.sh +++ /dev/null @@ -1,14 +0,0 @@ -#/bin/sh -# -# Run this script in a directory with a working makefile to check for -# compiler warnings in SQLite. -# -rm -f sqlite3.c -make sqlite3.c -echo '************* FTS4 and RTREE ****************' -scan-build gcc -c -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \ - -DSQLITE_DEBUG -DSQLITE_ENABLE_STAT3 sqlite3.c 2>&1 | grep -v 'ANALYZE:' -echo '********** ENABLE_STAT3. THREADSAFE=0 *******' -scan-build gcc -c -I. -DSQLITE_ENABLE_STAT3 -DSQLITE_THREADSAFE=0 \ - -DSQLITE_DEBUG \ - sqlite3.c ../sqlite/src/shell.c -ldl 2>&1 | grep -v 'ANALYZE:' diff --git a/lib/libsqlite3/tool/warnings.sh b/lib/libsqlite3/tool/warnings.sh deleted file mode 100644 index d69cbaf5dbc..00000000000 --- a/lib/libsqlite3/tool/warnings.sh +++ /dev/null @@ -1,41 +0,0 @@ -#/bin/sh -# -# Run this script in a directory with a working makefile to check for -# compiler warnings in SQLite. -# -rm -f sqlite3.c -make sqlite3.c -echo '********** No optimizations. Includes FTS4 and RTREE *********' -gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \ - -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \ - sqlite3.c -echo '********** Android configuration ******************************' -gcc -c \ - -DHAVE_USLEEP=1 \ - -DSQLITE_HAVE_ISNAN \ - -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 \ - -DSQLITE_THREADSAFE=2 \ - -DSQLITE_TEMP_STORE=3 \ - -DSQLITE_POWERSAFE_OVERWRITE=1 \ - -DSQLITE_DEFAULT_FILE_FORMAT=4 \ - -DSQLITE_DEFAULT_AUTOVACUUM=1 \ - -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 \ - -DSQLITE_ENABLE_FTS3 \ - -DSQLITE_ENABLE_FTS3_BACKWARDS \ - -DSQLITE_ENABLE_FTS4 \ - -DSQLITE_OMIT_BUILTIN_TEST \ - -DSQLITE_OMIT_COMPILEOPTION_DIAGS \ - -DSQLITE_OMIT_LOAD_EXTENSION \ - -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600 \ - -DSQLITE_ENABLE_ICU \ - -DUSE_PREAD64 \ - -Wshadow -Wall -Wextra \ - -Os sqlite3.c shell.c -echo '********** No optimizations. ENABLE_STAT4. THREADSAFE=0 *******' -gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \ - -ansi -DSQLITE_ENABLE_STAT4 -DSQLITE_THREADSAFE=0 \ - sqlite3.c -echo '********** Optimized -O3. Includes FTS4 and RTREE ************' -gcc -O3 -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \ - -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \ - sqlite3.c diff --git a/lib/libsqlite3/tool/win/sqlite.vsix b/lib/libsqlite3/tool/win/sqlite.vsix Binary files differdeleted file mode 100644 index 1450011266b..00000000000 --- a/lib/libsqlite3/tool/win/sqlite.vsix +++ /dev/null |