diff --git a/.travis.yml b/.travis.yml index 25529f5cd..c111cbc8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,101 @@ language: cpp -compiler: - - gcc - - clang -before_install: - - sudo apt-get update -qq -# - sudo DEBIAN_FRONTEND=noninteractive apt-get -qq -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade - - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev -script: ./configure && make -s -j2 +cache: + - apt + +before_install: + # we need a recent version of CMake + - sudo add-apt-repository -y ppa:andykimpe/cmake3 + - sudo apt-get update -qq + - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev g++-arm-linux-gnueabi g++-arm-linux-gnueabihf sloccount cppcheck + +services: + - mongodb + +env: + global: TEST_NAME="" + +before_script: + - echo ${TEST_NAME} + +matrix: + include: + - env: TEST_NAME="gcc (make)" + compiler: gcc + script: + - ./configure && make -s -j2 + +# TODO add this as soon as Linux-clang config is ready +# - env: TEST_NAME="clang (make)" +# compiler: clang +# script: +# - ./configure --config=Linux-clang && make -s -j2 + + - env: TEST_NAME="arm-linux-gnueabi- (make)" + script: + - ./configure --omit=Data/ODBC,Data/MySQL,Crypto,NetSSL,PageCompiler && make -s -j2 CROSS_COMPILE=arm-linux-gnueabi- POCO_TARGET_OSARCH=armv7l + + - env: TEST_NAME="gcc (CMake)" + compiler: gcc + script: + - sudo apt-get install -qq -y cmake3 + # disable tests, gcc-4.6 gets an internal compiler error + - mkdir cmake-build && cd cmake-build && cmake -DENABLE_TESTS=OFF .. && make -j2 && cd .. + + - env: TEST_NAME="gcc-4.8 (CMake)" + compiler: gcc + script: + - sudo apt-get install -qq -y cmake3 + - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + - sudo apt-get update -qq + - sudo apt-get install -qq -y g++-4.8 + - export CC="gcc-4.8" + - export CXX="g++-4.8" + - mkdir cmake-build && cd cmake-build && cmake -DENABLE_TESTS=ON .. && make -j2 && cd .. + + - env: TEST_NAME="clang (CMake)" + compiler: clang + script: + - sudo apt-get install -qq -y cmake3 + - mkdir cmake-build && cd cmake-build && cmake -DENABLE_TESTS=ON .. && make -j2 && cd .. + + - env: TEST_NAME="arm-linux-gnueabi-g++ (CMake)" + script: + - sudo apt-get install -qq -y cmake3 + - export CC="arm-linux-gnueabi-gcc" + - export CXX="arm-linux-gnueabi-g++" + - mkdir cmake-build && cd cmake-build && cmake -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_TESTS=ON .. && make -j2 && cd .. + + - env: TEST_NAME="arm-linux-gnueabihf-g++ (CMake)" + script: + - sudo apt-get install -qq -y cmake3 + - export CC="arm-linux-gnueabihf-gcc" + - export CXX="arm-linux-gnueabihf-g++" + - mkdir cmake-build && cd cmake-build && cmake -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_TESTS=ON .. && make -j2 && cd .. + + # TODO osx build + # TODO run test suite + # script: + # - ./configure && make -s -j2 + # - sudo ifconfig -a + # - sudo ifconfig venet0 multicast + # - sudo ifconfig -a + # - export POCO_BASE=`pwd` + # - sudo -E build/script/runtests.sh + + # QA jobs for code analytics and metrics + # static code analysis with cppcheck (we can add --enable=all later) + - env: TEST_NAME="cppcheck" + script: cppcheck --force --quiet --inline-suppr -j2 -iData/SQLite/src/sqlite3.c . + # search for TODO within source tree + - env: TEST_NAME="TODO" + script: grep -r TODO * + # search for FIXME within source tree + - env: TEST_NAME="FIXME" + script: grep -r FIXME * + # search for HACK within source tree + - env: TEST_NAME="HACK" + script: grep -r HACK * + # some statistics about the code base + - env: TEST_NAME="sloccount" + script: sloccount . diff --git a/ApacheConnector/CMakeLists.txt b/ApacheConnector/CMakeLists.txt index 447488cc3..4328c18b6 100644 --- a/ApacheConnector/CMakeLists.txt +++ b/ApacheConnector/CMakeLists.txt @@ -8,14 +8,18 @@ POCO_SOURCES_AUTO( SRCS ${SRCS_G}) file(GLOB_RECURSE HDRS_G "include/*.h" ) POCO_HEADERS_AUTO( SRCS ${HDRS_G}) -include_directories( "include" ) - -add_library( ${LIBNAME} SHARED ${SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" SHARED ${SRCS} ) +set_target_properties( "${LIBNAME}" PROPERTIES VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} DEFINE_SYMBOL ApacheHandlers_EXPORTS) -target_link_libraries( ${LIBNAME} ) +target_link_libraries( "${LIBNAME}" ) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) if (ENABLE_TESTS) add_subdirectory(samples) diff --git a/CMakeLists.txt b/CMakeLists.txt index d92438f68..296d2b719 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(Poco) -cmake_minimum_required(VERSION 2.8.0) +cmake_minimum_required(VERSION 3.0.0) file(STRINGS "${CMAKE_SOURCE_DIR}/libversion" SHARED_LIBRARY_VERSION) @@ -75,12 +75,18 @@ option(ENABLE_PDF "Enable PDF" ON) option(ENABLE_UTIL "Enable Util" ON) option(ENABLE_NET "Enable Net" ON) option(ENABLE_NETSSL "Enable NetSSL" ON) +option(ENABLE_NETSSL_WIN "Enable NetSSL Windows" ON) option(ENABLE_CRYPTO "Enable Crypto" ON) option(ENABLE_DATA "Enable Data" ON) +option(ENABLE_DATA_SQLITE "Enable Data SQlite" ON) +option(ENABLE_DATA_MYSQL "Enable Data MySQL" ON) +option(ENABLE_DATA_ODBC "Enable Data ODBC" ON) option(ENABLE_SEVENZIP "Enable SevenZip" ON) option(ENABLE_ZIP "Enable Zip" ON) option(ENABLE_APACHECONNECTOR "Enable ApacheConnector" ON) +option(FORCE_OPENSSL "Force usage of OpenSSL even under windows" OFF) + option(ENABLE_TESTS "Set to OFF|ON (default is OFF) to control build of POCO tests & samples" OFF) @@ -115,32 +121,21 @@ else () message(STATUS "Build with using internal copy of sqlite, libz, pcre, expat, ...") endif () -# Set local include path -include_directories( CppUnit/include CppUnit/WinTestRunner/include Foundation/include XML/include Net/include NetSSL_OpenSSL/include Util/include Data/include Data/MySQL/include Data/SQLite/include Data/ODBC/include Zip/include Crypto/include Web/include JSON/include MongoDB/include PDF/include SevenZip/include) - include(CheckTypeSize) find_package(Cygwin) -#include(CMakeDetermineCompilerId) - # OS Detection -if(CMAKE_SYSTEM MATCHES "Windows") +if(WIN32) + add_definitions( -DPOCO_OS_FAMILY_WINDOWS -DUNICODE -D_UNICODE) + #set(SYSLIBS iphlpapi gdi32 odbc32) +endif(WIN32) - add_definitions( -DPOCO_OS_FAMILY_WINDOWS) - set(SYSLIBS iphlpapi gdi32 odbc32) - - if (CMAKE_C_COMPILER_ID MATCHES "MSVC") - message(STATUS "XXX: MS Visual Compiler detected") - endif (CMAKE_C_COMPILER_ID MATCHES "MSVC") - -endif(CMAKE_SYSTEM MATCHES "Windows") - -if (CMAKE_SYSTEM MATCHES "Linux" AND NOT ANDROID ) +if (UNIX AND NOT ANDROID ) add_definitions( -DPOCO_OS_FAMILY_UNIX ) # Standard 'must be' defines add_definitions( -D_XOPEN_SOURCE=500 -D_REENTRANT -D_THREAD_SAFE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) set(SYSLIBS pthread dl rt) -endif(CMAKE_SYSTEM MATCHES "Linux" AND NOT ANDROID ) +endif(UNIX AND NOT ANDROID ) if (CMAKE_SYSTEM MATCHES "SunOS") add_definitions( -DPOCO_OS_FAMILY_UNIX ) @@ -150,15 +145,15 @@ if (CMAKE_SYSTEM MATCHES "SunOS") endif(CMAKE_SYSTEM MATCHES "SunOS") if (CMAKE_COMPILER_IS_MINGW) - add_definitions(-DWC_NO_BEST_FIT_CHARS=0x400 -DPOCO_WIN32_UTF8) - add_definitions(-mno-cygwin -D_WIN32 -DMINGW32 -DWINVER=0x500 -DODBCVER=0x0300 -DPOCO_THREAD_STACK_SIZE -DFoundation_Config_INCLUDED ) + add_definitions(-DWC_NO_BEST_FIT_CHARS=0x400 -DPOCO_WIN32_UTF8) + add_definitions(-mno-cygwin -D_WIN32 -DMINGW32 -DWINVER=0x500 -DODBCVER=0x0300 -DPOCO_THREAD_STACK_SIZE -DFoundation_Config_INCLUDED ) link_directories(/usr/local/lib /usr/lib) include_directories(/usr/local/include /usr/include) endif (CMAKE_COMPILER_IS_MINGW) -if (CMAKE_COMPILER_IS_CYGWIN) +if (CYGWIN) # add_definitions(-DWC_NO_BEST_FIT_CHARS=0x400 -DPOCO_WIN32_UTF8) -endif (CMAKE_COMPILER_IS_CYGWIN) +endif (CYGWIN) # SunPro C++ if (${CMAKE_CXX_COMPILER_ID} MATCHES "SunPro") @@ -170,10 +165,14 @@ if (IOS) add_definitions( -DPOCO_HAVE_IPv6 -DPOCO_NO_FPENVIRONMENT -DPOCO_NO_STAT64 -DPOCO_NO_SHAREDLIBS -DPOCO_NO_NET_IFTYPES ) endif(IOS) -#ANDROID +#Android if (ANDROID) add_definitions( -DPOCO_ANDROID -DPOCO_NO_FPENVIRONMENT -DPOCO_NO_WSTRING -DPOCO_NO_SHAREDMEMORY ) -endif() +endif(ANDROID) + + +# Collect the built libraries and include dirs, the will be used to create the PocoConfig.cmake file +set(Poco_COMPONENTS "") if (ENABLE_TESTS) add_subdirectory(CppUnit) @@ -182,43 +181,62 @@ endif () add_subdirectory(Foundation) if(ENABLE_XML) add_subdirectory(XML) +list(APPEND Poco_COMPONENTS "XML") endif() if(ENABLE_JSON) add_subdirectory(JSON) +list(APPEND Poco_COMPONENTS "JSON") endif() if(ENABLE_MONGODB) add_subdirectory(MongoDB) +list(APPEND Poco_COMPONENTS "MongoDB") endif() if(ENABLE_PDF) add_subdirectory(PDF) +list(APPEND Poco_COMPONENTS "PDF") endif() if(ENABLE_UTIL) add_subdirectory(Util) +list(APPEND Poco_COMPONENTS "Util") endif() if(ENABLE_NET) add_subdirectory(Net) +list(APPEND Poco_COMPONENTS "Net") endif() -# OPENSSL_SSL_LIBRARY + +#NetSSL + + +if(WIN32 AND ENABLE_NETSSL_WIN) + add_subdirectory(NetSSL_Win) + list(APPEND Poco_COMPONENTS "NetSSL_Win") +endif(WIN32 AND ENABLE_NETSSL_WIN) + find_package(OpenSSL) if(OPENSSL_FOUND) include_directories("${OPENSSL_INCLUDE_DIR}") if(ENABLE_NETSSL) add_subdirectory(NetSSL_OpenSSL) + list(APPEND Poco_COMPONENTS "NetSSL_OpenSSL") endif() if(ENABLE_CRYPTO) add_subdirectory(Crypto) + list(APPEND Poco_COMPONENTS "Crypto") endif() endif(OPENSSL_FOUND) if(ENABLE_DATA) add_subdirectory(Data) +list(APPEND Poco_COMPONENTS "Data") endif() if(ENABLE_SEVENZIP) add_subdirectory(SevenZip) +list(APPEND Poco_COMPONENTS "SevenZip") endif() if(ENABLE_ZIP) add_subdirectory(Zip) +list(APPEND Poco_COMPONENTS "Zip") endif() find_package(APR) @@ -227,6 +245,7 @@ if(APRUTIL_FOUND AND APACHE_FOUND) include_directories( "${APACHE_INCLUDE_DIR}" "${APRUTIL_INCLUDE_DIR}" ) if(ENABLE_APACHECONNECTOR) add_subdirectory(ApacheConnector) + list(APPEND Poco_COMPONENTS "ApacheConnector") endif() endif(APRUTIL_FOUND AND APACHE_FOUND) @@ -253,9 +272,38 @@ set(CPACK_PACKAGE_INSTALL_DIRECTORY "/usr/local") include(CPack) +############################################################# +# cmake config files + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion +) + +configure_file(cmake/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}Config.cmake" @ONLY) +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}ConfigVersion.cmake + DESTINATION + "lib/cmake/${PROJECT_NAME}" + COMPONENT + Devel +) + +# in tree build settings +#configure_file(PocoBuildTreeSettings.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/PocoBuildTreeSettings.cmake @ONLY) + + message(STATUS "CMake ${CMAKE_VERSION} successfully configured ${PROJECT_NAME} using ${CMAKE_GENERATOR} generator") message(STATUS "Installation target path: ${CMAKE_INSTALL_PREFIX}") message(STATUS "C_FLAGS: =${CMAKE_C_FLAGS}") message(STATUS "CXX_FLAGS:=${CMAKE_CXX_FLAGS}") +foreach(component ${Poco_COMPONENTS}) +message(STATUS "Building: ${component}") +endforeach() + diff --git a/CppUnit/CMakeLists.txt b/CppUnit/CMakeLists.txt index 9fbec4b0b..6ab8b1c64 100644 --- a/CppUnit/CMakeLists.txt +++ b/CppUnit/CMakeLists.txt @@ -8,12 +8,18 @@ POCO_SOURCES_AUTO( SRCS ${SRCS_G}) file(GLOB_RECURSE HDRS_G "include/*.h" ) POCO_HEADERS_AUTO( SRCS ${HDRS_G}) -add_library( ${LIBNAME} ${LIB_MODE} ${SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} ) +set_target_properties( "${LIBNAME}" PROPERTIES VERSION "1" SOVERSION "1" DEFINE_SYMBOL CppUnit_EXPORTS) -target_link_libraries( ${LIBNAME} ) +target_link_libraries( "${LIBNAME}" ) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) if(WIN32) add_subdirectory(WinTestRunner) diff --git a/CppUnit/WinTestRunner/CMakeLists.txt b/CppUnit/WinTestRunner/CMakeLists.txt index 2eaf12e54..541233bc8 100644 --- a/CppUnit/WinTestRunner/CMakeLists.txt +++ b/CppUnit/WinTestRunner/CMakeLists.txt @@ -13,15 +13,21 @@ POCO_HEADERS_AUTO( WIN_SRCS ${HDRS_G}) # TODO: Is this flag always required? add_definitions("-D_AFXDLL") +#TODO: Use instead of the flag above: find_package(MFC) -include_directories( "src" ) - -add_library( ${LIBNAME} ${LIB_MODE} ${WIN_SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${WIN_SRCS} ) +set_target_properties( "${LIBNAME}" PROPERTIES VERSION "1" SOVERSION "1" DEFINE_SYMBOL WinTestRunner_EXPORTS) -target_link_libraries( ${LIBNAME} CppUnit ) +target_link_libraries( "${LIBNAME}" CppUnit ) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) + if(WIN32) target_link_libraries( ${LIBNAME} winmm ) endif(WIN32) diff --git a/Crypto/CMakeLists.txt b/Crypto/CMakeLists.txt index 9c4210cd7..507c573e9 100644 --- a/Crypto/CMakeLists.txt +++ b/Crypto/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoCrypto") +set(LIBNAME "Crypto") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -8,29 +9,41 @@ POCO_SOURCES_AUTO( SRCS ${SRCS_G}) file(GLOB_RECURSE HDRS_G "include/*.h" ) POCO_HEADERS_AUTO( SRCS ${HDRS_G}) -add_definitions(-D_USRDLL) -include_directories( "include" ) +#add_definitions(-D_USRDLL) -add_library( ${LIBNAME} ${LIB_MODE} ${SRCS} ) -set_target_properties( ${LIBNAME} - PROPERTIES +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" + PROPERTIES VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL Crypto_EXPORTS) -target_link_libraries( ${LIBNAME} PocoFoundation ${OPENSSL_LIBRARIES} ) + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL Crypto_EXPORTS + ) +target_link_libraries( "${LIBNAME}" Foundation ${OPENSSL_LIBRARIES} ) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + if (ENABLE_TESTS) add_subdirectory(samples) add_subdirectory(testsuite) diff --git a/Crypto/cmake/PocoCryptoConfig.cmake b/Crypto/cmake/PocoCryptoConfig.cmake new file mode 100644 index 000000000..ef43e456b --- /dev/null +++ b/Crypto/cmake/PocoCryptoConfig.cmake @@ -0,0 +1,4 @@ +include(CMakeFindDependencyMacro) +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}) +find_dependency(PocoFoundation) +include("${CMAKE_CURRENT_LIST_DIR}/PocoCryptoTargets.cmake") \ No newline at end of file diff --git a/Crypto/include/Poco/Crypto/OpenSSLInitializer.h b/Crypto/include/Poco/Crypto/OpenSSLInitializer.h index f4f128dcb..868530062 100644 --- a/Crypto/include/Poco/Crypto/OpenSSLInitializer.h +++ b/Crypto/include/Poco/Crypto/OpenSSLInitializer.h @@ -22,8 +22,10 @@ #include "Poco/Crypto/Crypto.h" #include "Poco/Mutex.h" -#include -#ifdef OPENSSL_FIPS +#include "Poco/AtomicCounter.h" +#include +#include +#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_NUMBER < 0x010001000L #include #endif @@ -81,8 +83,7 @@ protected: private: static Poco::FastMutex* _mutexes; - static Poco::FastMutex _mutex; - static int _rc; + static Poco::AtomicCounter _rc; }; @@ -109,6 +110,7 @@ inline void OpenSSLInitializer::enableFIPSMode(bool /*enabled*/) } #endif + } } // namespace Poco::Crypto diff --git a/Crypto/src/OpenSSLInitializer.cpp b/Crypto/src/OpenSSLInitializer.cpp index d652d31a3..28ecd115d 100644 --- a/Crypto/src/OpenSSLInitializer.cpp +++ b/Crypto/src/OpenSSLInitializer.cpp @@ -35,8 +35,7 @@ namespace Crypto { Poco::FastMutex* OpenSSLInitializer::_mutexes(0); -Poco::FastMutex OpenSSLInitializer::_mutex; -int OpenSSLInitializer::_rc(0); +Poco::AtomicCounter OpenSSLInitializer::_rc; OpenSSLInitializer::OpenSSLInitializer() @@ -60,8 +59,6 @@ OpenSSLInitializer::~OpenSSLInitializer() void OpenSSLInitializer::initialize() { - Poco::FastMutex::ScopedLock lock(_mutex); - if (++_rc == 1) { #if OPENSSL_VERSION_NUMBER >= 0x0907000L @@ -98,8 +95,6 @@ void OpenSSLInitializer::initialize() void OpenSSLInitializer::uninitialize() { - Poco::FastMutex::ScopedLock lock(_mutex); - if (--_rc == 0) { EVP_cleanup(); @@ -109,6 +104,8 @@ void OpenSSLInitializer::uninitialize() CRYPTO_set_id_callback(0); #endif delete [] _mutexes; + + CONF_modules_free(); } } diff --git a/Crypto/testsuite/Makefile b/Crypto/testsuite/Makefile index 3e4684bc8..e1702500c 100644 --- a/Crypto/testsuite/Makefile +++ b/Crypto/testsuite/Makefile @@ -13,9 +13,6 @@ ifeq ($(POCO_CONFIG),FreeBSD) SYSLIBS += -lssl -lcrypto -lz else SYSLIBS += -lssl -lcrypto -lz -ldl - ifeq ($(POCO_CONFIG),Linux) - SYSLIBS += -lkrb5 - endif endif objects = CryptoTestSuite Driver \ diff --git a/DLLVersion.rc b/DLLVersion.rc index 4667f3d3c..e4aec7833 100644 --- a/DLLVersion.rc +++ b/DLLVersion.rc @@ -4,8 +4,8 @@ #include "winres.h" -#define POCO_VERSION 1,5,4,0 -#define POCO_VERSION_STR "1.5.4" +#define POCO_VERSION 1,6,0,0 +#define POCO_VERSION_STR "1.6.0d1" VS_VERSION_INFO VERSIONINFO FILEVERSION POCO_VERSION diff --git a/Data/CMakeLists.txt b/Data/CMakeLists.txt index 31b727b31..b70c1075c 100644 --- a/Data/CMakeLists.txt +++ b/Data/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoData") +set(LIBNAME "Data") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -17,29 +18,45 @@ if(MSVC AND NOT(MSVC_VERSION LESS 1400)) PROPERTIES COMPILE_FLAGS "/bigobj") endif() -add_library( ${LIBNAME} ${LIB_MODE} ${SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" PROPERTIES VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL Data_EXPORTS) -target_link_libraries( ${LIBNAME} PocoFoundation) + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL Data_EXPORTS + ) +target_link_libraries( "${LIBNAME}" Foundation) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + +if(ENABLE_DATA_SQLITE) # SQlite3 is built in any case add_subdirectory( SQLite ) +endif(ENABLE_DATA_SQLITE) +if(ENABLE_DATA_MYSQL) find_package(MySQL) if(MYSQL_FOUND) include_directories("${MYSQL_INCLUDE_DIR}") @@ -48,21 +65,24 @@ if(MYSQL_FOUND) else() message(STATUS "MySQL Support Disabled - no MySQL library") endif(MYSQL_FOUND) +endif(ENABLE_DATA_MYSQL) +if(ENABLE_DATA_ODBC) find_package(ODBC) -if(CMAKE_SYSTEM MATCHES "Windows") - set(ODBC_LIBRARIES "") +if(WIN32 AND NOT WINCE) + set(ODBC_LIBRARIES "odbc32" "odbccp32") message(STATUS "Windows native ODBC Support Enabled") add_subdirectory( ODBC ) -else () - if (ODBC_FOUND) +else(WIN32 AND NOT WINCE) + if(ODBC_FOUND) include_directories("${ODBC_INCLUDE_DIRECTORIES}") message(STATUS "ODBC Support Enabled") add_subdirectory( ODBC ) - else () + else() message(STATUS "ODBC Support Disabled - no ODBC runtime") - endif () -endif() + endif() +endif(WIN32 AND NOT WINCE) +endif(ENABLE_DATA_ODBC) if (ENABLE_TESTS) add_subdirectory(samples) diff --git a/Data/MySQL/CMakeLists.txt b/Data/MySQL/CMakeLists.txt index ba5014804..87a572168 100644 --- a/Data/MySQL/CMakeLists.txt +++ b/Data/MySQL/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoDataMySQL") +set(LIBNAME "DataMySQL") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -10,28 +11,39 @@ POCO_HEADERS_AUTO( MYSQL_SRCS ${HDRS_G}) add_definitions(-DTHREADSAFE -DNO_TCL) -include_directories( "include" ) - -add_library( ${LIBNAME} ${LIB_MODE} ${MYSQL_SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${MYSQL_SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" PROPERTIES VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL MySQL_EXPORTS) -target_link_libraries( ${LIBNAME} PocoData PocoFoundation ${MYSQL_LIB}) + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL MySQL_EXPORTS + ) +target_link_libraries( "${LIBNAME}" Foundation Data ${MYSQL_LIB}) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + if (ENABLE_TESTS) add_subdirectory(testsuite) endif () diff --git a/Data/MySQL/cmake/PocoDataMySQLConfig.cmake b/Data/MySQL/cmake/PocoDataMySQLConfig.cmake new file mode 100644 index 000000000..687d70f67 --- /dev/null +++ b/Data/MySQL/cmake/PocoDataMySQLConfig.cmake @@ -0,0 +1,5 @@ +include(CMakeFindDependencyMacro) +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}) +find_dependency(PocoFoundation) +find_dependency(PocoData) +include("${CMAKE_CURRENT_LIST_DIR}/PocoDataMySQLTargets.cmake") \ No newline at end of file diff --git a/Data/ODBC/CMakeLists.txt b/Data/ODBC/CMakeLists.txt index c7b7bd2b9..007dc8661 100644 --- a/Data/ODBC/CMakeLists.txt +++ b/Data/ODBC/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoDataODBC") +set(LIBNAME "DataODBC") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -8,30 +9,41 @@ POCO_SOURCES_AUTO( ODBC_SRCS ${SRCS_G}) file(GLOB_RECURSE HDRS_G "include/*.h" ) POCO_HEADERS_AUTO( ODBC_SRCS ${HDRS_G}) -add_definitions( ${ODBC_CFLAGS} ) +add_definitions( ${ODBC_CFLAGS} -DTHREADSAFE) -include_directories( "include" ) - -add_library( ${LIBNAME} ${LIB_MODE} ${ODBC_SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${ODBC_SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" PROPERTIES - VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL ODBC_EXPORTS) -target_link_libraries( ${LIBNAME} PocoData PocoFoundation ${ODBC_LIBRARIES}) + VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL ODBC_EXPORTS + ) +target_link_libraries( "${LIBNAME}" Foundation Data ${ODBC_LIBRARIES}) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + if (ENABLE_TESTS) add_subdirectory(testsuite) endif () diff --git a/Data/ODBC/cmake/PocoDataODBCConfig.cmake b/Data/ODBC/cmake/PocoDataODBCConfig.cmake new file mode 100644 index 000000000..8795de04f --- /dev/null +++ b/Data/ODBC/cmake/PocoDataODBCConfig.cmake @@ -0,0 +1,5 @@ +include(CMakeFindDependencyMacro) +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}) +find_dependency(PocoFoundation) +find_dependency(PocoData) +include("${CMAKE_CURRENT_LIST_DIR}/PocoDataODBCTargets.cmake") \ No newline at end of file diff --git a/Data/SQLite/CMakeLists.txt b/Data/SQLite/CMakeLists.txt index c182cf244..559303f24 100644 --- a/Data/SQLite/CMakeLists.txt +++ b/Data/SQLite/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoDataSQLite") +set(LIBNAME "DataSQLite") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -8,11 +9,9 @@ POCO_SOURCES_AUTO( SQLITE_SRCS ${SRCS_G}) file(GLOB_RECURSE HDRS_G "include/*.h" ) POCO_HEADERS_AUTO( SQLITE_SRCS ${HDRS_G}) -include_directories( "include" "src" ) - if (POCO_UNBUNDLED) find_package(SQLite3) - set(DATASQLITELIBS PocoData PocoFoundation ${SQLITE3_LIBRARIES}) + set(DATASQLITELIBS ${SQLITE3_LIBRARIES}) include_directories("${SQLITE3_INCLUDE_DIRS}") else() # sqlite3 @@ -24,31 +23,48 @@ else() src/sqlite3.h ) - set(DATASQLITELIBS PocoData PocoFoundation) + set(DATASQLITELIBS "") endif() +if(WINCE) + add_definitions(-DSQLITE_MSVC_LOCALTIME_API) +endif(WINCE) + add_definitions(-DSQLITE_THREADSAFE=1 -DSQLITE_DISABLE_LFS -DSQLITE_OMIT_UTF16 -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_COMPLETE -DSQLITE_OMIT_TCL_VARIABLE -DSQLITE_OMIT_DEPRECATED) -add_library( ${LIBNAME} ${LIB_MODE} ${SQLITE_SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${SQLITE_SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" PROPERTIES VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL SQLite_EXPORTS) -target_link_libraries( ${LIBNAME} ${DATASQLITELIBS} ) + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL SQLite_EXPORTS + ) +target_link_libraries( "${LIBNAME}" Foundation Data ${DATASQLITELIBS} ) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + if (ENABLE_TESTS) add_subdirectory(testsuite) endif () diff --git a/Data/SQLite/cmake/PocoDataSQLiteConfig.cmake b/Data/SQLite/cmake/PocoDataSQLiteConfig.cmake new file mode 100644 index 000000000..7b27debfc --- /dev/null +++ b/Data/SQLite/cmake/PocoDataSQLiteConfig.cmake @@ -0,0 +1,5 @@ +include(CMakeFindDependencyMacro) +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}) +find_dependency(PocoFoundation) +find_dependency(PocoData) +include("${CMAKE_CURRENT_LIST_DIR}/PocoDataSQLiteTargets.cmake") \ No newline at end of file diff --git a/Data/SQLite/src/SessionImpl.cpp b/Data/SQLite/src/SessionImpl.cpp index f1f72f71f..2440a8749 100644 --- a/Data/SQLite/src/SessionImpl.cpp +++ b/Data/SQLite/src/SessionImpl.cpp @@ -28,6 +28,11 @@ #include +#ifndef SQLITE_OPEN_URI +#define SQLITE_OPEN_URI 0 +#endif + + namespace Poco { namespace Data { namespace SQLite { @@ -150,7 +155,7 @@ private: inline int connectImpl() { - return sqlite3_open(_connectString.c_str(), _ppDB); + return sqlite3_open_v2(_connectString.c_str(), _ppDB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI, NULL); } std::string _connectString; @@ -184,7 +189,8 @@ void SessionImpl::open(const std::string& connect) close(); Utility::throwException(rc); } - } catch (SQLiteException& ex) + } + catch (SQLiteException& ex) { throw ConnectionFailedException(ex.displayText()); } diff --git a/Data/SQLite/src/Utility.cpp b/Data/SQLite/src/Utility.cpp index 0d412fe12..cf4593489 100644 --- a/Data/SQLite/src/Utility.cpp +++ b/Data/SQLite/src/Utility.cpp @@ -29,6 +29,11 @@ #endif +#ifndef SQLITE_OPEN_URI +#define SQLITE_OPEN_URI 0 +#endif + + namespace Poco { namespace Data { namespace SQLite { @@ -55,6 +60,7 @@ const std::string Utility::SQLITE_TIME_FORMAT = "%H:%M:%S"; Utility::TypeMap Utility::_types; Poco::Mutex Utility::_mutex; + Utility::Utility() { Poco::Mutex::ScopedLock l(_mutex); @@ -158,6 +164,8 @@ void Utility::throwException(int rc, const std::string& addErrMsg) case SQLITE_ABORT: throw ExecutionAbortedException(std::string("Callback routine requested an abort"), addErrMsg); case SQLITE_BUSY: + case SQLITE_BUSY_RECOVERY: + case SQLITE_BUSY_SNAPSHOT: throw DBLockedException(std::string("The database file is locked"), addErrMsg); case SQLITE_LOCKED: throw TableLockedException(std::string("A table in the database is locked"), addErrMsg); @@ -217,7 +225,7 @@ bool Utility::fileToMemory(sqlite3* pInMemory, const std::string& fileName) sqlite3* pFile; sqlite3_backup* pBackup; - rc = sqlite3_open(fileName.c_str(), &pFile); + rc = sqlite3_open_v2(fileName.c_str(), &pFile, SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, NULL); if(rc == SQLITE_OK ) { pBackup = sqlite3_backup_init(pInMemory, "main", pFile, "main"); @@ -240,7 +248,7 @@ bool Utility::memoryToFile(const std::string& fileName, sqlite3* pInMemory) sqlite3* pFile; sqlite3_backup* pBackup; - rc = sqlite3_open(fileName.c_str(), &pFile); + rc = sqlite3_open_v2(fileName.c_str(), &pFile, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI, NULL); if(rc == SQLITE_OK ) { pBackup = sqlite3_backup_init(pFile, "main", pInMemory, "main"); @@ -306,6 +314,4 @@ void* Utility::eventHookRegister(sqlite3* pDB, RollbackCallbackType callbackFn, } - - } } } // namespace Poco::Data::SQLite diff --git a/Data/SQLite/src/sqlite3.c b/Data/SQLite/src/sqlite3.c index c1278e656..9a8a0eac8 100644 --- a/Data/SQLite/src/sqlite3.c +++ b/Data/SQLite/src/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.8.6. By combining all the individual C code files into this +** version 3.8.7.2. 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 @@ -75,6 +75,15 @@ # define _LARGEFILE_SOURCE 1 #endif +/* Needed for various definitions... */ +#if defined(__GNUC__) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif + +#if defined(__OpenBSD__) && !defined(_BSD_SOURCE) +# define _BSD_SOURCE +#endif + /* ** For MinGW, check to see if we can include the header file containing its ** version information, among other things. Normally, this internal MinGW @@ -222,9 +231,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.8.6" -#define SQLITE_VERSION_NUMBER 3008006 -#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e" +#define SQLITE_VERSION "3.8.7.2" +#define SQLITE_VERSION_NUMBER 3008007 +#define SQLITE_SOURCE_ID "2014-11-18 20:57:56 2ab564bf9655b7c7b97ab85cafc8a48329b27f93" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -612,6 +621,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) +#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations @@ -2214,7 +2224,7 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); ** turns off all busy handlers. ** ** ^(There can only be a single busy handler for a particular -** [database connection] any any given moment. If another busy handler +** [database connection] at any given moment. If another busy handler ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ ** @@ -2418,6 +2428,10 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns ** a NULL pointer. ** +** ^The sqlite3_malloc64(N) routine works just like +** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead +** of a signed 32-bit integer. +** ** ^Calling sqlite3_free() with a pointer previously returned ** by sqlite3_malloc() or sqlite3_realloc() releases that memory so ** that it might be reused. ^The sqlite3_free() routine is @@ -2429,24 +2443,38 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** might result if sqlite3_free() is called with a non-NULL pointer that ** was not obtained from sqlite3_malloc() or sqlite3_realloc(). ** -** ^(The sqlite3_realloc() interface attempts to resize a -** prior memory allocation to be at least N bytes, where N is the -** second parameter. The memory allocation to be resized is the first -** parameter.)^ ^ If the first parameter to sqlite3_realloc() +** ^The sqlite3_realloc(X,N) interface attempts to resize a +** prior memory allocation X to be at least N bytes. +** ^If the X parameter to sqlite3_realloc(X,N) ** is a NULL pointer then its behavior is identical to calling -** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc(). -** ^If the second parameter to sqlite3_realloc() is zero or +** sqlite3_malloc(N). +** ^If the N parameter to sqlite3_realloc(X,N) is zero or ** negative then the behavior is exactly the same as calling -** sqlite3_free(P) where P is the first parameter to sqlite3_realloc(). -** ^sqlite3_realloc() returns a pointer to a memory allocation -** of at least N bytes in size or NULL if sufficient memory is unavailable. +** sqlite3_free(X). +** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation +** of at least N bytes in size or NULL if insufficient memory is available. ** ^If M is the size of the prior allocation, then min(N,M) bytes ** of the prior allocation are copied into the beginning of buffer returned -** by sqlite3_realloc() and the prior allocation is freed. -** ^If sqlite3_realloc() returns NULL, then the prior allocation -** is not freed. +** by sqlite3_realloc(X,N) and the prior allocation is freed. +** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the +** prior allocation is not freed. ** -** ^The memory returned by sqlite3_malloc() and sqlite3_realloc() +** ^The sqlite3_realloc64(X,N) interfaces works the same as +** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead +** of a 32-bit signed integer. +** +** ^If X is a memory allocation previously obtained from sqlite3_malloc(), +** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then +** sqlite3_msize(X) returns the size of that memory allocation in bytes. +** ^The value returned by sqlite3_msize(X) might be larger than the number +** of bytes requested when X was allocated. ^If X is a NULL pointer then +** sqlite3_msize(X) returns zero. If X points to something that is not +** the beginning of memory allocation, or if it points to a formerly +** valid memory allocation that has now been freed, then the behavior +** of sqlite3_msize(X) is undefined and possibly harmful. +** +** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(), +** sqlite3_malloc64(), and sqlite3_realloc64() ** is always aligned to at least an 8 byte boundary, or to a ** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time ** option is used. @@ -2474,8 +2502,11 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** [sqlite3_free()] or [sqlite3_realloc()]. */ SQLITE_API void *sqlite3_malloc(int); +SQLITE_API void *sqlite3_malloc64(sqlite3_uint64); SQLITE_API void *sqlite3_realloc(void*, int); +SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64); SQLITE_API void sqlite3_free(void*); +SQLITE_API sqlite3_uint64 sqlite3_msize(void*); /* ** CAPI3REF: Memory Allocator Statistics @@ -2762,9 +2793,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** an English language description of the error following a failure of any ** of the sqlite3_open() routines. ** -** ^The default encoding for the database will be UTF-8 if -** sqlite3_open() or sqlite3_open_v2() is called and -** UTF-16 in the native byte order if sqlite3_open16() is used. +** ^The default encoding will be UTF-8 for databases created using +** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases +** created using sqlite3_open16() will be UTF-16 in the native byte order. ** ** Whether or not an error occurs when it is opened, resources ** associated with the [database connection] handle should be released by @@ -2852,13 +2883,14 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** then it is interpreted as an absolute path. ^If the path does not begin ** with a '/' (meaning that the authority section is omitted from the URI) ** then the path is interpreted as a relative path. -** ^On windows, the first component of an absolute path -** is a drive specification (e.g. "C:"). +** ^(On windows, the first component of an absolute path +** is a drive specification (e.g. "C:").)^ ** ** [[core URI query parameters]] ** The query component of a URI may contain parameters that are interpreted ** either by SQLite itself, or by a [VFS | custom VFS implementation]. -** SQLite interprets the following three query parameters: +** SQLite and its built-in [VFSes] interpret the +** following query parameters: ** **
    **
  • vfs: ^The "vfs" parameter may be used to specify the name of @@ -2893,11 +2925,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** -**
  • psow: ^The psow parameter may be "true" (or "on" or "yes" or -** "1") or "false" (or "off" or "no" or "0") to indicate that the +**
  • psow: ^The psow parameter indicates whether or not the ** [powersafe overwrite] property does or does not apply to the -** storage media on which the database file resides. ^The psow query -** parameter only works for the built-in unix and Windows VFSes. +** storage media on which the database file resides. ** **
  • nolock: ^The nolock parameter is a boolean query parameter ** which if set disables file locking in rollback journal modes. This @@ -3193,6 +3223,10 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
    SQLITE_LIMIT_TRIGGER_DEPTH
    **
    The maximum depth of recursion for triggers.
    )^ +** +** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
    SQLITE_LIMIT_WORKER_THREADS
    +**
    The maximum number of auxiliary worker threads that a single +** [prepared statement] may start.
    )^ ** */ #define SQLITE_LIMIT_LENGTH 0 @@ -3206,6 +3240,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 +#define SQLITE_LIMIT_WORKER_THREADS 11 /* ** CAPI3REF: Compiling An SQL Statement @@ -3479,18 +3514,18 @@ typedef struct sqlite3_context sqlite3_context; ** If the fourth parameter to sqlite3_bind_blob() is negative, then ** the behavior is undefined. ** If a non-negative fourth parameter is provided to sqlite3_bind_text() -** or sqlite3_bind_text16() then that parameter must be the byte offset +** or sqlite3_bind_text16() or sqlite3_bind_text64() then +** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL ** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** -** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and -** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or +** ^The fifth argument to the BLOB and string binding interfaces +** is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor is called -** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(), -** sqlite3_bind_text(), or sqlite3_bind_text16() fails. +** to dispose of the BLOB or string even if the call to bind API fails. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. @@ -3498,6 +3533,14 @@ typedef struct sqlite3_context sqlite3_context; ** SQLite makes its own private copy of the data immediately, before ** the sqlite3_bind_*() routine returns. ** +** ^The sixth argument to sqlite3_bind_text64() must be one of +** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] +** to specify the encoding of the text in the third parameter. If +** the sixth argument to sqlite3_bind_text64() is not one of the +** allowed values shown above, or if the text encoding is different +** from the encoding specified by the sixth parameter, then the behavior +** is undefined. +** ** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that ** is filled with zeroes. ^A zeroblob uses a fixed amount of memory ** (just an integer to hold its size) while it is being processed. @@ -3518,6 +3561,9 @@ typedef struct sqlite3_context sqlite3_context; ** ** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an ** [error code] if anything goes wrong. +** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB +** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or +** [SQLITE_MAX_LENGTH]. ** ^[SQLITE_RANGE] is returned if the parameter ** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. ** @@ -3525,12 +3571,16 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. */ SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); +SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, + void(*)(void*)); SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); -SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); +SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); +SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, + void(*)(void*), unsigned char encoding); SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); @@ -4279,7 +4329,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** object results in undefined behavior. ** ** ^These routines work just like the corresponding [column access functions] -** except that these routines take a single [protected sqlite3_value] object +** except that these routines take a single [protected sqlite3_value] object ** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. ** ** ^The sqlite3_value_text16() interface extracts a UTF-16 string @@ -4526,6 +4576,10 @@ typedef void (*sqlite3_destructor_type)(void*); ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. +** ^The sqlite3_result_text64() interface sets the return value of an +** application-defined function to be a text string in an encoding +** specified by the fifth (and last) parameter, which must be one +** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to the sqlite3_result_text* interfaces @@ -4569,6 +4623,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** the [sqlite3_context] pointer, the results are undefined. */ SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,sqlite3_uint64,void(*)(void*)); SQLITE_API void sqlite3_result_double(sqlite3_context*, double); SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); @@ -4579,6 +4634,8 @@ SQLITE_API void sqlite3_result_int(sqlite3_context*, int); SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, + void(*)(void*), unsigned char encoding); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); @@ -6275,12 +6332,13 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 -#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 +#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_ISINIT 23 -#define SQLITE_TESTCTRL_LAST 23 +#define SQLITE_TESTCTRL_SORTER_MMAP 24 +#define SQLITE_TESTCTRL_LAST 24 /* ** CAPI3REF: SQLite Runtime Status @@ -6471,12 +6529,12 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
    SQLITE_DBSTATUS_CACHE_USED
    -**
    This parameter returns the approximate number of of bytes of heap +**
    This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
    SQLITE_DBSTATUS_SCHEMA_USED
    -**
    This parameter returns the approximate number of of bytes of heap +**
    This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the @@ -6485,7 +6543,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. ** ** [[SQLITE_DBSTATUS_STMT_USED]] ^(
    SQLITE_DBSTATUS_STMT_USED
    -**
    This parameter returns the approximate number of of bytes of heap +**
    This parameter returns the approximate number of bytes of heap ** and lookaside memory used by all prepared statements associated with ** the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. @@ -7842,15 +7900,6 @@ struct sqlite3_rtree_query_info { #pragma warn -spa /* Suspicious pointer arithmetic */ #endif -/* Needed for various definitions... */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - -#if defined(__OpenBSD__) && !defined(_BSD_SOURCE) -# define _BSD_SOURCE -#endif - /* ** Include standard header files as necessary */ @@ -7891,6 +7940,18 @@ struct sqlite3_rtree_query_info { # define SQLITE_PTR_TO_INT(X) ((int)(X)) #endif +/* +** A macro to hint to the compiler that a function should not be +** inlined. +*/ +#if defined(__GNUC__) +# define SQLITE_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) && _MSC_VER>=1310 +# define SQLITE_NOINLINE __declspec(noinline) +#else +# define SQLITE_NOINLINE +#endif + /* ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. ** 0 means mutexes are permanently disable and the library is never @@ -8077,7 +8138,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int); #endif /* -** Return true (non-zero) if the input is a integer that is too large +** Return true (non-zero) if the input is an integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() ** macros to verify that we have tested SQLite for large-file support. */ @@ -8156,15 +8217,15 @@ struct Hash { struct HashElem { HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ - const char *pKey; int nKey; /* Key associated with this element */ + const char *pKey; /* Key associated with this element */ }; /* ** Access routines. To delete, insert a NULL pointer. */ SQLITE_PRIVATE void sqlite3HashInit(Hash*); -SQLITE_PRIVATE void *sqlite3HashInsert(Hash*, const char *pKey, int nKey, void *pData); -SQLITE_PRIVATE void *sqlite3HashFind(const Hash*, const char *pKey, int nKey); +SQLITE_PRIVATE void *sqlite3HashInsert(Hash*, const char *pKey, void *pData); +SQLITE_PRIVATE void *sqlite3HashFind(const Hash*, const char *pKey); SQLITE_PRIVATE void sqlite3HashClear(Hash*); /* @@ -8423,6 +8484,27 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); # define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */ #endif +/* +** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if +** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it +** to zero. +*/ +#if SQLITE_TEMP_STORE==3 || SQLITE_THREADSAFE==0 +# undef SQLITE_MAX_WORKER_THREADS +# define SQLITE_MAX_WORKER_THREADS 0 +#endif +#ifndef SQLITE_MAX_WORKER_THREADS +# define SQLITE_MAX_WORKER_THREADS 8 +#endif +#ifndef SQLITE_DEFAULT_WORKER_THREADS +# define SQLITE_DEFAULT_WORKER_THREADS 0 +#endif +#if SQLITE_DEFAULT_WORKER_THREADS>SQLITE_MAX_WORKER_THREADS +# undef SQLITE_MAX_WORKER_THREADS +# define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS +#endif + + /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. @@ -8437,6 +8519,11 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define MIN(A,B) ((A)<(B)?(A):(B)) #define MAX(A,B) ((A)>(B)?(A):(B)) +/* +** Swap two objects of type TYPE. +*/ +#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} + /* ** Check to see if this machine uses EBCDIC. (Yes, believe it or ** not, there are still machines out there that use EBCDIC.) @@ -8607,7 +8694,7 @@ SQLITE_PRIVATE const int sqlite3one; ** all alignment restrictions correct. ** ** Except, if SQLITE_4_BYTE_ALIGNED_MALLOC is defined, then the -** underlying malloc() implemention might return us 4-byte aligned +** underlying malloc() implementation might return us 4-byte aligned ** pointers. In that case, only verify 4-byte alignment. */ #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC @@ -8674,6 +8761,16 @@ SQLITE_PRIVATE const int sqlite3one; # undef SQLITE_ENABLE_STAT3_OR_STAT4 #endif +/* +** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not +** the Select query generator tracing logic is turned on. +*/ +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE) +# define SELECTTRACE_ENABLED 1 +#else +# define SELECTTRACE_ENABLED 0 +#endif + /* ** An instance of the following structure is used to store the busy-handler ** callback for a given sqlite handle. @@ -8806,12 +8903,14 @@ typedef struct PrintfArguments PrintfArguments; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; +typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; typedef struct SrcList SrcList; typedef struct StrAccum StrAccum; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; +typedef struct TreeView TreeView; typedef struct Trigger Trigger; typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; @@ -8914,7 +9013,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int); SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*); -SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int); +SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int); SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags); SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*); @@ -8947,7 +9046,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *); SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*); SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*); -SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int); +SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree*, int, int); SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); @@ -9000,7 +9099,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( int bias, int *pRes ); -SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*, int*); +SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*); +SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*); SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, const void *pData, int nData, @@ -9291,42 +9391,42 @@ typedef struct VdbeOpList VdbeOpList; #define OP_AddImm 37 /* synopsis: r[P1]=r[P1]+P2 */ #define OP_MustBeInt 38 #define OP_RealAffinity 39 -#define OP_Permutation 40 -#define OP_Compare 41 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_Jump 42 -#define OP_Once 43 -#define OP_If 44 -#define OP_IfNot 45 -#define OP_Column 46 /* synopsis: r[P3]=PX */ -#define OP_Affinity 47 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 48 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 49 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 50 -#define OP_SetCookie 51 -#define OP_ReopenIdx 52 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 53 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 54 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenAutoindex 55 /* synopsis: nColumn=P2 */ -#define OP_OpenEphemeral 56 /* synopsis: nColumn=P2 */ -#define OP_SorterOpen 57 -#define OP_OpenPseudo 58 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 59 -#define OP_SeekLT 60 /* synopsis: key=r[P3@P4] */ -#define OP_SeekLE 61 /* synopsis: key=r[P3@P4] */ -#define OP_SeekGE 62 /* synopsis: key=r[P3@P4] */ -#define OP_SeekGT 63 /* synopsis: key=r[P3@P4] */ -#define OP_Seek 64 /* synopsis: intkey=r[P2] */ -#define OP_NoConflict 65 /* synopsis: key=r[P3@P4] */ -#define OP_NotFound 66 /* synopsis: key=r[P3@P4] */ -#define OP_Found 67 /* synopsis: key=r[P3@P4] */ -#define OP_NotExists 68 /* synopsis: intkey=r[P3] */ -#define OP_Sequence 69 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_NewRowid 70 /* synopsis: r[P2]=rowid */ +#define OP_Cast 40 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 41 +#define OP_Compare 42 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_Jump 43 +#define OP_Once 44 +#define OP_If 45 +#define OP_IfNot 46 +#define OP_Column 47 /* synopsis: r[P3]=PX */ +#define OP_Affinity 48 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 49 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 50 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 51 +#define OP_SetCookie 52 +#define OP_ReopenIdx 53 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenRead 54 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 55 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenAutoindex 56 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 57 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 58 +#define OP_SequenceTest 59 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 60 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 61 +#define OP_SeekLT 62 /* synopsis: key=r[P3@P4] */ +#define OP_SeekLE 63 /* synopsis: key=r[P3@P4] */ +#define OP_SeekGE 64 /* synopsis: key=r[P3@P4] */ +#define OP_SeekGT 65 /* synopsis: key=r[P3@P4] */ +#define OP_Seek 66 /* synopsis: intkey=r[P2] */ +#define OP_NoConflict 67 /* synopsis: key=r[P3@P4] */ +#define OP_NotFound 68 /* synopsis: key=r[P3@P4] */ +#define OP_Found 69 /* synopsis: key=r[P3@P4] */ +#define OP_NotExists 70 /* synopsis: intkey=r[P3] */ #define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_Insert 73 /* synopsis: intkey=r[P3] data=r[P2] */ -#define OP_InsertInt 74 /* synopsis: intkey=P3 data=r[P2] */ -#define OP_Delete 75 +#define OP_Sequence 73 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 74 /* synopsis: r[P2]=rowid */ +#define OP_Insert 75 /* synopsis: intkey=r[P3] data=r[P2] */ #define OP_IsNull 76 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 77 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 78 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */ @@ -9335,7 +9435,7 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Le 81 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */ #define OP_Lt 82 /* same as TK_LT, synopsis: if r[P1]=r[P3] goto P2 */ -#define OP_ResetCount 84 +#define OP_InsertInt 84 /* synopsis: intkey=P3 data=r[P2] */ #define OP_BitAnd 85 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 86 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 87 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<0 goto P2 */ -#define OP_IfNeg 136 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */ -#define OP_IfZero 137 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */ -#define OP_AggFinal 138 /* synopsis: accum=r[P1] N=P2 */ -#define OP_IncrVacuum 139 -#define OP_Expire 140 -#define OP_TableLock 141 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 142 -#define OP_ToText 143 /* same as TK_TO_TEXT */ -#define OP_ToBlob 144 /* same as TK_TO_BLOB */ -#define OP_ToNumeric 145 /* same as TK_TO_NUMERIC */ -#define OP_ToInt 146 /* same as TK_TO_INT */ -#define OP_ToReal 147 /* same as TK_TO_REAL */ -#define OP_VCreate 148 -#define OP_VDestroy 149 -#define OP_VOpen 150 -#define OP_VColumn 151 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VNext 152 -#define OP_VRename 153 -#define OP_Pagecount 154 -#define OP_MaxPgcnt 155 -#define OP_Init 156 /* synopsis: Start at P2 */ -#define OP_Noop 157 -#define OP_Explain 158 +#define OP_FkCounter 134 /* synopsis: fkctr[P1]+=P2 */ +#define OP_FkIfZero 135 /* synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_MemMax 136 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_IfPos 137 /* synopsis: if r[P1]>0 goto P2 */ +#define OP_IfNeg 138 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */ +#define OP_IfZero 139 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */ +#define OP_AggFinal 140 /* synopsis: accum=r[P1] N=P2 */ +#define OP_IncrVacuum 141 +#define OP_Expire 142 +#define OP_TableLock 143 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 144 +#define OP_VCreate 145 +#define OP_VDestroy 146 +#define OP_VOpen 147 +#define OP_VColumn 148 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VNext 149 +#define OP_VRename 150 +#define OP_Pagecount 151 +#define OP_MaxPgcnt 152 +#define OP_Init 153 /* synopsis: Start at P2 */ +#define OP_Noop 154 +#define OP_Explain 155 /* Properties such as "out2" or "jump" that are specified in @@ -9429,21 +9526,21 @@ typedef struct VdbeOpList VdbeOpList; /* 16 */ 0x01, 0x01, 0x04, 0x24, 0x01, 0x04, 0x05, 0x10,\ /* 24 */ 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02,\ /* 32 */ 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x05, 0x04,\ -/* 40 */ 0x00, 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00,\ -/* 48 */ 0x00, 0x02, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00,\ -/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\ -/* 64 */ 0x08, 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x4c,\ -/* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\ +/* 40 */ 0x04, 0x00, 0x00, 0x01, 0x01, 0x05, 0x05, 0x00,\ +/* 48 */ 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x00, 0x00,\ +/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11,\ +/* 64 */ 0x11, 0x11, 0x08, 0x11, 0x11, 0x11, 0x11, 0x4c,\ +/* 72 */ 0x4c, 0x02, 0x02, 0x00, 0x05, 0x05, 0x15, 0x15,\ /* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\ /* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\ -/* 96 */ 0x24, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,\ -/* 104 */ 0x01, 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01,\ -/* 112 */ 0x01, 0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02,\ -/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45,\ -/* 128 */ 0x15, 0x01, 0x02, 0x00, 0x01, 0x02, 0x08, 0x05,\ -/* 136 */ 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04,\ -/* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,\ -/* 152 */ 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,} +/* 96 */ 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\ +/* 104 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x00,\ +/* 112 */ 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00,\ +/* 120 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 128 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x02, 0x00, 0x01,\ +/* 136 */ 0x08, 0x05, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00,\ +/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,\ +/* 152 */ 0x02, 0x01, 0x00, 0x00,} /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ @@ -9501,10 +9598,10 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); -SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int); +SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); -typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int); +typedef int (*RecordCompare)(int,const void*,UnpackedRecord*); SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); #ifndef SQLITE_OMIT_TRIGGER @@ -9862,7 +9959,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *, int sz, int n); ** Under memory stress, invoke xStress to try to make pages clean. ** Only clean and unpinned pages can be reclaimed. */ -SQLITE_PRIVATE void sqlite3PcacheOpen( +SQLITE_PRIVATE int sqlite3PcacheOpen( int szPage, /* Size of every page */ int szExtra, /* Extra space associated with each page */ int bPurgeable, /* True if pages are on backing store */ @@ -9872,7 +9969,7 @@ SQLITE_PRIVATE void sqlite3PcacheOpen( ); /* Modify the page-size after the cache has been created. */ -SQLITE_PRIVATE void sqlite3PcacheSetPageSize(PCache *, int); +SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *, int); /* Return the size in bytes of a PCache object. Used to preallocate ** storage space. @@ -9882,7 +9979,9 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void); /* One release per successful fetch. Page is pinned until released. ** Reference counted. */ -SQLITE_PRIVATE int sqlite3PcacheFetch(PCache*, Pgno, int createFlag, PgHdr**); +SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(PCache*, Pgno, int createFlag); +SQLITE_PRIVATE int sqlite3PcacheFetchStress(PCache*, Pgno, sqlite3_pcache_page**); +SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(PCache*, Pgno, sqlite3_pcache_page *pPage); SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr*); SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache */ @@ -10142,7 +10241,7 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void); ** shared locks begins at SHARED_FIRST. ** ** The same locking strategy and -** byte ranges are used for Unix. This leaves open the possiblity of having +** byte ranges are used for Unix. This leaves open the possibility of having ** clients on win95, winNT, and unix all talking to the same shared file ** and all locking correctly. To do so would require that samba (or whatever ** tool is being used for file sharing) implements locks correctly between @@ -10261,7 +10360,7 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *); ** Figure out what version of the code to use. The choices are ** ** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The -** mutexes implemention cannot be overridden +** mutexes implementation cannot be overridden ** at start-time. ** ** SQLITE_MUTEX_NOOP For single-threaded applications. No @@ -10381,7 +10480,7 @@ struct Schema { ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ -#define SQLITE_N_LIMIT (SQLITE_LIMIT_TRIGGER_DEPTH+1) +#define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1) /* ** Lookaside malloc is a set of fixed-size buffers that can be used @@ -10428,6 +10527,45 @@ struct FuncDefHash { FuncDef *a[23]; /* Hash table for functions */ }; +#ifdef SQLITE_USER_AUTHENTICATION +/* +** Information held in the "sqlite3" database connection object and used +** to manage user authentication. +*/ +typedef struct sqlite3_userauth sqlite3_userauth; +struct sqlite3_userauth { + u8 authLevel; /* Current authentication level */ + int nAuthPW; /* Size of the zAuthPW in bytes */ + char *zAuthPW; /* Password used to authenticate */ + char *zAuthUser; /* User name used to authenticate */ +}; + +/* Allowed values for sqlite3_userauth.authLevel */ +#define UAUTH_Unknown 0 /* Authentication not yet checked */ +#define UAUTH_Fail 1 /* User authentication failed */ +#define UAUTH_User 2 /* Authenticated as a normal user */ +#define UAUTH_Admin 3 /* Authenticated as an administrator */ + +/* Functions used only by user authorization logic */ +SQLITE_PRIVATE int sqlite3UserAuthTable(const char*); +SQLITE_PRIVATE int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*); +SQLITE_PRIVATE void sqlite3UserAuthInit(sqlite3*); +SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); + +#endif /* SQLITE_USER_AUTHENTICATION */ + +/* +** typedef for the authorization callback function. +*/ +#ifdef SQLITE_USER_AUTHENTICATION + typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*, const char*); +#else + typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*); +#endif + + /* ** Each database connection is an instance of the following structure. */ @@ -10458,6 +10596,7 @@ struct sqlite3 { int nChange; /* Value returned by sqlite3_changes() */ int nTotalChange; /* Value returned by sqlite3_total_changes() */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ + int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ struct sqlite3InitInfo { /* Information used during initialization */ int newTnum; /* Rootpage of table being initialized */ u8 iDb; /* Which db file is being initialized */ @@ -10494,8 +10633,7 @@ struct sqlite3 { } u1; Lookaside lookaside; /* Lookaside malloc configuration */ #ifndef SQLITE_OMIT_AUTHORIZATION - int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); - /* Access authorization function */ + sqlite3_xauth xAuth; /* Access authorization function */ void *pAuthArg; /* 1st argument to the access auth function */ #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK @@ -10521,7 +10659,6 @@ struct sqlite3 { i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ - #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MASTER ** mutex, not by sqlite3.mutex. They are used by code in notify.c. @@ -10539,6 +10676,9 @@ struct sqlite3 { void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif +#ifdef SQLITE_USER_AUTHENTICATION + sqlite3_userauth auth; /* User authentication information */ +#endif }; /* @@ -10598,7 +10738,6 @@ struct sqlite3 { #define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ #define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */ -#define SQLITE_AdjustOutEst 0x1000 /* Adjust output estimates using WHERE */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* @@ -10685,6 +10824,7 @@ struct FuncDestructor { #define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */ #define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */ #define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */ +#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are @@ -10732,6 +10872,9 @@ struct FuncDestructor { #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0} +#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ + {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ + SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0} /* ** All current savepoints are stored in a linked list starting at @@ -10818,18 +10961,18 @@ struct CollSeq { ** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve ** the speed a little by numbering the values consecutively. ** -** But rather than start with 0 or 1, we begin with 'a'. That way, +** But rather than start with 0 or 1, we begin with 'A'. That way, ** when multiple affinity types are concatenated into a string and ** used as the P4 operand, they will be more readable. ** ** Note also that the numeric types are grouped together so that testing -** for a numeric type is a single comparison. +** for a numeric type is a single comparison. And the NONE type is first. */ -#define SQLITE_AFF_TEXT 'a' -#define SQLITE_AFF_NONE 'b' -#define SQLITE_AFF_NUMERIC 'c' -#define SQLITE_AFF_INTEGER 'd' -#define SQLITE_AFF_REAL 'e' +#define SQLITE_AFF_NONE 'A' +#define SQLITE_AFF_TEXT 'B' +#define SQLITE_AFF_NUMERIC 'C' +#define SQLITE_AFF_INTEGER 'D' +#define SQLITE_AFF_REAL 'E' #define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) @@ -10837,7 +10980,7 @@ struct CollSeq { ** The SQLITE_AFF_MASK values masks off the significant bits of an ** affinity value. */ -#define SQLITE_AFF_MASK 0x67 +#define SQLITE_AFF_MASK 0x47 /* ** Additional bit values that can be ORed with an affinity without @@ -10848,10 +10991,10 @@ struct CollSeq { ** operator is NULL. It is added to certain comparison operators to ** prove that the operands are always NOT NULL. */ -#define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */ -#define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */ +#define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */ +#define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ -#define SQLITE_NOTNULL 0x88 /* Assert that operands are never NULL */ +#define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */ /* ** An object of this type is created for each virtual table present in @@ -11121,7 +11264,7 @@ struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ u16 nField; /* Number of entries in apMem[] */ i8 default_rc; /* Comparison result if keys are equal */ - u8 isCorrupt; /* Corruption detected by xRecordCompare() */ + u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */ Mem *aMem; /* Values */ int r1; /* Value to return if (lhs > rhs) */ int r2; /* Value to return if (rhs < lhs) */ @@ -11181,6 +11324,7 @@ struct Index { int nSampleCol; /* Size of IndexSample.anEq[] and so on */ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ + tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this table */ #endif }; @@ -11611,7 +11755,7 @@ struct SrcList { #define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */ #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ -#define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ + /* 0x0080 // not currently used */ #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ @@ -11654,17 +11798,22 @@ struct NameContext { NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ int nErr; /* Number of errors encountered while resolving names */ - u8 ncFlags; /* Zero or more NC_* flags defined below */ + u16 ncFlags; /* Zero or more NC_* flags defined below */ }; /* ** Allowed values for the NameContext, ncFlags field. +** +** Note: NC_MinMaxAgg must have the same value as SF_MinMaxAgg and +** SQLITE_FUNC_MINMAX. +** */ -#define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */ -#define NC_HasAgg 0x02 /* One or more aggregate functions seen */ -#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */ -#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */ -#define NC_PartIdx 0x10 /* True if resolving a partial index WHERE */ +#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ +#define NC_HasAgg 0x0002 /* One or more aggregate functions seen */ +#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ +#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ +#define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */ +#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ /* ** An instance of the following structure contains all information @@ -11691,6 +11840,9 @@ struct Select { u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ u16 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ +#if SELECTTRACE_ENABLED + char zSelName[12]; /* Symbolic name of this SELECT use for debugging */ +#endif int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ u64 nSelectRow; /* Estimated number of result rows */ SrcList *pSrc; /* The FROM clause */ @@ -11715,13 +11867,13 @@ struct Select { #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ - /* 0x0040 NOT USED */ +#define SF_Compound 0x0040 /* Part of a compound query */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */ /* 0x0100 NOT USED */ #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */ #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */ #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */ -#define SF_Compound 0x1000 /* Part of a compound query */ +#define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */ /* @@ -11949,6 +12101,10 @@ struct Parse { int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ int nMaxArg; /* Max args passed to user function by sub-program */ +#if SELECTTRACE_ENABLED + int nSelect; /* Number of SELECT statements seen */ + int nSelectIndent; /* How far to indent SELECTTRACE() output */ +#endif #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ @@ -12028,11 +12184,11 @@ struct AuthContext { ** Bitfield flags for P5 value in various opcodes. */ #define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */ +#define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ #define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ #define OPFLAG_APPEND 0x08 /* This is likely to be an append */ #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ -#define OPFLAG_CLEARCACHE 0x20 /* Clear pseudo-table cache in OP_Column */ #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ #define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ #define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ @@ -12296,6 +12452,17 @@ struct With { } a[1]; }; +#ifdef SQLITE_DEBUG +/* +** An instance of the TreeView object is used for printing the content of +** data structures on sqlite3DebugPrintf() using a tree-like view. +*/ +struct TreeView { + int iLevel; /* Which level of the tree we are on */ + u8 bLine[100]; /* Draw vertical in column i if bLine[i] is true */ +}; +#endif /* SQLITE_DEBUG */ + /* ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. @@ -12323,8 +12490,8 @@ SQLITE_PRIVATE int sqlite3CantopenError(int); /* ** FTS4 is really an extension for FTS3. It is enabled using the -** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all -** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3. +** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also call +** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3. */ #if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3) # define SQLITE_ENABLE_FTS3 @@ -12361,6 +12528,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int); # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) #endif +SQLITE_PRIVATE int sqlite3IsIdChar(u8); /* ** Internal function prototypes @@ -12371,15 +12539,15 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char*); SQLITE_PRIVATE int sqlite3MallocInit(void); SQLITE_PRIVATE void sqlite3MallocEnd(void); -SQLITE_PRIVATE void *sqlite3Malloc(int); -SQLITE_PRIVATE void *sqlite3MallocZero(int); -SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, int); -SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, int); +SQLITE_PRIVATE void *sqlite3Malloc(u64); +SQLITE_PRIVATE void *sqlite3MallocZero(u64); +SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, u64); +SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64); SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*); -SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, int); -SQLITE_PRIVATE void *sqlite3Realloc(void*, int); -SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, int); -SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, int); +SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64); +SQLITE_PRIVATE void *sqlite3Realloc(void*, u64); +SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); +SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64); SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*); SQLITE_PRIVATE int sqlite3MallocSize(void*); SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*); @@ -12459,25 +12627,14 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char*, ...); SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*); #endif -/* Output formatting for SQLITE_TESTCTRL_EXPLAIN */ -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) -SQLITE_PRIVATE void sqlite3ExplainBegin(Vdbe*); -SQLITE_PRIVATE void sqlite3ExplainPrintf(Vdbe*, const char*, ...); -SQLITE_PRIVATE void sqlite3ExplainNL(Vdbe*); -SQLITE_PRIVATE void sqlite3ExplainPush(Vdbe*); -SQLITE_PRIVATE void sqlite3ExplainPop(Vdbe*); -SQLITE_PRIVATE void sqlite3ExplainFinish(Vdbe*); -SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe*, Select*); -SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe*, Expr*); -SQLITE_PRIVATE void sqlite3ExplainExprList(Vdbe*, ExprList*); -SQLITE_PRIVATE const char *sqlite3VdbeExplanation(Vdbe*); -#else -# define sqlite3ExplainBegin(X) -# define sqlite3ExplainSelect(A,B) -# define sqlite3ExplainExpr(A,B) -# define sqlite3ExplainExprList(A,B) -# define sqlite3ExplainFinish(X) -# define sqlite3VdbeExplanation(X) 0 +#if defined(SQLITE_DEBUG) +SQLITE_PRIVATE TreeView *sqlite3TreeViewPush(TreeView*,u8); +SQLITE_PRIVATE void sqlite3TreeViewPop(TreeView*); +SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView*, const char*, ...); +SQLITE_PRIVATE void sqlite3TreeViewItem(TreeView*, const char*, u8); +SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); +SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); +SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8); #endif @@ -12659,7 +12816,7 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*); SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*); -SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*); +SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8); SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); @@ -12683,6 +12840,11 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*); SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int); +#if SELECTTRACE_ENABLED +SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*); +#else +# define sqlite3SelectSetName(A,B) +#endif SQLITE_PRIVATE void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8); SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*); @@ -12769,38 +12931,23 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst); /* ** Routines to read and write variable-length integers. These used to ** be defined locally, but now we use the varint routines in the util.c -** file. Code should use the MACRO forms below, as the Varint32 versions -** are coded to assume the single byte case is already handled (which -** the MACRO form does). +** file. */ SQLITE_PRIVATE int sqlite3PutVarint(unsigned char*, u64); -SQLITE_PRIVATE int sqlite3PutVarint32(unsigned char*, u32); SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *, u64 *); SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *, u32 *); SQLITE_PRIVATE int sqlite3VarintLen(u64 v); /* -** The header of a record consists of a sequence variable-length integers. -** These integers are almost always small and are encoded as a single byte. -** The following macros take advantage this fact to provide a fast encode -** and decode of the integers in a record header. It is faster for the common -** case where the integer is a single byte. It is a little slower when the -** integer is two or more bytes. But overall it is faster. -** -** The following expressions are equivalent: -** -** x = sqlite3GetVarint32( A, &B ); -** x = sqlite3PutVarint32( A, B ); -** -** x = getVarint32( A, B ); -** x = putVarint32( A, B ); -** +** The common case is for a varint to be a single byte. They following +** macros handle the common case without a procedure call, but then call +** the procedure for larger varints. */ #define getVarint32(A,B) \ (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B))) #define putVarint32(A,B) \ (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\ - sqlite3PutVarint32((A),(B))) + sqlite3PutVarint((A),(B))) #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint @@ -12812,7 +12959,8 @@ SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*); -SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); +SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); +SQLITE_PRIVATE void sqlite3Error(sqlite3*,int); SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); SQLITE_PRIVATE u8 sqlite3HexToInt(int h); SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); @@ -12914,7 +13062,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *); SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, char*, int, int); SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum*,const char*,int); SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum*,const char*); -SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum*,int); +SQLITE_PRIVATE void sqlite3AppendChar(StrAccum*,int,char); SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*); SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum*); SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int); @@ -12934,7 +13082,7 @@ SQLITE_PRIVATE int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_v /* ** The interface to the LEMON-generated parser */ -SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(size_t)); +SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64)); SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*)); SQLITE_PRIVATE void sqlite3Parser(void*, int, Token, Parse*); #ifdef YYTRACKMAXSTACKDEPTH @@ -13174,10 +13322,17 @@ SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8); # define sqlite3MemdebugNoType(X,Y) 1 #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ -#define MEMTYPE_LOOKASIDE 0x02 /* Might have been lookaside memory */ +#define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */ #define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */ #define MEMTYPE_PCACHE 0x08 /* Page cache allocations */ -#define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */ + +/* +** Threading interface +*/ +#if SQLITE_MAX_WORKER_THREADS>0 +SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*); +SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**); +#endif #endif /* _SQLITEINT_H_ */ @@ -13195,7 +13350,7 @@ SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8); ** ************************************************************************* ** -** This file contains definitions of global variables and contants. +** This file contains definitions of global variables and constants. */ /* An array to map all upper-case characters into their corresponding @@ -13313,6 +13468,13 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { }; #endif +/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards +** compatibility for legacy applications, the URI filename capability is +** disabled by default. +** +** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled +** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options. +*/ #ifndef SQLITE_USE_URI # define SQLITE_USE_URI 0 #endif @@ -13792,6 +13954,9 @@ static const char * const azCompileOpt[] = { #ifdef SQLITE_USE_ALLOCA "USE_ALLOCA", #endif +#ifdef SQLITE_USER_AUTHENTICATION + "USER_AUTHENTICATION", +#endif #ifdef SQLITE_WIN32_MALLOC "WIN32_MALLOC", #endif @@ -13816,7 +13981,7 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){ ** linear search is adequate. No need for a binary search. */ for(i=0; iaDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ - u8 rowidIsValid; /* True if lastRowid is valid */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ @@ -13941,7 +14105,6 @@ struct VdbeCursor { sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ - i64 lastRowid; /* Rowid being deleted by OP_Delete */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ /* Cached information about the header for the data record that the @@ -13958,6 +14121,7 @@ struct VdbeCursor { u32 szRow; /* Byte available in aRow */ u32 iHdrOffset; /* Offset to next unparsed byte of the header */ const u8 *aRow; /* Data for the current row, if all on one page */ + u32 *aOffset; /* Pointer to aType[nField] */ u32 aType[1]; /* Type values for all entries in the record */ /* 2*nField extra array elements allocated for aType[], beyond the one ** static element declared in the structure. nField total array slots for @@ -14019,25 +14183,28 @@ struct VdbeFrame { ** integer etc.) of the same value. */ struct Mem { - sqlite3 *db; /* The associated database connection */ - char *z; /* String or BLOB value */ - double r; /* Real value */ - union { + union MemValue { + double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ int nZero; /* Used when bit MEM_Zero is set in flags */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ } u; - int n; /* Number of characters in string value, excluding '\0' */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ + int n; /* Number of characters in string value, excluding '\0' */ + char *z; /* String or BLOB value */ + /* ShallowCopy only needs to copy the information above */ + char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ + int szMalloc; /* Size of the zMalloc allocation */ + u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */ + sqlite3 *db; /* The associated database connection */ + void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */ #endif - void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ - char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */ }; /* One or more of the following flags are set to indicate the validOK @@ -14096,7 +14263,7 @@ struct Mem { #endif /* -** Each auxilliary data pointer stored by a user defined function +** Each auxiliary data pointer stored by a user defined function ** implementation calling sqlite3_set_auxdata() is stored in an instance ** of this structure. All such structures associated with a single VM ** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed @@ -14111,7 +14278,7 @@ struct AuxData { }; /* -** The "context" argument for a installable function. A pointer to an +** The "context" argument for an installable function. A pointer to an ** instance of this structure is the first argument to the routines used ** implement the SQL functions. ** @@ -14124,14 +14291,13 @@ struct AuxData { ** (Mem) which are only defined there. */ struct sqlite3_context { - FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ - Mem s; /* The return value is stored here */ + Mem *pOut; /* The return value is stored here */ + FuncDef *pFunc; /* Pointer to function information */ Mem *pMem; /* Memory cell used to store aggregate context */ - CollSeq *pColl; /* Collating sequence */ Vdbe *pVdbe; /* The VM that owns this context */ int iOp; /* Instruction number of OP_Function */ int isError; /* Error code returned by the function. */ - u8 skipFlag; /* Skip skip accumulator loading if true */ + u8 skipFlag; /* Skip accumulator loading if true */ u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */ }; @@ -14216,10 +14382,6 @@ struct Vdbe { i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ char *zSql; /* Text of the SQL statement that generated this */ void *pFree; /* Free this when deleting the vdbe */ -#ifdef SQLITE_ENABLE_TREE_EXPLAIN - Explain *pExplain; /* The explainer */ - char *zExplain; /* Explanation of data structures */ -#endif VdbeFrame *pFrame; /* Parent frame */ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ int nFrame; /* Number of frames in pFrame list */ @@ -14244,6 +14406,7 @@ struct Vdbe { SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*); +SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*); #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*); #endif @@ -14254,8 +14417,8 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); -SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*); -SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *); +SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*); +SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*); SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*); @@ -14272,39 +14435,39 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64); #else SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double); #endif +SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*); SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int); SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); -SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, int); +SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8); SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*); SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*); SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*); +SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8); SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*); SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); -SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p); #define VdbeMemDynamic(X) \ (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) -#define VdbeMemRelease(X) \ - if( VdbeMemDynamic(X) ) sqlite3VdbeMemReleaseExternal(X); SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); SQLITE_PRIVATE const char *sqlite3OpcodeName(int); SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); +SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); -SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); +SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); -SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *); -SQLITE_PRIVATE int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *); +SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); +SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 @@ -14543,7 +14706,7 @@ SQLITE_API int sqlite3_db_status( } db->pnBytesFreed = 0; - *pHighwater = 0; + *pHighwater = 0; /* IMP: R-64479-57858 */ *pCurrent = nByte; break; @@ -14568,7 +14731,9 @@ SQLITE_API int sqlite3_db_status( sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); } } - *pHighwater = 0; + *pHighwater = 0; /* IMP: R-42420-56072 */ + /* IMP: R-54100-20147 */ + /* IMP: R-29431-39229 */ *pCurrent = nRet; break; } @@ -14578,7 +14743,7 @@ SQLITE_API int sqlite3_db_status( ** have been satisfied. The *pHighwater is always set to zero. */ case SQLITE_DBSTATUS_DEFERRED_FKS: { - *pHighwater = 0; + *pHighwater = 0; /* IMP: R-11967-56545 */ *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; break; } @@ -14619,7 +14784,7 @@ SQLITE_API int sqlite3_db_status( ** 1970-01-01 00:00:00 is JD 2440587.5 ** 2000-01-01 00:00:00 is JD 2451544.5 ** -** This implemention requires years to be expressed as a 4-digit number +** This implementation requires years to be expressed as a 4-digit number ** which means that only dates between 0000-01-01 and 9999-12-31 can ** be represented, even though julian day numbers allow a much wider ** range of dates. @@ -16463,7 +16628,7 @@ static int sqlite3MemSize(void *pPrior){ ** ** For this low-level interface, we know that pPrior!=0. Cases where ** pPrior==0 while have been intercepted by higher-level routine and -** redirected to xMalloc. Similarly, we know that nByte>0 becauses +** redirected to xMalloc. Similarly, we know that nByte>0 because ** cases where nByte<=0 will have been intercepted by higher-level ** routines and redirected to xFree. */ @@ -16966,7 +17131,7 @@ SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){ ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** -** assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) ); +** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); */ SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){ int rc = 1; @@ -16988,7 +17153,7 @@ SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){ ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** -** assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) ); +** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); */ SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){ int rc = 1; @@ -17820,7 +17985,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){ ** 1. All memory allocations sizes are rounded up to a power of 2. ** ** 2. If two adjacent free blocks are the halves of a larger block, -** then the two blocks are coalesed into the single larger block. +** then the two blocks are coalesced into the single larger block. ** ** 3. New memory is allocated from the first available free block. ** @@ -19389,6 +19554,16 @@ SQLITE_API int sqlite3_open_file_count = 0; # define SQLITE_OS_WINRT 0 #endif +/* +** For WinCE, some API function parameters do not appear to be declared as +** volatile. +*/ +#if SQLITE_OS_WINCE +# define SQLITE_WIN32_VOLATILE +#else +# define SQLITE_WIN32_VOLATILE volatile +#endif + #endif /* _OS_WIN_H_ */ /************** End of os_win.h **********************************************/ @@ -19469,7 +19644,7 @@ static int winMutex_isNt = -1; /* <0 means "need to query" */ ** of the sqlite3_initialize() and sqlite3_shutdown() processing, the ** "interlocked" magic used here is probably not strictly necessary. */ -static LONG volatile winMutex_lock = 0; +static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0; SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ @@ -20037,11 +20212,9 @@ static int mallocWithAlarm(int n, void **pp){ ** Allocate memory. This routine is like sqlite3_malloc() except that it ** assumes the memory subsystem has already been initialized. */ -SQLITE_PRIVATE void *sqlite3Malloc(int n){ +SQLITE_PRIVATE void *sqlite3Malloc(u64 n){ void *p; - if( n<=0 /* IMP: R-65312-04917 */ - || n>=0x7fffff00 - ){ + if( n==0 || n>=0x7fffff00 ){ /* A memory allocation of a number of bytes which is near the maximum ** signed integer value might cause an integer overflow inside of the ** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving @@ -20050,12 +20223,12 @@ SQLITE_PRIVATE void *sqlite3Malloc(int n){ p = 0; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); - mallocWithAlarm(n, &p); + mallocWithAlarm((int)n, &p); sqlite3_mutex_leave(mem0.mutex); }else{ - p = sqlite3GlobalConfig.m.xMalloc(n); + p = sqlite3GlobalConfig.m.xMalloc((int)n); } - assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-04675-44850 */ + assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-11148-40995 */ return p; } @@ -20065,6 +20238,12 @@ SQLITE_PRIVATE void *sqlite3Malloc(int n){ ** allocation. */ SQLITE_API void *sqlite3_malloc(int n){ +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return n<=0 ? 0 : sqlite3Malloc(n); +} +SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif @@ -20095,22 +20274,20 @@ SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){ assert( n>0 ); sqlite3_mutex_enter(mem0.mutex); + sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n); if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){ p = mem0.pScratchFree; mem0.pScratchFree = mem0.pScratchFree->pNext; mem0.nScratchFree--; sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1); - sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n); sqlite3_mutex_leave(mem0.mutex); }else{ - if( sqlite3GlobalConfig.bMemstat ){ - sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n); - n = mallocWithAlarm(n, &p); - if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n); + sqlite3_mutex_leave(mem0.mutex); + p = sqlite3Malloc(n); + if( sqlite3GlobalConfig.bMemstat && p ){ + sqlite3_mutex_enter(mem0.mutex); + sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p)); sqlite3_mutex_leave(mem0.mutex); - }else{ - sqlite3_mutex_leave(mem0.mutex); - p = sqlite3GlobalConfig.m.xMalloc(n); } sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH); } @@ -20188,29 +20365,37 @@ static int isLookaside(sqlite3 *db, void *p){ */ SQLITE_PRIVATE int sqlite3MallocSize(void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); - assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) ); return sqlite3GlobalConfig.m.xSize(p); } SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){ - assert( db!=0 ); - assert( sqlite3_mutex_held(db->mutex) ); - if( isLookaside(db, p) ){ - return db->lookaside.sz; + if( db==0 ){ + assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); + assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); + return sqlite3MallocSize(p); }else{ - assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) ); - assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) ); - assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); - return sqlite3GlobalConfig.m.xSize(p); + assert( sqlite3_mutex_held(db->mutex) ); + if( isLookaside(db, p) ){ + return db->lookaside.sz; + }else{ + assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + return sqlite3GlobalConfig.m.xSize(p); + } } } +SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){ + assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); + assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); + return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p); +} /* ** Free memory previously obtained from sqlite3Malloc(). */ SQLITE_API void sqlite3_free(void *p){ if( p==0 ) return; /* IMP: R-49053-54554 */ - assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); + assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p)); @@ -20222,6 +20407,14 @@ SQLITE_API void sqlite3_free(void *p){ } } +/* +** Add the size of memory allocation "p" to the count in +** *db->pnBytesFreed. +*/ +static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){ + *db->pnBytesFreed += sqlite3DbMallocSize(db,p); +} + /* ** Free memory that might be associated with a particular database ** connection. @@ -20231,7 +20424,7 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ if( p==0 ) return; if( db ){ if( db->pnBytesFreed ){ - *db->pnBytesFreed += sqlite3DbMallocSize(db, p); + measureAllocationSize(db, p); return; } if( isLookaside(db, p) ){ @@ -20246,8 +20439,8 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ return; } } - assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) ); - assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) ); + assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); @@ -20256,14 +20449,16 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ /* ** Change the size of an existing memory allocation */ -SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){ +SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ int nOld, nNew, nDiff; void *pNew; + assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); + assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); if( pOld==0 ){ - return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */ + return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */ } - if( nBytes<=0 ){ - sqlite3_free(pOld); /* IMP: R-31593-10574 */ + if( nBytes==0 ){ + sqlite3_free(pOld); /* IMP: R-26507-47431 */ return 0; } if( nBytes>=0x7fffff00 ){ @@ -20274,22 +20469,20 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){ /* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second ** argument to xRealloc is always a value returned by a prior call to ** xRoundup. */ - nNew = sqlite3GlobalConfig.m.xRoundup(nBytes); + nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes); if( nOld==nNew ){ pNew = pOld; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes); + sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); nDiff = nNew - nOld; if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); } - assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); - assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); if( pNew==0 && mem0.alarmCallback ){ - sqlite3MallocAlarm(nBytes); + sqlite3MallocAlarm((int)nBytes); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } if( pNew ){ @@ -20300,7 +20493,7 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){ }else{ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } - assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-04675-44850 */ + assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-11148-40995 */ return pNew; } @@ -20309,6 +20502,13 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){ ** subsystem is initialized prior to invoking sqliteRealloc. */ SQLITE_API void *sqlite3_realloc(void *pOld, int n){ +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + if( n<0 ) n = 0; /* IMP: R-26507-47431 */ + return sqlite3Realloc(pOld, n); +} +SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif @@ -20319,10 +20519,10 @@ SQLITE_API void *sqlite3_realloc(void *pOld, int n){ /* ** Allocate and zero memory. */ -SQLITE_PRIVATE void *sqlite3MallocZero(int n){ +SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){ void *p = sqlite3Malloc(n); if( p ){ - memset(p, 0, n); + memset(p, 0, (size_t)n); } return p; } @@ -20331,10 +20531,10 @@ SQLITE_PRIVATE void *sqlite3MallocZero(int n){ ** Allocate and zero memory. If the allocation fails, make ** the mallocFailed flag in the connection pointer. */ -SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, int n){ +SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){ void *p = sqlite3DbMallocRaw(db, n); if( p ){ - memset(p, 0, n); + memset(p, 0, (size_t)n); } return p; } @@ -20357,7 +20557,7 @@ SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, int n){ ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed ** that all prior mallocs (ex: "a") worked too. */ -SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, int n){ +SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){ void *p; assert( db==0 || sqlite3_mutex_held(db->mutex) ); assert( db==0 || db->pnBytesFreed==0 ); @@ -20392,8 +20592,8 @@ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, int n){ if( !p && db ){ db->mallocFailed = 1; } - sqlite3MemdebugSetType(p, MEMTYPE_DB | - ((db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); + sqlite3MemdebugSetType(p, + (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); return p; } @@ -20401,7 +20601,7 @@ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, int n){ ** Resize the block of memory pointed to by p to n bytes. If the ** resize fails, set the mallocFailed flag in the connection object. */ -SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){ +SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ void *pNew = 0; assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); @@ -20419,15 +20619,14 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){ sqlite3DbFree(db, p); } }else{ - assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) ); - assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) ); + assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); - pNew = sqlite3_realloc(p, n); + pNew = sqlite3_realloc64(p, n); if( !pNew ){ - sqlite3MemdebugSetType(p, MEMTYPE_DB|MEMTYPE_HEAP); db->mallocFailed = 1; } - sqlite3MemdebugSetType(pNew, MEMTYPE_DB | + sqlite3MemdebugSetType(pNew, (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); } } @@ -20438,7 +20637,7 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){ ** Attempt to reallocate p. If the reallocation fails, then free p ** and set the mallocFailed flag in the database connection. */ -SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){ +SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){ void *pNew; pNew = sqlite3DbRealloc(db, p, n); if( !pNew ){ @@ -20468,7 +20667,7 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){ } return zNew; } -SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){ +SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ char *zNew; if( z==0 ){ return 0; @@ -20476,7 +20675,7 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){ assert( (n&0x7fffffff)==n ); zNew = sqlite3DbMallocRaw(db, n+1); if( zNew ){ - memcpy(zNew, z, n); + memcpy(zNew, z, (size_t)n); zNew[n] = 0; } return zNew; @@ -20498,6 +20697,14 @@ SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat *pz = z; } +/* +** Take actions at the end of an API call to indicate an OOM error +*/ +static SQLITE_NOINLINE int apiOomError(sqlite3 *db){ + db->mallocFailed = 0; + sqlite3Error(db, SQLITE_NOMEM); + return SQLITE_NOMEM; +} /* ** This function must be called before exiting any API function (i.e. @@ -20518,12 +20725,11 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ ** is unsafe, as is the call to sqlite3Error(). */ assert( !db || sqlite3_mutex_held(db->mutex) ); - if( db && (db->mallocFailed || rc==SQLITE_IOERR_NOMEM) ){ - sqlite3Error(db, SQLITE_NOMEM, 0); - db->mallocFailed = 0; - rc = SQLITE_NOMEM; + if( db==0 ) return rc & 0xff; + if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ + return apiOomError(db); } - return rc & (db ? db->errMask : 0xff); + return rc & db->errMask; } /************** End of malloc.c **********************************************/ @@ -20543,6 +20749,17 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ ** SQLlite. */ +/* +** If the strchrnul() library function is available, then set +** HAVE_STRCHRNUL. If that routine is not available, this module +** will supply its own. The built-in version is slower than +** the glibc version so the glibc version is definitely preferred. +*/ +#if !defined(HAVE_STRCHRNUL) +# define HAVE_STRCHRNUL 0 +#endif + + /* ** Conversion types fall into various categories as defined by the ** following enumeration. @@ -20730,7 +20947,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf( const et_info *infop; /* Pointer to the appropriate info structure */ char *zOut; /* Rendering buffer */ int nOut; /* Size of the rendering buffer */ - char *zExtra; /* Malloced memory used by some conversion */ + char *zExtra = 0; /* Malloced memory used by some conversion */ #ifndef SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ int nsd; /* Number of significant digits returned */ @@ -20753,9 +20970,13 @@ SQLITE_PRIVATE void sqlite3VXPrintf( for(; (c=(*fmt))!=0; ++fmt){ if( c!='%' ){ bufpt = (char *)fmt; - while( (c=(*++fmt))!='%' && c!=0 ){}; +#if HAVE_STRCHRNUL + fmt = strchrnul(fmt, '%'); +#else + do{ fmt++; }while( *fmt && *fmt != '%' ); +#endif sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt)); - if( c==0 ) break; + if( *fmt==0 ) break; } if( (c=(*++fmt))==0 ){ sqlite3StrAccumAppend(pAccum, "%", 1); @@ -20843,7 +21064,6 @@ SQLITE_PRIVATE void sqlite3VXPrintf( break; } } - zExtra = 0; /* ** At this point, variables are initialized as follows: @@ -21134,13 +21354,16 @@ SQLITE_PRIVATE void sqlite3VXPrintf( }else{ c = va_arg(ap,int); } - buf[0] = (char)c; - if( precision>=0 ){ - for(idx=1; idx1 ){ + width -= precision-1; + if( width>1 && !flag_leftjustify ){ + sqlite3AppendChar(pAccum, width-1, ' '); + width = 0; + } + sqlite3AppendChar(pAccum, precision-1, c); } + length = 1; + buf[0] = c; bufpt = buf; break; case etSTRING: @@ -21241,11 +21464,14 @@ SQLITE_PRIVATE void sqlite3VXPrintf( ** the output. */ width -= length; - if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width); + if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); sqlite3StrAccumAppend(pAccum, bufpt, length); - if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width); + if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); - if( zExtra ) sqlite3_free(zExtra); + if( zExtra ){ + sqlite3_free(zExtra); + zExtra = 0; + } }/* End for loop over the format string */ } /* End of function */ @@ -21298,11 +21524,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ } /* -** Append N space characters to the given string buffer. +** Append N copies of character c to the given string buffer. */ -SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *p, int N){ +SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){ if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return; - while( (N--)>0 ) p->zText[p->nChar++] = ' '; + while( (N--)>0 ) p->zText[p->nChar++] = c; } /* @@ -21313,7 +21539,7 @@ SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *p, int N){ ** work (enlarging the buffer) using tail recursion, so that the ** sqlite3StrAccumAppend() routine can use fast calling semantics. */ -static void enlargeAndAppend(StrAccum *p, const char *z, int N){ +static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ N = sqlite3StrAccumEnlarge(p, N); if( N>0 ){ memcpy(&p->zText[p->nChar], z, N); @@ -21332,11 +21558,11 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ assert( p->accError==0 || p->nAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ enlargeAndAppend(p,z,N); - return; + }else{ + assert( p->zText ); + p->nChar += N; + memcpy(&p->zText[p->nChar-N], z, N); } - assert( p->zText ); - memcpy(&p->zText[p->nChar], z, N); - p->nChar += N; } /* @@ -21433,7 +21659,7 @@ SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){ /* ** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting -** the string and before returnning. This routine is intended to be used +** the string and before returning. This routine is intended to be used ** to modify an existing string. For example: ** ** x = sqlite3MPrintf(db, x, "prefix %s suffix", x); @@ -21566,6 +21792,69 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){ } #endif +#ifdef SQLITE_DEBUG +/************************************************************************* +** Routines for implementing the "TreeView" display of hierarchical +** data structures for debugging. +** +** The main entry points (coded elsewhere) are: +** sqlite3TreeViewExpr(0, pExpr, 0); +** sqlite3TreeViewExprList(0, pList, 0, 0); +** sqlite3TreeViewSelect(0, pSelect, 0); +** Insert calls to those routines while debugging in order to display +** a diagram of Expr, ExprList, and Select objects. +** +*/ +/* Add a new subitem to the tree. The moreToFollow flag indicates that this +** is not the last item in the tree. */ +SQLITE_PRIVATE TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ + if( p==0 ){ + p = sqlite3_malloc( sizeof(*p) ); + if( p==0 ) return 0; + memset(p, 0, sizeof(*p)); + }else{ + p->iLevel++; + } + assert( moreToFollow==0 || moreToFollow==1 ); + if( p->iLevelbLine) ) p->bLine[p->iLevel] = moreToFollow; + return p; +} +/* Finished with one layer of the tree */ +SQLITE_PRIVATE void sqlite3TreeViewPop(TreeView *p){ + if( p==0 ) return; + p->iLevel--; + if( p->iLevel<0 ) sqlite3_free(p); +} +/* Generate a single line of output for the tree, with a prefix that contains +** all the appropriate tree lines */ +SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ + va_list ap; + int i; + StrAccum acc; + char zBuf[500]; + sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0); + acc.useMalloc = 0; + if( p ){ + for(i=0; iiLevel && ibLine)-1; i++){ + sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4); + } + sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); + } + va_start(ap, zFormat); + sqlite3VXPrintf(&acc, 0, zFormat, ap); + va_end(ap); + if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1); + sqlite3StrAccumFinish(&acc); + fprintf(stdout,"%s", zBuf); + fflush(stdout); +} +/* Shorthand for starting a new tree item that consists of a single label */ +SQLITE_PRIVATE void sqlite3TreeViewItem(TreeView *p, const char *zLabel, u8 moreToFollow){ + p = sqlite3TreeViewPush(p, moreToFollow); + sqlite3TreeViewLine(p, "%s", zLabel); +} +#endif /* SQLITE_DEBUG */ + /* ** variable-argument wrapper around sqlite3VXPrintf(). */ @@ -21705,6 +21994,270 @@ SQLITE_PRIVATE void sqlite3PrngRestoreState(void){ #endif /* SQLITE_OMIT_BUILTIN_TEST */ /************** End of random.c **********************************************/ +/************** Begin file threads.c *****************************************/ +/* +** 2012 July 21 +** +** 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 presents a simple cross-platform threading interface for +** use internally by SQLite. +** +** A "thread" can be created using sqlite3ThreadCreate(). This thread +** runs independently of its creator until it is joined using +** sqlite3ThreadJoin(), at which point it terminates. +** +** Threads do not have to be real. It could be that the work of the +** "thread" is done by the main thread at either the sqlite3ThreadCreate() +** or sqlite3ThreadJoin() call. This is, in fact, what happens in +** single threaded systems. Nothing in SQLite requires multiple threads. +** This interface exists so that applications that want to take advantage +** of multiple cores can do so, while also allowing applications to stay +** single-threaded if desired. +*/ + +#if SQLITE_MAX_WORKER_THREADS>0 + +/********************************* Unix Pthreads ****************************/ +#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0 + +#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ +/* #include */ + +/* A running thread */ +struct SQLiteThread { + pthread_t tid; /* Thread ID */ + int done; /* Set to true when thread finishes */ + void *pOut; /* Result returned by the thread */ + void *(*xTask)(void*); /* The thread routine */ + void *pIn; /* Argument to the thread */ +}; + +/* Create a new thread */ +SQLITE_PRIVATE int sqlite3ThreadCreate( + SQLiteThread **ppThread, /* OUT: Write the thread object here */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + SQLiteThread *p; + int rc; + + assert( ppThread!=0 ); + assert( xTask!=0 ); + /* This routine is never used in single-threaded mode */ + assert( sqlite3GlobalConfig.bCoreMutex!=0 ); + + *ppThread = 0; + p = sqlite3Malloc(sizeof(*p)); + if( p==0 ) return SQLITE_NOMEM; + memset(p, 0, sizeof(*p)); + p->xTask = xTask; + p->pIn = pIn; + if( sqlite3FaultSim(200) ){ + rc = 1; + }else{ + rc = pthread_create(&p->tid, 0, xTask, pIn); + } + if( rc ){ + p->done = 1; + p->pOut = xTask(pIn); + } + *ppThread = p; + return SQLITE_OK; +} + +/* Get the results of the thread */ +SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ + int rc; + + assert( ppOut!=0 ); + if( NEVER(p==0) ) return SQLITE_NOMEM; + if( p->done ){ + *ppOut = p->pOut; + rc = SQLITE_OK; + }else{ + rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK; + } + sqlite3_free(p); + return rc; +} + +#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */ +/******************************** End Unix Pthreads *************************/ + + +/********************************* Win32 Threads ****************************/ +#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0 + +#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ +#include + +/* A running thread */ +struct SQLiteThread { + void *tid; /* The thread handle */ + unsigned id; /* The thread identifier */ + void *(*xTask)(void*); /* The routine to run as a thread */ + void *pIn; /* Argument to xTask */ + void *pResult; /* Result of xTask */ +}; + +/* Thread procedure Win32 compatibility shim */ +static unsigned __stdcall sqlite3ThreadProc( + void *pArg /* IN: Pointer to the SQLiteThread structure */ +){ + SQLiteThread *p = (SQLiteThread *)pArg; + + assert( p!=0 ); +#if 0 + /* + ** This assert appears to trigger spuriously on certain + ** versions of Windows, possibly due to _beginthreadex() + ** and/or CreateThread() not fully setting their thread + ** ID parameter before starting the thread. + */ + assert( p->id==GetCurrentThreadId() ); +#endif + assert( p->xTask!=0 ); + p->pResult = p->xTask(p->pIn); + + _endthreadex(0); + return 0; /* NOT REACHED */ +} + +/* Create a new thread */ +SQLITE_PRIVATE int sqlite3ThreadCreate( + SQLiteThread **ppThread, /* OUT: Write the thread object here */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + SQLiteThread *p; + + assert( ppThread!=0 ); + assert( xTask!=0 ); + *ppThread = 0; + p = sqlite3Malloc(sizeof(*p)); + if( p==0 ) return SQLITE_NOMEM; + if( sqlite3GlobalConfig.bCoreMutex==0 ){ + memset(p, 0, sizeof(*p)); + }else{ + p->xTask = xTask; + p->pIn = pIn; + p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id); + if( p->tid==0 ){ + memset(p, 0, sizeof(*p)); + } + } + if( p->xTask==0 ){ + p->id = GetCurrentThreadId(); + p->pResult = xTask(pIn); + } + *ppThread = p; + return SQLITE_OK; +} + +SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */ + +/* Get the results of the thread */ +SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ + DWORD rc; + BOOL bRc; + + assert( ppOut!=0 ); + if( NEVER(p==0) ) return SQLITE_NOMEM; + if( p->xTask==0 ){ + assert( p->id==GetCurrentThreadId() ); + rc = WAIT_OBJECT_0; + assert( p->tid==0 ); + }else{ + assert( p->id!=0 && p->id!=GetCurrentThreadId() ); + rc = sqlite3Win32Wait((HANDLE)p->tid); + assert( rc!=WAIT_IO_COMPLETION ); + bRc = CloseHandle((HANDLE)p->tid); + assert( bRc ); + } + if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; + sqlite3_free(p); + return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; +} + +#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT */ +/******************************** End Win32 Threads *************************/ + + +/********************************* Single-Threaded **************************/ +#ifndef SQLITE_THREADS_IMPLEMENTED +/* +** This implementation does not actually create a new thread. It does the +** work of the thread in the main thread, when either the thread is created +** or when it is joined +*/ + +/* A running thread */ +struct SQLiteThread { + void *(*xTask)(void*); /* The routine to run as a thread */ + void *pIn; /* Argument to xTask */ + void *pResult; /* Result of xTask */ +}; + +/* Create a new thread */ +SQLITE_PRIVATE int sqlite3ThreadCreate( + SQLiteThread **ppThread, /* OUT: Write the thread object here */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + SQLiteThread *p; + + assert( ppThread!=0 ); + assert( xTask!=0 ); + *ppThread = 0; + p = sqlite3Malloc(sizeof(*p)); + if( p==0 ) return SQLITE_NOMEM; + if( (SQLITE_PTR_TO_INT(p)/17)&1 ){ + p->xTask = xTask; + p->pIn = pIn; + }else{ + p->xTask = 0; + p->pResult = xTask(pIn); + } + *ppThread = p; + return SQLITE_OK; +} + +/* Get the results of the thread */ +SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ + + assert( ppOut!=0 ); + if( NEVER(p==0) ) return SQLITE_NOMEM; + if( p->xTask ){ + *ppOut = p->xTask(p->pIn); + }else{ + *ppOut = p->pResult; + } + sqlite3_free(p); + +#if defined(SQLITE_TEST) + { + void *pTstAlloc = sqlite3Malloc(10); + if (!pTstAlloc) return SQLITE_NOMEM; + sqlite3_free(pTstAlloc); + } +#endif + + return SQLITE_OK; +} + +#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */ +/****************************** End Single-Threaded *************************/ +#endif /* SQLITE_MAX_WORKER_THREADS>0 */ + +/************** End of threads.c *********************************************/ /************** Begin file utf.c *********************************************/ /* ** 2004 April 13 @@ -21905,7 +22458,7 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read( ** desiredEnc. It is an error if the string is already of the desired ** encoding, or if *pMem does not contain a string value. */ -SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ +SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ int len; /* Maximum length of output string in bytes */ unsigned char *zOut; /* Output buffer */ unsigned char *zIn; /* Input iterator */ @@ -22020,12 +22573,13 @@ SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ *z = 0; assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); + c = pMem->flags; sqlite3VdbeMemRelease(pMem); - pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem); + pMem->flags = MEM_Str|MEM_Term|(c&MEM_AffMask); pMem->enc = desiredEnc; - pMem->flags |= (MEM_Term); pMem->z = (char*)zOut; pMem->zMalloc = pMem->z; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->z); translate_out: #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) @@ -22348,6 +22902,15 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){ return 0x3fffffff & (int)(z2 - z); } +/* +** Set the current error code to err_code and clear any prior error message. +*/ +SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){ + assert( db!=0 ); + db->errCode = err_code; + if( db->pErr ) sqlite3ValueSetNull(db->pErr); +} + /* ** Set the most recent error code and error string for the sqlite ** handle "db". The error code is set to "err_code". @@ -22369,18 +22932,18 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){ ** should be called with err_code set to SQLITE_OK and zFormat set ** to NULL. */ -SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){ +SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){ assert( db!=0 ); db->errCode = err_code; - if( zFormat && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){ + if( zFormat==0 ){ + sqlite3Error(db, err_code); + }else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){ char *z; va_list ap; va_start(ap, zFormat); z = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC); - }else if( db->pErr ){ - sqlite3ValueSetNull(db->pErr); } } @@ -22394,12 +22957,12 @@ SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ** %T Insert a token ** %S Insert the first element of a SrcList ** -** This function should be used to report any error that occurs whilst +** This function should be used to report any error that occurs while ** compiling an SQL statement (i.e. within sqlite3_prepare()). The ** last thing the sqlite3_prepare() function does is copy the error ** stored by this function into the database handle using sqlite3Error(). -** Function sqlite3Error() should be used during statement execution -** (sqlite3_step() etc.). +** Functions sqlite3Error() or sqlite3ErrorWithMsg() should be used +** during statement execution (sqlite3_step() etc.). */ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ char *zMsg; @@ -22432,7 +22995,7 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ ** occur. ** ** 2002-Feb-14: This routine is extended to remove MS-Access style -** brackets from around identifers. For example: "[a-b-c]" becomes +** brackets from around identifiers. For example: "[a-b-c]" becomes ** "a-b-c". */ SQLITE_PRIVATE int sqlite3Dequote(char *z){ @@ -22936,7 +23499,7 @@ SQLITE_PRIVATE int sqlite3Atoi(const char *z){ ** bit clear. Except, if we get to the 9th byte, it stores the full ** 8 bits and is the last byte. */ -SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){ +static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){ int i, j, n; u8 buf[10]; if( v & (((u64)0xff000000)<<32) ){ @@ -22960,28 +23523,17 @@ SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){ } return n; } - -/* -** This routine is a faster version of sqlite3PutVarint() that only -** works for 32-bit positive integers and which is optimized for -** the common case of small integers. A MACRO version, putVarint32, -** is provided which inlines the single-byte case. All code should use -** the MACRO version as this function assumes the single-byte case has -** already been handled. -*/ -SQLITE_PRIVATE int sqlite3PutVarint32(unsigned char *p, u32 v){ -#ifndef putVarint32 - if( (v & ~0x7f)==0 ){ - p[0] = v; +SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){ + if( v<=0x7f ){ + p[0] = v&0x7f; return 1; } -#endif - if( (v & ~0x3fff)==0 ){ - p[0] = (u8)((v>>7) | 0x80); - p[1] = (u8)(v & 0x7f); + if( v<=0x3fff ){ + p[0] = ((v>>7)&0x7f)|0x80; + p[1] = v&0x7f; return 2; } - return sqlite3PutVarint(p, v); + return putVarint64(p,v); } /* @@ -23657,12 +24209,11 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){ /* ** The hashing function. */ -static unsigned int strHash(const char *z, int nKey){ +static unsigned int strHash(const char *z){ unsigned int h = 0; - assert( nKey>=0 ); - while( nKey > 0 ){ - h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++]; - nKey--; + unsigned char c; + while( (c = (unsigned char)*z++)!=0 ){ + h = (h<<3) ^ h ^ sqlite3UpperToLower[c]; } return h; } @@ -23734,7 +24285,7 @@ static int rehash(Hash *pH, unsigned int new_size){ pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht); memset(new_ht, 0, new_size*sizeof(struct _ht)); for(elem=pH->first, pH->first=0; elem; elem = next_elem){ - unsigned int h = strHash(elem->pKey, elem->nKey) % new_size; + unsigned int h = strHash(elem->pKey) % new_size; next_elem = elem->next; insertElement(pH, &new_ht[h], elem); } @@ -23742,28 +24293,33 @@ static int rehash(Hash *pH, unsigned int new_size){ } /* This function (for internal use only) locates an element in an -** hash table that matches the given key. The hash for this key has -** already been computed and is passed as the 4th parameter. +** hash table that matches the given key. The hash for this key is +** also computed and returned in the *pH parameter. */ -static HashElem *findElementGivenHash( +static HashElem *findElementWithHash( const Hash *pH, /* The pH to be searched */ const char *pKey, /* The key we are searching for */ - int nKey, /* Bytes in key (not counting zero terminator) */ - unsigned int h /* The hash for this key. */ + unsigned int *pHash /* Write the hash value here */ ){ HashElem *elem; /* Used to loop thru the element list */ int count; /* Number of elements left to test */ + unsigned int h; /* The computed hash */ if( pH->ht ){ - struct _ht *pEntry = &pH->ht[h]; + struct _ht *pEntry; + h = strHash(pKey) % pH->htsize; + pEntry = &pH->ht[h]; elem = pEntry->chain; count = pEntry->count; }else{ + h = 0; elem = pH->first; count = pH->count; } - while( count-- && ALWAYS(elem) ){ - if( elem->nKey==nKey && sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){ + *pHash = h; + while( count-- ){ + assert( elem!=0 ); + if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ return elem; } elem = elem->next; @@ -23806,26 +24362,20 @@ static void removeElementGivenHash( } /* Attempt to locate an element of the hash table pH with a key -** that matches pKey,nKey. Return the data for this element if it is +** that matches pKey. Return the data for this element if it is ** found, or NULL if there is no match. */ -SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey, int nKey){ +SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){ HashElem *elem; /* The element that matches key */ unsigned int h; /* A hash on key */ assert( pH!=0 ); assert( pKey!=0 ); - assert( nKey>=0 ); - if( pH->ht ){ - h = strHash(pKey, nKey) % pH->htsize; - }else{ - h = 0; - } - elem = findElementGivenHash(pH, pKey, nKey, h); + elem = findElementWithHash(pH, pKey, &h); return elem ? elem->data : 0; } -/* Insert an element into the hash table pH. The key is pKey,nKey +/* Insert an element into the hash table pH. The key is pKey ** and the data is "data". ** ** If no element exists with a matching key, then a new @@ -23839,20 +24389,14 @@ SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey, int nKey) ** If the "data" parameter to this function is NULL, then the ** element corresponding to "key" is removed from the hash table. */ -SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, void *data){ +SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ unsigned int h; /* the hash of the key modulo hash table size */ HashElem *elem; /* Used to loop thru the element list */ HashElem *new_elem; /* New element added to the pH */ assert( pH!=0 ); assert( pKey!=0 ); - assert( nKey>=0 ); - if( pH->htsize ){ - h = strHash(pKey, nKey) % pH->htsize; - }else{ - h = 0; - } - elem = findElementGivenHash(pH,pKey,nKey,h); + elem = findElementWithHash(pH,pKey,&h); if( elem ){ void *old_data = elem->data; if( data==0 ){ @@ -23860,7 +24404,6 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, voi }else{ elem->data = data; elem->pKey = pKey; - assert(nKey==elem->nKey); } return old_data; } @@ -23868,20 +24411,15 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, voi new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) ); if( new_elem==0 ) return data; new_elem->pKey = pKey; - new_elem->nKey = nKey; new_elem->data = data; pH->count++; if( pH->count>=10 && pH->count > 2*pH->htsize ){ if( rehash(pH, pH->count*2) ){ assert( pH->htsize>0 ); - h = strHash(pKey, nKey) % pH->htsize; + h = strHash(pKey) % pH->htsize; } } - if( pH->ht ){ - insertElement(pH, &pH->ht[h], new_elem); - }else{ - insertElement(pH, 0, new_elem); - } + insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem); return 0; } @@ -23936,42 +24474,42 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 37 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), /* 38 */ "MustBeInt" OpHelp(""), /* 39 */ "RealAffinity" OpHelp(""), - /* 40 */ "Permutation" OpHelp(""), - /* 41 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 42 */ "Jump" OpHelp(""), - /* 43 */ "Once" OpHelp(""), - /* 44 */ "If" OpHelp(""), - /* 45 */ "IfNot" OpHelp(""), - /* 46 */ "Column" OpHelp("r[P3]=PX"), - /* 47 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 48 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 49 */ "Count" OpHelp("r[P2]=count()"), - /* 50 */ "ReadCookie" OpHelp(""), - /* 51 */ "SetCookie" OpHelp(""), - /* 52 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 53 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 54 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 55 */ "OpenAutoindex" OpHelp("nColumn=P2"), - /* 56 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 57 */ "SorterOpen" OpHelp(""), - /* 58 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 59 */ "Close" OpHelp(""), - /* 60 */ "SeekLT" OpHelp("key=r[P3@P4]"), - /* 61 */ "SeekLE" OpHelp("key=r[P3@P4]"), - /* 62 */ "SeekGE" OpHelp("key=r[P3@P4]"), - /* 63 */ "SeekGT" OpHelp("key=r[P3@P4]"), - /* 64 */ "Seek" OpHelp("intkey=r[P2]"), - /* 65 */ "NoConflict" OpHelp("key=r[P3@P4]"), - /* 66 */ "NotFound" OpHelp("key=r[P3@P4]"), - /* 67 */ "Found" OpHelp("key=r[P3@P4]"), - /* 68 */ "NotExists" OpHelp("intkey=r[P3]"), - /* 69 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), - /* 70 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 40 */ "Cast" OpHelp("affinity(r[P1])"), + /* 41 */ "Permutation" OpHelp(""), + /* 42 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 43 */ "Jump" OpHelp(""), + /* 44 */ "Once" OpHelp(""), + /* 45 */ "If" OpHelp(""), + /* 46 */ "IfNot" OpHelp(""), + /* 47 */ "Column" OpHelp("r[P3]=PX"), + /* 48 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 49 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 50 */ "Count" OpHelp("r[P2]=count()"), + /* 51 */ "ReadCookie" OpHelp(""), + /* 52 */ "SetCookie" OpHelp(""), + /* 53 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 54 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 55 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 56 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 57 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 58 */ "SorterOpen" OpHelp(""), + /* 59 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 60 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 61 */ "Close" OpHelp(""), + /* 62 */ "SeekLT" OpHelp("key=r[P3@P4]"), + /* 63 */ "SeekLE" OpHelp("key=r[P3@P4]"), + /* 64 */ "SeekGE" OpHelp("key=r[P3@P4]"), + /* 65 */ "SeekGT" OpHelp("key=r[P3@P4]"), + /* 66 */ "Seek" OpHelp("intkey=r[P2]"), + /* 67 */ "NoConflict" OpHelp("key=r[P3@P4]"), + /* 68 */ "NotFound" OpHelp("key=r[P3@P4]"), + /* 69 */ "Found" OpHelp("key=r[P3@P4]"), + /* 70 */ "NotExists" OpHelp("intkey=r[P3]"), /* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), /* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), - /* 73 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), - /* 74 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), - /* 75 */ "Delete" OpHelp(""), + /* 73 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 74 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 75 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), /* 76 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 77 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 78 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"), @@ -23980,7 +24518,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 81 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"), /* 82 */ "Lt" OpHelp("if r[P1]=r[P3] goto P2"), - /* 84 */ "ResetCount" OpHelp(""), + /* 84 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), /* 85 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 86 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 87 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<0 goto P2"), - /* 136 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"), - /* 137 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"), - /* 138 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 139 */ "IncrVacuum" OpHelp(""), - /* 140 */ "Expire" OpHelp(""), - /* 141 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 142 */ "VBegin" OpHelp(""), - /* 143 */ "ToText" OpHelp(""), - /* 144 */ "ToBlob" OpHelp(""), - /* 145 */ "ToNumeric" OpHelp(""), - /* 146 */ "ToInt" OpHelp(""), - /* 147 */ "ToReal" OpHelp(""), - /* 148 */ "VCreate" OpHelp(""), - /* 149 */ "VDestroy" OpHelp(""), - /* 150 */ "VOpen" OpHelp(""), - /* 151 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 152 */ "VNext" OpHelp(""), - /* 153 */ "VRename" OpHelp(""), - /* 154 */ "Pagecount" OpHelp(""), - /* 155 */ "MaxPgcnt" OpHelp(""), - /* 156 */ "Init" OpHelp("Start at P2"), - /* 157 */ "Noop" OpHelp(""), - /* 158 */ "Explain" OpHelp(""), + /* 134 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 135 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 136 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 137 */ "IfPos" OpHelp("if r[P1]>0 goto P2"), + /* 138 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"), + /* 139 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"), + /* 140 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 141 */ "IncrVacuum" OpHelp(""), + /* 142 */ "Expire" OpHelp(""), + /* 143 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 144 */ "VBegin" OpHelp(""), + /* 145 */ "VCreate" OpHelp(""), + /* 146 */ "VDestroy" OpHelp(""), + /* 147 */ "VOpen" OpHelp(""), + /* 148 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 149 */ "VNext" OpHelp(""), + /* 150 */ "VRename" OpHelp(""), + /* 151 */ "Pagecount" OpHelp(""), + /* 152 */ "MaxPgcnt" OpHelp(""), + /* 153 */ "Init" OpHelp("Start at P2"), + /* 154 */ "Noop" OpHelp(""), + /* 155 */ "Explain" OpHelp(""), }; return azName[i]; } @@ -24570,6 +25105,14 @@ SQLITE_API int sqlite3_open_file_count = 0; # endif #endif +/* +** Explicitly call the 64-bit version of lseek() on Android. Otherwise, lseek() +** is the 32-bit version, even if _FILE_OFFSET_BITS=64 is defined. +*/ +#ifdef __ANDROID__ +# define lseek lseek64 +#endif + /* ** Different Unix systems declare open() in different ways. Same use ** open(const char*,int,mode_t). Others use open(const char*,int,...). @@ -24902,7 +25445,7 @@ static int unixMutexHeld(void) { #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) /* ** Helper function for printing out trace information from debugging -** binaries. This returns the string represetation of the supplied +** binaries. This returns the string representation of the supplied ** integer lock-type. */ static const char *azFileLock(int eFileLock){ @@ -24979,9 +25522,22 @@ static int lockTrace(int fd, int op, struct flock *p){ /* ** Retry ftruncate() calls that fail due to EINTR +** +** All calls to ftruncate() within this file should be made through this wrapper. +** On the Android platform, bypassing the logic below could lead to a corrupt +** database. */ static int robust_ftruncate(int h, sqlite3_int64 sz){ int rc; +#ifdef __ANDROID__ + /* On Android, ftruncate() always uses 32-bit offsets, even if + ** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to + ** truncate a file to any size larger than 2GiB. Silently ignore any + ** such attempts. */ + if( sz>(sqlite3_int64)0x7FFFFFFF ){ + rc = SQLITE_OK; + }else +#endif do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR ); return rc; } @@ -27369,7 +27925,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){ ** NB: If you define USE_PREAD or USE_PREAD64, then it might also ** be necessary to define _XOPEN_SOURCE to be 500. This varies from ** one system to another. Since SQLite does not define USE_PREAD -** any any form by default, we will not attempt to define _XOPEN_SOURCE. +** in any form by default, we will not attempt to define _XOPEN_SOURCE. ** See tickets #2741 and #2681. ** ** To avoid stomping the errno value on a failed read the lastErrno value @@ -27866,7 +28422,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } - rc = robust_ftruncate(pFile->h, (off_t)nByte); + rc = robust_ftruncate(pFile->h, nByte); if( rc ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); @@ -28001,7 +28557,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ } /* -** If *pArg is inititially negative then this is a query. Set *pArg to +** If *pArg is initially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ** ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. @@ -28208,7 +28764,7 @@ static int unixSectorSize(sqlite3_file *id){ ** Return the device characteristics for the file. ** ** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default. -** However, that choice is contraversial since technically the underlying +** However, that choice is controversial since technically the underlying ** file system does not always provide powersafe overwrites. (In other ** words, after a power-loss event, parts of the file that were never ** written might end up being altered.) However, non-PSOW behavior is very, @@ -29180,7 +29736,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ ** looks at the filesystem type and tries to guess the best locking ** strategy from that. ** -** For finder-funtion F, two objects are created: +** For finder-function F, two objects are created: ** ** (1) The real finder-function named "FImpt()". ** @@ -29201,7 +29757,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ ** * An I/O method finder function called FINDER that returns a pointer ** to the METHOD object in the previous bullet. */ -#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK) \ +#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK, SHMMAP) \ static const sqlite3_io_methods METHOD = { \ VERSION, /* iVersion */ \ CLOSE, /* xClose */ \ @@ -29216,7 +29772,7 @@ static const sqlite3_io_methods METHOD = { \ unixFileControl, /* xFileControl */ \ unixSectorSize, /* xSectorSize */ \ unixDeviceCharacteristics, /* xDeviceCapabilities */ \ - unixShmMap, /* xShmMap */ \ + SHMMAP, /* xShmMap */ \ unixShmLock, /* xShmLock */ \ unixShmBarrier, /* xShmBarrier */ \ unixShmUnmap, /* xShmUnmap */ \ @@ -29242,16 +29798,18 @@ IOMETHODS( unixClose, /* xClose method */ unixLock, /* xLock method */ unixUnlock, /* xUnlock method */ - unixCheckReservedLock /* xCheckReservedLock method */ + unixCheckReservedLock, /* xCheckReservedLock method */ + unixShmMap /* xShmMap method */ ) IOMETHODS( nolockIoFinder, /* Finder function name */ nolockIoMethods, /* sqlite3_io_methods object name */ - 1, /* shared memory is disabled */ + 3, /* shared memory is disabled */ nolockClose, /* xClose method */ nolockLock, /* xLock method */ nolockUnlock, /* xUnlock method */ - nolockCheckReservedLock /* xCheckReservedLock method */ + nolockCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) IOMETHODS( dotlockIoFinder, /* Finder function name */ @@ -29260,7 +29818,8 @@ IOMETHODS( dotlockClose, /* xClose method */ dotlockLock, /* xLock method */ dotlockUnlock, /* xUnlock method */ - dotlockCheckReservedLock /* xCheckReservedLock method */ + dotlockCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS @@ -29271,7 +29830,8 @@ IOMETHODS( flockClose, /* xClose method */ flockLock, /* xLock method */ flockUnlock, /* xUnlock method */ - flockCheckReservedLock /* xCheckReservedLock method */ + flockCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #endif @@ -29283,7 +29843,8 @@ IOMETHODS( semClose, /* xClose method */ semLock, /* xLock method */ semUnlock, /* xUnlock method */ - semCheckReservedLock /* xCheckReservedLock method */ + semCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #endif @@ -29295,7 +29856,8 @@ IOMETHODS( afpClose, /* xClose method */ afpLock, /* xLock method */ afpUnlock, /* xUnlock method */ - afpCheckReservedLock /* xCheckReservedLock method */ + afpCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #endif @@ -29320,7 +29882,8 @@ IOMETHODS( proxyClose, /* xClose method */ proxyLock, /* xLock method */ proxyUnlock, /* xUnlock method */ - proxyCheckReservedLock /* xCheckReservedLock method */ + proxyCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #endif @@ -29333,7 +29896,8 @@ IOMETHODS( unixClose, /* xClose method */ unixLock, /* xLock method */ nfsUnlock, /* xUnlock method */ - unixCheckReservedLock /* xCheckReservedLock method */ + unixCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #endif @@ -29442,7 +30006,7 @@ static const sqlite3_io_methods #endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */ /* -** An abstract type for a pointer to a IO method finder function: +** An abstract type for a pointer to an IO method finder function: */ typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); @@ -29756,7 +30320,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ ** descriptor on the same path, fail, and return an error to SQLite. ** ** Even if a subsequent open() call does succeed, the consequences of - ** not searching for a resusable file descriptor are not dire. */ + ** not searching for a reusable file descriptor are not dire. */ if( 0==osStat(zPath, &sStat) ){ unixInodeInfo *pInode; @@ -29787,7 +30351,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ ** written to *pMode. If an IO error occurs, an SQLite error code is ** returned and the value of *pMode is not modified. ** -** In most cases cases, this routine sets *pMode to 0, which will become +** In most cases, this routine sets *pMode to 0, which will become ** an indication to robust_open() to create the file using ** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask. ** But if the file being opened is a WAL or regular journal file, then @@ -30156,7 +30720,7 @@ static int unixDelete( if( osUnlink(zPath)==(-1) ){ if( errno==ENOENT #if OS_VXWORKS - || errno==0x380003 + || osAccess(zPath,0)!=0 #endif ){ rc = SQLITE_IOERR_DELETE_NOENT; @@ -30579,7 +31143,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** proxy path against the values stored in the conch. The conch file is ** stored in the same directory as the database file and the file name ** is patterned after the database file name as ".-conch". -** If the conch file does not exist, or it's contents do not match the +** If the conch file does not exist, or its contents do not match the ** host ID and/or proxy path, then the lock is escalated to an exclusive ** lock and the conch file contents is updated with the host ID and proxy ** path and the lock is downgraded to a shared lock again. If the conch @@ -30631,7 +31195,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will ** force proxy locking to be used for every database file opened, and 0 ** will force automatic proxy locking to be disabled for all database -** files (explicity calling the SQLITE_SET_LOCKPROXYFILE pragma or +** files (explicitly calling the SQLITE_SET_LOCKPROXYFILE pragma or ** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING). */ @@ -32393,9 +32957,9 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void); ** can manually set this value to 1 to emulate Win98 behavior. */ #ifdef SQLITE_TEST -SQLITE_API LONG volatile sqlite3_os_type = 0; +SQLITE_API LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; #else -static LONG volatile sqlite3_os_type = 0; +static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; #endif #ifndef SYSCALL @@ -32926,7 +33490,7 @@ static struct win_syscall { #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ DWORD))aSyscall[63].pCurrent) -#if SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, #else { "WaitForSingleObjectEx", (SYSCALL)0, 0 }, @@ -33038,8 +33602,8 @@ static struct win_syscall { #else { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, -#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*, \ - LONG,LONG))aSyscall[76].pCurrent) +#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \ + SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent) #endif /* defined(InterlockedCompareExchange) */ }; /* End of the overrideable system calls */ @@ -33273,6 +33837,16 @@ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){ #endif } +#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ + SQLITE_THREADSAFE>0 +SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ + DWORD rc; + while( (rc = osWaitForSingleObjectEx(hObject, INFINITE, + TRUE))==WAIT_IO_COMPLETION ){} + return rc; +} +#endif + /* ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, ** or WinCE. Return false (zero) for Win95, Win98, or WinME. @@ -33300,27 +33874,36 @@ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){ ** based on the NT kernel. */ SQLITE_API int sqlite3_win32_is_nt(void){ -#if defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX +#if SQLITE_OS_WINRT + /* + ** NOTE: The WinRT sub-platform is always assumed to be based on the NT + ** kernel. + */ + return 1; +#elif defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ - defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8 - OSVERSIONINFOW sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - osGetVersionExW(&sInfo); - osInterlockedCompareExchange(&sqlite3_os_type, - (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); -#elif defined(SQLITE_WIN32_HAS_ANSI) +#if defined(SQLITE_WIN32_HAS_ANSI) OSVERSIONINFOA sInfo; sInfo.dwOSVersionInfoSize = sizeof(sInfo); osGetVersionExA(&sInfo); osInterlockedCompareExchange(&sqlite3_os_type, (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); +#elif defined(SQLITE_WIN32_HAS_WIDE) + OSVERSIONINFOW sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExW(&sInfo); + osInterlockedCompareExchange(&sqlite3_os_type, + (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); #endif } return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; #elif SQLITE_TEST return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; #else + /* + ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are + ** deprecated are always assumed to be based on the NT kernel. + */ return 1; #endif } @@ -35097,7 +35680,7 @@ static int winUnlock(sqlite3_file *id, int locktype){ } /* -** If *pArg is inititially negative then this is a query. Set *pArg to +** If *pArg is initially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ** ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. @@ -36111,7 +36694,7 @@ static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){ }else{ /* FIXME: If Windows truly always prevents truncating or deleting a ** file while a mapping is held, then the following winUnmapfile() call - ** is unnecessary can can be omitted - potentially improving + ** is unnecessary can be omitted - potentially improving ** performance. */ winUnmapfile(pFd); } @@ -37969,88 +38552,71 @@ struct PCache { /********************************** Linked List Management ********************/ -#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) -/* -** Check that the pCache->pSynced variable is set correctly. If it -** is not, either fail an assert or return zero. Otherwise, return -** non-zero. This is only used in debugging builds, as follows: -** -** expensive_assert( pcacheCheckSynced(pCache) ); -*/ -static int pcacheCheckSynced(PCache *pCache){ - PgHdr *p; - for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pDirtyPrev){ - assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) ); - } - return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0); -} -#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */ +/* Allowed values for second argument to pcacheManageDirtyList() */ +#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */ +#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */ +#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */ /* -** Remove page pPage from the list of dirty pages. +** Manage pPage's participation on the dirty list. Bits of the addRemove +** argument determines what operation to do. The 0x01 bit means first +** remove pPage from the dirty list. The 0x02 means add pPage back to +** the dirty list. Doing both moves pPage to the front of the dirty list. */ -static void pcacheRemoveFromDirtyList(PgHdr *pPage){ +static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ PCache *p = pPage->pCache; - assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); - assert( pPage->pDirtyPrev || pPage==p->pDirty ); - - /* Update the PCache1.pSynced variable if necessary. */ - if( p->pSynced==pPage ){ - PgHdr *pSynced = pPage->pDirtyPrev; - while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){ - pSynced = pSynced->pDirtyPrev; + if( addRemove & PCACHE_DIRTYLIST_REMOVE ){ + assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); + assert( pPage->pDirtyPrev || pPage==p->pDirty ); + + /* Update the PCache1.pSynced variable if necessary. */ + if( p->pSynced==pPage ){ + PgHdr *pSynced = pPage->pDirtyPrev; + while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){ + pSynced = pSynced->pDirtyPrev; + } + p->pSynced = pSynced; } - p->pSynced = pSynced; + + if( pPage->pDirtyNext ){ + pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; + }else{ + assert( pPage==p->pDirtyTail ); + p->pDirtyTail = pPage->pDirtyPrev; + } + if( pPage->pDirtyPrev ){ + pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; + }else{ + assert( pPage==p->pDirty ); + p->pDirty = pPage->pDirtyNext; + if( p->pDirty==0 && p->bPurgeable ){ + assert( p->eCreate==1 ); + p->eCreate = 2; + } + } + pPage->pDirtyNext = 0; + pPage->pDirtyPrev = 0; } - - if( pPage->pDirtyNext ){ - pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; - }else{ - assert( pPage==p->pDirtyTail ); - p->pDirtyTail = pPage->pDirtyPrev; - } - if( pPage->pDirtyPrev ){ - pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; - }else{ - assert( pPage==p->pDirty ); - p->pDirty = pPage->pDirtyNext; - if( p->pDirty==0 && p->bPurgeable ){ - assert( p->eCreate==1 ); - p->eCreate = 2; + if( addRemove & PCACHE_DIRTYLIST_ADD ){ + assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage ); + + pPage->pDirtyNext = p->pDirty; + if( pPage->pDirtyNext ){ + assert( pPage->pDirtyNext->pDirtyPrev==0 ); + pPage->pDirtyNext->pDirtyPrev = pPage; + }else{ + p->pDirtyTail = pPage; + if( p->bPurgeable ){ + assert( p->eCreate==2 ); + p->eCreate = 1; + } + } + p->pDirty = pPage; + if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){ + p->pSynced = pPage; } } - pPage->pDirtyNext = 0; - pPage->pDirtyPrev = 0; - - expensive_assert( pcacheCheckSynced(p) ); -} - -/* -** Add page pPage to the head of the dirty list (PCache1.pDirty is set to -** pPage). -*/ -static void pcacheAddToDirtyList(PgHdr *pPage){ - PCache *p = pPage->pCache; - - assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage ); - - pPage->pDirtyNext = p->pDirty; - if( pPage->pDirtyNext ){ - assert( pPage->pDirtyNext->pDirtyPrev==0 ); - pPage->pDirtyNext->pDirtyPrev = pPage; - }else if( p->bPurgeable ){ - assert( p->eCreate==2 ); - p->eCreate = 1; - } - p->pDirty = pPage; - if( !p->pDirtyTail ){ - p->pDirtyTail = pPage; - } - if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){ - p->pSynced = pPage; - } - expensive_assert( pcacheCheckSynced(p) ); } /* @@ -38058,12 +38624,22 @@ static void pcacheAddToDirtyList(PgHdr *pPage){ ** being used for an in-memory database, this function is a no-op. */ static void pcacheUnpin(PgHdr *p){ - PCache *pCache = p->pCache; - if( pCache->bPurgeable ){ + if( p->pCache->bPurgeable ){ if( p->pgno==1 ){ - pCache->pPage1 = 0; + p->pCache->pPage1 = 0; } - sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 0); + sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); + } +} + +/* +** Compute the number of pages of cache requested. +*/ +static int numberOfCachePages(PCache *p){ + if( p->szCache>=0 ){ + return p->szCache; + }else{ + return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); } } @@ -38099,7 +38675,7 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); } ** The caller discovers how much space needs to be allocated by ** calling sqlite3PcacheSize(). */ -SQLITE_PRIVATE void sqlite3PcacheOpen( +SQLITE_PRIVATE int sqlite3PcacheOpen( int szPage, /* Size of every page */ int szExtra, /* Extra space associated with each page */ int bPurgeable, /* True if pages are on backing store */ @@ -38108,76 +38684,75 @@ SQLITE_PRIVATE void sqlite3PcacheOpen( PCache *p /* Preallocated space for the PCache */ ){ memset(p, 0, sizeof(PCache)); - p->szPage = szPage; + p->szPage = 1; p->szExtra = szExtra; p->bPurgeable = bPurgeable; p->eCreate = 2; p->xStress = xStress; p->pStress = pStress; p->szCache = 100; + return sqlite3PcacheSetPageSize(p, szPage); } /* ** Change the page size for PCache object. The caller must ensure that there ** are no outstanding page references when this function is called. */ -SQLITE_PRIVATE void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ +SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ assert( pCache->nRef==0 && pCache->pDirty==0 ); - if( pCache->pCache ){ - sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); - pCache->pCache = 0; + if( pCache->szPage ){ + sqlite3_pcache *pNew; + pNew = sqlite3GlobalConfig.pcache2.xCreate( + szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable + ); + if( pNew==0 ) return SQLITE_NOMEM; + sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache)); + if( pCache->pCache ){ + sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); + } + pCache->pCache = pNew; pCache->pPage1 = 0; + pCache->szPage = szPage; } - pCache->szPage = szPage; -} - -/* -** Compute the number of pages of cache requested. -*/ -static int numberOfCachePages(PCache *p){ - if( p->szCache>=0 ){ - return p->szCache; - }else{ - return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); - } + return SQLITE_OK; } /* ** Try to obtain a page from the cache. +** +** This routine returns a pointer to an sqlite3_pcache_page object if +** such an object is already in cache, or if a new one is created. +** This routine returns a NULL pointer if the object was not in cache +** and could not be created. +** +** The createFlags should be 0 to check for existing pages and should +** be 3 (not 1, but 3) to try to create a new page. +** +** If the createFlag is 0, then NULL is always returned if the page +** is not already in the cache. If createFlag is 1, then a new page +** is created only if that can be done without spilling dirty pages +** and without exceeding the cache size limit. +** +** The caller needs to invoke sqlite3PcacheFetchFinish() to properly +** initialize the sqlite3_pcache_page object and convert it into a +** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish() +** routines are split this way for performance reasons. When separated +** they can both (usually) operate without having to push values to +** the stack on entry and pop them back off on exit, which saves a +** lot of pushing and popping. */ -SQLITE_PRIVATE int sqlite3PcacheFetch( +SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch( PCache *pCache, /* Obtain the page from this cache */ Pgno pgno, /* Page number to obtain */ - int createFlag, /* If true, create page if it does not exist already */ - PgHdr **ppPage /* Write the page here */ + int createFlag /* If true, create page if it does not exist already */ ){ - sqlite3_pcache_page *pPage; - PgHdr *pPgHdr = 0; int eCreate; assert( pCache!=0 ); - assert( createFlag==1 || createFlag==0 ); + assert( pCache->pCache!=0 ); + assert( createFlag==3 || createFlag==0 ); assert( pgno>0 ); - /* If the pluggable cache (sqlite3_pcache*) has not been allocated, - ** allocate it now. - */ - if( !pCache->pCache ){ - sqlite3_pcache *p; - if( !createFlag ){ - *ppPage = 0; - return SQLITE_OK; - } - p = sqlite3GlobalConfig.pcache2.xCreate( - pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable - ); - if( !p ){ - return SQLITE_NOMEM; - } - sqlite3GlobalConfig.pcache2.xCachesize(p, numberOfCachePages(pCache)); - pCache->pCache = p; - } - /* eCreate defines what to do if the page does not exist. ** 0 Do not allocate a new page. (createFlag==0) ** 1 Allocate a new page if doing so is inexpensive. @@ -38185,89 +38760,135 @@ SQLITE_PRIVATE int sqlite3PcacheFetch( ** 2 Allocate a new page even it doing so is difficult. ** (createFlag==1 AND !(bPurgeable AND pDirty) */ - eCreate = createFlag==0 ? 0 : pCache->eCreate; - assert( (createFlag*(1+(!pCache->bPurgeable||!pCache->pDirty)))==eCreate ); - pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); - if( !pPage && eCreate==1 ){ - PgHdr *pPg; + eCreate = createFlag & pCache->eCreate; + assert( eCreate==0 || eCreate==1 || eCreate==2 ); + assert( createFlag==0 || pCache->eCreate==eCreate ); + assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); + return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); +} - /* Find a dirty page to write-out and recycle. First try to find a - ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC - ** cleared), but if that is not possible settle for any other - ** unreferenced dirty page. - */ - expensive_assert( pcacheCheckSynced(pCache) ); - for(pPg=pCache->pSynced; - pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); - pPg=pPg->pDirtyPrev - ); - pCache->pSynced = pPg; - if( !pPg ){ - for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); - } - if( pPg ){ - int rc; +/* +** If the sqlite3PcacheFetch() routine is unable to allocate a new +** page because new clean pages are available for reuse and the cache +** size limit has been reached, then this routine can be invoked to +** try harder to allocate a page. This routine might invoke the stress +** callback to spill dirty pages to the journal. It will then try to +** allocate the new page and will only fail to allocate a new page on +** an OOM error. +** +** This routine should be invoked only after sqlite3PcacheFetch() fails. +*/ +SQLITE_PRIVATE int sqlite3PcacheFetchStress( + PCache *pCache, /* Obtain the page from this cache */ + Pgno pgno, /* Page number to obtain */ + sqlite3_pcache_page **ppPage /* Write result here */ +){ + PgHdr *pPg; + if( pCache->eCreate==2 ) return 0; + + + /* Find a dirty page to write-out and recycle. First try to find a + ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC + ** cleared), but if that is not possible settle for any other + ** unreferenced dirty page. + */ + for(pPg=pCache->pSynced; + pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); + pPg=pPg->pDirtyPrev + ); + pCache->pSynced = pPg; + if( !pPg ){ + for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); + } + if( pPg ){ + int rc; #ifdef SQLITE_LOG_CACHE_SPILL - sqlite3_log(SQLITE_FULL, - "spill page %d making room for %d - cache used: %d/%d", - pPg->pgno, pgno, - sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), - numberOfCachePages(pCache)); + sqlite3_log(SQLITE_FULL, + "spill page %d making room for %d - cache used: %d/%d", + pPg->pgno, pgno, + sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), + numberOfCachePages(pCache)); #endif - rc = pCache->xStress(pCache->pStress, pPg); - if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ - return rc; - } - } - - pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); - } - - if( pPage ){ - pPgHdr = (PgHdr *)pPage->pExtra; - - if( !pPgHdr->pPage ){ - memset(pPgHdr, 0, sizeof(PgHdr)); - pPgHdr->pPage = pPage; - pPgHdr->pData = pPage->pBuf; - pPgHdr->pExtra = (void *)&pPgHdr[1]; - memset(pPgHdr->pExtra, 0, pCache->szExtra); - pPgHdr->pCache = pCache; - pPgHdr->pgno = pgno; - } - assert( pPgHdr->pCache==pCache ); - assert( pPgHdr->pgno==pgno ); - assert( pPgHdr->pData==pPage->pBuf ); - assert( pPgHdr->pExtra==(void *)&pPgHdr[1] ); - - if( 0==pPgHdr->nRef ){ - pCache->nRef++; - } - pPgHdr->nRef++; - if( pgno==1 ){ - pCache->pPage1 = pPgHdr; + rc = pCache->xStress(pCache->pStress, pPg); + if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ + return rc; } } - *ppPage = pPgHdr; - return (pPgHdr==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK; + *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); + return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK; +} + +/* +** This is a helper routine for sqlite3PcacheFetchFinish() +** +** In the uncommon case where the page being fetched has not been +** initialized, this routine is invoked to do the initialization. +** This routine is broken out into a separate function since it +** requires extra stack manipulation that can be avoided in the common +** case. +*/ +static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit( + PCache *pCache, /* Obtain the page from this cache */ + Pgno pgno, /* Page number obtained */ + sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */ +){ + PgHdr *pPgHdr; + assert( pPage!=0 ); + pPgHdr = (PgHdr*)pPage->pExtra; + assert( pPgHdr->pPage==0 ); + memset(pPgHdr, 0, sizeof(PgHdr)); + pPgHdr->pPage = pPage; + pPgHdr->pData = pPage->pBuf; + pPgHdr->pExtra = (void *)&pPgHdr[1]; + memset(pPgHdr->pExtra, 0, pCache->szExtra); + pPgHdr->pCache = pCache; + pPgHdr->pgno = pgno; + return sqlite3PcacheFetchFinish(pCache,pgno,pPage); +} + +/* +** This routine converts the sqlite3_pcache_page object returned by +** sqlite3PcacheFetch() into an initialized PgHdr object. This routine +** must be called after sqlite3PcacheFetch() in order to get a usable +** result. +*/ +SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish( + PCache *pCache, /* Obtain the page from this cache */ + Pgno pgno, /* Page number obtained */ + sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */ +){ + PgHdr *pPgHdr; + + if( pPage==0 ) return 0; + pPgHdr = (PgHdr *)pPage->pExtra; + + if( !pPgHdr->pPage ){ + return pcacheFetchFinishWithInit(pCache, pgno, pPage); + } + if( 0==pPgHdr->nRef ){ + pCache->nRef++; + } + pPgHdr->nRef++; + if( pgno==1 ){ + pCache->pPage1 = pPgHdr; + } + return pPgHdr; } /* ** Decrement the reference count on a page. If the page is clean and the -** reference count drops to 0, then it is made elible for recycling. +** reference count drops to 0, then it is made eligible for recycling. */ -SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr *p){ +SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ assert( p->nRef>0 ); p->nRef--; if( p->nRef==0 ){ - PCache *pCache = p->pCache; - pCache->nRef--; + p->pCache->nRef--; if( (p->flags&PGHDR_DIRTY)==0 ){ pcacheUnpin(p); - }else{ + }else if( p->pDirtyPrev!=0 ){ /* Move the page to the head of the dirty list. */ - pcacheRemoveFromDirtyList(p); - pcacheAddToDirtyList(p); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } } @@ -38286,17 +38907,15 @@ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){ ** page pointed to by p is invalid. */ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){ - PCache *pCache; assert( p->nRef==1 ); if( p->flags&PGHDR_DIRTY ){ - pcacheRemoveFromDirtyList(p); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); } - pCache = p->pCache; - pCache->nRef--; + p->pCache->nRef--; if( p->pgno==1 ){ - pCache->pPage1 = 0; + p->pCache->pPage1 = 0; } - sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 1); + sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1); } /* @@ -38308,7 +38927,7 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){ assert( p->nRef>0 ); if( 0==(p->flags & PGHDR_DIRTY) ){ p->flags |= PGHDR_DIRTY; - pcacheAddToDirtyList( p); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); } } @@ -38318,7 +38937,7 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){ */ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){ if( (p->flags & PGHDR_DIRTY) ){ - pcacheRemoveFromDirtyList(p); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC); if( p->nRef==0 ){ pcacheUnpin(p); @@ -38357,8 +38976,7 @@ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); p->pgno = newPgno; if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ - pcacheRemoveFromDirtyList(p); - pcacheAddToDirtyList(p); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } @@ -38399,9 +39017,8 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ ** Close a cache. */ SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){ - if( pCache->pCache ){ - sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); - } + assert( pCache->pCache!=0 ); + sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } /* @@ -38510,11 +39127,8 @@ SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){ ** Return the total number of pages in the cache. */ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){ - int nPage = 0; - if( pCache->pCache ){ - nPage = sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache); - } - return nPage; + assert( pCache->pCache!=0 ); + return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache); } #ifdef SQLITE_TEST @@ -38530,20 +39144,18 @@ SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){ ** Set the suggested cache-size value. */ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ + assert( pCache->pCache!=0 ); pCache->szCache = mxPage; - if( pCache->pCache ){ - sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache, - numberOfCachePages(pCache)); - } + sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache, + numberOfCachePages(pCache)); } /* ** Free up as much memory as possible from the page cache. */ SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){ - if( pCache->pCache ){ - sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); - } + assert( pCache->pCache!=0 ); + sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); } #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) @@ -38577,7 +39189,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd ** This file implements the default page cache implementation (the ** sqlite3_pcache interface). It also contains part of the implementation ** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features. -** If the default page cache implementation is overriden, then neither of +** If the default page cache implementation is overridden, then neither of ** these two features are available. */ @@ -38588,7 +39200,7 @@ typedef struct PgFreeslot PgFreeslot; typedef struct PGroup PGroup; /* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set -** of one or more PCaches that are able to recycle each others unpinned +** of one or more PCaches that are able to recycle each other's unpinned ** pages when they are under memory pressure. A PGroup is an instance of ** the following object. ** @@ -38946,7 +39558,7 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){ ** ** The PCache mutex must be held when this function is called. */ -static int pcache1ResizeHash(PCache1 *p){ +static void pcache1ResizeHash(PCache1 *p){ PgHdr1 **apNew; unsigned int nNew; unsigned int i; @@ -38978,8 +39590,6 @@ static int pcache1ResizeHash(PCache1 *p){ p->apHash = apNew; p->nHash = nNew; } - - return (p->apHash ? SQLITE_OK : SQLITE_NOMEM); } /* @@ -39114,6 +39724,9 @@ static void pcache1Shutdown(void *NotUsed){ memset(&pcache1, 0, sizeof(pcache1)); } +/* forward declaration */ +static void pcache1Destroy(sqlite3_pcache *p); + /* ** Implementation of the sqlite3_pcache.xCreate method. ** @@ -39158,12 +39771,17 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ pCache->szPage = szPage; pCache->szExtra = szExtra; pCache->bPurgeable = (bPurgeable ? 1 : 0); + pcache1EnterMutex(pGroup); + pcache1ResizeHash(pCache); if( bPurgeable ){ pCache->nMin = 10; - pcache1EnterMutex(pGroup); pGroup->nMinPage += pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; - pcache1LeaveMutex(pGroup); + } + pcache1LeaveMutex(pGroup); + if( pCache->nHash==0 ){ + pcache1Destroy((sqlite3_pcache*)pCache); + pCache = 0; } } return (sqlite3_pcache *)pCache; @@ -39219,6 +39837,95 @@ static int pcache1Pagecount(sqlite3_pcache *p){ return n; } + +/* +** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described +** in the header of the pcache1Fetch() procedure. +** +** This steps are broken out into a separate procedure because they are +** usually not needed, and by avoiding the stack initialization required +** for these steps, the main pcache1Fetch() procedure can run faster. +*/ +static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( + PCache1 *pCache, + unsigned int iKey, + int createFlag +){ + unsigned int nPinned; + PGroup *pGroup = pCache->pGroup; + PgHdr1 *pPage = 0; + + /* Step 3: Abort if createFlag is 1 but the cache is nearly full */ + assert( pCache->nPage >= pCache->nRecyclable ); + nPinned = pCache->nPage - pCache->nRecyclable; + assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage ); + assert( pCache->n90pct == pCache->nMax*9/10 ); + if( createFlag==1 && ( + nPinned>=pGroup->mxPinned + || nPinned>=pCache->n90pct + || (pcache1UnderMemoryPressure(pCache) && pCache->nRecyclablenPage>=pCache->nHash ) pcache1ResizeHash(pCache); + assert( pCache->nHash>0 && pCache->apHash ); + + /* Step 4. Try to recycle a page. */ + if( pCache->bPurgeable && pGroup->pLruTail && ( + (pCache->nPage+1>=pCache->nMax) + || pGroup->nCurrentPage>=pGroup->nMaxPage + || pcache1UnderMemoryPressure(pCache) + )){ + PCache1 *pOther; + pPage = pGroup->pLruTail; + assert( pPage->isPinned==0 ); + pcache1RemoveFromHash(pPage); + pcache1PinPage(pPage); + pOther = pPage->pCache; + + /* We want to verify that szPage and szExtra are the same for pOther + ** and pCache. Assert that we can verify this by comparing sums. */ + assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 ); + assert( pCache->szExtra<512 ); + assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 ); + assert( pOther->szExtra<512 ); + + if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){ + pcache1FreePage(pPage); + pPage = 0; + }else{ + pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable); + } + } + + /* Step 5. If a usable page buffer has still not been found, + ** attempt to allocate a new one. + */ + if( !pPage ){ + if( createFlag==1 ) sqlite3BeginBenignMalloc(); + pPage = pcache1AllocPage(pCache); + if( createFlag==1 ) sqlite3EndBenignMalloc(); + } + + if( pPage ){ + unsigned int h = iKey % pCache->nHash; + pCache->nPage++; + pPage->iKey = iKey; + pPage->pNext = pCache->apHash[h]; + pPage->pCache = pCache; + pPage->pLruPrev = 0; + pPage->pLruNext = 0; + pPage->isPinned = 1; + *(void **)pPage->page.pExtra = 0; + pCache->apHash[h] = pPage; + if( iKey>pCache->iMaxKey ){ + pCache->iMaxKey = iKey; + } + } + return pPage; +} + /* ** Implementation of the sqlite3_pcache.xFetch method. ** @@ -39278,9 +39985,7 @@ static sqlite3_pcache_page *pcache1Fetch( unsigned int iKey, int createFlag ){ - unsigned int nPinned; PCache1 *pCache = (PCache1 *)p; - PGroup *pGroup; PgHdr1 *pPage = 0; assert( offsetof(PgHdr1,page)==0 ); @@ -39288,107 +39993,22 @@ static sqlite3_pcache_page *pcache1Fetch( assert( pCache->bPurgeable || pCache->nMin==0 ); assert( pCache->bPurgeable==0 || pCache->nMin==10 ); assert( pCache->nMin==0 || pCache->bPurgeable ); - pcache1EnterMutex(pGroup = pCache->pGroup); + assert( pCache->nHash>0 ); + pcache1EnterMutex(pCache->pGroup); /* Step 1: Search the hash table for an existing entry. */ - if( pCache->nHash>0 ){ - unsigned int h = iKey % pCache->nHash; - for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext); - } + pPage = pCache->apHash[iKey % pCache->nHash]; + while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; } /* Step 2: Abort if no existing page is found and createFlag is 0 */ if( pPage ){ if( !pPage->isPinned ) pcache1PinPage(pPage); - goto fetch_out; + }else if( createFlag ){ + /* Steps 3, 4, and 5 implemented by this subroutine */ + pPage = pcache1FetchStage2(pCache, iKey, createFlag); } - if( createFlag==0 ){ - goto fetch_out; - } - - /* The pGroup local variable will normally be initialized by the - ** pcache1EnterMutex() macro above. But if SQLITE_MUTEX_OMIT is defined, - ** then pcache1EnterMutex() is a no-op, so we have to initialize the - ** local variable here. Delaying the initialization of pGroup is an - ** optimization: The common case is to exit the module before reaching - ** this point. - */ -#ifdef SQLITE_MUTEX_OMIT - pGroup = pCache->pGroup; -#endif - - /* Step 3: Abort if createFlag is 1 but the cache is nearly full */ - assert( pCache->nPage >= pCache->nRecyclable ); - nPinned = pCache->nPage - pCache->nRecyclable; - assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage ); - assert( pCache->n90pct == pCache->nMax*9/10 ); - if( createFlag==1 && ( - nPinned>=pGroup->mxPinned - || nPinned>=pCache->n90pct - || pcache1UnderMemoryPressure(pCache) - )){ - goto fetch_out; - } - - if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){ - goto fetch_out; - } - assert( pCache->nHash>0 && pCache->apHash ); - - /* Step 4. Try to recycle a page. */ - if( pCache->bPurgeable && pGroup->pLruTail && ( - (pCache->nPage+1>=pCache->nMax) - || pGroup->nCurrentPage>=pGroup->nMaxPage - || pcache1UnderMemoryPressure(pCache) - )){ - PCache1 *pOther; - pPage = pGroup->pLruTail; - assert( pPage->isPinned==0 ); - pcache1RemoveFromHash(pPage); - pcache1PinPage(pPage); - pOther = pPage->pCache; - - /* We want to verify that szPage and szExtra are the same for pOther - ** and pCache. Assert that we can verify this by comparing sums. */ - assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 ); - assert( pCache->szExtra<512 ); - assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 ); - assert( pOther->szExtra<512 ); - - if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){ - pcache1FreePage(pPage); - pPage = 0; - }else{ - pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable); - } - } - - /* Step 5. If a usable page buffer has still not been found, - ** attempt to allocate a new one. - */ - if( !pPage ){ - if( createFlag==1 ) sqlite3BeginBenignMalloc(); - pPage = pcache1AllocPage(pCache); - if( createFlag==1 ) sqlite3EndBenignMalloc(); - } - - if( pPage ){ - unsigned int h = iKey % pCache->nHash; - pCache->nPage++; - pPage->iKey = iKey; - pPage->pNext = pCache->apHash[h]; - pPage->pCache = pCache; - pPage->pLruPrev = 0; - pPage->pLruNext = 0; - pPage->isPinned = 1; - *(void **)pPage->page.pExtra = 0; - pCache->apHash[h] = pPage; - } - -fetch_out: - if( pPage && iKey>pCache->iMaxKey ){ - pCache->iMaxKey = iKey; - } - pcache1LeaveMutex(pGroup); + assert( pPage==0 || pCache->iMaxKey>=iKey ); + pcache1LeaveMutex(pCache->pGroup); return (sqlite3_pcache_page*)pPage; } @@ -39647,7 +40267,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats( ** No INSERTs may occurs after a SMALLEST. An assertion will fail if ** that is attempted. ** -** The cost of an INSERT is roughly constant. (Sometime new memory +** The cost of an INSERT is roughly constant. (Sometimes new memory ** has to be allocated on an INSERT.) The cost of a TEST with a new ** batch number is O(NlogN) where N is the number of elements in the RowSet. ** The cost of a TEST using the same batch number is O(logN). The cost @@ -40039,8 +40659,8 @@ SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ ** Check to see if element iRowid was inserted into the rowset as ** part of any insert batch prior to iBatch. Return 1 or 0. ** -** If this is the first test of a new batch and if there exist entires -** on pRowSet->pEntry, then sort those entires into the forest at +** If this is the first test of a new batch and if there exist entries +** on pRowSet->pEntry, then sort those entries into the forest at ** pRowSet->pForest so that they can be tested. */ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){ @@ -40322,12 +40942,12 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal); ** Definition: Two databases (or the same database at two points it time) ** are said to be "logically equivalent" if they give the same answer to ** all queries. Note in particular the content of freelist leaf -** pages can be changed arbitarily without effecting the logical equivalence +** pages can be changed arbitrarily without affecting the logical equivalence ** of the database. ** ** (7) At any time, if any subset, including the empty set and the total set, ** of the unsynced changes to a rollback journal are removed and the -** journal is rolled back, the resulting database file will be logical +** journal is rolled back, the resulting database file will be logically ** equivalent to the database file at the beginning of the transaction. ** ** (8) When a transaction is rolled back, the xTruncate method of the VFS @@ -40624,7 +41244,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** ** The exception is when the database file is unlocked as the pager moves ** from ERROR to OPEN state. At this point there may be a hot-journal file -** in the file-system that needs to be rolled back (as part of a OPEN->SHARED +** in the file-system that needs to be rolled back (as part of an OPEN->SHARED ** transition, by the same pager or any other). If the call to xUnlock() ** fails at this point and the pager is left holding an EXCLUSIVE lock, this ** can confuse the call to xCheckReservedLock() call made later as part @@ -40707,7 +41327,7 @@ struct PagerSavepoint { #define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */ /* -** A open page cache is an instance of struct Pager. A description of +** An open page cache is an instance of struct Pager. A description of ** some of the more important member variables follows: ** ** eState @@ -40879,7 +41499,7 @@ struct Pager { /************************************************************************** ** The following block contains those class members that change during - ** routine opertion. Class members not in this block are either fixed + ** routine operation. Class members not in this block are either fixed ** when the pager is first created or else only change when there is a ** significant mode change (such as changing the page_size, locking_mode, ** or the journal_mode). From another view, these class members describe @@ -41923,21 +42543,6 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ return rc; } -/* -** Find a page in the hash table given its page number. Return -** a pointer to the page or NULL if the requested page is not -** already in memory. -*/ -static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ - PgHdr *p = 0; /* Return value */ - - /* It is not possible for a call to PcacheFetch() with createFlag==0 to - ** fail, since no attempt to allocate dynamic memory will be made. - */ - (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &p); - return p; -} - /* ** Discard the entire contents of the in-memory page-cache. */ @@ -42202,6 +42807,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ rc = SQLITE_OK; }else{ rc = sqlite3OsTruncate(pPager->jfd, 0); + if( rc==SQLITE_OK && pPager->fullSync ){ + /* Make sure the new file size is written into the inode right away. + ** Otherwise the journal might resurrect following a power loss and + ** cause the last transaction to roll back. See + ** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773 + */ + rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); + } } pPager->journalOff = 0; }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST @@ -42230,7 +42843,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ #ifdef SQLITE_CHECK_PAGES sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash); if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){ - PgHdr *p = pager_lookup(pPager, 1); + PgHdr *p = sqlite3PagerLookup(pPager, 1); if( p ){ p->pageHash = 0; sqlite3PagerUnrefNotNull(p); @@ -42509,7 +43122,7 @@ static int pager_playback_one_page( if( pagerUseWal(pPager) ){ pPg = 0; }else{ - pPg = pager_lookup(pPager, pgno); + pPg = sqlite3PagerLookup(pPager, pgno); } assert( pPg || !MEMDB ); assert( pPager->eState!=PAGER_OPEN || pPg==0 ); @@ -42689,7 +43302,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){ rc = sqlite3OsFileSize(pMaster, &nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; nMasterPtr = pVfs->mxPathname+1; - zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1); + zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1); if( !zMasterJournal ){ rc = SQLITE_NOMEM; goto delmaster_out; @@ -42758,7 +43371,7 @@ delmaster_out: ** If the file on disk is currently larger than nPage pages, then use the VFS ** xTruncate() method to truncate it. ** -** Or, it might might be the case that the file on disk is smaller than +** Or, it might be the case that the file on disk is smaller than ** nPage pages. Some operating system implementations can get confused if ** you try to truncate a file to some size that is larger than it ** currently is, so detect this case and write a single zero byte to @@ -42817,7 +43430,7 @@ SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *pFile){ /* ** Set the value of the Pager.sectorSize variable for the given ** pager based on the value returned by the xSectorSize method -** of the open database file. The sector size will be used used +** of the open database file. The sector size will be used ** to determine the size and alignment of journal header and ** master journal pointers within created journal files. ** @@ -43879,11 +44492,15 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR if( rc==SQLITE_OK ){ pager_reset(pPager); - pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); - pPager->pageSize = pageSize; + rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); + } + if( rc==SQLITE_OK ){ sqlite3PageFree(pPager->pTmpSpace); pPager->pTmpSpace = pNew; - sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); + pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); + pPager->pageSize = pageSize; + }else{ + sqlite3PageFree(pNew); } } @@ -44017,7 +44634,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){ int rc; /* Return code */ /* Check that this is either a no-op (because the requested lock is - ** already held, or one of the transistions that the busy-handler + ** already held), or one of the transitions that the busy-handler ** may be invoked during, according to the comment above ** sqlite3PagerSetBusyhandler(). */ @@ -44645,8 +45262,8 @@ static int pagerStress(void *p, PgHdr *pPg){ ** a rollback or by user request, respectively. ** ** Spilling is also prohibited when in an error state since that could - ** lead to database corruption. In the current implementaton it - ** is impossible for sqlite3PcacheFetch() to be called with createFlag==1 + ** lead to database corruption. In the current implementation it + ** is impossible for sqlite3PcacheFetch() to be called with createFlag==3 ** while in the error state, hence it is impossible for this routine to ** be called in the error state. Nevertheless, we include a NEVER() ** test for the error state as a safeguard against future changes. @@ -44982,22 +45599,23 @@ act_like_temp_file: testcase( rc!=SQLITE_OK ); } - /* If an error occurred in either of the blocks above, free the - ** Pager structure and close the file. + /* Initialize the PCache object. */ + if( rc==SQLITE_OK ){ + assert( nExtra<1000 ); + nExtra = ROUND8(nExtra); + rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, + !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); + } + + /* If an error occurred above, free the Pager structure and close the file. */ if( rc!=SQLITE_OK ){ - assert( !pPager->pTmpSpace ); sqlite3OsClose(pPager->fd); + sqlite3PageFree(pPager->pTmpSpace); sqlite3_free(pPager); return rc; } - /* Initialize the PCache object. */ - assert( nExtra<1000 ); - nExtra = ROUND8(nExtra); - sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, - !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); - PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename)); IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename)) @@ -45184,7 +45802,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ *pExists = (first!=0); }else if( rc==SQLITE_CANTOPEN ){ /* If we cannot open the rollback journal file in order to see if - ** its has a zero header, that might be due to an I/O error, or + ** it has a zero header, that might be due to an I/O error, or ** it might be due to the race condition described above and in ** ticket #3883. Either way, assume that the journal is hot. ** This might be a false positive. But if it is, then the @@ -45546,7 +46164,6 @@ SQLITE_PRIVATE int sqlite3PagerAcquire( if( pPager->errCode!=SQLITE_OK ){ rc = pPager->errCode; }else{ - if( bMmapOk && pagerUseWal(pPager) ){ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); if( rc!=SQLITE_OK ) goto pager_acquire_err; @@ -45561,7 +46178,7 @@ SQLITE_PRIVATE int sqlite3PagerAcquire( if( rc==SQLITE_OK && pData ){ if( pPager->eState>PAGER_READER ){ - (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); + pPg = sqlite3PagerLookup(pPager, pgno); } if( pPg==0 ){ rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg); @@ -45579,7 +46196,16 @@ SQLITE_PRIVATE int sqlite3PagerAcquire( } } - rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage); + { + sqlite3_pcache_page *pBase; + pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); + if( pBase==0 ){ + rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase); + if( rc!=SQLITE_OK ) goto pager_acquire_err; + } + pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase); + if( pPg==0 ) rc = SQLITE_NOMEM; + } } if( rc!=SQLITE_OK ){ @@ -45676,13 +46302,12 @@ pager_acquire_err: ** has ever happened. */ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ - PgHdr *pPg = 0; + sqlite3_pcache_page *pPage; assert( pPager!=0 ); assert( pgno!=0 ); assert( pPager->pPCache!=0 ); - assert( pPager->eState>=PAGER_READER && pPager->eState!=PAGER_ERROR ); - sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); - return pPg; + pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0); + return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage); } /* @@ -46018,6 +46643,97 @@ static int pager_write(PgHdr *pPg){ return rc; } +/* +** This is a variant of sqlite3PagerWrite() that runs when the sector size +** is larger than the page size. SQLite makes the (reasonable) assumption that +** all bytes of a sector are written together by hardware. Hence, all bytes of +** a sector need to be journalled in case of a power loss in the middle of +** a write. +** +** Usually, the sector size is less than or equal to the page size, in which +** case pages can be individually written. This routine only runs in the exceptional +** case where the page size is smaller than the sector size. +*/ +static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){ + int rc = SQLITE_OK; /* Return code */ + Pgno nPageCount; /* Total number of pages in database file */ + Pgno pg1; /* First page of the sector pPg is located on. */ + int nPage = 0; /* Number of pages starting at pg1 to journal */ + int ii; /* Loop counter */ + int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */ + Pager *pPager = pPg->pPager; /* The pager that owns pPg */ + Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); + + /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow + ** a journal header to be written between the pages journaled by + ** this function. + */ + assert( !MEMDB ); + assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 ); + pPager->doNotSpill |= SPILLFLAG_NOSYNC; + + /* This trick assumes that both the page-size and sector-size are + ** an integer power of 2. It sets variable pg1 to the identifier + ** of the first page of the sector pPg is located on. + */ + pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1; + + nPageCount = pPager->dbSize; + if( pPg->pgno>nPageCount ){ + nPage = (pPg->pgno - pg1)+1; + }else if( (pg1+nPagePerSector-1)>nPageCount ){ + nPage = nPageCount+1-pg1; + }else{ + nPage = nPagePerSector; + } + assert(nPage>0); + assert(pg1<=pPg->pgno); + assert((pg1+nPage)>pPg->pgno); + + for(ii=0; iipgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ + if( pg!=PAGER_MJ_PGNO(pPager) ){ + rc = sqlite3PagerGet(pPager, pg, &pPage); + if( rc==SQLITE_OK ){ + rc = pager_write(pPage); + if( pPage->flags&PGHDR_NEED_SYNC ){ + needSync = 1; + } + sqlite3PagerUnrefNotNull(pPage); + } + } + }else if( (pPage = sqlite3PagerLookup(pPager, pg))!=0 ){ + if( pPage->flags&PGHDR_NEED_SYNC ){ + needSync = 1; + } + sqlite3PagerUnrefNotNull(pPage); + } + } + + /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages + ** starting at pg1, then it needs to be set for all of them. Because + ** writing to any of these nPage pages may damage the others, the + ** journal file must contain sync()ed copies of all of them + ** before any of them can be written out to the database file. + */ + if( rc==SQLITE_OK && needSync ){ + assert( !MEMDB ); + for(ii=0; iiflags |= PGHDR_NEED_SYNC; + sqlite3PagerUnrefNotNull(pPage); + } + } + } + + assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 ); + pPager->doNotSpill &= ~SPILLFLAG_NOSYNC; + return rc; +} + /* ** Mark a data page as writeable. This routine must be called before ** making changes to a page. The caller must check the return value @@ -46032,96 +46748,16 @@ static int pager_write(PgHdr *pPg){ ** If an error occurs, SQLITE_NOMEM or an IO error code is returned ** as appropriate. Otherwise, SQLITE_OK. */ -SQLITE_PRIVATE int sqlite3PagerWrite(DbPage *pDbPage){ - int rc = SQLITE_OK; - - PgHdr *pPg = pDbPage; - Pager *pPager = pPg->pPager; - +SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){ assert( (pPg->flags & PGHDR_MMAP)==0 ); - assert( pPager->eState>=PAGER_WRITER_LOCKED ); - assert( pPager->eState!=PAGER_ERROR ); - assert( assert_pager_state(pPager) ); - - if( pPager->sectorSize > (u32)pPager->pageSize ){ - Pgno nPageCount; /* Total number of pages in database file */ - Pgno pg1; /* First page of the sector pPg is located on. */ - int nPage = 0; /* Number of pages starting at pg1 to journal */ - int ii; /* Loop counter */ - int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */ - Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); - - /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow - ** a journal header to be written between the pages journaled by - ** this function. - */ - assert( !MEMDB ); - assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 ); - pPager->doNotSpill |= SPILLFLAG_NOSYNC; - - /* This trick assumes that both the page-size and sector-size are - ** an integer power of 2. It sets variable pg1 to the identifier - ** of the first page of the sector pPg is located on. - */ - pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1; - - nPageCount = pPager->dbSize; - if( pPg->pgno>nPageCount ){ - nPage = (pPg->pgno - pg1)+1; - }else if( (pg1+nPagePerSector-1)>nPageCount ){ - nPage = nPageCount+1-pg1; - }else{ - nPage = nPagePerSector; - } - assert(nPage>0); - assert(pg1<=pPg->pgno); - assert((pg1+nPage)>pPg->pgno); - - for(ii=0; iipgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ - if( pg!=PAGER_MJ_PGNO(pPager) ){ - rc = sqlite3PagerGet(pPager, pg, &pPage); - if( rc==SQLITE_OK ){ - rc = pager_write(pPage); - if( pPage->flags&PGHDR_NEED_SYNC ){ - needSync = 1; - } - sqlite3PagerUnrefNotNull(pPage); - } - } - }else if( (pPage = pager_lookup(pPager, pg))!=0 ){ - if( pPage->flags&PGHDR_NEED_SYNC ){ - needSync = 1; - } - sqlite3PagerUnrefNotNull(pPage); - } - } - - /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages - ** starting at pg1, then it needs to be set for all of them. Because - ** writing to any of these nPage pages may damage the others, the - ** journal file must contain sync()ed copies of all of them - ** before any of them can be written out to the database file. - */ - if( rc==SQLITE_OK && needSync ){ - assert( !MEMDB ); - for(ii=0; iiflags |= PGHDR_NEED_SYNC; - sqlite3PagerUnrefNotNull(pPage); - } - } - } - - assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 ); - pPager->doNotSpill &= ~SPILLFLAG_NOSYNC; + assert( pPg->pPager->eState>=PAGER_WRITER_LOCKED ); + assert( pPg->pPager->eState!=PAGER_ERROR ); + assert( assert_pager_state(pPg->pPager) ); + if( pPg->pPager->sectorSize > (u32)pPg->pPager->pageSize ){ + return pagerWriteLargeSector(pPg); }else{ - rc = pager_write(pDbPage); + return pager_write(pPg); } - return rc; } /* @@ -47017,7 +47653,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i ** for the page moved there. */ pPg->flags &= ~PGHDR_NEED_SYNC; - pPgOld = pager_lookup(pPager, pgno); + pPgOld = sqlite3PagerLookup(pPager, pgno); assert( !pPgOld || pPgOld->nRef==1 ); if( pPgOld ){ pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); @@ -47470,7 +48106,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){ ** is empty, return 0. */ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ - assert( pPager->eState==PAGER_READER ); + assert( pPager->eState>=PAGER_READER ); return sqlite3WalFramesize(pPager->pWal); } #endif @@ -48054,7 +48690,7 @@ static volatile WalIndexHdr *walIndexHdr(Wal *pWal){ ** The argument to this macro must be of type u32. On a little-endian ** architecture, it returns the u32 value that results from interpreting ** the 4 bytes as a big-endian value. On a big-endian architecture, it -** returns the value that would be produced by intepreting the 4 bytes +** returns the value that would be produced by interpreting the 4 bytes ** of the input value as a little-endian integer. */ #define BYTESWAP32(x) ( \ @@ -48468,7 +49104,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ assert( idx <= HASHTABLE_NSLOT/2 + 1 ); /* If this is the first entry to be added to this hash-table, zero the - ** entire hash table and aPgno[] array before proceding. + ** entire hash table and aPgno[] array before proceeding. */ if( idx==1 ){ int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]); @@ -49126,7 +49762,7 @@ static int walPagesize(Wal *pWal){ ** database file. ** ** This routine uses and updates the nBackfill field of the wal-index header. -** This is the only routine tha will increase the value of nBackfill. +** This is the only routine that will increase the value of nBackfill. ** (A WAL reset or recovery will revert nBackfill to zero, but not increase ** its value.) ** @@ -49430,7 +50066,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){ ** wal-index from the WAL before returning. ** ** Set *pChanged to 1 if the wal-index header value in pWal->hdr is -** changed by this opertion. If pWal->hdr is unchanged, set *pChanged +** changed by this operation. If pWal->hdr is unchanged, set *pChanged ** to 0. ** ** If the wal-index header is successfully read, return SQLITE_OK. @@ -49634,7 +50270,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** may have been appended to the log before READ_LOCK(0) was obtained. ** When holding READ_LOCK(0), the reader ignores the entire log file, ** which implies that the database file contains a trustworthy - ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from + ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from ** happening, this is usually correct. ** ** However, if frames have been appended to the log (or if the log @@ -50005,7 +50641,6 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p } if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal); } - assert( rc==SQLITE_OK ); return rc; } @@ -50302,7 +50937,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( ** ** Padding and syncing only occur if this set of frames complete a ** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL - ** or synchonous==OFF, then no padding or syncing are needed. + ** or synchronous==OFF, then no padding or syncing are needed. ** ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not ** needed and only the sync is done. If padding is needed, then the @@ -50605,7 +51240,7 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file implements a external (disk-based) database using BTrees. +** This file implements an external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: @@ -50731,7 +51366,7 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){ ** ** The flags define the format of this btree page. The leaf flag means that ** this page has no children. The zerodata flag means that this page carries -** only keys and no data. The intkey flag means that the key is a integer +** only keys and no data. The intkey flag means that the key is an integer ** which is stored in the key size entry of the cell header rather than in ** the payload area. ** @@ -50868,9 +51503,10 @@ typedef struct BtLock BtLock; struct MemPage { u8 isInit; /* True if previously initialized. MUST BE FIRST! */ u8 nOverflow; /* Number of overflow cell bodies in aCell[] */ - u8 intKey; /* True if intkey flag is set */ - u8 leaf; /* True if leaf flag is set */ - u8 hasData; /* True if this page stores data */ + u8 intKey; /* True if table b-trees. False for index b-trees */ + u8 intKeyLeaf; /* True if the leaf of an intKey table */ + u8 noPayload; /* True if internal intKey page (thus w/o data) */ + u8 leaf; /* True if a leaf page */ u8 hdrOffset; /* 100 for page 1. 0 otherwise */ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ u8 max1bytePayload; /* min(maxLocal,127) */ @@ -51030,7 +51666,7 @@ struct BtShared { BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif - u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */ + u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ }; /* @@ -51051,12 +51687,10 @@ struct BtShared { */ typedef struct CellInfo CellInfo; struct CellInfo { - i64 nKey; /* The key for INTKEY tables, or number of bytes in key */ - u8 *pCell; /* Pointer to the start of cell content */ - u32 nData; /* Number of bytes of data */ - u32 nPayload; /* Total amount of payload */ - u16 nHeader; /* Size of the cell content header in bytes */ - u16 nLocal; /* Amount of payload held locally */ + i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */ + u8 *pPayload; /* Pointer to the start of payload */ + u32 nPayload; /* Bytes of payload */ + u16 nLocal; /* Amount of payload held locally, not on overflow */ u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */ u16 nSize; /* Size of the cell content on the main b-tree page */ }; @@ -51085,6 +51719,11 @@ struct CellInfo { ** ** Fields in this structure are accessed under the BtShared.mutex ** found at self->pBt->mutex. +** +** skipNext meaning: +** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op. +** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op. +** eState==FAULT: Cursor fault with skipNext as error code. */ struct BtCursor { Btree *pBtree; /* The Btree to which this cursor belongs */ @@ -51097,7 +51736,8 @@ struct BtCursor { void *pKey; /* Saved key that was cursor last known position */ Pgno pgnoRoot; /* The root page of this tree */ int nOvflAlloc; /* Allocated size of aOverflow[] array */ - int skipNext; /* Prev() is noop if negative. Next() is noop if positive */ + int skipNext; /* Prev() is noop if negative. Next() is noop if positive. + ** Error code if eState==CURSOR_FAULT */ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 hints; /* As configured by CursorSetHints() */ @@ -51139,11 +51779,11 @@ struct BtCursor { ** seek the cursor to the saved position. ** ** CURSOR_FAULT: -** A unrecoverable error (an I/O error or a malloc failure) has occurred +** An unrecoverable error (an I/O error or a malloc failure) has occurred ** on a different connection that shares the BtShared cache with this ** cursor. The error has left the cache in an inconsistent state. ** Do nothing else with this cursor. Any attempt to use the cursor -** should return the error code stored in BtCursor.skip +** should return the error code stored in BtCursor.skipNext */ #define CURSOR_INVALID 0 #define CURSOR_VALID 1 @@ -51253,6 +51893,8 @@ struct IntegrityCk { int mxErr; /* Stop accumulating errors when this reaches zero */ int nErr; /* Number of messages written to zErrMsg so far */ int mallocFailed; /* A memory allocation error has occurred */ + const char *zPfx; /* Error message prefix */ + int v1, v2; /* Values for up to two %d fields in zPfx */ StrAccum errMsg; /* Accumulate the error message text here */ }; @@ -51288,7 +51930,7 @@ static void lockBtreeMutex(Btree *p){ ** Release the BtShared mutex associated with B-Tree handle p and ** clear the p->locked boolean. */ -static void unlockBtreeMutex(Btree *p){ +static void SQLITE_NOINLINE unlockBtreeMutex(Btree *p){ BtShared *pBt = p->pBt; assert( p->locked==1 ); assert( sqlite3_mutex_held(pBt->mutex) ); @@ -51299,6 +51941,9 @@ static void unlockBtreeMutex(Btree *p){ p->locked = 0; } +/* Forward reference */ +static void SQLITE_NOINLINE btreeLockCarefully(Btree *p); + /* ** Enter a mutex on the given BTree object. ** @@ -51316,8 +51961,6 @@ static void unlockBtreeMutex(Btree *p){ ** subsequent Btrees that desire a lock. */ SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){ - Btree *pLater; - /* Some basic sanity checking on the Btree. The list of Btrees ** connected by pNext and pPrev should be in sorted order by ** Btree.pBt value. All elements of the list should belong to @@ -51342,9 +51985,20 @@ SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){ if( !p->sharable ) return; p->wantToLock++; if( p->locked ) return; + btreeLockCarefully(p); +} + +/* This is a helper function for sqlite3BtreeLock(). By moving +** complex, but seldom used logic, out of sqlite3BtreeLock() and +** into this routine, we avoid unnecessary stack pointer changes +** and thus help the sqlite3BtreeLock() routine to run much faster +** in the common case. +*/ +static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){ + Btree *pLater; /* In most cases, we should be able to acquire the lock we - ** want without having to go throught the ascending lock + ** want without having to go through the ascending lock ** procedure that follows. Just be sure not to block. */ if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){ @@ -51374,6 +52028,7 @@ SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){ } } + /* ** Exit the recursive mutex on a Btree. */ @@ -51549,7 +52204,7 @@ SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file implements a external (disk-based) database using BTrees. +** This file implements an external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ @@ -52026,7 +52681,9 @@ static void invalidateIncrblobCursors( BtShared *pBt = pBtree->pBt; assert( sqlite3BtreeHoldsMutex(pBtree) ); for(p=pBt->pCursor; p; p=p->pNext){ - if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){ + if( (p->curFlags & BTCF_Incrblob)!=0 + && (isClearTable || p->info.nKey==iRow) + ){ p->eState = CURSOR_INVALID; } } @@ -52145,7 +52802,7 @@ static int saveCursorPosition(BtCursor *pCur){ ** data. */ if( 0==pCur->apPage[0]->intKey ){ - void *pKey = sqlite3Malloc( (int)pCur->nKey ); + void *pKey = sqlite3Malloc( pCur->nKey ); if( pKey ){ rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ @@ -52168,16 +52825,42 @@ static int saveCursorPosition(BtCursor *pCur){ return rc; } +/* Forward reference */ +static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*); + /* ** Save the positions of all cursors (except pExcept) that are open on -** the table with root-page iRoot. Usually, this is called just before cursor -** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()). +** the table with root-page iRoot. "Saving the cursor position" means that +** the location in the btree is remembered in such a way that it can be +** moved back to the same spot after the btree has been modified. This +** routine is called just before cursor pExcept is used to modify the +** table, for example in BtreeDelete() or BtreeInsert(). +** +** Implementation note: This routine merely checks to see if any cursors +** need to be saved. It calls out to saveCursorsOnList() in the (unusual) +** event that cursors are in need to being saved. */ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ BtCursor *p; assert( sqlite3_mutex_held(pBt->mutex) ); assert( pExcept==0 || pExcept->pBt==pBt ); for(p=pBt->pCursor; p; p=p->pNext){ + if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ) break; + } + return p ? saveCursorsOnList(p, iRoot, pExcept) : SQLITE_OK; +} + +/* This helper routine to saveAllCursors does the actual work of saving +** the cursors if and when a cursor is found that actually requires saving. +** The common case is that no cursors need to be saved, so this routine is +** broken out from its caller to avoid unnecessary stack pointer movement. +*/ +static int SQLITE_NOINLINE saveCursorsOnList( + BtCursor *p, /* The first cursor that needs saving */ + Pgno iRoot, /* Only save cursor with this iRoot. Save all if zero */ + BtCursor *pExcept /* Do not save this cursor */ +){ + do{ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){ if( p->eState==CURSOR_VALID ){ int rc = saveCursorPosition(p); @@ -52189,7 +52872,8 @@ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ btreeReleaseAllCursorPages(p); } } - } + p = p->pNext; + }while( p ); return SQLITE_OK; } @@ -52274,37 +52958,48 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){ SQLITE_OK) /* -** Determine whether or not a cursor has moved from the position it -** was last placed at. Cursors can move when the row they are pointing -** at is deleted out from under them. +** Determine whether or not a cursor has moved from the position where +** it was last placed, or has been invalidated for any other reason. +** Cursors can move when the row they are pointing at is deleted out +** from under them, for example. Cursor might also move if a btree +** is rebalanced. ** -** This routine returns an error code if something goes wrong. The -** integer *pHasMoved is set as follows: +** Calling this routine with a NULL cursor pointer returns false. ** -** 0: The cursor is unchanged -** 1: The cursor is still pointing at the same row, but the pointers -** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch() -** might now be invalid because of a balance() or other change to the -** b-tree. -** 2: The cursor is no longer pointing to the row. The row might have -** been deleted out from under the cursor. +** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor +** back to where it ought to be if this routine returns true. */ -SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){ +SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ + return pCur->eState!=CURSOR_VALID; +} + +/* +** This routine restores a cursor back to its original position after it +** has been moved by some outside activity (such as a btree rebalance or +** a row having been deleted out from under the cursor). +** +** On success, the *pDifferentRow parameter is false if the cursor is left +** pointing at exactly the same row. *pDifferntRow is the row the cursor +** was pointing to has been deleted, forcing the cursor to point to some +** nearby row. +** +** This routine should only be called for a cursor that just returned +** TRUE from sqlite3BtreeCursorHasMoved(). +*/ +SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){ int rc; - if( pCur->eState==CURSOR_VALID ){ - *pHasMoved = 0; - return SQLITE_OK; - } + assert( pCur!=0 ); + assert( pCur->eState!=CURSOR_VALID ); rc = restoreCursorPosition(pCur); if( rc ){ - *pHasMoved = 2; + *pDifferentRow = 1; return rc; } if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){ - *pHasMoved = 2; + *pDifferentRow = 1; }else{ - *pHasMoved = 1; + *pDifferentRow = 0; } return SQLITE_OK; } @@ -52469,47 +53164,44 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){ ** are two versions of this function. btreeParseCell() takes a ** cell index as the second argument and btreeParseCellPtr() ** takes a pointer to the body of the cell as its second argument. -** -** Within this file, the parseCell() macro can be called instead of -** btreeParseCellPtr(). Using some compilers, this will be faster. */ static void btreeParseCellPtr( MemPage *pPage, /* Page containing the cell */ u8 *pCell, /* Pointer to the cell text. */ CellInfo *pInfo /* Fill in this structure */ ){ - u16 n; /* Number bytes in cell content header */ + u8 *pIter; /* For scanning through pCell */ u32 nPayload; /* Number of bytes of cell payload */ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - - pInfo->pCell = pCell; assert( pPage->leaf==0 || pPage->leaf==1 ); - n = pPage->childPtrSize; - assert( n==4-4*pPage->leaf ); - if( pPage->intKey ){ - if( pPage->hasData ){ - assert( n==0 ); - n = getVarint32(pCell, nPayload); - }else{ - nPayload = 0; - } - n += getVarint(&pCell[n], (u64*)&pInfo->nKey); - pInfo->nData = nPayload; + if( pPage->intKeyLeaf ){ + assert( pPage->childPtrSize==0 ); + pIter = pCell + getVarint32(pCell, nPayload); + pIter += getVarint(pIter, (u64*)&pInfo->nKey); + }else if( pPage->noPayload ){ + assert( pPage->childPtrSize==4 ); + pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey); + pInfo->nPayload = 0; + pInfo->nLocal = 0; + pInfo->iOverflow = 0; + pInfo->pPayload = 0; + return; }else{ - pInfo->nData = 0; - n += getVarint32(&pCell[n], nPayload); + pIter = pCell + pPage->childPtrSize; + pIter += getVarint32(pIter, nPayload); pInfo->nKey = nPayload; } pInfo->nPayload = nPayload; - pInfo->nHeader = n; + pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==pPage->maxLocal+1 ); - if( likely(nPayload<=pPage->maxLocal) ){ + if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ - if( (pInfo->nSize = (u16)(n+nPayload))<4 ) pInfo->nSize = 4; + pInfo->nSize = nPayload + (u16)(pIter - pCell); + if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; pInfo->iOverflow = 0; }else{ @@ -52536,18 +53228,16 @@ static void btreeParseCellPtr( }else{ pInfo->nLocal = (u16)minLocal; } - pInfo->iOverflow = (u16)(pInfo->nLocal + n); + pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell); pInfo->nSize = pInfo->iOverflow + 4; } } -#define parseCell(pPage, iCell, pInfo) \ - btreeParseCellPtr((pPage), findCell((pPage), (iCell)), (pInfo)) static void btreeParseCell( MemPage *pPage, /* Page containing the cell */ int iCell, /* The cell index. First cell is 0 */ CellInfo *pInfo /* Fill in this structure */ ){ - parseCell(pPage, iCell, pInfo); + btreeParseCellPtr(pPage, findCell(pPage, iCell), pInfo); } /* @@ -52557,8 +53247,9 @@ static void btreeParseCell( ** the space used by the cell pointer. */ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ - u8 *pIter = &pCell[pPage->childPtrSize]; - u32 nSize; + u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */ + u8 *pEnd; /* End mark for a varint */ + u32 nSize; /* Size value to return */ #ifdef SQLITE_DEBUG /* The value returned by this function should always be the same as @@ -52569,26 +53260,34 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ btreeParseCellPtr(pPage, pCell, &debuginfo); #endif + if( pPage->noPayload ){ + pEnd = &pIter[9]; + while( (*pIter++)&0x80 && pIterchildPtrSize==4 ); + return (u16)(pIter - pCell); + } + nSize = *pIter; + if( nSize>=0x80 ){ + pEnd = &pIter[9]; + nSize &= 0x7f; + do{ + nSize = (nSize<<7) | (*++pIter & 0x7f); + }while( *(pIter)>=0x80 && pIterintKey ){ - u8 *pEnd; - if( pPage->hasData ){ - pIter += getVarint32(pIter, nSize); - }else{ - nSize = 0; - } - /* pIter now points at the 64-bit integer key value, a variable length ** integer. The following block moves pIter to point at the first byte ** past the end of the key value. */ pEnd = &pIter[9]; while( (*pIter++)&0x80 && pItermaxLocal ); testcase( nSize==pPage->maxLocal+1 ); - if( nSize>pPage->maxLocal ){ + if( nSize<=pPage->maxLocal ){ + nSize += (u32)(pIter - pCell); + if( nSize<4 ) nSize = 4; + }else{ int minLocal = pPage->minLocal; nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); testcase( nSize==pPage->maxLocal ); @@ -52596,16 +53295,9 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ if( nSize>pPage->maxLocal ){ nSize = minLocal; } - nSize += 4; + nSize += 4 + (u16)(pIter - pCell); } - nSize += (u32)(pIter - pCell); - - /* The minimum size of any cell is 4 bytes. */ - if( nSize<4 ){ - nSize = 4; - } - - assert( nSize==debuginfo.nSize ); + assert( nSize==debuginfo.nSize || CORRUPT_DB ); return (u16)nSize; } @@ -52628,7 +53320,6 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ if( *pRC ) return; assert( pCell!=0 ); btreeParseCellPtr(pPage, pCell, &info); - assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); if( info.iOverflow ){ Pgno ovfl = get4byte(&pCell[info.iOverflow]); ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC); @@ -52645,7 +53336,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ */ static int defragmentPage(MemPage *pPage){ int i; /* Loop counter */ - int pc; /* Address of a i-th cell */ + int pc; /* Address of the i-th cell */ int hdr; /* Offset to the page header */ int size; /* Size of a cell */ int usableSize; /* Number of usable bytes on a page */ @@ -52736,7 +53427,6 @@ static int defragmentPage(MemPage *pPage){ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */ u8 * const data = pPage->aData; /* Local cache of pPage->aData */ - int nFrag; /* Number of fragmented bytes on pPage */ int top; /* First byte of cell content area */ int gap; /* First byte of gap between cell pointers and cell content */ int rc; /* Integer return code */ @@ -52751,25 +53441,26 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ usableSize = pPage->pBt->usableSize; assert( nByte < usableSize-8 ); - nFrag = data[hdr+7]; assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf ); gap = pPage->cellOffset + 2*pPage->nCell; - top = get2byteNotZero(&data[hdr+5]); - if( gap>top ) return SQLITE_CORRUPT_BKPT; + assert( gap<=65536 ); + top = get2byte(&data[hdr+5]); + if( gap>top ){ + if( top==0 ){ + top = 65536; + }else{ + return SQLITE_CORRUPT_BKPT; + } + } + + /* If there is enough space between gap and top for one more cell pointer + ** array entry offset, and if the freelist is not empty, then search the + ** freelist looking for a free slot big enough to satisfy the request. + */ testcase( gap+2==top ); testcase( gap+1==top ); testcase( gap==top ); - - if( nFrag>=60 ){ - /* Always defragment highly fragmented pages */ - rc = defragmentPage(pPage); - if( rc ) return rc; - top = get2byteNotZero(&data[hdr+5]); - }else if( gap+2<=top ){ - /* Search the freelist looking for a free slot big enough to satisfy - ** the request. The allocation is made from the first free slot in - ** the list that is large enough to accommodate it. - */ + if( gap+2<=top && (data[hdr+1] || data[hdr+2]) ){ int pc, addr; for(addr=hdr+1; (pc = get2byte(&data[addr]))>0; addr=pc){ int size; /* Size of the free slot */ @@ -52782,10 +53473,11 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ testcase( x==4 ); testcase( x==3 ); if( x<4 ){ + if( data[hdr+7]>=60 ) goto defragment_page; /* Remove the slot from the free-list. Update the number of ** fragmented bytes within the page. */ memcpy(&data[addr], &data[pc], 2); - data[hdr+7] = (u8)(nFrag + x); + data[hdr+7] += (u8)x; }else if( size+pc > usableSize ){ return SQLITE_CORRUPT_BKPT; }else{ @@ -52799,11 +53491,13 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ } } - /* Check to make sure there is enough space in the gap to satisfy - ** the allocation. If not, defragment. + /* The request could not be fulfilled using a freelist slot. Check + ** to see if defragmentation is necessary. */ testcase( gap+2+nByte==top ); if( gap+2+nByte>top ){ +defragment_page: + testcase( pPage->nCell==0 ); rc = defragmentPage(pPage); if( rc ) return rc; top = get2byteNotZero(&data[hdr+5]); @@ -52826,90 +53520,100 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ /* ** Return a section of the pPage->aData to the freelist. -** The first byte of the new free block is pPage->aDisk[start] -** and the size of the block is "size" bytes. +** The first byte of the new free block is pPage->aData[iStart] +** and the size of the block is iSize bytes. ** -** Most of the effort here is involved in coalesing adjacent -** free blocks into a single big free block. +** Adjacent freeblocks are coalesced. +** +** Note that even though the freeblock list was checked by btreeInitPage(), +** that routine will not detect overlap between cells or freeblocks. Nor +** does it detect cells or freeblocks that encrouch into the reserved bytes +** at the end of the page. So do additional corruption checks inside this +** routine and return SQLITE_CORRUPT if any problems are found. */ -static int freeSpace(MemPage *pPage, int start, int size){ - int addr, pbegin, hdr; - int iLast; /* Largest possible freeblock offset */ - unsigned char *data = pPage->aData; +static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ + u16 iPtr; /* Address of ptr to next freeblock */ + u16 iFreeBlk; /* Address of the next freeblock */ + u8 hdr; /* Page header size. 0 or 100 */ + u8 nFrag = 0; /* Reduction in fragmentation */ + u16 iOrigSize = iSize; /* Original value of iSize */ + u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */ + u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ + unsigned char *data = pPage->aData; /* Page content */ assert( pPage->pBt!=0 ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); - assert( start>=pPage->hdrOffset+6+pPage->childPtrSize ); - assert( (start + size) <= (int)pPage->pBt->usableSize ); + assert( iStart>=pPage->hdrOffset+6+pPage->childPtrSize ); + assert( iEnd <= pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - assert( size>=0 ); /* Minimum cell size is 4 */ + assert( iSize>=4 ); /* Minimum cell size is 4 */ + assert( iStart<=iLast ); + /* Overwrite deleted information with zeros when the secure_delete + ** option is enabled */ if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){ - /* Overwrite deleted information with zeros when the secure_delete - ** option is enabled */ - memset(&data[start], 0, size); + memset(&data[iStart], 0, iSize); } - /* Add the space back into the linked list of freeblocks. Note that - ** even though the freeblock list was checked by btreeInitPage(), - ** btreeInitPage() did not detect overlapping cells or - ** freeblocks that overlapped cells. Nor does it detect when the - ** cell content area exceeds the value in the page header. If these - ** situations arise, then subsequent insert operations might corrupt - ** the freelist. So we do need to check for corruption while scanning - ** the freelist. + /* The list of freeblocks must be in ascending order. Find the + ** spot on the list where iStart should be inserted. */ hdr = pPage->hdrOffset; - addr = hdr + 1; - iLast = pPage->pBt->usableSize - 4; - assert( start<=iLast ); - while( (pbegin = get2byte(&data[addr]))0 ){ - if( pbegin0 && iFreeBlkiLast ){ - return SQLITE_CORRUPT_BKPT; - } - assert( pbegin>addr || pbegin==0 ); - put2byte(&data[addr], start); - put2byte(&data[start], pbegin); - put2byte(&data[start+2], size); - pPage->nFree = pPage->nFree + (u16)size; - - /* Coalesce adjacent free blocks */ - addr = hdr + 1; - while( (pbegin = get2byte(&data[addr]))>0 ){ - int pnext, psize, x; - assert( pbegin>addr ); - assert( pbegin <= (int)pPage->pBt->usableSize-4 ); - pnext = get2byte(&data[pbegin]); - psize = get2byte(&data[pbegin+2]); - if( pbegin + psize + 3 >= pnext && pnext>0 ){ - int frag = pnext - (pbegin+psize); - if( (frag<0) || (frag>(int)data[hdr+7]) ){ - return SQLITE_CORRUPT_BKPT; + if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT; + assert( iFreeBlk>iPtr || iFreeBlk==0 ); + + /* At this point: + ** iFreeBlk: First freeblock after iStart, or zero if none + ** iPtr: The address of a pointer iFreeBlk + ** + ** Check to see if iFreeBlk should be coalesced onto the end of iStart. + */ + if( iFreeBlk && iEnd+3>=iFreeBlk ){ + nFrag = iFreeBlk - iEnd; + if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT; + iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); + iSize = iEnd - iStart; + iFreeBlk = get2byte(&data[iFreeBlk]); + } + + /* If iPtr is another freeblock (that is, if iPtr is not the freelist + ** pointer in the page header) then check to see if iStart should be + ** coalesced onto the end of iPtr. + */ + if( iPtr>hdr+1 ){ + int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); + if( iPtrEnd+3>=iStart ){ + if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT; + nFrag += iStart - iPtrEnd; + iSize = iEnd - iPtr; + iStart = iPtr; } - data[hdr+7] -= (u8)frag; - x = get2byte(&data[pnext]); - put2byte(&data[pbegin], x); - x = pnext + get2byte(&data[pnext+2]) - pbegin; - put2byte(&data[pbegin+2], x); - }else{ - addr = pbegin; } + if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT; + data[hdr+7] -= nFrag; } - - /* If the cell content area begins with a freeblock, remove it. */ - if( data[hdr+1]==data[hdr+5] && data[hdr+2]==data[hdr+6] ){ - int top; - pbegin = get2byte(&data[hdr+1]); - memcpy(&data[hdr+1], &data[pbegin], 2); - top = get2byte(&data[hdr+5]) + get2byte(&data[pbegin+2]); - put2byte(&data[hdr+5], top); + if( iStart==get2byte(&data[hdr+5]) ){ + /* The new freeblock is at the beginning of the cell content area, + ** so just extend the cell content area rather than create another + ** freelist entry */ + if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT; + put2byte(&data[hdr+1], iFreeBlk); + put2byte(&data[hdr+5], iEnd); + }else{ + /* Insert the new freeblock into the freelist */ + put2byte(&data[iPtr], iStart); + put2byte(&data[iStart], iFreeBlk); + put2byte(&data[iStart+2], iSize); } - assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + pPage->nFree += iOrigSize; return SQLITE_OK; } @@ -52936,12 +53640,14 @@ static int decodeFlags(MemPage *pPage, int flagByte){ pBt = pPage->pBt; if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){ pPage->intKey = 1; - pPage->hasData = pPage->leaf; + pPage->intKeyLeaf = pPage->leaf; + pPage->noPayload = !pPage->leaf; pPage->maxLocal = pBt->maxLeaf; pPage->minLocal = pBt->minLeaf; }else if( flagByte==PTF_ZERODATA ){ pPage->intKey = 0; - pPage->hasData = 0; + pPage->intKeyLeaf = 0; + pPage->noPayload = 0; pPage->maxLocal = pBt->maxLocal; pPage->minLocal = pBt->minLocal; }else{ @@ -53596,7 +54302,8 @@ static int removeFromSharingList(BtShared *pBt){ /* ** Make sure pBt->pTmpSpace points to an allocation of -** MX_CELL_SIZE(pBt) bytes. +** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child +** pointer. */ static void allocateTempSpace(BtShared *pBt){ if( !pBt->pTmpSpace ){ @@ -53611,8 +54318,16 @@ static void allocateTempSpace(BtShared *pBt){ ** it into a database page. This is not actually a problem, but it ** does cause a valgrind error when the 1 or 2 bytes of unitialized ** data is passed to system call write(). So to avoid this error, - ** zero the first 4 bytes of temp space here. */ - if( pBt->pTmpSpace ) memset(pBt->pTmpSpace, 0, 4); + ** zero the first 4 bytes of temp space here. + ** + ** Also: Provide four bytes of initialized space before the + ** beginning of pTmpSpace as an area available to prepend the + ** left-child pointer to the beginning of a cell. + */ + if( pBt->pTmpSpace ){ + memset(pBt->pTmpSpace, 0, 8); + pBt->pTmpSpace += 4; + } } } @@ -53620,8 +54335,11 @@ static void allocateTempSpace(BtShared *pBt){ ** Free the pBt->pTmpSpace allocation */ static void freeTempSpace(BtShared *pBt){ - sqlite3PageFree( pBt->pTmpSpace); - pBt->pTmpSpace = 0; + if( pBt->pTmpSpace ){ + pBt->pTmpSpace -= 4; + sqlite3PageFree(pBt->pTmpSpace); + pBt->pTmpSpace = 0; + } } /* @@ -53647,7 +54365,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. */ - sqlite3BtreeRollback(p, SQLITE_OK); + sqlite3BtreeRollback(p, SQLITE_OK, 0); sqlite3BtreeLeave(p); /* If there are still other outstanding references to the shared-btree @@ -54089,7 +54807,7 @@ page1_init_failed: ** false then all cursors are counted. ** ** For the purposes of this routine, a cursor is any cursor that -** is capable of reading or writing to the databse. Cursors that +** is capable of reading or writing to the database. Cursors that ** have been tripped into the CURSOR_FAULT state are not counted. */ static int countValidCursors(BtShared *pBt, int wrOnly){ @@ -54115,11 +54833,11 @@ static void unlockBtreeIfUnused(BtShared *pBt){ assert( sqlite3_mutex_held(pBt->mutex) ); assert( countValidCursors(pBt,0)==0 || pBt->inTransaction>TRANS_NONE ); if( pBt->inTransaction==TRANS_NONE && pBt->pPage1!=0 ){ - assert( pBt->pPage1->aData ); + MemPage *pPage1 = pBt->pPage1; + assert( pPage1->aData ); assert( sqlite3PagerRefcount(pBt->pPager)==1 ); - assert( pBt->pPage1->aData ); - releasePage(pBt->pPage1); pBt->pPage1 = 0; + releasePage(pPage1); } } @@ -54553,7 +55271,7 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); ** calling this function again), return SQLITE_DONE. Or, if an error ** occurs, return some other error code. ** -** More specificly, this function attempts to re-organize the database so +** More specifically, this function attempts to re-organize the database so ** that the last page of the file currently in use is no longer in use. ** ** Parameter nFin is the number of pages that this database would contain @@ -54561,7 +55279,7 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); ** ** If the bCommit parameter is non-zero, this function assumes that the ** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE -** or an error. bCommit is passed true for an auto-vacuum-on-commmit +** or an error. bCommit is passed true for an auto-vacuum-on-commit ** operation, or false for an incremental vacuum. */ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ @@ -54940,60 +55658,91 @@ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){ /* ** This routine sets the state to CURSOR_FAULT and the error -** code to errCode for every cursor on BtShared that pBtree -** references. +** code to errCode for every cursor on any BtShared that pBtree +** references. Or if the writeOnly flag is set to 1, then only +** trip write cursors and leave read cursors unchanged. ** -** Every cursor is tripped, including cursors that belong -** to other database connections that happen to be sharing -** the cache with pBtree. +** Every cursor is a candidate to be tripped, including cursors +** that belong to other database connections that happen to be +** sharing the cache with pBtree. ** -** This routine gets called when a rollback occurs. -** All cursors using the same cache must be tripped -** to prevent them from trying to use the btree after -** the rollback. The rollback may have deleted tables -** or moved root pages, so it is not sufficient to -** save the state of the cursor. The cursor must be -** invalidated. +** This routine gets called when a rollback occurs. If the writeOnly +** flag is true, then only write-cursors need be tripped - read-only +** cursors save their current positions so that they may continue +** following the rollback. Or, if writeOnly is false, all cursors are +** tripped. In general, writeOnly is false if the transaction being +** rolled back modified the database schema. In this case b-tree root +** pages may be moved or deleted from the database altogether, making +** it unsafe for read cursors to continue. +** +** If the writeOnly flag is true and an error is encountered while +** saving the current position of a read-only cursor, all cursors, +** including all read-cursors are tripped. +** +** SQLITE_OK is returned if successful, or if an error occurs while +** saving a cursor position, an SQLite error code. */ -SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){ +SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ BtCursor *p; - if( pBtree==0 ) return; - sqlite3BtreeEnter(pBtree); - for(p=pBtree->pBt->pCursor; p; p=p->pNext){ - int i; - sqlite3BtreeClearCursor(p); - p->eState = CURSOR_FAULT; - p->skipNext = errCode; - for(i=0; i<=p->iPage; i++){ - releasePage(p->apPage[i]); - p->apPage[i] = 0; + int rc = SQLITE_OK; + + assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 ); + if( pBtree ){ + sqlite3BtreeEnter(pBtree); + for(p=pBtree->pBt->pCursor; p; p=p->pNext){ + int i; + if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ + if( p->eState==CURSOR_VALID ){ + rc = saveCursorPosition(p); + if( rc!=SQLITE_OK ){ + (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); + break; + } + } + }else{ + sqlite3BtreeClearCursor(p); + p->eState = CURSOR_FAULT; + p->skipNext = errCode; + } + for(i=0; i<=p->iPage; i++){ + releasePage(p->apPage[i]); + p->apPage[i] = 0; + } } + sqlite3BtreeLeave(pBtree); } - sqlite3BtreeLeave(pBtree); + return rc; } /* -** Rollback the transaction in progress. All cursors will be -** invalided by this operation. Any attempt to use a cursor -** that was open at the beginning of this operation will result -** in an error. +** Rollback the transaction in progress. +** +** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). +** Only write cursors are tripped if writeOnly is true but all cursors are +** tripped if writeOnly is false. Any attempt to use +** a tripped cursor will result in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ -SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){ +SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ int rc; BtShared *pBt = p->pBt; MemPage *pPage1; + assert( writeOnly==1 || writeOnly==0 ); + assert( tripCode==SQLITE_ABORT_ROLLBACK || tripCode==SQLITE_OK ); sqlite3BtreeEnter(p); if( tripCode==SQLITE_OK ){ rc = tripCode = saveAllCursors(pBt, 0, 0); + if( rc ) writeOnly = 0; }else{ rc = SQLITE_OK; } if( tripCode ){ - sqlite3BtreeTripAllCursors(p, tripCode); + int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); + assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) ); + if( rc2!=SQLITE_OK ) rc = rc2; } btreeIntegrity(p); @@ -55028,7 +55777,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){ } /* -** Start a statement subtransaction. The subtransaction can can be rolled +** Start a statement subtransaction. The subtransaction can be rolled ** back independently of the main transaction. You must start a transaction ** before starting a subtransaction. The subtransaction is ended automatically ** if the main transaction commits or rolls back. @@ -55160,6 +55909,10 @@ static int btreeCursor( if( NEVER(wrFlag && (pBt->btsFlags & BTS_READ_ONLY)!=0) ){ return SQLITE_READONLY; } + if( wrFlag ){ + allocateTempSpace(pBt); + if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM; + } if( iTable==1 && btreePagecount(pBt)==0 ){ assert( wrFlag==0 ); iTable = 0; @@ -55262,7 +56015,7 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ ** compiler to crash when getCellInfo() is implemented as a macro. ** But there is a measureable speed advantage to using the macro on gcc ** (when less compiler optimizations like -Os or -O0 are used and the -** compiler is not doing agressive inlining.) So we use a real function +** compiler is not doing aggressive inlining.) So we use a real function ** for MSVC and a macro for everything else. Ticket #2457. */ #ifndef NDEBUG @@ -55324,13 +56077,9 @@ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){ */ SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ assert( cursorHoldsMutex(pCur) ); - assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); - if( pCur->eState!=CURSOR_VALID ){ - *pSize = 0; - }else{ - getCellInfo(pCur); - *pSize = pCur->info.nKey; - } + assert( pCur->eState==CURSOR_VALID ); + getCellInfo(pCur); + *pSize = pCur->info.nKey; return SQLITE_OK; } @@ -55349,8 +56098,9 @@ SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); + assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 ); getCellInfo(pCur); - *pSize = pCur->info.nData; + *pSize = pCur->info.nPayload; return SQLITE_OK; } @@ -55479,7 +56229,7 @@ static int copyPayload( ** ** If the current cursor entry uses one or more overflow pages and the ** eOp argument is not 2, this function may allocate space for and lazily -** popluates the overflow page-list cache array (BtCursor.aOverflow). +** populates the overflow page-list cache array (BtCursor.aOverflow). ** Subsequent calls use this cache to make seeking to the supplied offset ** more efficient. ** @@ -55501,30 +56251,28 @@ static int accessPayload( ){ unsigned char *aPayload; int rc = SQLITE_OK; - u32 nKey; int iIdx = 0; MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ #ifdef SQLITE_DIRECT_OVERFLOW_READ - int bEnd; /* True if reading to end of data */ + unsigned char * const pBufStart = pBuf; + int bEnd; /* True if reading to end of data */ #endif assert( pPage ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->aiIdx[pCur->iPage]nCell ); assert( cursorHoldsMutex(pCur) ); - assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */ + assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */ getCellInfo(pCur); - aPayload = pCur->info.pCell + pCur->info.nHeader; - nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey); + aPayload = pCur->info.pPayload; #ifdef SQLITE_DIRECT_OVERFLOW_READ - bEnd = (offset+amt==nKey+pCur->info.nData); + bEnd = offset+amt==pCur->info.nPayload; #endif + assert( offset+amt <= pCur->info.nPayload ); - if( NEVER(offset+amt > nKey+pCur->info.nData) - || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] - ){ + if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){ /* Trying to read or write past the end of the data is an error */ return SQLITE_CORRUPT_BKPT; } @@ -55580,7 +56328,9 @@ static int accessPayload( ** entry for the first required overflow page is valid, skip ** directly to it. */ - if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){ + if( (pCur->curFlags & BTCF_ValidOvfl)!=0 + && pCur->aOverflow[offset/ovflSize] + ){ iIdx = (offset/ovflSize); nextPage = pCur->aOverflow[iIdx]; offset = (offset%ovflSize); @@ -55633,6 +56383,7 @@ static int accessPayload( ** 4) there is no open write-transaction, and ** 5) the database is not a WAL database, ** 6) all data from the page is being read. + ** 7) at least 4 bytes have already been read into the output buffer ** ** then data can be read directly from the database file into the ** output buffer, bypassing the page-cache altogether. This speeds @@ -55644,9 +56395,11 @@ static int accessPayload( && pBt->inTransaction==TRANS_READ /* (4) */ && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */ && pBt->pPage1->aData[19]==0x01 /* (5) */ + && &pBuf[-4]>=pBufStart /* (7) */ ){ u8 aSave[4]; u8 *aWrite = &pBuf[-4]; + assert( aWrite>=pBufStart ); /* hence (7) */ memcpy(aSave, aWrite, 4); rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1)); nextPage = get4byte(aWrite); @@ -55681,7 +56434,7 @@ static int accessPayload( /* ** Read part of the key associated with cursor pCur. Exactly -** "amt" bytes will be transfered into pBuf[]. The transfer +** "amt" bytes will be transferred into pBuf[]. The transfer ** begins at "offset". ** ** The caller must ensure that pCur is pointing to a valid row @@ -55758,7 +56511,7 @@ static const void *fetchPayload( assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); assert( pCur->info.nSize>0 ); *pAmt = pCur->info.nLocal; - return (void*)(pCur->info.pCell + pCur->info.nHeader); + return (void*)pCur->info.pPayload; } @@ -56001,17 +56754,16 @@ static int moveToRightmost(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); pCur->aiIdx[pCur->iPage] = pPage->nCell; rc = moveToChild(pCur, pgno); + if( rc ) return rc; } - if( rc==SQLITE_OK ){ - pCur->aiIdx[pCur->iPage] = pPage->nCell-1; - pCur->info.nSize = 0; - pCur->curFlags &= ~BTCF_ValidNKey; - } - return rc; + pCur->aiIdx[pCur->iPage] = pPage->nCell-1; + assert( pCur->info.nSize==0 ); + assert( (pCur->curFlags & BTCF_ValidNKey)==0 ); + return SQLITE_OK; } /* Move the cursor to the first entry in the table. Return SQLITE_OK @@ -56142,7 +56894,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( if( pIdxKey ){ xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); - pIdxKey->isCorrupt = 0; + pIdxKey->errCode = 0; assert( pIdxKey->default_rc==1 || pIdxKey->default_rc==0 || pIdxKey->default_rc==-1 @@ -56187,7 +56939,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( for(;;){ i64 nCellKey; pCell = findCell(pPage, idx) + pPage->childPtrSize; - if( pPage->hasData ){ + if( pPage->intKeyLeaf ){ while( 0x80 <= *(pCell++) ){ if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT; } @@ -56235,14 +56987,14 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( ** single byte varint and the record fits entirely on the main ** b-tree page. */ testcase( pCell+nCell+1==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey, 0); + c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ testcase( pCell+nCell+2==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey, 0); + c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* The record flows over onto one or more overflow pages. In ** this case the whole cell needs to be parsed, a buffer allocated @@ -56263,10 +57015,13 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( sqlite3_free(pCellKey); goto moveto_finish; } - c = xRecordCompare(nCell, pCellKey, pIdxKey, 0); + c = xRecordCompare(nCell, pCellKey, pIdxKey); sqlite3_free(pCellKey); } - assert( pIdxKey->isCorrupt==0 || c==0 ); + assert( + (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) + && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) + ); if( c<0 ){ lwr = idx+1; }else if( c>0 ){ @@ -56276,7 +57031,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( *pRes = 0; rc = SQLITE_OK; pCur->aiIdx[pCur->iPage] = (u16)idx; - if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT; + if( pIdxKey->errCode ) rc = SQLITE_CORRUPT; goto moveto_finish; } if( lwr>upr ) break; @@ -56331,6 +57086,12 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){ ** was already pointing to the last entry in the database before ** this routine was called, then set *pRes=1. ** +** The main entry point is sqlite3BtreeNext(). That routine is optimized +** for the common case of merely incrementing the cell counter BtCursor.aiIdx +** to the next cell on the current page. The (slower) btreeNext() helper +** routine is called when it is necessary to move to a different page or +** to restore the cursor. +** ** The calling function will set *pRes to 0 or 1. The initial *pRes value ** will be 1 if the cursor being stepped corresponds to an SQL index and ** if this routine could have been skipped if that SQL index had been @@ -56340,20 +57101,18 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){ ** SQLite btree implementation does not. (Note that the comdb2 btree ** implementation does use this hint, however.) */ -SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ +static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ int rc; int idx; MemPage *pPage; assert( cursorHoldsMutex(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + assert( *pRes==0 ); if( pCur->eState!=CURSOR_VALID ){ - invalidateOverflowCache(pCur); + assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ - *pRes = 0; return rc; } if( CURSOR_INVALID==pCur->eState ){ @@ -56365,7 +57124,6 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ pCur->eState = CURSOR_VALID; if( pCur->skipNext>0 ){ pCur->skipNext = 0; - *pRes = 0; return SQLITE_OK; } pCur->skipNext = 0; @@ -56383,18 +57141,11 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ ** page into more than one b-tree structure. */ testcase( idx>pPage->nCell ); - pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); if( idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); - if( rc ){ - *pRes = 0; - return rc; - } - rc = moveToLeftmost(pCur); - *pRes = 0; - return rc; + if( rc ) return rc; + return moveToLeftmost(pCur); } do{ if( pCur->iPage==0 ){ @@ -56405,22 +57156,39 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ moveToParent(pCur); pPage = pCur->apPage[pCur->iPage]; }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell ); - *pRes = 0; if( pPage->intKey ){ - rc = sqlite3BtreeNext(pCur, pRes); + return sqlite3BtreeNext(pCur, pRes); }else{ - rc = SQLITE_OK; + return SQLITE_OK; } - return rc; } - *pRes = 0; if( pPage->leaf ){ return SQLITE_OK; + }else{ + return moveToLeftmost(pCur); + } +} +SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ + MemPage *pPage; + assert( cursorHoldsMutex(pCur) ); + assert( pRes!=0 ); + assert( *pRes==0 || *pRes==1 ); + assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + pCur->info.nSize = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + *pRes = 0; + if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes); + pPage = pCur->apPage[pCur->iPage]; + if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){ + pCur->aiIdx[pCur->iPage]--; + return btreeNext(pCur, pRes); + } + if( pPage->leaf ){ + return SQLITE_OK; + }else{ + return moveToLeftmost(pCur); } - rc = moveToLeftmost(pCur); - return rc; } - /* ** Step the cursor to the back to the previous entry in the database. If @@ -56428,6 +57196,12 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ ** was already pointing to the first entry in the database before ** this routine was called, then set *pRes=1. ** +** The main entry point is sqlite3BtreePrevious(). That routine is optimized +** for the common case of merely decrementing the cell counter BtCursor.aiIdx +** to the previous cell on the current page. The (slower) btreePrevious() +** helper routine is called when it is necessary to move to a different page +** or to restore the cursor. +** ** The calling function will set *pRes to 0 or 1. The initial *pRes value ** will be 1 if the cursor being stepped corresponds to an SQL index and ** if this routine could have been skipped if that SQL index had been @@ -56437,22 +57211,20 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ ** SQLite btree implementation does not. (Note that the comdb2 btree ** implementation does use this hint, however.) */ -SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ +static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ int rc; MemPage *pPage; assert( cursorHoldsMutex(pCur) ); assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); + assert( *pRes==0 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl); + assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 ); + assert( pCur->info.nSize==0 ); if( pCur->eState!=CURSOR_VALID ){ - if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){ - rc = btreeRestoreCursorPosition(pCur); - if( rc!=SQLITE_OK ){ - *pRes = 0; - return rc; - } + rc = restoreCursorPosition(pCur); + if( rc!=SQLITE_OK ){ + return rc; } if( CURSOR_INVALID==pCur->eState ){ *pRes = 1; @@ -56463,7 +57235,6 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ pCur->eState = CURSOR_VALID; if( pCur->skipNext<0 ){ pCur->skipNext = 0; - *pRes = 0; return SQLITE_OK; } pCur->skipNext = 0; @@ -56475,10 +57246,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ if( !pPage->leaf ){ int idx = pCur->aiIdx[pCur->iPage]; rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); - if( rc ){ - *pRes = 0; - return rc; - } + if( rc ) return rc; rc = moveToRightmost(pCur); }else{ while( pCur->aiIdx[pCur->iPage]==0 ){ @@ -56489,8 +57257,8 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ } moveToParent(pCur); } - pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + assert( pCur->info.nSize==0 ); + assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 ); pCur->aiIdx[pCur->iPage]--; pPage = pCur->apPage[pCur->iPage]; @@ -56500,9 +57268,25 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ rc = SQLITE_OK; } } - *pRes = 0; return rc; } +SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ + assert( cursorHoldsMutex(pCur) ); + assert( pRes!=0 ); + assert( *pRes==0 || *pRes==1 ); + assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + *pRes = 0; + pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); + pCur->info.nSize = 0; + if( pCur->eState!=CURSOR_VALID + || pCur->aiIdx[pCur->iPage]==0 + || pCur->apPage[pCur->iPage]->leaf==0 + ){ + return btreePrevious(pCur, pRes); + } + pCur->aiIdx[pCur->iPage]--; + return SQLITE_OK; +} /* ** Allocate a new page from the database file. @@ -56743,7 +57527,7 @@ static int allocateBtreePage( memcpy(&aData[8+closest*4], &aData[4+k*4], 4); } put4byte(&aData[4], k-1); - noContent = !btreeGetHasContent(pBt, *pPgno) ? PAGER_GET_NOCONTENT : 0; + noContent = !btreeGetHasContent(pBt, *pPgno)? PAGER_GET_NOCONTENT : 0; rc = btreeGetPage(pBt, *pPgno, ppPage, noContent); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite((*ppPage)->pDbPage); @@ -56776,7 +57560,7 @@ static int allocateBtreePage( ** here are confined to those pages that lie between the end of the ** database image and the end of the database file. */ - int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate)) ? PAGER_GET_NOCONTENT : 0; + int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate))? PAGER_GET_NOCONTENT:0; rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( rc ) return rc; @@ -56975,9 +57759,15 @@ static void freePage(MemPage *pPage, int *pRC){ } /* -** Free any overflow pages associated with the given Cell. +** Free any overflow pages associated with the given Cell. Write the +** local Cell size (the number of bytes on the original page, omitting +** overflow) into *pnSize. */ -static int clearCell(MemPage *pPage, unsigned char *pCell){ +static int clearCell( + MemPage *pPage, /* The page that contains the Cell */ + unsigned char *pCell, /* First byte of the Cell */ + u16 *pnSize /* Write the size of the Cell here */ +){ BtShared *pBt = pPage->pBt; CellInfo info; Pgno ovflPgno; @@ -56987,6 +57777,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); btreeParseCellPtr(pPage, pCell, &info); + *pnSize = info.nSize; if( info.iOverflow==0 ){ return SQLITE_OK; /* No overflow pages. Return without doing anything */ } @@ -57070,7 +57861,6 @@ static int fillInCell( BtShared *pBt = pPage->pBt; Pgno pgnoOvfl = 0; int nHeader; - CellInfo info; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); @@ -57080,23 +57870,17 @@ static int fillInCell( || sqlite3PagerIswriteable(pPage->pDbPage) ); /* Fill in the header. */ - nHeader = 0; - if( !pPage->leaf ){ - nHeader += 4; - } - if( pPage->hasData ){ - nHeader += putVarint32(&pCell[nHeader], nData+nZero); + nHeader = pPage->childPtrSize; + nPayload = nData + nZero; + if( pPage->intKeyLeaf ){ + nHeader += putVarint32(&pCell[nHeader], nPayload); }else{ - nData = nZero = 0; + assert( nData==0 ); + assert( nZero==0 ); } nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); - btreeParseCellPtr(pPage, pCell, &info); - assert( info.nHeader==nHeader ); - assert( info.nKey==nKey ); - assert( info.nData==(u32)(nData+nZero) ); - /* Fill in the payload */ - nPayload = nData + nZero; + /* Fill in the payload size */ if( pPage->intKey ){ pSrc = pData; nSrc = nData; @@ -57105,15 +57889,55 @@ static int fillInCell( if( NEVER(nKey>0x7fffffff || pKey==0) ){ return SQLITE_CORRUPT_BKPT; } - nPayload += (int)nKey; + nPayload = (int)nKey; pSrc = pKey; nSrc = (int)nKey; } - *pnSize = info.nSize; - spaceLeft = info.nLocal; + if( nPayload<=pPage->maxLocal ){ + n = nHeader + nPayload; + testcase( n==3 ); + testcase( n==4 ); + if( n<4 ) n = 4; + *pnSize = n; + spaceLeft = nPayload; + pPrior = pCell; + }else{ + int mn = pPage->minLocal; + n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4); + testcase( n==pPage->maxLocal ); + testcase( n==pPage->maxLocal+1 ); + if( n > pPage->maxLocal ) n = mn; + spaceLeft = n; + *pnSize = n + nHeader + 4; + pPrior = &pCell[nHeader+n]; + } pPayload = &pCell[nHeader]; - pPrior = &pCell[info.iOverflow]; + /* At this point variables should be set as follows: + ** + ** nPayload Total payload size in bytes + ** pPayload Begin writing payload here + ** spaceLeft Space available at pPayload. If nPayload>spaceLeft, + ** that means content must spill into overflow pages. + ** *pnSize Size of the local cell (not counting overflow pages) + ** pPrior Where to write the pgno of the first overflow page + ** + ** Use a call to btreeParseCellPtr() to verify that the values above + ** were computed correctly. + */ +#if SQLITE_DEBUG + { + CellInfo info; + btreeParseCellPtr(pPage, pCell, &info); + assert( nHeader=(int)(info.pPayload - pCell) ); + assert( info.nKey==nKey ); + assert( *pnSize == info.nSize ); + assert( spaceLeft == info.nLocal ); + assert( pPrior == &pCell[info.iOverflow] ); + } +#endif + + /* Write the payload into the local Cell and any extra into overflow pages */ while( nPayload>0 ){ if( spaceLeft==0 ){ #ifndef SQLITE_OMIT_AUTOVACUUM @@ -57254,11 +58078,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. -** -** If nSkip is non-zero, then do not copy the first nSkip bytes of the -** cell. The caller will overwrite them after this function returns. If -** nSkip is non-zero, then pCell may not point to an invalid memory location -** (but pCell+nSkip is always valid). */ static void insertCell( MemPage *pPage, /* Page into which we are copying */ @@ -57275,7 +58094,6 @@ static void insertCell( int ins; /* Index in data[] where new cell pointer is inserted */ int cellOffset; /* Address of first cell pointer in data[] */ u8 *data; /* The content of the whole page */ - int nSkip = (iChild ? 4 : 0); if( *pRC ) return; @@ -57293,7 +58111,7 @@ static void insertCell( assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ - memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip); + memcpy(pTemp, pCell, sz); pCell = pTemp; } if( iChild ){ @@ -57322,7 +58140,7 @@ static void insertCell( assert( idx+sz <= (int)pPage->pBt->usableSize ); pPage->nCell++; pPage->nFree -= (u16)(2 + sz); - memcpy(&data[idx+nSkip], pCell+nSkip, sz-nSkip); + memcpy(&data[idx], pCell, sz); if( iChild ){ put4byte(&data[idx], iChild); } @@ -57345,7 +58163,7 @@ static void insertCell( ** The cells are guaranteed to fit on the page. */ static void assemblePage( - MemPage *pPage, /* The page to be assemblied */ + MemPage *pPage, /* The page to be assembled */ int nCell, /* The number of cells to add to this page */ u8 **apCell, /* Pointers to cell bodies */ u16 *aSize /* Sizes of the cells */ @@ -57821,7 +58639,7 @@ static int balance_nonroot( ** leafData: 1 if pPage holds key+data and pParent holds only keys. */ leafCorrection = apOld[0]->leaf*4; - leafData = apOld[0]->hasData; + leafData = apOld[0]->intKeyLeaf; for(i=0; ipDbPage); if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_QUICKBALANCE - if( pPage->hasData + if( pPage->intKeyLeaf && pPage->nOverflow==1 && pPage->aiOvfl[0]==pPage->nCell && pParent->pgno!=1 @@ -58406,7 +59224,7 @@ static int balance(BtCursor *pCur){ /* Call balance_quick() to create a new sibling of pPage on which ** to store the overflow cell. balance_quick() inserts a new cell ** into pParent, which may cause pParent overflow. If this - ** happens, the next interation of the do-loop will balance pParent + ** happens, the next iteration of the do-loop will balance pParent ** use either balance_nonroot() or balance_deeper(). Until this ** happens, the overflow cell is stored in the aBalanceQuickSpace[] ** buffer. @@ -58483,7 +59301,7 @@ static int balance(BtCursor *pCur){ ** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already ** been performed. seekResult is the search result returned (a negative ** number if pCur points at an entry that is smaller than (pKey, nKey), or -** a positive value if pCur points at an etry that is larger than +** a positive value if pCur points at an entry that is larger than ** (pKey, nKey)). ** ** If the seekResult parameter is non-zero, then the caller guarantees that @@ -58516,7 +59334,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( } assert( cursorHoldsMutex(pCur) ); - assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE + assert( (pCur->curFlags & BTCF_WriteFlag)!=0 + && pBt->inTransaction==TRANS_WRITE && (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); @@ -58549,7 +59368,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( /* If the cursor is currently on the last row and we are appending a ** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto() ** call */ - if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){ + if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 + && pCur->info.nKey==nKey-1 ){ loc = -1; } } @@ -58568,9 +59388,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( pCur->pgnoRoot, nKey, nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); assert( pPage->isInit ); - allocateTempSpace(pBt); newCell = pBt->pTmpSpace; - if( newCell==0 ) return SQLITE_NOMEM; + assert( newCell!=0 ); rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew); if( rc ) goto end_insert; assert( szNew==cellSizePtr(pPage, newCell) ); @@ -58587,8 +59406,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } - szOld = cellSizePtr(pPage, oldCell); - rc = clearCell(pPage, oldCell); + rc = clearCell(pPage, oldCell, &szOld); dropCell(pPage, idx, szOld, &rc); if( rc ) goto end_insert; }else if( loc<0 && pPage->nCell>0 ){ @@ -58640,7 +59458,7 @@ end_insert: /* ** Delete the entry that the cursor is pointing to. The cursor -** is left pointing at a arbitrary location. +** is left pointing at an arbitrary location. */ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){ Btree *p = pCur->pBtree; @@ -58650,6 +59468,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){ unsigned char *pCell; /* Pointer to cell to delete */ int iCellIdx; /* Index of cell to delete */ int iCellDepth; /* Depth of node containing pCell */ + u16 szCell; /* Size of the cell being deleted */ assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); @@ -58698,8 +59517,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; - rc = clearCell(pPage, pCell); - dropCell(pPage, iCellIdx, cellSizePtr(pPage, pCell), &rc); + rc = clearCell(pPage, pCell, &szCell); + dropCell(pPage, iCellIdx, szCell, &rc); if( rc ) return rc; /* If the cell deleted was not located on a leaf page, then the cursor @@ -58716,10 +59535,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){ pCell = findCell(pLeaf, pLeaf->nCell-1); nCell = cellSizePtr(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); - - allocateTempSpace(pBt); pTmp = pBt->pTmpSpace; - + assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); @@ -58931,6 +59748,7 @@ static int clearDatabasePage( unsigned char *pCell; int i; int hdr; + u16 szCell; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ @@ -58946,7 +59764,7 @@ static int clearDatabasePage( rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); if( rc ) goto cleardatabasepage_out; } - rc = clearCell(pPage, pCell); + rc = clearCell(pPage, pCell, &szCell); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ @@ -59292,11 +60110,11 @@ SQLITE_PRIVATE Pager *sqlite3BtreePager(Btree *p){ */ static void checkAppendMsg( IntegrityCk *pCheck, - char *zMsg1, const char *zFormat, ... ){ va_list ap; + char zBuf[200]; if( !pCheck->mxErr ) return; pCheck->mxErr--; pCheck->nErr++; @@ -59304,8 +60122,9 @@ static void checkAppendMsg( if( pCheck->errMsg.nChar ){ sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1); } - if( zMsg1 ){ - sqlite3StrAccumAppendAll(&pCheck->errMsg, zMsg1); + if( pCheck->zPfx ){ + sqlite3_snprintf(sizeof(zBuf), zBuf, pCheck->zPfx, pCheck->v1, pCheck->v2); + sqlite3StrAccumAppendAll(&pCheck->errMsg, zBuf); } sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap); va_end(ap); @@ -59338,19 +60157,19 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){ /* ** Add 1 to the reference count for page iPage. If this is the second ** reference to the page, add an error message to pCheck->zErrMsg. -** Return 1 if there are 2 ore more references to the page and 0 if +** Return 1 if there are 2 or more references to the page and 0 if ** if this is the first reference to the page. ** ** Also check that the page number is in bounds. */ -static int checkRef(IntegrityCk *pCheck, Pgno iPage, char *zContext){ +static int checkRef(IntegrityCk *pCheck, Pgno iPage){ if( iPage==0 ) return 1; if( iPage>pCheck->nPage ){ - checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage); + checkAppendMsg(pCheck, "invalid page number %d", iPage); return 1; } if( getPageReferenced(pCheck, iPage) ){ - checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage); + checkAppendMsg(pCheck, "2nd reference to page %d", iPage); return 1; } setPageReferenced(pCheck, iPage); @@ -59367,8 +60186,7 @@ static void checkPtrmap( IntegrityCk *pCheck, /* Integrity check context */ Pgno iChild, /* Child page number */ u8 eType, /* Expected pointer map type */ - Pgno iParent, /* Expected pointer map parent page number */ - char *zContext /* Context description (used for error msg) */ + Pgno iParent /* Expected pointer map parent page number */ ){ int rc; u8 ePtrmapType; @@ -59377,12 +60195,12 @@ static void checkPtrmap( rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->mallocFailed = 1; - checkAppendMsg(pCheck, zContext, "Failed to read ptrmap key=%d", iChild); + checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild); return; } if( ePtrmapType!=eType || iPtrmapParent!=iParent ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", iChild, eType, iParent, ePtrmapType, iPtrmapParent); } @@ -59397,8 +60215,7 @@ static void checkList( IntegrityCk *pCheck, /* Integrity checking context */ int isFreeList, /* True for a freelist. False for overflow page list */ int iPage, /* Page number for first page in the list */ - int N, /* Expected number of pages in the list */ - char *zContext /* Context for error messages */ + int N /* Expected number of pages in the list */ ){ int i; int expected = N; @@ -59407,14 +60224,14 @@ static void checkList( DbPage *pOvflPage; unsigned char *pOvflData; if( iPage<1 ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "%d of %d pages missing from overflow list starting at %d", N+1, expected, iFirst); break; } - if( checkRef(pCheck, iPage, zContext) ) break; + if( checkRef(pCheck, iPage) ) break; if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage) ){ - checkAppendMsg(pCheck, zContext, "failed to get page %d", iPage); + checkAppendMsg(pCheck, "failed to get page %d", iPage); break; } pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage); @@ -59422,11 +60239,11 @@ static void checkList( int n = get4byte(&pOvflData[4]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pCheck->pBt->autoVacuum ){ - checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0, zContext); + checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0); } #endif if( n>(int)pCheck->pBt->usableSize/4-2 ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "freelist leaf count too big on page %d", iPage); N--; }else{ @@ -59434,10 +60251,10 @@ static void checkList( Pgno iFreePage = get4byte(&pOvflData[8+i*4]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pCheck->pBt->autoVacuum ){ - checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0, zContext); + checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0); } #endif - checkRef(pCheck, iFreePage, zContext); + checkRef(pCheck, iFreePage); } N -= n; } @@ -59450,7 +60267,7 @@ static void checkList( */ if( pCheck->pBt->autoVacuum && N>0 ){ i = get4byte(pOvflData); - checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage, zContext); + checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage); } } #endif @@ -59482,7 +60299,6 @@ static void checkList( static int checkTreePage( IntegrityCk *pCheck, /* Context for the sanity check */ int iPage, /* Page number of the page to check */ - char *zParentContext, /* Parent context */ i64 *pnParentMinKey, i64 *pnParentMaxKey ){ @@ -59493,23 +60309,26 @@ static int checkTreePage( u8 *data; BtShared *pBt; int usableSize; - char zContext[100]; char *hit = 0; i64 nMinKey = 0; i64 nMaxKey = 0; - - sqlite3_snprintf(sizeof(zContext), zContext, "Page %d: ", iPage); + const char *saved_zPfx = pCheck->zPfx; + int saved_v1 = pCheck->v1; + int saved_v2 = pCheck->v2; /* Check that the page exists */ pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; - if( checkRef(pCheck, iPage, zParentContext) ) return 0; + if( checkRef(pCheck, iPage) ) return 0; + pCheck->zPfx = "Page %d: "; + pCheck->v1 = iPage; if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "unable to get the page. error code=%d", rc); - return 0; + depth = -1; + goto end_of_check; } /* Clear MemPage.isInit to make sure the corruption detection code in @@ -59517,10 +60336,11 @@ static int checkTreePage( pPage->isInit = 0; if( (rc = btreeInitPage(pPage))!=0 ){ assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "btreeInitPage() returns error code %d", rc); releasePage(pPage); - return 0; + depth = -1; + goto end_of_check; } /* Check out all the cells. @@ -59533,23 +60353,23 @@ static int checkTreePage( /* Check payload overflow pages */ - sqlite3_snprintf(sizeof(zContext), zContext, - "On tree page %d cell %d: ", iPage, i); + pCheck->zPfx = "On tree page %d cell %d: "; + pCheck->v1 = iPage; + pCheck->v2 = i; pCell = findCell(pPage,i); btreeParseCellPtr(pPage, pCell, &info); - sz = info.nData; - if( !pPage->intKey ) sz += (int)info.nKey; + sz = info.nPayload; /* For intKey pages, check that the keys are in order. */ - else if( i==0 ) nMinKey = nMaxKey = info.nKey; - else{ - if( info.nKey <= nMaxKey ){ - checkAppendMsg(pCheck, zContext, - "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey); + if( pPage->intKey ){ + if( i==0 ){ + nMinKey = nMaxKey = info.nKey; + }else if( info.nKey <= nMaxKey ){ + checkAppendMsg(pCheck, + "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey); } nMaxKey = info.nKey; } - assert( sz==info.nPayload ); if( (sz>info.nLocal) && (&pCell[info.iOverflow]<=&pPage->aData[pBt->usableSize]) ){ @@ -59557,10 +60377,10 @@ static int checkTreePage( Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage, zContext); + checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage); } #endif - checkList(pCheck, 0, pgnoOvfl, nPage, zContext); + checkList(pCheck, 0, pgnoOvfl, nPage); } /* Check sanity of left child page. @@ -59569,12 +60389,12 @@ static int checkTreePage( pgno = get4byte(pCell); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext); + checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); } #endif - d2 = checkTreePage(pCheck, pgno, zContext, &nMinKey, i==0 ? NULL : &nMaxKey); + d2 = checkTreePage(pCheck, pgno, &nMinKey, i==0?NULL:&nMaxKey); if( i>0 && d2!=depth ){ - checkAppendMsg(pCheck, zContext, "Child page depth differs"); + checkAppendMsg(pCheck, "Child page depth differs"); } depth = d2; } @@ -59582,37 +60402,39 @@ static int checkTreePage( if( !pPage->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); - sqlite3_snprintf(sizeof(zContext), zContext, - "On page %d at right child: ", iPage); + pCheck->zPfx = "On page %d at right child: "; + pCheck->v1 = iPage; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext); + checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); } #endif - checkTreePage(pCheck, pgno, zContext, NULL, !pPage->nCell ? NULL : &nMaxKey); + checkTreePage(pCheck, pgno, NULL, !pPage->nCell?NULL:&nMaxKey); } /* For intKey leaf pages, check that the min/max keys are in order ** with any left/parent/right pages. */ + pCheck->zPfx = "Page %d: "; + pCheck->v1 = iPage; if( pPage->leaf && pPage->intKey ){ /* if we are a left child page */ if( pnParentMinKey ){ /* if we are the left most child page */ if( !pnParentMaxKey ){ if( nMaxKey > *pnParentMinKey ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "Rowid %lld out of order (max larger than parent min of %lld)", nMaxKey, *pnParentMinKey); } }else{ if( nMinKey <= *pnParentMinKey ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "Rowid %lld out of order (min less than parent min of %lld)", nMinKey, *pnParentMinKey); } if( nMaxKey > *pnParentMaxKey ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "Rowid %lld out of order (max larger than parent max of %lld)", nMaxKey, *pnParentMaxKey); } @@ -59621,7 +60443,7 @@ static int checkTreePage( /* else if we're a right child page */ } else if( pnParentMaxKey ){ if( nMinKey <= *pnParentMaxKey ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "Rowid %lld out of order (min less than parent max of %lld)", nMinKey, *pnParentMaxKey); } @@ -59633,6 +60455,7 @@ static int checkTreePage( data = pPage->aData; hdr = pPage->hdrOffset; hit = sqlite3PageMalloc( pBt->pageSize ); + pCheck->zPfx = 0; if( hit==0 ){ pCheck->mallocFailed = 1; }else{ @@ -59650,7 +60473,8 @@ static int checkTreePage( size = cellSizePtr(pPage, &data[pc]); } if( (int)(pc+size-1)>=usableSize ){ - checkAppendMsg(pCheck, 0, + pCheck->zPfx = 0; + checkAppendMsg(pCheck, "Corruption detected in cell %d on page %d",i,iPage); }else{ for(j=pc+size-1; j>=pc; j--) hit[j]++; @@ -59672,19 +60496,24 @@ static int checkTreePage( if( hit[i]==0 ){ cnt++; }else if( hit[i]>1 ){ - checkAppendMsg(pCheck, 0, + checkAppendMsg(pCheck, "Multiple uses for byte %d of page %d", i, iPage); break; } } if( cnt!=data[hdr+7] ){ - checkAppendMsg(pCheck, 0, + checkAppendMsg(pCheck, "Fragmentation of %d bytes reported as %d on page %d", cnt, data[hdr+7], iPage); } } sqlite3PageFree(hit); releasePage(pPage); + +end_of_check: + pCheck->zPfx = saved_zPfx; + pCheck->v1 = saved_v1; + pCheck->v2 = saved_v2; return depth+1; } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -59725,6 +60554,9 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( sCheck.mxErr = mxErr; sCheck.nErr = 0; sCheck.mallocFailed = 0; + sCheck.zPfx = 0; + sCheck.v1 = 0; + sCheck.v2 = 0; *pnErr = 0; if( sCheck.nPage==0 ){ sqlite3BtreeLeave(p); @@ -59744,8 +60576,10 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( /* Check the integrity of the freelist */ + sCheck.zPfx = "Main freelist: "; checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), - get4byte(&pBt->pPage1->aData[36]), "Main freelist: "); + get4byte(&pBt->pPage1->aData[36])); + sCheck.zPfx = 0; /* Check all the tables. */ @@ -59753,10 +60587,12 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( if( aRoot[i]==0 ) continue; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum && aRoot[i]>1 ){ - checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0, 0); + checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); } #endif - checkTreePage(&sCheck, aRoot[i], "List of tree roots: ", NULL, NULL); + sCheck.zPfx = "List of tree roots: "; + checkTreePage(&sCheck, aRoot[i], NULL, NULL); + sCheck.zPfx = 0; } /* Make sure every page in the file is referenced @@ -59764,7 +60600,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ #ifdef SQLITE_OMIT_AUTOVACUUM if( getPageReferenced(&sCheck, i)==0 ){ - checkAppendMsg(&sCheck, 0, "Page %d is never used", i); + checkAppendMsg(&sCheck, "Page %d is never used", i); } #else /* If the database supports auto-vacuum, make sure no tables contain @@ -59772,11 +60608,11 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( */ if( getPageReferenced(&sCheck, i)==0 && (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ - checkAppendMsg(&sCheck, 0, "Page %d is never used", i); + checkAppendMsg(&sCheck, "Page %d is never used", i); } if( getPageReferenced(&sCheck, i)!=0 && (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ - checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i); + checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); } #endif } @@ -59786,7 +60622,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( ** of the integrity check. */ if( NEVER(nRef != sqlite3PagerRefcount(pBt->pPager)) ){ - checkAppendMsg(&sCheck, 0, + checkAppendMsg(&sCheck, "Outstanding page count goes from %d to %d during this analysis", nRef, sqlite3PagerRefcount(pBt->pPager) ); @@ -59982,7 +60818,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void ** required in case any of them are holding references to an xFetch ** version of the b-tree page modified by the accessPayload call below. ** - ** Note that pCsr must be open on a BTREE_INTKEY table and saveCursorPosition() + ** Note that pCsr must be open on a INTKEY table and saveCursorPosition() ** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence ** saveAllCursors can only return SQLITE_OK. */ @@ -60157,12 +60993,12 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ int rc = 0; pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse)); if( pParse==0 ){ - sqlite3Error(pErrorDb, SQLITE_NOMEM, "out of memory"); + sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory"); rc = SQLITE_NOMEM; }else{ pParse->db = pDb; if( sqlite3OpenTempDatabase(pParse) ){ - sqlite3Error(pErrorDb, pParse->rc, "%s", pParse->zErrMsg); + sqlite3ErrorWithMsg(pErrorDb, pParse->rc, "%s", pParse->zErrMsg); rc = SQLITE_ERROR; } sqlite3DbFree(pErrorDb, pParse->zErrMsg); @@ -60175,7 +61011,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ } if( i<0 ){ - sqlite3Error(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb); + sqlite3ErrorWithMsg(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb); return 0; } @@ -60220,7 +61056,7 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3_mutex_enter(pDestDb->mutex); if( pSrcDb==pDestDb ){ - sqlite3Error( + sqlite3ErrorWithMsg( pDestDb, SQLITE_ERROR, "source and destination must be distinct" ); p = 0; @@ -60231,7 +61067,7 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init( ** sqlite3_backup_finish(). */ p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup)); if( !p ){ - sqlite3Error(pDestDb, SQLITE_NOMEM, 0); + sqlite3Error(pDestDb, SQLITE_NOMEM); } } @@ -60667,12 +61503,12 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){ } /* If a transaction is still open on the Btree, roll it back. */ - sqlite3BtreeRollback(p->pDest, SQLITE_OK); + sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; if( p->pDestDb ){ - sqlite3Error(p->pDestDb, rc, 0); + sqlite3Error(p->pDestDb, rc); /* Exit the mutexes and free the backup context structure. */ sqlite3LeaveMutexAndCloseZombie(p->pDestDb); @@ -60845,29 +61681,40 @@ copy_finished: ** this: assert( sqlite3VdbeCheckMemInvariants(pMem) ); */ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ - /* The MEM_Dyn bit is set if and only if Mem.xDel is a non-NULL destructor - ** function for Mem.z + /* If MEM_Dyn is set then Mem.xDel!=0. + ** Mem.xDel is might not be initialized if MEM_Dyn is clear. */ assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); - assert( (p->flags & MEM_Dyn)!=0 || p->xDel==0 ); + + /* MEM_Dyn may only be set if Mem.szMalloc==0. In this way we + ** ensure that if Mem.szMalloc>0 then it is safe to do + ** Mem.z = Mem.zMalloc without having to check Mem.flags&MEM_Dyn. + ** That saves a few cycles in inner loops. */ + assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 ); + + /* Cannot be both MEM_Int and MEM_Real at the same time */ + assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); + + /* The szMalloc field holds the correct memory allocation size */ + assert( p->szMalloc==0 + || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) ); /* If p holds a string or blob, the Mem.z must point to exactly ** one of the following: ** ** (1) Memory in Mem.zMalloc and managed by the Mem object ** (2) Memory to be freed using Mem.xDel - ** (3) An ephermal string or blob + ** (3) An ephemeral string or blob ** (4) A static string or blob */ - if( (p->flags & (MEM_Str|MEM_Blob)) && p->z!=0 ){ + if( (p->flags & (MEM_Str|MEM_Blob)) && p->n>0 ){ assert( - ((p->z==p->zMalloc)? 1 : 0) + + ((p->szMalloc>0 && p->z==p->zMalloc)? 1 : 0) + ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1 ); } - return 1; } #endif @@ -60921,7 +61768,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ ** blob if bPreserve is true. If bPreserve is false, any prior content ** in pMem->z is discarded. */ -SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ +SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( sqlite3VdbeCheckMemInvariants(pMem) ); assert( (pMem->flags&MEM_RowSet)==0 ); @@ -60930,24 +61777,28 @@ SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) ); testcase( bPreserve && pMem->z==0 ); - if( pMem->zMalloc==0 || sqlite3DbMallocSize(pMem->db, pMem->zMalloc)szMalloc==0 + || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) ); + if( pMem->szMallocz==pMem->zMalloc ){ + if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); bPreserve = 0; }else{ - sqlite3DbFree(pMem->db, pMem->zMalloc); + if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc); pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); } if( pMem->zMalloc==0 ){ - VdbeMemRelease(pMem); + sqlite3VdbeMemSetNull(pMem); pMem->z = 0; - pMem->flags = MEM_Null; + pMem->szMalloc = 0; return SQLITE_NOMEM; + }else{ + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); } } - if( pMem->z && bPreserve && pMem->z!=pMem->zMalloc ){ + if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){ memcpy(pMem->zMalloc, pMem->z, pMem->n); } if( (pMem->flags&MEM_Dyn)!=0 ){ @@ -60957,15 +61808,37 @@ SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ pMem->z = pMem->zMalloc; pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static); - pMem->xDel = 0; return SQLITE_OK; } /* -** Make the given Mem object MEM_Dyn. In other words, make it so -** that any TEXT or BLOB content is stored in memory obtained from -** malloc(). In this way, we know that the memory is safe to be -** overwritten or altered. +** Change the pMem->zMalloc allocation to be at least szNew bytes. +** If pMem->zMalloc already meets or exceeds the requested size, this +** routine is a no-op. +** +** Any prior string or blob content in the pMem object may be discarded. +** The pMem->xDel destructor is called, if it exists. Though MEM_Str +** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null +** values are preserved. +** +** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM) +** if unable to complete the resizing. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ + assert( szNew>0 ); + assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 ); + if( pMem->szMallocflags & MEM_Dyn)==0 ); + pMem->z = pMem->zMalloc; + pMem->flags &= (MEM_Null|MEM_Int|MEM_Real); + return SQLITE_OK; +} + +/* +** Change pMem so that its MEM_Str or MEM_Blob value is stored in +** MEM.zMalloc, where it can be safely written. ** ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ @@ -60975,7 +61848,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ assert( (pMem->flags&MEM_RowSet)==0 ); ExpandBlob(pMem); f = pMem->flags; - if( (f&(MEM_Str|MEM_Blob)) && pMem->z!=pMem->zMalloc ){ + if( (f&(MEM_Str|MEM_Blob)) && (pMem->szMalloc==0 || pMem->z!=pMem->zMalloc) ){ if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){ return SQLITE_NOMEM; } @@ -61019,15 +61892,11 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ } #endif - /* -** Make sure the given Mem is \u0000 terminated. +** It is already known that pMem contains an unterminated string. +** Add the zero terminator. */ -SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ - assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){ - return SQLITE_OK; /* Nothing to do */ - } +static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ return SQLITE_NOMEM; } @@ -61037,21 +61906,35 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ return SQLITE_OK; } +/* +** Make sure the given Mem is \u0000 terminated. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) ); + testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 ); + if( (pMem->flags & (MEM_Term|MEM_Str))!=MEM_Str ){ + return SQLITE_OK; /* Nothing to do */ + }else{ + return vdbeMemAddTerminator(pMem); + } +} + /* ** Add MEM_Str to the set of representations for the given Mem. Numbers ** are converted using sqlite3_snprintf(). Converting a BLOB to a string ** is a no-op. ** -** Existing representations MEM_Int and MEM_Real are *not* invalidated. +** Existing representations MEM_Int and MEM_Real are invalidated if +** bForce is true but are retained if bForce is false. ** ** A MEM_Null value will never be passed to this function. This function is ** used for converting values to text for returning to the user (i.e. via ** sqlite3_value_text()), or for ensuring that values to be used as btree ** keys are strings. In the former case a NULL pointer is returned the -** user and the later is an internal programming error. +** user and the latter is an internal programming error. */ -SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, int enc){ - int rc = SQLITE_OK; +SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ int fg = pMem->flags; const int nByte = 32; @@ -61063,11 +61946,11 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, int enc){ assert( EIGHT_BYTE_ALIGNMENT(pMem) ); - if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){ + if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){ return SQLITE_NOMEM; } - /* For a Real or Integer, use sqlite3_mprintf() to produce the UTF-8 + /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 ** string representation of the value. Then, if the required encoding ** is UTF-16le or UTF-16be do a translation. ** @@ -61077,13 +61960,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, int enc){ sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i); }else{ assert( fg & MEM_Real ); - sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->r); + sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r); } pMem->n = sqlite3Strlen30(pMem->z); pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str|MEM_Term; + if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real); sqlite3VdbeChangeEncoding(pMem, enc); - return rc; + return SQLITE_OK; } /* @@ -61098,59 +61982,90 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ int rc = SQLITE_OK; if( ALWAYS(pFunc && pFunc->xFinalize) ){ sqlite3_context ctx; + Mem t; assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); memset(&ctx, 0, sizeof(ctx)); - ctx.s.flags = MEM_Null; - ctx.s.db = pMem->db; + memset(&t, 0, sizeof(t)); + t.flags = MEM_Null; + t.db = pMem->db; + ctx.pOut = &t; ctx.pMem = pMem; ctx.pFunc = pFunc; pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */ - assert( 0==(pMem->flags&MEM_Dyn) && !pMem->xDel ); - sqlite3DbFree(pMem->db, pMem->zMalloc); - memcpy(pMem, &ctx.s, sizeof(ctx.s)); + assert( (pMem->flags & MEM_Dyn)==0 ); + if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc); + memcpy(pMem, &t, sizeof(t)); rc = ctx.isError; } return rc; } /* -** If the memory cell contains a string value that must be freed by -** invoking an external callback, free it now. Calling this function -** does not free any Mem.zMalloc buffer. +** If the memory cell contains a value that must be freed by +** invoking the external callback in Mem.xDel, then this routine +** will free that value. It also sets Mem.flags to MEM_Null. +** +** This is a helper routine for sqlite3VdbeMemSetNull() and +** for sqlite3VdbeMemRelease(). Use those other routines as the +** entry point for releasing Mem resources. */ -SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p){ +static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); + assert( VdbeMemDynamic(p) ); if( p->flags&MEM_Agg ){ sqlite3VdbeMemFinalize(p, p->u.pDef); assert( (p->flags & MEM_Agg)==0 ); - sqlite3VdbeMemRelease(p); - }else if( p->flags&MEM_Dyn ){ + testcase( p->flags & MEM_Dyn ); + } + if( p->flags&MEM_Dyn ){ assert( (p->flags&MEM_RowSet)==0 ); assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); p->xDel((void *)p->z); - p->xDel = 0; }else if( p->flags&MEM_RowSet ){ sqlite3RowSetClear(p->u.pRowSet); }else if( p->flags&MEM_Frame ){ - sqlite3VdbeMemSetNull(p); + VdbeFrame *pFrame = p->u.pFrame; + pFrame->pParent = pFrame->v->pDelFrame; + pFrame->v->pDelFrame = pFrame; } + p->flags = MEM_Null; } /* -** Release any memory held by the Mem. This may leave the Mem in an -** inconsistent state, for example with (Mem.z==0) and -** (Mem.flags==MEM_Str). +** Release memory held by the Mem p, both external memory cleared +** by p->xDel and memory in p->zMalloc. +** +** This is a helper routine invoked by sqlite3VdbeMemRelease() in +** the unusual case where there really is memory in p that needs +** to be freed. +*/ +static SQLITE_NOINLINE void vdbeMemClear(Mem *p){ + if( VdbeMemDynamic(p) ){ + vdbeMemClearExternAndSetNull(p); + } + if( p->szMalloc ){ + sqlite3DbFree(p->db, p->zMalloc); + p->szMalloc = 0; + } + p->z = 0; +} + +/* +** Release any memory resources held by the Mem. Both the memory that is +** free by Mem.xDel and the Mem.zMalloc allocation are freed. +** +** Use this routine prior to clean up prior to abandoning a Mem, or to +** reset a Mem back to its minimum memory utilization. +** +** Use sqlite3VdbeMemSetNull() to release just the Mem.xDel space +** prior to inserting new content into the Mem. */ SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){ assert( sqlite3VdbeCheckMemInvariants(p) ); - VdbeMemRelease(p); - if( p->zMalloc ){ - sqlite3DbFree(p->db, p->zMalloc); - p->zMalloc = 0; + if( VdbeMemDynamic(p) || p->szMalloc ){ + vdbeMemClear(p); } - p->z = 0; - assert( p->xDel==0 ); /* Zeroed by VdbeMemRelease() above */ } /* @@ -61189,7 +62104,7 @@ static i64 doubleToInt64(double r){ ** If pMem is an integer, then the value is exact. If pMem is ** a floating-point then the value returned is the integer part. ** If pMem is a string or blob, then we make an attempt to convert -** it into a integer and return that. If pMem represents an +** it into an integer and return that. If pMem represents an ** an SQL-NULL value, return 0. ** ** If pMem represents a string value, its encoding might be changed. @@ -61202,11 +62117,10 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ if( flags & MEM_Int ){ return pMem->u.i; }else if( flags & MEM_Real ){ - return doubleToInt64(pMem->r); + return doubleToInt64(pMem->u.r); }else if( flags & (MEM_Str|MEM_Blob) ){ i64 value = 0; assert( pMem->z || pMem->n==0 ); - testcase( pMem->z==0 ); sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); return value; }else{ @@ -61224,7 +62138,7 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( pMem->flags & MEM_Real ){ - return pMem->r; + return pMem->u.r; }else if( pMem->flags & MEM_Int ){ return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ @@ -61243,12 +62157,13 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ ** MEM_Int if we can. */ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ + i64 ix; assert( pMem->flags & MEM_Real ); assert( (pMem->flags & MEM_RowSet)==0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); - pMem->u.i = doubleToInt64(pMem->r); + ix = doubleToInt64(pMem->u.r); /* Only mark the value as an integer if ** @@ -61260,11 +62175,9 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ ** the second condition under the assumption that addition overflow causes ** values to wrap around. */ - if( pMem->r==(double)pMem->u.i - && pMem->u.i>SMALLEST_INT64 - && pMem->u.iflags |= MEM_Int; + if( pMem->u.r==ix && ix>SMALLEST_INT64 && ixu.i = ix; + MemSetTypeFlag(pMem, MEM_Int); } } @@ -61289,7 +62202,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); - pMem->r = sqlite3VdbeRealValue(pMem); + pMem->u.r = sqlite3VdbeRealValue(pMem); MemSetTypeFlag(pMem, MEM_Real); return SQLITE_OK; } @@ -61309,7 +62222,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){ MemSetTypeFlag(pMem, MEM_Int); }else{ - pMem->r = sqlite3VdbeRealValue(pMem); + pMem->u.r = sqlite3VdbeRealValue(pMem); MemSetTypeFlag(pMem, MEM_Real); sqlite3VdbeIntegerAffinity(pMem); } @@ -61319,19 +62232,81 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ return SQLITE_OK; } +/* +** Cast the datatype of the value in pMem according to the affinity +** "aff". Casting is different from applying affinity in that a cast +** is forced. In other words, the value is converted into the desired +** affinity even if that results in loss of data. This routine is +** used (for example) to implement the SQL "cast()" operator. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ + if( pMem->flags & MEM_Null ) return; + switch( aff ){ + case SQLITE_AFF_NONE: { /* Really a cast to BLOB */ + if( (pMem->flags & MEM_Blob)==0 ){ + sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); + assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); + MemSetTypeFlag(pMem, MEM_Blob); + }else{ + pMem->flags &= ~(MEM_TypeMask&~MEM_Blob); + } + break; + } + case SQLITE_AFF_NUMERIC: { + sqlite3VdbeMemNumerify(pMem); + break; + } + case SQLITE_AFF_INTEGER: { + sqlite3VdbeMemIntegerify(pMem); + break; + } + case SQLITE_AFF_REAL: { + sqlite3VdbeMemRealify(pMem); + break; + } + default: { + assert( aff==SQLITE_AFF_TEXT ); + assert( MEM_Str==(MEM_Blob>>3) ); + pMem->flags |= (pMem->flags&MEM_Blob)>>3; + sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); + assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); + pMem->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero); + break; + } + } +} + +/* +** Initialize bulk memory to be a consistent Mem object. +** +** The minimum amount of initialization feasible is performed. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem *pMem, sqlite3 *db, u16 flags){ + assert( (flags & ~MEM_TypeMask)==0 ); + pMem->flags = flags; + pMem->db = db; + pMem->szMalloc = 0; +} + + /* ** Delete any previous value and set the value stored in *pMem to NULL. +** +** This routine calls the Mem.xDel destructor to dispose of values that +** require the destructor. But it preserves the Mem.zMalloc memory allocation. +** To free all resources, use sqlite3VdbeMemRelease(), which both calls this +** routine to invoke the destructor and deallocates Mem.zMalloc. +** +** Use this routine to reset the Mem prior to insert a new value. +** +** Use sqlite3VdbeMemRelease() to complete erase the Mem prior to abandoning it. */ SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){ - if( pMem->flags & MEM_Frame ){ - VdbeFrame *pFrame = pMem->u.pFrame; - pFrame->pParent = pFrame->v->pDelFrame; - pFrame->v->pDelFrame = pFrame; + if( VdbeMemDynamic(pMem) ){ + vdbeMemClearExternAndSetNull(pMem); + }else{ + pMem->flags = MEM_Null; } - if( pMem->flags & MEM_RowSet ){ - sqlite3RowSetClear(pMem->u.pRowSet); - } - MemSetTypeFlag(pMem, MEM_Null); } SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value *p){ sqlite3VdbeMemSetNull((Mem*)p); @@ -61348,14 +62323,18 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ if( n<0 ) n = 0; pMem->u.nZero = n; pMem->enc = SQLITE_UTF8; + pMem->z = 0; +} -#ifdef SQLITE_OMIT_INCRBLOB - sqlite3VdbeMemGrow(pMem, n, 0); - if( pMem->z ){ - pMem->n = n; - memset(pMem->z, 0, n); - } -#endif +/* +** The pMem is known to contain content that needs to be destroyed prior +** to a value change. So invoke the destructor, then set the value to +** a 64-bit integer. +*/ +static SQLITE_NOINLINE void vdbeReleaseAndSetInt64(Mem *pMem, i64 val){ + sqlite3VdbeMemSetNull(pMem); + pMem->u.i = val; + pMem->flags = MEM_Int; } /* @@ -61363,9 +62342,12 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ ** manifest type INTEGER. */ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ - sqlite3VdbeMemRelease(pMem); - pMem->u.i = val; - pMem->flags = MEM_Int; + if( VdbeMemDynamic(pMem) ){ + vdbeReleaseAndSetInt64(pMem, val); + }else{ + pMem->u.i = val; + pMem->flags = MEM_Int; + } } #ifndef SQLITE_OMIT_FLOATING_POINT @@ -61374,11 +62356,9 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ ** manifest type REAL. */ SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ - if( sqlite3IsNaN(val) ){ - sqlite3VdbeMemSetNull(pMem); - }else{ - sqlite3VdbeMemRelease(pMem); - pMem->r = val; + sqlite3VdbeMemSetNull(pMem); + if( !sqlite3IsNaN(val) ){ + pMem->u.r = val; pMem->flags = MEM_Real; } } @@ -61396,10 +62376,11 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){ pMem->zMalloc = sqlite3DbMallocRaw(db, 64); if( db->mallocFailed ){ pMem->flags = MEM_Null; + pMem->szMalloc = 0; }else{ assert( pMem->zMalloc ); - pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, - sqlite3DbMallocSize(db, pMem->zMalloc)); + pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc); + pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc); assert( pMem->u.pRowSet!=0 ); pMem->flags = MEM_RowSet; } @@ -61423,7 +62404,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){ #ifdef SQLITE_DEBUG /* -** This routine prepares a memory cell for modication by breaking +** This routine prepares a memory cell for modification by breaking ** its link to a shallow copy and by marking any current shallow ** copies of this cell as invalid. ** @@ -61456,9 +62437,9 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ */ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ assert( (pFrom->flags & MEM_RowSet)==0 ); - VdbeMemRelease(pTo); + assert( pTo->db==pFrom->db ); + if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); - pTo->xDel = 0; if( (pFrom->flags&MEM_Static)==0 ){ pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem); assert( srcType==MEM_Ephem || srcType==MEM_Static ); @@ -61473,12 +62454,11 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; + assert( pTo->db==pFrom->db ); assert( (pFrom->flags & MEM_RowSet)==0 ); - VdbeMemRelease(pTo); + if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; - pTo->xDel = 0; - if( pTo->flags&(MEM_Str|MEM_Blob) ){ if( 0==(pFrom->flags&MEM_Static) ){ pTo->flags |= MEM_Ephem; @@ -61503,8 +62483,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ sqlite3VdbeMemRelease(pTo); memcpy(pTo, pFrom, sizeof(Mem)); pFrom->flags = MEM_Null; - pFrom->xDel = 0; - pFrom->zMalloc = 0; + pFrom->szMalloc = 0; } /* @@ -61551,7 +62530,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( if( nByte<0 ){ assert( enc!=0 ); if( enc==SQLITE_UTF8 ){ - for(nByte=0; nByte<=iLimit && z[nByte]; nByte++){} + nByte = sqlite3Strlen30(z); + if( nByte>iLimit ) nByte = iLimit+1; }else{ for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} } @@ -61570,14 +62550,17 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( if( nByte>iLimit ){ return SQLITE_TOOBIG; } - if( sqlite3VdbeMemGrow(pMem, nAlloc, 0) ){ + testcase( nAlloc==0 ); + testcase( nAlloc==31 ); + testcase( nAlloc==32 ); + if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){ return SQLITE_NOMEM; } memcpy(pMem->z, z, nAlloc); }else if( xDel==SQLITE_DYNAMIC ){ sqlite3VdbeMemRelease(pMem); pMem->zMalloc = pMem->z = (char *)z; - pMem->xDel = 0; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); }else{ sqlite3VdbeMemRelease(pMem); pMem->z = (char *)z; @@ -61609,8 +62592,11 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( ** key is true to get the key or false to get data. The result is written ** into the pMem element. ** -** The pMem structure is assumed to be uninitialized. Any prior content -** is overwritten without being freed. +** The pMem object must have been initialized. This routine will use +** pMem->zMalloc to hold the content from the btree, if possible. New +** pMem->zMalloc space will be allocated if necessary. The calling routine +** is responsible for making sure that the pMem object is eventually +** destroyed. ** ** If this routine fails for any reason (malloc returns NULL or unable ** to read from the disk) then the pMem is left in an inconsistent state. @@ -61627,6 +62613,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( int rc = SQLITE_OK; /* Return code */ assert( sqlite3BtreeCursorIsValid(pCur) ); + assert( !VdbeMemDynamic(pMem) ); /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ @@ -61639,29 +62626,70 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( assert( zData!=0 ); if( offset+amt<=available ){ - sqlite3VdbeMemRelease(pMem); pMem->z = &zData[offset]; pMem->flags = MEM_Blob|MEM_Ephem; pMem->n = (int)amt; - }else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){ - if( key ){ - rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z); - }else{ - rc = sqlite3BtreeData(pCur, offset, amt, pMem->z); - } - if( rc==SQLITE_OK ){ - pMem->z[amt] = 0; - pMem->z[amt+1] = 0; - pMem->flags = MEM_Blob|MEM_Term; - pMem->n = (int)amt; - }else{ - sqlite3VdbeMemRelease(pMem); + }else{ + pMem->flags = MEM_Null; + if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){ + if( key ){ + rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z); + }else{ + rc = sqlite3BtreeData(pCur, offset, amt, pMem->z); + } + if( rc==SQLITE_OK ){ + pMem->z[amt] = 0; + pMem->z[amt+1] = 0; + pMem->flags = MEM_Blob|MEM_Term; + pMem->n = (int)amt; + }else{ + sqlite3VdbeMemRelease(pMem); + } } } return rc; } +/* +** The pVal argument is known to be a value other than NULL. +** Convert it into a string with encoding enc and return a pointer +** to a zero-terminated version of that string. +*/ +static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ + assert( pVal!=0 ); + assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); + assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); + assert( (pVal->flags & MEM_RowSet)==0 ); + assert( (pVal->flags & (MEM_Null))==0 ); + if( pVal->flags & (MEM_Blob|MEM_Str) ){ + pVal->flags |= MEM_Str; + if( pVal->flags & MEM_Zero ){ + sqlite3VdbeMemExpandBlob(pVal); + } + if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){ + sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); + } + if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&SQLITE_PTR_TO_INT(pVal->z)) ){ + assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 ); + if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){ + return 0; + } + } + sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-31275-44060 */ + }else{ + sqlite3VdbeMemStringify(pVal, enc, 0); + assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) ); + } + assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 + || pVal->db->mallocFailed ); + if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ + return pVal->z; + }else{ + return 0; + } +} + /* This function is only available internally, it is not part of the ** external API. It works in a similar way to sqlite3_value_text(), ** except the data returned is in the encoding specified by the second @@ -61674,38 +62702,16 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( */ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ if( !pVal ) return 0; - assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( (pVal->flags & MEM_RowSet)==0 ); - + if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ + return pVal->z; + } if( pVal->flags&MEM_Null ){ return 0; } - assert( (MEM_Blob>>3) == MEM_Str ); - pVal->flags |= (pVal->flags & MEM_Blob)>>3; - ExpandBlob(pVal); - if( pVal->flags&MEM_Str ){ - sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); - if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&SQLITE_PTR_TO_INT(pVal->z)) ){ - assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 ); - if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){ - return 0; - } - } - sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-31275-44060 */ - }else{ - assert( (pVal->flags&MEM_Blob)==0 ); - sqlite3VdbeMemStringify(pVal, enc); - assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) ); - } - assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 - || pVal->db->mallocFailed ); - if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ - return pVal->z; - }else{ - return 0; - } + return valueToText(pVal, enc); } /* @@ -61812,9 +62818,20 @@ static int valueFromExpr( *ppVal = 0; return SQLITE_OK; } - op = pExpr->op; + while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft; if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; + if( op==TK_CAST ){ + u8 aff = sqlite3AffinityType(pExpr->u.zToken,0); + rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); + testcase( rc!=SQLITE_OK ); + if( *ppVal ){ + sqlite3VdbeMemCast(*ppVal, aff, SQLITE_UTF8); + sqlite3ValueApplyAffinity(*ppVal, affinity, SQLITE_UTF8); + } + return rc; + } + /* Handle negative integers in a single step. This is needed in the ** case when the value is -9223372036854775808. */ @@ -61851,14 +62868,14 @@ static int valueFromExpr( && pVal!=0 ){ sqlite3VdbeMemNumerify(pVal); - if( pVal->u.i==SMALLEST_INT64 ){ - pVal->flags &= ~MEM_Int; - pVal->flags |= MEM_Real; - pVal->r = (double)SMALLEST_INT64; + if( pVal->flags & MEM_Real ){ + pVal->u.r = -pVal->u.r; + }else if( pVal->u.i==SMALLEST_INT64 ){ + pVal->u.r = -(double)SMALLEST_INT64; + MemSetTypeFlag(pVal, MEM_Real); }else{ pVal->u.i = -pVal->u.i; } - pVal->r = -pVal->r; sqlite3ValueApplyAffinity(pVal, affinity, enc); } }else if( op==TK_NULL ){ @@ -61949,7 +62966,7 @@ static void recordFunc( sqlite3_result_error_nomem(context); }else{ aRet[0] = nSerial+1; - sqlite3PutVarint(&aRet[1], iSerial); + putVarint32(&aRet[1], iSerial); sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial); sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT); sqlite3DbFree(db, aRet); @@ -62166,7 +63183,7 @@ SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){ Mem *aMem = pRec->aMem; sqlite3 *db = aMem[0].db; for(i=0; ipKeyInfo); sqlite3DbFree(db, pRec); @@ -62226,9 +63243,7 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ ** ************************************************************************* ** This file contains code used for creating, destroying, and populating -** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior -** to version 2.8.7, all this code was combined into the vdbe.c source file. -** But that file was getting too big so this subroutines were split out. +** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) */ /* @@ -62912,7 +63927,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ sqlite3ValueFree((sqlite3_value*)p4); }else{ Mem *p = (Mem*)p4; - sqlite3DbFree(db, p->zMalloc); + if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); sqlite3DbFree(db, p); } break; @@ -62968,7 +63983,8 @@ SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ } /* -** Remove the last opcode inserted +** If the last opcode is "op" and it is not a jump destination, +** then remove it. Return true if and only if an opcode was removed. */ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){ @@ -63109,7 +64125,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){ ** routine, then a pointer to a dummy VdbeOp will be returned. That opcode ** is readable but not writable, though it is cast to a writable value. ** The return of a dummy opcode allows the call to continue functioning -** after a OOM fault without having to check to see if the return from +** after an OOM fault without having to check to see if the return from ** this routine is a valid pointer. But because the dummy.opcode is 0, ** dummy will never be written to. This is verified by code inspection and ** by running with Valgrind. @@ -63290,7 +64306,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ }else if( pMem->flags & MEM_Int ){ sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ - sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r); + sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->u.r); }else if( pMem->flags & MEM_Null ){ sqlite3_snprintf(nTemp, zTemp, "NULL"); }else{ @@ -63440,16 +64456,16 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ */ static void releaseMemArray(Mem *p, int N){ if( p && N ){ - Mem *pEnd; + Mem *pEnd = &p[N]; sqlite3 *db = p->db; u8 malloc_failed = db->mallocFailed; if( db->pnBytesFreed ){ - for(pEnd=&p[N]; pzMalloc); - } + do{ + if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); + }while( (++p)flags & MEM_RowSet ); if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){ sqlite3VdbeMemRelease(p); - }else if( p->zMalloc ){ + }else if( p->szMalloc ){ sqlite3DbFree(db, p->zMalloc); - p->zMalloc = 0; + p->szMalloc = 0; } p->flags = MEM_Undefined; - } + }while( (++p)mallocFailed = malloc_failed; } } @@ -63640,7 +64656,7 @@ SQLITE_PRIVATE int sqlite3VdbeList( pMem->u.i = pOp->p3; /* P3 */ pMem++; - if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */ + if( sqlite3VdbeMemClearAndResize(pMem, 32) ){ /* P4 */ assert( p->db->mallocFailed ); return SQLITE_ERROR; } @@ -63656,7 +64672,7 @@ SQLITE_PRIVATE int sqlite3VdbeList( pMem++; if( p->explain==1 ){ - if( sqlite3VdbeMemGrow(pMem, 4, 0) ){ + if( sqlite3VdbeMemClearAndResize(pMem, 4) ){ assert( p->db->mallocFailed ); return SQLITE_ERROR; } @@ -63667,7 +64683,7 @@ SQLITE_PRIVATE int sqlite3VdbeList( pMem++; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS - if( sqlite3VdbeMemGrow(pMem, 500, 0) ){ + if( sqlite3VdbeMemClearAndResize(pMem, 500) ){ assert( p->db->mallocFailed ); return SQLITE_ERROR; } @@ -63820,13 +64836,13 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){ /* ** Prepare a virtual machine for execution for the first time after ** creating the virtual machine. This involves things such -** as allocating stack space and initializing the program counter. +** as allocating registers and initializing the program counter. ** After the VDBE has be prepped, it can be executed by one or more ** calls to sqlite3VdbeExec(). ** -** This function may be called exact once on a each virtual machine. +** This function may be called exactly once on each virtual machine. ** After this routine is called the VM has been "packaged" and is ready -** to run. After this routine is called, futher calls to +** to run. After this routine is called, further calls to ** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects ** the Vdbe from the Parse object that helped generate it so that the ** the Vdbe becomes an independent entity and the Parse object can be @@ -63960,7 +64976,7 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ sqlite3BtreeCloseCursor(pCx->pCursor); } #ifndef SQLITE_OMIT_VIRTUALTABLE - if( pCx->pVtabCursor ){ + else if( pCx->pVtabCursor ){ sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor; const sqlite3_module *pModule = pVtabCursor->pVtab->pModule; p->inVtabMethod = 1; @@ -64003,9 +65019,10 @@ static void closeAllCursors(Vdbe *p){ VdbeFrame *pFrame; for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); sqlite3VdbeFrameRestore(pFrame); + p->pFrame = 0; + p->nFrame = 0; } - p->pFrame = 0; - p->nFrame = 0; + assert( p->nFrame==0 ); if( p->apCsr ){ int i; @@ -64027,16 +65044,12 @@ static void closeAllCursors(Vdbe *p){ } /* Delete any auxdata allocations made by the VM */ - sqlite3VdbeDeleteAuxData(p, -1, 0); + if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0); assert( p->pAuxData==0 ); } /* -** Clean up the VM after execution. -** -** This routine will automatically close any cursors, lists, and/or -** sorters that were left open. It also deletes the values of -** variables in the aVar[] array. +** Clean up the VM after a single run. */ static void Cleanup(Vdbe *p){ sqlite3 *db = p->db; @@ -64204,7 +65217,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ /* The complex case - There is a multi-file write-transaction active. ** This requires a master journal file to ensure the transaction is - ** committed atomicly. + ** committed atomically. */ #ifndef SQLITE_OMIT_DISKIO else{ @@ -64711,7 +65724,7 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){ db->mallocFailed = mallocFailed; db->errCode = rc; }else{ - sqlite3Error(db, rc, 0); + sqlite3Error(db, rc); } return rc; } @@ -64774,7 +65787,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ ** to sqlite3_step(). For consistency (since sqlite3_step() was ** called), set the database error in this case as well. */ - sqlite3Error(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); + sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } @@ -64852,7 +65865,7 @@ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){ ** from left to right), or ** ** * the corresponding bit in argument mask is clear (where the first -** function parameter corrsponds to bit 0 etc.). +** function parameter corresponds to bit 0 etc.). */ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){ AuxData **pp = &pVdbe->pAuxData; @@ -64897,10 +65910,6 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - sqlite3DbFree(db, p->zExplain); - sqlite3DbFree(db, p->pExplain); -#endif } /* @@ -64927,6 +65936,57 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){ sqlite3DbFree(db, p); } +/* +** The cursor "p" has a pending seek operation that has not yet been +** carried out. Seek the cursor now. If an error occurs, return +** the appropriate error code. +*/ +static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){ + int res, rc; +#ifdef SQLITE_TEST + extern int sqlite3_search_count; +#endif + assert( p->deferredMoveto ); + assert( p->isTable ); + rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res); + if( rc ) return rc; + if( res!=0 ) return SQLITE_CORRUPT_BKPT; +#ifdef SQLITE_TEST + sqlite3_search_count++; +#endif + p->deferredMoveto = 0; + p->cacheStatus = CACHE_STALE; + return SQLITE_OK; +} + +/* +** Something has moved cursor "p" out of place. Maybe the row it was +** pointed to was deleted out from under it. Or maybe the btree was +** rebalanced. Whatever the cause, try to restore "p" to the place it +** is supposed to be pointing. If the row was deleted out from under the +** cursor, set the cursor to point to a NULL row. +*/ +static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){ + int isDifferentRow, rc; + assert( p->pCursor!=0 ); + assert( sqlite3BtreeCursorHasMoved(p->pCursor) ); + rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow); + p->cacheStatus = CACHE_STALE; + if( isDifferentRow ) p->nullRow = 1; + return rc; +} + +/* +** Check to ensure that the cursor is valid. Restore the cursor +** if need be. Return any I/O error from the restore operation. +*/ +SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){ + if( sqlite3BtreeCursorHasMoved(p->pCursor) ){ + return handleMovedCursor(p); + } + return SQLITE_OK; +} + /* ** Make sure the cursor p is ready to read or write the row to which it ** was last positioned. Return an error code if an OOM fault or I/O error @@ -64942,29 +66002,10 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){ */ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){ if( p->deferredMoveto ){ - int res, rc; -#ifdef SQLITE_TEST - extern int sqlite3_search_count; -#endif - assert( p->isTable ); - rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res); - if( rc ) return rc; - p->lastRowid = p->movetoTarget; - if( res!=0 ) return SQLITE_CORRUPT_BKPT; - p->rowidIsValid = 1; -#ifdef SQLITE_TEST - sqlite3_search_count++; -#endif - p->deferredMoveto = 0; - p->cacheStatus = CACHE_STALE; - }else if( p->pCursor ){ - int hasMoved; - int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved); - if( rc ) return rc; - if( hasMoved ){ - p->cacheStatus = CACHE_STALE; - if( hasMoved==2 ) p->nullRow = 1; - } + return handleDeferredMoveto(p); + } + if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){ + return handleMovedCursor(p); } return SQLITE_OK; } @@ -65140,17 +66181,18 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ u64 v; u32 i; if( serial_type==7 ){ - assert( sizeof(v)==sizeof(pMem->r) ); - memcpy(&v, &pMem->r, sizeof(v)); + assert( sizeof(v)==sizeof(pMem->u.r) ); + memcpy(&v, &pMem->u.r, sizeof(v)); swapMixedEndianFloat(v); }else{ v = pMem->u.i; } len = i = sqlite3VdbeSerialTypeLen(serial_type); - while( i-- ){ - buf[i] = (u8)(v&0xFF); + assert( i>0 ); + do{ + buf[--i] = (u8)(v&0xFF); v >>= 8; - } + }while( i ); return len; } @@ -65174,18 +66216,54 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ #define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1]) #define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2]) #define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) +#define FOUR_BYTE_INT(x) (16777216*(i8)((x)[0])|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) /* ** Deserialize the data blob pointed to by buf as serial type serial_type ** and store the result in pMem. Return the number of bytes read. +** +** This function is implemented as two separate routines for performance. +** The few cases that require local variables are broken out into a separate +** routine so that in most cases the overhead of moving the stack pointer +** is avoided. */ +static u32 SQLITE_NOINLINE serialGet( + const unsigned char *buf, /* Buffer to deserialize from */ + u32 serial_type, /* Serial type to deserialize */ + Mem *pMem /* Memory cell to write value into */ +){ + u64 x = FOUR_BYTE_UINT(buf); + u32 y = FOUR_BYTE_UINT(buf+4); + x = (x<<32) + y; + if( serial_type==6 ){ + pMem->u.i = *(i64*)&x; + pMem->flags = MEM_Int; + testcase( pMem->u.i<0 ); + }else{ +#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT) + /* Verify that integers and floating point values use the same + ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is + ** defined that 64-bit floating point values really are mixed + ** endian. + */ + static const u64 t1 = ((u64)0x3ff00000)<<32; + static const double r1 = 1.0; + u64 t2 = t1; + swapMixedEndianFloat(t2); + assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); +#endif + assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); + swapMixedEndianFloat(x); + memcpy(&pMem->u.r, &x, sizeof(x)); + pMem->flags = sqlite3IsNaN(pMem->u.r) ? MEM_Null : MEM_Real; + } + return 8; +} SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ ){ - u64 x; - u32 y; switch( serial_type ){ case 10: /* Reserved for future use */ case 11: /* Reserved for future use */ @@ -65212,8 +66290,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( return 3; } case 4: { /* 4-byte signed integer */ - y = FOUR_BYTE_UINT(buf); - pMem->u.i = (i64)*(int*)&y; + pMem->u.i = FOUR_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return 4; @@ -65226,32 +66303,9 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( } case 6: /* 8-byte signed integer */ case 7: { /* IEEE floating point */ -#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT) - /* Verify that integers and floating point values use the same - ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is - ** defined that 64-bit floating point values really are mixed - ** endian. - */ - static const u64 t1 = ((u64)0x3ff00000)<<32; - static const double r1 = 1.0; - u64 t2 = t1; - swapMixedEndianFloat(t2); - assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); -#endif - x = FOUR_BYTE_UINT(buf); - y = FOUR_BYTE_UINT(buf+4); - x = (x<<32) | y; - if( serial_type==6 ){ - pMem->u.i = *(i64*)&x; - pMem->flags = MEM_Int; - testcase( pMem->u.i<0 ); - }else{ - assert( sizeof(x)==8 && sizeof(pMem->r)==8 ); - swapMixedEndianFloat(x); - memcpy(&pMem->r, &x, sizeof(x)); - pMem->flags = sqlite3IsNaN(pMem->r) ? MEM_Null : MEM_Real; - } - return 8; + /* These use local variables, so do them in a separate routine + ** to avoid having to move the frame pointer in the common case */ + return serialGet(buf,serial_type,pMem); } case 8: /* Integer 0 */ case 9: { /* Integer 1 */ @@ -65261,17 +66315,14 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( } default: { static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem }; - u32 len = (serial_type-12)/2; pMem->z = (char *)buf; - pMem->n = len; - pMem->xDel = 0; + pMem->n = (serial_type-12)/2; pMem->flags = aFlag[serial_type&1]; - return len; + return pMem->n; } } return 0; } - /* ** This routine is used to allocate sufficient space for an UnpackedRecord ** structure large enough to be used with sqlite3VdbeRecordUnpack() if @@ -65341,17 +66392,17 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( idx = getVarint32(aKey, szHdr); d = szHdr; u = 0; - while( idxnField && d<=nKey ){ + while( idxenc = pKeyInfo->enc; pMem->db = pKeyInfo->db; /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */ - pMem->zMalloc = 0; + pMem->szMalloc = 0; d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); pMem++; - u++; + if( (++u)>=p->nField ) break; } assert( u<=pKeyInfo->nField + 1 ); p->nField = u; @@ -65365,10 +66416,14 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( ** sqlite3VdbeSerialGet() and sqlite3MemCompare() functions. It is used ** in assert() statements to ensure that the optimized code in ** sqlite3VdbeRecordCompare() returns results with these two primitives. +** +** Return true if the result of comparison is equivalent to desiredResult. +** Return false if there is a disagreement. */ static int vdbeRecordCompareDebug( int nKey1, const void *pKey1, /* Left key */ - const UnpackedRecord *pPKey2 /* Right key */ + const UnpackedRecord *pPKey2, /* Right key */ + int desiredResult /* Correct answer */ ){ u32 d1; /* Offset into aKey[] of next data element */ u32 idx1; /* Offset into aKey[] of next header element */ @@ -65380,10 +66435,11 @@ static int vdbeRecordCompareDebug( Mem mem1; pKeyInfo = pPKey2->pKeyInfo; + if( pKeyInfo->db==0 ) return 1; mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; /* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */ - VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ + VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ /* Compilers may complain that mem1.u.i is potentially uninitialized. ** We could initialize it, as shown here, to silence those complaints. @@ -65426,11 +66482,11 @@ static int vdbeRecordCompareDebug( */ rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]); if( rc!=0 ){ - assert( mem1.zMalloc==0 ); /* See comment below */ + assert( mem1.szMalloc==0 ); /* See comment below */ if( pKeyInfo->aSortOrder[i] ){ rc = -rc; /* Invert the result for DESC sort order. */ } - return rc; + goto debugCompareEnd; } i++; }while( idx1nField ); @@ -65439,12 +66495,20 @@ static int vdbeRecordCompareDebug( ** the following assert(). If the assert() fails, it indicates a ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ - assert( mem1.zMalloc==0 ); + assert( mem1.szMalloc==0 ); /* rc==0 here means that one of the keys ran out of fields and - ** all the fields up to that point were equal. Return the the default_rc + ** all the fields up to that point were equal. Return the default_rc ** value. */ - return pPKey2->default_rc; + rc = pPKey2->default_rc; + +debugCompareEnd: + if( desiredResult==0 && rc==0 ) return 1; + if( desiredResult<0 && rc<0 ) return 1; + if( desiredResult>0 && rc>0 ) return 1; + if( CORRUPT_DB ) return 1; + if( pKeyInfo->db->mallocFailed ) return 1; + return 0; } #endif @@ -65457,7 +66521,8 @@ static int vdbeRecordCompareDebug( static int vdbeCompareMemString( const Mem *pMem1, const Mem *pMem2, - const CollSeq *pColl + const CollSeq *pColl, + u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */ ){ if( pMem1->enc==pColl->enc ){ /* The strings are already in the correct encoding. Call the @@ -65469,8 +66534,8 @@ static int vdbeCompareMemString( int n1, n2; Mem c1; Mem c2; - memset(&c1, 0, sizeof(c1)); - memset(&c2, 0, sizeof(c2)); + sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null); + sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null); sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); @@ -65480,10 +66545,23 @@ static int vdbeCompareMemString( rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); sqlite3VdbeMemRelease(&c1); sqlite3VdbeMemRelease(&c2); + if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM; return rc; } } +/* +** Compare two blobs. Return negative, zero, or positive if the first +** is less than, equal to, or greater than the second, respectively. +** If one blob is a prefix of the other, then the shorter is the lessor. +*/ +static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){ + int c = memcmp(pB1->z, pB2->z, pB1->n>pB2->n ? pB2->n : pB1->n); + if( c ) return c; + return pB1->n - pB2->n; +} + + /* ** Compare the values contained by the two memory cells, returning ** negative, zero or positive if pMem1 is less than, equal to, or greater @@ -65494,7 +66572,6 @@ static int vdbeCompareMemString( ** Two NULL values are considered equal by this function. */ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ - int rc; int f1, f2; int combined_flags; @@ -65522,14 +66599,14 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C return 0; } if( (f1&MEM_Real)!=0 ){ - r1 = pMem1->r; + r1 = pMem1->u.r; }else if( (f1&MEM_Int)!=0 ){ r1 = (double)pMem1->u.i; }else{ return 1; } if( (f2&MEM_Real)!=0 ){ - r2 = pMem2->r; + r2 = pMem2->u.r; }else if( (f2&MEM_Int)!=0 ){ r2 = (double)pMem2->u.i; }else{ @@ -65562,18 +66639,14 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C assert( !pColl || pColl->xCmp ); if( pColl ){ - return vdbeCompareMemString(pMem1, pMem2, pColl); + return vdbeCompareMemString(pMem1, pMem2, pColl, 0); } /* If a NULL pointer was passed as the collate function, fall through ** to the blob case and use memcmp(). */ } /* Both values must be blobs. Compare using memcmp(). */ - rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n); - if( rc==0 ){ - rc = pMem1->n - pMem2->n; - } - return rc; + return sqlite3BlobCompare(pMem1, pMem2); } @@ -65623,7 +66696,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ ** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero ** or positive integer if key1 is less than, equal to or ** greater than key2. The {nKey1, pKey1} key must be a blob -** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 +** created by the OP_MakeRecord opcode of the VDBE. The pPKey2 ** key must be a parsed key such as obtained from ** sqlite3VdbeParseRecord. ** @@ -65634,10 +66707,12 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ ** fields that appear in both keys are equal, then pPKey2->default_rc is ** returned. ** -** If database corruption is discovered, set pPKey2->isCorrupt to non-zero -** and return 0. +** If database corruption is discovered, set pPKey2->errCode to +** SQLITE_CORRUPT and return 0. If an OOM error is encountered, +** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the +** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db). */ -SQLITE_PRIVATE int sqlite3VdbeRecordCompare( +static int vdbeRecordCompareWithSkip( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2, /* Right key */ int bSkip /* If true, skip the first field */ @@ -65666,13 +66741,13 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; if( d1>(unsigned)nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ } i = 0; } - VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ + VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB ); assert( pPKey2->pKeyInfo->aSortOrder!=0 ); @@ -65692,9 +66767,9 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( }else if( serial_type==7 ){ double rhs = (double)pRhs->u.i; sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); - if( mem1.rrhs ){ + }else if( mem1.u.r>rhs ){ rc = +1; } }else{ @@ -65716,11 +66791,11 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( }else if( serial_type==0 ){ rc = -1; }else{ - double rhs = pRhs->r; + double rhs = pRhs->u.r; double lhs; sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); if( serial_type==7 ){ - lhs = mem1.r; + lhs = mem1.u.r; }else{ lhs = (double)mem1.u.i; } @@ -65745,14 +66820,16 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( testcase( (d1+mem1.n)==(unsigned)nKey1 ); testcase( (d1+mem1.n+1)==(unsigned)nKey1 ); if( (d1+mem1.n) > (unsigned)nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ }else if( pKeyInfo->aColl[i] ){ mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; mem1.flags = MEM_Str; mem1.z = (char*)&aKey1[d1]; - rc = vdbeCompareMemString(&mem1, pRhs, pKeyInfo->aColl[i]); + rc = vdbeCompareMemString( + &mem1, pRhs, pKeyInfo->aColl[i], &pPKey2->errCode + ); }else{ int nCmp = MIN(mem1.n, pRhs->n); rc = memcmp(&aKey1[d1], pRhs->z, nCmp); @@ -65772,7 +66849,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( testcase( (d1+nStr)==(unsigned)nKey1 ); testcase( (d1+nStr+1)==(unsigned)nKey1 ); if( (d1+nStr) > (unsigned)nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ }else{ int nCmp = MIN(nStr, pRhs->n); @@ -65792,12 +66869,8 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( if( pKeyInfo->aSortOrder[i] ){ rc = -rc; } - assert( CORRUPT_DB - || (rc<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) - || (rc>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) - || pKeyInfo->db->mallocFailed - ); - assert( mem1.zMalloc==0 ); /* See comment below */ + assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) ); + assert( mem1.szMalloc==0 ); /* See comment below */ return rc; } @@ -65810,17 +66883,24 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( /* No memory allocation is ever used on mem1. Prove this using ** the following assert(). If the assert() fails, it indicates a ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ - assert( mem1.zMalloc==0 ); + assert( mem1.szMalloc==0 ); /* rc==0 here means that one or both of the keys ran out of fields and - ** all the fields up to that point were equal. Return the the default_rc + ** all the fields up to that point were equal. Return the default_rc ** value. */ assert( CORRUPT_DB - || pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2) + || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) || pKeyInfo->db->mallocFailed ); return pPKey2->default_rc; } +SQLITE_PRIVATE int sqlite3VdbeRecordCompare( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *pPKey2 /* Right key */ +){ + return vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0); +} + /* ** This function is an optimized version of sqlite3VdbeRecordCompare() @@ -65833,8 +66913,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( */ static int vdbeRecordCompareInt( int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2, /* Right key */ - int bSkip /* Ignored */ + UnpackedRecord *pPKey2 /* Right key */ ){ const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F]; int serial_type = ((const u8*)pKey1)[1]; @@ -65843,9 +66922,7 @@ static int vdbeRecordCompareInt( u64 x; i64 v = pPKey2->aMem[0].u.i; i64 lhs; - UNUSED_PARAMETER(bSkip); - assert( bSkip==0 ); assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB ); switch( serial_type ){ case 1: { /* 1-byte signed integer */ @@ -65895,10 +66972,10 @@ static int vdbeRecordCompareInt( ** (as gcc is clever enough to combine the two like cases). Other ** compilers might be similar. */ case 0: case 7: - return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0); + return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); default: - return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0); + return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); } if( v>lhs ){ @@ -65908,18 +66985,14 @@ static int vdbeRecordCompareInt( }else if( pPKey2->nField>1 ){ /* The first fields of the two keys are equal. Compare the trailing ** fields. */ - res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1); + res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); }else{ /* The first fields of the two keys are equal and there are no trailing ** fields. Return pPKey2->default_rc in this case. */ res = pPKey2->default_rc; } - assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0) - || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) - || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) - || CORRUPT_DB - ); + assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) ); return res; } @@ -65931,17 +67004,13 @@ static int vdbeRecordCompareInt( */ static int vdbeRecordCompareString( int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2, /* Right key */ - int bSkip + UnpackedRecord *pPKey2 /* Right key */ ){ const u8 *aKey1 = (const u8*)pKey1; int serial_type; int res; - UNUSED_PARAMETER(bSkip); - assert( bSkip==0 ); getVarint32(&aKey1[1], serial_type); - if( serial_type<12 ){ res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */ }else if( !(serial_type & 0x01) ){ @@ -65953,7 +67022,7 @@ static int vdbeRecordCompareString( nStr = (serial_type-12) / 2; if( (szHdr + nStr) > nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ } nCmp = MIN( pPKey2->aMem[0].n, nStr ); @@ -65963,7 +67032,7 @@ static int vdbeRecordCompareString( res = nStr - pPKey2->aMem[0].n; if( res==0 ){ if( pPKey2->nField>1 ){ - res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1); + res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); }else{ res = pPKey2->default_rc; } @@ -65979,9 +67048,7 @@ static int vdbeRecordCompareString( } } - assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0) - || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) - || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) + assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) || CORRUPT_DB || pPKey2->pKeyInfo->db->mallocFailed ); @@ -66047,8 +67114,6 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ u32 lenRowid; /* Size of the rowid */ Mem m, v; - UNUSED_PARAMETER(db); - /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so @@ -66060,7 +67125,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); /* Read in the complete content of the index entry */ - memset(&m, 0, sizeof(m)); + sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m); if( rc ){ return rc; @@ -66103,7 +67168,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ /* Jump here if database corruption is detected after m has been ** allocated. Free the m object and return SQLITE_CORRUPT. */ idx_rowid_corruption: - testcase( m.zMalloc!=0 ); + testcase( m.szMalloc!=0 ); sqlite3VdbeMemRelease(&m); return SQLITE_CORRUPT_BKPT; } @@ -66120,6 +67185,7 @@ idx_rowid_corruption: ** of the keys prior to the final rowid, not the entire key. */ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare( + sqlite3 *db, /* Database connection */ VdbeCursor *pC, /* The cursor to compare against */ UnpackedRecord *pUnpacked, /* Unpacked version of key */ int *res /* Write the comparison result here */ @@ -66138,12 +67204,12 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare( *res = 0; return SQLITE_CORRUPT_BKPT; } - memset(&m, 0, sizeof(m)); + sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m); if( rc ){ return rc; } - *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked, 0); + *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked); sqlite3VdbeMemRelease(&m); return SQLITE_OK; } @@ -66457,9 +67523,12 @@ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ ** The following routines are used by user-defined functions to specify ** the function result. ** -** The setStrOrError() funtion calls sqlite3VdbeMemSetStr() to store the +** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the ** result as a string or blob but if the string or blob is too large, it ** then sets the error code to SQLITE_TOOBIG +** +** The invokeValueDestructor(P,X) routine invokes destructor function X() +** on value P is not going to be used and need to be destroyed. */ static void setResultStrOrError( sqlite3_context *pCtx, /* Function context */ @@ -66468,10 +67537,26 @@ static void setResultStrOrError( u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ - if( sqlite3VdbeMemSetStr(&pCtx->s, z, n, enc, xDel)==SQLITE_TOOBIG ){ + if( sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel)==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(pCtx); } } +static int invokeValueDestructor( + const void *p, /* Value to destroy */ + void (*xDel)(void*), /* The destructor */ + sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */ +){ + assert( xDel!=SQLITE_DYNAMIC ); + if( xDel==0 ){ + /* noop */ + }else if( xDel==SQLITE_TRANSIENT ){ + /* noop */ + }else{ + xDel((void*)p); + } + if( pCtx ) sqlite3_result_error_toobig(pCtx); + return SQLITE_TOOBIG; +} SQLITE_API void sqlite3_result_blob( sqlite3_context *pCtx, const void *z, @@ -66479,38 +67564,52 @@ SQLITE_API void sqlite3_result_blob( void (*xDel)(void *) ){ assert( n>=0 ); - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, 0, xDel); } +SQLITE_API void sqlite3_result_blob64( + sqlite3_context *pCtx, + const void *z, + sqlite3_uint64 n, + void (*xDel)(void *) +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + assert( xDel!=SQLITE_DYNAMIC ); + if( n>0x7fffffff ){ + (void)invokeValueDestructor(z, xDel, pCtx); + }else{ + setResultStrOrError(pCtx, z, (int)n, 0, xDel); + } +} SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetDouble(&pCtx->s, rVal); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetDouble(pCtx->pOut, rVal); } SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; pCtx->fErrorOrAux = 1; - sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); + sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; pCtx->fErrorOrAux = 1; - sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); + sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); } #endif SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal); } SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetInt64(&pCtx->s, iVal); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetInt64(pCtx->pOut, iVal); } SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetNull(&pCtx->s); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetNull(pCtx->pOut); } SQLITE_API void sqlite3_result_text( sqlite3_context *pCtx, @@ -66518,9 +67617,25 @@ SQLITE_API void sqlite3_result_text( int n, void (*xDel)(void *) ){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel); } +SQLITE_API void sqlite3_result_text64( + sqlite3_context *pCtx, + const char *z, + sqlite3_uint64 n, + void (*xDel)(void *), + unsigned char enc +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + assert( xDel!=SQLITE_DYNAMIC ); + if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; + if( n>0x7fffffff ){ + (void)invokeValueDestructor(z, xDel, pCtx); + }else{ + setResultStrOrError(pCtx, z, (int)n, enc, xDel); + } +} #ifndef SQLITE_OMIT_UTF16 SQLITE_API void sqlite3_result_text16( sqlite3_context *pCtx, @@ -66528,7 +67643,7 @@ SQLITE_API void sqlite3_result_text16( int n, void (*xDel)(void *) ){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel); } SQLITE_API void sqlite3_result_text16be( @@ -66537,7 +67652,7 @@ SQLITE_API void sqlite3_result_text16be( int n, void (*xDel)(void *) ){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel); } SQLITE_API void sqlite3_result_text16le( @@ -66546,43 +67661,43 @@ SQLITE_API void sqlite3_result_text16le( int n, void (*xDel)(void *) ){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel); } #endif /* SQLITE_OMIT_UTF16 */ SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemCopy(&pCtx->s, pValue); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemCopy(pCtx->pOut, pValue); } SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetZeroBlob(&pCtx->s, n); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n); } SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ pCtx->isError = errCode; pCtx->fErrorOrAux = 1; - if( pCtx->s.flags & MEM_Null ){ - sqlite3VdbeMemSetStr(&pCtx->s, sqlite3ErrStr(errCode), -1, + if( pCtx->pOut->flags & MEM_Null ){ + sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, SQLITE_UTF8, SQLITE_STATIC); } } /* Force an SQLITE_TOOBIG error. */ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_TOOBIG; pCtx->fErrorOrAux = 1; - sqlite3VdbeMemSetStr(&pCtx->s, "string or blob too big", -1, + sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, SQLITE_UTF8, SQLITE_STATIC); } /* An SQLITE_NOMEM error. */ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetNull(&pCtx->s); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetNull(pCtx->pOut); pCtx->isError = SQLITE_NOMEM; pCtx->fErrorOrAux = 1; - pCtx->s.db->mallocFailed = 1; + pCtx->pOut->db->mallocFailed = 1; } /* @@ -66758,10 +67873,12 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ sqlite3_mutex_enter(db->mutex); v->doingRerun = 0; while( (rc = sqlite3Step(v))==SQLITE_SCHEMA - && cnt++ < SQLITE_MAX_SCHEMA_RETRY - && (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){ + && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ + int savedPc = v->pc; + rc2 = rc = sqlite3Reprepare(v); + if( rc!=SQLITE_OK) break; sqlite3_reset(pStmt); - v->doingRerun = 1; + if( savedPc>=0 ) v->doingRerun = 1; assert( v->expired==0 ); } if( rc2!=SQLITE_OK ){ @@ -66811,7 +67928,7 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ */ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ assert( p && p->pFunc ); - return p->s.db; + return p->pOut->db; } /* @@ -66821,7 +67938,7 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ Vdbe *v = p->pVdbe; int rc; if( v->iCurrentTime==0 ){ - rc = sqlite3OsCurrentTimeInt64(p->s.db->pVfs, &v->iCurrentTime); + rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, &v->iCurrentTime); if( rc ) v->iCurrentTime = 0; } return v->iCurrentTime; @@ -66850,41 +67967,50 @@ SQLITE_PRIVATE void sqlite3InvalidFunction( } /* -** Allocate or return the aggregate context for a user function. A new -** context is allocated on the first call. Subsequent calls return the -** same context that was returned on prior calls. +** Create a new aggregate context for p and return a pointer to +** its pMem->z element. */ -SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ - Mem *pMem; - assert( p && p->pFunc && p->pFunc->xStep ); - assert( sqlite3_mutex_held(p->s.db->mutex) ); - pMem = p->pMem; - testcase( nByte<0 ); - if( (pMem->flags & MEM_Agg)==0 ){ - if( nByte<=0 ){ - sqlite3VdbeMemReleaseExternal(pMem); - pMem->flags = MEM_Null; - pMem->z = 0; - }else{ - sqlite3VdbeMemGrow(pMem, nByte, 0); - pMem->flags = MEM_Agg; - pMem->u.pDef = p->pFunc; - if( pMem->z ){ - memset(pMem->z, 0, nByte); - } +static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){ + Mem *pMem = p->pMem; + assert( (pMem->flags & MEM_Agg)==0 ); + if( nByte<=0 ){ + sqlite3VdbeMemSetNull(pMem); + pMem->z = 0; + }else{ + sqlite3VdbeMemClearAndResize(pMem, nByte); + pMem->flags = MEM_Agg; + pMem->u.pDef = p->pFunc; + if( pMem->z ){ + memset(pMem->z, 0, nByte); } } return (void*)pMem->z; } /* -** Return the auxilary data pointer, if any, for the iArg'th argument to +** Allocate or return the aggregate context for a user function. A new +** context is allocated on the first call. Subsequent calls return the +** same context that was returned on prior calls. +*/ +SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ + assert( p && p->pFunc && p->pFunc->xStep ); + assert( sqlite3_mutex_held(p->pOut->db->mutex) ); + testcase( nByte<0 ); + if( (p->pMem->flags & MEM_Agg)==0 ){ + return createAggContext(p, nByte); + }else{ + return (void*)p->pMem->z; + } +} + +/* +** Return the auxiliary data pointer, if any, for the iArg'th argument to ** the user-function defined by pCtx. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; } @@ -66893,7 +68019,7 @@ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ } /* -** Set the auxilary data pointer and delete function, for the iArg'th +** Set the auxiliary data pointer and delete function, for the iArg'th ** argument to the user-function defined by pCtx. Any previous value is ** deleted by calling the delete function specified when it was set. */ @@ -66906,7 +68032,7 @@ SQLITE_API void sqlite3_set_auxdata( AuxData *pAuxData; Vdbe *pVdbe = pCtx->pVdbe; - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); if( iArg<0 ) goto failed; for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ @@ -66939,7 +68065,7 @@ failed: #ifndef SQLITE_OMIT_DEPRECATED /* -** Return the number of times the Step function of a aggregate has been +** Return the number of times the Step function of an aggregate has been ** called. ** ** This function is deprecated. Do not use it for new code. It is @@ -66988,11 +68114,22 @@ static const Mem *columnNullValue(void){ #if defined(SQLITE_DEBUG) && defined(__GNUC__) __attribute__((aligned(8))) #endif - = {0, "", (double)0, {0}, 0, MEM_Null, 0, + = { + /* .u = */ {0}, + /* .flags = */ MEM_Null, + /* .enc = */ 0, + /* .n = */ 0, + /* .z = */ 0, + /* .zMalloc = */ 0, + /* .szMalloc = */ 0, + /* .iPadding1 = */ 0, + /* .db = */ 0, + /* .xDel = */ 0, #ifdef SQLITE_DEBUG - 0, 0, /* pScopyFrom, pFiller */ + /* .pScopyFrom = */ 0, + /* .pFiller = */ 0, #endif - 0, 0 }; + }; return &nullMem; } @@ -67013,7 +68150,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){ }else{ if( pVm && ALWAYS(pVm->db) ){ sqlite3_mutex_enter(pVm->db->mutex); - sqlite3Error(pVm->db, SQLITE_RANGE, 0); + sqlite3Error(pVm->db, SQLITE_RANGE); } pOut = (Mem*)columnNullValue(); } @@ -67209,7 +68346,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ /* ** Return the name of the database from which a result column derives. ** NULL is returned if the result column is an expression or constant or -** anything else which is not an unabiguous reference to a database column. +** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ return columnName( @@ -67225,7 +68362,7 @@ SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N /* ** Return the name of the table from which a result column derives. ** NULL is returned if the result column is an expression or constant or -** anything else which is not an unabiguous reference to a database column. +** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ return columnName( @@ -67241,7 +68378,7 @@ SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ /* ** Return the name of the table column from which a result column derives. ** NULL is returned if the result column is an expression or constant or -** anything else which is not an unabiguous reference to a database column. +** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ return columnName( @@ -67278,14 +68415,14 @@ static int vdbeUnbind(Vdbe *p, int i){ } sqlite3_mutex_enter(p->db->mutex); if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){ - sqlite3Error(p->db, SQLITE_MISUSE, 0); + sqlite3Error(p->db, SQLITE_MISUSE); sqlite3_mutex_leave(p->db->mutex); sqlite3_log(SQLITE_MISUSE, "bind on a busy prepared statement: [%s]", p->zSql); return SQLITE_MISUSE_BKPT; } if( i<1 || i>p->nVar ){ - sqlite3Error(p->db, SQLITE_RANGE, 0); + sqlite3Error(p->db, SQLITE_RANGE); sqlite3_mutex_leave(p->db->mutex); return SQLITE_RANGE; } @@ -67293,7 +68430,7 @@ static int vdbeUnbind(Vdbe *p, int i){ pVar = &p->aVar[i]; sqlite3VdbeMemRelease(pVar); pVar->flags = MEM_Null; - sqlite3Error(p->db, SQLITE_OK, 0); + sqlite3Error(p->db, SQLITE_OK); /* If the bit corresponding to this variable in Vdbe.expmask is set, then ** binding a new value to this variable invalidates the current query plan. @@ -67335,7 +68472,7 @@ static int bindText( if( rc==SQLITE_OK && encoding!=0 ){ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); } - sqlite3Error(p->db, rc, 0); + sqlite3Error(p->db, rc); rc = sqlite3ApiExit(p->db, rc); } sqlite3_mutex_leave(p->db->mutex); @@ -67358,6 +68495,20 @@ SQLITE_API int sqlite3_bind_blob( ){ return bindText(pStmt, i, zData, nData, xDel, 0); } +SQLITE_API int sqlite3_bind_blob64( + sqlite3_stmt *pStmt, + int i, + const void *zData, + sqlite3_uint64 nData, + void (*xDel)(void*) +){ + assert( xDel!=SQLITE_DYNAMIC ); + if( nData>0x7fffffff ){ + return invokeValueDestructor(zData, xDel, 0); + }else{ + return bindText(pStmt, i, zData, (int)nData, xDel, 0); + } +} SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ int rc; Vdbe *p = (Vdbe *)pStmt; @@ -67399,6 +68550,22 @@ SQLITE_API int sqlite3_bind_text( ){ return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8); } +SQLITE_API int sqlite3_bind_text64( + sqlite3_stmt *pStmt, + int i, + const char *zData, + sqlite3_uint64 nData, + void (*xDel)(void*), + unsigned char enc +){ + assert( xDel!=SQLITE_DYNAMIC ); + if( nData>0x7fffffff ){ + return invokeValueDestructor(zData, xDel, 0); + }else{ + if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; + return bindText(pStmt, i, zData, (int)nData, xDel, enc); + } +} #ifndef SQLITE_OMIT_UTF16 SQLITE_API int sqlite3_bind_text16( sqlite3_stmt *pStmt, @@ -67418,7 +68585,7 @@ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_valu break; } case SQLITE_FLOAT: { - rc = sqlite3_bind_double(pStmt, i, pValue->r); + rc = sqlite3_bind_double(pStmt, i, pValue->u.r); break; } case SQLITE_BLOB: { @@ -67521,7 +68688,7 @@ SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt ** Deprecated external interface. Internal/core SQLite code ** should call sqlite3TransferBindings. ** -** Is is misuse to call this routine with statements from different +** It is misuse to call this routine with statements from different ** database connections. But as this is a deprecated interface, we ** will not bother to check for that condition. ** @@ -67665,7 +68832,7 @@ static int findNextHostParameter(const char *zSql, int *pnToken){ ** ALGORITHM: Scan the input string looking for host parameters in any of ** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within ** string literals, quoted identifier names, and comments. For text forms, -** the host parameter index is found by scanning the perpared +** the host parameter index is found by scanning the prepared ** statement for the corresponding OP_Variable opcode. Once the host ** parameter index is known, locate the value in p->aVar[]. Then render ** the value as a literal in place of the host parameter name. @@ -67728,7 +68895,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( }else if( pVar->flags & MEM_Int ){ sqlite3XPrintf(&out, 0, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ - sqlite3XPrintf(&out, 0, "%!.15g", pVar->r); + sqlite3XPrintf(&out, 0, "%!.15g", pVar->u.r); }else if( pVar->flags & MEM_Str ){ int nOut; /* Number of bytes of the string text to include in output */ #ifndef SQLITE_OMIT_UTF16 @@ -67785,121 +68952,6 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( #endif /* #ifndef SQLITE_OMIT_TRACE */ -/***************************************************************************** -** The following code implements the data-structure explaining logic -** for the Vdbe. -*/ - -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - -/* -** Allocate a new Explain object -*/ -SQLITE_PRIVATE void sqlite3ExplainBegin(Vdbe *pVdbe){ - if( pVdbe ){ - Explain *p; - sqlite3BeginBenignMalloc(); - p = (Explain *)sqlite3MallocZero( sizeof(Explain) ); - if( p ){ - p->pVdbe = pVdbe; - sqlite3_free(pVdbe->pExplain); - pVdbe->pExplain = p; - sqlite3StrAccumInit(&p->str, p->zBase, sizeof(p->zBase), - SQLITE_MAX_LENGTH); - p->str.useMalloc = 2; - }else{ - sqlite3EndBenignMalloc(); - } - } -} - -/* -** Return true if the Explain ends with a new-line. -*/ -static int endsWithNL(Explain *p){ - return p && p->str.zText && p->str.nChar - && p->str.zText[p->str.nChar-1]=='\n'; -} - -/* -** Append text to the indentation -*/ -SQLITE_PRIVATE void sqlite3ExplainPrintf(Vdbe *pVdbe, const char *zFormat, ...){ - Explain *p; - if( pVdbe && (p = pVdbe->pExplain)!=0 ){ - va_list ap; - if( p->nIndent && endsWithNL(p) ){ - int n = p->nIndent; - if( n>ArraySize(p->aIndent) ) n = ArraySize(p->aIndent); - sqlite3AppendSpace(&p->str, p->aIndent[n-1]); - } - va_start(ap, zFormat); - sqlite3VXPrintf(&p->str, SQLITE_PRINTF_INTERNAL, zFormat, ap); - va_end(ap); - } -} - -/* -** Append a '\n' if there is not already one. -*/ -SQLITE_PRIVATE void sqlite3ExplainNL(Vdbe *pVdbe){ - Explain *p; - if( pVdbe && (p = pVdbe->pExplain)!=0 && !endsWithNL(p) ){ - sqlite3StrAccumAppend(&p->str, "\n", 1); - } -} - -/* -** Push a new indentation level. Subsequent lines will be indented -** so that they begin at the current cursor position. -*/ -SQLITE_PRIVATE void sqlite3ExplainPush(Vdbe *pVdbe){ - Explain *p; - if( pVdbe && (p = pVdbe->pExplain)!=0 ){ - if( p->str.zText && p->nIndentaIndent) ){ - const char *z = p->str.zText; - int i = p->str.nChar-1; - int x; - while( i>=0 && z[i]!='\n' ){ i--; } - x = (p->str.nChar - 1) - i; - if( p->nIndent && xaIndent[p->nIndent-1] ){ - x = p->aIndent[p->nIndent-1]; - } - p->aIndent[p->nIndent] = x; - } - p->nIndent++; - } -} - -/* -** Pop the indentation stack by one level. -*/ -SQLITE_PRIVATE void sqlite3ExplainPop(Vdbe *p){ - if( p && p->pExplain ) p->pExplain->nIndent--; -} - -/* -** Free the indentation structure -*/ -SQLITE_PRIVATE void sqlite3ExplainFinish(Vdbe *pVdbe){ - if( pVdbe && pVdbe->pExplain ){ - sqlite3_free(pVdbe->zExplain); - sqlite3ExplainNL(pVdbe); - pVdbe->zExplain = sqlite3StrAccumFinish(&pVdbe->pExplain->str); - sqlite3_free(pVdbe->pExplain); - pVdbe->pExplain = 0; - sqlite3EndBenignMalloc(); - } -} - -/* -** Return the explanation of a virtual machine. -*/ -SQLITE_PRIVATE const char *sqlite3VdbeExplanation(Vdbe *pVdbe){ - return (pVdbe && pVdbe->zExplain) ? pVdbe->zExplain : 0; -} -#endif /* defined(SQLITE_DEBUG) */ - /************** End of vdbetrace.c *******************************************/ /************** Begin file vdbe.c ********************************************/ /* @@ -68048,7 +69100,7 @@ SQLITE_API int sqlite3_found_count = 0; ** already. Return non-zero if a malloc() fails. */ #define Stringify(P, enc) \ - if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc)) \ + if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \ { goto no_mem; } /* @@ -68111,11 +69163,12 @@ static VdbeCursor *allocateCursor( sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } - if( SQLITE_OK==sqlite3VdbeMemGrow(pMem, nByte, 0) ){ + if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; memset(pCx, 0, sizeof(VdbeCursor)); pCx->iDb = iDb; pCx->nField = nField; + pCx->aOffset = &pCx->aType[nField]; if( isBtreeCursor ){ pCx->pCursor = (BtCursor*) &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; @@ -68130,23 +69183,31 @@ static VdbeCursor *allocateCursor( ** do so without loss of information. In other words, if the string ** looks like a number, convert it into a number. If it does not ** look like a number, leave it alone. +** +** If the bTryForInt flag is true, then extra effort is made to give +** an integer representation. Strings that look like floating point +** values but which have no fractional component (example: '48.00') +** will have a MEM_Int representation when bTryForInt is true. +** +** If bTryForInt is false, then if the input string contains a decimal +** point or exponential notation, the result is only MEM_Real, even +** if there is an exact integer representation of the quantity. */ -static void applyNumericAffinity(Mem *pRec){ +static void applyNumericAffinity(Mem *pRec, int bTryForInt){ double rValue; i64 iValue; u8 enc = pRec->enc; - if( (pRec->flags&MEM_Str)==0 ) return; + assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str ); if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ pRec->u.i = iValue; pRec->flags |= MEM_Int; }else{ - pRec->r = rValue; + pRec->u.r = rValue; pRec->flags |= MEM_Real; + if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec); } } -#define ApplyNumericAffinity(X) \ - if(((X)->flags&(MEM_Real|MEM_Int))==0){applyNumericAffinity(X);} /* ** Processing is determine by the affinity parameter: @@ -68171,21 +69232,23 @@ static void applyAffinity( char affinity, /* The affinity to be applied */ u8 enc /* Use this text encoding */ ){ - if( affinity==SQLITE_AFF_TEXT ){ + if( affinity>=SQLITE_AFF_NUMERIC ){ + assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL + || affinity==SQLITE_AFF_NUMERIC ); + if( (pRec->flags & MEM_Int)==0 ){ + if( (pRec->flags & MEM_Real)==0 ){ + if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1); + }else{ + sqlite3VdbeIntegerAffinity(pRec); + } + } + }else if( affinity==SQLITE_AFF_TEXT ){ /* Only attempt the conversion to TEXT if there is an integer or real ** representation (blob and NULL do not get converted) but no string ** representation. */ if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){ - sqlite3VdbeMemStringify(pRec, enc); - } - pRec->flags &= ~(MEM_Real|MEM_Int); - }else if( affinity!=SQLITE_AFF_NONE ){ - assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL - || affinity==SQLITE_AFF_NUMERIC ); - ApplyNumericAffinity(pRec); - if( pRec->flags & MEM_Real ){ - sqlite3VdbeIntegerAffinity(pRec); + sqlite3VdbeMemStringify(pRec, enc, 1); } } } @@ -68200,7 +69263,7 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ int eType = sqlite3_value_type(pVal); if( eType==SQLITE_TEXT ){ Mem *pMem = (Mem*)pVal; - applyNumericAffinity(pMem); + applyNumericAffinity(pMem, 0); eType = sqlite3_value_type(pVal); } return eType; @@ -68218,25 +69281,37 @@ SQLITE_PRIVATE void sqlite3ValueApplyAffinity( applyAffinity((Mem *)pVal, affinity, enc); } +/* +** pMem currently only holds a string type (or maybe a BLOB that we can +** interpret as a string if we want to). Compute its corresponding +** numeric type, if has one. Set the pMem->u.r and pMem->u.i fields +** accordingly. +*/ +static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ + assert( (pMem->flags & (MEM_Int|MEM_Real))==0 ); + assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); + if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){ + return 0; + } + if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ + return MEM_Int; + } + return MEM_Real; +} + /* ** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or ** none. ** ** Unlike applyNumericAffinity(), this routine does not modify pMem->flags. -** But it does set pMem->r and pMem->u.i appropriately. +** But it does set pMem->u.r and pMem->u.i appropriately. */ static u16 numericType(Mem *pMem){ if( pMem->flags & (MEM_Int|MEM_Real) ){ return pMem->flags & (MEM_Int|MEM_Real); } if( pMem->flags & (MEM_Str|MEM_Blob) ){ - if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){ - return 0; - } - if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ - return MEM_Int; - } - return MEM_Real; + return computeNumericType(pMem); } return 0; } @@ -68339,7 +69414,7 @@ static void memTracePrint(Mem *p){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT }else if( p->flags & MEM_Real ){ - printf(" r:%g", p->r); + printf(" r:%g", p->u.r); #endif }else if( p->flags & MEM_RowSet ){ printf(" (rowset)"); @@ -68609,7 +69684,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec( assert( pOp->p2<=(p->nMem-p->nCursor) ); pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); - VdbeMemRelease(pOut); + if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut); pOut->flags = MEM_Int; } @@ -68971,7 +70046,7 @@ case OP_Int64: { /* out2-prerelease */ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */ pOut->flags = MEM_Real; assert( !sqlite3IsNaN(*pOp->p4.pReal) ); - pOut->r = *pOp->p4.pReal; + pOut->u.r = *pOp->p4.pReal; break; } #endif @@ -68994,9 +70069,9 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); if( rc==SQLITE_TOOBIG ) goto too_big; if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; - assert( pOut->zMalloc==pOut->z ); + assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); assert( VdbeMemDynamic(pOut)==0 ); - pOut->zMalloc = 0; + pOut->szMalloc = 0; pOut->flags |= MEM_Static; if( pOp->p4type==P4_DYNAMIC ){ sqlite3DbFree(db, pOp->p4.z); @@ -69048,7 +70123,7 @@ case OP_Null: { /* out2-prerelease */ while( cnt>0 ){ pOut++; memAboutToChange(p, pOut); - VdbeMemRelease(pOut); + sqlite3VdbeMemSetNull(pOut); pOut->flags = nullFlag; cnt--; } @@ -69116,7 +70191,6 @@ case OP_Variable: { /* out2-prerelease */ ** for P3 to be less than 1. */ case OP_Move: { - char *zMalloc; /* Holding variable for allocated memory */ int n; /* Number of registers left to copy */ int p1; /* Register to copy from */ int p2; /* Register to copy to */ @@ -69134,17 +70208,12 @@ case OP_Move: { assert( pIn1<=&aMem[(p->nMem-p->nCursor)] ); assert( memIsValid(pIn1) ); memAboutToChange(p, pOut); - VdbeMemRelease(pOut); - zMalloc = pOut->zMalloc; - memcpy(pOut, pIn1, sizeof(Mem)); + sqlite3VdbeMemMove(pOut, pIn1); #ifdef SQLITE_DEBUG if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){ pOut->pScopyFrom += p1 - pOp->p2; } #endif - pIn1->flags = MEM_Undefined; - pIn1->xDel = 0; - pIn1->zMalloc = zMalloc; REGISTER_TRACE(p2++, pOut); pIn1++; pOut++; @@ -69449,7 +70518,7 @@ fp_math: if( sqlite3IsNaN(rB) ){ goto arithmetic_result_is_null; } - pOut->r = rB; + pOut->u.r = rB; MemSetTypeFlag(pOut, MEM_Real); if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ sqlite3VdbeIntegerAffinity(pOut); @@ -69514,8 +70583,8 @@ case OP_Function: { apVal = p->apArg; assert( apVal || n==0 ); assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); - pOut = &aMem[pOp->p3]; - memAboutToChange(p, pOut); + ctx.pOut = &aMem[pOp->p3]; + memAboutToChange(p, ctx.pOut); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) ); assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); @@ -69531,65 +70600,29 @@ case OP_Function: { ctx.pFunc = pOp->p4.pFunc; ctx.iOp = pc; ctx.pVdbe = p; - - /* The output cell may already have a buffer allocated. Move - ** the pointer to ctx.s so in case the user-function can use - ** the already allocated buffer instead of allocating a new one. - */ - memcpy(&ctx.s, pOut, sizeof(Mem)); - pOut->flags = MEM_Null; - pOut->xDel = 0; - pOut->zMalloc = 0; - MemSetTypeFlag(&ctx.s, MEM_Null); - + MemSetTypeFlag(ctx.pOut, MEM_Null); ctx.fErrorOrAux = 0; - if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ - assert( pOp>aOp ); - assert( pOp[-1].p4type==P4_COLLSEQ ); - assert( pOp[-1].opcode==OP_CollSeq ); - ctx.pColl = pOp[-1].p4.pColl; - } db->lastRowid = lastRowid; (*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */ - lastRowid = db->lastRowid; - - if( db->mallocFailed ){ - /* Even though a malloc() has failed, the implementation of the - ** user function may have called an sqlite3_result_XXX() function - ** to return a value. The following call releases any resources - ** associated with such a value. - */ - sqlite3VdbeMemRelease(&ctx.s); - goto no_mem; - } + lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */ /* If the function returned an error, throw an exception */ if( ctx.fErrorOrAux ){ if( ctx.isError ){ - sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s)); + sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(ctx.pOut)); rc = ctx.isError; } sqlite3VdbeDeleteAuxData(p, pc, pOp->p1); } /* Copy the result of the function into register P3 */ - sqlite3VdbeChangeEncoding(&ctx.s, encoding); - assert( pOut->flags==MEM_Null ); - memcpy(pOut, &ctx.s, sizeof(Mem)); - if( sqlite3VdbeMemTooBig(pOut) ){ + sqlite3VdbeChangeEncoding(ctx.pOut, encoding); + if( sqlite3VdbeMemTooBig(ctx.pOut) ){ goto too_big; } -#if 0 - /* The app-defined function has done something that as caused this - ** statement to expire. (Perhaps the function called sqlite3_exec() - ** with a CREATE TABLE statement.) - */ - if( p->expired ) rc = SQLITE_ABORT; -#endif - - REGISTER_TRACE(pOp->p3, pOut); - UPDATE_MAX_BLOBSIZE(pOut); + REGISTER_TRACE(pOp->p3, ctx.pOut); + UPDATE_MAX_BLOBSIZE(ctx.pOut); break; } @@ -69737,106 +70770,37 @@ case OP_RealAffinity: { /* in1 */ #endif #ifndef SQLITE_OMIT_CAST -/* Opcode: ToText P1 * * * * +/* Opcode: Cast P1 P2 * * * +** Synopsis: affinity(r[P1]) ** -** Force the value in register P1 to be text. -** If the value is numeric, convert it to a string using the -** equivalent of sprintf(). Blob values are unchanged and -** are afterwards simply interpreted as text. +** Force the value in register P1 to be the type defined by P2. +** +**
      +**
    • TEXT +**
    • BLOB +**
    • NUMERIC +**
    • INTEGER +**
    • REAL +**
    ** ** A NULL value is not changed by this routine. It remains NULL. */ -case OP_ToText: { /* same as TK_TO_TEXT, in1 */ +case OP_Cast: { /* in1 */ + assert( pOp->p2>=SQLITE_AFF_NONE && pOp->p2<=SQLITE_AFF_REAL ); + testcase( pOp->p2==SQLITE_AFF_TEXT ); + testcase( pOp->p2==SQLITE_AFF_NONE ); + testcase( pOp->p2==SQLITE_AFF_NUMERIC ); + testcase( pOp->p2==SQLITE_AFF_INTEGER ); + testcase( pOp->p2==SQLITE_AFF_REAL ); pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); - if( pIn1->flags & MEM_Null ) break; - assert( MEM_Str==(MEM_Blob>>3) ); - pIn1->flags |= (pIn1->flags&MEM_Blob)>>3; - applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); rc = ExpandBlob(pIn1); - assert( pIn1->flags & MEM_Str || db->mallocFailed ); - pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero); + sqlite3VdbeMemCast(pIn1, pOp->p2, encoding); UPDATE_MAX_BLOBSIZE(pIn1); break; } - -/* Opcode: ToBlob P1 * * * * -** -** Force the value in register P1 to be a BLOB. -** If the value is numeric, convert it to a string first. -** Strings are simply reinterpreted as blobs with no change -** to the underlying data. -** -** A NULL value is not changed by this routine. It remains NULL. -*/ -case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */ - pIn1 = &aMem[pOp->p1]; - if( pIn1->flags & MEM_Null ) break; - if( (pIn1->flags & MEM_Blob)==0 ){ - applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); - assert( pIn1->flags & MEM_Str || db->mallocFailed ); - MemSetTypeFlag(pIn1, MEM_Blob); - }else{ - pIn1->flags &= ~(MEM_TypeMask&~MEM_Blob); - } - UPDATE_MAX_BLOBSIZE(pIn1); - break; -} - -/* Opcode: ToNumeric P1 * * * * -** -** Force the value in register P1 to be numeric (either an -** integer or a floating-point number.) -** If the value is text or blob, try to convert it to an using the -** equivalent of atoi() or atof() and store 0 if no such conversion -** is possible. -** -** A NULL value is not changed by this routine. It remains NULL. -*/ -case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */ - pIn1 = &aMem[pOp->p1]; - sqlite3VdbeMemNumerify(pIn1); - break; -} #endif /* SQLITE_OMIT_CAST */ -/* Opcode: ToInt P1 * * * * -** -** Force the value in register P1 to be an integer. If -** The value is currently a real number, drop its fractional part. -** If the value is text or blob, try to convert it to an integer using the -** equivalent of atoi() and store 0 if no such conversion is possible. -** -** A NULL value is not changed by this routine. It remains NULL. -*/ -case OP_ToInt: { /* same as TK_TO_INT, in1 */ - pIn1 = &aMem[pOp->p1]; - if( (pIn1->flags & MEM_Null)==0 ){ - sqlite3VdbeMemIntegerify(pIn1); - } - break; -} - -#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) -/* Opcode: ToReal P1 * * * * -** -** Force the value in register P1 to be a floating point number. -** If The value is currently an integer, convert it. -** If the value is text or blob, try to convert it to an integer using the -** equivalent of atoi() and store 0.0 if no such conversion is possible. -** -** A NULL value is not changed by this routine. It remains NULL. -*/ -case OP_ToReal: { /* same as TK_TO_REAL, in1 */ - pIn1 = &aMem[pOp->p1]; - memAboutToChange(p, pIn1); - if( (pIn1->flags & MEM_Null)==0 ){ - sqlite3VdbeMemRealify(pIn1); - } - break; -} -#endif /* !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) */ - /* Opcode: Lt P1 P2 P3 P4 P5 ** Synopsis: if r[P1]p5 & SQLITE_AFF_MASK; - if( affinity ){ - applyAffinity(pIn1, affinity, encoding); - applyAffinity(pIn3, affinity, encoding); - if( db->mallocFailed ) goto no_mem; + if( affinity>=SQLITE_AFF_NUMERIC ){ + if( (pIn1->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn1,0); + } + if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn3,0); + } + }else if( affinity==SQLITE_AFF_TEXT ){ + if( (pIn1->flags & MEM_Str)==0 && (pIn1->flags & (MEM_Int|MEM_Real))!=0 ){ + testcase( pIn1->flags & MEM_Int ); + testcase( pIn1->flags & MEM_Real ); + sqlite3VdbeMemStringify(pIn1, encoding, 1); + } + if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){ + testcase( pIn3->flags & MEM_Int ); + testcase( pIn3->flags & MEM_Real ); + sqlite3VdbeMemStringify(pIn3, encoding, 1); + } } - assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); - ExpandBlob(pIn1); - ExpandBlob(pIn3); + if( pIn1->flags & MEM_Zero ){ + sqlite3VdbeMemExpandBlob(pIn1); + flags1 &= ~MEM_Zero; + } + if( pIn3->flags & MEM_Zero ){ + sqlite3VdbeMemExpandBlob(pIn3); + flags3 &= ~MEM_Zero; + } + if( db->mallocFailed ) goto no_mem; res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); } switch( pOp->opcode ){ @@ -70005,8 +70989,8 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ } } /* Undo any changes made by applyAffinity() to the input registers. */ - pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (flags1&MEM_TypeMask); - pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (flags3&MEM_TypeMask); + pIn1->flags = flags1; + pIn3->flags = flags3; break; } @@ -70174,10 +71158,10 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ case OP_Not: { /* same as TK_NOT, in1, out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; - if( pIn1->flags & MEM_Null ){ - sqlite3VdbeMemSetNull(pOut); - }else{ - sqlite3VdbeMemSetInt64(pOut, !sqlite3VdbeIntValue(pIn1)); + sqlite3VdbeMemSetNull(pOut); + if( (pIn1->flags & MEM_Null)==0 ){ + pOut->flags = MEM_Int; + pOut->u.i = !sqlite3VdbeIntValue(pIn1); } break; } @@ -70192,10 +71176,10 @@ case OP_Not: { /* same as TK_NOT, in1, out2 */ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; - if( pIn1->flags & MEM_Null ){ - sqlite3VdbeMemSetNull(pOut); - }else{ - sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1)); + sqlite3VdbeMemSetNull(pOut); + if( (pIn1->flags & MEM_Null)==0 ){ + pOut->flags = MEM_Int; + pOut->u.i = ~sqlite3VdbeIntValue(pIn1); } break; } @@ -70313,7 +71297,6 @@ case OP_Column: { int p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The BTree cursor */ - u32 *aType; /* aType[i] holds the numeric type of the i-th column */ u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ int len; /* The length of the serialized data for the column */ int i; /* Loop counter */ @@ -70326,6 +71309,7 @@ case OP_Column: { u32 szField; /* Number of bytes in the content of a field */ u32 avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ + u16 fx; /* pDest->flags value */ Mem *pReg; /* PseudoTable input register */ p2 = pOp->p2; @@ -70336,8 +71320,7 @@ case OP_Column: { pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( p2nField ); - aType = pC->aType; - aOffset = aType + pC->nField; + aOffset = pC->aOffset; #ifndef SQLITE_OMIT_VIRTUALTABLE assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */ #endif @@ -70348,7 +71331,7 @@ case OP_Column: { /* If the cursor cache is stale, bring it up-to-date */ rc = sqlite3VdbeCursorMoveto(pC); if( rc ) goto abort_due_to_error; - if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){ + if( pC->cacheStatus!=p->cacheCtr ){ if( pC->nullRow ){ if( pCrsr==0 ){ assert( pC->pseudoTableReg>0 ); @@ -70358,7 +71341,7 @@ case OP_Column: { pC->payloadSize = pC->szRow = avail = pReg->n; pC->aRow = (u8*)pReg->z; }else{ - MemSetTypeFlag(pDest, MEM_Null); + sqlite3VdbeMemSetNull(pDest); goto op_column_out; } }else{ @@ -70393,14 +71376,6 @@ case OP_Column: { pC->iHdrOffset = getVarint32(pC->aRow, offset); pC->nHdrParsed = 0; aOffset[0] = offset; - if( availaRow does not have to hold the entire row, but it does at least - ** need to cover the header of the record. If pC->aRow does not contain - ** the complete header, then set it to zero, forcing the header to be - ** dynamically allocated. */ - pC->aRow = 0; - pC->szRow = 0; - } /* Make sure a corrupt database has not given us an oversize header. ** Do this now to avoid an oversize memory allocation. @@ -70415,15 +71390,32 @@ case OP_Column: { rc = SQLITE_CORRUPT_BKPT; goto op_column_error; } + + if( availaRow does not have to hold the entire row, but it does at least + ** need to cover the header of the record. If pC->aRow does not contain + ** the complete header, then set it to zero, forcing the header to be + ** dynamically allocated. */ + pC->aRow = 0; + pC->szRow = 0; + } + + /* The following goto is an optimization. It can be omitted and + ** everything will still work. But OP_Column is measurably faster + ** by skipping the subsequent conditional, which is always true. + */ + assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ + goto op_column_read_header; } /* Make sure at least the first p2+1 entries of the header have been - ** parsed and valid information is in aOffset[] and aType[]. + ** parsed and valid information is in aOffset[] and pC->aType[]. */ if( pC->nHdrParsed<=p2 ){ /* If there is more header available for parsing in the record, try ** to extract additional fields up through the p2+1-th field */ + op_column_read_header: if( pC->iHdrOffsetaRow==0 ){ @@ -70438,7 +71430,7 @@ case OP_Column: { zData = pC->aRow; } - /* Fill in aType[i] and aOffset[i] values through the p2-th field. */ + /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */ i = pC->nHdrParsed; offset = aOffset[i]; zHdr = zData + pC->iHdrOffset; @@ -70451,7 +71443,7 @@ case OP_Column: { }else{ zHdr += sqlite3GetVarint32(zHdr, &t); } - aType[i] = t; + pC->aType[i] = t; szField = sqlite3VdbeSerialTypeLen(t); offset += szField; if( offsetzEndHdr) + ** (2) the entire header was used but not all data was used + ** (zHdr==zEndHdr && offset!=pC->payloadSize) + ** (3) the end of the data extends beyond the end of the record. + ** (offset > pC->payloadSize) */ - if( (zHdr > zEndHdr) + if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset!=pC->payloadSize)) || (offset > pC->payloadSize) - || (zHdr==zEndHdr && offset!=pC->payloadSize) ){ rc = SQLITE_CORRUPT_BKPT; goto op_column_error; @@ -70491,68 +71484,68 @@ case OP_Column: { if( pOp->p4type==P4_MEM ){ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); }else{ - MemSetTypeFlag(pDest, MEM_Null); + sqlite3VdbeMemSetNull(pDest); } goto op_column_out; } } /* Extract the content for the p2+1-th column. Control can only - ** reach this point if aOffset[p2], aOffset[p2+1], and aType[p2] are + ** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are ** all valid. */ assert( p2nHdrParsed ); assert( rc==SQLITE_OK ); assert( sqlite3VdbeCheckMemInvariants(pDest) ); + if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest); + t = pC->aType[p2]; if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ - VdbeMemRelease(pDest); - sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest); + sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest); }else{ /* This branch happens only when content is on overflow pages */ - t = aType[p2]; if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)) || (len = sqlite3VdbeSerialTypeLen(t))==0 ){ - /* Content is irrelevant for the typeof() function and for - ** the length(X) function if X is a blob. So we might as well use - ** bogus content rather than reading content from disk. NULL works - ** for text and blob and whatever is in the payloadSize64 variable - ** will work for everything else. Content is also irrelevant if - ** the content length is 0. */ - zData = t<=13 ? (u8*)&payloadSize64 : 0; - sMem.zMalloc = 0; + /* Content is irrelevant for + ** 1. the typeof() function, + ** 2. the length(X) function if X is a blob, and + ** 3. if the content length is zero. + ** So we might as well use bogus content rather than reading + ** content from disk. NULL will work for the value for strings + ** and blobs and whatever is in the payloadSize64 variable + ** will work for everything else. */ + sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest); }else{ - memset(&sMem, 0, sizeof(sMem)); - sqlite3VdbeMemMove(&sMem, pDest); rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable, - &sMem); + pDest); if( rc!=SQLITE_OK ){ goto op_column_error; } - zData = (u8*)sMem.z; - } - sqlite3VdbeSerialGet(zData, t, pDest); - /* If we dynamically allocated space to hold the data (in the - ** sqlite3VdbeMemFromBtree() call above) then transfer control of that - ** dynamically allocated space over to the pDest structure. - ** This prevents a memory copy. */ - if( sMem.zMalloc ){ - assert( sMem.z==sMem.zMalloc ); - assert( VdbeMemDynamic(pDest)==0 ); - assert( (pDest->flags & (MEM_Blob|MEM_Str))==0 || pDest->z==sMem.z ); - pDest->flags &= ~(MEM_Ephem|MEM_Static); - pDest->flags |= MEM_Term; - pDest->z = sMem.z; - pDest->zMalloc = sMem.zMalloc; + sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); + pDest->flags &= ~MEM_Ephem; } } pDest->enc = encoding; op_column_out: - Deephemeralize(pDest); + /* If the column value is an ephemeral string, go ahead and persist + ** that string in case the cursor moves before the column value is + ** used. The following code does the equivalent of Deephemeralize() + ** but does it faster. */ + if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){ + fx = pDest->flags & (MEM_Str|MEM_Blob); + assert( fx!=0 ); + zData = (const u8*)pDest->z; + len = pDest->n; + if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem; + memcpy(pDest->z, zData, len); + pDest->z[len] = 0; + pDest->z[len+1] = 0; + pDest->flags = fx|MEM_Term; + } op_column_error: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); @@ -70627,7 +71620,7 @@ case OP_MakeRecord: { ** ------------------------------------------------------------------------ ** ** Data(0) is taken from register P1. Data(1) comes from register P1+1 - ** and so froth. + ** and so forth. ** ** Each type field is a varint representing the serial type of the ** corresponding data element (see sqlite3VdbeSerialType()). The @@ -70667,7 +71660,7 @@ case OP_MakeRecord: { pRec = pLast; do{ assert( memIsValid(pRec) ); - serial_type = sqlite3VdbeSerialType(pRec, file_format); + pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format); len = sqlite3VdbeSerialTypeLen(serial_type); if( pRec->flags & MEM_Zero ){ if( nData ){ @@ -70703,9 +71696,9 @@ case OP_MakeRecord: { /* Make sure the output register has a buffer large enough to store ** the new record. The output register (pOp->p3) is not allowed to ** be one of the input registers (because the following call to - ** sqlite3VdbeMemGrow() could clobber the value before it is used). + ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used). */ - if( sqlite3VdbeMemGrow(pOut, (int)nByte, 0) ){ + if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ goto no_mem; } zNewRecord = (u8 *)pOut->z; @@ -70716,7 +71709,7 @@ case OP_MakeRecord: { assert( pData0<=pLast ); pRec = pData0; do{ - serial_type = sqlite3VdbeSerialType(pRec, file_format); + serial_type = pRec->uTemp; i += putVarint32(&zNewRecord[i], serial_type); /* serial type */ j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */ }while( (++pRec)<=pLast ); @@ -70726,7 +71719,6 @@ case OP_MakeRecord: { assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); pOut->n = (int)nByte; pOut->flags = MEM_Blob; - pOut->xDel = 0; if( nZero ){ pOut->u.nZero = nZero; pOut->flags |= MEM_Zero; @@ -70873,11 +71865,18 @@ case OP_Savepoint: { db->isTransactionSavepoint = 0; rc = p->rc; }else{ + int isSchemaChange; iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ + isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; for(ii=0; iinDb; ii++){ - sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT); + rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, + SQLITE_ABORT_ROLLBACK, + isSchemaChange==0); + if( rc!=SQLITE_OK ) goto abort_due_to_error; } + }else{ + isSchemaChange = 0; } for(ii=0; iinDb; ii++){ rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); @@ -70885,7 +71884,7 @@ case OP_Savepoint: { goto abort_due_to_error; } } - if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ + if( isSchemaChange ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); db->flags = (db->flags | SQLITE_InternChanges); @@ -71282,7 +72281,7 @@ case OP_OpenWrite: { || p->readOnly==0 ); if( p->expired ){ - rc = SQLITE_ABORT; + rc = SQLITE_ABORT_ROLLBACK; break; } @@ -71342,10 +72341,6 @@ case OP_OpenWrite: { assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR)); - /* Since it performs no memory allocation or IO, the only value that - ** sqlite3BtreeCursor() may return is SQLITE_OK. */ - assert( rc==SQLITE_OK ); - /* Set the VdbeCursor.isTable variable. Previous versions of ** SQLite used to check if the root-page flags were sane at this point ** and report database corruption if they were not, but this check has @@ -71429,11 +72424,15 @@ case OP_OpenEphemeral: { break; } -/* Opcode: SorterOpen P1 P2 * P4 * +/* Opcode: SorterOpen P1 P2 P3 P4 * ** ** This opcode works like OP_OpenEphemeral except that it opens ** a transient index that is specifically designed to sort large ** tables using an external merge-sort algorithm. +** +** If argument P3 is non-zero, then it indicates that the sorter may +** assume that a stable sort considering the first P3 fields of each +** key is sufficient to produce the required results. */ case OP_SorterOpen: { VdbeCursor *pCx; @@ -71445,7 +72444,25 @@ case OP_SorterOpen: { pCx->pKeyInfo = pOp->p4.pKeyInfo; assert( pCx->pKeyInfo->db==db ); assert( pCx->pKeyInfo->enc==ENC(db) ); - rc = sqlite3VdbeSorterInit(db, pCx); + rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx); + break; +} + +/* Opcode: SequenceTest P1 P2 * * * +** Synopsis: if( cursor[P1].ctr++ ) pc = P2 +** +** P1 is a sorter cursor. If the sequence counter is currently zero, jump +** to P2. Regardless of whether or not the jump is taken, increment the +** the sequence value. +*/ +case OP_SequenceTest: { + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC->pSorter ); + if( (pC->seqCount++)==0 ){ + pc = pOp->p2 - 1; + } break; } @@ -71592,11 +72609,12 @@ case OP_SeekGT: { /* jump, in3 */ if( pC->isTable ){ /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do - ** the seek, so covert it. */ + ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; - ApplyNumericAffinity(pIn3); + if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn3, 0); + } iKey = sqlite3VdbeIntValue(pIn3); - pC->rowidIsValid = 0; /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ @@ -71615,7 +72633,7 @@ case OP_SeekGT: { /* jump, in3 */ ** (x > 4.9) -> (x >= 5) ** (x <= 4.9) -> (x < 5) */ - if( pIn3->r<(double)iKey ){ + if( pIn3->u.r<(double)iKey ){ assert( OP_SeekGE==(OP_SeekGT-1) ); assert( OP_SeekLT==(OP_SeekLE-1) ); assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) ); @@ -71624,7 +72642,7 @@ case OP_SeekGT: { /* jump, in3 */ /* If the approximation iKey is smaller than the actual real search ** term, substitute <= for < and > for >=. */ - else if( pIn3->r>(double)iKey ){ + else if( pIn3->u.r>(double)iKey ){ assert( OP_SeekLE==(OP_SeekLT+1) ); assert( OP_SeekGT==(OP_SeekGE+1) ); assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); @@ -71632,13 +72650,10 @@ case OP_SeekGT: { /* jump, in3 */ } } rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res); + pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - if( res==0 ){ - pC->rowidIsValid = 1; - pC->lastRowid = iKey; - } }else{ nField = pOp->p4.i; assert( pOp->p4type==P4_INT32 ); @@ -71668,7 +72683,6 @@ case OP_SeekGT: { /* jump, in3 */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - pC->rowidIsValid = 0; } pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; @@ -71680,7 +72694,6 @@ case OP_SeekGT: { /* jump, in3 */ res = 0; rc = sqlite3BtreeNext(pC->pCursor, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; - pC->rowidIsValid = 0; }else{ res = 0; } @@ -71690,7 +72703,6 @@ case OP_SeekGT: { /* jump, in3 */ res = 0; rc = sqlite3BtreePrevious(pC->pCursor, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; - pC->rowidIsValid = 0; }else{ /* res might be negative because the table is empty. Check to ** see if this is the case. @@ -71727,7 +72739,6 @@ case OP_Seek: { /* in2 */ pC->nullRow = 0; pIn2 = &aMem[pOp->p2]; pC->movetoTarget = sqlite3VdbeIntValue(pIn2); - pC->rowidIsValid = 0; pC->deferredMoveto = 1; break; } @@ -71913,15 +72924,13 @@ case OP_NotExists: { /* jump, in3 */ res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); - pC->lastRowid = pIn3->u.i; - pC->rowidIsValid = res==0 ?1:0; + pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; VdbeBranchTaken(res!=0,2); if( res!=0 ){ pc = pOp->p2 - 1; - assert( pC->rowidIsValid==0 ); } pC->seekResult = res; break; @@ -72055,32 +73064,20 @@ case OP_NewRowid: { /* out2-prerelease */ ** it finds one that is not previously used. */ assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is ** an AUTOINCREMENT table. */ - /* on the first attempt, simply do one more than previous */ - v = lastRowid; - v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ - v++; /* ensure non-zero */ cnt = 0; - while( ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v, + do{ + sqlite3_randomness(sizeof(v), &v); + v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */ + }while( ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v, 0, &res))==SQLITE_OK) && (res==0) - && (++cnt<100)){ - /* collision - try another random rowid */ - sqlite3_randomness(sizeof(v), &v); - if( cnt<5 ){ - /* try "small" random rowids for the initial attempts */ - v &= 0xffffff; - }else{ - v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ - } - v++; /* ensure non-zero */ - } + && (++cnt<100)); if( rc==SQLITE_OK && res==0 ){ rc = SQLITE_FULL; /* IMP: R-38219-53002 */ goto abort_due_to_error; } assert( v>0 ); /* EV: R-40812-03570 */ } - pC->rowidIsValid = 0; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } @@ -72185,7 +73182,6 @@ case OP_InsertInt: { pData->z, pData->n, nZero, (pOp->p5 & OPFLAG_APPEND)!=0, seekResult ); - pC->rowidIsValid = 0; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; @@ -72222,33 +73218,32 @@ case OP_InsertInt: { ** using OP_NotFound prior to invoking this opcode. */ case OP_Delete: { - i64 iKey; VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */ - iKey = pC->lastRowid; /* Only used for the update hook */ - - /* The OP_Delete opcode always follows an OP_NotExists or OP_Last or - ** OP_Column on the same table without any intervening operations that - ** might move or invalidate the cursor. Hence cursor pC is always pointing - ** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation - ** below is always a no-op and cannot fail. We will run it anyhow, though, - ** to guard against future changes to the code generator. - **/ assert( pC->deferredMoveto==0 ); - rc = sqlite3VdbeCursorMoveto(pC); - if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; +#ifdef SQLITE_DEBUG + /* The seek operation that positioned the cursor prior to OP_Delete will + ** have also set the pC->movetoTarget field to the rowid of the row that + ** is being deleted */ + if( pOp->p4.z && pC->isTable ){ + i64 iKey = 0; + sqlite3BtreeKeySize(pC->pCursor, &iKey); + assert( pC->movetoTarget==iKey ); + } +#endif + rc = sqlite3BtreeDelete(pC->pCursor); pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, - db->aDb[pC->iDb].zName, pOp->p4.z, iKey); + db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget); assert( pC->iDb>=0 ); } if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; @@ -72292,6 +73287,7 @@ case OP_SorterCompare: { assert( pOp->p4type==P4_INT32 ); pIn3 = &aMem[pOp->p3]; nKeyCol = pOp->p4.i; + res = 0; rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); VdbeBranchTaken(res!=0,2); if( res ){ @@ -72300,10 +73296,17 @@ case OP_SorterCompare: { break; }; -/* Opcode: SorterData P1 P2 * * * +/* Opcode: SorterData P1 P2 P3 * * ** Synopsis: r[P2]=data ** ** Write into register P2 the current sorter data for sorter cursor P1. +** Then clear the column header cache on cursor P3. +** +** This opcode is normally use to move a record out of the sorter and into +** a register that is the source for a pseudo-table cursor created using +** OpenPseudo. That pseudo-table cursor is the one that is identified by +** parameter P3. Clearing the P3 column cache as part of this opcode saves +** us from having to issue a separate NullRow instruction to clear that cache. */ case OP_SorterData: { VdbeCursor *pC; @@ -72313,6 +73316,8 @@ case OP_SorterData: { assert( isSorter(pC) ); rc = sqlite3VdbeSorterRowkey(pC, pOut); assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); + assert( pOp->p1>=0 && pOp->p1nCursor ); + p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE; break; } @@ -72359,16 +73364,20 @@ case OP_RowData: { assert( pC->pseudoTableReg==0 ); assert( pC->pCursor!=0 ); pCrsr = pC->pCursor; - assert( sqlite3BtreeCursorIsValid(pCrsr) ); /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or ** OP_Rewind/Op_Next with no intervening instructions that might invalidate - ** the cursor. Hence the following sqlite3VdbeCursorMoveto() call is always - ** a no-op and can never fail. But we leave it in place as a safety. + ** the cursor. If this where not the case, on of the following assert()s + ** would fail. Should this ever change (because of changes in the code + ** generator) then the fix would be to insert a call to + ** sqlite3VdbeCursorMoveto(). */ assert( pC->deferredMoveto==0 ); + assert( sqlite3BtreeCursorIsValid(pCrsr) ); +#if 0 /* Not required due to the previous to assert() statements */ rc = sqlite3VdbeCursorMoveto(pC); - if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; + if( rc!=SQLITE_OK ) goto abort_due_to_error; +#endif if( pC->isTable==0 ){ assert( !pC->isTable ); @@ -72385,7 +73394,8 @@ case OP_RowData: { goto too_big; } } - if( sqlite3VdbeMemGrow(pOut, n, 0) ){ + testcase( n==0 ); + if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){ goto no_mem; } pOut->n = n; @@ -72436,14 +73446,14 @@ case OP_Rowid: { /* out2-prerelease */ #endif /* SQLITE_OMIT_VIRTUALTABLE */ }else{ assert( pC->pCursor!=0 ); - rc = sqlite3VdbeCursorMoveto(pC); + rc = sqlite3VdbeCursorRestore(pC); if( rc ) goto abort_due_to_error; - if( pC->rowidIsValid ){ - v = pC->lastRowid; - }else{ - rc = sqlite3BtreeKeySize(pC->pCursor, &v); - assert( rc==SQLITE_OK ); /* Always so because of CursorMoveto() above */ + if( pC->nullRow ){ + pOut->flags = MEM_Null; + break; } + rc = sqlite3BtreeKeySize(pC->pCursor, &v); + assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */ } pOut->u.i = v; break; @@ -72462,7 +73472,6 @@ case OP_NullRow: { pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pC->nullRow = 1; - pC->rowidIsValid = 0; pC->cacheStatus = CACHE_STALE; if( pC->pCursor ){ sqlite3BtreeClearCursor(pC->pCursor); @@ -72496,7 +73505,6 @@ case OP_Last: { /* jump */ rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = (u8)res; pC->deferredMoveto = 0; - pC->rowidIsValid = 0; pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_DEBUG pC->seekOp = OP_Last; @@ -72556,14 +73564,13 @@ case OP_Rewind: { /* jump */ pC->seekOp = OP_Rewind; #endif if( isSorter(pC) ){ - rc = sqlite3VdbeSorterRewind(db, pC, &res); + rc = sqlite3VdbeSorterRewind(pC, &res); }else{ pCrsr = pC->pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; - pC->rowidIsValid = 0; } pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2nOp ); @@ -72689,7 +73696,6 @@ next_tail: }else{ pC->nullRow = 1; } - pC->rowidIsValid = 0; goto check_for_interrupt; } @@ -72734,7 +73740,7 @@ case OP_IdxInsert: { /* in2 */ rc = ExpandBlob(pIn2); if( rc==SQLITE_OK ){ if( isSorter(pC) ){ - rc = sqlite3VdbeSorterWrite(db, pC, pIn2); + rc = sqlite3VdbeSorterWrite(pC, pIn2); }else{ nKey = pIn2->n; zKey = pIn2->z; @@ -72805,10 +73811,16 @@ case OP_IdxRowid: { /* out2-prerelease */ pCrsr = pC->pCursor; assert( pCrsr!=0 ); pOut->flags = MEM_Null; - rc = sqlite3VdbeCursorMoveto(pC); - if( NEVER(rc) ) goto abort_due_to_error; - assert( pC->deferredMoveto==0 ); assert( pC->isTable==0 ); + assert( pC->deferredMoveto==0 ); + + /* sqlite3VbeCursorRestore() can only fail if the record has been deleted + ** out from under the cursor. That will never happend for an IdxRowid + ** opcode, hence the NEVER() arround the check of the return value. + */ + rc = sqlite3VdbeCursorRestore(pC); + if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; + if( !pC->nullRow ){ rowid = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid); @@ -72895,7 +73907,7 @@ case OP_IdxGE: { /* jump */ { int i; for(i=0; iopcode&1)==(OP_IdxLT&1) ){ assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT ); @@ -73647,6 +74659,7 @@ case OP_AggStep: { int i; Mem *pMem; Mem *pRec; + Mem t; sqlite3_context ctx; sqlite3_value **apVal; @@ -73664,23 +74677,15 @@ case OP_AggStep: { assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); ctx.pMem = pMem = &aMem[pOp->p3]; pMem->n++; - ctx.s.flags = MEM_Null; - ctx.s.z = 0; - ctx.s.zMalloc = 0; - ctx.s.xDel = 0; - ctx.s.db = db; + sqlite3VdbeMemInit(&t, db, MEM_Null); + ctx.pOut = &t; ctx.isError = 0; - ctx.pColl = 0; + ctx.pVdbe = p; + ctx.iOp = pc; ctx.skipFlag = 0; - if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ - assert( pOp>p->aOp ); - assert( pOp[-1].p4type==P4_COLLSEQ ); - assert( pOp[-1].opcode==OP_CollSeq ); - ctx.pColl = pOp[-1].p4.pColl; - } (ctx.pFunc->xStep)(&ctx, n, apVal); /* IMP: R-24505-23230 */ if( ctx.isError ){ - sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s)); + sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&t)); rc = ctx.isError; } if( ctx.skipFlag ){ @@ -73688,9 +74693,7 @@ case OP_AggStep: { i = pOp[-1].p1; if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1); } - - sqlite3VdbeMemRelease(&ctx.s); - + sqlite3VdbeMemRelease(&t); break; } @@ -74140,27 +75143,14 @@ case OP_VColumn: { pModule = pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); - - /* The output cell may already have a buffer allocated. Move - ** the current contents to sContext.s so in case the user-function - ** can use the already allocated buffer instead of allocating a - ** new one. - */ - sqlite3VdbeMemMove(&sContext.s, pDest); - MemSetTypeFlag(&sContext.s, MEM_Null); - + sContext.pOut = pDest; + MemSetTypeFlag(pDest, MEM_Null); rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2); sqlite3VtabImportErrmsg(p, pVtab); if( sContext.isError ){ rc = sContext.isError; } - - /* Copy the result of the function to the P3 register. We - ** do this regardless of whether or not an error occurred to ensure any - ** dynamic allocation in sContext.s (a Mem struct) is released. - */ - sqlite3VdbeChangeEncoding(&sContext.s, encoding); - sqlite3VdbeMemMove(pDest, &sContext.s); + sqlite3VdbeChangeEncoding(pDest, encoding); REGISTER_TRACE(pOp->p3, pDest); UPDATE_MAX_BLOBSIZE(pDest); @@ -74850,7 +75840,7 @@ blob_open_out: if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); sqlite3DbFree(db, pBlob); } - sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr); + sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); sqlite3ParserReset(pParse); sqlite3StackFree(db, pParse); @@ -74903,7 +75893,7 @@ static int blobReadWrite( if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){ /* Request is out of range. Return a transient error. */ rc = SQLITE_ERROR; - sqlite3Error(db, SQLITE_ERROR, 0); + sqlite3Error(db, SQLITE_ERROR); }else if( v==0 ){ /* If there is no statement handle, then the blob-handle has ** already been invalidated. Return SQLITE_ABORT in this case. @@ -74983,7 +75973,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ char *zErr; rc = blobSeekToRow(p, iRow, &zErr); if( rc!=SQLITE_OK ){ - sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr); + sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); } assert( rc!=SQLITE_SCHEMA ); @@ -75000,7 +75990,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ /************** End of vdbeblob.c ********************************************/ /************** Begin file vdbesort.c ****************************************/ /* -** 2011 July 9 +** 2011-07-09 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -75011,42 +76001,196 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ ** ************************************************************************* ** This file contains code for the VdbeSorter object, used in concert with -** a VdbeCursor to sort large numbers of keys (as may be required, for -** example, by CREATE INDEX statements on tables too large to fit in main -** memory). +** a VdbeCursor to sort large numbers of keys for CREATE INDEX statements +** or by SELECT statements with ORDER BY clauses that cannot be satisfied +** using indexes and without LIMIT clauses. +** +** The VdbeSorter object implements a multi-threaded external merge sort +** algorithm that is efficient even if the number of elements being sorted +** exceeds the available memory. +** +** Here is the (internal, non-API) interface between this module and the +** rest of the SQLite system: +** +** sqlite3VdbeSorterInit() Create a new VdbeSorter object. +** +** sqlite3VdbeSorterWrite() Add a single new row to the VdbeSorter +** object. The row is a binary blob in the +** OP_MakeRecord format that contains both +** the ORDER BY key columns and result columns +** in the case of a SELECT w/ ORDER BY, or +** the complete record for an index entry +** in the case of a CREATE INDEX. +** +** sqlite3VdbeSorterRewind() Sort all content previously added. +** Position the read cursor on the +** first sorted element. +** +** sqlite3VdbeSorterNext() Advance the read cursor to the next sorted +** element. +** +** sqlite3VdbeSorterRowkey() Return the complete binary blob for the +** row currently under the read cursor. +** +** sqlite3VdbeSorterCompare() Compare the binary blob for the row +** currently under the read cursor against +** another binary blob X and report if +** X is strictly less than the read cursor. +** Used to enforce uniqueness in a +** CREATE UNIQUE INDEX statement. +** +** sqlite3VdbeSorterClose() Close the VdbeSorter object and reclaim +** all resources. +** +** sqlite3VdbeSorterReset() Refurbish the VdbeSorter for reuse. This +** is like Close() followed by Init() only +** much faster. +** +** The interfaces above must be called in a particular order. Write() can +** only occur in between Init()/Reset() and Rewind(). Next(), Rowkey(), and +** Compare() can only occur in between Rewind() and Close()/Reset(). i.e. +** +** Init() +** for each record: Write() +** Rewind() +** Rowkey()/Compare() +** Next() +** Close() +** +** Algorithm: +** +** Records passed to the sorter via calls to Write() are initially held +** unsorted in main memory. Assuming the amount of memory used never exceeds +** a threshold, when Rewind() is called the set of records is sorted using +** an in-memory merge sort. In this case, no temporary files are required +** and subsequent calls to Rowkey(), Next() and Compare() read records +** directly from main memory. +** +** If the amount of space used to store records in main memory exceeds the +** threshold, then the set of records currently in memory are sorted and +** written to a temporary file in "Packed Memory Array" (PMA) format. +** A PMA created at this point is known as a "level-0 PMA". Higher levels +** of PMAs may be created by merging existing PMAs together - for example +** merging two or more level-0 PMAs together creates a level-1 PMA. +** +** The threshold for the amount of main memory to use before flushing +** records to a PMA is roughly the same as the limit configured for the +** page-cache of the main database. Specifically, the threshold is set to +** the value returned by "PRAGMA main.page_size" multipled by +** that returned by "PRAGMA main.cache_size", in bytes. +** +** If the sorter is running in single-threaded mode, then all PMAs generated +** are appended to a single temporary file. Or, if the sorter is running in +** multi-threaded mode then up to (N+1) temporary files may be opened, where +** N is the configured number of worker threads. In this case, instead of +** sorting the records and writing the PMA to a temporary file itself, the +** calling thread usually launches a worker thread to do so. Except, if +** there are already N worker threads running, the main thread does the work +** itself. +** +** The sorter is running in multi-threaded mode if (a) the library was built +** with pre-processor symbol SQLITE_MAX_WORKER_THREADS set to a value greater +** than zero, and (b) worker threads have been enabled at runtime by calling +** sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, ...). +** +** When Rewind() is called, any data remaining in memory is flushed to a +** final PMA. So at this point the data is stored in some number of sorted +** PMAs within temporary files on disk. +** +** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the +** sorter is running in single-threaded mode, then these PMAs are merged +** incrementally as keys are retreived from the sorter by the VDBE. The +** MergeEngine object, described in further detail below, performs this +** merge. +** +** Or, if running in multi-threaded mode, then a background thread is +** launched to merge the existing PMAs. Once the background thread has +** merged T bytes of data into a single sorted PMA, the main thread +** begins reading keys from that PMA while the background thread proceeds +** with merging the next T bytes of data. And so on. +** +** Parameter T is set to half the value of the memory threshold used +** by Write() above to determine when to create a new PMA. +** +** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when +** Rewind() is called, then a hierarchy of incremental-merges is used. +** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on +** disk are merged together. Then T bytes of data from the second set, and +** so on, such that no operation ever merges more than SORTER_MAX_MERGE_COUNT +** PMAs at a time. This done is to improve locality. +** +** If running in multi-threaded mode and there are more than +** SORTER_MAX_MERGE_COUNT PMAs on disk when Rewind() is called, then more +** than one background thread may be created. Specifically, there may be +** one background thread for each temporary file on disk, and one background +** thread to merge the output of each of the others to a single PMA for +** the main thread to read from. */ - - -typedef struct VdbeSorterIter VdbeSorterIter; -typedef struct SorterRecord SorterRecord; -typedef struct FileWriter FileWriter; +/* +** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various +** messages to stderr that may be helpful in understanding the performance +** characteristics of the sorter in multi-threaded mode. +*/ +#if 0 +# define SQLITE_DEBUG_SORTER_THREADS 1 +#endif /* -** NOTES ON DATA STRUCTURE USED FOR N-WAY MERGES: +** Private objects used by the sorter +*/ +typedef struct MergeEngine MergeEngine; /* Merge PMAs together */ +typedef struct PmaReader PmaReader; /* Incrementally read one PMA */ +typedef struct PmaWriter PmaWriter; /* Incrementally write one PMA */ +typedef struct SorterRecord SorterRecord; /* A record being sorted */ +typedef struct SortSubtask SortSubtask; /* A sub-task in the sort process */ +typedef struct SorterFile SorterFile; /* Temporary file object wrapper */ +typedef struct SorterList SorterList; /* In-memory list of records */ +typedef struct IncrMerger IncrMerger; /* Read & merge multiple PMAs */ + +/* +** A container for a temp file handle and the current amount of data +** stored in the file. +*/ +struct SorterFile { + sqlite3_file *pFd; /* File handle */ + i64 iEof; /* Bytes of data stored in pFd */ +}; + +/* +** An in-memory list of objects to be sorted. ** -** As keys are added to the sorter, they are written to disk in a series -** of sorted packed-memory-arrays (PMAs). The size of each PMA is roughly -** the same as the cache-size allowed for temporary databases. In order -** to allow the caller to extract keys from the sorter in sorted order, -** all PMAs currently stored on disk must be merged together. This comment -** describes the data structure used to do so. The structure supports -** merging any number of arrays in a single pass with no redundant comparison -** operations. +** If aMemory==0 then each object is allocated separately and the objects +** are connected using SorterRecord.u.pNext. If aMemory!=0 then all objects +** are stored in the aMemory[] bulk memory, one right after the other, and +** are connected using SorterRecord.u.iNext. +*/ +struct SorterList { + SorterRecord *pList; /* Linked list of records */ + u8 *aMemory; /* If non-NULL, bulk memory to hold pList */ + int szPMA; /* Size of pList as PMA in bytes */ +}; + +/* +** The MergeEngine object is used to combine two or more smaller PMAs into +** one big PMA using a merge operation. Separate PMAs all need to be +** combined into one big PMA in order to be able to step through the sorted +** records in order. ** -** The aIter[] array contains an iterator for each of the PMAs being merged. -** An aIter[] iterator either points to a valid key or else is at EOF. For -** the purposes of the paragraphs below, we assume that the array is actually -** N elements in size, where N is the smallest power of 2 greater to or equal -** to the number of iterators being merged. The extra aIter[] elements are -** treated as if they are empty (always at EOF). +** The aReadr[] array contains a PmaReader object for each of the PMAs being +** merged. An aReadr[] object either points to a valid key or else is at EOF. +** ("EOF" means "End Of File". When aReadr[] is at EOF there is no more data.) +** For the purposes of the paragraphs below, we assume that the array is +** actually N elements in size, where N is the smallest power of 2 greater +** to or equal to the number of PMAs being merged. The extra aReadr[] elements +** are treated as if they are empty (always at EOF). ** ** The aTree[] array is also N elements in size. The value of N is stored in -** the VdbeSorter.nTree variable. +** the MergeEngine.nTree variable. ** ** The final (N/2) elements of aTree[] contain the results of comparing -** pairs of iterator keys together. Element i contains the result of -** comparing aIter[2*i-N] and aIter[2*i-N+1]. Whichever key is smaller, the +** pairs of PMA keys together. Element i contains the result of +** comparing aReadr[2*i-N] and aReadr[2*i-N+1]. Whichever key is smaller, the ** aTree element is set to the index of it. ** ** For the purposes of this comparison, EOF is considered greater than any @@ -75054,34 +76198,34 @@ typedef struct FileWriter FileWriter; ** values), it doesn't matter which index is stored. ** ** The (N/4) elements of aTree[] that precede the final (N/2) described -** above contains the index of the smallest of each block of 4 iterators. -** And so on. So that aTree[1] contains the index of the iterator that +** above contains the index of the smallest of each block of 4 PmaReaders +** And so on. So that aTree[1] contains the index of the PmaReader that ** currently points to the smallest key value. aTree[0] is unused. ** ** Example: ** -** aIter[0] -> Banana -** aIter[1] -> Feijoa -** aIter[2] -> Elderberry -** aIter[3] -> Currant -** aIter[4] -> Grapefruit -** aIter[5] -> Apple -** aIter[6] -> Durian -** aIter[7] -> EOF +** aReadr[0] -> Banana +** aReadr[1] -> Feijoa +** aReadr[2] -> Elderberry +** aReadr[3] -> Currant +** aReadr[4] -> Grapefruit +** aReadr[5] -> Apple +** aReadr[6] -> Durian +** aReadr[7] -> EOF ** ** aTree[] = { X, 5 0, 5 0, 3, 5, 6 } ** ** The current element is "Apple" (the value of the key indicated by -** iterator 5). When the Next() operation is invoked, iterator 5 will +** PmaReader 5). When the Next() operation is invoked, PmaReader 5 will ** be advanced to the next key in its segment. Say the next key is ** "Eggplant": ** -** aIter[5] -> Eggplant +** aReadr[5] -> Eggplant ** -** The contents of aTree[] are updated first by comparing the new iterator -** 5 key to the current key of iterator 4 (still "Grapefruit"). The iterator +** The contents of aTree[] are updated first by comparing the new PmaReader +** 5 key to the current key of PmaReader 4 (still "Grapefruit"). The PmaReader ** 5 value is still smaller, so aTree[6] is set to 5. And so on up the tree. -** The value of iterator 6 - "Durian" - is now smaller than that of iterator +** The value of PmaReader 6 - "Durian" - is now smaller than that of PmaReader ** 5, so aTree[3] is set to 6. Key 0 is smaller than key 6 (Bananafile2. And instead of using a +** background thread to prepare data for the PmaReader, with a single +** threaded IncrMerger the allocate part of pTask->file2 is "refilled" with +** keys from pMerger by the calling thread whenever the PmaReader runs out +** of data. */ -struct FileWriter { +struct IncrMerger { + SortSubtask *pTask; /* Task that owns this merger */ + MergeEngine *pMerger; /* Merge engine thread reads data from */ + i64 iStartOff; /* Offset to start writing file at */ + int mxSz; /* Maximum bytes of data to store */ + int bEof; /* Set to true when merge is finished */ + int bUseThread; /* True to use a bg thread for this object */ + SorterFile aFile[2]; /* aFile[0] for reading, [1] for writing */ +}; + +/* +** An instance of this object is used for writing a PMA. +** +** The PMA is written one record at a time. Each record is of an arbitrary +** size. But I/O is more efficient if it occurs in page-sized blocks where +** each block is aligned on a page boundary. This object caches writes to +** the PMA so that aligned, page-size blocks are written. +*/ +struct PmaWriter { int eFWErr; /* Non-zero if in an error state */ u8 *aBuffer; /* Pointer to write buffer */ int nBuffer; /* Size of write buffer in bytes */ int iBufStart; /* First byte of buffer to write */ int iBufEnd; /* Last byte of buffer to write */ i64 iWriteOff; /* Offset of start of buffer in file */ - sqlite3_file *pFile; /* File to write to */ + sqlite3_file *pFd; /* File handle to write to */ }; /* -** A structure to store a single record. All in-memory records are connected -** together into a linked list headed at VdbeSorter.pRecord using the -** SorterRecord.pNext pointer. +** This object is the header on a single record while that record is being +** held in memory and prior to being written out as part of a PMA. +** +** How the linked list is connected depends on how memory is being managed +** by this module. If using a separate allocation for each in-memory record +** (VdbeSorter.list.aMemory==0), then the list is always connected using the +** SorterRecord.u.pNext pointers. +** +** Or, if using the single large allocation method (VdbeSorter.list.aMemory!=0), +** then while records are being accumulated the list is linked using the +** SorterRecord.u.iNext offset. This is because the aMemory[] array may +** be sqlite3Realloc()ed while records are being accumulated. Once the VM +** has finished passing records to the sorter, or when the in-memory buffer +** is full, the list is sorted. As part of the sorting process, it is +** converted to use the SorterRecord.u.pNext pointers. See function +** vdbeSorterSort() for details. */ struct SorterRecord { - void *pVal; - int nVal; - SorterRecord *pNext; + int nVal; /* Size of the record in bytes */ + union { + SorterRecord *pNext; /* Pointer to next record in list */ + int iNext; /* Offset within aMemory of next record */ + } u; + /* The data for the record immediately follows this header */ }; -/* Minimum allowable value for the VdbeSorter.nWorking variable */ +/* Return a pointer to the buffer containing the record data for SorterRecord +** object p. Should be used as if: +** +** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; } +*/ +#define SRVAL(p) ((void*)((SorterRecord*)(p) + 1)) + +/* The minimum PMA size is set to this value multiplied by the database +** page size in bytes. */ #define SORTER_MIN_WORKING 10 -/* Maximum number of segments to merge in a single pass. */ +/* Maximum number of PMAs that a single MergeEngine can merge */ #define SORTER_MAX_MERGE_COUNT 16 +static int vdbeIncrSwap(IncrMerger*); +static void vdbeIncrFree(IncrMerger *); + /* -** Free all memory belonging to the VdbeSorterIter object passed as the second +** Free all memory belonging to the PmaReader object passed as the ** argument. All structure fields are set to zero before returning. */ -static void vdbeSorterIterZero(sqlite3 *db, VdbeSorterIter *pIter){ - sqlite3DbFree(db, pIter->aAlloc); - sqlite3DbFree(db, pIter->aBuffer); - memset(pIter, 0, sizeof(VdbeSorterIter)); +static void vdbePmaReaderClear(PmaReader *pReadr){ + sqlite3_free(pReadr->aAlloc); + sqlite3_free(pReadr->aBuffer); + if( pReadr->aMap ) sqlite3OsUnfetch(pReadr->pFd, 0, pReadr->aMap); + vdbeIncrFree(pReadr->pIncr); + memset(pReadr, 0, sizeof(PmaReader)); } /* -** Read nByte bytes of data from the stream of data iterated by object p. +** Read the next nByte bytes of data from the PMA p. ** If successful, set *ppOut to point to a buffer containing the data ** and return SQLITE_OK. Otherwise, if an error occurs, return an SQLite ** error code. ** -** The buffer indicated by *ppOut may only be considered valid until the +** The buffer returned in *ppOut is only valid until the ** next call to this function. */ -static int vdbeSorterIterRead( - sqlite3 *db, /* Database handle (for malloc) */ - VdbeSorterIter *p, /* Iterator */ +static int vdbePmaReadBlob( + PmaReader *p, /* PmaReader from which to take the blob */ int nByte, /* Bytes of data to read */ u8 **ppOut /* OUT: Pointer to buffer containing data */ ){ int iBuf; /* Offset within buffer to read from */ int nAvail; /* Bytes of data available in buffer */ + + if( p->aMap ){ + *ppOut = &p->aMap[p->iReadOff]; + p->iReadOff += nByte; + return SQLITE_OK; + } + assert( p->aBuffer ); /* If there is no more data to be read from the buffer, read the next @@ -75200,8 +76493,8 @@ static int vdbeSorterIterRead( } assert( nRead>0 ); - /* Read data from the file. Return early if an error occurs. */ - rc = sqlite3OsRead(p->pFile, p->aBuffer, nRead, p->iReadOff); + /* Readr data from the file. Return early if an error occurs. */ + rc = sqlite3OsRead(p->pFd, p->aBuffer, nRead, p->iReadOff); assert( rc!=SQLITE_IOERR_SHORT_READ ); if( rc!=SQLITE_OK ) return rc; } @@ -75221,11 +76514,13 @@ static int vdbeSorterIterRead( /* Extend the p->aAlloc[] allocation if required. */ if( p->nAllocnAlloc*2; + u8 *aNew; + int nNew = MAX(128, p->nAlloc*2); while( nByte>nNew ) nNew = nNew*2; - p->aAlloc = sqlite3DbReallocOrFree(db, p->aAlloc, nNew); - if( !p->aAlloc ) return SQLITE_NOMEM; + aNew = sqlite3Realloc(p->aAlloc, nNew); + if( !aNew ) return SQLITE_NOMEM; p->nAlloc = nNew; + p->aAlloc = aNew; } /* Copy as much data as is available in the buffer into the start of @@ -75237,13 +76532,13 @@ static int vdbeSorterIterRead( /* The following loop copies up to p->nBuffer bytes per iteration into ** the p->aAlloc[] buffer. */ while( nRem>0 ){ - int rc; /* vdbeSorterIterRead() return code */ + int rc; /* vdbePmaReadBlob() return code */ int nCopy; /* Number of bytes to copy */ u8 *aNext; /* Pointer to buffer to copy data from */ nCopy = nRem; if( nRem>p->nBuffer ) nCopy = p->nBuffer; - rc = vdbeSorterIterRead(db, p, nCopy, &aNext); + rc = vdbePmaReadBlob(p, nCopy, &aNext); if( rc!=SQLITE_OK ) return rc; assert( aNext!=p->aAlloc ); memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy); @@ -75260,108 +76555,174 @@ static int vdbeSorterIterRead( ** Read a varint from the stream of data accessed by p. Set *pnOut to ** the value read. */ -static int vdbeSorterIterVarint(sqlite3 *db, VdbeSorterIter *p, u64 *pnOut){ +static int vdbePmaReadVarint(PmaReader *p, u64 *pnOut){ int iBuf; - iBuf = p->iReadOff % p->nBuffer; - if( iBuf && (p->nBuffer-iBuf)>=9 ){ - p->iReadOff += sqlite3GetVarint(&p->aBuffer[iBuf], pnOut); + if( p->aMap ){ + p->iReadOff += sqlite3GetVarint(&p->aMap[p->iReadOff], pnOut); }else{ - u8 aVarint[16], *a; - int i = 0, rc; - do{ - rc = vdbeSorterIterRead(db, p, 1, &a); - if( rc ) return rc; - aVarint[(i++)&0xf] = a[0]; - }while( (a[0]&0x80)!=0 ); - sqlite3GetVarint(aVarint, pnOut); + iBuf = p->iReadOff % p->nBuffer; + if( iBuf && (p->nBuffer-iBuf)>=9 ){ + p->iReadOff += sqlite3GetVarint(&p->aBuffer[iBuf], pnOut); + }else{ + u8 aVarint[16], *a; + int i = 0, rc; + do{ + rc = vdbePmaReadBlob(p, 1, &a); + if( rc ) return rc; + aVarint[(i++)&0xf] = a[0]; + }while( (a[0]&0x80)!=0 ); + sqlite3GetVarint(aVarint, pnOut); + } } return SQLITE_OK; } +/* +** Attempt to memory map file pFile. If successful, set *pp to point to the +** new mapping and return SQLITE_OK. If the mapping is not attempted +** (because the file is too large or the VFS layer is configured not to use +** mmap), return SQLITE_OK and set *pp to NULL. +** +** Or, if an error occurs, return an SQLite error code. The final value of +** *pp is undefined in this case. +*/ +static int vdbeSorterMapFile(SortSubtask *pTask, SorterFile *pFile, u8 **pp){ + int rc = SQLITE_OK; + if( pFile->iEof<=(i64)(pTask->pSorter->db->nMaxSorterMmap) ){ + sqlite3_file *pFd = pFile->pFd; + if( pFd->pMethods->iVersion>=3 ){ + rc = sqlite3OsFetch(pFd, 0, (int)pFile->iEof, (void**)pp); + testcase( rc!=SQLITE_OK ); + } + } + return rc; +} /* -** Advance iterator pIter to the next key in its PMA. Return SQLITE_OK if -** no error occurs, or an SQLite error code if one does. +** Attach PmaReader pReadr to file pFile (if it is not already attached to +** that file) and seek it to offset iOff within the file. Return SQLITE_OK +** if successful, or an SQLite error code if an error occurs. */ -static int vdbeSorterIterNext( - sqlite3 *db, /* Database handle (for sqlite3DbMalloc() ) */ - VdbeSorterIter *pIter /* Iterator to advance */ +static int vdbePmaReaderSeek( + SortSubtask *pTask, /* Task context */ + PmaReader *pReadr, /* Reader whose cursor is to be moved */ + SorterFile *pFile, /* Sorter file to read from */ + i64 iOff /* Offset in pFile */ ){ - int rc; /* Return Code */ - u64 nRec = 0; /* Size of record in bytes */ + int rc = SQLITE_OK; - if( pIter->iReadOff>=pIter->iEof ){ - /* This is an EOF condition */ - vdbeSorterIterZero(db, pIter); - return SQLITE_OK; + assert( pReadr->pIncr==0 || pReadr->pIncr->bEof==0 ); + + if( sqlite3FaultSim(201) ) return SQLITE_IOERR_READ; + if( pReadr->aMap ){ + sqlite3OsUnfetch(pReadr->pFd, 0, pReadr->aMap); + pReadr->aMap = 0; } + pReadr->iReadOff = iOff; + pReadr->iEof = pFile->iEof; + pReadr->pFd = pFile->pFd; - rc = vdbeSorterIterVarint(db, pIter, &nRec); - if( rc==SQLITE_OK ){ - pIter->nKey = (int)nRec; - rc = vdbeSorterIterRead(db, pIter, (int)nRec, &pIter->aKey); + rc = vdbeSorterMapFile(pTask, pFile, &pReadr->aMap); + if( rc==SQLITE_OK && pReadr->aMap==0 ){ + int pgsz = pTask->pSorter->pgsz; + int iBuf = pReadr->iReadOff % pgsz; + if( pReadr->aBuffer==0 ){ + pReadr->aBuffer = (u8*)sqlite3Malloc(pgsz); + if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM; + pReadr->nBuffer = pgsz; + } + if( rc==SQLITE_OK && iBuf ){ + int nRead = pgsz - iBuf; + if( (pReadr->iReadOff + nRead) > pReadr->iEof ){ + nRead = (int)(pReadr->iEof - pReadr->iReadOff); + } + rc = sqlite3OsRead( + pReadr->pFd, &pReadr->aBuffer[iBuf], nRead, pReadr->iReadOff + ); + testcase( rc!=SQLITE_OK ); + } } return rc; } /* -** Initialize iterator pIter to scan through the PMA stored in file pFile -** starting at offset iStart and ending at offset iEof-1. This function -** leaves the iterator pointing to the first key in the PMA (or EOF if the -** PMA is empty). +** Advance PmaReader pReadr to the next key in its PMA. Return SQLITE_OK if +** no error occurs, or an SQLite error code if one does. */ -static int vdbeSorterIterInit( - sqlite3 *db, /* Database handle */ - const VdbeSorter *pSorter, /* Sorter object */ - i64 iStart, /* Start offset in pFile */ - VdbeSorterIter *pIter, /* Iterator to populate */ - i64 *pnByte /* IN/OUT: Increment this value by PMA size */ -){ - int rc = SQLITE_OK; - int nBuf; +static int vdbePmaReaderNext(PmaReader *pReadr){ + int rc = SQLITE_OK; /* Return Code */ + u64 nRec = 0; /* Size of record in bytes */ - nBuf = sqlite3BtreeGetPageSize(db->aDb[0].pBt); - assert( pSorter->iWriteOff>iStart ); - assert( pIter->aAlloc==0 ); - assert( pIter->aBuffer==0 ); - pIter->pFile = pSorter->pTemp1; - pIter->iReadOff = iStart; - pIter->nAlloc = 128; - pIter->aAlloc = (u8 *)sqlite3DbMallocRaw(db, pIter->nAlloc); - pIter->nBuffer = nBuf; - pIter->aBuffer = (u8 *)sqlite3DbMallocRaw(db, nBuf); - - if( !pIter->aBuffer ){ - rc = SQLITE_NOMEM; - }else{ - int iBuf; - - iBuf = iStart % nBuf; - if( iBuf ){ - int nRead = nBuf - iBuf; - if( (iStart + nRead) > pSorter->iWriteOff ){ - nRead = (int)(pSorter->iWriteOff - iStart); + if( pReadr->iReadOff>=pReadr->iEof ){ + IncrMerger *pIncr = pReadr->pIncr; + int bEof = 1; + if( pIncr ){ + rc = vdbeIncrSwap(pIncr); + if( rc==SQLITE_OK && pIncr->bEof==0 ){ + rc = vdbePmaReaderSeek( + pIncr->pTask, pReadr, &pIncr->aFile[0], pIncr->iStartOff + ); + bEof = 0; } - rc = sqlite3OsRead( - pSorter->pTemp1, &pIter->aBuffer[iBuf], nRead, iStart - ); } - if( rc==SQLITE_OK ){ - u64 nByte; /* Size of PMA in bytes */ - pIter->iEof = pSorter->iWriteOff; - rc = vdbeSorterIterVarint(db, pIter, &nByte); - pIter->iEof = pIter->iReadOff + nByte; - *pnByte += nByte; + if( bEof ){ + /* This is an EOF condition */ + vdbePmaReaderClear(pReadr); + testcase( rc!=SQLITE_OK ); + return rc; } } if( rc==SQLITE_OK ){ - rc = vdbeSorterIterNext(db, pIter); + rc = vdbePmaReadVarint(pReadr, &nRec); + } + if( rc==SQLITE_OK ){ + pReadr->nKey = (int)nRec; + rc = vdbePmaReadBlob(pReadr, (int)nRec, &pReadr->aKey); + testcase( rc!=SQLITE_OK ); + } + + return rc; +} + +/* +** Initialize PmaReader pReadr to scan through the PMA stored in file pFile +** starting at offset iStart and ending at offset iEof-1. This function +** leaves the PmaReader pointing to the first key in the PMA (or EOF if the +** PMA is empty). +** +** If the pnByte parameter is NULL, then it is assumed that the file +** contains a single PMA, and that that PMA omits the initial length varint. +*/ +static int vdbePmaReaderInit( + SortSubtask *pTask, /* Task context */ + SorterFile *pFile, /* Sorter file to read from */ + i64 iStart, /* Start offset in pFile */ + PmaReader *pReadr, /* PmaReader to populate */ + i64 *pnByte /* IN/OUT: Increment this value by PMA size */ +){ + int rc; + + assert( pFile->iEof>iStart ); + assert( pReadr->aAlloc==0 && pReadr->nAlloc==0 ); + assert( pReadr->aBuffer==0 ); + assert( pReadr->aMap==0 ); + + rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart); + if( rc==SQLITE_OK ){ + u64 nByte; /* Size of PMA in bytes */ + rc = vdbePmaReadVarint(pReadr, &nByte); + pReadr->iEof = pReadr->iReadOff + nByte; + *pnByte += nByte; + } + + if( rc==SQLITE_OK ){ + rc = vdbePmaReaderNext(pReadr); } return rc; } @@ -75369,125 +76730,130 @@ static int vdbeSorterIterInit( /* ** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, -** size nKey2 bytes). Argument pKeyInfo supplies the collation functions -** used by the comparison. If an error occurs, return an SQLite error code. -** Otherwise, return SQLITE_OK and set *pRes to a negative, zero or positive -** value, depending on whether key1 is smaller, equal to or larger than key2. +** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences +** used by the comparison. Return the result of the comparison. ** -** If the bOmitRowid argument is non-zero, assume both keys end in a rowid -** field. For the purposes of the comparison, ignore it. Also, if bOmitRowid -** is true and key1 contains even a single NULL value, it is considered to -** be less than key2. Even if key2 also contains NULL values. +** Before returning, object (pTask->pUnpacked) is populated with the +** unpacked version of key2. Or, if pKey2 is passed a NULL pointer, then it +** is assumed that the (pTask->pUnpacked) structure already contains the +** unpacked key to use as key2. ** -** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace -** has been allocated and contains an unpacked record that is used as key2. +** If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set +** to SQLITE_NOMEM. */ -static void vdbeSorterCompare( - const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */ - int nKeyCol, /* Num of columns. 0 means "all" */ +static int vdbeSorterCompare( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ const void *pKey1, int nKey1, /* Left side of comparison */ - const void *pKey2, int nKey2, /* Right side of comparison */ - int *pRes /* OUT: Result of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ ){ - KeyInfo *pKeyInfo = pCsr->pKeyInfo; - VdbeSorter *pSorter = pCsr->pSorter; - UnpackedRecord *r2 = pSorter->pUnpacked; - int i; - + UnpackedRecord *r2 = pTask->pUnpacked; if( pKey2 ){ - sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2); + sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); } - - if( nKeyCol ){ - r2->nField = nKeyCol; - for(i=0; iaMem[i].flags & MEM_Null ){ - *pRes = -1; - return; - } - } - assert( r2->default_rc==0 ); - } - - *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2, 0); -} - -/* -** This function is called to compare two iterator keys when merging -** multiple b-tree segments. Parameter iOut is the index of the aTree[] -** value to recalculate. -*/ -static int vdbeSorterDoCompare(const VdbeCursor *pCsr, int iOut){ - VdbeSorter *pSorter = pCsr->pSorter; - int i1; - int i2; - int iRes; - VdbeSorterIter *p1; - VdbeSorterIter *p2; - - assert( iOutnTree && iOut>0 ); - - if( iOut>=(pSorter->nTree/2) ){ - i1 = (iOut - pSorter->nTree/2) * 2; - i2 = i1 + 1; - }else{ - i1 = pSorter->aTree[iOut*2]; - i2 = pSorter->aTree[iOut*2+1]; - } - - p1 = &pSorter->aIter[i1]; - p2 = &pSorter->aIter[i2]; - - if( p1->pFile==0 ){ - iRes = i2; - }else if( p2->pFile==0 ){ - iRes = i1; - }else{ - int res; - assert( pCsr->pSorter->pUnpacked!=0 ); /* allocated in vdbeSorterMerge() */ - vdbeSorterCompare( - pCsr, 0, p1->aKey, p1->nKey, p2->aKey, p2->nKey, &res - ); - if( res<=0 ){ - iRes = i1; - }else{ - iRes = i2; - } - } - - pSorter->aTree[iOut] = iRes; - return SQLITE_OK; + return sqlite3VdbeRecordCompare(nKey1, pKey1, r2); } /* ** Initialize the temporary index cursor just opened as a sorter cursor. +** +** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField) +** to determine the number of fields that should be compared from the +** records being sorted. However, if the value passed as argument nField +** is non-zero and the sorter is able to guarantee a stable sort, nField +** is used instead. This is used when sorting records for a CREATE INDEX +** statement. In this case, keys are always delivered to the sorter in +** order of the primary key, which happens to be make up the final part +** of the records being sorted. So if the sort is stable, there is never +** any reason to compare PK fields and they can be ignored for a small +** performance boost. +** +** The sorter can guarantee a stable sort when running in single-threaded +** mode, but not in multi-threaded mode. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ -SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *db, VdbeCursor *pCsr){ +SQLITE_PRIVATE int sqlite3VdbeSorterInit( + sqlite3 *db, /* Database connection (for malloc()) */ + int nField, /* Number of key fields in each record */ + VdbeCursor *pCsr /* Cursor that holds the new sorter */ +){ int pgsz; /* Page size of main database */ + int i; /* Used to iterate through aTask[] */ int mxCache; /* Cache size */ VdbeSorter *pSorter; /* The new sorter */ - char *d; /* Dummy */ + KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */ + int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */ + int sz; /* Size of pSorter in bytes */ + int rc = SQLITE_OK; +#if SQLITE_MAX_WORKER_THREADS==0 +# define nWorker 0 +#else + int nWorker; +#endif + + /* Initialize the upper limit on the number of worker threads */ +#if SQLITE_MAX_WORKER_THREADS>0 + if( sqlite3TempInMemory(db) || sqlite3GlobalConfig.bCoreMutex==0 ){ + nWorker = 0; + }else{ + nWorker = db->aLimit[SQLITE_LIMIT_WORKER_THREADS]; + } +#endif + + /* Do not allow the total number of threads (main thread + all workers) + ** to exceed the maximum merge count */ +#if SQLITE_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT + if( nWorker>=SORTER_MAX_MERGE_COUNT ){ + nWorker = SORTER_MAX_MERGE_COUNT-1; + } +#endif assert( pCsr->pKeyInfo && pCsr->pBt==0 ); - pCsr->pSorter = pSorter = sqlite3DbMallocZero(db, sizeof(VdbeSorter)); + szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*); + sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); + + pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); + pCsr->pSorter = pSorter; if( pSorter==0 ){ - return SQLITE_NOMEM; - } - - pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo, 0, 0, &d); - if( pSorter->pUnpacked==0 ) return SQLITE_NOMEM; - assert( pSorter->pUnpacked==(UnpackedRecord *)d ); + rc = SQLITE_NOMEM; + }else{ + pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); + memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); + pKeyInfo->db = 0; + if( nField && nWorker==0 ) pKeyInfo->nField = nField; + pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); + pSorter->nTask = nWorker + 1; + pSorter->bUseThreads = (pSorter->nTask>1); + pSorter->db = db; + for(i=0; inTask; i++){ + SortSubtask *pTask = &pSorter->aTask[i]; + pTask->pSorter = pSorter; + } - if( !sqlite3TempInMemory(db) ){ - pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); - pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz; - mxCache = db->aDb[0].pSchema->cache_size; - if( mxCachemxPmaSize = mxCache * pgsz; + if( !sqlite3TempInMemory(db) ){ + pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz; + mxCache = db->aDb[0].pSchema->cache_size; + if( mxCachemxPmaSize = mxCache * pgsz; + + /* If the application has not configure scratch memory using + ** SQLITE_CONFIG_SCRATCH then we assume it is OK to do large memory + ** allocations. If scratch memory has been configured, then assume + ** large memory allocations should be avoided to prevent heap + ** fragmentation. + */ + if( sqlite3GlobalConfig.pScratch==0 ){ + assert( pSorter->iMemory==0 ); + pSorter->nMemory = pgsz; + pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); + if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM; + } + } } - return SQLITE_OK; + return rc; } +#undef nWorker /* Defined at the top of this function */ /* ** Free the list of sorted records starting at pRecord. @@ -75496,38 +76862,233 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ SorterRecord *p; SorterRecord *pNext; for(p=pRecord; p; p=pNext){ - pNext = p->pNext; + pNext = p->u.pNext; sqlite3DbFree(db, p); } } +/* +** Free all resources owned by the object indicated by argument pTask. All +** fields of *pTask are zeroed before returning. +*/ +static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){ + sqlite3DbFree(db, pTask->pUnpacked); + pTask->pUnpacked = 0; +#if SQLITE_MAX_WORKER_THREADS>0 + /* pTask->list.aMemory can only be non-zero if it was handed memory + ** from the main thread. That only occurs SQLITE_MAX_WORKER_THREADS>0 */ + if( pTask->list.aMemory ){ + sqlite3_free(pTask->list.aMemory); + pTask->list.aMemory = 0; + }else +#endif + { + assert( pTask->list.aMemory==0 ); + vdbeSorterRecordFree(0, pTask->list.pList); + } + pTask->list.pList = 0; + if( pTask->file.pFd ){ + sqlite3OsCloseFree(pTask->file.pFd); + pTask->file.pFd = 0; + pTask->file.iEof = 0; + } + if( pTask->file2.pFd ){ + sqlite3OsCloseFree(pTask->file2.pFd); + pTask->file2.pFd = 0; + pTask->file2.iEof = 0; + } +} + +#ifdef SQLITE_DEBUG_SORTER_THREADS +static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){ + i64 t; + int iTask = (pTask - pTask->pSorter->aTask); + sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); + fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); +} +static void vdbeSorterRewindDebug(const char *zEvent){ + i64 t; + sqlite3OsCurrentTimeInt64(sqlite3_vfs_find(0), &t); + fprintf(stderr, "%lld:X %s\n", t, zEvent); +} +static void vdbeSorterPopulateDebug( + SortSubtask *pTask, + const char *zEvent +){ + i64 t; + int iTask = (pTask - pTask->pSorter->aTask); + sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); + fprintf(stderr, "%lld:bg%d %s\n", t, iTask, zEvent); +} +static void vdbeSorterBlockDebug( + SortSubtask *pTask, + int bBlocked, + const char *zEvent +){ + if( bBlocked ){ + i64 t; + sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); + fprintf(stderr, "%lld:main %s\n", t, zEvent); + } +} +#else +# define vdbeSorterWorkDebug(x,y) +# define vdbeSorterRewindDebug(y) +# define vdbeSorterPopulateDebug(x,y) +# define vdbeSorterBlockDebug(x,y,z) +#endif + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** Join thread pTask->thread. +*/ +static int vdbeSorterJoinThread(SortSubtask *pTask){ + int rc = SQLITE_OK; + if( pTask->pThread ){ +#ifdef SQLITE_DEBUG_SORTER_THREADS + int bDone = pTask->bDone; +#endif + void *pRet = SQLITE_INT_TO_PTR(SQLITE_ERROR); + vdbeSorterBlockDebug(pTask, !bDone, "enter"); + (void)sqlite3ThreadJoin(pTask->pThread, &pRet); + vdbeSorterBlockDebug(pTask, !bDone, "exit"); + rc = SQLITE_PTR_TO_INT(pRet); + assert( pTask->bDone==1 ); + pTask->bDone = 0; + pTask->pThread = 0; + } + return rc; +} + +/* +** Launch a background thread to run xTask(pIn). +*/ +static int vdbeSorterCreateThread( + SortSubtask *pTask, /* Thread will use this task object */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + assert( pTask->pThread==0 && pTask->bDone==0 ); + return sqlite3ThreadCreate(&pTask->pThread, xTask, pIn); +} + +/* +** Join all outstanding threads launched by SorterWrite() to create +** level-0 PMAs. +*/ +static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){ + int rc = rcin; + int i; + + /* This function is always called by the main user thread. + ** + ** If this function is being called after SorterRewind() has been called, + ** it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread + ** is currently attempt to join one of the other threads. To avoid a race + ** condition where this thread also attempts to join the same object, join + ** thread pSorter->aTask[pSorter->nTask-1].pThread first. */ + for(i=pSorter->nTask-1; i>=0; i--){ + SortSubtask *pTask = &pSorter->aTask[i]; + int rc2 = vdbeSorterJoinThread(pTask); + if( rc==SQLITE_OK ) rc = rc2; + } + return rc; +} +#else +# define vdbeSorterJoinAll(x,rcin) (rcin) +# define vdbeSorterJoinThread(pTask) SQLITE_OK +#endif + +/* +** Allocate a new MergeEngine object capable of handling up to +** nReader PmaReader inputs. +** +** nReader is automatically rounded up to the next power of two. +** nReader may not exceed SORTER_MAX_MERGE_COUNT even after rounding up. +*/ +static MergeEngine *vdbeMergeEngineNew(int nReader){ + int N = 2; /* Smallest power of two >= nReader */ + int nByte; /* Total bytes of space to allocate */ + MergeEngine *pNew; /* Pointer to allocated object to return */ + + assert( nReader<=SORTER_MAX_MERGE_COUNT ); + + while( NnTree = N; + pNew->pTask = 0; + pNew->aReadr = (PmaReader*)&pNew[1]; + pNew->aTree = (int*)&pNew->aReadr[N]; + } + return pNew; +} + +/* +** Free the MergeEngine object passed as the only argument. +*/ +static void vdbeMergeEngineFree(MergeEngine *pMerger){ + int i; + if( pMerger ){ + for(i=0; inTree; i++){ + vdbePmaReaderClear(&pMerger->aReadr[i]); + } + } + sqlite3_free(pMerger); +} + +/* +** Free all resources associated with the IncrMerger object indicated by +** the first argument. +*/ +static void vdbeIncrFree(IncrMerger *pIncr){ + if( pIncr ){ +#if SQLITE_MAX_WORKER_THREADS>0 + if( pIncr->bUseThread ){ + vdbeSorterJoinThread(pIncr->pTask); + if( pIncr->aFile[0].pFd ) sqlite3OsCloseFree(pIncr->aFile[0].pFd); + if( pIncr->aFile[1].pFd ) sqlite3OsCloseFree(pIncr->aFile[1].pFd); + } +#endif + vdbeMergeEngineFree(pIncr->pMerger); + sqlite3_free(pIncr); + } +} + /* ** Reset a sorting cursor back to its original empty state. */ SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){ - if( pSorter->aIter ){ - int i; - for(i=0; inTree; i++){ - vdbeSorterIterZero(db, &pSorter->aIter[i]); - } - sqlite3DbFree(db, pSorter->aIter); - pSorter->aIter = 0; + int i; + (void)vdbeSorterJoinAll(pSorter, SQLITE_OK); + assert( pSorter->bUseThreads || pSorter->pReader==0 ); +#if SQLITE_MAX_WORKER_THREADS>0 + if( pSorter->pReader ){ + vdbePmaReaderClear(pSorter->pReader); + sqlite3DbFree(db, pSorter->pReader); + pSorter->pReader = 0; } - if( pSorter->pTemp1 ){ - sqlite3OsCloseFree(pSorter->pTemp1); - pSorter->pTemp1 = 0; +#endif + vdbeMergeEngineFree(pSorter->pMerger); + pSorter->pMerger = 0; + for(i=0; inTask; i++){ + SortSubtask *pTask = &pSorter->aTask[i]; + vdbeSortSubtaskCleanup(db, pTask); } - vdbeSorterRecordFree(db, pSorter->pRecord); - pSorter->pRecord = 0; - pSorter->iWriteOff = 0; - pSorter->iReadOff = 0; - pSorter->nInMemory = 0; - pSorter->nTree = 0; - pSorter->nPMA = 0; - pSorter->aTree = 0; + if( pSorter->list.aMemory==0 ){ + vdbeSorterRecordFree(0, pSorter->list.pList); + } + pSorter->list.pList = 0; + pSorter->list.szPMA = 0; + pSorter->bUsePMA = 0; + pSorter->iMemory = 0; + pSorter->mxKeysize = 0; + sqlite3DbFree(db, pSorter->pUnpacked); + pSorter->pUnpacked = 0; } - /* ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. */ @@ -75535,54 +77096,110 @@ SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ VdbeSorter *pSorter = pCsr->pSorter; if( pSorter ){ sqlite3VdbeSorterReset(db, pSorter); - sqlite3DbFree(db, pSorter->pUnpacked); + sqlite3_free(pSorter->list.aMemory); sqlite3DbFree(db, pSorter); pCsr->pSorter = 0; } } +#if SQLITE_MAX_MMAP_SIZE>0 +/* +** The first argument is a file-handle open on a temporary file. The file +** is guaranteed to be nByte bytes or smaller in size. This function +** attempts to extend the file to nByte bytes in size and to ensure that +** the VFS has memory mapped it. +** +** Whether or not the file does end up memory mapped of course depends on +** the specific VFS implementation. +*/ +static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){ + if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){ + int rc = sqlite3OsTruncate(pFd, nByte); + if( rc==SQLITE_OK ){ + void *p = 0; + sqlite3OsFetch(pFd, 0, (int)nByte, &p); + sqlite3OsUnfetch(pFd, 0, p); + } + } +} +#else +# define vdbeSorterExtendFile(x,y,z) +#endif + /* ** Allocate space for a file-handle and open a temporary file. If successful, -** set *ppFile to point to the malloc'd file-handle and return SQLITE_OK. -** Otherwise, set *ppFile to 0 and return an SQLite error code. +** set *ppFd to point to the malloc'd file-handle and return SQLITE_OK. +** Otherwise, set *ppFd to 0 and return an SQLite error code. */ -static int vdbeSorterOpenTempFile(sqlite3 *db, sqlite3_file **ppFile){ - int dummy; - return sqlite3OsOpenMalloc(db->pVfs, 0, ppFile, +static int vdbeSorterOpenTempFile( + sqlite3 *db, /* Database handle doing sort */ + i64 nExtend, /* Attempt to extend file to this size */ + sqlite3_file **ppFd +){ + int rc; + rc = sqlite3OsOpenMalloc(db->pVfs, 0, ppFd, SQLITE_OPEN_TEMP_JOURNAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | - SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &dummy + SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &rc ); + if( rc==SQLITE_OK ){ + i64 max = SQLITE_MAX_MMAP_SIZE; + sqlite3OsFileControlHint(*ppFd, SQLITE_FCNTL_MMAP_SIZE, (void*)&max); + if( nExtend>0 ){ + vdbeSorterExtendFile(db, *ppFd, nExtend); + } + } + return rc; } +/* +** If it has not already been allocated, allocate the UnpackedRecord +** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or +** if no allocation was required), or SQLITE_NOMEM otherwise. +*/ +static int vdbeSortAllocUnpacked(SortSubtask *pTask){ + if( pTask->pUnpacked==0 ){ + char *pFree; + pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord( + pTask->pSorter->pKeyInfo, 0, 0, &pFree + ); + assert( pTask->pUnpacked==(UnpackedRecord*)pFree ); + if( pFree==0 ) return SQLITE_NOMEM; + pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField; + pTask->pUnpacked->errCode = 0; + } + return SQLITE_OK; +} + + /* ** Merge the two sorted lists p1 and p2 into a single list. ** Set *ppOut to the head of the new list. */ static void vdbeSorterMerge( - const VdbeCursor *pCsr, /* For pKeyInfo */ + SortSubtask *pTask, /* Calling thread context */ SorterRecord *p1, /* First list to merge */ SorterRecord *p2, /* Second list to merge */ SorterRecord **ppOut /* OUT: Head of merged list */ ){ SorterRecord *pFinal = 0; SorterRecord **pp = &pFinal; - void *pVal2 = p2 ? p2->pVal : 0; + void *pVal2 = p2 ? SRVAL(p2) : 0; while( p1 && p2 ){ int res; - vdbeSorterCompare(pCsr, 0, p1->pVal, p1->nVal, pVal2, p2->nVal, &res); + res = vdbeSorterCompare(pTask, SRVAL(p1), p1->nVal, pVal2, p2->nVal); if( res<=0 ){ *pp = p1; - pp = &p1->pNext; - p1 = p1->pNext; + pp = &p1->u.pNext; + p1 = p1->u.pNext; pVal2 = 0; }else{ *pp = p2; - pp = &p2->pNext; - p2 = p2->pNext; + pp = &p2->u.pNext; + p2 = p2->u.pNext; if( p2==0 ) break; - pVal2 = p2->pVal; + pVal2 = SRVAL(p2); } } *pp = p1 ? p1 : p2; @@ -75590,27 +77207,41 @@ static void vdbeSorterMerge( } /* -** Sort the linked list of records headed at pCsr->pRecord. Return SQLITE_OK -** if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if an error -** occurs. +** Sort the linked list of records headed at pTask->pList. Return +** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if +** an error occurs. */ -static int vdbeSorterSort(const VdbeCursor *pCsr){ +static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ int i; SorterRecord **aSlot; SorterRecord *p; - VdbeSorter *pSorter = pCsr->pSorter; + int rc; + + rc = vdbeSortAllocUnpacked(pTask); + if( rc!=SQLITE_OK ) return rc; aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); if( !aSlot ){ return SQLITE_NOMEM; } - p = pSorter->pRecord; + p = pList->pList; while( p ){ - SorterRecord *pNext = p->pNext; - p->pNext = 0; + SorterRecord *pNext; + if( pList->aMemory ){ + if( (u8*)p==pList->aMemory ){ + pNext = 0; + }else{ + assert( p->u.iNextaMemory) ); + pNext = (SorterRecord*)&pList->aMemory[p->u.iNext]; + } + }else{ + pNext = p->u.pNext; + } + + p->u.pNext = 0; for(i=0; aSlot[i]; i++){ - vdbeSorterMerge(pCsr, p, aSlot[i], &p); + vdbeSorterMerge(pTask, p, aSlot[i], &p); aSlot[i] = 0; } aSlot[i] = p; @@ -75619,42 +77250,43 @@ static int vdbeSorterSort(const VdbeCursor *pCsr){ p = 0; for(i=0; i<64; i++){ - vdbeSorterMerge(pCsr, p, aSlot[i], &p); + vdbeSorterMerge(pTask, p, aSlot[i], &p); } - pSorter->pRecord = p; + pList->pList = p; sqlite3_free(aSlot); - return SQLITE_OK; + assert( pTask->pUnpacked->errCode==SQLITE_OK + || pTask->pUnpacked->errCode==SQLITE_NOMEM + ); + return pTask->pUnpacked->errCode; } /* -** Initialize a file-writer object. +** Initialize a PMA-writer object. */ -static void fileWriterInit( - sqlite3 *db, /* Database (for malloc) */ - sqlite3_file *pFile, /* File to write to */ - FileWriter *p, /* Object to populate */ - i64 iStart /* Offset of pFile to begin writing at */ +static void vdbePmaWriterInit( + sqlite3_file *pFd, /* File handle to write to */ + PmaWriter *p, /* Object to populate */ + int nBuf, /* Buffer size */ + i64 iStart /* Offset of pFd to begin writing at */ ){ - int nBuf = sqlite3BtreeGetPageSize(db->aDb[0].pBt); - - memset(p, 0, sizeof(FileWriter)); - p->aBuffer = (u8 *)sqlite3DbMallocRaw(db, nBuf); + memset(p, 0, sizeof(PmaWriter)); + p->aBuffer = (u8*)sqlite3Malloc(nBuf); if( !p->aBuffer ){ p->eFWErr = SQLITE_NOMEM; }else{ p->iBufEnd = p->iBufStart = (iStart % nBuf); p->iWriteOff = iStart - p->iBufStart; p->nBuffer = nBuf; - p->pFile = pFile; + p->pFd = pFd; } } /* -** Write nData bytes of data to the file-write object. Return SQLITE_OK +** Write nData bytes of data to the PMA. Return SQLITE_OK ** if successful, or an SQLite error code if an error occurs. */ -static void fileWriterWrite(FileWriter *p, u8 *pData, int nData){ +static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){ int nRem = nData; while( nRem>0 && p->eFWErr==0 ){ int nCopy = nRem; @@ -75665,7 +77297,7 @@ static void fileWriterWrite(FileWriter *p, u8 *pData, int nData){ memcpy(&p->aBuffer[p->iBufEnd], &pData[nData-nRem], nCopy); p->iBufEnd += nCopy; if( p->iBufEnd==p->nBuffer ){ - p->eFWErr = sqlite3OsWrite(p->pFile, + p->eFWErr = sqlite3OsWrite(p->pFd, &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, p->iWriteOff + p->iBufStart ); @@ -75679,43 +77311,44 @@ static void fileWriterWrite(FileWriter *p, u8 *pData, int nData){ } /* -** Flush any buffered data to disk and clean up the file-writer object. -** The results of using the file-writer after this call are undefined. +** Flush any buffered data to disk and clean up the PMA-writer object. +** The results of using the PMA-writer after this call are undefined. ** Return SQLITE_OK if flushing the buffered data succeeds or is not ** required. Otherwise, return an SQLite error code. ** ** Before returning, set *piEof to the offset immediately following the ** last byte written to the file. */ -static int fileWriterFinish(sqlite3 *db, FileWriter *p, i64 *piEof){ +static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){ int rc; if( p->eFWErr==0 && ALWAYS(p->aBuffer) && p->iBufEnd>p->iBufStart ){ - p->eFWErr = sqlite3OsWrite(p->pFile, + p->eFWErr = sqlite3OsWrite(p->pFd, &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, p->iWriteOff + p->iBufStart ); } *piEof = (p->iWriteOff + p->iBufEnd); - sqlite3DbFree(db, p->aBuffer); + sqlite3_free(p->aBuffer); rc = p->eFWErr; - memset(p, 0, sizeof(FileWriter)); + memset(p, 0, sizeof(PmaWriter)); return rc; } /* -** Write value iVal encoded as a varint to the file-write object. Return +** Write value iVal encoded as a varint to the PMA. Return ** SQLITE_OK if successful, or an SQLite error code if an error occurs. */ -static void fileWriterWriteVarint(FileWriter *p, u64 iVal){ +static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){ int nByte; u8 aByte[10]; nByte = sqlite3PutVarint(aByte, iVal); - fileWriterWrite(p, aByte, nByte); + vdbePmaWriteBlob(p, aByte, nByte); } /* -** Write the current contents of the in-memory linked-list to a PMA. Return -** SQLITE_OK if successful, or an SQLite error code otherwise. +** Write the current contents of in-memory linked-list pList to a level-0 +** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if +** successful, or an SQLite error code otherwise. ** ** The format of a PMA is: ** @@ -75726,76 +77359,246 @@ static void fileWriterWriteVarint(FileWriter *p, u64 iVal){ ** Each record consists of a varint followed by a blob of data (the ** key). The varint is the number of bytes in the blob of data. */ -static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){ +static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){ + sqlite3 *db = pTask->pSorter->db; int rc = SQLITE_OK; /* Return code */ - VdbeSorter *pSorter = pCsr->pSorter; - FileWriter writer; + PmaWriter writer; /* Object used to write to the file */ - memset(&writer, 0, sizeof(FileWriter)); +#ifdef SQLITE_DEBUG + /* Set iSz to the expected size of file pTask->file after writing the PMA. + ** This is used by an assert() statement at the end of this function. */ + i64 iSz = pList->szPMA + sqlite3VarintLen(pList->szPMA) + pTask->file.iEof; +#endif - if( pSorter->nInMemory==0 ){ - assert( pSorter->pRecord==0 ); - return rc; - } - - rc = vdbeSorterSort(pCsr); + vdbeSorterWorkDebug(pTask, "enter"); + memset(&writer, 0, sizeof(PmaWriter)); + assert( pList->szPMA>0 ); /* If the first temporary PMA file has not been opened, open it now. */ - if( rc==SQLITE_OK && pSorter->pTemp1==0 ){ - rc = vdbeSorterOpenTempFile(db, &pSorter->pTemp1); - assert( rc!=SQLITE_OK || pSorter->pTemp1 ); - assert( pSorter->iWriteOff==0 ); - assert( pSorter->nPMA==0 ); + if( pTask->file.pFd==0 ){ + rc = vdbeSorterOpenTempFile(db, 0, &pTask->file.pFd); + assert( rc!=SQLITE_OK || pTask->file.pFd ); + assert( pTask->file.iEof==0 ); + assert( pTask->nPMA==0 ); + } + + /* Try to get the file to memory map */ + if( rc==SQLITE_OK ){ + vdbeSorterExtendFile(db, pTask->file.pFd, pTask->file.iEof+pList->szPMA+9); + } + + /* Sort the list */ + if( rc==SQLITE_OK ){ + rc = vdbeSorterSort(pTask, pList); } if( rc==SQLITE_OK ){ SorterRecord *p; SorterRecord *pNext = 0; - fileWriterInit(db, pSorter->pTemp1, &writer, pSorter->iWriteOff); - pSorter->nPMA++; - fileWriterWriteVarint(&writer, pSorter->nInMemory); - for(p=pSorter->pRecord; p; p=pNext){ - pNext = p->pNext; - fileWriterWriteVarint(&writer, p->nVal); - fileWriterWrite(&writer, p->pVal, p->nVal); - sqlite3DbFree(db, p); + vdbePmaWriterInit(pTask->file.pFd, &writer, pTask->pSorter->pgsz, + pTask->file.iEof); + pTask->nPMA++; + vdbePmaWriteVarint(&writer, pList->szPMA); + for(p=pList->pList; p; p=pNext){ + pNext = p->u.pNext; + vdbePmaWriteVarint(&writer, p->nVal); + vdbePmaWriteBlob(&writer, SRVAL(p), p->nVal); + if( pList->aMemory==0 ) sqlite3_free(p); + } + pList->pList = p; + rc = vdbePmaWriterFinish(&writer, &pTask->file.iEof); + } + + vdbeSorterWorkDebug(pTask, "exit"); + assert( rc!=SQLITE_OK || pList->pList==0 ); + assert( rc!=SQLITE_OK || pTask->file.iEof==iSz ); + return rc; +} + +/* +** Advance the MergeEngine to its next entry. +** Set *pbEof to true there is no next entry because +** the MergeEngine has reached the end of all its inputs. +** +** Return SQLITE_OK if successful or an error code if an error occurs. +*/ +static int vdbeMergeEngineStep( + MergeEngine *pMerger, /* The merge engine to advance to the next row */ + int *pbEof /* Set TRUE at EOF. Set false for more content */ +){ + int rc; + int iPrev = pMerger->aTree[1];/* Index of PmaReader to advance */ + SortSubtask *pTask = pMerger->pTask; + + /* Advance the current PmaReader */ + rc = vdbePmaReaderNext(&pMerger->aReadr[iPrev]); + + /* Update contents of aTree[] */ + if( rc==SQLITE_OK ){ + int i; /* Index of aTree[] to recalculate */ + PmaReader *pReadr1; /* First PmaReader to compare */ + PmaReader *pReadr2; /* Second PmaReader to compare */ + u8 *pKey2; /* To pReadr2->aKey, or 0 if record cached */ + + /* Find the first two PmaReaders to compare. The one that was just + ** advanced (iPrev) and the one next to it in the array. */ + pReadr1 = &pMerger->aReadr[(iPrev & 0xFFFE)]; + pReadr2 = &pMerger->aReadr[(iPrev | 0x0001)]; + pKey2 = pReadr2->aKey; + + for(i=(pMerger->nTree+iPrev)/2; i>0; i=i/2){ + /* Compare pReadr1 and pReadr2. Store the result in variable iRes. */ + int iRes; + if( pReadr1->pFd==0 ){ + iRes = +1; + }else if( pReadr2->pFd==0 ){ + iRes = -1; + }else{ + iRes = vdbeSorterCompare(pTask, + pReadr1->aKey, pReadr1->nKey, pKey2, pReadr2->nKey + ); + } + + /* If pReadr1 contained the smaller value, set aTree[i] to its index. + ** Then set pReadr2 to the next PmaReader to compare to pReadr1. In this + ** case there is no cache of pReadr2 in pTask->pUnpacked, so set + ** pKey2 to point to the record belonging to pReadr2. + ** + ** Alternatively, if pReadr2 contains the smaller of the two values, + ** set aTree[i] to its index and update pReadr1. If vdbeSorterCompare() + ** was actually called above, then pTask->pUnpacked now contains + ** a value equivalent to pReadr2. So set pKey2 to NULL to prevent + ** vdbeSorterCompare() from decoding pReadr2 again. + ** + ** If the two values were equal, then the value from the oldest + ** PMA should be considered smaller. The VdbeSorter.aReadr[] array + ** is sorted from oldest to newest, so pReadr1 contains older values + ** than pReadr2 iff (pReadr1aTree[i] = (int)(pReadr1 - pMerger->aReadr); + pReadr2 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; + pKey2 = pReadr2->aKey; + }else{ + if( pReadr1->pFd ) pKey2 = 0; + pMerger->aTree[i] = (int)(pReadr2 - pMerger->aReadr); + pReadr1 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; + } + } + *pbEof = (pMerger->aReadr[pMerger->aTree[1]].pFd==0); + } + + return (rc==SQLITE_OK ? pTask->pUnpacked->errCode : rc); +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** The main routine for background threads that write level-0 PMAs. +*/ +static void *vdbeSorterFlushThread(void *pCtx){ + SortSubtask *pTask = (SortSubtask*)pCtx; + int rc; /* Return code */ + assert( pTask->bDone==0 ); + rc = vdbeSorterListToPMA(pTask, &pTask->list); + pTask->bDone = 1; + return SQLITE_INT_TO_PTR(rc); +} +#endif /* SQLITE_MAX_WORKER_THREADS>0 */ + +/* +** Flush the current contents of VdbeSorter.list to a new PMA, possibly +** using a background thread. +*/ +static int vdbeSorterFlushPMA(VdbeSorter *pSorter){ +#if SQLITE_MAX_WORKER_THREADS==0 + pSorter->bUsePMA = 1; + return vdbeSorterListToPMA(&pSorter->aTask[0], &pSorter->list); +#else + int rc = SQLITE_OK; + int i; + SortSubtask *pTask = 0; /* Thread context used to create new PMA */ + int nWorker = (pSorter->nTask-1); + + /* Set the flag to indicate that at least one PMA has been written. + ** Or will be, anyhow. */ + pSorter->bUsePMA = 1; + + /* Select a sub-task to sort and flush the current list of in-memory + ** records to disk. If the sorter is running in multi-threaded mode, + ** round-robin between the first (pSorter->nTask-1) tasks. Except, if + ** the background thread from a sub-tasks previous turn is still running, + ** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy, + ** fall back to using the final sub-task. The first (pSorter->nTask-1) + ** sub-tasks are prefered as they use background threads - the final + ** sub-task uses the main thread. */ + for(i=0; iiPrev + i + 1) % nWorker; + pTask = &pSorter->aTask[iTest]; + if( pTask->bDone ){ + rc = vdbeSorterJoinThread(pTask); + } + if( rc!=SQLITE_OK || pTask->pThread==0 ) break; + } + + if( rc==SQLITE_OK ){ + if( i==nWorker ){ + /* Use the foreground thread for this operation */ + rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], &pSorter->list); + }else{ + /* Launch a background thread for this operation */ + u8 *aMem = pTask->list.aMemory; + void *pCtx = (void*)pTask; + + assert( pTask->pThread==0 && pTask->bDone==0 ); + assert( pTask->list.pList==0 ); + assert( pTask->list.aMemory==0 || pSorter->list.aMemory!=0 ); + + pSorter->iPrev = (u8)(pTask - pSorter->aTask); + pTask->list = pSorter->list; + pSorter->list.pList = 0; + pSorter->list.szPMA = 0; + if( aMem ){ + pSorter->list.aMemory = aMem; + pSorter->nMemory = sqlite3MallocSize(aMem); + }else if( pSorter->list.aMemory ){ + pSorter->list.aMemory = sqlite3Malloc(pSorter->nMemory); + if( !pSorter->list.aMemory ) return SQLITE_NOMEM; + } + + rc = vdbeSorterCreateThread(pTask, vdbeSorterFlushThread, pCtx); } - pSorter->pRecord = p; - rc = fileWriterFinish(db, &writer, &pSorter->iWriteOff); } return rc; +#endif /* SQLITE_MAX_WORKER_THREADS!=0 */ } /* ** Add a record to the sorter. */ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( - sqlite3 *db, /* Database handle */ - const VdbeCursor *pCsr, /* Sorter cursor */ + const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal /* Memory cell containing record */ ){ VdbeSorter *pSorter = pCsr->pSorter; int rc = SQLITE_OK; /* Return Code */ SorterRecord *pNew; /* New list element */ + int bFlush; /* True to flush contents of memory to PMA */ + int nReq; /* Bytes of memory required */ + int nPMA; /* Bytes of PMA space required */ + assert( pSorter ); - pSorter->nInMemory += sqlite3VarintLen(pVal->n) + pVal->n; - pNew = (SorterRecord *)sqlite3DbMallocRaw(db, pVal->n + sizeof(SorterRecord)); - if( pNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - pNew->pVal = (void *)&pNew[1]; - memcpy(pNew->pVal, pVal->z, pVal->n); - pNew->nVal = pVal->n; - pNew->pNext = pSorter->pRecord; - pSorter->pRecord = pNew; - } - - /* See if the contents of the sorter should now be written out. They - ** are written out when either of the following are true: + /* Figure out whether or not the current contents of memory should be + ** flushed to a PMA before continuing. If so, do so. + ** + ** If using the single large allocation mode (pSorter->aMemory!=0), then + ** flush the contents of memory to a new PMA if (a) at least one value is + ** already in memory and (b) the new value will not fit in memory. + ** + ** Or, if using separate allocations for each record, flush the contents + ** of memory to a PMA if either of the following are true: ** ** * The total memory allocated for the in-memory list is greater ** than (page-size * cache-size), or @@ -75803,161 +77606,778 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( ** * The total memory allocated for the in-memory list is greater ** than (page-size * 10) and sqlite3HeapNearlyFull() returns true. */ - if( rc==SQLITE_OK && pSorter->mxPmaSize>0 && ( - (pSorter->nInMemory>pSorter->mxPmaSize) - || (pSorter->nInMemory>pSorter->mnPmaSize && sqlite3HeapNearlyFull()) - )){ -#ifdef SQLITE_DEBUG - i64 nExpect = pSorter->iWriteOff - + sqlite3VarintLen(pSorter->nInMemory) - + pSorter->nInMemory; + nReq = pVal->n + sizeof(SorterRecord); + nPMA = pVal->n + sqlite3VarintLen(pVal->n); + if( pSorter->mxPmaSize ){ + if( pSorter->list.aMemory ){ + bFlush = pSorter->iMemory && (pSorter->iMemory+nReq) > pSorter->mxPmaSize; + }else{ + bFlush = ( + (pSorter->list.szPMA > pSorter->mxPmaSize) + || (pSorter->list.szPMA > pSorter->mnPmaSize && sqlite3HeapNearlyFull()) + ); + } + if( bFlush ){ + rc = vdbeSorterFlushPMA(pSorter); + pSorter->list.szPMA = 0; + pSorter->iMemory = 0; + assert( rc!=SQLITE_OK || pSorter->list.pList==0 ); + } + } + + pSorter->list.szPMA += nPMA; + if( nPMA>pSorter->mxKeysize ){ + pSorter->mxKeysize = nPMA; + } + + if( pSorter->list.aMemory ){ + int nMin = pSorter->iMemory + nReq; + + if( nMin>pSorter->nMemory ){ + u8 *aNew; + int nNew = pSorter->nMemory * 2; + while( nNew < nMin ) nNew = nNew*2; + if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize; + if( nNew < nMin ) nNew = nMin; + + aNew = sqlite3Realloc(pSorter->list.aMemory, nNew); + if( !aNew ) return SQLITE_NOMEM; + pSorter->list.pList = (SorterRecord*)( + aNew + ((u8*)pSorter->list.pList - pSorter->list.aMemory) + ); + pSorter->list.aMemory = aNew; + pSorter->nMemory = nNew; + } + + pNew = (SorterRecord*)&pSorter->list.aMemory[pSorter->iMemory]; + pSorter->iMemory += ROUND8(nReq); + pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory); + }else{ + pNew = (SorterRecord *)sqlite3Malloc(nReq); + if( pNew==0 ){ + return SQLITE_NOMEM; + } + pNew->u.pNext = pSorter->list.pList; + } + + memcpy(SRVAL(pNew), pVal->z, pVal->n); + pNew->nVal = pVal->n; + pSorter->list.pList = pNew; + + return rc; +} + +/* +** Read keys from pIncr->pMerger and populate pIncr->aFile[1]. The format +** of the data stored in aFile[1] is the same as that used by regular PMAs, +** except that the number-of-bytes varint is omitted from the start. +*/ +static int vdbeIncrPopulate(IncrMerger *pIncr){ + int rc = SQLITE_OK; + int rc2; + i64 iStart = pIncr->iStartOff; + SorterFile *pOut = &pIncr->aFile[1]; + SortSubtask *pTask = pIncr->pTask; + MergeEngine *pMerger = pIncr->pMerger; + PmaWriter writer; + assert( pIncr->bEof==0 ); + + vdbeSorterPopulateDebug(pTask, "enter"); + + vdbePmaWriterInit(pOut->pFd, &writer, pTask->pSorter->pgsz, iStart); + while( rc==SQLITE_OK ){ + int dummy; + PmaReader *pReader = &pMerger->aReadr[ pMerger->aTree[1] ]; + int nKey = pReader->nKey; + i64 iEof = writer.iWriteOff + writer.iBufEnd; + + /* Check if the output file is full or if the input has been exhausted. + ** In either case exit the loop. */ + if( pReader->pFd==0 ) break; + if( (iEof + nKey + sqlite3VarintLen(nKey))>(iStart + pIncr->mxSz) ) break; + + /* Write the next key to the output. */ + vdbePmaWriteVarint(&writer, nKey); + vdbePmaWriteBlob(&writer, pReader->aKey, nKey); + assert( pIncr->pMerger->pTask==pTask ); + rc = vdbeMergeEngineStep(pIncr->pMerger, &dummy); + } + + rc2 = vdbePmaWriterFinish(&writer, &pOut->iEof); + if( rc==SQLITE_OK ) rc = rc2; + vdbeSorterPopulateDebug(pTask, "exit"); + return rc; +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** The main routine for background threads that populate aFile[1] of +** multi-threaded IncrMerger objects. +*/ +static void *vdbeIncrPopulateThread(void *pCtx){ + IncrMerger *pIncr = (IncrMerger*)pCtx; + void *pRet = SQLITE_INT_TO_PTR( vdbeIncrPopulate(pIncr) ); + pIncr->pTask->bDone = 1; + return pRet; +} + +/* +** Launch a background thread to populate aFile[1] of pIncr. +*/ +static int vdbeIncrBgPopulate(IncrMerger *pIncr){ + void *p = (void*)pIncr; + assert( pIncr->bUseThread ); + return vdbeSorterCreateThread(pIncr->pTask, vdbeIncrPopulateThread, p); +} #endif - rc = vdbeSorterListToPMA(db, pCsr); - pSorter->nInMemory = 0; - assert( rc!=SQLITE_OK || (nExpect==pSorter->iWriteOff) ); + +/* +** This function is called when the PmaReader corresponding to pIncr has +** finished reading the contents of aFile[0]. Its purpose is to "refill" +** aFile[0] such that the PmaReader should start rereading it from the +** beginning. +** +** For single-threaded objects, this is accomplished by literally reading +** keys from pIncr->pMerger and repopulating aFile[0]. +** +** For multi-threaded objects, all that is required is to wait until the +** background thread is finished (if it is not already) and then swap +** aFile[0] and aFile[1] in place. If the contents of pMerger have not +** been exhausted, this function also launches a new background thread +** to populate the new aFile[1]. +** +** SQLITE_OK is returned on success, or an SQLite error code otherwise. +*/ +static int vdbeIncrSwap(IncrMerger *pIncr){ + int rc = SQLITE_OK; + +#if SQLITE_MAX_WORKER_THREADS>0 + if( pIncr->bUseThread ){ + rc = vdbeSorterJoinThread(pIncr->pTask); + + if( rc==SQLITE_OK ){ + SorterFile f0 = pIncr->aFile[0]; + pIncr->aFile[0] = pIncr->aFile[1]; + pIncr->aFile[1] = f0; + } + + if( rc==SQLITE_OK ){ + if( pIncr->aFile[0].iEof==pIncr->iStartOff ){ + pIncr->bEof = 1; + }else{ + rc = vdbeIncrBgPopulate(pIncr); + } + } + }else +#endif + { + rc = vdbeIncrPopulate(pIncr); + pIncr->aFile[0] = pIncr->aFile[1]; + if( pIncr->aFile[0].iEof==pIncr->iStartOff ){ + pIncr->bEof = 1; + } } return rc; } /* -** Helper function for sqlite3VdbeSorterRewind(). +** Allocate and return a new IncrMerger object to read data from pMerger. +** +** If an OOM condition is encountered, return NULL. In this case free the +** pMerger argument before returning. */ -static int vdbeSorterInitMerge( - sqlite3 *db, /* Database handle */ - const VdbeCursor *pCsr, /* Cursor handle for this sorter */ - i64 *pnByte /* Sum of bytes in all opened PMAs */ +static int vdbeIncrMergerNew( + SortSubtask *pTask, /* The thread that will be using the new IncrMerger */ + MergeEngine *pMerger, /* The MergeEngine that the IncrMerger will control */ + IncrMerger **ppOut /* Write the new IncrMerger here */ ){ + int rc = SQLITE_OK; + IncrMerger *pIncr = *ppOut = (IncrMerger*) + (sqlite3FaultSim(100) ? 0 : sqlite3MallocZero(sizeof(*pIncr))); + if( pIncr ){ + pIncr->pMerger = pMerger; + pIncr->pTask = pTask; + pIncr->mxSz = MAX(pTask->pSorter->mxKeysize+9,pTask->pSorter->mxPmaSize/2); + pTask->file2.iEof += pIncr->mxSz; + }else{ + vdbeMergeEngineFree(pMerger); + rc = SQLITE_NOMEM; + } + return rc; +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** Set the "use-threads" flag on object pIncr. +*/ +static void vdbeIncrMergerSetThreads(IncrMerger *pIncr){ + pIncr->bUseThread = 1; + pIncr->pTask->file2.iEof -= pIncr->mxSz; +} +#endif /* SQLITE_MAX_WORKER_THREADS>0 */ + + + +/* +** Recompute pMerger->aTree[iOut] by comparing the next keys on the +** two PmaReaders that feed that entry. Neither of the PmaReaders +** are advanced. This routine merely does the comparison. +*/ +static void vdbeMergeEngineCompare( + MergeEngine *pMerger, /* Merge engine containing PmaReaders to compare */ + int iOut /* Store the result in pMerger->aTree[iOut] */ +){ + int i1; + int i2; + int iRes; + PmaReader *p1; + PmaReader *p2; + + assert( iOutnTree && iOut>0 ); + + if( iOut>=(pMerger->nTree/2) ){ + i1 = (iOut - pMerger->nTree/2) * 2; + i2 = i1 + 1; + }else{ + i1 = pMerger->aTree[iOut*2]; + i2 = pMerger->aTree[iOut*2+1]; + } + + p1 = &pMerger->aReadr[i1]; + p2 = &pMerger->aReadr[i2]; + + if( p1->pFd==0 ){ + iRes = i2; + }else if( p2->pFd==0 ){ + iRes = i1; + }else{ + int res; + assert( pMerger->pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */ + res = vdbeSorterCompare( + pMerger->pTask, p1->aKey, p1->nKey, p2->aKey, p2->nKey + ); + if( res<=0 ){ + iRes = i1; + }else{ + iRes = i2; + } + } + + pMerger->aTree[iOut] = iRes; +} + +/* +** Allowed values for the eMode parameter to vdbeMergeEngineInit() +** and vdbePmaReaderIncrMergeInit(). +** +** Only INCRINIT_NORMAL is valid in single-threaded builds (when +** SQLITE_MAX_WORKER_THREADS==0). The other values are only used +** when there exists one or more separate worker threads. +*/ +#define INCRINIT_NORMAL 0 +#define INCRINIT_TASK 1 +#define INCRINIT_ROOT 2 + +/* Forward reference. +** The vdbeIncrMergeInit() and vdbePmaReaderIncrMergeInit() routines call each +** other (when building a merge tree). +*/ +static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode); + +/* +** Initialize the MergeEngine object passed as the second argument. Once this +** function returns, the first key of merged data may be read from the +** MergeEngine object in the usual fashion. +** +** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge +** objects attached to the PmaReader objects that the merger reads from have +** already been populated, but that they have not yet populated aFile[0] and +** set the PmaReader objects up to read from it. In this case all that is +** required is to call vdbePmaReaderNext() on each PmaReader to point it at +** its first key. +** +** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use +** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data +** to pMerger. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int vdbeMergeEngineInit( + SortSubtask *pTask, /* Thread that will run pMerger */ + MergeEngine *pMerger, /* MergeEngine to initialize */ + int eMode /* One of the INCRINIT_XXX constants */ +){ + int rc = SQLITE_OK; /* Return code */ + int i; /* For looping over PmaReader objects */ + int nTree = pMerger->nTree; + + /* eMode is always INCRINIT_NORMAL in single-threaded mode */ + assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); + + /* Verify that the MergeEngine is assigned to a single thread */ + assert( pMerger->pTask==0 ); + pMerger->pTask = pTask; + + for(i=0; i0 && eMode==INCRINIT_ROOT ){ + /* PmaReaders should be normally initialized in order, as if they are + ** reading from the same temp file this makes for more linear file IO. + ** However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is + ** in use it will block the vdbePmaReaderNext() call while it uses + ** the main thread to fill its buffer. So calling PmaReaderNext() + ** on this PmaReader before any of the multi-threaded PmaReaders takes + ** better advantage of multi-processor hardware. */ + rc = vdbePmaReaderNext(&pMerger->aReadr[nTree-i-1]); + }else{ + rc = vdbePmaReaderIncrMergeInit(&pMerger->aReadr[i], INCRINIT_NORMAL); + } + if( rc!=SQLITE_OK ) return rc; + } + + for(i=pMerger->nTree-1; i>0; i--){ + vdbeMergeEngineCompare(pMerger, i); + } + return pTask->pUnpacked->errCode; +} + +/* +** Initialize the IncrMerge field of a PmaReader. +** +** If the PmaReader passed as the first argument is not an incremental-reader +** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it serves +** to open and/or initialize the temp file related fields of the IncrMerge +** object at (pReadr->pIncr). +** +** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders +** in the sub-tree headed by pReadr are also initialized. Data is then loaded +** into the buffers belonging to pReadr and it is set to +** point to the first key in its range. +** +** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed +** to be a multi-threaded PmaReader and this function is being called in a +** background thread. In this case all PmaReaders in the sub-tree are +** initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to +** pReadr is populated. However, pReadr itself is not set up to point +** to its first key. A call to vdbePmaReaderNext() is still required to do +** that. +** +** The reason this function does not call vdbePmaReaderNext() immediately +** in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has +** to block on thread (pTask->thread) before accessing aFile[1]. But, since +** this entire function is being run by thread (pTask->thread), that will +** lead to the current background thread attempting to join itself. +** +** Finally, if argument eMode is set to INCRINIT_ROOT, it may be assumed +** that pReadr->pIncr is a multi-threaded IncrMerge objects, and that all +** child-trees have already been initialized using IncrInit(INCRINIT_TASK). +** In this case vdbePmaReaderNext() is called on all child PmaReaders and +** the current PmaReader set to point to the first key in its range. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ + int rc = SQLITE_OK; + IncrMerger *pIncr = pReadr->pIncr; + + /* eMode is always INCRINIT_NORMAL in single-threaded mode */ + assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); + + if( pIncr ){ + SortSubtask *pTask = pIncr->pTask; + sqlite3 *db = pTask->pSorter->db; + + rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode); + + /* Set up the required files for pIncr. A multi-theaded IncrMerge object + ** requires two temp files to itself, whereas a single-threaded object + ** only requires a region of pTask->file2. */ + if( rc==SQLITE_OK ){ + int mxSz = pIncr->mxSz; +#if SQLITE_MAX_WORKER_THREADS>0 + if( pIncr->bUseThread ){ + rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd); + if( rc==SQLITE_OK ){ + rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd); + } + }else +#endif + /*if( !pIncr->bUseThread )*/{ + if( pTask->file2.pFd==0 ){ + assert( pTask->file2.iEof>0 ); + rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd); + pTask->file2.iEof = 0; + } + if( rc==SQLITE_OK ){ + pIncr->aFile[1].pFd = pTask->file2.pFd; + pIncr->iStartOff = pTask->file2.iEof; + pTask->file2.iEof += mxSz; + } + } + } + +#if SQLITE_MAX_WORKER_THREADS>0 + if( rc==SQLITE_OK && pIncr->bUseThread ){ + /* Use the current thread to populate aFile[1], even though this + ** PmaReader is multi-threaded. The reason being that this function + ** is already running in background thread pIncr->pTask->thread. */ + assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK ); + rc = vdbeIncrPopulate(pIncr); + } +#endif + + if( rc==SQLITE_OK + && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) + ){ + rc = vdbePmaReaderNext(pReadr); + } + } + return rc; +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** The main routine for vdbePmaReaderIncrMergeInit() operations run in +** background threads. +*/ +static void *vdbePmaReaderBgInit(void *pCtx){ + PmaReader *pReader = (PmaReader*)pCtx; + void *pRet = SQLITE_INT_TO_PTR( + vdbePmaReaderIncrMergeInit(pReader,INCRINIT_TASK) + ); + pReader->pIncr->pTask->bDone = 1; + return pRet; +} + +/* +** Use a background thread to invoke vdbePmaReaderIncrMergeInit(INCRINIT_TASK) +** on the PmaReader object passed as the first argument. +** +** This call will initialize the various fields of the pReadr->pIncr +** structure and, if it is a multi-threaded IncrMerger, launch a +** background thread to populate aFile[1]. +*/ +static int vdbePmaReaderBgIncrInit(PmaReader *pReadr){ + void *pCtx = (void*)pReadr; + return vdbeSorterCreateThread(pReadr->pIncr->pTask, vdbePmaReaderBgInit, pCtx); +} +#endif + +/* +** Allocate a new MergeEngine object to merge the contents of nPMA level-0 +** PMAs from pTask->file. If no error occurs, set *ppOut to point to +** the new object and return SQLITE_OK. Or, if an error does occur, set *ppOut +** to NULL and return an SQLite error code. +** +** When this function is called, *piOffset is set to the offset of the +** first PMA to read from pTask->file. Assuming no error occurs, it is +** set to the offset immediately following the last byte of the last +** PMA before returning. If an error does occur, then the final value of +** *piOffset is undefined. +*/ +static int vdbeMergeEngineLevel0( + SortSubtask *pTask, /* Sorter task to read from */ + int nPMA, /* Number of PMAs to read */ + i64 *piOffset, /* IN/OUT: Readr offset in pTask->file */ + MergeEngine **ppOut /* OUT: New merge-engine */ +){ + MergeEngine *pNew; /* Merge engine to return */ + i64 iOff = *piOffset; + int i; + int rc = SQLITE_OK; + + *ppOut = pNew = vdbeMergeEngineNew(nPMA); + if( pNew==0 ) rc = SQLITE_NOMEM; + + for(i=0; iaReadr[i]; + rc = vdbePmaReaderInit(pTask, &pTask->file, iOff, pReadr, &nDummy); + iOff = pReadr->iEof; + } + + if( rc!=SQLITE_OK ){ + vdbeMergeEngineFree(pNew); + *ppOut = 0; + } + *piOffset = iOff; + return rc; +} + +/* +** Return the depth of a tree comprising nPMA PMAs, assuming a fanout of +** SORTER_MAX_MERGE_COUNT. The returned value does not include leaf nodes. +** +** i.e. +** +** nPMA<=16 -> TreeDepth() == 0 +** nPMA<=256 -> TreeDepth() == 1 +** nPMA<=65536 -> TreeDepth() == 2 +*/ +static int vdbeSorterTreeDepth(int nPMA){ + int nDepth = 0; + i64 nDiv = SORTER_MAX_MERGE_COUNT; + while( nDiv < (i64)nPMA ){ + nDiv = nDiv * SORTER_MAX_MERGE_COUNT; + nDepth++; + } + return nDepth; +} + +/* +** pRoot is the root of an incremental merge-tree with depth nDepth (according +** to vdbeSorterTreeDepth()). pLeaf is the iSeq'th leaf to be added to the +** tree, counting from zero. This function adds pLeaf to the tree. +** +** If successful, SQLITE_OK is returned. If an error occurs, an SQLite error +** code is returned and pLeaf is freed. +*/ +static int vdbeSorterAddToTree( + SortSubtask *pTask, /* Task context */ + int nDepth, /* Depth of tree according to TreeDepth() */ + int iSeq, /* Sequence number of leaf within tree */ + MergeEngine *pRoot, /* Root of tree */ + MergeEngine *pLeaf /* Leaf to add to tree */ +){ + int rc = SQLITE_OK; + int nDiv = 1; + int i; + MergeEngine *p = pRoot; + IncrMerger *pIncr; + + rc = vdbeIncrMergerNew(pTask, pLeaf, &pIncr); + + for(i=1; iaReadr[iIter]; + + if( pReadr->pIncr==0 ){ + MergeEngine *pNew = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = vdbeIncrMergerNew(pTask, pNew, &pReadr->pIncr); + } + } + if( rc==SQLITE_OK ){ + p = pReadr->pIncr->pMerger; + nDiv = nDiv / SORTER_MAX_MERGE_COUNT; + } + } + + if( rc==SQLITE_OK ){ + p->aReadr[iSeq % SORTER_MAX_MERGE_COUNT].pIncr = pIncr; + }else{ + vdbeIncrFree(pIncr); + } + return rc; +} + +/* +** This function is called as part of a SorterRewind() operation on a sorter +** that has already written two or more level-0 PMAs to one or more temp +** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that +** can be used to incrementally merge all PMAs on disk. +** +** If successful, SQLITE_OK is returned and *ppOut set to point to the +** MergeEngine object at the root of the tree before returning. Or, if an +** error occurs, an SQLite error code is returned and the final value +** of *ppOut is undefined. +*/ +static int vdbeSorterMergeTreeBuild( + VdbeSorter *pSorter, /* The VDBE cursor that implements the sort */ + MergeEngine **ppOut /* Write the MergeEngine here */ +){ + MergeEngine *pMain = 0; + int rc = SQLITE_OK; + int iTask; + +#if SQLITE_MAX_WORKER_THREADS>0 + /* If the sorter uses more than one task, then create the top-level + ** MergeEngine here. This MergeEngine will read data from exactly + ** one PmaReader per sub-task. */ + assert( pSorter->bUseThreads || pSorter->nTask==1 ); + if( pSorter->nTask>1 ){ + pMain = vdbeMergeEngineNew(pSorter->nTask); + if( pMain==0 ) rc = SQLITE_NOMEM; + } +#endif + + for(iTask=0; rc==SQLITE_OK && iTasknTask; iTask++){ + SortSubtask *pTask = &pSorter->aTask[iTask]; + assert( pTask->nPMA>0 || SQLITE_MAX_WORKER_THREADS>0 ); + if( SQLITE_MAX_WORKER_THREADS==0 || pTask->nPMA ){ + MergeEngine *pRoot = 0; /* Root node of tree for this task */ + int nDepth = vdbeSorterTreeDepth(pTask->nPMA); + i64 iReadOff = 0; + + if( pTask->nPMA<=SORTER_MAX_MERGE_COUNT ){ + rc = vdbeMergeEngineLevel0(pTask, pTask->nPMA, &iReadOff, &pRoot); + }else{ + int i; + int iSeq = 0; + pRoot = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT); + if( pRoot==0 ) rc = SQLITE_NOMEM; + for(i=0; inPMA && rc==SQLITE_OK; i += SORTER_MAX_MERGE_COUNT){ + MergeEngine *pMerger = 0; /* New level-0 PMA merger */ + int nReader; /* Number of level-0 PMAs to merge */ + + nReader = MIN(pTask->nPMA - i, SORTER_MAX_MERGE_COUNT); + rc = vdbeMergeEngineLevel0(pTask, nReader, &iReadOff, &pMerger); + if( rc==SQLITE_OK ){ + rc = vdbeSorterAddToTree(pTask, nDepth, iSeq++, pRoot, pMerger); + } + } + } + + if( rc==SQLITE_OK ){ +#if SQLITE_MAX_WORKER_THREADS>0 + if( pMain!=0 ){ + rc = vdbeIncrMergerNew(pTask, pRoot, &pMain->aReadr[iTask].pIncr); + }else +#endif + { + assert( pMain==0 ); + pMain = pRoot; + } + }else{ + vdbeMergeEngineFree(pRoot); + } + } + } + + if( rc!=SQLITE_OK ){ + vdbeMergeEngineFree(pMain); + pMain = 0; + } + *ppOut = pMain; + return rc; +} + +/* +** This function is called as part of an sqlite3VdbeSorterRewind() operation +** on a sorter that has written two or more PMAs to temporary files. It sets +** up either VdbeSorter.pMerger (for single threaded sorters) or pReader +** (for multi-threaded sorters) so that it can be used to iterate through +** all records stored in the sorter. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int vdbeSorterSetupMerge(VdbeSorter *pSorter){ + int rc; /* Return code */ + SortSubtask *pTask0 = &pSorter->aTask[0]; + MergeEngine *pMain = 0; +#if SQLITE_MAX_WORKER_THREADS + sqlite3 *db = pTask0->pSorter->db; +#endif + + rc = vdbeSorterMergeTreeBuild(pSorter, &pMain); + if( rc==SQLITE_OK ){ +#if SQLITE_MAX_WORKER_THREADS + assert( pSorter->bUseThreads==0 || pSorter->nTask>1 ); + if( pSorter->bUseThreads ){ + int iTask; + PmaReader *pReadr = 0; + SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1]; + rc = vdbeSortAllocUnpacked(pLast); + if( rc==SQLITE_OK ){ + pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader)); + pSorter->pReader = pReadr; + if( pReadr==0 ) rc = SQLITE_NOMEM; + } + if( rc==SQLITE_OK ){ + rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr); + if( rc==SQLITE_OK ){ + vdbeIncrMergerSetThreads(pReadr->pIncr); + for(iTask=0; iTask<(pSorter->nTask-1); iTask++){ + IncrMerger *pIncr; + if( (pIncr = pMain->aReadr[iTask].pIncr) ){ + vdbeIncrMergerSetThreads(pIncr); + assert( pIncr->pTask!=pLast ); + } + } + for(iTask=0; rc==SQLITE_OK && iTasknTask; iTask++){ + PmaReader *p = &pMain->aReadr[iTask]; + assert( p->pIncr==0 || p->pIncr->pTask==&pSorter->aTask[iTask] ); + if( p->pIncr ){ + if( iTask==pSorter->nTask-1 ){ + rc = vdbePmaReaderIncrMergeInit(p, INCRINIT_TASK); + }else{ + rc = vdbePmaReaderBgIncrInit(p); + } + } + } + } + pMain = 0; + } + if( rc==SQLITE_OK ){ + rc = vdbePmaReaderIncrMergeInit(pReadr, INCRINIT_ROOT); + } + }else +#endif + { + rc = vdbeMergeEngineInit(pTask0, pMain, INCRINIT_NORMAL); + pSorter->pMerger = pMain; + pMain = 0; + } + } + + if( rc!=SQLITE_OK ){ + vdbeMergeEngineFree(pMain); + } + return rc; +} + + +/* +** Once the sorter has been populated by calls to sqlite3VdbeSorterWrite, +** this function is called to prepare for iterating through the records +** in sorted order. +*/ +SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ VdbeSorter *pSorter = pCsr->pSorter; int rc = SQLITE_OK; /* Return code */ - int i; /* Used to iterator through aIter[] */ - i64 nByte = 0; /* Total bytes in all opened PMAs */ - - /* Initialize the iterators. */ - for(i=0; iaIter[i]; - rc = vdbeSorterIterInit(db, pSorter, pSorter->iReadOff, pIter, &nByte); - pSorter->iReadOff = pIter->iEof; - assert( rc!=SQLITE_OK || pSorter->iReadOff<=pSorter->iWriteOff ); - if( rc!=SQLITE_OK || pSorter->iReadOff>=pSorter->iWriteOff ) break; - } - - /* Initialize the aTree[] array. */ - for(i=pSorter->nTree-1; rc==SQLITE_OK && i>0; i--){ - rc = vdbeSorterDoCompare(pCsr, i); - } - - *pnByte = nByte; - return rc; -} - -/* -** Once the sorter has been populated, this function is called to prepare -** for iterating through its contents in sorted order. -*/ -SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ - VdbeSorter *pSorter = pCsr->pSorter; - int rc; /* Return code */ - sqlite3_file *pTemp2 = 0; /* Second temp file to use */ - i64 iWrite2 = 0; /* Write offset for pTemp2 */ - int nIter; /* Number of iterators used */ - int nByte; /* Bytes of space required for aIter/aTree */ - int N = 2; /* Power of 2 >= nIter */ assert( pSorter ); /* If no data has been written to disk, then do not do so now. Instead, ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly ** from the in-memory list. */ - if( pSorter->nPMA==0 ){ - *pbEof = !pSorter->pRecord; - assert( pSorter->aTree==0 ); - return vdbeSorterSort(pCsr); - } - - /* Write the current in-memory list to a PMA. */ - rc = vdbeSorterListToPMA(db, pCsr); - if( rc!=SQLITE_OK ) return rc; - - /* Allocate space for aIter[] and aTree[]. */ - nIter = pSorter->nPMA; - if( nIter>SORTER_MAX_MERGE_COUNT ) nIter = SORTER_MAX_MERGE_COUNT; - assert( nIter>0 ); - while( NaIter = (VdbeSorterIter *)sqlite3DbMallocZero(db, nByte); - if( !pSorter->aIter ) return SQLITE_NOMEM; - pSorter->aTree = (int *)&pSorter->aIter[N]; - pSorter->nTree = N; - - do { - int iNew; /* Index of new, merged, PMA */ - - for(iNew=0; - rc==SQLITE_OK && iNew*SORTER_MAX_MERGE_COUNTnPMA; - iNew++ - ){ - int rc2; /* Return code from fileWriterFinish() */ - FileWriter writer; /* Object used to write to disk */ - i64 nWrite; /* Number of bytes in new PMA */ - - memset(&writer, 0, sizeof(FileWriter)); - - /* If there are SORTER_MAX_MERGE_COUNT or less PMAs in file pTemp1, - ** initialize an iterator for each of them and break out of the loop. - ** These iterators will be incrementally merged as the VDBE layer calls - ** sqlite3VdbeSorterNext(). - ** - ** Otherwise, if pTemp1 contains more than SORTER_MAX_MERGE_COUNT PMAs, - ** initialize interators for SORTER_MAX_MERGE_COUNT of them. These PMAs - ** are merged into a single PMA that is written to file pTemp2. - */ - rc = vdbeSorterInitMerge(db, pCsr, &nWrite); - assert( rc!=SQLITE_OK || pSorter->aIter[ pSorter->aTree[1] ].pFile ); - if( rc!=SQLITE_OK || pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){ - break; - } - - /* Open the second temp file, if it is not already open. */ - if( pTemp2==0 ){ - assert( iWrite2==0 ); - rc = vdbeSorterOpenTempFile(db, &pTemp2); - } - - if( rc==SQLITE_OK ){ - int bEof = 0; - fileWriterInit(db, pTemp2, &writer, iWrite2); - fileWriterWriteVarint(&writer, nWrite); - while( rc==SQLITE_OK && bEof==0 ){ - VdbeSorterIter *pIter = &pSorter->aIter[ pSorter->aTree[1] ]; - assert( pIter->pFile ); - - fileWriterWriteVarint(&writer, pIter->nKey); - fileWriterWrite(&writer, pIter->aKey, pIter->nKey); - rc = sqlite3VdbeSorterNext(db, pCsr, &bEof); - } - rc2 = fileWriterFinish(db, &writer, &iWrite2); - if( rc==SQLITE_OK ) rc = rc2; - } - } - - if( pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){ - break; + if( pSorter->bUsePMA==0 ){ + if( pSorter->list.pList ){ + *pbEof = 0; + rc = vdbeSorterSort(&pSorter->aTask[0], &pSorter->list); }else{ - sqlite3_file *pTmp = pSorter->pTemp1; - pSorter->nPMA = iNew; - pSorter->pTemp1 = pTemp2; - pTemp2 = pTmp; - pSorter->iWriteOff = iWrite2; - pSorter->iReadOff = 0; - iWrite2 = 0; + *pbEof = 1; } - }while( rc==SQLITE_OK ); - - if( pTemp2 ){ - sqlite3OsCloseFree(pTemp2); + return rc; } - *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); + + /* Write the current in-memory list to a PMA. When the VdbeSorterWrite() + ** function flushes the contents of memory to disk, it immediately always + ** creates a new list consisting of a single key immediately afterwards. + ** So the list is never empty at this point. */ + assert( pSorter->list.pList ); + rc = vdbeSorterFlushPMA(pSorter); + + /* Join all threads */ + rc = vdbeSorterJoinAll(pSorter, rc); + + vdbeSorterRewindDebug("rewind"); + + /* Assuming no errors have occurred, set up a merger structure to + ** incrementally read and merge all remaining PMAs. */ + assert( pSorter->pReader==0 ); + if( rc==SQLITE_OK ){ + rc = vdbeSorterSetupMerge(pSorter); + *pbEof = 0; + } + + vdbeSorterRewindDebug("rewinddone"); return rc; } @@ -75968,63 +78388,27 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, in VdbeSorter *pSorter = pCsr->pSorter; int rc; /* Return code */ - if( pSorter->aTree ){ - int iPrev = pSorter->aTree[1];/* Index of iterator to advance */ - rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]); - if( rc==SQLITE_OK ){ - int i; /* Index of aTree[] to recalculate */ - VdbeSorterIter *pIter1; /* First iterator to compare */ - VdbeSorterIter *pIter2; /* Second iterator to compare */ - u8 *pKey2; /* To pIter2->aKey, or 0 if record cached */ - - /* Find the first two iterators to compare. The one that was just - ** advanced (iPrev) and the one next to it in the array. */ - pIter1 = &pSorter->aIter[(iPrev & 0xFFFE)]; - pIter2 = &pSorter->aIter[(iPrev | 0x0001)]; - pKey2 = pIter2->aKey; - - for(i=(pSorter->nTree+iPrev)/2; i>0; i=i/2){ - /* Compare pIter1 and pIter2. Store the result in variable iRes. */ - int iRes; - if( pIter1->pFile==0 ){ - iRes = +1; - }else if( pIter2->pFile==0 ){ - iRes = -1; - }else{ - vdbeSorterCompare(pCsr, 0, - pIter1->aKey, pIter1->nKey, pKey2, pIter2->nKey, &iRes - ); - } - - /* If pIter1 contained the smaller value, set aTree[i] to its index. - ** Then set pIter2 to the next iterator to compare to pIter1. In this - ** case there is no cache of pIter2 in pSorter->pUnpacked, so set - ** pKey2 to point to the record belonging to pIter2. - ** - ** Alternatively, if pIter2 contains the smaller of the two values, - ** set aTree[i] to its index and update pIter1. If vdbeSorterCompare() - ** was actually called above, then pSorter->pUnpacked now contains - ** a value equivalent to pIter2. So set pKey2 to NULL to prevent - ** vdbeSorterCompare() from decoding pIter2 again. */ - if( iRes<=0 ){ - pSorter->aTree[i] = (int)(pIter1 - pSorter->aIter); - pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ]; - pKey2 = pIter2->aKey; - }else{ - if( pIter1->pFile ) pKey2 = 0; - pSorter->aTree[i] = (int)(pIter2 - pSorter->aIter); - pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ]; - } - - } - *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); + assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) ); + if( pSorter->bUsePMA ){ + assert( pSorter->pReader==0 || pSorter->pMerger==0 ); + assert( pSorter->bUseThreads==0 || pSorter->pReader ); + assert( pSorter->bUseThreads==1 || pSorter->pMerger ); +#if SQLITE_MAX_WORKER_THREADS>0 + if( pSorter->bUseThreads ){ + rc = vdbePmaReaderNext(pSorter->pReader); + *pbEof = (pSorter->pReader->pFd==0); + }else +#endif + /*if( !pSorter->bUseThreads )*/ { + assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) ); + rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof); } }else{ - SorterRecord *pFree = pSorter->pRecord; - pSorter->pRecord = pFree->pNext; - pFree->pNext = 0; - vdbeSorterRecordFree(db, pFree); - *pbEof = !pSorter->pRecord; + SorterRecord *pFree = pSorter->list.pList; + pSorter->list.pList = pFree->u.pNext; + pFree->u.pNext = 0; + if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree); + *pbEof = !pSorter->list.pList; rc = SQLITE_OK; } return rc; @@ -76039,14 +78423,21 @@ static void *vdbeSorterRowkey( int *pnKey /* OUT: Size of current key in bytes */ ){ void *pKey; - if( pSorter->aTree ){ - VdbeSorterIter *pIter; - pIter = &pSorter->aIter[ pSorter->aTree[1] ]; - *pnKey = pIter->nKey; - pKey = pIter->aKey; + if( pSorter->bUsePMA ){ + PmaReader *pReader; +#if SQLITE_MAX_WORKER_THREADS>0 + if( pSorter->bUseThreads ){ + pReader = pSorter->pReader; + }else +#endif + /*if( !pSorter->bUseThreads )*/{ + pReader = &pSorter->pMerger->aReadr[pSorter->pMerger->aTree[1]]; + } + *pnKey = pReader->nKey; + pKey = pReader->aKey; }else{ - *pnKey = pSorter->pRecord->nVal; - pKey = pSorter->pRecord->pVal; + *pnKey = pSorter->list.pList->nVal; + pKey = SRVAL(pSorter->list.pList); } return pKey; } @@ -76059,7 +78450,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ void *pKey; int nKey; /* Sorter key to copy into pOut */ pKey = vdbeSorterRowkey(pSorter, &nKey); - if( sqlite3VdbeMemGrow(pOut, nKey, 0) ){ + if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){ return SQLITE_NOMEM; } pOut->n = nKey; @@ -76074,22 +78465,48 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ ** passed as the first argument currently points to. For the purposes of ** the comparison, ignore the rowid field at the end of each record. ** +** If the sorter cursor key contains any NULL values, consider it to be +** less than pVal. Even if pVal also contains NULL values. +** ** If an error occurs, return an SQLite error code (i.e. SQLITE_NOMEM). ** Otherwise, set *pRes to a negative, zero or positive value if the ** key in pVal is smaller than, equal to or larger than the current sorter ** key. +** +** This routine forms the core of the OP_SorterCompare opcode, which in +** turn is used to verify uniqueness when constructing a UNIQUE INDEX. */ SQLITE_PRIVATE int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ - int nKeyCol, /* Only compare this many fields */ + int nKeyCol, /* Compare this many columns */ int *pRes /* OUT: Result of comparison */ ){ VdbeSorter *pSorter = pCsr->pSorter; + UnpackedRecord *r2 = pSorter->pUnpacked; + KeyInfo *pKeyInfo = pCsr->pKeyInfo; + int i; void *pKey; int nKey; /* Sorter key to compare pVal with */ + if( r2==0 ){ + char *p; + r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p); + assert( pSorter->pUnpacked==(UnpackedRecord*)p ); + if( r2==0 ) return SQLITE_NOMEM; + r2->nField = nKeyCol; + } + assert( r2->nField==nKeyCol ); + pKey = vdbeSorterRowkey(pSorter, &nKey); - vdbeSorterCompare(pCsr, nKeyCol, pVal->z, pVal->n, pKey, nKey, pRes); + sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2); + for(i=0; iaMem[i].flags & MEM_Null ){ + *pRes = -1; + return SQLITE_OK; + } + } + + *pRes = sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2); return SQLITE_OK; } @@ -76380,7 +78797,7 @@ typedef struct FileChunk FileChunk; ** ** The size chosen is a little less than a power of two. That way, ** the FileChunk object will have a size that almost exactly fills -** a power-of-two allocation. This mimimizes wasted space in power-of-two +** a power-of-two allocation. This minimizes wasted space in power-of-two ** memory allocators. */ #define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*))) @@ -76630,7 +79047,7 @@ SQLITE_PRIVATE int sqlite3MemJournalSize(void){ /* ** Walk an expression tree. Invoke the callback once for each node -** of the expression, while decending. (In other words, the callback +** of the expression, while descending. (In other words, the callback ** is invoked before visiting children.) ** ** The return value from the callback should be one of the WRC_* @@ -77486,9 +79903,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938; } } - } #ifndef SQLITE_OMIT_AUTHORIZATION - if( pDef ){ auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0); if( auth!=SQLITE_OK ){ if( auth==SQLITE_DENY ){ @@ -77499,9 +79914,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pExpr->op = TK_NULL; return WRC_Prune; } +#endif if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant); } -#endif if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); pNC->nErr++; @@ -77524,7 +79939,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pExpr->op2++; pNC2 = pNC2->pNext; } - if( pNC2 ) pNC2->ncFlags |= NC_HasAgg; + assert( pDef!=0 ); + if( pNC2 ){ + assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); + testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); + pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); + + } pNC->ncFlags |= NC_AllowAgg; } /* FIX ME: Compute pExpr->affinity based on the expected return @@ -77885,7 +80306,7 @@ static int resolveOrderGroupBy( } /* -** Resolve names in the SELECT statement p and all of its descendents. +** Resolve names in the SELECT statement p and all of its descendants. */ static int resolveSelectStep(Walker *pWalker, Select *p){ NameContext *pOuterNC; /* Context that contains this SELECT */ @@ -77989,7 +80410,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ assert( (p->selFlags & SF_Aggregate)==0 ); pGroupBy = p->pGroupBy; if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ - p->selFlags |= SF_Aggregate; + assert( NC_MinMaxAgg==SF_MinMaxAgg ); + p->selFlags |= SF_Aggregate | (sNC.ncFlags&NC_MinMaxAgg); }else{ sNC.ncFlags &= ~NC_AllowAgg; } @@ -78117,7 +80539,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */ ){ - u8 savedHasAgg; + u16 savedHasAgg; Walker w; if( pExpr==0 ) return 0; @@ -78130,8 +80552,8 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( pParse->nHeight += pExpr->nHeight; } #endif - savedHasAgg = pNC->ncFlags & NC_HasAgg; - pNC->ncFlags &= ~NC_HasAgg; + savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg); memset(&w, 0, sizeof(w)); w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; @@ -78146,9 +80568,8 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( } if( pNC->ncFlags & NC_HasAgg ){ ExprSetProperty(pExpr, EP_Agg); - }else if( savedHasAgg ){ - pNC->ncFlags |= NC_HasAgg; } + pNC->ncFlags |= savedHasAgg; return ExprHasProperty(pExpr, EP_Error); } @@ -78248,7 +80669,7 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference( ** affinity of that column is returned. Otherwise, 0x00 is returned, ** indicating no affinity for the expression. ** -** i.e. the WHERE clause expresssions in the following statements all +** i.e. the WHERE clause expressions in the following statements all ** have an affinity: ** ** CREATE TABLE t1(a); @@ -78727,7 +81148,7 @@ SQLITE_PRIVATE void sqlite3ExprAttachSubtrees( } /* -** Allocate a Expr node which joins as many as two subtrees. +** Allocate an Expr node which joins as many as two subtrees. ** ** One or both of the subtrees can be NULL. Return a pointer to the new ** Expr node. Or, if an OOM error occurs, set pParse->db->mallocFailed, @@ -78837,7 +81258,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token * ** ** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number ** as the previous instance of the same wildcard. Or if this is the first -** instance of the wildcard, the next sequenial variable number is +** instance of the wildcard, the next sequential variable number is ** assigned. */ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ @@ -78972,7 +81393,7 @@ static int exprStructSize(Expr *p){ ** During expression analysis, extra information is computed and moved into ** later parts of teh Expr object and that extra information might get chopped ** off if the expression is reduced. Note also that it does not work to -** make a EXPRDUP_REDUCE copy of a reduced expression. It is only legal +** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal ** to reduce a pristine expression tree from the parser. The implementation ** of dupedExprStructSize() contain multiple assert() statements that attempt ** to enforce this constraint. @@ -79041,7 +81462,7 @@ static int dupedExprSize(Expr *p, int flags){ ** is not NULL then *pzBuffer is assumed to point to a buffer large enough ** to store the copy of expression p, the copies of p->u.zToken ** (if applicable), and the copies of the p->pLeft and p->pRight expressions, -** if any. Before returning, *pzBuffer is set to the first byte passed the +** if any. Before returning, *pzBuffer is set to the first byte past the ** portion of the buffer copied into by this function. */ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){ @@ -79295,6 +81716,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = p->nSelectRow; pNew->pWith = withDup(db, p->pWith); + sqlite3SelectSetName(pNew, p->zSelName); return pNew; } #else @@ -79437,32 +81859,40 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ /* ** These routines are Walker callbacks. Walker.u.pi is a pointer ** to an integer. These routines are checking an expression to see -** if it is a constant. Set *Walker.u.pi to 0 if the expression is +** if it is a constant. Set *Walker.u.i to 0 if the expression is ** not constant. ** ** These callback routines are used to implement the following: ** -** sqlite3ExprIsConstant() -** sqlite3ExprIsConstantNotJoin() -** sqlite3ExprIsConstantOrFunction() +** sqlite3ExprIsConstant() pWalker->u.i==1 +** sqlite3ExprIsConstantNotJoin() pWalker->u.i==2 +** sqlite3ExprIsConstantOrFunction() pWalker->u.i==3 or 4 ** +** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions +** in a CREATE TABLE statement. The Walker.u.i value is 4 when parsing +** an existing schema and 3 when processing a new statement. A bound +** parameter raises an error for new statements, but is silently converted +** to NULL for existing schemas. This allows sqlite_master tables that +** contain a bound parameter because they were generated by older versions +** of SQLite to be parsed by newer versions of SQLite without raising a +** malformed schema error. */ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ - /* If pWalker->u.i is 3 then any term of the expression that comes from + /* If pWalker->u.i is 2 then any term of the expression that comes from ** the ON or USING clauses of a join disqualifies the expression ** from being considered constant. */ - if( pWalker->u.i==3 && ExprHasProperty(pExpr, EP_FromJoin) ){ + if( pWalker->u.i==2 && ExprHasProperty(pExpr, EP_FromJoin) ){ pWalker->u.i = 0; return WRC_Abort; } switch( pExpr->op ){ /* Consider functions to be constant if all their arguments are constant - ** and either pWalker->u.i==2 or the function as the SQLITE_FUNC_CONST + ** and either pWalker->u.i==3 or 4 or the function as the SQLITE_FUNC_CONST ** flag. */ case TK_FUNCTION: - if( pWalker->u.i==2 || ExprHasProperty(pExpr,EP_Constant) ){ + if( pWalker->u.i>=3 || ExprHasProperty(pExpr,EP_Constant) ){ return WRC_Continue; } /* Fall through */ @@ -79476,6 +81906,19 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_AGG_COLUMN ); pWalker->u.i = 0; return WRC_Abort; + case TK_VARIABLE: + if( pWalker->u.i==4 ){ + /* Silently convert bound parameters that appear inside of CREATE + ** statements into a NULL when parsing the CREATE statement text out + ** of the sqlite_master table */ + pExpr->op = TK_NULL; + }else if( pWalker->u.i==3 ){ + /* A bound parameter in a CREATE statement that originates from + ** sqlite3_prepare() causes an error */ + pWalker->u.i = 0; + return WRC_Abort; + } + /* Fall through */ default: testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */ testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */ @@ -79516,7 +81959,7 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){ ** an ON or USING clause. */ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){ - return exprIsConst(p, 3); + return exprIsConst(p, 2); } /* @@ -79528,8 +81971,9 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){ ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ -SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p){ - return exprIsConst(p, 2); +SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ + assert( isInit==0 || isInit==1 ); + return exprIsConst(p, 3+isInit); } /* @@ -79767,7 +82211,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){ ** ** If the RHS of the IN operator is a list or a more complex subquery, then ** an ephemeral table might need to be generated from the RHS and then -** pX->iTable made to point to the ephermeral table instead of an +** pX->iTable made to point to the ephemeral table instead of an ** existing table. ** ** The inFlags parameter must contain exactly one of the bits @@ -79897,7 +82341,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int ** and IN_INDEX_NOOP is an allowed reply ** and the RHS of the IN operator is a list, not a subquery ** and the RHS is not contant or has two or fewer terms, - ** then it is not worth creating an ephermeral table to evaluate + ** then it is not worth creating an ephemeral table to evaluate ** the IN operator so return IN_INDEX_NOOP. */ if( eType==0 @@ -80039,7 +82483,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); pSelect->iLimit = 0; testcase( pSelect->selFlags & SF_Distinct ); - pSelect->selFlags &= ~SF_Distinct; testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ if( sqlite3Select(pParse, pSelect, &dest) ){ sqlite3KeyInfoUnref(pKeyInfo); @@ -80138,6 +82581,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( sqlite3SelectDestInit(&dest, 0, ++pParse->nMem); if( pExpr->op==TK_SELECT ){ dest.eDest = SRT_Mem; + dest.iSdst = dest.iSDParm; sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iSDParm); VdbeComment((v, "Init subquery result")); }else{ @@ -80657,16 +83101,9 @@ SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, in ** over to iTo..iTo+nReg-1. Keep the column cache up-to-date. */ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ - int i; - struct yColCache *p; assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); - for(i=0, p=pParse->aColCache; iiReg; - if( x>=iFrom && xiReg += iTo-iFrom; - } - } + sqlite3ExprCacheRemove(pParse, iFrom, nReg); } #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) @@ -80821,26 +83258,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ - int aff, to_op; inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); - assert( !ExprHasProperty(pExpr, EP_IntValue) ); - aff = sqlite3AffinityType(pExpr->u.zToken, 0); - to_op = aff - SQLITE_AFF_TEXT + OP_ToText; - assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT ); - assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE ); - assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC ); - assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); - assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL ); - testcase( to_op==OP_ToText ); - testcase( to_op==OP_ToBlob ); - testcase( to_op==OP_ToNumeric ); - testcase( to_op==OP_ToInt ); - testcase( to_op==OP_ToReal ); if( inReg!=target ){ sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); inReg = target; } - sqlite3VdbeAddOp1(v, to_op, inReg); + sqlite3VdbeAddOp2(v, OP_Cast, target, + sqlite3AffinityType(pExpr->u.zToken, 0)); testcase( usedAsColumnCache(pParse, inReg, inReg) ); sqlite3ExprCacheAffinityChange(pParse, inReg, 1); break; @@ -80996,7 +83420,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) } /* Attempt a direct implementation of the built-in COALESCE() and - ** IFNULL() functions. This avoids unnecessary evalation of + ** IFNULL() functions. This avoids unnecessary evaluation of ** arguments past the first non-NULL argument. */ if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){ @@ -81435,7 +83859,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int ta } /* -** Generate code that evalutes the given expression and puts the result +** Generate code that evaluates the given expression and puts the result ** in register target. ** ** Also make a copy of the expression results into another "cache" register @@ -81458,90 +83882,86 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ exprToRegister(pExpr, iMem); } -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) +#ifdef SQLITE_DEBUG /* ** Generate a human-readable explanation of an expression tree. */ -SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ - int op; /* The opcode being coded */ +SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ + pView = sqlite3TreeViewPush(pView, moreToFollow); if( pExpr==0 ){ - op = TK_NULL; - }else{ - op = pExpr->op; + sqlite3TreeViewLine(pView, "nil"); + sqlite3TreeViewPop(pView); + return; } - switch( op ){ + switch( pExpr->op ){ case TK_AGG_COLUMN: { - sqlite3ExplainPrintf(pOut, "AGG{%d:%d}", + sqlite3TreeViewLine(pView, "AGG{%d:%d}", pExpr->iTable, pExpr->iColumn); break; } case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ - sqlite3ExplainPrintf(pOut, "COLUMN(%d)", pExpr->iColumn); + sqlite3TreeViewLine(pView, "COLUMN(%d)", pExpr->iColumn); }else{ - sqlite3ExplainPrintf(pOut, "{%d:%d}", + sqlite3TreeViewLine(pView, "{%d:%d}", pExpr->iTable, pExpr->iColumn); } break; } case TK_INTEGER: { if( pExpr->flags & EP_IntValue ){ - sqlite3ExplainPrintf(pOut, "%d", pExpr->u.iValue); + sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); }else{ - sqlite3ExplainPrintf(pOut, "%s", pExpr->u.zToken); + sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); } break; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { - sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken); + sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_STRING: { - sqlite3ExplainPrintf(pOut,"%Q", pExpr->u.zToken); + sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; } case TK_NULL: { - sqlite3ExplainPrintf(pOut,"NULL"); + sqlite3TreeViewLine(pView,"NULL"); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { - sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken); + sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_VARIABLE: { - sqlite3ExplainPrintf(pOut,"VARIABLE(%s,%d)", - pExpr->u.zToken, pExpr->iColumn); + sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", + pExpr->u.zToken, pExpr->iColumn); break; } case TK_REGISTER: { - sqlite3ExplainPrintf(pOut,"REGISTER(%d)", pExpr->iTable); + sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); break; } case TK_AS: { - sqlite3ExplainExpr(pOut, pExpr->pLeft); + sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } + case TK_ID: { + sqlite3TreeViewLine(pView,"ID %Q", pExpr->u.zToken); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ - const char *zAff = "unk"; - switch( sqlite3AffinityType(pExpr->u.zToken, 0) ){ - case SQLITE_AFF_TEXT: zAff = "TEXT"; break; - case SQLITE_AFF_NONE: zAff = "NONE"; break; - case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break; - case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break; - case SQLITE_AFF_REAL: zAff = "REAL"; break; - } - sqlite3ExplainPrintf(pOut, "CAST-%s(", zAff); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut, ")"); + sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } #endif /* SQLITE_OMIT_CAST */ @@ -81565,6 +83985,7 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ case TK_LSHIFT: zBinOp = "LSHIFT"; break; case TK_RSHIFT: zBinOp = "RSHIFT"; break; case TK_CONCAT: zBinOp = "CONCAT"; break; + case TK_DOT: zBinOp = "DOT"; break; case TK_UMINUS: zUniOp = "UMINUS"; break; case TK_UPLUS: zUniOp = "UPLUS"; break; @@ -81574,8 +83995,8 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ case TK_NOTNULL: zUniOp = "NOTNULL"; break; case TK_COLLATE: { - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut,".COLLATE(%s)",pExpr->u.zToken); + sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } @@ -81587,41 +84008,36 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ }else{ pFarg = pExpr->x.pList; } - if( op==TK_AGG_FUNCTION ){ - sqlite3ExplainPrintf(pOut, "AGG_FUNCTION%d:%s(", + if( pExpr->op==TK_AGG_FUNCTION ){ + sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", pExpr->op2, pExpr->u.zToken); }else{ - sqlite3ExplainPrintf(pOut, "FUNCTION:%s(", pExpr->u.zToken); + sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); } if( pFarg ){ - sqlite3ExplainExprList(pOut, pFarg); + sqlite3TreeViewExprList(pView, pFarg, 0, 0); } - sqlite3ExplainPrintf(pOut, ")"); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { - sqlite3ExplainPrintf(pOut, "EXISTS("); - sqlite3ExplainSelect(pOut, pExpr->x.pSelect); - sqlite3ExplainPrintf(pOut,")"); + sqlite3TreeViewLine(pView, "EXISTS-expr"); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { - sqlite3ExplainPrintf(pOut, "("); - sqlite3ExplainSelect(pOut, pExpr->x.pSelect); - sqlite3ExplainPrintf(pOut, ")"); + sqlite3TreeViewLine(pView, "SELECT-expr"); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_IN: { - sqlite3ExplainPrintf(pOut, "IN("); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut, ","); + sqlite3TreeViewLine(pView, "IN"); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - sqlite3ExplainSelect(pOut, pExpr->x.pSelect); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); }else{ - sqlite3ExplainExprList(pOut, pExpr->x.pList); + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); } - sqlite3ExplainPrintf(pOut, ")"); break; } #endif /* SQLITE_OMIT_SUBQUERY */ @@ -81641,13 +84057,10 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ Expr *pX = pExpr->pLeft; Expr *pY = pExpr->x.pList->a[0].pExpr; Expr *pZ = pExpr->x.pList->a[1].pExpr; - sqlite3ExplainPrintf(pOut, "BETWEEN("); - sqlite3ExplainExpr(pOut, pX); - sqlite3ExplainPrintf(pOut, ","); - sqlite3ExplainExpr(pOut, pY); - sqlite3ExplainPrintf(pOut, ","); - sqlite3ExplainExpr(pOut, pZ); - sqlite3ExplainPrintf(pOut, ")"); + sqlite3TreeViewLine(pView, "BETWEEN"); + sqlite3TreeViewExpr(pView, pX, 1); + sqlite3TreeViewExpr(pView, pY, 1); + sqlite3TreeViewExpr(pView, pZ, 0); break; } case TK_TRIGGER: { @@ -81658,15 +84071,14 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ ** is set to the column of the pseudo-table to read, or to -1 to ** read the rowid field. */ - sqlite3ExplainPrintf(pOut, "%s(%d)", + sqlite3TreeViewLine(pView, "%s(%d)", pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); break; } case TK_CASE: { - sqlite3ExplainPrintf(pOut, "CASE("); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut, ","); - sqlite3ExplainExprList(pOut, pExpr->x.pList); + sqlite3TreeViewLine(pView, "CASE"); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); break; } #ifndef SQLITE_OMIT_TRIGGER @@ -81678,55 +84090,57 @@ SQLITE_PRIVATE void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } - sqlite3ExplainPrintf(pOut, "RAISE-%s(%s)", zType, pExpr->u.zToken); + sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } #endif + default: { + sqlite3TreeViewLine(pView, "op=%d", pExpr->op); + break; + } } if( zBinOp ){ - sqlite3ExplainPrintf(pOut,"%s(", zBinOp); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut,","); - sqlite3ExplainExpr(pOut, pExpr->pRight); - sqlite3ExplainPrintf(pOut,")"); + sqlite3TreeViewLine(pView, "%s", zBinOp); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + sqlite3TreeViewExpr(pView, pExpr->pRight, 0); }else if( zUniOp ){ - sqlite3ExplainPrintf(pOut,"%s(", zUniOp); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut,")"); + sqlite3TreeViewLine(pView, "%s", zUniOp); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } + sqlite3TreeViewPop(pView); } -#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */ +#endif /* SQLITE_DEBUG */ -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) +#ifdef SQLITE_DEBUG /* ** Generate a human-readable explanation of an expression list. */ -SQLITE_PRIVATE void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){ +SQLITE_PRIVATE void sqlite3TreeViewExprList( + TreeView *pView, + const ExprList *pList, + u8 moreToFollow, + const char *zLabel +){ int i; - if( pList==0 || pList->nExpr==0 ){ - sqlite3ExplainPrintf(pOut, "(empty-list)"); - return; - }else if( pList->nExpr==1 ){ - sqlite3ExplainExpr(pOut, pList->a[0].pExpr); + pView = sqlite3TreeViewPush(pView, moreToFollow); + if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; + if( pList==0 ){ + sqlite3TreeViewLine(pView, "%s (empty)", zLabel); }else{ - sqlite3ExplainPush(pOut); + sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; inExpr; i++){ - sqlite3ExplainPrintf(pOut, "item[%d] = ", i); - sqlite3ExplainPush(pOut); - sqlite3ExplainExpr(pOut, pList->a[i].pExpr); - sqlite3ExplainPop(pOut); - if( pList->a[i].zName ){ + sqlite3TreeViewExpr(pView, pList->a[i].pExpr, inExpr-1); +#if 0 + if( pList->a[i].zName ){ sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName); } if( pList->a[i].bSpanIsTab ){ sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan); } - if( inExpr-1 ){ - sqlite3ExplainNL(pOut); - } +#endif } - sqlite3ExplainPop(pOut); } + sqlite3TreeViewPop(pView); } #endif /* SQLITE_DEBUG */ @@ -81790,7 +84204,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList( ** x>=y AND x<=z ** ** Code it as such, taking care to do the common subexpression -** elementation of x. +** elimination of x. */ static void exprCodeBetween( Parse *pParse, /* Parsing and code generating context */ @@ -82527,7 +84941,7 @@ SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){ ** purpose. ** ** If a register is currently being used by the column cache, then -** the dallocation is deferred until the column cache line that uses +** the deallocation is deferred until the column cache line that uses ** the register becomes stale. */ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ @@ -82754,8 +85168,8 @@ static void renameTriggerFunc( UNUSED_PARAMETER(NotUsed); /* The principle used to locate the table name in the CREATE TRIGGER - ** statement is that the table name is the first token that is immediatedly - ** preceded by either TK_ON or TK_DOT and immediatedly followed by one + ** statement is that the table name is the first token that is immediately + ** preceded by either TK_ON or TK_DOT and immediately followed by one ** of TK_WHEN, TK_BEGIN or TK_FOR. */ if( zSql ){ @@ -83446,7 +85860,7 @@ exit_begin_add_column: ** not possible to enable both STAT3 and STAT4 at the same time. If they ** are both enabled, then STAT4 takes precedence. ** -** For most applications, sqlite_stat1 provides all the statisics required +** For most applications, sqlite_stat1 provides all the statistics required ** for the query planner to make good choices. ** ** Format of sqlite_stat1: @@ -83797,8 +86211,9 @@ static void stat4Destructor(void *pOld){ ** original WITHOUT ROWID table as N==K as a special case. ** ** This routine allocates the Stat4Accum object in heap memory. The return -** value is a pointer to the the Stat4Accum object encoded as a blob (i.e. -** the size of the blob is sizeof(void*) bytes). +** value is a pointer to the Stat4Accum object. The datatype of the +** return value is BLOB, but it is really just a pointer to the Stat4Accum +** object. */ static void statInit( sqlite3_context *context, @@ -83876,8 +86291,11 @@ static void statInit( } #endif - /* Return a pointer to the allocated object to the caller */ - sqlite3_result_blob(context, p, sizeof(p), stat4Destructor); + /* Return a pointer to the allocated object to the caller. Note that + ** only the pointer (the 2nd parameter) matters. The size of the object + ** (given by the 3rd parameter) is never used and can be any positive + ** value. */ + sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor); } static const FuncDef statInitFuncdef = { 2+IsStat34, /* nArg */ @@ -84203,7 +86621,7 @@ static const FuncDef statPushFuncdef = { ** Implementation of the stat_get(P,J) SQL function. This routine is ** used to query statistical information that has been gathered into ** the Stat4Accum object by prior calls to stat_push(). The P parameter -** is a BLOB which is decoded into a pointer to the Stat4Accum objects. +** has type BLOB but it is really just a pointer to the Stat4Accum object. ** The content to returned is determined by the parameter J ** which is one of the STAT_GET_xxxx values defined above. ** @@ -84607,7 +87025,8 @@ static void analyzeOneTable( /* Add the entry to the stat1 table. */ callStatGet(v, regStat4, STAT_GET_STAT1, regStat1); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0); + assert( "BBB"[0]==SQLITE_AFF_TEXT ); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); @@ -84670,7 +87089,8 @@ static void analyzeOneTable( sqlite3VdbeAddOp2(v, OP_Count, iTabCur, regStat1); jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0); + assert( "BBB"[0]==SQLITE_AFF_TEXT ); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); @@ -84841,7 +87261,7 @@ static void decodeIntArray( #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( z==0 ) z = ""; #else - if( NEVER(z==0) ) z = ""; + assert( z!=0 ); #endif for(i=0; *z && inKeyCol+1; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + tRowcnt * const aiRowEst = pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero( + sizeof(tRowcnt) * nCol + ); + if( aiRowEst==0 ) pInfo->db->mallocFailed = 1; +#else + tRowcnt * const aiRowEst = 0; +#endif pIndex->bUnordered = 0; - decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex); + decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex); if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0]; }else{ Index fakeIdx; @@ -84980,25 +87407,38 @@ static void initAvgEq(Index *pIdx){ pIdx->aAvgEq[nCol] = 1; } for(iCol=0; iColnSample; int i; /* Used to iterate through samples */ tRowcnt sumEq = 0; /* Sum of the nEq values */ - tRowcnt nSum = 0; /* Number of terms contributing to sumEq */ tRowcnt avgEq = 0; - tRowcnt nDLt = pFinal->anDLt[iCol]; + tRowcnt nRow; /* Number of rows in index */ + i64 nSum100 = 0; /* Number of terms contributing to sumEq */ + i64 nDist100; /* Number of distinct values in index */ + + if( pIdx->aiRowEst==0 || pIdx->aiRowEst[iCol+1]==0 ){ + nRow = pFinal->anLt[iCol]; + nDist100 = (i64)100 * pFinal->anDLt[iCol]; + nSample--; + }else{ + nRow = pIdx->aiRowEst[0]; + nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1]; + } /* Set nSum to the number of distinct (iCol+1) field prefixes that - ** occur in the stat4 table for this index before pFinal. Set - ** sumEq to the sum of the nEq values for column iCol for the same - ** set (adding the value only once where there exist dupicate - ** prefixes). */ - for(i=0; i<(pIdx->nSample-1); i++){ - if( aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){ + ** occur in the stat4 table for this index. Set sumEq to the sum of + ** the nEq values for column iCol for the same set (adding the value + ** only once where there exist duplicate prefixes). */ + for(i=0; inSample-1) + || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] + ){ sumEq += aSample[i].anEq[iCol]; - nSum++; + nSum100 += 100; } } - if( nDLt>nSum ){ - avgEq = (pFinal->anLt[iCol] - sumEq)/(nDLt - nSum); + + if( nDist100>nSum100 ){ + avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100); } if( avgEq==0 ) avgEq = 1; pIdx->aAvgEq[iCol] = avgEq; @@ -85250,6 +87690,11 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ rc = loadStat4(db, sInfo.zDatabase); db->lookaside.bEnabled = lookasideEnabled; } + for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ + Index *pIdx = sqliteHashData(i); + sqlite3_free(pIdx->aiRowEst); + pIdx->aiRowEst = 0; + } #endif if( rc==SQLITE_NOMEM ){ @@ -85471,6 +87916,15 @@ static void attachFunc( rc = sqlite3Init(db, &zErrDyn); sqlite3BtreeLeaveAll(db); } +#ifdef SQLITE_USER_AUTHENTICATION + if( rc==SQLITE_OK ){ + u8 newAuth = 0; + rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); + if( newAuthauth.authLevel ){ + rc = SQLITE_AUTH_USER; + } + } +#endif if( rc ){ int iDb = db->nDb - 1; assert( iDb>=2 ); @@ -85913,7 +88367,7 @@ SQLITE_API int sqlite3_set_authorizer( void *pArg ){ sqlite3_mutex_enter(db->mutex); - db->xAuth = xAuth; + db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; sqlite3ExpirePreparedStatements(db); sqlite3_mutex_leave(db->mutex); @@ -85948,7 +88402,11 @@ SQLITE_PRIVATE int sqlite3AuthReadCol( char *zDb = db->aDb[iDb].zName; /* Name of attached database */ int rc; /* Auth callback return code */ - rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext); + rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext +#ifdef SQLITE_USER_AUTHENTICATION + ,db->auth.zAuthUser +#endif + ); if( rc==SQLITE_DENY ){ if( db->nDb>2 || iDb!=0 ){ sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol); @@ -86048,7 +88506,11 @@ SQLITE_PRIVATE int sqlite3AuthCheck( if( db->xAuth==0 ){ return SQLITE_OK; } - rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext); + rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext +#ifdef SQLITE_USER_AUTHENTICATION + ,db->auth.zAuthUser +#endif + ); if( rc==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized"); pParse->rc = SQLITE_AUTH; @@ -86247,6 +88709,17 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){} sqlite3VdbeAddOp0(v, OP_Halt); +#if SQLITE_USER_AUTHENTICATION + if( pParse->nTableLock>0 && db->init.busy==0 ){ + sqlite3UserAuthInit(db); + if( db->auth.authLevelrc = SQLITE_AUTH_USER; + sqlite3ErrorMsg(pParse, "user not authenticated"); + return; + } + } +#endif + /* The cookie mask contains one bit for each database file open. ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are ** set for each database that is used. Generate code to start a @@ -86362,6 +88835,16 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ pParse->nested--; } +#if SQLITE_USER_AUTHENTICATION +/* +** Return TRUE if zTable is the name of the system table that stores the +** list of users and their access credentials. +*/ +SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){ + return sqlite3_stricmp(zTable, "sqlite_user")==0; +} +#endif + /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the @@ -86377,16 +88860,21 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; - int nName; assert( zName!=0 ); - nName = sqlite3Strlen30(zName); /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); +#if SQLITE_USER_AUTHENTICATION + /* Only the admin user is allowed to know that the sqlite_user table + ** exists */ + if( db->auth.authLevelnDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); - p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, nName); + p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); if( p ) break; } return p; @@ -86426,6 +88914,12 @@ SQLITE_PRIVATE Table *sqlite3LocateTable( } pParse->checkSchema = 1; } +#if SQLITE_USER_AUTHENICATION + else if( pParse->db->auth.authLevelnDb; i++){ @@ -86478,7 +88971,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha assert( pSchema ); if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); - p = sqlite3HashFind(&pSchema->idxHash, zName, nName); + p = sqlite3HashFind(&pSchema->idxHash, zName); if( p ) break; } return p; @@ -86495,6 +88988,9 @@ static void freeIndex(sqlite3 *db, Index *p){ sqlite3ExprDelete(db, p->pPartIdxWhere); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, p->azColl); +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + sqlite3_free(p->aiRowEst); +#endif sqlite3DbFree(db, p); } @@ -86506,13 +89002,11 @@ static void freeIndex(sqlite3 *db, Index *p){ */ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ Index *pIndex; - int len; Hash *pHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pHash = &db->aDb[iDb].pSchema->idxHash; - len = sqlite3Strlen30(zIdxName); - pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0); + pIndex = sqlite3HashInsert(pHash, zIdxName, 0); if( ALWAYS(pIndex) ){ if( pIndex->pTable->pIndex==pIndex ){ pIndex->pTable->pIndex = pIndex->pNext; @@ -86672,7 +89166,7 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ if( !db || db->pnBytesFreed==0 ){ char *zName = pIndex->zName; TESTONLY ( Index *pOld = ) sqlite3HashInsert( - &pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0 + &pIndex->pSchema->idxHash, zName, 0 ); assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); assert( pOld==pIndex || pOld==0 ); @@ -86715,8 +89209,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */ pDb = &db->aDb[iDb]; - p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, - sqlite3Strlen30(zTabName),0); + p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); sqlite3DeleteTable(db, p); db->flags |= SQLITE_InternChanges; } @@ -87240,7 +89733,7 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){ ** estimate is scaled so that the size of an integer is 1. */ if( pszEst ){ *pszEst = 1; /* default size is approx 4 bytes */ - if( aff<=SQLITE_AFF_NONE ){ + if( affpNewTable; if( p!=0 ){ pCol = &(p->aCol[p->nCol-1]); - if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr) ){ + if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){ sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", pCol->zName); }else{ @@ -87611,8 +90104,8 @@ static char *createTableStmt(sqlite3 *db, Table *p){ zStmt[k++] = '('; for(pCol=p->aCol, i=0; inCol; i++, pCol++){ static const char * const azType[] = { - /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NONE */ "", + /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NUMERIC */ " NUM", /* SQLITE_AFF_INTEGER */ " INT", /* SQLITE_AFF_REAL */ " REAL" @@ -87624,15 +90117,15 @@ static char *createTableStmt(sqlite3 *db, Table *p){ k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; identPut(zStmt, &k, pCol->zName); - assert( pCol->affinity-SQLITE_AFF_TEXT >= 0 ); - assert( pCol->affinity-SQLITE_AFF_TEXT < ArraySize(azType) ); - testcase( pCol->affinity==SQLITE_AFF_TEXT ); + assert( pCol->affinity-SQLITE_AFF_NONE >= 0 ); + assert( pCol->affinity-SQLITE_AFF_NONE < ArraySize(azType) ); testcase( pCol->affinity==SQLITE_AFF_NONE ); + testcase( pCol->affinity==SQLITE_AFF_TEXT ); testcase( pCol->affinity==SQLITE_AFF_NUMERIC ); testcase( pCol->affinity==SQLITE_AFF_INTEGER ); testcase( pCol->affinity==SQLITE_AFF_REAL ); - zType = azType[pCol->affinity - SQLITE_AFF_TEXT]; + zType = azType[pCol->affinity - SQLITE_AFF_NONE]; len = sqlite3Strlen30(zType); assert( pCol->affinity==SQLITE_AFF_NONE || pCol->affinity==sqlite3AffinityType(zType, 0) ); @@ -87716,7 +90209,7 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){ ** no rowid btree for a WITHOUT ROWID. Instead, the canonical ** data storage is a covering index btree. ** (2) Bypass the creation of the sqlite_master table entry -** for the PRIMARY KEY as the the primary key index is now +** for the PRIMARY KEY as the primary key index is now ** identified by the sqlite_master table entry of the table itself. ** (3) Set the Index.tnum of the PRIMARY KEY Index object in the ** schema to the rootpage from the main table. @@ -87737,7 +90230,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ Vdbe *v = pParse->pVdbe; /* Convert the OP_CreateTable opcode that would normally create the - ** root-page for the table into a OP_CreateIndex opcode. The index + ** root-page for the table into an OP_CreateIndex opcode. The index ** created will become the PRIMARY KEY index. */ if( pParse->addrCrTab ){ @@ -88038,8 +90531,7 @@ SQLITE_PRIVATE void sqlite3EndTable( Table *pOld; Schema *pSchema = p->pSchema; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, - sqlite3Strlen30(p->zName),p); + pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ db->mallocFailed = 1; @@ -88150,7 +90642,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ int nErr = 0; /* Number of errors encountered */ int n; /* Temporarily holds the number of cursors assigned */ sqlite3 *db = pParse->db; /* Database connection for malloc errors */ - int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); + sqlite3_xauth xAuth; /* Saved xAuth pointer */ assert( pTable ); @@ -88689,7 +91181,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash, - pFKey->zTo, sqlite3Strlen30(pFKey->zTo), (void *)pFKey + pFKey->zTo, (void *)pFKey ); if( pNextTo==pFKey ){ db->mallocFailed = 1; @@ -88752,7 +91244,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ int iPartIdxLabel; /* Jump to this label to skip a row */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ - int regRecord; /* Register holding assemblied index record */ + int regRecord; /* Register holding assembled index record */ sqlite3 *db = pParse->db; /* The database connection */ int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); @@ -88777,7 +91269,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ /* Open the sorter cursor if we are to use one. */ iSorter = pParse->nTab++; - sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*) + sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*) sqlite3KeyInfoRef(pKey), P4_KEYINFO); /* Open the table. Loop through all rows of the table, inserting index @@ -88808,7 +91300,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ }else{ addr2 = sqlite3VdbeCurrentAddr(v); } - sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord); + sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); @@ -88965,6 +91457,10 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( assert( pTab!=0 ); assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 + && db->init.busy==0 +#if SQLITE_USER_AUTHENTICATION + && sqlite3UserAuthTable(pTab->zName)==0 +#endif && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; @@ -89126,7 +91622,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( pParse->checkSchema = 1; goto exit_create_index; } - assert( pTab->nCol<=0x7fff && j<=0x7fff ); + assert( j<=0x7fff ); pIndex->aiColumn[i] = (i16)j; if( pListItem->pExpr ){ int nColl; @@ -89237,8 +91733,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( Index *p; assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); p = sqlite3HashInsert(&pIndex->pSchema->idxHash, - pIndex->zName, sqlite3Strlen30(pIndex->zName), - pIndex); + pIndex->zName, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ db->mallocFailed = 1; @@ -89353,7 +91848,7 @@ exit_create_index: ** Fill the Index.aiRowEst[] array with default information - information ** to be used when we have not run the ANALYZE command. ** -** aiRowEst[0] is suppose to contain the number of elements in the index. +** aiRowEst[0] is supposed to contain the number of elements in the index. ** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the ** number of rows in the table that match any particular value of the ** first column of the index. aiRowEst[2] is an estimate of the number @@ -89732,7 +92227,7 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ ** if this is the first term of the FROM clause. pTable and pDatabase ** are the name of the table and database named in the FROM clause term. ** pDatabase is NULL if the database name qualifier is missing - the -** usual case. If the term has a alias, then pAlias points to the +** usual case. If the term has an alias, then pAlias points to the ** alias token. If the term is a subquery, then pSubquery is the ** SELECT statement that the subquery encodes. The pTable and ** pDatabase parameters are NULL for subqueries. The pOn and pUsing @@ -90495,7 +92990,7 @@ SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ ** ** Each pointer stored in the sqlite3.aCollSeq hash table contains an ** array of three CollSeq structures. The first is the collation sequence -** prefferred for UTF-8, the second UTF-16le, and the third UTF-16be. +** preferred for UTF-8, the second UTF-16le, and the third UTF-16be. ** ** Stored immediately after the three collation sequences is a copy of ** the collation sequence name. A pointer to this string is stored in @@ -90507,11 +93002,11 @@ static CollSeq *findCollSeqEntry( int create /* Create a new entry if true */ ){ CollSeq *pColl; - int nName = sqlite3Strlen30(zName); - pColl = sqlite3HashFind(&db->aCollSeq, zName, nName); + pColl = sqlite3HashFind(&db->aCollSeq, zName); if( 0==pColl && create ){ - pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1 ); + int nName = sqlite3Strlen30(zName); + pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1); if( pColl ){ CollSeq *pDel = 0; pColl[0].zName = (char*)&pColl[3]; @@ -90522,7 +93017,7 @@ static CollSeq *findCollSeqEntry( pColl[2].enc = SQLITE_UTF16BE; memcpy(pColl[0].zName, zName, nName); pColl[0].zName[nName] = 0; - pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl); + pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl); /* If a malloc() failure occurred in sqlite3HashInsert(), it will ** return the pColl pointer to be deleted (because it wasn't added @@ -90922,7 +93417,7 @@ SQLITE_PRIVATE void sqlite3MaterializeView( Parse *pParse, /* Parsing context */ Table *pView, /* View definition */ Expr *pWhere, /* Optional WHERE clause to be added */ - int iCur /* Cursor number for ephemerial table */ + int iCur /* Cursor number for ephemeral table */ ){ SelectDest dest; Select *pSel; @@ -91080,7 +93575,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( int addrBypass = 0; /* Address of jump over the delete logic */ int addrLoop = 0; /* Top of the delete loop */ int addrDelete = 0; /* Jump directly to the delete logic */ - int addrEphOpen = 0; /* Instruction to open the Ephermeral table */ + int addrEphOpen = 0; /* Instruction to open the Ephemeral table */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ @@ -91160,7 +93655,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( sqlite3BeginWriteOperation(pParse, 1, iDb); /* If we are trying to delete from a view, realize that view into - ** a ephemeral table. + ** an ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( isView ){ @@ -91214,7 +93709,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( iRowSet = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); }else{ - /* For a WITHOUT ROWID table, create an ephermeral table used to + /* For a WITHOUT ROWID table, create an ephemeral table used to ** hold all primary keys for rows to be deleted. */ pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); @@ -91298,10 +93793,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( ** triggers. */ if( !isView ){ + testcase( IsVirtual(pTab) ); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen, &iDataCur, &iIdxCur); - assert( pPk || iDataCur==iTabCur ); - assert( pPk || iIdxCur==iDataCur+1 ); + assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur ); + assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 ); } /* Set up a loop over the rowids/primary-keys that were found in the @@ -91309,9 +93805,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( */ if( okOnePass ){ /* Just one row. Hence the top-of-loop is a no-op */ - assert( nKey==nPk ); /* OP_Found will use an unpacked key */ + assert( nKey==nPk ); /* OP_Found will use an unpacked key */ + assert( !IsVirtual(pTab) ); if( aToOpen[iDataCur-iTabCur] ){ - assert( pPk!=0 ); + assert( pPk!=0 || pTab->pSelect!=0 ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); VdbeCoverage(v); } @@ -91387,7 +93884,7 @@ delete_from_cleanup: return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise -** thely may interfere with compilation of other functions in this file +** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView @@ -91681,7 +94178,7 @@ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file contains the C-language implementions for many of the SQL +** This file contains the C-language implementations for many of the SQL ** functions of SQLite. (Some function, and in particular the date and ** time functions, are implemented separately.) */ @@ -91692,7 +94189,10 @@ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ ** Return the collating function associated with a function. */ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ - return context->pColl; + VdbeOp *pOp = &context->pVdbe->aOp[context->iOp-1]; + assert( pOp->opcode==OP_CollSeq ); + assert( pOp->p4type==P4_COLLSEQ ); + return pOp->p4.pColl; } /* @@ -91995,13 +94495,14 @@ static void substrFunc( for(z2=z; *z2 && p2; p2--){ SQLITE_SKIP_UTF8(z2); } - sqlite3_result_text(context, (char*)z, (int)(z2-z), SQLITE_TRANSIENT); + sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT, + SQLITE_UTF8); }else{ if( p1+p2>len ){ p2 = len-p1; if( p2<0 ) p2 = 0; } - sqlite3_result_blob(context, (char*)&z[p1], (int)p2, SQLITE_TRANSIENT); + sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT); } } @@ -92060,7 +94561,7 @@ static void *contextMalloc(sqlite3_context *context, i64 nByte){ sqlite3_result_error_toobig(context); z = 0; }else{ - z = sqlite3Malloc((int)nByte); + z = sqlite3Malloc(nByte); if( !z ){ sqlite3_result_error_nomem(context); } @@ -92236,10 +94737,12 @@ struct compareInfo { ** whereas only characters less than 0x80 do in ASCII. */ #if defined(SQLITE_EBCDIC) -# define sqlite3Utf8Read(A) (*((*A)++)) -# define GlobUpperToLower(A) A = sqlite3UpperToLower[A] +# define sqlite3Utf8Read(A) (*((*A)++)) +# define GlobUpperToLower(A) A = sqlite3UpperToLower[A] +# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A] #else -# define GlobUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; } +# define GlobUpperToLower(A) if( A<=0x7f ){ A = sqlite3UpperToLower[A]; } +# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A] #endif static const struct compareInfo globInfo = { '*', '?', '[', 0 }; @@ -92252,7 +94755,7 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; /* ** Compare two UTF-8 strings for equality where the first string can -** potentially be a "glob" expression. Return true (1) if they +** potentially be a "glob" or "like" expression. Return true (1) if they ** are the same and false (0) if they are different. ** ** Globbing rules: @@ -92272,11 +94775,18 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; ** "[a-z]" matches any single lower-case letter. To match a '-', make ** it the last character in the list. ** +** Like matching rules: +** +** '%' Matches any sequence of zero or more characters +** +*** '_' Matches any one character +** +** Ec Where E is the "esc" character and c is any other +** character, including '%', '_', and esc, match exactly c. +** +** The comments through this routine usually assume glob matching. +** ** This routine is usually quick, but can be N**2 in the worst case. -** -** Hints: to match '*' or '?', put them in "[]". Like this: -** -** abc[*]xyz Matches "abc*xyz" only */ static int patternCompare( const u8 *zPattern, /* The glob pattern */ @@ -92284,17 +94794,25 @@ static int patternCompare( const struct compareInfo *pInfo, /* Information about how to do the compare */ u32 esc /* The escape character */ ){ - u32 c, c2; - int invert; - int seen; - u8 matchOne = pInfo->matchOne; - u8 matchAll = pInfo->matchAll; - u8 matchSet = pInfo->matchSet; - u8 noCase = pInfo->noCase; - int prevEscape = 0; /* True if the previous character was 'escape' */ + u32 c, c2; /* Next pattern and input string chars */ + u32 matchOne = pInfo->matchOne; /* "?" or "_" */ + u32 matchAll = pInfo->matchAll; /* "*" or "%" */ + u32 matchOther; /* "[" or the escape character */ + u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */ + const u8 *zEscaped = 0; /* One past the last escaped input char */ + + /* The GLOB operator does not have an ESCAPE clause. And LIKE does not + ** have the matchSet operator. So we either have to look for one or + ** the other, never both. Hence the single variable matchOther is used + ** to store the one we have to look for. + */ + matchOther = esc ? esc : pInfo->matchSet; while( (c = sqlite3Utf8Read(&zPattern))!=0 ){ - if( c==matchAll && !prevEscape ){ + if( c==matchAll ){ /* Match "*" */ + /* Skip over multiple "*" characters in the pattern. If there + ** are also "?" characters, skip those as well, but consume a + ** single character of the input string for each "?" skipped */ while( (c=sqlite3Utf8Read(&zPattern)) == matchAll || c == matchOne ){ if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){ @@ -92302,86 +94820,98 @@ static int patternCompare( } } if( c==0 ){ - return 1; - }else if( c==esc ){ - c = sqlite3Utf8Read(&zPattern); - if( c==0 ){ - return 0; - } - }else if( c==matchSet ){ - assert( esc==0 ); /* This is GLOB, not LIKE */ - assert( matchSet<0x80 ); /* '[' is a single-byte character */ - while( *zString && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){ - SQLITE_SKIP_UTF8(zString); - } - return *zString!=0; - } - while( (c2 = sqlite3Utf8Read(&zString))!=0 ){ - if( noCase ){ - GlobUpperToLower(c2); - GlobUpperToLower(c); - while( c2 != 0 && c2 != c ){ - c2 = sqlite3Utf8Read(&zString); - GlobUpperToLower(c2); - } + return 1; /* "*" at the end of the pattern matches */ + }else if( c==matchOther ){ + if( esc ){ + c = sqlite3Utf8Read(&zPattern); + if( c==0 ) return 0; }else{ - while( c2 != 0 && c2 != c ){ - c2 = sqlite3Utf8Read(&zString); + /* "[...]" immediately follows the "*". We have to do a slow + ** recursive search in this case, but it is an unusual case. */ + assert( matchOther<0x80 ); /* '[' is a single-byte character */ + while( *zString + && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){ + SQLITE_SKIP_UTF8(zString); } + return *zString!=0; + } + } + + /* At this point variable c contains the first character of the + ** pattern string past the "*". Search in the input string for the + ** first matching character and recursively contine the match from + ** that point. + ** + ** For a case-insensitive search, set variable cx to be the same as + ** c but in the other case and search the input string for either + ** c or cx. + */ + if( c<=0x80 ){ + u32 cx; + if( noCase ){ + cx = sqlite3Toupper(c); + c = sqlite3Tolower(c); + }else{ + cx = c; + } + while( (c2 = *(zString++))!=0 ){ + if( c2!=c && c2!=cx ) continue; + if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; + } + }else{ + while( (c2 = sqlite3Utf8Read(&zString))!=0 ){ + if( c2!=c ) continue; + if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; } - if( c2==0 ) return 0; - if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; } return 0; - }else if( c==matchOne && !prevEscape ){ - if( sqlite3Utf8Read(&zString)==0 ){ - return 0; - } - }else if( c==matchSet ){ - u32 prior_c = 0; - assert( esc==0 ); /* This only occurs for GLOB, not LIKE */ - seen = 0; - invert = 0; - c = sqlite3Utf8Read(&zString); - if( c==0 ) return 0; - c2 = sqlite3Utf8Read(&zPattern); - if( c2=='^' ){ - invert = 1; - c2 = sqlite3Utf8Read(&zPattern); - } - if( c2==']' ){ - if( c==']' ) seen = 1; - c2 = sqlite3Utf8Read(&zPattern); - } - while( c2 && c2!=']' ){ - if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ - c2 = sqlite3Utf8Read(&zPattern); - if( c>=prior_c && c<=c2 ) seen = 1; - prior_c = 0; - }else{ - if( c==c2 ){ - seen = 1; - } - prior_c = c2; - } - c2 = sqlite3Utf8Read(&zPattern); - } - if( c2==0 || (seen ^ invert)==0 ){ - return 0; - } - }else if( esc==c && !prevEscape ){ - prevEscape = 1; - }else{ - c2 = sqlite3Utf8Read(&zString); - if( noCase ){ - GlobUpperToLower(c); - GlobUpperToLower(c2); - } - if( c!=c2 ){ - return 0; - } - prevEscape = 0; } + if( c==matchOther ){ + if( esc ){ + c = sqlite3Utf8Read(&zPattern); + if( c==0 ) return 0; + zEscaped = zPattern; + }else{ + u32 prior_c = 0; + int seen = 0; + int invert = 0; + c = sqlite3Utf8Read(&zString); + if( c==0 ) return 0; + c2 = sqlite3Utf8Read(&zPattern); + if( c2=='^' ){ + invert = 1; + c2 = sqlite3Utf8Read(&zPattern); + } + if( c2==']' ){ + if( c==']' ) seen = 1; + c2 = sqlite3Utf8Read(&zPattern); + } + while( c2 && c2!=']' ){ + if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ + c2 = sqlite3Utf8Read(&zPattern); + if( c>=prior_c && c<=c2 ) seen = 1; + prior_c = 0; + }else{ + if( c==c2 ){ + seen = 1; + } + prior_c = c2; + } + c2 = sqlite3Utf8Read(&zPattern); + } + if( c2==0 || (seen ^ invert)==0 ){ + return 0; + } + continue; + } + } + c2 = sqlite3Utf8Read(&zString); + if( c==c2 ) continue; + if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){ + continue; + } + if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; + return 0; } return *zString==0; } @@ -92711,7 +95241,7 @@ static void charFunc( *zOut++ = 0x80 + (u8)(c & 0x3F); } \ } - sqlite3_result_text(context, (char*)z, (int)(zOut-z), sqlite3_free); + sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8); } /* @@ -93161,6 +95691,7 @@ static void minmaxStep( sqlite3SkipAccumulatorLoad(context); } }else{ + pBest->db = sqlite3_context_db_handle(context); sqlite3VdbeMemCopy(pBest, pArg); } } @@ -93308,7 +95839,7 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas } /* -** All all of the FuncDef structures in the aBuiltinFunc[] array above +** All of the FuncDef structures in the aBuiltinFunc[] array above ** to the global function hash table. This occurs at start-time (as ** a consequence of calling sqlite3_initialize()). ** @@ -93332,10 +95863,12 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){ FUNCTION(trim, 2, 3, 0, trimFunc ), FUNCTION(min, -1, 0, 1, minmaxFunc ), FUNCTION(min, 0, 0, 1, 0 ), - AGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize ), + AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize, + SQLITE_FUNC_MINMAX ), FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, 0, 1, 1, 0 ), - AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ), + AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize, + SQLITE_FUNC_MINMAX ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION(instr, 2, 0, 0, instrFunc ), @@ -93365,6 +95898,9 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){ FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), +#if SQLITE_USER_AUTHENTICATION + FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), +#endif #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), @@ -93385,8 +95921,8 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){ AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ), AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ), - /* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */ - {0,SQLITE_UTF8|SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0}, + AGGREGATE2(count, 0, 0, 0, countStep, countFinalize, + SQLITE_FUNC_COUNT ), AGGREGATE(count, 1, 0, 0, countStep, countFinalize ), AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize), AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), @@ -93593,7 +96129,7 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){ ** ** 4) No parent key columns were provided explicitly as part of the ** foreign key definition, and the PRIMARY KEY of the parent table -** consists of a a different number of columns to the child key in +** consists of a different number of columns to the child key in ** the child table. ** ** then non-zero is returned, and a "foreign key mismatch" error loaded @@ -94079,8 +96615,7 @@ static void fkScanChildren( ** table). */ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){ - int nName = sqlite3Strlen30(pTab->zName); - return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName, nName); + return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName); } /* @@ -94758,7 +97293,7 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){ }else{ void *p = (void *)pFKey->pNextTo; const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo); - sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, sqlite3Strlen30(z), p); + sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p); } if( pFKey->pNextTo ){ pFKey->pNextTo->pPrevTo = pFKey->pPrevTo; @@ -94841,13 +97376,13 @@ SQLITE_PRIVATE void sqlite3OpenTable( ** ** Character Column affinity ** ------------------------------ -** 'a' TEXT -** 'b' NONE -** 'c' NUMERIC -** 'd' INTEGER -** 'e' REAL +** 'A' NONE +** 'B' TEXT +** 'C' NUMERIC +** 'D' INTEGER +** 'F' REAL ** -** An extra 'd' is appended to the end of the string to cover the +** An extra 'D' is appended to the end of the string to cover the ** rowid that appears as the last column in every index. ** ** Memory for the buffer containing the column index affinity string @@ -94896,11 +97431,11 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ ** ** Character Column affinity ** ------------------------------ -** 'a' TEXT -** 'b' NONE -** 'c' NUMERIC -** 'd' INTEGER -** 'e' REAL +** 'A' NONE +** 'B' TEXT +** 'C' NUMERIC +** 'D' INTEGER +** 'E' REAL */ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ int i; @@ -95195,7 +97730,7 @@ static int xferOptimization( ** The 4th template is used if the insert statement takes its ** values from a SELECT but the data is being inserted into a table ** that is also read as part of the SELECT. In the third form, -** we have to use a intermediate table to store the results of +** we have to use an intermediate table to store the results of ** the select. The template is like this: ** ** X <- A @@ -95360,7 +97895,7 @@ SQLITE_PRIVATE void sqlite3Insert( regAutoinc = autoIncBegin(pParse, iDb, pTab); /* Allocate registers for holding the rowid of the new row, - ** the content of the new row, and the assemblied row record. + ** the content of the new row, and the assembled row record. */ regRowid = regIns = pParse->nMem+1; pParse->nMem += pTab->nCol + 1; @@ -95812,7 +98347,7 @@ insert_cleanup: } /* Make sure "isView" and other macros defined above are undefined. Otherwise -** thely may interfere with compilation of other functions in this file +** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView @@ -95928,7 +98463,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( int ix; /* Index loop counter */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ - int j1; /* Addresss of jump instruction */ + int j1; /* Address of jump instruction */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ int ipkTop = 0; /* Top of the rowid change constraint check */ @@ -96332,7 +98867,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( Index *pIdx; /* An index being inserted or updated */ u8 pik_flags; /* flag values passed to the btree insert */ int regData; /* Content registers (after the rowid) */ - int regRec; /* Register holding assemblied record for the table */ + int regRec; /* Register holding assembled record for the table */ int i; /* Loop counter */ u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */ @@ -96397,6 +98932,9 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( ** For a WITHOUT ROWID table, *piDataCur will be somewhere in the range ** of *piIdxCurs, depending on where the PRIMARY KEY index appears on the ** pTab->pIndex list. +** +** If pTab is a virtual table, then this routine is a no-op and the +** *piDataCur and *piIdxCur values are left uninitialized. */ SQLITE_PRIVATE int sqlite3OpenTableAndIndices( Parse *pParse, /* Parsing context */ @@ -96415,9 +98953,9 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices( assert( op==OP_OpenRead || op==OP_OpenWrite ); if( IsVirtual(pTab) ){ - assert( aToOpen==0 ); - *piDataCur = 0; - *piIdxCur = 1; + /* This routine is a no-op for virtual tables. Leave the output + ** variables *piDataCur and *piIdxCur uninitialized so that valgrind + ** can detect if they are used by mistake in the caller. */ return 0; } iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); @@ -96454,7 +98992,7 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices( ** The following global variable is incremented whenever the ** transfer optimization is used. This is used for testing ** purposes only - to make sure the transfer optimization really -** is happening when it is suppose to. +** is happening when it is supposed to. */ SQLITE_API int sqlite3_xferopt_count; #endif /* SQLITE_TEST */ @@ -96521,7 +99059,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ ** INSERT INTO tab1 SELECT * FROM tab2; ** ** The xfer optimization transfers raw records from tab2 over to tab1. -** Columns are not decoded and reassemblied, which greatly improves +** Columns are not decoded and reassembled, which greatly improves ** performance. Raw index records are transferred in the same way. ** ** The xfer optimization is only attempted if tab1 and tab2 are compatible. @@ -96849,7 +99387,7 @@ SQLITE_API int sqlite3_exec( if( zSql==0 ) zSql = ""; sqlite3_mutex_enter(db->mutex); - sqlite3Error(db, SQLITE_OK, 0); + sqlite3Error(db, SQLITE_OK); while( rc==SQLITE_OK && zSql[0] ){ int nCol; char **azVals = 0; @@ -96907,7 +99445,7 @@ SQLITE_API int sqlite3_exec( rc = SQLITE_ABORT; sqlite3VdbeFinalize((Vdbe *)pStmt); pStmt = 0; - sqlite3Error(db, SQLITE_ABORT, 0); + sqlite3Error(db, SQLITE_ABORT); goto exec_out; } } @@ -96930,14 +99468,14 @@ exec_out: sqlite3DbFree(db, azCols); rc = sqlite3ApiExit(db, rc); - if( rc!=SQLITE_OK && ALWAYS(rc==sqlite3_errcode(db)) && pzErrMsg ){ + if( rc!=SQLITE_OK && pzErrMsg ){ int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db)); *pzErrMsg = sqlite3Malloc(nErrMsg); if( *pzErrMsg ){ memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg); }else{ rc = SQLITE_NOMEM; - sqlite3Error(db, SQLITE_NOMEM, 0); + sqlite3Error(db, SQLITE_NOMEM); } }else if( pzErrMsg ){ *pzErrMsg = 0; @@ -96999,7 +99537,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** WARNING: In order to maintain backwards compatibility, add new ** interfaces to the end of this structure only. If you insert new ** interfaces in the middle of this structure, then older different -** versions of SQLite will not be able to load each others' shared +** versions of SQLite will not be able to load each other's shared ** libraries! */ struct sqlite3_api_routines { @@ -97221,11 +99759,28 @@ struct sqlite3_api_routines { const char *(*uri_parameter)(const char*,const char*); char *(*vsnprintf)(int,char*,const char*,va_list); int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); + /* Version 3.8.7 and later */ + int (*auto_extension)(void(*)(void)); + int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, + void(*)(void*)); + int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, + void(*)(void*),unsigned char); + int (*cancel_auto_extension)(void(*)(void)); + int (*load_extension)(sqlite3*,const char*,const char*,char**); + void *(*malloc64)(sqlite3_uint64); + sqlite3_uint64 (*msize)(void*); + void *(*realloc64)(void*,sqlite3_uint64); + void (*reset_auto_extension)(void); + void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, + void(*)(void*)); + void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, + void(*)(void*), unsigned char); + int (*strglob)(const char*,const char*); }; /* ** The following macros redefine the API routines so that they are -** redirected throught the global sqlite3_api structure. +** redirected through the global sqlite3_api structure. ** ** This header file is also used by the loadext.c source file ** (part of the main SQLite library - not an extension) so that @@ -97438,6 +99993,19 @@ struct sqlite3_api_routines { #define sqlite3_uri_parameter sqlite3_api->uri_parameter #define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 +/* Version 3.8.7 and later */ +#define sqlite3_auto_extension sqlite3_api->auto_extension +#define sqlite3_bind_blob64 sqlite3_api->bind_blob64 +#define sqlite3_bind_text64 sqlite3_api->bind_text64 +#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension +#define sqlite3_load_extension sqlite3_api->load_extension +#define sqlite3_malloc64 sqlite3_api->malloc64 +#define sqlite3_msize sqlite3_api->msize +#define sqlite3_realloc64 sqlite3_api->realloc64 +#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension +#define sqlite3_result_blob64 sqlite3_api->result_blob64 +#define sqlite3_result_text64 sqlite3_api->result_text64 +#define sqlite3_strglob sqlite3_api->strglob #endif /* SQLITE_CORE */ #ifndef SQLITE_CORE @@ -97831,7 +100399,20 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_uri_int64, sqlite3_uri_parameter, sqlite3_vsnprintf, - sqlite3_wal_checkpoint_v2 + sqlite3_wal_checkpoint_v2, + /* Version 3.8.7 and later */ + sqlite3_auto_extension, + sqlite3_bind_blob64, + sqlite3_bind_text64, + sqlite3_cancel_auto_extension, + sqlite3_load_extension, + sqlite3_malloc64, + sqlite3_msize, + sqlite3_realloc64, + sqlite3_reset_auto_extension, + sqlite3_result_blob64, + sqlite3_result_text64, + sqlite3_strglob }; /* @@ -98190,7 +100771,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ sqlite3_mutex_leave(mutex); zErrmsg = 0; if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){ - sqlite3Error(db, rc, + sqlite3ErrorWithMsg(db, rc, "automatic extension loading failed: %s", zErrmsg); go = 0; } @@ -98262,14 +100843,15 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ #define PragTyp_TABLE_INFO 30 #define PragTyp_TEMP_STORE 31 #define PragTyp_TEMP_STORE_DIRECTORY 32 -#define PragTyp_WAL_AUTOCHECKPOINT 33 -#define PragTyp_WAL_CHECKPOINT 34 -#define PragTyp_ACTIVATE_EXTENSIONS 35 -#define PragTyp_HEXKEY 36 -#define PragTyp_KEY 37 -#define PragTyp_REKEY 38 -#define PragTyp_LOCK_STATUS 39 -#define PragTyp_PARSER_TRACE 40 +#define PragTyp_THREADS 33 +#define PragTyp_WAL_AUTOCHECKPOINT 34 +#define PragTyp_WAL_CHECKPOINT 35 +#define PragTyp_ACTIVATE_EXTENSIONS 36 +#define PragTyp_HEXKEY 37 +#define PragTyp_KEY 38 +#define PragTyp_REKEY 39 +#define PragTyp_LOCK_STATUS 40 +#define PragTyp_PARSER_TRACE 41 #define PragFlag_NeedSchema 0x01 static const struct sPragmaNames { const char *const zName; /* Name of pragma */ @@ -98619,6 +101201,10 @@ static const struct sPragmaNames { /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif + { /* zName: */ "threads", + /* ePragTyp: */ PragTyp_THREADS, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) { /* zName: */ "user_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, @@ -98666,7 +101252,7 @@ static const struct sPragmaNames { /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, #endif }; -/* Number of pragmas: 56 on by default, 69 total. */ +/* Number of pragmas: 57 on by default, 70 total. */ /* End of the automatically generated pragma table. ***************************************************************************/ @@ -99593,6 +102179,12 @@ SQLITE_PRIVATE void sqlite3Pragma( ** in auto-commit mode. */ mask &= ~(SQLITE_ForeignKeys); } +#if SQLITE_USER_AUTHENTICATION + if( db->auth.authLevel==UAUTH_User ){ + /* Do not allow non-admin users to modify the schema arbitrarily */ + mask &= ~(SQLITE_WriteSchema); + } +#endif if( sqlite3GetBoolean(zRight, 0) ){ db->flags |= mask; @@ -100474,6 +103066,26 @@ SQLITE_PRIVATE void sqlite3Pragma( break; } + /* + ** PRAGMA threads + ** PRAGMA threads = N + ** + ** Configure the maximum number of worker threads. Return the new + ** maximum, which might be less than requested. + */ + case PragTyp_THREADS: { + sqlite3_int64 N; + if( zRight + && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK + && N>=0 + ){ + sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff)); + } + returnSingleInt(pParse, "threads", + sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1)); + break; + } + #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Report the current state of file logs for all databases @@ -100890,7 +103502,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ db->aDb[iDb].zName, zMasterName); #ifndef SQLITE_OMIT_AUTHORIZATION { - int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); + sqlite3_xauth xAuth; xAuth = db->xAuth; db->xAuth = 0; #endif @@ -100956,6 +103568,7 @@ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int commit_internal = !(db->flags&SQLITE_InternChanges); assert( sqlite3_mutex_held(db->mutex) ); + assert( db->init.busy==0 ); rc = SQLITE_OK; db->init.busy = 1; for(i=0; rc==SQLITE_OK && inDb; i++){ @@ -100971,8 +103584,8 @@ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){ ** schema may contain references to objects in other databases. */ #ifndef SQLITE_OMIT_TEMPDB - if( rc==SQLITE_OK && ALWAYS(db->nDb>1) - && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ + assert( db->nDb>1 ); + if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, 1, pzErrMsg); if( rc ){ sqlite3ResetOneSchema(db, 1); @@ -101155,7 +103768,7 @@ static int sqlite3Prepare( rc = sqlite3BtreeSchemaLocked(pBt); if( rc ){ const char *zDb = db->aDb[i].zName; - sqlite3Error(db, rc, "database schema is locked: %s", zDb); + sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); testcase( db->flags & SQLITE_ReadUncommitted ); goto end_prepare; } @@ -101172,7 +103785,7 @@ static int sqlite3Prepare( testcase( nBytes==mxLen ); testcase( nBytes==mxLen+1 ); if( nBytes>mxLen ){ - sqlite3Error(db, SQLITE_TOOBIG, "statement too long"); + sqlite3ErrorWithMsg(db, SQLITE_TOOBIG, "statement too long"); rc = sqlite3ApiExit(db, SQLITE_TOOBIG); goto end_prepare; } @@ -101239,10 +103852,10 @@ static int sqlite3Prepare( } if( zErrMsg ){ - sqlite3Error(db, rc, "%s", zErrMsg); + sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg); sqlite3DbFree(db, zErrMsg); }else{ - sqlite3Error(db, rc, 0); + sqlite3Error(db, rc); } /* Delete any TriggerPrg structures allocated while parsing this statement. */ @@ -101463,6 +104076,20 @@ SQLITE_API int sqlite3_prepare16_v2( ** to handle SELECT statements in SQLite. */ +/* +** Trace output macros +*/ +#if SELECTTRACE_ENABLED +/***/ int sqlite3SelectTrace = 0; +# define SELECTTRACE(K,P,S,X) \ + if(sqlite3SelectTrace&(K)) \ + sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",(S)->zSelName,(S)),\ + sqlite3DebugPrintf X +#else +# define SELECTTRACE(K,P,S,X) +#endif + + /* ** An instance of the following object is used to record information about ** how to process the DISTINCT keyword, to simplify passing that information @@ -101575,6 +104202,18 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( return pNew; } +#if SELECTTRACE_ENABLED +/* +** Set the name of a Select object +*/ +SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){ + if( p && zName ){ + sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName); + } +} +#endif + + /* ** Delete the given Select structure and all of its substructures. */ @@ -101904,28 +104543,43 @@ static KeyInfo *keyInfoFromExprList( ); /* -** Insert code into "v" that will push the record in register regData -** into the sorter. +** Generate code that will push the record in registers regData +** through regData+nData-1 onto the sorter. */ static void pushOntoSorter( Parse *pParse, /* Parser context */ SortCtx *pSort, /* Information about the ORDER BY clause */ Select *pSelect, /* The whole SELECT statement */ - int regData /* Register holding data to be sorted */ + int regData, /* First register holding data to be sorted */ + int nData, /* Number of elements in the data array */ + int nPrefixReg /* No. of reg prior to regData available for use */ ){ - Vdbe *v = pParse->pVdbe; - int nExpr = pSort->pOrderBy->nExpr; - int regRecord = ++pParse->nMem; - int regBase = pParse->nMem+1; - int nOBSat = pSort->nOBSat; - int op; + Vdbe *v = pParse->pVdbe; /* Stmt under construction */ + int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter)==0); + int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */ + int nBase = nExpr + bSeq + nData; /* Fields in sorter record */ + int regBase; /* Regs for sorter record */ + int regRecord = ++pParse->nMem; /* Assembled sorter record */ + int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */ + int op; /* Opcode to add sorter record to sorter */ - pParse->nMem += nExpr+2; /* nExpr+2 registers allocated at regBase */ - sqlite3ExprCacheClear(pParse); - sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0); - sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); - sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat,regRecord); + assert( bSeq==0 || bSeq==1 ); + if( nPrefixReg ){ + assert( nPrefixReg==nExpr+bSeq ); + regBase = regData - nExpr - bSeq; + }else{ + regBase = pParse->nMem + 1; + pParse->nMem += nBase; + } + sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, SQLITE_ECEL_DUP); + if( bSeq ){ + sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); + } + if( nPrefixReg==0 ){ + sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData); + } + + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord); if( nOBSat>0 ){ int regPrevKey; /* The first nOBSat columns of the previous row */ int addrFirst; /* Address of the OP_IfNot opcode */ @@ -101936,12 +104590,17 @@ static void pushOntoSorter( regPrevKey = pParse->nMem+1; pParse->nMem += pSort->nOBSat; - nKey = nExpr - pSort->nOBSat + 1; - addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v); + nKey = nExpr - pSort->nOBSat + bSeq; + if( bSeq ){ + addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); + }else{ + addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor); + } + VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat); pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); if( pParse->db->mallocFailed ) return; - pOp->p2 = nKey + 1; + pOp->p2 = nKey + nData; pKI = pOp->p4.pKeyInfo; memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */ sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); @@ -101953,7 +104612,7 @@ static void pushOntoSorter( sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); sqlite3VdbeJumpHere(v, addrFirst); - sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat); + sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat); sqlite3VdbeJumpHere(v, addrJmp); } if( pSort->sortFlags & SORTFLAG_UseSorter ){ @@ -102075,6 +104734,7 @@ static void selectInnerLoop( int eDest = pDest->eDest; /* How to dispose of results */ int iParm = pDest->iSDParm; /* First argument to disposal method */ int nResultCol; /* Number of result columns */ + int nPrefixReg = 0; /* Number of extra registers before regResult */ assert( v ); assert( pEList!=0 ); @@ -102090,6 +104750,11 @@ static void selectInnerLoop( nResultCol = pEList->nExpr; if( pDest->iSdst==0 ){ + if( pSort ){ + nPrefixReg = pSort->pOrderBy->nExpr; + if( !(pSort->sortFlags & SORTFLAG_UseSorter) ) nPrefixReg++; + pParse->nMem += nPrefixReg; + } pDest->iSdst = pParse->nMem+1; pParse->nMem += nResultCol; }else if( pDest->iSdst+nResultCol > pParse->nMem ){ @@ -102206,10 +104871,10 @@ static void selectInnerLoop( case SRT_DistFifo: case SRT_Table: case SRT_EphemTab: { - int r1 = sqlite3GetTempReg(pParse); + int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1); testcase( eDest==SRT_Table ); testcase( eDest==SRT_EphemTab ); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg); #ifndef SQLITE_OMIT_CTE if( eDest==SRT_DistFifo ){ /* If the destination is DistFifo, then cursor (iParm+1) is open @@ -102224,7 +104889,7 @@ static void selectInnerLoop( } #endif if( pSort ){ - pushOntoSorter(pParse, pSort, p, r1); + pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, 1, nPrefixReg); }else{ int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); @@ -102232,7 +104897,7 @@ static void selectInnerLoop( sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); } - sqlite3ReleaseTempReg(pParse, r1); + sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1); break; } @@ -102250,7 +104915,7 @@ static void selectInnerLoop( ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ - pushOntoSorter(pParse, pSort, p, regResult); + pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg); }else{ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1); @@ -102276,9 +104941,9 @@ static void selectInnerLoop( case SRT_Mem: { assert( nResultCol==1 ); if( pSort ){ - pushOntoSorter(pParse, pSort, p, regResult); + pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg); }else{ - sqlite3ExprCodeMove(pParse, regResult, iParm, 1); + assert( regResult==iParm ); /* The LIMIT clause will jump out of the loop for us */ } break; @@ -102290,10 +104955,7 @@ static void selectInnerLoop( testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); if( pSort ){ - int r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); - pushOntoSorter(pParse, pSort, p, r1); - sqlite3ReleaseTempReg(pParse, r1); + pushOntoSorter(pParse, pSort, p, regResult, nResultCol, nPrefixReg); }else if( eDest==SRT_Coroutine ){ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); }else{ @@ -102436,7 +105098,7 @@ SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; } ** then the KeyInfo structure is appropriate for initializing a virtual ** index to implement a DISTINCT test. ** -** Space to hold the KeyInfo structure is obtain from malloc. The calling +** Space to hold the KeyInfo structure is obtained from malloc. The calling ** function is responsible for seeing that this structure is eventually ** freed. */ @@ -102573,46 +105235,58 @@ static void generateSortTail( int addr; int addrOnce = 0; int iTab; - int pseudoTab = 0; ExprList *pOrderBy = pSort->pOrderBy; int eDest = pDest->eDest; int iParm = pDest->iSDParm; int regRow; int regRowid; int nKey; + int iSortTab; /* Sorter cursor to read from */ + int nSortData; /* Trailing values to read from sorter */ + int i; + int bSeq; /* True if sorter record includes seq. no. */ +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + struct ExprList_item *aOutEx = p->pEList->a; +#endif if( pSort->labelBkOut ){ sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak); sqlite3VdbeResolveLabel(v, pSort->labelBkOut); - addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); } iTab = pSort->iECursor; - regRow = sqlite3GetTempReg(pParse); if( eDest==SRT_Output || eDest==SRT_Coroutine ){ - pseudoTab = pParse->nTab++; - sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn); regRowid = 0; + regRow = pDest->iSdst; + nSortData = nColumn; }else{ regRowid = sqlite3GetTempReg(pParse); + regRow = sqlite3GetTempReg(pParse); + nSortData = 1; } nKey = pOrderBy->nExpr - pSort->nOBSat; if( pSort->sortFlags & SORTFLAG_UseSorter ){ int regSortOut = ++pParse->nMem; - int ptab2 = pParse->nTab++; - sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2); + iSortTab = pParse->nTab++; + if( pSort->labelBkOut ){ + addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); + } + sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData); if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); - sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut); - sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow); - sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); + sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab); + bSeq = 0; }else{ - if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); - sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow); + iSortTab = iTab; + bSeq = 1; + } + for(i=0; iiSdst+i ); - sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iSdst+i); - if( i==0 ){ - sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); - } - } if( eDest==SRT_Output ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn); sqlite3ExprCacheAffinityChange(pParse, pDest->iSdst, nColumn); @@ -102661,9 +105327,10 @@ static void generateSortTail( break; } } - sqlite3ReleaseTempReg(pParse, regRow); - sqlite3ReleaseTempReg(pParse, regRowid); - + if( regRowid ){ + sqlite3ReleaseTempReg(pParse, regRow); + sqlite3ReleaseTempReg(pParse, regRowid); + } /* The bottom of the loop */ sqlite3VdbeResolveLabel(v, addrContinue); @@ -102958,7 +105625,7 @@ static void generateColumnNames( } /* -** Given a an expression list (which is really the list of expressions +** Given an expression list (which is really the list of expressions ** that form the result set of a SELECT statement) compute appropriate ** column names for a table that would hold the expression list. ** @@ -103031,7 +105698,7 @@ static int selectColumnsFromExprList( } /* Make sure the column name is unique. If the name is not unique, - ** append a integer to the name so that it becomes unique. + ** append an integer to the name so that it becomes unique. */ nName = sqlite3Strlen30(zName); for(j=cnt=0; j5 ** -** The code generated for this simpification gives the same result +** The code generated for this simplification gives the same result ** but only has to scan the data once. And because indices might ** exist on the table t1, a complete scan of the data might be ** avoided. @@ -104548,8 +107215,10 @@ static void substSelect( ** (9) The subquery does not use LIMIT or the outer query does not use ** aggregates. ** -** (10) The subquery does not use aggregates or the outer query does not -** use LIMIT. +** (**) Restriction (10) was removed from the code on 2005-02-05 but we +** accidently carried the comment forward until 2014-09-15. Original +** text: "The subquery does not use aggregates or the outer query does not +** use LIMIT." ** ** (11) The subquery and the outer query do not both have ORDER BY clauses. ** @@ -104612,6 +107281,11 @@ static void substSelect( ** parent to a compound query confuses the code that handles ** recursive queries in multiSelect(). ** +** (24) The subquery is not an aggregate that uses the built-in min() or +** or max() functions. (Without this restriction, a query like: +** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily +** return the value X for which Y was maximal.) +** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query @@ -104659,7 +107333,7 @@ static int flattenSubquery( pSubSrc = pSub->pSrc; assert( pSubSrc ); /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, - ** not arbitrary expresssions, we allowed some combining of LIMIT and OFFSET + ** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET ** because they could be computed at compile-time. But when LIMIT and OFFSET ** became arbitrary expressions, we were forced to add restrictions (13) ** and (14). */ @@ -104684,8 +107358,14 @@ static int flattenSubquery( if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){ return 0; /* Restriction (21) */ } - if( pSub->selFlags & SF_Recursive ) return 0; /* Restriction (22) */ - if( (p->selFlags & SF_Recursive) && pSub->pPrior ) return 0; /* (23) */ + testcase( pSub->selFlags & SF_Recursive ); + testcase( pSub->selFlags & SF_MinMaxAgg ); + if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){ + return 0; /* Restrictions (22) and (24) */ + } + if( (p->selFlags & SF_Recursive) && pSub->pPrior ){ + return 0; /* Restriction (23) */ + } /* OBSOLETE COMMENT 1: ** Restriction 3: If the subquery is a join, make sure the subquery is @@ -104759,6 +107439,8 @@ static int flattenSubquery( } /***** If we reach this point, flattening is permitted. *****/ + SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n", + pSub->zSelName, pSub, iFrom)); /* Authorize the subquery */ pParse->zAuthContext = pSubitem->zName; @@ -104811,6 +107493,7 @@ static int flattenSubquery( p->pLimit = 0; p->pOffset = 0; pNew = sqlite3SelectDup(db, p, 0); + sqlite3SelectSetName(pNew, pSub->zSelName); p->pOffset = pOffset; p->pLimit = pLimit; p->pOrderBy = pOrderBy; @@ -104823,6 +107506,9 @@ static int flattenSubquery( if( pPrior ) pPrior->pNext = pNew; pNew->pNext = p; p->pPrior = pNew; + SELECTTRACE(2,pParse,p, + ("compound-subquery flattener creates %s.%p as peer\n", + pNew->zSelName, pNew)); } if( db->mallocFailed ) return 1; } @@ -104952,8 +107638,23 @@ static int flattenSubquery( pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList); } if( pSub->pOrderBy ){ + /* At this point, any non-zero iOrderByCol values indicate that the + ** ORDER BY column expression is identical to the iOrderByCol'th + ** expression returned by SELECT statement pSub. Since these values + ** do not necessarily correspond to columns in SELECT statement pParent, + ** zero them before transfering the ORDER BY clause. + ** + ** Not doing this may cause an error if a subsequent call to this + ** function attempts to flatten a compound sub-query into pParent + ** (the only way this can happen is if the compound sub-query is + ** currently part of pSub->pSrc). See ticket [d11a6e908f]. */ + ExprList *pOrderBy = pSub->pOrderBy; + for(i=0; inExpr; i++){ + pOrderBy->a[i].u.x.iOrderByCol = 0; + } assert( pParent->pOrderBy==0 ); - pParent->pOrderBy = pSub->pOrderBy; + assert( pSub->pPrior==0 ); + pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; }else if( pParent->pOrderBy ){ substExprList(db, pParent->pOrderBy, iParent, pSub->pEList); @@ -104999,6 +107700,13 @@ static int flattenSubquery( */ sqlite3SelectDelete(db, pSub1); +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x100 ){ + sqlite3DebugPrintf("After flattening:\n"); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ @@ -105045,7 +107753,7 @@ static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){ /* ** The select statement passed as the first argument is an aggregate query. -** The second argment is the associated aggregate-info object. This +** The second argument is the associated aggregate-info object. This ** function tests if the SELECT is of the form: ** ** SELECT count(*) FROM @@ -105375,10 +108083,10 @@ static void selectPopWith(Walker *pWalker, Select *p){ ** fill pTabList->a[].pSelect with a copy of the SELECT statement ** that implements the view. A copy is made of the view's SELECT ** statement so that we can freely modify or delete that statement -** without worrying about messing up the presistent representation +** without worrying about messing up the persistent representation ** of the view. ** -** (3) Add terms to the WHERE clause to accomodate the NATURAL keyword +** (3) Add terms to the WHERE clause to accommodate the NATURAL keyword ** on joins and the ON and USING clause of joins. ** ** (4) Scan the list of columns in the result set (pEList) looking @@ -105469,6 +108177,7 @@ static int selectExpander(Walker *pWalker, Select *p){ if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); + sqlite3SelectSetName(pFrom->pSelect, pTab->zName); sqlite3WalkSelect(pWalker, pFrom->pSelect); } #endif @@ -106003,6 +108712,13 @@ SQLITE_PRIVATE int sqlite3Select( } if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); +#if SELECTTRACE_ENABLED + pParse->nSelectIndent++; + SELECTTRACE(1,pParse,p, ("begin processing:\n")); + if( sqlite3SelectTrace & 0x100 ){ + sqlite3TreeViewSelect(0, p, 0); + } +#endif assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); @@ -106159,6 +108875,10 @@ SQLITE_PRIVATE int sqlite3Select( if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); explainSetInteger(pParse->iSelectId, iRestoreSelectId); +#if SELECTTRACE_ENABLED + SELECTTRACE(1,pParse,p,("end compound-select processing\n")); + pParse->nSelectIndent--; +#endif return rc; } #endif @@ -106204,8 +108924,9 @@ SQLITE_PRIVATE int sqlite3Select( sSort.iECursor = pParse->nTab++; sSort.addrSortIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, - sSort.iECursor, sSort.pOrderBy->nExpr+2, 0, - (char*)pKeyInfo, P4_KEYINFO); + sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0, + (char*)pKeyInfo, P4_KEYINFO + ); }else{ sSort.addrSortIndex = -1; } @@ -106336,7 +109057,7 @@ SQLITE_PRIVATE int sqlite3Select( sNC.pSrcList = pTabList; sNC.pAggInfo = &sAggInfo; sAggInfo.mnReg = pParse->nMem+1; - sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0; + sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; sAggInfo.pGroupBy = pGroupBy; sqlite3ExprAnalyzeAggList(&sNC, pEList); sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); @@ -106429,8 +109150,8 @@ SQLITE_PRIVATE int sqlite3Select( groupBySort = 1; nGroupBy = pGroupBy->nExpr; - nCol = nGroupBy + 1; - j = nGroupBy+1; + nCol = nGroupBy; + j = nGroupBy; for(i=0; i=j ){ nCol++; @@ -106440,8 +109161,7 @@ SQLITE_PRIVATE int sqlite3Select( regBase = sqlite3GetTempRange(pParse, nCol); sqlite3ExprCacheClear(pParse); sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0); - sqlite3VdbeAddOp2(v, OP_Sequence, sAggInfo.sortingIdx,regBase+nGroupBy); - j = nGroupBy+1; + j = nGroupBy; for(i=0; iiSorterColumn>=j ){ @@ -106494,12 +109214,11 @@ SQLITE_PRIVATE int sqlite3Select( addrTopOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3ExprCacheClear(pParse); if( groupBySort ){ - sqlite3VdbeAddOp2(v, OP_SorterData, sAggInfo.sortingIdx, sortOut); + sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, sortOut,sortPTab); } for(j=0; jnExpr; j++){ if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); - if( j==0 ) sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); }else{ sAggInfo.directMode = 1; sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); @@ -106758,103 +109477,106 @@ select_end: sqlite3DbFree(db, sAggInfo.aCol); sqlite3DbFree(db, sAggInfo.aFunc); +#if SELECTTRACE_ENABLED + SELECTTRACE(1,pParse,p,("end processing\n")); + pParse->nSelectIndent--; +#endif return rc; } -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) +#ifdef SQLITE_DEBUG /* ** Generate a human-readable description of a the Select object. */ -static void explainOneSelect(Vdbe *pVdbe, Select *p){ - sqlite3ExplainPrintf(pVdbe, "SELECT "); - if( p->selFlags & (SF_Distinct|SF_Aggregate) ){ - if( p->selFlags & SF_Distinct ){ - sqlite3ExplainPrintf(pVdbe, "DISTINCT "); - } - if( p->selFlags & SF_Aggregate ){ - sqlite3ExplainPrintf(pVdbe, "agg_flag "); - } - sqlite3ExplainNL(pVdbe); - sqlite3ExplainPrintf(pVdbe, " "); - } - sqlite3ExplainExprList(pVdbe, p->pEList); - sqlite3ExplainNL(pVdbe); +SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ + int n = 0; + pView = sqlite3TreeViewPush(pView, moreToFollow); + sqlite3TreeViewLine(pView, "SELECT%s%s", + ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), + ((p->selFlags & SF_Aggregate) ? " agg_flag" : "") + ); + if( p->pSrc && p->pSrc->nSrc ) n++; + if( p->pWhere ) n++; + if( p->pGroupBy ) n++; + if( p->pHaving ) n++; + if( p->pOrderBy ) n++; + if( p->pLimit ) n++; + if( p->pOffset ) n++; + if( p->pPrior ) n++; + sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set"); if( p->pSrc && p->pSrc->nSrc ){ int i; - sqlite3ExplainPrintf(pVdbe, "FROM "); - sqlite3ExplainPush(pVdbe); + pView = sqlite3TreeViewPush(pView, (n--)>0); + sqlite3TreeViewLine(pView, "FROM"); for(i=0; ipSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; - sqlite3ExplainPrintf(pVdbe, "{%d,*} = ", pItem->iCursor); - if( pItem->pSelect ){ - sqlite3ExplainSelect(pVdbe, pItem->pSelect); - if( pItem->pTab ){ - sqlite3ExplainPrintf(pVdbe, " (tabname=%s)", pItem->pTab->zName); - } + StrAccum x; + char zLine[100]; + sqlite3StrAccumInit(&x, zLine, sizeof(zLine), 0); + sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor); + if( pItem->zDatabase ){ + sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName); }else if( pItem->zName ){ - sqlite3ExplainPrintf(pVdbe, "%s", pItem->zName); + sqlite3XPrintf(&x, 0, " %s", pItem->zName); + } + if( pItem->pTab ){ + sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName); } if( pItem->zAlias ){ - sqlite3ExplainPrintf(pVdbe, " (AS %s)", pItem->zAlias); + sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias); } if( pItem->jointype & JT_LEFT ){ - sqlite3ExplainPrintf(pVdbe, " LEFT-JOIN"); + sqlite3XPrintf(&x, 0, " LEFT-JOIN"); } - sqlite3ExplainNL(pVdbe); + sqlite3StrAccumFinish(&x); + sqlite3TreeViewItem(pView, zLine, ipSrc->nSrc-1); + if( pItem->pSelect ){ + sqlite3TreeViewSelect(pView, pItem->pSelect, 0); + } + sqlite3TreeViewPop(pView); } - sqlite3ExplainPop(pVdbe); + sqlite3TreeViewPop(pView); } if( p->pWhere ){ - sqlite3ExplainPrintf(pVdbe, "WHERE "); - sqlite3ExplainExpr(pVdbe, p->pWhere); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "WHERE", (n--)>0); + sqlite3TreeViewExpr(pView, p->pWhere, 0); + sqlite3TreeViewPop(pView); } if( p->pGroupBy ){ - sqlite3ExplainPrintf(pVdbe, "GROUPBY "); - sqlite3ExplainExprList(pVdbe, p->pGroupBy); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); } if( p->pHaving ){ - sqlite3ExplainPrintf(pVdbe, "HAVING "); - sqlite3ExplainExpr(pVdbe, p->pHaving); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "HAVING", (n--)>0); + sqlite3TreeViewExpr(pView, p->pHaving, 0); + sqlite3TreeViewPop(pView); } if( p->pOrderBy ){ - sqlite3ExplainPrintf(pVdbe, "ORDERBY "); - sqlite3ExplainExprList(pVdbe, p->pOrderBy); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); } if( p->pLimit ){ - sqlite3ExplainPrintf(pVdbe, "LIMIT "); - sqlite3ExplainExpr(pVdbe, p->pLimit); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); + sqlite3TreeViewExpr(pView, p->pLimit, 0); + sqlite3TreeViewPop(pView); } if( p->pOffset ){ - sqlite3ExplainPrintf(pVdbe, "OFFSET "); - sqlite3ExplainExpr(pVdbe, p->pOffset); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); + sqlite3TreeViewExpr(pView, p->pOffset, 0); + sqlite3TreeViewPop(pView); } + if( p->pPrior ){ + const char *zOp = "UNION"; + switch( p->op ){ + case TK_ALL: zOp = "UNION ALL"; break; + case TK_INTERSECT: zOp = "INTERSECT"; break; + case TK_EXCEPT: zOp = "EXCEPT"; break; + } + sqlite3TreeViewItem(pView, zOp, (n--)>0); + sqlite3TreeViewSelect(pView, p->pPrior, 0); + sqlite3TreeViewPop(pView); + } + sqlite3TreeViewPop(pView); } -SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){ - if( p==0 ){ - sqlite3ExplainPrintf(pVdbe, "(null-select)"); - return; - } - sqlite3ExplainPush(pVdbe); - while( p ){ - explainOneSelect(pVdbe, p); - p = p->pNext; - if( p==0 ) break; - sqlite3ExplainNL(pVdbe); - sqlite3ExplainPrintf(pVdbe, "%s\n", selectOpName(p->op)); - } - sqlite3ExplainPrintf(pVdbe, "END"); - sqlite3ExplainPop(pVdbe); -} - -/* End of the structure debug printing code -*****************************************************************************/ -#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */ +#endif /* SQLITE_DEBUG */ /************** End of select.c **********************************************/ /************** Begin file table.c *******************************************/ @@ -106888,10 +109610,10 @@ SQLITE_PRIVATE void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){ typedef struct TabResult { char **azResult; /* Accumulated output */ char *zErrMsg; /* Error message text, if an error occurs */ - int nAlloc; /* Slots allocated for azResult[] */ - int nRow; /* Number of rows in the result */ - int nColumn; /* Number of columns in the result */ - int nData; /* Slots used in azResult[]. (nRow+1)*nColumn */ + u32 nAlloc; /* Slots allocated for azResult[] */ + u32 nRow; /* Number of rows in the result */ + u32 nColumn; /* Number of columns in the result */ + u32 nData; /* Slots used in azResult[]. (nRow+1)*nColumn */ int rc; /* Return code from sqlite3_exec() */ } TabResult; @@ -106917,7 +109639,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ if( p->nData + need > p->nAlloc ){ char **azNew; p->nAlloc = p->nAlloc*2 + need; - azNew = sqlite3_realloc( p->azResult, sizeof(char*)*p->nAlloc ); + azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc ); if( azNew==0 ) goto malloc_failed; p->azResult = azNew; } @@ -106932,7 +109654,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ if( z==0 ) goto malloc_failed; p->azResult[p->nData++] = z; } - }else if( p->nColumn!=nCol ){ + }else if( (int)p->nColumn!=nCol ){ sqlite3_free(p->zErrMsg); p->zErrMsg = sqlite3_mprintf( "sqlite3_get_table() called with two or more incompatible queries" @@ -107041,7 +109763,7 @@ SQLITE_API int sqlite3_get_table( ** This routine frees the space the sqlite3_get_table() malloced. */ SQLITE_API void sqlite3_free_table( - char **azResult /* Result returned from from sqlite3_get_table() */ + char **azResult /* Result returned from sqlite3_get_table() */ ){ if( azResult ){ int i, n; @@ -107185,7 +109907,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( ** ^^^^^^^^ ** ** To maintain backwards compatibility, ignore the database - ** name on pTableName if we are reparsing our of SQLITE_MASTER. + ** name on pTableName if we are reparsing out of SQLITE_MASTER. */ if( db->init.busy && iDb!=1 ){ sqlite3DbFree(db, pTableName->a[0].zDatabase); @@ -107238,8 +109960,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( goto trigger_cleanup; } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), - zName, sqlite3Strlen30(zName)) ){ + if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); }else{ @@ -107382,13 +110103,12 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( Trigger *pLink = pTrig; Hash *pHash = &db->aDb[iDb].pSchema->trigHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - pTrig = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), pTrig); + pTrig = sqlite3HashInsert(pHash, zName, pTrig); if( pTrig ){ db->mallocFailed = 1; }else if( pLink->pSchema==pLink->pTabSchema ){ Table *pTab; - int n = sqlite3Strlen30(pLink->table); - pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table, n); + pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table); assert( pTab!=0 ); pLink->pNext = pTab->pTrigger; pTab->pTrigger = pLink; @@ -107547,7 +110267,6 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr) int i; const char *zDb; const char *zName; - int nName; sqlite3 *db = pParse->db; if( db->mallocFailed ) goto drop_trigger_cleanup; @@ -107558,13 +110277,12 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr) assert( pName->nSrc==1 ); zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; - nName = sqlite3Strlen30(zName); assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); - pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName); + pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); if( pTrigger ) break; } if( !pTrigger ){ @@ -107587,8 +110305,7 @@ drop_trigger_cleanup: ** is set on. */ static Table *tableOfTrigger(Trigger *pTrigger){ - int n = sqlite3Strlen30(pTrigger->table); - return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n); + return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table); } @@ -107660,7 +110377,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const ch assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pHash = &(db->aDb[iDb].pSchema->trigHash); - pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0); + pTrigger = sqlite3HashInsert(pHash, zName, 0); if( ALWAYS(pTrigger) ){ if( pTrigger->pSchema==pTrigger->pTabSchema ){ Table *pTab = tableOfTrigger(pTrigger); @@ -108511,7 +111228,7 @@ SQLITE_PRIVATE void sqlite3Update( } /* If we are trying to update a view, realize that view into - ** a ephemeral table. + ** an ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( isView ){ @@ -108615,8 +111332,8 @@ SQLITE_PRIVATE void sqlite3Update( /* Top of the update loop */ if( okOnePass ){ - if( aToOpen[iDataCur-iBaseCur] ){ - assert( pPk!=0 ); + if( aToOpen[iDataCur-iBaseCur] && !isView ){ + assert( pPk ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey); VdbeCoverageNeverTaken(v); } @@ -108672,7 +111389,7 @@ SQLITE_PRIVATE void sqlite3Update( } /* Populate the array of registers beginning at regNew with the new - ** row data. This array is used to check constaints, create the new + ** row data. This array is used to check constants, create the new ** table and index records, and as the values for any new.* references ** made by triggers. ** @@ -108852,7 +111569,7 @@ update_cleanup: return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise -** thely may interfere with compilation of other functions in this file +** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView @@ -108865,7 +111582,7 @@ update_cleanup: /* ** Generate code for an UPDATE of a virtual table. ** -** The strategy is that we create an ephemerial table that contains +** The strategy is that we create an ephemeral table that contains ** for each row to be changed: ** ** (A) The original rowid of that row. @@ -108873,7 +111590,7 @@ update_cleanup: ** (C) The content of every column in the row. ** ** Then we loop over this ephemeral table and for each row in -** the ephermeral table call VUpdate. +** the ephemeral table call VUpdate. ** ** When finished, drop the ephemeral table. ** @@ -109046,7 +111763,7 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ ** step (3) requires additional temporary disk space approximately equal ** to the size of the original database for the rollback journal. ** Hence, temporary disk space that is approximately 2x the size of the -** orginal database is required. Every page of the database is written +** original database is required. Every page of the database is written ** approximately 3 times: Once for step (2) and twice for step (3). ** Two writes per page are required in step (3) because the original ** database content must be written into the rollback journal prior to @@ -109373,7 +112090,7 @@ static int createModule( sqlite3_mutex_enter(db->mutex); nName = sqlite3Strlen30(zName); - if( sqlite3HashFind(&db->aModule, zName, nName) ){ + if( sqlite3HashFind(&db->aModule, zName) ){ rc = SQLITE_MISUSE_BKPT; }else{ Module *pMod; @@ -109386,7 +112103,7 @@ static int createModule( pMod->pModule = pModule; pMod->pAux = pAux; pMod->xDestroy = xDestroy; - pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,nName,(void*)pMod); + pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); assert( pDel==0 || pDel==pMod ); if( pDel ){ db->mallocFailed = 1; @@ -109755,9 +112472,8 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ Table *pOld; Schema *pSchema = pTab->pSchema; const char *zName = pTab->zName; - int nName = sqlite3Strlen30(zName); assert( sqlite3SchemaMutexHeld(db, 0, pSchema) ); - pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); + pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); if( pOld ){ db->mallocFailed = 1; assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ @@ -109850,6 +112566,7 @@ static int vtabCallConstructor( }else if( ALWAYS(pVTable->pVtab) ){ /* Justification of ALWAYS(): A correct vtab constructor must allocate ** the sqlite3_vtab object if successful. */ + memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); pVTable->pVtab->pModule = pMod->pModule; pVTable->nRef = 1; if( sCtx.pTab ){ @@ -109923,7 +112640,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ /* Locate the required virtual table module */ zMod = pTab->azModuleArg[0]; - pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod)); + pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); if( !pMod ){ const char *zModule = pTab->azModuleArg[0]; @@ -109991,7 +112708,7 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, /* Locate the required virtual table module */ zMod = pTab->azModuleArg[0]; - pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod)); + pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); /* If the module has been registered and includes a Create method, ** invoke it now. If the module has not been registered, return an @@ -110030,7 +112747,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ sqlite3_mutex_enter(db->mutex); if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){ - sqlite3Error(db, SQLITE_MISUSE, 0); + sqlite3Error(db, SQLITE_MISUSE); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } @@ -110058,7 +112775,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ } db->pVtabCtx->pTab = 0; }else{ - sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); + sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); rc = SQLITE_ERROR; } @@ -110419,7 +113136,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){ } va_end(ap); - if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0); + if( rc!=SQLITE_OK ) sqlite3Error(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } @@ -110626,7 +113343,7 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int); ** 1. Then using those as a basis to compute the N best WherePath objects ** of length 2. And so forth until the length of WherePaths equals the ** number of nodes in the FROM clause. The best (lowest cost) WherePath -** at the end is the choosen query plan. +** at the end is the chosen query plan. */ struct WherePath { Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ @@ -111258,11 +113975,6 @@ static int allowedOp(int op){ return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL; } -/* -** Swap two objects of type TYPE. -*/ -#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} - /* ** Commute a comparison operator. Expressions of the form "X op Y" ** are converted into "Y op X". @@ -111595,7 +114307,7 @@ static int isLikeOrGlob( ** value of the variable means there is no need to invoke the LIKE ** function, then no OP_Variable will be added to the program. ** This causes problems for the sqlite3_bind_parameter_name() - ** API. To workaround them, add a dummy OP_Variable here. + ** API. To work around them, add a dummy OP_Variable here. */ int r1 = sqlite3GetTempReg(pParse); sqlite3ExprCodeTarget(pParse, pRight, r1); @@ -111715,7 +114427,7 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ ** appropriate for indexing exist. ** ** All examples A through E above satisfy case 2. But if a term -** also statisfies case 1 (such as B) we know that the optimizer will +** also satisfies case 1 (such as B) we know that the optimizer will ** always prefer case 1, so in that case we pretend that case 2 is not ** satisfied. ** @@ -111873,7 +114585,7 @@ static void exprAnalyzeOrTerm( } if( (chngToIN & getMask(&pWInfo->sMaskSet, pOrTerm->leftCursor))==0 ){ /* This term must be of the form t1.a==t2.b where t2 is in the - ** chngToIN set but t1 is not. This term will be either preceeded + ** chngToIN set but t1 is not. This term will be either preceded ** or follwed by an inverted copy (t2.b==t1.a). Skip this term ** and use its inversion. */ testcase( pOrTerm->wtFlags & TERM_COPIED ); @@ -112284,7 +114996,7 @@ static void exprAnalyze( } /* -** This function searches pList for a entry that matches the iCol-th column +** This function searches pList for an entry that matches the iCol-th column ** of index pIdx. ** ** If such an expression is found, its index in pList->a[] is returned. If @@ -112807,7 +115519,7 @@ static void whereKeyStats( assert( pRec->nField>0 && iColnSampleCol ); do{ iTest = (iMin+i)/2; - res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec, 0); + res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec); if( res<0 ){ iMin = iTest+1; }else{ @@ -112822,16 +115534,16 @@ static void whereKeyStats( if( res==0 ){ /* If (res==0) is true, then sample $i must be equal to pRec */ assert( inSample ); - assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0) + assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec) || pParse->db->mallocFailed ); }else{ /* Otherwise, pRec must be smaller than sample $i and larger than ** sample ($i-1). */ assert( i==pIdx->nSample - || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0)>0 + || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0 || pParse->db->mallocFailed ); assert( i==0 - || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec, 0)<0 + || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 || pParse->db->mallocFailed ); } #endif /* ifdef SQLITE_DEBUG */ @@ -113034,7 +115746,7 @@ static int whereRangeSkipScanEst( ** number of rows that the index scan is expected to visit without ** considering the range constraints. If nEq is 0, this is the number of ** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced) -** to account for the range contraints pLower and pUpper. +** to account for the range constraints pLower and pUpper. ** ** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be ** used, a single range inequality reduces the search space by a factor of 4. @@ -113085,6 +115797,10 @@ static int whereRangeScanEst( tRowcnt iLower; tRowcnt iUpper; + if( pRec ){ + testcase( pRec->nField!=pBuilder->nRecValid ); + pRec->nField = pBuilder->nRecValid; + } if( nEq==p->nKeyCol ){ aff = SQLITE_AFF_INTEGER; }else{ @@ -113102,18 +115818,26 @@ static int whereRangeScanEst( iUpper = a[0] + a[1]; } + assert( pLower==0 || (pLower->eOperator & (WO_GT|WO_GE))!=0 ); + assert( pUpper==0 || (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); + assert( p->aSortOrder!=0 ); + if( p->aSortOrder[nEq] ){ + /* The roles of pLower and pUpper are swapped for a DESC index */ + SWAP(WhereTerm*, pLower, pUpper); + } + /* If possible, improve on the iLower estimate using ($P:$L). */ if( pLower ){ int bOk; /* True if value is extracted from pExpr */ Expr *pExpr = pLower->pExpr->pRight; - assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 ); rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ tRowcnt iNew; whereKeyStats(pParse, p, pRec, 0, a); - iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0); + iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); if( iNew>iLower ) iLower = iNew; nOut--; + pLower = 0; } } @@ -113121,14 +115845,14 @@ static int whereRangeScanEst( if( pUpper ){ int bOk; /* True if value is extracted from pExpr */ Expr *pExpr = pUpper->pExpr->pRight; - assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ tRowcnt iNew; whereKeyStats(pParse, p, pRec, 1, a); - iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0); + iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); if( iNewnOut = (LogEst)nOut; - WHERETRACE(0x10, ("range scan regions: %u..%u est=%d\n", + WHERETRACE(0x10, ("STAT4 range scan: %u..%u est=%d\n", (u32)iLower, (u32)iUpper, nOut)); - return SQLITE_OK; } }else{ int bDone = 0; @@ -113156,8 +115878,8 @@ static int whereRangeScanEst( #else UNUSED_PARAMETER(pParse); UNUSED_PARAMETER(pBuilder); -#endif assert( pLower || pUpper ); +#endif assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 ); nNew = whereRangeAdjust(pLower, nOut); nNew = whereRangeAdjust(pUpper, nNew); @@ -113172,6 +115894,12 @@ static int whereRangeScanEst( nOut -= (pLower!=0) + (pUpper!=0); if( nNew<10 ) nNew = 10; if( nNewnOut>nOut ){ + WHERETRACE(0x10,("Range scan lowers nOut from %d to %d\n", + pLoop->nOut, nOut)); + } +#endif pLoop->nOut = (LogEst)nOut; return rc; } @@ -113284,7 +116012,7 @@ static int whereInScanEst( if( rc==SQLITE_OK ){ if( nRowEst > nRow0 ) nRowEst = nRow0; *pnRow = nRowEst; - WHERETRACE(0x10,("IN row estimate: est=%g\n", nRowEst)); + WHERETRACE(0x10,("IN row estimate: est=%d\n", nRowEst)); } assert( pBuilder->nRecValid==nRecValid ); return rc; @@ -113620,9 +116348,8 @@ static void explainAppendTerm( /* ** Argument pLevel describes a strategy for scanning table pTab. This -** function returns a pointer to a string buffer containing a description -** of the subset of table rows scanned by the strategy in the form of an -** SQL expression. Or, if all rows are scanned, NULL is returned. +** function appends text to pStr that describes the subset of table +** rows scanned by the strategy in the form of an SQL expression. ** ** For example, if the query: ** @@ -113632,49 +116359,37 @@ static void explainAppendTerm( ** string similar to: ** ** "a=? AND b>?" -** -** The returned pointer points to memory obtained from sqlite3DbMalloc(). -** It is the responsibility of the caller to free the buffer when it is -** no longer required. */ -static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){ +static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ Index *pIndex = pLoop->u.btree.pIndex; u16 nEq = pLoop->u.btree.nEq; u16 nSkip = pLoop->u.btree.nSkip; int i, j; Column *aCol = pTab->aCol; i16 *aiColumn = pIndex->aiColumn; - StrAccum txt; - if( nEq==0 && (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){ - return 0; - } - sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH); - txt.db = db; - sqlite3StrAccumAppend(&txt, " (", 2); + if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; + sqlite3StrAccumAppend(pStr, " (", 2); for(i=0; i=nSkip ){ - explainAppendTerm(&txt, i, z, "="); + explainAppendTerm(pStr, i, z, "="); }else{ - if( i ) sqlite3StrAccumAppend(&txt, " AND ", 5); - sqlite3StrAccumAppend(&txt, "ANY(", 4); - sqlite3StrAccumAppendAll(&txt, z); - sqlite3StrAccumAppend(&txt, ")", 1); + if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5); + sqlite3XPrintf(pStr, 0, "ANY(%s)", z); } } j = i; if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; - explainAppendTerm(&txt, i++, z, ">"); + explainAppendTerm(pStr, i++, z, ">"); } if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; - explainAppendTerm(&txt, i, z, "<"); + explainAppendTerm(pStr, i, z, "<"); } - sqlite3StrAccumAppend(&txt, ")", 1); - return sqlite3StrAccumFinish(&txt); + sqlite3StrAccumAppend(pStr, ")", 1); } /* @@ -113698,11 +116413,13 @@ static void explainOneScan( struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ - char *zMsg; /* Text to add to EQP output */ int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ + char *zMsg; /* Text to add to EQP output */ + StrAccum str; /* EQP output string */ + char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; @@ -113712,54 +116429,70 @@ static void explainOneScan( || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); - zMsg = sqlite3MPrintf(db, "%s", isSearch?"SEARCH":"SCAN"); + sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); + str.db = db; + sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s SUBQUERY %d", zMsg,pItem->iSelectId); + sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); }else{ - zMsg = sqlite3MAppendf(db, zMsg, "%s TABLE %s", zMsg, pItem->zName); + sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); + sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias); } - if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 - && ALWAYS(pLoop->u.btree.pIndex!=0) - ){ - const char *zFmt; - Index *pIdx = pLoop->u.btree.pIndex; - char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); + if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ + const char *zFmt = 0; + Index *pIdx; + + assert( pLoop->u.btree.pIndex!=0 ); + pIdx = pLoop->u.btree.pIndex; assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ - zFmt = zWhere ? "%s USING PRIMARY KEY%.0s%s" : "%s%.0s%s"; + if( isSearch ){ + zFmt = "PRIMARY KEY"; + } }else if( flags & WHERE_AUTO_INDEX ){ - zFmt = "%s USING AUTOMATIC COVERING INDEX%.0s%s"; + zFmt = "AUTOMATIC COVERING INDEX"; }else if( flags & WHERE_IDX_ONLY ){ - zFmt = "%s USING COVERING INDEX %s%s"; + zFmt = "COVERING INDEX %s"; }else{ - zFmt = "%s USING INDEX %s%s"; + zFmt = "INDEX %s"; + } + if( zFmt ){ + sqlite3StrAccumAppend(&str, " USING ", 7); + sqlite3XPrintf(&str, 0, zFmt, pIdx->zName); + explainIndexRange(&str, pLoop, pItem->pTab); } - zMsg = sqlite3MAppendf(db, zMsg, zFmt, zMsg, pIdx->zName, zWhere); - sqlite3DbFree(db, zWhere); }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); - + const char *zRange; if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg); + zRange = "(rowid=?)"; }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid? AND rowid?)", zMsg); - }else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid?)"; + }else{ + assert( flags&WHERE_TOP_LIMIT); + zRange = "(rowidu.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif - zMsg = sqlite3MAppendf(db, zMsg, "%s", zMsg); +#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS + if( pLoop->nOut>=10 ){ + sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); + }else{ + sqlite3StrAccumAppend(&str, " (~1 row)", 9); + } +#endif + zMsg = sqlite3StrAccumFinish(&str); sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); } } @@ -114301,7 +117034,7 @@ static Bitmask codeOneLoopStart( ** B: ** ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then - ** use an ephermeral index instead of a RowSet to record the primary + ** use an ephemeral index instead of a RowSet to record the primary ** keys of the rows we have already seen. ** */ @@ -114352,7 +117085,7 @@ static Bitmask codeOneLoopStart( } /* Initialize the rowset register to contain NULL. An SQL NULL is - ** equivalent to an empty rowset. Or, create an ephermeral index + ** equivalent to an empty rowset. Or, create an ephemeral index ** capable of holding primary keys in the case of a WITHOUT ROWID. ** ** Also initialize regReturn to contain the address of the instruction @@ -114413,8 +117146,9 @@ static Bitmask codeOneLoopStart( ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ - wctrlFlags = WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | - WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY; + wctrlFlags = WHERE_OMIT_OPEN_CLOSE + | WHERE_FORCE_TABLE + | WHERE_ONETABLE_ONLY; for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ @@ -114426,6 +117160,7 @@ static Bitmask codeOneLoopStart( pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ + WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, wctrlFlags, iCovCur); assert( pSubWInfo || pParse->nErr || db->mallocFailed ); @@ -114645,21 +117380,26 @@ static Bitmask codeOneLoopStart( return pLevel->notReady; } -#if defined(WHERETRACE_ENABLED) && defined(SQLITE_ENABLE_TREE_EXPLAIN) +#ifdef WHERETRACE_ENABLED /* -** Generate "Explanation" text for a WhereTerm. +** Print the content of a WhereTerm object */ -static void whereExplainTerm(Vdbe *v, WhereTerm *pTerm){ - char zType[4]; - memcpy(zType, "...", 4); - if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; - if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; - sqlite3ExplainPrintf(v, "%s ", zType); - sqlite3ExplainExpr(v, pTerm->pExpr); +static void whereTermPrint(WhereTerm *pTerm, int iTerm){ + if( pTerm==0 ){ + sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); + }else{ + char zType[4]; + memcpy(zType, "...", 4); + if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; + if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; + sqlite3DebugPrintf("TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x\n", + iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb, + pTerm->eOperator); + sqlite3TreeViewExpr(0, pTerm->pExpr, 0); + } } -#endif /* WHERETRACE_ENABLED && SQLITE_ENABLE_TREE_EXPLAIN */ - +#endif #ifdef WHERETRACE_ENABLED /* @@ -114675,8 +117415,8 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ sqlite3DebugPrintf(" %12s", pItem->zAlias ? pItem->zAlias : pTab->zName); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ - const char *zName; - if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){ + const char *zName; + if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){ if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){ int i = sqlite3Strlen30(zName) - 1; while( zName[i]!='_' ) i--; @@ -114697,29 +117437,18 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ sqlite3DebugPrintf(" %-19s", z); sqlite3_free(z); } - sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); - sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); -#ifdef SQLITE_ENABLE_TREE_EXPLAIN - /* If the 0x100 bit of wheretracing is set, then show all of the constraint - ** expressions in the WhereLoop.aLTerm[] array. - */ - if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ /* WHERETRACE 0x100 */ - int i; - Vdbe *v = pWInfo->pParse->pVdbe; - sqlite3ExplainBegin(v); - for(i=0; inLTerm; i++){ - WhereTerm *pTerm = p->aLTerm[i]; - if( pTerm==0 ) continue; - sqlite3ExplainPrintf(v, " (%d) #%-2d ", i+1, (int)(pTerm-pWC->a)); - sqlite3ExplainPush(v); - whereExplainTerm(v, pTerm); - sqlite3ExplainPop(v); - sqlite3ExplainNL(v); - } - sqlite3ExplainFinish(v); - sqlite3DebugPrintf("%s", sqlite3VdbeExplanation(v)); + if( p->wsFlags & WHERE_SKIPSCAN ){ + sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->u.btree.nSkip); + }else{ + sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); + } + sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); + if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ + int i; + for(i=0; inLTerm; i++){ + whereTermPrint(p->aLTerm[i], i); + } } -#endif } #endif @@ -115032,7 +117761,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** than pTemplate, so just ignore pTemplate */ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf("ins-noop: "); + sqlite3DebugPrintf(" skip: "); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif @@ -115048,10 +117777,10 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ if( p!=0 ){ - sqlite3DebugPrintf("ins-del: "); + sqlite3DebugPrintf("replace: "); whereLoopPrint(p, pBuilder->pWC); } - sqlite3DebugPrintf("ins-new: "); + sqlite3DebugPrintf(" add: "); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif @@ -115075,7 +117804,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ *ppTail = pToDel->pNextLoop; #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf("ins-del: "); + sqlite3DebugPrintf(" delete: "); whereLoopPrint(pToDel, pBuilder->pWC); } #endif @@ -115101,14 +117830,16 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** the number of output rows by a factor of 10 and each additional term ** reduces the number of output rows by sqrt(2). */ -static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){ +static void whereLoopOutputAdjust( + WhereClause *pWC, /* The WHERE clause */ + WhereLoop *pLoop, /* The loop to adjust downward */ + LogEst nRow /* Number of rows in the entire table */ +){ WhereTerm *pTerm, *pX; Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf); int i, j; + int nEq = 0; /* Number of = constraints not within likely()/unlikely() */ - if( !OptimizationEnabled(pWC->pWInfo->pParse->db, SQLITE_AdjustOutEst) ){ - return; - } for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){ if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break; if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue; @@ -115120,9 +117851,21 @@ static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){ if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; } if( j<0 ){ - pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1); + if( pTerm->truthProb<=0 ){ + pLoop->nOut += pTerm->truthProb; + }else{ + pLoop->nOut--; + if( pTerm->eOperator&WO_EQ ) nEq++; + } } } + /* TUNING: If there is at least one equality constraint in the WHERE + ** clause that does not have a likelihood() explicitly assigned to it + ** then do not let the estimated number of output rows exceed half + ** the number of rows in the table. */ + if( nEq && pLoop->nOut>nRow-10 ){ + pLoop->nOut = nRow - 10; + } } /* @@ -115168,6 +117911,7 @@ static int whereLoopAddBtreeIndex( LogEst saved_nOut; /* Original value of pNew->nOut */ int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ + LogEst rSize; /* Number of rows in the table */ LogEst rLogSize; /* Logarithm of table size */ WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ @@ -115197,7 +117941,8 @@ static int whereLoopAddBtreeIndex( saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; pNew->rSetup = 0; - rLogSize = estLog(pProbe->aiRowLogEst[0]); + rSize = pProbe->aiRowLogEst[0]; + rLogSize = estLog(rSize); /* Consider using a skip-scan if there are no WHERE clause constraints ** available for the left-most terms of the index, and if the average @@ -115210,8 +117955,7 @@ static int whereLoopAddBtreeIndex( ** On the other hand, the extra seeks could end up being significantly ** more expensive. */ assert( 42==sqlite3LogEst(18) ); - if( pTerm==0 - && saved_nEq==saved_nSkip + if( saved_nEq==saved_nSkip && saved_nEq+1nKeyCol && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK @@ -115222,9 +117966,20 @@ static int whereLoopAddBtreeIndex( pNew->aLTerm[pNew->nLTerm++] = 0; pNew->wsFlags |= WHERE_SKIPSCAN; nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1]; + if( pTerm ){ + /* TUNING: When estimating skip-scan for a term that is also indexable, + ** multiply the cost of the skip-scan by 2.0, to make it a little less + ** desirable than the regular index lookup. */ + nIter += 10; assert( 10==sqlite3LogEst(2) ); + } pNew->nOut -= nIter; + /* TUNING: Because uncertainties in the estimates for skip-scan queries, + ** add a 1.375 fudge factor to make skip-scan slightly less likely. */ + nIter += 5; whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul); pNew->nOut = saved_nOut; + pNew->u.btree.nEq = saved_nEq; + pNew->u.btree.nSkip = saved_nSkip; } for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */ @@ -115367,7 +118122,7 @@ static int whereLoopAddBtreeIndex( nOutUnadjusted = pNew->nOut; pNew->rRun += nInMul + nIn; pNew->nOut += nInMul + nIn; - whereLoopOutputAdjust(pBuilder->pWC, pNew); + whereLoopOutputAdjust(pBuilder->pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ @@ -115417,6 +118172,7 @@ static int indexMightHelpWithOrderBy( Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr); if( pExpr->op!=TK_COLUMN ) return 0; if( pExpr->iTable==iCursor ){ + if( pExpr->iColumn<0 ) return 1; for(jj=0; jjnKeyCol; jj++){ if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; } @@ -115574,13 +118330,21 @@ static int whereLoopAddBtree( pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; /* TUNING: One-time cost for computing the automatic index is - ** approximately 7*N*log2(N) where N is the number of rows in - ** the table being indexed. */ - pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) ); + ** estimated to be X*N*log2(N) where N is the number of rows in + ** the table being indexed and where X is 7 (LogEst=28) for normal + ** tables or 1.375 (LogEst=4) for views and subqueries. The value + ** of X is smaller for views and subqueries so that the query planner + ** will be more aggressive about generating automatic indexes for + ** those objects, since there is no opportunity to add schema + ** indexes on subqueries and views. */ + pNew->rSetup = rLogSize + rSize + 4; + if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){ + pNew->rSetup += 24; + } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); /* TUNING: Each index lookup yields 20 rows in the table. This ** is more than the usual guess of 10 rows, since we have no way - ** of knowning how selective the index will ultimately be. It would + ** of knowing how selective the index will ultimately be. It would ** not be unreasonable to make this value much larger. */ pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut); @@ -115596,7 +118360,8 @@ static int whereLoopAddBtree( */ for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){ if( pProbe->pPartIdxWhere!=0 - && !whereUsablePartialIndex(pNew->iTab, pWC, pProbe->pPartIdxWhere) ){ + && !whereUsablePartialIndex(pSrc->iCursor, pWC, pProbe->pPartIdxWhere) ){ + testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */ continue; /* Partial index inappropriate for this query */ } rSize = pProbe->aiRowLogEst[0]; @@ -115620,7 +118385,7 @@ static int whereLoopAddBtree( /* TUNING: Cost of full table scan is (N*3.0). */ pNew->rRun = rSize + 16; ApplyCostMultiplier(pNew->rRun, pTab->costMult); - whereLoopOutputAdjust(pWC, pNew); + whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; @@ -115656,7 +118421,7 @@ static int whereLoopAddBtree( pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16); } ApplyCostMultiplier(pNew->rRun, pTab->costMult); - whereLoopOutputAdjust(pWC, pNew); + whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; @@ -115863,7 +118628,6 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ struct SrcList_item *pItem; pWC = pBuilder->pWC; - if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; memset(&sSum, 0, sizeof(sSum)); @@ -115884,6 +118648,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ sSubBuild.pOrderBy = 0; sSubBuild.pOrSet = &sCur; + WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm)); for(pOrTerm=pOrWC->a; pOrTermeOperator & WO_AND)!=0 ){ sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; @@ -115898,6 +118663,15 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ continue; } sCur.n = 0; +#ifdef WHERETRACE_ENABLED + WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", + (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); + if( sqlite3WhereTrace & 0x400 ){ + for(i=0; inTerm; i++){ + whereTermPrint(&sSubBuild.pWC->a[i], i); + } + } +#endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mExtra); @@ -115906,6 +118680,9 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ { rc = whereLoopAddBtree(&sSubBuild, mExtra); } + if( rc==SQLITE_OK ){ + rc = whereLoopAddOr(&sSubBuild, mExtra); + } assert( rc==SQLITE_OK || sCur.n==0 ); if( sCur.n==0 ){ sSum.n = 0; @@ -115950,6 +118727,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); } + WHERETRACE(0x200, ("End processing OR-clause %p\n", pTerm)); } } return rc; @@ -116009,7 +118787,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ ** strict. With GROUP BY and DISTINCT the only requirement is that ** equivalent rows appear immediately adjacent to one another. GROUP BY ** and DISTINCT do not require rows to appear in any particular order as long -** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT +** as equivalent rows are grouped together. Thus for GROUP BY and DISTINCT ** the pOrderBy terms can be matched in any order. With ORDER BY, the ** pOrderBy terms must be matched in strict left-to-right order. */ @@ -116193,7 +118971,7 @@ static i8 wherePathSatisfiesOrderBy( isMatch = 1; break; } - if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ + if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){ /* Make sure the sort order is compatible in an ORDER BY clause. ** Sort order is irrelevant for a GROUP BY clause. */ if( revSet ){ @@ -116658,12 +119436,15 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr ){ - Bitmask notUsed = 0; + Bitmask revMask = 0; int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, - pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used + pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask ); assert( pWInfo->sorted==0 ); - pWInfo->sorted = (nOrder==pWInfo->pOrderBy->nExpr); + if( nOrder==pWInfo->pOrderBy->nExpr ){ + pWInfo->sorted = 1; + pWInfo->revMask = revMask; + } } } @@ -117016,23 +119797,16 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(0xffff,("*** Optimizer Start ***\n")); +#if defined(WHERETRACE_ENABLED) /* Display all terms of the WHERE clause */ -#if defined(WHERETRACE_ENABLED) && defined(SQLITE_ENABLE_TREE_EXPLAIN) if( sqlite3WhereTrace & 0x100 ){ int i; - Vdbe *v = pParse->pVdbe; - sqlite3ExplainBegin(v); for(i=0; inTerm; i++){ - sqlite3ExplainPrintf(v, "#%-2d ", i); - sqlite3ExplainPush(v); - whereExplainTerm(v, &sWLB.pWC->a[i]); - sqlite3ExplainPop(v); - sqlite3ExplainNL(v); + whereTermPrint(&sWLB.pWC->a[i], i); } - sqlite3ExplainFinish(v); - sqlite3DebugPrintf("%s", sqlite3VdbeExplanation(v)); } #endif + if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; @@ -117559,7 +120333,7 @@ struct AttachKey { int type; Token key; }; ** unary TK_ISNULL or TK_NOTNULL expression. */ static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ sqlite3 *db = pParse->db; - if( db->mallocFailed==0 && pY->op==TK_NULL ){ + if( pY && pA && pY->op==TK_NULL ){ pA->op = (u8)op; sqlite3ExprDelete(db, pA->pRight); pA->pRight = 0; @@ -118786,9 +121560,9 @@ static void yyGrowStack(yyParser *p){ ** A pointer to a parser. This pointer is used in subsequent calls ** to sqlite3Parser and sqlite3ParserFree. */ -SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(size_t)){ +SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(u64)){ yyParser *pParser; - pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); + pParser = (yyParser*)(*mallocProc)( (u64)sizeof(yyParser) ); if( pParser ){ pParser->yyidx = -1; #ifdef YYTRACKMAXSTACKDEPTH @@ -119818,9 +122592,6 @@ static void yy_reduce( { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; sqlite3Select(pParse, yymsp[0].minor.yy3, &dest); - sqlite3ExplainBegin(pParse->pVdbe); - sqlite3ExplainSelect(pParse->pVdbe, yymsp[0].minor.yy3); - sqlite3ExplainFinish(pParse->pVdbe); sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy3); } break; @@ -119877,6 +122648,30 @@ static void yy_reduce( case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { yygotominor.yy3 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy65,yymsp[-4].minor.yy132,yymsp[-3].minor.yy14,yymsp[-2].minor.yy132,yymsp[-1].minor.yy14,yymsp[-7].minor.yy381,yymsp[0].minor.yy476.pLimit,yymsp[0].minor.yy476.pOffset); +#if SELECTTRACE_ENABLED + /* Populate the Select.zSelName[] string that is used to help with + ** query planner debugging, to differentiate between multiple Select + ** objects in a complex query. + ** + ** If the SELECT keyword is immediately followed by a C-style comment + ** then extract the first few alphanumeric characters from within that + ** comment to be the zSelName value. Otherwise, the label is #N where + ** is an integer that is incremented with each SELECT statement seen. + */ + if( yygotominor.yy3!=0 ){ + const char *z = yymsp[-8].minor.yy0.z+6; + int i; + sqlite3_snprintf(sizeof(yygotominor.yy3->zSelName), yygotominor.yy3->zSelName, "#%d", + ++pParse->nSelect); + while( z[0]==' ' ) z++; + if( z[0]=='/' && z[1]=='*' ){ + z += 2; + while( z[0]==' ' ) z++; + for(i=0; sqlite3Isalnum(z[i]); i++){} + sqlite3_snprintf(sizeof(yygotominor.yy3->zSelName), yygotominor.yy3->zSelName, "%.*s", i, z); + } + } +#endif /* SELECTRACE_ENABLED */ } break; case 120: /* values ::= VALUES LP nexprlist RP */ @@ -121343,7 +124138,7 @@ SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){ ** end result. ** ** Ticket #1066. the SQL standard does not allow '$' in the -** middle of identfiers. But many SQL implementations do. +** middle of identifiers. But many SQL implementations do. ** SQLite will allow '$' in identifiers for compatibility. ** But the feature is undocumented. */ @@ -121368,6 +124163,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = { }; #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) #endif +SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); } /* @@ -121664,7 +124460,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr pParse->zTail = zSql; i = 0; assert( pzErrMsg!=0 ); - pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3Malloc); + pEngine = sqlite3ParserAlloc(sqlite3Malloc); if( pEngine==0 ){ db->mallocFailed = 1; return SQLITE_NOMEM; @@ -121859,7 +124655,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[]; ** a statement. ** ** (4) CREATE The keyword CREATE has been seen at the beginning of a -** statement, possibly preceeded by EXPLAIN and/or followed by +** statement, possibly preceded by EXPLAIN and/or followed by ** TEMP or TEMPORARY ** ** (5) TRIGGER We are in the middle of a trigger definition that must be @@ -121869,7 +124665,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[]; ** the end of a trigger definition. ** ** (7) END We've seen the ";END" of the ";END;" that occurs at the end -** of a trigger difinition. +** of a trigger definition. ** ** Transitions between states above are determined by tokens extracted ** from the input. The following tokens are significant: @@ -121912,7 +124708,7 @@ SQLITE_API int sqlite3_complete(const char *zSql){ }; #else /* If triggers are not supported by this compile then the statement machine - ** used to detect the end of a statement is much simplier + ** used to detect the end of a statement is much simpler */ static const u8 trans[3][3] = { /* Token: */ @@ -122638,6 +125434,11 @@ SQLITE_API int sqlite3_config(int op, ...){ break; } + /* EVIDENCE-OF: R-55548-33817 The compile-time setting for URI filenames + ** can be changed at start-time using the + ** sqlite3_config(SQLITE_CONFIG_URI,1) or + ** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls. + */ case SQLITE_CONFIG_URI: { sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); break; @@ -123014,7 +125815,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){ ** SQLITE_BUSY if the connection can not be closed immediately. */ if( !forceZombie && connectionIsBusy(db) ){ - sqlite3Error(db, SQLITE_BUSY, "unable to close due to unfinalized " + sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to close due to unfinalized " "statements or unfinished backups"); sqlite3_mutex_leave(db->mutex); return SQLITE_BUSY; @@ -123144,9 +125945,13 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ sqlite3HashClear(&db->aModule); #endif - sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ + sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ sqlite3ValueFree(db->pErr); sqlite3CloseExtensions(db); +#if SQLITE_USER_AUTHENTICATION + sqlite3_free(db->auth.zAuthUser); + sqlite3_free(db->auth.zAuthPW); +#endif db->magic = SQLITE_MAGIC_ERROR; @@ -123169,13 +125974,15 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ /* ** Rollback all database files. If tripCode is not SQLITE_OK, then -** any open cursors are invalidated ("tripped" - as in "tripping a circuit +** any write cursors are invalidated ("tripped" - as in "tripping a circuit ** breaker") and made to return tripCode if there are any further -** attempts to use that cursor. +** attempts to use that cursor. Read cursors remain open and valid +** but are "saved" in case the table pages are moved around. */ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ int i; int inTrans = 0; + int schemaChange; assert( sqlite3_mutex_held(db->mutex) ); sqlite3BeginBenignMalloc(); @@ -123186,6 +125993,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ ** the database rollback and schema reset, which can cause false ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); + schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0; for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; @@ -123193,7 +126001,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ if( sqlite3BtreeIsInTrans(p) ){ inTrans = 1; } - sqlite3BtreeRollback(p, tripCode); + sqlite3BtreeRollback(p, tripCode, !schemaChange); } } sqlite3VtabRollback(db); @@ -123577,7 +126385,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc( p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0); if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){ if( db->nVdbeActive ){ - sqlite3Error(db, SQLITE_BUSY, + sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify user-function due to active statements"); assert( !db->mallocFailed ); return SQLITE_BUSY; @@ -123915,10 +126723,10 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( } if( iDb<0 ){ rc = SQLITE_ERROR; - sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb); + sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb); }else{ rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt); - sqlite3Error(db, rc, 0); + sqlite3Error(db, rc); } rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); @@ -124073,7 +126881,7 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){ }else{ z = sqlite3_value_text16(db->pErr); if( z==0 ){ - sqlite3Error(db, db->errCode, sqlite3ErrStr(db->errCode)); + sqlite3ErrorWithMsg(db, db->errCode, sqlite3ErrStr(db->errCode)); z = sqlite3_value_text16(db->pErr); } /* A malloc() may have failed within the call to sqlite3_value_text16() @@ -124160,7 +126968,6 @@ static int createCollation( ){ CollSeq *pColl; int enc2; - int nName = sqlite3Strlen30(zName); assert( sqlite3_mutex_held(db->mutex) ); @@ -124185,7 +126992,7 @@ static int createCollation( pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0); if( pColl && pColl->xCmp ){ if( db->nVdbeActive ){ - sqlite3Error(db, SQLITE_BUSY, + sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify collation sequence due to active statements"); return SQLITE_BUSY; } @@ -124199,7 +127006,7 @@ static int createCollation( ** to be called. */ if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){ - CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName, nName); + CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName); int j; for(j=0; j<3; j++){ CollSeq *p = &aColl[j]; @@ -124219,7 +127026,7 @@ static int createCollation( pColl->pUser = pCtx; pColl->xDel = xDel; pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED)); - sqlite3Error(db, SQLITE_OK, 0); + sqlite3Error(db, SQLITE_OK); return SQLITE_OK; } @@ -124241,6 +127048,7 @@ static const int aHardLimit[] = { SQLITE_MAX_LIKE_PATTERN_LENGTH, SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ SQLITE_MAX_TRIGGER_DEPTH, + SQLITE_MAX_WORKER_THREADS, }; /* @@ -124276,6 +127084,9 @@ static const int aHardLimit[] = { #if SQLITE_MAX_TRIGGER_DEPTH<1 # error SQLITE_MAX_TRIGGER_DEPTH must be at least 1 #endif +#if SQLITE_MAX_WORKER_THREADS<0 || SQLITE_MAX_WORKER_THREADS>50 +# error SQLITE_MAX_WORKER_THREADS must be between 0 and 50 +#endif /* @@ -124309,7 +127120,8 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ SQLITE_MAX_LIKE_PATTERN_LENGTH ); assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER); assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH ); - assert( SQLITE_LIMIT_TRIGGER_DEPTH==(SQLITE_N_LIMIT-1) ); + assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS ); + assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) ); if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ @@ -124367,7 +127179,7 @@ SQLITE_PRIVATE int sqlite3ParseUri( assert( *pzErrMsg==0 ); if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) - && nUri>=5 && memcmp(zUri, "file:", 5)==0 + && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ ){ char *zOpt; int eState; /* Parser state when parsing URI */ @@ -124597,7 +127409,9 @@ static int openDatabase( testcase( (1<<(flags&7))==0x02 ); /* READONLY */ testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ - if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE_BKPT; + if( ((1<<(flags&7)) & 0x46)==0 ){ + return SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */ + } if( sqlite3GlobalConfig.bCoreMutex==0 ){ isThreadsafe = 0; @@ -124656,10 +127470,12 @@ static int openDatabase( assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); + db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS; db->autoCommit = 1; db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; + db->nMaxSorterMmap = 0x7FFFFFFF; db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill #if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX | SQLITE_AutoIndex @@ -124704,7 +127520,7 @@ static int openDatabase( rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; - sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg); + sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg); sqlite3_free(zErrMsg); goto opendb_out; } @@ -124716,13 +127532,12 @@ static int openDatabase( if( rc==SQLITE_IOERR_NOMEM ){ rc = SQLITE_NOMEM; } - sqlite3Error(db, rc, 0); + sqlite3Error(db, rc); goto opendb_out; } db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); - /* The default safety_level for the main database is 'full'; for the temp ** database it is 'NONE'. This matches the pager layer defaults. */ @@ -124740,7 +127555,7 @@ static int openDatabase( ** database schema yet. This is delayed until the first time the database ** is accessed. */ - sqlite3Error(db, SQLITE_OK, 0); + sqlite3Error(db, SQLITE_OK); sqlite3RegisterBuiltinFunctions(db); /* Load automatic extensions - extensions that have been registered @@ -124797,7 +127612,7 @@ static int openDatabase( SQLITE_DEFAULT_LOCKING_MODE); #endif - if( rc ) sqlite3Error(db, rc, 0); + if( rc ) sqlite3Error(db, rc); /* Enable the lookaside-malloc subsystem */ setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside, @@ -125009,9 +127824,9 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){ } /* -** The following routines are subtitutes for constants SQLITE_CORRUPT, +** The following routines are substitutes for constants SQLITE_CORRUPT, ** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error -** constants. They server two purposes: +** constants. They serve two purposes: ** ** 1. Serve as a convenient place to set a breakpoint in a debugger ** to detect when version error conditions occurs. @@ -125159,7 +127974,7 @@ error_out: zColumnName); rc = SQLITE_ERROR; } - sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg); + sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg); sqlite3DbFree(db, zErrMsg); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); @@ -125325,7 +128140,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){ ** IMPORTANT: Changing the PENDING byte from 0x40000000 results in ** an incompatible database file format. Changing the PENDING byte ** while any database connection is open results in undefined and - ** dileterious behavior. + ** deleterious behavior. */ case SQLITE_TESTCTRL_PENDING_BYTE: { rc = PENDING_BYTE; @@ -125480,22 +128295,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - /* sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, - ** sqlite3_stmt*,const char**); - ** - ** If compiled with SQLITE_ENABLE_TREE_EXPLAIN, each sqlite3_stmt holds - ** a string that describes the optimized parse tree. This test-control - ** returns a pointer to that string. - */ - case SQLITE_TESTCTRL_EXPLAIN_STMT: { - sqlite3_stmt *pStmt = va_arg(ap, sqlite3_stmt*); - const char **pzRet = va_arg(ap, const char**); - *pzRet = sqlite3VdbeExplanation((Vdbe*)pStmt); - break; - } -#endif - /* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int); ** ** Set or clear a flag that indicates that the database file is always well- @@ -125524,6 +128323,13 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } + /* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */ + case SQLITE_TESTCTRL_SORTER_MMAP: { + sqlite3 *db = va_arg(ap, sqlite3*); + db->nMaxSorterMmap = va_arg(ap, int); + break; + } + /* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT); ** ** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if @@ -125533,7 +128339,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){ if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; break; } - } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ @@ -125807,7 +128612,7 @@ SQLITE_API int sqlite3_unlock_notify( leaveMutex(); assert( !db->mallocFailed ); - sqlite3Error(db, rc, (rc?"database is deadlocked":0)); + sqlite3ErrorWithMsg(db, rc, (rc?"database is deadlocked":0)); sqlite3_mutex_leave(db->mutex); return rc; } @@ -129949,6 +132754,7 @@ static int fts3FilterMethod( /* In case the cursor has been used before, clear it now. */ sqlite3_finalize(pCsr->pStmt); sqlite3_free(pCsr->aDoclist); + sqlite3_free(pCsr->aMatchinfo); sqlite3Fts3ExprFree(pCsr->pExpr); memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); @@ -131259,7 +134065,7 @@ static int fts3EvalIncrPhraseNext( bMaxSet = 1; } } - assert( rc!=SQLITE_OK || a[p->nToken-1].bIgnore==0 ); + assert( rc!=SQLITE_OK || (p->nToken>=1 && a[p->nToken-1].bIgnore==0) ); assert( rc!=SQLITE_OK || bMaxSet ); /* Keep advancing iterators until they all point to the same document */ @@ -133376,7 +136182,7 @@ static int getNextToken( /* Set variable i to the maximum number of bytes of input to tokenize. */ for(i=0; i **
  • vfs: ^The "vfs" parameter may be used to specify the name of @@ -2778,11 +2801,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** -**
  • psow: ^The psow parameter may be "true" (or "on" or "yes" or -** "1") or "false" (or "off" or "no" or "0") to indicate that the +**
  • psow: ^The psow parameter indicates whether or not the ** [powersafe overwrite] property does or does not apply to the -** storage media on which the database file resides. ^The psow query -** parameter only works for the built-in unix and Windows VFSes. +** storage media on which the database file resides. ** **
  • nolock: ^The nolock parameter is a boolean query parameter ** which if set disables file locking in rollback journal modes. This @@ -3078,6 +3099,10 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
    SQLITE_LIMIT_TRIGGER_DEPTH
    **
    The maximum depth of recursion for triggers.
    )^ +** +** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
    SQLITE_LIMIT_WORKER_THREADS
    +**
    The maximum number of auxiliary worker threads that a single +** [prepared statement] may start.
    )^ ** */ #define SQLITE_LIMIT_LENGTH 0 @@ -3091,6 +3116,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 +#define SQLITE_LIMIT_WORKER_THREADS 11 /* ** CAPI3REF: Compiling An SQL Statement @@ -3364,18 +3390,18 @@ typedef struct sqlite3_context sqlite3_context; ** If the fourth parameter to sqlite3_bind_blob() is negative, then ** the behavior is undefined. ** If a non-negative fourth parameter is provided to sqlite3_bind_text() -** or sqlite3_bind_text16() then that parameter must be the byte offset +** or sqlite3_bind_text16() or sqlite3_bind_text64() then +** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL ** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** -** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and -** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or +** ^The fifth argument to the BLOB and string binding interfaces +** is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor is called -** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(), -** sqlite3_bind_text(), or sqlite3_bind_text16() fails. +** to dispose of the BLOB or string even if the call to bind API fails. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. @@ -3383,6 +3409,14 @@ typedef struct sqlite3_context sqlite3_context; ** SQLite makes its own private copy of the data immediately, before ** the sqlite3_bind_*() routine returns. ** +** ^The sixth argument to sqlite3_bind_text64() must be one of +** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] +** to specify the encoding of the text in the third parameter. If +** the sixth argument to sqlite3_bind_text64() is not one of the +** allowed values shown above, or if the text encoding is different +** from the encoding specified by the sixth parameter, then the behavior +** is undefined. +** ** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that ** is filled with zeroes. ^A zeroblob uses a fixed amount of memory ** (just an integer to hold its size) while it is being processed. @@ -3403,6 +3437,9 @@ typedef struct sqlite3_context sqlite3_context; ** ** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an ** [error code] if anything goes wrong. +** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB +** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or +** [SQLITE_MAX_LENGTH]. ** ^[SQLITE_RANGE] is returned if the parameter ** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. ** @@ -3410,12 +3447,16 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. */ SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); +SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, + void(*)(void*)); SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); -SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); +SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); +SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, + void(*)(void*), unsigned char encoding); SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); @@ -4164,7 +4205,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** object results in undefined behavior. ** ** ^These routines work just like the corresponding [column access functions] -** except that these routines take a single [protected sqlite3_value] object +** except that these routines take a single [protected sqlite3_value] object ** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. ** ** ^The sqlite3_value_text16() interface extracts a UTF-16 string @@ -4411,6 +4452,10 @@ typedef void (*sqlite3_destructor_type)(void*); ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. +** ^The sqlite3_result_text64() interface sets the return value of an +** application-defined function to be a text string in an encoding +** specified by the fifth (and last) parameter, which must be one +** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to the sqlite3_result_text* interfaces @@ -4454,6 +4499,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** the [sqlite3_context] pointer, the results are undefined. */ SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,sqlite3_uint64,void(*)(void*)); SQLITE_API void sqlite3_result_double(sqlite3_context*, double); SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); @@ -4464,6 +4510,8 @@ SQLITE_API void sqlite3_result_int(sqlite3_context*, int); SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, + void(*)(void*), unsigned char encoding); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); @@ -6160,12 +6208,13 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 -#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 +#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_ISINIT 23 -#define SQLITE_TESTCTRL_LAST 23 +#define SQLITE_TESTCTRL_SORTER_MMAP 24 +#define SQLITE_TESTCTRL_LAST 24 /* ** CAPI3REF: SQLite Runtime Status @@ -6356,12 +6405,12 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
    SQLITE_DBSTATUS_CACHE_USED
    -**
    This parameter returns the approximate number of of bytes of heap +**
    This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
    SQLITE_DBSTATUS_SCHEMA_USED
    -**
    This parameter returns the approximate number of of bytes of heap +**
    This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the @@ -6370,7 +6419,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. ** ** [[SQLITE_DBSTATUS_STMT_USED]] ^(
    SQLITE_DBSTATUS_STMT_USED
    -**
    This parameter returns the approximate number of of bytes of heap +**
    This parameter returns the approximate number of bytes of heap ** and lookaside memory used by all prepared statements associated with ** the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. diff --git a/Data/cmake/PocoDataConfig.cmake b/Data/cmake/PocoDataConfig.cmake new file mode 100644 index 000000000..a598c9f7d --- /dev/null +++ b/Data/cmake/PocoDataConfig.cmake @@ -0,0 +1,4 @@ +include(CMakeFindDependencyMacro) +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}) +find_dependency(PocoFoundation) +include("${CMAKE_CURRENT_LIST_DIR}/PocoDataTargets.cmake") \ No newline at end of file diff --git a/Foundation/CMakeLists.txt b/Foundation/CMakeLists.txt index 352cd6cc8..833425c27 100644 --- a/Foundation/CMakeLists.txt +++ b/Foundation/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoFoundation") +set(LIBNAME "Foundation") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -15,10 +16,18 @@ POCO_HEADERS_AUTO( SRCS include/Poco/OpcomChannel.h ) POCO_SOURCES_AUTO_PLAT( SRCS UNIX src/SyslogChannel.cpp ) POCO_HEADERS_AUTO( SRCS include/Poco/SyslogChannel.h ) +# For Windows CE we need to disable these +if(WINCE) +POCO_SOURCES_AUTO_PLAT( SRCS OFF + src/WindowsConsoleChannel.cpp + src/EventLogChannel.cpp + ) +else() POCO_SOURCES_AUTO_PLAT( SRCS WIN32 src/WindowsConsoleChannel.cpp src/EventLogChannel.cpp ) +endif() POCO_HEADERS_AUTO( SRCS include/Poco/WindowsConsoleChannel.h @@ -90,36 +99,50 @@ else() ) endif (POCO_UNBUNDLED) -if(CMAKE_SYSTEM MATCHES "Windows") - add_definitions( -DPCRE_STATIC) +if(WIN32) set(SYSLIBS ${SYSLIBS} iphlpapi) -else (CMAKE_SYSTEM MATCHES "Windows") - add_definitions( -DPCRE_STATIC) -endif(CMAKE_SYSTEM MATCHES "Windows") - -add_library( ${LIBNAME} ${LIB_MODE} ${SRCS}) -set_target_properties( ${LIBNAME} - PROPERTIES - VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL Foundation_EXPORTS) +endif(WIN32) if (${CMAKE_CXX_COMPILER_ID} MATCHES "SunPro") - set_target_properties( ${LIBNAME} PROPERTIES LINK_FLAGS "-library=stlport4") + set_target_properties( "${LIBNAME}" PROPERTIES LINK_FLAGS "-library=stlport4") endif (${CMAKE_CXX_COMPILER_ID} MATCHES "SunPro") -target_link_libraries( ${LIBNAME} ${SYSLIBS}) + +# TODO: Why is this here? +add_definitions( -DPCRE_STATIC) + +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS}) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" + PROPERTIES + VERSION ${PROJECT_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL Foundation_EXPORTS + ) + +target_link_libraries( "${LIBNAME}" ${SYSLIBS}) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + if (ENABLE_TESTS) add_subdirectory( samples ) add_subdirectory( testsuite ) diff --git a/Foundation/cmake/PocoFoundationConfig.cmake b/Foundation/cmake/PocoFoundationConfig.cmake new file mode 100644 index 000000000..ebf740bc1 --- /dev/null +++ b/Foundation/cmake/PocoFoundationConfig.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/PocoFoundationTargets.cmake") \ No newline at end of file diff --git a/Foundation/include/Poco/Bugcheck.h b/Foundation/include/Poco/Bugcheck.h index f48ffb27c..3683ac98d 100644 --- a/Foundation/include/Poco/Bugcheck.h +++ b/Foundation/include/Poco/Bugcheck.h @@ -40,7 +40,7 @@ class Foundation_API Bugcheck /// automatically provide useful context information. { public: - static void assertion(const char* cond, const char* file, int line); + static void assertion(const char* cond, const char* file, int line, const char* text = 0); /// An assertion failed. Break into the debugger, if /// possible, then throw an AssertionViolationException. @@ -71,7 +71,7 @@ public: /// possible. protected: - static std::string what(const char* msg, const char* file, int line); + static std::string what(const char* msg, const char* file, int line, const char* text = 0); }; @@ -84,7 +84,11 @@ protected: #if defined(_DEBUG) #define poco_assert_dbg(cond) \ if (!(cond)) Poco::Bugcheck::assertion(#cond, __FILE__, __LINE__); else (void) 0 + + #define poco_assert_msg_dbg(cond, text) \ + if (!(cond)) Poco::Bugcheck::assertion(#cond, __FILE__, __LINE__, text); else (void) 0 #else + #define poco_assert_msg_dbg(cond, text) #define poco_assert_dbg(cond) #endif @@ -93,6 +97,10 @@ protected: if (!(cond)) Poco::Bugcheck::assertion(#cond, __FILE__, __LINE__); else (void) 0 +#define poco_assert_msg(cond, text) \ + if (!(cond)) Poco::Bugcheck::assertion(#cond, __FILE__, __LINE__, text); else (void) 0 + + #define poco_check_ptr(ptr) \ if (!(ptr)) Poco::Bugcheck::nullPointer(#ptr, __FILE__, __LINE__); else (void) 0 diff --git a/Foundation/include/Poco/Clock.h b/Foundation/include/Poco/Clock.h index 2924ebd0f..db6428873 100644 --- a/Foundation/include/Poco/Clock.h +++ b/Foundation/include/Poco/Clock.h @@ -48,6 +48,9 @@ public: typedef Int64 ClockVal; /// monotonic clock value in microsecond resolution typedef Int64 ClockDiff; /// difference between two clock values in microseconds + static const ClockVal CLOCKVAL_MIN; /// minimum clock value + static const ClockVal CLOCKVAL_MAX; /// maximum clock value + Clock(); /// Creates a Clock with the current system clock value. diff --git a/Foundation/include/Poco/DateTimeParser.h b/Foundation/include/Poco/DateTimeParser.h index eebd6d20c..74e6a2ebd 100644 --- a/Foundation/include/Poco/DateTimeParser.h +++ b/Foundation/include/Poco/DateTimeParser.h @@ -47,6 +47,14 @@ class Foundation_API DateTimeParser /// additional specifier is supported: %r will parse a year given by either /// two or four digits. Years 69-00 are interpreted in the 20th century /// (1969-2000), years 01-68 in the 21th century (2001-2068). + /// + /// Note that in the current implementation all characters other than format specifiers in + /// the format string are ignored/not matched against the date/time string. This may + /// lead to non-error results even with nonsense input strings. + /// This may change in a future version to a more strict behavior. + /// If more strict format validation of date/time strings is required, a regular + /// expression could be used for initial validation, before passing the string + /// to DateTimeParser. { public: static void parse(const std::string& fmt, const std::string& str, DateTime& dateTime, int& timeZoneDifferential); diff --git a/Foundation/include/Poco/Dynamic/Var.h b/Foundation/include/Poco/Dynamic/Var.h index e5e8c0245..6076e6f38 100644 --- a/Foundation/include/Poco/Dynamic/Var.h +++ b/Foundation/include/Poco/Dynamic/Var.h @@ -542,6 +542,7 @@ private: static Var parseObject(const std::string& val, std::string::size_type& pos); static Var parseArray(const std::string& val, std::string::size_type& pos); static std::string parseString(const std::string& val, std::string::size_type& pos); + static std::string parseJSONString(const std::string& val, std::string::size_type& pos); static void skipWhiteSpace(const std::string& val, std::string::size_type& pos); template diff --git a/Foundation/include/Poco/Error.h b/Foundation/include/Poco/Error.h index 1270fc835..1f96556b8 100644 --- a/Foundation/include/Poco/Error.h +++ b/Foundation/include/Poco/Error.h @@ -33,9 +33,15 @@ class Foundation_API Error public: #ifdef POCO_OS_FAMILY_WINDOWS + static DWORD last(); + /// Utility function returning the last error. + static std::string getMessage(DWORD errorCode); /// Utility function translating numeric error code to string. #else + static int last(); + /// Utility function returning the last error. + static std::string getMessage(int errorCode); /// Utility function translating numeric error code to string. #endif diff --git a/Foundation/include/Poco/Format.h b/Foundation/include/Poco/Format.h index 995fcb5da..1b43e9744 100644 --- a/Foundation/include/Poco/Format.h +++ b/Foundation/include/Poco/Format.h @@ -109,6 +109,10 @@ std::string Foundation_API format(const std::string& fmt, const Any& value1, con std::string Foundation_API format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4); std::string Foundation_API format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5); std::string Foundation_API format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6); +std::string Foundation_API format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7); +std::string Foundation_API format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8); +std::string Foundation_API format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9); +std::string Foundation_API format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10); void Foundation_API format(std::string& result, const std::string& fmt, const Any& value); @@ -119,6 +123,10 @@ void Foundation_API format(std::string& result, const std::string& fmt, const An void Foundation_API format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4); void Foundation_API format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5); void Foundation_API format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6); +void Foundation_API format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7); +void Foundation_API format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8); +void Foundation_API format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9); +void Foundation_API format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10); void Foundation_API format(std::string& result, const std::string& fmt, const std::vector& values); diff --git a/Foundation/include/Poco/Logger.h b/Foundation/include/Poco/Logger.h index e2e53e9d5..67a591f0c 100644 --- a/Foundation/include/Poco/Logger.h +++ b/Foundation/include/Poco/Logger.h @@ -158,6 +158,10 @@ public: void fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4); void fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5); void fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6); + void fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7); + void fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8); + void fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9); + void fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10); void critical(const std::string& msg); /// If the Logger's log level is at least PRIO_CRITICAL, @@ -181,6 +185,10 @@ public: void critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4); void critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5); void critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6); + void critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7); + void critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8); + void critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9); + void critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10); void error(const std::string& msg); /// If the Logger's log level is at least PRIO_ERROR, @@ -204,6 +212,10 @@ public: void error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4); void error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5); void error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6); + void error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7); + void error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8); + void error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9); + void error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10); void warning(const std::string& msg); /// If the Logger's log level is at least PRIO_WARNING, @@ -227,6 +239,10 @@ public: void warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4); void warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5); void warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6); + void warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7); + void warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8); + void warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9); + void warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10); void notice(const std::string& msg); /// If the Logger's log level is at least PRIO_NOTICE, @@ -250,6 +266,10 @@ public: void notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4); void notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5); void notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6); + void notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7); + void notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8); + void notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9); + void notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10); void information(const std::string& msg); /// If the Logger's log level is at least PRIO_INFORMATION, @@ -273,6 +293,10 @@ public: void information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4); void information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5); void information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6); + void information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7); + void information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8); + void information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9); + void information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10); void debug(const std::string& msg); /// If the Logger's log level is at least PRIO_DEBUG, @@ -296,6 +320,10 @@ public: void debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4); void debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5); void debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6); + void debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7); + void debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8); + void debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9); + void debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10); void trace(const std::string& msg); /// If the Logger's log level is at least PRIO_TRACE, @@ -319,6 +347,10 @@ public: void trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4); void trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5); void trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6); + void trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7); + void trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8); + void trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9); + void trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10); void dump(const std::string& msg, const void* buffer, std::size_t length, Message::Priority prio = Message::PRIO_DEBUG); /// Logs the given message, followed by the data in buffer. @@ -700,6 +732,30 @@ inline void Logger::fatal(const std::string& fmt, const Any& value1, const Any& } +inline void Logger::fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7), Message::PRIO_FATAL); +} + + +inline void Logger::fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8), Message::PRIO_FATAL); +} + + +inline void Logger::fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9), Message::PRIO_FATAL); +} + + +inline void Logger::fatal(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10), Message::PRIO_FATAL); +} + + inline void Logger::critical(const std::string& msg) { log(msg, Message::PRIO_CRITICAL); @@ -748,6 +804,30 @@ inline void Logger::critical(const std::string& fmt, const Any& value1, const An } +inline void Logger::critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7), Message::PRIO_CRITICAL); +} + + +inline void Logger::critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8), Message::PRIO_CRITICAL); +} + + +inline void Logger::critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9), Message::PRIO_CRITICAL); +} + + +inline void Logger::critical(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10), Message::PRIO_CRITICAL); +} + + inline void Logger::error(const std::string& msg) { log(msg, Message::PRIO_ERROR); @@ -796,6 +876,30 @@ inline void Logger::error(const std::string& fmt, const Any& value1, const Any& } +inline void Logger::error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7), Message::PRIO_ERROR); +} + + +inline void Logger::error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8), Message::PRIO_ERROR); +} + + +inline void Logger::error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9), Message::PRIO_ERROR); +} + + +inline void Logger::error(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10), Message::PRIO_ERROR); +} + + inline void Logger::warning(const std::string& msg) { log(msg, Message::PRIO_WARNING); @@ -844,6 +948,30 @@ inline void Logger::warning(const std::string& fmt, const Any& value1, const Any } +inline void Logger::warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7), Message::PRIO_WARNING); +} + + +inline void Logger::warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8), Message::PRIO_WARNING); +} + + +inline void Logger::warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9), Message::PRIO_WARNING); +} + + +inline void Logger::warning(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10), Message::PRIO_WARNING); +} + + inline void Logger::notice(const std::string& msg) { log(msg, Message::PRIO_NOTICE); @@ -892,6 +1020,30 @@ inline void Logger::notice(const std::string& fmt, const Any& value1, const Any& } +inline void Logger::notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7), Message::PRIO_NOTICE); +} + + +inline void Logger::notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8), Message::PRIO_NOTICE); +} + + +inline void Logger::notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9), Message::PRIO_NOTICE); +} + + +inline void Logger::notice(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10), Message::PRIO_NOTICE); +} + + inline void Logger::information(const std::string& msg) { log(msg, Message::PRIO_INFORMATION); @@ -940,6 +1092,30 @@ inline void Logger::information(const std::string& fmt, const Any& value1, const } +inline void Logger::information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7), Message::PRIO_INFORMATION); +} + + +inline void Logger::information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8), Message::PRIO_INFORMATION); +} + + +inline void Logger::information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9), Message::PRIO_INFORMATION); +} + + +inline void Logger::information(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10), Message::PRIO_INFORMATION); +} + + inline void Logger::debug(const std::string& msg) { log(msg, Message::PRIO_DEBUG); @@ -988,6 +1164,30 @@ inline void Logger::debug(const std::string& fmt, const Any& value1, const Any& } +inline void Logger::debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7), Message::PRIO_DEBUG); +} + + +inline void Logger::debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8), Message::PRIO_DEBUG); +} + + +inline void Logger::debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9), Message::PRIO_DEBUG); +} + + +inline void Logger::debug(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10), Message::PRIO_DEBUG); +} + + inline void Logger::trace(const std::string& msg) { log(msg, Message::PRIO_TRACE); @@ -1036,6 +1236,30 @@ inline void Logger::trace(const std::string& fmt, const Any& value1, const Any& } +inline void Logger::trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7), Message::PRIO_TRACE); +} + + +inline void Logger::trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8), Message::PRIO_TRACE); +} + + +inline void Logger::trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9), Message::PRIO_TRACE); +} + + +inline void Logger::trace(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10) +{ + log(Poco::format(fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10), Message::PRIO_TRACE); +} + + inline bool Logger::is(int level) const { return _level >= level; diff --git a/Foundation/include/Poco/PatternFormatter.h b/Foundation/include/Poco/PatternFormatter.h index 50c87643f..0ab1a33b3 100644 --- a/Foundation/include/Poco/PatternFormatter.h +++ b/Foundation/include/Poco/PatternFormatter.h @@ -121,10 +121,11 @@ protected: /// Returns a string for the given priority value. private: - struct PatternAction { - PatternAction(): key(0), length(0) {} + PatternAction(): key(0), length(0) + { + } char key; int length; @@ -132,16 +133,14 @@ private: std::string prepend; }; - std::vector _patternActions; - bool _localTime; - Timestamp::TimeDiff _localTimeOffset; - std::string _pattern; - - - void ParsePattern(); + void parsePattern(); /// Will parse the _pattern string into the vector of PatternActions, /// which contains the message key, any text that needs to be written first /// a proprety in case of %[] and required length. + + std::vector _patternActions; + bool _localTime; + std::string _pattern; }; diff --git a/Foundation/include/Poco/Thread.h b/Foundation/include/Poco/Thread.h index 541fa1bdc..d5653292c 100644 --- a/Foundation/include/Poco/Thread.h +++ b/Foundation/include/Poco/Thread.h @@ -122,7 +122,7 @@ public: /// May return 0 if the priority has not been explicitly set. static int getMinOSPriority(int policy = POLICY_DEFAULT); - /// Returns the mininum operating system-specific priority value, + /// Returns the minimum operating system-specific priority value, /// which can be passed to setOSPriority() for the given policy. static int getMaxOSPriority(int policy = POLICY_DEFAULT); @@ -149,6 +149,13 @@ public: void start(Callable target, void* pData = 0); /// Starts the thread with the given target and parameter. + template + void startFunc(Functor fn) + /// Starts the thread with the given functor object or lambda. + { + startImpl(new FunctorRunnable(fn)); + } + void join(); /// Waits until the thread completes execution. /// If multiple threads try to join the same @@ -221,7 +228,29 @@ protected: static int uniqueId(); /// Creates and returns a unique id for a thread. - + + template + class FunctorRunnable: public Runnable + { + public: + FunctorRunnable(const Functor& functor): + _functor(functor) + { + } + + ~FunctorRunnable() + { + } + + void run() + { + _functor(); + } + + private: + Functor _functor; + }; + private: Thread(const Thread&); Thread& operator = (const Thread&); diff --git a/Foundation/include/Poco/Thread_POSIX.h b/Foundation/include/Poco/Thread_POSIX.h index 120f7a86e..5bfae4a28 100644 --- a/Foundation/include/Poco/Thread_POSIX.h +++ b/Foundation/include/Poco/Thread_POSIX.h @@ -26,6 +26,7 @@ #include "Poco/Event.h" #include "Poco/RefCountedObject.h" #include "Poco/AutoPtr.h" +#include "Poco/SharedPtr.h" #include // must be limits.h (not ) for PTHREAD_STACK_MIN on Solaris #include @@ -61,16 +62,6 @@ public: POLICY_DEFAULT_IMPL = SCHED_OTHER }; - struct CallbackData: public RefCountedObject - { - CallbackData(): callback(0), pData(0) - { - } - - Callable callback; - void* pData; - }; - ThreadImpl(); ~ThreadImpl(); @@ -83,9 +74,7 @@ public: static int getMaxOSPriorityImpl(int policy); void setStackSizeImpl(int size); int getStackSizeImpl() const; - void startImpl(Runnable& target); - void startImpl(Callable target, void* pData = 0); - + void startImpl(SharedPtr pTarget); void joinImpl(); bool joinImpl(long milliseconds); bool isRunningImpl() const; @@ -96,7 +85,6 @@ public: protected: static void* runnableEntry(void* pThread); - static void* callableEntry(void* pThread); static int mapPrio(int prio, int policy = SCHED_OTHER); static int reverseMapPrio(int osPrio, int policy = SCHED_OTHER); @@ -129,8 +117,6 @@ private: struct ThreadData: public RefCountedObject { ThreadData(): - pRunnableTarget(0), - pCallbackTarget(0), thread(0), prio(PRIO_NORMAL_IMPL), policy(SCHED_OTHER), @@ -146,8 +132,7 @@ private: #endif } - Runnable* pRunnableTarget; - AutoPtr pCallbackTarget; + SharedPtr pRunnableTarget; pthread_t thread; int prio; int osPrio; @@ -186,8 +171,7 @@ inline int ThreadImpl::getOSPriorityImpl() const inline bool ThreadImpl::isRunningImpl() const { - return _pData->pRunnableTarget != 0 || - (_pData->pCallbackTarget.get() != 0 && _pData->pCallbackTarget->callback != 0); + return !_pData->pRunnableTarget.isNull(); } diff --git a/Foundation/include/Poco/Thread_WIN32.h b/Foundation/include/Poco/Thread_WIN32.h index a954c2a4a..598db8e7a 100644 --- a/Foundation/include/Poco/Thread_WIN32.h +++ b/Foundation/include/Poco/Thread_WIN32.h @@ -22,6 +22,7 @@ #include "Poco/Foundation.h" #include "Poco/Runnable.h" +#include "Poco/SharedPtr.h" #include "Poco/UnWindows.h" @@ -40,16 +41,6 @@ public: typedef unsigned (__stdcall *Entry)(void*); #endif - struct CallbackData - { - CallbackData(): callback(0), pData(0) - { - } - - Callable callback; - void* pData; - }; - enum Priority { PRIO_LOWEST_IMPL = THREAD_PRIORITY_LOWEST, @@ -76,9 +67,7 @@ public: static int getMaxOSPriorityImpl(int policy); void setStackSizeImpl(int size); int getStackSizeImpl() const; - void startImpl(Runnable& target); - void startImpl(Callable target, void* pData = 0); - + void startImpl(SharedPtr pTarget); void joinImpl(); bool joinImpl(long milliseconds); bool isRunningImpl() const; @@ -94,12 +83,6 @@ protected: static unsigned __stdcall runnableEntry(void* pThread); #endif -#if defined(_DLL) - static DWORD WINAPI callableEntry(LPVOID pThread); -#else - static unsigned __stdcall callableEntry(void* pThread); -#endif - void createImpl(Entry ent, void* pData); void threadCleanup(); @@ -129,12 +112,11 @@ private: DWORD _slot; }; - Runnable* _pRunnableTarget; - CallbackData _callbackTarget; - HANDLE _thread; - DWORD _threadId; - int _prio; - int _stackSize; + SharedPtr _pRunnableTarget; + HANDLE _thread; + DWORD _threadId; + int _prio; + int _stackSize; static CurrentThreadHolder _currentThreadHolder; }; diff --git a/Foundation/include/Poco/Timestamp.h b/Foundation/include/Poco/Timestamp.h index 2ce171048..ec8e63662 100644 --- a/Foundation/include/Poco/Timestamp.h +++ b/Foundation/include/Poco/Timestamp.h @@ -28,6 +28,7 @@ namespace Poco { class Timespan; + class Foundation_API Timestamp /// A Timestamp stores a monotonic* time value /// with (theoretical) microseconds resolution. @@ -47,6 +48,9 @@ public: typedef Int64 UtcTimeVal; /// monotonic UTC time value in 100 nanosecond resolution typedef Int64 TimeDiff; /// difference between two timestamps in microseconds + static const TimeVal TIMEVAL_MIN; /// minimum timestamp value + static const TimeVal TIMEVAL_MAX; /// maximum timestamp value + Timestamp(); /// Creates a timestamp with the current time. diff --git a/Foundation/include/Poco/URI.h b/Foundation/include/Poco/URI.h index b1613d38e..3af292f1f 100644 --- a/Foundation/include/Poco/URI.h +++ b/Foundation/include/Poco/URI.h @@ -22,6 +22,7 @@ #include "Poco/Foundation.h" #include +#include namespace Poco { @@ -40,11 +41,13 @@ class Foundation_API URI /// /// The class automatically performs a few normalizations on /// all URIs and URI parts passed to it: - /// * scheme identifiers are converted to lower case. + /// * scheme identifiers are converted to lower case /// * percent-encoded characters are decoded /// * optionally, dot segments are removed from paths (see normalize()) { public: + typedef std::vector > QueryParameters; + URI(); /// Creates an empty URI. @@ -159,10 +162,30 @@ public: /// Sets the path part of the URI. std::string getQuery() const; - /// Returns the query part of the URI. + /// Returns the decoded query part of the URI. + /// + /// Note that encoded ampersand characters ('&', "%26") + /// will be decoded, which could cause ambiguities if the query + /// string contains multiple parameters and a parameter name + /// or value contains an ampersand as well. + /// In such a case it's better to use getRawQuery() or + /// getQueryParameters(). void setQuery(const std::string& query); /// Sets the query part of the URI. + /// + /// The query string will be percent-encoded. If the query + /// already contains percent-encoded characters, these + /// will be double-encoded, which is probably not what's + /// intended by the caller. Furthermore, ampersand ('&') + /// characters in the query will not be encoded. This could + /// lead to ambiguity issues if the query string contains multiple + /// name-value parameters separated by ampersand, and if any + /// name or value also contains an ampersand. In such a + /// case, it's better to use setRawQuery() with a properly + /// percent-encoded query string, or use addQueryParameter() + /// or setQueryParameters(), which take care of appropriate + /// percent encoding of parameter names and values. void addQueryParameter(const std::string& param, const std::string& val = ""); /// Adds "param=val" to the query; "param" may not be empty. @@ -172,11 +195,24 @@ public: /// if found in param or val. const std::string& getRawQuery() const; - /// Returns the unencoded query part of the URI. + /// Returns the query string in raw form, which usually + /// means percent encoded. void setRawQuery(const std::string& query); /// Sets the query part of the URI. + /// + /// The given query string must be properly percent-encoded. + QueryParameters getQueryParameters() const; + /// Returns the decoded query string parameters as a vector + /// of name-value pairs. + + void setQueryParameters(const QueryParameters& params); + /// Sets the query part of the URI from a vector + /// of query parameters. + /// + /// Calls addQueryParameter() for each parameter name and value. + const std::string& getFragment() const; /// Returns the fragment part of the URI. @@ -246,6 +282,7 @@ public: /// URI-decodes the given string by replacing percent-encoded /// characters with the actual character. The decoded string /// is appended to decodedStr. + /// /// When plusAsSpace is true, non-encoded plus signs in the query are decoded as spaces. /// (http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1) diff --git a/Foundation/include/Poco/UTF8String.h b/Foundation/include/Poco/UTF8String.h index 36c280dea..d719b609e 100644 --- a/Foundation/include/Poco/UTF8String.h +++ b/Foundation/include/Poco/UTF8String.h @@ -35,6 +35,9 @@ struct Foundation_API UTF8 /// /// toUpper(), toUpperInPlace(), toLower() and toLowerInPlace() provide /// Unicode-based character case transformation for UTF-8 encoded strings. + /// + /// removeBOM() removes the UTF-8 Byte Order Mark sequence (0xEF, 0xBB, 0xBF) + /// from the beginning of the given string, if it's there. { static int icompare(const std::string& str, std::string::size_type pos, std::string::size_type n, std::string::const_iterator it2, std::string::const_iterator end2); static int icompare(const std::string& str1, const std::string& str2); @@ -51,6 +54,10 @@ struct Foundation_API UTF8 static std::string& toUpperInPlace(std::string& str); static std::string toLower(const std::string& str); static std::string& toLowerInPlace(std::string& str); + + static void removeBOM(std::string& str); + /// Remove the UTF-8 Byte Order Mark sequence (0xEF, 0xBB, 0xBF) + /// from the beginning of the string, if it's there. }; diff --git a/Foundation/include/Poco/Version.h b/Foundation/include/Poco/Version.h index 927be89b0..319beebb5 100644 --- a/Foundation/include/Poco/Version.h +++ b/Foundation/include/Poco/Version.h @@ -34,7 +34,7 @@ // Ax are alpha releases // Bx are beta releases // -#define POCO_VERSION 0x01050400 +#define POCO_VERSION 0x010600D1 #endif // Foundation_Version_INCLUDED diff --git a/Foundation/src/Bugcheck.cpp b/Foundation/src/Bugcheck.cpp index ea2cfe9f5..debb0fe22 100644 --- a/Foundation/src/Bugcheck.cpp +++ b/Foundation/src/Bugcheck.cpp @@ -23,10 +23,18 @@ namespace Poco { -void Bugcheck::assertion(const char* cond, const char* file, int line) +void Bugcheck::assertion(const char* cond, const char* file, int line, const char* text) { - Debugger::enter(std::string("Assertion violation: ") + cond, file, line); - throw AssertionViolationException(what(cond, file, line)); + std::string message("Assertion violation: "); + message += cond; + if (text) + { + message += " ("; + message += text; + message += ")"; + } + Debugger::enter(message, file, line); + throw AssertionViolationException(what(cond, file, line, text)); } @@ -100,10 +108,11 @@ void Bugcheck::debugger(const char* msg, const char* file, int line) } -std::string Bugcheck::what(const char* msg, const char* file, int line) +std::string Bugcheck::what(const char* msg, const char* file, int line, const char* text) { std::ostringstream str; if (msg) str << msg << " "; + if (text != NULL) str << "(" << text << ") "; str << "in file \"" << file << "\", line " << line; return str.str(); } diff --git a/Foundation/src/Clock.cpp b/Foundation/src/Clock.cpp index 808f9b10c..1b85905df 100644 --- a/Foundation/src/Clock.cpp +++ b/Foundation/src/Clock.cpp @@ -28,11 +28,18 @@ #include "Poco/UnWindows.h" #endif #include +#undef min +#undef max +#include namespace Poco { +const Clock::ClockVal Clock::CLOCKVAL_MIN = std::numeric_limits::min(); +const Clock::ClockVal Clock::CLOCKVAL_MAX = std::numeric_limits::max(); + + Clock::Clock() { update(); diff --git a/Foundation/src/DateTime.cpp b/Foundation/src/DateTime.cpp index fcc0205ec..c4d7f446f 100644 --- a/Foundation/src/DateTime.cpp +++ b/Foundation/src/DateTime.cpp @@ -392,7 +392,38 @@ void DateTime::computeGregorian(double julianDay) void DateTime::computeDaytime() { Timespan span(_utcTime/10); - _hour = span.hours(); + int hour = span.hours(); + // Due to double rounding issues, the previous call to computeGregorian() + // may have crossed into the next or previous day. We need to correct that. + if (hour == 23 && _hour == 0) + { + _day--; + if (_day == 0) + { + _month--; + if (_month == 0) + { + _month = 12; + _year--; + } + _day = daysOfMonth(_year, _month); + } + } + else if (hour == 0 && _hour == 23) + { + _day++; + if (_day > daysOfMonth(_year, _month)) + { + _month++; + if (_month > 12) + { + _month = 1; + _year++; + } + _day = 1; + } + } + _hour = hour; _minute = span.minutes(); _second = span.seconds(); _millisecond = span.milliseconds(); diff --git a/Foundation/src/Error.cpp b/Foundation/src/Error.cpp index a65965dff..a37375be1 100644 --- a/Foundation/src/Error.cpp +++ b/Foundation/src/Error.cpp @@ -19,12 +19,18 @@ #include "Poco/Error.h" #include #include +#include namespace Poco { #ifdef POCO_OS_FAMILY_WINDOWS + DWORD Error::last() + { + return GetLastError(); + } + std::string Error::getMessage(DWORD errorCode) { @@ -44,6 +50,11 @@ namespace Poco { } #else + int Error::last() + { + return errno; + } + std::string Error::getMessage(int errorCode) { diff --git a/Foundation/src/File_WIN32.cpp b/Foundation/src/File_WIN32.cpp index f58282632..202152d7f 100644 --- a/Foundation/src/File_WIN32.cpp +++ b/Foundation/src/File_WIN32.cpp @@ -228,7 +228,7 @@ void FileImpl::setLastModifiedImpl(const Timestamp& ts) FILETIME ft; ft.dwLowDateTime = low; ft.dwHighDateTime = high; - FileHandle fh(_path, FILE_ALL_ACCESS, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); + FileHandle fh(_path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); if (SetFileTime(fh.get(), 0, &ft, &ft) == 0) handleLastErrorImpl(_path); } diff --git a/Foundation/src/File_WIN32U.cpp b/Foundation/src/File_WIN32U.cpp index 0522ab631..0c2a053e8 100644 --- a/Foundation/src/File_WIN32U.cpp +++ b/Foundation/src/File_WIN32U.cpp @@ -232,7 +232,7 @@ void FileImpl::setLastModifiedImpl(const Timestamp& ts) FILETIME ft; ft.dwLowDateTime = low; ft.dwHighDateTime = high; - FileHandle fh(_path, _upath, FILE_ALL_ACCESS, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); + FileHandle fh(_path, _upath, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); if (SetFileTime(fh.get(), 0, &ft, &ft) == 0) handleLastErrorImpl(_path); } diff --git a/Foundation/src/Format.cpp b/Foundation/src/Format.cpp index c5697cddd..e16a980bc 100644 --- a/Foundation/src/Format.cpp +++ b/Foundation/src/Format.cpp @@ -275,6 +275,38 @@ std::string format(const std::string& fmt, const Any& value1, const Any& value2, } +std::string format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7) +{ + std::string result; + format(result, fmt, value1, value2, value3, value4, value5, value6, value7); + return result; +} + + +std::string format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8) +{ + std::string result; + format(result, fmt, value1, value2, value3, value4, value5, value6, value7, value8); + return result; +} + + +std::string format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9) +{ + std::string result; + format(result, fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9); + return result; +} + + +std::string format(const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10) +{ + std::string result; + format(result, fmt, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10); + return result; +} + + void format(std::string& result, const std::string& fmt, const Any& value) { std::vector args; @@ -338,6 +370,68 @@ void format(std::string& result, const std::string& fmt, const Any& value1, cons } +void format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7) +{ + std::vector args; + args.push_back(value1); + args.push_back(value2); + args.push_back(value3); + args.push_back(value4); + args.push_back(value5); + args.push_back(value6); + args.push_back(value7); + format(result, fmt, args); +} + + +void format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8) +{ + std::vector args; + args.push_back(value1); + args.push_back(value2); + args.push_back(value3); + args.push_back(value4); + args.push_back(value5); + args.push_back(value6); + args.push_back(value7); + args.push_back(value8); + format(result, fmt, args); +} + + +void format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9) +{ + std::vector args; + args.push_back(value1); + args.push_back(value2); + args.push_back(value3); + args.push_back(value4); + args.push_back(value5); + args.push_back(value6); + args.push_back(value7); + args.push_back(value8); + args.push_back(value9); + format(result, fmt, args); +} + + +void format(std::string& result, const std::string& fmt, const Any& value1, const Any& value2, const Any& value3, const Any& value4, const Any& value5, const Any& value6, const Any& value7, const Any& value8, const Any& value9, const Any& value10) +{ + std::vector args; + args.push_back(value1); + args.push_back(value2); + args.push_back(value3); + args.push_back(value4); + args.push_back(value5); + args.push_back(value6); + args.push_back(value7); + args.push_back(value8); + args.push_back(value9); + args.push_back(value10); + format(result, fmt, args); +} + + void format(std::string& result, const std::string& fmt, const std::vector& values) { std::string::const_iterator itFmt = fmt.begin(); diff --git a/Foundation/src/NumericString.cpp b/Foundation/src/NumericString.cpp index b2975ce24..1dc666bc0 100644 --- a/Foundation/src/NumericString.cpp +++ b/Foundation/src/NumericString.cpp @@ -93,12 +93,11 @@ void insertThousandSep(std::string& str, char thSep, char decSep = '.') std::string::size_type decPos = str.find(decSep); // there's no rinsert, using forward iterator to go backwards std::string::iterator it = str.end(); - std::string::iterator begin = str.begin(); if (exPos != std::string::npos) it -= str.size() - exPos; if (decPos != std::string::npos) { - while (it != begin) + while (it != str.begin()) { --it; if (*it == decSep) break; @@ -106,7 +105,7 @@ void insertThousandSep(std::string& str, char thSep, char decSep = '.') } int thCount = 0; if (it == str.end()) --it; - for (; it != begin;) + for (; it != str.begin();) { std::string::iterator pos = it; std::string::value_type chr = *it; diff --git a/Foundation/src/PatternFormatter.cpp b/Foundation/src/PatternFormatter.cpp index 29ad388dd..ff216c49c 100644 --- a/Foundation/src/PatternFormatter.cpp +++ b/Foundation/src/PatternFormatter.cpp @@ -34,18 +34,16 @@ const std::string PatternFormatter::PROP_TIMES = "times"; PatternFormatter::PatternFormatter(): - _localTime(false), - _localTimeOffset(Timestamp::resolution()*(Timezone::utcOffset() + Timezone::dst())) + _localTime(false) { } PatternFormatter::PatternFormatter(const std::string& format): _localTime(false), - _localTimeOffset(Timestamp::resolution()*(Timezone::utcOffset() + Timezone::dst())), _pattern(format) { - ParsePattern(); + parsePattern(); } @@ -60,7 +58,8 @@ void PatternFormatter::format(const Message& msg, std::string& text) bool localTime = _localTime; if (localTime) { - timestamp += _localTimeOffset; + timestamp += Timezone::utcOffset()*Timestamp::resolution(); + timestamp += Timezone::dst()*Timestamp::resolution(); } DateTime dateTime = timestamp; for (std::vector::iterator ip = _patternActions.begin(); ip != _patternActions.end(); ++ip) @@ -124,7 +123,8 @@ void PatternFormatter::format(const Message& msg, std::string& text) if (!localTime) { localTime = true; - timestamp += _localTimeOffset; + timestamp += Timezone::utcOffset()*Timestamp::resolution(); + timestamp += Timezone::dst()*Timestamp::resolution(); dateTime = timestamp; } break; @@ -132,7 +132,8 @@ void PatternFormatter::format(const Message& msg, std::string& text) } } -void PatternFormatter::ParsePattern() + +void PatternFormatter::parsePattern() { _patternActions.clear(); std::string::const_iterator it = _pattern.begin(); @@ -196,7 +197,7 @@ void PatternFormatter::setProperty(const std::string& name, const std::string& v if (name == PROP_PATTERN) { _pattern = value; - ParsePattern(); + parsePattern(); } else if (name == PROP_TIMES) { diff --git a/Foundation/src/Process_UNIX.cpp b/Foundation/src/Process_UNIX.cpp index eb58033cf..f496e7b97 100644 --- a/Foundation/src/Process_UNIX.cpp +++ b/Foundation/src/Process_UNIX.cpp @@ -20,6 +20,7 @@ #include "Poco/Pipe.h" #include #include +#include #include #include #include @@ -149,6 +150,20 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command, const ArgsImpl& args, const std::string& initialDirectory, Pipe* inPipe, Pipe* outPipe, Pipe* errPipe, const EnvImpl& env) { + // We must not allocated memory after fork(), + // therefore allocate all required buffers first. + std::vector envChars = getEnvironmentVariablesBuffer(env); + std::vector argv(args.size() + 2); + int i = 0; + argv[i++] = const_cast(command.c_str()); + for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it) + { + argv[i++] = const_cast(it->c_str()); + } + argv[i] = NULL; + + const char* pInitialDirectory = initialDirectory.empty() ? 0 : initialDirectory.c_str(); + int pid = fork(); if (pid < 0) { @@ -156,15 +171,22 @@ ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command, } else if (pid == 0) { - if (!initialDirectory.empty()) + if (pInitialDirectory) { - if (chdir(initialDirectory.c_str()) != 0) + if (chdir(pInitialDirectory) != 0) { _exit(72); } } - setEnvironmentVariables(env); + // set environment variables + char* p = &envChars[0]; + while (*p) + { + putenv(p); + while (*p) ++p; + ++p; + } // setup redirection if (inPipe) @@ -179,15 +201,11 @@ ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command, if (errPipe) errPipe->close(Pipe::CLOSE_BOTH); // close all open file descriptors other than stdin, stdout, stderr for (int i = 3; i < getdtablesize(); ++i) + { close(i); + } - char** argv = new char*[args.size() + 2]; - int i = 0; - argv[i++] = const_cast(command.c_str()); - for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it) - argv[i++] = const_cast(it->c_str()); - argv[i] = NULL; - execvp(command.c_str(), argv); + execvp(argv[0], &argv[0]); _exit(72); } diff --git a/Foundation/src/Thread.cpp b/Foundation/src/Thread.cpp index 2b55fed79..e4a87dad0 100644 --- a/Foundation/src/Thread.cpp +++ b/Foundation/src/Thread.cpp @@ -38,6 +38,57 @@ namespace Poco { +namespace { + +class RunnableHolder: public Runnable +{ +public: + RunnableHolder(Runnable& target): + _target(target) + { + } + + ~RunnableHolder() + { + } + + void run() + { + _target.run(); + } + +private: + Runnable& _target; +}; + + +class CallableHolder: public Runnable +{ +public: + CallableHolder(Thread::Callable callable, void* pData): + _callable(callable), + _pData(pData) + { + } + + ~CallableHolder() + { + } + + void run() + { + _callable(_pData); + } + +private: + Thread::Callable _callable; + void* _pData; +}; + + +} // namespace + + Thread::Thread(): _id(uniqueId()), _name(makeName()), @@ -76,13 +127,13 @@ Thread::Priority Thread::getPriority() const void Thread::start(Runnable& target) { - startImpl(target); + startImpl(new RunnableHolder(target)); } void Thread::start(Callable target, void* pData) { - startImpl(target, pData); + startImpl(new CallableHolder(target, pData)); } diff --git a/Foundation/src/Thread_POSIX.cpp b/Foundation/src/Thread_POSIX.cpp index ae9707769..48af45cd1 100644 --- a/Foundation/src/Thread_POSIX.cpp +++ b/Foundation/src/Thread_POSIX.cpp @@ -104,7 +104,10 @@ void ThreadImpl::setPriorityImpl(int prio) _pData->policy = SCHED_OTHER; if (isRunningImpl()) { - struct sched_param par; + struct sched_param par; struct MyStruct + { + + }; par.sched_priority = mapPrio(_pData->prio, SCHED_OTHER); if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par)) throw SystemException("cannot set thread priority"); @@ -117,7 +120,7 @@ void ThreadImpl::setOSPriorityImpl(int prio, int policy) { if (prio != _pData->osPrio || policy != _pData->policy) { - if (_pData->pRunnableTarget || _pData->pCallbackTarget) + if (_pData->pRunnableTarget) { struct sched_param par; par.sched_priority = prio; @@ -177,7 +180,7 @@ void ThreadImpl::setStackSizeImpl(int size) } -void ThreadImpl::startImpl(Runnable& target) +void ThreadImpl::startImpl(SharedPtr pTarget) { if (_pData->pRunnableTarget) throw SystemException("thread already running"); @@ -194,7 +197,7 @@ void ThreadImpl::startImpl(Runnable& target) } } - _pData->pRunnableTarget = ⌖ + _pData->pRunnableTarget = pTarget; if (pthread_create(&_pData->thread, &attributes, runnableEntry, this)) { _pData->pRunnableTarget = 0; @@ -224,56 +227,6 @@ void ThreadImpl::startImpl(Runnable& target) } -void ThreadImpl::startImpl(Callable target, void* pData) -{ - if (_pData->pCallbackTarget && _pData->pCallbackTarget->callback) - throw SystemException("thread already running"); - - pthread_attr_t attributes; - pthread_attr_init(&attributes); - - if (_pData->stackSize != 0) - { - if (0 != pthread_attr_setstacksize(&attributes, _pData->stackSize)) - throw SystemException("can not set thread stack size"); - } - - if (0 == _pData->pCallbackTarget.get()) - _pData->pCallbackTarget = new CallbackData; - - _pData->pCallbackTarget->callback = target; - _pData->pCallbackTarget->pData = pData; - - if (pthread_create(&_pData->thread, &attributes, callableEntry, this)) - { - _pData->pCallbackTarget->callback = 0; - _pData->pCallbackTarget->pData = 0; - pthread_attr_destroy(&attributes); - throw SystemException("cannot start thread"); - } - _pData->started = true; - pthread_attr_destroy(&attributes); - - if (_pData->policy == SCHED_OTHER) - { - if (_pData->prio != PRIO_NORMAL_IMPL) - { - struct sched_param par; - par.sched_priority = mapPrio(_pData->prio, SCHED_OTHER); - if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par)) - throw SystemException("cannot set thread priority"); - } - } - else - { - struct sched_param par; - par.sched_priority = _pData->osPrio; - if (pthread_setschedparam(_pData->thread, _pData->policy, &par)) - throw SystemException("cannot set thread priority"); - } -} - - void ThreadImpl::joinImpl() { if (!_pData->started) return; @@ -409,48 +362,6 @@ void* ThreadImpl::runnableEntry(void* pThread) } -void* ThreadImpl::callableEntry(void* pThread) -{ - _currentThreadHolder.set(reinterpret_cast(pThread)); - -#if defined(POCO_OS_FAMILY_UNIX) - sigset_t sset; - sigemptyset(&sset); - sigaddset(&sset, SIGQUIT); - sigaddset(&sset, SIGTERM); - sigaddset(&sset, SIGPIPE); - pthread_sigmask(SIG_BLOCK, &sset, 0); -#endif - - ThreadImpl* pThreadImpl = reinterpret_cast(pThread); -#if defined(POCO_POSIX_DEBUGGER_THREAD_NAMES) - setThreadName(pThreadImpl->_pData->thread, reinterpret_cast(pThread)->getName().c_str()); -#endif - AutoPtr pData = pThreadImpl->_pData; - try - { - pData->pCallbackTarget->callback(pData->pCallbackTarget->pData); - } - catch (Exception& exc) - { - ErrorHandler::handle(exc); - } - catch (std::exception& exc) - { - ErrorHandler::handle(exc); - } - catch (...) - { - ErrorHandler::handle(); - } - - pData->pCallbackTarget->callback = 0; - pData->pCallbackTarget->pData = 0; - pData->done.set(); - return 0; -} - - int ThreadImpl::mapPrio(int prio, int policy) { int pmin = getMinOSPriorityImpl(policy); diff --git a/Foundation/src/Thread_WIN32.cpp b/Foundation/src/Thread_WIN32.cpp index 8a6c34f04..0eb2c4c4f 100644 --- a/Foundation/src/Thread_WIN32.cpp +++ b/Foundation/src/Thread_WIN32.cpp @@ -70,7 +70,6 @@ ThreadImpl::CurrentThreadHolder ThreadImpl::_currentThreadHolder; ThreadImpl::ThreadImpl(): - _pRunnableTarget(0), _thread(0), _threadId(0), _prio(PRIO_NORMAL_IMPL), @@ -105,30 +104,16 @@ void ThreadImpl::setOSPriorityImpl(int prio, int /* policy */) } -void ThreadImpl::startImpl(Runnable& target) +void ThreadImpl::startImpl(SharedPtr pTarget) { if (isRunningImpl()) throw SystemException("thread already running"); - _pRunnableTarget = ⌖ - + _pRunnableTarget = pTarget; createImpl(runnableEntry, this); } -void ThreadImpl::startImpl(Callable target, void* pData) -{ - if (isRunningImpl()) - throw SystemException("thread already running"); - - threadCleanup(); - _callbackTarget.callback = target; - _callbackTarget.pData = pData; - - createImpl(callableEntry, this); -} - - void ThreadImpl::createImpl(Entry ent, void* pData) { #if defined(_DLL) @@ -237,35 +222,4 @@ unsigned __stdcall ThreadImpl::runnableEntry(void* pThread) } -#if defined(_DLL) -DWORD WINAPI ThreadImpl::callableEntry(LPVOID pThread) -#else -unsigned __stdcall ThreadImpl::callableEntry(void* pThread) -#endif -{ - _currentThreadHolder.set(reinterpret_cast(pThread)); -#if defined(POCO_WIN32_DEBUGGER_THREAD_NAMES) - setThreadName(-1, reinterpret_cast(pThread)->getName().c_str()); -#endif - try - { - ThreadImpl* pTI = reinterpret_cast(pThread); - pTI->_callbackTarget.callback(pTI->_callbackTarget.pData); - } - catch (Exception& exc) - { - ErrorHandler::handle(exc); - } - catch (std::exception& exc) - { - ErrorHandler::handle(exc); - } - catch (...) - { - ErrorHandler::handle(); - } - return 0; -} - - } // namespace Poco diff --git a/Foundation/src/Timestamp.cpp b/Foundation/src/Timestamp.cpp index a3c8a55f0..7b9237135 100644 --- a/Foundation/src/Timestamp.cpp +++ b/Foundation/src/Timestamp.cpp @@ -18,6 +18,9 @@ #include "Poco/Timespan.h" #include "Poco/Exception.h" #include +#undef min +#undef max +#include #if defined(POCO_OS_FAMILY_UNIX) #include #include @@ -141,6 +144,10 @@ void GetSystemTimeAsFileTimeWithMillisecondResolution(FILETIME* pFT) namespace Poco { +const Timestamp::TimeVal Timestamp::TIMEVAL_MIN = std::numeric_limits::min(); +const Timestamp::TimeVal Timestamp::TIMEVAL_MAX = std::numeric_limits::max(); + + Timestamp::Timestamp() { update(); diff --git a/Foundation/src/URI.cpp b/Foundation/src/URI.cpp index 8e61564f9..f645b6f83 100644 --- a/Foundation/src/URI.cpp +++ b/Foundation/src/URI.cpp @@ -26,7 +26,7 @@ namespace Poco { const std::string URI::RESERVED_PATH = "?#"; -const std::string URI::RESERVED_QUERY = "#/"; +const std::string URI::RESERVED_QUERY = "?#/"; const std::string URI::RESERVED_FRAGMENT = ""; const std::string URI::ILLEGAL = "%<>{}|\\\"^`"; @@ -335,9 +335,9 @@ void URI::addQueryParameter(const std::string& param, const std::string& val) { std::string reserved(RESERVED_QUERY); reserved += "=&"; - if (!_query.empty()) _query.append(1, '&'); + if (!_query.empty()) _query += '&'; encode(param, reserved, _query); - _query.append(1, '='); + _query += '='; encode(val, reserved, _query); } @@ -350,6 +350,56 @@ std::string URI::getQuery() const } +URI::QueryParameters URI::getQueryParameters() const +{ + QueryParameters result; + std::string::const_iterator it(_query.begin()); + std::string::const_iterator end(_query.end()); + while (it != end) + { + std::string name; + std::string value; + while (it != end && *it != '=' && *it != '&') + { + if (*it == '+') + name += ' '; + else + name += *it; + ++it; + } + if (it != end && *it == '=') + { + ++it; + while (it != end && *it != '&') + { + if (*it == '+') + value += ' '; + else + value += *it; + ++it; + } + } + std::string decodedName; + std::string decodedValue; + URI::decode(name, decodedName); + URI::decode(value, decodedValue); + result.push_back(std::make_pair(decodedName, decodedValue)); + if (it != end && *it == '&') ++it; + } + return result; +} + + +void URI::setQueryParameters(const QueryParameters& params) +{ + _query.clear(); + for (QueryParameters::const_iterator it = params.begin(); it != params.end(); ++it) + { + addQueryParameter(it->first, it->second); + } +} + + void URI::setFragment(const std::string& fragment) { _fragment.clear(); diff --git a/Foundation/src/UTF8String.cpp b/Foundation/src/UTF8String.cpp index 8f10d8a0f..b7c6eb877 100644 --- a/Foundation/src/UTF8String.cpp +++ b/Foundation/src/UTF8String.cpp @@ -160,4 +160,16 @@ std::string& UTF8::toLowerInPlace(std::string& str) } +void UTF8::removeBOM(std::string& str) +{ + if (str.size() >= 3 + && static_cast(str[0]) == 0xEF + && static_cast(str[1]) == 0xBB + && static_cast(str[2]) == 0xBF) + { + str.erase(0, 3); + } +} + + } // namespace Poco diff --git a/Foundation/src/Var.cpp b/Foundation/src/Var.cpp index 135ff2648..714560477 100644 --- a/Foundation/src/Var.cpp +++ b/Foundation/src/Var.cpp @@ -401,6 +401,8 @@ Var Var::parse(const std::string& val, std::string::size_type& pos) return parseObject(val, pos); case '[': return parseArray(val, pos); + case '"': + return parseJSONString(val, pos); default: return parseString(val, pos); } @@ -464,41 +466,79 @@ Var Var::parseArray(const std::string& val, std::string::size_type& pos) std::string Var::parseString(const std::string& val, std::string::size_type& pos) { - static const std::string STR_STOP("\""); - static const std::string OTHER_STOP("\n ,]}"); - - bool inString = false; - //skip optional ' " if (val[pos] == '"') { - inString = true; - ++pos; - } - - std::string::size_type stop = std::string::npos; - if (inString) - { - stop = val.find_first_of(STR_STOP, pos); - if (stop == std::string::npos) - throw DataFormatException("Unterminated string"); + return parseJSONString(val, pos); } else { - // we stop at space, ',', ']' or '}' or end of string - stop = val.find_first_of(OTHER_STOP, pos); - if (stop == std::string::npos) - stop = val.size(); - - std::string::size_type safeCheck = val.find_first_of(STR_STOP, pos); - if (safeCheck != std::string::npos && safeCheck < stop) - throw DataFormatException("Misplaced string termination char found"); - + std::string result; + while (pos < val.size() + && !Poco::Ascii::isSpace(val[pos]) + && val[pos] != ',' + && val[pos] != ']' + && val[pos] != '}') + { + result += val[pos++]; + } + return result; } +} - // stop now points to the last char to be not included - std::string result = val.substr(pos, stop - pos); - ++stop; // point past '/" - pos = stop; + +std::string Var::parseJSONString(const std::string& val, std::string::size_type& pos) +{ + poco_assert_dbg (val[pos] == '"'); + ++pos; + std::string result; + bool done = false; + while (pos < val.size() && !done) + { + switch (val[pos]) + { + case '"': + done = true; + ++pos; + break; + case '\\': + if (pos < val.size()) + { + ++pos; + switch (val[pos]) + { + case 'b': + result += '\b'; + break; + case 'f': + result += '\f'; + break; + case 'n': + result += '\n'; + break; + case 'r': + result += '\r'; + break; + case 't': + result += '\t'; + break; + default: + result += val[pos]; + break; + } + break; + } + else + { + result += val[pos]; + } + ++pos; + break; + default: + result += val[pos++]; + break; + } + } + if (!done) throw Poco::DataFormatException("unterminated JSON string"); return result; } diff --git a/Foundation/src/VarHolder.cpp b/Foundation/src/VarHolder.cpp index 6240075d4..8dde3e52e 100644 --- a/Foundation/src/VarHolder.cpp +++ b/Foundation/src/VarHolder.cpp @@ -35,6 +35,43 @@ VarHolder::~VarHolder() namespace Impl { +void escape(std::string& target, const std::string& source) +{ + std::string::const_iterator it(source.begin()); + std::string::const_iterator end(source.end()); + for (; it != end; ++it) + { + switch (*it) + { + case '"': + target += "\\\""; + break; + case '\\': + target += "\\\\"; + break; + case '\b': + target += "\\b"; + break; + case '\f': + target += "\\f"; + break; + case '\n': + target += "\\n"; + break; + case '\r': + target += "\\r"; + break; + case '\t': + target += "\\t"; + break; + default: + target += *it; + break; + } + } +} + + bool isJSONString(const Var& any) { return any.type() == typeid(std::string) || @@ -48,9 +85,9 @@ bool isJSONString(const Var& any) void appendJSONString(std::string& val, const Var& any) { - val.append(1, '"'); - val.append(any.convert()); - val.append(1, '"'); + val += '"'; + escape(val, any.convert()); + val += '"'; } @@ -62,13 +99,21 @@ void appendJSONKey(std::string& val, const Var& any) void appendJSONValue(std::string& val, const Var& any) { - if (any.isEmpty()) val.append("null"); + if (any.isEmpty()) + { + val.append("null"); + } else { bool isStr = isJSONString(any); - if (isStr) val.append(1, '"'); - val.append(any.convert()); - if (isStr) val.append(1, '"'); + if (isStr) + { + appendJSONString(val, any.convert()); + } + else + { + val.append(any.convert()); + } } } diff --git a/Foundation/testsuite/CMakeLists.txt b/Foundation/testsuite/CMakeLists.txt index 7c00313ed..93d3f4197 100644 --- a/Foundation/testsuite/CMakeLists.txt +++ b/Foundation/testsuite/CMakeLists.txt @@ -46,10 +46,12 @@ set_target_properties( TestApp PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTI target_link_libraries( TestApp PocoFoundation ) # TODO: Add TestApp_WINCE +if(NOT POCO_STATIC) # TestLibrary add_library( TestLibrary SHARED src/TestLibrary.cpp src/TestPlugin.cpp src/TestPlugin.h ) set_target_properties( TestLibrary PROPERTIES PREFIX "" DEBUG_POSTFIX "") # The test requires the library named TestLibrary. By default it is prefixed with lib. # The test is run in the runtime directory. So the TestLibrary is built there too because it is used by the tests set_target_properties( TestLibrary PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) target_link_libraries( TestLibrary PocoFoundation ) +endif() diff --git a/Foundation/testsuite/src/DateTimeTest.cpp b/Foundation/testsuite/src/DateTimeTest.cpp index 67f24764d..55146f780 100644 --- a/Foundation/testsuite/src/DateTimeTest.cpp +++ b/Foundation/testsuite/src/DateTimeTest.cpp @@ -18,8 +18,10 @@ #include "Poco/Timespan.h" #include "Poco/Exception.h" + GCC_DIAG_OFF(unused-variable) + using Poco::Timestamp; using Poco::DateTime; using Poco::Timespan; @@ -443,6 +445,28 @@ void DateTimeTest::testArithmetics() loop_1_assert(line, data[di].month2 == X.month()); loop_1_assert(line, data[di].day2 == X.day()); } + + DateTime edgeTime(2014, 9, 16, 0, 0, 0, 0, 10); + edgeTime -= Poco::Timespan(11); + assert (edgeTime.year() == 2014); + assert (edgeTime.month() == 9); + assert (edgeTime.day() == 15); + assert (edgeTime.hour() == 23); + assert (edgeTime.minute() == 59); + assert (edgeTime.second() == 59); + assert (edgeTime.millisecond() == 999); + assert (edgeTime.microsecond() == 999); + + edgeTime.assign(2014, 9, 15, 23, 59, 59, 999, 968); + edgeTime += Poco::Timespan(11); + assert (edgeTime.year() == 2014); + assert (edgeTime.month() == 9); + assert (edgeTime.day() == 15); + assert (edgeTime.hour() == 23); + assert (edgeTime.minute() == 59); + assert (edgeTime.second() == 59); + assert (edgeTime.millisecond() == 999); + assert (edgeTime.microsecond() == 979); } void DateTimeTest::testIncrementDecrement() diff --git a/Foundation/testsuite/src/LoggerTest.cpp b/Foundation/testsuite/src/LoggerTest.cpp index 407110cda..19fe63fa1 100644 --- a/Foundation/testsuite/src/LoggerTest.cpp +++ b/Foundation/testsuite/src/LoggerTest.cpp @@ -199,6 +199,18 @@ void LoggerTest::testFormatAny() root.error("%d%d%d%d%d%d", 1, 2, 3, 4, 5, 6); assert (pChannel->getLastMessage().getText() == "123456"); + + root.error("%d%d%d%d%d%d%d", 1, 2, 3, 4, 5, 6, 7); + assert(pChannel->getLastMessage().getText() == "1234567"); + + root.error("%d%d%d%d%d%d%d%d", 1, 2, 3, 4, 5, 6, 7, 8); + assert(pChannel->getLastMessage().getText() == "12345678"); + + root.error("%d%d%d%d%d%d%d%d%d", 1, 2, 3, 4, 5, 6, 7, 8, 9); + assert(pChannel->getLastMessage().getText() == "123456789"); + + root.error("%d%d%d%d%d%d%d%d%d%d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + assert(pChannel->getLastMessage().getText() == "12345678910"); } diff --git a/Foundation/testsuite/src/ThreadTest.cpp b/Foundation/testsuite/src/ThreadTest.cpp index 1509e6e4b..e9fa73072 100644 --- a/Foundation/testsuite/src/ThreadTest.cpp +++ b/Foundation/testsuite/src/ThreadTest.cpp @@ -363,6 +363,45 @@ void ThreadTest::testThreadFunction() } +struct Functor +{ + void operator () () + { + ++MyRunnable::_staticVar; + } +}; + + +void ThreadTest::testThreadFunctor() +{ + Thread thread; + + assert (!thread.isRunning()); + + MyRunnable::_staticVar = 0; + thread.startFunc(Functor()); + thread.join(); + assert (1 == MyRunnable::_staticVar); + + assert (!thread.isRunning()); + +#if __cplusplus >= 201103L + + Thread thread2; + + assert (!thread2.isRunning()); + + MyRunnable::_staticVar = 0; + thread.startFunc([] () {MyRunnable::_staticVar++;}); + thread.join(); + assert (1 == MyRunnable::_staticVar); + + assert (!thread2.isRunning()); + +#endif +} + + void ThreadTest::testThreadStackSize() { int stackSize = 50000000; @@ -436,6 +475,7 @@ CppUnit::Test* ThreadTest::suite() CppUnit_addTest(pSuite, ThreadTest, testTrySleep); CppUnit_addTest(pSuite, ThreadTest, testThreadTarget); CppUnit_addTest(pSuite, ThreadTest, testThreadFunction); + CppUnit_addTest(pSuite, ThreadTest, testThreadFunctor); CppUnit_addTest(pSuite, ThreadTest, testThreadStackSize); CppUnit_addTest(pSuite, ThreadTest, testSleep); diff --git a/Foundation/testsuite/src/ThreadTest.h b/Foundation/testsuite/src/ThreadTest.h index b984e869c..3e9f50dae 100644 --- a/Foundation/testsuite/src/ThreadTest.h +++ b/Foundation/testsuite/src/ThreadTest.h @@ -37,6 +37,7 @@ public: void testTrySleep(); void testThreadTarget(); void testThreadFunction(); + void testThreadFunctor(); void testThreadStackSize(); void testSleep(); diff --git a/Foundation/testsuite/src/URITest.cpp b/Foundation/testsuite/src/URITest.cpp index 709a60f5c..e7753f7e2 100644 --- a/Foundation/testsuite/src/URITest.cpp +++ b/Foundation/testsuite/src/URITest.cpp @@ -720,6 +720,7 @@ void URITest::testSwap() assert (uri2.toString() == "http://www.appinf.com/search.cgi?keyword=test%20encoded&scope=all#result"); } + void URITest::testOther() { // The search string is "hello%world"; google happens to ignore the '%' @@ -735,6 +736,18 @@ void URITest::testOther() assert(uri.toString() == "http://google.com/search?q=hello%25world#frag%20ment"); assert(uri.getPathEtc() == "/search?q=hello%25world#frag%20ment"); + uri.setQuery("q=foo&bar"); + assert(uri.getQuery() == "q=foo&bar"); + assert(uri.getRawQuery() == "q=foo&bar"); + assert(uri.toString() == "http://google.com/search?q=foo&bar#frag%20ment"); + assert(uri.getPathEtc() == "/search?q=foo&bar#frag%20ment"); + + uri.setQuery("q=foo/bar"); + assert(uri.getQuery() == "q=foo/bar"); + assert(uri.getRawQuery() == "q=foo%2Fbar"); + assert(uri.toString() == "http://google.com/search?q=foo%2Fbar#frag%20ment"); + assert(uri.getPathEtc() == "/search?q=foo%2Fbar#frag%20ment"); + uri.setQuery("q=goodbye cruel world"); assert(uri.getQuery() == "q=goodbye cruel world"); assert(uri.getRawQuery() == "q=goodbye%20cruel%20world"); @@ -753,6 +766,15 @@ void URITest::testOther() uri.addQueryParameter("pa=ra&m2", "val&ue"); assert(uri.getRawQuery() == "q=pony%7eride&pa%3Dra%26m1=&pa%3Dra%26m2=val%26ue"); assert(uri.getQuery() == "q=pony~ride&pa=ra&m1=&pa=ra&m2=val&ue"); + + uri = "http://google.com/search?q=hello+world#frag%20ment"; + assert(uri.getHost() == "google.com"); + assert(uri.getPath() == "/search"); + assert(uri.getQuery() == "q=hello+world"); + assert(uri.getRawQuery() == "q=hello+world"); + assert(uri.getFragment() == "frag ment"); + assert(uri.toString() == "http://google.com/search?q=hello+world#frag%20ment"); + assert(uri.getPathEtc() == "/search?q=hello+world#frag%20ment"); } @@ -792,6 +814,40 @@ void URITest::testFromPath() } +void URITest::testQueryParameters() +{ + Poco::URI uri("http://google.com/search?q=hello+world&client=safari"); + URI::QueryParameters params = uri.getQueryParameters(); + assert (params.size() == 2); + assert (params[0].first == "q"); + assert (params[0].second == "hello world"); + assert (params[1].first == "client"); + assert (params[1].second == "safari"); + + uri.setQueryParameters(params); + assert (uri.toString() == "http://google.com/search?q=hello%20world&client=safari"); + + uri = "http://google.com/search?q=&client&"; + params = uri.getQueryParameters(); + assert (params.size() == 2); + assert (params[0].first == "q"); + assert (params[0].second == ""); + assert (params[1].first == "client"); + assert (params[1].second == ""); + + uri.setQueryParameters(params); + assert (uri.toString() == "http://google.com/search?q=&client="); + + params[0].second = "foo/bar?"; + uri.setQueryParameters(params); + assert (uri.toString() == "http://google.com/search?q=foo%2Fbar%3F&client="); + + params[0].second = "foo&bar"; + uri.setQueryParameters(params); + assert (uri.toString() == "http://google.com/search?q=foo%26bar&client="); +} + + void URITest::setUp() { } @@ -816,6 +872,7 @@ CppUnit::Test* URITest::suite() CppUnit_addTest(pSuite, URITest, testEncodeDecode); CppUnit_addTest(pSuite, URITest, testOther); CppUnit_addTest(pSuite, URITest, testFromPath); + CppUnit_addTest(pSuite, URITest, testQueryParameters); return pSuite; } diff --git a/Foundation/testsuite/src/URITest.h b/Foundation/testsuite/src/URITest.h index a0cbc4784..83416c8f6 100644 --- a/Foundation/testsuite/src/URITest.h +++ b/Foundation/testsuite/src/URITest.h @@ -36,6 +36,7 @@ public: void testEncodeDecode(); void testOther(); void testFromPath(); + void testQueryParameters(); void setUp(); void tearDown(); diff --git a/Foundation/testsuite/src/VarTest.cpp b/Foundation/testsuite/src/VarTest.cpp index 5272494ac..871792b57 100644 --- a/Foundation/testsuite/src/VarTest.cpp +++ b/Foundation/testsuite/src/VarTest.cpp @@ -2089,6 +2089,20 @@ void VarTest::testArrayToString() } +void VarTest::testArrayToStringEscape() +{ + std::string s1("\"quoted string\""); + Poco::Int8 s2(23); + std::vector s16; + s16.push_back(s1); + s16.push_back(s2); + Var a1(s16); + std::string res = a1.convert(); + std::string expected("[ \"\\\"quoted string\\\"\", 23 ]"); + assert (res == expected); +} + + void VarTest::testStructToString() { DynamicStruct aStruct; @@ -2103,6 +2117,18 @@ void VarTest::testStructToString() } +void VarTest::testStructToStringEscape() +{ + DynamicStruct aStruct; + aStruct["Value"] = "Value with \" and \n"; + Var a1(aStruct); + std::string res = a1.convert(); + std::string expected = "{ \"Value\" : \"Value with \\\" and \\n\" }"; + assert (res == expected); + assert (aStruct.toString() == res); +} + + void VarTest::testArrayOfStructsToString() { std::vector s16; @@ -2592,7 +2618,9 @@ CppUnit::Test* VarTest::suite() CppUnit_addTest(pSuite, VarTest, testDynamicStructString); CppUnit_addTest(pSuite, VarTest, testDynamicStructInt); CppUnit_addTest(pSuite, VarTest, testArrayToString); + CppUnit_addTest(pSuite, VarTest, testArrayToStringEscape); CppUnit_addTest(pSuite, VarTest, testStructToString); + CppUnit_addTest(pSuite, VarTest, testStructToStringEscape); CppUnit_addTest(pSuite, VarTest, testArrayOfStructsToString); CppUnit_addTest(pSuite, VarTest, testStructWithArraysToString); CppUnit_addTest(pSuite, VarTest, testJSONDeserializeString); diff --git a/Foundation/testsuite/src/VarTest.h b/Foundation/testsuite/src/VarTest.h index b985c2af1..7e27108da 100644 --- a/Foundation/testsuite/src/VarTest.h +++ b/Foundation/testsuite/src/VarTest.h @@ -59,7 +59,9 @@ public: void testDynamicStructString(); void testDynamicStructInt(); void testArrayToString(); + void testArrayToStringEscape(); void testStructToString(); + void testStructToStringEscape(); void testArrayOfStructsToString(); void testStructWithArraysToString(); void testJSONDeserializeString(); diff --git a/JSON/CMakeLists.txt b/JSON/CMakeLists.txt index 27488fd9d..7e314a0cc 100644 --- a/JSON/CMakeLists.txt +++ b/JSON/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoJSON") +set(LIBNAME "JSON") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -8,26 +9,40 @@ POCO_SOURCES_AUTO( SRCS ${SRCS_G}) file(GLOB_RECURSE HDRS_G "include/*.h" ) POCO_HEADERS_AUTO( SRCS ${HDRS_G}) -add_library( ${LIBNAME} ${LIB_MODE} ${SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" PROPERTIES VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL JSON_EXPORTS) -target_link_libraries( ${LIBNAME} PocoFoundation) + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL JSON_EXPORTS + ) + +target_link_libraries( "${LIBNAME}" Foundation) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + if (ENABLE_TESTS) add_subdirectory(samples) add_subdirectory(testsuite) diff --git a/JSON/cmake/PocoJSONConfig.cmake b/JSON/cmake/PocoJSONConfig.cmake new file mode 100644 index 000000000..294208f4f --- /dev/null +++ b/JSON/cmake/PocoJSONConfig.cmake @@ -0,0 +1,4 @@ +include(CMakeFindDependencyMacro) +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}) +find_dependency(PocoFoundation) +include("${CMAKE_CURRENT_LIST_DIR}/PocoJSONTargets.cmake") \ No newline at end of file diff --git a/MongoDB/CMakeLists.txt b/MongoDB/CMakeLists.txt index e12a709de..03e1fbcb9 100644 --- a/MongoDB/CMakeLists.txt +++ b/MongoDB/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoMongoDB") +set(LIBNAME "MongoDB") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -8,26 +9,39 @@ POCO_SOURCES_AUTO( SRCS ${SRCS_G}) file(GLOB_RECURSE HDRS_G "include/*.h" ) POCO_HEADERS_AUTO( SRCS ${HDRS_G}) -add_library( ${LIBNAME} ${LIB_MODE} ${SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" PROPERTIES VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL MongoDB_EXPORTS) -target_link_libraries( ${LIBNAME} PocoNet PocoFoundation) + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL MongoDB_EXPORTS + ) +target_link_libraries( "${LIBNAME}" Net Foundation) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + if (ENABLE_TESTS) add_subdirectory(samples) add_subdirectory(testsuite) diff --git a/MongoDB/cmake/PocoMongoDBConfig.cmake b/MongoDB/cmake/PocoMongoDBConfig.cmake new file mode 100644 index 000000000..18e1bf7fb --- /dev/null +++ b/MongoDB/cmake/PocoMongoDBConfig.cmake @@ -0,0 +1,5 @@ +include(CMakeFindDependencyMacro) +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}) +find_dependency(PocoFoundation) +find_dependency(PocoNet) +include("${CMAKE_CURRENT_LIST_DIR}/PocoMongoDBTargets.cmake") \ No newline at end of file diff --git a/Net/CMakeLists.txt b/Net/CMakeLists.txt index bd734dfd9..3a3969dc1 100644 --- a/Net/CMakeLists.txt +++ b/Net/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoNet") +set(LIBNAME "Net") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -8,31 +9,48 @@ POCO_SOURCES_AUTO( SRCS ${SRCS_G}) file(GLOB_RECURSE HDRS_G "include/*.h" ) POCO_HEADERS_AUTO( SRCS ${HDRS_G}) -#TODO: Can WIN32 be used here? -if(CMAKE_SYSTEM MATCHES "Windows") - set(SYSLIBS ${SYSLIBS} "ws2_32.lib" "iphlpapi.lib") -endif(CMAKE_SYSTEM MATCHES "Windows") +# Windows and WindowsCE need additional libraries +if(WIN32) + if(WINCE) + set(SYSLIBS ${SYSLIBS} "ws2.lib" "iphlpapi.lib") + else() + set(SYSLIBS ${SYSLIBS} "ws2_32.lib" "iphlpapi.lib") + endif() +endif(WIN32) -add_library( ${LIBNAME} ${LIB_MODE} ${SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" PROPERTIES VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL Net_EXPORTS) -target_link_libraries( ${LIBNAME} PocoFoundation ${SYSLIBS}) + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL Net_EXPORTS + ) +target_link_libraries( "${LIBNAME}" Foundation ${SYSLIBS}) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + if (ENABLE_TESTS) add_subdirectory(samples) add_subdirectory(testsuite) diff --git a/Net/Makefile b/Net/Makefile index 3068e8ec6..52275f6ac 100644 --- a/Net/Makefile +++ b/Net/Makefile @@ -32,7 +32,8 @@ objects = \ ICMPSocket ICMPSocketImpl ICMPv4PacketImpl \ NTPClient NTPEventArgs NTPPacket \ RemoteSyslogChannel RemoteSyslogListener SMTPChannel \ - WebSocket WebSocketImpl + WebSocket WebSocketImpl \ + OAuth10Credentials OAuth20Credentials target = PocoNet target_version = $(LIBVERSION) diff --git a/Net/Net_CE_vs90.vcproj b/Net/Net_CE_vs90.vcproj index e3180ad4b..7ec895f25 100644 --- a/Net/Net_CE_vs90.vcproj +++ b/Net/Net_CE_vs90.vcproj @@ -819,10 +819,12 @@ Name="Reactor"> - + + - @@ -969,6 +969,23 @@ RelativePath=".\src\WebSocketImpl.cpp"/> + + + + + + + + + + - + + - @@ -362,6 +362,8 @@ + + @@ -461,6 +463,8 @@ + + diff --git a/Net/Net_WEC2013_vs110.vcxproj.filters b/Net/Net_WEC2013_vs110.vcxproj.filters index 17b92d61c..2b18c5f57 100644 --- a/Net/Net_WEC2013_vs110.vcxproj.filters +++ b/Net/Net_WEC2013_vs110.vcxproj.filters @@ -2,139 +2,148 @@ - {c5903a6c-8e48-4644-9f2c-d424d8e165cc} + {cd987b2e-01c7-43fa-8744-d9de3c93857f} - {8200782f-111b-415f-94fc-3d3b4304a80b} + {5b2a7574-6bec-485e-ad27-3dcd16fdf94f} - {feb34fc5-8d83-4f9a-ab52-081e99ec8960} + {825980e9-05c0-4a95-9bce-f8ff6c306f8d} - {d862efd8-2dd5-48a9-9c45-ff0cd439ec40} + {b15de1cb-66c0-4add-bb5d-57cb58bed565} - {a244fc56-e260-470e-b2a4-cab7da3c0808} + {27b3010f-fd83-473f-9954-5842f2faea9f} - {dd12a8f7-f4b9-4733-81ea-8f0bdb59b44d} + {943df401-b8cb-4330-8ce4-886e34692d43} - {8153fb51-c507-46bf-8dae-8f3ef42eb35d} + {18ba3f64-3fe7-4bc3-8655-304d682f035e} - {252a929e-1da1-49ae-b2d5-4713b6c03632} + {2b86e007-4a0b-4f8a-abc6-3ef3a01f53c2} - {77ba251d-ce7d-42c3-9b40-149fef4a837d} + {a0a73fa5-efd0-400c-8934-8588cd5b4597} - {f9c5703d-3cb6-401a-839a-f7ac6b83360a} + {9b4f898b-08b4-4d0e-997c-245ed25ffd32} - {739c28cb-20bc-423c-86fc-20eaa859cdf6} + {3a447457-4238-423b-a43f-b2dc922057e8} - {b63a2dfb-ae99-487a-8362-e4880b0555c5} + {5d8e4197-9dae-4103-a28f-ff176fad4310} - {81df8653-4e2d-4bc2-a6ec-8daedb0ab17e} + {2873cdb3-36b8-4485-a500-340d56958f05} - {3705a943-1838-4a44-b5b0-b9abac417b4e} + {1b17bd07-bee6-4e03-bf62-28329a29b4a8} - {90a9f28f-355d-4cef-84de-64437ae18375} + {211c4e65-5421-4ec8-8564-1dfb9352d808} - {bb9531b4-6901-4f7d-9609-8f01214d7545} + {8fa8027e-6c8c-4e2b-85ee-e4fda6a62c0d} - {eb561a4c-c14f-444b-bec2-99e770a501e5} + {5b5fe4f8-9137-4ea9-a9b1-760c7b64c1e6} - {30eb8b20-cb65-497d-8357-2e1abdf7b5ee} + {147d14f1-6f5e-4f8b-896c-5ad4142d92f0} - {5f77dbeb-f7b8-4d26-8a19-0d9107073151} + {518f793d-3213-4b88-a5a3-926d92f4d76e} - {fbe689c4-5443-48f6-ad57-afe26ee4e979} + {a75d596e-f78a-4001-b0e2-9a3df90a7485} - {eaf9cbbe-8ebd-45eb-af83-af4c12e26b36} + {4bdc2ab8-5afe-4a54-b083-6d0904b103e9} - {e9cdd43a-dd7d-4682-967d-3c89bd7118b5} + {041a7d67-6f17-4859-b292-d82effcc25e4} - {a42a1546-112b-42f4-9401-8b21ad52a5e8} + {3c29b9fa-93fd-4f97-8e10-a3a417c3c907} - {b22b2350-f3a2-4c3c-9085-1f66161a80e0} + {9ce0e2a7-e5e9-4b58-81b9-edaa19befd08} - {706db337-7dad-4e3a-890d-620f862d7471} + {136bfe67-2cd8-489e-a92a-2387f49ececa} - {a31923e9-825e-4c5b-8455-5a3c4c960b70} + {1440669f-dd9b-4157-83de-d1f3f8d4fcaa} - {63a06007-e121-4ea5-9b40-9126d59a760a} + {c6cb991d-2f5d-44af-be01-61a7c113f68a} - {15d62f8e-e448-499b-8584-2ae19cbe2c39} + {fdf1e06a-25de-43c3-962a-77e405cd0798} - {383b014d-dbbe-482e-b278-f56a1eb46c1f} + {54ca0dbd-ac2e-4947-8c53-14504808d98f} - {d10bfa1b-d858-496a-a1dd-059aca60a960} + {c5a05a94-73ed-4501-9fea-2da0e1ca0ef5} - {915639e2-b424-41f0-8853-b15861068a9b} + {e98abe3f-311c-4ec7-a451-f854c78f4cd8} - {840ae175-7d75-4bdc-9760-2c8b136f899e} + {1398eddd-8d1e-415d-91f4-7645111e166c} - {954b0030-4236-4a1a-ad62-a535c8a8974f} + {673be950-eb56-448b-b446-a834e60bd9bc} - {4a07c293-5039-4180-98c3-3b95ce34e410} + {a554392b-0a40-442b-abdb-bed6a75f61d7} - {2b29289f-c77b-41f0-a8bd-955a3cf2a5e4} + {70ede3d9-2737-4af7-8a19-b73f8b5ca13a} - {efe0118e-f8ea-4e7f-8f93-d5176eb34fe0} + {cd3146fb-c327-4bdc-a609-f6e35e2d985c} - {bde6d18e-3aec-44b8-a7ef-e08ba7bac1e8} + {8ba593ed-955c-4247-8b9d-42320ef070a7} - {091ff77c-d66c-42b8-a013-40952350e53c} + {6830107a-14b1-4ce3-b0d5-dc02d59fcb33} - {23c79763-9906-4d0e-8898-e1cf2e694f69} + {4a48fefa-5501-4cfa-ac26-d0e3eceb407f} - {796e3d54-f706-4cfd-8485-9c1e5aa182c7} + {24e5bae1-09f6-4607-804f-4a7ed9a53f6d} - {a570f081-73e3-4cd5-9ec3-c929b90f31ce} + {d00119ab-ebea-45b7-8b2c-8a44cc61dde9} - {e1afe942-3011-4416-b045-7098c4f09126} + {9a5d5c26-e1da-4c31-ade8-ba60e6d7a1a1} - {3b5725f7-7429-4668-986c-bfd1cfd55156} + {a8e1b860-a078-42a8-a66e-e732c93de8c3} - {e62071a7-a945-44f9-bc78-518e97639f0e} + {aade08d9-3b9a-45b5-976a-d8b3cbfc9ada} - {bf26761c-3072-4c06-9b6c-10133ffa34cb} + {57904ed1-f383-44ae-8e96-47c034a67c3c} + + + {be877161-009f-4cd3-9cf3-5f382de51152} + + + {ae504077-de48-41c7-a821-cb1efaed05de} + + + {60bb69a9-bdd2-490c-8450-8bb777e665a6} @@ -366,10 +375,13 @@ FTPClient\Header Files - + Reactor\Header Files - + + Reactor\Header Files + + Reactor\Header Files @@ -384,9 +396,6 @@ Reactor\Header Files - - Reactor\Header Files - Mail\Header Files @@ -447,6 +456,12 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + @@ -740,6 +755,12 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + diff --git a/Net/Net_WEC2013_vs120.vcxproj b/Net/Net_WEC2013_vs120.vcxproj index 4f14005ef..c33e487b6 100644 --- a/Net/Net_WEC2013_vs120.vcxproj +++ b/Net/Net_WEC2013_vs120.vcxproj @@ -325,6 +325,8 @@ + + @@ -429,6 +431,8 @@ + + diff --git a/Net/Net_WEC2013_vs120.vcxproj.filters b/Net/Net_WEC2013_vs120.vcxproj.filters index 1748e159c..a55e4f60d 100644 --- a/Net/Net_WEC2013_vs120.vcxproj.filters +++ b/Net/Net_WEC2013_vs120.vcxproj.filters @@ -2,139 +2,148 @@ - {1bd8f372-4a06-4215-b913-d7b3c22b886e} + {d773e47d-ad7c-4e3e-aaea-2bc7425f59e6} - {10c5b3f9-e0da-4e57-81b3-8f65c56ad594} + {efa75fa1-02c1-4b8c-b398-808a3043329b} - {7486bc28-20a7-48a6-8de0-cfc881229e82} + {6f5a2fe8-4246-4b63-aaad-7bb4d1ec1829} - {0489e47a-4820-4a1f-9c39-71ee4f7cd308} + {6da1e452-09c0-442c-973c-18f86b7597af} - {745ae453-9273-4eb0-8c76-ef84a122308f} + {422b8206-bd5c-4fb7-8022-7f5b90a4a022} - {f7843494-4608-4d75-86c1-9d436e26df29} + {000b601f-76a6-4612-b669-c10e044b8f5f} - {83119330-c2fe-4051-b894-206c0dbd1609} + {ac01ac79-711b-4025-9447-ef5a7379c28c} - {418ef227-6d88-4bb1-bca5-84446baa8118} + {6cfa10b5-c70a-47ff-850f-b833c7687007} - {bcd55f4a-3efb-41e8-b614-fa7d2240f1a2} + {c63851c1-2f3e-4ed7-a61f-e09d5f8085f4} - {4e6d5b73-57a0-4306-9b99-cc5c4e6096db} + {22c287fc-b927-48bc-bba2-fe01cbc975f3} - {1320ffd7-f156-48ce-b720-f60c7f46d726} + {6551bf58-8858-4460-8e17-7c1ec190a43b} - {0100127a-2734-4485-983d-2301e64bd562} + {a3c0ac5c-05fc-465b-aba7-ce2731c6ceec} - {cef17310-bcee-4d27-9d5a-4b1b067aac43} + {21ff19f3-28a9-4fee-8d5c-d6cbdcdeb9af} - {ead9324b-e69f-47c0-a7cd-836dcbe5f127} + {037bba1e-9c73-4b39-b505-43628c5fdb04} - {820160f8-6e19-491e-a55b-bd5d9ff71c60} + {53bc79cb-24b9-435e-b51b-fa4989864b0a} - {0f530a09-6c04-4b46-8015-d016b5e98fe0} + {c342ef19-e362-446b-b128-dee22e07d489} - {bded0c21-897b-42ba-8575-2d567933eccb} + {c3ebbba2-3a98-4e1e-9cab-52db7ff0c395} - {2ebcc81f-0b0e-4388-939c-6abcc707bc0d} + {e0419e19-23cf-4482-acdb-9a7bafade67d} - {1dbbacde-8628-4a0f-a838-59d873d9133a} + {a388af05-9249-4183-9d3b-a2d7d0599054} - {27c236f4-edb0-4024-82eb-327a52d7670b} + {30d793c9-beed-485a-bef5-c00f62ef06d2} - {e11a6b88-fb75-4483-8080-299a5c66deed} + {c527296e-f8cd-499f-ba38-13c9e8a18c77} - {87810ce2-7362-4686-a125-3607f2c75f0e} + {50a91170-731f-41f4-badb-b4a6a42d8a43} - {84b99672-ee76-4e02-b925-290659e38fdb} + {096e16f3-9b9e-42fa-9e88-f4eed49090e9} - {81c35217-67c7-48c4-a5fa-42c8bf4de16b} + {73d1451a-8af5-45f8-82b1-4b2b9f07fdcb} - {61e05400-d7ba-4f4c-aac7-59efa7acd541} + {d95bbc6e-ad06-40c8-a708-6f65207943cc} - {3e0d064b-141c-424c-a167-10641ce48860} + {02cc7095-77a8-4022-920b-67d705fb46f0} - {10be7076-2962-405e-ad29-412633063655} + {3bff4846-9cd4-413d-801a-e2a7acdbeec3} - {5c405085-17e4-4cf0-b7df-9d46c5a29954} + {1b14132c-51f7-455f-8bb7-141d75c14588} - {85942ad9-a45c-4a23-a54a-b0603ed5c40b} + {5fef30ac-0aca-4bf3-babb-f691134092a3} - {ca98bbc6-24f3-4c02-99c5-f008c5662b2f} + {7085357c-73fc-4970-b470-6366f97f1f9c} - {4e2cf42e-bca1-4216-b718-e6e9211487e6} + {f57d1e54-e56a-43e3-9807-1fd50a74a541} - {f1446fea-99da-4760-ac5d-4ae62f3e42dc} + {ef39724b-b805-4470-8194-3eb0e43dacfa} - {2b430714-9761-4d20-9e70-45569377a10d} + {38091277-72a9-4480-a418-fe579e713814} - {df7dca54-0c19-45ce-89c8-12ba9afd7e5c} + {a6a7dbec-c686-4d31-b2d0-d84c8c66c108} - {72100236-f75d-4bb0-bbe5-2de2269d0819} + {477c05ac-0c2e-4cef-9906-e515b4f1e026} - {eaf72227-78ac-4435-88e6-d59722ae71b1} + {8abe2107-8d91-43fd-9b7c-f045e76e3839} - {5ba657ed-3e9b-434a-808a-a9f9e039b430} + {197d678e-2f31-4f9f-92d7-0f07a52e6c67} - {994f69bd-37f2-4bd7-b0dd-17ad994cf08f} + {af32e278-f3dd-4aa1-a2ee-defa709c8e69} - {7d368f1c-74c9-467b-80b0-128cd5f66f76} + {0234eb6e-2d72-4cde-ad85-e573207dc1a3} - {8e87c63e-9e10-4c09-a34a-44a9c630de83} + {cfad3c96-912f-4257-bcc5-56e4db3aa17e} - {b3d5faf2-95ec-4b26-a5af-4cbf560e49e9} + {a1007f06-0b6a-4d4b-ae49-5ca579de2f09} - {391a67c5-9b1b-402c-ab56-7a56bc035987} + {4bfd361c-840e-44ad-9710-e328ba148f9e} - {de335503-a61f-48c3-980c-a70541e94b2f} + {23e5f814-1af6-4af8-bfb7-18a4e5bfc9e4} - {efeb9d69-a7ed-4631-806e-a2c4a30fe4b2} + {5ec57e22-0d90-489b-a512-e4b4be22b6b1} - {d1c02a2a-2799-4726-880e-7c548ca4c575} + {60584647-da84-4b50-a694-bcef255858eb} + + + {248806ca-b7e7-447a-98ed-1ca3d243426a} + + + {1f13413b-759e-499f-b833-b5c6bcb55765} + + + {3f2d79c9-070e-4599-a674-739f82f9fbfd} @@ -366,10 +375,13 @@ FTPClient\Header Files - + Reactor\Header Files - + + Reactor\Header Files + + Reactor\Header Files @@ -384,9 +396,6 @@ Reactor\Header Files - - Reactor\Header Files - Mail\Header Files @@ -447,6 +456,12 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + @@ -740,6 +755,12 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + diff --git a/Net/Net_vs100.vcxproj b/Net/Net_vs100.vcxproj index 6f0d53fa0..fc4ed4d28 100644 --- a/Net/Net_vs100.vcxproj +++ b/Net/Net_vs100.vcxproj @@ -351,13 +351,13 @@ - + + - @@ -378,6 +378,8 @@ + + @@ -477,6 +479,8 @@ + + diff --git a/Net/Net_vs100.vcxproj.filters b/Net/Net_vs100.vcxproj.filters index 8ea917c5a..58f98dfff 100644 --- a/Net/Net_vs100.vcxproj.filters +++ b/Net/Net_vs100.vcxproj.filters @@ -2,139 +2,148 @@ - {868afd7b-9ddc-4099-b7d2-9422051a121d} + {8992cc5d-dce8-4cbd-9f79-d83fcacbceff} - {78b3c0fc-d752-48f5-a83a-c476145d29cb} + {ef0bc40b-4dea-4d70-baf2-411c917a2a04} - {f376f6e5-5c36-407f-8a1e-ee199e006221} + {972a588d-e448-43e1-977b-2d63e3aed8a5} - {4166578b-0db6-4181-97dd-7928827643d8} + {807bfc62-24fe-472d-89b1-0e4c2001d03a} - {b11b34d9-48fb-4635-976c-7b1e2f601e5a} + {4bb17e12-2ce2-4949-b304-6eb8af2d6289} - {8e596142-b445-4a03-b2a0-636629fa7b3c} + {33353466-e67b-44ff-85ca-5de84aede57c} - {690b97b4-9a6d-4abc-bd10-36dcc425095e} + {83cd1254-3b0c-4ed8-a35d-a1f121268c6b} - {8958f03a-b070-41fc-9923-3bc00af399d4} + {d9a30f35-503d-42ab-8682-89ad8d72d681} - {64e16e38-054f-49d0-9321-3489c6ca977a} + {c218d8e8-f8fa-42d7-87e9-06795ba738dc} - {247797c4-8afb-4499-84b1-1dd8437cacb1} + {361cfb55-d05a-468f-a94a-7a51ded1e1f0} - {ed02b09b-30ad-4eea-bb95-b8e753f91623} + {52e86aa3-1941-4e71-9678-04dfec6655d1} - {7f152f99-9399-4b1d-a80f-39df188952b0} + {307e34da-d304-456e-beaf-1f892ba64f8c} - {a9f3be6e-2ee0-4e5e-9d76-cbf6ab7ff7e7} + {5b66a17e-614b-4d1f-928d-72786f663402} - {2fe8f637-1419-4d6b-842a-307b45ab73f1} + {0a9e0188-c6a0-4c89-8042-d013eb9c5582} - {e5a62fdb-becc-4c39-aaaa-106e79ab5e5a} + {0783991c-f479-4684-af60-39de190a4691} - {a5048a86-ad4a-452e-9409-c1de45c6272e} + {7d4e934f-eb6d-4da3-907e-5d191756da92} - {ce27c701-96b3-48ea-9ce4-41a03ac25477} + {cd2fcefe-9696-475b-ab37-4c08b6e47299} - {3898a8a4-5ee7-4b34-a0e3-7f1d62aa0bf4} + {e14cc478-986c-4cf1-b016-f759f59a4df8} - {448680fc-cbe0-463c-bcef-67061553b960} + {fddc7781-3120-4b2e-bd72-24fab8eb2876} - {ff8d7576-47da-4843-a614-074b69cbdc81} + {3bf05b5b-843d-4a24-bc81-ee0ab271abc6} - {bbc32086-7f39-4a2a-b3c9-fd54ad5739ac} + {0df32b72-7869-427c-be84-7d93fd01d2f9} - {136d29f6-2556-4333-bd33-c33c5493c2ec} + {fc5a3893-7a92-4c7f-aa18-0deff8fb7ec3} - {b4c5f603-37ba-46f5-b135-20c9b9485acf} + {725a3534-81c8-4692-93fa-d19dcf94df05} - {fddcdb59-5692-4401-8711-a1f5aaed0eed} + {e60b3912-17e3-4da8-a18c-28bafb03bf29} - {9ff78a10-c12f-494f-ba04-e36e038f2f5a} + {d2bdc7f6-562f-421a-979e-017c1477f2b4} - {1330f6ba-4ae2-4e43-baef-a7503d518730} + {58d9e32b-6474-436f-90b9-0e03a72b52c7} - {b95728ac-29e2-48b7-b291-3f8127ec18b1} + {1700f029-1e81-4577-8ad4-e23c88db3407} - {da5918ef-f976-4f88-8fd9-ee788c14385d} + {dcdfdb7a-f57c-4cb5-a472-2159b221f3fa} - {0fbcfaec-bcc2-4074-b6e5-5c21d88ac55b} + {3966019b-9d88-4e47-aa4b-a9764c36b158} - {7c1d8e92-8c42-41e2-9709-4025acbba345} + {da8b4987-f460-4766-b89b-51b7397e856a} - {705b2179-605d-431d-8e05-2a44ad4ebc18} + {90149743-2979-4a92-a410-e7775624aece} - {600d7055-3dfc-4734-8220-64fc8010ac05} + {36354d0b-458f-4014-a56b-108d266f6127} - {cffa8a67-e06e-4071-a594-20240fc8f7d2} + {c904ae66-5ce7-4384-9a92-deb8c947fb32} - {b771108e-60ef-4320-88b1-bf4f7c521245} + {6aa80d93-797b-4ada-a0b0-e90c4a2e8cb0} - {670c47c7-dca3-498d-9f66-016fd8944a44} + {f9ad26ae-23e1-4479-a1a9-2db396440980} - {a34fbe55-2594-4c26-b717-84e062fed982} + {12c80174-c81f-4242-879a-984805cdc37f} - {d4bfa61b-e7d9-4101-8c33-6bbfe0f1518c} + {514d9218-2747-4a62-ae56-ba9e790a97a8} - {8caa48b2-fa82-4a2f-b8d6-febe1e8caca5} + {a1ab3ec6-6365-42c1-af1f-e59b49a254de} - {9682b5f6-9208-4678-b3d5-a0a3064aa7a8} + {70c708ce-dab0-47a9-8f46-bb65c1b1107b} - {35ac4b7f-89ac-4e41-88f2-da0d28ccb386} + {a3911999-71b8-4ece-8acc-8b30308c52da} - {a7875e68-cd65-4cd9-a5dd-6dcd7ad65329} + {539e0da2-26b1-4758-b63e-476076a75cf2} - {18077d14-f8e6-4d73-a9d8-85be79311339} + {bb000f13-92eb-44b9-ae49-25da40be51f7} - {e21a67b9-af67-4586-91e6-4ec7cf89a331} + {54061de0-20ef-4ece-954f-dc72228fa3b7} - {a6ae8f68-e668-4e2f-9ef0-621a6d08c3b1} + {c047f946-6d85-4d95-9067-c16e842224d8} - {0787ec62-4f72-4cee-bc0c-9d9ead93915d} + {ef6a40c2-9208-43ab-987a-18a3794723af} + + + {6b7dfa9b-da58-456b-a01e-29dc2eb48247} + + + {af21120c-95b2-44a1-939b-e69e55b1ab5f} + + + {4841abc5-52fe-4c7d-9f47-ed3080b09345} @@ -366,10 +375,13 @@ FTPClient\Header Files - + Reactor\Header Files - + + Reactor\Header Files + + Reactor\Header Files @@ -384,9 +396,6 @@ Reactor\Header Files - - Reactor\Header Files - Mail\Header Files @@ -447,6 +456,12 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + @@ -740,6 +755,12 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + diff --git a/Net/Net_vs110.vcxproj b/Net/Net_vs110.vcxproj index ac8a4214d..42e42aa63 100644 --- a/Net/Net_vs110.vcxproj +++ b/Net/Net_vs110.vcxproj @@ -355,13 +355,13 @@ - + + - @@ -382,6 +382,8 @@ + + @@ -481,6 +483,8 @@ + + diff --git a/Net/Net_vs110.vcxproj.filters b/Net/Net_vs110.vcxproj.filters index 738135cbf..084bf6994 100644 --- a/Net/Net_vs110.vcxproj.filters +++ b/Net/Net_vs110.vcxproj.filters @@ -2,139 +2,148 @@ - {a3af4ef1-6f1f-4019-ad03-cf603baab7be} + {8a56f4f5-7d02-4904-9712-5548455e9dfa} - {1ff07142-2c75-4bc0-908c-7727b56857c0} + {a212859d-7da7-4e05-b0d8-90752be3f94f} - {75142fb5-987b-4a1e-970f-44f8418cd327} + {f7047606-5c9f-4b44-a656-07785c3cab63} - {9185cc10-b1f3-4afd-a30a-ee2e33dd994e} + {44541ffc-d111-454b-b6b0-5ffb28ba233d} - {68a3746d-7c99-46e3-8fcc-7febcd8ef76d} + {6ee8ec1d-3abb-41cd-a755-7494f055aeec} - {3e131394-38a4-4ab3-9f82-917e1e898dd7} + {a77dd5c2-1fdc-4c90-9e96-73875b9810c1} - {c0c86510-f1d6-47d4-88f3-63b69421df47} + {99095bb0-c212-4c24-a77c-7fc23b6112a5} - {a05a6147-f3e2-4bab-843d-0546b67bc609} + {c43242da-2e59-44cb-880c-504e99169cbe} - {b341409b-1308-4718-8aef-0c6608e490d7} + {cd09ad44-257e-4ad6-acbe-de6936ddb8aa} - {e852c0fb-8235-4c78-b8f6-6262cbb7eeaa} + {7fdf4262-ac26-4ce8-9162-2be7e9e559c3} - {454e3956-e034-4ed7-91fa-550fbe58f498} + {d0aa83cd-9afa-48b1-b588-4080124f7b49} - {e75fee2e-d917-41fb-81b1-f5e6bcee24aa} + {dee1d1c1-4446-42ee-b40d-091d2a1b0398} - {b56bf35d-6b29-4cdb-8dd0-942cc3280473} + {02b6dd6b-1094-4af4-a00c-20f11729253e} - {0c6f8de2-2013-4d9c-addd-ce6deb21a621} + {275e0474-f651-4aa3-b7c2-a90869abb744} - {3ab705c9-5cb2-452a-a125-dba390cdb8c2} + {ef2687d6-a517-44f3-bee7-e97cc9aa24b1} - {23c39bf2-b3cc-45a0-a0cf-7942fa542a11} + {59871822-507d-43dc-ac9b-8dfe76fb577f} - {573e3c60-e30b-4d30-af54-1f400ed01c6e} + {1dbd0702-ceec-4f57-a287-6ca430dca434} - {24346e33-f2d8-42d8-949b-8d1711e34991} + {cb79e883-2c74-4c9a-a2d7-c7c7caf2a59c} - {9cb400c4-43da-4a01-a032-e91e9bc0977b} + {32644429-fd5a-4233-a5df-d410a0561a2c} - {4823497f-32f7-41f8-a498-994684ea66e2} + {2b7f1983-009e-4870-aaab-54b3595b4494} - {072b1028-3a4a-4fb3-9186-708558a8bec9} + {5bf9b6ae-cbe1-4ac8-8fb2-7ade2e83a699} - {49f5cca8-1352-4e05-8fad-54a36924e4e3} + {66805cbf-afc5-4987-9202-c6629619a5d3} - {de2e3f31-772d-4cb7-b169-570f3a14660e} + {661eb990-2478-4b0c-8693-146e05e7ebee} - {42f5d684-ab7f-4aee-b5c1-7dea079afceb} + {2e74c8de-34fe-4aef-b988-e9d3574f221d} - {af8d3698-7ef7-463a-84a8-dcde9f4d7c7b} + {591083d4-f9e1-4c97-b412-305ce97073d3} - {fe614a37-e433-4891-9d80-7b6f6d105a9e} + {5a297919-9989-414d-b07e-3e8d9d151e42} - {dfd3d0c5-c585-400b-a344-ad738cd294ad} + {21b5ebf2-56f4-4e91-81ee-5885598c08af} - {7f8da00b-7e85-4734-9ebc-afa23d9369e8} + {22e4bdcf-a8b4-42d7-9134-431688663a62} - {2959d58a-f846-4834-974b-5207c26fb542} + {2930aa85-6122-4100-b575-24863510edde} - {4cf57737-d60f-4177-b083-9f00cb6686ea} + {6dab84de-443f-4731-853f-3ed84dcd8f0e} - {c40c0ee3-5034-413b-9cc7-f527a1c0b883} + {289862bd-c5d4-44ff-89d6-23cd986452d5} - {945d0d89-13f8-4040-b7a2-7c1cb08fd753} + {dd94726f-df1f-4b61-a48c-d456872e5310} - {5239666a-427a-4b69-9c39-b9e1e27d4e9c} + {9d694c91-87c4-43d0-8d62-b328ffb92a96} - {88971214-062e-4ada-a985-1914c32b15da} + {af7042ce-1728-413b-9ae8-dc3b06bd280b} - {7f363464-ac5c-4123-b334-e913b859e3e4} + {e7e875e3-b1f4-48a9-b8f5-79ff834e3511} - {95390bb3-6322-4cda-9075-d0627d95cb0a} + {cd13faa7-c7f4-4647-8da2-e96bd7d49b41} - {852964e1-041b-4b64-9db6-fb81057fb14b} + {ea847260-3182-49fe-8f7e-e700edecd5c9} - {80e88a16-3aea-4b06-8183-43fec4beff5c} + {7a1ddf83-d05d-4d44-b11c-96fcc75406f9} - {0b4ea484-3ef7-48f4-9229-292f458537b8} + {97ef1aea-37b6-4b01-8e01-c6e1405d422f} - {94aa65ed-d92b-4a34-9609-c102f1ec3b63} + {aab8bfd5-04a3-4c7d-befc-ec84e02ea846} - {2480d750-27fc-4eff-a166-adf56d3ea8e7} + {5967b928-fae3-49f0-ad2f-8568a28674fe} - {ecd50d25-a2c6-40f1-87c4-fdf20ee6979e} + {9d11424e-615a-4e9a-8949-8f1714d7bb1e} - {887d54f6-df14-4bbe-a03c-2ea5b551bacb} + {b6a56fc4-71c6-43f1-982e-afaf4958692b} - {756a9c38-5858-4121-a4d1-5c706d75616a} + {6cb305b8-2267-414d-8f7a-03bbbff2ed23} - {19d603a5-204f-41cf-a757-d28e910e34a1} + {9ca21cb6-5761-4cc3-8ec1-2d92ba39c9cd} + + + {a7290aac-51b3-4d96-bfda-8519d1fbb021} + + + {b488773f-2fcc-4af2-ac54-ab31038914f0} + + + {c2a2a6b5-e3f5-4881-8cd1-c4700bf76bc8} @@ -366,10 +375,13 @@ FTPClient\Header Files - + Reactor\Header Files - + + Reactor\Header Files + + Reactor\Header Files @@ -384,9 +396,6 @@ Reactor\Header Files - - Reactor\Header Files - Mail\Header Files @@ -447,6 +456,12 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + @@ -740,6 +755,12 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + diff --git a/Net/Net_vs120.vcxproj b/Net/Net_vs120.vcxproj index 1dcc0ffe3..2570e9db7 100644 --- a/Net/Net_vs120.vcxproj +++ b/Net/Net_vs120.vcxproj @@ -345,6 +345,8 @@ + + @@ -449,6 +451,8 @@ + + diff --git a/Net/Net_vs120.vcxproj.filters b/Net/Net_vs120.vcxproj.filters index 17cd45508..2714bb4c8 100644 --- a/Net/Net_vs120.vcxproj.filters +++ b/Net/Net_vs120.vcxproj.filters @@ -2,139 +2,148 @@ - {89dfa39e-ad24-46ea-86c9-f789630396dd} + {70effd40-579f-4b35-88e1-8c5c2f7dd5e9} - {a56cf516-c6be-43e7-85d7-25b0f3592e15} + {d6e0c1e0-ee61-4b34-95d8-60cc9065d830} - {f06b35d1-85d7-4f62-9e90-3cb8196459a4} + {32ad1b0e-a6ab-424e-839d-d52bdb56f345} - {4fda8f2b-2126-448b-943f-e91be8da76e8} + {5401dbb8-86fb-406a-8b46-b9c5ce93cce6} - {5ef4f74a-7a37-4736-8699-fe7a2c448d94} + {878a60b4-1807-4ceb-9c2f-2eee1e1dd004} - {29fd6308-9867-4e03-9116-d2ad61f2044d} + {5f667910-09cb-4367-a125-113ee3c28e3c} - {f3bf89e7-ed18-430a-b682-4d7dd0e6cb0c} + {fe6fcc09-f76d-4f81-9b96-d03e39128533} - {9d4e0317-69cf-4449-b4d8-5e821eaad176} + {9e81e2c5-efe9-47d6-bad1-749d9067bb0f} - {d3ef5ee1-0fa6-4a4a-8545-ebd2bcadc918} + {763bc264-5a2c-4d32-a527-ab84c0460c34} - {35b0c849-2665-41a1-8ac2-1a6b57aaaa49} + {8424bd69-7677-495d-869a-bd15c261ddca} - {570791b7-f6d0-4b76-a631-ee9afe3e0033} + {134ec01a-9de1-4224-8133-279b97050034} - {7b36ffec-98b6-464e-a41b-499958aa350c} + {46c5c26a-9503-45b4-8bfc-63d47fe94834} - {b9fab3e9-bc08-4edd-a621-095627ac25d7} + {fd964795-3846-41f1-9ff2-65676011d61d} - {2f4619a7-ca7a-4ff9-b130-5d7efb12d61f} + {0d0fee5f-73d3-4cb3-9a92-18ce1c82777a} - {7e2e0c29-96f0-4e01-8e25-50ecac3304f6} + {2f0a0f61-6f61-4414-96c4-96c5892dc18e} - {a44e7f01-d170-4f6e-a48e-8087b693f66e} + {8baf5722-d3df-4bd5-83c7-3e47ddeb73a7} - {8648d7c5-91da-4f15-959f-00c70ab0d886} + {507fbe2f-e2c2-40d2-8a43-e317f7445213} - {e691f99c-9535-4bb2-a511-cd3369a7c4d4} + {1ac3d85b-e599-4753-8c66-60f3dad02e95} - {39158408-141f-49b0-a948-abb40921ec55} + {12bf4e5e-07e3-40a3-9713-ac6d4876ba87} - {390c8e67-a893-4a2a-a663-01ff271fa94d} + {b51d3a42-7842-459c-9574-da9b1bf5fd36} - {90db6b5f-da58-4130-80eb-915f56caf31b} + {3bbb0c78-abb7-40d3-9e90-cd53cb7e0d73} - {f5a79864-21ff-46ff-a51e-b9816672ba63} + {1e709b86-a55c-4247-9e72-11d73c0c59d1} - {2c553354-e4d1-42d1-b61e-50806a67969d} + {6832f178-d5bf-4390-97fb-88b3163a6164} - {dd584b28-3bfe-473a-90e0-3af9be253312} + {9141f96a-659d-485c-84a5-cbe18390eb7e} - {681d4815-663b-49cf-a52b-08413da0b8da} + {7878109b-58d6-4136-bb08-4d11ad958619} - {d62aff28-7886-4935-836c-38e21ec280f0} + {01cf4d8f-22db-4373-b839-8cfe76d3bd37} - {31103b5d-344c-4c16-abfb-d930a36cffd7} + {b1c2ef28-941b-420e-9569-cb1b7bd92104} - {279e2d67-1ece-4531-97f1-a2376302151e} + {b64b52c4-8b18-46bf-854d-1c83ec53ddab} - {414e932f-0230-4488-9534-c126f0a7df92} + {004ebd58-756e-4abd-a395-be34faf965cd} - {2c9ab677-6961-43c8-a0ce-b24336092f74} + {2cdf071e-9fd2-48e6-9209-46cde4b9453f} - {28d11e96-e676-412f-958f-75d39a089b69} + {de224d11-d1aa-446f-950e-f2c3cef03495} - {909109ac-7394-4346-8016-3bcbace65eab} + {4799f8e2-9325-4ca4-9375-f1e87bc9903c} - {f23c7a2a-67ec-45b5-b05b-049d69f18164} + {854312e2-cb0a-4e5b-ad0d-618488a00cfb} - {d2970aed-fb39-48d8-8afd-727216457982} + {a275768d-9e5a-4709-b55d-582e3dcdd044} - {2aad1647-ca99-4897-915e-eb64993cad6b} + {2a99714c-327d-49b4-994f-c26ea561fd83} - {4582cba3-5a99-4b1d-a651-e9df1afaadec} + {ae71deb7-6615-420e-b56d-608e2a3157f6} - {9df8ff4b-e5f7-481e-9686-fe108208bf5e} + {fda84b24-dec7-401d-9342-f464863a568c} - {c0f83b5e-c2f2-44a2-810d-363842ef0598} + {a3a094c0-6c8d-481a-93cb-2b9188b5de0c} - {c6739a2a-c3d5-42ed-b304-d62e10b63034} + {7ab3821c-9806-43ab-8828-b57480a2c87c} - {bc2d78a7-970e-4f8b-8a5d-2c293434bb7c} + {12dc26f8-8401-450d-b2b4-466389ffbbec} - {96b695bb-bc21-4a6b-815b-67070e178941} + {0c086ae8-9f8a-4c4d-a95d-26d13418972d} - {c530a5f0-e938-4622-b8af-09d3ae12ccc9} + {10c68257-0862-47dd-8980-41e9e15c5cfd} - {f53517f1-ab79-406d-9225-e21233b52c1e} + {4ba8a208-184b-4df0-8707-a7be92f2d7fb} - {30ce306d-e65b-47ae-8874-dcf40f07970b} + {f7c228e1-6718-46d7-9800-ba2cccbe0a03} - {eefbc204-bc81-415e-b3a3-31aec354b648} + {78f1b313-c81d-47d6-bcbe-419208c76ebf} + + + {27a9c78f-e3e1-4f6a-9e33-79dcb6417f63} + + + {8bee1113-b0b2-4ca0-a388-f35276c1f0db} + + + {5dd5779a-61bb-4f38-8c4f-99e7f15de26e} @@ -366,10 +375,13 @@ FTPClient\Header Files - + Reactor\Header Files - + + Reactor\Header Files + + Reactor\Header Files @@ -384,9 +396,6 @@ Reactor\Header Files - - Reactor\Header Files - Mail\Header Files @@ -447,6 +456,12 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + @@ -740,6 +755,12 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + diff --git a/Net/Net_vs71.vcproj b/Net/Net_vs71.vcproj index 225680305..a042387a2 100644 --- a/Net/Net_vs71.vcproj +++ b/Net/Net_vs71.vcproj @@ -753,10 +753,12 @@ Name="Reactor"> - + + - @@ -903,6 +903,23 @@ RelativePath=".\src\WebSocketImpl.cpp"/> + + + + + + + + + + - + + - @@ -924,6 +924,23 @@ RelativePath=".\src\WebSocketImpl.cpp"/> + + + + + + + + + + - + + - @@ -923,6 +923,23 @@ RelativePath=".\src\WebSocketImpl.cpp"/> + + + + + + + + + + - + + - @@ -376,6 +376,8 @@ + + @@ -475,6 +477,8 @@ + + diff --git a/Net/Net_x64_vs100.vcxproj.filters b/Net/Net_x64_vs100.vcxproj.filters index e17509b86..411405249 100644 --- a/Net/Net_x64_vs100.vcxproj.filters +++ b/Net/Net_x64_vs100.vcxproj.filters @@ -2,139 +2,148 @@ - {8e3d69e2-e6fb-4342-a548-76a4208c4c52} + {0e684948-188b-4dff-94ba-5a3b2592d958} - {b8eaea0c-f111-4370-b0b5-2392f64789ff} + {f5f055c6-353e-4e82-a17a-3a9f44e35b2f} - {5cddac8c-cf82-4ccc-9376-2aedf97126b1} + {27793d08-064c-4bc9-9aac-62a145b1ef8e} - {b809ef86-991a-49ec-b0d4-31920f023353} + {2bac578d-6fb2-474b-a070-ae8237a10838} - {c5005892-f777-4680-a595-e6c0cf6a6556} + {ed6d7692-5db7-4c1a-960f-f97dd2d0c70b} - {6c12f3a1-32ec-4cde-be86-1a1758af9e36} + {a256aea2-3631-497b-aae5-b9e7e36d70f6} - {90a5ec99-de61-45ac-8df5-464b6f3f55e2} + {380049ff-c872-4bce-8c04-21096336a30d} - {02fc3b1b-7f49-4dd4-865c-48e727e4dea9} + {f49e216c-de1b-43ba-9ce1-b4742bc34d0e} - {c159daf2-91e7-4ddd-b9c1-410a330e065d} + {a2b7c6c5-107d-4887-b7c2-550ec6d29be7} - {63524e47-ab28-45a9-a7c6-a1d625a31a94} + {ac4037d9-8cbc-4345-80c6-9be190c99a0a} - {ce030e8e-ab33-4a72-9d7d-238fd5626d70} + {7ce50c4c-91cb-4f9f-abe5-49dc62820e4e} - {023a942d-5392-4906-911a-646466af90a1} + {70a4de8f-06c7-4156-9b42-180376586912} - {9e7643ad-914c-4993-9d6c-7285746d6941} + {36fc189f-7e0d-482f-996b-fa936fc59258} - {7f990c8c-a319-4296-bc0a-638bfb5a5874} + {6894c44b-9bdf-4aa9-8a69-d9b7f87a615c} - {4015d430-f282-42fc-b527-37b4e7876773} + {822bde50-d60c-4920-b7c6-6b523089ab0b} - {7f51a35c-b758-42a2-81f9-6c5867371319} + {562cad03-3ad8-47c3-90e3-499cc41a4bb9} - {e17e8d3a-5d4f-4a05-b48e-a5bd720f4f15} + {45b1837d-b60a-49b8-969b-02f8eed03576} - {9e7f1497-e359-4de1-a646-41c230bdd934} + {8ddf3dde-ea40-4a6f-a3e5-0b3fb77ec9c7} - {1001c202-18e1-4527-901a-490056b7d062} + {599127d7-ea32-4912-b5ac-0cc986a7d3af} - {db1fec5a-6f39-4911-80d7-d4c80fd6e4e5} + {75a17a9a-096f-46c2-a1c9-f5fdcc115d6c} - {74d3c551-5751-4275-b352-fecb4b654e2f} + {b7baf8b5-562a-4830-bf76-eeac4fc0b7f0} - {48d9cbbb-5706-4e22-8d38-fc613de77d27} + {74a8513c-f327-44f2-b379-e40b3ceb0921} - {d576555e-2400-4972-81dc-a37494442d2d} + {f87ddd8a-31cf-462a-805f-34a0d7e86f35} - {0ebe2556-1333-448c-8405-3eaf24ac4595} + {0035c77b-387b-4c80-ad7a-e9642adcdac4} - {ec35dc9e-bb87-480a-895a-d736402c77b5} + {271e2d93-f4c1-4647-bcc6-c39079eb1814} - {8c2f48b3-210e-4fe4-8df1-3cddadb00c10} + {c1406825-b11d-4a58-bc0f-f233b897e148} - {d562603f-ac84-4a0a-987c-6209a8b7f2f0} + {1508fcf5-bb61-4c64-9506-7ce242b25ce9} - {45af0262-1f04-4711-a9b2-d2157e5c6de4} + {e7f40f63-96fd-42a8-842b-d115588537ca} - {4a9e8c9e-98ee-4786-9551-4de7380346fa} + {49869627-d039-4800-b2ed-2dd7093881c6} - {359dbb68-a896-4ea2-a2d8-704660c9dfc9} + {6aec4b6b-e209-4372-8761-42de21b05fad} - {f3da7cc6-9c3c-45a7-8875-714df53001c1} + {0806b807-5008-48c3-931f-b1eb71a1ebeb} - {e9141d26-ed7e-448a-83a3-44eb355ab332} + {9454a93e-1d76-4d11-bd45-8a6e530ba1c5} - {39bbdf81-b2a5-43bf-848b-0f9cd971fa8e} + {7815863b-a650-478b-8d13-88f54df0d491} - {ccfae288-932d-4df4-9242-c6624ae873ad} + {d1941515-ad0b-443f-8226-57996e0efd93} - {3d9c8d6b-43b5-4b4e-89aa-22f93bc3be6b} + {24474967-8b4c-4b9f-9d04-c375b435e030} - {0023c2ce-68d8-45b0-ae82-7b1ee5aa7663} + {a30c8c19-349c-4115-96e3-df5221dcfc0e} - {0bd54d17-d778-4aaa-a715-4a708ffb2337} + {430f415a-4f7e-4e52-b8be-0b07466b6ea7} - {a78d68b6-fcd3-470e-bbaf-b8ccfae9ce0a} + {5730f8c8-c848-4dc7-b719-835e7c1a515c} - {8b3d99b1-15f9-46aa-a045-3162f98185b3} + {2c682dff-ce49-4559-9406-fc66389af334} - {68d93f08-e6e3-411d-b51f-c96104db387f} + {e4dbce30-5a35-448e-b0b4-54aa03ea668f} - {4351dba7-7a0f-4a17-98c6-7f5e0191f49c} + {67d1f965-0818-493e-8ea3-a428f3af0056} - {57e8ddec-29c4-43ee-a420-b0ac73335153} + {620f7a52-9caa-4b4d-a02f-99ea1cb4477c} - {12f50834-a755-416e-b3c3-7529c4577b2f} + {41e97600-b364-4e51-bf08-bb0bb960fadf} - {cdfa453e-df49-4e05-982f-2f17efa5fe33} + {3c9e53be-2c27-4186-af38-7addd2950eed} - {5aeb733f-114c-4a71-8616-54c487d193b4} + {d9718db5-45ff-41da-89d5-51903bf8bfef} + + + {63d8e138-5f44-474c-b7d1-db4350081f4e} + + + {fcd2535e-2d48-493b-95fd-48fed56678f5} + + + {8266beb0-ec3e-45a7-a1ca-92508a66551e} @@ -366,10 +375,13 @@ FTPClient\Header Files - + Reactor\Header Files - + + Reactor\Header Files + + Reactor\Header Files @@ -384,9 +396,6 @@ Reactor\Header Files - - Reactor\Header Files - Mail\Header Files @@ -447,6 +456,12 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + @@ -740,6 +755,12 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + diff --git a/Net/Net_x64_vs110.vcxproj b/Net/Net_x64_vs110.vcxproj index 3c59767de..02e333c8d 100644 --- a/Net/Net_x64_vs110.vcxproj +++ b/Net/Net_x64_vs110.vcxproj @@ -353,13 +353,13 @@ - + + - @@ -380,6 +380,8 @@ + + @@ -479,6 +481,8 @@ + + diff --git a/Net/Net_x64_vs110.vcxproj.filters b/Net/Net_x64_vs110.vcxproj.filters index cbf951991..85f463b91 100644 --- a/Net/Net_x64_vs110.vcxproj.filters +++ b/Net/Net_x64_vs110.vcxproj.filters @@ -2,139 +2,148 @@ - {e08e44b4-9dec-4cb6-9204-ccdc38834b75} + {8b79740f-5f2b-4bb8-b7c2-7d8ade7895fb} - {d384df7b-2a2f-4251-8fb0-2d52a264187c} + {77b093a0-7e8a-46ad-b323-3e3ee536a44b} - {b99299de-9786-4de4-b161-dd6281eff07a} + {38981bf1-2b07-4388-83b8-893ba56ab97a} - {6fdfaade-d5d8-4d21-99b5-65cf3094e1ee} + {29a1edd8-5054-4870-a991-36d0b058834a} - {fd4621e4-cc12-4e60-a9cb-b35d51d2b688} + {3db91091-e499-481a-9d9f-c0b10e467219} - {8be2664c-7fd9-4554-8fd8-2663f0b697fd} + {36dbb957-a3d0-428e-a185-c5d863d9ddc9} - {8fae8720-c87a-4715-af8f-9eed22ff2222} + {54e0fe28-0a82-4a93-aead-eb48a3308e3c} - {60e42c48-f36b-4a4d-9a02-a17f7ed02a5d} + {1678d97d-c659-4734-a1c7-d914bf593a78} - {382f1c20-cd9d-4eb7-8ebc-ab25adf00811} + {bc802b92-3e76-409f-86c3-014e4e5e3c73} - {3e3a2e1b-9e00-4c7c-9908-663ca50ff3e0} + {92adeefb-c441-4dec-a953-af8deaa7af42} - {584d2538-45c0-4492-bc47-a376286a835a} + {2aa73222-db5d-4d81-9d4b-ad05e76690b5} - {e05f00e4-651e-4472-a2f2-b7a2e5d80ef6} + {16785a5c-57b7-43b8-b04f-ecaaf820abf9} - {387fdb73-e79e-4062-9a6a-4bb0b0ff9bb6} + {449aee27-1278-40c1-bc15-1bf04488f040} - {1acfaba3-e89b-420c-99ea-09f50f568039} + {863eed1a-0ed6-4b0d-b760-67a9092e6079} - {b303a7c0-baaf-44c6-8012-b076ef9071a5} + {5d8d8f89-c248-46fc-86b9-45b9ae00799b} - {464b2df0-d7f1-4456-be1f-70a8fd5f0847} + {dd2ecbc0-e0a1-4cc4-91f5-123002ec3708} - {af432d68-324c-472f-9bd8-bc7743356505} + {485d1ab2-c019-4edf-8e2c-0a522addd714} - {9d693794-b193-41f2-9948-6ddde571830d} + {81852566-d474-40e1-8391-40319e9e74bb} - {c1cf6cec-300b-4735-8eeb-351c371cef69} + {957c2e9c-63c7-4bdb-9c7b-9bc09db5aa35} - {0b87b631-0302-4d2d-b269-a5e6c10092d9} + {c328ee9c-1a96-4c38-9449-71b6fbc324d4} - {500c8154-3f86-467a-a176-56b00036634c} + {c62b6c96-a553-4082-a5a0-709593a212ae} - {41dfd08a-40f1-4375-90e7-9ed4f6053584} + {58108adb-6dd3-4e32-9454-163dc6cbc840} - {c198e1d9-6477-49da-af2a-050ac5a108d3} + {579a38d6-6459-40d3-81f1-b6b969e6f5bf} - {068c3124-2108-43f2-9141-7a582ef0cefb} + {74fb4754-53c9-4a6c-999a-8e2a028eb6ec} - {63ab2416-6ce9-4038-9531-1efe3bf57a65} + {69cf3d26-1928-4635-adea-69f24ccd303a} - {6477027b-a9ec-4c44-85ec-17395759a843} + {708f84a9-d3f2-4f69-afcb-bfe8301601d6} - {a2ddff38-4bcb-4420-90ca-4a7df791973d} + {32582505-392e-4422-9b81-805b2ffa67ce} - {4ea53f8e-ae8a-40aa-97ea-a7635d44b2c9} + {33685e8c-a08a-4040-ac17-7b265fc4d676} - {48b3bff1-486a-477c-b039-c3f129239359} + {a9948dc1-873b-41cc-aa83-4b4c93f6531e} - {a5dec7c3-d553-4e65-98ae-7099630cf8c2} + {5d81c21e-73a7-4b3a-941e-038fde18ef1b} - {2e41bfe4-defc-4e08-aebf-59bc3f726d1f} + {29a59296-dae7-4afa-8d4f-89990462160b} - {b5c10625-5be1-4d82-b18b-d4427e0db3ad} + {c4979f45-3f19-4f16-a166-07722a9f6c12} - {5e3e4153-dbd4-421e-80d8-0a36f80b745d} + {eeb87922-1772-4949-827e-1ad5196d4a5c} - {0a0e56d0-f5db-4a6b-b9f3-af6aa63aa4ee} + {7e3a52a7-a1a2-478a-aeba-26cb0738aacd} - {2245d37e-d376-4be0-94ce-505a4cb45972} + {bd24cab5-fca0-4995-86fb-6cf19e520e5e} - {3cd5e464-0ef2-4804-812c-3501fee0948f} + {ca2dfcea-cd5c-401e-aba8-831030e983ac} - {80548011-9377-4157-b6e6-e7e6b34560e0} + {8ce9a419-885a-4a0d-8f8d-635dc406ac0b} - {9b504655-465f-4539-87a9-4f9b8a64e35d} + {54b4b901-ef04-4415-9ee8-fe71593cf437} - {4c98bd72-536b-42b7-981a-b9cc2159d116} + {ffe2e5cf-56f4-4052-8015-d761f1ae62bd} - {bcd7c17b-156e-4da1-bd17-085986baf014} + {edcdafcb-8e5b-414d-ac01-d77ace4d6364} - {61f7bb72-fe65-48b9-9933-53e9c810d7d1} + {912cf4a5-aed2-4007-8aca-52b24c993d46} - {0eeec5eb-646b-4aad-a63c-4a8bc7cea9f9} + {c26c1a41-3dbb-4321-a760-ed606b2f699d} - {eeea8a4f-6f5e-4517-8ac9-7534474ebc2b} + {4b5d9420-58d1-4930-9229-8928748b2ffd} - {45320c9b-7dea-4e4d-a4d0-02de98c9e38f} + {d2ccadb8-3d21-4822-92c0-f8e223e80464} - {c9cf3a12-3044-459e-bfcb-578999fee2e7} + {b6705b4c-3825-47a1-ab60-bfca0dcd5048} + + + {62e28747-6165-4c1b-842c-2fbf329334fe} + + + {f5e0a5cc-7920-4e59-a308-9627618a4c50} + + + {85cdb27c-4252-44b5-862c-e868e38bd1c8} @@ -366,10 +375,13 @@ FTPClient\Header Files - + Reactor\Header Files - + + Reactor\Header Files + + Reactor\Header Files @@ -384,9 +396,6 @@ Reactor\Header Files - - Reactor\Header Files - Mail\Header Files @@ -447,6 +456,12 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + @@ -740,6 +755,12 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + diff --git a/Net/Net_x64_vs120.vcxproj b/Net/Net_x64_vs120.vcxproj index 456da4a52..a028cbef4 100644 --- a/Net/Net_x64_vs120.vcxproj +++ b/Net/Net_x64_vs120.vcxproj @@ -343,6 +343,8 @@ + + @@ -447,6 +449,8 @@ + + diff --git a/Net/Net_x64_vs120.vcxproj.filters b/Net/Net_x64_vs120.vcxproj.filters index b599a85f3..ff328e3ce 100644 --- a/Net/Net_x64_vs120.vcxproj.filters +++ b/Net/Net_x64_vs120.vcxproj.filters @@ -2,139 +2,148 @@ - {748b70d8-8d1f-4d4a-8030-4db4de82959c} + {aac5d536-c1be-4f4e-8c57-27889d98e145} - {f938698e-2091-4c7d-86fb-a270ea4dca1b} + {a61efc71-7221-4db3-afa0-2001b72c747a} - {865c5f06-57a4-4cbb-8dc1-fae5f4e03b9f} + {3c1563e7-c552-4b5a-8c4c-5669162386f4} - {3ca197ab-8a07-4ec5-843e-e71361b0d374} + {93d957f5-4326-456f-b5e9-da92263a1532} - {70fbd523-176b-45ce-9d6b-d3209ea4cf38} + {1283a815-6cfb-4c76-8a2d-ff1e35776629} - {bcbcec0d-8320-4a40-bc07-45b07457a956} + {087ae413-7ab3-4a4c-a378-c038e4a4127e} - {72c8a630-ae81-41e1-a06f-ec9bfb71da3e} + {52d401e2-bb15-453e-8ce3-ee8664fc38a9} - {8de4887d-12cc-49f4-a746-88990a02bc00} + {ff371447-ea14-4e41-85d1-3ff83d040ff5} - {97181ae3-a577-422a-8d8d-182f82db1342} + {77c5e3e7-2eb4-4d7f-aa37-ec4115e7b8fb} - {75d12a04-aa53-4907-9360-809682adbca5} + {edccbc3c-bb83-44ab-a803-66012bc97817} - {5ba5dde3-896d-4a3e-8ef7-83b8adcfadd5} + {f6b58ff8-dc88-4383-a9e1-6fecee9b6748} - {efeec3b4-5769-4ea5-9bed-d48d65c761ff} + {abbb2a15-1246-452a-ac4b-b2f535376bcd} - {197fbe09-5b0e-4b05-b0b9-acd3bf8c38c6} + {6b2b7dd6-3f79-47b4-aa0c-828464eda990} - {067ee135-4cb2-4f86-9625-5d3d7440f4e0} + {79926dbc-d9e6-46ab-9ded-8765a1f6ca91} - {f1b5945c-e137-47a1-b1e7-c4a0b92daeaa} + {75224067-227b-4b22-9094-2d103cbd38c6} - {33a78b95-ff6d-4597-a94e-ae61e52e0885} + {a71977ef-8430-4d4a-aac5-97467ff01938} - {2adc4b30-fc61-40b9-a43f-5a7721b32e5e} + {a717eca0-6864-45f1-86cb-61d423fdfbe8} - {04e57c25-a378-4689-8d5b-2f99ba8d28fa} + {e8c83d6f-a959-4910-81f5-073341a0b500} - {f364fcab-b7ab-4d8b-ad5b-db828e7515ef} + {61903a63-97ac-40ba-a478-3438bfe14907} - {14953248-c3d6-4e3d-bd32-fa4006de441a} + {902b73d2-b62d-4c32-ba84-55548cf7ca1c} - {cfe325e8-5db2-4c88-bd77-22b780e4f528} + {a78d0f23-529a-4b8f-98b4-724d9475ca4f} - {9d0a4350-3844-4736-ba04-7b5b293d7202} + {16c5b556-454e-4d6d-bf14-9bb319d46775} - {8ac00aab-efd2-4041-b8d6-8ae2bebbf170} + {706b7e24-6dbf-46f0-957e-e6a0f17a6d74} - {05a9b623-bb78-48e3-9400-a0a0c53c0805} + {4c9f94a5-e181-409c-b7ab-f10724f169a7} - {323d6671-9450-46ec-a48b-321d11c885d7} + {e2c0ea2e-f2e8-44df-9c55-7f5ba8185ffd} - {8ad0d983-56fc-49e1-a9da-b1bfccd3b727} + {27e1c996-f41c-4a5b-9b3f-0fecf23a5cec} - {37adb4e7-70bb-4faa-8c57-5fb243d6ad5c} + {cf178752-55fd-49ef-afa0-c89a65bb37a2} - {32b17b88-c2f8-4b67-ab9d-1cd7a4615c37} + {e50b82d8-f9a0-4188-a69f-bbda286b1e88} - {0ae04f74-17ee-4820-814a-f3a0ee2d0bf0} + {614f75ee-eb6d-4247-bcc9-61acdfd9ec20} - {58b177ba-e816-40af-9a0c-50f61d488990} + {b8272de6-103e-4445-9523-62ece15273c4} - {60010d16-ae04-4391-8493-ee5cf7088e02} + {59e64683-46ef-4fff-b884-0a3d7fdac2f1} - {73977b18-4da5-4aa8-b173-76806dec58d8} + {4ff9883a-4a78-40eb-864c-668b903c33f9} - {a4971a6e-ebbc-4b4d-aa76-596dad4094ff} + {9625c8b6-3f32-4311-8d8d-c3a8dd65b3ee} - {ae2ef237-a13e-4a63-b293-b3b9d4c3b8fc} + {757a7f4b-a99c-4941-a678-328002f6f8c2} - {7a3df994-da53-4ec9-abdd-dbfacd1b50b2} + {187d141d-e523-4359-b9f1-24d4a1cf381a} - {f45d9993-e067-4486-9aaa-6c2efa0d5494} + {19e9ed87-3965-410a-8d4d-35e2f5a17241} - {5a758c0b-8661-4b1f-8571-7db0981fbacb} + {0d61c190-64df-42f1-9c3a-dd48c4b8e733} - {90719a77-3c4e-465e-a9e3-71ba8877f090} + {5322030d-4ae5-45f1-9fdf-9d700d8f1110} - {5480a2ae-3c99-43da-8328-b7c97b809f67} + {434d080a-05c5-4227-92e3-5cb2bf03fb90} - {df65186b-ae80-48b5-90e0-417ef741dd76} + {4b9e7a8f-f7d0-450c-a28b-2976b73ce59f} - {710be0b9-197e-4733-af41-c8d137ee396b} + {8f94d381-4bd6-42f8-be0c-48ba21048dea} - {a08c1cf1-573a-44c8-875c-c71ca92948ee} + {2e75419c-e353-44aa-a731-59a9be7c323d} - {d3c58ac2-0f37-4307-b2a1-b42b7b1663db} + {b9b97401-ca38-4e1c-a13b-2f88dd212993} - {110d889c-a3cf-4c40-b1d7-bb1cddb0e339} + {6d17abf0-6368-4646-b3d5-580f0c2f2c60} - {247dd0dc-eb53-48b3-8638-04181cadba27} + {8524bf2e-ba28-49bc-b137-b8027e9e766b} + + + {6f0952fe-f142-403d-974a-4f5947399f0c} + + + {f211e86e-a051-4b8d-af46-edcad88bd474} + + + {e11a3189-6a08-422d-9dbb-5155d3d67199} @@ -366,10 +375,13 @@ FTPClient\Header Files - + Reactor\Header Files - + + Reactor\Header Files + + Reactor\Header Files @@ -384,9 +396,6 @@ Reactor\Header Files - - Reactor\Header Files - Mail\Header Files @@ -447,6 +456,12 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + @@ -740,6 +755,12 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + diff --git a/Net/Net_x64_vs90.vcproj b/Net/Net_x64_vs90.vcproj index c8efc94b0..fd5e3ad67 100644 --- a/Net/Net_x64_vs90.vcproj +++ b/Net/Net_x64_vs90.vcproj @@ -778,10 +778,12 @@ Name="Reactor"> - + + - @@ -928,6 +928,23 @@ RelativePath=".\src\WebSocketImpl.cpp"/> + + + + + + + + + + _pRequestStream; Poco::SharedPtr _pResponseStream; + + static ProxyConfig _globalProxyConfig; HTTPClientSession(const HTTPClientSession&); HTTPClientSession& operator = (const HTTPClientSession&); @@ -273,25 +320,37 @@ inline Poco::UInt16 HTTPClientSession::getPort() const inline const std::string& HTTPClientSession::getProxyHost() const { - return _proxyHost; + return _proxyConfig.host; } inline Poco::UInt16 HTTPClientSession::getProxyPort() const { - return _proxyPort; + return _proxyConfig.port; } inline const std::string& HTTPClientSession::getProxyUsername() const { - return _proxyUsername; + return _proxyConfig.username; } inline const std::string& HTTPClientSession::getProxyPassword() const { - return _proxyPassword; + return _proxyConfig.password; +} + + +inline const HTTPClientSession::ProxyConfig& HTTPClientSession::getProxyConfig() const +{ + return _proxyConfig; +} + + +inline const HTTPClientSession::ProxyConfig& HTTPClientSession::getGlobalProxyConfig() +{ + return _globalProxyConfig; } diff --git a/Net/include/Poco/Net/HTTPDigestCredentials.h b/Net/include/Poco/Net/HTTPDigestCredentials.h index cde91ec72..709077d3f 100644 --- a/Net/include/Poco/Net/HTTPDigestCredentials.h +++ b/Net/include/Poco/Net/HTTPDigestCredentials.h @@ -52,6 +52,9 @@ public: ~HTTPDigestCredentials(); /// Destroys the HTTPDigestCredentials. + void reset(); + /// Resets the HTTPDigestCredentials object to a clean state. + void setUsername(const std::string& username); /// Sets the username. diff --git a/Net/include/Poco/Net/HTTPServer.h b/Net/include/Poco/Net/HTTPServer.h index 4d695eb98..c84908824 100644 --- a/Net/include/Poco/Net/HTTPServer.h +++ b/Net/include/Poco/Net/HTTPServer.h @@ -90,7 +90,7 @@ public: /// their pace, this allows finer control over client connections. /// /// If abortCurrent is false, all current requests are allowed to - /// complete. If abortCurrent is false, the underlying sockets of + /// complete. If abortCurrent is true, the underlying sockets of /// all client connections are shut down, causing all requests /// to abort. diff --git a/Net/include/Poco/Net/NameValueCollection.h b/Net/include/Poco/Net/NameValueCollection.h index 4ae9b5b81..404100890 100644 --- a/Net/include/Poco/Net/NameValueCollection.h +++ b/Net/include/Poco/Net/NameValueCollection.h @@ -23,6 +23,7 @@ #include "Poco/Net/Net.h" #include "Poco/String.h" #include "Poco/ListMap.h" +#include namespace Poco { @@ -97,7 +98,7 @@ public: bool empty() const; /// Returns true iff the header does not have any content. - int size() const; + std::size_t size() const; /// Returns the number of name-value pairs in the /// collection. diff --git a/Net/include/Poco/Net/OAuth10Credentials.h b/Net/include/Poco/Net/OAuth10Credentials.h new file mode 100644 index 000000000..a7b59b630 --- /dev/null +++ b/Net/include/Poco/Net/OAuth10Credentials.h @@ -0,0 +1,276 @@ +// +// OAuth10Credentials.h +// +// $Id$ +// +// Library: Net +// Package: OAuth +// Module: OAuth10Credentials +// +// Definition of the OAuth10Credentials class. +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Net_OAuth10Credentials_INCLUDED +#define Net_OAuth10Credentials_INCLUDED + + +#include "Poco/Net/Net.h" +#include "Poco/URI.h" + + +namespace Poco { +namespace Net { + + +class HTTPRequest; +class HTMLForm; + + +class Net_API OAuth10Credentials + /// This class implements OAuth 1.0A authentication for HTTP requests, + /// according to RFC 5849. + /// + /// Only PLAINTEXT and HMAC-SHA1 signature methods are + /// supported. The RSA-SHA1 signature method is not supported. + /// + /// The OAuth10Credentials can be used to sign a client request, as + /// well as to verify the signature of a request on the server. + /// + /// To sign a client request, using a known consumer (client) key, consumer (client) secret, + /// OAuth token and token secret: + /// + /// 1. Create an OAuth10Credentials object using all four credentials, either using + /// the four argument constructor, or by using the default constructor and setting + /// the credentials using the setter methods. + /// 2. Create a URI containing the full request URI. + /// 3. Create an appropriate HTTPRequest object. + /// 4. Optionally, create a HTMLForm object containing additional parameters to sign. + /// 5. Sign the request by calling authenticate(). This will add an OAuth + /// Authorization header to the request. + /// 6. Send the request using a HTTPClientSession. + /// + /// To request the OAuth request token from a server, using only the consumer (client) key + /// and consumer (client) secret: + /// + /// 1. Create an OAuth10Credentials object using the two consumer credentials, either using + /// the two argument constructor, or by using the default constructor and setting + /// the credentials using the setter methods. + /// 2. Specify the callback URI using setCallback(). + /// 3. Create a URI containing the full request URI to obtain the token. + /// 4. Create an appropriate HTTPRequest object. + /// 5. Sign the request by calling authenticate(). This will add an OAuth + /// Authorization header to the request. + /// 6. Send the request using a HTTPClientSession. + /// 7. The response will contain the request token and request token secret. + /// These can be extracted from the response body using a HTMLForm object. + /// + /// Requesting the access token and secret (temporary credentials) from the server + /// is analogous to signing a client request using consumer key, consumer secret, + /// request token and request token secret. + /// The server response will contain the access token and access token secret, + /// which can again be extracted from the response body using a HTMLForm object. + /// + /// To verify a request on the server: + /// + /// 1. Create an OAuth10Credentials object using the constructor taking a + /// HTTPRequest object. This will extract the consumer key and token (if + /// provided). + /// 2. Provide the consumer secret and token secret (if required) matching the + /// consumer key and token to the OAuth10Credentials object using the + /// setter methods. + /// 3. Create an URI object containing the full request URI. + /// 4. Call verify() to verify the signature. + /// 5. If verification was successful, and the request was a request for + /// a request (temporary) token, call getCallback() to + /// obtain the callback URI provided by the client. +{ +public: + enum SignatureMethod + /// OAuth 1.0A Signature Method. + { + SIGN_PLAINTEXT, /// OAuth 1.0A PLAINTEXT signature method + SIGN_HMAC_SHA1 /// OAuth 1.0A HMAC-SHA1 signature method + }; + + OAuth10Credentials(); + /// Creates an empty OAuth10Credentials object. + + OAuth10Credentials(const std::string& consumerKey, const std::string& consumerSecret); + /// Creates an OAuth10Credentials object with the given consumer key and consumer secret. + /// + /// The token and tokenSecret will be left empty. + + OAuth10Credentials(const std::string& consumerKey, const std::string& consumerSecret, const std::string& token, const std::string& tokenSecret); + /// Creates an OAuth10Credentials object with the given consumer key and + /// consumer secret, as well as token and token secret. + + explicit OAuth10Credentials(const HTTPRequest& request); + /// Creates an OAuth10Credentials object from a HTTPRequest object. + /// + /// Extracts consumer key and token (if available) from the Authorization header. + /// + /// Throws a NotAuthenticatedException if the request does + /// not contain OAuth 1.0 credentials. + + ~OAuth10Credentials(); + /// Destroys the OAuth10Credentials. + + void setConsumerKey(const std::string& consumerKey); + /// Sets the consumer key. + + const std::string& getConsumerKey() const; + /// Returns the consumer key. + + void setConsumerSecret(const std::string& consumerSecret); + /// Sets the consumer secret. + + const std::string& getConsumerSecret() const; + /// Returns the consumer secret. + + void setToken(const std::string& token); + /// Sets the token. + + const std::string& getToken() const; + /// Returns the token. + + void setTokenSecret(const std::string& tokenSecret); + /// Sets the token. + + const std::string& getTokenSecret() const; + /// Returns the token secret. + + void setRealm(const std::string& realm); + /// Sets the optional realm to be included in the Authorization header. + + const std::string& getRealm() const; + /// Returns the optional realm to be included in the Authorization header. + + void setCallback(const std::string& uri); + /// Sets the callback URI. + + const std::string& getCallback() const; + /// Returns the callback URI. + + void authenticate(HTTPRequest& request, const Poco::URI& uri, SignatureMethod method = SIGN_HMAC_SHA1); + /// Adds an OAuth 1.0A Authentication header to the given request, using + /// the given signature method. + + void authenticate(HTTPRequest& request, const Poco::URI& uri, const Poco::Net::HTMLForm& params, SignatureMethod method = SIGN_HMAC_SHA1); + /// Adds an OAuth 1.0A Authentication header to the given request, using + /// the given signature method. + + bool verify(const HTTPRequest& request, const Poco::URI& uri); + /// Verifies the signature of the given request. + /// + /// The consumer key, consumer secret, token and token secret must have been set. + /// + /// Returns true if the signature is valid, otherwise false. + /// + /// Throws a NotAuthenticatedException if the request does not contain OAuth + /// credentials, or in case of an unsupported OAuth version or signature method. + + bool verify(const HTTPRequest& request, const Poco::URI& uri, const Poco::Net::HTMLForm& params); + /// Verifies the signature of the given request. + /// + /// The consumer key, consumer secret, token and token secret must have been set. + /// + /// Returns true if the signature is valid, otherwise false. + /// + /// Throws a NotAuthenticatedException if the request does not contain OAuth + /// credentials, or in case of an unsupported OAuth version or signature method. + + void nonceAndTimestampForTesting(const std::string& nonce, const std::string& timestamp); + /// Sets the nonce and timestamp to a wellknown value. + /// + /// For use by testsuite only, to test the signature + /// algorithm with wellknown inputs. + /// + /// In normal operation, the nonce is a random value + /// computed by createNonce() and the timestamp is taken + /// from the system time. + + static const std::string SCHEME; + +protected: + void signPlaintext(Poco::Net::HTTPRequest& request) const; + /// Signs the given HTTP request according to OAuth 1.0A PLAINTEXT signature method. + + void signHMACSHA1(Poco::Net::HTTPRequest& request, const std::string& uri, const Poco::Net::HTMLForm& params) const; + /// Signs the given HTTP request according to OAuth 1.0A HMAC-SHA1 signature method. + + std::string createNonce() const; + /// Creates a nonce, which is basically a Base64-encoded 32 character random + /// string, with non-alphanumeric characters removed. + + std::string createSignature(const Poco::Net::HTTPRequest& request, const std::string& uri, const Poco::Net::HTMLForm& params, const std::string& nonce, const std::string& timestamp) const; + /// Creates a OAuth signature for the given request and its parameters, according + /// to . + + static std::string percentEncode(const std::string& str); + /// Percent-encodes the given string according to Twitter API's rules, + /// given in . + +private: + OAuth10Credentials(const OAuth10Credentials&); + OAuth10Credentials& operator = (const OAuth10Credentials&); + + std::string _consumerKey; + std::string _consumerSecret; + std::string _token; + std::string _tokenSecret; + std::string _callback; + std::string _realm; + std::string _nonce; + std::string _timestamp; +}; + + +// +// inlines +// +inline const std::string& OAuth10Credentials::getConsumerKey() const +{ + return _consumerKey; +} + + +inline const std::string& OAuth10Credentials::getConsumerSecret() const +{ + return _consumerSecret; +} + + +inline const std::string& OAuth10Credentials::getToken() const +{ + return _token; +} + + +inline const std::string& OAuth10Credentials::getTokenSecret() const +{ + return _tokenSecret; +} + + +inline const std::string& OAuth10Credentials::getRealm() const +{ + return _realm; +} + + +inline const std::string& OAuth10Credentials::getCallback() const +{ + return _callback; +} + + +} } // namespace Poco::Net + + +#endif // Net_OAuth10Credentials_INCLUDED diff --git a/Net/include/Poco/Net/OAuth20Credentials.h b/Net/include/Poco/Net/OAuth20Credentials.h new file mode 100644 index 000000000..e622cca1e --- /dev/null +++ b/Net/include/Poco/Net/OAuth20Credentials.h @@ -0,0 +1,134 @@ +// +// OAuth20Credentials.h +// +// $Id$ +// +// Library: Net +// Package: OAuth +// Module: OAuth20Credentials +// +// Definition of the OAuth20Credentials class. +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Net_OAuth20Credentials_INCLUDED +#define Net_OAuth20Credentials_INCLUDED + + +#include "Poco/Net/Net.h" + + +namespace Poco { +namespace Net { + + +class HTTPRequest; + + +class Net_API OAuth20Credentials + /// This class implements OAuth 2.0 authentication for HTTP requests, + /// via Bearer tokens in the Authorization header, + /// according to RFC 6749 and RFC 6750. + /// + /// To add an Authorization header containing a bearer token + /// to a HTTPRequest object, create an OAuth20Credentials object + /// with the bearer token and call authenticate(). + /// + /// The bearer token can also be extracted from a HTTPRequest + /// by creating the OAuth20Credentials object with a HTTPRequest + /// object containing a "Bearer" Authorization header and + /// calling getBearerToken(). + /// + /// The authorization header scheme can be changed from + /// "Bearer" to a custom value. For example, GitHub uses + /// the "token" scheme. +{ +public: + OAuth20Credentials(); + /// Creates an empty OAuth20Credentials object. + + explicit OAuth20Credentials(const std::string& bearerToken); + /// Creates an OAuth20Credentials object with the given bearer token. + + OAuth20Credentials(const std::string& bearerToken, const std::string& scheme); + /// Creates an OAuth20Credentials object with the given bearer token + /// and authorization scheme, which overrides the default scheme ("Bearer"). + /// + /// This is useful for services like GitHub, which use "token" as scheme. + + explicit OAuth20Credentials(const HTTPRequest& request); + /// Creates an OAuth20Credentials object from a HTTPRequest object. + /// + /// Extracts bearer token from the Authorization header, which + /// must use the "Bearer" authorization scheme. + /// + /// Throws a NotAuthenticatedException if the request does + /// not contain a bearer token in the Authorization header. + + OAuth20Credentials(const HTTPRequest& request, const std::string& scheme); + /// Creates an OAuth20Credentials object from a HTTPRequest object. + /// + /// Extracts bearer token from the Authorization header, which must + /// use the given authorization scheme. + /// + /// Throws a NotAuthenticatedException if the request does + /// not contain a bearer token in the Authorization header. + + ~OAuth20Credentials(); + /// Destroys the HTTPCredentials. + + void setBearerToken(const std::string& bearerToken); + /// Sets the bearer token. + + const std::string& getBearerToken() const; + /// Returns the bearer token. + + void setScheme(const std::string& scheme); + /// Sets the Authorization header scheme. + + const std::string& getScheme() const; + /// Returns the Authorization header scheme. + + void authenticate(HTTPRequest& request); + /// Adds an Authorization header containing the bearer token to + /// the HTTPRequest. + + static const std::string SCHEME; + +protected: + void extractBearerToken(const HTTPRequest& request); + /// Extracts the bearer token from the HTTPRequest. + +private: + OAuth20Credentials(const OAuth20Credentials&); + OAuth20Credentials& operator = (const OAuth20Credentials&); + + std::string _bearerToken; + std::string _scheme; +}; + + +// +// inlines +// +inline const std::string& OAuth20Credentials::getBearerToken() const +{ + return _bearerToken; +} + + +inline const std::string& OAuth20Credentials::getScheme() const +{ + return _scheme; +} + + +} } // namespace Poco::Net + + +#endif // Net_OAuth20Credentials_INCLUDED diff --git a/Net/include/Poco/Net/ParallelSocketAcceptor.h b/Net/include/Poco/Net/ParallelSocketAcceptor.h index bd986716c..0532065de 100644 --- a/Net/include/Poco/Net/ParallelSocketAcceptor.h +++ b/Net/include/Poco/Net/ParallelSocketAcceptor.h @@ -129,6 +129,7 @@ public: { pNotification->release(); StreamSocket sock = _socket.acceptConnection(); + _pReactor->wakeUp(); createServiceHandler(sock); } @@ -140,6 +141,7 @@ protected: { std::size_t next = _next++; if (_next == _reactors.size()) _next = 0; + _reactors[next]->wakeUp(); return new ServiceHandler(socket, *_reactors[next]); } @@ -167,9 +169,27 @@ protected: _reactors.push_back(new ParallelReactor); } -private: typedef std::vector ReactorVec; + ReactorVec& reactors() + /// Returns reference to vector of reactors. + { + return _reactors; + } + + SocketReactor* reactor(std::size_t idx) + /// Returns reference to the reactor at position idx. + { + return _reactors.at(idx).get(); + } + + std::size_t& next() + /// Returns reference to the next reactor index. + { + return _next; + } + +private: ParallelSocketAcceptor(); ParallelSocketAcceptor(const ParallelSocketAcceptor&); ParallelSocketAcceptor& operator = (const ParallelSocketAcceptor&); diff --git a/Net/include/Poco/Net/RawSocket.h b/Net/include/Poco/Net/RawSocket.h index ebd20e42f..047688433 100644 --- a/Net/include/Poco/Net/RawSocket.h +++ b/Net/include/Poco/Net/RawSocket.h @@ -69,7 +69,7 @@ public: /// Restricts incoming and outgoing /// packets to the specified address. /// - /// Cannot be used together with bind(). + /// Calls to connect() cannot come before calls to bind(). void bind(const SocketAddress& address, bool reuseAddress = false); /// Bind a local address to the socket. @@ -80,7 +80,7 @@ public: /// If reuseAddress is true, sets the SO_REUSEADDR /// socket option. /// - /// Cannot be used together with connect(). + /// Calls to connect() cannot come before calls to bind(). int sendBytes(const void* buffer, int length, int flags = 0); /// Sends the contents of the given buffer through diff --git a/Net/include/Poco/Net/SocketAcceptor.h b/Net/include/Poco/Net/SocketAcceptor.h index 6d625f865..b6cbd3f89 100644 --- a/Net/include/Poco/Net/SocketAcceptor.h +++ b/Net/include/Poco/Net/SocketAcceptor.h @@ -129,6 +129,7 @@ public: { pNotification->release(); StreamSocket sock = _socket.acceptConnection(); + _pReactor->wakeUp(); createServiceHandler(sock); } diff --git a/Net/include/Poco/Net/SocketReactor.h b/Net/include/Poco/Net/SocketReactor.h index befdc9a0f..a39e9d25b 100644 --- a/Net/include/Poco/Net/SocketReactor.h +++ b/Net/include/Poco/Net/SocketReactor.h @@ -30,6 +30,11 @@ namespace Poco { + + +class Thread; + + namespace Net { @@ -128,6 +133,9 @@ public: /// The reactor will be stopped when the next event /// (including a timeout event) occurs. + void wakeUp(); + /// Wakes up idle reactor. + void setTimeout(const Poco::Timespan& timeout); /// Sets the timeout. /// @@ -166,7 +174,7 @@ protected: /// Can be overridden by subclasses. The default implementation /// dispatches the TimeoutNotification and thus should be called by overriding /// implementations. - + virtual void onIdle(); /// Called if no sockets are available to call select() on. /// @@ -194,7 +202,7 @@ protected: void dispatch(SocketNotification* pNotification); /// Dispatches the given notification to all observers. - + private: typedef Poco::AutoPtr NotifierPtr; typedef Poco::AutoPtr NotificationPtr; @@ -206,7 +214,7 @@ private: { DEFAULT_TIMEOUT = 250000 }; - + bool _stop; Poco::Timespan _timeout; EventHandlerMap _handlers; @@ -217,6 +225,7 @@ private: NotificationPtr _pIdleNotification; NotificationPtr _pShutdownNotification; Poco::FastMutex _mutex; + Poco::Thread* _pThread; friend class SocketNotifier; }; diff --git a/Net/samples/CMakeLists.txt b/Net/samples/CMakeLists.txt index a73eacbaf..9cf2a0457 100644 --- a/Net/samples/CMakeLists.txt +++ b/Net/samples/CMakeLists.txt @@ -6,7 +6,6 @@ add_subdirectory(Mail) add_subdirectory(Ping) add_subdirectory(SMTPLogger) add_subdirectory(TimeServer) -add_subdirectory(TwitterClient) add_subdirectory(WebSocketServer) add_subdirectory(dict) add_subdirectory(download) diff --git a/Net/samples/Makefile b/Net/samples/Makefile index 55cd04cf1..ec93df92b 100644 --- a/Net/samples/Makefile +++ b/Net/samples/Makefile @@ -19,7 +19,6 @@ projects: $(MAKE) -C EchoServer $(MAKECMDGOALS) $(MAKE) -C Mail $(MAKECMDGOALS) $(MAKE) -C Ping $(MAKECMDGOALS) - $(MAKE) -C TwitterClient $(MAKECMDGOALS) $(MAKE) -C WebSocketServer $(MAKECMDGOALS) $(MAKE) -C SMTPLogger $(MAKECMDGOALS) $(MAKE) -C ifconfig $(MAKECMDGOALS) diff --git a/Net/samples/TwitterClient/src/Twitter.cpp b/Net/samples/TwitterClient/src/Twitter.cpp deleted file mode 100644 index 05b33aebe..000000000 --- a/Net/samples/TwitterClient/src/Twitter.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// -// Twitter.cpp -// -// $Id: //poco/1.4/Net/samples/TwitterClient/src/Twitter.cpp#2 $ -// -// A C++ implementation of a Twitter client based on the POCO Net library. -// -// Copyright (c) 2009-2013, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// SPDX-License-Identifier: BSL-1.0 -// - - -#include "Twitter.h" -#include "Poco/Net/HTTPClientSession.h" -#include "Poco/Net/HTTPRequest.h" -#include "Poco/Net/HTTPResponse.h" -#include "Poco/Net/HTTPBasicCredentials.h" -#include "Poco/Util/JSONConfiguration.h" -#include "Poco/URI.h" -#include "Poco/SHA1Engine.h" -#include "Poco/HMACEngine.h" -#include "Poco/Base64Encoder.h" -#include "Poco/RandomStream.h" -#include "Poco/Timestamp.h" -#include "Poco/NumberParser.h" -#include "Poco/NumberFormatter.h" -#include "Poco/Format.h" -#include "Poco/StreamCopier.h" -#include -#include - - -const std::string Twitter::TWITTER_URI("http://api.twitter.com/1.1/statuses/"); - - -Twitter::Twitter(): - _uri(TWITTER_URI) -{ -} - - -Twitter::Twitter(const std::string& twitterURI): - _uri(twitterURI) -{ -} - - -Twitter::~Twitter() -{ -} - - -void Twitter::login(const std::string& consumerKey, const std::string& consumerSecret, const std::string& token, const std::string& tokenSecret) -{ - _consumerKey = consumerKey; - _consumerSecret = consumerSecret; - _token = token; - _tokenSecret = tokenSecret; -} - - -Poco::Int64 Twitter::update(const std::string& status) -{ - Poco::Net::HTMLForm form; - form.set("status", status); - Poco::AutoPtr pResult = invoke(Poco::Net::HTTPRequest::HTTP_POST, "update", form); - return pResult->getInt64("id", 0); -} - - -Poco::AutoPtr Twitter::invoke(const std::string& httpMethod, const std::string& twitterMethod, Poco::Net::HTMLForm& form) -{ - // Create the request URI. - // We use the JSON version of the Twitter API. - Poco::URI uri(_uri + twitterMethod + ".json"); - - Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort()); - Poco::Net::HTTPRequest req(httpMethod, uri.getPath(), Poco::Net::HTTPMessage::HTTP_1_1); - - // Sign request - sign(req, form, uri.toString()); - - // Send the request. - form.prepareSubmit(req); - std::ostream& ostr = session.sendRequest(req); - form.write(ostr); - - // Receive the response. - Poco::Net::HTTPResponse res; - std::istream& rs = session.receiveResponse(res); - - Poco::AutoPtr pResult = new Poco::Util::JSONConfiguration(rs); - - // If everything went fine, return the JSON document. - // Otherwise throw an exception. - if (res.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) - { - return pResult; - } - else - { - throw Poco::ApplicationException("Twitter Error", pResult->getString("errors[0].message", "")); - } -} - - -void Twitter::sign(Poco::Net::HTTPRequest& request, const Poco::Net::HTMLForm& params, const std::string& uri) const -{ - std::string nonce(createNonce()); - std::string timestamp(Poco::NumberFormatter::format(Poco::Timestamp().epochTime())); - std::string signature(createSignature(request, params, uri, nonce, timestamp)); - std::string authorization( - Poco::format( - "OAuth" - " oauth_consumer_key=\"%s\"," - " oauth_nonce=\"%s\"," - " oauth_signature=\"%s\"," - " oauth_signature_method=\"HMAC-SHA1\"," - " oauth_timestamp=\"%s\"," - " oauth_token=\"%s\"," - " oauth_version=\"1.0\"", - percentEncode(_consumerKey), - percentEncode(nonce), - percentEncode(signature), - timestamp, - percentEncode(_token) - ) - ); - request.set("Authorization", authorization); -} - - -std::string Twitter::createNonce() const -{ - std::ostringstream base64Nonce; - Poco::Base64Encoder base64Encoder(base64Nonce); - Poco::RandomInputStream randomStream; - for (int i = 0; i < 32; i++) - { - base64Encoder.put(randomStream.get()); - } - base64Encoder.close(); - std::string nonce = base64Nonce.str(); - return Poco::translate(nonce, "+/=", ""); -} - - -std::string Twitter::createSignature(Poco::Net::HTTPRequest& request, const Poco::Net::HTMLForm& params, const std::string& uri, const std::string& nonce, const std::string& timestamp) const -{ - std::map paramsMap; - paramsMap["oauth_consumer_key"] = percentEncode(_consumerKey); - paramsMap["oauth_nonce"] = percentEncode(nonce); - paramsMap["oauth_signature_method"] = "HMAC-SHA1"; - paramsMap["oauth_timestamp"] = timestamp; - paramsMap["oauth_token"] = percentEncode(_token); - paramsMap["oauth_version"] = "1.0"; - for (Poco::Net::HTMLForm::ConstIterator it = params.begin(); it != params.end(); ++it) - { - paramsMap[percentEncode(it->first)] = percentEncode(it->second); - } - - std::string paramsString; - for (std::map::const_iterator it = paramsMap.begin(); it != paramsMap.end(); ++it) - { - if (it != paramsMap.begin()) paramsString += '&'; - paramsString += it->first; - paramsString += "="; - paramsString += it->second; - } - - std::string signatureBase = request.getMethod(); - signatureBase += '&'; - signatureBase += percentEncode(uri); - signatureBase += '&'; - signatureBase += percentEncode(paramsString); - - std::string signingKey; - signingKey += percentEncode(_consumerSecret); - signingKey += '&'; - signingKey += percentEncode(_tokenSecret); - - Poco::HMACEngine hmacEngine(signingKey); - hmacEngine.update(signatureBase); - Poco::DigestEngine::Digest digest = hmacEngine.digest(); - std::ostringstream digestBase64; - Poco::Base64Encoder base64Encoder(digestBase64); - base64Encoder.write(reinterpret_cast(&digest[0]), digest.size()); - base64Encoder.close(); - return digestBase64.str(); -} - - -std::string Twitter::percentEncode(const std::string& str) -{ - std::string encoded; - Poco::URI::encode(str, "!?#/'\",;:$&()[]*+=@", encoded); - return encoded; -} diff --git a/Net/samples/samples.progen b/Net/samples/samples.progen index 9f94a333a..3574e787d 100644 --- a/Net/samples/samples.progen +++ b/Net/samples/samples.progen @@ -12,7 +12,6 @@ vc.solution.include = \ Mail\\Mail;\ Ping\\Ping;\ TimeServer\\TimeServer;\ - TwitterClient\\TwitterClient;\ WebSocketServer\\WebSocketServer;\ SMTPLogger\\SMTPLogger;\ ifconfig\\ifconfig diff --git a/Net/samples/samples_CE_vs90.sln b/Net/samples/samples_CE_vs90.sln index 94d4736aa..69caa22e9 100644 --- a/Net/samples/samples_CE_vs90.sln +++ b/Net/samples/samples_CE_vs90.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_CE_vs90.v EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_CE_vs90.vcproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_CE_vs90.vcproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_CE_vs90.vcproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_CE_vs90.vcproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Digi JumpStart (ARMV4I).ActiveCfg = release_static_md|Digi JumpStart (ARMV4I) {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Digi JumpStart (ARMV4I).Build.0 = release_static_md|Digi JumpStart (ARMV4I) {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Digi JumpStart (ARMV4I).Deploy.0 = release_static_md|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Digi JumpStart (ARMV4I).ActiveCfg = debug_shared|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Digi JumpStart (ARMV4I).Build.0 = debug_shared|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Digi JumpStart (ARMV4I).Deploy.0 = debug_shared|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Digi JumpStart (ARMV4I).ActiveCfg = release_shared|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Digi JumpStart (ARMV4I).Build.0 = release_shared|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Digi JumpStart (ARMV4I).Deploy.0 = release_shared|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Digi JumpStart (ARMV4I).ActiveCfg = debug_static_mt|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Digi JumpStart (ARMV4I).Build.0 = debug_static_mt|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Digi JumpStart (ARMV4I).Deploy.0 = debug_static_mt|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Digi JumpStart (ARMV4I).ActiveCfg = release_static_mt|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Digi JumpStart (ARMV4I).Build.0 = release_static_mt|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Digi JumpStart (ARMV4I).Deploy.0 = release_static_mt|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Digi JumpStart (ARMV4I).ActiveCfg = debug_static_md|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Digi JumpStart (ARMV4I).Build.0 = debug_static_md|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Digi JumpStart (ARMV4I).Deploy.0 = debug_static_md|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Digi JumpStart (ARMV4I).ActiveCfg = release_static_md|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Digi JumpStart (ARMV4I).Build.0 = release_static_md|Digi JumpStart (ARMV4I) - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Digi JumpStart (ARMV4I).Deploy.0 = release_static_md|Digi JumpStart (ARMV4I) {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Digi JumpStart (ARMV4I).ActiveCfg = debug_shared|Digi JumpStart (ARMV4I) {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Digi JumpStart (ARMV4I).Build.0 = debug_shared|Digi JumpStart (ARMV4I) {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Digi JumpStart (ARMV4I).Deploy.0 = debug_shared|Digi JumpStart (ARMV4I) diff --git a/Net/samples/samples_WEC2013_vs110.sln b/Net/samples/samples_WEC2013_vs110.sln index 60ce0d54f..3537fb587 100644 --- a/Net/samples/samples_WEC2013_vs110.sln +++ b/Net/samples/samples_WEC2013_vs110.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_WEC2013_v EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_WEC2013_vs110.vcxproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_WEC2013_vs110.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_WEC2013_vs110.vcxproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_WEC2013_vs110.vcxproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_md|SDK_AM335X_SK_WEC2013_V300 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_shared|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_shared|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_shared|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_shared|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_mt|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_static_md|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_md|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_shared|SDK_AM335X_SK_WEC2013_V300 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 diff --git a/Net/samples/samples_WEC2013_vs120.sln b/Net/samples/samples_WEC2013_vs120.sln index d2c63cb60..f641fe964 100644 --- a/Net/samples/samples_WEC2013_vs120.sln +++ b/Net/samples/samples_WEC2013_vs120.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_WEC2013_v EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_WEC2013_vs120.vcxproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_WEC2013_vs120.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_WEC2013_vs120.vcxproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_WEC2013_vs120.vcxproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = release_static_md|SDK_AM335X_SK_WEC2013_V310 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|SDK_AM335X_SK_WEC2013_V310.Build.0 = release_static_md|SDK_AM335X_SK_WEC2013_V310 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = release_static_md|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = debug_shared|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V310.Build.0 = debug_shared|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = debug_shared|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = release_shared|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V310.Build.0 = release_shared|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = release_shared|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = debug_static_mt|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V310.Build.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = release_static_mt|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V310.Build.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = debug_static_md|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V310.Build.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = release_static_md|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V310.Build.0 = release_static_md|SDK_AM335X_SK_WEC2013_V310 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = release_static_md|SDK_AM335X_SK_WEC2013_V310 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = debug_shared|SDK_AM335X_SK_WEC2013_V310 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|SDK_AM335X_SK_WEC2013_V310.Build.0 = debug_shared|SDK_AM335X_SK_WEC2013_V310 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = debug_shared|SDK_AM335X_SK_WEC2013_V310 diff --git a/Net/samples/samples_vs100.sln b/Net/samples/samples_vs100.sln index 1f75ed6c7..f34c2932a 100644 --- a/Net/samples/samples_vs100.sln +++ b/Net/samples/samples_vs100.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_vs100.vcx EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_vs100.vcxproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs100.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_vs100.vcxproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_vs100.vcxproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.Build.0 = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Build.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.ActiveCfg = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Build.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Deploy.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.ActiveCfg = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Build.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Deploy.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.ActiveCfg = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Build.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Deploy.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.ActiveCfg = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Build.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Deploy.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Build.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.Build.0 = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 diff --git a/Net/samples/samples_vs110.sln b/Net/samples/samples_vs110.sln index 45611e65e..7fd8af512 100644 --- a/Net/samples/samples_vs110.sln +++ b/Net/samples/samples_vs110.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_vs110.vcx EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_vs110.vcxproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs110.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_vs110.vcxproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_vs110.vcxproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.Build.0 = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Build.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.ActiveCfg = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Build.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Deploy.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.ActiveCfg = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Build.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Deploy.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.ActiveCfg = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Build.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Deploy.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.ActiveCfg = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Build.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Deploy.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Build.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.Build.0 = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 diff --git a/Net/samples/samples_vs120.sln b/Net/samples/samples_vs120.sln index 744dcfa69..15409ffcf 100644 --- a/Net/samples/samples_vs120.sln +++ b/Net/samples/samples_vs120.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_vs120.vcx EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_vs120.vcxproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs120.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_vs120.vcxproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_vs120.vcxproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.Build.0 = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Build.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.ActiveCfg = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Build.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Deploy.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.ActiveCfg = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Build.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Deploy.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.ActiveCfg = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Build.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Deploy.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.ActiveCfg = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Build.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Deploy.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Build.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.Build.0 = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 diff --git a/Net/samples/samples_vs71.sln b/Net/samples/samples_vs71.sln index 364c55756..cba92d21b 100644 --- a/Net/samples/samples_vs71.sln +++ b/Net/samples/samples_vs71.sln @@ -39,10 +39,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\Ti ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs71.vcproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_vs71.vcproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" ProjectSection(ProjectDependencies) = postProject EndProjectSection @@ -185,18 +181,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.debug_static_md.Build.0 = debug_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md.ActiveCfg = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md.Build.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared.ActiveCfg = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared.Build.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared.ActiveCfg = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared.Build.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt.ActiveCfg = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt.Build.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt.ActiveCfg = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt.Build.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md.ActiveCfg = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md.Build.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md.ActiveCfg = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md.Build.0 = release_static_md|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared.ActiveCfg = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared.Build.0 = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.release_shared.ActiveCfg = release_shared|Win32 diff --git a/Net/samples/samples_vs80.sln b/Net/samples/samples_vs80.sln index c960de236..1d25df621 100644 --- a/Net/samples/samples_vs80.sln +++ b/Net/samples/samples_vs80.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_vs80.vcpr EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_vs80.vcproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs80.vcproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_vs80.vcproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_vs80.vcproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.Build.0 = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Build.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.ActiveCfg = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Build.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Deploy.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.ActiveCfg = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Build.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Deploy.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.ActiveCfg = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Build.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Deploy.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.ActiveCfg = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Build.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Deploy.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Build.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.Build.0 = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 diff --git a/Net/samples/samples_vs90.sln b/Net/samples/samples_vs90.sln index 57e31eaba..5ecdeaa8e 100644 --- a/Net/samples/samples_vs90.sln +++ b/Net/samples/samples_vs90.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_vs90.vcpr EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_vs90.vcproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs90.vcproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_vs90.vcproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_vs90.vcproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.Build.0 = release_static_md|Win32 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Build.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.ActiveCfg = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Build.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Deploy.0 = release_shared|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.ActiveCfg = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Build.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Deploy.0 = debug_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.ActiveCfg = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Build.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Deploy.0 = release_static_mt|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.ActiveCfg = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Build.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Deploy.0 = debug_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Build.0 = release_static_md|Win32 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.Build.0 = debug_shared|Win32 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 diff --git a/Net/samples/samples_x64_vs100.sln b/Net/samples/samples_x64_vs100.sln index 202ea7fb3..a7abc00e8 100644 --- a/Net/samples/samples_x64_vs100.sln +++ b/Net/samples/samples_x64_vs100.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_x64_vs100 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_x64_vs100.vcxproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_x64_vs100.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_x64_vs100.vcxproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_x64_vs100.vcxproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.ActiveCfg = release_static_md|x64 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.Build.0 = release_static_md|x64 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.Deploy.0 = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.ActiveCfg = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Build.0 = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Deploy.0 = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.ActiveCfg = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Build.0 = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Deploy.0 = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.ActiveCfg = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Build.0 = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Deploy.0 = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.ActiveCfg = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Build.0 = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Deploy.0 = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.ActiveCfg = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Build.0 = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Deploy.0 = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.ActiveCfg = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Build.0 = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Deploy.0 = release_static_md|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.ActiveCfg = debug_shared|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.Build.0 = debug_shared|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.Deploy.0 = debug_shared|x64 diff --git a/Net/samples/samples_x64_vs110.sln b/Net/samples/samples_x64_vs110.sln index f37b5093d..20f6a5ba8 100644 --- a/Net/samples/samples_x64_vs110.sln +++ b/Net/samples/samples_x64_vs110.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_x64_vs110 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_x64_vs110.vcxproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_x64_vs110.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_x64_vs110.vcxproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_x64_vs110.vcxproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.ActiveCfg = release_static_md|x64 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.Build.0 = release_static_md|x64 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.Deploy.0 = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.ActiveCfg = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Build.0 = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Deploy.0 = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.ActiveCfg = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Build.0 = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Deploy.0 = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.ActiveCfg = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Build.0 = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Deploy.0 = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.ActiveCfg = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Build.0 = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Deploy.0 = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.ActiveCfg = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Build.0 = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Deploy.0 = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.ActiveCfg = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Build.0 = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Deploy.0 = release_static_md|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.ActiveCfg = debug_shared|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.Build.0 = debug_shared|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.Deploy.0 = debug_shared|x64 diff --git a/Net/samples/samples_x64_vs120.sln b/Net/samples/samples_x64_vs120.sln index 110a20bdd..d796b9131 100644 --- a/Net/samples/samples_x64_vs120.sln +++ b/Net/samples/samples_x64_vs120.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_x64_vs120 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_x64_vs120.vcxproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_x64_vs120.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_x64_vs120.vcxproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_x64_vs120.vcxproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.ActiveCfg = release_static_md|x64 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.Build.0 = release_static_md|x64 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.Deploy.0 = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.ActiveCfg = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Build.0 = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Deploy.0 = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.ActiveCfg = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Build.0 = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Deploy.0 = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.ActiveCfg = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Build.0 = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Deploy.0 = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.ActiveCfg = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Build.0 = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Deploy.0 = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.ActiveCfg = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Build.0 = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Deploy.0 = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.ActiveCfg = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Build.0 = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Deploy.0 = release_static_md|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.ActiveCfg = debug_shared|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.Build.0 = debug_shared|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.Deploy.0 = debug_shared|x64 diff --git a/Net/samples/samples_x64_vs90.sln b/Net/samples/samples_x64_vs90.sln index e2af41695..5f9aea996 100644 --- a/Net/samples/samples_x64_vs90.sln +++ b/Net/samples/samples_x64_vs90.sln @@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ping", "Ping\Ping_x64_vs90. EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_x64_vs90.vcproj", "{59EDFD20-9968-30F7-9532-44C08DA58C6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_x64_vs90.vcproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer_x64_vs90.vcproj", "{0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMTPLogger", "SMTPLogger\SMTPLogger_x64_vs90.vcproj", "{83E96E4E-A7E8-340B-B6D2-31B4D40D99AF}" @@ -218,24 +216,6 @@ Global {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.ActiveCfg = release_static_md|x64 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.Build.0 = release_static_md|x64 {59EDFD20-9968-30F7-9532-44C08DA58C6E}.release_static_md|x64.Deploy.0 = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.ActiveCfg = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Build.0 = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Deploy.0 = debug_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.ActiveCfg = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Build.0 = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Deploy.0 = release_shared|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.ActiveCfg = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Build.0 = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Deploy.0 = debug_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.ActiveCfg = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Build.0 = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Deploy.0 = release_static_mt|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.ActiveCfg = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Build.0 = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Deploy.0 = debug_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.ActiveCfg = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Build.0 = release_static_md|x64 - {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Deploy.0 = release_static_md|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.ActiveCfg = debug_shared|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.Build.0 = debug_shared|x64 {0DC40FE3-6C42-365E-8DAB-899C50ECFB1C}.debug_shared|x64.Deploy.0 = debug_shared|x64 diff --git a/Net/src/HTMLForm.cpp b/Net/src/HTMLForm.cpp index 92943092d..24ee4a60b 100644 --- a/Net/src/HTMLForm.cpp +++ b/Net/src/HTMLForm.cpp @@ -28,6 +28,7 @@ #include "Poco/URI.h" #include "Poco/String.h" #include "Poco/CountingStream.h" +#include "Poco/UTF8String.h" #include @@ -42,20 +43,31 @@ namespace Poco { namespace Net { -const std::string HTMLForm::ENCODING_URL = "application/x-www-form-urlencoded"; -const std::string HTMLForm::ENCODING_MULTIPART = "multipart/form-data"; -const int HTMLForm::UNKNOWN_CONTENT_LENGTH = -1; +const std::string HTMLForm::ENCODING_URL = "application/x-www-form-urlencoded"; +const std::string HTMLForm::ENCODING_MULTIPART = "multipart/form-data"; +const int HTMLForm::UNKNOWN_CONTENT_LENGTH = -1; -class HTMLFormCountingOutputStream : public CountingOutputStream +class HTMLFormCountingOutputStream: public CountingOutputStream { public: - HTMLFormCountingOutputStream() : _isvalid(true) {} + HTMLFormCountingOutputStream(): + _valid(true) + { + } + + bool isValid() const + { + return _valid; + } + + void setValid(bool v) + { + _valid = v; + } - bool getIsValid() const { return _isvalid; } - void setIsValid(bool v) { _isvalid = v; } private: - bool _isvalid; + bool _valid; }; @@ -238,7 +250,7 @@ std::streamsize HTMLForm::calculateContentLength() HTMLFormCountingOutputStream c; write(c); - if (c.getIsValid()) + if (c.isValid()) return c.chars(); else return UNKNOWN_CONTENT_LENGTH; @@ -274,6 +286,7 @@ void HTMLForm::readUrl(std::istream& istr) int fields = 0; int ch = istr.get(); + bool isFirst = true; while (ch != eof) { if (_fieldLimit > 0 && fields == _fieldLimit) @@ -296,6 +309,11 @@ void HTMLForm::readUrl(std::istream& istr) ch = istr.get(); } } + // remove UTF-8 byte order mark from first name, if present + if (isFirst) + { + UTF8::removeBOM(name); + } std::string decodedName; std::string decodedValue; URI::decode(name, decodedName); @@ -303,6 +321,7 @@ void HTMLForm::readUrl(std::istream& istr) add(decodedName, decodedValue); ++fields; if (ch == '&') ch = istr.get(); + isFirst = false; } } @@ -402,7 +421,7 @@ void HTMLForm::writeMultipart(std::ostream& ostr) if (partlen != PartSource::UNKNOWN_CONTENT_LENGTH) costr->addChars(static_cast(partlen)); else - costr->setIsValid(false); + costr->setValid(false); } else StreamCopier::copyStream(ita->pSource->stream(), ostr); diff --git a/Net/src/HTTPAuthenticationParams.cpp b/Net/src/HTTPAuthenticationParams.cpp index 53eff21fa..29ed198a0 100644 --- a/Net/src/HTTPAuthenticationParams.cpp +++ b/Net/src/HTTPAuthenticationParams.cpp @@ -68,6 +68,8 @@ namespace Net { const std::string HTTPAuthenticationParams::REALM("realm"); +const std::string HTTPAuthenticationParams::WWW_AUTHENTICATE("WWW-Authenticate"); +const std::string HTTPAuthenticationParams::PROXY_AUTHENTICATE("Proxy-Authenticate"); HTTPAuthenticationParams::HTTPAuthenticationParams() @@ -87,9 +89,9 @@ HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPRequest& request) } -HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPResponse& response) +HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPResponse& response, const std::string& header) { - fromResponse(response); + fromResponse(response, header); } @@ -126,22 +128,29 @@ void HTTPAuthenticationParams::fromRequest(const HTTPRequest& request) } -void HTTPAuthenticationParams::fromResponse(const HTTPResponse& response) +void HTTPAuthenticationParams::fromResponse(const HTTPResponse& response, const std::string& header) { - if (!response.has("WWW-Authenticate")) + NameValueCollection::ConstIterator it = response.find(header); + if (it == response.end()) throw NotAuthenticatedException("HTTP response has no authentication header"); - const std::string& header = response.get("WWW-Authenticate"); - - if (icompare(header, 0, 6, "Basic ") == 0) + bool found = false; + while (!found && it != response.end() && icompare(it->first, header) == 0) { - parse(header.begin() + 6, header.end()); - } - else if (icompare(header, 0, 7, "Digest ") == 0) - { - parse(header.begin() + 7, header.end()); - } - else throw InvalidArgumentException("Invalid authentication scheme", header); + const std::string& header = it->second; + if (icompare(header, 0, 6, "Basic ") == 0) + { + parse(header.begin() + 6, header.end()); + found = true; + } + else if (icompare(header, 0, 7, "Digest ") == 0) + { + parse(header.begin() + 7, header.end()); + found = true; + } + ++it; + } + if (!found) throw NotAuthenticatedException("No Basic or Digest authentication header found"); } @@ -203,7 +212,7 @@ void HTTPAuthenticationParams::parse(std::string::const_iterator first, std::str switch (state) { case STATE_SPACE: - if (Ascii::isAlphaNumeric(*it)) + if (Ascii::isAlphaNumeric(*it) || *it == '_') { token += *it; state = STATE_TOKEN; @@ -220,7 +229,7 @@ void HTTPAuthenticationParams::parse(std::string::const_iterator first, std::str { state = STATE_EQUALS; } - else if (Ascii::isAlphaNumeric(*it)) + else if (Ascii::isAlphaNumeric(*it) || *it == '_') { token += *it; } @@ -228,7 +237,7 @@ void HTTPAuthenticationParams::parse(std::string::const_iterator first, std::str break; case STATE_EQUALS: - if (Ascii::isAlphaNumeric(*it)) + if (Ascii::isAlphaNumeric(*it) || *it == '_') { value += *it; state = STATE_VALUE; diff --git a/Net/src/HTTPClientSession.cpp b/Net/src/HTTPClientSession.cpp index 5e4d28d07..b79424217 100644 --- a/Net/src/HTTPClientSession.cpp +++ b/Net/src/HTTPClientSession.cpp @@ -1,7 +1,7 @@ // // HTTPClientSession.cpp // -// $Id: //poco/1.4/Net/src/HTTPClientSession.cpp#11 $ +// $Id: //poco/1.4/Net/src/HTTPClientSession.cpp#15 $ // // Library: Net // Package: HTTPClient @@ -25,7 +25,7 @@ #include "Poco/Net/NetException.h" #include "Poco/NumberFormatter.h" #include "Poco/CountingStream.h" -#include "Poco/Base64Encoder.h" +#include "Poco/RegularExpression.h" #include @@ -37,9 +37,12 @@ namespace Poco { namespace Net { +HTTPClientSession::ProxyConfig HTTPClientSession::_globalProxyConfig; + + HTTPClientSession::HTTPClientSession(): _port(HTTPSession::HTTP_PORT), - _proxyPort(HTTPSession::HTTP_PORT), + _proxyConfig(_globalProxyConfig), _keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0), _reconnect(false), _mustReconnect(false), @@ -51,7 +54,7 @@ HTTPClientSession::HTTPClientSession(): HTTPClientSession::HTTPClientSession(const StreamSocket& socket): HTTPSession(socket), _port(HTTPSession::HTTP_PORT), - _proxyPort(HTTPSession::HTTP_PORT), + _proxyConfig(_globalProxyConfig), _keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0), _reconnect(false), _mustReconnect(false), @@ -63,7 +66,7 @@ HTTPClientSession::HTTPClientSession(const StreamSocket& socket): HTTPClientSession::HTTPClientSession(const SocketAddress& address): _host(address.host().toString()), _port(address.port()), - _proxyPort(HTTPSession::HTTP_PORT), + _proxyConfig(_globalProxyConfig), _keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0), _reconnect(false), _mustReconnect(false), @@ -75,7 +78,19 @@ HTTPClientSession::HTTPClientSession(const SocketAddress& address): HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port): _host(host), _port(port), - _proxyPort(HTTPSession::HTTP_PORT), + _proxyConfig(_globalProxyConfig), + _keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0), + _reconnect(false), + _mustReconnect(false), + _expectResponseBody(false) +{ +} + + +HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port, const ProxyConfig& proxyConfig): + _host(host), + _port(port), + _proxyConfig(proxyConfig), _keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0), _reconnect(false), _mustReconnect(false), @@ -111,8 +126,8 @@ void HTTPClientSession::setProxy(const std::string& host, Poco::UInt16 port) { if (!connected()) { - _proxyHost = host; - _proxyPort = port; + _proxyConfig.host = host; + _proxyConfig.port = port; } else throw IllegalStateException("Cannot set the proxy host and port for an already connected session"); } @@ -121,7 +136,7 @@ void HTTPClientSession::setProxy(const std::string& host, Poco::UInt16 port) void HTTPClientSession::setProxyHost(const std::string& host) { if (!connected()) - _proxyHost = host; + _proxyConfig.host = host; else throw IllegalStateException("Cannot set the proxy host for an already connected session"); } @@ -130,7 +145,7 @@ void HTTPClientSession::setProxyHost(const std::string& host) void HTTPClientSession::setProxyPort(Poco::UInt16 port) { if (!connected()) - _proxyPort = port; + _proxyConfig.port = port; else throw IllegalStateException("Cannot set the proxy port number for an already connected session"); } @@ -138,23 +153,35 @@ void HTTPClientSession::setProxyPort(Poco::UInt16 port) void HTTPClientSession::setProxyCredentials(const std::string& username, const std::string& password) { - _proxyUsername = username; - _proxyPassword = password; + _proxyConfig.username = username; + _proxyConfig.password = password; } void HTTPClientSession::setProxyUsername(const std::string& username) { - _proxyUsername = username; + _proxyConfig.username = username; } void HTTPClientSession::setProxyPassword(const std::string& password) { - _proxyPassword = password; + _proxyConfig.password = password; } - + +void HTTPClientSession::setProxyConfig(const ProxyConfig& config) +{ + _proxyConfig = config; +} + + +void HTTPClientSession::setGlobalProxyConfig(const ProxyConfig& config) +{ + _globalProxyConfig = config; +} + + void HTTPClientSession::setKeepAliveTimeout(const Poco::Timespan& timeout) { _keepAliveTimeout = timeout; @@ -180,7 +207,7 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request) request.setKeepAlive(false); if (!request.has(HTTPRequest::HOST)) request.setHost(_host, _port); - if (!_proxyHost.empty()) + if (!_proxyConfig.host.empty() && !bypassProxy()) { request.setURI(proxyRequestPrefix() + request.getURI()); proxyAuthenticate(request); @@ -240,17 +267,13 @@ std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response) { response.read(his); } - catch (MessageException&) + catch (Exception&) { close(); if (networkException()) networkException()->rethrow(); else throw; - } - catch (Exception&) - { - close(); throw; } } @@ -312,14 +335,14 @@ int HTTPClientSession::write(const char* buffer, std::streamsize length) void HTTPClientSession::reconnect() { - if (_proxyHost.empty()) + if (_proxyConfig.host.empty() || bypassProxy()) { SocketAddress addr(_host, _port); connect(addr); } else { - SocketAddress addr(_proxyHost, _proxyPort); + SocketAddress addr(_proxyConfig.host, _proxyConfig.port); connect(addr); } } @@ -354,9 +377,9 @@ void HTTPClientSession::proxyAuthenticate(HTTPRequest& request) void HTTPClientSession::proxyAuthenticateImpl(HTTPRequest& request) { - if (!_proxyUsername.empty()) + if (!_proxyConfig.username.empty()) { - HTTPBasicCredentials creds(_proxyUsername, _proxyPassword); + HTTPBasicCredentials creds(_proxyConfig.username, _proxyConfig.password); creds.proxyAuthenticate(request); } } @@ -364,7 +387,8 @@ void HTTPClientSession::proxyAuthenticateImpl(HTTPRequest& request) StreamSocket HTTPClientSession::proxyConnect() { - HTTPClientSession proxySession(getProxyHost(), getProxyPort()); + ProxyConfig emptyProxyConfig; + HTTPClientSession proxySession(getProxyHost(), getProxyPort(), emptyProxyConfig); proxySession.setTimeout(getTimeout()); std::string targetAddress(_host); targetAddress.append(":"); @@ -390,4 +414,14 @@ void HTTPClientSession::proxyTunnel() } +bool HTTPClientSession::bypassProxy() const +{ + if (!_proxyConfig.nonProxyHosts.empty()) + { + return RegularExpression::match(_host, _proxyConfig.nonProxyHosts, RegularExpression::RE_CASELESS | RegularExpression::RE_ANCHORED); + } + else return false; +} + + } } // namespace Poco::Net diff --git a/Net/src/HTTPCredentials.cpp b/Net/src/HTTPCredentials.cpp index 4b576ffc6..78643912d 100644 --- a/Net/src/HTTPCredentials.cpp +++ b/Net/src/HTTPCredentials.cpp @@ -57,7 +57,7 @@ void HTTPCredentials::fromUserInfo(const std::string& userInfo) extractCredentials(userInfo, username, password); setUsername(username); setPassword(password); - // TODO: Reset digest state? + _digest.reset(); } @@ -69,13 +69,13 @@ void HTTPCredentials::fromURI(const URI& uri) extractCredentials(uri, username, password); setUsername(username); setPassword(password); - // TODO: Reset digest state? + _digest.reset(); } void HTTPCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response) { - for (HTTPResponse::ConstIterator iter = response.find("WWW-Authenticate"); iter != response.end(); ++iter) + for (HTTPResponse::ConstIterator iter = response.find(HTTPAuthenticationParams::WWW_AUTHENTICATE); iter != response.end(); ++iter) { if (isBasicCredentials(iter->second)) { @@ -111,7 +111,7 @@ void HTTPCredentials::updateAuthInfo(HTTPRequest& request) void HTTPCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response) { - for (HTTPResponse::ConstIterator iter = response.find("Proxy-Authenticate"); iter != response.end(); ++iter) + for (HTTPResponse::ConstIterator iter = response.find(HTTPAuthenticationParams::PROXY_AUTHENTICATE); iter != response.end(); ++iter) { if (isBasicCredentials(iter->second)) { diff --git a/Net/src/HTTPDigestCredentials.cpp b/Net/src/HTTPDigestCredentials.cpp index 94971db57..1ca2a7a38 100644 --- a/Net/src/HTTPDigestCredentials.cpp +++ b/Net/src/HTTPDigestCredentials.cpp @@ -104,6 +104,13 @@ HTTPDigestCredentials::~HTTPDigestCredentials() } +void HTTPDigestCredentials::reset() +{ + _requestAuthParams.clear(); + _nc.clear(); +} + + void HTTPDigestCredentials::setUsername(const std::string& username) { _username = username; @@ -138,7 +145,7 @@ void HTTPDigestCredentials::updateAuthInfo(HTTPRequest& request) void HTTPDigestCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response) { - proxyAuthenticate(request, HTTPAuthenticationParams(response)); + proxyAuthenticate(request, HTTPAuthenticationParams(response, HTTPAuthenticationParams::PROXY_AUTHENTICATE)); } diff --git a/Net/src/HTTPRequest.cpp b/Net/src/HTTPRequest.cpp index ac568f94c..74d3a5824 100644 --- a/Net/src/HTTPRequest.cpp +++ b/Net/src/HTTPRequest.cpp @@ -209,7 +209,6 @@ void HTTPRequest::read(std::istream& istr) uri.reserve(64); version.reserve(16); int ch = istr.get(); - if (istr.bad()) throw NetException("Network failure while reading HTTP request header"); if (istr.bad()) throw NetException("Error reading HTTP request header"); if (ch == eof) throw NoMessageException(); while (Poco::Ascii::isSpace(ch)) ch = istr.get(); @@ -259,5 +258,4 @@ void HTTPRequest::setCredentials(const std::string& header, const std::string& s } - } } // namespace Poco::Net diff --git a/Net/src/HTTPResponse.cpp b/Net/src/HTTPResponse.cpp index c6d40a658..854753996 100644 --- a/Net/src/HTTPResponse.cpp +++ b/Net/src/HTTPResponse.cpp @@ -208,6 +208,7 @@ void HTTPResponse::read(std::istream& istr) std::string reason; int ch = istr.get(); + if (istr.bad()) throw NetException("Error reading HTTP response header"); if (ch == eof) throw NoMessageException(); while (Poco::Ascii::isSpace(ch)) ch = istr.get(); if (ch == eof) throw MessageException("No HTTP response header"); diff --git a/Net/src/HTTPStreamFactory.cpp b/Net/src/HTTPStreamFactory.cpp index 85918dccc..a7b14ce31 100644 --- a/Net/src/HTTPStreamFactory.cpp +++ b/Net/src/HTTPStreamFactory.cpp @@ -87,10 +87,21 @@ std::istream* HTTPStreamFactory::open(const URI& uri) pSession = new HTTPClientSession(resolvedURI.getHost(), resolvedURI.getPort()); if (proxyUri.empty()) - pSession->setProxy(_proxyHost, _proxyPort); + { + if (!_proxyHost.empty()) + { + pSession->setProxy(_proxyHost, _proxyPort); + pSession->setProxyCredentials(_proxyUsername, _proxyPassword); + } + } else + { pSession->setProxy(proxyUri.getHost(), proxyUri.getPort()); - pSession->setProxyCredentials(_proxyUsername, _proxyPassword); + if (!_proxyUsername.empty()) + { + pSession->setProxyCredentials(_proxyUsername, _proxyPassword); + } + } } std::string path = resolvedURI.getPathAndQuery(); @@ -131,7 +142,8 @@ std::istream* HTTPStreamFactory::open(const URI& uri) // single request via the proxy. 305 responses MUST only be generated by origin servers. // only use for one single request! proxyUri.resolve(res.get("Location")); - delete pSession; pSession = 0; + delete pSession; + pSession = 0; retry = true; // only allow useproxy once } else if (res.getStatus() == HTTPResponse::HTTP_UNAUTHORIZED && !authorize) diff --git a/Net/src/IPAddress.cpp b/Net/src/IPAddress.cpp index 30e509002..783d90a81 100644 --- a/Net/src/IPAddress.cpp +++ b/Net/src/IPAddress.cpp @@ -53,7 +53,7 @@ IPAddress::IPAddress(const IPAddress& addr) if (addr.family() == IPv4) newIPv4(addr.addr()); else - newIPv6(addr.addr()); + newIPv6(addr.addr(), addr.scope()); } @@ -118,7 +118,7 @@ IPAddress::IPAddress(const std::string& addr, Family family) else if (family == IPv6) { IPv6AddressImpl addr6(IPv6AddressImpl::parse(addr)); - newIPv6(addr6.addr()); + newIPv6(addr6.addr(), addr6.scope()); return; } #endif @@ -128,7 +128,7 @@ IPAddress::IPAddress(const std::string& addr, Family family) IPAddress::IPAddress(const void* addr, poco_socklen_t length) #ifndef POCO_HAVE_ALIGNMENT -: _pImpl(0) + : _pImpl(0) #endif { if (length == sizeof(struct in_addr)) @@ -178,7 +178,7 @@ IPAddress::IPAddress(unsigned prefix, Family family) #if defined(_WIN32) IPAddress::IPAddress(const SOCKET_ADDRESS& socket_address) #ifndef POCO_HAVE_ALIGNMENT -: _pImpl(0) + : _pImpl(0) #endif { ADDRESS_FAMILY family = socket_address.lpSockaddr->sa_family; @@ -187,7 +187,7 @@ IPAddress::IPAddress(const SOCKET_ADDRESS& socket_address) #if defined(POCO_HAVE_IPv6) else if (family == AF_INET6) newIPv6(&reinterpret_cast(socket_address.lpSockaddr)->sin6_addr, - reinterpret_cast(socket_address.lpSockaddr)->sin6_scope_id); + reinterpret_cast(socket_address.lpSockaddr)->sin6_scope_id); #endif else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); } @@ -202,7 +202,7 @@ IPAddress::IPAddress(const struct sockaddr& sockaddr) #if defined(POCO_HAVE_IPv6) else if (family == AF_INET6) newIPv6(&reinterpret_cast(&sockaddr)->sin6_addr, - reinterpret_cast(&sockaddr)->sin6_scope_id); + reinterpret_cast(&sockaddr)->sin6_scope_id); #endif else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); } @@ -222,7 +222,7 @@ IPAddress& IPAddress::operator = (const IPAddress& addr) if (addr.family() == IPAddress::IPv4) newIPv4(addr.addr()); else - newIPv6(addr.addr()); + newIPv6(addr.addr(), addr.scope()); } return *this; } @@ -341,20 +341,20 @@ bool IPAddress::operator == (const IPAddress& a) const poco_socklen_t l1 = length(); poco_socklen_t l2 = a.length(); if (l1 == l2) + { +#if defined(POCO_HAVE_IPv6) + if ( scope() != a.scope() ) + return false; +#endif return std::memcmp(addr(), a.addr(), l1) == 0; - else - return false; + } + else return false; } bool IPAddress::operator != (const IPAddress& a) const { - poco_socklen_t l1 = length(); - poco_socklen_t l2 = a.length(); - if (l1 == l2) - return std::memcmp(addr(), a.addr(), l1) != 0; - else - return true; + return !(*this == a); } @@ -363,42 +363,32 @@ bool IPAddress::operator < (const IPAddress& a) const poco_socklen_t l1 = length(); poco_socklen_t l2 = a.length(); if (l1 == l2) + { +#if defined(POCO_HAVE_IPv6) + if ( scope() != a.scope() ) + return scope() < a.scope(); +#endif return std::memcmp(addr(), a.addr(), l1) < 0; - else - return l1 < l2; + } + else return l1 < l2; } bool IPAddress::operator <= (const IPAddress& a) const { - poco_socklen_t l1 = length(); - poco_socklen_t l2 = a.length(); - if (l1 == l2) - return std::memcmp(addr(), a.addr(), l1) <= 0; - else - return l1 < l2; + return !(a < *this); } bool IPAddress::operator > (const IPAddress& a) const { - poco_socklen_t l1 = length(); - poco_socklen_t l2 = a.length(); - if (l1 == l2) - return std::memcmp(addr(), a.addr(), l1) > 0; - else - return l1 > l2; + return a < *this; } bool IPAddress::operator >= (const IPAddress& a) const { - poco_socklen_t l1 = length(); - poco_socklen_t l2 = a.length(); - if (l1 == l2) - return std::memcmp(addr(), a.addr(), l1) >= 0; - else - return l1 > l2; + return !(*this < a); } @@ -415,16 +405,15 @@ IPAddress IPAddress::operator & (const IPAddress& other) const #if defined(POCO_HAVE_IPv6) else if (family() == IPv6) { - IPv6AddressImpl t(pImpl()->addr()); - IPv6AddressImpl o(other.pImpl()->addr()); - return IPAddress((t & o).addr(), sizeof(struct in6_addr)); + const IPv6AddressImpl t(pImpl()->addr(), pImpl()->scope()); + const IPv6AddressImpl o(other.pImpl()->addr(), other.pImpl()->scope()); + const IPv6AddressImpl r = t & o; + return IPAddress(r.addr(), r.scope(), sizeof(struct in6_addr)); } #endif - else - throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); + else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); } - else - throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); + else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); } @@ -441,16 +430,15 @@ IPAddress IPAddress::operator | (const IPAddress& other) const #if defined(POCO_HAVE_IPv6) else if (family() == IPv6) { - IPv6AddressImpl t(pImpl()->addr()); - IPv6AddressImpl o(other.pImpl()->addr()); - return IPAddress((t | o).addr(), sizeof(struct in6_addr)); + const IPv6AddressImpl t(pImpl()->addr(), pImpl()->scope()); + const IPv6AddressImpl o(other.pImpl()->addr(), other.pImpl()->scope()); + const IPv6AddressImpl r = t | o; + return IPAddress(r.addr(), r.scope(), sizeof(struct in6_addr)); } #endif - else - throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); + else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); } - else - throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); + else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); } @@ -467,16 +455,15 @@ IPAddress IPAddress::operator ^ (const IPAddress& other) const #if defined(POCO_HAVE_IPv6) else if (family() == IPv6) { - IPv6AddressImpl t(pImpl()->addr()); - IPv6AddressImpl o(other.pImpl()->addr()); - return IPAddress((t ^ o).addr(), sizeof(struct in6_addr)); + const IPv6AddressImpl t(pImpl()->addr(), pImpl()->scope()); + const IPv6AddressImpl o(other.pImpl()->addr(), other.pImpl()->scope()); + const IPv6AddressImpl r = t ^ o; + return IPAddress(r.addr(), r.scope(), sizeof(struct in6_addr)); } #endif - else - throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); + else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); } - else - throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); + else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); } @@ -490,12 +477,12 @@ IPAddress IPAddress::operator ~ () const #if defined(POCO_HAVE_IPv6) else if (family() == IPv6) { - IPv6AddressImpl self(this->pImpl()->addr()); - return IPAddress((~self).addr(), sizeof(struct in6_addr)); + const IPv6AddressImpl self(pImpl()->addr(), pImpl()->scope()); + const IPv6AddressImpl r = ~self; + return IPAddress(r.addr(), sizeof(struct in6_addr), r.scope()); } #endif - else - throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); + else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()"); } @@ -529,7 +516,7 @@ IPAddress IPAddress::parse(const std::string& addr) } - bool IPAddress::tryParse(const std::string& addr, IPAddress& result) +bool IPAddress::tryParse(const std::string& addr, IPAddress& result) { IPv4AddressImpl impl4(IPv4AddressImpl::parse(addr)); if (impl4 != IPv4AddressImpl() || trim(addr) == "0.0.0.0") @@ -541,11 +528,11 @@ IPAddress IPAddress::parse(const std::string& addr) IPv6AddressImpl impl6(IPv6AddressImpl::parse(addr)); if (impl6 != IPv6AddressImpl()) { - result.newIPv6(impl6.addr()); + result.newIPv6(impl6.addr(), impl6.scope()); return true; } #endif - return false; + return false; } diff --git a/Net/src/IPAddressImpl.cpp b/Net/src/IPAddressImpl.cpp index b237711b5..5097bbb5d 100644 --- a/Net/src/IPAddressImpl.cpp +++ b/Net/src/IPAddressImpl.cpp @@ -18,6 +18,7 @@ #include "Poco/Net/NetException.h" #include "Poco/RefCountedObject.h" #include "Poco/NumberFormatter.h" +#include "Poco/ByteOrder.h" #include "Poco/String.h" #include "Poco/Types.h" @@ -32,6 +33,7 @@ using Poco::UInt32; namespace { + template unsigned maskBits(T val, unsigned size) /// Returns the length of the mask (number of bits set in val). @@ -49,6 +51,7 @@ unsigned maskBits(T val, unsigned size) return size - count; } + } // namespace @@ -92,7 +95,7 @@ IPv4AddressImpl::IPv4AddressImpl(const void* addr) IPv4AddressImpl::IPv4AddressImpl(unsigned prefix) { UInt32 addr = (prefix == 32) ? 0xffffffff : ~(0xffffffff >> prefix); - _addr.s_addr = htonl(addr); + _addr.s_addr = ByteOrder::toNetwork(addr); } @@ -104,6 +107,9 @@ IPv4AddressImpl::IPv4AddressImpl(const IPv4AddressImpl& addr) IPv4AddressImpl& IPv4AddressImpl::operator = (const IPv4AddressImpl& addr) { + if (this == &addr) + return *this; + std::memcpy(&_addr, &addr._addr, sizeof(_addr)); return *this; } @@ -371,6 +377,9 @@ IPv6AddressImpl::IPv6AddressImpl(const IPv6AddressImpl& addr): _scope(addr._scop IPv6AddressImpl& IPv6AddressImpl::operator = (const IPv6AddressImpl& addr) { + if (this == &addr) + return *this; + _scope = addr._scope; std::memcpy(&_addr, &addr._addr, sizeof(_addr)); return *this; @@ -382,21 +391,31 @@ IPv6AddressImpl::IPv6AddressImpl(unsigned prefix): { unsigned i = 0; #ifdef POCO_OS_FAMILY_WINDOWS - for (; prefix >= 16; ++i, prefix -= 16) { + for (; prefix >= 16; ++i, prefix -= 16) + { _addr.s6_addr16[i] = 0xffff; } if (prefix > 0) - _addr.s6_addr16[i++] = htons(~(0xffff >> prefix)); + { + _addr.s6_addr16[i++] = ByteOrder::toNetwork(static_cast(~(0xffff >> prefix))); + } while (i < 8) + { _addr.s6_addr16[i++] = 0; + } #else - for (; prefix >= 32; ++i, prefix -= 32) { + for (; prefix >= 32; ++i, prefix -= 32) + { _addr.s6_addr32[i] = 0xffffffff; } if (prefix > 0) - _addr.s6_addr32[i++] = htonl(~(0xffffffffU >> prefix)); + { + _addr.s6_addr32[i++] = ByteOrder::toNetwork(~(0xffffffffU >> prefix)); + } while (i < 4) + { _addr.s6_addr32[i++] = 0; + } #endif } @@ -442,7 +461,7 @@ std::string IPv6AddressImpl::toString() const } } if (i > 0) result.append(":"); - if (i < 8) NumberFormatter::appendHex(result, ntohs(words[i++])); + if (i < 8) NumberFormatter::appendHex(result, ByteOrder::fromNetwork(words[i++])); } if (_scope > 0) { @@ -505,7 +524,7 @@ unsigned IPv6AddressImpl::prefixLength() const #elif defined(POCO_OS_FAMILY_WINDOWS) for (int i = 7; i >= 0; --i) { - unsigned short addr = ntohs(_addr.s6_addr16[i]); + unsigned short addr = ByteOrder::fromNetwork(_addr.s6_addr16[i]); if ((bits = maskBits(addr, 16))) return (bitPos - (16 - bits)); bitPos -= 16; } @@ -539,28 +558,28 @@ bool IPv6AddressImpl::isLoopback() const { const UInt16* words = reinterpret_cast(&_addr); return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && - words[4] == 0 && words[5] == 0 && words[6] == 0 && ntohs(words[7]) == 0x0001; + words[4] == 0 && words[5] == 0 && words[6] == 0 && ByteOrder::fromNetwork(words[7]) == 0x0001; } bool IPv6AddressImpl::isMulticast() const { const UInt16* words = reinterpret_cast(&_addr); - return (ntohs(words[0]) & 0xFFE0) == 0xFF00; + return (ByteOrder::fromNetwork(words[0]) & 0xFFE0) == 0xFF00; } bool IPv6AddressImpl::isLinkLocal() const { const UInt16* words = reinterpret_cast(&_addr); - return (ntohs(words[0]) & 0xFFE0) == 0xFE80; + return (ByteOrder::fromNetwork(words[0]) & 0xFFE0) == 0xFE80; } bool IPv6AddressImpl::isSiteLocal() const { const UInt16* words = reinterpret_cast(&_addr); - return ((ntohs(words[0]) & 0xFFE0) == 0xFEC0) || ((ntohs(words[0]) & 0xFF00) == 0xFC00); + return ((ByteOrder::fromNetwork(words[0]) & 0xFFE0) == 0xFEC0) || ((ByteOrder::fromNetwork(words[0]) & 0xFF00) == 0xFC00); } @@ -574,49 +593,49 @@ bool IPv6AddressImpl::isIPv4Compatible() const bool IPv6AddressImpl::isIPv4Mapped() const { const UInt16* words = reinterpret_cast(&_addr); - return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && ntohs(words[5]) == 0xFFFF; + return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && ByteOrder::fromNetwork(words[5]) == 0xFFFF; } bool IPv6AddressImpl::isWellKnownMC() const { const UInt16* words = reinterpret_cast(&_addr); - return (ntohs(words[0]) & 0xFFF0) == 0xFF00; + return (ByteOrder::fromNetwork(words[0]) & 0xFFF0) == 0xFF00; } bool IPv6AddressImpl::isNodeLocalMC() const { const UInt16* words = reinterpret_cast(&_addr); - return (ntohs(words[0]) & 0xFFEF) == 0xFF01; + return (ByteOrder::fromNetwork(words[0]) & 0xFFEF) == 0xFF01; } bool IPv6AddressImpl::isLinkLocalMC() const { const UInt16* words = reinterpret_cast(&_addr); - return (ntohs(words[0]) & 0xFFEF) == 0xFF02; + return (ByteOrder::fromNetwork(words[0]) & 0xFFEF) == 0xFF02; } bool IPv6AddressImpl::isSiteLocalMC() const { const UInt16* words = reinterpret_cast(&_addr); - return (ntohs(words[0]) & 0xFFEF) == 0xFF05; + return (ByteOrder::fromNetwork(words[0]) & 0xFFEF) == 0xFF05; } bool IPv6AddressImpl::isOrgLocalMC() const { const UInt16* words = reinterpret_cast(&_addr); - return (ntohs(words[0]) & 0xFFEF) == 0xFF08; + return (ByteOrder::fromNetwork(words[0]) & 0xFFEF) == 0xFF08; } bool IPv6AddressImpl::isGlobalMC() const { const UInt16* words = reinterpret_cast(&_addr); - return (ntohs(words[0]) & 0xFFEF) == 0xFF0F; + return (ByteOrder::fromNetwork(words[0]) & 0xFFEF) == 0xFF0F; } @@ -671,13 +690,16 @@ void IPv6AddressImpl::mask(const IPAddressImpl* pMask, const IPAddressImpl* pSet IPAddressImpl* IPv6AddressImpl::clone() const { - return new IPv6AddressImpl(&_addr, _scope); + return new IPv6AddressImpl(*this); } IPv6AddressImpl IPv6AddressImpl::operator & (const IPv6AddressImpl& addr) const { - IPv6AddressImpl result(&_addr); + if (_scope != addr._scope) + throw Poco::InvalidArgumentException("Scope ID of passed IPv6 address does not match with the source one."); + + IPv6AddressImpl result(*this); #ifdef POCO_OS_FAMILY_WINDOWS result._addr.s6_addr16[0] &= addr._addr.s6_addr16[0]; result._addr.s6_addr16[1] &= addr._addr.s6_addr16[1]; @@ -699,7 +721,10 @@ IPv6AddressImpl IPv6AddressImpl::operator & (const IPv6AddressImpl& addr) const IPv6AddressImpl IPv6AddressImpl::operator | (const IPv6AddressImpl& addr) const { - IPv6AddressImpl result(&_addr); + if (_scope != addr._scope) + throw Poco::InvalidArgumentException("Scope ID of passed IPv6 address does not match with the source one."); + + IPv6AddressImpl result(*this); #ifdef POCO_OS_FAMILY_WINDOWS result._addr.s6_addr16[0] |= addr._addr.s6_addr16[0]; result._addr.s6_addr16[1] |= addr._addr.s6_addr16[1]; @@ -721,7 +746,11 @@ IPv6AddressImpl IPv6AddressImpl::operator | (const IPv6AddressImpl& addr) const IPv6AddressImpl IPv6AddressImpl::operator ^ (const IPv6AddressImpl& addr) const { - IPv6AddressImpl result(&_addr); + if (_scope != addr._scope) + throw Poco::InvalidArgumentException("Scope ID of passed IPv6 address does not match with the source one."); + + IPv6AddressImpl result(*this); + #ifdef POCO_OS_FAMILY_WINDOWS result._addr.s6_addr16[0] ^= addr._addr.s6_addr16[0]; result._addr.s6_addr16[1] ^= addr._addr.s6_addr16[1]; @@ -743,7 +772,7 @@ IPv6AddressImpl IPv6AddressImpl::operator ^ (const IPv6AddressImpl& addr) const IPv6AddressImpl IPv6AddressImpl::operator ~ () const { - IPv6AddressImpl result(&_addr); + IPv6AddressImpl result(*this); #ifdef POCO_OS_FAMILY_WINDOWS result._addr.s6_addr16[0] ^= 0xffff; result._addr.s6_addr16[1] ^= 0xffff; @@ -765,7 +794,7 @@ IPv6AddressImpl IPv6AddressImpl::operator ~ () const bool IPv6AddressImpl::operator == (const IPv6AddressImpl& addr) const { - return 0 == std::memcmp(&addr._addr, &_addr, sizeof(_addr)); + return _scope == addr._scope && 0 == std::memcmp(&addr._addr, &_addr, sizeof(_addr)); } diff --git a/Net/src/NameValueCollection.cpp b/Net/src/NameValueCollection.cpp index df4a457cf..8f8b5f502 100644 --- a/Net/src/NameValueCollection.cpp +++ b/Net/src/NameValueCollection.cpp @@ -134,9 +134,9 @@ bool NameValueCollection::empty() const } -int NameValueCollection::size() const +std::size_t NameValueCollection::size() const { - return (int) _map.size(); + return _map.size(); } diff --git a/Net/src/OAuth10Credentials.cpp b/Net/src/OAuth10Credentials.cpp new file mode 100644 index 000000000..c0f6f01c7 --- /dev/null +++ b/Net/src/OAuth10Credentials.cpp @@ -0,0 +1,367 @@ +// +// OAuth10Credentials.cpp +// +// $Id$ +// +// Library: Net +// Package: OAuth +// Module: OAuth10Credentials +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/Net/OAuth10Credentials.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/HTMLForm.h" +#include "Poco/Net/NetException.h" +#include "Poco/Net/HTTPAuthenticationParams.h" +#include "Poco/SHA1Engine.h" +#include "Poco/HMACEngine.h" +#include "Poco/Base64Encoder.h" +#include "Poco/RandomStream.h" +#include "Poco/Timestamp.h" +#include "Poco/NumberParser.h" +#include "Poco/NumberFormatter.h" +#include "Poco/Format.h" +#include "Poco/String.h" +#include +#include + + +namespace Poco { +namespace Net { + + +const std::string OAuth10Credentials::SCHEME = "OAuth"; + + +OAuth10Credentials::OAuth10Credentials() +{ +} + + +OAuth10Credentials::OAuth10Credentials(const std::string& consumerKey, const std::string& consumerSecret): + _consumerKey(consumerKey), + _consumerSecret(consumerSecret) +{ +} + + +OAuth10Credentials::OAuth10Credentials(const std::string& consumerKey, const std::string& consumerSecret, const std::string& token, const std::string& tokenSecret): + _consumerKey(consumerKey), + _consumerSecret(consumerSecret), + _token(token), + _tokenSecret(tokenSecret) +{ +} + + +OAuth10Credentials::OAuth10Credentials(const Poco::Net::HTTPRequest& request) +{ + if (request.hasCredentials()) + { + std::string authScheme; + std::string authParams; + request.getCredentials(authScheme, authParams); + if (icompare(authScheme, SCHEME) == 0) + { + HTTPAuthenticationParams params(authParams); + std::string consumerKey = params.get("oauth_consumer_key", ""); + URI::decode(consumerKey, _consumerKey); + std::string token = params.get("oauth_token", ""); + URI::decode(token, _token); + std::string callback = params.get("oauth_callback", ""); + URI::decode(callback, _callback); + } + else throw NotAuthenticatedException("No OAuth credentials in Authorization header", authScheme); + } + else throw NotAuthenticatedException("No Authorization header found"); +} + + +OAuth10Credentials::~OAuth10Credentials() +{ +} + + +void OAuth10Credentials::setConsumerKey(const std::string& consumerKey) +{ + _consumerKey = consumerKey; +} + + +void OAuth10Credentials::setConsumerSecret(const std::string& consumerSecret) +{ + _consumerSecret = consumerSecret; +} + + +void OAuth10Credentials::setToken(const std::string& token) +{ + _token = token; +} + + +void OAuth10Credentials::setTokenSecret(const std::string& tokenSecret) +{ + _tokenSecret = tokenSecret; +} + + +void OAuth10Credentials::setRealm(const std::string& realm) +{ + _realm = realm; +} + + +void OAuth10Credentials::setCallback(const std::string& callback) +{ + _callback = callback; +} + + +void OAuth10Credentials::authenticate(HTTPRequest& request, const Poco::URI& uri, SignatureMethod method) +{ + HTMLForm emptyParams; + authenticate(request, uri, emptyParams, method); +} + + +void OAuth10Credentials::authenticate(HTTPRequest& request, const Poco::URI& uri, const Poco::Net::HTMLForm& params, SignatureMethod method) +{ + if (method == SIGN_PLAINTEXT) + { + signPlaintext(request); + } + else + { + URI uriWithoutQuery(uri); + uriWithoutQuery.setQuery(""); + uriWithoutQuery.setFragment(""); + signHMACSHA1(request, uriWithoutQuery.toString(), params); + } +} + + +bool OAuth10Credentials::verify(const HTTPRequest& request, const Poco::URI& uri) +{ + HTMLForm params; + return verify(request, uri, params); +} + + +bool OAuth10Credentials::verify(const HTTPRequest& request, const Poco::URI& uri, const Poco::Net::HTMLForm& params) +{ + if (request.hasCredentials()) + { + std::string authScheme; + std::string authParams; + request.getCredentials(authScheme, authParams); + if (icompare(authScheme, SCHEME) == 0) + { + HTTPAuthenticationParams oauthParams(authParams); + + std::string version = oauthParams.get("oauth_version", "1.0"); + if (version != "1.0") throw NotAuthenticatedException("Unsupported OAuth version", version); + + _consumerKey.clear(); + std::string consumerKey = oauthParams.get("oauth_consumer_key", ""); + URI::decode(consumerKey, _consumerKey); + + _token.clear(); + std::string token = oauthParams.get("oauth_token", ""); + URI::decode(token, _token); + + _callback.clear(); + std::string callback = oauthParams.get("oauth_callback", ""); + URI::decode(callback, _callback); + + std::string nonceEnc = oauthParams.get("oauth_nonce", ""); + std::string nonce; + URI::decode(nonceEnc, nonce); + + std::string timestamp = oauthParams.get("oauth_timestamp", ""); + + std::string method = oauthParams.get("oauth_signature_method", ""); + + std::string signatureEnc = oauthParams.get("oauth_signature", ""); + std::string signature; + URI::decode(signatureEnc, signature); + + std::string refSignature; + if (icompare(method, "PLAINTEXT") == 0) + { + refSignature = percentEncode(_consumerSecret); + refSignature += '&'; + refSignature += percentEncode(_tokenSecret); + } + else if (icompare(method, "HMAC-SHA1") == 0) + { + URI uriWithoutQuery(uri); + uriWithoutQuery.setQuery(""); + uriWithoutQuery.setFragment(""); + refSignature = createSignature(request, uriWithoutQuery.toString(), params, nonce, timestamp); + } + else throw NotAuthenticatedException("Unsupported OAuth signature method", method); + + return refSignature == signature; + } + else throw NotAuthenticatedException("No OAuth credentials found in Authorization header"); + } + else throw NotAuthenticatedException("No Authorization header found"); +} + + +void OAuth10Credentials::nonceAndTimestampForTesting(const std::string& nonce, const std::string& timestamp) +{ + _nonce = nonce; + _timestamp = timestamp; +} + + +void OAuth10Credentials::signPlaintext(Poco::Net::HTTPRequest& request) const +{ + std::string signature(percentEncode(_consumerSecret)); + signature += '&'; + signature += percentEncode(_tokenSecret); + + std::string authorization(SCHEME); + if (!_realm.empty()) + { + Poco::format(authorization, " realm=\"%s\",", _realm); + } + Poco::format(authorization, " oauth_consumer_key=\"%s\"", percentEncode(_consumerKey)); + Poco::format(authorization, ", oauth_signature=\"%s\"", percentEncode(signature)); + authorization += ", oauth_signature_method=\"PLAINTEXT\""; + if (!_token.empty()) + { + Poco::format(authorization, ", oauth_token=\"%s\"", percentEncode(_token)); + } + if (!_callback.empty()) + { + Poco::format(authorization, ", oauth_callback=\"%s\"", percentEncode(_callback)); + } + authorization += ", oauth_version=\"1.0\""; + + request.set(HTTPRequest::AUTHORIZATION, authorization); +} + + +void OAuth10Credentials::signHMACSHA1(Poco::Net::HTTPRequest& request, const std::string& uri, const Poco::Net::HTMLForm& params) const +{ + std::string nonce(_nonce); + if (nonce.empty()) + { + nonce = createNonce(); + } + std::string timestamp(_timestamp); + if (timestamp.empty()) + { + timestamp = Poco::NumberFormatter::format(Poco::Timestamp().epochTime()); + } + std::string signature(createSignature(request, uri, params, nonce, timestamp)); + + std::string authorization(SCHEME); + if (!_realm.empty()) + { + Poco::format(authorization, " realm=\"%s\",", _realm); + } + Poco::format(authorization, " oauth_consumer_key=\"%s\"", percentEncode(_consumerKey)); + Poco::format(authorization, ", oauth_nonce=\"%s\"", percentEncode(nonce)); + Poco::format(authorization, ", oauth_signature=\"%s\"", percentEncode(signature)); + authorization += ", oauth_signature_method=\"HMAC-SHA1\""; + Poco::format(authorization, ", oauth_timestamp=\"%s\"", timestamp); + if (!_token.empty()) + { + Poco::format(authorization, ", oauth_token=\"%s\"", percentEncode(_token)); + } + if (!_callback.empty()) + { + Poco::format(authorization, ", oauth_callback=\"%s\"", percentEncode(_callback)); + } + authorization += ", oauth_version=\"1.0\""; + + request.set(HTTPRequest::AUTHORIZATION, authorization); +} + + +std::string OAuth10Credentials::createNonce() const +{ + std::ostringstream base64Nonce; + Poco::Base64Encoder base64Encoder(base64Nonce); + Poco::RandomInputStream randomStream; + for (int i = 0; i < 32; i++) + { + base64Encoder.put(randomStream.get()); + } + base64Encoder.close(); + std::string nonce = base64Nonce.str(); + return Poco::translate(nonce, "+/=", ""); +} + + +std::string OAuth10Credentials::createSignature(const Poco::Net::HTTPRequest& request, const std::string& uri, const Poco::Net::HTMLForm& params, const std::string& nonce, const std::string& timestamp) const +{ + std::map paramsMap; + paramsMap["oauth_version"] = "1.0"; + paramsMap["oauth_consumer_key"] = percentEncode(_consumerKey); + paramsMap["oauth_nonce"] = percentEncode(nonce); + paramsMap["oauth_signature_method"] = "HMAC-SHA1"; + paramsMap["oauth_timestamp"] = timestamp; + if (!_token.empty()) + { + paramsMap["oauth_token"] = percentEncode(_token); + } + if (!_callback.empty()) + { + paramsMap["oauth_callback"] = percentEncode(_callback); + } + for (Poco::Net::HTMLForm::ConstIterator it = params.begin(); it != params.end(); ++it) + { + paramsMap[percentEncode(it->first)] = percentEncode(it->second); + } + + std::string paramsString; + for (std::map::const_iterator it = paramsMap.begin(); it != paramsMap.end(); ++it) + { + if (it != paramsMap.begin()) paramsString += '&'; + paramsString += it->first; + paramsString += "="; + paramsString += it->second; + } + + std::string signatureBase = request.getMethod(); + signatureBase += '&'; + signatureBase += percentEncode(uri); + signatureBase += '&'; + signatureBase += percentEncode(paramsString); + + std::string signingKey; + signingKey += percentEncode(_consumerSecret); + signingKey += '&'; + signingKey += percentEncode(_tokenSecret); + + Poco::HMACEngine hmacEngine(signingKey); + hmacEngine.update(signatureBase); + Poco::DigestEngine::Digest digest = hmacEngine.digest(); + std::ostringstream digestBase64; + Poco::Base64Encoder base64Encoder(digestBase64); + base64Encoder.write(reinterpret_cast(&digest[0]), digest.size()); + base64Encoder.close(); + return digestBase64.str(); +} + + +std::string OAuth10Credentials::percentEncode(const std::string& str) +{ + std::string encoded; + Poco::URI::encode(str, "!?#/'\",;:$&()[]*+=@", encoded); + return encoded; +} + + +} } // namespace Poco::Net diff --git a/Net/src/OAuth20Credentials.cpp b/Net/src/OAuth20Credentials.cpp new file mode 100644 index 000000000..36e79701d --- /dev/null +++ b/Net/src/OAuth20Credentials.cpp @@ -0,0 +1,107 @@ +// +// OAuth20Credentials.cpp +// +// $Id$ +// +// Library: Net +// Package: OAuth +// Module: OAuth20Credentials +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/Net/OAuth20Credentials.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/NetException.h" +#include "Poco/String.h" + + +namespace Poco { +namespace Net { + + +const std::string OAuth20Credentials::SCHEME = "Bearer"; + + +OAuth20Credentials::OAuth20Credentials(): + _scheme(SCHEME) +{ +} + + +OAuth20Credentials::OAuth20Credentials(const std::string& bearerToken): + _bearerToken(bearerToken), + _scheme(SCHEME) +{ +} + + +OAuth20Credentials::OAuth20Credentials(const std::string& bearerToken, const std::string& scheme): + _bearerToken(bearerToken), + _scheme(scheme) +{ +} + + +OAuth20Credentials::OAuth20Credentials(const HTTPRequest& request): + _scheme(SCHEME) +{ + extractBearerToken(request); +} + + +OAuth20Credentials::OAuth20Credentials(const HTTPRequest& request, const std::string& scheme): + _scheme(scheme) +{ + extractBearerToken(request); +} + + +OAuth20Credentials::~OAuth20Credentials() +{ +} + + +void OAuth20Credentials::setBearerToken(const std::string& bearerToken) +{ + _bearerToken = bearerToken; +} + + +void OAuth20Credentials::setScheme(const std::string& scheme) +{ + _scheme = scheme; +} + + +void OAuth20Credentials::authenticate(HTTPRequest& request) +{ + std::string auth(_scheme); + auth += ' '; + auth += _bearerToken; + request.set(HTTPRequest::AUTHORIZATION, auth); +} + + +void OAuth20Credentials::extractBearerToken(const HTTPRequest& request) +{ + if (request.hasCredentials()) + { + std::string authScheme; + std::string authInfo; + request.getCredentials(authScheme, authInfo); + if (icompare(authScheme, _scheme) == 0) + { + _bearerToken = authInfo; + } + else throw NotAuthenticatedException("No bearer token in Authorization header", authScheme); + } + else throw NotAuthenticatedException("No Authorization header found"); +} + + +} } // namespace Poco::Net diff --git a/Net/src/POP3ClientSession.cpp b/Net/src/POP3ClientSession.cpp index 1fd2f7e33..b6eadd577 100644 --- a/Net/src/POP3ClientSession.cpp +++ b/Net/src/POP3ClientSession.cpp @@ -196,7 +196,7 @@ void POP3ClientSession::retrieveMessage(int id, MailMessage& message) { std::string response; sendCommand("RETR", NumberFormatter::format(id), response); - if (!isPositive(response)) throw POP3Exception("Cannot get message list", response); + if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response); DialogInputStream sis(_socket); MailInputStream mis(sis); message.read(mis); @@ -208,7 +208,7 @@ void POP3ClientSession::retrieveMessage(int id, MailMessage& message, PartHandle { std::string response; sendCommand("RETR", NumberFormatter::format(id), response); - if (!isPositive(response)) throw POP3Exception("Cannot get message list", response); + if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response); DialogInputStream sis(_socket); MailInputStream mis(sis); message.read(mis, handler); @@ -220,7 +220,7 @@ void POP3ClientSession::retrieveMessage(int id, std::ostream& ostr) { std::string response; sendCommand("RETR", NumberFormatter::format(id), response); - if (!isPositive(response)) throw POP3Exception("Cannot get message list", response); + if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response); DialogInputStream sis(_socket); MailInputStream mis(sis); StreamCopier::copyStream(mis, ostr); @@ -231,7 +231,7 @@ void POP3ClientSession::retrieveHeader(int id, MessageHeader& header) { std::string response; sendCommand("TOP", NumberFormatter::format(id), "0", response); - if (!isPositive(response)) throw POP3Exception("Cannot get message list", response); + if (!isPositive(response)) throw POP3Exception("Cannot retrieve header", response); DialogInputStream sis(_socket); MailInputStream mis(sis); header.read(mis); diff --git a/Net/src/SocketReactor.cpp b/Net/src/SocketReactor.cpp index 19aeb88d2..fb43589d1 100644 --- a/Net/src/SocketReactor.cpp +++ b/Net/src/SocketReactor.cpp @@ -39,7 +39,8 @@ SocketReactor::SocketReactor(): _pErrorNotification(new ErrorNotification(this)), _pTimeoutNotification(new TimeoutNotification(this)), _pIdleNotification(new IdleNotification(this)), - _pShutdownNotification(new ShutdownNotification(this)) + _pShutdownNotification(new ShutdownNotification(this)), + _pThread(0) { } @@ -52,7 +53,8 @@ SocketReactor::SocketReactor(const Poco::Timespan& timeout): _pErrorNotification(new ErrorNotification(this)), _pTimeoutNotification(new TimeoutNotification(this)), _pIdleNotification(new IdleNotification(this)), - _pShutdownNotification(new ShutdownNotification(this)) + _pShutdownNotification(new ShutdownNotification(this)), + _pThread(0) { } @@ -64,6 +66,8 @@ SocketReactor::~SocketReactor() void SocketReactor::run() { + _pThread = Thread::current(); + Socket::SocketList readable; Socket::SocketList writable; Socket::SocketList except; @@ -100,6 +104,7 @@ void SocketReactor::run() if (nSockets == 0) { onIdle(); + Thread::trySleep(_timeout.milliseconds()); } else if (Socket::select(readable, writable, except, _timeout)) { @@ -130,19 +135,25 @@ void SocketReactor::run() onShutdown(); } - + void SocketReactor::stop() { _stop = true; } +void SocketReactor::wakeUp() +{ + if (_pThread) _pThread->wakeUp(); +} + + void SocketReactor::setTimeout(const Poco::Timespan& timeout) { _timeout = timeout; } - + const Poco::Timespan& SocketReactor::getTimeout() const { return _timeout; diff --git a/Net/testsuite/Makefile b/Net/testsuite/Makefile index 0bb0d96fe..1f0d65f31 100644 --- a/Net/testsuite/Makefile +++ b/Net/testsuite/Makefile @@ -27,7 +27,8 @@ objects = \ RawSocketTest ICMPClientTest ICMPSocketTest ICMPClientTestSuite \ NTPClientTest NTPClientTestSuite \ WebSocketTest WebSocketTestSuite \ - SyslogTest + SyslogTest \ + OAuth10CredentialsTest OAuth20CredentialsTest OAuthTestSuite target = testrunner target_version = 1 diff --git a/Net/testsuite/TestSuite_CE_vs90.vcproj b/Net/testsuite/TestSuite_CE_vs90.vcproj index 250722ab9..921069414 100644 --- a/Net/testsuite/TestSuite_CE_vs90.vcproj +++ b/Net/testsuite/TestSuite_CE_vs90.vcproj @@ -842,6 +842,27 @@ RelativePath=".\src\WebSocketTestSuite.cpp"/> + + + + + + + + + + + + diff --git a/Net/testsuite/TestSuite_WEC2013_vs110.vcxproj b/Net/testsuite/TestSuite_WEC2013_vs110.vcxproj index b0876af42..b652a0385 100644 --- a/Net/testsuite/TestSuite_WEC2013_vs110.vcxproj +++ b/Net/testsuite/TestSuite_WEC2013_vs110.vcxproj @@ -364,6 +364,9 @@ + + + @@ -424,6 +427,9 @@ + + + diff --git a/Net/testsuite/TestSuite_WEC2013_vs110.vcxproj.filters b/Net/testsuite/TestSuite_WEC2013_vs110.vcxproj.filters index 17d428391..c2e0bc038 100644 --- a/Net/testsuite/TestSuite_WEC2013_vs110.vcxproj.filters +++ b/Net/testsuite/TestSuite_WEC2013_vs110.vcxproj.filters @@ -2,154 +2,163 @@ - {686392ac-5b73-4f61-828b-2757431259e2} + {f6d72736-2f58-4111-b0c0-63c8b8d68ec4} - {00a2a9c4-2c45-45d4-8d05-95a7d9a141a9} + {453f97a0-d526-4f86-8c4f-c9d19cb5ecb4} - {0c6ea42d-2752-4367-8590-6f4165148ecd} + {3b8f1217-0a4e-41fd-b0ae-8108ef550b12} - {185648ee-bfd4-494a-bfdd-57bf1d881323} + {e076dcc7-015d-4200-bb47-32da68231264} - {f51f8d1e-df45-4510-97c8-5281b48bb441} + {b7ee90ce-d9a2-43ba-85c2-f1be3348db17} - {3f6667bd-cf83-44f4-9bf7-20171623f19d} + {39ef4797-ffd6-404e-9c68-9d54130d795c} - {5d439061-40d4-43c6-a8ed-22c3c4d690a6} + {fb8e00ba-4c2a-472a-98bb-4d1930bb15c5} - {7ae235c5-5891-40e3-a3f0-5f442e5cb56e} + {88ea4954-0fea-49bf-88e6-9a60d35ef399} - {a66ba89e-2e0b-4c7f-afc1-7383ecbeaad0} + {fa39e6e8-1a01-40a1-a9dc-9ed0b2c6265c} - {c8105844-50dd-4bb3-8528-e8d97ecddf19} + {3b557eff-97a0-4a7f-91d1-c4c756ec780b} - {bd3e9226-c715-4747-806c-fb02d4a6cb3a} + {3e74b566-3fdf-4872-b8b3-d73b604e6ffc} - {563ed0ed-459d-4c22-aa12-91a29e497a4c} + {f7883531-a60d-4e7b-ac41-269324030a92} - {7ab4648c-a176-4acf-9c42-787af9ec8f42} + {a4fbfd17-93f2-4116-a67b-0cee3c0bdb5e} - {996f708f-e31b-4477-92ab-0fd871796ba0} + {c1cb02cd-550c-4654-98f4-eac2e9306455} - {3e2b8de3-af93-4186-b0bf-9e0969a5662d} + {02d05ce3-b7f4-4dd0-b859-8cbd5a19d589} - {6428664b-276c-4cd5-aefa-c572938492ea} + {684a1675-a9b3-4498-b807-96009db6b99a} - {e9bc4f89-4606-422e-9e81-03093a4eb43e} + {2e3ce2db-71ba-4404-ba03-8e8bb7fff2b2} - {ed703f45-16f7-43d7-b44d-765948722082} + {51665d9d-b1a5-4dba-af03-5242e57f279d} - {5c835c13-d1e1-4668-8f6f-c410e30c889c} + {69f42a83-97ed-4e3a-a17f-f1d572fabaff} - {fcd184b2-1296-4790-845e-4f3dc2cd3a2e} + {6070cd50-7eba-4fa4-87aa-55bebbae0459} - {c0ce67b7-e72a-40ad-8537-2e9034755fec} + {56955e99-66da-4075-a841-206d6750cc7c} - {74fa69fc-a1c9-403a-ae9d-1690caed93f3} + {68d39f16-1e27-408b-8513-ddb49cd5e3df} - {caf3e2d9-1825-4cf2-b30e-b10f07735f16} + {49a8d3fc-37fb-4f99-b64b-b065e4ae1494} - {96ca91e6-bff6-49cf-ab82-2b09815346d3} + {571bb3c7-a860-4063-9a88-31a21e254079} - {7370234a-13aa-4161-8133-d0e41c284085} + {9d8783e2-a742-48ab-a24b-d8d9af3e90e0} - {d7d57527-1a91-4ec3-bcad-e268944b9e6c} + {23bc882a-e95b-4efe-94bb-7a0f67f066f5} - {be189aca-e774-4637-a67b-9c8ef69b3613} + {65785ef5-deb4-464e-a08a-aeea0754e8e1} - {96457215-f952-4f6f-9b12-a74a6a350cc6} + {526bff52-410b-4c88-b3a7-cd644404ab21} - {ab04c4f2-8b57-475d-acfb-64a0ebd1b2ff} + {f7711652-b692-418b-a58d-1a6f67e08346} - {988ab614-fdcb-4852-9957-6615e83b8295} + {8cc0ea5c-c9be-48aa-892b-780335ebf84b} - {1e2ff033-4d89-44ea-945a-ef2869a549f5} + {2f315b4c-9515-4dbe-a7e2-4f2211a1ca2a} - {8da2702f-09cf-4052-801b-7ecdd6168a43} + {931defb5-b289-44f3-b214-a861adffc299} - {7b5c33a2-aec2-488d-ae8d-89a12801b1b6} + {6b107bca-2cdf-48cc-90ab-2c802ff3c03d} - {a0f32b3e-46cb-4825-a073-df773b728fd6} + {92b12255-8f79-4621-b5e4-5a03715c6270} - {ffbbc606-5de0-4f0a-9829-74bfd11eb60b} + {2164b5a2-58ba-4ffc-971a-838287730d53} - {1d58b254-90de-4715-b33a-128d033f5336} + {0eadb69e-c4f2-4b52-a5c7-d3d21eedef7d} - {22a3942d-6948-4be2-94fd-0dfedc2b7c82} + {30f29edc-3e16-4093-a2b0-38fe911ea843} - {458742cc-e064-4983-aff3-dcc8979b85c1} + {471485c4-fc24-4dbb-bee4-3f0746d59829} - {f83b745a-8ddf-43fd-b0a4-2259e5104da6} + {77edceeb-9218-4acd-afd4-62f0c4c65710} - {e321f502-bad8-4e01-bde0-57ba4f487774} + {4353760c-205b-40e2-93fc-97333f356f07} - {64e6c7d6-e380-4c9f-b7f9-c8aba948ac10} + {1e2c92c1-75f3-45e7-a997-60787dc2ab16} - {8f141371-fb8e-4b39-bf51-2efed37a5ed9} + {efd516e3-534a-4819-b489-502be54c194c} - {c6e2d2da-02e0-4e90-b253-e9193d8ad5cb} + {6139f9e4-b6a4-4ba4-a265-dd55a6366506} - {be9d2d9b-da87-444a-9eb5-034a3ff5a42d} + {3572bb06-a4a6-4cb2-8465-2fc6fb2b6e34} - {dffd2025-69ca-4850-a2de-f5d012c1ecc7} + {a926bee4-4ea3-42af-b82e-db4b85734059} - {5660e5f6-9a66-4d7c-a23c-1f3772ce140c} + {840af821-8b06-4cde-b5bd-2a5490e3c4f8} - {6134f9bb-bfa5-437b-90cb-d5492b4a1222} + {eb95e9d0-be1a-4949-9e54-f09e491501f7} - {65452f8d-802b-41ce-9d19-20d1dfb1c391} + {d70a803c-808f-4977-87f7-f4ee815f579a} - {2830b90b-7846-46f1-b76a-dccfe9541f77} + {e54b8a4d-7fcc-49ab-8ecc-22eb68c8dbb0} - {4994d211-ca8b-4252-b8c5-17e6b1738148} + {f2d07840-92ac-4b57-b6fa-68e7e19c5898} + + + {4c7ef5b3-f1d0-471d-b9f7-c83e0ef98174} + + + {d470c326-659d-4a9f-b5c9-e32ef1ea0b8d} + + + {10ff6b87-0fe2-493d-95e8-e87ff5f5ba39} @@ -324,6 +333,15 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + + + OAuth\Header Files + @@ -500,5 +518,14 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + + + OAuth\Source Files + \ No newline at end of file diff --git a/Net/testsuite/TestSuite_WEC2013_vs120.vcxproj b/Net/testsuite/TestSuite_WEC2013_vs120.vcxproj index 1d94dfb25..642720242 100644 --- a/Net/testsuite/TestSuite_WEC2013_vs120.vcxproj +++ b/Net/testsuite/TestSuite_WEC2013_vs120.vcxproj @@ -348,6 +348,9 @@ + + + @@ -407,6 +410,9 @@ + + + diff --git a/Net/testsuite/TestSuite_WEC2013_vs120.vcxproj.filters b/Net/testsuite/TestSuite_WEC2013_vs120.vcxproj.filters index f6a9fba48..8154537e2 100644 --- a/Net/testsuite/TestSuite_WEC2013_vs120.vcxproj.filters +++ b/Net/testsuite/TestSuite_WEC2013_vs120.vcxproj.filters @@ -2,154 +2,163 @@ - {9c28c7cb-d3b6-4f27-a6d6-48ebab42dc8c} + {2bd1f8fe-1412-45c0-a23d-89e52dbdd4b4} - {cbd28011-235d-4528-8af9-fcbf7a24de11} + {b4bd6202-257e-4f57-870e-1bd0b9d68049} - {25b58175-9a9c-4ae4-92a0-ded234aa5173} + {8360e937-e241-43bd-b865-82651ff90ba8} - {d6c548e9-4954-4927-8a0b-e32abad65075} + {fdd84d6b-fc87-4218-ad50-383bb1bc886f} - {b7ab26bd-c75d-4727-9b73-10e618ea2a47} + {4d20c140-2509-4497-915f-f2fb0946dbaa} - {d65c458c-e60a-4614-9314-b18c401c4150} + {643fcdf8-b98a-47fd-aef1-3ab07325e6a1} - {d1d21b95-cc94-4240-8058-f5517400ae2d} + {6e325364-4b10-421c-9ec2-64a05003a6dc} - {e5c3baa9-81c1-425e-9564-799d1e0f3847} + {34e817e2-de4a-4b97-8027-541477411804} - {19e58bd8-c637-41a1-8755-32a8b47a4294} + {f71ec148-3505-49ab-ab85-680cd4a26d8a} - {703de9e5-c997-438c-b486-f8cb2c16c41f} + {ee6c34b2-0f90-467c-8946-525166c52c7f} - {5fcce864-91c0-445c-ade4-24b867be48df} + {d508cada-f5db-4102-9b67-8139048e010e} - {451bc5a3-537d-4d9d-afc5-5a612cc2252a} + {7ca219c1-cdb8-46be-9f1f-93e2ee1c82a3} - {ee81089d-db20-4904-9a3e-593c8ff9cb03} + {a49bb03c-ea81-4d0d-9eba-2a48d253844b} - {1a0eaef2-630b-4774-b9a9-1a58838b827c} + {c06a500f-2823-4542-8c9c-44174b5a7961} - {46b2b599-16b0-4c5b-8b1f-abfd6dbc7832} + {eaa654e8-b589-4d68-8a76-63fc0014c505} - {a21f40b9-953e-4bb3-9783-924909cbb6d6} + {a824f9c9-b830-49e2-924c-aa62ba4dbb20} - {691611fe-e0aa-411b-9ccf-00ac0ba27bf6} + {9e336778-c9ab-466c-bbb4-779a4e543977} - {1f3671fb-bc14-4571-9329-7ea710c4e681} + {8035cdf7-e4d0-4535-b312-17a26b8a6b31} - {f69dfe3d-650b-4317-b391-a8bcde36bbe4} + {65c4a284-39d6-493a-9917-e1cb212b2651} - {df068bd7-8093-4cc5-9db3-72365e587152} + {63157483-e22b-47ed-8292-82a164317f42} - {7c0d39ed-7c6b-437b-949d-ad1f5428e4c2} + {e0060551-d83c-4b66-a867-a20d18716038} - {eb0bd197-15f8-475b-ac5f-cfc6b0c75e92} + {b7ee6a09-a2ae-40e2-8273-d39f619f2ef7} - {5c00d788-0642-4de5-ab0f-83b1be2b675f} + {4c154296-e6f6-41e2-b9f3-7ab483c86616} - {52c3d517-73f7-4e4d-ab1c-3bcfa44a89cd} + {8c6b59cd-4191-4bdc-83e0-2ecb2e18ecfc} - {5bb37ddb-f3f7-4786-83e5-1ce009198754} + {efd1305e-bf99-4f9e-9a49-4bcbe837b911} - {ce08125b-1be6-4631-aba5-cdeb44308436} + {a90c4281-6322-41f7-b30f-16c84da1abce} - {8613611a-b99d-4b52-871b-ca023ea95e96} + {dc473a32-0807-459f-bd5d-583f218832c8} - {101deb25-da77-4b78-967b-292ada2709b2} + {403c280d-f7a3-498d-995e-54488a715757} - {9122e20d-73ea-416a-80a1-ded475d158a9} + {c030e3eb-956b-4545-a483-170c99644828} - {643945f8-e9c5-4a4c-adc4-eaf75b6ca069} + {2010d543-16e6-4bda-9084-145a2d82ce54} - {4d6d1f7c-2c67-49d2-b559-79bc6f50471a} + {224cd726-03cc-40e7-b8e9-ac11822ff6c4} - {5f661718-77c3-4452-a5df-da80fd1e6d0c} + {106c996e-0aab-46fd-904d-b3bb6b50b0c1} - {894dbf1f-9605-42d9-885a-bb2cd23e17cd} + {5ec07142-ddfd-4fb4-9910-8f2dda8a353a} - {030d9c38-dee7-4089-92db-497f0c8629bb} + {059b3c92-669b-47de-98f7-475e5b34d20f} - {c0f08fa3-dc02-449d-9172-f1b26b6d7ee7} + {166c9ced-d884-4d16-b78f-30f5c10f1fd9} - {e7fa24db-1b7d-46e0-b9a6-527a85a6ea81} + {de315fb9-05b7-4444-a8b9-e5c2baf3b987} - {4c517396-b24a-41b8-a4df-d2b6ac5f9bc1} + {194ccaba-425f-448f-9723-09eea47d0077} - {df6111db-b7e0-4aba-9e56-9b6ad999f416} + {d2e78f0c-5780-43ac-b53a-7416d6b6cf4d} - {6017ffd9-fe72-4fbf-b076-f186a18708ca} + {429e234c-f3c0-48a5-afbc-700f16afa43f} - {8214187f-6c2c-497c-848f-eead15ccfd09} + {c4b5e147-6a5c-45bc-afe7-515cc401e9c7} - {207d8b27-e6bf-476f-b94f-92bb9931d296} + {594a3af0-70c8-4511-8876-a2d27ace4cd5} - {d06b49a4-25b0-4f87-b5d1-f988f8c2db5a} + {7bc332cd-37ce-406c-a99a-3d80a5f2eb58} - {f288c515-062f-4819-962c-dd5e2360893d} + {7adeb69e-aa4a-4a93-8c45-9e2d14857e72} - {25856364-b6a1-4aea-ab32-601c7afc50df} + {c281b6be-0094-4220-b19a-9c55c246f521} - {f9b99370-27d2-45fb-b4f5-31cd4f9e272b} + {b6e712a7-3db1-4766-bd26-b8c71149e0cf} - {ac595e19-59f6-4ef8-acc0-01be31a39e80} + {c16bd40d-d0f1-40c2-934c-000909e0652c} - {16b13a17-8b25-48db-a5a0-c0a6eed3f6cb} + {16ae1de6-daa3-4e7b-80e0-b36c3df68a85} - {981fb239-64b1-4c5c-9cd1-01e2f57cba2e} + {b135525a-7e27-4a26-ba70-f25914724cc5} - {6b97c67a-1df8-46ad-b899-765881bf9e3f} + {a3478248-0a62-45a6-9fc3-87844e3b7ec9} - {00d20e48-2aca-4556-9f65-9186b18d50a6} + {da6412bf-add2-4bb8-8d6a-4a54936b7474} + + + {256a0a77-6ea3-4dd2-8c74-cb2c95a22884} + + + {86b9e7f8-1459-43e9-9838-20f82cd2996c} + + + {0235f4fe-33d0-497e-a87d-e476cf26d850} @@ -324,6 +333,15 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + + + OAuth\Header Files + @@ -500,5 +518,14 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + + + OAuth\Source Files + \ No newline at end of file diff --git a/Net/testsuite/TestSuite_vs100.vcxproj b/Net/testsuite/TestSuite_vs100.vcxproj index 4adfe0ced..cadb4fa7e 100644 --- a/Net/testsuite/TestSuite_vs100.vcxproj +++ b/Net/testsuite/TestSuite_vs100.vcxproj @@ -369,6 +369,9 @@ + + + @@ -429,6 +432,9 @@ + + + diff --git a/Net/testsuite/TestSuite_vs100.vcxproj.filters b/Net/testsuite/TestSuite_vs100.vcxproj.filters index 1b60e8e4b..332248d1f 100644 --- a/Net/testsuite/TestSuite_vs100.vcxproj.filters +++ b/Net/testsuite/TestSuite_vs100.vcxproj.filters @@ -2,154 +2,163 @@ - {9a50e11c-540c-49cb-9d0c-12bbeb25e111} + {6331ce60-a0f7-4ed8-b0e5-73ef30834fc3} - {820d50aa-729c-4013-9096-92f4622b2480} + {47799602-82a4-4d7d-a4ce-c28954025e0e} - {76548a4b-3072-4a10-aae7-fce8fb10ab30} + {15f9a62d-a873-4994-9354-e89c35242923} - {83992b21-601d-4bca-b48f-bd598a293816} + {5c74c459-c124-4352-a2b5-b305bf7da933} - {e0bdfc54-cf41-4c4b-bc7d-2eb5b15c8f13} + {e37cbacb-8c51-4a6d-b7c4-22e2f674eaac} - {c5e0fcc9-ca66-43db-892c-942ff451bab8} + {f77ce4a8-bfd2-442c-8fd3-b99d625e0330} - {a8dbe607-951c-44f8-8606-a82d5d79a6e0} + {3c4f41ea-6e59-4066-9a55-02379f19b541} - {a43f4600-6b9f-4987-a650-db03bc55d8f5} + {2a5fcdb2-7d85-4799-8b4a-ef8a56738950} - {6cd7195b-47c6-477b-b9f2-77b29f3919a7} + {4c43a4df-b1c5-4cc0-80e4-28c7cb2f27ae} - {1a2730e6-e0e7-4aef-bd4b-9aa36543c346} + {40197011-7e9c-4c40-8779-f62bbdfb5eb5} - {71825b00-548e-44d7-8a8e-2e191586f417} + {558d88b7-9b9f-4e78-9910-ccdacc81e0a9} - {5b0c71fc-8595-48cb-baa8-d1cafb23a524} + {21b02a3d-58d7-4f63-8bd4-dc3d84465427} - {7b42738b-62e0-4cdd-bad1-7b477b1479a9} + {344f0c77-1415-49f3-89a6-22083d41d608} - {a6d26d0e-a9b4-4473-95af-dcc2d81e222c} + {6c80632a-c28d-44ac-baf8-32693a52a861} - {b3e8032f-04a7-45d8-9d7d-ae66d7352806} + {e222b461-f600-4a7c-ab1e-251aeb706741} - {4e65da6e-fc61-472b-bedc-05a37d585ac1} + {9447e5f6-8bb5-46eb-a0a0-df46f0d0f90a} - {3b879808-d820-4e96-bf17-b3eb7d8cff74} + {077eba4e-cbd7-414a-8298-98312e9777cb} - {e1b5d3f9-19e1-4408-b5be-d97ff2327b46} + {5769cae1-73a0-4438-b88b-3aa77dc80a92} - {d2e0ac7a-7702-4d4c-9042-bdde1230a871} + {9d1a7d9f-6917-46f8-9edc-1d77e9488fbd} - {c73e9c10-05fe-4a36-9310-72c78101d79a} + {1de2787e-de2b-477f-8829-1d1bfb6569e2} - {060a32a4-41dd-4390-8029-c3512beb8d59} + {ce370739-9d9a-4e3f-af52-c028f0c898c1} - {1ca7b386-4779-4062-8c0f-039b215fa056} + {e044bc3f-4b8c-41b4-9343-5b7e75e112c9} - {09af9ea9-b301-4b97-beef-9e20848a2360} + {e5d821de-a5d4-46ee-b426-2b748483d450} - {0f5abe8e-1cde-4716-9033-f163d382376d} + {b853b44c-9209-4252-aef3-78a968c65e96} - {1f9b3099-2231-47d3-a01c-132e8ad5ee18} + {1204dfbf-2cb3-4eef-88d2-7f471019b066} - {173385f9-64b6-497f-8697-3442003a2ae4} + {f2b63cb9-90f2-4de6-811f-c84a924654f2} - {02ee7cbe-b63f-4bbd-a914-767362fc9d93} + {9fee0b5f-eb96-481d-8b47-1f5c62dfcb25} - {be2060cc-3cec-451d-a997-ba2e2eb2780c} + {57cfaedf-6d22-470d-8297-cdd603f80b69} - {a9a6de8e-9e42-46ba-b9a1-2ecab3c80d26} + {e04fe90b-9c15-4eda-bf9d-ed09481ed026} - {3147d536-ca3e-44bb-b77b-67679df0d96a} + {aca59f2f-ffc8-46ff-a3ae-5d9fad6ac7cb} - {ba48c2b6-6111-4867-8012-4e7313853358} + {db5f46fb-2c50-4817-9bd3-4292899c2842} - {9eef763d-e964-46ac-8242-c6f127679b8a} + {f3dac468-ba47-40db-95e8-faed578cafdc} - {9b901a3d-a199-4e1f-a37b-9bb8d314d59f} + {07172c43-fc45-4284-b696-4e50e66314e2} - {775b3148-d751-4c09-8abe-565f9d698d27} + {898f7308-def4-4a1e-a40d-1161e3cad913} - {844fbad1-8325-4152-b70a-194201d5da7b} + {2eb3656b-4709-4a7e-adb3-9dcb238524db} - {93c394d4-a83c-4b10-a464-ecd4b99381d1} + {33a6a4e4-c190-4bb4-b1a5-eeeaec4e37b2} - {2d7590c9-ef3e-4ec1-8c30-ee856f3a4234} + {4b686264-38af-43b7-962f-c5084921f8aa} - {953712b2-da85-4388-9e23-387b8c0dad59} + {108c9139-8417-451c-9da8-840833fd483d} - {88ef3eb6-3451-4a0f-a2c3-f549f0719299} + {3f89bbbd-108b-4293-a370-b9abda0c6d98} - {3b2fc5b5-5706-4848-98de-5c511fa09c84} + {05dec6df-2c10-4c24-9900-1fb4d4da9d43} - {f84fb19e-4903-4a05-a37f-59f651b837ee} + {507ad654-7dd8-4278-bc6b-7c94679982ad} - {b04ba3ff-a5b0-4014-8528-7bd734461b66} + {2f33fd54-98ef-462b-8a25-b912adf90ad4} - {a00ec248-8472-4ab4-8218-2bc404a3e020} + {511999cb-f86d-428a-9873-634af6663d88} - {499f95cb-20f7-4cf0-8a2d-87133196ef5f} + {54512f7b-81e2-4405-953a-c096a3b7d9b0} - {91b1d423-f266-4cfa-b4ae-2ac1d810d522} + {dff2e238-7a62-42d7-bb49-43cf5111e270} - {27ee8a65-e8e8-4677-b48a-64307b4f48ee} + {a3e87482-adf6-4064-baf2-7923ee29f96b} - {eda3ae82-c164-4009-b6f9-4ac3f79730c6} + {9cb15bda-d739-4b92-aeff-dcbb6500ed1e} - {d4f262d0-bcca-42a1-a989-9d976f51405e} + {b086b941-4deb-4b54-9f15-1e8a958258a3} - {8d571989-9770-4c2d-979a-1799313f0da2} + {bbfb330c-340d-4f09-8b2f-930a04f680f6} - {295de34e-fd03-4560-8200-4c5eb330aecf} + {7f87ee90-45ef-4718-83c9-20ea2da778d9} + + + {dbea5515-d888-47fa-bb1a-2118f484873f} + + + {0dc00433-9971-4dc0-9ec7-d16529ecc481} + + + {6d3ffad0-e7b5-4a18-924b-aa3ea62192ab} @@ -324,6 +333,15 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + + + OAuth\Header Files + @@ -500,5 +518,14 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + + + OAuth\Source Files + \ No newline at end of file diff --git a/Net/testsuite/TestSuite_vs110.vcxproj b/Net/testsuite/TestSuite_vs110.vcxproj index 0eb7800b3..6b9b3ee78 100644 --- a/Net/testsuite/TestSuite_vs110.vcxproj +++ b/Net/testsuite/TestSuite_vs110.vcxproj @@ -369,6 +369,9 @@ + + + @@ -429,6 +432,9 @@ + + + diff --git a/Net/testsuite/TestSuite_vs110.vcxproj.filters b/Net/testsuite/TestSuite_vs110.vcxproj.filters index 9f9dea0ad..56b1fd653 100644 --- a/Net/testsuite/TestSuite_vs110.vcxproj.filters +++ b/Net/testsuite/TestSuite_vs110.vcxproj.filters @@ -2,154 +2,163 @@ - {4a80adc5-9c8c-4d20-b3d3-b5e6b0fc807a} + {879b0ee1-27b4-4ac0-8235-ab6e44f8a492} - {94a48f8b-e566-471c-bea6-606913a53b51} + {568ab7c3-95a4-4515-ac9a-06c1d9d1a962} - {cfe6f3cb-b76d-49bf-8dcb-d6e508344436} + {0cfc8d52-b366-4207-841c-9f7d0a6444c5} - {71cd4b18-a3d2-4ccb-aa97-d54498864672} + {09ba290e-dc84-4039-bad8-2001beeefdf8} - {0d719cca-68e3-4618-af06-6a44b5ece555} + {541790bf-51cb-491f-a37c-7cfb31eb5eec} - {913d58c2-0917-4939-8839-c431ca5cc1f2} + {fb04e013-8e05-49b9-836d-2bb79ab8ac2d} - {979717f4-4e3e-4dc0-a75a-94444c54ad7e} + {9b2f0584-ba23-4f86-a44e-37d699b27d17} - {982278a6-3951-4905-861e-607937426826} + {e86a5bf9-7da1-42a5-8b28-7da17f1aea02} - {9cd455a6-dd78-4168-988f-b246bacbe638} + {469b1147-c87a-4eab-80fc-d1723208c0e8} - {9c4a8b7e-3ed6-4176-bbf9-949566b6e77a} + {531bd9cd-465f-47dc-8bec-5a8911c92f07} - {fc45428f-6084-4eff-8852-515bb7552795} + {d820ec8f-5fcf-4d2c-9ef2-cb498da1f19c} - {3ce9506f-6962-4b08-b5d3-b458080b5cd7} + {e7688061-9c65-4316-a11c-d8d1785833eb} - {c48e07b6-bd38-496e-9e31-f2e4b620d01e} + {910d9813-ffb8-42d7-89ba-2decbd3ffb95} - {51e85b46-4412-4c78-a61e-feea17f55954} + {f86f9273-4a5e-40ca-a3c2-3e7f923e1cf8} - {c36151b6-5080-4f74-bf2b-08dbcd244eeb} + {42a2c31b-9a8b-4843-914d-a6c1fc1870f0} - {56e8c1ba-d822-4a9f-a8f8-be74153eef2e} + {8e2e7798-8c3c-44d7-94b7-d0f6f2b10c54} - {81df1e63-83e6-4ef9-a96a-a01c529837e9} + {90db7e5b-5a89-4749-89e3-71825bf0c0a9} - {502c5ea5-45e6-48b4-8686-cc5bcef589f7} + {1992b0c3-e295-48d4-b6a7-2201290d229c} - {91d346ea-90c4-4190-823f-270cd62a2d0a} + {b982f489-c3e3-4a2d-a1b3-5ed3dd738243} - {3aaa55ae-fa2a-4030-834e-3bfa352feb76} + {ea7c782e-48a5-41e3-bd9c-53ac03ab381d} - {dd85a9dd-aca7-4828-93e7-d4dae7366665} + {ec00c33a-c4e1-465a-bd6f-5565dfb3ee20} - {223aad8c-7fd0-4d28-a8fd-476f99a4fa3d} + {39e1f7d9-fe94-44a7-adfb-219836fd1738} - {faf00e83-ae1a-477b-b837-5c8e48853867} + {a3f9601d-7316-441f-bf84-03043e239ba7} - {26202fc6-57c7-437c-9cc9-bfc395998e45} + {e80e452a-7ad9-4e69-b6f2-09d26267927c} - {60e2e03e-0976-466b-a964-0947fc55d5a2} + {94e785d9-f85a-4afe-976c-780b0738ad27} - {fa49b1d5-d920-4c3f-bde2-9714630919ec} + {28ba1eed-d6cf-45b9-abd6-64c2ce31fbf1} - {b8c8d0bb-ddc8-48ff-aac5-b5b51c3abd5f} + {b4866ba8-a7df-4855-afa9-d4e9feffbfe0} - {0eba10db-a0c1-4796-8ddd-0d2ba4f02e14} + {bd9b8d68-4212-438c-b333-2b3dee90d63b} - {69c2e16d-f44a-492b-997f-ba9e49401afe} + {2f86659c-a95d-4a47-9512-250de5b2d82b} - {a8918d9e-69cd-4711-a55e-b514c3ebc26b} + {dc991e1f-044e-483d-acf1-90c6b5d67606} - {ccbd3706-4599-4552-b216-72743f1b1c54} + {274f4088-896f-43a5-a1e8-0a6ec1199147} - {52149dec-3326-4f95-b6e6-27f94d9e77dc} + {decddff1-16ec-4585-ae7c-91ab163e9f85} - {983594f2-eff6-451f-ad59-c02d8c61c81c} + {1fe6713a-4273-4350-a307-d4a1b6d858d6} - {21c74b41-d60c-4d3e-96db-39cb4eda3209} + {55b60a9d-3674-4a7c-9b3e-965322a92b71} - {6a625282-e426-4478-939a-e0ae1001c917} + {2e07dbba-5767-44c8-b053-0046ec6f198f} - {d4c99584-0860-452c-a0c9-83f47ebfe176} + {c3f55197-d84a-4e64-88b3-b0c2eb8df3ed} - {4f1f0904-196d-4b99-a654-f1acd0c78e8d} + {03313f72-4a25-44ae-8dd2-45e3d2ba1af3} - {b904ba9e-d112-487c-a531-32bd39930d29} + {62205b3d-4ff6-4f43-bb3b-81695ab9840c} - {76a0f9e7-560d-497a-9435-57da79e2d415} + {5a67b949-f36b-4218-9e6b-346927f3e5e4} - {ec35a06a-bd1f-47e2-9526-ef82df731f7f} + {611baa74-2a34-46d8-b7d9-680a56302f45} - {a70a7e8e-79a1-4b68-aa47-d47a200b2cb0} + {df4950a7-bfd7-4a5d-b9ad-3e5df184659b} - {63cd5e95-9588-47cf-a214-01a2bbc7921a} + {52090dc2-a6b2-474b-8b84-a440b8dcffe5} - {8ac8d822-a889-439f-b62d-38adc4a77930} + {08fda89d-cc91-4175-8fa0-30f95c14128d} - {a18d2f9d-ac94-4e4e-99a7-8cff5ab9bfeb} + {840fc908-2ea4-4111-b1d2-c1619cb936d8} - {1d625583-2070-41b9-870b-03e2b1638761} + {eb3df288-1b4b-4c77-8ecb-d18f2d7695c4} - {d35e6090-77ae-4b7a-af9d-0b0a3e70d47e} + {5c594377-1b6d-4b6c-a9e6-24b4b4a69e03} - {dc56ccae-f81b-4596-83cd-0843132572be} + {5b114f32-44d3-44cf-865b-7937d131cac0} - {424e29e6-5c40-4e4f-90bb-44ae4e991f6b} + {92705784-dccc-4b51-92e2-bbb89edebca8} - {8fab31fa-8723-47a1-8c08-d10a343e968f} + {02b113fb-ebd1-4be6-a676-a22f2260ad00} - {b25b0039-18db-4c6b-8920-e621a10e066b} + {fdce4a1a-2dfd-4d9b-91eb-115fa455a862} + + + {1043e0e0-9d54-41e7-9f43-a8b015af71a0} + + + {a37753d2-556b-4dd1-9960-e529048ced63} + + + {594966c0-eabd-4a2e-aac9-d8870e9989e5} @@ -324,6 +333,15 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + + + OAuth\Header Files + @@ -500,5 +518,14 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + + + OAuth\Source Files + \ No newline at end of file diff --git a/Net/testsuite/TestSuite_vs120.vcxproj b/Net/testsuite/TestSuite_vs120.vcxproj index bcc0a0f52..d2fb01368 100644 --- a/Net/testsuite/TestSuite_vs120.vcxproj +++ b/Net/testsuite/TestSuite_vs120.vcxproj @@ -345,6 +345,9 @@ + + + @@ -405,6 +408,9 @@ + + + diff --git a/Net/testsuite/TestSuite_vs120.vcxproj.filters b/Net/testsuite/TestSuite_vs120.vcxproj.filters index 072b98fc8..61fea1e12 100644 --- a/Net/testsuite/TestSuite_vs120.vcxproj.filters +++ b/Net/testsuite/TestSuite_vs120.vcxproj.filters @@ -2,154 +2,163 @@ - {eb29abc6-954f-4f5c-ae5c-28e971a816c3} + {58f57e5a-56b3-4108-aba3-7a145652efa8} - {92e9d299-ad7a-4c79-91e6-d3ace39185ec} + {32681d77-66b8-4076-ade5-72a34413284e} - {4c4cd2c7-d90d-4c46-bcae-ac6a4dec4a05} + {6abdc48a-8c59-4f44-909f-1c67efadfdf1} - {c686a819-9ee4-4a44-9ef8-2cbc866aad69} + {48d76a10-cfa9-4831-a7ef-a83b36819b6e} - {3a021b37-e4c9-42ef-bb7f-95442137b99d} + {4dcc0633-1192-4ee8-a540-3ff7fbe68ba4} - {6d7c3bd1-96b7-4c4d-8b53-1dbb35d0464f} + {35679f04-da46-48ca-87d3-52a83c9ddfde} - {39e9334d-b014-42f3-97e3-a50675e527b4} + {bae06462-9863-4fe9-931f-6d67aeefed30} - {8466d157-d3ea-4f4e-a995-c95c98ccdd7a} + {3e25aaa1-ed60-4cd2-b8bf-48b932770900} - {d0bee9cd-86dc-4950-bfd8-0e2d2a3d6d22} + {be7113c2-1f79-4eaf-b403-c9b8a5c89bb7} - {00582f90-c49f-4b79-a359-2cce9f8434a7} + {e55b0d20-44c1-4c09-a774-b88b238ffe47} - {057ddf4d-e7db-42b6-9c19-c1361ab01511} + {c12a733e-fdbb-4a05-a4da-4c391faa4a93} - {2aec132a-12bb-45e6-a09f-d06508c6b180} + {04b4539a-b6ae-4eeb-aec7-1945a54932fa} - {05afca58-9cdb-495e-85f6-97694cfd974e} + {ce9bce60-255c-4d5d-b447-b1f37d3ad140} - {03b62852-bb8c-4a09-ba78-c5a2255cd013} + {6d9a3687-a253-4b06-baca-8426c3d42281} - {4af4d3b3-27dc-4f30-8551-27040b80e5fd} + {d887a506-fb6c-4f75-8952-7e0cda6cda5e} - {82fa0956-f742-47ab-bcc7-dde850e5ec8e} + {8aebd365-06ad-475b-84f2-897aeb93408e} - {9547f14a-e614-4e25-8ed4-44f4848b6141} + {eefc9d78-f197-4817-b49a-3ab45f484177} - {cf8212da-43b6-4261-8985-b86498d8f44c} + {8aae7592-1c78-41b7-b746-98b55562c910} - {8f7f6d27-1c38-4d47-bddb-c79a6efc3a9c} + {a565b34c-5f1d-44c2-b3c1-56a69795df60} - {4543fb06-d773-43d3-8a11-fa9f88379959} + {56d838a8-133d-4d2f-afd9-4c781ea39106} - {513a26e2-f692-405e-9424-043b383846bd} + {f827f045-21f1-446e-8559-4b47f8541a33} - {6a6563d4-5e1b-4005-9388-6068d7cbe4d7} + {98b46bb5-dc6d-40f6-af1e-35925bdf19ec} - {5d029742-7fe7-450b-8724-7bb99585afce} + {c67b00df-690d-4c70-8b2b-8283ad26a652} - {3cbced9d-21b2-4812-ae22-3957e5bfdd3b} + {b2fcf60c-f08b-41b4-aa28-c9a07bb988a0} - {4f82a46d-06ee-43f6-aeeb-fa22884c193b} + {e35a0162-9cd5-4ba8-b54e-99ce3f2d2c30} - {41a488cc-c6ae-43b2-925d-40c726e45ad6} + {acf55a3f-1dd5-4a8e-bf28-d4f0c657f0ca} - {41b45f7b-3cb2-4a8d-be3e-a770095d1f26} + {c1cfdcb1-ee27-434e-88e6-f669b41fdf87} - {d4e1489d-2e7d-4e29-a6f4-7d51b6c04656} + {782bec71-82c8-48ce-8e8c-f75462ddc8cb} - {d7af8e2c-4d0f-46c9-942b-b5a1a5f116aa} + {270bc053-18cc-41e2-8f59-1e61293531a5} - {62815b2d-5bd7-43a4-b4e6-0858fbf4c750} + {879154bb-c85d-489e-8827-aa30272a29bc} - {fa894ac5-0703-4e04-838a-08abfe94254f} + {d6e4990d-29c2-48e0-8d3e-e1e4dd6df0fe} - {450d7ab3-a161-4af1-934b-ce9fce3d4d9b} + {111bdf85-754c-4540-9335-7b050037ed23} - {b5865eed-f609-47f0-b024-bfe7437f65f2} + {4ba93644-a0c2-4fbf-b3ff-a3319cb44a57} - {2afce342-9a0d-451f-8ea7-7ac089b4c961} + {1bfd0ceb-e5a3-4296-898c-912dd6599360} - {d9f61034-48e9-49eb-bc1c-2716c94d5cde} + {9e1f4094-e131-4a61-975e-289d4d244bc4} - {4d25640d-b6c9-4dc6-a550-05b217dc6682} + {02f23030-6228-4800-98dc-21f969bf7d8a} - {323b9fda-23a2-425e-b421-58b5b13149c8} + {ef994fa5-4395-41ca-835b-7d8c5d477c49} - {0e46cb38-08b8-4602-ac94-253a8b2d6dca} + {1d65692e-f7af-4e18-9e9a-db2634bf0ddf} - {cf48d5b3-b34b-4df2-a1a9-4dc3a2780df9} + {9acb0cb5-24d4-4e51-9933-44317f97a708} - {65b4dd75-68b2-4a07-8aae-5cc309360ad4} + {f6c5cadc-eb91-434c-aac8-70daa0e6b7eb} - {073ca7f6-696c-4750-985d-b2d42fa3f125} + {f7b5b947-9d5b-40b2-abac-c42ab364e4fa} - {5a8c4b18-ad81-4539-8155-915d2869f6c7} + {4864689a-3c07-4075-87da-c612ae04c55a} - {ef490991-8e3c-4e06-b46f-30013c3fe1c0} + {3010216f-2df2-4d9a-80bb-226f345022c1} - {0353c06a-d8ac-454c-a9d2-fdc3d5529d24} + {767e0c7b-aa18-4ae4-8b1d-f5a4c11c2064} - {1c71a26a-4f4e-4a38-90b9-18ac0c83ba42} + {5f2c8b6d-7b10-48aa-9977-32fdda2da10f} - {0fde6531-47e5-4f91-b062-73afea789db0} + {4c32cc2c-05f8-41d9-9937-d3bf62676aaf} - {9fe340db-fe17-452d-b05b-ed37c389596b} + {b31d1d6c-6d89-4b45-8da3-4a8b54536c49} - {305cac84-1642-4a40-b491-8d3aeb41f686} + {a6202bc8-2d98-418a-822e-08022dd11f65} - {428e7233-99d0-49ce-bbfe-ca72a44e0793} + {739ef1d2-5927-482c-8335-4f59b5f75e94} - {bf525da9-4301-45b1-9387-7818b4c1f815} + {292f8511-9614-436b-bccb-b45356ce3861} + + + {79b0eee8-1cce-4525-9b3e-a7006278acbb} + + + {b3a9aa2d-d699-4a51-a6e5-50bf83911790} + + + {3bddd19e-9793-4760-919e-d6083057cbc7} @@ -324,6 +333,15 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + + + OAuth\Header Files + @@ -500,5 +518,14 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + + + OAuth\Source Files + \ No newline at end of file diff --git a/Net/testsuite/TestSuite_vs71.vcproj b/Net/testsuite/TestSuite_vs71.vcproj index 5251e0d17..bbd05160c 100644 --- a/Net/testsuite/TestSuite_vs71.vcproj +++ b/Net/testsuite/TestSuite_vs71.vcproj @@ -783,6 +783,27 @@ RelativePath=".\src\WebSocketTestSuite.cpp"/> + + + + + + + + + + + + diff --git a/Net/testsuite/TestSuite_vs80.vcproj b/Net/testsuite/TestSuite_vs80.vcproj index f44ddd890..fcfbc1dc8 100644 --- a/Net/testsuite/TestSuite_vs80.vcproj +++ b/Net/testsuite/TestSuite_vs80.vcproj @@ -823,6 +823,27 @@ RelativePath=".\src\WebSocketTestSuite.cpp"/> + + + + + + + + + + + + diff --git a/Net/testsuite/TestSuite_vs90.vcproj b/Net/testsuite/TestSuite_vs90.vcproj index 4ce50989b..21d9968ea 100644 --- a/Net/testsuite/TestSuite_vs90.vcproj +++ b/Net/testsuite/TestSuite_vs90.vcproj @@ -823,6 +823,27 @@ RelativePath=".\src\WebSocketTestSuite.cpp"/> + + + + + + + + + + + + diff --git a/Net/testsuite/TestSuite_x64_vs100.vcxproj b/Net/testsuite/TestSuite_x64_vs100.vcxproj index 3b1d10d37..0d3d877cb 100644 --- a/Net/testsuite/TestSuite_x64_vs100.vcxproj +++ b/Net/testsuite/TestSuite_x64_vs100.vcxproj @@ -369,6 +369,9 @@ + + + @@ -429,6 +432,9 @@ + + + diff --git a/Net/testsuite/TestSuite_x64_vs100.vcxproj.filters b/Net/testsuite/TestSuite_x64_vs100.vcxproj.filters index d93007978..6be60911d 100644 --- a/Net/testsuite/TestSuite_x64_vs100.vcxproj.filters +++ b/Net/testsuite/TestSuite_x64_vs100.vcxproj.filters @@ -2,154 +2,163 @@ - {33c101dc-28e6-4ad0-a271-926d2b4cc214} + {fea5f37a-a326-442b-9d1b-571b7bcc7cd8} - {88aaeefd-875a-4cab-b16f-df8d85f19f90} + {288a3886-daff-4e10-9957-cdcfee673c85} - {e7370b38-8d57-4000-ad46-fe733e41cd82} + {7c5a7bc6-31a6-4801-bad6-cc71a210d04a} - {32d9eb9d-de2f-4dc9-b549-5a7ce8b2aac4} + {18b7f6d6-3a3f-4851-922e-a16a96aa3fb5} - {ae71062b-0865-4c90-bb64-a62c4aa07d08} + {e74a3b7a-b243-4f89-b47f-c2003c53972d} - {82abb76e-ca47-445c-a5ce-aa575fdc0900} + {734e002b-3e98-4271-8659-7bdee6f54ffb} - {199f9014-2d42-4eb4-b2d0-ebddf65d0c35} + {21631084-314e-4298-9e6e-d3d2bd75035c} - {c61e6c55-eb0a-4657-937f-e7fd701af451} + {01afd055-02d2-4d9a-9ffb-18433c6d36f6} - {e6ad5333-cd16-4d1c-9712-b68f873ce932} + {6d524968-0d01-48a4-b938-095d97e5bacb} - {f6ed60b6-e4cc-401c-b25f-e1632f8a796f} + {1515113c-a4a2-48cc-9332-c222a3d39b6a} - {83267cb5-e2fc-4ac0-b6d7-b01d8c70dd1f} + {8fea7c5f-3620-4de7-9ad5-f5c88ae30cbc} - {579d0f31-7455-4ca4-ba90-0d28948674d6} + {b9da9606-6bbc-4760-9822-29eb2c1468ca} - {9d5308f5-5ca3-4673-874a-1683f7301ea4} + {e34484a3-f587-40de-a5d1-e4b2935175b8} - {b2e62d78-ec4f-41b0-842e-03a5cfb61717} + {58c6f1b0-cd25-45b4-9ad2-0402099430f9} - {f7beca02-b4b0-41e1-9556-262e904182ab} + {c67da689-3d67-4823-98b4-02fd233a50f8} - {8a3ce086-e4fc-4fd4-901e-f6a3fdd0eedc} + {0f7d245b-01fa-4eac-a2cc-8b166f2e5dd2} - {3da16e79-5a85-4c73-8fae-e77d8030a7ff} + {c609bfa4-dfda-451f-bd15-69f634145420} - {cabb4268-0cea-4d7d-8758-5c866586abce} + {7f6fee2f-7281-4b86-a8bf-3c0e3adc7de4} - {ae45038a-30f6-4cee-ad4d-528bb724f802} + {743b7bf6-2067-4ac8-943d-48655872c3fd} - {649efe75-fbf6-4cb5-a786-a1e6916b4837} + {1de1146c-c3c2-4765-9733-17995533018f} - {68d8cd60-19f1-4d13-bc54-b880dc0da840} + {b4991f67-2ad7-46a9-bae1-d50e01cec429} - {1273008b-1251-4834-9a65-91b8b1b6c844} + {0cfe2b68-aad2-42fe-ac7a-e80294b8fdaf} - {c6f3d4c1-fcef-486d-95cc-0ab07a02099b} + {13052d0c-c4cb-4a67-b030-f3c08efd9aa2} - {f6fbdd41-13c1-474e-8dec-12bde845e8ca} + {ef6f8465-bcb5-4ed4-b7b7-d203047f35be} - {12d7a633-411f-4821-ab72-43dfa7086d4e} + {b31c5374-38a8-48ff-875a-7ee7eeeeb419} - {7e8101c4-38a9-4c0f-a638-0d7f0940339f} + {71fb091b-1f43-43b1-9daf-a5be6a0265fd} - {9518dff9-6040-49af-9b6e-89ed1cb904b3} + {8ae17e46-1755-4988-bdfa-36901f018c8d} - {8d8f6a4c-1f74-4509-87f8-58ff6a741998} + {b76377ae-1776-4430-a099-759aefe77545} - {65859da6-5dbf-419a-b19d-da2dbe1b5e5c} + {8b8b6e50-3418-49a9-89dc-05cf4a3d22e3} - {1bda2546-bc6f-48cd-ad15-5f27e88563dd} + {0b991aff-ff53-4799-85f9-f8273f975748} - {63b1e6f1-f780-4ea1-95fc-6ee8d2ae0ba8} + {c271f430-6697-4089-8aeb-639ded907f1f} - {227e0d74-e6b9-4a40-91da-42c78dcc786b} + {0d77fc3d-ca55-4e4b-a791-c972c47ea16e} - {70cbbf35-2664-40f8-bd85-6b3a1f5ff982} + {3e8b51e4-797f-47d6-be98-9700b277603d} - {e409ecc8-3f6a-46f5-80ab-65ceaff3b399} + {a6b19611-1fcc-4c40-8294-6ac01010a4da} - {e324fb54-4555-4998-a373-093fe5833979} + {c19dea5c-23f4-4bcb-8531-3b9f800283e4} - {77299e22-1ebb-445e-b132-7f7e181a6e63} + {93234c8e-1b89-4a6c-ac69-3911865ca33c} - {70f43f03-d2fa-4176-bbe6-be1f246072a9} + {54164848-3df1-4114-9a9d-f4ad3e4a253e} - {149de86b-2156-4136-8542-d9d6ee6a48c4} + {0304f9e4-eb70-4915-88cb-f292d87b5868} - {b45f1026-7c36-4bd6-af63-4a4f8d75c0a1} + {6442130b-649a-4a3b-b4d0-e7e859bf2dbb} - {0dfa6e9d-2aa1-44b2-bbb5-de5d7ffa30a3} + {28c2b47a-6f02-42b7-b94e-8645eeb3785d} - {5bfebdb5-0ac7-4f3e-a2b4-daddf7f0850f} + {885e582a-db20-46cd-9537-75f0105d1f05} - {b672a540-e209-42aa-b79e-d369cd50a3cf} + {d524db3d-6f48-445c-a42b-f6ea8efc4762} - {ae7eebfc-14d9-4943-9daf-76bb3219c058} + {8e375861-6577-4bb3-b3f2-3aadc3557e7e} - {c90924c7-9a6e-4da6-a3bb-fa4248697509} + {6b96aedf-3df6-4da6-8c08-86d0b48ce240} - {64f2b664-5b2c-4011-9903-29d8dd3cec46} + {036cca16-894e-43ce-849f-03a3285fc2d7} - {4acba6a7-92d6-4965-ae07-06e2156827a2} + {d96c16b9-f532-4011-91e0-8fde609dc7df} - {eab20730-aaaf-4ce3-807c-e17fe1e1a11f} + {5db62bb4-fa76-41c2-bfcb-1f6cdbe1a1d5} - {5cf55f2b-7808-46af-88d7-0c175914720f} + {0907bb55-213c-4ee4-8ba1-d8b1f9f4413e} - {4b45590d-6097-4c03-ab83-8a103a825d95} + {30a519c4-9cc6-4fc0-8d81-962d8a4569b0} - {2def153f-9d56-4b2e-b4c1-4dc62618598a} + {dbe78387-665c-4920-9caf-fd80fc6cb687} + + + {630e694d-e6b5-4903-bf3d-80820d574323} + + + {ceaf014d-f338-4bbf-b31b-807d1a737ad3} + + + {ad7ce875-9b66-404f-a6e6-96bd89cabe93} @@ -324,6 +333,15 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + + + OAuth\Header Files + @@ -500,5 +518,14 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + + + OAuth\Source Files + \ No newline at end of file diff --git a/Net/testsuite/TestSuite_x64_vs110.vcxproj b/Net/testsuite/TestSuite_x64_vs110.vcxproj index 4ad3d1094..9fe3bf6bf 100644 --- a/Net/testsuite/TestSuite_x64_vs110.vcxproj +++ b/Net/testsuite/TestSuite_x64_vs110.vcxproj @@ -369,6 +369,9 @@ + + + @@ -429,6 +432,9 @@ + + + diff --git a/Net/testsuite/TestSuite_x64_vs110.vcxproj.filters b/Net/testsuite/TestSuite_x64_vs110.vcxproj.filters index 70e81e871..062f00eee 100644 --- a/Net/testsuite/TestSuite_x64_vs110.vcxproj.filters +++ b/Net/testsuite/TestSuite_x64_vs110.vcxproj.filters @@ -2,154 +2,163 @@ - {037f65ff-7307-4faf-826d-34a0aa886ad6} + {f6e56a6b-c496-4f5d-a122-b08efce4fceb} - {d65c6014-0d08-46f5-a1b6-df4e6d284899} + {61e90855-67c4-4b3b-855b-3c8b0a641128} - {1c201b71-4a7b-4c84-8ea8-47fc00e830de} + {68bad3b7-37f8-4553-86e2-d18c357fd904} - {b1504c1b-bb23-402a-8b6f-4e95e1df1782} + {7e0dac2e-768d-417f-9efe-b839c8b0af39} - {95bba649-4f03-4789-8437-39d340f739ff} + {ac2fe62f-68ce-40f0-80a8-a3a0f50d08a4} - {7d5d1e54-8316-4516-b679-721aa5e94054} + {08e7e74f-0a71-47d9-83cc-5d7532f20743} - {ecc16bb0-03fe-454c-b8e3-6329242d1482} + {ae5c88e7-e416-45f4-9c5e-e12d278362fc} - {142b00ed-ad45-40e6-b525-fe785ebf7be4} + {d5b149fa-eec0-4676-9bc1-17ca8b6f5382} - {09076b28-1a9c-4a4b-a8d3-1e0319ce54a0} + {f4e024c8-04cd-432a-aa2c-523e7435fd8e} - {4710d782-d7a0-4944-8dd3-31f737b0ad81} + {4db74ff3-3fbb-4a51-8f7f-33b94a775309} - {2d2f5164-837f-4dfe-afb1-31ea3197671c} + {c2aa3b49-6d82-4231-ab8c-9694135300b0} - {0322eb71-e1ab-4b52-9a44-039d2baa1054} + {f5070a0b-fa65-4f1e-8630-c54d0bd3572c} - {7e53a2da-182e-415c-847b-7c9d26aa87b3} + {34d460dc-ead0-43d2-8931-dfccf594a50d} - {74de4d90-3d79-4978-bcad-dbc89a19339f} + {f0488715-a6ea-4e60-8f00-41fc937ba92f} - {93157bc3-0f93-4781-891b-cca686733c11} + {a04e9483-23c2-4de9-8a5d-ed640c99ef60} - {9c85643c-db21-4a28-a012-cd58c98e0994} + {e1f9bcf2-076f-4066-8972-3bb767854785} - {7a39e67c-97a6-4c6a-86c8-79e65dc0dea0} + {b3f9a7a9-f741-4069-8985-c3bd2104445e} - {4ef668e2-3bea-4903-9944-28af4b144bf2} + {c74665e2-d566-420e-b374-13745b30421b} - {4870644d-f716-4367-abcf-b7f0adffb762} + {a31e43a3-25ee-4d15-8e0d-8c655cd09716} - {19de5849-a929-4d51-ac64-78f478533aa9} + {870203fa-a7f6-4d7c-b77c-876840c1215d} - {03a3e53e-fec9-4a62-a37e-ca091fbb656e} + {36689fdf-a027-4c99-af85-56e529b40503} - {cff0f735-f09e-4744-a9d0-7ef5df15502d} + {07842041-a8a9-4074-baf8-09a2df918f12} - {0f4a004a-b601-44f1-8fcd-3f3b8cffe82a} + {146adec3-637f-4010-8e68-d52f1285532e} - {343f8c23-7a19-4e57-852a-a04fc6f3b6e8} + {46f54f49-f2f2-4459-b6a5-d4077c8a3d08} - {77a7042d-00af-4aa0-9993-6696f9dd9d28} + {aa478506-9939-498b-bb70-06c1befd0d59} - {d351424f-5c2c-48dc-a727-520872a89008} + {d0548542-97a5-4027-afdc-8bcc738fb187} - {8af6b5a8-6985-4243-9882-4fe52ec5710f} + {3d1188d9-6a4c-46f7-bb2b-b1587bd59819} - {afb0db5c-cf7f-46b7-b87d-139299a153d5} + {9cabad65-f5a2-48fe-9e65-b2ec17047462} - {cb9fb41d-3e24-4a38-8767-600dcf01c4b6} + {2a58e2a9-67f8-4410-acbe-e985491a6c01} - {036cf810-9be2-4e3f-b3c8-6b8961b53fd6} + {3e189361-aa22-4cbd-b19d-0a9e168bd186} - {f1eb248f-72fd-4626-a945-fff60a64b481} + {e207f410-691b-4e4f-b40f-8bec522e011f} - {a135934e-b840-4afe-b0e2-e5784c02fdff} + {d6ca0094-6aa0-4843-a45b-1f1183c81627} - {4e63e501-1b85-4aee-93e2-d030c4c24d05} + {574d9b26-d978-447f-be20-5041c9ae1b0e} - {7951dde7-b5e9-482c-a8d6-69f459eb6799} + {b1e8604e-f039-4882-b9df-0091e244fcfc} - {eb42b26c-4191-4a1a-8032-0c24dcb16276} + {9126a243-10e7-48dc-b26a-7c2ce7b98c1c} - {d3508005-61a1-4436-a735-95624ae915b8} + {aa6f255e-e70a-473d-83d8-8d898c2830a5} - {4a312890-3311-4766-8e88-0d3446fb91a5} + {17d9aebc-1d13-47ec-a5ed-3e4c2534ab3a} - {ada3be0d-12aa-40ba-abb8-93933d58ae72} + {e1628f86-c82a-4728-843d-f7de84d48e49} - {e3aa9bfd-70ee-4202-90a4-011e27772248} + {2e8002ba-3d38-496c-9ef3-bf3a7039ed27} - {5c78e0c9-250b-4ec7-9029-f9b0d15c316a} + {b23123c0-f458-4eeb-8b75-058a6b1824c8} - {db4260dd-e71f-402c-853a-ed2789f28b73} + {b4682ce4-39d1-4e4a-a989-821b7ce6eb90} - {cf8286bc-6d94-4bb9-9d66-0ae9f50b8310} + {1ad885bc-d3de-47ba-878e-3a0e26a7ca7c} - {e3242d8d-02b7-4a45-aaad-d0e8753ebd0c} + {ada227d1-d2cf-4181-a3e4-66257504bbda} - {2082027b-c21d-4ccf-9023-2a570cc7d683} + {21e1e985-4d17-46b4-ad1b-6910b83b6711} - {926cdc38-7782-4c77-be10-7638e7bbef25} + {9e236068-ef00-4bd6-901e-eda8737aa6eb} - {b2f07879-f2a7-4a2e-bd58-16c7af786f70} + {1b42713b-1ecb-45d9-b660-8dba6989fc92} - {8c737785-88b3-4435-a120-10da770d8b57} + {019061b6-a699-442a-8317-856baab0cf1d} - {7fdb1591-8e0c-4ca3-b463-8676e2ee9932} + {7ac63706-4856-4167-877d-6b3a7d649ca9} - {1b16df8a-6d57-4cff-94b7-be697662b735} + {0f7d5824-bc11-439e-823d-b1cc9dc40377} - {4c0332e5-8e86-4645-b4b5-bab72d091b2f} + {c0afa90c-38cc-4a53-9e8f-69c5e12cc9a5} + + + {d4bdd769-114b-4efb-9bd0-8af6741592c2} + + + {3e25c250-b24e-4025-8ba3-275cf2c43e7b} + + + {2a202fd5-022e-4227-a9ee-991e11846b18} @@ -324,6 +333,15 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + + + OAuth\Header Files + @@ -500,5 +518,14 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + + + OAuth\Source Files + \ No newline at end of file diff --git a/Net/testsuite/TestSuite_x64_vs120.vcxproj b/Net/testsuite/TestSuite_x64_vs120.vcxproj index 33ce7eebf..6ab3b86ea 100644 --- a/Net/testsuite/TestSuite_x64_vs120.vcxproj +++ b/Net/testsuite/TestSuite_x64_vs120.vcxproj @@ -345,6 +345,9 @@ + + + @@ -405,6 +408,9 @@ + + + diff --git a/Net/testsuite/TestSuite_x64_vs120.vcxproj.filters b/Net/testsuite/TestSuite_x64_vs120.vcxproj.filters index 95519dac2..c9dd2f2cc 100644 --- a/Net/testsuite/TestSuite_x64_vs120.vcxproj.filters +++ b/Net/testsuite/TestSuite_x64_vs120.vcxproj.filters @@ -2,154 +2,163 @@ - {12bc37eb-4afc-4aad-a5ec-b6bf45a971e4} + {c27350d5-cfcb-4811-98bb-ca0619bb333c} - {b2e7150b-a2be-4096-847e-e0a5e5420e47} + {a9c63165-04b2-4d14-9561-dc472b9b02ff} - {1222c9cb-54dd-4a75-bc9b-2ec8ef9ee1a7} + {96d43800-712c-49e8-b67e-7085db8f638b} - {597d35d2-8b53-44a9-a8c3-0f2e2f298d9d} + {002fde91-13bd-403d-975d-33ff826433e9} - {23cf5efa-62da-44a6-bf8f-8407dd4de96d} + {7a89e504-3e0f-4e2b-bab3-98cc3effe5d2} - {0b041bfc-f92f-458f-8ca2-d5903c716b81} + {11561c77-c173-461a-a8d5-275759021af8} - {c24a0349-4f45-4562-bcdf-a8c98af202c4} + {a58d9eda-f1d1-47f3-af70-712ab91899a0} - {be3b6ae9-2f3b-4937-b214-5900d93e609a} + {bbc7bf46-43ed-4684-897b-60cb7acfe8e8} - {aba262e4-2f60-401d-a171-b2c72bd3423f} + {affd1334-cef6-4d4c-b1a0-c083dbca008d} - {3a81378d-b9d1-4de5-a6bb-e45827f4e112} + {82451f02-30ba-4550-9fd7-af8ad0b556cc} - {443e750b-431c-4907-a2c3-959fc4d35af9} + {078bb2d2-b88a-43b3-8ba2-f3314f2a4ef6} - {295fb993-fa6f-405c-be2f-7477c19b3957} + {af2a307d-3d49-4241-8142-9b8b056c4009} - {bbd5e4d5-99ab-4e49-a5ea-10a2e8f3ec2d} + {5c31e4d3-eee3-43f4-9de8-17903c9aa679} - {f411587a-1c7e-44d7-8408-b7872aa68f35} + {7c918cfd-160a-4891-b658-31ff2ab0d274} - {df69947b-fba1-45a2-b511-49663f5aae10} + {7315b0a6-6252-4264-a87d-c24e0775a9ae} - {a9965623-f733-4ce6-953a-13793db95ca8} + {8619ed4c-0d40-4f6a-b50a-2b3271fc1efa} - {6fadc25a-39a6-40a9-9744-5f4fe153d9fe} + {94ca5f0c-0ac3-412e-ad31-605e6726258e} - {b6110e96-5705-4a36-9982-265597a417b8} + {7994ec73-a8ec-4bf5-a15f-5c1dcbc5c240} - {c8ec07ea-a83d-46b7-a6c6-06a199dcfe76} + {caa07218-06db-4506-92a8-71d225f08022} - {eb952dfa-a10b-437b-873e-fe021a7b7002} + {9ec43e95-28e9-44be-ada9-dfb9283273de} - {222c30d6-3798-48d8-b96c-23c85612dcf9} + {28c360a9-d065-4e82-9c1d-b9c6669eb3de} - {1950bb2f-ecdd-472c-b8d6-6cdd272f8cd4} + {4784c973-c3f1-4e50-ab04-816e6ca17005} - {5a9c4f8a-9c67-42b6-92e7-038fe81c85a2} + {a07261a7-fc70-4855-a5bc-11753137a764} - {37a3fa42-8fda-4bc4-b19a-8ad4b7e61f14} + {84a20033-8a3a-4eae-8262-f68b1d43a386} - {0833d9a9-d2d4-4eef-bef4-2643b5222e5d} + {9915f183-0326-411c-9bf8-9351990a11a7} - {bb347695-2f03-43e4-8a79-dfbf91414eed} + {42ab644e-4816-4696-b5fc-7ca40ba04568} - {379591a0-dcb8-4e8f-b03b-2206b73f7ef1} + {cd813fed-22cd-4f11-be74-4a406b54b1e1} - {4920dcc1-5b06-4f5e-916d-dbca95ac9ca6} + {0809a508-a11f-4759-aeec-dabcd01834c8} - {d3afb0bb-8d3a-4241-be5b-26a8e58aefcc} + {46350456-9466-4008-badd-746eb06406e9} - {6bc0f644-82dd-4a8f-a341-48c824bb8483} + {a63716fe-1d27-4a39-b01a-00d67bfc9b21} - {fbaca3e4-b265-4445-ba18-29a3da019ad2} + {eeb19b62-f6eb-46d9-87cb-03e0888f0264} - {12c75943-bce7-4073-b5fc-1e4d6fa35ed2} + {0b485a3d-8744-4d7b-938d-8ac77ed5593b} - {9884ca35-b766-4921-802e-258d3db7e5a0} + {be077488-b0c8-4d39-ab0c-662f64036725} - {351d9485-49c0-4440-8a4b-3b22c69b59d7} + {e62ac345-8211-4eec-93a4-60367c738cb7} - {3b5e0616-31e4-4751-b324-e6e9e252753b} + {ea85b0f2-27d1-4298-9f4b-c35b4c28fa30} - {45fdab23-7176-418c-b1fd-602796f0993c} + {d122a8e3-0c0b-46a0-acc6-8debcccd968b} - {60573dfe-6869-445d-9a4b-7b449ef8ad6e} + {8b7c5a17-2556-4d0a-b602-97fc70d0df52} - {cf45eaf7-3f2e-4d26-ba00-c5adb94e47b5} + {3a274f7b-f7c8-4b42-8659-34e9d86ab675} - {b43e10f2-858a-4420-848a-21c01655ee80} + {589623cd-2fad-435c-a0e6-456faedcd913} - {6df194e9-232f-43e8-827c-d3bd43468f0c} + {efe50ca9-8abf-4d14-8628-086b7d8d9875} - {f4ad80f0-e5c3-4876-be1d-789e6972d73f} + {222ad1f2-5023-4510-b29d-85af0f6f5003} - {f19263ca-7b6c-4d2b-b22b-c7e84fbe5bf5} + {4ab90855-107a-4875-9543-2f623482cea0} - {95e1c26b-462f-4cd6-adaf-daa1d16085cd} + {a6ba0751-aa75-4ce6-a855-f8af6186b4a8} - {e51810a9-25b6-454d-9f92-f554a1e9d657} + {7c706bae-2caf-4fe8-a358-b5d058864d4d} - {faa972ef-3774-489e-826a-8f4dbdac1cce} + {87bc8f6d-7076-41d1-84db-abb568c5ed5d} - {a110f5a7-1def-4c41-b652-fcc798266177} + {3945c3de-def5-4604-bbb4-05cc1aaf2c84} - {46233ff0-0703-4d85-8c2a-3a72fa32eb46} + {9a0365be-3473-41ff-ab72-9e1df09041d4} - {bf079626-de93-490a-8bbb-180f06c1f048} + {76c1c79e-804a-4062-bb57-ab99e10247a5} - {e17854c2-232d-46b4-9005-f0bac70548b8} + {af82194e-f1f5-4529-9490-d86a6f992a61} - {b1de33f6-936e-42f2-b774-ceb6e3a53463} + {e8fe43b0-e2e5-4d49-a43f-83f14792f7ca} + + + {c67adc20-2953-4afc-b174-06869a4b558f} + + + {dd969f2b-e44d-4ae2-a905-f703edde87b3} + + + {9e9831c6-bdc3-45d8-9b46-ab8d05eeffc3} @@ -324,6 +333,15 @@ WebSocket\Header Files + + OAuth\Header Files + + + OAuth\Header Files + + + OAuth\Header Files + @@ -500,5 +518,14 @@ WebSocket\Source Files + + OAuth\Source Files + + + OAuth\Source Files + + + OAuth\Source Files + \ No newline at end of file diff --git a/Net/testsuite/TestSuite_x64_vs90.vcproj b/Net/testsuite/TestSuite_x64_vs90.vcproj index 89eeb95cb..35577d7d4 100644 --- a/Net/testsuite/TestSuite_x64_vs90.vcproj +++ b/Net/testsuite/TestSuite_x64_vs90.vcproj @@ -823,6 +823,27 @@ RelativePath=".\src\WebSocketTestSuite.cpp"/> + + + + + + + + + + + + diff --git a/Net/testsuite/src/HTMLFormTest.cpp b/Net/testsuite/src/HTMLFormTest.cpp index 3f0693571..318c66b83 100644 --- a/Net/testsuite/src/HTMLFormTest.cpp +++ b/Net/testsuite/src/HTMLFormTest.cpp @@ -191,6 +191,20 @@ void HTMLFormTest::testReadUrlPUT() } +void HTMLFormTest::testReadUrlBOM() +{ + HTTPRequest req("PUT", "/form.cgi?field0=value0"); + std::istringstream istr("\357\273\277field1=value1&field2=value%202&field3=value%3D3&field4=value%264"); + HTMLForm form(req, istr); + assert (form.size() == 5); + assert (form["field0"] == "value0"); + assert (form["field1"] == "value1"); + assert (form["field2"] == "value 2"); + assert (form["field3"] == "value=3"); + assert (form["field4"] == "value&4"); +} + + void HTMLFormTest::testReadMultipart() { std::istringstream istr( @@ -359,6 +373,7 @@ CppUnit::Test* HTMLFormTest::suite() CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlGET); CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlPOST); CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlPUT); + CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlBOM); CppUnit_addTest(pSuite, HTMLFormTest, testReadMultipart); CppUnit_addTest(pSuite, HTMLFormTest, testSubmit1); CppUnit_addTest(pSuite, HTMLFormTest, testSubmit2); diff --git a/Net/testsuite/src/HTMLFormTest.h b/Net/testsuite/src/HTMLFormTest.h index 2da5923fa..7f9242d49 100644 --- a/Net/testsuite/src/HTMLFormTest.h +++ b/Net/testsuite/src/HTMLFormTest.h @@ -31,6 +31,7 @@ public: void testReadUrlGET(); void testReadUrlPOST(); void testReadUrlPUT(); + void testReadUrlBOM(); void testReadMultipart(); void testSubmit1(); void testSubmit2(); diff --git a/Net/testsuite/src/HTTPClientSessionTest.cpp b/Net/testsuite/src/HTTPClientSessionTest.cpp index b1001769a..484852f39 100644 --- a/Net/testsuite/src/HTTPClientSessionTest.cpp +++ b/Net/testsuite/src/HTTPClientSessionTest.cpp @@ -1,7 +1,7 @@ // // HTTPClientSessionTest.cpp // -// $Id: //poco/1.4/Net/testsuite/src/HTTPClientSessionTest.cpp#1 $ +// $Id: //poco/1.4/Net/testsuite/src/HTTPClientSessionTest.cpp#2 $ // // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. // and Contributors. @@ -279,6 +279,27 @@ void HTTPClientSessionTest::testProxyAuth() } +void HTTPClientSessionTest::testBypassProxy() +{ + HTTPClientSession::ProxyConfig proxyConfig; + proxyConfig.host = "proxy.domain.com"; + proxyConfig.port = 80; + proxyConfig.nonProxyHosts = "localhost|127\\.0\\.0\\.1"; + + HTTPClientSession s1("localhost", 80); + s1.setProxyConfig(proxyConfig); + assert (s1.bypassProxy()); + + HTTPClientSession s2("127.0.0.1", 80); + s2.setProxyConfig(proxyConfig); + assert (s2.bypassProxy()); + + HTTPClientSession s3("www.appinf.com", 80); + s3.setProxyConfig(proxyConfig); + assert (!s3.bypassProxy()); +} + + void HTTPClientSessionTest::setUp() { } @@ -305,6 +326,7 @@ CppUnit::Test* HTTPClientSessionTest::suite() CppUnit_addTest(pSuite, HTTPClientSessionTest, testKeepAlive); CppUnit_addTest(pSuite, HTTPClientSessionTest, testProxy); CppUnit_addTest(pSuite, HTTPClientSessionTest, testProxyAuth); + CppUnit_addTest(pSuite, HTTPClientSessionTest, testBypassProxy); return pSuite; } diff --git a/Net/testsuite/src/HTTPClientSessionTest.h b/Net/testsuite/src/HTTPClientSessionTest.h index ba098729b..099b23269 100644 --- a/Net/testsuite/src/HTTPClientSessionTest.h +++ b/Net/testsuite/src/HTTPClientSessionTest.h @@ -38,6 +38,7 @@ public: void testKeepAlive(); void testProxy(); void testProxyAuth(); + void testBypassProxy(); void setUp(); void tearDown(); diff --git a/Net/testsuite/src/HTTPCredentialsTest.cpp b/Net/testsuite/src/HTTPCredentialsTest.cpp index 5186b9467..d91351e3c 100644 --- a/Net/testsuite/src/HTTPCredentialsTest.cpp +++ b/Net/testsuite/src/HTTPCredentialsTest.cpp @@ -145,6 +145,19 @@ void HTTPCredentialsTest::testAuthenticationParams() } +void HTTPCredentialsTest::testAuthenticationParamsMultipleHeaders() +{ + HTTPResponse response; + response.add("WWW-Authenticate", "Unsupported realm=\"TestUnsupported\""); + response.add("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\""); + HTTPAuthenticationParams params(response); + + assert (params["realm"] == "TestDigest"); + assert (params["nonce"] == "212573bb90170538efad012978ab811f%lu"); + assert (params.size() == 2); +} + + void HTTPCredentialsTest::testDigestCredentials() { HTTPDigestCredentials creds("user", "s3cr3t"); @@ -231,6 +244,19 @@ void HTTPCredentialsTest::testCredentialsDigest() } +void HTTPCredentialsTest::testCredentialsDigestMultipleHeaders() +{ + HTTPCredentials creds("user", "s3cr3t"); + HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/"); + HTTPResponse response; + response.add("WWW-Authenticate", "Unsupported realm=\"TestUnsupported\""); + response.add("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\""); + creds.authenticate(request, response); + std::string auth = request.get("Authorization"); + assert (auth == "Digest username=\"user\", nonce=\"212573bb90170538efad012978ab811f%lu\", realm=\"TestDigest\", uri=\"/digest/\", response=\"40e4889cfbd0e561f71e3107a2863bc4\""); +} + + void HTTPCredentialsTest::testProxyCredentialsDigest() { HTTPCredentials creds("user", "s3cr3t"); @@ -299,11 +325,13 @@ CppUnit::Test* HTTPCredentialsTest::suite() CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyBasicCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testBadCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testAuthenticationParams); + CppUnit_addTest(pSuite, HTTPCredentialsTest, testAuthenticationParamsMultipleHeaders); CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentialsQoP); CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsBasic); CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsBasic); CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsDigest); + CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsDigestMultipleHeaders); CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsDigest); CppUnit_addTest(pSuite, HTTPCredentialsTest, testExtractCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testVerifyAuthInfo); diff --git a/Net/testsuite/src/HTTPCredentialsTest.h b/Net/testsuite/src/HTTPCredentialsTest.h index 94f85099f..4f0d3ac8a 100644 --- a/Net/testsuite/src/HTTPCredentialsTest.h +++ b/Net/testsuite/src/HTTPCredentialsTest.h @@ -30,11 +30,13 @@ public: void testProxyBasicCredentials(); void testBadCredentials(); void testAuthenticationParams(); + void testAuthenticationParamsMultipleHeaders(); void testDigestCredentials(); void testDigestCredentialsQoP(); void testCredentialsBasic(); void testProxyCredentialsBasic(); void testCredentialsDigest(); + void testCredentialsDigestMultipleHeaders(); void testProxyCredentialsDigest(); void testExtractCredentials(); void testVerifyAuthInfo(); diff --git a/Net/testsuite/src/NetTestSuite.cpp b/Net/testsuite/src/NetTestSuite.cpp index f94e249cb..7d28084ea 100644 --- a/Net/testsuite/src/NetTestSuite.cpp +++ b/Net/testsuite/src/NetTestSuite.cpp @@ -25,6 +25,7 @@ #include "ICMPClientTestSuite.h" #include "NTPClientTestSuite.h" #include "WebSocketTestSuite.h" +#include "OAuthTestSuite.h" #include "SyslogTest.h" @@ -46,6 +47,7 @@ CppUnit::Test* NetTestSuite::suite() pSuite->addTest(ICMPClientTestSuite::suite()); pSuite->addTest(NTPClientTestSuite::suite()); pSuite->addTest(WebSocketTestSuite::suite()); + pSuite->addTest(OAuthTestSuite::suite()); pSuite->addTest(SyslogTest::suite()); return pSuite; diff --git a/Net/testsuite/src/OAuth10CredentialsTest.cpp b/Net/testsuite/src/OAuth10CredentialsTest.cpp new file mode 100644 index 000000000..c47b8ba6e --- /dev/null +++ b/Net/testsuite/src/OAuth10CredentialsTest.cpp @@ -0,0 +1,266 @@ +// +// OAuth10CredentialsTest.cpp +// +// $Id$ +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "OAuth10CredentialsTest.h" +#include "CppUnit/TestCaller.h" +#include "CppUnit/TestSuite.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/HTTPResponse.h" +#include "Poco/Net/OAuth10Credentials.h" +#include "Poco/Net/NetException.h" +#include "Poco/Net/HTMLForm.h" +#include "Poco/URI.h" + + +using Poco::Net::HTTPRequest; +using Poco::Net::HTTPResponse; +using Poco::Net::OAuth10Credentials; +using Poco::Net::NotAuthenticatedException; +using Poco::Net::HTMLForm; +using Poco::URI; + + +OAuth10CredentialsTest::OAuth10CredentialsTest(const std::string& name): CppUnit::TestCase(name) +{ +} + + +OAuth10CredentialsTest::~OAuth10CredentialsTest() +{ +} + + +void OAuth10CredentialsTest::testCallback() +{ + // Note: Request taken from + // + // POST /oauth/request_token HTTP/1.1 + // Host: api.twitter.com + // Authorization: + // OAuth oauth_callback="http%3A%2F%2Flocalhost%2Fsign-in-with-twitter%2F", + // oauth_consumer_key="cChZNFj6T5R0TigYB9yd1w", + // oauth_nonce="ea9ec8429b68d6b77cd5600adbbb0456", + // oauth_signature="F1Li3tvehgcraF8DMJ7OyxO4w9Y%3D", + // oauth_signature_method="HMAC-SHA1", + // oauth_timestamp="1318467427", + // oauth_version="1.0" + + + URI uri("https://api.twitter.com/oauth/request_token"); + OAuth10Credentials creds("cChZNFj6T5R0TigYB9yd1w", "L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg"); + creds.setCallback("http://localhost/sign-in-with-twitter/"); + creds.nonceAndTimestampForTesting("ea9ec8429b68d6b77cd5600adbbb0456", "1318467427"); + HTTPRequest request(HTTPRequest::HTTP_POST, uri.getPathEtc()); + + creds.authenticate(request, uri); + + std::string auth = request.get("Authorization"); + assert (auth == "OAuth" + " oauth_consumer_key=\"cChZNFj6T5R0TigYB9yd1w\"," + " oauth_nonce=\"ea9ec8429b68d6b77cd5600adbbb0456\"," + " oauth_signature=\"F1Li3tvehgcraF8DMJ7OyxO4w9Y%3D\"," + " oauth_signature_method=\"HMAC-SHA1\"," + " oauth_timestamp=\"1318467427\"," + " oauth_callback=\"http%3A%2F%2Flocalhost%2Fsign-in-with-twitter%2F\"," + " oauth_version=\"1.0\""); +} + + +void OAuth10CredentialsTest::testParams() +{ + // Note: Request taken from + // and . + // + // POST /1/statuses/update.json?include_entities=true HTTP/1.1 + // Content-Type: application/x-www-form-urlencoded + // Authorization: + // OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", + // oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", + // oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D", + // oauth_signature_method="HMAC-SHA1", + // oauth_timestamp="1318622958", + // oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", + // oauth_version="1.0" + // Content-Length: 76 + // Host: api.twitter.com + // + // status=Hello%20Ladies%20%2b%20Gentlemen%2c%20a%20signed%20OAuth%20request%21 + + URI uri("https://api.twitter.com/1/statuses/update.json?include_entities=true"); + OAuth10Credentials creds( + "xvz1evFS4wEEPTGEFPHBog", + "kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw", + "370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", + "LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE" + ); + creds.nonceAndTimestampForTesting("kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", "1318622958"); + HTTPRequest request(HTTPRequest::HTTP_POST, uri.getPathEtc()); + + HTMLForm params; + params.set("include_entities", "true"); + params.set("status", "Hello Ladies + Gentlemen, a signed OAuth request!"); + + creds.authenticate(request, uri, params); + + std::string auth = request.get("Authorization"); + assert (auth == "OAuth" + " oauth_consumer_key=\"xvz1evFS4wEEPTGEFPHBog\"," + " oauth_nonce=\"kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg\"," + " oauth_signature=\"tnnArxj06cWHq44gCs1OSKk%2FjLY%3D\"," + " oauth_signature_method=\"HMAC-SHA1\"," + " oauth_timestamp=\"1318622958\"," + " oauth_token=\"370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb\"," + " oauth_version=\"1.0\""); +} + + +void OAuth10CredentialsTest::testRealm() +{ + // Note: Request taken from + // and . + // + // POST /1/statuses/update.json?include_entities=true HTTP/1.1 + // Content-Type: application/x-www-form-urlencoded + // Authorization: + // OAuth realm="Twitter API" + // oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", + // oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", + // oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D", + // oauth_signature_method="HMAC-SHA1", + // oauth_timestamp="1318622958", + // oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", + // oauth_version="1.0" + // Content-Length: 76 + // Host: api.twitter.com + // + // status=Hello%20Ladies%20%2b%20Gentlemen%2c%20a%20signed%20OAuth%20request%21 + + URI uri("https://api.twitter.com/1/statuses/update.json?include_entities=true"); + OAuth10Credentials creds( + "xvz1evFS4wEEPTGEFPHBog", + "kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw", + "370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", + "LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE" + ); + creds.setRealm("Twitter API"); + creds.nonceAndTimestampForTesting("kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", "1318622958"); + HTTPRequest request(HTTPRequest::HTTP_POST, uri.getPathEtc()); + + HTMLForm params; + params.set("include_entities", "true"); + params.set("status", "Hello Ladies + Gentlemen, a signed OAuth request!"); + + creds.authenticate(request, uri, params); + + std::string auth = request.get("Authorization"); + assert (auth == "OAuth" + " realm=\"Twitter API\"," + " oauth_consumer_key=\"xvz1evFS4wEEPTGEFPHBog\"," + " oauth_nonce=\"kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg\"," + " oauth_signature=\"tnnArxj06cWHq44gCs1OSKk%2FjLY%3D\"," + " oauth_signature_method=\"HMAC-SHA1\"," + " oauth_timestamp=\"1318622958\"," + " oauth_token=\"370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb\"," + " oauth_version=\"1.0\""); +} + + +void OAuth10CredentialsTest::testPlaintext() +{ + URI uri("https://api.twitter.com/oauth/request_token"); + OAuth10Credentials creds("consumerKey", "consumerSecret"); + creds.setCallback("http://localhost/sign-in-with-twitter/"); + HTTPRequest request(HTTPRequest::HTTP_POST, uri.getPathEtc()); + + creds.authenticate(request, uri, OAuth10Credentials::SIGN_PLAINTEXT); + + std::string auth = request.get("Authorization"); + + assert (auth == "OAuth" + " oauth_consumer_key=\"consumerKey\"," + " oauth_signature=\"consumerSecret%26\"," + " oauth_signature_method=\"PLAINTEXT\"," + " oauth_callback=\"http%3A%2F%2Flocalhost%2Fsign-in-with-twitter%2F\"," + " oauth_version=\"1.0\""); +} + + +void OAuth10CredentialsTest::testVerify() +{ + URI uri("https://api.twitter.com/1/statuses/update.json?include_entities=true"); + HTTPRequest request(HTTPRequest::HTTP_POST, uri.getPathEtc()); + request.set("Authorization", "OAuth" + " oauth_consumer_key=\"xvz1evFS4wEEPTGEFPHBog\"," + " oauth_nonce=\"kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg\"," + " oauth_signature=\"tnnArxj06cWHq44gCs1OSKk%2FjLY%3D\"," + " oauth_signature_method=\"HMAC-SHA1\"," + " oauth_timestamp=\"1318622958\"," + " oauth_token=\"370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb\"," + " oauth_version=\"1.0\""); + + OAuth10Credentials creds(request); + assert (creds.getConsumerKey() == "xvz1evFS4wEEPTGEFPHBog"); + assert (creds.getToken() == "370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb"); + creds.setConsumerSecret("kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw"); + creds.setTokenSecret("LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE"); + + HTMLForm params; + params.read(uri.getRawQuery()); + params.read("status=Hello%20Ladies%20%2b%20Gentlemen%2c%20a%20signed%20OAuth%20request%21"); + + assert (creds.verify(request, uri, params)); +} + + +void OAuth10CredentialsTest::testVerifyPlaintext() +{ + URI uri("https://api.twitter.com/oauth/request_token"); + HTTPRequest request(HTTPRequest::HTTP_POST, uri.getPathEtc()); + request.set("Authorization", "OAuth" + " oauth_consumer_key=\"consumerKey\"," + " oauth_signature=\"consumerSecret%26\"," + " oauth_signature_method=\"PLAINTEXT\"," + " oauth_callback=\"http%3A%2F%2Flocalhost%2Fsign-in-with-twitter%2F\"," + " oauth_version=\"1.0\""); + + OAuth10Credentials creds(request); + assert (creds.getConsumerKey() == "consumerKey"); + creds.setConsumerSecret("consumerSecret"); + + assert (creds.verify(request, uri)); + assert (creds.getCallback() == "http://localhost/sign-in-with-twitter/"); +} + + +void OAuth10CredentialsTest::setUp() +{ +} + + +void OAuth10CredentialsTest::tearDown() +{ +} + + +CppUnit::Test* OAuth10CredentialsTest::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("OAuth10CredentialsTest"); + + CppUnit_addTest(pSuite, OAuth10CredentialsTest, testCallback); + CppUnit_addTest(pSuite, OAuth10CredentialsTest, testParams); + CppUnit_addTest(pSuite, OAuth10CredentialsTest, testRealm); + CppUnit_addTest(pSuite, OAuth10CredentialsTest, testPlaintext); + CppUnit_addTest(pSuite, OAuth10CredentialsTest, testVerify); + CppUnit_addTest(pSuite, OAuth10CredentialsTest, testVerifyPlaintext); + + return pSuite; +} diff --git a/Net/testsuite/src/OAuth10CredentialsTest.h b/Net/testsuite/src/OAuth10CredentialsTest.h new file mode 100644 index 000000000..eb035426f --- /dev/null +++ b/Net/testsuite/src/OAuth10CredentialsTest.h @@ -0,0 +1,45 @@ +// +// OAuth10CredentialsTest.h +// +// $Id$ +// +// Definition of the OAuth10CredentialsTest class. +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef OAuth10CredentialsTest_INCLUDED +#define OAuth10CredentialsTest_INCLUDED + + +#include "Poco/Net/Net.h" +#include "CppUnit/TestCase.h" + + +class OAuth10CredentialsTest: public CppUnit::TestCase +{ +public: + OAuth10CredentialsTest(const std::string& name); + ~OAuth10CredentialsTest(); + + void testCallback(); + void testParams(); + void testRealm(); + void testPlaintext(); + void testVerify(); + void testVerifyPlaintext(); + + void setUp(); + void tearDown(); + + static CppUnit::Test* suite(); + +private: +}; + + +#endif // OAuth10CredentialsTest_INCLUDED diff --git a/Net/testsuite/src/OAuth20CredentialsTest.cpp b/Net/testsuite/src/OAuth20CredentialsTest.cpp new file mode 100644 index 000000000..6735cf0f8 --- /dev/null +++ b/Net/testsuite/src/OAuth20CredentialsTest.cpp @@ -0,0 +1,109 @@ +// +// OAuth20CredentialsTest.cpp +// +// $Id$ +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "OAuth20CredentialsTest.h" +#include "CppUnit/TestCaller.h" +#include "CppUnit/TestSuite.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/OAuth20Credentials.h" +#include "Poco/Net/NetException.h" + + +using Poco::Net::HTTPRequest; +using Poco::Net::OAuth20Credentials; +using Poco::Net::NotAuthenticatedException; + + +OAuth20CredentialsTest::OAuth20CredentialsTest(const std::string& name): CppUnit::TestCase(name) +{ +} + + +OAuth20CredentialsTest::~OAuth20CredentialsTest() +{ +} + + +void OAuth20CredentialsTest::testAuthorize() +{ + OAuth20Credentials creds("s3cr3tt0k3n"); + HTTPRequest request(HTTPRequest::HTTP_GET, "/"); + creds.authenticate(request); + std::string auth = request.get("Authorization"); + assert (auth == "Bearer s3cr3tt0k3n"); +} + + +void OAuth20CredentialsTest::testAuthorizeCustomScheme() +{ + OAuth20Credentials creds("s3cr3tt0k3n", "token"); + HTTPRequest request(HTTPRequest::HTTP_GET, "/"); + creds.authenticate(request); + std::string auth = request.get("Authorization"); + assert (auth == "token s3cr3tt0k3n"); +} + + +void OAuth20CredentialsTest::testExtract() +{ + HTTPRequest request(HTTPRequest::HTTP_GET, "/"); + request.set("Authorization", "Bearer s3cr3tt0k3n"); + OAuth20Credentials creds(request); + assert (creds.getBearerToken() == "s3cr3tt0k3n"); +} + + +void OAuth20CredentialsTest::testExtractCustomScheme() +{ + HTTPRequest request(HTTPRequest::HTTP_GET, "/"); + request.set("Authorization", "token s3cr3tt0k3n"); + OAuth20Credentials creds(request, "token"); + assert (creds.getBearerToken() == "s3cr3tt0k3n"); +} + + +void OAuth20CredentialsTest::testExtractNoCreds() +{ + HTTPRequest request(HTTPRequest::HTTP_GET, "/"); + try + { + OAuth20Credentials creds(request); + fail("no credentials - must throw"); + } + catch (NotAuthenticatedException&) + { + } +} + + +void OAuth20CredentialsTest::setUp() +{ +} + + +void OAuth20CredentialsTest::tearDown() +{ +} + + +CppUnit::Test* OAuth20CredentialsTest::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("OAuth20CredentialsTest"); + + CppUnit_addTest(pSuite, OAuth20CredentialsTest, testAuthorize); + CppUnit_addTest(pSuite, OAuth20CredentialsTest, testAuthorizeCustomScheme); + CppUnit_addTest(pSuite, OAuth20CredentialsTest, testExtract); + CppUnit_addTest(pSuite, OAuth20CredentialsTest, testExtractCustomScheme); + CppUnit_addTest(pSuite, OAuth20CredentialsTest, testExtractNoCreds); + + return pSuite; +} diff --git a/Net/testsuite/src/OAuth20CredentialsTest.h b/Net/testsuite/src/OAuth20CredentialsTest.h new file mode 100644 index 000000000..f146d456f --- /dev/null +++ b/Net/testsuite/src/OAuth20CredentialsTest.h @@ -0,0 +1,44 @@ +// +// OAuth20CredentialsTest.h +// +// $Id$ +// +// Definition of the OAuth20CredentialsTest class. +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef OAuth20CredentialsTest_INCLUDED +#define OAuth20CredentialsTest_INCLUDED + + +#include "Poco/Net/Net.h" +#include "CppUnit/TestCase.h" + + +class OAuth20CredentialsTest: public CppUnit::TestCase +{ +public: + OAuth20CredentialsTest(const std::string& name); + ~OAuth20CredentialsTest(); + + void testAuthorize(); + void testAuthorizeCustomScheme(); + void testExtract(); + void testExtractCustomScheme(); + void testExtractNoCreds(); + + void setUp(); + void tearDown(); + + static CppUnit::Test* suite(); + +private: +}; + + +#endif // OAuth20CredentialsTest_INCLUDED diff --git a/Net/testsuite/src/OAuthTestSuite.cpp b/Net/testsuite/src/OAuthTestSuite.cpp new file mode 100644 index 000000000..d1ca6f6a1 --- /dev/null +++ b/Net/testsuite/src/OAuthTestSuite.cpp @@ -0,0 +1,26 @@ +// +// OAuthTestSuite.cpp +// +// $Id$ +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "OAuthTestSuite.h" +#include "OAuth10CredentialsTest.h" +#include "OAuth20CredentialsTest.h" + + +CppUnit::Test* OAuthTestSuite::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("OAuthTestSuite"); + + pSuite->addTest(OAuth10CredentialsTest::suite()); + pSuite->addTest(OAuth20CredentialsTest::suite()); + + return pSuite; +} diff --git a/Net/testsuite/src/OAuthTestSuite.h b/Net/testsuite/src/OAuthTestSuite.h new file mode 100644 index 000000000..7ecb345f3 --- /dev/null +++ b/Net/testsuite/src/OAuthTestSuite.h @@ -0,0 +1,29 @@ +// +// OAuthTestSuite.h +// +// $Id$ +// +// Definition of the OAuthTestSuite class. +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef OAuthTestSuite_INCLUDED +#define OAuthTestSuite_INCLUDED + + +#include "CppUnit/TestSuite.h" + + +class OAuthTestSuite +{ +public: + static CppUnit::Test* suite(); +}; + + +#endif // OAuthTestSuite_INCLUDED diff --git a/NetSSL_OpenSSL/CMakeLists.txt b/NetSSL_OpenSSL/CMakeLists.txt index 36862f2a7..0ad6a67f1 100644 --- a/NetSSL_OpenSSL/CMakeLists.txt +++ b/NetSSL_OpenSSL/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoNetSSL") +set(LIBNAME "NetSSL") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -8,26 +9,39 @@ POCO_SOURCES_AUTO( SRCS ${SRCS_G}) file(GLOB_RECURSE HDRS_G "include/*.h" ) POCO_HEADERS_AUTO( SRCS ${HDRS_G}) -add_library( ${LIBNAME} ${LIB_MODE} ${SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" PROPERTIES VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL NetSSL_EXPORTS) -target_link_libraries( ${LIBNAME} PocoCrypto PocoNet PocoUtil PocoFoundation ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} ) + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL NetSSL_EXPORTS + ) +target_link_libraries( "${LIBNAME}" Crypto Net Util Foundation ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} ) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + if (ENABLE_TESTS) add_subdirectory(samples) add_subdirectory(testsuite) diff --git a/NetSSL_OpenSSL/cmake/PocoNetSSLConfig.cmake b/NetSSL_OpenSSL/cmake/PocoNetSSLConfig.cmake new file mode 100644 index 000000000..65fb88c26 --- /dev/null +++ b/NetSSL_OpenSSL/cmake/PocoNetSSLConfig.cmake @@ -0,0 +1,7 @@ +include(CMakeFindDependencyMacro) +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}) +find_dependency(PocoFoundation) +find_dependency(PocoUtil) +find_dependency(PocoNet) +find_dependency(PocoCrypto) +include("${CMAKE_CURRENT_LIST_DIR}/PocoNetSSLTargets.cmake") \ No newline at end of file diff --git a/NetSSL_OpenSSL/samples/CMakeLists.txt b/NetSSL_OpenSSL/samples/CMakeLists.txt index e6ad6f591..66f895a6f 100644 --- a/NetSSL_OpenSSL/samples/CMakeLists.txt +++ b/NetSSL_OpenSSL/samples/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory( HTTPSTimeServer ) add_subdirectory( download ) add_subdirectory( Mail ) +add_subdirectory( TwitterClient ) diff --git a/NetSSL_OpenSSL/samples/Makefile b/NetSSL_OpenSSL/samples/Makefile index 9565d4173..e35b87468 100644 --- a/NetSSL_OpenSSL/samples/Makefile +++ b/NetSSL_OpenSSL/samples/Makefile @@ -10,3 +10,4 @@ $(MAKE) -C HTTPSTimeServer $(MAKECMDGOALS) $(MAKE) -C download $(MAKECMDGOALS) $(MAKE) -C Mail $(MAKECMDGOALS) + $(MAKE) -C TwitterClient $(MAKECMDGOALS) diff --git a/Net/samples/TwitterClient/CMakeLists.txt b/NetSSL_OpenSSL/samples/TwitterClient/CMakeLists.txt similarity index 55% rename from Net/samples/TwitterClient/CMakeLists.txt rename to NetSSL_OpenSSL/samples/TwitterClient/CMakeLists.txt index 687b55c69..66907c034 100644 --- a/Net/samples/TwitterClient/CMakeLists.txt +++ b/NetSSL_OpenSSL/samples/TwitterClient/CMakeLists.txt @@ -4,4 +4,4 @@ set(LOCAL_SRCS "") aux_source_directory(src LOCAL_SRCS) add_executable( ${SAMPLE_NAME} ${LOCAL_SRCS} ) -target_link_libraries( ${SAMPLE_NAME} PocoNet PocoUtil PocoJSON PocoXML PocoFoundation ) +target_link_libraries( ${SAMPLE_NAME} PocoNetSSL PocoCrypto PocoNet PocoUtil PocoJSON PocoXML PocoFoundation ) diff --git a/Net/samples/TwitterClient/Makefile b/NetSSL_OpenSSL/samples/TwitterClient/Makefile similarity index 78% rename from Net/samples/TwitterClient/Makefile rename to NetSSL_OpenSSL/samples/TwitterClient/Makefile index d5683dbeb..7983a95b3 100644 --- a/Net/samples/TwitterClient/Makefile +++ b/NetSSL_OpenSSL/samples/TwitterClient/Makefile @@ -12,7 +12,7 @@ objects = Twitter TweetApp target = tweet target_version = 1 -target_libs = PocoUtil PocoJSON PocoNet PocoXML PocoFoundation +target_libs = PocoUtil PocoJSON PocoNetSSL PocoCrypto PocoNet PocoXML PocoFoundation include $(POCO_BASE)/build/rules/exec diff --git a/Net/samples/TwitterClient/TwitterClient.progen b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient.progen similarity index 88% rename from Net/samples/TwitterClient/TwitterClient.progen rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient.progen index cb66b60d0..de0ca0bd2 100644 --- a/Net/samples/TwitterClient/TwitterClient.progen +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient.progen @@ -6,7 +6,7 @@ vc.project.pocobase = ..\\..\\.. vc.project.platforms = Win32, x64, WinCE vc.project.configurations = debug_shared, release_shared, debug_static_mt, release_static_mt, debug_static_md, release_static_md vc.project.prototype = ${vc.project.name}_vs90.vcproj -vc.project.compiler.include = ..\\..\\..\\Foundation\\include;..\\..\\..\\XML\\include;..\\..\\..\\JSON\\include;..\\..\\..\\Util\\include;..\\..\\..\\Net\\include +vc.project.compiler.include = ..\\..\\..\\Foundation\\include;..\\..\\..\\XML\\include;..\\..\\..\\JSON\\include;..\\..\\..\\Util\\include;..\\..\\..\\Net\\include;..\\..\\..\\NetSSL_OpenSSL\\include;..\\..\\..\\Crypto\\include vc.project.linker.dependencies.Win32 = ws2_32.lib iphlpapi.lib vc.project.linker.dependencies.x64 = ws2_32.lib iphlpapi.lib vc.project.linker.dependencies.WinCE = ws2.lib iphlpapi.lib diff --git a/Net/samples/TwitterClient/TwitterClient_CE_vs90.vcproj b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_CE_vs90.vcproj similarity index 96% rename from Net/samples/TwitterClient/TwitterClient_CE_vs90.vcproj rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_CE_vs90.vcproj index cc85a0571..5bfc68aa8 100644 --- a/Net/samples/TwitterClient/TwitterClient_CE_vs90.vcproj +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_CE_vs90.vcproj @@ -33,7 +33,7 @@ Name="VCCLCompilerTool" ExecutionBucket="7" Optimization="0" - AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include" + AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include" PreprocessorDefinitions="_DEBUG;_WIN32_WCE=$(CEVER);UNDER_CE;WINCE;$(ARCHFAM);$(_ARCHFAM_);_CONSOLE;_CRT_SECURE_NO_WARNINGS;" StringPooling="true" MinimalRebuild="false" @@ -106,7 +106,7 @@ Name="VCCLCompilerTool" ExecutionBucket="7" Optimization="0" - AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include" + AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include" PreprocessorDefinitions="_DEBUG;_WIN32_WCE=$(CEVER);UNDER_CE;WINCE;$(ARCHFAM);$(_ARCHFAM_);_CONSOLE;_CRT_SECURE_NO_WARNINGS;" StringPooling="true" MinimalRebuild="false" @@ -180,7 +180,7 @@ Name="VCCLCompilerTool" ExecutionBucket="7" Optimization="0" - AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include" + AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include" PreprocessorDefinitions="_DEBUG;_WIN32_WCE=$(CEVER);UNDER_CE;WINCE;$(ARCHFAM);$(_ARCHFAM_);POCO_STATIC;_CONSOLE;_CRT_SECURE_NO_WARNINGS;" StringPooling="true" MinimalRebuild="false" @@ -256,7 +256,7 @@ InlineFunctionExpansion="0" EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" - AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include" + AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include" PreprocessorDefinitions="NDEBUG;_WIN32_WCE=$(CEVER);UNDER_CE;WINCE;$(ARCHFAM);$(_ARCHFAM_);POCO_STATIC;_CONSOLE;_CRT_SECURE_NO_WARNINGS;" StringPooling="true" MinimalRebuild="false" @@ -330,7 +330,7 @@ Name="VCCLCompilerTool" ExecutionBucket="7" Optimization="0" - AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include" + AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include" PreprocessorDefinitions="_DEBUG;_WIN32_WCE=$(CEVER);UNDER_CE;WINCE;$(ARCHFAM);$(_ARCHFAM_);POCO_STATIC;_CONSOLE;_CRT_SECURE_NO_WARNINGS;" StringPooling="true" MinimalRebuild="false" @@ -406,7 +406,7 @@ InlineFunctionExpansion="0" EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" - AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include" + AdditionalIncludeDirectories="..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include" PreprocessorDefinitions="NDEBUG;_WIN32_WCE=$(CEVER);UNDER_CE;WINCE;$(ARCHFAM);$(_ARCHFAM_);POCO_STATIC;_CONSOLE;_CRT_SECURE_NO_WARNINGS;" StringPooling="true" MinimalRebuild="false" diff --git a/Net/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj similarity index 95% rename from Net/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj index 3a96dd217..0af6908b6 100644 --- a/Net/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj @@ -129,7 +129,7 @@ Disabled - ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) _DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -156,7 +156,7 @@ Disabled true Speed - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) NDEBUG;$(ProjectName)_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -181,7 +181,7 @@ Disabled - ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) _DEBUG;POCO_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -209,7 +209,7 @@ Default true Speed - ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) NDEBUG;POCO_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -236,7 +236,7 @@ Disabled - ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) _DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -264,7 +264,7 @@ Default true Speed - ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) NDEBUG;POCO_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false diff --git a/Net/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj.filters b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj.filters similarity index 83% rename from Net/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj.filters rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj.filters index 0e3bf1267..ceb6160f9 100644 --- a/Net/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj.filters +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs110.vcxproj.filters @@ -2,10 +2,10 @@ - {b5474087-a2a1-4e71-9626-29efe9ee5bf2} + {60b0a3ce-ab8b-4721-b2e2-873bc325d0ba} - {624057d4-59aa-4ebe-9e39-cdd607b3034a} + {cb9f6372-6e80-4757-81b9-928ac4f18f49} diff --git a/Net/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj similarity index 95% rename from Net/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj index a003ad6c4..52f65e61b 100644 --- a/Net/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj @@ -129,7 +129,7 @@ Disabled - ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) _DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -156,7 +156,7 @@ Disabled true Speed - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) NDEBUG;$(ProjectName)_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -181,7 +181,7 @@ Disabled - ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) _DEBUG;POCO_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -209,7 +209,7 @@ Default true Speed - ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) NDEBUG;POCO_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -236,7 +236,7 @@ Disabled - ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) _DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -264,7 +264,7 @@ Default true Speed - ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + ..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) NDEBUG;POCO_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false diff --git a/Net/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj.filters b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj.filters similarity index 83% rename from Net/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj.filters rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj.filters index 8002ae987..bacb5513a 100644 --- a/Net/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj.filters +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_WEC2013_vs120.vcxproj.filters @@ -2,10 +2,10 @@ - {442351cf-69e4-4f22-a338-008f2fb9e7c6} + {59701d5b-03c7-4334-929e-c8c238a5fd80} - {ffa2790a-bb33-4361-b112-9e4c9295a9f7} + {1bf2cf81-b76a-424b-b102-946689efc80a} diff --git a/Net/samples/TwitterClient/TwitterClient_vs100.vcxproj b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs100.vcxproj similarity index 95% rename from Net/samples/TwitterClient/TwitterClient_vs100.vcxproj rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs100.vcxproj index d1fc6400c..9bf679b95 100644 --- a/Net/samples/TwitterClient/TwitterClient_vs100.vcxproj +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs100.vcxproj @@ -108,7 +108,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true true @@ -144,7 +144,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true MultiThreadedDLL @@ -174,7 +174,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -210,7 +210,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreaded @@ -240,7 +240,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -276,7 +276,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreadedDLL diff --git a/Net/samples/TwitterClient/TwitterClient_vs100.vcxproj.filters b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs100.vcxproj.filters similarity index 83% rename from Net/samples/TwitterClient/TwitterClient_vs100.vcxproj.filters rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs100.vcxproj.filters index 995884176..8d70ca1c4 100644 --- a/Net/samples/TwitterClient/TwitterClient_vs100.vcxproj.filters +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs100.vcxproj.filters @@ -2,10 +2,10 @@ - {8c3d76b4-4019-4fe0-b228-e1d37f43840e} + {0e50f5e8-9486-42ef-943d-58c799102067} - {6d65ed68-8842-46a7-8d3e-6dbfe10cac0c} + {8c7769cc-0197-4968-b706-460f8d47d2ac} diff --git a/Net/samples/TwitterClient/TwitterClient_vs110.vcxproj b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs110.vcxproj similarity index 95% rename from Net/samples/TwitterClient/TwitterClient_vs110.vcxproj rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs110.vcxproj index 00c3db2ee..077614571 100644 --- a/Net/samples/TwitterClient/TwitterClient_vs110.vcxproj +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs110.vcxproj @@ -126,7 +126,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true true @@ -159,7 +159,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true MultiThreadedDLL @@ -186,7 +186,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -219,7 +219,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreaded @@ -246,7 +246,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -279,7 +279,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreadedDLL diff --git a/Net/samples/TwitterClient/TwitterClient_vs110.vcxproj.filters b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs110.vcxproj.filters similarity index 83% rename from Net/samples/TwitterClient/TwitterClient_vs110.vcxproj.filters rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs110.vcxproj.filters index 11e27cc26..54c348c24 100644 --- a/Net/samples/TwitterClient/TwitterClient_vs110.vcxproj.filters +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs110.vcxproj.filters @@ -2,10 +2,10 @@ - {93d8883d-4191-4c49-93ac-86eb0dce6fe7} + {99a5886f-52f7-4001-990c-c5ebc2d0971f} - {5ef67436-af14-46c9-adb5-a2dee8151237} + {399f16e2-e784-4916-be3a-cab5753bcd32} diff --git a/Net/samples/TwitterClient/TwitterClient_vs120.vcxproj b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs120.vcxproj similarity index 95% rename from Net/samples/TwitterClient/TwitterClient_vs120.vcxproj rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs120.vcxproj index 95d62966c..6cd9218e4 100644 --- a/Net/samples/TwitterClient/TwitterClient_vs120.vcxproj +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs120.vcxproj @@ -126,7 +126,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true true @@ -159,7 +159,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true MultiThreadedDLL @@ -186,7 +186,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -219,7 +219,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreaded @@ -246,7 +246,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -279,7 +279,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreadedDLL diff --git a/Net/samples/TwitterClient/TwitterClient_vs120.vcxproj.filters b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs120.vcxproj.filters similarity index 83% rename from Net/samples/TwitterClient/TwitterClient_vs120.vcxproj.filters rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs120.vcxproj.filters index b51e1d25c..5ed2260c7 100644 --- a/Net/samples/TwitterClient/TwitterClient_vs120.vcxproj.filters +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs120.vcxproj.filters @@ -2,10 +2,10 @@ - {d3ee1c1e-12ea-4a81-9069-9fd705ac0311} + {6359a70f-49b0-4466-9ac5-f39802ab2099} - {66fae26b-7f05-4353-818b-eb3eb3bf2cf4} + {e71aa79b-49aa-4364-b9a7-18e07d82b764} diff --git a/Net/samples/TwitterClient/TwitterClient_vs71.vcproj b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs71.vcproj similarity index 95% rename from Net/samples/TwitterClient/TwitterClient_vs71.vcproj rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs71.vcproj index add463f69..47b274088 100644 --- a/Net/samples/TwitterClient/TwitterClient_vs71.vcproj +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_vs71.vcproj @@ -20,7 +20,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true true @@ -144,7 +144,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true MultiThreadedDLL @@ -174,7 +174,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -210,7 +210,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreaded @@ -240,7 +240,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -276,7 +276,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreadedDLL diff --git a/Net/samples/TwitterClient/TwitterClient_x64_vs100.vcxproj.filters b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs100.vcxproj.filters similarity index 83% rename from Net/samples/TwitterClient/TwitterClient_x64_vs100.vcxproj.filters rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs100.vcxproj.filters index 5611bffea..ce1402728 100644 --- a/Net/samples/TwitterClient/TwitterClient_x64_vs100.vcxproj.filters +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs100.vcxproj.filters @@ -2,10 +2,10 @@ - {502e5089-9f4d-422f-8253-3b420f499915} + {7a5fa43a-d241-4c8d-b933-ee9a4e64d543} - {e356359a-d0dd-4b18-93cc-f1d5a9b936cd} + {eb2a5010-5f72-4492-a0b2-4bc5bc2151c9} diff --git a/Net/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj similarity index 95% rename from Net/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj index 7fd0d7326..2aafb42bd 100644 --- a/Net/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj @@ -126,7 +126,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true true @@ -159,7 +159,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true MultiThreadedDLL @@ -186,7 +186,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -219,7 +219,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreaded @@ -246,7 +246,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -279,7 +279,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreadedDLL diff --git a/Net/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj.filters b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj.filters similarity index 83% rename from Net/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj.filters rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj.filters index aefd9d8fd..68a41aa11 100644 --- a/Net/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj.filters +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs110.vcxproj.filters @@ -2,10 +2,10 @@ - {c0e473ca-f598-4411-b27c-0b748ec14f98} + {c077f563-7808-43f7-ac1e-2ee378f72ae1} - {d19c11e0-d273-4b4a-9677-f455830ac33d} + {af8152b6-9e03-48da-85b4-5d33b7bef21a} diff --git a/Net/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj similarity index 95% rename from Net/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj index 5a397bd9f..10caecb11 100644 --- a/Net/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj @@ -126,7 +126,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true true @@ -159,7 +159,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) true MultiThreadedDLL @@ -186,7 +186,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -219,7 +219,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreaded @@ -246,7 +246,7 @@ Disabled - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true true @@ -279,7 +279,7 @@ true Speed true - .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;%(AdditionalIncludeDirectories) + .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\JSON\include;..\..\..\Util\include;..\..\..\Net\include;..\..\..\NetSSL_OpenSSL\include;..\..\..\Crypto\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreadedDLL diff --git a/Net/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj.filters b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj.filters similarity index 83% rename from Net/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj.filters rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj.filters index d35612d9d..856384d34 100644 --- a/Net/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj.filters +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs120.vcxproj.filters @@ -2,10 +2,10 @@ - {2fc87553-1f46-40fe-b480-6e0e818f153b} + {c5c23ac2-f266-4757-8dc8-c19dc3eef2a6} - {71b7207b-5e72-4c82-93d1-6151ce1426d6} + {821fbf1a-efa6-4a13-ad4b-c25e3032e82e} diff --git a/Net/samples/TwitterClient/TwitterClient_x64_vs90.vcproj b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs90.vcproj similarity index 95% rename from Net/samples/TwitterClient/TwitterClient_x64_vs90.vcproj rename to NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs90.vcproj index bdbb91b03..22e7a3c98 100644 --- a/Net/samples/TwitterClient/TwitterClient_x64_vs90.vcproj +++ b/NetSSL_OpenSSL/samples/TwitterClient/TwitterClient_x64_vs90.vcproj @@ -31,7 +31,7 @@ (this, &TweetApp::handleHelp))); options.addOption( - Option("message", "m", "specify the status message to post") + Option("message", "m", "Specify the status message to post.") .required(true) .repeatable(false) .argument("message") .callback(OptionCallback(this, &TweetApp::handleMessage))); options.addOption( - Option("ckey", "c", "specify the Twitter consumer key") + Option("ckey", "c", "Specify the Twitter consumer key.") .required(true) .repeatable(false) .argument("consumer key") .callback(OptionCallback(this, &TweetApp::handleConsumerKey))); options.addOption( - Option("csecret", "s", "specify the Twitter consumer secret") + Option("csecret", "s", "Specify the Twitter consumer secret.") .required(true) .repeatable(false) .argument("consumer secret") .callback(OptionCallback(this, &TweetApp::handleConsumerSecret))); options.addOption( - Option("token", "t", "specify the Twitter access token") - .required(false) + Option("token", "t", "Specify the Twitter access token.") + .required(true) .repeatable(true) .argument("access token") .callback(OptionCallback(this, &TweetApp::handleAccessToken))); options.addOption( - Option("tsecret", "S", "specify the Twitter access token secret") - .required(false) + Option("tsecret", "S", "Specify the Twitter access token secret.") + .required(true) .repeatable(true) .argument("access token secret") .callback(OptionCallback(this, &TweetApp::handleAccessTokenSecret))); @@ -112,17 +111,7 @@ protected: void handleMessage(const std::string& name, const std::string& value) { - try - { - _twitter.login(_consumerKey, _consumerSecret, _accessToken, _accessTokenSecret); - Poco::Int64 statusId = _twitter.update(value); - std::cout << statusId << std::endl; - } - catch (Poco::Exception& exc) - { - std::cerr << exc.displayText() << std::endl; - _status = Application::EXIT_SOFTWARE; - } + _message = value; } void displayHelp() @@ -136,7 +125,22 @@ protected: int main(const std::vector& args) { - return _status; + try + { + if (!_message.empty()) + { + Twitter twitter; + twitter.login(_consumerKey, _consumerSecret, _accessToken, _accessTokenSecret); + Poco::Int64 statusId = twitter.update(_message); + std::cout << statusId << std::endl; + } + } + catch (Poco::Exception& exc) + { + std::cerr << exc.displayText() << std::endl; + return Application::EXIT_SOFTWARE; + } + return Application::EXIT_OK; } private: @@ -144,8 +148,7 @@ private: std::string _consumerSecret; std::string _accessToken; std::string _accessTokenSecret; - Twitter _twitter; - int _status; + std::string _message; }; diff --git a/NetSSL_OpenSSL/samples/TwitterClient/src/Twitter.cpp b/NetSSL_OpenSSL/samples/TwitterClient/src/Twitter.cpp new file mode 100644 index 000000000..362ec6fc6 --- /dev/null +++ b/NetSSL_OpenSSL/samples/TwitterClient/src/Twitter.cpp @@ -0,0 +1,98 @@ +// +// Twitter.cpp +// +// $Id: //poco/1.4/Net/samples/TwitterClient/src/Twitter.cpp#2 $ +// +// A C++ implementation of a Twitter client based on the POCO Net library. +// +// Copyright (c) 2009-2013, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Twitter.h" +#include "Poco/Net/HTTPSClientSession.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/HTTPResponse.h" +#include "Poco/Net/OAuth10Credentials.h" +#include "Poco/Util/JSONConfiguration.h" +#include "Poco/URI.h" +#include "Poco/Format.h" +#include "Poco/StreamCopier.h" + + +const std::string Twitter::TWITTER_URI("https://api.twitter.com/1.1/statuses/"); + + +Twitter::Twitter(): + _uri(TWITTER_URI) +{ +} + + +Twitter::Twitter(const std::string& twitterURI): + _uri(twitterURI) +{ +} + + +Twitter::~Twitter() +{ +} + + +void Twitter::login(const std::string& consumerKey, const std::string& consumerSecret, const std::string& token, const std::string& tokenSecret) +{ + _consumerKey = consumerKey; + _consumerSecret = consumerSecret; + _token = token; + _tokenSecret = tokenSecret; +} + + +Poco::Int64 Twitter::update(const std::string& status) +{ + Poco::Net::HTMLForm form; + form.set("status", status); + Poco::AutoPtr pResult = invoke(Poco::Net::HTTPRequest::HTTP_POST, "update", form); + return pResult->getInt64("id", 0); +} + + +Poco::AutoPtr Twitter::invoke(const std::string& httpMethod, const std::string& twitterMethod, Poco::Net::HTMLForm& form) +{ + // Create the request URI. + // We use the JSON version of the Twitter API. + Poco::URI uri(_uri + twitterMethod + ".json"); + + Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort()); + Poco::Net::HTTPRequest req(httpMethod, uri.getPath(), Poco::Net::HTTPMessage::HTTP_1_1); + + // Sign request + Poco::Net::OAuth10Credentials creds(_consumerKey, _consumerSecret, _token, _tokenSecret); + creds.authenticate(req, uri, form); + + // Send the request. + form.prepareSubmit(req); + std::ostream& ostr = session.sendRequest(req); + form.write(ostr); + + // Receive the response. + Poco::Net::HTTPResponse res; + std::istream& rs = session.receiveResponse(res); + + Poco::AutoPtr pResult = new Poco::Util::JSONConfiguration(rs); + + // If everything went fine, return the JSON document. + // Otherwise throw an exception. + if (res.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) + { + return pResult; + } + else + { + throw Poco::ApplicationException("Twitter Error", pResult->getString("errors[0].message", "")); + } +} diff --git a/Net/samples/TwitterClient/src/Twitter.h b/NetSSL_OpenSSL/samples/TwitterClient/src/Twitter.h similarity index 66% rename from Net/samples/TwitterClient/src/Twitter.h rename to NetSSL_OpenSSL/samples/TwitterClient/src/Twitter.h index 2e3fb8e1c..0124f41c8 100644 --- a/Net/samples/TwitterClient/src/Twitter.h +++ b/NetSSL_OpenSSL/samples/TwitterClient/src/Twitter.h @@ -58,25 +58,6 @@ public: static const std::string TWITTER_URI; -protected: - void sign(Poco::Net::HTTPRequest& request, const Poco::Net::HTMLForm& params, const std::string& uri) const; - /// Signs the given HTTP request according to OAuth 1.0a as used by the Twitter API. - /// - /// See and - /// for more information. - - std::string createNonce() const; - /// Creates a nonce, which is basically a Base64-encoded 32 character random - /// string, with non-alphanumeric characters removed. - - std::string createSignature(Poco::Net::HTTPRequest& request, const Poco::Net::HTMLForm& params, const std::string& uri, const std::string& nonce, const std::string& timestamp) const; - /// Creates a OAuth signature for the given request and its parameters, according - /// to . - - static std::string percentEncode(const std::string& str); - /// Percent-encodes the given string according to Twitter API's rules, - /// given in . - private: Twitter(const Twitter&); Twitter& operator = (const Twitter&); diff --git a/NetSSL_OpenSSL/samples/samples.progen b/NetSSL_OpenSSL/samples/samples.progen index 7bb3a564e..3d16b1a03 100644 --- a/NetSSL_OpenSSL/samples/samples.progen +++ b/NetSSL_OpenSSL/samples/samples.progen @@ -4,4 +4,5 @@ vc.solution.create = true vc.solution.include = \ download\\download;\ HTTPSTimeServer\\HTTPSTimeServer;\ - Mail\\Mail + Mail\\Mail;\ + TwitterClient\\TwitterClient diff --git a/NetSSL_OpenSSL/samples/samples_CE_vs90.sln b/NetSSL_OpenSSL/samples/samples_CE_vs90.sln index 1a96370ea..675634622 100644 --- a/NetSSL_OpenSSL/samples/samples_CE_vs90.sln +++ b/NetSSL_OpenSSL/samples/samples_CE_vs90.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_CE_vs90.vcproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_CE_vs90.vcproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|Digi JumpStart (ARMV4I) = debug_shared|Digi JumpStart (ARMV4I) @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Digi JumpStart (ARMV4I).ActiveCfg = release_static_md|Digi JumpStart (ARMV4I) {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Digi JumpStart (ARMV4I).Build.0 = release_static_md|Digi JumpStart (ARMV4I) {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Digi JumpStart (ARMV4I).Deploy.0 = release_static_md|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Digi JumpStart (ARMV4I).ActiveCfg = debug_shared|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Digi JumpStart (ARMV4I).Build.0 = debug_shared|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Digi JumpStart (ARMV4I).Deploy.0 = debug_shared|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Digi JumpStart (ARMV4I).ActiveCfg = release_shared|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Digi JumpStart (ARMV4I).Build.0 = release_shared|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Digi JumpStart (ARMV4I).Deploy.0 = release_shared|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Digi JumpStart (ARMV4I).ActiveCfg = debug_static_mt|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Digi JumpStart (ARMV4I).Build.0 = debug_static_mt|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Digi JumpStart (ARMV4I).Deploy.0 = debug_static_mt|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Digi JumpStart (ARMV4I).ActiveCfg = release_static_mt|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Digi JumpStart (ARMV4I).Build.0 = release_static_mt|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Digi JumpStart (ARMV4I).Deploy.0 = release_static_mt|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Digi JumpStart (ARMV4I).ActiveCfg = debug_static_md|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Digi JumpStart (ARMV4I).Build.0 = debug_static_md|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Digi JumpStart (ARMV4I).Deploy.0 = debug_static_md|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Digi JumpStart (ARMV4I).ActiveCfg = release_static_md|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Digi JumpStart (ARMV4I).Build.0 = release_static_md|Digi JumpStart (ARMV4I) + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Digi JumpStart (ARMV4I).Deploy.0 = release_static_md|Digi JumpStart (ARMV4I) EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/samples/samples_WEC2013_vs110.sln b/NetSSL_OpenSSL/samples/samples_WEC2013_vs110.sln new file mode 100644 index 000000000..ee89c11c4 --- /dev/null +++ b/NetSSL_OpenSSL/samples/samples_WEC2013_vs110.sln @@ -0,0 +1,97 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "download", "download\download_WEC2013_vs110.vcxproj", "{D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTimeServer\HTTPSTimeServer_WEC2013_vs110.vcxproj", "{F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_WEC2013_vs110.vcxproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_WEC2013_vs110.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + debug_shared|SDK_AM335X_SK_WEC2013_V300 = debug_shared|SDK_AM335X_SK_WEC2013_V300 + release_shared|SDK_AM335X_SK_WEC2013_V300 = release_shared|SDK_AM335X_SK_WEC2013_V300 + debug_static_mt|SDK_AM335X_SK_WEC2013_V300 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + release_static_mt|SDK_AM335X_SK_WEC2013_V300 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + debug_static_md|SDK_AM335X_SK_WEC2013_V300 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + release_static_md|SDK_AM335X_SK_WEC2013_V300 = release_static_md|SDK_AM335X_SK_WEC2013_V300 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.debug_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.release_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_shared|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.release_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_shared|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.release_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_shared|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.release_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {D853F3D6-0D6F-3E8E-82C7-4216D7A21C4D}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.debug_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.release_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_shared|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.release_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_shared|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.release_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_shared|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.release_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {F8DE5054-3EC1-3FB4-9FE6-38EE974745A9}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.debug_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_shared|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_shared|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_shared|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_shared|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_shared|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_shared|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_shared|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V300.ActiveCfg = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Build.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V300.Deploy.0 = release_static_md|SDK_AM335X_SK_WEC2013_V300 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/NetSSL_OpenSSL/samples/samples_WEC2013_vs120.sln b/NetSSL_OpenSSL/samples/samples_WEC2013_vs120.sln index 3f5246c6e..3883d0a1e 100644 --- a/NetSSL_OpenSSL/samples/samples_WEC2013_vs120.sln +++ b/NetSSL_OpenSSL/samples/samples_WEC2013_vs120.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_WEC2013_vs120.vcxproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_WEC2013_vs120.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|SDK_AM335X_SK_WEC2013_V310 = debug_shared|SDK_AM335X_SK_WEC2013_V310 @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = release_static_md|SDK_AM335X_SK_WEC2013_V310 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|SDK_AM335X_SK_WEC2013_V310.Build.0 = release_static_md|SDK_AM335X_SK_WEC2013_V310 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = release_static_md|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = debug_shared|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V310.Build.0 = debug_shared|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = debug_shared|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = release_shared|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V310.Build.0 = release_shared|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = release_shared|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = debug_static_mt|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V310.Build.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = debug_static_mt|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = release_static_mt|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V310.Build.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = release_static_mt|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = debug_static_md|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V310.Build.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = debug_static_md|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V310.ActiveCfg = release_static_md|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V310.Build.0 = release_static_md|SDK_AM335X_SK_WEC2013_V310 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|SDK_AM335X_SK_WEC2013_V310.Deploy.0 = release_static_md|SDK_AM335X_SK_WEC2013_V310 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/samples/samples_vs100.sln b/NetSSL_OpenSSL/samples/samples_vs100.sln index 37d5deab0..b4edae91f 100644 --- a/NetSSL_OpenSSL/samples/samples_vs100.sln +++ b/NetSSL_OpenSSL/samples/samples_vs100.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_vs100.vcxproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs100.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|Win32 = debug_shared|Win32 @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.Build.0 = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Build.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.ActiveCfg = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Build.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Deploy.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.ActiveCfg = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Build.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Deploy.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.ActiveCfg = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Build.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Deploy.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.ActiveCfg = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Build.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Deploy.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Build.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/samples/samples_vs110.sln b/NetSSL_OpenSSL/samples/samples_vs110.sln index ed247c027..713628716 100644 --- a/NetSSL_OpenSSL/samples/samples_vs110.sln +++ b/NetSSL_OpenSSL/samples/samples_vs110.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_vs110.vcxproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs110.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|Win32 = debug_shared|Win32 @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.Build.0 = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Build.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.ActiveCfg = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Build.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Deploy.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.ActiveCfg = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Build.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Deploy.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.ActiveCfg = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Build.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Deploy.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.ActiveCfg = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Build.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Deploy.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Build.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/samples/samples_vs120.sln b/NetSSL_OpenSSL/samples/samples_vs120.sln index 3db78f8b7..b8d2b1759 100644 --- a/NetSSL_OpenSSL/samples/samples_vs120.sln +++ b/NetSSL_OpenSSL/samples/samples_vs120.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_vs120.vcxproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs120.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|Win32 = debug_shared|Win32 @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.Build.0 = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Build.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.ActiveCfg = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Build.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Deploy.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.ActiveCfg = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Build.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Deploy.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.ActiveCfg = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Build.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Deploy.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.ActiveCfg = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Build.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Deploy.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Build.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/samples/samples_vs71.sln b/NetSSL_OpenSSL/samples/samples_vs71.sln index 66c343eae..c66b4966a 100644 --- a/NetSSL_OpenSSL/samples/samples_vs71.sln +++ b/NetSSL_OpenSSL/samples/samples_vs71.sln @@ -11,6 +11,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_vs71.vcpr ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs71.vcproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution debug_shared = debug_shared @@ -57,6 +61,18 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.debug_static_md.Build.0 = debug_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md.ActiveCfg = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md.Build.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared.ActiveCfg = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared.Build.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared.ActiveCfg = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared.Build.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt.ActiveCfg = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt.Build.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt.ActiveCfg = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt.Build.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md.ActiveCfg = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md.Build.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md.ActiveCfg = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md.Build.0 = release_static_md|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/NetSSL_OpenSSL/samples/samples_vs80.sln b/NetSSL_OpenSSL/samples/samples_vs80.sln index de8a399ba..df1ea6424 100644 --- a/NetSSL_OpenSSL/samples/samples_vs80.sln +++ b/NetSSL_OpenSSL/samples/samples_vs80.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_vs80.vcproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs80.vcproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|Win32 = debug_shared|Win32 @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.Build.0 = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Build.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.ActiveCfg = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Build.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Deploy.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.ActiveCfg = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Build.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Deploy.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.ActiveCfg = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Build.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Deploy.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.ActiveCfg = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Build.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Deploy.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Build.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/samples/samples_vs90.sln b/NetSSL_OpenSSL/samples/samples_vs90.sln index ed82012a1..8be7631ef 100644 --- a/NetSSL_OpenSSL/samples/samples_vs90.sln +++ b/NetSSL_OpenSSL/samples/samples_vs90.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_vs90.vcproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_vs90.vcproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|Win32 = debug_shared|Win32 @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.Build.0 = release_static_md|Win32 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Build.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|Win32.Deploy.0 = debug_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.ActiveCfg = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Build.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|Win32.Deploy.0 = release_shared|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.ActiveCfg = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Build.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|Win32.Deploy.0 = debug_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.ActiveCfg = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Build.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|Win32.Deploy.0 = release_static_mt|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.ActiveCfg = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Build.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|Win32.Deploy.0 = debug_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.ActiveCfg = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Build.0 = release_static_md|Win32 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|Win32.Deploy.0 = release_static_md|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/samples/samples_x64_vs100.sln b/NetSSL_OpenSSL/samples/samples_x64_vs100.sln index 878c4752d..99c682052 100644 --- a/NetSSL_OpenSSL/samples/samples_x64_vs100.sln +++ b/NetSSL_OpenSSL/samples/samples_x64_vs100.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_x64_vs100.vcxproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_x64_vs100.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|x64 = debug_shared|x64 @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.ActiveCfg = release_static_md|x64 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.Build.0 = release_static_md|x64 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.Deploy.0 = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.ActiveCfg = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Build.0 = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Deploy.0 = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.ActiveCfg = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Build.0 = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Deploy.0 = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.ActiveCfg = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Build.0 = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Deploy.0 = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.ActiveCfg = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Build.0 = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Deploy.0 = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.ActiveCfg = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Build.0 = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Deploy.0 = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.ActiveCfg = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Build.0 = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Deploy.0 = release_static_md|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/samples/samples_x64_vs110.sln b/NetSSL_OpenSSL/samples/samples_x64_vs110.sln index d93b615ca..c6f9205ed 100644 --- a/NetSSL_OpenSSL/samples/samples_x64_vs110.sln +++ b/NetSSL_OpenSSL/samples/samples_x64_vs110.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_x64_vs110.vcxproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_x64_vs110.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|x64 = debug_shared|x64 @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.ActiveCfg = release_static_md|x64 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.Build.0 = release_static_md|x64 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.Deploy.0 = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.ActiveCfg = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Build.0 = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Deploy.0 = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.ActiveCfg = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Build.0 = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Deploy.0 = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.ActiveCfg = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Build.0 = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Deploy.0 = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.ActiveCfg = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Build.0 = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Deploy.0 = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.ActiveCfg = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Build.0 = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Deploy.0 = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.ActiveCfg = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Build.0 = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Deploy.0 = release_static_md|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/samples/samples_x64_vs120.sln b/NetSSL_OpenSSL/samples/samples_x64_vs120.sln index c03e39656..f9b1f21a9 100644 --- a/NetSSL_OpenSSL/samples/samples_x64_vs120.sln +++ b/NetSSL_OpenSSL/samples/samples_x64_vs120.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_x64_vs120.vcxproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_x64_vs120.vcxproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|x64 = debug_shared|x64 @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.ActiveCfg = release_static_md|x64 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.Build.0 = release_static_md|x64 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.Deploy.0 = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.ActiveCfg = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Build.0 = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Deploy.0 = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.ActiveCfg = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Build.0 = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Deploy.0 = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.ActiveCfg = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Build.0 = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Deploy.0 = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.ActiveCfg = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Build.0 = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Deploy.0 = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.ActiveCfg = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Build.0 = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Deploy.0 = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.ActiveCfg = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Build.0 = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Deploy.0 = release_static_md|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/samples/samples_x64_vs90.sln b/NetSSL_OpenSSL/samples/samples_x64_vs90.sln index 6b6324728..eb5ef2597 100644 --- a/NetSSL_OpenSSL/samples/samples_x64_vs90.sln +++ b/NetSSL_OpenSSL/samples/samples_x64_vs90.sln @@ -6,6 +6,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HTTPSTimeServer", "HTTPSTim EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mail", "Mail\Mail_x64_vs90.vcproj", "{BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TwitterClient", "TwitterClient\TwitterClient_x64_vs90.vcproj", "{CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug_shared|x64 = debug_shared|x64 @@ -70,6 +72,24 @@ Global {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.ActiveCfg = release_static_md|x64 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.Build.0 = release_static_md|x64 {BF75C029-EFC9-3A0F-A8F2-8001C11D1FBA}.release_static_md|x64.Deploy.0 = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.ActiveCfg = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Build.0 = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_shared|x64.Deploy.0 = debug_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.ActiveCfg = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Build.0 = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_shared|x64.Deploy.0 = release_shared|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.ActiveCfg = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Build.0 = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_mt|x64.Deploy.0 = debug_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.ActiveCfg = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Build.0 = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_mt|x64.Deploy.0 = release_static_mt|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.ActiveCfg = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Build.0 = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.debug_static_md|x64.Deploy.0 = debug_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.ActiveCfg = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Build.0 = release_static_md|x64 + {CCDD82BC-680D-39C0-AE25-1FBC5B615F7E}.release_static_md|x64.Deploy.0 = release_static_md|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NetSSL_OpenSSL/src/HTTPSClientSession.cpp b/NetSSL_OpenSSL/src/HTTPSClientSession.cpp index 3a25874c8..d338981d1 100644 --- a/NetSSL_OpenSSL/src/HTTPSClientSession.cpp +++ b/NetSSL_OpenSSL/src/HTTPSClientSession.cpp @@ -1,7 +1,7 @@ // // HTTPSClientSession.cpp // -// $Id: //poco/1.4/NetSSL_OpenSSL/src/HTTPSClientSession.cpp#3 $ +// $Id: //poco/1.4/NetSSL_OpenSSL/src/HTTPSClientSession.cpp#4 $ // // Library: NetSSL_OpenSSL // Package: HTTPSClient @@ -145,7 +145,7 @@ void HTTPSClientSession::proxyAuthenticate(HTTPRequest& request) void HTTPSClientSession::connect(const SocketAddress& address) { - if (getProxyHost().empty()) + if (getProxyHost().empty() || bypassProxy()) { SecureStreamSocket sss(socket()); if (_pContext->sessionCacheEnabled()) @@ -176,7 +176,8 @@ int HTTPSClientSession::read(char* buffer, std::streamsize length) try { return HTTPSession::read(buffer, length); - } catch(SSLConnectionUnexpectedlyClosedException&) + } + catch(SSLConnectionUnexpectedlyClosedException&) { return 0; } diff --git a/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp b/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp index b3f1d096f..37c3a47be 100644 --- a/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp +++ b/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp @@ -89,11 +89,23 @@ std::istream* HTTPSStreamFactory::open(const URI& uri) pSession = new HTTPSClientSession(resolvedURI.getHost(), resolvedURI.getPort()); else pSession = new HTTPClientSession(resolvedURI.getHost(), resolvedURI.getPort()); + if (proxyUri.empty()) - pSession->setProxy(_proxyHost, _proxyPort); + { + if (!_proxyHost.empty()) + { + pSession->setProxy(_proxyHost, _proxyPort); + pSession->setProxyCredentials(_proxyUsername, _proxyPassword); + } + } else + { pSession->setProxy(proxyUri.getHost(), proxyUri.getPort()); - pSession->setProxyCredentials(_proxyUsername, _proxyPassword); + if (!_proxyUsername.empty()) + { + pSession->setProxyCredentials(_proxyUsername, _proxyPassword); + } + } } std::string path = resolvedURI.getPathAndQuery(); if (path.empty()) path = "/"; @@ -136,7 +148,8 @@ std::istream* HTTPSStreamFactory::open(const URI& uri) // single request via the proxy. 305 responses MUST only be generated by origin servers. // only use for one single request! proxyUri.resolve(res.get("Location")); - delete pSession; pSession = 0; + delete pSession; + pSession = 0; retry = true; // only allow useproxy once } else if (res.getStatus() == HTTPResponse::HTTP_UNAUTHORIZED && !authorize) diff --git a/NetSSL_Win/CMakeLists.txt b/NetSSL_Win/CMakeLists.txt new file mode 100644 index 000000000..c5b41de63 --- /dev/null +++ b/NetSSL_Win/CMakeLists.txt @@ -0,0 +1,50 @@ +set(LIBNAME "NetSSLWin") +set(POCO_LIBNAME "Poco${LIBNAME}") + +# Sources +file(GLOB SRCS_G "src/*.cpp") +POCO_SOURCES_AUTO( SRCS ${SRCS_G}) + +# Headers +file(GLOB_RECURSE HDRS_G "include/*.h" ) +POCO_HEADERS_AUTO( SRCS ${HDRS_G}) + +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" + PROPERTIES + VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL NetSSL_Win_EXPORTS + ) + +target_link_libraries( "${LIBNAME}" Net Util Foundation Crypt32.lib ) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) +install( + DIRECTORY include/Poco + DESTINATION include + COMPONENT Devel + PATTERN ".svn" EXCLUDE + ) + +install( + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX} + RUNTIME DESTINATION bin + INCLUDES DESTINATION include + ) + +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + +if (ENABLE_TESTS) + #TODO: Looks like the samples use crypto somehow? + #add_subdirectory(samples) + #add_subdirectory(testsuite) +endif () + diff --git a/NetSSL_Win/cmake/PocoNetSSLWinConfig.cmake b/NetSSL_Win/cmake/PocoNetSSLWinConfig.cmake new file mode 100644 index 000000000..679cde78e --- /dev/null +++ b/NetSSL_Win/cmake/PocoNetSSLWinConfig.cmake @@ -0,0 +1,6 @@ +include(CMakeFindDependencyMacro) +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}) +find_dependency(PocoFoundation) +find_dependency(PocoUtil) +find_dependency(PocoNet) +include("${CMAKE_CURRENT_LIST_DIR}/PocoNetSSLWinTargets.cmake") \ No newline at end of file diff --git a/NetSSL_Win/include/Poco/Net/NetSSL.h b/NetSSL_Win/include/Poco/Net/NetSSL.h index 0fad93b93..84789a0a2 100644 --- a/NetSSL_Win/include/Poco/Net/NetSSL.h +++ b/NetSSL_Win/include/Poco/Net/NetSSL.h @@ -51,6 +51,12 @@ #endif +// +// Allow detection of NetSSL_Win at compile time +// +#define POCO_NETSSL_WIN 1 + + // // Automatically link NetSSL library. // diff --git a/NetSSL_Win/samples/HTTPSTimeServer/CMakeLists.txt b/NetSSL_Win/samples/HTTPSTimeServer/CMakeLists.txt index 85dcd4584..ae5014ddb 100644 --- a/NetSSL_Win/samples/HTTPSTimeServer/CMakeLists.txt +++ b/NetSSL_Win/samples/HTTPSTimeServer/CMakeLists.txt @@ -1,4 +1,4 @@ -set(SAMPLE_NAME "HTTPSTimeServer") +set(SAMPLE_NAME "HTTPSTimeServer-win") set(LOCAL_SRCS "") aux_source_directory(src LOCAL_SRCS) diff --git a/NetSSL_Win/samples/Mail/CMakeLists.txt b/NetSSL_Win/samples/Mail/CMakeLists.txt index e9126a607..c6fa18840 100644 --- a/NetSSL_Win/samples/Mail/CMakeLists.txt +++ b/NetSSL_Win/samples/Mail/CMakeLists.txt @@ -1,4 +1,4 @@ -set(SAMPLE_NAME "Mail-ssl") +set(SAMPLE_NAME "Mail-ssl-win") set(LOCAL_SRCS "") aux_source_directory(src LOCAL_SRCS) diff --git a/NetSSL_Win/samples/download/CMakeLists.txt b/NetSSL_Win/samples/download/CMakeLists.txt index 7bb405ec9..b7a546005 100644 --- a/NetSSL_Win/samples/download/CMakeLists.txt +++ b/NetSSL_Win/samples/download/CMakeLists.txt @@ -1,4 +1,4 @@ -set(SAMPLE_NAME "download-ssl") +set(SAMPLE_NAME "download-ssl-win") set(LOCAL_SRCS "") aux_source_directory(src LOCAL_SRCS) diff --git a/NetSSL_Win/src/HTTPSClientSession.cpp b/NetSSL_Win/src/HTTPSClientSession.cpp index 07e66143c..aa65c4b51 100644 --- a/NetSSL_Win/src/HTTPSClientSession.cpp +++ b/NetSSL_Win/src/HTTPSClientSession.cpp @@ -1,7 +1,7 @@ // // HTTPSClientSession.cpp // -// $Id: //poco/1.4/NetSSL_Win/src/HTTPSClientSession.cpp#3 $ +// $Id: //poco/1.4/NetSSL_Win/src/HTTPSClientSession.cpp#4 $ // // Library: NetSSL_Win // Package: HTTPSClient @@ -145,7 +145,7 @@ void HTTPSClientSession::proxyAuthenticate(HTTPRequest& request) void HTTPSClientSession::connect(const SocketAddress& address) { - if (getProxyHost().empty()) + if (getProxyHost().empty() || bypassProxy()) { SecureStreamSocket sss(socket()); if (_pContext->sessionCacheEnabled()) @@ -176,7 +176,8 @@ int HTTPSClientSession::read(char* buffer, std::streamsize length) try { return HTTPSession::read(buffer, length); - } catch(SSLConnectionUnexpectedlyClosedException&) + } + catch(SSLConnectionUnexpectedlyClosedException&) { return 0; } diff --git a/NetSSL_Win/src/HTTPSStreamFactory.cpp b/NetSSL_Win/src/HTTPSStreamFactory.cpp index 5e2367252..f6f8c3aab 100644 --- a/NetSSL_Win/src/HTTPSStreamFactory.cpp +++ b/NetSSL_Win/src/HTTPSStreamFactory.cpp @@ -90,10 +90,21 @@ std::istream* HTTPSStreamFactory::open(const URI& uri) else pSession = new HTTPClientSession(resolvedURI.getHost(), resolvedURI.getPort()); if (proxyUri.empty()) - pSession->setProxy(_proxyHost, _proxyPort); + { + if (!_proxyHost.empty()) + { + pSession->setProxy(_proxyHost, _proxyPort); + pSession->setProxyCredentials(_proxyUsername, _proxyPassword); + } + } else + { pSession->setProxy(proxyUri.getHost(), proxyUri.getPort()); - pSession->setProxyCredentials(_proxyUsername, _proxyPassword); + if (!_proxyUsername.empty()) + { + pSession->setProxyCredentials(_proxyUsername, _proxyPassword); + } + } } std::string path = resolvedURI.getPathAndQuery(); if (path.empty()) path = "/"; @@ -120,7 +131,8 @@ std::istream* HTTPSStreamFactory::open(const URI& uri) resolvedURI.setUserInfo(username + ":" + password); authorize = false; } - delete pSession; pSession = 0; + delete pSession; + pSession = 0; ++redirects; retry = true; } diff --git a/NetSSL_Win/testsuite/CMakeLists.txt b/NetSSL_Win/testsuite/CMakeLists.txt new file mode 100644 index 000000000..3b5389928 --- /dev/null +++ b/NetSSL_Win/testsuite/CMakeLists.txt @@ -0,0 +1,33 @@ +set(TESTUNIT "${LIBNAME}-testrunner") + +# Sources +file(GLOB SRCS_G "src/*.cpp") +POCO_SOURCES_AUTO( TEST_SRCS ${SRCS_G}) + +# Headers +file(GLOB_RECURSE HDRS_G "src/*.h" ) +POCO_HEADERS_AUTO( TEST_SRCS ${HDRS_G}) + +POCO_SOURCES_AUTO_PLAT( TEST_SRCS WIN32 + src/WinDriver.cpp +) + +POCO_SOURCES_AUTO_PLAT( TEST_SRCS WINCE + src/WinCEDriver.cpp +) + +add_executable( ${TESTUNIT} ${TEST_SRCS} ) +add_test(NAME ${LIBNAME} WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} COMMAND ${TESTUNIT} -all) +target_link_libraries( ${TESTUNIT} PocoNetSSL PocoCrypto PocoNet PocoUtil PocoXML PocoFoundation CppUnit) +if( WIN32) + add_definitions("-D_AFXDLL") + target_link_libraries( ${TESTUNIT} WinTestRunner) +endif(WIN32) + +# The test is run in the build directory. So the test data is copied there too +add_custom_command(TARGET ${TESTUNIT} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/any.pem ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rootcert.pem ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/testrunner.xml ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTUNIT}.xml + ) + diff --git a/PDF/CMakeLists.txt b/PDF/CMakeLists.txt index 716a1906a..fbca89940 100644 --- a/PDF/CMakeLists.txt +++ b/PDF/CMakeLists.txt @@ -1,4 +1,5 @@ -set(LIBNAME "PocoPDF") +set(LIBNAME "PDF") +set(POCO_LIBNAME "Poco${LIBNAME}") # Sources file(GLOB SRCS_G "src/*.cpp") @@ -110,28 +111,42 @@ POCO_SOURCES( SRCS libpng src/pngwutil.c ) +#TODO: Can we put this with the below includes? PRIVAT eg. include_directories( "include/Poco/PDF" ) # zip src -add_library( ${LIBNAME} ${LIB_MODE} ${SRCS} ) -set_target_properties( ${LIBNAME} +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" PROPERTIES VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} - DEFINE_SYMBOL PDF_EXPORTS) -target_link_libraries( ${LIBNAME} ${SYSLIBS} PocoFoundation ) + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL PDF_EXPORTS + ) +target_link_libraries( "${LIBNAME}" ${SYSLIBS} Foundation ) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) install( DIRECTORY include/Poco DESTINATION include + COMPONENT Devel PATTERN ".svn" EXCLUDE ) install( - TARGETS ${LIBNAME} + TARGETS "${LIBNAME}" EXPORT "${LIBNAME}Targets" LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} RUNTIME DESTINATION bin + INCLUDES DESTINATION include ) +POCO_GENERATE_PACKAGE("${LIBNAME}" "${LIBNAME}Targets" "lib/cmake/${PROJECT_NAME}") + if (ENABLE_TESTS) add_subdirectory(samples) add_subdirectory(testsuite) diff --git a/PDF/cmake/PocoPDFConfig.cmake b/PDF/cmake/PocoPDFConfig.cmake new file mode 100644 index 000000000..d12a4c64c --- /dev/null +++ b/PDF/cmake/PocoPDFConfig.cmake @@ -0,0 +1,4 @@ +include(CMakeFindDependencyMacro) +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}) +find_dependency(PocoFoundation) +include("${CMAKE_CURRENT_LIST_DIR}/PocoPDFTargets.cmake") \ No newline at end of file diff --git a/PocoDoc/resources/js/CollapsibleLists.js b/PocoDoc/resources/js/CollapsibleLists.js new file mode 100644 index 000000000..66ca0ecb8 --- /dev/null +++ b/PocoDoc/resources/js/CollapsibleLists.js @@ -0,0 +1,202 @@ +/* + +CollapsibleLists.js + +An object allowing lists to dynamically expand and collapse + +Created by Stephen Morley - http://code.stephenmorley.org/ - and released under +the terms of the CC0 1.0 Universal legal code: + +http://creativecommons.org/publicdomain/zero/1.0/legalcode + +Modified by Guenter Obiltschnig (added expansion via URI query string) + +*/ + +// create the CollapsibleLists object +var CollapsibleLists = + new function(){ + + /* Makes all lists with the class 'collapsibleList' collapsible. The + * parameter is: + * + * doNotRecurse - true if sub-lists should not be made collapsible + */ + this.apply = function(doNotRecurse){ + + // loop over the unordered lists + var uls = document.getElementsByTagName('ul'); + for (var index = 0; index < uls.length; index ++){ + + // check whether this list should be made collapsible + if (uls[index].className.match(/(^| )collapsibleList( |$)/)){ + + // make this list collapsible + this.applyTo(uls[index], true); + + // check whether sub-lists should also be made collapsible + if (!doNotRecurse){ + + // add the collapsibleList class to the sub-lists + var subUls = uls[index].getElementsByTagName('ul'); + for (var subIndex = 0; subIndex < subUls.length; subIndex ++){ + subUls[subIndex].className += ' collapsibleList'; + } + + } + + } + + var id = getParameterByName('expand'); + if (id){ + + var node = document.getElementById(id); + if (node){ + + expand(node); + } + } + + } + + }; + + /* Makes the specified list collapsible. The parameters are: + * + * node - the list element + * doNotRecurse - true if sub-lists should not be made collapsible + */ + this.applyTo = function(node, doNotRecurse){ + + // loop over the list items within this node + var lis = node.getElementsByTagName('li'); + for (var index = 0; index < lis.length; index ++){ + + // check whether this list item should be collapsible + if (!doNotRecurse || node == lis[index].parentNode){ + + // prevent text from being selected unintentionally + if (lis[index].addEventListener){ + lis[index].addEventListener( + 'mousedown', function (e){ e.preventDefault(); }, false); + }else{ + lis[index].attachEvent( + 'onselectstart', function(){ event.returnValue = false; }); + } + + // add the click listener + if (lis[index].addEventListener){ + lis[index].addEventListener( + 'click', createClickListener(lis[index]), false); + }else{ + lis[index].attachEvent( + 'onclick', createClickListener(lis[index])); + } + + // close the unordered lists within this list item + toggle(lis[index]); + + } + + } + + }; + + /* Expands a node. + * + * node - the node containing the unordered list elements + */ + function expand(node){ + // loop over the unordered list elements with the node + var uls = node.getElementsByTagName('ul'); + for (var index = 0; index < uls.length; index ++){ + + // find the parent list item of this unordered list + var li = uls[index]; + while (li.nodeName != 'LI') li = li.parentNode; + + // style the unordered list if it is directly within this node + if (li == node) uls[index].style.display = 'block'; + } + // remove the current class from the node + node.className = + node.className.replace( + /(^| )collapsibleList(Open|Closed)( |$)/, ''); + + // if the node contains unordered lists, set its class + if (uls.length > 0){ + node.className += ' collapsibleList' + (open ? 'Open' : 'Closed'); + } + } + + /* Returns a function that toggles the display status of any unordered + * list elements within the specified node. The parameter is: + * + * node - the node containing the unordered list elements + */ + function createClickListener(node){ + + // return the function + return function(e){ + + // ensure the event object is defined + if (!e) e = window.event; + + // find the list item containing the target of the event + var li = (e.target ? e.target : e.srcElement); + while (li.nodeName != 'LI') li = li.parentNode; + + // toggle the state of the node if it was the target of the event + if (li == node) toggle(node); + + }; + + } + + /* Opens or closes the unordered list elements directly within the + * specified node. The parameter is: + * + * node - the node containing the unordered list elements + */ + function toggle(node){ + + // determine whether to open or close the unordered lists + var open = node.className.match(/(^| )collapsibleListClosed( |$)/); + + // loop over the unordered list elements with the node + var uls = node.getElementsByTagName('ul'); + for (var index = 0; index < uls.length; index ++){ + + // find the parent list item of this unordered list + var li = uls[index]; + while (li.nodeName != 'LI') li = li.parentNode; + + // style the unordered list if it is directly within this node + if (li == node) uls[index].style.display = (open ? 'block' : 'none'); + + } + + // remove the current class from the node + node.className = + node.className.replace( + /(^| )collapsibleList(Open|Closed)( |$)/, ''); + + // if the node contains unordered lists, set its class + if (uls.length > 0){ + node.className += ' collapsibleList' + (open ? 'Open' : 'Closed'); + } + } + + /* Get a URL query string parameter. + * + * name - the parameter name + */ + function getParameterByName(name){ + + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); + } + + }(); diff --git a/PocoDoc/resources/js/iframeResizer.contentWindow.js b/PocoDoc/resources/js/iframeResizer.contentWindow.js new file mode 100755 index 000000000..c1c3b2ab0 --- /dev/null +++ b/PocoDoc/resources/js/iframeResizer.contentWindow.js @@ -0,0 +1,575 @@ +/* + * File: iframeSizer.contentWindow.js + * Desc: Include this file in any page being loaded into an iframe + * to force the iframe to resize to the content size. + * Requires: iframeResizer.js on host page. + * Author: David J. Bradshaw - dave@bradshaw.net + * Contributor: Jure Mav - jure.mav@gmail.com + */ + +;(function() { + 'use strict'; + + var + autoResize = true, + base = 10, + bodyBackground = '', + bodyMargin = 0, + bodyMarginStr = '', + bodyPadding = '', + calculateWidth = false, + doubleEventList = {'resize':1,'click':1}, + eventCancelTimer = 128, + height = 1, + firstRun = true, + heightCalcModeDefault = 'offset', + heightCalcMode = heightCalcModeDefault, + initLock = true, + initMsg = '', + interval = 32, + logging = false, + msgID = '[iFrameSizer]', //Must match host page msg ID + msgIdLen = msgID.length, + myID = '', + publicMethods = false, + resetRequiredMethods = {max:1,scroll:1,bodyScroll:1,documentElementScroll:1}, + targetOriginDefault = '*', + target = window.parent, + tolerance = 0, + triggerLocked = false, + triggerLockedTimer = null, + width = 1; + + + function addEventListener(el,evt,func){ + if ('addEventListener' in window){ + el.addEventListener(evt,func, false); + } else if ('attachEvent' in window){ //IE + el.attachEvent('on'+evt,func); + } + } + + function formatLogMsg(msg){ + return msgID + '[' + myID + ']' + ' ' + msg; + } + + function log(msg){ + if (logging && ('object' === typeof window.console)){ + console.log(formatLogMsg(msg)); + } + } + + function warn(msg){ + if ('object' === typeof window.console){ + console.warn(formatLogMsg(msg)); + } + } + + + function init(){ + log('Initialising iFrame'); + readData(); + setMargin(); + setBodyStyle('background',bodyBackground); + setBodyStyle('padding',bodyPadding); + injectClearFixIntoBodyElement(); + checkHeightMode(); + stopInfiniteResizingOfIFrame(); + setupPublicMethods(); + startEventListeners(); + sendSize('init','Init message from host page'); + } + + function readData(){ + + var data = initMsg.substr(msgIdLen).split(':'); + + function strBool(str){ + return 'true' === str ? true : false; + } + + myID = data[0]; + bodyMargin = (undefined !== data[1]) ? Number(data[1]) : bodyMargin; //For V1 compatibility + calculateWidth = (undefined !== data[2]) ? strBool(data[2]) : calculateWidth; + logging = (undefined !== data[3]) ? strBool(data[3]) : logging; + interval = (undefined !== data[4]) ? Number(data[4]) : interval; + publicMethods = (undefined !== data[5]) ? strBool(data[5]) : publicMethods; + autoResize = (undefined !== data[6]) ? strBool(data[6]) : autoResize; + bodyMarginStr = data[7]; + heightCalcMode = (undefined !== data[8]) ? data[8] : heightCalcMode; + bodyBackground = data[9]; + bodyPadding = data[10]; + tolerance = (undefined !== data[11]) ? Number(data[11]) : tolerance; + } + + function chkCSS(attr,value){ + if (-1 !== value.indexOf('-')){ + warn('Negative CSS value ignored for '+attr); + value=''; + } + return value; + } + + function setBodyStyle(attr,value){ + if ((undefined !== value) && ('' !== value) && ('null' !== value)){ + document.body.style[attr] = value; + log('Body '+attr+' set to "'+value+'"'); + } + } + + function setMargin(){ + //If called via V1 script, convert bodyMargin from int to str + if (undefined === bodyMarginStr){ + bodyMarginStr = bodyMargin+'px'; + } + chkCSS('margin',bodyMarginStr); + setBodyStyle('margin',bodyMarginStr); + } + + function stopInfiniteResizingOfIFrame(){ + document.documentElement.style.height = ''; + document.body.style.height = ''; + log('HTML & body height set to "auto"'); + } + + function initWindowResizeListener(){ + addEventListener(window,'resize', function(){ + sendSize('resize','Window resized'); + }); + } + + function initWindowClickListener(){ + addEventListener(window,'click', function(){ + sendSize('click','Window clicked'); + }); + } + + function checkHeightMode(){ + if (heightCalcModeDefault !== heightCalcMode){ + if (!(heightCalcMode in getHeight)){ + warn(heightCalcMode + ' is not a valid option for heightCalculationMethod.'); + heightCalcMode='bodyScroll'; + } + log('Height calculation method set to "'+heightCalcMode+'"'); + } + } + + function startEventListeners(){ + if ( true === autoResize ) { + initWindowResizeListener(); + initWindowClickListener(); + setupMutationObserver(); + } + else { + log('Auto Resize disabled'); + } + } + + function injectClearFixIntoBodyElement(){ + var clearFix = document.createElement('div'); + clearFix.style.clear = 'both'; + clearFix.style.display = 'block'; //Guard against this having been globally redefined in CSS. + document.body.appendChild(clearFix); + } + + function setupPublicMethods(){ + if (publicMethods) { + log('Enable public methods'); + + window.parentIFrame = { + close: function closeF(){ + sendSize('close','parentIFrame.close()', 0, 0); + }, + getId: function getIdF(){ + return myID; + }, + reset: function resetF(){ + resetIFrame('parentIFrame.size'); + }, + scrollTo: function scrollToF(x,y){ + sendMsg(y,x,'scrollTo'); // X&Y reversed at sendMsg uses hieght/width + }, + sendMessage: function sendMessageF(msg,targetOrigin){ + sendMsg(0,0,'message',msg,targetOrigin); + }, + setHeightCalculationMethod: function setHeightCalculationMethodF(heightCalculationMethod){ + heightCalcMode = heightCalculationMethod; + checkHeightMode(); + }, + setTargetOrigin: function setTargetOriginF(targetOrigin){ + log('Set targetOrigin: '+targetOrigin); + targetOriginDefault = targetOrigin; + }, + size: function sizeF(customHeight, customWidth){ + var valString = ''+(customHeight?customHeight:'')+(customWidth?','+customWidth:''); + lockTrigger(); + sendSize('size','parentIFrame.size('+valString+')', customHeight, customWidth); + } + }; + } + } + + function initInterval(){ + if ( 0 !== interval ){ + log('setInterval: '+interval+'ms'); + setInterval(function(){ + sendSize('interval','setInterval: '+interval); + },Math.abs(interval)); + } + } + + function setupInjectElementLoadListners(mutations){ + function addLoadListener(element){ + if (element.height === undefined || element.width === undefined || 0 === element.height || 0 === element.width){ + log('Attach listerner to '+element.src); + addEventListener(element,'load', function imageLoaded(){ + sendSize('imageLoad','Image loaded'); + }); + } + } + + mutations.forEach(function (mutation) { + if (mutation.type === 'attributes' && mutation.attributeName === 'src'){ + addLoadListener(mutation.target); + } else if (mutation.type === 'childList'){ + var images = mutation.target.querySelectorAll('img'); + Array.prototype.forEach.call(images,function (image) { + addLoadListener(image); + }); + } + }); + } + + function setupMutationObserver(){ + + var MutationObserver = window.MutationObserver || window.WebKitMutationObserver; + + function createMutationObserver(){ + var + target = document.querySelector('body'), + + config = { + attributes : true, + attributeOldValue : false, + characterData : true, + characterDataOldValue : false, + childList : true, + subtree : true + }, + + observer = new MutationObserver(function(mutations) { + sendSize('mutationObserver','mutationObserver: ' + mutations[0].target + ' ' + mutations[0].type); + setupInjectElementLoadListners(mutations); //Deal with WebKit asyncing image loading when tags are injected into the page + }); + + log('Enable MutationObserver'); + observer.observe(target, config); + } + + if (MutationObserver){ + if (0 > interval) { + initInterval(); + } else { + createMutationObserver(); + } + } + else { + warn('MutationObserver not supported in this browser!'); + initInterval(); + } + } + + + // document.documentElement.offsetHeight is not reliable, so + // we have to jump through hoops to get a better value. + function getBodyOffsetHeight(){ + function getComputedBodyStyle(prop) { + function convertUnitsToPxForIE8(value) { + var PIXEL = /^\d+(px)?$/i; + + if (PIXEL.test(value)) { + return parseInt(value,base); + } + + var + style = el.style.left, + runtimeStyle = el.runtimeStyle.left; + + el.runtimeStyle.left = el.currentStyle.left; + el.style.left = value || 0; + value = el.style.pixelLeft; + el.style.left = style; + el.runtimeStyle.left = runtimeStyle; + + return value; + } + + var + el = document.body, + retVal = 0; + + if (('defaultView' in document) && ('getComputedStyle' in document.defaultView)) { + retVal = document.defaultView.getComputedStyle(el, null); + retVal = (null !== retVal) ? retVal[prop] : 0; + } else {//IE8 + retVal = convertUnitsToPxForIE8(el.currentStyle[prop]); + } + + return parseInt(retVal,base); + } + + return document.body.offsetHeight + + getComputedBodyStyle('marginTop') + + getComputedBodyStyle('marginBottom'); + } + + function getBodyScrollHeight(){ + return document.body.scrollHeight; + } + + function getDEOffsetHeight(){ + return document.documentElement.offsetHeight; + } + + function getDEScrollHeight(){ + return document.documentElement.scrollHeight; + } + + //From https://github.com/guardian/iframe-messenger + function getLowestElementHeight() { + var + allElements = document.querySelectorAll('body *'), + allElementsLength = allElements.length, + maxBottomVal = 0, + timer = new Date().getTime(); + + for (var i = 0; i < allElementsLength; i++) { + if (allElements[i].getBoundingClientRect().bottom > maxBottomVal) { + maxBottomVal = allElements[i].getBoundingClientRect().bottom; + } + } + + timer = new Date().getTime() - timer; + + log('Parsed '+allElementsLength+' HTML elements'); + log('LowestElement bottom position calculated in ' + timer + 'ms'); + + return maxBottomVal; + } + + function getAllHeights(){ + return [ + getBodyOffsetHeight(), + getBodyScrollHeight(), + getDEOffsetHeight(), + getDEScrollHeight() + ]; + } + + function getMaxHeight(){ + return Math.max.apply(null,getAllHeights()); + } + + function getMinHeight(){ + return Math.min.apply(null,getAllHeights()); + } + + function getBestHeight(){ + return Math.max(getBodyOffsetHeight(),getLowestElementHeight()); + } + + var getHeight = { + offset : getBodyOffsetHeight, //Backward compatability + bodyOffset : getBodyOffsetHeight, + bodyScroll : getBodyScrollHeight, + documentElementOffset : getDEOffsetHeight, + scroll : getDEScrollHeight, //Backward compatability + documentElementScroll : getDEScrollHeight, + max : getMaxHeight, + min : getMinHeight, + grow : getMaxHeight, + lowestElement : getBestHeight + }; + + function getWidth(){ + return Math.max( + document.documentElement.scrollWidth, + document.body.scrollWidth + ); + } + + function sendSize(triggerEvent, triggerEventDesc, customHeight, customWidth){ + + var currentHeight,currentWidth; + + function recordTrigger(){ + if (!(triggerEvent in {'reset':1,'resetPage':1,'init':1})){ + log( 'Trigger event: ' + triggerEventDesc ); + } + } + + function resizeIFrame(){ + height = currentHeight; + width = currentWidth; + + sendMsg(height,width,triggerEvent); + } + + function isDoubleFiredEvent(){ + return triggerLocked && (triggerEvent in doubleEventList); + } + + function isSizeChangeDetected(){ + function checkTolarance(a,b){ + var retVal = Math.abs(a-b) <= tolerance; + return !retVal; + } + + currentHeight = (undefined !== customHeight) ? customHeight : getHeight[heightCalcMode](); + currentWidth = (undefined !== customWidth ) ? customWidth : getWidth(); + + return checkTolarance(height,currentHeight) || + (calculateWidth && checkTolarance(width,currentWidth)); + + //return (height !== currentHeight) || + // (calculateWidth && width !== currentWidth); + } + + function isForceResizableEvent(){ + return !(triggerEvent in {'init':1,'interval':1,'size':1}); + } + + function isForceResizableHeightCalcMode(){ + return (heightCalcMode in resetRequiredMethods); + } + + function logIgnored(){ + log('No change in size detected'); + } + + function checkDownSizing(){ + if (isForceResizableEvent() && isForceResizableHeightCalcMode()){ + resetIFrame(triggerEventDesc); + } else if (!(triggerEvent in {'interval':1})){ + recordTrigger(); + logIgnored(); + } + } + + if (!isDoubleFiredEvent()){ + if (isSizeChangeDetected()){ + recordTrigger(); + lockTrigger(); + resizeIFrame(); + } else { + checkDownSizing(); + } + } else { + log('Trigger event cancelled: '+triggerEvent); + } + } + + function lockTrigger(){ + if (!triggerLocked){ + triggerLocked = true; + log('Trigger event lock on'); + } + clearTimeout(triggerLockedTimer); + triggerLockedTimer = setTimeout(function(){ + triggerLocked = false; + log('Trigger event lock off'); + log('--'); + },eventCancelTimer); + } + + function triggerReset(triggerEvent){ + height = getHeight[heightCalcMode](); + width = getWidth(); + + sendMsg(height,width,triggerEvent); + } + + function resetIFrame(triggerEventDesc){ + var hcm = heightCalcMode; + heightCalcMode = heightCalcModeDefault; + + log('Reset trigger event: ' + triggerEventDesc); + lockTrigger(); + triggerReset('reset'); + + heightCalcMode = hcm; + } + + function sendMsg(height,width,triggerEvent,msg,targetOrigin){ + function setTargetOrigin(){ + if (undefined === targetOrigin){ + targetOrigin = targetOriginDefault; + } else { + log('Message targetOrigin: '+targetOrigin); + } + } + + function sendToParent(){ + var + size = height + ':' + width, + message = myID + ':' + size + ':' + triggerEvent + (undefined !== msg ? ':' + msg : ''); + + log('Sending message to host page (' + message + ')'); + target.postMessage( msgID + message, targetOrigin); + } + + setTargetOrigin(); + sendToParent(); + } + + function receiver(event) { + function isMessageForUs(){ + return msgID === (''+event.data).substr(0,msgIdLen); //''+ Protects against non-string messages + } + + function initFromParent(){ + initMsg = event.data; + target = event.source; + + init(); + firstRun = false; + setTimeout(function(){ initLock = false;},eventCancelTimer); + } + + function resetFromParent(){ + if (!initLock){ + log('Page size reset by host page'); + triggerReset('resetPage'); + } else { + log('Page reset ignored by init'); + } + } + + function getMessageType(){ + return event.data.split(']')[1]; + } + + function isMiddleTier(){ + return ('iFrameResize' in window); + } + + function isInitMsg(){ + //test if this message is from a child below us. This is an ugly test, however, updating + //the message format would break backwards compatibity. + return event.data.split(':')[2] in {'true':1,'false':1}; + } + + if (isMessageForUs()){ + if (firstRun && isInitMsg()){ //Check msg ID + initFromParent(); + } else if ('reset' === getMessageType()){ + resetFromParent(); + } else if (event.data !== initMsg && !isMiddleTier()){ + warn('Unexpected message ('+event.data+')'); + } + } + } + + addEventListener(window, 'message', receiver); + +})(); diff --git a/PocoDoc/resources/js/iframeResizer.js b/PocoDoc/resources/js/iframeResizer.js new file mode 100755 index 000000000..977df0d2f --- /dev/null +++ b/PocoDoc/resources/js/iframeResizer.js @@ -0,0 +1,442 @@ +/* + * File: iframeReizer.js + * Desc: Force iframes to size to content. + * Requires: iframeResizer.contentWindow.js to be loaded into the target frame. + * Author: David J. Bradshaw - dave@bradshaw.net + * Contributor: Jure Mav - jure.mav@gmail.com + */ +;(function() { + 'use strict'; + + var + count = 0, + firstRun = true, + msgHeader = 'message', + msgHeaderLen = msgHeader.length, + msgId = '[iFrameSizer]', //Must match iframe msg ID + msgIdLen = msgId.length, + page = '', //:'+location.href, //Uncoment to debug nested iFrames + pagePosition = null, + requestAnimationFrame = window.requestAnimationFrame, + resetRequiredMethods = {max:1,scroll:1,bodyScroll:1,documentElementScroll:1}, + settings = {}, + + defaults = { + autoResize : true, + bodyBackground : null, + bodyMargin : null, + bodyMarginV1 : 8, + bodyPadding : null, + checkOrigin : true, + enablePublicMethods : false, + heightCalculationMethod : 'offset', + interval : 32, + log : false, + maxHeight : Infinity, + maxWidth : Infinity, + minHeight : 0, + minWidth : 0, + scrolling : false, + sizeHeight : true, + sizeWidth : false, + tolerance : 0, + closedCallback : function(){}, + initCallback : function(){}, + messageCallback : function(){}, + resizedCallback : function(){} + }; + + function addEventListener(obj,evt,func){ + if ('addEventListener' in window){ + obj.addEventListener(evt,func, false); + } else if ('attachEvent' in window){//IE + obj.attachEvent('on'+evt,func); + } + } + + function setupRequestAnimationFrame(){ + var + vendors = ['moz', 'webkit', 'o', 'ms'], + x; + + // Remove vendor prefixing if prefixed and break early if not + for (x = 0; x < vendors.length && !requestAnimationFrame; x += 1) { + requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; + } + + if (!(requestAnimationFrame)){ + log(' RequestAnimationFrame not supported'); + } + } + + function log(msg){ + if (settings.log && (typeof console === 'object')){ + console.log(msgId + '[Host page'+page+']' + msg); + } + } + + + function iFrameListener(event){ + function resizeIFrame(){ + function resize(){ + setSize(messageData); + setPagePosition(); + settings.resizedCallback(messageData); + } + + syncResize(resize,messageData,'resetPage'); + } + + function closeIFrame(iframe){ + var iframeID = iframe.id; + + log(' Removing iFrame: '+iframeID); + iframe.parentNode.removeChild(iframe); + settings.closedCallback(iframeID); + log(' --'); + } + + function processMsg(){ + var data = msg.substr(msgIdLen).split(':'); + + return { + iframe: document.getElementById(data[0]), + id: data[0], + height: data[1], + width: data[2], + type: data[3] + }; + } + + function ensureInRange(Dimension){ + var + max = Number(settings['max'+Dimension]), + min = Number(settings['min'+Dimension]), + dimension = Dimension.toLowerCase(), + size = Number(messageData[dimension]); + + if (min>max){ + throw new Error('Value for min'+Dimension+' can not be greater than max'+Dimension); + } + + log(' Checking '+dimension+' is in range '+min+'-'+max); + + if (sizemax) { + size=max; + log(' Set '+dimension+' to max value'); + } + + messageData[dimension]=''+size; + } + + function isMessageFromIFrame(){ + + var + origin = event.origin, + remoteHost = messageData.iframe.src.split('/').slice(0,3).join('/'); + + if (settings.checkOrigin) { + log(' Checking connection is from: '+remoteHost); + + if ((''+origin !== 'null') && (origin !== remoteHost)) { + throw new Error( + 'Unexpected message received from: ' + origin + + ' for ' + messageData.iframe.id + + '. Message was: ' + event.data + + '. This error can be disabled by adding the checkOrigin: false option.' + ); + } + } + + return true; + } + + function isMessageForUs(){ + return msgId === ('' + msg).substr(0,msgIdLen); //''+Protects against non-string msg + } + + function isMessageFromMetaParent(){ + //test if this message is from a parent above us. This is an ugly test, however, updating + //the message format would break backwards compatibity. + var retCode = messageData.type in {'true':1,'false':1}; + + if (retCode){ + log(' Ignoring init message from meta parent page'); + } + + return retCode; + } + + function forwardMsgFromIFrame(){ + var msgBody = msg.substr(msg.indexOf(':')+msgHeaderLen+6); //6 === ':0:0:' + ':' (Ideas to name this magic number most welcome) + + log(' MessageCallback passed: {iframe: '+ messageData.iframe.id + ', message: ' + msgBody + '}'); + settings.messageCallback({ + iframe: messageData.iframe, + message: msgBody + }); + log(' --'); + } + + function checkIFrameExists(){ + if (null === messageData.iframe) { + throw new Error('iFrame ('+messageData.id+') does not exist on ' + page); + } + return true; + } + + function scrollRequestFromChild(){ + log(' Reposition requested from iFrame'); + pagePosition = { + x: messageData.width, + y: messageData.height + }; + setPagePosition(); + } + + function actionMsg(){ + switch(messageData.type){ + case 'close': + closeIFrame(messageData.iframe); + settings.resizedCallback(messageData); //To be removed. + break; + case 'message': + forwardMsgFromIFrame(); + break; + case 'scrollTo': + scrollRequestFromChild(); + break; + case 'reset': + resetIFrame(messageData); + break; + case 'init': + resizeIFrame(); + settings.initCallback(messageData.iframe); + break; + default: + resizeIFrame(); + } + } + + var + msg = event.data, + messageData = {}; + + if (isMessageForUs()){ + log(' Received: '+msg); + messageData = processMsg(); + ensureInRange('Height'); + ensureInRange('Width'); + + if ( !isMessageFromMetaParent() && checkIFrameExists() && isMessageFromIFrame() ){ + actionMsg(); + firstRun = false; + } + } + } + + + function getPagePosition (){ + if(null === pagePosition){ + pagePosition = { + x: (window.pageXOffset !== undefined) ? window.pageXOffset : document.documentElement.scrollLeft, + y: (window.pageYOffset !== undefined) ? window.pageYOffset : document.documentElement.scrollTop + }; + log(' Get position: '+pagePosition.x+','+pagePosition.y); + } + } + + function setPagePosition(){ + if(null !== pagePosition){ + window.scrollTo(pagePosition.x,pagePosition.y); + log(' Set position: '+pagePosition.x+','+pagePosition.y); + pagePosition = null; + } + } + + function resetIFrame(messageData){ + function reset(){ + setSize(messageData); + trigger('reset','reset',messageData.iframe); + } + + log(' Size reset requested by '+('init'===messageData.type?'host page':'iFrame')); + getPagePosition(); + syncResize(reset,messageData,'init'); + } + + function setSize(messageData){ + function setDimension(dimension){ + messageData.iframe.style[dimension] = messageData[dimension] + 'px'; + log( + ' IFrame (' + messageData.iframe.id + + ') ' + dimension + + ' set to ' + messageData[dimension] + 'px' + ); + } + + if( settings.sizeHeight) { setDimension('height'); } + if( settings.sizeWidth ) { setDimension('width'); } + } + + function syncResize(func,messageData,doNotSync){ + if(doNotSync!==messageData.type && requestAnimationFrame){ + log(' Requesting animation frame'); + requestAnimationFrame(func); + } else { + func(); + } + } + + function trigger(calleeMsg,msg,iframe){ + log('[' + calleeMsg + '] Sending msg to iframe ('+msg+')'); + iframe.contentWindow.postMessage( msgId + msg, '*' ); + } + + + function setupIFrame(){ + function setLimits(){ + function addStyle(style){ + if ((Infinity !== settings[style]) && (0 !== settings[style])){ + iframe.style[style] = settings[style] + 'px'; + log(' Set '+style+' = '+settings[style]+'px'); + } + } + + addStyle('maxHeight'); + addStyle('minHeight'); + addStyle('maxWidth'); + addStyle('minWidth'); + } + + function ensureHasId(iframeID){ + if (''===iframeID){ + iframe.id = iframeID = 'iFrameResizer' + count++; + log(' Added missing iframe ID: '+ iframeID +' (' + iframe.src + ')'); + } + + return iframeID; + } + + function setScrolling(){ + log(' IFrame scrolling ' + (settings.scrolling ? 'enabled' : 'disabled') + ' for ' + iframeID); + iframe.style.overflow = false === settings.scrolling ? 'hidden' : 'auto'; + iframe.scrolling = false === settings.scrolling ? 'no' : 'yes'; + } + + //The V1 iFrame script expects an int, where as in V2 expects a CSS + //string value such as '1px 3em', so if we have an int for V2, set V1=V2 + //and then convert V2 to a string PX value. + function setupBodyMarginValues(){ + if (('number'===typeof(settings.bodyMargin)) || ('0'===settings.bodyMargin)){ + settings.bodyMarginV1 = settings.bodyMargin; + settings.bodyMargin = '' + settings.bodyMargin + 'px'; + } + } + + function createOutgoingMsg(){ + return iframeID + + ':' + settings.bodyMarginV1 + + ':' + settings.sizeWidth + + ':' + settings.log + + ':' + settings.interval + + ':' + settings.enablePublicMethods + + ':' + settings.autoResize + + ':' + settings.bodyMargin + + ':' + settings.heightCalculationMethod + + ':' + settings.bodyBackground + + ':' + settings.bodyPadding + + ':' + settings.tolerance; + } + + function init(msg){ + //We have to call trigger twice, as we can not be sure if all + //iframes have completed loading when this code runs. The + //event listener also catches the page changing in the iFrame. + addEventListener(iframe,'load',function(){ + var fr = firstRun; // Reduce scope of var to function, because IE8's JS execution + // context stack is borked and this value gets externally + // changed midway through running this function. + trigger('iFrame.onload',msg,iframe); + if (!fr && settings.heightCalculationMethod in resetRequiredMethods){ + resetIFrame({ + iframe:iframe, + height:0, + width:0, + type:'init' + }); + } + }); + trigger('init',msg,iframe); + } + + var + /*jshint validthis:true */ + iframe = this, + iframeID = ensureHasId(iframe.id); + + setScrolling(); + setLimits(); + setupBodyMarginValues(); + init(createOutgoingMsg()); + } + + function checkOptions(options){ + if ('object' !== typeof options){ + throw new TypeError('Options is not an object.'); + } + } + + function createNativePublicFunction(){ + function init(element){ + if('IFRAME' !== element.tagName.toUpperCase()) { + throw new TypeError('Expected