diff --git a/.gitignore b/.gitignore index dd9b4ee..780389a 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ LICENSE.txt /IntegrationTests/ /opensearchenlist/ /sqlodbc/ +/output/ /PerformanceTests/ /UnitTests/ *.filters @@ -60,3 +61,6 @@ CTestTestfile.cmake /src/PowerBIConnector/obj/ /src/PowerBIConnector/.vs/ src/vcpkg_installed/ +/extensionBiConnector/ +/comparisonBiConnector/ +/extensionTableauConnector/ diff --git a/CppProperties.json b/CppProperties.json new file mode 100644 index 0000000..6017def --- /dev/null +++ b/CppProperties.json @@ -0,0 +1,21 @@ +{ + "configurations": [ + { + "inheritEnvironments": [ + "msvc_x64" + ], + "name": "x64-Release", + "includePath": [ + "${env.INCLUDE}", + "${workspaceRoot}\\**" + ], + "defines": [ + "WIN32", + "NDEBUG", + "UNICODE", + "_UNICODE" + ], + "intelliSenseMode": "windows-msvc-x64" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 8d58c9c..bb76f41 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # OpenSearch ODBC Driver -OpenSearchODBC is a read-only ODBC driver for Windows and Mac for connecting to OpenSearch SQL support. +OpenSearchODBC is a read-only ODBC driver for Windows and Mac for connecting to OpenSearch SQL support. This driver version allows to levereage on Oauth2 authentication/authorization. ### ODBC Driver diff --git a/bi-connectors/PowerBIConnector/AmazonOpenSearchService.md b/bi-connectors/PowerBIConnector/AmazonOpenSearchService.md index 8f665b9..a1c4ec1 100644 --- a/bi-connectors/PowerBIConnector/AmazonOpenSearchService.md +++ b/bi-connectors/PowerBIConnector/AmazonOpenSearchService.md @@ -52,7 +52,7 @@ ## Troubleshooting -* If you get the following error, please install the [OpenSearch SQL ODBC Driver](https://docs-beta.opensearch.org/search-plugins/sql/odbc/). +* If you get the following error, please install the [OpenSearch SQL ODBC Driver](https://opensearch.org/docs/latest/search-plugins/sql/sql/odbc/). diff --git a/bi-connectors/PowerBIConnector/OpenSearchProject.md b/bi-connectors/PowerBIConnector/OpenSearchProject.md index 7153d56..f7c4fea 100644 --- a/bi-connectors/PowerBIConnector/OpenSearchProject.md +++ b/bi-connectors/PowerBIConnector/OpenSearchProject.md @@ -23,36 +23,53 @@ ## Connect to OpenSearch Project 1. Open Power BI Desktop. -2. Click on **Home** > **Get Data** > **More** > **Other**. Select **OpenSearch Project**. Click on **Connect**. +2. If necessary clear the previous permissions. + + + +3. Click on **Home** > **Get Data** > **More** > **Other**. Select **OpenSearch Project**. Click on **Connect**. -3. You will get a warning for using a third-party service. Click on **Continue**. +4. You will get a warning for using a third-party service. Click on **Continue**. -4. Enter host and port values and select your preferred SSL and Certificate validation options. Click on **OK**. +5. Enter host and port values and select your preferred SSL and Certificate validation options. Click on **OK**. -5. Select authentication option. Enter credentials if required and click on **Connect**. +6. Select authentication option. Enter credentials if required and click on **Connect**. -6. Select required table. Data preview will be loaded. +7. Select required table. Data preview will be loaded. -7. Click on **Load**. +8. Click on **Load**. -8. Select required columns for creating a graph. +9. Select required columns for creating a graph. +## Set up Oauth2 + +* In the same folder of the source files to build put a JSON file filling the three fields required in the template provided. + +## Login with Oauth2 + +1. Select the `OAUTH2` authentication and click on **Sign In** + + + +2. After provided the user-id and the user-secret, click on **Connect** + + ## Troubleshooting -* If you get the following error, please install the [OpenSearch SQL ODBC Driver](https://docs-beta.opensearch.org/search-plugins/sql/odbc/). +* If you get the following error, please install the [OpenSearch SQL ODBC Driver](https://opensearch.org/docs/latest/search-plugins/sql/sql/odbc/). diff --git a/bi-connectors/PowerBIConnector/README.md b/bi-connectors/PowerBIConnector/README.md index 9d90dc6..7eab3e2 100644 --- a/bi-connectors/PowerBIConnector/README.md +++ b/bi-connectors/PowerBIConnector/README.md @@ -3,6 +3,18 @@ The Power BI connector is available to download from the automated CI workflow: [link](https://github.com/opensearch-project/sql-odbc/actions/workflows/bi-connectors.yml). The release snapshots are also available here: [OpenSearch Project](OpenSearchProject.mez) and [Amazon OpenSearch Service](AmazonOpenSearchService.mez). +## Connector Development + +The development of the connector is related to the PoweQuery SDK for [VisualStudio](https://marketplace.visualstudio.com/items?itemName=Dakahn.PowerQuerySDK) or for Visual Studio Code from the `Extensions` left tab. + +Is possible to initialize a project for example in VSC with + +The main logic is in `.pq` file (not `.query.pq`) and is not possible to have multiple files of this extension. In connector development there are limitation to the functionalities that is possibile to use as the [data source functions](https://learn.microsoft.com/en-us/power-query/handling-data-access#data-source-functions). The reference and guides of [Power Query M](https://learn.microsoft.com/en-us/powerquery-m/) is available. + +After created the program it is required to run compiling and packaging phases as . + +The output `.mez` file will appear in `bin\AnyCPU\Debug` of the same folder. + ## Connector Install 1. Put connector `mez` file into: `C:\Users\%USERNAME%\Documents\Power BI Desktop\Custom Connectors`. diff --git a/bi-connectors/PowerBIConnector/img/Oauth2_init.png b/bi-connectors/PowerBIConnector/img/Oauth2_init.png new file mode 100644 index 0000000..d5de4e1 Binary files /dev/null and b/bi-connectors/PowerBIConnector/img/Oauth2_init.png differ diff --git a/bi-connectors/PowerBIConnector/img/Oauth2_signedIn.png b/bi-connectors/PowerBIConnector/img/Oauth2_signedIn.png new file mode 100644 index 0000000..714d54b Binary files /dev/null and b/bi-connectors/PowerBIConnector/img/Oauth2_signedIn.png differ diff --git a/bi-connectors/PowerBIConnector/img/build_task.png b/bi-connectors/PowerBIConnector/img/build_task.png new file mode 100644 index 0000000..58e5e91 Binary files /dev/null and b/bi-connectors/PowerBIConnector/img/build_task.png differ diff --git a/bi-connectors/PowerBIConnector/img/powerbi_cached.png b/bi-connectors/PowerBIConnector/img/powerbi_cached.png new file mode 100644 index 0000000..730a3ad Binary files /dev/null and b/bi-connectors/PowerBIConnector/img/powerbi_cached.png differ diff --git a/bi-connectors/PowerBIConnector/img/powerquery_SDK.png b/bi-connectors/PowerBIConnector/img/powerquery_SDK.png new file mode 100644 index 0000000..c190784 Binary files /dev/null and b/bi-connectors/PowerBIConnector/img/powerquery_SDK.png differ diff --git a/bi-connectors/PowerBIConnector/power_bi_support.md b/bi-connectors/PowerBIConnector/power_bi_support.md index 2c5451a..ba20d0e 100644 --- a/bi-connectors/PowerBIConnector/power_bi_support.md +++ b/bi-connectors/PowerBIConnector/power_bi_support.md @@ -2,8 +2,8 @@ ## Prerequisites * Microsoft Power BI Desktop -* [OpenSearch](https://docs-beta.opensearch.org/opensearch/install/index/) -* [OpenSearch SQL ODBC driver](https://docs-beta.opensearch.org/search-plugins/sql/odbc/) +* [OpenSearch](https://opensearch.org/docs/latest/install-and-configure/install-opensearch/index/) +* [OpenSearch SQL ODBC driver](https://opensearch.org/docs/latest/search-plugins/sql/sql/odbc/) * [OpenSearchProject.mez](OpenSearchProject.mez) or [AmazonOpenSearchService.mez](AmazonOpenSearchService.mez) * Optional: [sqlodbc_import.pbids](PBIDSExamples/sqlodbc_import.pbids) to help with repeated connections to the same server @@ -86,7 +86,7 @@ It will take you straight to the **Navigator** window for selecting the tables f ## Troubleshooting -* If you get an following error, please install [OpenSearch SQL ODBC Driver](https://docs-beta.opensearch.org/search-plugins/sql/odbc/). +* If you get an following error, please install [OpenSearch SQL ODBC Driver](https://opensearch.org/docs/latest/search-plugins/sql/sql/odbc/). diff --git a/bi-connectors/PowerBIConnector/src/OauthConf.json b/bi-connectors/PowerBIConnector/src/OauthConf.json new file mode 100644 index 0000000..c727fdb --- /dev/null +++ b/bi-connectors/PowerBIConnector/src/OauthConf.json @@ -0,0 +1,5 @@ +{ + "ClientId": "", + "ClientSecret": "", + "IDPurl": "" +} \ No newline at end of file diff --git a/bi-connectors/PowerBIConnector/src/OpenSearchProject.pq b/bi-connectors/PowerBIConnector/src/OpenSearchProject.pq index 9a2d67d..b14be50 100644 --- a/bi-connectors/PowerBIConnector/src/OpenSearchProject.pq +++ b/bi-connectors/PowerBIConnector/src/OpenSearchProject.pq @@ -2,47 +2,57 @@ [Version = "1.0.1"] section OpenSearchProject; -// When set to true, additional trace information will be written out to the User log. -// This should be set to false before release. Tracing is done through a call to -// Diagnostics.LogValue(). When EnableTraceOutput is set to false, the call becomes a +// When set to true, additional trace information will be written out to the User log. +// This should be set to false before release. Tracing is done through a call to +// Diagnostics.LogValue(). When EnableTraceOutput is set to false, the call becomes a // no-op and simply returns the original value. -EnableTraceOutput = false; -[DataSource.Kind="OpenSearchProject", Publish="OpenSearchProject.Publish"] +config = Text.FromBinary(Extension.Contents("OauthConf.json")); + +EnableTraceOutput = true; + +[DataSource.Kind = "OpenSearchProject", Publish = "OpenSearchProject.Publish"] shared OpenSearchProject.Contents = Value.ReplaceType(OpenSearchProjectImpl, OpenSearchProjectType); // Wrapper function to provide additional UI customization. OpenSearchProjectType = type function ( - Server as (type text meta [ + Server as ( + type text meta [ Documentation.FieldCaption = "Server", Documentation.FieldDescription = "The hostname of the OpenSearch server.", - Documentation.SampleValues = { "localhost" } - ]), - Port as (type number meta [ + Documentation.SampleValues = {"localhost"} + ] + ), + Port as ( + type number meta [ Documentation.FieldCaption = "Port", Documentation.FieldDescription = "Port which OpenSearch server listens on.", - Documentation.SampleValues = { 9200 } - ]), - UseSSL as (type logical meta [ + Documentation.SampleValues = {9200} + ] + ), + UseSSL as ( + type logical meta [ Documentation.FieldCaption = "Use SSL", Documentation.FieldDescription = "Use SSL", - Documentation.AllowedValues = { true, false } - ]), - HostnameVerification as (type logical meta [ + Documentation.AllowedValues = {true, false} + ] + ), + HostnameVerification as ( + type logical meta [ Documentation.FieldCaption = "Certificate validation", Documentation.FieldDescription = "Certificate validation", - Documentation.AllowedValues = { true, false } - ]) + Documentation.AllowedValues = {true, false} + ] ) - as table meta [ - Documentation.Name = "OpenSearch Project" - ]; +) as table meta [ + Documentation.Name = "OpenSearch Project" +]; + OpenSearchProjectImpl = (Server as text, Port as number, UseSSL as logical, HostnameVerification as logical) as table => let Credential = Extension.CurrentCredential(), AuthenticationMode = Credential[AuthenticationKind], - // Sets connection string properties for authentication. CredentialConnectionString = if AuthenticationMode = "UsernamePassword" then @@ -56,11 +66,15 @@ OpenSearchProjectImpl = (Server as text, Port as number, UseSSL as logical, Host Auth = "AWS_SIGV4", Region = Credential[Key] ] - else + else if AuthenticationMode = "OAuth" then + [ + Auth = "OAUTH2", + JWT = Credential[access_token] + ] + else [ Auth = "NONE" ], - // Sets connection string properties for encrypted connections. EncryptedConnectionString = if Credential[EncryptConnection] = null or Credential[EncryptConnection] = true then @@ -71,40 +85,46 @@ OpenSearchProjectImpl = (Server as text, Port as number, UseSSL as logical, Host [ UseSSL = 0 ], - // Subtract the server from the user input in case it's entered like 'http://localhost' or 'https://srv.com:100500' or 'localhost:0' // And build the proper string on our own - FinalServerString = if UseSSL then + FinalServerString = + if UseSSL then "https://" & Uri.Parts(Server)[Host] & ":" & Text.From(Port) else "http://" & Uri.Parts(Server)[Host] & ":" & Text.From(Port), - ConnectionString = [ Driver = "OpenSearch SQL ODBC Driver", Host = FinalServerString, HostnameVerification = if HostnameVerification then 1 else 0 ], - - SQLGetInfo = Diagnostics.LogValue("SQLGetInfo_Options", [ - SQL_AGGREGATE_FUNCTIONS = ODBC[SQL_AF][All], - SQL_SQL_CONFORMANCE = ODBC[SQL_SC][SQL_SC_SQL92_INTERMEDIATE] - ]), - - SQLGetTypeInfo = (types) => - if (EnableTraceOutput <> true) then types else - let - // Outputting the entire table might be too large, and result in the value being truncated. - // We can output a row at a time instead with Table.TransformRows() - rows = Table.TransformRows(types, each Diagnostics.LogValue("SQLGetTypeInfo " & _[TYPE_NAME], _)), - toTable = Table.FromRecords(rows) - in - Value.ReplaceType(toTable, Value.Type(types)), - + SQLGetInfo = Diagnostics.LogValue( + "SQLGetInfo_Options", + [ + SQL_AGGREGATE_FUNCTIONS = ODBC[SQL_AF][All], + SQL_SQL_CONFORMANCE = ODBC[SQL_SC][SQL_SC_SQL92_INTERMEDIATE] + ] + ), + SQLGetTypeInfo = (types) => + if (EnableTraceOutput <> true) then + types + else + let + // Outputting the entire table might be too large, and result in the value being truncated. + // We can output a row at a time instead with Table.TransformRows() + rows = Table.TransformRows(types, each Diagnostics.LogValue("SQLGetTypeInfo " & _[TYPE_NAME], _)), + toTable = Table.FromRecords(rows) + in + Value.ReplaceType(toTable, Value.Type(types)), // SQLColumns is a function handler that receives the results of an ODBC call to SQLColumns(). SQLColumns = (catalogName, schemaName, tableName, columnName, source) => - if (EnableTraceOutput <> true) then source else + if (EnableTraceOutput <> true) then + source + else // the if statement conditions will force the values to evaluated/written to diagnostics - if (Diagnostics.LogValue("SQLColumns.TableName", tableName) <> "***" and Diagnostics.LogValue("SQLColumns.ColumnName", columnName) <> "***") then + if ( + Diagnostics.LogValue("SQLColumns.TableName", tableName) <> "***" + and Diagnostics.LogValue("SQLColumns.ColumnName", columnName) <> "***" + ) then let // Outputting the entire table might be too large, and result in the value being truncated. // We can output a row at a time instead with Table.TransformRows() @@ -114,24 +134,24 @@ OpenSearchProjectImpl = (Server as text, Port as number, UseSSL as logical, Host Value.ReplaceType(toTable, Value.Type(source)) else source, - SQLGetFunctions = Diagnostics.LogValue("SQLGetFunctions_Options", [ SQL_API_SQLBINDPARAMETER = false ]), - - SqlCapabilities = Diagnostics.LogValue("SqlCapabilities_Options", [ - SupportsTop = false, - LimitClauseKind = LimitClauseKind.LimitOffset, - Sql92Conformance = ODBC[SQL_SC][SQL_SC_SQL92_FULL], - SupportsNumericLiterals = true, - SupportsStringLiterals = true, - SupportsOdbcDateLiterals = true, - SupportsOdbcTimeLiterals = true, - SupportsOdbcTimestampLiterals = true - ]), - + SqlCapabilities = Diagnostics.LogValue( + "SqlCapabilities_Options", + [ + SupportsTop = false, + LimitClauseKind = LimitClauseKind.LimitOffset, + Sql92Conformance = ODBC[SQL_SC][SQL_SC_SQL92_FULL], + SupportsNumericLiterals = true, + SupportsStringLiterals = true, + SupportsOdbcDateLiterals = true, + SupportsOdbcTimeLiterals = true, + SupportsOdbcTimestampLiterals = true + ] + ), OdbcOptions = [ - // Do not view the tables grouped by their schema names. + // Do not view the tables grouped by their schema names. HierarchicalNavigation = false, // Prevents execution of native SQL statements. Extensions should set this to true. HideNativeQuery = true, @@ -141,22 +161,17 @@ OpenSearchProjectImpl = (Server as text, Port as number, UseSSL as logical, Host TolerateConcatOverflow = true, // Enables connection pooling via the system ODBC manager ClientConnectionPooling = true, - // These values should be set by previous steps SQLColumns = SQLColumns, SQLGetTypeInfo = SQLGetTypeInfo, SQLGetInfo = SQLGetInfo, SQLGetFunctions = SQLGetFunctions, SqlCapabilities = SqlCapabilities, - OnError = OnOdbcError, - // Connection string properties used for encrypted connections. CredentialConnectionString = EncryptedConnectionString ], - FullConnectionString = (ConnectionString & CredentialConnectionString & EncryptedConnectionString), - OdbcDatasource = Odbc.DataSource(FullConnectionString, OdbcOptions) in OdbcDatasource; @@ -165,28 +180,31 @@ OpenSearchProjectImpl = (Server as text, Port as number, UseSSL as logical, Host OnOdbcError = (errorRecord as record) => let ErrorMessage = errorRecord[Message], - ConnectionServer = errorRecord[Detail][DataSourcePath], - + ConnectionServer = errorRecord[Detail][DataSourcePath], IsDriverNotInstalled = Text.Contains(ErrorMessage, "doesn't correspond to an installed ODBC driver"), - OdbcError = errorRecord[Detail][OdbcErrors]{0}, OdbcErrorCode = OdbcError[NativeError], - // Failed to connect to given host - IsHostUnreachable = - OdbcErrorCode = 202 + IsHostUnreachable = OdbcErrorCode = 202 in if IsDriverNotInstalled then - error Error.Record("DataSource.Error", "The OpenSearch SQL ODBC driver is not installed. Please install the driver") - else if IsHostUnreachable then - error Error.Record("DataSource.Error", "Couldn't reach server. Please double-check the server and auth. [" & ConnectionServer & "]") - else + error + Error.Record( + "DataSource.Error", "The OpenSearch SQL ODBC driver is not installed. Please install the driver" + ) + else if IsHostUnreachable then + error + Error.Record( + "DataSource.Error", + "Couldn't reach server. Please double-check the server and auth. [" & ConnectionServer & "]" + ) + else error errorRecord; // Data Source Kind description OpenSearchProject = [ - // Required for use with Power BI Service. - TestConnection = (dataSourcePath) => + + TestConnection = (dataSourcePath) => let json = Json.Document(dataSourcePath), Server = json[Server], @@ -194,7 +212,7 @@ OpenSearchProject = [ UseSSL = json[UseSSL], HostnameVerification = json[HostnameVerification] in - { "OpenSearchProject.Contents", Server, Port, UseSSL, HostnameVerification }, + {"OpenSearchProject.Contents", Server, Port, UseSSL, HostnameVerification}, // Authentication modes Authentication = [ @@ -207,25 +225,129 @@ OpenSearchProject = [ Key = [ Label = "AWS_SIGV4", KeyLabel = "Region" + ], + OAuth = [ + Label = "OAUTH2", + StartLogin = StartLogin, + FinishLogin = FinishLogin, + Refresh = Refresh, + Logout = Logout ] ], + callbackUri = "https://oauth.powerbi.com/views/oauthredirect.html", + logout_uri = "https://login.microsoftonline.com/logout.srf", + + oauthConfig = Json.Document(config), + + AuthUrl = oauthConfig [IDPurl] & "auth?", + TokenUrl = oauthConfig [IDPurl] & "token", + LogoutUrl = oauthConfig [IDPurl] & "logout", + ClientId = oauthConfig [ClientId] , + ClientSecret = oauthConfig[ClientSecret], + + Scope = "opensearch", + + // StartLogin function initiates OAuth2 authentication + StartLogin = (resourceUrl, state, display) => + let + AuthorizeUrl = AuthUrl + & Uri.BuildQueryString( + [ + client_id = ClientId, + scope = Scope, + state = state, + response_type = "code", + redirect_uri = callbackUri + ] + ) + in + [ + LoginUri = AuthorizeUrl, + CallbackUri = callbackUri, + WindowHeight = 720, + WindowWidth = 720, + Context = null + ], + + FinishLogin = (context, callbackUri, state) => let Parts = Uri.Parts(callbackUri)[Query] in TokenMethod(Parts[code]), + + TokenMethod = (code) => + let + Response = Web.Contents( + TokenUrl, + [ + Content = Text.ToBinary( + Uri.BuildQueryString( + [ + client_id = ClientId, + client_secret = ClientSecret, + code = code, + grant_type = "authorization_code", + redirect_uri = callbackUri + ] + ) + ), + Headers = [#"Content-type" = "application/x-www-form-urlencoded", #"Accept" = "application/json"] + ] + ), + Parts = Json.Document(Response) + in + Parts, + + Refresh = (refreshToken) => + let + tokenUrl = TokenUrl, + requestBody = "grant_type=refresh_token&refresh_token=" & refreshToken & "&client_id=" & ClientId & "&client_secret=" & ClientSecret, + refreshResponse = Json.Document(Web.Contents(tokenUrl, [Content = Text.ToBinary(requestBody), Headers = [#"Content-Type"="application/x-www-form-urlencoded"]])), + refreshedAccessToken = refreshResponse[access_token] + in + refreshedAccessToken, + + Logout = (accessToken) => + let + logoutUrl = LogoutUrl, + redirectUrl = callbackUri, + response = Web.Contents(logoutUrl, [Query = [redirect_uri = redirectUrl], Headers = [Authorization="Bearer " & accessToken]]) + in + // Assuming successful logout + null, + // PBIDS Handler DSRHandlers = [ - opensearchproject = [ - GetDSR = (Server, Port, UseSSL, HostnameVerification, optional Options) => [ protocol = "opensearchproject-odbc", address = [ server = Server, port = Port, useSSL = UseSSL, hostnameVerification = HostnameVerification ] ], - GetFormula = (dsr, optional options) => () => - let - db = OpenSearchProject.Contents(dsr[address][server], dsr[address][port], dsr[address][useSSL], dsr[address][hostnameVerification]) - in - db, - GetFriendlyName = (dsr) => "OpenSearch Project" - ] + opensearchproject = [ + GetDSR = (Server, Port, UseSSL, HostnameVerification, IDPurl, ClientId, ClientSecret, optional Options) => + [ + protocol = "opensearchproject-odbc", + address = [ + server = Server, + port = Port, + useSSL = UseSSL, + idpURL = IDPurl, + username = ClientId, + secret = ClientSecret, + hostnameVerification = HostnameVerification + ] + ], + GetFormula = (dsr, optional options) => + () => + let + db = OpenSearchProject.Contents( + dsr[address][server], + dsr[address][port], + dsr[address][useSSL], + dsr[address][idpURL], + dsr[address][ClientId], + dsr[address][ClientSecret], + dsr[address][hostnameVerification] + ) + in + db, + GetFriendlyName = (dsr) => "OpenSearch Project" + ] ], - // Enable Encryption SupportsEncryption = true, - Label = Extension.LoadString("DataSourceLabel") ]; @@ -233,30 +355,38 @@ OpenSearchProject = [ OpenSearchProject.Publish = [ Beta = false, Category = "Other", - ButtonText = { Extension.LoadString("ButtonTitle"), Extension.LoadString("ButtonHelp") }, + ButtonText = {Extension.LoadString("ButtonTitle"), Extension.LoadString("ButtonHelp")}, LearnMoreUrl = "https://github.com/opensearch-project/sql-odbc/blob/main/bi-connectors/PowerBIConnector/OpenSearchProject.md", - SupportsDirectQuery = true, - SourceImage = OpenSearch.Icons, SourceTypeImage = OpenSearch.Icons ]; OpenSearch.Icons = [ - Icon16 = { Extension.Contents("OpenSearch16.png"), Extension.Contents("OpenSearch20.png"), Extension.Contents("OpenSearch24.png"), Extension.Contents("OpenSearch32.png") }, - Icon32 = { Extension.Contents("OpenSearch32.png"), Extension.Contents("OpenSearch40.png"), Extension.Contents("OpenSearch48.png"), Extension.Contents("OpenSearch64.png") } + Icon16 = { + Extension.Contents("OpenSearch16.png"), + Extension.Contents("OpenSearch20.png"), + Extension.Contents("OpenSearch24.png"), + Extension.Contents("OpenSearch32.png") + }, + Icon32 = { + Extension.Contents("OpenSearch32.png"), + Extension.Contents("OpenSearch40.png"), + Extension.Contents("OpenSearch48.png"), + Extension.Contents("OpenSearch64.png") + } ]; // Load common library functions Extension.LoadFunction = (name as text) => let - binary = Extension.Contents(name), - asText = Text.FromBinary(binary) + binary = Extension.Contents(name), asText = Text.FromBinary(binary) in Expression.Evaluate(asText, #shared); // Diagnostics module contains multiple functions. . Diagnostics = Extension.LoadFunction("Diagnostics.pqm"); + Diagnostics.LogValue = if (EnableTraceOutput) then Diagnostics[LogValue] else (prefix, value) => value; // OdbcConstants contains numeric constants from the ODBC header files, and helper function to create bitfield values. diff --git a/bi-connectors/PowerBIConnector/src/bin/AnyCPU/Debug/src.mez b/bi-connectors/PowerBIConnector/src/bin/AnyCPU/Debug/src.mez new file mode 100644 index 0000000..ffc3b8e Binary files /dev/null and b/bi-connectors/PowerBIConnector/src/bin/AnyCPU/Debug/src.mez differ diff --git a/build_win_debug32.ps1 b/build_win_debug32.ps1 index 2717064..dd4edd9 100644 --- a/build_win_debug32.ps1 +++ b/build_win_debug32.ps1 @@ -3,4 +3,4 @@ $env:VCPKG_DEFAULT_TRIPLET = 'x86-windows' cd src vcpkg install cd .. -.\scripts\build_windows.ps1 $WORKING_DIR Debug 32 +.\scripts\build_windows.ps1 $WORKING_DIR Debug 32 \ No newline at end of file diff --git a/build_win_debug64.ps1 b/build_win_debug64.ps1 index 98a9a24..ab65d2c 100644 --- a/build_win_debug64.ps1 +++ b/build_win_debug64.ps1 @@ -3,4 +3,4 @@ $env:VCPKG_DEFAULT_TRIPLET = 'x64-windows' cd src vcpkg install cd .. -.\scripts\build_windows.ps1 $WORKING_DIR Debug 64 +.\scripts\build_windows.ps1 $WORKING_DIR Debug 64 \ No newline at end of file diff --git a/build_win_release32.ps1 b/build_win_release32.ps1 index c7e41da..dd7726c 100644 --- a/build_win_release32.ps1 +++ b/build_win_release32.ps1 @@ -3,4 +3,4 @@ $env:VCPKG_DEFAULT_TRIPLET = 'x86-windows' cd src vcpkg install cd .. -.\scripts\build_windows.ps1 $WORKING_DIR Release 32 +.\scripts\build_windows.ps1 $WORKING_DIR Release 32 \ No newline at end of file diff --git a/build_win_release64.ps1 b/build_win_release64.ps1 index a17f4d6..8d1d32b 100644 --- a/build_win_release64.ps1 +++ b/build_win_release64.ps1 @@ -3,4 +3,4 @@ $env:VCPKG_DEFAULT_TRIPLET = 'x64-windows' cd src vcpkg install cd .. -.\scripts\build_windows.ps1 $WORKING_DIR Release 64 +.\scripts\build_windows.ps1 $WORKING_DIR Release 64 \ No newline at end of file diff --git a/docs/dev/BUILD_INSTRUCTIONS.md b/docs/dev/BUILD_INSTRUCTIONS.md index dfd3d77..6eef1c5 100644 --- a/docs/dev/BUILD_INSTRUCTIONS.md +++ b/docs/dev/BUILD_INSTRUCTIONS.md @@ -5,12 +5,11 @@ ### Requirements * Install [cmake](https://cmake.org/install/) -* Install [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) - * Other versions may work, but only 2019 has been tested +* Install [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) (works also with Visual Studio 2022) **NOTE:** All Windows/`.ps1` scripts must be run from a [Developer Powershell](https://devblogs.microsoft.com/visualstudio/the-powershell-you-know-and-love-now-with-a-side-of-visual-studio/). -> A shortcut is installed on your system with Visual Studio (**"Developer Powershell for VS 2019"**) +> A shortcut is installed on your system with Visual Studio (**"Developer Powershell for VS 2019"**) or (**"Developer Powershell for VS 2022"**) > Programs launched with this prompt (ex: VS Code) also have access to the Developer shell. diff --git a/docs/dev/Pagination.md b/docs/dev/Pagination.md index ff2a862..b06b7c4 100644 --- a/docs/dev/Pagination.md +++ b/docs/dev/Pagination.md @@ -3,7 +3,7 @@ ## Overview OpenSearch ODBC Driver supports forward-only cursor. This document illustrates how the cursor(pagination) is handled in the driver. -For information on how the pagination is supported on OpenSearch server, check [OpenSearch SQL Cursor (Pagination) Support](https://github.com/opensearch-project/sql/blob/main/docs/dev/Pagination.md). +For information on how the pagination is supported on OpenSearch server, check [OpenSearch SQL Cursor (Pagination) Support](https://github.com/opensearch-project/sql-odbc/blob/cb5f4bd7ba4a15a2614ecbd3b53ddfcd9b4320fc/docs/dev/Pagination.md). ## Data Flow

@@ -14,7 +14,7 @@ For information on how the pagination is supported on OpenSearch server, check [ * Step 5 will send a request to close cursor whenever the connection is closed. * ODBC Driver will provide an option to define fetch size as a connection parameter. * If fetch size is zero, query will fallback to non-cursor behavior. - * If fetch size is not given then the number of rows per request will be as per server-defined [default fetch size](https://github.com/opensearch-project/sql/blob/main/docs/dev/Pagination.md#42-salient-points). + * If fetch size is not given then the number of rows per request will be as per server-defined [default fetch size](https://github.com/opensearch-project/sql-odbc/blob/cb5f4bd7ba4a15a2614ecbd3b53ddfcd9b4320fc/docs/dev/Pagination.md). * ODBC Driver will send the request to close cursor whenever the connection is closed. ## Detailed Design diff --git a/docs/dev/run_tests.md b/docs/dev/run_tests.md index 6d7dd14..93ad885 100644 --- a/docs/dev/run_tests.md +++ b/docs/dev/run_tests.md @@ -2,13 +2,13 @@ ## Requirements -* Latest version of [OpenSearch](https://docs-beta.opensearch.org/opensearch/install/index/) +* Latest version of [OpenSearch](https://opensearch.org/docs/latest/install-and-configure/install-opensearch/index/) * [Required datasets loaded](#set-up-test-datasets) * [DSN configured](#set-up-dsn) ### Set up test datasets -Loading a dataset requires an [OpenSearch](https://docs-beta.opensearch.org/opensearch/install/index/) service running with [OpenSearch Dashboards](https://docs-beta.opensearch.org/dashboards/index/). If either of these are missing, please refer to the documentation on how to set them up. +Loading a dataset requires an [OpenSearch](https://opensearch.org/docs/latest/install-and-configure/install-opensearch/index/) service running with [OpenSearch Dashboards](https://opensearch.org/docs/latest/dashboards/). If either of these are missing, please refer to the documentation on how to set them up. Note, if you wish to work with SSL/TLS, you need to configure OpenSearch and OpenSearch Dashboards to support it. See the [build instructions](./BUILD_INSTRUCTIONS.md) for more info. diff --git a/docs/test/excel_connection.md b/docs/test/excel_connection.md index 562ac1c..e80a1cc 100644 --- a/docs/test/excel_connection.md +++ b/docs/test/excel_connection.md @@ -2,7 +2,7 @@ ## Prerequisites * [Download and install](../../README.md) OpenSearch SQL ODBC Driver. -* [Install and configure](https://docs-beta.opensearch.org/opensearch/install/index/) OpenSearch. +* [Install and configure](https://opensearch.org/docs/latest/install-and-configure/install-opensearch/index/) OpenSearch. * Open ODBC Data Source Administrator. Click on **System DSN** > **OpenSearch SQL ODBC DSN** > **Configure**. * Set all connection options & Click on **Test**. Connection test should return `Connection Successful`. diff --git a/docs/user/configuration_options.md b/docs/user/configuration_options.md index 0a8201c..d1faba4 100644 --- a/docs/user/configuration_options.md +++ b/docs/user/configuration_options.md @@ -12,13 +12,14 @@ #### Authentication Options -| Option | Description | Type | Acceptable Values | Default | -|--------------------|-------------------------------------------------------------------------------|--------|------------------------------------------------------|---------| -| `Auth` | Authentication mechanism to use. | string | `BASIC` (basic HTTP), `AWS_SIGV4` (AWS auth), `NONE` | `NONE` | -| `User` / `UID` | [`Auth=BASIC`] Username for the connection. | string | | | -| `Password` / `PWD` | [`Auth=BASIC`] Password for the connection. | string | | | -| `Region` | [`Auth=AWS_SIGV4`] Region used for signing requests | string | AWS region (eg. `us-west-1`) | | -| `TunnelHost` | [`Auth=AWS_SIGV4`] VPC endpoint hostname if connected through tunnel or proxy | string | | | +| Option | Description | Type | Acceptable Values | Default | +|------------------------|-------------------------------------------------------------------------------|--------|----------------------------------------------------------------|---------| +| `Auth` | Authentication mechanism to use. | string | `BASIC` (basic HTTP), `AWS_SIGV4` (AWS auth), `OAUTH2`, `NONE` | `NONE` | +| `User` / `UID` | [`Auth=BASIC`] Username for the connection. | string | | | +| `Password` / `PWD` | [`Auth=BASIC`] Password for the connection. | string | | | +| `access_token` / `JWT` | [`Auth=OAUTH2`] Password for the connection. | string | | | +| `Region` | [`Auth=AWS_SIGV4`] Region used for signing requests | string | AWS region (eg. `us-west-1`) | | +| `TunnelHost` | [`Auth=AWS_SIGV4`] VPC endpoint hostname if connected through tunnel or proxy | string | | | **NOTE:** To use `AWS_SIGV4` authentication you need to create `~/.aws/credentials` and add `opensearchodbc` profile with aws access key id, secret key and session token (if used). @@ -33,9 +34,9 @@ #### Logging Options -| Option | Description | Type | Acceptable Values | Default | -|-------------|-----------------------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------| -| `LogLevel` | Severity level for driver logs. | integer | `0` -- `OFF`
`1` -- `FATAL`
`2` -- `ERROR`
`3` -- `WARNING`
`4` -- `INFO`
`5` -- `DEBUG`
`6` -- `TRACE`
`7` -- `ALL` | `3` | +| Option | Description | Type | Acceptable Values | Default | +|-------------|-----------------------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| +| `LogLevel` | Severity level for driver logs. | integer | `0` -- `OFF`
`1` -- `FATAL`
`2` -- `ERROR`
`3` -- `WARNING`
`4` -- `INFO`
`5` -- `DEBUG`
`6` -- `TRACE`
`7` -- `ALL` | `3` | | `LogOutput` | Location for storing driver logs. | string | | WIN: `C:\`
MAC: `/Library/ODBC/opensearch-sql-odbc` | diff --git a/docs/user/img/odbc_setup.png b/docs/user/img/odbc_setup.png new file mode 100644 index 0000000..04d72ec Binary files /dev/null and b/docs/user/img/odbc_setup.png differ diff --git a/docs/user/img/odbc_test.png b/docs/user/img/odbc_test.png new file mode 100644 index 0000000..89e7e6b Binary files /dev/null and b/docs/user/img/odbc_test.png differ diff --git a/docs/user/microsoft_excel_support.md b/docs/user/microsoft_excel_support.md index 1d53c11..9b5a732 100644 --- a/docs/user/microsoft_excel_support.md +++ b/docs/user/microsoft_excel_support.md @@ -3,8 +3,8 @@ ## Prerequisites * Microsoft Excel 2016 and higher -* [OpenSearch](https://docs-beta.opensearch.org/opensearch/install/index/) -* [OpenSearch SQL ODBC driver](https://docs-beta.opensearch.org/search-plugins/sql/odbc/) +* [OpenSearch](https://opensearch.org/docs/latest/install-and-configure/install-opensearch/index/) +* [OpenSearch SQL ODBC driver](https://opensearch.org/docs/latest/search-plugins/sql/sql/odbc/) * A preconfigured [User or System DSN](../../README.md) ## Test Successful Connection @@ -70,7 +70,7 @@ Alternately, **Data** > **Refresh** option can also be used to refresh the data. ## Troubleshooting -* If the table has large number of datarows, increase [the keepalive](https://github.com/opensearch-project/sql/blob/main/docs/dev/Pagination.md#opendistrosqlcursorkeep_alive) value accordlingly. +* If the table has large number of datarows, increase [the keepalive](https://github.com/opensearch-project/sql-odbc/blob/cb5f4bd7ba4a15a2614ecbd3b53ddfcd9b4320fc/docs/dev/Pagination.md) value accordlingly. * If the table has nested or object type column, you might get an error as below. diff --git a/docs/user/microsoft_excel_support_mac.md b/docs/user/microsoft_excel_support_mac.md index 7d0e852..6e5d463 100644 --- a/docs/user/microsoft_excel_support_mac.md +++ b/docs/user/microsoft_excel_support_mac.md @@ -3,8 +3,8 @@ ## Prerequisites * Microsoft Excel 2016 and higher -* [OpenSearch](https://docs-beta.opensearch.org/opensearch/install/index/) -* [OpenSearch SQL ODBC driver](https://docs-beta.opensearch.org/search-plugins/sql/odbc/) +* [OpenSearch](https://opensearch.org/docs/latest/install-and-configure/install-opensearch/index/) +* [OpenSearch SQL ODBC driver](https://opensearch.org/docs/latest/search-plugins/sql/sql/odbc/) * A preconfigured [User or System DSN](mac_configure_dsn.md) ## Test Successful Connection @@ -84,7 +84,7 @@ Alternately, **Data** > **Refresh** option can also be used to refresh the data. ## Troubleshooting -* If the table has large number of datarows, increase [the keepalive](https://github.com/opensearch-project/sql/blob/main/docs/dev/Pagination.md#opendistrosqlcursorkeep_alive) value accordlingly. +* If the table has large number of datarows, increase [the keepalive](https://github.com/opensearch-project/sql-odbc/blob/cb5f4bd7ba4a15a2614ecbd3b53ddfcd9b4320fc/docs/dev/Pagination.md) value accordlingly. * You might need to remove `;` from SQL statement to load data preview. diff --git a/docs/user/windows_configure_dsn.md b/docs/user/windows_configure_dsn.md index e356cf3..81ddf0c 100644 --- a/docs/user/windows_configure_dsn.md +++ b/docs/user/windows_configure_dsn.md @@ -60,4 +60,4 @@ For example, if you can connect to server using following curl command In case if you use a tunnel or a proxy to connect to an OpenSearch cluster located into a VPC, `Host` doesn't represent a real OpenSearch hostname. To properly sign requests with AWS signature, real OpenSearch cluster hostname is required. It could be set in `Tunnel Host` field. - + \ No newline at end of file diff --git a/docs/user/windows_test_oauth.md b/docs/user/windows_test_oauth.md new file mode 100644 index 0000000..fa2770b --- /dev/null +++ b/docs/user/windows_test_oauth.md @@ -0,0 +1,22 @@ +# Test the Oauth2 connection on Windows + +## Test Default Connection + +1. Open ODBC Data Source Administrator. + + + +**NOTE**: Use 32 bit application to configure 32 bit driver and 64 bit app for 64 bit driver. + +2. Select the OpenSearch driver and click on the **Configure...** tab. + + + +3. Change values of configuration options accordingly, then select `OAUTH2` and insert the token. + + + +4. Click on `Test` to verify connectivity. You will get a message as `Connection successful`. + + + diff --git a/jenkins/release.jenkinsFile b/jenkins/release.jenkinsFile index b8d8687..cd5a5a5 100644 --- a/jenkins/release.jenkinsFile +++ b/jenkins/release.jenkinsFile @@ -4,20 +4,21 @@ lib = library(identifier: 'jenkins@4.4.0', retriever: modernSCM([ ])) standardReleasePipelineWithGenericTrigger( + overrideDockerImage: 'opensearchstaging/ci-runner:release-centos7-clients-v4', tokenIdCredential: 'jenkins-sql-odbc-generic-webhook-token', causeString: 'A tag was cut on opensearch-project/sql-odbc repository causing this workflow to run', downloadReleaseAsset: true, publishRelease: true) { publishToArtifactsProdBucket( assumedRoleName: 'sql-odbc-upload-role', - source: "windows32-installer/OpenSearch-SQL-ODBC-Driver-32-bit-${tag}-Windows.msi", + source: "${WORKSPACE}/windows32-installer/OpenSearch-SQL-ODBC-Driver-32-bit-${tag}-Windows.msi", destination: "opensearch-clients/odbc/opensearch-sql-odbc-driver-32-bit-${tag}-Windows.msi", signingPlatform: 'windows', sigOverwrite: true ) publishToArtifactsProdBucket( assumedRoleName: 'sql-odbc-upload-role', - source: "windows64-installer/OpenSearch-SQL-ODBC-Driver-64-bit-${tag}-Windows.msi", + source: "${WORKSPACE}/windows64-installer/OpenSearch-SQL-ODBC-Driver-64-bit-${tag}-Windows.msi", destination: "opensearch-clients/odbc/opensearch-sql-odbc-driver-64-bit-${tag}-Windows.msi", signingPlatform: 'windows', sigOverwrite: true diff --git a/odbc_result.txt b/odbc_result.txt new file mode 100644 index 0000000..e69de29 diff --git a/scripts/build_windows.ps1 b/scripts/build_windows.ps1 index f2090df..e8e7e69 100644 --- a/scripts/build_windows.ps1 +++ b/scripts/build_windows.ps1 @@ -36,4 +36,4 @@ if ($BITNESS -eq "32") { $BITNESS = $null $WIN_ARCH = "x86" } -Copy-Item .\libraries\VisualLeakDetector\bin$BITNESS\vld_$WIN_ARCH.dll $DRIVER_BIN_DIR +Copy-Item .\libraries\VisualLeakDetector\bin$BITNESS\vld_$WIN_ARCH.dll $DRIVER_BIN_DIR \ No newline at end of file diff --git a/src/IntegrationTests/CMakeLists.txt b/src/IntegrationTests/CMakeLists.txt index bc2dc38..96dd921 100644 --- a/src/IntegrationTests/CMakeLists.txt +++ b/src/IntegrationTests/CMakeLists.txt @@ -9,6 +9,7 @@ set(INFO_ITEST "${CMAKE_CURRENT_SOURCE_DIR}/ITODBCInfo") set(RESULTS_ITEST "${CMAKE_CURRENT_SOURCE_DIR}/ITODBCResults") set(TABLEAU_QUERIES_ITEST "${CMAKE_CURRENT_SOURCE_DIR}/ITODBCTableauQueries") set(AWS_AUTH_ITEST "${CMAKE_CURRENT_SOURCE_DIR}/ITODBCAwsAuth") +set(OAUTH_ITEST "${CMAKE_CURRENT_SOURCE_DIR}/ITODBCOauth") set(PAGINATION_ITEST "${CMAKE_CURRENT_SOURCE_DIR}/ITODBCPagination") # Projects to build @@ -21,4 +22,5 @@ add_subdirectory(${INFO_ITEST}) add_subdirectory(${RESULTS_ITEST}) add_subdirectory(${TABLEAU_QUERIES_ITEST}) add_subdirectory(${AWS_AUTH_ITEST}) +add_subdirectory(${OAUTH_ITEST}) add_subdirectory(${PAGINATION_ITEST}) diff --git a/src/IntegrationTests/ITODBCHelper/it_odbc_helper.h b/src/IntegrationTests/ITODBCHelper/it_odbc_helper.h index 8a911d5..578a4c3 100644 --- a/src/IntegrationTests/ITODBCHelper/it_odbc_helper.h +++ b/src/IntegrationTests/ITODBCHelper/it_odbc_helper.h @@ -26,6 +26,7 @@ std::vector< std::pair< std::wstring, std::wstring > > conn_str_pair = { {L"port", L"9200"}, {L"user", L"admin"}, {L"password", L"admin"}, + {L"access_token", L"token"}, {L"auth", L"BASIC"}, {L"useSSL", (use_ssl ? L"1" : L"0")}, {L"hostnameVerification", L"0"}, diff --git a/src/IntegrationTests/ITODBCOauth/CMakeLists.txt b/src/IntegrationTests/ITODBCOauth/CMakeLists.txt new file mode 100644 index 0000000..75ce555 --- /dev/null +++ b/src/IntegrationTests/ITODBCOauth/CMakeLists.txt @@ -0,0 +1,20 @@ +project(itodbc_Oauth) + +# Source, headers, and include dirs +set(SOURCE_FILES test_odbc_Oauth.cpp) +include_directories( ${UT_HELPER} + ${OPENSEARCHODBC_SRC} + ${RAPIDJSON_SRC} + ${RABBIT_SRC} + ${LIBCURL_SRC} + ${VLD_SRC}) + +# Generate executable +add_executable(itodbc_Oauth ${SOURCE_FILES}) + +# Find packages from vcpkg +find_package(GTest CONFIG REQUIRED) + +# Library dependencies +target_link_libraries(itodbc_Oauth ut_helper GTest::gtest_main aws-cpp-sdk-core ${VLD}) +target_compile_definitions(itodbc_Oauth PUBLIC _UNICODE UNICODE) diff --git a/src/IntegrationTests/ITODBCOauth/packages.config b/src/IntegrationTests/ITODBCOauth/packages.config new file mode 100644 index 0000000..3c6fe17 --- /dev/null +++ b/src/IntegrationTests/ITODBCOauth/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/IntegrationTests/ITODBCOauth/pch.cpp b/src/IntegrationTests/ITODBCOauth/pch.cpp new file mode 100644 index 0000000..97b544e --- /dev/null +++ b/src/IntegrationTests/ITODBCOauth/pch.cpp @@ -0,0 +1,6 @@ +// +// pch.cpp +// Include the standard header and generate the precompiled header. +// + +#include "pch.h" diff --git a/src/IntegrationTests/ITODBCOauth/pch.h b/src/IntegrationTests/ITODBCOauth/pch.h new file mode 100644 index 0000000..29c81ff --- /dev/null +++ b/src/IntegrationTests/ITODBCOauth/pch.h @@ -0,0 +1,8 @@ +// +// pch.h +// Header for standard system include files. +// + +#pragma once + +#include "gtest/gtest.h" diff --git a/src/IntegrationTests/ITODBCOauth/test_odbc_Oauth.cpp b/src/IntegrationTests/ITODBCOauth/test_odbc_Oauth.cpp new file mode 100644 index 0000000..d2339a6 --- /dev/null +++ b/src/IntegrationTests/ITODBCOauth/test_odbc_Oauth.cpp @@ -0,0 +1,142 @@ +// clang-format off +#include "pch.h" +#ifdef __APPLE__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif // __APPLE__ +#include +#include +#include +#include +#ifdef __APPLE__ +#pragma clang diagnostic pop +#endif // __APPLE__ +#include "unit_test_helper.h" + +using namespace Aws; +using namespace Aws::Client; +using namespace Aws::Utils::Json; +using namespace Aws::Http; +using namespace std; + +class OAuth2TokenProvider { +public: + + static std::string GetToken() { + // Set up HTTP request with client credentials flow + Aws::String endpoint = "http://localhost:1852/realms/local-development/protocol/openid-connect/token"; + Aws::String username = "opensearch-admin"; + Aws::String password = "opensearch-admin-secret"; + Aws::String scope = "opensearch"; + Aws::String requestBody = "grant_type=client_credentials&client_id=" + username + "&client_secret=" + password + "&scope=" + scope; + auto request = CreateHttpRequest(endpoint, HttpMethod::HTTP_POST, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + + // Set headers + request->SetHeaderValue(Aws::Http::CONTENT_TYPE_HEADER, "application/x-www-form-urlencoded"); + + // Set body + std::shared_ptr bodyStream = Aws::MakeShared(""); + *bodyStream << requestBody; + request->AddContentBody(bodyStream); + request->SetContentLength(std::to_string(requestBody.length())); + + // Create HTTP client + auto httpClient = Aws::Http::CreateHttpClient(Aws::Client::ClientConfiguration()); + + // Send request + auto httpResponse = httpClient->MakeRequest(request); + + // Check if request was successful + if (!httpResponse || !httpResponse->GetResponseBody().good()) { + throw std::runtime_error("Failed to fetch token"); + } + + // Read token from response body + Aws::StringStream responseBody; + responseBody << httpResponse->GetResponseBody().rdbuf(); + JsonValue jsonValue(responseBody.str()); + + if (!jsonValue.WasParseSuccessful()) { + throw std::runtime_error("Failed to parse JSON response"); + } + + JsonView jsonView = jsonValue.View(); + + if (!jsonView.ValueExists("access_token")) { + throw std::runtime_error("Access token not found in JSON response"); + } + + return jsonView.GetString("access_token").c_str(); + } +}; + +TEST(OAuth2_Auth, TokenAuthentication) { + Aws::SDKOptions options; + Aws::String host = "http://localhost:9200"; + + EXPECT_NO_THROW(Aws::InitAPI(options)); + + auto request = CreateHttpRequest(host, HttpMethod::HTTP_GET, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + + // Obtain the OAuth2 token + std::string token = OAuth2TokenProvider::GetToken(); + + ASSERT_FALSE(token.empty()); + + // Set the Authorization header with the Bearer token + request->SetAuthorization("Bearer " + token); + + auto http_client = CreateHttpClient(Aws::Client::ClientConfiguration()); + + auto response = http_client->MakeRequest(request); + ASSERT_NE(response, nullptr); + EXPECT_EQ(Aws::Http::HttpResponseCode::OK, response->GetResponseCode()); + + EXPECT_NO_THROW(Aws::ShutdownAPI(options)); +} + +TEST(OAuth2_Auth, InvalidToken) { + Aws::SDKOptions options; + Aws::String host = "http://localhost:9200"; + + EXPECT_NO_THROW(Aws::InitAPI(options)); + + auto request = CreateHttpRequest(host, HttpMethod::HTTP_GET, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + + // Obtain the OAuth2 token + std::string token = OAuth2TokenProvider::GetToken(); + + ASSERT_FALSE(token.empty()); + + // Corrupt the token + token.pop_back(); + + // Set the Authorization header with the Bearer token + request->SetAuthorization("Bearer " + token); + + auto http_client = CreateHttpClient(Aws::Client::ClientConfiguration()); + + auto response = http_client->MakeRequest(request); + ASSERT_NE(response, nullptr); + EXPECT_EQ(Aws::Http::HttpResponseCode::FORBIDDEN, response->GetResponseCode()); + + EXPECT_NO_THROW(Aws::ShutdownAPI(options)); +} + +TEST(SettingSDKOptions, TurnLoggingOn) { + Aws::SDKOptions options; + options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Info; + EXPECT_NO_THROW(Aws::InitAPI(options)); + EXPECT_NO_THROW(Aws::ShutdownAPI(options)); +} + +int main(int argc, char** argv) { + testing::internal::CaptureStdout(); + ::testing::InitGoogleTest(&argc, argv); + int failures = RUN_ALL_TESTS(); + std::string output = testing::internal::GetCapturedStdout(); + std::cout << output << std::endl; + std::cout << (failures ? "Not all tests passed." : "All tests passed") << std::endl; + WriteFileIfSpecified(argv, argv + argc, "-fout", output); + return failures; +} \ No newline at end of file diff --git a/src/PerformanceTests/PTODBCInfo/performance_odbc_info.cpp b/src/PerformanceTests/PTODBCInfo/performance_odbc_info.cpp index f660d5d..0c8950b 100644 --- a/src/PerformanceTests/PTODBCInfo/performance_odbc_info.cpp +++ b/src/PerformanceTests/PTODBCInfo/performance_odbc_info.cpp @@ -48,6 +48,8 @@ runtime_options rt_opts = []() { temp_opts.auth.username = wstring_to_string(it.second); else if (tmp == L"password") temp_opts.auth.password = wstring_to_string(it.second); + else if (tmp == L"access_token") + temp_opts.auth.access_token = wstring_to_string(it.second); else if (tmp == L"region") temp_opts.auth.region = wstring_to_string(it.second); else if (tmp == L"tunnelhost") diff --git a/src/TestRunner/test_runner.py b/src/TestRunner/test_runner.py index ad2c4d9..9921bc4 100644 --- a/src/TestRunner/test_runner.py +++ b/src/TestRunner/test_runner.py @@ -18,7 +18,7 @@ ".py", ".c", ".cmake", ".log", ".pdb", ".dll", ".sln", ".vcxproj", ".user", ".tlog", ".lastbuildstate", ".filters", - ".obj", ".exp", ".lib", ".h", ".cpp", ".ilk") + ".obj", ".exp", ".lib", ".h", ".cpp", ".ilk", ".recipe",".pyc") total_failures = 0 SYNC_START = "%%__PARSE__SYNC__START__%%" SYNC_SEP = "%%__SEP__%%" diff --git a/src/UnitTests/UTConn/test_conn.cpp b/src/UnitTests/UTConn/test_conn.cpp index 0e56831..b2c385a 100644 --- a/src/UnitTests/UTConn/test_conn.cpp +++ b/src/UnitTests/UTConn/test_conn.cpp @@ -18,15 +18,19 @@ const std::string invalid_port = "920"; const std::string invalid_user = "amin"; const std::string invalid_pw = "amin"; const std::string invalid_region = "bad-region"; +const std::string no_token = ""; runtime_options valid_opt_val = {{valid_host, valid_port, "1", "0"}, - {"BASIC", valid_user, valid_pw, valid_region, valid_tunnel_host}, + {"BASIC", valid_user, valid_pw, no_token, valid_region, valid_tunnel_host}, {use_ssl, false, "", "", "", ""}}; runtime_options invalid_opt_val = { {invalid_host, invalid_port, "1", "0"}, - {"BASIC", invalid_user, invalid_pw, valid_region, valid_tunnel_host}, + {"BASIC", invalid_user, invalid_pw, no_token, valid_region, valid_tunnel_host}, {use_ssl, false, "", "", "", ""}}; runtime_options missing_opt_val = {{"", "", "1", "0"}, - {"BASIC", "", invalid_pw, valid_region, valid_tunnel_host}, + {"BASIC", "", invalid_pw, no_token, valid_region, valid_tunnel_host}, + {use_ssl, false, "", "", "", ""}}; +runtime_options missing_opt_val_token = {{"", "", "1", "0"}, + {"OAUTH2", "","", no_token, "", ""}, {use_ssl, false, "", "", "", ""}}; TEST(TestOpenSearchConnConnectionOptions, ValidParameters) { @@ -81,6 +85,13 @@ TEST_F(TestOpenSearchConnConnectDBStart, MissingParameters) { EXPECT_EQ(CONNECTION_BAD, m_conn.GetConnectionStatus()); } +TEST_F(TestOpenSearchConnConnectDBStart, MissingParametersOauth) { + ASSERT_NE(true, m_conn.ConnectionOptions(missing_opt_val_token, 1, 1, + missing_option_count)); + EXPECT_EQ(false, m_conn.ConnectDBStart()); + EXPECT_EQ(CONNECTION_BAD, m_conn.GetConnectionStatus()); +} + TEST(TestOpenSearchConnDropDBConnection, InvalidParameters) { OpenSearchCommunication conn; ASSERT_EQ(CONNECTION_BAD, conn.GetConnectionStatus()); @@ -103,6 +114,17 @@ TEST(TestOpenSearchConnDropDBConnection, MissingParameters) { EXPECT_EQ(CONNECTION_BAD, conn.GetConnectionStatus()); } +TEST(TestOpenSearchConnDropDBConnection, MissingParametersOauth) { + OpenSearchCommunication conn; + ASSERT_EQ(CONNECTION_BAD, conn.GetConnectionStatus()); + ASSERT_NE(true, conn.ConnectionOptions(missing_opt_val_token, 1, 1, + missing_option_count)); + ASSERT_NE(true, conn.ConnectDBStart()); + ASSERT_EQ(CONNECTION_BAD, conn.GetConnectionStatus()); + conn.DropDBConnection(); + EXPECT_EQ(CONNECTION_BAD, conn.GetConnectionStatus()); +} + TEST(TestOpenSearchConnDropDBConnection, ValidParameters) { OpenSearchCommunication conn; ASSERT_NE(false, diff --git a/src/opensearchenlist/msdtc_enlist.cpp b/src/opensearchenlist/msdtc_enlist.cpp index f427d83..cad9ab3 100644 --- a/src/opensearchenlist/msdtc_enlist.cpp +++ b/src/opensearchenlist/msdtc_enlist.cpp @@ -40,6 +40,11 @@ #define CSTR static const char *const #endif /* CSTR */ +/* Makes CPPcheck happy */ +#ifndef KEYWORD_DTC_CHECK +#define KEYWORD_DTC_CHECK +#endif /*KEYWORD_DTC_CHECK*/ + EXTERN_C { HINSTANCE s_hModule; /* Saved module handle. */ } diff --git a/src/sqlodbc/dlg_specific.c b/src/sqlodbc/dlg_specific.c index 3d2f8f8..056cf29 100644 --- a/src/sqlodbc/dlg_specific.c +++ b/src/sqlodbc/dlg_specific.c @@ -26,34 +26,60 @@ static opensearchNAME decode_or_remove_braces(const char *in); void makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len) { UNUSED(len); char got_dsn = (ci->dsn[0] != '\0'); - char encoded_item[LARGE_REGISTRY_LEN]; + char encoded_item[XLARGE_REGISTRY_LEN]; // This value can manage a JWT token size char *connsetStr = NULL; char *esoptStr = NULL; + #ifdef _HANDLE_ENLIST_IN_DTC_ char xaOptStr[16]; #endif ssize_t hlen, nlen, olen; - - encode(ci->password, encoded_item, sizeof(encoded_item)); - /* fundamental info */ - nlen = MAX_CONNECT_STRING; - olen = snprintf( - connect_string, nlen, - "%s=%s;" INI_SERVER - "=%s;" - "database=OpenSearch;" INI_PORT "=%s;" INI_USERNAME_ABBR - "=%s;" INI_PASSWORD_ABBR "=%s;" INI_AUTH_MODE "=%s;" INI_REGION - "=%s;" INI_TUNNEL_HOST "=%s;" INI_SSL_USE "=%d;" INI_SSL_HOST_VERIFY - "=%d;" INI_LOG_LEVEL "=%d;" INI_LOG_OUTPUT "=%s;" INI_TIMEOUT "=%s;" - INI_FETCH_SIZE "=%s;", - got_dsn ? "DSN" : "DRIVER", got_dsn ? ci->dsn : ci->drivername, - ci->server, ci->port, ci->username, encoded_item, ci->authtype, - ci->region, ci->tunnel_host, (int)ci->use_ssl, (int)ci->verify_server, - (int)ci->drivers.loglevel, ci->drivers.output_dir, - ci->response_timeout, ci->fetch_size); - if (olen < 0 || olen >= nlen) { - connect_string[0] = '\0'; - return; + // Build the connect string with the JWT token and so encoded_item as ci->access_token + if (ci->username[0] == '\0') { + encode(ci->access_token, encoded_item, sizeof(encoded_item)); + /* fundamental info */ + nlen = MAX_CONNECT_STRING; + olen = snprintf( + connect_string, nlen, + "%s=%s;" INI_SERVER + "=%s;" + "database=OpenSearch;" INI_PORT "=%s;" INI_USERNAME_ABBR + "=%s;" INI_TOKEN_ABBR "=%s;" INI_AUTH_MODE "=%s;" INI_REGION + "=%s;" INI_TUNNEL_HOST "=%s;" INI_SSL_USE "=%d;" INI_SSL_HOST_VERIFY + "=%d;" INI_LOG_LEVEL "=%d;" INI_LOG_OUTPUT "=%s;" INI_TIMEOUT "=%s;" + INI_FETCH_SIZE "=%s;", + got_dsn ? "DSN" : "DRIVER", got_dsn ? ci->dsn : ci->drivername, + ci->server, ci->port, ci->username, encoded_item, ci->authtype, + ci->region, ci->tunnel_host, (int)ci->use_ssl, (int)ci->verify_server, + (int)ci->drivers.loglevel, ci->drivers.output_dir, + ci->response_timeout, ci->fetch_size); + if (olen < 0 || olen >= nlen) { + connect_string[0] = '\0'; + return; + } + // Build the connect string with password as encoded_item as ci->password + } else { + encode(ci->password, encoded_item, sizeof(encoded_item)); + /* fundamental info */ + nlen = MAX_CONNECT_STRING; + olen = snprintf( + connect_string, nlen, + "%s=%s;" INI_SERVER + "=%s;" + "database=OpenSearch;" INI_PORT "=%s;" INI_USERNAME_ABBR + "=%s;" INI_PASSWORD_ABBR "=%s;" INI_AUTH_MODE "=%s;" INI_REGION + "=%s;" INI_TUNNEL_HOST "=%s;" INI_SSL_USE "=%d;" INI_SSL_HOST_VERIFY + "=%d;" INI_LOG_LEVEL "=%d;" INI_LOG_OUTPUT "=%s;" INI_TIMEOUT "=%s;" + INI_FETCH_SIZE "=%s;", + got_dsn ? "DSN" : "DRIVER", got_dsn ? ci->dsn : ci->drivername, + ci->server, ci->port, ci->username, encoded_item, ci->authtype, + ci->region, ci->tunnel_host, (int)ci->use_ssl, (int)ci->verify_server, + (int)ci->drivers.loglevel, ci->drivers.output_dir, + ci->response_timeout, ci->fetch_size); + if (olen < 0 || olen >= nlen) { + connect_string[0] = '\0'; + return; + } } /* extra info */ @@ -106,7 +132,10 @@ BOOL copyConnAttributes(ConnInfo *ci, const char *attribute, MYLOG(OPENSEARCH_DEBUG, "key='%s' value='xxxxxxxx'\n", attribute); printed = TRUE; #endif - } else if (stricmp(attribute, INI_AUTH_MODE) == 0) + } else if ((stricmp(attribute, INI_TOKEN) == 0) + || (stricmp(attribute, INI_TOKEN_ABBR) == 0)) + ci->access_token = decode_or_remove_braces(value); + else if (stricmp(attribute, INI_AUTH_MODE) == 0) STRCPY_FIXED(ci->authtype, value); else if (stricmp(attribute, INI_REGION) == 0) STRCPY_FIXED(ci->region, value); @@ -147,6 +176,9 @@ static void getCiDefaults(ConnInfo *ci) { if (ci->password.name != NULL) free(ci->password.name); ci->password.name = NULL; + if (ci->access_token.name != NULL) + free(ci->access_token.name); + ci->access_token.name = NULL; strncpy(ci->username, DEFAULT_USERNAME, MEDIUM_REGISTRY_LEN); strncpy(ci->region, DEFAULT_REGION, MEDIUM_REGISTRY_LEN); strncpy(ci->tunnel_host, DEFAULT_TUNNEL_HOST, MEDIUM_REGISTRY_LEN); @@ -246,6 +278,14 @@ void getDSNinfo(ConnInfo *ci, const char *configDrvrname) { sizeof(temp), ODBC_INI) > 0) ci->password = decode(temp); + if (SQLGetPrivateProfileString(DSN, INI_TOKEN, NULL_STRING, temp, + sizeof(temp), ODBC_INI) + > 0) + ci->access_token = decode(temp); + if (SQLGetPrivateProfileString(DSN, INI_TOKEN_ABBR, NULL_STRING, temp, + sizeof(temp), ODBC_INI) + > 0) + ci->access_token = decode(temp); if (SQLGetPrivateProfileString(DSN, INI_AUTH_MODE, NULL_STRING, temp, sizeof(temp), ODBC_INI) > 0) @@ -310,6 +350,8 @@ void writeDSNinfo(const ConnInfo *ci) { SQLWritePrivateProfileString(DSN, INI_USERNAME, ci->username, ODBC_INI); encode(ci->password, encoded_item, sizeof(encoded_item)); SQLWritePrivateProfileString(DSN, INI_PASSWORD, encoded_item, ODBC_INI); + encode(ci->access_token, encoded_item, sizeof(encoded_item)); + SQLWritePrivateProfileString(DSN, INI_TOKEN, encoded_item, ODBC_INI); SQLWritePrivateProfileString(DSN, INI_AUTH_MODE, ci->authtype, ODBC_INI); SQLWritePrivateProfileString(DSN, INI_REGION, ci->region, ODBC_INI); SQLWritePrivateProfileString(DSN, INI_TUNNEL_HOST, ci->tunnel_host, ODBC_INI); @@ -438,6 +480,7 @@ static opensearchNAME decode_or_remove_braces(const char *in) { void CC_conninfo_release(ConnInfo *conninfo) { NULL_THE_NAME(conninfo->password); + NULL_THE_NAME(conninfo->access_token); finalize_globals(&conninfo->drivers); } @@ -461,6 +504,9 @@ void CC_conninfo_init(ConnInfo *conninfo, UInt4 option) { if (conninfo->password.name != NULL) free(conninfo->password.name); conninfo->password.name = NULL; + if (conninfo->access_token.name != NULL) + free(conninfo->access_token.name); + conninfo->access_token.name = NULL; strncpy(conninfo->username, DEFAULT_USERNAME, MEDIUM_REGISTRY_LEN); strncpy(conninfo->region, DEFAULT_REGION, MEDIUM_REGISTRY_LEN); strncpy(conninfo->tunnel_host, DEFAULT_TUNNEL_HOST, MEDIUM_REGISTRY_LEN); @@ -506,6 +552,7 @@ void CC_copy_conninfo(ConnInfo *ci, const ConnInfo *sci) { CORR_STRCPY(region); CORR_STRCPY(tunnel_host); NAME_TO_NAME(ci->password, sci->password); + NAME_TO_NAME(ci->access_token, sci->access_token); CORR_VALCPY(use_ssl); CORR_VALCPY(verify_server); CORR_STRCPY(port); diff --git a/src/sqlodbc/dlg_specific.h b/src/sqlodbc/dlg_specific.h index c93fcad..4aec28b 100644 --- a/src/sqlodbc/dlg_specific.h +++ b/src/sqlodbc/dlg_specific.h @@ -43,6 +43,10 @@ extern "C" { #define INI_PASSWORD "password" #define INI_PASSWORD_ABBR "PWD" #define INI_AUTH_MODE "auth" + +#define INI_TOKEN "access_token" +#define INI_TOKEN_ABBR "JWT" + #define INI_REGION "region" #define INI_TUNNEL_HOST "TunnelHost" #define INI_SSL_USE "useSSL" @@ -54,8 +58,8 @@ extern "C" { #define DEFAULT_FETCH_SIZE -1 #define DEFAULT_FETCH_SIZE_STR "-1" -#define DEFAULT_RESPONSE_TIMEOUT 10 // Seconds -#define DEFAULT_RESPONSE_TIMEOUT_STR "10" +#define DEFAULT_RESPONSE_TIMEOUT 20 // Seconds +#define DEFAULT_RESPONSE_TIMEOUT_STR "20" #define DEFAULT_AUTHTYPE "NONE" #define DEFAULT_HOST "" #define DEFAULT_PORT "" @@ -68,7 +72,8 @@ extern "C" { #define AUTHTYPE_NONE "NONE" #define AUTHTYPE_BASIC "BASIC" -#define AUTHTYPE_IAM "AWS_SIGV4" +#define AUTHTYPE_IAM "AWS_SIGV4" +#define AUTHTYPE_OAUTH2 "OAUTH2" #ifdef _HANDLE_ENLIST_IN_DTC_ #define INI_XAOPT "XaOpt" diff --git a/src/sqlodbc/dlg_wingui.c b/src/sqlodbc/dlg_wingui.c index 06bed13..f29ffb7 100644 --- a/src/sqlodbc/dlg_wingui.c +++ b/src/sqlodbc/dlg_wingui.c @@ -13,7 +13,7 @@ #define HTTP_PREFIX "http://" #define HTTPS_PREFIX "https://" -#define AUTHMODE_CNT 3 +#define AUTHMODE_CNT 4 #define LOGLEVEL_CNT 8 extern HINSTANCE s_hModule; @@ -30,7 +30,8 @@ int loglevels[LOGLEVEL_CNT] = { static const struct authmode authmodes[AUTHMODE_CNT] = { {IDS_AUTHTYPE_NONE, AUTHTYPE_IAM}, {IDS_AUTHTYPE_BASIC, AUTHTYPE_BASIC}, - {IDS_AUTHTYPE_IAM, AUTHTYPE_NONE}}; + {IDS_AUTHTYPE_IAM, AUTHTYPE_NONE}, + {IDS_AUTHTYPE_OAUTH2, AUTHTYPE_OAUTH2}}; const struct authmode *GetCurrentAuthMode(HWND hdlg) { unsigned int ams_cnt = 0; @@ -62,16 +63,26 @@ void SetAuthenticationVisibility(HWND hdlg, const struct authmode *am) { if (strcmp(am->authtype_str, AUTHTYPE_BASIC) == 0) { EnableWindow(GetDlgItem(hdlg, IDC_USER), TRUE); EnableWindow(GetDlgItem(hdlg, IDC_PASSWORD), TRUE); + EnableWindow(GetDlgItem(hdlg, IDC_TOKEN), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_REGION), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_TUNNEL_HOST), FALSE); } else if (strcmp(am->authtype_str, AUTHTYPE_IAM) == 0) { EnableWindow(GetDlgItem(hdlg, IDC_USER), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_PASSWORD), FALSE); + EnableWindow(GetDlgItem(hdlg, IDC_TOKEN), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_REGION), TRUE); EnableWindow(GetDlgItem(hdlg, IDC_TUNNEL_HOST), TRUE); - } else { + } else if (strcmp(am->authtype_str, AUTHTYPE_OAUTH2) == 0) { EnableWindow(GetDlgItem(hdlg, IDC_USER), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_PASSWORD), FALSE); + EnableWindow(GetDlgItem(hdlg, IDC_TOKEN), TRUE); + EnableWindow(GetDlgItem(hdlg, IDC_REGION), FALSE); + EnableWindow(GetDlgItem(hdlg, IDC_TUNNEL_HOST), FALSE); + } + else { + EnableWindow(GetDlgItem(hdlg, IDC_USER), FALSE); + EnableWindow(GetDlgItem(hdlg, IDC_PASSWORD), FALSE); + EnableWindow(GetDlgItem(hdlg, IDC_TOKEN), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_REGION), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_TUNNEL_HOST), FALSE); } @@ -88,10 +99,10 @@ void SetDlgStuff(HWND hdlg, const ConnInfo *ci) { int authtype_selection_idx = 0; unsigned int ams_cnt = 0; const struct authmode *ams = GetAuthModes(&ams_cnt); - char buff[MEDIUM_REGISTRY_LEN + 1]; + char buff[MEDIUM_LARGE_REGISTRY_LEN + 1]; for (unsigned int i = 0; i < ams_cnt; i++) { LoadString(GetWindowInstance(hdlg), ams[i].authtype_id, buff, - MEDIUM_REGISTRY_LEN); + MEDIUM_LARGE_REGISTRY_LEN); SendDlgItemMessage(hdlg, IDC_AUTHTYPE, CB_ADDSTRING, 0, (WPARAM)buff); if (!stricmp(ci->authtype, ams[i].authtype_str)) { authtype_selection_idx = i; @@ -101,12 +112,13 @@ void SetDlgStuff(HWND hdlg, const ConnInfo *ci) { ams[authtype_selection_idx].authtype_id, (WPARAM)0); SetDlgItemText(hdlg, IDC_USER, ci->username); SetDlgItemText(hdlg, IDC_PASSWORD, SAFE_NAME(ci->password)); + SetDlgItemText(hdlg, IDC_TOKEN, SAFE_NAME(ci->access_token)); SetDlgItemText(hdlg, IDC_REGION, ci->region); SetDlgItemText(hdlg, IDC_TUNNEL_HOST, ci->tunnel_host); } static void GetNameField(HWND hdlg, int item, opensearchNAME *name) { - char medium_buf[MEDIUM_REGISTRY_LEN + 1]; + char medium_buf[MEDIUM_LARGE_REGISTRY_LEN + 1]; GetDlgItemText(hdlg, item, medium_buf, sizeof(medium_buf)); STR_TO_NAME((*name), medium_buf); } @@ -120,6 +132,7 @@ void GetDlgStuff(HWND hdlg, ConnInfo *ci) { // Authentication GetDlgItemText(hdlg, IDC_USER, ci->username, sizeof(ci->username)); GetNameField(hdlg, IDC_PASSWORD, &ci->password); + GetNameField(hdlg, IDC_TOKEN, &ci->access_token); GetDlgItemText(hdlg, IDC_REGION, ci->region, sizeof(ci->region)); GetDlgItemText(hdlg, IDC_TUNNEL_HOST, ci->tunnel_host, sizeof(ci->tunnel_host)); diff --git a/src/sqlodbc/drvconn.c b/src/sqlodbc/drvconn.c index 71b166a..44ed49c 100644 --- a/src/sqlodbc/drvconn.c +++ b/src/sqlodbc/drvconn.c @@ -50,6 +50,25 @@ char *hide_password(const char *str) { return outstr; } +char *hide_token(const char *str) { + char *outstr, *jwtp; + + if (!str) + return NULL; + outstr = strdup(str); + if (!outstr) + return NULL; + if (jwtp = strstr(outstr, "JWT="), !jwtp) + jwtp = strstr(outstr, "jwt="); + if (jwtp) { + char *p; + + for (p = jwtp + 4; *p && *p != ';'; p++) + *p = 'x'; + } + return outstr; +} + int paramRequired(const ConnInfo *ci, int reqs) { int required = 0; const char *pw = SAFE_NAME(ci->password); @@ -204,7 +223,8 @@ BOOL dconn_get_attributes(copyfunc func, const char *connect_string, MYLOG(OPENSEARCH_DEBUG, "our_connect_string = '%s'\n", our_connect_string); #else if (get_mylog()) { - char *hide_str = hide_password(our_connect_string); + char *hide_str = hide_password(our_connect_string); + hide_str = hide_token(our_connect_string); MYLOG(OPENSEARCH_DEBUG, "our_connect_string = '%s'\n", hide_str); free(hide_str); diff --git a/src/sqlodbc/opensearch_communication.cpp b/src/sqlodbc/opensearch_communication.cpp index 571357f..36a59f6 100644 --- a/src/sqlodbc/opensearch_communication.cpp +++ b/src/sqlodbc/opensearch_communication.cpp @@ -340,6 +340,13 @@ bool OpenSearchCommunication::CheckConnectionOptions() { SetErrorDetails("Auth error", m_error_message, ConnErrorType::CONN_ERROR_INVALID_AUTH); } + } else if (m_rt_opts.auth.auth_type == AUTHTYPE_OAUTH2){ + if (m_rt_opts.auth.access_token.empty()) { + m_error_message = AUTHTYPE_OAUTH2 + " no token sended. "; + SetErrorDetails("Auth error", m_error_message, + ConnErrorType::CONN_ERROR_INVALID_AUTH); + } } else { m_error_message = "Unknown authentication type: '" + m_rt_opts.auth.auth_type + "'"; @@ -459,8 +466,11 @@ OpenSearchCommunication::IssueRequest( .c_str()); } signer.SignRequest(*request); + } else if (m_rt_opts.auth.auth_type == AUTHTYPE_OAUTH2) { + request->SetAuthorization("Bearer " + m_rt_opts.auth.access_token); } + // Issue request and return response return m_http_client->MakeRequest(request); } diff --git a/src/sqlodbc/opensearch_connection.cpp b/src/sqlodbc/opensearch_connection.cpp index 1262a5d..822ab35 100644 --- a/src/sqlodbc/opensearch_connection.cpp +++ b/src/sqlodbc/opensearch_connection.cpp @@ -122,6 +122,7 @@ int LIBOPENSEARCH_connect(ConnectionClass *self) { rt_opts.auth.auth_type.assign(self->connInfo.authtype); rt_opts.auth.username.assign(self->connInfo.username); rt_opts.auth.password.assign(SAFE_NAME(self->connInfo.password)); + rt_opts.auth.access_token.assign(SAFE_NAME(self->connInfo.access_token)); rt_opts.auth.region.assign(self->connInfo.region); rt_opts.auth.tunnel_host.assign(self->connInfo.tunnel_host); diff --git a/src/sqlodbc/opensearch_odbc.h b/src/sqlodbc/opensearch_odbc.h index a20ce48..0f8dec7 100644 --- a/src/sqlodbc/opensearch_odbc.h +++ b/src/sqlodbc/opensearch_odbc.h @@ -381,8 +381,8 @@ BOOL isSqlServr(void); /* Limits */ #define MAXESPATH 1024 -/* see an easy way round this - DJP 24-1-2001 */ -#define MAX_CONNECT_STRING 4096 +/* see an easy way round this - DJP 24-1-2001 predefined as 4096*/ +#define MAX_CONNECT_STRING 20480 #define FETCH_MAX \ 100 /* default number of rows to cache \ \ * for declare/fetch */ @@ -409,7 +409,9 @@ BOOL isSqlServr(void); #define INDEX_KEYS_STORAGE_COUNT 32 /* Registry length limits */ +#define XLARGE_REGISTRY_LEN 8192 /* used for adapt to the lenght of the JWT token in OAUTH2*/ #define LARGE_REGISTRY_LEN 4096 /* used for special cases */ +#define MEDIUM_LARGE_REGISTRY_LEN 1536 /* used for adapt to the lenght of the JWT token in OAUTH2 */ #define MEDIUM_REGISTRY_LEN \ 256 /* normal size for \ \ * user,database,etc. */ @@ -611,6 +613,7 @@ typedef struct { char authtype[MEDIUM_REGISTRY_LEN]; char username[MEDIUM_REGISTRY_LEN]; opensearchNAME password; + opensearchNAME access_token; char region[MEDIUM_REGISTRY_LEN]; char tunnel_host[MEDIUM_REGISTRY_LEN]; diff --git a/src/sqlodbc/opensearch_odbc.rc b/src/sqlodbc/opensearch_odbc.rc index ceb19fa..2bb634f 100644 --- a/src/sqlodbc/opensearch_odbc.rc +++ b/src/sqlodbc/opensearch_odbc.rc @@ -7,7 +7,11 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#include "afxres.h" + +// The file "afxres.h" is not available in the Visual Studio 2019 Build Tools "MFC C++ v14.29 (16.10) for Build Tools v142 (x86 and x64)" and "winres.h" will substitute that. +// #include "afxres.h" + +#include "winres.h" #include "version.h" ///////////////////////////////////////////////////////////////////////////// @@ -33,7 +37,10 @@ END 2 TEXTINCLUDE BEGIN - "#include ""afxres.h""\r\n" + // The file "afxres.h" is not available in the Visual Studio 2019 Build Tools "MFC C++ v14.29 (16.10) for Build Tools v142 (x86 and x64)" and "winres.h" will substitute that. + // "#include ""afxres.h""\r\n" + + "#include ""winres.h""\r\n" "#include ""version.h""\r\n" "\0" END @@ -62,7 +69,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Dialog // -DLG_CONFIG DIALOGEX 65, 43, 275, 270 +DLG_CONFIG DIALOGEX 65, 63, 275, 290 STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "OpenSearch ODBC Driver DSN Setup" FONT 8, "MS Sans Serif", 0, 0, 0x0 @@ -74,23 +81,25 @@ BEGIN EDITTEXT IDC_SERVER,60,44,192,12,ES_AUTOHSCROLL LTEXT "Port",IDC_STATIC,20,66,19,8 EDITTEXT IDC_PORT,60,64,192,13,ES_AUTOHSCROLL - GROUPBOX "Authentication Settings",IDC_AUTH_SETTINGS,7,93,260,115,BS_FLAT + GROUPBOX "Authentication Settings",IDC_AUTH_SETTINGS,7,93,260,135,BS_FLAT LTEXT "Auth",IDC_AUTH_STATIC,21,110,19,8 COMBOBOX IDC_AUTHTYPE,65,108,192,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "User",IDC_USERNAME_STATIC,20,129,19,8 EDITTEXT IDC_USER,65,127,191,12,ES_AUTOHSCROLL | WS_DISABLED LTEXT "Password",IDC_PASSWORD_STATIC,20,149,41,12 EDITTEXT IDC_PASSWORD,65,147,191,12,ES_PASSWORD | ES_AUTOHSCROLL | WS_DISABLED - LTEXT "Region",IDC_REGION_STATIC,20,170,28,8 - EDITTEXT IDC_REGION,65,168,191,12,ES_AUTOHSCROLL | WS_DISABLED - LTEXT "Tunnel host",IDC_TUNNEL_HOST_STATIC,20,190,56,8 - EDITTEXT IDC_TUNNEL_HOST,65,188,191,12,ES_AUTOHSCROLL | WS_DISABLED - PUSHBUTTON "Advanced Options",ID_ADVANCED_OPTIONS,21,215,111,15,WS_GROUP - PUSHBUTTON "Logging Options",ID_LOG_OPTIONS,144,215,108,15,WS_GROUP - LTEXT "V.N.N.N",IDC_DRIVER_VERSION,10,248,108,8 - DEFPUSHBUTTON "OK",IDOK,119,244,44,15,WS_GROUP - DEFPUSHBUTTON "Test",IDOK2,167,244,44,15,WS_GROUP - PUSHBUTTON "Cancel",IDCANCEL,215,244,44,15 + LTEXT "Token",IDC_TOKEN_STATIC,20,169,41,12 + EDITTEXT IDC_TOKEN,65,167,191,12,ES_AUTOHSCROLL | WS_DISABLED + LTEXT "Region",IDC_REGION_STATIC,20,189,28,8 + EDITTEXT IDC_REGION,65,187,191,12,ES_AUTOHSCROLL | WS_DISABLED + LTEXT "Tunnel host",IDC_TUNNEL_HOST_STATIC,20,209,56,8 + EDITTEXT IDC_TUNNEL_HOST,65,207,191,12,ES_AUTOHSCROLL | WS_DISABLED + PUSHBUTTON "Advanced Options",ID_ADVANCED_OPTIONS,21,235,111,15,WS_GROUP + PUSHBUTTON "Logging Options",ID_LOG_OPTIONS,144,235,108,15,WS_GROUP + LTEXT "V.N.N.N",IDC_DRIVER_VERSION,10,268,108,8 + DEFPUSHBUTTON "OK",IDOK,119,264,44,15,WS_GROUP + DEFPUSHBUTTON "Test",IDOK2,167,264,44,15,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,215,264,44,15 END DLG_ADVANCED_OPTIONS DIALOGEX 0, 0, 157, 113 @@ -232,6 +241,7 @@ BEGIN IDS_AUTHTYPE_NONE "NONE" IDS_AUTHTYPE_BASIC "BASIC" IDS_AUTHTYPE_IAM "AWS_SIGV4" + IDS_AUTHTYPE_OAUTH2 "OAUTH2" IDS_LOGTYPE_OFF "LOG_OFF" IDS_LOGTYPE_FATAL "LOG_FATAL" IDS_LOGTYPE_ERROR "LOG_ERROR" diff --git a/src/sqlodbc/opensearch_types.h b/src/sqlodbc/opensearch_types.h index 3c61b4a..27568e1 100644 --- a/src/sqlodbc/opensearch_types.h +++ b/src/sqlodbc/opensearch_types.h @@ -254,6 +254,7 @@ typedef struct authentication_options { std::string auth_type; std::string username; std::string password; + std::string access_token; std::string region; std::string tunnel_host; } authentication_options; diff --git a/src/sqlodbc/resource.h b/src/sqlodbc/resource.h index 45aa0eb..9dec11b 100644 --- a/src/sqlodbc/resource.h +++ b/src/sqlodbc/resource.h @@ -7,6 +7,7 @@ #define IDOK2 3 #define IDC_TEST 4 #define IDC_PASSWORD_STATIC 4 +#define IDC_TOKEN_STATIC 6 #define IDC_SSL_STATIC 4 #define IDC_HOST_VER_STATIC 5 #define IDC_DSNAME 400 @@ -26,10 +27,12 @@ #define IDS_LOGTYPE_DEBUG 425 #define IDS_LOGTYPE_TRACE 426 #define IDS_LOGTYPE_ALL 427 +#define IDS_AUTHTYPE_OAUTH2 428 #define DLG_CONFIG 1001 #define IDC_PORT 1002 #define IDC_USER 1006 #define IDC_PASSWORD 1009 +#define IDC_TOKEN 1010 #define IDC_MANAGEDSN 1077 #define IDC_EDIT1 1112 #define IDC_CONNTIMEOUT_STATIC 1112 diff --git a/src/sqlodbc/setup.c b/src/sqlodbc/setup.c index 89cc0dc..66e1fb7 100644 --- a/src/sqlodbc/setup.c +++ b/src/sqlodbc/setup.c @@ -272,9 +272,12 @@ INT_PTR CALLBACK ConfigDlgProc(HWND hdlg, UINT wMsg, WPARAM wParam, } else if (!stricmp(ci->authtype, AUTHTYPE_BASIC)) { SendDlgItemMessage(hdlg, IDC_AUTHTYPE, CB_SETCURSEL, 1, (WPARAM)0); - } else { // AUTHTYPE_NONE + } else if (!stricmp(ci->authtype, AUTHTYPE_OAUTH2)) { SendDlgItemMessage(hdlg, IDC_AUTHTYPE, CB_SETCURSEL, 2, (WPARAM)0); + } else { // AUTHTYPE_NONE + SendDlgItemMessage(hdlg, IDC_AUTHTYPE, CB_SETCURSEL, 3, + (WPARAM)0); } return TRUE; /* Focus was not set */ diff --git a/src/vcpkg.json b/src/vcpkg.json index 7e34853..925d035 100644 --- a/src/vcpkg.json +++ b/src/vcpkg.json @@ -2,7 +2,7 @@ "name": "sql-odbc", "version-string": "1.1.0.1", "dependencies": [ - "aws-sdk-cpp", + {"name": "aws-sdk-cpp", "version>=": "1.11.285"}, "rapidjson", "zlib", "gtest", diff --git a/test_output.html b/test_output.html new file mode 100644 index 0000000..b004b39 --- /dev/null +++ b/test_output.html @@ -0,0 +1,3476 @@ + + + + + + Elastic Search Test Results + + + + +

+

Test Results

+

Unit Tests

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Unit TestCasesErrors
ut_conn62
ut_critical_section10
ut_rabbit80
+
+ +

ut_conn - Failed 2/6

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
ValidParameters23 msOK
MissingParameters15 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
ValidParameters24392 msOK
InvalidParameters27623 msOK
MissingParameters15 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
InvalidParameters27992 msOK
MissingParameters15 msOK
ValidParameters24025 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
ValidQuery24561 msOK
MissingQuery23469 msOK
MissingConnection0 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
ValidQueryAllColumns24025 msFAILED
ValidQuerySomeColumns24006 msOK
InvalidQuery24103 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
PopEmptyQueue23851 msOK
PopTwoQueryResults24072 msFAILED
+
+
+
+ +

ut_critical_section - Passed 1/1

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
SingleEnterExit0 msOK
MultipleEntersMultipleExits0 msOK
MultipleEnterExit0 msOK
MultiThreadSingleLock2011 msOK
RaceConditions115 msOK
+
+
+
+ +

ut_rabbit - Passed 8/8

+ +
+ +
+
+ + + + + + + + + + + + + + + + +
Test NameTimeResult
ValidIterator0 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
IteratorAtStringConvert0 msOK
ValidObject0 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
ValidSchemaValidDoc0 msOK
InvalidSchemaValidDoc0 msOK
ValidSchemaInvalidDoc0 msOK
InvalidSchemaInvalidDoc0 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
ValidObj0 msOK
InvalidObj0 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
ValidArr0 msOK
InvalidArr0 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
ValidStr0 msOK
InvalidStr0 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
ValidInt0 msOK
InvalidInt0 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + +
Test NameTimeResult
InvalidJson0 msOK
+
+
+
+ +
+

Integration Tests

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Unit TestCasesErrors
itodbc_catalog42
itodbc_connection32
itodbc_descriptors31
itodbc_execution61
itodbc_info11
itodbc_pagination11
itodbc_results83
itodbc_tableau_queries10
+
+ +

itodbc_catalog - Failed 2/4

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
Null24172 msOK
WildCatalogs23914 msOK
WildSchema24044 msOK
ValidTable24040 msOK
SingleTable24025 msFAILED
WildTable23943 msOK
InvalidTable24021 msOK
ValidTableType24040 msOK
InvalidTableType24021 msOK
ExcelSQLTables23991 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
Null24024 msOK
ValidTable23981 msOK
InvalidTable24033 msFAILED
ValidColumn23947 msOK
InvalidColumn24022 msOK
ValidTable_ValidColumn24051 msOK
ValidTable_InvalidColumn23981 msOK
InvalidTable_ValidColumn23970 msFAILED
InvalidTable_InvalidColumn24033 msFAILED
FlightsValidation23994 msFAILED
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
PrimaryKeys_NULL23936 msOK
ForeignKeys_NULL23928 msOK
PrimaryKeys_Catalog23964 msOK
ForeignKeys_Catalog24025 msOK
PrimaryKeys_Table24003 msOK
ForeignKeys_Table24033 msOK
PrimaryKeys_CatalogTable23964 msOK
ForeignKeys_CatalogTable24025 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
AllTypes23977 msOK
SingleTypeMultipleRows24019 msOK
SingleType23993 msOK
UnsupportedType24011 msOK
+
+
+
+ +

itodbc_connection - Failed 2/3

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
SqlSuccess6 msFAILED
SqlError4 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
DSNConnectionString4 msFAILED
SqlDriverPrompt24081 msOK
SqlDriverComplete24039 msOK
SqlDriverCompleteRequired24039 msOK
SqlDriverNoprompt24006 msOK
InvalidDriver28004 msOK
InvalidHost27902 msOK
InvalidPort28043 msOK
UnsupportedKeyword28024 msOK
ConnStringAbbrevsUID24046 msOK
ConnStringAbbrevsPWD24000 msOK
ConnStringAbbrevsUIDPWD24046 msOK
ConnStringAbbrevsHost23960 msOK
ConnStringAbbrevsHostProtocol23960 msOK
ConnStringAbbrevsServer24010 msOK
ConnStringAbbrevsServerUIDPWD24010 msOK
Timeout1Second27907 msFAILED
Timeout3Second28007 msFAILED
Timeout7Second32003 msFAILED
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
TestSuccess24042 msOK
TestReconnectOnce47980 msOK
TestReconnectMultipleTimes264043 msOK
TestDisconnectWithoutConnect1 msOK
+
+
+
+ +

itodbc_descriptors - Failed 1/3

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
TestCopyArdToArd24145 msOK
TestNotCopyArdToIrd24038 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
Test_SQL_DESC_ALLOC_TYPE23981 msOK
Test_SQL_DESC_ARRAY_SIZE24035 msOK
Test_SQL_DESC_ARRAY_STATUS_PTR23964 msOK
Test_SQL_DESC_BIND_OFFSET_PTR24004 msOK
Test_SQL_DESC_BIND_TYPE24025 msOK
Test_SQL_DESC_COUNT23985 msOK
Test_SQL_DESC_ROWS_PROCESSED_PTR24013 msOK
TestUndefinedError_SQL_DESC_AUTO_UNIQUE_VALUE23939 msOK
TestUndefinedError_SQL_DESC_BASE_COLUMN_NAME24080 msOK
TestUndefinedError_SQL_DESC_BASE_TABLE_NAME23949 msOK
TestUndefinedError_SQL_DESC_CASE_SENSITIVE23931 msOK
TestUndefinedError_SQL_DESC_CATALOG_NAME24085 msOK
TestUndefinedError_SQL_DESC_CONCISE_TYPE24012 msOK
TestUndefinedError_SQL_DESC_DATA_PTR23926 msOK
TestUndefinedError_SQL_DESC_DATETIME_INTERVAL_CODE24105 msOK
TestUndefinedError_SQL_DESC_DATETIME_INTERVAL_PRECISION23933 msOK
TestUndefinedError_SQL_DESC_DISPLAY_SIZE24009 msOK
TestUndefinedError_SQL_DESC_FIXED_PREC_SCALE23987 msOK
TestUndefinedError_SQL_DESC_INDICATOR_PTR24010 msOK
TestUndefinedError_SQL_DESC_LABEL23979 msOK
TestUndefinedError_SQL_DESC_LENGTH24036 msOK
TestUndefinedError_SQL_DESC_LITERAL_PREFIX23989 msOK
TestUndefinedError_SQL_DESC_LITERAL_SUFFIX23974 msOK
TestUndefinedError_SQL_DESC_LOCAL_TYPE_NAME23996 msOK
TestUndefinedError_SQL_DESC_NAME24022 msOK
TestUndefinedError_SQL_DESC_NULLABLE24006 msOK
TestUndefinedError_SQL_DESC_NUM_PREC_RADIX23931 msOK
TestUndefinedError_SQL_DESC_OCTET_LENGTH24008 msOK
TestUndefinedError_SQL_DESC_OCTET_LENGTH_PTR24008 msOK
TestUndefinedError_SQL_DESC_PARAMETER_TYPE23991 msOK
TestUndefinedError_SQL_DESC_PRECISION24011 msOK
TestUndefinedError_SQL_DESC_ROWVER23988 msOK
TestUndefinedError_SQL_DESC_SCALE24025 msOK
TestUndefinedError_SQL_DESC_SCHEMA_NAME23977 msOK
TestUndefinedError_SQL_DESC_SEARCHABLE24010 msOK
TestUndefinedError_SQL_DESC_TABLE_NAME24030 msOK
TestUndefinedError_SQL_DESC_TYPE23989 msOK
TestUndefinedError_SQL_DESC_TYPE_NAME23989 msOK
TestUndefinedError_SQL_DESC_UNNAMED23995 msOK
TestUndefinedError_SQL_DESC_UNSIGNED24006 msOK
TestUndefinedError_SQL_DESC_UPDATABLE23955 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
Test_SQL_DESC_ALLOC_TYPE24059 msOK
Test_SQL_DESC_ARRAY_SIZE23986 msOK
Test_SQL_DESC_ARRAY_STATUS_PTR24007 msOK
Test_SQL_DESC_BIND_OFFSET_PTR24067 msOK
Test_SQL_DESC_BIND_TYPE23915 msOK
Test_SQL_DESC_COUNT24007 msFAILED
Test_SQL_DESC_ROWS_PROCESSED_PTR23953 msOK
Test_SQL_DESC_AUTO_UNIQUE_VALUE24099 msOK
Test_SQL_DESC_BASE_COLUMN_NAME23941 msOK
Test_SQL_DESC_BASE_TABLE_NAME23949 msOK
Test_SQL_DESC_CASE_SENSITIVE24056 msOK
Test_SQL_DESC_CATALOG_NAME24003 msOK
Test_SQL_DESC_CONCISE_TYPE24017 msOK
Test_SQL_DESC_DATA_PTR23983 msOK
Test_SQL_DESC_DATETIME_INTERVAL_CODE23991 msOK
Test_SQL_DESC_DATETIME_INTERVAL_PRECISION23995 msOK
Test_SQL_DESC_DISPLAY_SIZE24006 msOK
Test_SQL_DESC_FIXED_PREC_SCALE24007 msOK
Test_SQL_DESC_INDICATOR_PTR23988 msOK
Test_SQL_DESC_LABEL24049 msOK
Test_SQL_DESC_LENGTH23912 msOK
Test_SQL_DESC_LITERAL_PREFIX24039 msOK
Test_SQL_DESC_LITERAL_SUFFIX24024 msOK
Test_SQL_DESC_LOCAL_TYPE_NAME23993 msOK
Test_SQL_DESC_NAME24025 msOK
Test_SQL_DESC_NULLABLE23912 msOK
Test_SQL_DESC_NUM_PREC_RADIX24040 msOK
Test_SQL_DESC_OCTET_LENGTH23898 msOK
Test_SQL_DESC_OCTET_LENGTH_PTR23898 msOK
Test_SQL_DESC_PRECISION24057 msOK
Test_SQL_DESC_ROWVER23990 msOK
Test_SQL_DESC_SCALE24018 msOK
Test_SQL_DESC_SCHEMA_NAME23977 msOK
Test_SQL_DESC_SEARCHABLE24003 msOK
Test_SQL_DESC_TABLE_NAME24041 msOK
Test_SQL_DESC_TYPE24022 msOK
Test_SQL_DESC_TYPE_NAME24022 msOK
Test_SQL_DESC_UNNAMED24007 msOK
Test_SQL_DESC_UNSIGNED23979 msOK
Test_SQL_DESC_UPDATABLE23994 msOK
+
+
+
+ +

itodbc_execution - Failed 1/6

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
NoPrepareCallError24068 msOK
Success24046 msOK
ResetPrepareError24052 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
Success23916 msOK
PrepareMetadata24133 msFAILED
NullQueryError23876 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
Success24116 msOK
NullQueryError23850 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + +
Test NameTimeResult
Success24056 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
Success24002 msOK
WrongLengthForCursorName23986 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
NULLHandle23998 msOK
QueryNotSent24003 msOK
QueryFinished24324 msOK
+
+
+
+ +

itodbc_info - Failed 1/1

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
SQLDriverName24074 msOK
SQLDriverODBCVer24010 msOK
SQLDriverVer24065 msOK
SQLGetDataExtensions23955 msOK
SQLSearchPatternEscape24009 msOK
SQLCursorCommitBehavior23990 msOK
SQLTxnCapable24019 msOK
SQLConcatNullBehavior23988 msOK
SQLSchemaTerm24010 msOK
SQLCatalogTerm24005 msOK
SQLDBMSName24000 msOK
SQLDBMSVer23982 msFAILED
SQLColumnAlias24008 msOK
SQLGroupBy23990 msOK
SQLIdentifierQuoteChar23989 msOK
SQLOJCapabilities24022 msOK
SQLSchemaUsage24008 msOK
SQLQuotedIdentifierCase23990 msOK
SQLSpecialCharacters23990 msOK
SQLODBCInterfaceConformance23997 msOK
SQLSQLConformance24013 msOK
SQLCatalogUsage23985 msOK
SQLCatalogLocation24010 msOK
SQLCatalogNameSeparator24005 msOK
SQLSQL92Predicates23997 msOK
SQLSQL92RelationalJoinOperators24007 msOK
SQLSQL92ValueExpressions24019 msOK
SQLDatetimeLiterals23972 msOK
SQLOrderByColumnsInSelect24006 msOK
SQLCatalogName23995 msOK
SQLConvertInteger23999 msOK
SQLConvertSmallint23976 msOK
SQLConvertTinyint24025 msOK
SQLConvertBit23987 msOK
SQLConvertVarchar24005 msOK
SQLConvertBigint24002 msOK
SQLConvertDecimal24001 msOK
SQLConvertDouble24012 msOK
SQLConvertFloat23986 msOK
SQLConvertNumeric23989 msOK
SQLConvertReal24012 msOK
SQLConvertDate23992 msOK
SQLConvertTime24041 msOK
SQLConvertTimestamp24041 msOK
SQLConvertBinary23981 msOK
SQLConvertLongvarbinary24000 msOK
SQLConvertVarbinary23997 msOK
SQLConvertChar23999 msOK
SQLConvertLongVarchar24025 msOK
SQLConvertWChar23976 msOK
SQLConvertWLongVarchar24017 msOK
SQLConvertWVarchar23996 msOK
SQLConvertGuid24009 msOK
SQLConvertFunctions24001 msOK
SQLNumericFunctions23994 msOK
SQLStringFunctions23986 msOK
SQLSystemFunctions24018 msOK
SQLTimedateAddIntervals23974 msOK
SQLTimedateDiffIntervals24025 msOK
SQLTimedateFunctions23991 msOK
SQLSQL92DatetimeFunctions23989 msOK
SQLSQL92NumericValueFunctions23992 msOK
SQLSQL92StringFunctions24017 msOK
SQLMaxIdentifierLen24011 msOK
SQLMaxColumnsInGroupBy23990 msOK
SQLMaxColumnsInOrderBy23999 msOK
SQLMaxColumnsInSelect23988 msOK
+
+
+
+ +

itodbc_pagination - Failed 1/1

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
EnablePagination24153 msFAILED
DisablePagination24032 msOK
+
+
+
+ +

itodbc_results - Failed 3/8

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
SingleColumnSingleBind24098 msOK
MultiColumnMultiBind24062 msOK
InvalidColIndex023991 msOK
InsufficientSpace24026 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
SingleCol_SingleRow23975 msOK
SingleCol_MultiRow23997 msOK
MultiCol_SingleRow24002 msOK
MultiCol_MultiRow24005 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
SingleCol_SingleRow24041 msOK
SingleCol_MultiRow_SingleFetch23962 msOK
SingleCol_MultiRow_MultiFetch_Aligned24052 msOK
SingleCol_MultiRow_MultiFetch_Misaligned23922 msOK
MultiCol_SingleRow24004 msOK
MultiCol_MultiRow_SingleFetch24023 msOK
MultiCol_MultiRow_MultiFetch_Aligned24002 msOK
MultiCol_MultiRow_MultiFetch_Misaligned23991 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
GetWVARCHARData23949 msOK
GetFloatData24032 msOK
GetIntegerData24025 msOK
GetBitData24033 msOK
TypeDataSet_GetBoolData24044 msOK
TypeDataSet_GetByteData23935 msOK
TypeDataSet_GetDateData24076 msFAILED
TypeDataSet_GetShortData23989 msOK
TypeDataSet_GetIntegerData23941 msOK
TypeDataSet_GetLongData24102 msOK
TypeDataSet_GetHalfFloatData23910 msOK
TypeDataSet_GetFloatData24016 msOK
TypeDataSet_GetDoubleData23976 msOK
TypeDataSet_GetScaledFloatData24029 msOK
TypeDataSet_GetKeywordData23975 msOK
TypeDataSet_GetKeywordDataMultiReadSingleByte24017 msOK
TypeDataSet_GetKeywordDataMultiReadMultiByte23975 msOK
TypeDataSet_GetTextData24046 msOK
TypeDataSet_GetTextDataMultiReadSingleByte23917 msOK
TypeDataSet_GetTextDataMultiReadMultiByte24046 msOK
SQLSTATE_01004_StringDataRightTruncated23913 msOK
SQLSTATE_07009_InvalidDescriptorIndex24007 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
SingleColumn24050 msOK
MultiColumn23962 msFAILED
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test NameTimeResult
SingleColumnMetadata24043 msOK
MultiColumnMetadata23951 msOK
MultiColumnNameLengthType24011 msFAILED
InvalidColumnMetadata23977 msFAILED
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + +
Test NameTimeResult
NoData23919 msOK
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + +
Test NameTimeResult
RowCountNotAvailable24049 msOK
+
+
+
+ +

itodbc_tableau_queries - Passed 1/1

+ +
+ +
+
+ + + + + + + + + + + + + + + + +
Test NameTimeResult
IssueQueriesAll24067 msOK
+
+
+
+ +
+

Integration Tests

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Unit TestCasesErrors
itodbc_catalog42
itodbc_connection32
itodbc_descriptors31
itodbc_execution61
itodbc_info11
itodbc_pagination11
itodbc_results83
itodbc_tableau_queries10
+
+ +
+

Performance Info

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
InfoData
Nameos01
Cluster Nameopensearch-cluster
Cluster Uuidd0gOctxQRaqZDzAORkvzuQ
Version Number2.11.1
+
+ +
+

Performance Results

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Test CaseQueryMinMaxMeanMedian
Execute QuerySELECT * FROM opensearch_dashboards_sample_data_flights limit 100001753 ms2138 ms1928 ms1968 ms
Bind and (1 row) FetchSELECT * FROM opensearch_dashboards_sample_data_flights limit 1000089 ms128 ms96 ms92 ms
Bind and (5 row) FetchSELECT * FROM opensearch_dashboards_sample_data_flights limit 1000088 ms105 ms91 ms89 ms
Bind and (50 row) FetchSELECT * FROM opensearch_dashboards_sample_data_flights limit 1000088 ms102 ms92 ms89 ms
Execute Query, Bind and (1 row) FetchSELECT * FROM opensearch_dashboards_sample_data_flights limit 100001785 ms2114 ms1935 ms1930 ms
+
+ + +