├── restore-packages.cmd ├── language-extensions ├── dotnet-core-CSharp │ ├── lib │ │ └── hostfxr.dll │ ├── sample │ │ ├── regex │ │ │ ├── RegexSampleResult.PNG │ │ │ ├── pkg │ │ │ │ ├── RegexSample.csproj │ │ │ │ └── RegexSample.cs │ │ │ └── dotnet-core-CSharp-regex-win.sql │ │ ├── SubModuleCall │ │ │ └── SubModuleProject │ │ │ │ └── SubModule │ │ │ │ ├── SubModule.csproj │ │ │ │ ├── SubModule.sln │ │ │ │ └── Program.cs │ │ └── LoopBackConnection │ │ │ ├── README.md │ │ │ └── LoopBackConnectionOLEDB.cs │ ├── build │ │ └── windows │ │ │ ├── restore-packages.cmd │ │ │ └── create-dotnet-core-CSharp-extension-zip.cmd │ ├── src │ │ ├── managed │ │ │ ├── Microsoft.SqlServer.CSharpExtension.csproj │ │ │ ├── utils │ │ │ │ ├── ExceptionUtils.cs │ │ │ │ └── DataSetUtils.cs │ │ │ ├── CSharpDataSet.cs │ │ │ ├── CSharpColumn.cs │ │ │ ├── sdk │ │ │ │ └── AbstractSqlServerExtensionExecutor.cs │ │ │ └── CSharpParam.cs │ │ └── native │ │ │ └── Logger.cpp │ ├── test │ │ ├── include │ │ │ └── Common.h │ │ ├── src │ │ │ ├── managed │ │ │ │ └── Microsoft.SqlServer.CSharpExtensionTest.csproj │ │ │ └── native │ │ │ │ ├── main.cpp │ │ │ │ ├── CSharpInitSessionTests.cpp │ │ │ │ └── CMakeLists.txt │ │ └── build │ │ │ └── windows │ │ │ └── run-dotnet-core-CSharp-extension-test.cmd │ ├── include │ │ ├── Logger.h │ │ ├── coreclr_delegates.h │ │ └── hostfxr.h │ └── LICENSE ├── python │ ├── test │ │ ├── test_packages │ │ │ ├── astor.whl │ │ │ ├── astor-0.7.1-WHL.zip │ │ │ ├── bad-package-ZIP.zip │ │ │ ├── statsd-3.3.0-WHL.zip │ │ │ ├── testpackageA-ZIP.zip │ │ │ ├── testpackageB-ZIP.zip │ │ │ ├── testpackageC-ZIP.zip │ │ │ ├── absl-py-1.0.0-TAR.zip │ │ │ ├── testpackagebad-ZIP.zip │ │ │ ├── Markdown-2.6.11-ZIP.zip │ │ │ ├── telemetry-0.3.2-TAR.zip │ │ │ ├── termcolor-1.1.0-TAR.zip │ │ │ └── testpackageA-v2-ZIP.zip │ │ ├── include │ │ │ ├── Common.h │ │ │ ├── PythonTestUtilities.h │ │ │ └── PythonLibraryTests.h │ │ ├── src │ │ │ ├── main.cpp │ │ │ ├── PythonInitTests.cpp │ │ │ └── PythonInitColumnTests.cpp │ │ └── build │ │ │ ├── windows │ │ │ └── run-pythonextension-test.cmd │ │ │ └── linux │ │ │ └── run-pythonextension-test.sh │ ├── include │ │ ├── Common.h │ │ ├── Logger.h │ │ ├── PythonColumn.h │ │ ├── PythonNamespace.h │ │ ├── PythonPathSettings.h │ │ ├── PythonExtensionUtils.h │ │ └── PythonLibrarySession.h │ ├── build │ │ ├── linux │ │ │ ├── create-python-extension-zip.sh │ │ │ └── restore-packages.sh │ │ └── windows │ │ │ └── create-python-extension-zip.cmd │ ├── LICENSE_1_0.txt │ └── src │ │ ├── PythonColumn.cpp │ │ ├── PythonPathSettings.cpp │ │ ├── Logger.cpp │ │ ├── PythonNamespace.cpp │ │ └── linux │ │ └── PythonExtensionUtils_linux.cpp ├── R │ ├── test │ │ ├── test-packages │ │ │ ├── linux │ │ │ │ ├── 1_1_bindr_0.1.1.zip │ │ │ │ ├── 1_1_plogr_0.2.0.zip │ │ │ │ ├── 24_58_rlang_1.1.6.zip │ │ │ │ ├── 1_1_assertthat_0.2.1.zip │ │ │ │ ├── 1_1_lazyeval_0.2.2.zip │ │ │ │ ├── 1_1_pkgconfig_2.0.3.zip │ │ │ │ ├── 24_58_bindrcpp_0.2.3.zip │ │ │ │ ├── 24_58_lazyeval_0.2.1.zip │ │ │ │ ├── 1_1_assertthatbad_0.2.1.zip │ │ │ │ ├── 1_1_assertthatinterchange_0.2.1.zip │ │ │ │ └── 1_1_assertthatzipwithinzip_0.2.1.zip │ │ │ └── windows │ │ │ │ ├── 1_1_bindr_0.1.1.zip │ │ │ │ ├── 1_1_lazyeval_0.2.2.zip │ │ │ │ ├── 24_58_rlang_0.4.7.zip │ │ │ │ ├── 1_1_assertthat_0.2.1.zip │ │ │ │ ├── 1_1_pkgconfig_2.0.3.zip │ │ │ │ ├── 24_58_bindrcpp_0.2.2.zip │ │ │ │ ├── 24_58_lazyeval_0.2.1.zip │ │ │ │ ├── 1_1_assertthatbad_0.2.1.zip │ │ │ │ ├── 1_1_assertthatinterchange_0.2.1.zip │ │ │ │ └── 1_1_assertthatzipwithinzip_0.2.1.zip │ │ ├── src │ │ │ ├── CMakeSettings.json │ │ │ └── main.cpp │ │ ├── build │ │ │ ├── linux │ │ │ │ ├── run-RExtension-test.sh │ │ │ │ └── build-RExtension-test.sh │ │ │ └── windows │ │ │ │ ├── run-RExtension-test.cmd │ │ │ │ └── build-RExtension-test.cmd │ │ └── include │ │ │ ├── Common.h │ │ │ └── Utilities.h │ ├── build │ │ ├── linux │ │ │ ├── create-RExtension-zip.sh │ │ │ └── restore-packages.sh │ │ └── windows │ │ │ ├── create-RExtension-zip.cmd │ │ │ └── restore-packages.cmd │ ├── include │ │ ├── Common.h │ │ ├── Logger.h │ │ ├── RColumn.h │ │ ├── Utilities.h │ │ ├── RPathSettings.h │ │ └── REnvironment.h │ ├── src │ │ ├── RColumn.cpp │ │ ├── RPathSettings.cpp │ │ ├── linux │ │ │ ├── RPathSettings_linux.cpp │ │ │ └── Utilities_linux.cpp │ │ └── windows │ │ │ └── RPathSettings_win.cpp │ └── common │ │ └── include │ │ └── Unicode.h └── java │ ├── build │ ├── linux │ │ ├── restore-packages.sh │ │ └── create-java-extension-zip.sh │ └── windows │ │ ├── restore-packages.cmd │ │ └── create-java-extension-zip.cmd │ ├── include │ ├── JavaSqlTypeHelper.h │ ├── Common.h │ ├── JavaLibraryUtils.h │ ├── Logger.h │ ├── JavaPathSettings.h │ ├── JniHelper.h │ └── JavaExtensionUtils.h │ ├── LICENSE │ ├── src │ ├── windows │ │ ├── Logger_win.cpp │ │ └── JavaLibraryUtils_win.cpp │ ├── JavaPathSettings.cpp │ ├── linux │ │ ├── Logger_linux.cpp │ │ └── JavaLibraryUtils_linux.cpp │ ├── JavaLibraryUtils.cpp │ ├── Logger.cpp │ └── JniHelper.cpp │ ├── sdk │ └── src │ │ └── java │ │ └── main │ │ └── java │ │ └── com │ │ └── microsoft │ │ └── sqlserver │ │ └── javalangextension │ │ └── AbstractSqlServerExtensionExecutor.java │ └── samples │ └── regex │ └── readme.md ├── packages.config ├── NuGet.Config ├── restore-packages.sh ├── test ├── run-unittests.cmd └── googletest │ ├── src │ ├── linux │ │ └── CMakeLists.txt.in │ ├── windows │ │ └── CMakeLists.txt.in │ └── CMakeLists.txt │ └── build │ ├── linux │ └── build-googletest.sh │ └── windows │ └── build-googletest.cmd ├── extension-host └── include │ └── sqlexternallibrary.h ├── LICENSE ├── README.md └── SECURITY.md /restore-packages.cmd: -------------------------------------------------------------------------------- 1 | SET EnlRoot=%~dp0 2 | nuget restore %EnlRoot%packages.config -PackagesDirectory %EnlRoot%packages -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/lib/hostfxr.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/dotnet-core-CSharp/lib/hostfxr.dll -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/astor.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/astor.whl -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/1_1_bindr_0.1.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/1_1_bindr_0.1.1.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/1_1_plogr_0.2.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/1_1_plogr_0.2.0.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/astor-0.7.1-WHL.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/astor-0.7.1-WHL.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/bad-package-ZIP.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/bad-package-ZIP.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/statsd-3.3.0-WHL.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/statsd-3.3.0-WHL.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/testpackageA-ZIP.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/testpackageA-ZIP.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/testpackageB-ZIP.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/testpackageB-ZIP.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/testpackageC-ZIP.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/testpackageC-ZIP.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/24_58_rlang_1.1.6.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/24_58_rlang_1.1.6.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/windows/1_1_bindr_0.1.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/windows/1_1_bindr_0.1.1.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/absl-py-1.0.0-TAR.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/absl-py-1.0.0-TAR.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/testpackagebad-ZIP.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/testpackagebad-ZIP.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/1_1_assertthat_0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/1_1_assertthat_0.2.1.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/1_1_lazyeval_0.2.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/1_1_lazyeval_0.2.2.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/1_1_pkgconfig_2.0.3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/1_1_pkgconfig_2.0.3.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/24_58_bindrcpp_0.2.3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/24_58_bindrcpp_0.2.3.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/24_58_lazyeval_0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/24_58_lazyeval_0.2.1.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/windows/1_1_lazyeval_0.2.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/windows/1_1_lazyeval_0.2.2.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/windows/24_58_rlang_0.4.7.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/windows/24_58_rlang_0.4.7.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/Markdown-2.6.11-ZIP.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/Markdown-2.6.11-ZIP.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/telemetry-0.3.2-TAR.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/telemetry-0.3.2-TAR.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/termcolor-1.1.0-TAR.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/termcolor-1.1.0-TAR.zip -------------------------------------------------------------------------------- /language-extensions/python/test/test_packages/testpackageA-v2-ZIP.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/python/test/test_packages/testpackageA-v2-ZIP.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/windows/1_1_assertthat_0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/windows/1_1_assertthat_0.2.1.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/windows/1_1_pkgconfig_2.0.3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/windows/1_1_pkgconfig_2.0.3.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/windows/24_58_bindrcpp_0.2.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/windows/24_58_bindrcpp_0.2.2.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/windows/24_58_lazyeval_0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/windows/24_58_lazyeval_0.2.1.zip -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/sample/regex/RegexSampleResult.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/dotnet-core-CSharp/sample/regex/RegexSampleResult.PNG -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/1_1_assertthatbad_0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/1_1_assertthatbad_0.2.1.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/windows/1_1_assertthatbad_0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/windows/1_1_assertthatbad_0.2.1.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/1_1_assertthatinterchange_0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/1_1_assertthatinterchange_0.2.1.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/linux/1_1_assertthatzipwithinzip_0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/linux/1_1_assertthatzipwithinzip_0.2.1.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/windows/1_1_assertthatinterchange_0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/windows/1_1_assertthatinterchange_0.2.1.zip -------------------------------------------------------------------------------- /language-extensions/R/test/test-packages/windows/1_1_assertthatzipwithinzip_0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/sql-server-language-extensions/HEAD/language-extensions/R/test/test-packages/windows/1_1_assertthatzipwithinzip_0.2.1.zip -------------------------------------------------------------------------------- /packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/sample/SubModuleCall/SubModuleProject/SubModule/SubModule.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /language-extensions/java/build/linux/restore-packages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | 5 | export DEBIAN_FRONTEND=noninteractive 6 | apt-get update 7 | 8 | apt-get --no-install-recommends -y install curl zip unzip apt-transport-https 9 | 10 | apt-get install -y openjdk-17-jdk libc++1 libc6 libc++-dev libc++abi-dev libc++abi1 11 | 12 | exit $? 13 | -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /restore-packages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install unixodbc-dev for development headers 4 | # 5 | apt-get -q -y install unixodbc-dev 6 | 7 | apt-get update -y 8 | apt-get install build-essential software-properties-common -y 9 | add-apt-repository ppa:ubuntu-toolchain-r/test -y 10 | apt-get update -y 11 | apt-get install gcc-13 g++-13 -y 12 | apt-get install cmake -y 13 | update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 70 --slave /usr/bin/g++ g++ /usr/bin/g++-13 14 | 15 | exit $? 16 | 17 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/build/windows/restore-packages.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | SET ENL_ROOT=%~dp0..\..\..\.. 5 | 6 | REM Call the root level restore-packages 7 | REM 8 | SET PACKAGES_ROOT=%ENL_ROOT%\packages 9 | CALL %ENL_ROOT%\restore-packages.cmd 10 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to restore common nuget packages." || EXIT /b %ERRORLEVEL% 11 | 12 | EXIT /b %ERRORLEVEL% 13 | 14 | :CHECKERROR 15 | IF %1 NEQ 0 ( 16 | ECHO %2 17 | EXIT /b %1 18 | ) 19 | 20 | EXIT /b 0 21 | -------------------------------------------------------------------------------- /language-extensions/java/build/windows/restore-packages.cmd: -------------------------------------------------------------------------------- 1 | SET ENL_ROOT=%~dp0..\..\..\.. 2 | CALL %ENL_ROOT%\restore-packages.cmd 3 | 4 | SET PACKAGES_ROOT=%ENL_ROOT%\packages 5 | SET JAVA_VERSION=17.0.5 6 | 7 | REM Download and install JAVA 8 | REM 9 | SET JAVA_DOWNLOAD_URL="https://aka.ms/download-jdk/microsoft-jdk-%JAVA_VERSION%-windows-x64.zip" 10 | SET JAVA_INSTALLATION_PATH=%ProgramFiles%\JAVA 11 | 12 | curl %JAVA_DOWNLOAD_URL% -L -o "java-%JAVA_VERSION%.zip" 13 | powershell -NoProfile -ExecutionPolicy Unrestricted -Command "Expand-Archive -Force -Path 'java-%JAVA_VERSION%.zip' -DestinationPath '%PACKAGES_ROOT%'" 14 | DEL "java-%JAVA_VERSION%.zip" 15 | -------------------------------------------------------------------------------- /language-extensions/java/include/JavaSqlTypeHelper.h: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: JavaSqlTypeHelper.h 6 | // 7 | // Purpose: 8 | // Handles converting ODBC C type to JDBC type 9 | // 10 | //********************************************************************* 11 | #pragma once 12 | 13 | #include "Common.h" 14 | 15 | class JavaSqlTypeHelper 16 | { 17 | public: 18 | static bool GetJavaSqlType(SQLSMALLINT sqlType, jint &jdbcType); 19 | 20 | static bool GetOdbcType(jint jdbcType, SQLSMALLINT &odbcType); 21 | }; 22 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/src/managed/Microsoft.SqlServer.CSharpExtension.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | true 5 | true 6 | 7 | 8 | $(BinRoot)/$(Configuration)/ 9 | false 10 | LatestMajor 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /language-extensions/java/include/Common.h: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: Common.h 6 | // 7 | // Purpose: 8 | // Common header containing only the most common includes shared 9 | // across majority of the files 10 | // 11 | //********************************************************************* 12 | #pragma once 13 | 14 | #ifdef _WIN64 15 | #include 16 | #endif 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | -------------------------------------------------------------------------------- /language-extensions/java/include/JavaLibraryUtils.h: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: JavaLibraryUtils.h 6 | // 7 | // Purpose: 8 | // Library utility classes used by the Java extension. 9 | // 10 | //********************************************************************* 11 | #pragma once 12 | 13 | #include "Common.h" 14 | 15 | //--------------------------------------------------------------------- 16 | // Description: 17 | // Library utility functions for the Java extension. 18 | // 19 | class JavaLibraryUtils 20 | { 21 | public: 22 | static std::string GetLibrariesClassPath(); 23 | 24 | private: 25 | static void FindAppendFileNames(const std::string &basePath, std::string &output); 26 | }; 27 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/test/include/Common.h: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: Common.h 6 | // 7 | // Purpose: 8 | // Common headers for .NET Core CSharpExtenion-test. 9 | // 10 | //********************************************************************* 11 | #pragma once 12 | 13 | #ifdef _WIN64 14 | #include 15 | #endif 16 | 17 | #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "gtest/gtest.h" 26 | #include "nativecsharpextension.h" 27 | #include "CSharpExtensionApiTests.h" -------------------------------------------------------------------------------- /test/run-unittests.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | :LOOP 5 | 6 | IF "%~1"=="" GOTO USAGE 7 | 8 | REM Set config to first arg 9 | REM 10 | SET MSVC_BUILD_CONFIGURATION=%1 11 | 12 | IF NOT DEFINED CDP_USER_SOURCE_FOLDER_CONTAINER_PATH (SET ENL_ROOT=%~dp0..) ELSE (SET ENL_ROOT=%CDP_USER_SOURCE_FOLDER_CONTAINER_PATH%) 13 | 14 | pushd %ENL_ROOT%\build-output\sample-test\x64\%MSVC_BUILD_CONFIGURATION% 15 | sample-test.exe --gtest_output=xml:%ENL_ROOT%\out\TestReport_sample-test.xml 16 | IF %ERRORLEVEL% NEQ 0 GOTO error 17 | popd 18 | 19 | REM Advance arg passed to this script 20 | REM 21 | SHIFT 22 | 23 | REM Continue running using more configs until args have been exhausted 24 | REM 25 | IF NOT "%~1"=="" GOTO LOOP 26 | 27 | :error 28 | EXIT /b %ERRORLEVEL% 29 | 30 | :USAGE 31 | echo. 32 | echo Usage: 33 | echo %0 { debug ^| release } 34 | -------------------------------------------------------------------------------- /test/googletest/src/linux/CMakeLists.txt.in: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(googletest-download NONE) 4 | 5 | include(ExternalProject) 6 | ExternalProject_Add(googletest 7 | GIT_REPOSITORY https://github.com/google/googletest.git 8 | GIT_TAG release-1.12.1 9 | 10 | # GIT_CONFIG should have core.bare=false, core.symlinks=false, core.longpaths=true 11 | # for successful clone and checkout. 12 | # These are the defaults on linux. So no special configuration is needed here. 13 | # If GIT_CONFIG is at all needed, modify the cmake_minimum_required to 3.8.2. 14 | # 15 | 16 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" 17 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" 18 | CONFIGURE_COMMAND "" 19 | BUILD_COMMAND "" 20 | INSTALL_COMMAND "" 21 | TEST_COMMAND "" 22 | ) 23 | -------------------------------------------------------------------------------- /test/googletest/src/windows/CMakeLists.txt.in: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8.2) 2 | 3 | project(googletest-download NONE) 4 | 5 | include(ExternalProject) 6 | ExternalProject_Add(googletest 7 | GIT_REPOSITORY https://github.com/google/googletest.git 8 | GIT_TAG release-1.12.1 9 | 10 | # Make sure core.symlinks, core.bare are set to false otherwise 11 | # git clone fails with "operation need to be run in a working tree". 12 | # Keep core.longpaths = true as a precaution to not fail on longpaths. 13 | # 14 | GIT_CONFIG core.bare=false core.symlinks=false core.longpaths=true 15 | 16 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" 17 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" 18 | CONFIGURE_COMMAND "" 19 | BUILD_COMMAND "" 20 | INSTALL_COMMAND "" 21 | TEST_COMMAND "" 22 | ) 23 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/include/Logger.h: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: Logger.h 6 | // 7 | // Purpose: 8 | // Wrapper class around logging to standardize logging messages and errors. 9 | // 10 | //********************************************************************* 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | #define LOG(msg) Logger::Log(msg) 17 | #define LOG_ERROR(msg) Logger::LogError(msg) 18 | 19 | class Logger 20 | { 21 | public: 22 | // Logs a message to stdout. 23 | // 24 | static void Log(const string &msg); 25 | 26 | // Logs an error to stderr 27 | // 28 | static void LogError(const string &errorMsg); 29 | }; 30 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/test/src/managed/Microsoft.SqlServer.CSharpExtensionTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | true 5 | 6 | 7 | $(BinRoot)/$(Configuration)/ 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | ..\..\..\..\..\build-output\dotnet-core-CSharp-extension\windows\release\Microsoft.SqlServer.CSharpExtension.dll 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/sample/regex/pkg/RegexSample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | true 5 | true 6 | 7 | 8 | $(BinRoot)/$(Configuration)/ 9 | false 10 | 11 | 12 | 13 | 14 | 15 | 16 | ..\..\..\..\..\build-output\dotnet-core-CSharp-extension\windows\release\Microsoft.SqlServer.CSharpExtension.dll 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /language-extensions/python/include/Common.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: Common.h 8 | // 9 | // Purpose: 10 | // Common headers for extension 11 | // 12 | //************************************************************************************************* 13 | 14 | #pragma once 15 | 16 | #ifdef _WIN64 17 | #include 18 | #endif 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | -------------------------------------------------------------------------------- /language-extensions/python/test/include/Common.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: Common.h 8 | // 9 | // Purpose: 10 | // Common headers for the python test project 11 | // 12 | //************************************************************************************************* 13 | #pragma once 14 | 15 | #ifdef _WIN64 16 | #include 17 | #endif 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "gtest/gtest.h" 29 | #include "sqlexternallibrary.h" 30 | -------------------------------------------------------------------------------- /language-extensions/python/test/src/main.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: main.cpp 8 | // 9 | // Purpose: 10 | // Initialize gtest and run all Python extension tests 11 | // 12 | //************************************************************************************************* 13 | #include 14 | 15 | int main(int argc, const char **argv) 16 | { 17 | // banner 18 | // 19 | std::cout << "Running PythonExtension C++ unit tests.\n"; 20 | 21 | // First, initiate Google Test framework - this will remove 22 | // framework-specific parameters from argc and argv 23 | // 24 | ::testing::InitGoogleTest(&argc, const_cast(argv)); 25 | int rc = RUN_ALL_TESTS(); 26 | 27 | return rc; 28 | } 29 | -------------------------------------------------------------------------------- /language-extensions/R/build/linux/create-RExtension-zip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function check_exit_code { 4 | EXIT_CODE=$? 5 | if [ ${EXIT_CODE} -eq 0 ]; then 6 | echo "Success: Created zip for $1 config" 7 | else 8 | echo "Error: Failed to create zip for $1 config" 9 | exit ${EXIT_CODE} 10 | fi 11 | } 12 | 13 | function build { 14 | BUILD_CONFIGURATION=$1 15 | 16 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 17 | ENL_ROOT=${SCRIPTDIR}/../../../.. 18 | 19 | BUILD_OUTPUT=${ENL_ROOT}/build-output/RExtension/linux/${BUILD_CONFIGURATION} 20 | 21 | mkdir -p ${BUILD_OUTPUT}/packages 22 | cd ${BUILD_OUTPUT} 23 | zip packages/R-lang-extension-linux libRExtension.so.1.2 24 | check_exit_code ${BUILD_CONFIGURATION} 25 | } 26 | 27 | # Build in release mode if nothing is specified 28 | # 29 | if [ "$1" == "" ]; then 30 | set -- release 31 | fi 32 | 33 | while [ "$1" != "" ]; do 34 | # Advance arg passed to this script 35 | # 36 | build $1 37 | shift 38 | done; 39 | 40 | exit $? 41 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/test/src/native/main.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: main.cpp 6 | // 7 | // Purpose: 8 | // Main driver to invoke tests testing the dotnet-core-CSharp-extension's 9 | // implementation of the external language APIs. 10 | // 11 | //********************************************************************* 12 | #include "gtest/gtest.h" 13 | #include 14 | 15 | int g_argc = 0; 16 | const char **g_argv = nullptr; 17 | 18 | int main(int argc, const char **argv) 19 | { 20 | std::cout << "Running dotnetcore-CSharp-extension C++ unit tests.\n"; 21 | 22 | // First, initiate Google Test framework - this will remove 23 | // framework-specific parameters from argc and argv 24 | // 25 | ::testing::InitGoogleTest(&argc, const_cast(argv)); 26 | g_argc = argc; 27 | g_argv = argv; 28 | 29 | int rc = RUN_ALL_TESTS(); 30 | 31 | return rc; 32 | } 33 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/sample/LoopBackConnection/README.md: -------------------------------------------------------------------------------- 1 | # Loopback Connection 2 | This example demonstrates how to establish a loopback connection to SQL server. A loopback connection will allow your C# language extension to run any custom query against SQL Server. 3 | ## Prerequisites 4 | * [LoopBackConnectionADONET.cs](LoopBackConnectionADONET.cs). This contains the ADO.NET driver implementation sample for Loopback connection. 5 | * [LoopBackCOnnectionOLEDB.cs](LoopBackConnectionOLEDB.cs). This contains the OLEDB driver implementation sample for Loopback Connection. 6 | 7 | ## Implementation Steps 8 | 9 | 1) Download/clone the this folder. 10 | 2) Depending on what driver you would like to use, edit that particual component. 11 | 3) Follow the standard method to outlined in documentation to moved the language Extension DLL code into respective folders. 12 | 4) Execute the code through a stored procedure call as outlined in the regex sample. 13 | 5) Once your run it you should be able to see the console output in SSMS. -------------------------------------------------------------------------------- /language-extensions/java/build/linux/create-java-extension-zip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function check_exit_code { 4 | EXIT_CODE=$? 5 | if [ ${EXIT_CODE} -eq 0 ]; then 6 | echo "Success: Created zip for $1 config" 7 | else 8 | echo "Error: Failed to create zip for $1 config" 9 | exit ${EXIT_CODE} 10 | fi 11 | } 12 | 13 | 14 | function build { 15 | BUILD_CONFIGURATION=$1 16 | 17 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 18 | ENL_ROOT=${SCRIPTDIR}/../../../.. 19 | 20 | BUILD_OUTPUT=${ENL_ROOT}/build-output/java-extension/linux/${BUILD_CONFIGURATION} 21 | 22 | mkdir -p ${BUILD_OUTPUT}/packages 23 | cd ${BUILD_OUTPUT} 24 | zip packages/java-lang-extension-linux libJavaExtension.so.1.0 25 | check_exit_code ${BUILD_CONFIGURATION} 26 | } 27 | 28 | # Build in release mode if nothing is specified 29 | # 30 | if [ "$1" == "" ]; then 31 | set -- release 32 | fi 33 | 34 | while [ "$1" != "" ]; do 35 | # Advance arg passed to this script 36 | # 37 | build $1 38 | shift 39 | done; 40 | 41 | exit $? 42 | -------------------------------------------------------------------------------- /language-extensions/python/build/linux/create-python-extension-zip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function check_exit_code { 4 | EXIT_CODE=$? 5 | if [ ${EXIT_CODE} -eq 0 ]; then 6 | echo "Success: Created zip for $1 config" 7 | else 8 | echo "Error: Failed to create zip for $1 config" 9 | exit ${EXIT_CODE} 10 | fi 11 | } 12 | 13 | 14 | function build { 15 | BUILD_CONFIGURATION=$1 16 | 17 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 18 | ENL_ROOT=${SCRIPTDIR}/../../../.. 19 | 20 | BUILD_OUTPUT=${ENL_ROOT}/build-output/pythonextension/linux/${BUILD_CONFIGURATION} 21 | 22 | mkdir -p ${BUILD_OUTPUT}/packages 23 | cd ${BUILD_OUTPUT} 24 | zip packages/python-lang-extension-linux libPythonExtension.so.1.2 25 | check_exit_code ${BUILD_CONFIGURATION} 26 | } 27 | 28 | # Build in release mode if nothing is specified 29 | # 30 | if [ "$1" == "" ]; then 31 | set -- release 32 | fi 33 | 34 | while [ "$1" != "" ]; do 35 | # Advance arg passed to this script 36 | # 37 | build $1 38 | shift 39 | done; 40 | 41 | exit $? 42 | -------------------------------------------------------------------------------- /test/googletest/build/linux/build-googletest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function check_exit_code { 4 | EXIT_CODE=$? 5 | if [ ${EXIT_CODE} -eq 0 ]; then 6 | echo $1 7 | else 8 | echo $2 9 | exit ${EXIT_CODE} 10 | fi 11 | } 12 | 13 | # Enlistment root and location of googletest 14 | # 15 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 16 | ENL_ROOT=${SCRIPTDIR}/../../../.. 17 | PACKAGES_ROOT=${ENL_ROOT}/packages 18 | GTEST_HOME=${ENL_ROOT}/test/googletest 19 | 20 | # Set environment variables required in cmake 21 | # 22 | BUILD_OUTPUT=${ENL_ROOT}/build-output/googletest/linux 23 | 24 | # Generate the build output directory 25 | # 26 | rm -rf ${BUILD_OUTPUT} 27 | mkdir -p ${BUILD_OUTPUT} 28 | pushd ${BUILD_OUTPUT} 29 | 30 | # Compile 31 | # 32 | cmake -DCMAKE_INSTALL_PREFIX:PATH=${BUILD_OUTPUT} \ 33 | -DPLATFORM=linux \ 34 | ${GTEST_HOME}/src 35 | cmake --build ${BUILD_OUTPUT} --target install 36 | 37 | # Check the exit code of the compiler and exit appropriately so that build will fail. 38 | # 39 | check_exit_code "Success: Built googletest" "Error: Failed to build Rextension-test" 40 | 41 | popd 42 | 43 | exit $? 44 | -------------------------------------------------------------------------------- /language-extensions/python/test/include/PythonTestUtilities.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonTestUtilities.h 8 | // 9 | // Purpose: 10 | // Utility functions for the tests 11 | // 12 | //************************************************************************************************* 13 | 14 | #pragma once 15 | #include "Common.h" 16 | 17 | class PythonTestUtilities 18 | { 19 | public: 20 | 21 | // Parses the value of the active python exception 22 | // Type, value, and traceback are in separate pointers 23 | // 24 | static std::string ParsePythonException(); 25 | 26 | // Extract the string from a boost::python object 27 | // 28 | static std::string ExtractString(PyObject * pObj); 29 | static std::string ExtractString(boost::python::object handle); 30 | static void Tokenize(char *input, const char *delimiter, std::vector *tokens); 31 | }; 32 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/src/native/Logger.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: Logger.cpp 6 | // 7 | // Purpose: 8 | // Wrapper class around logging to standardize logging messages and errors. 9 | // 10 | //********************************************************************* 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "Logger.h" 16 | 17 | using namespace std; 18 | 19 | //-------------------------------------------------------------------------------------------------- 20 | // Name: Logger::Log 21 | // 22 | // Description: 23 | // Logs a message to stdout. 24 | // 25 | void Logger::Log(const string &msg) 26 | { 27 | #ifdef DEBUG 28 | cout << msg < 14 | #include 15 | 16 | #define TIMESTAMP_LENGTH 35 17 | 18 | using namespace std; 19 | 20 | char Logger::timestampBuffer[TIMESTAMP_LENGTH] = {0}; 21 | 22 | //--------------------------------------------------------------------- 23 | // Name: GetCurrentTimestamp 24 | // 25 | // Description: 26 | // Gets the current system time and format it to the SQL log format 27 | // (Year-Month-Day Hour:Minute:Second.Millisecond). 28 | // 29 | const char* Logger::GetCurrentTimestamp() 30 | { 31 | SYSTEMTIME sysTime; 32 | 33 | GetLocalTime(&sysTime); 34 | 35 | sprintf_s(timestampBuffer, TIMESTAMP_LENGTH, 36 | "%04d-%02d-%02d %02d:%02d:%02d.%02d\t", 37 | sysTime.wYear, 38 | sysTime.wMonth, 39 | sysTime.wDay, 40 | sysTime.wHour, 41 | sysTime.wMinute, 42 | sysTime.wSecond, 43 | sysTime.wMilliseconds / 10); 44 | 45 | return timestampBuffer; 46 | } 47 | -------------------------------------------------------------------------------- /language-extensions/R/build/windows/create-RExtension-zip.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | SET ENL_ROOT=%~dp0..\..\..\.. 5 | 6 | :LOOP 7 | 8 | REM Set cmake config to first arg 9 | REM 10 | SET BUILD_CONFIGURATION=%1 11 | 12 | REM Setting BUILD_CONFIGURATION to anything but "debug" will set BUILD_CONFIGURATION to "release". 13 | REM The string comparison for BUILD_CONFIGURATION is case-insensitive. 14 | REM 15 | IF NOT DEFINED BUILD_CONFIGURATION (SET BUILD_CONFIGURATION=release) 16 | IF /I NOT %BUILD_CONFIGURATION%==debug (SET BUILD_CONFIGURATION=release) 17 | 18 | SET BUILD_OUTPUT=%ENL_ROOT%\build-output\RExtension\windows\%BUILD_CONFIGURATION% 19 | 20 | mkdir %BUILD_OUTPUT%\packages 21 | 22 | powershell -NoProfile -ExecutionPolicy Unrestricted -Command "Compress-Archive -Path %BUILD_OUTPUT%\libRExtension.dll -DestinationPath %BUILD_OUTPUT%\packages\R-lang-extension.zip -Force" 23 | 24 | CALL :CHECK_BUILD_ERROR %ERRORLEVEL% %BUILD_CONFIGURATION% 25 | 26 | REM Advance arg passed to create-RExtension-zip.cmd 27 | REM 28 | SHIFT 29 | 30 | REM Continue building using more configs until argv has been exhausted 31 | REM 32 | IF NOT "%~1"=="" GOTO LOOP 33 | 34 | EXIT /b %ERRORLEVEL% 35 | 36 | :CHECK_BUILD_ERROR 37 | IF %1 == 0 ( 38 | ECHO Success: Created zip for %2 config 39 | ) ELSE ( 40 | ECHO Error: Failed to create zip for %2 config 41 | EXIT /b %1 42 | ) 43 | -------------------------------------------------------------------------------- /language-extensions/java/sdk/src/java/main/java/com/microsoft/sqlserver/javalangextension/AbstractSqlServerExtensionExecutor.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.sqlserver.javalangextension; 2 | 3 | import com.microsoft.sqlserver.javalangextension.AbstractSqlServerExtensionDataset; 4 | import java.lang.UnsupportedOperationException; 5 | import java.util.LinkedHashMap; 6 | 7 | /** 8 | * Abstract class containing interface used by the Java extension 9 | */ 10 | public abstract class AbstractSqlServerExtensionExecutor { 11 | /* Supported versions of the Java extension */ 12 | public final int SQLSERVER_JAVA_LANG_EXTENSION_V1 = 1; 13 | 14 | /* Members used by the extension to determine application specifics */ 15 | protected int executorExtensionVersion; 16 | protected String executorInputDatasetClassName; 17 | protected String executorOutputDatasetClassName; 18 | 19 | public AbstractSqlServerExtensionExecutor() { } 20 | 21 | public void init(String sessionId, int taskId, int numTasks) { 22 | /* Default implementation of init() is no-op */ 23 | } 24 | 25 | public AbstractSqlServerExtensionDataset execute(AbstractSqlServerExtensionDataset input, LinkedHashMap params) { 26 | throw new UnsupportedOperationException("AbstractSqlServerExtensionExecutor execute() is not implemented"); 27 | } 28 | 29 | public void cleanup() { 30 | /* Default implementation of cleanup() is no-op */ 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /language-extensions/python/include/Logger.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: Logger.h 8 | // 9 | // Purpose: 10 | // Logging functions for extension 11 | // 12 | //************************************************************************************************* 13 | 14 | #pragma once 15 | #include "Common.h" 16 | 17 | #define LOG(msg) Logger::Log(msg) 18 | #define LOG_ERROR(msg) Logger::LogError(msg) 19 | #define LOG_EXCEPTION(e) Logger::LogException(e) 20 | 21 | class Logger 22 | { 23 | public: 24 | // Log an error to stderr 25 | // 26 | static void LogError(const std::string &errorMsg); 27 | 28 | // Log a extension exception to stderr 29 | // 30 | static void LogException(const std::exception &e); 31 | 32 | // Log a message to stdout 33 | // 34 | static void Log(const std::string &msg); 35 | 36 | private: 37 | // Get a string of the current timestamp in the same format 38 | // of SQL format 39 | // 40 | static const std::string GetCurrentTimestamp(); 41 | 42 | // Buffer to hold the timestamp string. 43 | // 44 | static char sm_timestampBuffer[]; 45 | }; 46 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/test/build/windows/run-dotnet-core-CSharp-extension-test.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | REM Set environment variables 5 | REM 6 | SET ENL_ROOT=%~dp0..\..\..\..\.. 7 | SET DOTNETCORE_CSHARP_EXTENSION_TEST_WORKING_DIR=%ENL_ROOT%\build-output\dotnet-core-csharp-extension-test\windows 8 | SET PACKAGES_ROOT=%ENL_ROOT%\packages 9 | SET GTEST_HOME=%PACKAGES_ROOT%\Microsoft.googletest.v140.windesktop.msvcstl.dyn.rt-dyn.1.8.1.3 10 | SET GTEST_LIB_PATH=%GTEST_HOME%\lib\native\v140\windesktop\msvcstl\dyn\rt-dyn\x64 11 | 12 | :LOOP 13 | 14 | REM Set cmake config to first arg 15 | REM 16 | SET CMAKE_CONFIGURATION=%1 17 | 18 | REM CMAKE_CONFIGURATION is debug by default if not defined. 19 | REM 20 | IF NOT DEFINED CMAKE_CONFIGURATION (SET CMAKE_CONFIGURATION=release) 21 | 22 | PUSHD %DOTNETCORE_CSHARP_EXTENSION_TEST_WORKING_DIR%\%CMAKE_CONFIGURATION% 23 | COPY %GTEST_LIB_PATH%\%CMAKE_CONFIGURATION%\gtest*.dll . 24 | dotnet-core-CSharp-extension-test.exe --gtest_output=xml:%ENL_ROOT%\out\TestReport_dotnet-core-csharp-extension-test.xml 25 | IF %ERRORLEVEL% NEQ 0 GOTO error 26 | POPD 27 | 28 | REM Advance arg passed to run-dotnet-core-csharp-extension-test.cmd 29 | REM 30 | SHIFT 31 | 32 | REM Continue running using more configs until argv has been exhausted 33 | REM 34 | IF NOT "%~1"=="" GOTO LOOP 35 | 36 | :error 37 | EXIT /b %ERRORLEVEL% 38 | 39 | :USAGE 40 | echo. 41 | echo Usage: 42 | echo %0 { debug ^| release } 43 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/test/src/native/CSharpInitSessionTests.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: CSharpInitSessionTests.cpp 6 | // 7 | // Purpose: 8 | // Test the .NET Core CSharp extension initialization and 9 | // session initialization using the Extension API 10 | // 11 | //********************************************************************* 12 | #include "CSharpExtensionApiTests.h" 13 | 14 | using namespace std; 15 | 16 | namespace ExtensionApiTest 17 | { 18 | //---------------------------------------------------------------------------------------------- 19 | // Name: InitValidSessionTest 20 | // 21 | // Description: 22 | // Test InitSession() API with valid values. 23 | // 24 | TEST_F(CSharpExtensionApiTests, InitValidSessionTest) 25 | { 26 | SQLRETURN result = (*sm_initSessionFuncPtr)( 27 | *m_sessionId, 28 | m_taskId, 29 | m_numTasks, 30 | m_script, 31 | m_scriptString.length(), 32 | m_inputSchemaColumnsNumber, 33 | m_parametersNumber, 34 | m_inputDataName, 35 | m_inputDataNameString.length(), 36 | m_outputDataName, 37 | m_outputDataNameString.length()); 38 | 39 | EXPECT_EQ(result, SQL_SUCCESS); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /language-extensions/java/include/Logger.h: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: Logger.h 6 | // 7 | // Purpose: 8 | // Wrapper class around logging to standardize logging messages 9 | // and errors. 10 | // 11 | //********************************************************************* 12 | #pragma once 13 | 14 | #include "Common.h" 15 | 16 | #ifdef DEBUG 17 | #define LOG(msg) Logger::Log(msg) 18 | #else 19 | #define LOG(msg) 20 | #endif 21 | #define LOG_ERROR(msg) Logger::LogError(msg) 22 | #define LOG_EXCEPTION(e) Logger::LogException(e) 23 | #define LOG_JAVA_EXCEPTION(msg) Logger::LogJavaException(msg) 24 | 25 | class Logger 26 | { 27 | public: 28 | // Log an error to stderr 29 | // 30 | static void LogError(const std::string &errorMsg); 31 | 32 | // Log a extension exception to stderr 33 | // 34 | static void LogException(const std::exception &e); 35 | 36 | // Log a java exception to stderr 37 | // 38 | static void LogJavaException(const std::string &errorMsg); 39 | 40 | // Log a message to stdout 41 | // 42 | static void Log(const std::string &errorMsg); 43 | 44 | private: 45 | // Get a string of the current timestamp in the same format 46 | // of SQL format 47 | // 48 | static const char* GetCurrentTimestamp(); 49 | 50 | // Buffer to hold the timestamp string. 51 | // 52 | static char timestampBuffer[]; 53 | }; 54 | -------------------------------------------------------------------------------- /extension-host/include/sqlexternallibrary.h: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // 4 | // Library management protocol between Exthost and a 3rd party extension 5 | // 6 | // @File: sqlexternallibrary.h 7 | // 8 | //********************************************************************* 9 | 10 | #ifndef __SQLEXTERNALLIBRARY 11 | #define __SQLEXTERNALLIBRARY 12 | 13 | #include "sqlexternallanguage.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif /* __cplusplus */ 18 | 19 | // Optional API 20 | // 21 | SQLEXTENSION_INTERFACE 22 | SQLRETURN InstallExternalLibrary( 23 | SQLGUID SetupSessionId, 24 | SQLCHAR *LibraryName, 25 | SQLINTEGER LibraryNameLength, 26 | SQLCHAR *LibraryFile, 27 | SQLINTEGER LibraryFileLength, 28 | SQLCHAR *LibraryInstallDirectory, 29 | SQLINTEGER LibraryInstallDirectoryLength, 30 | SQLCHAR **LibraryError, 31 | SQLINTEGER *LibraryErrorLength); 32 | 33 | // Optional API 34 | // 35 | SQLEXTENSION_INTERFACE 36 | SQLRETURN UninstallExternalLibrary( 37 | SQLGUID SetupSessionId, 38 | SQLCHAR *LibraryName, 39 | SQLINTEGER LibraryNameLength, 40 | SQLCHAR *LibraryInstallDirectory, 41 | SQLINTEGER LibraryInstallDirectoryLength, 42 | SQLCHAR **LibraryError, 43 | SQLINTEGER *LibraryErrorLength); 44 | 45 | #ifdef __cplusplus 46 | } /* End of extern "C" { */ 47 | #endif /* __cplusplus */ 48 | 49 | #endif /* __SQLEXTERNALLIBRARY */ 50 | -------------------------------------------------------------------------------- /language-extensions/python/LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /test/googletest/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Downloads and unpacks googletest at configure time. Based on the instructions 2 | # at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project 3 | 4 | cmake_minimum_required (VERSION 3.5) 5 | 6 | project(googletest) 7 | 8 | set(CMAKE_CXX_STANDARD 17) 9 | 10 | # Populate the CMakeLists.txt.in with the actual values from build 11 | # 12 | configure_file(${PLATFORM}/CMakeLists.txt.in googletest-download/CMakeLists.txt) 13 | 14 | # Generate the make files 15 | # 16 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} 17 | RESULT_VARIABLE result 18 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download) 19 | if(result) 20 | message(FATAL_ERROR "CMake step for googletest failed: ${result}") 21 | endif() 22 | 23 | # Build googletest 24 | # 25 | execute_process(COMMAND "${CMAKE_COMMAND}" --build . 26 | RESULT_VARIABLE result 27 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) 28 | if(result) 29 | message(FATAL_ERROR "Build step for googletest failed: ${result}") 30 | endif() 31 | 32 | # Prevent overriding the parent project's compiler/linker 33 | # settings on Windows 34 | # 35 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 36 | 37 | # Add googletest directly to build. This defines 38 | # the gtest and gtest_main targets. 39 | # 40 | add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src 41 | ${CMAKE_CURRENT_BINARY_DIR}/googletest-build) 42 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/src/managed/utils/ExceptionUtils.cs: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: ExceptionUtils.cs 6 | // 7 | // Purpose: 8 | // Handle the exceptions from managed language extensions APIs 9 | // 10 | //********************************************************************* 11 | using System; 12 | using static Microsoft.SqlServer.CSharpExtension.Sql; 13 | 14 | namespace Microsoft.SqlServer.CSharpExtension 15 | { 16 | /// 17 | /// This class handles the exceptions from managed language extensions APIs and 18 | /// logs the error messages to the stderr. 19 | /// 20 | class ExceptionUtils 21 | { 22 | /// 23 | /// This method calls the APIs and handles exceptions. 24 | /// 25 | /// 26 | /// Managed language extensions APIs fucntion 27 | /// 28 | /// 29 | /// SQL_SUCCESS(0), SQL_ERROR(-1) 30 | /// 31 | public static short WrapError(Action func) 32 | { 33 | try 34 | { 35 | func(); 36 | return SQL_SUCCESS; 37 | } 38 | catch (Exception e) 39 | { 40 | Logging.Error(e.StackTrace + "Error: " + e.Message); 41 | return SQL_ERROR; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/sample/SubModuleCall/SubModuleProject/SubModule/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | namespace UserExecutor 7 | { 8 | // Lets assume that a DLL is created using this kind of code in another project. 9 | // The DLL is moved into the folder where access is granted. 10 | // You need to grant access to the DLL's parent folder before you execute these commands. 11 | // To grant access to the folder, run the following commands in Windows command prompt: 12 | // Note: The folder name may change in your environment. So please specify the right folder name. 13 | // Command1: 14 | // icacls "C:\Program Files\Microsoft SQL Server\MSSQL16.SQLSERVER2022\MSSQL\ExternalLibraries\6\65537\1" /grant "SQLRUsergroupSQLSERVER2022":(OI)(CI)RX /T 15 | // Change the server name according to your naming convension . 16 | // Command2: 17 | // icacls "C:\Program Files\Microsoft SQL Server\MSSQL16.SQLSERVER2022\MSSQL\ExternalLibraries\6\65537\1" /grant *S-1-15-2-1:(OI)(CI)RX /T 18 | // After executing above commands, SQL server will have access to local folder which has been specified in the commands. 19 | // All these commands are available in OneTimeSetupCommands.cmd file in this solution as well 20 | // 21 | public class SubModule 22 | { 23 | public void printConsole() 24 | { 25 | Console.WriteLine("This is hello world from adhoc DLL file"); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/include/coreclr_delegates.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | 4 | #ifndef __CORECLR_DELEGATES_H__ 5 | #define __CORECLR_DELEGATES_H__ 6 | 7 | #include 8 | 9 | #if defined(_WIN32) 10 | #define CORECLR_DELEGATE_CALLTYPE __stdcall 11 | #ifdef _WCHAR_T_DEFINED 12 | typedef wchar_t char_t; 13 | #else 14 | typedef unsigned short char_t; 15 | #endif 16 | #else 17 | #define CORECLR_DELEGATE_CALLTYPE 18 | typedef char char_t; 19 | #endif 20 | 21 | // Signature of delegate returned by coreclr_delegate_type::load_assembly_and_get_function_pointer 22 | typedef int (CORECLR_DELEGATE_CALLTYPE *load_assembly_and_get_function_pointer_fn)( 23 | const char_t *assembly_path /* Fully qualified path to assembly */, 24 | const char_t *type_name /* Assembly qualified type name */, 25 | const char_t *method_name /* Public static method name compatible with delegateType */, 26 | const char_t *delegate_type_name /* Assembly qualified delegate type name or null */, 27 | void *reserved /* Extensibility parameter (currently unused and must be 0) */, 28 | /*out*/ void **delegate /* Pointer where to store the function pointer result */); 29 | 30 | // Signature of delegate returned by load_assembly_and_get_function_pointer_fn when delegate_type_name == null (default) 31 | typedef int (CORECLR_DELEGATE_CALLTYPE *component_entry_point_fn)(void *arg, int32_t arg_size_in_bytes); 32 | 33 | #endif // __CORECLR_DELEGATES_H__ 34 | -------------------------------------------------------------------------------- /language-extensions/java/src/JavaPathSettings.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: JavaPathSettings.cpp 6 | // 7 | // Purpose: 8 | // Global class to keep language runtime settings. 9 | // 10 | //********************************************************************* 11 | #include "JavaPathSettings.h" 12 | 13 | //---------------------------------------------------------------------------- 14 | // Name: ExtensionConfig::Init 15 | // 16 | // Description: 17 | // Initialize the class 18 | // 19 | void 20 | JavaPathSettings::Init( 21 | const SQLCHAR *languageParams, 22 | const SQLCHAR *languagePath, 23 | const SQLCHAR *publicLibraryPath, 24 | const SQLCHAR *privateLibraryPath) 25 | { 26 | // nullptrs are mapped to empty strings - has the same effect when 27 | // the paths are used and avoids an additional flag. 28 | // 29 | m_languageParams = 30 | (languageParams == nullptr) ? "" : reinterpret_cast(languageParams); 31 | 32 | m_languagePath = 33 | (languagePath == nullptr) ? "" : reinterpret_cast(languagePath); 34 | 35 | m_publicLibraryPath = 36 | (publicLibraryPath == nullptr) ? "" : reinterpret_cast(publicLibraryPath); 37 | 38 | m_privateLibraryPath = 39 | (privateLibraryPath == nullptr) ? "" : reinterpret_cast(privateLibraryPath); 40 | } 41 | 42 | std::string JavaPathSettings::m_languagePath; 43 | std::string JavaPathSettings::m_languageParams; 44 | std::string JavaPathSettings::m_privateLibraryPath; 45 | std::string JavaPathSettings::m_publicLibraryPath; 46 | -------------------------------------------------------------------------------- /language-extensions/java/include/JavaPathSettings.h: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: JavaPathSettings.h 6 | // 7 | // Purpose: 8 | // Global class to keep language runtime settings. 9 | // 10 | //********************************************************************* 11 | #pragma once 12 | 13 | #include "Common.h" 14 | 15 | //--------------------------------------------------------------------- 16 | // Description: 17 | // Global class storing the language runtime paths and parameters 18 | // 19 | class JavaPathSettings 20 | { 21 | public: 22 | // Initialize this global class 23 | // 24 | static void Init( 25 | const SQLCHAR *languageParams, 26 | const SQLCHAR *languagePath, 27 | const SQLCHAR *publicLibraryPath, 28 | const SQLCHAR *privateLibraryPath); 29 | 30 | // Get the private library path sent by SQL Server 31 | // 32 | static const std::string& GetPrivateLibraryPath() { return m_privateLibraryPath; } 33 | 34 | // Get the public library path sent by SQL Server 35 | // 36 | static const std::string& GetPublicLibraryPath() { return m_publicLibraryPath; } 37 | 38 | // Get the extension root folder 39 | // 40 | static const std::string& GetRootPath() { return m_languagePath; } 41 | 42 | // Get the language parameters sent by SQL Server 43 | // 44 | static const std::string& GetParams() { return m_languageParams; } 45 | 46 | private: 47 | static std::string m_languagePath; 48 | static std::string m_languageParams; 49 | static std::string m_privateLibraryPath; 50 | static std::string m_publicLibraryPath; 51 | }; 52 | -------------------------------------------------------------------------------- /language-extensions/python/build/windows/create-python-extension-zip.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | SET ENL_ROOT=%~dp0..\..\..\.. 5 | 6 | :LOOP 7 | 8 | REM Set cmake config to first arg 9 | REM 10 | SET BUILD_CONFIGURATION=%1 11 | 12 | REM Setting BUILD_CONFIGURATION to anything but "debug" will set BUILD_CONFIGURATION to "release". 13 | REM The string comparison for BUILD_CONFIGURATION is case-insensitive. 14 | REM 15 | IF NOT DEFINED BUILD_CONFIGURATION (SET BUILD_CONFIGURATION=release) 16 | IF /I NOT %BUILD_CONFIGURATION%==debug (SET BUILD_CONFIGURATION=release) 17 | 18 | SET BUILD_OUTPUT=%ENL_ROOT%\build-output\pythonextension\windows\%BUILD_CONFIGURATION% 19 | 20 | mkdir %BUILD_OUTPUT%\packages 21 | 22 | REM Check if BUILD_CONFIGURATION is debug, then include pythonextension.pdb in the zip 23 | IF /I "%BUILD_CONFIGURATION%"=="debug" ( 24 | SET INCLUDE_FILES=%BUILD_OUTPUT%\pythonextension.dll, %BUILD_OUTPUT%\pythonextension.pdb 25 | ) ELSE ( 26 | SET INCLUDE_FILES=%BUILD_OUTPUT%\pythonextension.dll 27 | ) 28 | 29 | powershell -NoProfile -ExecutionPolicy Unrestricted -Command "Compress-Archive -Path %INCLUDE_FILES% -DestinationPath %BUILD_OUTPUT%\packages\python-lang-extension.zip -Force" 30 | 31 | CALL :CHECK_BUILD_ERROR %ERRORLEVEL% %BUILD_CONFIGURATION% 32 | 33 | REM Advance arg passed to create-python-extension.cmd 34 | REM 35 | SHIFT 36 | 37 | REM Continue building using more configs until argv has been exhausted 38 | REM 39 | IF NOT "%~1"=="" GOTO LOOP 40 | 41 | EXIT /b %ERRORLEVEL% 42 | 43 | :CHECK_BUILD_ERROR 44 | IF %1 == 0 ( 45 | ECHO Success: Created zip for %2 config 46 | ) ELSE ( 47 | ECHO Error: Failed to create zip for %2 config 48 | EXIT /b %1 49 | ) 50 | -------------------------------------------------------------------------------- /language-extensions/java/src/linux/Logger_linux.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: Logger.cpp 6 | // 7 | // Purpose: 8 | // Implementation of Linux platform dependent logging for the java 9 | // extension. 10 | // 11 | //********************************************************************* 12 | #include "Logger.h" 13 | #include 14 | #include 15 | 16 | #define TIMESTAMP_LENGTH 35 17 | #define NANOSECONDS_IN_MILLISECOND 1000000 18 | 19 | using namespace std; 20 | 21 | char Logger::timestampBuffer[TIMESTAMP_LENGTH] = {0}; 22 | 23 | //--------------------------------------------------------------------- 24 | // Name: GetCurrentTimestamp 25 | // 26 | // Description: 27 | // Gets the current system time and format it to the SQL log format 28 | // (Year-Month-Day Hour:Minute:Second.Millisecond). 29 | // 30 | const char* Logger::GetCurrentTimestamp() 31 | { 32 | timespec ts; 33 | char buffer[TIMESTAMP_LENGTH] = {0}; 34 | 35 | clock_gettime(CLOCK_REALTIME, &ts); 36 | 37 | // Convert the time to Year-Month-Day Hour:Minute:Second 38 | // 39 | strftime(buffer, sizeof(buffer), "%F %T", gmtime(&ts.tv_sec)); 40 | 41 | // Append the milliseconds and the tab to the timestamp 42 | // 43 | long ms = (ts.tv_nsec / NANOSECONDS_IN_MILLISECOND); 44 | 45 | // SQL outputs milliseconds in decimal with precision of 2, divide 46 | // by 10 to remove the last digit. 47 | // 48 | ms /= 10; 49 | 50 | // Append the milliseconds and the tab to the timestamp 51 | // 52 | sprintf(timestampBuffer, "%s.%02li\t", buffer, ms); 53 | 54 | return timestampBuffer; 55 | } 56 | -------------------------------------------------------------------------------- /language-extensions/java/build/windows/create-java-extension-zip.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | SET ENL_ROOT=%~dp0..\..\..\.. 5 | 6 | :LOOP 7 | 8 | REM Set cmake config to first arg 9 | REM 10 | SET BUILD_CONFIGURATION=%1 11 | 12 | REM Setting BUILD_CONFIGURATION to anything but "debug" will set BUILD_CONFIGURATION to "release". 13 | REM The string comparison for BUILD_CONFIGURATION is case-insensitive. 14 | REM 15 | IF NOT DEFINED BUILD_CONFIGURATION (SET BUILD_CONFIGURATION=release) 16 | IF /I NOT %BUILD_CONFIGURATION%==debug (SET BUILD_CONFIGURATION=release) 17 | 18 | SET BUILD_OUTPUT=%ENL_ROOT%\build-output\java-extension\windows\%BUILD_CONFIGURATION% 19 | 20 | mkdir %BUILD_OUTPUT%\packages 21 | 22 | REM Set common files to be included in the zip 23 | SET INCLUDE_FILES=%BUILD_OUTPUT%\javaextension.dll 24 | 25 | REM Check if BUILD_CONFIGURATION is debug, then include javaextension.pdb in the zip 26 | IF /I "%BUILD_CONFIGURATION%"=="debug" ( 27 | SET INCLUDE_FILES=%INCLUDE_FILES%, %BUILD_OUTPUT%\javaextension.pdb 28 | ) 29 | 30 | powershell -NoProfile -ExecutionPolicy Unrestricted -Command "Compress-Archive -Path %INCLUDE_FILES% -DestinationPath %BUILD_OUTPUT%\packages\java-lang-extension.zip -Force" 31 | CALL :CHECK_BUILD_ERROR %ERRORLEVEL% %BUILD_CONFIGURATION% 32 | 33 | REM Advance arg passed to create-java-extension.cmd 34 | REM 35 | SHIFT 36 | 37 | REM Continue building using more configs until argv has been exhausted 38 | REM 39 | IF NOT "%~1"=="" GOTO LOOP 40 | 41 | EXIT /b %ERRORLEVEL% 42 | 43 | :CHECK_BUILD_ERROR 44 | IF %1 == 0 ( 45 | ECHO Success: Created zip for %2 config 46 | ) ELSE ( 47 | ECHO Error: Failed to create zip for %2 config 48 | EXIT /b %1 49 | ) 50 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/src/managed/CSharpDataSet.cs: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: CSharpDataSet.cs 6 | // 7 | // Purpose: 8 | // Class handling loading and retrieving data from a DataFrame. 9 | // 10 | //********************************************************************* 11 | using System.Collections.Generic; 12 | using Microsoft.Data.Analysis; 13 | 14 | namespace Microsoft.SqlServer.CSharpExtension 15 | { 16 | /// 17 | /// This class loads and retrieves input/output dataset. 18 | /// 19 | public abstract class CSharpDataSet 20 | { 21 | public string Name { get; set; } 22 | public ushort ColumnsNumber { get; set; } 23 | 24 | /// 25 | /// This dataframe contains input/output dataset. 26 | /// 27 | public DataFrame CSharpDataFrame { get; set; } 28 | 29 | /// 30 | /// This property defines [] operator for CSharpDataSet. 31 | /// 32 | public CSharpColumn this[ushort columnNumber] 33 | { 34 | get 35 | { 36 | return _columns[columnNumber]; 37 | } 38 | 39 | private set 40 | { 41 | _columns[columnNumber] = value; 42 | } 43 | } 44 | 45 | /// 46 | /// This dictionary contains all the columns metadata as CSharpColumn objects. 47 | /// 48 | protected Dictionary _columns = new Dictionary(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | 3 | Microsoft SQL Server Language Extensions 4 | 5 | Copyright (c) Microsoft Corporation. All rights reserved. 6 | 7 | This repository contains language extensions for SQL Server that are separately licensed. Each language extension is contained in a separate folder accessible from the main repository and is licensed in accordance with the LICENSE.TXT file present in such folder. 8 | 9 | For all other material that is available from this repository, the following license applies. 10 | 11 | MIT License 12 | Copyright (c) Microsoft Corporation. All rights reserved. 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy 15 | of this software and associated documentation files (the "Software"), to deal 16 | in the Software without restriction, including without limitation the rights 17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the Software is 19 | furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in all 22 | copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | SOFTWARE 31 | -------------------------------------------------------------------------------- /language-extensions/R/test/build/linux/run-RExtension-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function check_exit_code { 4 | EXIT_CODE=$? 5 | if [ ${EXIT_CODE} -eq 0 ]; then 6 | echo $1 7 | else 8 | echo $2 9 | exit ${EXIT_CODE} 10 | fi 11 | } 12 | 13 | function build { 14 | # Set cmake config to first arg 15 | CMAKE_CONFIGURATION=$1 16 | if [ -z "${CMAKE_CONFIGURATION}" ]; then 17 | CMAKE_CONFIGURATION=release 18 | fi 19 | 20 | pushd ${REXTENSIONTEST_WORKING_DIR}/${CMAKE_CONFIGURATION} 21 | # Move the generated libs to configuration folder 22 | cp ${REXTENSION_WORKING_DIR}/${CMAKE_CONFIGURATION}/libRExtension.so.1.2 . 23 | ./RExtension-test --gtest_output=xml:${ENL_ROOT}/out/TestReport_RExtension-test.xml 24 | 25 | # Check the exit code of the tests. 26 | check_exit_code "Success: Ran RExtension-test" "Error: RExtension-test failed" 27 | 28 | popd 29 | } 30 | 31 | # Enlistment root and location of RExtension-test 32 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 33 | export ENL_ROOT=${SCRIPTDIR}/../../../../.. 34 | REXTENSION_WORKING_DIR=${ENL_ROOT}/build-output/RExtension/linux 35 | REXTENSIONTEST_WORKING_DIR=${ENL_ROOT}/build-output/RExtension-test/linux 36 | PACKAGES_ROOT=${ENL_ROOT}/packages 37 | 38 | DEFAULT_R_HOME=/usr/lib/R 39 | 40 | # Find R_HOME from user, or set to default for testing. 41 | # Error code 1 is generic bash error. 42 | # 43 | if [ -z "${R_HOME}" ]; then 44 | if [ -d "${DEFAULT_R_HOME}" ]; then 45 | export R_HOME=${DEFAULT_R_HOME} 46 | else 47 | echo "R_HOME is empty" 48 | exit 1 49 | fi 50 | fi 51 | 52 | # Test in release mode if nothing is specified 53 | # 54 | if [ "$1" == "" ]; then 55 | set -- release 56 | fi 57 | 58 | while [ "$1" != "" ]; do 59 | # Advance arg passed to build.cmd 60 | build $1 61 | shift 62 | done; 63 | -------------------------------------------------------------------------------- /language-extensions/python/src/PythonColumn.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonColumn.cpp 8 | // 9 | // Purpose: 10 | // Encapsulate data column attributes 11 | // 12 | //************************************************************************************************* 13 | 14 | #include "PythonColumn.h" 15 | 16 | using namespace std; 17 | 18 | //------------------------------------------------------------------------------------------------- 19 | // Name: PythonColumn::PythonColumn 20 | // 21 | // Description: 22 | // Initializes the class that encapsulates one column in the Python DataFrame/Dictionary 23 | // 24 | PythonColumn::PythonColumn( 25 | const SQLCHAR *columnName, 26 | SQLSMALLINT columnNameLength, 27 | SQLSMALLINT dataType, 28 | SQLULEN columnSize, 29 | SQLSMALLINT decimalDigits, 30 | SQLSMALLINT nullable) : 31 | m_dataType(dataType), 32 | m_size(columnSize), 33 | m_decimalDigits(decimalDigits), 34 | m_nullable(nullable) 35 | { 36 | const char *name = static_cast(static_cast(columnName)); 37 | 38 | // columnNameLength does not include the null terminator. 39 | // 40 | #if defined(_DEBUG) 41 | if (static_cast(columnNameLength) != strlen(name)) 42 | { 43 | throw invalid_argument("Invalid column name length, it doesn't match string length."); 44 | } 45 | #endif 46 | 47 | // Store the information for this column 48 | // 49 | m_name = string(name, columnNameLength); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /language-extensions/python/include/PythonColumn.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonColumn.h 8 | // 9 | // Purpose: 10 | // Encapsulate dataset column attributes 11 | // 12 | //************************************************************************************************* 13 | 14 | #pragma once 15 | #include "Common.h" 16 | 17 | // Encapsulate column information 18 | // 19 | class PythonColumn 20 | { 21 | public: 22 | PythonColumn( 23 | const SQLCHAR *columnName, 24 | SQLSMALLINT columnNameLength, 25 | SQLSMALLINT dataType, 26 | SQLULEN columnSize, 27 | SQLSMALLINT decimalDigits, 28 | SQLSMALLINT nullable); 29 | 30 | const std::string& Name() const 31 | { 32 | return m_name; 33 | } 34 | 35 | SQLSMALLINT DataType() const 36 | { 37 | return m_dataType; 38 | } 39 | 40 | SQLULEN Size() const 41 | { 42 | return m_size; 43 | } 44 | 45 | SQLSMALLINT DecimalDigits() const 46 | { 47 | return m_decimalDigits; 48 | } 49 | 50 | SQLSMALLINT Nullable() const 51 | { 52 | return m_nullable; 53 | } 54 | 55 | protected: 56 | // Name of the column. 57 | // 58 | std::string m_name; 59 | 60 | // Data Type of the column. 61 | // 62 | SQLSMALLINT m_dataType; 63 | 64 | // Size of the column. 65 | // 66 | SQLULEN m_size; 67 | 68 | // Decimal digits of the column. 69 | // 70 | SQLSMALLINT m_decimalDigits; 71 | 72 | // The column is nullable or not. 73 | // 74 | SQLSMALLINT m_nullable; 75 | }; 76 | -------------------------------------------------------------------------------- /language-extensions/python/test/build/windows/run-pythonextension-test.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | REM Set environment variables 5 | REM 6 | SET ENL_ROOT=%~dp0..\..\..\..\.. 7 | SET PACKAGES_ROOT=%ENL_ROOT%\packages 8 | SET PYTHONEXTENSION_TEST_WORKING_DIR=%ENL_ROOT%\build-output\pythonextension-test\windows 9 | SET PYTHONEXTENSION_WORKING_DIR=%ENL_ROOT%\build-output\pythonextension\windows 10 | SET GTEST_HOME=%PACKAGES_ROOT%\Microsoft.googletest.v140.windesktop.msvcstl.dyn.rt-dyn.1.8.1.3 11 | SET GTEST_LIB_PATH=%GTEST_HOME%\lib\native\v140\windesktop\msvcstl\dyn\rt-dyn\x64 12 | 13 | :LOOP 14 | 15 | REM Set cmake config to first arg 16 | REM 17 | SET CMAKE_CONFIGURATION=%1 18 | 19 | REM *Setting CMAKE_CONFIGURATION to anything but "debug" will set CMAKE_CONFIGURATION to "release". 20 | REM The string comparison for CMAKE_CONFIGURATION is case-insensitive. 21 | REM 22 | IF NOT DEFINED CMAKE_CONFIGURATION (SET CMAKE_CONFIGURATION=release) 23 | IF /I %CMAKE_CONFIGURATION%==debug (SET CMAKE_CONFIGURATION=debug) ELSE (SET CMAKE_CONFIGURATION=release) 24 | 25 | pushd %PYTHONEXTENSION_TEST_WORKING_DIR%\%CMAKE_CONFIGURATION% 26 | copy %PYTHONEXTENSION_WORKING_DIR%\%CMAKE_CONFIGURATION%\pythonextension.* . 27 | copy %GTEST_LIB_PATH%\%CMAKE_CONFIGURATION%\gtest* . 28 | 29 | IF "%PYTHONHOME%"=="" (SET PYTHONHOME=%PACKAGES_ROOT%\python) 30 | 31 | SET PATH=%PATH%;%PYTHONHOME%; 32 | 33 | pythonextension-test.exe --gtest_output=xml:%ENL_ROOT%\out\TestReport_PythonExtension-test.xml 34 | IF %ERRORLEVEL% NEQ 0 GOTO error 35 | popd 36 | 37 | REM Advance arg passed to build-pythonextension-test.cmd 38 | REM 39 | SHIFT 40 | 41 | REM Continue running using more configs until argv has been exhausted 42 | REM 43 | IF NOT "%~1"=="" GOTO LOOP 44 | 45 | :error 46 | EXIT /b %ERRORLEVEL% 47 | 48 | :USAGE 49 | echo. 50 | echo Usage: 51 | echo %0 { debug ^| release } 52 | -------------------------------------------------------------------------------- /language-extensions/R/test/src/main.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // RExtension-test : Executable testing language extension that implements the SQL Server 3 | // external language communication protocol. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension-test. 7 | // 8 | // RExtension-test is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension-test is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension-test. If not, see . 20 | // 21 | // @File: main.cpp 22 | // 23 | // Purpose: 24 | // Tests the RExtension's implementation of the external language APIs. 25 | // 26 | //************************************************************************************************* 27 | 28 | #include "Common.h" 29 | 30 | int g_argc = 0; 31 | const char **g_argv = nullptr; 32 | 33 | int main(int argc, const char **argv) 34 | { 35 | // Banner 36 | // 37 | std::cout << "Running RExtension C++ unit tests.\n"; 38 | 39 | // First, initiate Google Test framework - this will remove 40 | // framework-specific parameters from argc and argv 41 | // 42 | ::testing::InitGoogleTest(&argc, const_cast(argv)); 43 | g_argc = argc; 44 | g_argv = argv; 45 | 46 | int rc = RUN_ALL_TESTS(); 47 | 48 | return rc; 49 | } 50 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/sample/regex/dotnet-core-CSharp-regex-win.sql: -------------------------------------------------------------------------------- 1 | -- Step 1: Create sample data 2 | 3 | CREATE DATABASE csharptest 4 | GO 5 | USE csharptest 6 | GO 7 | 8 | CREATE TABLE testdata ( 9 | [id] int, 10 | [text] varchar(100), 11 | ) 12 | GO 13 | 14 | INSERT INTO testdata(id, "text") VALUES (4, 'This sentence contains C#') 15 | INSERT INTO testdata(id, "text") VALUES (1, 'This sentence does not') 16 | INSERT INTO testdata(id, "text") VALUES (3, 'I love c#!') 17 | INSERT INTO testdata(id, "text") VALUES (2, NULL) 18 | GO 19 | 20 | -- Step 2: Create the main class 21 | -- Step 3: Compile and create a .dll file 22 | 23 | -- Step 4: Create external language 24 | 25 | CREATE EXTERNAL LANGUAGE Dotnet 26 | FROM 27 | (CONTENT = N'\build-output\dotnet-core-CSharp-extension\windows\release\packages\dotnet-core-CSharp-lang-extension.zip', FILE_NAME = 'nativecsharpextension.dll' ); 28 | GO 29 | 30 | -- Step 5: Create external libraries 31 | 32 | CREATE EXTERNAL LIBRARY regex 33 | FROM (CONTENT = '\language-extensions\dotnet-core-CSharp\sample\regex\pkg\obj\Debug\RegexSample.dll') 34 | WITH (LANGUAGE = 'Dotnet'); 35 | GO 36 | 37 | -- Step 6: Call the .NET Core C# class 38 | 39 | declare @rowsCount int 40 | declare @regexExpr varchar(200) 41 | set @regexExpr = N'[Cc]#' 42 | 43 | EXEC sp_execute_external_script 44 | @language = N'Dotnet' 45 | , @script = N'regex;UserExecutor.CSharpRegexExecutor' 46 | , @input_data_1 = N'SELECT * FROM testdata' 47 | , @params = N'@regexExpr varchar(200) OUTPUT, @rowsCount int OUTPUT' 48 | , @regexExpr = @regexExpr OUTPUT 49 | , @rowsCount = @rowsCount OUTPUT 50 | with result sets ((id int, text varchar(100))); 51 | 52 | select @rowsCount as rowsCount, @regexExpr as message 53 | print @rowsCount 54 | print @regexExpr 55 | 56 | -------------------------------------------------------------------------------- /language-extensions/python/include/PythonNamespace.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonNamespace.h 8 | // 9 | // Purpose: 10 | // Global class to keep the global python namespace 11 | // 12 | //************************************************************************************************* 13 | 14 | #pragma once 15 | #include "Common.h" 16 | 17 | //------------------------------------------------------------------------------------------------- 18 | // Description: 19 | // Global class storing the python namespace 20 | // 21 | class PythonNamespace 22 | { 23 | public: 24 | // Initialize this global class 25 | // 26 | static void Init(); 27 | 28 | // Cleanup this global class 29 | // 30 | static void Cleanup(); 31 | 32 | // Get the main python module 33 | // 34 | static boost::python::object &MainModule() { return sm_mainModule; } 35 | 36 | // Get the main python namespace 37 | // 38 | static boost::python::object& MainNamespace() { return sm_mainNamespace; } 39 | 40 | // Get the original path list 41 | // 42 | static boost::python::object& OriginalPath() { return sm_originalPath; } 43 | 44 | private: 45 | static boost::python::object sm_mainModule; // The boost python module, contains the namespace. 46 | 47 | // The underlying boost::python namespace, which contains all the python variables. 48 | // We execute any python scripts on this namespace. 49 | // 50 | static boost::python::object sm_mainNamespace; 51 | 52 | static boost::python::object sm_originalPath; // The original system python path 53 | }; 54 | -------------------------------------------------------------------------------- /language-extensions/java/src/JavaLibraryUtils.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: JavaLibraryUtils.cpp 6 | // 7 | // Purpose: 8 | // Cross-platform utility functions to handle library management for 9 | // the Java extension. 10 | // 11 | //********************************************************************* 12 | #include "JavaLibraryUtils.h" 13 | #include "JavaPathSettings.h" 14 | #include "Logger.h" 15 | 16 | using namespace std; 17 | 18 | //-------------------------------------------------------------------------------------------------- 19 | // Name: JavaLibraryUtils::GetLibrariesClassPath 20 | // 21 | // Description: 22 | // Gets the string to include in the classpath for external libraries. This is done by searching 23 | // for every file under the directory and adding it to the path. This is needed, because JVM expects 24 | // that the full path for jars in the class path. 25 | // 26 | // Notes: 27 | // First private libraries are added to the classpath then public libraries. 28 | // 29 | // Returns: 30 | // The classpath of all the jars in the library management directories 31 | // 32 | string JavaLibraryUtils::GetLibrariesClassPath() 33 | { 34 | string classPath = ""; 35 | 36 | // Check if private library path was sent from SQL Server. 37 | // 38 | const string & privateLibraryPath = JavaPathSettings::GetPrivateLibraryPath(); 39 | 40 | if (!privateLibraryPath.empty()) 41 | { 42 | FindAppendFileNames(privateLibraryPath, classPath); 43 | } 44 | 45 | // Check if the public library path was sent from SQL Server. 46 | // 47 | const string & publicLibraryPath = JavaPathSettings::GetPublicLibraryPath(); 48 | 49 | if (!publicLibraryPath.empty()) 50 | { 51 | FindAppendFileNames(publicLibraryPath, classPath); 52 | } 53 | 54 | return classPath; 55 | } 56 | -------------------------------------------------------------------------------- /language-extensions/R/include/Common.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: Common.h 22 | // 23 | // Purpose: 24 | // Common headers for RExtension. 25 | // 26 | //************************************************************************************************** 27 | 28 | #pragma once 29 | 30 | #ifdef _WIN64 31 | #include 32 | #endif 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | // Before including Rcpp headers, undefine ERROR if it is defined already since 43 | // R_ext/RS.h defines ERROR and we want to avoid redefinition warnings. 44 | // 45 | #ifdef ERROR 46 | #undef ERROR 47 | #endif 48 | #include "Rcpp.h" 49 | #include "RInside.h" // for the embedded R via RInside 50 | 51 | #include "Logger.h" 52 | #include "REnvironment.h" 53 | #include "RPathSettings.h" 54 | #include "Utilities.h" 55 | -------------------------------------------------------------------------------- /language-extensions/python/include/PythonPathSettings.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonPathSettings.h 8 | // 9 | // Purpose: 10 | // Global class to keep language runtime settings 11 | // 12 | //************************************************************************************************* 13 | 14 | #pragma once 15 | #include "Common.h" 16 | 17 | //------------------------------------------------------------------------------------------------- 18 | // Description: 19 | // Global class storing the language runtime paths and parameters 20 | // 21 | class PythonPathSettings 22 | { 23 | public: 24 | // Initialize this global class 25 | // 26 | static void Init( 27 | const SQLCHAR *languageParams, 28 | const SQLCHAR *languagePath, 29 | const SQLCHAR *publicLibraryPath, 30 | const SQLCHAR *privateLibraryPath); 31 | 32 | // Get the private library path sent by SQL Server 33 | // 34 | static const std::string& PrivateLibraryPath() { return sm_privateLibraryPath; } 35 | 36 | // Get the public library path sent by SQL Server 37 | // 38 | static const std::string& PublicLibraryPath() { return sm_publicLibraryPath; } 39 | 40 | // Get the extension root folder 41 | // 42 | static const std::string& RootPath() { return sm_languagePath; } 43 | 44 | // Get the language parameters sent by SQL Server 45 | // 46 | static const std::string& Params() { return sm_languageParams; } 47 | 48 | private: 49 | static std::string sm_languagePath; 50 | static std::string sm_languageParams; 51 | static std::string sm_privateLibraryPath; 52 | static std::string sm_publicLibraryPath; 53 | }; 54 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/src/managed/CSharpColumn.cs: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: CSharpColumn.cs 6 | // 7 | // Purpose: 8 | // Encapsulate data column attributes 9 | // 10 | //********************************************************************* 11 | using System; 12 | using System.Collections.Generic; 13 | using static Microsoft.SqlServer.CSharpExtension.Sql; 14 | 15 | namespace Microsoft.SqlServer.CSharpExtension 16 | { 17 | /// 18 | /// This class stores column meta data 19 | /// 20 | public class CSharpColumn 21 | { 22 | /// 23 | /// An integer identifying the index of this column. 24 | /// Columns are numbered sequentially in increasing order starting at 0. 25 | /// 26 | public ushort Id { get; set; } 27 | 28 | /// 29 | /// The name of this column. 30 | /// 31 | public string Name { get; set; } 32 | 33 | /// 34 | /// The maximum size in bytes of the underlying data in this column. 35 | /// 36 | public ulong Size { get; set; } 37 | 38 | /// 39 | /// The Sql data type of this column. 40 | /// 41 | public SqlDataType DataType { get; set; } 42 | 43 | /// 44 | /// A value that indicates whether this column may contain NULL values. 45 | /// SQL_NO_NULLS(0): The column cannot contain NULL values. 46 | /// SQL_NULLABLE(1): The column may contain NULL values. 47 | /// 48 | public short Nullable { get; set; } 49 | 50 | /// 51 | /// The decimal digits of underlying data in this column. 52 | /// 53 | public short DecimalDigits { get; set; } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /language-extensions/java/src/Logger.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: Logger.cpp 6 | // 7 | // Purpose: 8 | // Implementation of logging for the java extension. 9 | // 10 | //********************************************************************* 11 | #include "Logger.h" 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | //--------------------------------------------------------------------- 18 | // Name: LogError 19 | // 20 | // Description: 21 | // Log an error to stderr with format "TIMESTAMP Error: ". 22 | // 23 | void Logger::LogError(const string &errorMsg) 24 | { 25 | cerr << GetCurrentTimestamp() << "Error: " << errorMsg << endl; 26 | } 27 | 28 | //--------------------------------------------------------------------- 29 | // Name: LogJavaException 30 | // 31 | // Description: 32 | // Log a c++ exception to stderr with format "TIMESTAMP Exception 33 | // occurred: ". 34 | // 35 | void Logger::LogException(const exception &e) 36 | { 37 | cerr << GetCurrentTimestamp() << "Exception occurred: " << e.what() << endl; 38 | } 39 | 40 | //--------------------------------------------------------------------- 41 | // Name: LogJavaException 42 | // 43 | // Description: 44 | // Log a java exception to stderr with format "TIMESTAMP Exception 45 | // thrown in Java: ". 46 | // 47 | void Logger::LogJavaException(const string &exceptionMsg) 48 | { 49 | cerr << GetCurrentTimestamp() << "Exception occurred in Java: " << exceptionMsg << endl; 50 | } 51 | 52 | //--------------------------------------------------------------------- 53 | // Name: Log 54 | // 55 | // Description: 56 | // Log a message to stdout with format "TIMESTAMP ". 57 | // 58 | void Logger::Log(const string &msg) 59 | { 60 | #ifdef DEBUG 61 | cout << GetCurrentTimestamp() << msg << endl; 62 | #endif 63 | } 64 | -------------------------------------------------------------------------------- /language-extensions/java/src/linux/JavaLibraryUtils_linux.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: JavaLibraryUtils_linux.cpp 6 | // 7 | // Purpose: 8 | // Linux specific utility functions to handle library management 9 | // for the Java extension. 10 | // 11 | //********************************************************************* 12 | #include "JavaLibraryUtils.h" 13 | #include "JavaExtensionUtils.h" 14 | #include "Logger.h" 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | 20 | //---------------------------------------------------------------------------- 21 | // Name: JavaLibraryUtils::AppendFileNames 22 | // 23 | // Description: 24 | // Finds all files under the base directory and appends them to the output. 25 | // 26 | // Notes: 27 | // This function will silently fail if an error occurs, this is expected 28 | // because the query should attempt to continue. 29 | // 30 | // Returns: 31 | // none 32 | // 33 | void JavaLibraryUtils::FindAppendFileNames(const string &basePath, string &output) 34 | { 35 | DIR *directory = nullptr; 36 | struct dirent *entry = nullptr; 37 | 38 | directory = opendir(basePath.c_str()); 39 | if (directory != nullptr) 40 | { 41 | entry = readdir(directory); 42 | while (entry != nullptr) 43 | { 44 | string fileName = string(entry->d_name); 45 | 46 | if (fileName.compare("..") != 0 && fileName.compare(".") != 0) 47 | { 48 | // Add the separator if needed. 49 | // 50 | if (!output.empty()) 51 | { 52 | output += JavaExtensionUtils::GetClassPathSeparator(); 53 | } 54 | 55 | output += basePath + "/" + fileName; 56 | } 57 | 58 | // Get next entry 59 | // 60 | entry = readdir(directory); 61 | } 62 | 63 | closedir(directory); 64 | } 65 | else 66 | { 67 | string msg = "Error opening library directory " + basePath; 68 | LOG_ERROR(msg); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /language-extensions/python/include/PythonExtensionUtils.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonExtensionUtils.h 8 | // 9 | // Purpose: 10 | // Platform specific utility functions for Python Extension 11 | // 12 | //************************************************************************************************* 13 | 14 | #pragma once 15 | #include "Common.h" 16 | #include 17 | 18 | class PythonExtensionUtils 19 | { 20 | public: 21 | 22 | // Parses the value of the active python exception 23 | // Type, value, and traceback are in separate pointers 24 | // 25 | static std::string ParsePythonException(); 26 | 27 | // Extract the string from a boost::python object or PyObject* 28 | // 29 | static std::string ExtractString(PyObject *pObj); 30 | static std::string ExtractString(boost::python::object handle); 31 | 32 | // Get the value of an environment variable 33 | // 34 | static std::string GetEnvVariable(const std::string &envVarName); 35 | 36 | // Normalize path strings from \ to / 37 | // 38 | static std::string NormalizePathString(std::string pathString); 39 | 40 | // Check if bitValue is True or not 41 | // 42 | static bool IsBitTrue(SQLCHAR bitValue); 43 | 44 | // Converts a SQLGUID to a string 45 | // 46 | static std::string ConvertGuidToString(const SQLGUID *guid); 47 | 48 | // Close an open dll handle 49 | // 50 | static void FreeDLL(void *pDll); 51 | 52 | // Get the path to the python executable 53 | // 54 | static std::string GetPathToPython(); 55 | 56 | // Map to store the ODBC C type to null value mapping 57 | // 58 | static const std::unordered_map sm_DataTypeToNullMap; 59 | }; 60 | -------------------------------------------------------------------------------- /language-extensions/python/test/build/linux/run-pythonextension-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function check_exit_code { 4 | EXIT_CODE=$? 5 | if [ ${EXIT_CODE} -eq 0 ]; then 6 | echo $1 7 | else 8 | echo $2 9 | exit ${EXIT_CODE} 10 | fi 11 | } 12 | 13 | function build { 14 | # Set cmake config to first arg 15 | # 16 | CMAKE_CONFIGURATION=$1 17 | if [ -z "${CMAKE_CONFIGURATION}" ]; then 18 | CMAKE_CONFIGURATION=release 19 | fi 20 | 21 | pushd ${PYTHONEXTENSIONTEST_WORKING_DIR}/${CMAKE_CONFIGURATION} 22 | 23 | # Move the generated libs to configuration folder 24 | # 25 | cp ${PYTHONEXTENSION_WORKING_DIR}/${CMAKE_CONFIGURATION}/libPythonExtension.so.1.2 . 26 | cp /usr/src/gtest/*.so . 27 | 28 | ENL_ROOT=${ENL_ROOT} ./pythonextension-test --gtest_output=xml:${ENL_ROOT}/out/TestReport_PythonExtension-test.xml 29 | 30 | # Check the exit code of the tests. 31 | # 32 | check_exit_code "Success: Ran pythonextension-test" "Error: pythonextension-test failed" 33 | 34 | popd 35 | } 36 | 37 | # Enlistment root and location of pythonextension-test 38 | # 39 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 40 | ENL_ROOT=${SCRIPTDIR}/../../../../.. 41 | PYTHONEXTENSION_WORKING_DIR=${ENL_ROOT}/build-output/pythonextension/linux 42 | PYTHONEXTENSIONTEST_WORKING_DIR=${ENL_ROOT}/build-output/pythonextension-test/linux 43 | PACKAGES_ROOT=${ENL_ROOT}/packages 44 | DEFAULT_PYTHONHOME=/usr 45 | 46 | # Find PYTHONHOME from user, or set to default for tests. 47 | # Error code 1 is generic bash error. 48 | # 49 | if [ -z "${PYTHONHOME}" ]; then 50 | if [ -x "${DEFAULT_PYTHONHOME}" ]; then 51 | PYTHONHOME=${DEFAULT_PYTHONHOME} 52 | else 53 | echo "PYTHONHOME is empty" 54 | exit 1 55 | fi 56 | fi 57 | 58 | echo "Python home is ${PYTHONHOME}" 59 | 60 | # Build in release mode if nothing is specified 61 | # 62 | if [ "$1" == "" ]; then 63 | set -- release 64 | fi 65 | 66 | while [ "$1" != "" ]; do 67 | # Advance arg passed to build.cmd 68 | # 69 | build $1 70 | shift 71 | done; 72 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/src/managed/sdk/AbstractSqlServerExtensionExecutor.cs: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: AbstractSqlServerExtensionExecutor.cs 6 | // 7 | // Purpose: 8 | // Abstract class containing interface used by the .NET Core C# extension 9 | // 10 | //********************************************************************* 11 | using System.Collections.Generic; 12 | using Microsoft.Data.Analysis; 13 | 14 | namespace Microsoft.SqlServer.CSharpExtension.SDK 15 | { 16 | /// 17 | /// Abstract class containing interface used by the .NET Core C# extension 18 | /// 19 | public abstract class AbstractSqlServerExtensionExecutor 20 | { 21 | /// 22 | /// Supported versions of the .NET Core C# extension 23 | /// 24 | public readonly int SQLSERVER_DOTNET_LANG_EXTENSION_V1 = 1; 25 | 26 | /// 27 | /// Default constructor for AbstractSqlServerExtensionExecutor 28 | /// 29 | public AbstractSqlServerExtensionExecutor() {} 30 | 31 | /// 32 | /// Default implementation of init() is no-op 33 | /// 34 | public virtual void Init(string sessionId, int taskId, int numTasks) {} 35 | 36 | /// 37 | /// User execute method 38 | /// 39 | /// 40 | /// A Dataframe containing all the input columns 41 | /// 42 | /// 43 | /// A Dictionary containing all the parameters with name as the key 44 | /// 45 | public abstract DataFrame Execute(DataFrame input, Dictionary sqlParams); 46 | 47 | /// 48 | /// Default implementation of cleanup() is no-op 49 | /// 50 | public virtual void Cleanup() {} 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /language-extensions/R/test/include/Common.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension-test : Executable testing language extension that implements the SQL Server 3 | // external language communication protocol. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | 6 | // This file is part of RExtension-test. 7 | 8 | // RExtension-test is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // RExtension-test is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension-test. If not, see . 20 | 21 | // @File: Common.h 22 | // 23 | // Purpose: 24 | // Common headers for RExtenion-test. 25 | // 26 | //************************************************************************************************** 27 | 28 | #pragma once 29 | 30 | #ifdef _WIN64 31 | #include 32 | #include 33 | #else 34 | #include 35 | #include 36 | #endif 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "gtest/gtest.h" 46 | 47 | // Before including Rcpp headers, undefine ERROR if it is defined already since 48 | // R_ext/RS.h defines ERROR and we want to avoid redefinition warnings. 49 | // 50 | #ifdef ERROR 51 | #undef ERROR 52 | #endif 53 | #include "Rcpp.h" 54 | #include "RInside.h" 55 | 56 | #define TOTAL_NUMBER_OF_TEST_SUITES 2 57 | 58 | #include "RExtensionApiTests.h" 59 | #include "Unicode.h" 60 | #include "Utilities.h" 61 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/src/managed/utils/DataSetUtils.cs: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: DataSetUtils.cs 6 | // 7 | // Purpose: 8 | // Provides methods needed for Input/Output DataSet 9 | // 10 | //********************************************************************* 11 | using System; 12 | 13 | namespace Microsoft.SqlServer.CSharpExtension 14 | { 15 | /// 16 | /// This class contains methods needed for Input/Output DataSet 17 | /// 18 | internal class DataSetUtils 19 | { 20 | /// 21 | /// This method splits a string to an array of substring according to lengths. 22 | /// 23 | /// 24 | /// The string to be split 25 | /// 26 | /// 27 | /// An array of integers representing the lengths 28 | /// 29 | public static string[] StringSplitToArray(string str, int[] strLens) 30 | { 31 | string[] strArray = new string[strLens.Length]; 32 | 33 | // Return empty string list if the string is null 34 | // 35 | if(str == null) 36 | { 37 | return strArray; 38 | } 39 | 40 | int startIndex = 0; 41 | for (int i = 0; i < strLens.Length; ++i) 42 | { 43 | if(strLens[i] == -1) 44 | { 45 | strArray[i] = null; 46 | continue; 47 | } 48 | 49 | if(startIndex + strLens[i] > str.Length) 50 | { 51 | strArray[i] = str.Substring(startIndex); 52 | break; 53 | } 54 | 55 | strArray[i] = str.Substring(startIndex, strLens[i]); 56 | startIndex += strLens[i]; 57 | } 58 | 59 | return strArray; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /language-extensions/R/test/build/windows/run-RExtension-test.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | REM Set environment variables 5 | REM 6 | SET ENL_ROOT=%~dp0..\..\..\..\.. 7 | SET REXTENSIONTEST_WORKING_DIR=%ENL_ROOT%\build-output\RExtension-test\windows 8 | SET REXTENSION_WORKING_DIR=%ENL_ROOT%\build-output\RExtension\windows 9 | SET PACKAGES_ROOT=%ENL_ROOT%\packages 10 | SET GTEST_HOME=%PACKAGES_ROOT%\Microsoft.googletest.v140.windesktop.msvcstl.dyn.rt-dyn.1.8.1.3 11 | SET GTEST_LIB_PATH=%GTEST_HOME%\lib\native\v140\windesktop\msvcstl\dyn\rt-dyn\x64 12 | 13 | SET DEFAULT_R_HOME=%PACKAGES_ROOT%\R-4.0.5-win 14 | 15 | REM Find R_HOME from user, or set to default. 16 | REM Error code 203 is ENVVAR_NOT_FOUND. 17 | REM 18 | SET ENVVAR_NOT_FOUND=203 19 | 20 | IF "%R_HOME%" == "" ( 21 | IF EXIST %DEFAULT_R_HOME% ( 22 | SET R_HOME=%DEFAULT_R_HOME% 23 | ) ELSE ( 24 | CALL :CHECKERROR %ENVVAR_NOT_FOUND% "Error: R_HOME variable must be set to run RExtension-test" || EXIT /b %ENVVAR_NOT_FOUND% 25 | ) 26 | ) 27 | 28 | :LOOP 29 | 30 | REM Set cmake config to first arg 31 | REM 32 | SET CMAKE_CONFIGURATION=%1 33 | 34 | REM *Setting CMAKE_CONFIGURATION to anything but "debug" will set MSVC_BUILD_CONFIGURATION to "release". 35 | REM The string comparison for CMAKE_CONFIGURATION is case-insensitive. 36 | REM 37 | IF NOT DEFINED CMAKE_CONFIGURATION (SET CMAKE_CONFIGURATION=release) 38 | IF /I %CMAKE_CONFIGURATION%==debug (SET MSVC_BUILD_CONFIGURATION=debug) ELSE (SET MSVC_BUILD_CONFIGURATION=release) 39 | 40 | pushd %REXTENSIONTEST_WORKING_DIR%\%MSVC_BUILD_CONFIGURATION% 41 | copy %REXTENSION_WORKING_DIR%\%MSVC_BUILD_CONFIGURATION%\libRExtension.dll . 42 | copy %GTEST_LIB_PATH%\debug\gtest.dll . 43 | SET PATH=%R_HOME%\bin\x64;%PATH% 44 | RExtension-test.exe --gtest_output=xml:%ENL_ROOT%\out\TestReport_RExtension-test.xml 45 | IF %ERRORLEVEL% NEQ 0 GOTO error 46 | popd 47 | 48 | REM Advance arg passed to build-RExtension-test.cmd 49 | REM 50 | SHIFT 51 | 52 | REM Continue running using more configs until argv has been exhausted 53 | REM 54 | IF NOT "%~1"=="" GOTO LOOP 55 | 56 | :error 57 | EXIT /b %ERRORLEVEL% 58 | 59 | :USAGE 60 | echo. 61 | echo Usage: 62 | echo %0 { debug ^| release } 63 | -------------------------------------------------------------------------------- /language-extensions/java/src/windows/JavaLibraryUtils_win.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: JavaLibraryUtils_win.cpp 6 | // 7 | // Purpose: 8 | // Windows specific utility functions to handle library management 9 | // for the Java extension. 10 | // 11 | //********************************************************************* 12 | #include "JavaLibraryUtils.h" 13 | #include "JavaExtensionUtils.h" 14 | 15 | using namespace std; 16 | 17 | //---------------------------------------------------------------------------- 18 | // Name: JavaLibraryUtils::AppendFileNames 19 | // 20 | // Description: 21 | // Finds all files under the base directory and appends them to the output. 22 | // 23 | // Notes: 24 | // This function will silently fail if an error occurs, this is expected 25 | // because the query should attempt to continue. 26 | // 27 | // Returns: 28 | // none 29 | // 30 | void JavaLibraryUtils::FindAppendFileNames(const string &basePath, string &output) 31 | { 32 | // String to indicate we should find all files under this directory 33 | // 34 | string wildCard = basePath + "\\*"; 35 | 36 | HRESULT hr = S_OK; 37 | WIN32_FIND_DATAA ffa; 38 | HANDLE hFind = INVALID_HANDLE_VALUE; 39 | 40 | // Find the first file in the directory. 41 | // 42 | if (SUCCEEDED(hr)) 43 | { 44 | hFind = FindFirstFileA(wildCard.c_str(), &ffa); 45 | if (INVALID_HANDLE_VALUE == hFind) 46 | { 47 | hr = HRESULT_FROM_WIN32(GetLastError()); 48 | } 49 | } 50 | 51 | // Loop through each file in the folder which represents a library, and delete it. 52 | // 53 | if (SUCCEEDED(hr)) 54 | { 55 | do 56 | { 57 | // Skip over the entry for the current directory 58 | // 59 | if (ffa.cFileName[0] == '.') 60 | { 61 | continue; 62 | } 63 | 64 | // Add the separator if needed. 65 | // 66 | if (!output.empty()) 67 | { 68 | output += JavaExtensionUtils::GetClassPathSeparator(); 69 | } 70 | 71 | output += basePath + "\\" + string(ffa.cFileName); 72 | } while (FindNextFileA(hFind, &ffa) != 0); 73 | 74 | FindClose(hFind); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/build/windows/create-dotnet-core-CSharp-extension-zip.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | SET ENL_ROOT=%~dp0..\..\..\.. 5 | SET DOTNET_EXTENSION_WORKING_DIR=%ENL_ROOT%\build-output\dotnet-core-CSharp-extension\windows 6 | 7 | :LOOP 8 | 9 | REM Set build config to first arg 10 | REM 11 | SET BUILD_CONFIGURATION=%1 12 | 13 | REM Setting BUILD_CONFIGURATION to anything but "debug" will set BUILD_CONFIGURATION to "release". 14 | REM The string comparison for BUILD_CONFIGURATION is case-insensitive. 15 | REM 16 | IF NOT DEFINED BUILD_CONFIGURATION (SET BUILD_CONFIGURATION=release) 17 | IF /I NOT %BUILD_CONFIGURATION%==debug (SET BUILD_CONFIGURATION=release) 18 | 19 | SET BUILD_OUTPUT=%DOTNET_EXTENSION_WORKING_DIR%\%BUILD_CONFIGURATION% 20 | 21 | MKDIR %BUILD_OUTPUT%\packages 22 | 23 | REM Delete the ref folder so that the zip can be loaded by the SPEES 24 | REM 25 | RD /S /Q %BUILD_OUTPUT%\ref 26 | POPD 27 | 28 | REM Define files to compress, conditionally including .pdb files if BUILD_CONFIGURATION is "debug" 29 | REM 30 | SET FILES_TO_COMPRESS=%BUILD_OUTPUT%\*.dll, %BUILD_OUTPUT%\Microsoft.SqlServer.CSharpExtension.runtimeconfig.json, %BUILD_OUTPUT%\Microsoft.SqlServer.CSharpExtension.deps.json 31 | IF /I "%BUILD_CONFIGURATION%"=="debug" (SET FILES_TO_COMPRESS=%FILES_TO_COMPRESS%, %BUILD_OUTPUT%\*.pdb) 32 | 33 | REM Package the signed binaries. 34 | REM 35 | powershell -NoProfile -ExecutionPolicy Unrestricted ^ 36 | -Command "Compress-Archive -Force -Path %FILES_TO_COMPRESS%" ^ 37 | "-DestinationPath %BUILD_OUTPUT%\packages\dotnet-core-CSharp-lang-extension.zip" 38 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to create zip for dotnet-core-CSharp-extension for configuration=%BUILD_CONFIGURATION%" || EXIT /b %ERRORLEVEL% 39 | 40 | ECHO "Success: Compressed dotnet-core-CSharp-extension for %BUILD_CONFIGURATION% configuration." 41 | 42 | REM Advance arg passed to create-dotnet-core-CSharp-extension-zip.cmd 43 | REM 44 | SHIFT 45 | REM Continue building using more configs until argv has been exhausted 46 | REM 47 | IF NOT "%~1"=="" GOTO LOOP 48 | 49 | EXIT /b %ERRORLEVEL% 50 | 51 | :CHECKERROR 52 | IF %1 NEQ 0 ( 53 | ECHO %2 54 | EXIT /b %1 55 | ) 56 | EXIT /b 0 57 | -------------------------------------------------------------------------------- /language-extensions/java/samples/regex/readme.md: -------------------------------------------------------------------------------- 1 | # Regex sample 2 | 3 | This sample shows you how to use SQL Server Language Extensions to create a Java program that receives two columns (ID and text) from SQL Server and a regular expression as an input parameter. The class returns two columns back to SQL Server (ID and text). 4 | 5 | For a given text in the text column sent to the Java program, the code checks if the given regular expression is fulfilled, and if it is fulfilled, it returns that text together with the original ID. 6 | 7 | This particular sample uses a regular expression that checks if a text contains the word "Java" or "java". 8 | 9 | ## Sample files 10 | 11 | * RegexSample.Java - This is the class containing the Java code that will be invoked from SQL Server 12 | * java-regex-linux.sql and java-regex-win.sql - SQL file containing T-SQL script for configuring and creating test data and calling the Java sample program. 13 | 14 | ## Prerequisites 15 | 16 | + SQL Server 2019 Database Engine instance with the extensibility framework and Java programming extension. [Installation guide](https://docs.microsoft.com/en-us/sql/language-extensions/install/install-sql-server-language-extensions-on-windows?view=sqlallproducts-allversions). 17 | 18 | + SQL Server Management Studio or Azure Data Studio for executing T-SQL. 19 | 20 | + Java SE Development Kit (JDK) 8 or JRE 8 on Windows or Linux. 21 | 22 | + Command-line compilation using **javac** is sufficient for this sample. 23 | 24 | ### Compiling a class file 25 | 26 | The class file can be created using the command-line compiler **javac**. For this sample, create a folder containing the RegexSample.java file. 27 | 28 | To create the class files, navigate to the folder containing your java file and run this command: 29 | 30 | ```cmd 31 | javac -cp *.java 32 | ``` 33 | 34 | ### Creating a jar file 35 | 36 | When using this sample and executing a Java code from SQL Server, we recommend packaging your class files into a jar file. 37 | 38 | To create a jar from class files, navigate to the parent folder of the location that contains the class file and run this command: 39 | 40 | ```cmd 41 | jar -cf folder/*.class 42 | ``` 43 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/src/managed/CSharpParam.cs: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: CSharpParam.cs 6 | // 7 | // Purpose: 8 | // Classes storing information about input/output parameter. 9 | // 10 | //********************************************************************* 11 | using System; 12 | using System.Collections.Generic; 13 | using static Microsoft.SqlServer.CSharpExtension.Sql; 14 | 15 | namespace Microsoft.SqlServer.CSharpExtension 16 | { 17 | /// 18 | /// This class stores input/output parameter. 19 | /// 20 | public class CSharpParam 21 | { 22 | /// 23 | /// An integer identifying the index of this parameter. 24 | /// 25 | public ushort Number { get; set; } 26 | 27 | /// 28 | /// Null-terminated UTF-8 string containing the parameter's name. 29 | /// 30 | public string Name { get; set; } 31 | 32 | /// 33 | /// The maximum size in bytes of the underlying data in this parameter. 34 | /// 35 | public ulong Size { get; set; } 36 | 37 | /// 38 | /// The Sql data type identifying this parameter's data type. 39 | /// 40 | public SqlDataType DataType { get; set; } 41 | 42 | /// 43 | /// The parameter's value. 44 | /// 45 | public dynamic Value { get; set; } 46 | 47 | /// 48 | /// The decimal digits of underlying data in this parameter 49 | /// 50 | public short DecimalDigits { get; set; } 51 | 52 | /// 53 | /// An integer value indicating the length in bytes 54 | /// of ParamValue, or SQL_NULL_DATA(-1) to indicate that the data is NULL. 55 | /// 56 | public int StrLenOrNullMap { get; set; } 57 | 58 | /// 59 | /// The type of the parameter. 60 | /// 61 | public short InputOutputType { get; set; } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /language-extensions/python/src/PythonPathSettings.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonPathSettings.cpp 8 | // 9 | // Purpose: 10 | // Global class to keep language runtime settings 11 | // 12 | //************************************************************************************************* 13 | 14 | #include "PythonPathSettings.h" 15 | #include "PythonExtensionUtils.h" 16 | 17 | //------------------------------------------------------------------------------------------------- 18 | // Name: PythonPathSettings::Init 19 | // 20 | // Description: 21 | // Initialize the class 22 | // 23 | void 24 | PythonPathSettings::Init( 25 | const SQLCHAR *languageParams, 26 | const SQLCHAR *languagePath, 27 | const SQLCHAR *publicLibraryPath, 28 | const SQLCHAR *privateLibraryPath) 29 | { 30 | // nullptrs are mapped to empty strings - has the same effect when 31 | // the paths are used and avoids an additional flag. 32 | // 33 | sm_languageParams = 34 | (languageParams == nullptr) ? "" : reinterpret_cast(languageParams); 35 | 36 | sm_languagePath = 37 | (languagePath == nullptr) ? "" : reinterpret_cast(languagePath); 38 | 39 | sm_publicLibraryPath = 40 | (publicLibraryPath == nullptr) ? "" : reinterpret_cast(publicLibraryPath); 41 | 42 | sm_privateLibraryPath = 43 | (privateLibraryPath == nullptr) ? "" : reinterpret_cast(privateLibraryPath); 44 | 45 | // Remove single slashes and replace with forward slashes in the paths 46 | // 47 | sm_languagePath = PythonExtensionUtils::NormalizePathString(sm_languagePath); 48 | sm_privateLibraryPath = PythonExtensionUtils::NormalizePathString(sm_privateLibraryPath); 49 | sm_publicLibraryPath = PythonExtensionUtils::NormalizePathString(sm_publicLibraryPath); 50 | } 51 | 52 | std::string PythonPathSettings::sm_languageParams; 53 | std::string PythonPathSettings::sm_languagePath; 54 | std::string PythonPathSettings::sm_privateLibraryPath; 55 | std::string PythonPathSettings::sm_publicLibraryPath; 56 | -------------------------------------------------------------------------------- /language-extensions/R/include/Logger.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: Logger.h 22 | // 23 | // Purpose: 24 | // Wrapper class around logging to standardize logging messages and errors. 25 | // 26 | //************************************************************************************************** 27 | 28 | #pragma once 29 | 30 | #define LOG(msg) Logger::Log(msg) 31 | #define LOG_ERROR(msg) Logger::LogError(msg) 32 | #define LOG_EXCEPTION(e) Logger::LogException(e) 33 | 34 | class Logger 35 | { 36 | public: 37 | 38 | // Logs an error to stderr 39 | // 40 | static void LogError(const std::string &errorMsg); 41 | 42 | // Logs an extension exception to stderr 43 | // 44 | static void LogException(const std::exception &e); 45 | 46 | // Logs a message to stdout 47 | // 48 | static void Log(const std::string &errorMsg); 49 | 50 | // Logs an R variable using R's print function 51 | // 52 | static void LogRVariable(const std::string &name); 53 | 54 | private: 55 | 56 | // Logs the message to stderr 57 | // 58 | static void LogToStdErr(const std::string &errorMsgWithTimestamp); 59 | 60 | // Gets a string of the current timestamp in the same format 61 | // of SQL format 62 | // 63 | static const char* GetCurrentTimestamp(); 64 | 65 | // Buffer to hold the timestamp string. 66 | // 67 | static char sm_timestampBuffer[]; 68 | }; 69 | -------------------------------------------------------------------------------- /language-extensions/java/src/JniHelper.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: JniHelper.cpp 6 | // 7 | // Purpose: 8 | // Wrappers around commonly used JNI functions 9 | // 10 | //********************************************************************* 11 | #include "JniHelper.h" 12 | #include "Logger.h" 13 | 14 | using namespace std; 15 | 16 | //-------------------------------------------------------------------------------------------------- 17 | // Name: JniHelper::ThrownOnJavaException 18 | // 19 | // Description: 20 | // Throw exception when a Java exception has occurred. 21 | // 22 | void JniHelper::ThrowOnJavaException(JNIEnv *env) 23 | { 24 | ThrowOnJavaException(env, ""); 25 | } 26 | 27 | //-------------------------------------------------------------------------------------------------- 28 | // Name: JniHelper::ThrownOnJavaException 29 | // 30 | // Description: 31 | // Throw exception with the provided error message when a Java exception has occurred. 32 | // 33 | void JniHelper::ThrowOnJavaException(JNIEnv *env, string &&errorMsg) 34 | { 35 | jboolean isException = env->ExceptionCheck(); 36 | 37 | if (isException == JNI_TRUE) 38 | { 39 | throw java_exception_error(errorMsg); 40 | } 41 | } 42 | 43 | //-------------------------------------------------------------------------------------------------- 44 | // Name: JniHelper::LogJavaException 45 | // 46 | // Description: 47 | // Logs the Java exception if one has occurred 48 | // 49 | void JniHelper::LogJavaException(JNIEnv *env) 50 | { 51 | jboolean isException = env->ExceptionCheck(); 52 | 53 | if (isException == JNI_TRUE) 54 | { 55 | env->ExceptionDescribe(); 56 | env->ExceptionClear(); 57 | } 58 | } 59 | 60 | //-------------------------------------------------------------------------------------------------- 61 | // Name: JniHelper::FindMethod 62 | // 63 | // Description: 64 | // Attempts to finds a Java method through JNI 65 | // 66 | jmethodID JniHelper::FindMethod( 67 | JNIEnv *env, 68 | jclass jClass, 69 | const string &funcName, 70 | const string &funcSignature) 71 | { 72 | jmethodID result = env->GetMethodID( 73 | jClass, 74 | funcName.c_str(), 75 | funcSignature.c_str()); 76 | 77 | ThrowOnJavaException(env); 78 | 79 | return result; 80 | } 81 | -------------------------------------------------------------------------------- /language-extensions/R/build/linux/restore-packages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function check_exit_code { 4 | EXIT_CODE=$? 5 | if [ ${EXIT_CODE} -eq 0 ]; then 6 | echo $1 7 | else 8 | echo $2 9 | exit ${EXIT_CODE} 10 | fi 11 | } 12 | 13 | export DEBIAN_FRONTEND=noninteractive 14 | apt-get update 15 | apt-get --no-install-recommends -y install curl zip unzip apt-transport-https libstdc++6 16 | 17 | # Install development libraries needed for R extension compilation 18 | apt-get --no-install-recommends -y install libpcre3-dev liblzma-dev libbz2-dev zlib1g-dev 19 | 20 | # Add R CRAN repository. 21 | # 22 | LSB_RELEASE=$(lsb_release -cs) 23 | curl -fsSL https://cloud.r-project.org/bin/linux/ubuntu/marutter_pubkey.asc | gpg --dearmor -o /usr/share/keyrings/r-project.gpg 24 | echo "deb [signed-by=/usr/share/keyrings/r-project.gpg] https://cloud.r-project.org/bin/linux/ubuntu ${LSB_RELEASE}-cran40/" > /etc/apt/sources.list.d/r-project.list 25 | apt-get update 26 | 27 | # Install R runtime. 28 | # 29 | apt-get --no-install-recommends -y install r-base-core 30 | check_exit_code "Success: Installed R runtime." "Error: Failed to install R runtime." 31 | 32 | DEFAULT_R_HOME=/usr/lib/R 33 | 34 | # Find R_HOME from user, or set to default for installing Rcpp and RInside. 35 | # Error code 1 is generic bash error. 36 | # 37 | if [ -z "${R_HOME}" ]; then 38 | if [ -d "${DEFAULT_R_HOME}" ]; then 39 | R_HOME=${DEFAULT_R_HOME} 40 | else 41 | echo "R_HOME is empty" 42 | exit 1 43 | fi 44 | fi 45 | R_LIBRARY_PATH=${R_HOME}/library 46 | 47 | # Remove codetools from default library so it doesn't interfere with Rcpp installation below. 48 | # 49 | ${R_HOME}/bin/R -e "remove.packages('codetools', lib = '${R_LIBRARY_PATH}')" 50 | 51 | # Install Rcpp. 52 | # 53 | ${R_HOME}/bin/R -e "install.packages('https://cran.r-project.org/src/contrib/Archive/Rcpp/Rcpp_1.0.13.tar.gz', lib = '${R_LIBRARY_PATH}', repos = NULL, type='source')" 54 | ${R_HOME}/bin/R -e "stopifnot(require(Rcpp))" 55 | check_exit_code "Success: Installed Rcpp package." "Error: Failed to install Rcpp package." 56 | 57 | # Install RInside. 58 | # 59 | ${R_HOME}/bin/R -e "install.packages('https://cran.r-project.org/src/contrib/Archive/RInside/RInside_0.2.15.tar.gz', lib = '${R_LIBRARY_PATH}', repos = NULL, , type='source')" 60 | ${R_HOME}/bin/R -e "stopifnot(require(RInside))" 61 | check_exit_code "Success: Installed RInside package." "Error: Failed to install RInside package." 62 | 63 | exit $? 64 | -------------------------------------------------------------------------------- /language-extensions/R/src/RColumn.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: RColumn.cpp 22 | // 23 | // Purpose: 24 | // Class encapsulating a DataSet's column attributes 25 | // 26 | //************************************************************************************************** 27 | 28 | #include "Common.h" 29 | #include "RColumn.h" 30 | 31 | using namespace std; 32 | 33 | //-------------------------------------------------------------------------------------------------- 34 | // Name: RColumn::RColumn 35 | // 36 | // Description: 37 | // The constructor assigning the given column information to members. 38 | // 39 | RColumn::RColumn( 40 | const SQLCHAR *columnName, 41 | SQLSMALLINT columnNameLength, 42 | SQLSMALLINT dataType, 43 | SQLULEN columnSize, 44 | SQLSMALLINT decimalDigits, 45 | SQLSMALLINT nullable) 46 | { 47 | const char *name = static_cast( 48 | static_cast(columnName)); 49 | 50 | // columnNameLength does not include the null terminator. 51 | // 52 | #if defined(_DEBUG) 53 | if (static_cast(columnNameLength) != strlen(name)) 54 | { 55 | throw invalid_argument("Invalid column name length, it doesn't match string length."); 56 | } 57 | #endif 58 | 59 | // Store the information for this column 60 | // 61 | m_name = string(name, columnNameLength); 62 | m_dataType = dataType; 63 | m_size = columnSize; 64 | m_decimalDigits = decimalDigits; 65 | m_nullable = nullable; 66 | } 67 | -------------------------------------------------------------------------------- /language-extensions/java/include/JniHelper.h: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: JniHelper.h 6 | // 7 | // Purpose: 8 | // Wrappers around commonly used JNI functions 9 | // 10 | //********************************************************************* 11 | #pragma once 12 | 13 | #include "Common.h" 14 | #include 15 | 16 | //--------------------------------------------------------------------- 17 | // Description: 18 | // Wrapper class around commonly used JNI functions 19 | // 20 | class JniHelper 21 | { 22 | public: 23 | // Checks if an Java exception occurred and throws an exception 24 | // 25 | static void ThrowOnJavaException(JNIEnv *env); 26 | 27 | // Checks if an Java exception occurred and throws an exception 28 | // 29 | static void ThrowOnJavaException(JNIEnv *env, std::string &&errorMsg); 30 | 31 | // Logs the Java exception 32 | // 33 | static void LogJavaException(JNIEnv *env); 34 | 35 | // Finds the method ID for the class, name, and signature 36 | // 37 | static jmethodID FindMethod( 38 | JNIEnv *env, 39 | jclass jClass, 40 | const std::string &funcName, 41 | const std::string &funcSignature); 42 | }; 43 | 44 | //--------------------------------------------------------------------- 45 | // Description: 46 | // In JNI, local references are associated with the current local frame, 47 | // when call native code from Java these are created and managed automatically. 48 | // But when calling Java from native, there is no local frame created by default. 49 | // This class manages a local frame pushing and popping, when this object is 50 | // destroyed all the JNI local references created during the lifetime of this 51 | // object are released. 52 | // 53 | class AutoJniLocalFrame 54 | { 55 | public: 56 | AutoJniLocalFrame(JNIEnv *env, jint capacity) 57 | { 58 | assert(env != nullptr); 59 | 60 | m_env = env; 61 | 62 | m_env->PushLocalFrame(capacity); 63 | } 64 | 65 | ~AutoJniLocalFrame() 66 | { 67 | m_env->PopLocalFrame(nullptr); 68 | } 69 | 70 | private: 71 | JNIEnv *m_env; 72 | }; 73 | 74 | //--------------------------------------------------------------------- 75 | // Description: 76 | // Specific runtime exception indicating a Java exception has occurred 77 | // 78 | class java_exception_error : public std::runtime_error 79 | { 80 | using runtime_error::runtime_error; 81 | }; 82 | -------------------------------------------------------------------------------- /test/googletest/build/windows/build-googletest.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | SET ENL_ROOT=%~dp0..\..\..\.. 5 | SET PACKAGES_ROOT=%ENL_ROOT%\packages 6 | SET CMAKE_ROOT=%PACKAGES_ROOT%\CMake-win64.3.15.5 7 | SET GTEST_HOME=%ENL_ROOT%\test\googletest 8 | SET BUILD_OUTPUT=%ENL_ROOT%\build-output\googletest\windows 9 | 10 | REM Call the root level restore-packages 11 | REM 12 | CALL %ENL_ROOT%\restore-packages.cmd 13 | 14 | REM Get RTools35 for mingw32-make and rtools40 for g++ v8.3.0 that works with C++17. 15 | REM 16 | SET RTOOLS_HOME=%PACKAGES_ROOT%\Rtools 17 | IF NOT EXIST %RTOOLS_HOME% ( 18 | MKDIR %RTOOLS_HOME% 19 | powershell -Command "Invoke-WebRequest https://cran.r-project.org/bin/windows/Rtools/Rtools35.exe -OutFile %RTOOLS_HOME%\Rtools35.exe" 20 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to download Rtools3.5." || EXIT /b %ERRORLEVEL% 21 | powershell -Command "Invoke-WebRequest https://cran.r-project.org/bin/windows/Rtools/rtools40-x86_64.exe -OutFile %RTOOLS_HOME%\rtools40.exe" 22 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to download Rtools4.0." || EXIT /b %ERRORLEVEL% 23 | REM Install RTools 24 | REM 25 | %RTOOLS_HOME%\Rtools35.exe /VERYSILENT /DIR="C:\Rtools\" 26 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to install Rtools3.5." || EXIT /b %ERRORLEVEL% 27 | %RTOOLS_HOME%\rtools40.exe /VERYSILENT /DIR="C:\rtools40\" 28 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to install Rtools4.0." || EXIT /b %ERRORLEVEL% 29 | ) 30 | 31 | RMDIR /s /q %BUILD_OUTPUT% 32 | MKDIR %BUILD_OUTPUT% 33 | PUSHD %BUILD_OUTPUT% 34 | 35 | REM Make sure g++, mingw32-make and R.dll are in the PATH. 36 | REM Do not enclose the C:\Rtools\mingw_64\bin path in quotes - cmake test fails 37 | REM 38 | SET PATH=C:\rtools40\mingw64\bin;C:\Rtools\mingw_64\bin;%R_HOME%\bin\x64;%PATH% 39 | 40 | CALL "%CMAKE_ROOT%\bin\cmake.exe" ^ 41 | -G "MinGW Makefiles" ^ 42 | -DCMAKE_MAKE_PROGRAM=mingw32-make ^ 43 | -DCMAKE_INSTALL_PREFIX:PATH=%BUILD_OUTPUT% ^ 44 | -DPLATFORM=windows ^ 45 | %GTEST_HOME%\src 46 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to configure googletest-framework || EXIT /b %ERRORLEVEL% 47 | 48 | REM Call build 49 | REM 50 | CALL "mingw32-make.exe" all 51 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to build googletest-framework." || EXIT /b %ERRORLEVEL% 52 | 53 | REM Continue building using more configs until argv has been exhausted 54 | REM 55 | IF NOT "%~1"=="" GOTO LOOP 56 | 57 | EXIT /b %ERRORLEVEL% 58 | 59 | :CHECKERROR 60 | IF %1 NEQ 0 ( 61 | ECHO %2 62 | EXIT /b %1 63 | ) 64 | 65 | EXIT /b 0 66 | -------------------------------------------------------------------------------- /language-extensions/R/include/RColumn.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: RColumn.h 22 | // 23 | // Purpose: 24 | // Class encapsulating a dataset's column attributes. 25 | // 26 | //************************************************************************************************** 27 | 28 | #pragma once 29 | 30 | //-------------------------------------------------------------------------------------------------- 31 | // Name: RColumn 32 | // 33 | // Description: 34 | // Class encapsulating a dataset's column attributes. 35 | // 36 | class RColumn 37 | { 38 | public: 39 | 40 | RColumn( 41 | const SQLCHAR *columnName, 42 | SQLSMALLINT columnNameLength, 43 | SQLSMALLINT dataType, 44 | SQLULEN columnSize, 45 | SQLSMALLINT decimalDigits, 46 | SQLSMALLINT nullable); 47 | 48 | const std::string& Name() const 49 | { 50 | return m_name; 51 | } 52 | 53 | SQLSMALLINT DataType() const 54 | { 55 | return m_dataType; 56 | } 57 | 58 | SQLULEN Size() const 59 | { 60 | return m_size; 61 | } 62 | 63 | SQLSMALLINT Nullable() const 64 | { 65 | return m_nullable; 66 | } 67 | 68 | SQLSMALLINT DecimalDigits() const 69 | { 70 | return m_decimalDigits; 71 | } 72 | 73 | private: 74 | 75 | // Name of the column. 76 | // 77 | std::string m_name; 78 | 79 | // Data Type of the column. 80 | // 81 | SQLSMALLINT m_dataType; 82 | 83 | // Size of the column. 84 | // 85 | SQLULEN m_size; 86 | 87 | // The column is nullable or not. 88 | // 89 | SQLSMALLINT m_nullable; 90 | 91 | // Decimal digits of the column. 92 | // 93 | SQLSMALLINT m_decimalDigits; 94 | }; 95 | -------------------------------------------------------------------------------- /language-extensions/java/include/JavaExtensionUtils.h: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: JavaExtensionUtils.h 6 | // 7 | // Purpose: 8 | // Utility functions used by the Java extension. 9 | // 10 | //********************************************************************* 11 | #pragma once 12 | 13 | #include "Common.h" 14 | 15 | //--------------------------------------------------------------------- 16 | // Description: 17 | // General utility functions for the Java extension 18 | // 19 | class JavaExtensionUtils 20 | { 21 | public: 22 | // Get the value of an enviroment variable 23 | // 24 | static std::string GetEnvVariable(const std::string &name); 25 | 26 | // Get the platform specifc classpath seperator 27 | // 28 | static const char GetClassPathSeparator(); 29 | 30 | // Get the platform specifc path seperator 31 | // 32 | static const char GetPathSeparator(); 33 | 34 | // Combines two paths 35 | // 36 | static std::string CombinePath(const std::string &basePath, const std::string &pathToAdd); 37 | 38 | // Determines if the file path is valid 39 | // 40 | static bool IsValidFile(const std::string &file); 41 | 42 | // Split a string based on a delimiter 43 | // 44 | static std::vector SplitString(const std::string &str, const char delimiter); 45 | 46 | // Creates a JVM 47 | // 48 | static JNIEnv* CreateJvm(); 49 | 50 | // Cleans up JVM 51 | // 52 | static void CleanupJvm(); 53 | 54 | private: 55 | // Function pointer definition for JNI_CreateJVM 56 | // 57 | using fn_createJvm = jint(*)(JavaVM **pvm, void **penv, void *args); 58 | 59 | // Constructs the classpath from the enviroment variable, 60 | // and external library paths 61 | // 62 | static std::string GetClassPath(); 63 | 64 | // Constructs the path to the JVM library to load 65 | // 66 | static std::string GetJvmPath(); 67 | 68 | // Constructs the platform specific relative path to the JVM with respect to 69 | // the JRE_HOME path 70 | // 71 | static const std::string& GetRelativeJvmPath(); 72 | 73 | // Returns the platform specific name of the JVM library 74 | // 75 | static const std::string& GetJvmFilename(); 76 | 77 | // Loads the JVM library and returns a function pointer to the JNICreate_JVM 78 | // 79 | static fn_createJvm LoadJvm(const std::string &jvmPath); 80 | 81 | // Cleans up the JVM instance 82 | // 83 | static void ShutdownJvm(JavaVM *jvm); 84 | 85 | // Unloads the JVM library 86 | // 87 | static void UnloadJvm(); 88 | }; 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Microsoft SQL Server Language Extensions 3 | 4 | Welcome to the SQL Server Language Extensions project! 5 | 6 | Starting in SQL Server 2019, we have added support for language extensibility, which means that you can now execute code in various languages like R, Python and Java from SQL Server. 7 | 8 | To download the released prebuilt versions of these extensions, go to the [Releases section of this repository](https://github.com/microsoft/sql-server-language-extensions/releases). Download the latest version of whichever extension corresponds to your machine configuration (Windows or Linux). There are separate releases for each language extension. 9 | 10 | We hope you enjoy using Microsoft SQL Server and the language extension feature. 11 | 12 | -SQL Server Team 13 | 14 | ## Documentation 15 | 16 | You can read more about how to use language extensions and how to use Java in SQL Server 2019 in the Microsoft [documentation](https://docs.microsoft.com/en-us/sql/language-extensions/language-extensions-overview?view=sqlallproducts-allversions). 17 | 18 | Tutorials and documentation for the R and Python extensions can be found here: 19 | 20 | [Python Documentation](https://docs.microsoft.com/en-us/sql/machine-learning/install/custom-runtime-python?view=sql-server-ver15) 21 | 22 | [R Documentation](https://docs.microsoft.com/en-us/sql/machine-learning/install/custom-runtime-r?view=sql-server-ver15) 23 | 24 | ## Custom Builds 25 | 26 | To build your own version of the language extensions, refer to each respective language's README file. \ 27 | For example, to modify and build a custom version of the R Extension, go to [language-extensions/R/README.md](language-extensions/R/README.md). 28 | 29 | ## Contributing 30 | 31 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 32 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 33 | the rights to use your contribution. For details, visit https://cla.microsoft.com. 34 | 35 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide 36 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions 37 | provided by the bot. You will only need to do this once across all repos using our CLA. 38 | 39 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 40 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 41 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 42 | -------------------------------------------------------------------------------- /language-extensions/R/test/build/linux/build-RExtension-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function check_exit_code { 4 | EXIT_CODE=$? 5 | if [ ${EXIT_CODE} -eq 0 ]; then 6 | echo $1 7 | else 8 | echo $2 9 | exit ${EXIT_CODE} 10 | fi 11 | } 12 | 13 | function build { 14 | # Set cmake config to first arg 15 | # 16 | CMAKE_CONFIGURATION=$1 17 | if [ -z "${CMAKE_CONFIGURATION}" ]; then 18 | CMAKE_CONFIGURATION=release 19 | fi 20 | 21 | rm -rf ${REXTENSIONTEST_WORKING_DIR}/${CMAKE_CONFIGURATION} 22 | mkdir -p ${REXTENSIONTEST_WORKING_DIR}/${CMAKE_CONFIGURATION} 23 | 24 | pushd ${REXTENSIONTEST_WORKING_DIR} 25 | 26 | # Compile 27 | # 28 | cmake -DCMAKE_INSTALL_PREFIX:PATH=${REXTENSIONTEST_WORKING_DIR}/${CMAKE_CONFIGURATION} \ 29 | -DCMAKE_BUILD_TYPE=${CMAKE_CONFIGURATION} \ 30 | -DENL_ROOT=${ENL_ROOT} \ 31 | -DPLATFORM=linux \ 32 | -DR_HOME=${R_HOME} \ 33 | -DR_INCLUDE_DIR=${R_INCLUDE} \ 34 | ${REXTENSIONTEST_SRC_DIR} 35 | cmake --build ${REXTENSIONTEST_WORKING_DIR} --target install 36 | 37 | # Check the exit code of the compiler and exit appropriately so that build will fail. 38 | # 39 | check_exit_code "Success: Built RExtension-test" "Error: Failed to build RExtension-test" 40 | 41 | # Move the generated libs to configuration folder 42 | mv RExtension-test ${CMAKE_CONFIGURATION}/ 43 | 44 | popd 45 | } 46 | 47 | # Enlistment root and location of RExtension-test 48 | # 49 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 50 | ENL_ROOT=${SCRIPTDIR}/../../../../.. 51 | REXTENSIONTEST_HOME=${ENL_ROOT}/language-extensions/R/test/ 52 | 53 | # Set environment variables required in Cmake 54 | # 55 | PACKAGES_ROOT=${ENL_ROOT}/packages 56 | REXTENSIONTEST_SRC_DIR=${REXTENSIONTEST_HOME}/src 57 | REXTENSIONTEST_WORKING_DIR=${ENL_ROOT}/build-output/RExtension-test/linux 58 | 59 | DEFAULT_R_HOME=/usr/lib/R 60 | DEFAULT_R_INCLUDE=/usr/share/R/include 61 | 62 | # Find R_HOME from user, or set to default for testing. 63 | # Error code 1 is generic bash error. 64 | # 65 | if [ -z "${R_HOME}" ]; then 66 | if [ -d "${DEFAULT_R_HOME}" ]; then 67 | export R_HOME=${DEFAULT_R_HOME} 68 | else 69 | echo "R_HOME is empty" 70 | exit 1 71 | fi 72 | fi 73 | 74 | # Find R_INCLUDE from user, or set to default for building the test. 75 | # Error code 1 is generic bash error. 76 | # 77 | if [ -z "${R_INCLUDE}" ]; then 78 | if [ -d "${DEFAULT_R_INCLUDE}" ]; then 79 | export R_INCLUDE=${DEFAULT_R_INCLUDE} 80 | else 81 | echo "R_INCLUDE is empty" 82 | exit 1 83 | fi 84 | fi 85 | 86 | # Build in release mode if nothing is specified 87 | # 88 | if [ "$1" == "" ]; then 89 | set -- release 90 | fi 91 | 92 | while [ "$1" != "" ]; do 93 | # Advance arg passed to build.cmd 94 | # 95 | build $1 96 | shift 97 | done; 98 | -------------------------------------------------------------------------------- /language-extensions/R/src/RPathSettings.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: RPathSettings.cpp 22 | // 23 | // Purpose: 24 | // Global class to keep language runtime path settings for both platforms. 25 | // 26 | //************************************************************************************************** 27 | 28 | #include "Common.h" 29 | 30 | using namespace std; 31 | 32 | string RPathSettings::sm_languagePath; 33 | string RPathSettings::sm_languageParams; 34 | string RPathSettings::sm_privateLibraryPath; 35 | string RPathSettings::sm_publicLibraryPath; 36 | string RPathSettings::sm_RHomePath; 37 | 38 | //-------------------------------------------------------------------------------------------------- 39 | // Name: RPathSettings::Init 40 | // 41 | // Description: 42 | // Initialize the class 43 | // 44 | void RPathSettings::Init( 45 | const SQLCHAR *languageParams, 46 | const SQLCHAR *languagePath, 47 | const SQLCHAR *publicLibraryPath, 48 | const SQLCHAR *privateLibraryPath) 49 | { 50 | LOG("RPathSettings::Init"); 51 | 52 | // nullptrs are mapped to empty strings - has the same effect when 53 | // the paths are used and avoids an additional flag. 54 | // 55 | sm_languageParams = 56 | (languageParams == nullptr) ? "" : static_cast( 57 | static_cast(languageParams)); 58 | 59 | sm_languagePath = 60 | (languagePath == nullptr) ? "" : static_cast( 61 | static_cast(languagePath)); 62 | 63 | sm_publicLibraryPath = 64 | (publicLibraryPath == nullptr) ? "" : static_cast( 65 | static_cast(publicLibraryPath)); 66 | 67 | sm_privateLibraryPath = 68 | (privateLibraryPath == nullptr) ? "" : static_cast( 69 | static_cast(privateLibraryPath)); 70 | } 71 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/sample/regex/pkg/RegexSample.cs: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: RegexSample.cs 6 | // 7 | // Purpose: 8 | // Regex sample class using a regular expression that checks if a text contains the word "C#" or "c#" 9 | // 10 | //********************************************************************* 11 | using System; 12 | using System.Runtime.InteropServices; 13 | using System.Collections.Generic; 14 | using Microsoft.Data.Analysis; 15 | using Microsoft.SqlServer.CSharpExtension.SDK; 16 | using System.Text.RegularExpressions; 17 | 18 | namespace UserExecutor 19 | { 20 | /// 21 | /// This class extends the AbstractSqlServerExtensionExecutor and uses 22 | /// a regular expression that checks if a text contains the word "C#" or "c#" 23 | /// 24 | public class CSharpRegexExecutor: AbstractSqlServerExtensionExecutor 25 | { 26 | /// 27 | /// This method overrides the Execute method from AbstractSqlServerExtensionExecutor. 28 | /// 29 | /// 30 | /// A C# DataFrame contains the input dataset. 31 | /// 32 | /// 33 | /// A Dictionary contains the parameters from SQL server with name as the key. 34 | /// 35 | /// 36 | /// A C# DataFrame contains the output dataset. 37 | /// 38 | public override DataFrame Execute(DataFrame input, Dictionary sqlParams){ 39 | // Drop NULL values and sort by id 40 | // 41 | input = input.DropNulls().OrderBy("id"); 42 | 43 | // Create empty output DataFrame with two columns 44 | // 45 | DataFrame output = new DataFrame(new PrimitiveDataFrameColumn("id", 0), new StringDataFrameColumn("text", 0)); 46 | 47 | // Filter text containing specific substring using regex expression 48 | // 49 | DataFrameColumn texts = input.Columns["text"]; 50 | for(int i = 0; i < texts.Length; ++i) 51 | { 52 | if(Regex.IsMatch((string)texts[i], sqlParams["@regexExpr"])) 53 | { 54 | output.Append(input.Rows[i], true); 55 | } 56 | } 57 | 58 | // Modify the parameters 59 | // 60 | sqlParams["@rowsCount"] = output.Rows.Count; 61 | sqlParams["@regexExpr"] = "Success!"; 62 | 63 | // Return output dataset as a DataFrame 64 | // 65 | return output; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /language-extensions/python/include/PythonLibrarySession.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonLibrarySession.h 8 | // 9 | // Purpose: 10 | // Class encapsulating operations performed in a library management session 11 | // 12 | //************************************************************************************************* 13 | 14 | #pragma once 15 | #include "Common.h" 16 | #ifdef _WIN64 17 | #include 18 | #else 19 | #include 20 | #endif 21 | 22 | class PythonLibrarySession 23 | { 24 | public: 25 | 26 | // Initializes the Python library session, initialize the main namespace. 27 | // 28 | void Init(const SQLGUID *sessionId); 29 | 30 | // Install the specified library. 31 | // 32 | SQLRETURN InstallLibrary( 33 | std::string tempFolder, 34 | SQLCHAR *libraryName, 35 | SQLINTEGER libraryNameLength, 36 | SQLCHAR *libraryFile, 37 | SQLINTEGER libraryFileLength, 38 | SQLCHAR *libraryInstallDirectory, 39 | SQLINTEGER libraryInstallDirectoryLength); 40 | 41 | // Uninstall the specified library. 42 | // 43 | SQLRETURN UninstallLibrary( 44 | SQLCHAR *libraryName, 45 | SQLINTEGER libraryNameLength, 46 | SQLCHAR *libraryInstallDirectory, 47 | SQLINTEGER libraryInstallDirectoryLength); 48 | 49 | #ifdef _WIN64 50 | // Get top level directory/ies for a package 51 | // 52 | std::vector GetTopLevel( 53 | std::string libName, 54 | std::string installDir); 55 | 56 | // Get all the artifacts we can find of a package that are in the path 57 | // 58 | std::vector GetAllArtifacts( 59 | std::string libName, 60 | std::string path); 61 | #else 62 | // Get top level directory/ies for a package 63 | // 64 | std::vector GetTopLevel( 65 | std::string libName, 66 | std::string installDir); 67 | 68 | // Get all the artifacts we can find of a package that are in the path 69 | // 70 | std::vector GetAllArtifacts( 71 | std::string libName, 72 | std::string path); 73 | #endif 74 | 75 | private: 76 | SQLGUID m_sessionId{ 0, 0, 0, {0} }; 77 | 78 | // The underlying boost::python namespace, which contains all the python variables. 79 | // We execute any python scripts on this namespace. 80 | // 81 | boost::python::object m_mainNamespace; 82 | }; 83 | -------------------------------------------------------------------------------- /language-extensions/python/test/src/PythonInitTests.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonInitTests.cpp 8 | // 9 | // Purpose: 10 | // Test the Python extension initialization and 11 | // session initialization using the Extension API 12 | // 13 | //************************************************************************************************* 14 | #include "PythonExtensionApiTests.h" 15 | 16 | using namespace std; 17 | 18 | namespace ExtensionApiTest 19 | { 20 | // Name: TestInitWithNulls 21 | // 22 | // Description: 23 | // Test Init() API with all nullptrs. 24 | // This tests the extension initialization, using nullptrs because 25 | // param and library paths are optional. 26 | // 27 | TEST_F(PythonExtensionApiTests, TestInitWithNulls) 28 | { 29 | SQLRETURN result = Init( 30 | nullptr, // Extension Params 31 | 0, // Extension Params Length 32 | nullptr, // Extension Path 33 | 0, // Extension Path Length 34 | nullptr, // Public Library Path 35 | 0, // Public Library Path Length 36 | nullptr, // Private Library Path 37 | 0 // Private Library Path Length 38 | ); 39 | 40 | EXPECT_EQ(result, SQL_SUCCESS); 41 | } 42 | 43 | // Name: TestInitWithValues 44 | // 45 | // Description: 46 | // Test Init() API with actual values. 47 | // 48 | TEST_F(PythonExtensionApiTests, TestInitWithValues) 49 | { 50 | SQLCHAR *extensionParams = nullptr; 51 | SQLULEN extensionParamsLength = 0; 52 | string extensionPath = "C:/Path/To/ExternalLanguages/1/65554"; 53 | SQLULEN extensionPathLength = extensionPath.length(); 54 | string publicLibraryPath = "C:/Path/To/ExternalLanguages/1/65554/1"; 55 | SQLULEN publicLibraryPathLength = publicLibraryPath.length(); 56 | SQLCHAR *privateLibraryPath = nullptr; 57 | SQLULEN privateLibraryPathLength = 0; 58 | 59 | SQLCHAR *unsignedExtensionPath = static_cast( 60 | static_cast(const_cast(extensionPath.c_str()))); 61 | SQLCHAR *unsignedPublicLibraryPath = static_cast( 62 | static_cast(const_cast(publicLibraryPath.c_str()))); 63 | 64 | SQLRETURN result = Init(extensionParams, 65 | extensionParamsLength, 66 | unsignedExtensionPath, 67 | extensionPathLength, 68 | unsignedPublicLibraryPath, 69 | publicLibraryPathLength, 70 | privateLibraryPath, 71 | privateLibraryPathLength 72 | ); 73 | 74 | EXPECT_EQ(result, SQL_SUCCESS); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /language-extensions/R/common/include/Unicode.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: Unicode.h 22 | // 23 | // Purpose: 24 | // Functions providing lengths and conversion between utf16, utf8 encoded unicode characters. 25 | // 26 | //************************************************************************************************** 27 | #pragma once 28 | 29 | #include 30 | 31 | namespace estd 32 | { 33 | std::u16string ToUtf16(const std::string &str); 34 | std::string ToUtf8(const std::u16string &str); 35 | 36 | std::u16string ToUtf16(const char *s, size_t len); 37 | std::string ToUtf8(const char16_t *s, size_t len); 38 | 39 | // These versions avoid memory allocation if the output string is big enough. 40 | // Useful for loops when multiple strings are converted. 41 | // 42 | void ToUtf16(const std::string &u8, std::u16string &u16); 43 | void ToUtf8(const std::u16string &str, std::string &u8); 44 | void ToUtf16(const char *s, size_t len, std::u16string &u16); 45 | void ToUtf8(const char16_t *s, size_t len, std::string &u8, bool throwOnError = false); 46 | 47 | // Returns the number of chars (bytes) in the string 48 | // 49 | size_t Utf8Size(const std::string &str); 50 | 51 | // Returns the number of chars (bytes) in the UTF8 representation of the string 52 | // 53 | size_t Utf8Size(const std::u16string &str); 54 | size_t Utf8Size(const char16_t *s, size_t l); 55 | 56 | // Returns the number of char16s in the string 57 | // 58 | size_t Utf16Size(const std::u16string &str); 59 | 60 | // Returns the number of char16s in the UTF16 representation of the string 61 | // 62 | size_t Utf16Size(const std::string &str); 63 | size_t Utf16Size(const char *s, size_t l); 64 | 65 | // Returns True if the string is a valid UTF8, false otherwise. 66 | // 67 | bool IsValidUTF8(const char* str, int strlen); 68 | } 69 | -------------------------------------------------------------------------------- /language-extensions/R/src/linux/RPathSettings_linux.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: RPathSettings_linux.cpp 22 | // 23 | // Purpose: 24 | // Global class to keep language runtime path settings for linux. 25 | // 26 | //************************************************************************************************** 27 | 28 | #include "Common.h" 29 | 30 | using namespace std; 31 | 32 | //-------------------------------------------------------------------------------------------------- 33 | // Name: RPathSettings::CheckAndSetRHome 34 | // 35 | // Description: 36 | // Checks if R_HOME is set, and sets it to be the language path if not already set. 37 | // Throws and exception if there is an error setting it. 38 | // 39 | void RPathSettings::CheckAndSetRHome() 40 | { 41 | LOG("RPathSettings::CheckAndSetRHome"); 42 | 43 | sm_RHomePath = 44 | Utilities::GetEnvVariable( 45 | "R_HOME", // envVarName 46 | // No need to log error on linux if R_HOME is not defined, since we can set it below. 47 | // 48 | false); // logError 49 | 50 | if (sm_RHomePath == "") 51 | { 52 | int result = Utilities::SetEnvVariable("R_HOME", sm_languagePath); 53 | if (result != 0) 54 | { 55 | throw runtime_error("Error setting R_HOME"); 56 | } 57 | else 58 | { 59 | sm_RHomePath = sm_languagePath; 60 | LOG("R_HOME set to be the extensionPath: " + sm_RHomePath); 61 | } 62 | } 63 | else 64 | { 65 | LOG("R_HOME is set as: " + sm_RHomePath); 66 | } 67 | } 68 | 69 | //-------------------------------------------------------------------------------------------------- 70 | // Name: RPathSettings::CheckAndSetTZDir 71 | // 72 | // Description: 73 | // Its a no-op on linux since TZDIR is not useful on linux. The time zones are always looked up 74 | // from fixed path: /usr/share/zoneinfo 75 | // 76 | void RPathSettings::CheckAndSetTZDir() 77 | { 78 | } 79 | -------------------------------------------------------------------------------- /language-extensions/R/include/Utilities.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: Utilities.h 22 | // 23 | // Purpose: 24 | // Utility functions 25 | // 26 | //************************************************************************************************** 27 | 28 | #pragma once 29 | 30 | class Utilities 31 | { 32 | public: 33 | 34 | // Converts a SQLGUID to a string 35 | // 36 | static std::string ConvertGuidToString(const SQLGUID * guid); 37 | 38 | // Splits the given character string using the delimiter and 39 | // adds the tokens to the input vector. 40 | // 41 | static void Tokenize(char *input, const char* delimiter, std::vector *tokens); 42 | 43 | // Given a constant string input, generates a unique pointer 44 | // pointing to a char array containing the same contents as that of the input 45 | // 46 | static std::unique_ptr GenerateUniquePtr(const std::string &input); 47 | 48 | // Gets the value of the given environment variable name. 49 | // 50 | static std::string GetEnvVariable(const std::string &envVarName, bool logError); 51 | 52 | // Sets the environment variable name to the specified value. 53 | // 54 | static int SetEnvVariable(const std::string &envVarName, const std::string &value); 55 | 56 | // From the given nanoSeconds value, generates a string 57 | // representing seconds after the decimal point. 58 | // 59 | static std::string GetSecondsAfterDecimalPointFromNanoSeconds( 60 | SQLUINTEGER nanoSeconds); 61 | 62 | // Finds the current time zone defined in R if any 63 | // 64 | static std::string GetTimeZoneInR(); 65 | 66 | // Sets the time zone in R to the given value or unset it if the value is empty. 67 | // 68 | static void SetTimeZoneInR(std::string valueToSet); 69 | 70 | // Normalizes path strings by replacting \ with / 71 | // 72 | static std::string NormalizePathString(std::string pathString); 73 | }; 74 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /language-extensions/R/test/include/Utilities.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension-test : Executable testing language extension that implements the SQL Server 3 | // external language communication protocol. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension-test. 7 | // 8 | // RExtension-test is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension-test is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension-test. If not, see . 20 | // 21 | // @File: Utilities.cpp 22 | // 23 | // Purpose: 24 | // Utility functions 25 | // 26 | //************************************************************************************************** 27 | 28 | #pragma once 29 | 30 | # define LOCAL_DATE 1 31 | # define UTC_DATE 2 32 | 33 | class Utilities 34 | { 35 | public: 36 | 37 | // Gets the handle for the given library path after loading it dynamically 38 | // 39 | static void* CrossPlatLoadLibrary( 40 | const char *libPath); 41 | 42 | // Gets the function pointer for the given function name from the given library handle 43 | // 44 | static void* CrossPlatGetFunctionFromLibHandle( 45 | void *libHandle, 46 | const std::string &fnName); 47 | 48 | // Given a valid library handle, closes it. 49 | // 50 | static void CrossPlatCloseLibrary( 51 | void *libHandle); 52 | 53 | // Gets max length from given arrayOfLengths with size = rowsNumber. 54 | // 55 | static SQLINTEGER GetMaxLength( 56 | SQLINTEGER *arrayOfLengths, 57 | SQLULEN rowsNumber); 58 | 59 | // Gets the length of a wchar_t *. 60 | // 61 | static SQLULEN GetWStringLength(const wchar_t *wstr); 62 | 63 | // Returns the current system clock time in terms of time_t which represents number of seconds 64 | // since epoch January 1, 1970 00:00:00. 65 | // 66 | static time_t GetNow(); 67 | 68 | // Gets the current date based on its type (UTC or local) in the form of a SQL_DATE_STRUCT. 69 | // 70 | template 71 | static SQL_DATE_STRUCT GetTodaysDate(); 72 | 73 | // Convert the given SQLDateTimeType into an equivalent UTC SQLDateTimeType 74 | // 75 | template 76 | static SQLDateTimeType ToUtc(SQLDateTimeType givenTimeStamp); 77 | 78 | // Normalizes path string. 79 | // 80 | static std::string NormalizePathString(std::string pathString); 81 | }; 82 | -------------------------------------------------------------------------------- /language-extensions/python/build/linux/restore-packages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 3 | 4 | export DEBIAN_FRONTEND=noninteractive 5 | apt-get update 6 | apt-get --no-install-recommends -y install curl zip unzip 7 | 8 | apt-get update 9 | apt-get install -y software-properties-common 10 | add-apt-repository -y ppa:deadsnakes/ppa 11 | apt-get update 12 | 13 | DEFAULT_PYTHONHOME=/usr 14 | BOOST_VERSION=1.87.0 15 | BOOST_VERSION_IN_UNDERSCORE=1_87_0 16 | PYTHON_VERSION=3.12 17 | NUMPY_VERSION=2.3.0 18 | PANDAS_VERSION=2.3.0 19 | 20 | apt-get install -y python3.12-dev python3.12 libpython3.12 libpython3.12-dev libboost-all-dev 21 | curl -sS https://bootstrap.pypa.io/get-pip.py | /usr/bin/python${PYTHON_VERSION} 22 | 23 | # Find PYTHONHOME from user, or set to default for tests. 24 | # Error code 1 is generic bash error. 25 | # 26 | if [ -z "${PYTHONHOME}" ]; then 27 | if [ -x "${DEFAULT_PYTHONHOME}" ]; then 28 | PYTHONHOME=${DEFAULT_PYTHONHOME} 29 | else 30 | echo "PYTHONHOME is empty" 31 | exit 1 32 | fi 33 | fi 34 | 35 | echo "Python home is ${PYTHONHOME}" 36 | 37 | # Lock versions of numpy and pandas to versions compatible for the defined python version 38 | # 39 | ${PYTHONHOME}/bin/python${PYTHON_VERSION} -m pip install --force-reinstall numpy==${NUMPY_VERSION} 40 | ${PYTHONHOME}/bin/python${PYTHON_VERSION} -m pip install --force-reinstall pandas==${PANDAS_VERSION} 41 | 42 | # Download and install boost, then navigate to boost root directory 43 | # Use /usr/local for boost installation to avoid conflicts with system packages 44 | # 45 | wget -O boost_${BOOST_VERSION_IN_UNDERSCORE}.tar.gz https://sourceforge.net/projects/boost/files/boost/${BOOST_VERSION}/boost_${BOOST_VERSION_IN_UNDERSCORE}.tar.gz/download 46 | tar xzvf boost_${BOOST_VERSION_IN_UNDERSCORE}.tar.gz -C /usr/local/lib/ 47 | pushd /usr/local/lib/boost_${BOOST_VERSION_IN_UNDERSCORE} 48 | 49 | # Build defined python version of boost and boost python 50 | # 51 | ./bootstrap.sh --without-icu --with-python=${PYTHONHOME}/bin/python${PYTHON_VERSION} --with-python-version=${PYTHON_VERSION} --with-python-root=${PYTHONHOME}/lib/python${PYTHON_VERSION} 52 | 53 | echo "using python : ${PYTHON_VERSION} : ${PYTHONHOME}/bin/python${PYTHON_VERSION} : ${PYTHONHOME}/include/python${PYTHON_VERSION} : ${PYTHONHOME}/lib ;" >> project-config.jam 54 | 55 | # Change cxx flags to force boost to compile with -fPIC compilation, otherwise will fail linking when building libPythonExtension.so 56 | # 57 | sed -i 's/using gcc[^;]*;/using gcc : foo : g++ : -fPIC ;/g' project-config.jam 58 | 59 | ./b2 --clean 60 | # Build both debug and release variants, and both static and shared libraries 61 | ./b2 toolset=gcc variant=debug,release address-model=64 include=${PYTHONHOME}/include/python${PYTHON_VERSION}/ link=shared,static threading=multi -j12 62 | 63 | cp -rf boost /usr/local/include/ 64 | 65 | popd 66 | 67 | exit $? 68 | -------------------------------------------------------------------------------- /language-extensions/python/src/Logger.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: Logger.cpp 8 | // 9 | // Purpose: 10 | // Logging functions for extension 11 | // 12 | //************************************************************************************************* 13 | 14 | #include "Logger.h" 15 | 16 | #define TIMESTAMP_LENGTH 35 17 | using namespace std; 18 | 19 | char Logger::sm_timestampBuffer[TIMESTAMP_LENGTH] = { 0 }; 20 | 21 | //------------------------------------------------------------------------------------------------- 22 | // Name: LogError 23 | // 24 | // Description: 25 | // Log an error to stderr with format "TIMESTAMP Error: ". 26 | // 27 | void Logger::LogError(const string &errorMsg) 28 | { 29 | cerr << GetCurrentTimestamp() << "Error: " << errorMsg << endl; 30 | } 31 | 32 | //------------------------------------------------------------------------------------------------- 33 | // Name: LogException 34 | // 35 | // Description: 36 | // Log a c++ exception to stderr with format "TIMESTAMP Exception 37 | // occurred: ". 38 | // 39 | void Logger::LogException(const exception &e) 40 | { 41 | cerr << GetCurrentTimestamp() << "Exception occurred: " << e.what() << endl; 42 | } 43 | 44 | //------------------------------------------------------------------------------------------------- 45 | // Name: Log 46 | // 47 | // Description: 48 | // Log a message to stdout with format "TIMESTAMP ". 49 | // 50 | void Logger::Log(const string &msg) 51 | { 52 | #if defined(_DEBUG) 53 | cout << GetCurrentTimestamp() << msg << endl; 54 | #endif 55 | } 56 | 57 | //------------------------------------------------------------------------------------------------- 58 | // Name: GetCurrentTimestamp 59 | // 60 | // Description: 61 | // Gets the current system time and format it to the SQL log format 62 | // (Year-Month-Day Hour:Minute:Second.Millisecond). 63 | // 64 | const std::string Logger::GetCurrentTimestamp() 65 | { 66 | #if defined ( _MSC_VER ) 67 | SYSTEMTIME sysTime; 68 | 69 | GetLocalTime(&sysTime); 70 | 71 | sprintf_s(sm_timestampBuffer, TIMESTAMP_LENGTH, 72 | "%04d-%02d-%02d %02d:%02d:%02d.%02d\t", 73 | sysTime.wYear, 74 | sysTime.wMonth, 75 | sysTime.wDay, 76 | sysTime.wHour, 77 | sysTime.wMinute, 78 | sysTime.wSecond, 79 | sysTime.wMilliseconds / 10); 80 | 81 | return sm_timestampBuffer; 82 | #else 83 | time_t now = time(0); 84 | struct tm tstruct; 85 | char buf[80]; 86 | 87 | tstruct = *localtime(&now); 88 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.000\t", &tstruct); // No millisecond support 89 | return buf; 90 | #endif 91 | } 92 | -------------------------------------------------------------------------------- /language-extensions/R/src/linux/Utilities_linux.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: Utilities_linux.cpp 22 | // 23 | // Purpose: 24 | // Utility functions implemented for the linux platform. 25 | // 26 | //************************************************************************************************** 27 | 28 | #include "Common.h" 29 | 30 | using namespace std; 31 | 32 | //-------------------------------------------------------------------------------------------------- 33 | // Name: Utilities::GetEnvVariable 34 | // 35 | // Description: 36 | // Gets the value of the given environment variable name and if logError is true, logs an error 37 | // message if the variable is not found. 38 | // 39 | // Returns: 40 | // String value of the environment variable requested. 41 | // 42 | string Utilities::GetEnvVariable(const string &envVarName, bool logError) 43 | { 44 | string envVarValueString; 45 | char * envVarValue = getenv(envVarName.c_str()); 46 | if (envVarValue != nullptr) 47 | { 48 | envVarValueString = string(const_cast(envVarValue), 49 | strlen(envVarValue)); 50 | } 51 | else if (logError) 52 | { 53 | LOG_ERROR("Did not find the environment variable " + envVarName); 54 | } 55 | 56 | return envVarValueString; 57 | } 58 | 59 | //-------------------------------------------------------------------------------------------------- 60 | // Name: Utilities::SetEnvVariable 61 | // 62 | // Description: 63 | // Sets the environment variable name to the specified value 64 | // 65 | // Returns: 66 | // Returns the result of the putenv operation. 0 indicates success, nonzero indicates error. 67 | // 68 | int Utilities::SetEnvVariable(const string &envVarName, const string &value) 69 | { 70 | errno = 0; 71 | string keyValue = string(envVarName + "=" + value); 72 | int result = putenv(const_cast(keyValue.c_str())); 73 | if (result != 0) 74 | { 75 | LOG_ERROR("Failed to set the value " + value + 76 | " to the environment variable " + envVarName + 77 | " with system error #" + to_string(errno) + "."); 78 | } 79 | 80 | return result; 81 | } 82 | -------------------------------------------------------------------------------- /language-extensions/R/include/RPathSettings.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: RPathSettings.h 22 | // 23 | // Purpose: 24 | // Global class to keep language runtime path settings. 25 | // 26 | //************************************************************************************************** 27 | 28 | #pragma once 29 | 30 | //-------------------------------------------------------------------------------------------------- 31 | // Name: RPathSettings 32 | // 33 | // Description: 34 | // Global class storing the language runtime paths and parameters. 35 | // 36 | class RPathSettings 37 | { 38 | public: 39 | 40 | // Initializes this global class 41 | // 42 | static void Init( 43 | const SQLCHAR *languageParams, 44 | const SQLCHAR *languagePath, 45 | const SQLCHAR *publicLibraryPath, 46 | const SQLCHAR *privateLibraryPath); 47 | 48 | // Gets the private library path sent by SQL Server 49 | // 50 | static const std::string& PrivateLibraryPath() {return sm_privateLibraryPath; } 51 | 52 | // Gets the public library path sent by SQL Server 53 | // 54 | static const std::string& PublicLibraryPath() {return sm_publicLibraryPath; } 55 | 56 | // Gets the extension root folder 57 | // 58 | static const std::string& RootPath() {return sm_languagePath; } 59 | 60 | // Gets the language parameters sent by SQL Server 61 | // 62 | static const std::string& Params() {return sm_languageParams; } 63 | 64 | // Checks if R_HOME is set, and sets it to be the language path if not already set. 65 | // 66 | static void CheckAndSetRHome(); 67 | 68 | // Sets the environment variable TZDIR. 69 | // 70 | static void CheckAndSetTZDir(); 71 | 72 | private: 73 | 74 | // Directory where R language extension library is extracted onto. 75 | // 76 | static std::string sm_languagePath; 77 | 78 | // Parameters passed to R language extension 79 | // 80 | static std::string sm_languageParams; 81 | 82 | // Private library path 83 | // 84 | static std::string sm_privateLibraryPath; 85 | 86 | // Public library path 87 | // 88 | static std::string sm_publicLibraryPath; 89 | 90 | // R_HOME path 91 | // 92 | static std::string sm_RHomePath; 93 | }; 94 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/include/hostfxr.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | 4 | #ifndef __HOSTFXR_H__ 5 | #define __HOSTFXR_H__ 6 | 7 | #include 8 | #include 9 | 10 | #if defined(_WIN32) 11 | #define HOSTFXR_CALLTYPE __cdecl 12 | #ifdef _WCHAR_T_DEFINED 13 | typedef wchar_t char_t; 14 | #else 15 | typedef unsigned short char_t; 16 | #endif 17 | #else 18 | #define HOSTFXR_CALLTYPE 19 | typedef char char_t; 20 | #endif 21 | 22 | enum hostfxr_delegate_type 23 | { 24 | hdt_com_activation, 25 | hdt_load_in_memory_assembly, 26 | hdt_winrt_activation, 27 | hdt_com_register, 28 | hdt_com_unregister, 29 | hdt_load_assembly_and_get_function_pointer 30 | }; 31 | 32 | typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_fn)(const int argc, const char_t **argv); 33 | typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_startupinfo_fn)( 34 | const int argc, 35 | const char_t **argv, 36 | const char_t *host_path, 37 | const char_t *dotnet_root, 38 | const char_t *app_path); 39 | 40 | typedef void(HOSTFXR_CALLTYPE *hostfxr_error_writer_fn)(const char_t *message); 41 | typedef hostfxr_error_writer_fn(HOSTFXR_CALLTYPE *hostfxr_set_error_writer_fn)(hostfxr_error_writer_fn error_writer); 42 | 43 | typedef void* hostfxr_handle; 44 | typedef struct hostfxr_initialize_parameters 45 | { 46 | size_t size; 47 | const char_t *host_path; 48 | const char_t *dotnet_root; 49 | } hostfxr_initialize_parameters; 50 | 51 | typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_initialize_for_dotnet_command_line_fn)( 52 | int argc, 53 | const char_t **argv, 54 | const hostfxr_initialize_parameters *parameters, 55 | /*out*/ hostfxr_handle *host_context_handle); 56 | typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_initialize_for_runtime_config_fn)( 57 | const char_t *runtime_config_path, 58 | const hostfxr_initialize_parameters*parameters, 59 | /*out*/ hostfxr_handle *host_context_handle); 60 | 61 | typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_property_value_fn)( 62 | const hostfxr_handle host_context_handle, 63 | const char_t *name, 64 | /*out*/ const char_t **value); 65 | typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_set_runtime_property_value_fn)( 66 | const hostfxr_handle host_context_handle, 67 | const char_t *name, 68 | const char_t *value); 69 | typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_properties_fn)( 70 | const hostfxr_handle host_context_handle, 71 | /*inout*/ size_t * count, 72 | /*out*/ const char_t **keys, 73 | /*out*/ const char_t **values); 74 | 75 | typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_run_app_fn)(const hostfxr_handle host_context_handle); 76 | typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_delegate_fn)( 77 | const hostfxr_handle host_context_handle, 78 | enum hostfxr_delegate_type type, 79 | /*out*/ void **delegate); 80 | 81 | typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_close_fn)(const hostfxr_handle host_context_handle); 82 | 83 | #endif //__HOSTFXR_H__ 84 | -------------------------------------------------------------------------------- /language-extensions/python/src/PythonNamespace.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonNamespace.cpp 8 | // 9 | // Purpose: 10 | // Global class to keep the global python namespace 11 | // 12 | //************************************************************************************************* 13 | 14 | #include "PythonNamespace.h" 15 | #include "PythonPathSettings.h" 16 | 17 | using namespace std; 18 | namespace bp = boost::python; 19 | 20 | //------------------------------------------------------------------------------------------------- 21 | // Name: PythonNamespace::Init 22 | // 23 | // Description: 24 | // Initialize the class 25 | // 26 | void PythonNamespace::Init() 27 | { 28 | sm_mainModule = bp::import("__main__"); 29 | sm_mainNamespace = sm_mainModule.attr("__dict__"); 30 | 31 | // Check that the module and namespace are populated, not None objects 32 | // 33 | if (sm_mainModule == bp::object() || 34 | sm_mainNamespace == bp::object()) 35 | { 36 | throw runtime_error("Main module or namespace was None"); 37 | } 38 | 39 | // Setup the devnull device (which we do not have access to in Windows) 40 | // to redirect to a file. We create that file here for future use. 41 | // Also, import packages that we will need in later functions. 42 | // 43 | string setupScript = 44 | "import os\n" 45 | "import sys\n" 46 | "import platform\n" 47 | "from pandas import DataFrame\n" 48 | "import numpy as np\n" 49 | "_originalpath = list(sys.path)\n" 50 | "if platform.system() == 'Windows':\n" 51 | " oldnulldevice = os.devnull\n" 52 | " os.devnull = 'nulldeviceout.txt'\n" 53 | " nulhandle = open(os.devnull, 'w+')\n" 54 | " nulhandle.close()"; 55 | 56 | bp::exec(setupScript.c_str(), sm_mainNamespace); 57 | 58 | string privateLibPath = PythonPathSettings::PrivateLibraryPath(); 59 | string publicLibPath = PythonPathSettings::PublicLibraryPath(); 60 | 61 | // Setup the path to include private and public external library paths 62 | // so that we can find the external packages that are installed. 63 | // We set the private/public paths in front of the sys.path so they are searched first. 64 | // 65 | sm_originalPath = bp::extract(bp::eval("sys.path", sm_mainNamespace)); 66 | bp::list newPath(sm_originalPath); 67 | newPath.insert(0, bp::str(publicLibPath)); 68 | newPath.insert(0, bp::str(privateLibPath)); 69 | 70 | PySys_SetObject("path", newPath.ptr()); 71 | } 72 | 73 | //------------------------------------------------------------------------------------------------- 74 | // Name: PythonNamespace::Cleanup 75 | // 76 | // Description: 77 | // Cleanup, reset the Python syspath 78 | // 79 | void PythonNamespace::Cleanup() 80 | { 81 | PySys_SetObject("path", sm_originalPath.ptr()); 82 | } 83 | 84 | bp::object PythonNamespace::sm_mainNamespace; 85 | bp::object PythonNamespace::sm_mainModule; 86 | bp::object PythonNamespace::sm_originalPath; 87 | -------------------------------------------------------------------------------- /language-extensions/R/src/windows/RPathSettings_win.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: RPathSettings_win.cpp 22 | // 23 | // Purpose: 24 | // Global class to keep language runtime path settings for windows. 25 | // 26 | //************************************************************************************************** 27 | 28 | #include "Common.h" 29 | 30 | using namespace std; 31 | 32 | //-------------------------------------------------------------------------------------------------- 33 | // Name: RPathSettings::CheckAndSetRHome 34 | // 35 | // Description: 36 | // Checks if R_HOME is set and throws an exception if its not set. 37 | // 38 | void RPathSettings::CheckAndSetRHome() 39 | { 40 | LOG("RPathSettings::CheckAndSetRHome"); 41 | 42 | sm_RHomePath = 43 | Utilities::GetEnvVariable( 44 | "R_HOME", // envVarName 45 | // We need to log error if R_HOME is not defined on Windows 46 | // since its too late to set it now. 47 | // 48 | true); // logError 49 | 50 | if (sm_RHomePath == "") 51 | { 52 | throw runtime_error("On Windows, R_HOME needs to be defined as" 53 | " a system environment variable."); 54 | } 55 | else 56 | { 57 | LOG("R_HOME is set as: " + sm_RHomePath); 58 | } 59 | } 60 | 61 | //-------------------------------------------------------------------------------------------------- 62 | // Name: RPathSettings::SetTZDir 63 | // 64 | // Description: 65 | // Check if environment variable TZDIR is set. 66 | // If it is not set, set sm_RHomePath first and then set TZDIR to R_HOME\share\zoneinfo path 67 | // so that time zone information is available when calling OlsonNames() in R. 68 | // 69 | void RPathSettings::CheckAndSetTZDir() 70 | { 71 | LOG("RPathSettings::CheckAndSetTZDir"); 72 | 73 | string tzDir = 74 | Utilities::GetEnvVariable( 75 | "TZDIR", // envVarName 76 | // No need to log error if TZDIR is not defined since we can set it below. 77 | // 78 | false); // logError 79 | 80 | if (tzDir == "") 81 | { 82 | if (sm_RHomePath == "") 83 | { 84 | CheckAndSetRHome(); 85 | } 86 | 87 | string valueForTZDir = sm_RHomePath + "\\share\\zoneinfo"; 88 | Utilities::SetEnvVariable("TZDIR", valueForTZDir); 89 | } 90 | else 91 | { 92 | LOG("TZDIR is set as: " + tzDir); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/sample/LoopBackConnection/LoopBackConnectionOLEDB.cs: -------------------------------------------------------------------------------- 1 | //********************************************************************* 2 | // Copyright (c) Microsoft Corporation. 3 | // Licensed under the MIT License. 4 | // 5 | // @File: LoopBackConnectionOLEDB.cs 6 | // 7 | // Purpose: 8 | // Connect to SQL server using the loopback connection in a Language extension environment. 9 | // 10 | //********************************************************************* 11 | using Microsoft.Data.Analysis; 12 | using Microsoft.Data.SqlClient; 13 | using Microsoft.SqlServer.CSharpExtension.SDK; 14 | using System; 15 | using System.Collections.Generic; 16 | using System.IO; 17 | using System.Text.RegularExpressions; 18 | using System.Data.OleDb; 19 | 20 | namespace UserExecutor 21 | { 22 | /// 23 | /// This class extends the AbstractSqlServerExtensionExecutor. 24 | /// This class can be used to execute custom SQL queries within the Language Extension environment. 25 | /// 26 | public class LoopBackConnectionOLEDB : AbstractSqlServerExtensionExecutor 27 | { 28 | /// 29 | /// This method overrides the Execute method from AbstractSqlServerExtensionExecutor. 30 | /// 31 | public override DataFrame Execute(DataFrame input, Dictionary sqlParams) 32 | { 33 | // Ole DB implementation 34 | // Connection string to the server.. 35 | // This is a standard connection string. 36 | // Example: 37 | //string connectionstring = "Data Source=;User Id=<>;Password=<>;Initial Catalog=<>;Trusted_Connection=True;Encrypt=False;"; 38 | string connectionstring = sqlParams["@connectionString"]; 39 | 40 | // Create empty output DataFrame with One column 41 | // 42 | DataFrame output = new DataFrame(new StringDataFrameColumn("text", 0)); 43 | using (OleDbConnection connection = new OleDbConnection(connectionstring)) 44 | { 45 | connection.Open(); 46 | 47 | // The SQL command that you need to execute on the SQL server. 48 | // This can be passed as a parameter as well into this method if you want to make it more dynamic. 49 | String sql = sqlParams["@query"]; 50 | using (OleDbCommand command = new OleDbCommand(sql, connection)) 51 | { 52 | using (OleDbDataReader reader = command.ExecuteReader()) 53 | { 54 | while (reader.Read()) 55 | { 56 | String outstring = "{0} {1}", reader.GetString(0), reader.GetString(1); 57 | Console.WriteLine(outstring); 58 | output.append(outstring); 59 | } 60 | } 61 | } 62 | } 63 | 64 | // Modify the parameters 65 | // 66 | sqlParams["@rowsCount"] = output.Rows.Count; 67 | sqlParams["@Status"] = "Success!"; 68 | 69 | return output; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /language-extensions/dotnet-core-CSharp/test/src/native/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | # This is what the final executable is going to be named 4 | # 5 | project(dotnet-core-CSharp-extension-test VERSION 1.0 LANGUAGES CXX) 6 | 7 | # All string comparisons are CASE SENSITIVE in CMAKE. Make all strings lower before comparisons! 8 | # 9 | string(TOLOWER ${PLATFORM} PLATFORM) 10 | string(TOLOWER ${CMAKE_CONFIGURATION} CMAKE_CONFIGURATION) 11 | 12 | file(TO_CMAKE_PATH ${ENL_ROOT}/extension-host EXTENSION_API_HOME) 13 | file(TO_CMAKE_PATH ${ENL_ROOT}/language-extensions/dotnet-core-CSharp DOTNETCORE_CSHARP_EXTENSION_HOME) 14 | file(TO_CMAKE_PATH ${DOTNETCORE_CSHARP_EXTENSION_HOME}/test DOTNETCORE_CSHARP_EXTENSION_TEST_HOME) 15 | file(TO_CMAKE_PATH ${DOTNETCORE_CSHARP_EXTENSION_TEST_HOME}/src/native DOTNETCORE_CSHARP_EXTENSION_TEST_SRC_DIR) 16 | 17 | # C++ unit tests code; only these files are compiled-in 18 | # 19 | file(GLOB DOTNETCORE_CSHARP_EXTENSION_TEST_SOURCE_FILES 20 | ${DOTNETCORE_CSHARP_EXTENSION_TEST_SRC_DIR}/*.cpp) 21 | 22 | add_executable(dotnet-core-CSharp-extension-test 23 | ${DOTNETCORE_CSHARP_EXTENSION_TEST_SOURCE_FILES} 24 | ) 25 | 26 | target_compile_options(dotnet-core-CSharp-extension-test PRIVATE --std=c++17) 27 | 28 | # Set the DLLEXPORT variable to export symbols 29 | # 30 | add_definitions(-DWIN_EXPORT -D_WIN64 -D_WINDOWS) 31 | target_compile_definitions(dotnet-core-CSharp-extension-test PRIVATE WIN_EXPORT) 32 | 33 | 34 | file(TO_CMAKE_PATH ${ENL_ROOT}/language-extensions/dotnet-core-CSharp/test/include/ DOTNETCORE_CSHARP_EXTENSION_TEST_INCLUDE_DIR) 35 | file(TO_CMAKE_PATH ${ENL_ROOT}/build-output/dotnet-core-CSharp-extension-test/${PLATFORM}/ DOTNETCORE_CSHARP_EXTENSION_TEST_WORKING_DIR) 36 | file(TO_CMAKE_PATH ${DOTNETCORE_CSHARP_EXTENSION_TEST_WORKING_DIR}/${CMAKE_CONFIGURATION} DOTNETCORE_CSHARP_EXTENSION_TEST_INSTALL_DIR) 37 | 38 | file(TO_CMAKE_PATH ${ENL_ROOT}/packages/Microsoft.googletest.v140.windesktop.msvcstl.dyn.rt-dyn.1.8.1.3 GTEST_HOME) 39 | file(TO_CMAKE_PATH ${GTEST_HOME}/build/native/include GTEST_INCLUDE_DIR) 40 | file(TO_CMAKE_PATH ${GTEST_HOME}/lib/native/v140/windesktop/msvcstl/dyn/rt-dyn/x64/${CMAKE_CONFIGURATION} GTEST_LIB_PATH) 41 | 42 | # MDd is for debug DLL and MD is for release DLL 43 | # 44 | if (${CMAKE_CONFIGURATION} STREQUAL debug) 45 | set(COMPILE_OPTIONS ${COMPILE_OPTIONS} /MDd) 46 | find_library(GTEST_LIB gtestd ${GTEST_LIB_PATH}) 47 | set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG} /Od) 48 | else() 49 | set(COMPILE_OPTIONS ${COMPILE_OPTIONS} /MD /O2) 50 | find_library(GTEST_LIB gtest ${GTEST_LIB_PATH}) 51 | endif() 52 | 53 | # This is not a standard include path so test projects need 54 | # to add it explicitly 55 | # 56 | include_directories( 57 | "${DOTNETCORE_CSHARP_EXTENSION_TEST_INCLUDE_DIR}" 58 | "${EXTENSION_API_HOME}/include" 59 | "${DOTNETCORE_CSHARP_EXTENSION_HOME}/include" 60 | "${GTEST_INCLUDE_DIR}" 61 | ) 62 | 63 | # This string comparison is case sensitive 64 | # 65 | if(${CMAKE_CONFIGURATION} STREQUAL debug) 66 | add_definitions(-D_DEBUG) 67 | endif() 68 | 69 | target_link_libraries(dotnet-core-CSharp-extension-test 70 | ${GTEST_LIB} 71 | ) 72 | 73 | install(TARGETS dotnet-core-CSharp-extension-test DESTINATION ${DOTNETCORE_CSHARP_EXTENSION_TEST_INSTALL_DIR}) 74 | -------------------------------------------------------------------------------- /language-extensions/R/build/windows/restore-packages.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | SET ENL_ROOT=%~dp0..\..\..\.. 5 | SET REXTENSION_HOME=%ENL_ROOT%\language-extensions\R 6 | 7 | REM Call the root level restore-packages 8 | REM 9 | SET PACKAGES_ROOT=%ENL_ROOT%\packages 10 | CALL %ENL_ROOT%\restore-packages.cmd 11 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to restore common nuget packages." || EXIT /b %ERRORLEVEL% 12 | 13 | REM Set DEFAULT_R_HOME 14 | REM 15 | SET R_VERSION=4.0.5 16 | SET R_INSTALLER=R-%R_VERSION%-win.exe 17 | SET DEFAULT_R_HOME=%PACKAGES_ROOT%\R-%R_VERSION%-win 18 | 19 | IF "%R_HOME%" == "" ( 20 | REM If R_HOME not defined, download and install R-%R_VERSION% 21 | REM 22 | SET R_HOME=%DEFAULT_R_HOME% 23 | MKDIR %DEFAULT_R_HOME% 24 | powershell -Command "Invoke-WebRequest https://cran.r-project.org/bin/windows/base/old/%R_VERSION%/%R_INSTALLER% -OutFile %DEFAULT_R_HOME%\%R_INSTALLER%" 25 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to download R-%R_VERSION%." || EXIT /b %ERRORLEVEL% 26 | %DEFAULT_R_HOME%\%R_INSTALLER% /VERYSILENT /DIR=%DEFAULT_R_HOME% 27 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to install R-%R_VERSION%." || EXIT /b %ERRORLEVEL% 28 | ) ELSE ( 29 | ECHO Using the already defined R_HOME=%R_HOME% 30 | ) 31 | 32 | SET R_BIN_PATH=%R_HOME%\bin 33 | 34 | SETLOCAL enabledelayedexpansion 35 | SET R_LIBRARY_PATH=%R_HOME%\library 36 | 37 | REM Get RTools35 for mingw32-make and rtools40 for g++ v8.3.0 that works with C++17. 38 | REM 39 | SET RTOOLS_HOME=%PACKAGES_ROOT%\Rtools 40 | MKDIR %RTOOLS_HOME% 41 | powershell -Command "Invoke-WebRequest https://cran.r-project.org/bin/windows/Rtools/Rtools35.exe -OutFile %RTOOLS_HOME%\Rtools35.exe" 42 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to download Rtools3.5." || EXIT /b %ERRORLEVEL% 43 | powershell -Command "Invoke-WebRequest https://cran.r-project.org/bin/windows/Rtools/rtools40-x86_64.exe -OutFile %RTOOLS_HOME%\rtools40.exe" 44 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to download Rtools4.0." || EXIT /b %ERRORLEVEL% 45 | 46 | REM Install RTools 47 | REM 48 | "%RTOOLS_HOME%\Rtools35.exe" /VERYSILENT /DIR="C:\Rtools\" 49 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to install Rtools3.5." || EXIT /b %ERRORLEVEL% 50 | "%RTOOLS_HOME%\rtools40.exe" /VERYSILENT /DIR="C:\rtools40\" 51 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to install Rtools4.0." || EXIT /b %ERRORLEVEL% 52 | 53 | REM Install Rcpp and RInside 54 | REM Setting PATH to access make.exe 55 | REM 56 | SET PATH=C:\rtools40\usr\bin;%PATH% 57 | 58 | "%R_BIN_PATH%\R" -e "install.packages('https://cran.r-project.org/src/contrib/Archive/Rcpp/Rcpp_1.0.6.tar.gz', lib = '!R_LIBRARY_PATH:\=/!', repos = NULL, type='source')" 59 | "%R_BIN_PATH%\R" -e "stopifnot(require(Rcpp))" 60 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to install Rcpp package" || EXIT /b %ERRORLEVEL% 61 | 62 | "%R_BIN_PATH%\R" -e "install.packages('https://cran.r-project.org/src/contrib/Archive/RInside/RInside_0.2.15.tar.gz', lib = '!R_LIBRARY_PATH:\=/!', repos = NULL, , type='source')" 63 | "%R_BIN_PATH%\R" -e "stopifnot(require(RInside))" 64 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to install RInside package" || EXIT /b %ERRORLEVEL% 65 | SETLOCAL disabledelayedexpansion 66 | 67 | EXIT /b %ERRORLEVEL% 68 | 69 | :CHECKERROR 70 | IF %1 NEQ 0 ( 71 | ECHO %2 72 | EXIT /b %1 73 | ) 74 | 75 | EXIT /b 0 76 | -------------------------------------------------------------------------------- /language-extensions/python/test/include/PythonLibraryTests.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonLibraryTests.h 8 | // 9 | // Purpose: 10 | // Define the gtest overrides and the External Library tests 11 | // 12 | //************************************************************************************************* 13 | #pragma once 14 | #include "Common.h" 15 | #ifdef _WIN64 16 | #include 17 | namespace fs = std::filesystem; 18 | #else 19 | #include 20 | namespace fs = std::experimental::filesystem; 21 | #endif 22 | 23 | namespace LibraryApiTests 24 | { 25 | // All the tests in the LibraryApiTests suite run one after the other 26 | // 27 | class ExternalLibraryApiTests : public ::testing::Test 28 | { 29 | protected: 30 | // Code here will be called immediately after the constructor (right 31 | // before each test). 32 | // 33 | void SetUp() override; 34 | 35 | // Code here will be called immediately after each test (right 36 | // before the destructor). 37 | // 38 | void TearDown() override; 39 | 40 | // Set up default, valid variables for use in tests 41 | // 42 | void SetupVariables(); 43 | 44 | // Call Cleanup on the PythonExtension. 45 | // Testing if Cleanup is implemented correctly. 46 | // 47 | void DoCleanup(); 48 | 49 | // Cleanup sys.modules in python to remove import traces 50 | // 51 | void CleanModules(std::string extLibName, std::string moduleName); 52 | 53 | // Install and test a package 54 | // 55 | void InstallAndTest( 56 | std::string extLibName, 57 | std::string moduleName, 58 | std::string pathToPackage, 59 | std::string installDir, 60 | std::string expectedVersion, 61 | std::string expectedLocation = "", 62 | bool successfulInstall = true, 63 | bool successfulImport = true); 64 | 65 | // Uninstall and test a package 66 | // 67 | void UninstallAndTest( 68 | std::string extLibName, 69 | std::string moduleName, 70 | std::string installDir, 71 | bool otherInstallationExists = false); 72 | 73 | // Initialize pythonextension for library management 74 | // 75 | void Initialize(); 76 | 77 | // Filesystem path to the packages we will install 78 | // 79 | fs::path m_packagesPath; 80 | 81 | // Some temp paths for public and private libraries 82 | // 83 | std::string m_libraryPath = "testInstallPkgs"; 84 | std::string m_publicLibraryPath; 85 | std::string m_privateLibraryPath; 86 | std::string m_pathToPython; 87 | 88 | // The boost python module; python will run in this object 89 | // 90 | boost::python::object m_mainModule; 91 | 92 | // The boost python namespace; backup dictionary containing all builtins 93 | // 94 | boost::python::dict m_backupNamespace; 95 | 96 | // The main namespace. We use this for all execution 97 | // 98 | boost::python::dict m_mainNamespace; 99 | 100 | }; 101 | } 102 | -------------------------------------------------------------------------------- /language-extensions/R/test/build/windows/build-RExtension-test.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | SETLOCAL 3 | 4 | REM Set environment variables 5 | REM 6 | SET ENL_ROOT=%~dp0..\..\..\..\.. 7 | SET REXTENSIONTEST_HOME=%ENL_ROOT%\language-extensions\R\test 8 | SET REXTENSIONTEST_WORKING_DIR=%ENL_ROOT%\build-output\RExtension-test\windows 9 | SET PACKAGES_ROOT=%ENL_ROOT%\packages 10 | SET DEFAULT_R_HOME=%PACKAGES_ROOT%\R-4.0.5-win 11 | SET DEFAULT_CMAKE_ROOT=%PACKAGES_ROOT%\CMake-win64.3.15.5 12 | 13 | REM Find R_HOME and CMAKE_ROOT from user, or set to default. 14 | REM Error code 203 is ENVVAR_NOT_FOUND. 15 | REM 16 | SET ENVVAR_NOT_FOUND=203 17 | 18 | IF "%R_HOME%" == "" ( 19 | IF EXIST %DEFAULT_R_HOME% ( 20 | SET R_HOME=%DEFAULT_R_HOME% 21 | ) ELSE ( 22 | CALL :CHECKERROR %ENVVAR_NOT_FOUND% "Error: R_HOME variable must be set to build RExtension-test" || EXIT /b %ENVVAR_NOT_FOUND% 23 | ) 24 | ) 25 | 26 | IF "%CMAKE_ROOT%" == "" ( 27 | IF EXIST %DEFAULT_CMAKE_ROOT% ( 28 | SET CMAKE_ROOT=%DEFAULT_CMAKE_ROOT% 29 | ) ELSE ( 30 | CALL :CHECKERROR %ENVVAR_NOT_FOUND% "Error: CMAKE_ROOT variable must be set to build RExtension-test" || EXIT /b %ENVVAR_NOT_FOUND% 31 | ) 32 | ) 33 | 34 | REM Create build working directory 35 | REM 36 | RMDIR /s /q %REXTENSIONTEST_WORKING_DIR% 37 | MKDIR %REXTENSIONTEST_WORKING_DIR% 38 | 39 | :LOOP 40 | 41 | REM Set cmake config to first arg 42 | REM 43 | SET CMAKE_CONFIGURATION=%1 44 | 45 | REM The string comparison for CMAKE_CONFIGURATION is case-insensitive. 46 | REM 47 | IF NOT DEFINED CMAKE_CONFIGURATION (SET CMAKE_CONFIGURATION=release) 48 | IF /I NOT %CMAKE_CONFIGURATION%==debug (SET CMAKE_CONFIGURATION=release) 49 | 50 | SET BUILD_OUTPUT=%REXTENSIONTEST_WORKING_DIR%\%CMAKE_CONFIGURATION% 51 | MKDIR %BUILD_OUTPUT% 52 | PUSHD %BUILD_OUTPUT% 53 | 54 | REM Make sure g++ is in the PATH. 55 | REM Do not enclose the C:\Rtools\mingw_64\bin path in quotes - cmake test fails 56 | REM Also need to have R_HOME\bin\x64 in the PATH so that linker finds definitions for R functions. 57 | REM 58 | SET PATH=C:\rtools40\mingw64\bin;C:\Rtools\mingw_64\bin;%R_HOME%\bin\x64;%PATH% 59 | 60 | ECHO "[INFO] Generating RExtension test project build files using CMAKE_CONFIGURATION=%CMAKE_CONFIGURATION%" 61 | 62 | REM Call cmake 63 | call "%CMAKE_ROOT%\bin\cmake.exe" ^ 64 | -G "MinGW Makefiles" ^ 65 | -DCMAKE_INSTALL_PREFIX:PATH="%REXTENSIONTEST_WORKING_DIR%\\%CMAKE_CONFIGURATION%" ^ 66 | -DENL_ROOT="%ENL_ROOT%" ^ 67 | -DCMAKE_MAKE_PROGRAM=mingw32-make ^ 68 | -DCMAKE_BUILD_TYPE=%CMAKE_CONFIGURATION% ^ 69 | -DPLATFORM=windows ^ 70 | -DR_HOME="%R_HOME%" ^ 71 | "%REXTENSIONTEST_HOME%\src" 72 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to generate make files for CMAKE_CONFIGURATION=%CMAKE_CONFIGURATION%" || EXIT /b %ERRORLEVEL% 73 | 74 | ECHO "[INFO] Building RExtension test project using CMAKE_CONFIGURATION=%CMAKE_CONFIGURATION%" 75 | REM Call cmake build 76 | REM 77 | CALL "mingw32-make.exe" -j all 78 | CALL :CHECKERROR %ERRORLEVEL% "Error: Failed to build RExtension-test for CMAKE_CONFIGURATION=%CMAKE_CONFIGURATION%" || EXIT /b %ERRORLEVEL% 79 | 80 | REM Advance arg passed to build-RExtension-test.cmd 81 | REM 82 | SHIFT 83 | 84 | REM Continue building using more configs until argv has been exhausted 85 | REM 86 | IF NOT "%~1"=="" GOTO LOOP 87 | 88 | EXIT /b %ERRORLEVEL% 89 | 90 | :CHECKERROR 91 | IF %1 NEQ 0 ( 92 | ECHO %2 93 | EXIT /b %1 94 | ) 95 | 96 | EXIT /b 0 97 | -------------------------------------------------------------------------------- /language-extensions/python/src/linux/PythonExtensionUtils_linux.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonExtensionUtils_linux.cpp 8 | // 9 | // Purpose: 10 | // Linux specific utility functions for Python Extension 11 | // 12 | //************************************************************************************************* 13 | 14 | #include 15 | #include 16 | 17 | #include "Logger.h" 18 | #include "PythonExtensionUtils.h" 19 | 20 | namespace fs = std::experimental::filesystem; 21 | 22 | const CHAR *GuidFormat = "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"; 23 | 24 | //-------------------------------------------------------------------------------------------------- 25 | // Name: PythonExtensionUtils::GetEnvVariable 26 | // 27 | // Description: 28 | // Get the value of an environment variable 29 | // 30 | // Returns: 31 | // String value of the environment variable requested 32 | // 33 | std::string PythonExtensionUtils::GetEnvVariable(const std::string &envVarName) 34 | { 35 | char* envVarValue; 36 | envVarValue = getenv(envVarName.c_str()); 37 | 38 | if (envVarValue == NULL) 39 | { 40 | throw std::runtime_error("Error while loading " + envVarName); 41 | } 42 | 43 | return std::string(envVarValue); 44 | } 45 | 46 | //-------------------------------------------------------------------------------------------------- 47 | // Name: PythonExtensionUtils::ConvertGuidToString 48 | // 49 | // Description: 50 | // Converts a SQLGUID to a string 51 | // 52 | // Returns: 53 | // string of the guid 54 | // 55 | std::string PythonExtensionUtils::ConvertGuidToString(const SQLGUID *guid) 56 | { 57 | // 32 hex chars + 4 hyphens + null terminator, so 37 characters. 58 | // 59 | char guidString[37]; 60 | 61 | snprintf(guidString, sizeof(guidString) / sizeof(guidString[0]), 62 | GuidFormat, 63 | static_cast(guid->Data1), guid->Data2, guid->Data3, 64 | guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], 65 | guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); 66 | 67 | std::string s(guidString); 68 | 69 | return s; 70 | } 71 | 72 | //-------------------------------------------------------------------------------------------------- 73 | // Name: PythonExtensionUtils::FreeDLL 74 | // 75 | // Description: 76 | // Close an open dll handle 77 | // 78 | void PythonExtensionUtils::FreeDLL(void *pDll) 79 | { 80 | if (pDll != nullptr) 81 | { 82 | dlclose(pDll); 83 | } 84 | } 85 | 86 | //-------------------------------------------------------------------------------------------------- 87 | // Name: PythonExtensionUtils::GetEnvVariable 88 | // 89 | // Description: 90 | // Get the path to the python executable 91 | // 92 | // Returns: 93 | // String value of the python executable path 94 | // 95 | std::string PythonExtensionUtils::GetPathToPython() 96 | { 97 | fs::path pathToPython = fs::path("python3.12"); 98 | return pathToPython.string(); 99 | } 100 | -------------------------------------------------------------------------------- /language-extensions/python/test/src/PythonInitColumnTests.cpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************************* 2 | // Copyright (C) Microsoft Corporation. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // @File: PythonInitColumnTests.cpp 8 | // 9 | // Purpose: 10 | // Test the Python extension columns using the Extension API 11 | // 12 | //************************************************************************************************* 13 | #include "PythonExtensionApiTests.h" 14 | 15 | namespace ExtensionApiTest 16 | { 17 | // Name: InitColumnTest 18 | // 19 | // Description: 20 | // Test InitColumn() API with valid values 21 | // 22 | TEST_F(PythonExtensionApiTests, InitColumnTest) 23 | { 24 | InitializeSession(0, // paramsNumber 25 | 1); // inputSchemaColumns 26 | 27 | SQLCHAR * columnName = static_cast( 28 | static_cast(const_cast("Column1"))); 29 | SQLSMALLINT columnNameLength = 7; 30 | SQLRETURN result = InitColumn( 31 | *m_sessionId, 32 | m_taskId, 33 | 0, // Column Number 34 | columnName, 35 | columnNameLength, 36 | SQL_C_SLONG, // Data Type 37 | m_IntSize, // Column Size 38 | 0, // Decimal Digits 39 | 1, // Nullable 40 | -1, // PartitionByNumber 41 | -1 // OrderByNumber 42 | ); 43 | EXPECT_EQ(result, SQL_SUCCESS); 44 | } 45 | 46 | // 47 | // Negative Tests 48 | // 49 | 50 | // Name: InitInvalidColumnTest 51 | // 52 | // Description: 53 | // Test InitColumn() API with null column name 54 | // 55 | TEST_F(PythonExtensionApiTests, InitInvalidColumnTest) 56 | { 57 | InitializeSession(0, // paramsNumber 58 | 1); // inputSchemaColumns 59 | 60 | SQLRETURN result = InitColumn( 61 | *m_sessionId, 62 | m_taskId, 63 | 0, // Column Number 64 | nullptr, // Column Name 65 | 0, // Column Name Length 66 | SQL_C_SLONG, // Data Type 67 | m_IntSize, // Column Size 68 | 0, // Decimal Digits 69 | 1, // Nullable 70 | -1, // PartitionByNumber 71 | -1 // OrderByNumber 72 | ); 73 | EXPECT_EQ(result, SQL_ERROR); 74 | } 75 | 76 | // Name: InitInvalidColumnNumberTest 77 | // 78 | // Description: 79 | // Test InitColumn() API with bad column numbers (too big) 80 | // 81 | TEST_F(PythonExtensionApiTests, InitInvalidColumnNumberTest) 82 | { 83 | InitializeSession(1); 84 | 85 | SQLCHAR * columnName = static_cast( 86 | static_cast(const_cast("Column1"))); 87 | SQLSMALLINT columnNameLength = 7; 88 | 89 | SQLRETURN result = InitColumn( 90 | *m_sessionId, 91 | m_taskId, 92 | 2, // column number greater than initialized columns 93 | columnName, 94 | columnNameLength, 95 | SQL_C_SLONG, // Data Type 96 | m_IntSize, // Column Size 97 | 0, // Decimal Digits 98 | 1, // Nullable 99 | -1, // PartitionByNumber 100 | -1 // OrderByNumber 101 | ); 102 | EXPECT_EQ(result, SQL_ERROR); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /language-extensions/R/include/REnvironment.h: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // RExtension : A language extension implementing the SQL Server 3 | // external language communication protocol for R. 4 | // Copyright (C) 2020 Microsoft Corporation. 5 | // 6 | // This file is part of RExtension. 7 | // 8 | // RExtension is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // RExtension is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with RExtension. If not, see . 20 | // 21 | // @File: REnvironment.h 22 | // 23 | // Purpose: 24 | // Class to keep the global embedded R environment. 25 | // 26 | //************************************************************************************************** 27 | 28 | #pragma once 29 | 30 | //-------------------------------------------------------------------------------------------------- 31 | // Name: REnvironment 32 | // 33 | // Description: 34 | // Global class storing the global embedded R environment. 35 | // 36 | class REnvironment 37 | { 38 | public: 39 | 40 | // Initializes this global class 41 | // 42 | static void Init(SQLULEN extensionParamsLength); 43 | 44 | // Cleans up this global class 45 | // 46 | static void Cleanup(); 47 | 48 | // Gets the global embedded R environment as an RInside object pointer. 49 | // 50 | static RInside* EmbeddedREnvironment() 51 | { 52 | if (sm_embeddedREnvPtr == nullptr) 53 | { 54 | throw std::runtime_error("Embedded R environment has not been initialized."); 55 | } 56 | 57 | return sm_embeddedREnvPtr.get(); 58 | } 59 | 60 | // Encloses the given script in a try catch block. 61 | // 62 | static std::string GetScriptWithTryCatch(const std::string &script); 63 | 64 | private: 65 | 66 | // An unique pointer to the embedded R environment via RInside. 67 | // We execute all R scripts in this environment and there can only be a single 68 | // instance of RInside in the extension. 69 | // Avoid using a shared pointer since it leads to data races. 70 | // 71 | static std::unique_ptr sm_embeddedREnvPtr; 72 | 73 | // Original library path 74 | // 75 | static std::unique_ptr sm_originalPath; 76 | }; 77 | 78 | #ifdef _WIN32 79 | #define REXTENSION_INTERFACE __declspec(dllexport) 80 | #elif __linux__ 81 | #define REXTENSION_INTERFACE __attribute__((visibility("default"))) 82 | #else 83 | #define REXTENSION_INTERFACE 84 | #endif 85 | 86 | #ifdef __cplusplus 87 | extern "C" { 88 | #endif/* __cplusplus */ 89 | 90 | // Simply executes the given script. 91 | // 92 | REXTENSION_INTERFACE void ExecuteScript(const std::string &script); 93 | 94 | // Executes the given script and returns the result as an SEXP pointer. 95 | // 96 | REXTENSION_INTERFACE SEXP ExecuteScriptAndGetResult(const std::string &script); 97 | 98 | #ifdef __cplusplus 99 | } /* End of extern "C" { */ 100 | #endif/* __cplusplus */ 101 | --------------------------------------------------------------------------------