├── .gitattributes ├── .github ├── CODEOWNERS ├── pull_request_template.md └── workflows │ ├── build-timestamped-master.yml │ ├── build-with-bal-test-graalvm.yml │ ├── central-publish.yml │ ├── fossa_scan.yml │ ├── publish-release.yml │ ├── pull-request.yml │ ├── trivy-scan.yml │ └── update-spec.yml ├── .gitignore ├── LICENSE ├── README.md ├── ballerina ├── Ballerina.toml ├── CompilerPlugin.toml ├── Config.toml ├── Dependencies.toml ├── README.md ├── annotation.bal ├── build.gradle ├── client.bal ├── connection-pool.bal ├── error.bal ├── icon.png ├── init.bal ├── metadata_types.bal ├── schema_client.bal ├── tests │ ├── Config.toml │ ├── array-params-query-test.bal │ ├── batch-execute-query-test.bal │ ├── call-procedures-test.bal │ ├── client.bal │ ├── complex-query-test.bal │ ├── connection-init-test.bal │ ├── connection-pool-test.bal │ ├── error-test.bal │ ├── execute-basic-test.bal │ ├── execute-params-query-test.bal │ ├── local-transaction-test.bal │ ├── metadata-test.bal │ ├── numerical-query-test.bal │ ├── process.bal │ ├── query-row-test.bal │ ├── record-mapping-test.bal │ ├── resources │ │ ├── files │ │ │ ├── blobValue.txt │ │ │ ├── byteValue.txt │ │ │ └── clobValue.txt │ │ └── sql │ │ │ ├── batchexecute │ │ │ └── batch-execute-test-data.sql │ │ │ ├── connection │ │ │ └── connector-init-test-data.sql │ │ │ ├── error │ │ │ └── error-database-init.sql │ │ │ ├── execute │ │ │ ├── execute-params-test-data.sql │ │ │ └── execute-test-data.sql │ │ │ ├── metadata │ │ │ └── metadata-test-data.sql │ │ │ ├── pool │ │ │ └── connection-pool-test-data.sql │ │ │ ├── procedures │ │ │ └── call-procedures-test-data.sql │ │ │ ├── query │ │ │ ├── complex-test-data.sql │ │ │ ├── numerical-test-data.sql │ │ │ ├── query-row-test-data.sql │ │ │ └── simple-params-test-data.sql │ │ │ └── transaction │ │ │ └── local-transaction-test-data.sql │ ├── schema_client.bal │ ├── simple-params-query-test.bal │ └── utils.bal ├── types.bal └── utils.bal ├── build-config ├── checkstyle │ └── build.gradle ├── release │ └── post-release-dependency-bump.sh ├── resources │ ├── Ballerina.toml │ └── CompilerPlugin.toml └── spotbugs-exclude.xml ├── build.gradle ├── changelog.md ├── codecov.yml ├── compiler-plugin-tests ├── build.gradle └── src │ └── test │ ├── java │ └── io │ │ └── ballerina │ │ └── stdlib │ │ └── sql │ │ └── compiler │ │ └── CompilerPluginTest.java │ └── resources │ ├── diagnostics │ ├── sample1 │ │ ├── Ballerina.toml │ │ └── main.bal │ ├── sample2 │ │ ├── Ballerina.toml │ │ └── main.bal │ ├── sample3 │ │ ├── Ballerina.toml │ │ └── main.bal │ └── sample4 │ │ ├── Ballerina.toml │ │ └── main.bal │ └── testng.xml ├── compiler-plugin ├── build.gradle └── src │ └── main │ └── java │ ├── io │ └── ballerina │ │ └── stdlib │ │ └── sql │ │ └── compiler │ │ ├── Constants.java │ │ ├── SQLCodeAnalyzer.java │ │ ├── SQLCompilerPlugin.java │ │ ├── SQLDiagnosticsCodes.java │ │ ├── Utils.java │ │ └── analyzer │ │ ├── ConnectionPoolConfigAnalyzer.java │ │ └── MethodAnalyzer.java │ └── module-info.java ├── docs ├── proposals │ ├── map_multiple_fields_to_single_return_field.md │ ├── metadata_retrieval_support.md │ ├── resources │ │ └── schema1.png │ └── support_annotation_for_column_mapping.md └── spec │ └── spec.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── native ├── build.gradle └── src │ ├── main │ ├── java │ │ ├── io │ │ │ └── ballerina │ │ │ │ └── stdlib │ │ │ │ └── sql │ │ │ │ ├── Constants.java │ │ │ │ ├── datasource │ │ │ │ ├── PoolKey.java │ │ │ │ └── SQLDatasource.java │ │ │ │ ├── exception │ │ │ │ ├── ApplicationError.java │ │ │ │ ├── ConversionError.java │ │ │ │ ├── DataError.java │ │ │ │ ├── FieldMismatchError.java │ │ │ │ ├── TypeMismatchError.java │ │ │ │ └── UnsupportedTypeError.java │ │ │ │ ├── nativeimpl │ │ │ │ ├── CallProcessor.java │ │ │ │ ├── ClientProcessor.java │ │ │ │ ├── ExecuteProcessor.java │ │ │ │ ├── OutParameterProcessor.java │ │ │ │ └── QueryProcessor.java │ │ │ │ ├── parameterprocessor │ │ │ │ ├── AbstractResultParameterProcessor.java │ │ │ │ ├── AbstractStatementParameterProcessor.java │ │ │ │ ├── DefaultResultParameterProcessor.java │ │ │ │ └── DefaultStatementParameterProcessor.java │ │ │ │ ├── transaction │ │ │ │ └── SQLTransactionContext.java │ │ │ │ └── utils │ │ │ │ ├── ColumnDefinition.java │ │ │ │ ├── ConnectionPoolUtils.java │ │ │ │ ├── ErrorGenerator.java │ │ │ │ ├── ModuleUtils.java │ │ │ │ ├── PrimitiveTypeColumnDefinition.java │ │ │ │ ├── ProcedureCallResultUtils.java │ │ │ │ ├── RecordColumnDefinition.java │ │ │ │ ├── RecordIteratorUtils.java │ │ │ │ ├── SQLColumnMetadata.java │ │ │ │ └── Utils.java │ │ └── module-info.java │ └── resources │ │ └── META-INF │ │ └── native-image │ │ └── io.ballerina.stdlib │ │ └── sql-native │ │ ├── proxy-config.json │ │ ├── reflect-config.json │ │ └── resource-config.json │ └── test │ ├── java │ └── io │ │ └── ballerina │ │ └── stdlib │ │ └── sql │ │ ├── TestUtils.java │ │ ├── datasource │ │ └── PoolKeyTest.java │ │ ├── exception │ │ └── ApplicationErrorTest.java │ │ ├── parameterprocessor │ │ ├── DefaultResultParameterProcessorTest.java │ │ └── DefaultStatementParameterProcessorTest.java │ │ ├── transaction │ │ └── SQLTransactionContextTest.java │ │ └── utils │ │ └── UtilsTest.java │ └── resources │ └── testng.xml ├── settings.gradle └── test-utils ├── build.gradle └── src └── main ├── java ├── io │ └── ballerina │ │ └── stdlib │ │ └── sql │ │ └── testutils │ │ ├── CallTestUtils.java │ │ ├── ClientTestUtils.java │ │ ├── ExecuteTestUtils.java │ │ ├── QueryTestUtils.java │ │ ├── nativeimpl │ │ ├── Exec.java │ │ ├── ExitCode.java │ │ ├── ModuleUtils.java │ │ └── WaitForExit.java │ │ └── utils │ │ ├── OSConstants.java │ │ └── OSUtils.java └── module-info.java └── resources └── META-INF └── native-image └── io.ballerina.stdlib └── sql-test-utils ├── reflect-config.json └── resource-config.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # Ensure all Java files use LF. 2 | *.java eol=lf 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # See: https://help.github.com/articles/about-codeowners/ 5 | 6 | # These owners will be the default owners for everything in the repo. 7 | * @niveathika @RDPerera @shafreenAnfar 8 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | Fixes: 4 | 5 | ## Examples 6 | 7 | ## Checklist 8 | - [ ] Linked to an issue 9 | - [ ] Updated the specification 10 | - [ ] Updated the changelog 11 | - [ ] Added tests 12 | - [ ] Checked native-image compatibility 13 | -------------------------------------------------------------------------------- /.github/workflows/build-timestamped-master.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths-ignore: 8 | - "*.md" 9 | - "docs/**" 10 | - "load-tests/**" 11 | workflow_dispatch: 12 | 13 | jobs: 14 | call_workflow: 15 | name: Run Build Workflow 16 | if: ${{ github.repository_owner == 'ballerina-platform' }} 17 | uses: ballerina-platform/ballerina-library/.github/workflows/build-timestamp-master-template.yml@main 18 | secrets: inherit 19 | -------------------------------------------------------------------------------- /.github/workflows/build-with-bal-test-graalvm.yml: -------------------------------------------------------------------------------- 1 | name: GraalVM Check 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | lang_tag: 7 | description: Branch/Release Tag of the Ballerina Lang 8 | required: true 9 | default: master 10 | lang_version: 11 | description: Ballerina Lang Version (If given ballerina lang buid will be skipped) 12 | required: false 13 | default: '' 14 | native_image_options: 15 | description: Default native-image options 16 | required: false 17 | default: '' 18 | schedule: 19 | - cron: '30 18 * * *' 20 | pull_request: 21 | branches: 22 | - master 23 | types: [ opened, synchronize, reopened, labeled, unlabeled ] 24 | 25 | concurrency: 26 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} 27 | cancel-in-progress: true 28 | 29 | jobs: 30 | call_stdlib_workflow: 31 | name: Run StdLib Workflow 32 | if: ${{ github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository_owner == 'ballerina-platform') }} 33 | uses: ballerina-platform/ballerina-library/.github/workflows/build-with-bal-test-graalvm-template.yml@main 34 | with: 35 | lang_tag: ${{ inputs.lang_tag }} 36 | lang_version: ${{ inputs.lang_version }} 37 | native_image_options: '-J-Xmx7G ${{ inputs.native_image_options }}' 38 | additional_windows_build_flags: '-x test' 39 | -------------------------------------------------------------------------------- /.github/workflows/central-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to the Ballerina central 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | environment: 7 | type: choice 8 | description: Select Environment 9 | required: true 10 | options: 11 | - DEV CENTRAL 12 | - STAGE CENTRAL 13 | 14 | jobs: 15 | call_workflow: 16 | name: Run Central Publish Workflow 17 | if: ${{ github.repository_owner == 'ballerina-platform' }} 18 | uses: ballerina-platform/ballerina-library/.github/workflows/central-publish-template.yml@main 19 | secrets: inherit 20 | with: 21 | environment: ${{ github.event.inputs.environment }} 22 | -------------------------------------------------------------------------------- /.github/workflows/fossa_scan.yml: -------------------------------------------------------------------------------- 1 | name: Fossa Scan 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: '30 18 * * *' # 00:00 in LK time (GMT+5:30) 6 | jobs: 7 | fossa-scan: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: fossas/fossa-action@main 12 | env: 13 | packageUser: ${{ secrets.BALLERINA_BOT_USERNAME }} 14 | packagePAT: ${{ secrets.BALLERINA_BOT_TOKEN }} 15 | with: 16 | api-key: ${{secrets.FOSSA_APIKEY}} 17 | -------------------------------------------------------------------------------- /.github/workflows/publish-release.yml: -------------------------------------------------------------------------------- 1 | name: Publish Release 2 | 3 | on: 4 | workflow_dispatch: 5 | repository_dispatch: 6 | types: [stdlib-release-pipeline] 7 | 8 | jobs: 9 | call_workflow: 10 | name: Run Release Workflow 11 | if: ${{ github.repository_owner == 'ballerina-platform' }} 12 | uses: ballerina-platform/ballerina-library/.github/workflows/release-package-template.yml@main 13 | secrets: inherit 14 | with: 15 | package-name: sql 16 | package-org: ballerina 17 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | name: PR Build 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} 5 | cancel-in-progress: true 6 | 7 | on: [pull_request] 8 | 9 | jobs: 10 | call_workflow: 11 | name: Run PR Build Workflow 12 | if: ${{ github.repository_owner == 'ballerina-platform' }} 13 | uses: ballerina-platform/ballerina-library/.github/workflows/pull-request-build-template.yml@main 14 | secrets: inherit 15 | with: 16 | additional-windows-test-flags: "-x test" 17 | -------------------------------------------------------------------------------- /.github/workflows/trivy-scan.yml: -------------------------------------------------------------------------------- 1 | name: Trivy 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: "30 20 * * *" 7 | 8 | jobs: 9 | call_workflow: 10 | name: Run Trivy Scan Workflow 11 | if: ${{ github.repository_owner == 'ballerina-platform' }} 12 | uses: ballerina-platform/ballerina-library/.github/workflows/trivy-scan-template.yml@main 13 | secrets: inherit 14 | -------------------------------------------------------------------------------- /.github/workflows/update-spec.yml: -------------------------------------------------------------------------------- 1 | name: Update Specifications 2 | 3 | env: 4 | SPEC_FOLDER_PATH: 'docs/spec' 5 | 6 | on: 7 | workflow_dispatch: 8 | push: 9 | branches: 10 | - master 11 | paths: 12 | - 'docs/spec/**' 13 | 14 | jobs: 15 | update_specs: 16 | name: Update Specifications 17 | if: github.repository_owner == 'ballerina-platform' 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Checkout Repository 22 | uses: actions/checkout@v3 23 | 24 | - name: Get current date 25 | id: date 26 | run: echo "::set-output name=date::$(date +'%Y-%m-%d')" 27 | 28 | - name: Get Repo Name 29 | id: repo_name 30 | run: | 31 | MODULE=${{ github.event.repository.name }} 32 | echo "::set-output name=short_name::${MODULE##*-}" 33 | 34 | - name: Trigger Workflow 35 | run: | 36 | curl --request POST \ 37 | 'https://api.github.com/repos/ballerina-platform/ballerina-dev-website/dispatches' \ 38 | -H 'Accept: application/vnd.github.v3+json' \ 39 | -H 'Authorization: Bearer ${{ secrets.BALLERINA_BOT_TOKEN }}' \ 40 | --data "{ 41 | \"event_type\": \"update-stdlib-specs\", 42 | \"client_payload\": { 43 | \"module_name\": \"${{ github.event.repository.name }}\", 44 | \"short_name\": \"${{ steps.repo_name.outputs.short_name }}\", 45 | \"file_dir\": \"${{ github.event.repository.name }}/${{ env.SPEC_FOLDER_PATH }}\", 46 | \"release_date\": \"${{ steps.date.outputs.date }}\" 47 | } 48 | }" 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # Ballerina 26 | Ballerina.lock 27 | 28 | #Idea files 29 | .idea 30 | *.iml 31 | *.ipr 32 | *.iws 33 | 34 | # generated files 35 | target 36 | .ballerina 37 | /compiler-plugin-tests/bin/ 38 | 39 | # gradle 40 | .gradle 41 | build/ 42 | gradle-app.setting 43 | !gradle-wrapper.jar 44 | .gradletasknamecache 45 | 46 | # mac 47 | .DS_Store 48 | 49 | .classpath 50 | .project 51 | .settings 52 | .vscode 53 | -------------------------------------------------------------------------------- /ballerina/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "ballerina" 3 | name = "sql" 4 | version = "1.16.0" 5 | authors = ["Ballerina"] 6 | keywords = ["database", "client", "network", "SQL", "RDBMS"] 7 | repository = "https://github.com/ballerina-platform/module-ballerina-sql" 8 | icon = "icon.png" 9 | license = ["Apache-2.0"] 10 | distribution = "2201.12.0" 11 | 12 | [platform.java21] 13 | graalvmCompatible = true 14 | 15 | [[platform.java21.dependency]] 16 | groupId = "io.ballerina.stdlib" 17 | artifactId = "sql-native" 18 | version = "1.16.0" 19 | path = "../native/build/libs/sql-native-1.16.0.jar" 20 | 21 | [[platform.java21.dependency]] 22 | path = "../test-utils/build/libs/sql-test-utils-1.16.0.jar" 23 | scope = "testOnly" 24 | 25 | [[platform.java21.dependency]] 26 | groupId = "com.zaxxer" 27 | artifactId = "HikariCP" 28 | version = "3.3.1" 29 | path = "./lib/HikariCP-3.3.1.jar" 30 | 31 | [[platform.java21.dependency]] 32 | path = "./lib/hsqldb-2.7.1.jar" 33 | scope = "testOnly" 34 | -------------------------------------------------------------------------------- /ballerina/CompilerPlugin.toml: -------------------------------------------------------------------------------- 1 | [plugin] 2 | id = "sql-compiler-plugin" 3 | class = "io.ballerina.stdlib.sql.compiler.SQLCompilerPlugin" 4 | 5 | [[dependency]] 6 | path = "../compiler-plugin/build/libs/sql-compiler-plugin-1.16.0.jar" 7 | -------------------------------------------------------------------------------- /ballerina/Config.toml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | # 4 | # WSO2 Inc. licenses this file to you under the Apache License, 5 | # Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | # 18 | 19 | [sql] 20 | maxOpenConnections=10 21 | maxConnectionLifeTime=2000.5 22 | minIdleConnections=5 23 | -------------------------------------------------------------------------------- /ballerina/annotation.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | # Defines the database column name which matches the record field. The default value is the record field name. 18 | # 19 | # + name - The database column name 20 | public type ColumnConfig record {| 21 | string name; 22 | |}; 23 | 24 | # The Annotation used to specify which database column matches the Typed record field. 25 | public annotation ColumnConfig Column on record field; 26 | -------------------------------------------------------------------------------- /ballerina/build.gradle: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.taskdefs.condition.Os 2 | 3 | /* 4 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | import org.apache.tools.ant.taskdefs.condition.Os 21 | 22 | plugins { 23 | id 'io.ballerina.plugin' 24 | } 25 | 26 | description = 'Ballerina - SQL Ballerina Generator' 27 | 28 | def packageName = 'sql' 29 | def packageOrg = 'ballerina' 30 | def tomlVersion = stripBallerinaExtensionVersion("${project.version}") 31 | 32 | def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/Ballerina.toml") 33 | def compilerPluginTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/CompilerPlugin.toml") 34 | def ballerinaTomlFile = new File("$project.projectDir/Ballerina.toml") 35 | def compilerPluginTomlFile = new File("$project.projectDir/CompilerPlugin.toml") 36 | 37 | def stripBallerinaExtensionVersion(String extVersion) { 38 | if (extVersion.matches(project.ext.timestampedVersionRegex)) { 39 | def splitVersion = extVersion.split('-') 40 | if (splitVersion.length > 3) { 41 | def strippedValues = splitVersion[0..-4] 42 | return strippedValues.join('-') 43 | } else { 44 | return extVersion 45 | } 46 | } else { 47 | return extVersion.replace("${project.ext.snapshotVersion}", '') 48 | } 49 | } 50 | 51 | ballerina { 52 | packageOrganization = packageOrg 53 | module = packageName 54 | langVersion = ballerinaLangVersion 55 | } 56 | 57 | task updateTomlFiles { 58 | doLast { 59 | def newConfig = ballerinaTomlFilePlaceHolder.text.replace('@project.version@', project.version.toString()) 60 | newConfig = newConfig.replace('@toml.version@', tomlVersion) 61 | newConfig = newConfig.replace('@hikkaricp.lib.version@', project.hikkariLibVersion) 62 | newConfig = newConfig.replace('@hsql.connector.version@', project.hsqlDriverVersion) 63 | ballerinaTomlFile.text = newConfig 64 | 65 | def newCompilerPluginToml = compilerPluginTomlFilePlaceHolder.text.replace("@project.version@", project.version) 66 | compilerPluginTomlFile.text = newCompilerPluginToml 67 | } 68 | } 69 | 70 | task commitTomlFiles { 71 | doLast { 72 | project.exec { 73 | ignoreExitValue true 74 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 75 | commandLine 'cmd', '/c', "git commit -m \"[Automated] Update native jar versions in toml files\" Ballerina.toml Dependencies.toml CompilerPlugin.toml" 76 | } else { 77 | commandLine 'sh', '-c', "git commit -m \"[Automated] Update native jar versions in toml files\" Ballerina.toml Dependencies.toml CompilerPlugin.toml" 78 | } 79 | } 80 | } 81 | } 82 | 83 | publishing { 84 | publications { 85 | maven(MavenPublication) { 86 | artifact source: createArtifactZip, extension: 'zip' 87 | } 88 | } 89 | repositories { 90 | maven { 91 | name = 'GitHubPackages' 92 | url = uri("https://maven.pkg.github.com/ballerina-platform/module-${packageOrg}-${packageName}") 93 | credentials { 94 | username = System.getenv('publishUser') 95 | password = System.getenv('publishPAT') 96 | } 97 | } 98 | } 99 | } 100 | 101 | updateTomlFiles.dependsOn copyStdlibs 102 | 103 | build.dependsOn "generatePomFileForMavenPublication" 104 | build.dependsOn ":${packageName}-native:build" 105 | build.dependsOn ":${packageName}-compiler-plugin:build" 106 | build.dependsOn ":${packageName}-test-utils:build" 107 | 108 | test.dependsOn ":${packageName}-native:build" 109 | test.dependsOn ":${packageName}-compiler-plugin:build" 110 | test.dependsOn ":${packageName}-test-utils:build" 111 | -------------------------------------------------------------------------------- /ballerina/client.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | # Represents an SQL client. 20 | public type Client isolated client object { 21 | 22 | # Executes the query, which may return multiple results. 23 | # When processing the stream, make sure to consume all fetched data or close the stream. 24 | # 25 | # + sqlQuery - The SQL query 26 | # + rowType - The `typedesc` of the record to which the result needs to be returned 27 | # + return - Stream of records in the `rowType` type 28 | remote isolated function query(ParameterizedQuery sqlQuery, typedesc rowType = <>) 29 | returns stream ; 30 | 31 | # Executes the query, which is expected to return at most one row of the result. 32 | # If the query does not return any results, `sql:NoRowsError` is returned. 33 | # 34 | # + sqlQuery - The SQL query 35 | # + returnType - The `typedesc` of the record to which the result needs to be returned. 36 | # It can be a basic type if the query result contains only one column 37 | # + return - Result in the `returnType` type or an `sql:Error` 38 | remote isolated function queryRow(ParameterizedQuery sqlQuery, typedesc returnType = <>) 39 | returns returnType|Error; 40 | 41 | # Executes the SQL query. Only the metadata of the execution is returned (not the results from the query). 42 | # 43 | # + sqlQuery - The SQL query 44 | # + return - Metadata of the query execution as an `sql:ExecutionResult` or an `sql:Error` 45 | remote isolated function execute(ParameterizedQuery sqlQuery) returns ExecutionResult|Error; 46 | 47 | # Executes the SQL query with multiple sets of parameters in a batch. Only the metadata of the execution is returned (not the results from the query). 48 | # If one of the commands in the batch fails, an `sql:BatchExecuteError` will be returned. However, the driver may 49 | # or may not continue to process the remaining commands in the batch after a failure. 50 | # 51 | # + sqlQueries - The SQL query with multiple sets of parameters 52 | # + return - Metadata of the query execution as an `sql:ExecutionResult[]` or an `sql:Error` 53 | remote isolated function batchExecute(ParameterizedQuery[] sqlQueries) returns ExecutionResult[]|Error; 54 | 55 | # Executes an SQL query, which calls a stored procedure. This may or may not 56 | # return results. Once the results are processed, the `close` method on `sql:ProcedureCallResult` must be called. 57 | # 58 | # + sqlQuery - The SQL query 59 | # + rowTypes - `typedesc` array of the records to which the results need to be returned 60 | # + return - Summary of the execution and results are returned in an `sql:ProcedureCallResult`, or an `sql:Error` 61 | remote isolated function call(ParameterizedCallQuery sqlQuery, typedesc[] rowTypes = []) 62 | returns ProcedureCallResult|Error; 63 | 64 | # Closes the SQL client and shuts down the connection pool. The client must be closed only at the end of the 65 | # application lifetime (or closed for graceful stops in a service). 66 | # 67 | # + return - Possible `sql:Error` when closing the client 68 | public isolated function close() returns Error?; 69 | }; 70 | 71 | isolated function closedStreamInvocationError() returns Error { 72 | return error ApplicationError("Stream is closed. Therefore, no operations are allowed further on the stream."); 73 | } 74 | 75 | isolated function nextResult(ResultIterator iterator) returns record {}|Error? = @java:Method { 76 | 'class: "io.ballerina.stdlib.sql.utils.RecordIteratorUtils" 77 | } external; 78 | 79 | isolated function closeResult(ResultIterator iterator) returns Error? = @java:Method { 80 | 'class: "io.ballerina.stdlib.sql.utils.RecordIteratorUtils" 81 | } external; 82 | 83 | isolated function getNextQueryResult(ProcedureCallResult callResult) returns boolean|Error = @java:Method { 84 | 'class: "io.ballerina.stdlib.sql.utils.ProcedureCallResultUtils" 85 | } external; 86 | 87 | isolated function closeCallResult(ProcedureCallResult callResult) returns Error? = @java:Method { 88 | 'class: "io.ballerina.stdlib.sql.utils.ProcedureCallResultUtils" 89 | } external; 90 | -------------------------------------------------------------------------------- /ballerina/connection-pool.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | configurable int maxOpenConnections = 15; 20 | configurable decimal maxConnectionLifeTime = 1800.0; 21 | configurable int minIdleConnections = 15; 22 | 23 | # Represents the properties, which are used to configure a DB connection pool. 24 | # Default values of the fields can be set through the configuration API. 25 | # 26 | # + maxOpenConnections - The maximum number of open connections that the pool is allowed to have. 27 | # Includes both idle and in-use connections. The default value is 15. This can be changed through 28 | # the configuration API with the `ballerina.sql.maxOpenConnections` key 29 | # + maxConnectionLifeTime - The maximum lifetime (in seconds) of a connection in the pool. The default value is 1800 30 | # seconds (30 minutes). A value of 0 indicates an unlimited maximum lifetime (infinite lifetime). 31 | # The minimum allowed value is 30 seconds. This can be changed through the configuration API 32 | # with the `ballerina.sql.maxConnectionLifeTime` key. 33 | # + minIdleConnections - The minimum number of idle connections that the pool tries to maintain. The default value 34 | # is the same as `maxOpenConnections` and it can be changed through the configuration 35 | # API with the `ballerina.sql.minIdleConnections` key 36 | public type ConnectionPool record {| 37 | int maxOpenConnections = maxOpenConnections; 38 | decimal maxConnectionLifeTime = maxConnectionLifeTime; 39 | int minIdleConnections = minIdleConnections; 40 | |}; 41 | 42 | // A container object that holds the global pool config and initializes the internal map of connection pools 43 | readonly class GlobalConnectionPoolContainer { 44 | private ConnectionPool connectionPool = {}; 45 | 46 | isolated function init() { 47 | // poolConfig record is frozen so that it cannot be modified during runtime 48 | ConnectionPool frozenConfig = self.connectionPool.cloneReadOnly(); 49 | initGlobalPoolContainer(frozenConfig); 50 | } 51 | 52 | public isolated function getGlobalConnectionPool() returns ConnectionPool { 53 | return self.connectionPool; 54 | } 55 | } 56 | 57 | isolated function initGlobalPoolContainer(ConnectionPool poolConfig) = @java:Method { 58 | 'class: "io.ballerina.stdlib.sql.utils.ConnectionPoolUtils" 59 | } external; 60 | 61 | // This is an instance of GlobalPoolConfigContainer object type. The init functions of database clients pass 62 | // poolConfig member of this instance to the external client creation logic in order to access the internal map 63 | // of connection pools. 64 | final GlobalConnectionPoolContainer globalPoolContainer = new; 65 | 66 | # Returns the global connection pool. 67 | # 68 | # + return - The connection pool 69 | public isolated function getGlobalConnectionPool() returns ConnectionPool { 70 | return globalPoolContainer.getGlobalConnectionPool(); 71 | } 72 | -------------------------------------------------------------------------------- /ballerina/error.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | # Represents the properties belonging to an `sql:BatchExecuteError`. 18 | # 19 | # + errorCode - SQL error code 20 | # + sqlState - SQL state 21 | # + executionResults - Metadata of the query executions 22 | public type BatchExecuteErrorDetail record { 23 | int errorCode; 24 | string? sqlState; 25 | ExecutionResult[] executionResults; 26 | }; 27 | 28 | # Represents the properties belonging to an `sql:DatabaseError`. 29 | # 30 | # + errorCode - SQL error code 31 | # + sqlState - SQL state 32 | public type DatabaseErrorDetail record { 33 | int errorCode; 34 | string? sqlState; 35 | }; 36 | 37 | //Level 1 38 | # Defines the generic error type for the `sql` module. 39 | public type Error distinct error; 40 | 41 | //Level 2 42 | # Represents an error caused by an issue related to database accessibility, erroneous queries, constraint violations, 43 | # database resource clean-up, and other similar scenarios. 44 | public type DatabaseError distinct (Error & error); 45 | 46 | # Represents an error that occurs during the execution of batch queries. 47 | public type BatchExecuteError distinct (Error & error); 48 | 49 | # Represents an error that occurs when a query retrieves does not retrieve any rows when at least one row is expected. 50 | public type NoRowsError distinct Error; 51 | 52 | # Represents an error originating from application-level configurations. 53 | public type ApplicationError distinct Error; 54 | 55 | //Level 3 56 | # Represents an error that occurs during the processing of the parameters or returned results. 57 | public type DataError distinct ApplicationError; 58 | 59 | // Level 4 60 | # Represents an error that occurs when a query retrieves a result that differs from the supported result type. 61 | public type TypeMismatchError distinct DataError; 62 | 63 | # Represents an error that occurs when a query retrieves a result that is corrupted and cannot be converted to the expected type. 64 | public type ConversionError distinct DataError; 65 | 66 | # Represents an error that occurs when a query retrieves a result that cannot be mapped to the expected record type. 67 | public type FieldMismatchError distinct DataError; 68 | 69 | # Represents an error that occurs when an unsupported parameter type is added to the query. 70 | public type UnsupportedTypeError distinct DataError; 71 | -------------------------------------------------------------------------------- /ballerina/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerina-sql/37e8f355043835786e007f2c3d555784de054cf8/ballerina/icon.png -------------------------------------------------------------------------------- /ballerina/init.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | isolated function init() { 20 | setModule(); 21 | } 22 | 23 | isolated function setModule() = @java:Method { 24 | 'class: "io.ballerina.stdlib.sql.utils.ModuleUtils" 25 | } external; 26 | -------------------------------------------------------------------------------- /ballerina/metadata_types.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | # Represents the type of the table/view retrieved through the `getTableInfo` function. 18 | # 19 | # + BASE_TABLE - The retrieved object is a table 20 | # + VIEW - The retrieved object is a view 21 | public enum TableType { 22 | BASE_TABLE = "BASE TABLE", 23 | VIEW = "VIEW" 24 | } 25 | 26 | # Represents the type of actions that would be taken on delete or on update for foreign key constraints. 27 | # 28 | # + NO_ACTION - Behaviour is dependent on the database 29 | # + RESTRICT - Rejects the operations if the foreign key constraint is violated 30 | # + CASCADE - The changes are propogated to the child table 31 | # + NET_NULL - Sets the values in the child table's corresponding rows to `null` 32 | # + SET_DEFAULT - Replaces the values in the child table's corresponding rows with the default value 33 | public enum ReferentialRule { 34 | NO_ACTION = "NO ACTION", 35 | RESTRICT = "RESTRICT", 36 | CASCADE = "CASCADE", 37 | SET_NULL = "SET NULL", 38 | SET_DEFAULT = "SET DEFAULT" 39 | } 40 | 41 | # Represents the type of the routine retrieved through the `getRoutineInfo` function. 42 | # 43 | # + PROCEDURE - The retrieved object is a procedure 44 | # + FUNCTION - The retrieved object is a function 45 | public enum RoutineType { 46 | PROCEDURE = "PROCEDURE", 47 | FUNCTION = "FUNCTION" 48 | } 49 | 50 | # Represents the mode of the parameter for a routine. 51 | # 52 | # + IN - Only used to pass an input into the routine 53 | # + OUT - Only used to retrieve an output from the routine 54 | # + INOUT - Used to both pass and input and retrieve an output from the routine 55 | public enum ParameterMode { 56 | IN = "IN", 57 | OUT = "OUT", 58 | INOUT = "INOUT" 59 | } 60 | 61 | # Represents a table in the database. 62 | # 63 | # + name - The name of the table 64 | # + 'type - Whether the table is a base table or a view 65 | # + columns - The columns included in the table 66 | # + checkConstraints - Check constraints associated with the table 67 | public type TableDefinition record { 68 | string name; 69 | TableType 'type; 70 | ColumnDefinition[] columns?; 71 | CheckConstraint[] checkConstraints?; 72 | }; 73 | 74 | # Represents a column in a table. 75 | # 76 | # + name - The name of the column 77 | # + 'type - The SQL data-type associated with the column 78 | # + defaultValue - The default value of the column 79 | # + nullable - Whether the column is nullable 80 | # + referentialConstraints - Referential constraints (foreign key relationships) associated with the column 81 | public type ColumnDefinition record { 82 | string name; 83 | string 'type; 84 | anydata? defaultValue; 85 | boolean nullable; 86 | ReferentialConstraint[] referentialConstraints?; 87 | }; 88 | 89 | # Represents a referential constraint (foriegn key constraint). 90 | # 91 | # + name - The name of the constraint 92 | # + tableName - The name of the table which contains the referenced column 93 | # + columnName - The name of the referenced column 94 | # + updateRule - The action taken when an update statement violates the constraint 95 | # + deleteRule - The action taken when a delete statement violates the constraint 96 | public type ReferentialConstraint record { 97 | string name; 98 | string tableName; 99 | string columnName; 100 | ReferentialRule updateRule; 101 | ReferentialRule deleteRule; 102 | }; 103 | 104 | # Represents a check constraint. 105 | # 106 | # + name - The name of the constraint 107 | # + clause - The actual text of the SQL definition statement 108 | public type CheckConstraint record { 109 | string name; 110 | string clause; 111 | }; 112 | 113 | # Represents a routine. 114 | # 115 | # + name - The name of the routine 116 | # + 'type - The type of the routine (procedure or function) 117 | # + returnType - If the routine returns a value, the return data-type. Else () 118 | # + parameters - The parameters associated with the routine 119 | public type RoutineDefinition record { 120 | string name; 121 | RoutineType 'type; 122 | string? returnType; 123 | ParameterDefinition[] parameters; 124 | }; 125 | 126 | # Represents a routine parameter. 127 | # 128 | # + mode - The mode of the parameter (IN, OUT, INOUT) 129 | # + name - The name of the parameter 130 | # + type - The data-type of the parameter 131 | public type ParameterDefinition record { 132 | ParameterMode mode; 133 | string name; 134 | string 'type; 135 | }; 136 | -------------------------------------------------------------------------------- /ballerina/schema_client.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | # Represents an SQL metadata client. 18 | # 19 | public type SchemaClient client object { 20 | 21 | # Retrieves all tables in the database. 22 | # 23 | # + return - A string array containing the names of the tables or an `sql:Error` 24 | remote isolated function listTables() returns string[]|Error; 25 | 26 | # Retrieves information relevant to the provided table in the database. 27 | # 28 | # + tableName - The name of the table 29 | # + include - Options on whether columnar and constraint related information should be fetched. 30 | # If `NO_COLUMNS` is provided, then no information related to columns will be retrieved. 31 | # If `COLUMNS_ONLY` is provided, then columnar information will be retrieved, but not constraint 32 | # related information. 33 | # If `COLUMNS_WITH_CONSTRAINTS` is provided, then columar information along with constraint related 34 | # information will be retrieved 35 | # + return - An 'sql:TableDefinition' with the relevant table information or an `sql:Error` 36 | remote isolated function getTableInfo(string tableName, ColumnRetrievalOptions include = COLUMNS_ONLY) returns TableDefinition|Error; 37 | 38 | # Retrieves all routines in the database. 39 | # 40 | # + return - A string array containing the names of the routines or an `sql:Error` 41 | remote isolated function listRoutines() returns string[]|Error; 42 | 43 | # Retrieves information relevant to the provided routine in the database. 44 | # 45 | # + name - The name of the routine 46 | # + return - An 'sql:RoutineDefinition' with the relevant routine information or an `sql:Error` 47 | remote isolated function getRoutineInfo(string name) returns RoutineDefinition|Error; 48 | 49 | # Closes the SQL metadata client. 50 | # 51 | # + return - Possible `sql:Error` when closing the client 52 | public isolated function close() returns Error?; 53 | }; 54 | 55 | public enum ColumnRetrievalOptions { 56 | NO_COLUMNS, 57 | COLUMNS_ONLY, 58 | COLUMNS_WITH_CONSTRAINTS 59 | } 60 | -------------------------------------------------------------------------------- /ballerina/tests/Config.toml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | # 4 | # WSO2 Inc. licenses this file to you under the Apache License, 5 | # Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | # 18 | 19 | [sql] 20 | maxOpenConnections=10 21 | maxConnectionLifeTime=2000.5 22 | minIdleConnections=5 23 | -------------------------------------------------------------------------------- /ballerina/tests/batch-execute-query-test.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/test; 18 | 19 | string batchExecuteDB = urlPrefix + "9005/BatchExecute"; 20 | 21 | @test:BeforeGroups { 22 | value: ["batch-execute"] 23 | } 24 | function initBatchExecuteContainer() returns error? { 25 | check initializeDockerContainer("sql-batch-execute", "BatchExecute", "9005", "batchexecute", "batch-execute-test-data.sql"); 26 | } 27 | 28 | @test:AfterGroups { 29 | value: ["batch-execute"] 30 | } 31 | function cleanBatchExecuteContainer() returns error? { 32 | check cleanDockerContainer("sql-batch-execute"); 33 | } 34 | 35 | @test:Config { 36 | groups: ["batch-execute"] 37 | } 38 | function batchInsertIntoDataTable() returns error? { 39 | var data = [ 40 | {intVal: 3, longVal: 9223372036854774807, floatVal: 123.34}, 41 | {intVal: 4, longVal: 9223372036854774807, floatVal: 123.34}, 42 | {intVal: 5, longVal: 9223372036854774807, floatVal: 123.34} 43 | ]; 44 | ParameterizedQuery[] sqlQueries = 45 | from var row in data 46 | select `INSERT INTO DataTable (int_type, long_type, float_type) VALUES (${row.intVal}, ${row.longVal}, ${row.floatVal})`; 47 | validateBatchExecutionResult(check batchExecuteQueryMockClient(sqlQueries), [1, 1, 1], [2,3,4]); 48 | } 49 | 50 | @test:Config { 51 | groups: ["batch-execute"], 52 | dependsOn: [batchInsertIntoDataTable] 53 | } 54 | function batchInsertIntoDataTable2() returns error? { 55 | int intType = 6; 56 | ParameterizedQuery sqlQuery = `INSERT INTO DataTable (int_type) VALUES(${intType})`; 57 | ParameterizedQuery[] sqlQueries = [sqlQuery]; 58 | validateBatchExecutionResult(check batchExecuteQueryMockClient(sqlQueries), [1], [5]); 59 | } 60 | 61 | @test:Config { 62 | groups: ["batch-execute"], 63 | dependsOn: [batchInsertIntoDataTable2] 64 | } 65 | function batchInsertIntoDataTableFailure() { 66 | var data = [ 67 | {intVal: 7, longVal: 9223372036854774807, floatVal: 123.34}, 68 | {intVal: 1, longVal: 9223372036854774807, floatVal: 123.34}, 69 | {intVal: 9, longVal: 9223372036854774807, floatVal: 123.34} 70 | ]; 71 | ParameterizedQuery[] sqlQueries = 72 | from var row in data 73 | select `INSERT INTO DataTable (int_type, long_type, float_type) VALUES (${row.intVal}, ${row.longVal}, ${row.floatVal})`; 74 | ExecutionResult[]|error result = batchExecuteQueryMockClient(sqlQueries); 75 | test:assertTrue(result is error); 76 | 77 | if result is BatchExecuteError { 78 | BatchExecuteErrorDetail errorDetails = result.detail(); 79 | test:assertEquals(errorDetails.executionResults.length(), 1); 80 | test:assertEquals(errorDetails.executionResults[0].affectedRowCount, 1); 81 | } else { 82 | test:assertFail("BatchExecuteError expected."); 83 | } 84 | } 85 | 86 | @test:Config { 87 | groups: ["batch-execute"], 88 | dependsOn: [batchInsertIntoDataTable2] 89 | } 90 | function batchInsertIntoDataTableFailure3() { 91 | ParameterizedQuery[] sqlQueries = [ 92 | `INSERT INTO DataTable (int_type, long_type, float_type) VALUES (13, 9223372036854774807, 123.34);`, 93 | `UPDATE DataTable1 SET int_type=13 WHERE int_type=13;` 94 | ]; 95 | ExecutionResult[]|error result = batchExecuteQueryMockClient(sqlQueries); 96 | test:assertTrue(result is ApplicationError); 97 | } 98 | 99 | isolated function validateBatchExecutionResult(ExecutionResult[] results, int[] rowCount, int[] lastId) { 100 | test:assertEquals(results.length(), rowCount.length()); 101 | 102 | int i = 0; 103 | while (i < results.length()) { 104 | test:assertEquals(results[i].affectedRowCount, rowCount[i]); 105 | int|string? lastInsertIdVal = results[i].lastInsertId; 106 | if lastId[i] == -1 { 107 | test:assertEquals(lastInsertIdVal, ()); 108 | } else if lastInsertIdVal is int { 109 | test:assertTrue(lastInsertIdVal > 1, "Last Insert Id is nil."); 110 | } else { 111 | test:assertFail("The last insert id should be an integer."); 112 | } 113 | i = i + 1; 114 | } 115 | } 116 | 117 | function batchExecuteQueryMockClient(ParameterizedQuery[] sqlQueries) 118 | returns ExecutionResult[]|error { 119 | MockClient dbClient = check new (url = batchExecuteDB, user = user, password = password); 120 | ExecutionResult[] result = check dbClient->batchExecute(sqlQueries); 121 | check dbClient.close(); 122 | return result; 123 | } 124 | -------------------------------------------------------------------------------- /ballerina/tests/client.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | # Represents a Mock database client. 20 | isolated client class MockClient { 21 | *Client; 22 | 23 | public function init(string url, string? user = (), string? password = (), string? datasourceName = (), 24 | map? options = (), ConnectionPool? connectionPool = (), 25 | map? connectionPoolOptions = ()) returns Error? { 26 | SQLParams sqlParams = { 27 | url: url, 28 | user: user, 29 | password: password, 30 | datasourceName: datasourceName, 31 | options: options, 32 | connectionPool: connectionPool, 33 | connectionPoolOptions: connectionPoolOptions 34 | }; 35 | return createSqlClient(self, sqlParams, getGlobalConnectionPool()); 36 | } 37 | 38 | remote isolated function query(ParameterizedQuery sqlQuery, typedesc rowType = <>) 39 | returns stream = @java:Method { 40 | 'class: "io.ballerina.stdlib.sql.testutils.QueryTestUtils", 41 | name: "nativeQuery" 42 | } external; 43 | 44 | remote isolated function queryRow(ParameterizedQuery sqlQuery, typedesc returnType = <>) 45 | returns returnType|Error = @java:Method { 46 | 'class: "io.ballerina.stdlib.sql.testutils.QueryTestUtils", 47 | name: "nativeQueryRow" 48 | } external; 49 | 50 | remote isolated function execute(ParameterizedQuery sqlQuery) 51 | returns ExecutionResult|Error = @java:Method { 52 | 'class: "io.ballerina.stdlib.sql.testutils.ExecuteTestUtils", 53 | name: "nativeExecute" 54 | } external; 55 | 56 | remote isolated function batchExecute(ParameterizedQuery[] sqlQueries) returns ExecutionResult[]|Error { 57 | if sqlQueries.length() == 0 { 58 | return error ApplicationError(" Parameter 'sqlQueries' cannot be empty array"); 59 | } 60 | return nativeBatchExecute(self, sqlQueries); 61 | } 62 | 63 | remote isolated function call(ParameterizedCallQuery sqlQuery, typedesc[] rowTypes = []) 64 | returns ProcedureCallResult|Error = @java:Method { 65 | 'class: "io.ballerina.stdlib.sql.testutils.CallTestUtils", 66 | name: "nativeCall" 67 | } external; 68 | 69 | public isolated function close() returns Error? = @java:Method { 70 | 'class: "io.ballerina.stdlib.sql.testutils.ClientTestUtils", 71 | name: "close" 72 | } external; 73 | } 74 | 75 | type SQLParams record {| 76 | string? url; 77 | string? user; 78 | string? password; 79 | string? datasourceName; 80 | map? options; 81 | ConnectionPool? connectionPool; 82 | map? connectionPoolOptions; 83 | |}; 84 | 85 | function createSqlClient(Client sqlClient, SQLParams sqlParams, ConnectionPool globalConnPool) 86 | returns Error? = @java:Method { 87 | 'class: "io.ballerina.stdlib.sql.testutils.ClientTestUtils" 88 | } external; 89 | 90 | isolated function nativeBatchExecute(Client sqlClient, ParameterizedQuery[] sqlQueries) 91 | returns ExecutionResult[]|Error = @java:Method { 92 | 'class: "io.ballerina.stdlib.sql.testutils.ExecuteTestUtils" 93 | } external; 94 | -------------------------------------------------------------------------------- /ballerina/tests/process.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | # Represents a Process error. 20 | public type ProcessError distinct error; 21 | 22 | # This object contains information on a process being created from Ballerina. 23 | # This is returned from the `exec` function. 24 | public class Process { 25 | 26 | # Waits for the process to finish its work and exit. 27 | # ```ballerina 28 | # int|error exitCode = process.waitForExit(); 29 | # ``` 30 | # 31 | # + return - Returns the exit code for the process or else an `Error` if a failure occurs 32 | public isolated function waitForExit() returns int|ProcessError { 33 | return nativeWaitForExit(self); 34 | } 35 | 36 | # Returns the exit code of the process when it has finished the execution. 37 | # Error if the process has not exited yet. 38 | # ```ballerina 39 | # int|error exitCode = process.exitCode(); 40 | # ``` 41 | # 42 | # + return - Returns the exit code of the process or else an `Error` if the process hasn't exited yet 43 | public isolated function exitCode() returns int|ProcessError { 44 | return nativeExitCode(self); 45 | } 46 | } 47 | 48 | isolated function nativeWaitForExit(Process process) returns int|ProcessError = @java:Method { 49 | name: "waitForExit", 50 | 'class: "io.ballerina.stdlib.sql.testutils.nativeimpl.WaitForExit" 51 | } external; 52 | 53 | isolated function nativeExitCode(Process process) returns int|ProcessError = @java:Method { 54 | name: "exitCode", 55 | 'class: "io.ballerina.stdlib.sql.testutils.nativeimpl.ExitCode" 56 | } external; 57 | 58 | -------------------------------------------------------------------------------- /ballerina/tests/resources/files/blobValue.txt: -------------------------------------------------------------------------------- 1 | wso2 ballerina blob test. -------------------------------------------------------------------------------- /ballerina/tests/resources/files/byteValue.txt: -------------------------------------------------------------------------------- 1 | wso2 ballerina binary test. -------------------------------------------------------------------------------- /ballerina/tests/resources/files/clobValue.txt: -------------------------------------------------------------------------------- 1 | very long text -------------------------------------------------------------------------------- /ballerina/tests/resources/sql/batchexecute/batch-execute-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS DataTable( 2 | id INT IDENTITY, 3 | int_type INTEGER UNIQUE, 4 | long_type BIGINT, 5 | float_type FLOAT, 6 | PRIMARY KEY (id) 7 | ); 8 | 9 | INSERT INTO DataTable (int_type, long_type, float_type) 10 | VALUES(1, 9223372036854774807, 123.34); 11 | 12 | INSERT INTO DataTable (int_type, long_type, float_type) 13 | VALUES(2, 9372036854774807, 124.34); 14 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql/connection/connector-init-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS Customers( 2 | customerId INTEGER NOT NULL IDENTITY, 3 | firstName VARCHAR(300), 4 | lastName VARCHAR(300), 5 | registrationID INTEGER, 6 | creditLimit DOUBLE, 7 | country VARCHAR(300), 8 | PRIMARY KEY (customerId) 9 | ); 10 | 11 | INSERT INTO Customers (firstName,lastName,registrationID,creditLimit,country) 12 | VALUES ('Peter', 'Stuart', 1, 5000.75, 'USA'); 13 | 14 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql/error/error-database-init.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS DataTable( 2 | row_id INTEGER, 3 | string_type VARCHAR(50), 4 | PRIMARY KEY (row_id) 5 | ); 6 | 7 | INSERT INTO DataTable (row_id, string_type) VALUES(1, '{""q}'); 8 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql/execute/execute-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE NumericTypes ( 2 | id INT IDENTITY, 3 | int_type INT, 4 | bigint_type BIGINT, 5 | smallint_type SMALLINT, 6 | tinyint_type TINYINT, 7 | bit_type BIT, 8 | decimal_type DECIMAL(10,2), 9 | numeric_type NUMERIC(10,2), 10 | float_type FLOAT, 11 | real_type REAL, 12 | PRIMARY KEY (id) 13 | ); 14 | 15 | INSERT INTO NumericTypes (int_type) VALUES (10); 16 | 17 | CREATE TABLE StringTypes ( 18 | id INT, 19 | varchar_type VARCHAR(255), 20 | charmax_type CHAR(10), 21 | char_type CHAR, 22 | charactermax_type CHARACTER(10), 23 | character_type CHARACTER, 24 | nvarcharmax_type NVARCHAR(255), 25 | longvarchar_type LONGVARCHAR, 26 | clob_type CLOB, 27 | PRIMARY KEY (id) 28 | ); 29 | 30 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql/metadata/metadata-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS Customers ( 2 | customerId INTEGER NOT NULL IDENTITY, 3 | firstName VARCHAR(300) NOT NULL, 4 | lastName VARCHAR(300) NOT NULL, 5 | registrationID INTEGER NOT NULL, 6 | creditLimit DOUBLE DEFAULT 100.00, 7 | country VARCHAR(300), 8 | PRIMARY KEY (customerId), 9 | CHECK (creditLimit > 50) 10 | ); 11 | 12 | CREATE TABLE IF NOT EXISTS DataTable ( 13 | row_id INTEGER IDENTITY, 14 | int_type INTEGER, 15 | long_type BIGINT, 16 | float_type FLOAT, 17 | double_type DOUBLE, 18 | boolean_type BOOLEAN, 19 | string_type VARCHAR(50) DEFAULT 'test', 20 | decimal_type DECIMAL(20, 2), 21 | PRIMARY KEY (row_id) 22 | ); 23 | 24 | CREATE TABLE IF NOT EXISTS NumericTypes ( 25 | id INT IDENTITY, 26 | int_type INT, 27 | bigint_type BIGINT, 28 | smallint_type SMALLINT, 29 | tinyint_type TINYINT, 30 | bit_type BIT, 31 | decimal_type DECIMAL(10,2), 32 | numeric_type NUMERIC(10,2), 33 | float_type FLOAT, 34 | real_type REAL, 35 | PRIMARY KEY (id) 36 | ); 37 | 38 | CREATE VIEW IF NOT EXISTS CustomerNames AS SELECT firstName, lastName FROM Customers; 39 | 40 | CREATE TABLE IF NOT EXISTS Company ( 41 | companyId INTEGER NOT NULL IDENTITY, 42 | name VARCHAR(300) NOT NULL 43 | ); 44 | 45 | CREATE TABLE IF NOT EXISTS Person ( 46 | personId INTEGER NOT NULL IDENTITY, 47 | name VARCHAR(300) NOT NULL, 48 | companyId INTEGER NOT NULL, 49 | FOREIGN KEY (companyId) REFERENCES Company(companyId), 50 | CHECK (personId > 100), 51 | CHECK (companyId > 20) 52 | ); 53 | 54 | CREATE TABLE IF NOT EXISTS Person2 ( 55 | personId INTEGER NOT NULL IDENTITY, 56 | name VARCHAR(300) NOT NULL, 57 | companyId INTEGER NOT NULL, 58 | FOREIGN KEY (companyId) REFERENCES Company(companyId) ON UPDATE CASCADE ON DELETE CASCADE, 59 | CHECK (personId > 100), 60 | CHECK (companyId > 20) 61 | ); 62 | 63 | 64 | CREATE TABLE IF NOT EXISTS StringTypes ( 65 | id INT IDENTITY, 66 | varchar_type VARCHAR(255), 67 | charmax_type CHAR(10), 68 | char_type CHAR, 69 | charactermax_type CHARACTER(10), 70 | character_type CHARACTER, 71 | nvarcharmax_type NVARCHAR(255), 72 | PRIMARY KEY (id) 73 | ); 74 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql/pool/connection-pool-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS Customers( 2 | customerId INTEGER NOT NULL IDENTITY, 3 | firstName VARCHAR(300), 4 | lastName VARCHAR(300), 5 | registrationID INTEGER, 6 | creditLimit DOUBLE, 7 | country VARCHAR(300), 8 | PRIMARY KEY (customerId) 9 | ); 10 | 11 | INSERT INTO Customers (firstName,lastName,registrationID,creditLimit,country) 12 | VALUES ('Peter', 'Stuart', 1, 5000.75, 'USA'); 13 | 14 | INSERT INTO Customers (firstName,lastName,registrationID,creditLimit,country) 15 | VALUES ('Dan', 'Brown', 2, 10000, 'UK'); 16 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql/query/numerical-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE NumericTypes ( 2 | id INT IDENTITY, 3 | int_type INT NOT NULL, 4 | bigint_type BIGINT NOT NULL, 5 | smallint_type SMALLINT NOT NULL , 6 | tinyint_type TINYINT NOT NULL , 7 | bit_type BIT NOT NULL , 8 | decimal_type DECIMAL(10,3) NOT NULL , 9 | numeric_type NUMERIC(10,3) NOT NULL , 10 | float_type FLOAT NOT NULL , 11 | real_type REAL NOT NULL , 12 | PRIMARY KEY (id) 13 | ); 14 | 15 | INSERT INTO NumericTypes (id, int_type, bigint_type, smallint_type, tinyint_type, bit_type, decimal_type, numeric_type, 16 | float_type, real_type) VALUES (1, 2147483647, 9223372036854774807, 32767, 127, 1, 1234.567, 1234.567, 1234.567, 17 | 1234.567); 18 | 19 | 20 | CREATE TABLE NumericNullTypes ( 21 | id INT IDENTITY, 22 | int_type INT, 23 | bigint_type BIGINT, 24 | smallint_type SMALLINT, 25 | tinyint_type TINYINT, 26 | bit_type BIT, 27 | decimal_type DECIMAL(10,3), 28 | numeric_type NUMERIC(10,3), 29 | float_type FLOAT, 30 | real_type REAL, 31 | PRIMARY KEY (id) 32 | ); 33 | 34 | INSERT INTO NumericNullTypes (id, int_type, bigint_type, smallint_type, tinyint_type, bit_type, decimal_type, numeric_type, 35 | float_type, real_type) VALUES (1, 2147483647, 9223372036854774807, 32767, 127, 1, 1234.567, 1234.567, 1234.567, 36 | 1234.567); 37 | 38 | 39 | INSERT INTO NumericNullTypes (id, int_type, bigint_type, smallint_type, tinyint_type, bit_type, decimal_type, numeric_type, 40 | float_type, real_type) VALUES (2, null , null , null , null , null , null , null , null , 41 | null ); 42 | 43 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql/query/simple-params-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS DataTable( 2 | row_id INTEGER, 3 | int_type INTEGER, 4 | long_type BIGINT, 5 | float_type FLOAT, 6 | double_type DOUBLE, 7 | boolean_type BOOLEAN, 8 | string_type VARCHAR(50), 9 | decimal_type DECIMAL(20, 2), 10 | PRIMARY KEY (row_id) 11 | ); 12 | 13 | INSERT INTO DataTable (row_id, int_type, long_type, float_type, double_type, boolean_type, string_type, decimal_type) 14 | VALUES(1, 1, 9223372036854774807, 123.34, 2139095039, TRUE, 'Hello', 23.45); 15 | 16 | INSERT INTO DataTable (row_id) VALUES (2); 17 | 18 | INSERT INTO DataTable (row_id, int_type, long_type, float_type, double_type, boolean_type, string_type, decimal_type) 19 | VALUES(3, 1, 9372036854774807, 124.34, 29095039, false, '1', 25.45); 20 | 21 | INSERT INTO DataTable (row_id, int_type, long_type, float_type, double_type, boolean_type, string_type, decimal_type) 22 | VALUES(100, 1, 9223372036852774807, 123.14, 2139055039, TRUE, 'Hi', 23.45); 23 | 24 | CREATE TABLE IF NOT EXISTS ComplexTypes( 25 | row_id INTEGER NOT NULL, 26 | blob_type BLOB(1024), 27 | clob_type CLOB(1024), 28 | binary_type BINARY(27), 29 | var_binary_type VARBINARY(27), 30 | PRIMARY KEY (row_id) 31 | ); 32 | 33 | INSERT INTO ComplexTypes (row_id, blob_type, clob_type, binary_type, var_binary_type) VALUES 34 | (1, X'77736F322062616C6C6572696E6120626C6F6220746573742E', CONVERT('very long text', CLOB), 35 | X'77736F322062616C6C6572696E612062696E61727920746573742E', X'77736F322062616C6C6572696E612062696E61727920746573742E'); 36 | 37 | INSERT INTO ComplexTypes (row_id, blob_type, clob_type, binary_type, var_binary_type) VALUES 38 | (2, null, null, null, null); 39 | 40 | 41 | CREATE TABLE NumericTypes ( 42 | id INT IDENTITY, 43 | int_type INT NOT NULL, 44 | bigint_type BIGINT NOT NULL, 45 | smallint_type SMALLINT NOT NULL , 46 | tinyint_type TINYINT NOT NULL , 47 | bit_type BIT NOT NULL , 48 | decimal_type DECIMAL(10,3) NOT NULL , 49 | numeric_type NUMERIC(10,3) NOT NULL , 50 | float_type FLOAT NOT NULL , 51 | real_type REAL NOT NULL , 52 | PRIMARY KEY (id) 53 | ); 54 | 55 | INSERT INTO NumericTypes (id, int_type, bigint_type, smallint_type, tinyint_type, bit_type, decimal_type, numeric_type, 56 | float_type, real_type) VALUES (1, 2147483647, 9223372036854774807, 32767, 127, 1, 1234.567, 1234.567, 1234.567, 57 | 1234.567); 58 | 59 | 60 | INSERT INTO NumericTypes (id, int_type, bigint_type, smallint_type, tinyint_type, bit_type, decimal_type, numeric_type, 61 | float_type, real_type) VALUES (2, 2147483647, 9223372036854774807, 32767, 127, 1, 1234, 1234, 1234, 62 | 1234); 63 | 64 | CREATE TABLE IF NOT EXISTS DateTimeTypes( 65 | row_id INTEGER NOT NULL, 66 | date_type DATE, 67 | time_type TIME, 68 | timestamp_type TIMESTAMP, 69 | datetime_type datetime, 70 | time_type2 TIME(6) WITH TIME ZONE, 71 | timestamp_type2 TIMESTAMP(2) WITH TIME ZONE, 72 | PRIMARY KEY (row_id) 73 | ); 74 | 75 | INSERT INTO DateTimeTypes (row_id, date_type, time_type, datetime_type, timestamp_type, time_type2, timestamp_type2) VALUES 76 | (1,'2017-02-03', '11:35:45', '2017-02-03 11:53:00', '2017-02-03 11:53:00','20:08:08-8:00','2008-08-08 20:08:08+8:00'); 77 | 78 | CREATE TABLE IF NOT EXISTS ArrayTypes( 79 | row_id INTEGER NOT NULL, 80 | int_array INTEGER ARRAY, 81 | long_array BIGINT ARRAY, 82 | float_array FLOAT ARRAY, 83 | double_array DOUBLE ARRAY, 84 | decimal_array DECIMAL ARRAY, 85 | boolean_array BOOLEAN ARRAY, 86 | string_array VARCHAR(20) ARRAY, 87 | blob_array VARBINARY(27) ARRAY, 88 | PRIMARY KEY (row_id) 89 | ); 90 | 91 | INSERT INTO ArrayTypes (row_id, int_array, long_array, float_array, double_array, decimal_array, boolean_array, string_array, blob_array) 92 | VALUES (1, ARRAY [1, 2, 3], ARRAY [10000, 20000, 30000], ARRAY[245.23, 5559.49, 8796.123], 93 | ARRAY[245.23, 5559.49, 8796.123], ARRAY[245, 5559, 8796], ARRAY[TRUE, FALSE, TRUE], ARRAY['Hello', 'Ballerina'], 94 | ARRAY[X'77736F322062616C6C6572696E6120626C6F6220746573742E']); 95 | 96 | INSERT INTO ArrayTypes (row_id, int_array, long_array, float_array, double_array, decimal_array, boolean_array, string_array, blob_array) 97 | VALUES (2, ARRAY[NULL, 2, 3], ARRAY[100000000, NULL, 300000000], ARRAY[NULL, 5559.49, NULL], 98 | ARRAY[NULL, NULL, 8796.123], ARRAY[NULL, NULL, 8796], ARRAY[NULL , NULL, TRUE], ARRAY[NULL, 'Ballerina'], 99 | ARRAY[NULL, X'77736F322062616C6C6572696E6120626C6F6220746573742E']); 100 | 101 | INSERT INTO ArrayTypes (row_id, int_array, long_array, float_array, double_array, decimal_array, boolean_array, string_array, blob_array) 102 | VALUES (3, NULL, NULL, NULL, NULL,NULL , NULL, NULL, NULL); 103 | 104 | INSERT INTO ArrayTypes (row_id, int_array, long_array, float_array, double_array, decimal_array, boolean_array, string_array, blob_array) 105 | VALUES (5, ARRAY[NULL, NULL, NULL], ARRAY[NULL, NULL, NULL], ARRAY[NULL, NULL, NULL], 106 | ARRAY[NULL, NULL, NULL], ARRAY[NULL , NULL, NULL], ARRAY[NULL , NULL, NULL], ARRAY[NULL, NULL], ARRAY[NULL, NULL]); 107 | 108 | CREATE TYPE MASK_ROW_TYPE AS INTEGER; 109 | 110 | CREATE TABLE IF NOT EXISTS MaskTable( 111 | row_id MASK_ROW_TYPE, 112 | int_type INTEGER, 113 | PRIMARY KEY (row_id) 114 | ); 115 | 116 | INSERT INTO MaskTable (row_id, int_type) VALUES(1, 1); 117 | 118 | CREATE TABLE Album ( 119 | id_test VARCHAR(10), 120 | name VARCHAR(10), 121 | artist_test VARCHAR(10), 122 | price DECIMAL 123 | ); 124 | 125 | INSERT INTO Album VALUES ('1', 'Lemonade', 'Beyonce', 20.0); 126 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql/transaction/local-transaction-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS Customers( 2 | customerId INTEGER NOT NULL IDENTITY, 3 | firstName VARCHAR(300), 4 | lastName VARCHAR(300), 5 | registrationID INTEGER, 6 | creditLimit DOUBLE, 7 | country VARCHAR(300), 8 | PRIMARY KEY (customerId) 9 | ); 10 | -------------------------------------------------------------------------------- /ballerina/tests/utils.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/file; 19 | import ballerina/lang.runtime as runtime; 20 | import ballerina/test; 21 | import ballerina/jballerina.java; 22 | 23 | string scriptPath = check file:getAbsolutePath("tests/resources/sql"); 24 | 25 | string user = "test"; 26 | string password = ""; 27 | string urlPrefix = "jdbc:hsqldb:hsql://localhost:"; 28 | 29 | @test:BeforeSuite 30 | isolated function beforeSuite() { 31 | setModuleForTest(); 32 | io:println("Test suite initiated"); 33 | } 34 | 35 | @test:AfterSuite {} 36 | isolated function afterSuite() { 37 | io:println("Test suite finished"); 38 | } 39 | 40 | function initializeDockerContainer(string containerName, string dbAlias, string port, string resFolder, 41 | string scriptName) returns error? { 42 | int exitCode = 1; 43 | Process result = check exec("docker", {}, scriptPath, "run", "--rm", 44 | "-d", "--name", containerName, 45 | "-e", "HSQLDB_DATABASE_ALIAS=" + dbAlias, 46 | "-e", "HSQLDB_USER=test", 47 | "-v", check file:joinPath(scriptPath, resFolder) + ":/scripts", 48 | "-p", port + ":9001", "kaneeldias/hsqldb"); 49 | _ = check result.waitForExit(); 50 | exitCode = check result.exitCode(); 51 | test:assertEquals(exitCode, 0, "Docker container '" + containerName + "' failed to start"); 52 | io:println("Docker container for Database '" + dbAlias + "' created."); 53 | runtime:sleep(20); 54 | 55 | int counter = 0; 56 | exitCode = 1; 57 | while (exitCode > 0 && counter < 12) { 58 | runtime:sleep(5); 59 | result = check exec( 60 | "docker", {}, scriptPath, "exec", containerName, 61 | "java", "-jar", "/opt/hsqldb/sqltool.jar", 62 | "--autoCommit", 63 | "--inlineRc", "url=" + urlPrefix + "9001/" + dbAlias + ",user=test,password=", 64 | "/scripts/" + scriptName 65 | ); 66 | _ = check result.waitForExit(); 67 | exitCode = check result.exitCode(); 68 | counter = counter + 1; 69 | } 70 | test:assertExactEquals(exitCode, 0, "Docker container '" + containerName + "' health test exceeded timeout!"); 71 | io:println("Docker container for Database '" + dbAlias + "' initialised with the script."); 72 | } 73 | 74 | function cleanDockerContainer(string containerName) returns error? { 75 | Process result = check exec("docker", {}, scriptPath, "stop", containerName); 76 | _ = check result.waitForExit(); 77 | 78 | int exitCode = check result.exitCode(); 79 | test:assertExactEquals(exitCode, 0, "Docker container '" + containerName + "' stop failed!"); 80 | io:println("Cleaned docker container '" + containerName + "'."); 81 | } 82 | 83 | isolated function getByteColumnChannel() returns io:ReadableByteChannel|error { 84 | io:ReadableByteChannel byteChannel = check io:openReadableFile("./tests/resources/files/byteValue.txt"); 85 | return byteChannel; 86 | } 87 | 88 | isolated function getBlobColumnChannel() returns io:ReadableByteChannel|error { 89 | io:ReadableByteChannel byteChannel = check io:openReadableFile("./tests/resources/files/blobValue.txt"); 90 | return byteChannel; 91 | } 92 | 93 | isolated function getClobColumnChannel() returns io:ReadableCharacterChannel|error { 94 | io:ReadableByteChannel byteChannel = check io:openReadableFile("./tests/resources/files/clobValue.txt"); 95 | io:ReadableCharacterChannel sourceChannel = new (byteChannel, "UTF-8"); 96 | return sourceChannel; 97 | } 98 | 99 | isolated function getUntaintedData(record {}? value, string fieldName) returns anydata { 100 | if value is record {} { 101 | return value[fieldName]; 102 | } 103 | return {}; 104 | } 105 | 106 | function getMockClient(string url) returns MockClient|error { 107 | MockClient dbClient = check new (url = url, user = user, password = password); 108 | return dbClient; 109 | } 110 | 111 | function queryMockClient(string url, ParameterizedQuery sqlQuery) 112 | returns record {}|error? { 113 | MockClient dbClient = check getMockClient(url); 114 | stream streamData = dbClient->query(sqlQuery); 115 | record {|record {} value;|}? data = check streamData.next(); 116 | check streamData.close(); 117 | record {}? value = data?.value; 118 | check dbClient.close(); 119 | return value; 120 | } 121 | 122 | function queryRecordMockClient(string url, ParameterizedQuery sqlQuery) 123 | returns record {}|error { 124 | MockClient dbClient = check getMockClient(url); 125 | record {} resultRecord = check dbClient->queryRow(sqlQuery); 126 | check dbClient.close(); 127 | return resultRecord; 128 | } 129 | 130 | function exec(string command, map env = {}, 131 | string? dir = (), string... args) returns Process|error = @java:Method { 132 | name: "exec", 133 | 'class: "io.ballerina.stdlib.sql.testutils.nativeimpl.Exec" 134 | } external; 135 | 136 | isolated function setModuleForTest() = @java:Method { 137 | name: "setModule", 138 | 'class: "io.ballerina.stdlib.sql.testutils.nativeimpl.ModuleUtils" 139 | } external; 140 | -------------------------------------------------------------------------------- /ballerina/utils.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | # Concatenates all provided `sql:ParameterizedQuery`s into a single `sql:ParameterizedQuery`. 18 | # 19 | # + queries - Set of `sql:ParameterizedQuery` queries 20 | # + return - An `sql:ParameterizedQuery` 21 | public isolated function queryConcat(ParameterizedQuery... queries) returns ParameterizedQuery { 22 | if queries.length() == 0 { 23 | return ``; 24 | } else if queries.length() == 1 { 25 | return queries[0]; 26 | } else { 27 | return prepareParameterizedQuery(queries); 28 | } 29 | } 30 | 31 | isolated function prepareParameterizedQuery(ParameterizedQuery[] queries) returns ParameterizedQuery { 32 | ParameterizedQuery newParameterizedQuery = ``; 33 | string[] newQueryStrings = []; 34 | Value[] newQueryInsertions = []; 35 | string previousString = ""; 36 | foreach ParameterizedQuery query in queries { 37 | int length = query.strings.length(); 38 | if length > 0 { 39 | previousString = previousString + query.strings[0]; 40 | if length > 1 { 41 | newQueryStrings.push(previousString); 42 | foreach var i in 1 ... length - 2 { 43 | newQueryStrings.push(query.strings[i]); 44 | } 45 | previousString = query.strings[length - 1]; 46 | } 47 | addValues(query.insertions, newQueryInsertions); 48 | } 49 | } 50 | newQueryStrings.push(previousString); 51 | newParameterizedQuery.insertions = newQueryInsertions; 52 | newParameterizedQuery.strings = newQueryStrings.cloneReadOnly(); 53 | return newParameterizedQuery; 54 | } 55 | 56 | isolated function addValues(Value[] insertionValues, Value[] values) { 57 | foreach Value insertionValue in insertionValues { 58 | values.push(insertionValue); 59 | } 60 | } 61 | 62 | # Joins the parameters in the array with the `,` delimiter into an `sql:ParameterizedQuery`. 63 | # 64 | # + values - An array of `sql:Value` values 65 | # + return - An `sql:ParameterizedQuery` 66 | public isolated function arrayFlattenQuery(Value[] values) returns ParameterizedQuery { 67 | if values.length() == 0 { 68 | return ``; 69 | } 70 | ParameterizedQuery newParameterizedQuery = `${values[0]}`; 71 | foreach var i in 1 ..< values.length() { 72 | newParameterizedQuery = queryConcat(newParameterizedQuery, `, ${values[i]}`); 73 | } 74 | return newParameterizedQuery; 75 | } 76 | 77 | # Generates a stream consisting of `sql:Error` elements. 78 | # 79 | # + message - Error message used to initialise an `sql:Error` 80 | # + return - A stream 81 | public isolated function generateApplicationErrorStream(string message) returns stream { 82 | ApplicationError applicationErr = error ApplicationError(message); 83 | ResultIterator resultIterator = new (err = applicationErr); 84 | stream errorStream = new (resultIterator); 85 | return errorStream; 86 | } 87 | -------------------------------------------------------------------------------- /build-config/checkstyle/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | plugins { 19 | id "de.undercouch.download" 20 | } 21 | 22 | apply plugin: 'java' 23 | 24 | 25 | task downloadCheckstyleRuleFiles(type: Download) { 26 | src([ 27 | 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/checkstyle.xml', 28 | 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/suppressions.xml' 29 | ]) 30 | overwrite false 31 | onlyIfNewer true 32 | dest buildDir 33 | } 34 | 35 | jar { 36 | enabled = false 37 | } 38 | 39 | clean { 40 | enabled = false 41 | } 42 | 43 | artifacts.add('default', file("$project.buildDir/checkstyle.xml")) { 44 | builtBy('downloadCheckstyleRuleFiles') 45 | } 46 | 47 | artifacts.add('default', file("$project.buildDir/suppressions.xml")) { 48 | builtBy('downloadCheckstyleRuleFiles') 49 | } 50 | -------------------------------------------------------------------------------- /build-config/release/post-release-dependency-bump.sh: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------- 2 | # Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | IFS="=" 17 | while read -r property value 18 | do 19 | if [[ $property = "ballerinaLangVersion" ]] && [[ $value = *Preview* ]] 20 | then 21 | oldVersion=$(echo $value | cut -d'w' -f 2) 22 | newVersion=`expr $oldVersion + 1` 23 | if [ ! -z "$newVersion" ] 24 | then 25 | version=$(echo $(echo $value | cut -d'w' -f 1)w$newVersion-SNAPSHOT) 26 | sed -i "s/ballerinaLangVersion=\(.*\)/ballerinaLangVersion=$version/g" gradle.properties 27 | fi 28 | fi 29 | if [[ $property = stdlib* ]] 30 | then 31 | oldVersion=$(echo $value | cut -d'.' -f 3) 32 | newVersion=`expr $oldVersion + 1` 33 | if [ ! -z "$newVersion" ] 34 | then 35 | version=$(echo $(echo $value | cut -d'.' -f 1).$(echo $value | cut -d'.' -f 2).$newVersion-SNAPSHOT) 36 | sed -i "s/$property=\(.*\)/$property=$version/g" gradle.properties 37 | fi 38 | fi 39 | done < gradle.properties 40 | -------------------------------------------------------------------------------- /build-config/resources/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "ballerina" 3 | name = "sql" 4 | version = "@toml.version@" 5 | authors = ["Ballerina"] 6 | keywords = ["database", "client", "network", "SQL", "RDBMS"] 7 | repository = "https://github.com/ballerina-platform/module-ballerina-sql" 8 | icon = "icon.png" 9 | license = ["Apache-2.0"] 10 | distribution = "2201.12.0" 11 | 12 | [platform.java21] 13 | graalvmCompatible = true 14 | 15 | [[platform.java21.dependency]] 16 | groupId = "io.ballerina.stdlib" 17 | artifactId = "sql-native" 18 | version = "@toml.version@" 19 | path = "../native/build/libs/sql-native-@project.version@.jar" 20 | 21 | [[platform.java21.dependency]] 22 | path = "../test-utils/build/libs/sql-test-utils-@project.version@.jar" 23 | scope = "testOnly" 24 | 25 | [[platform.java21.dependency]] 26 | groupId = "com.zaxxer" 27 | artifactId = "HikariCP" 28 | version = "@hikkaricp.lib.version@" 29 | path = "./lib/HikariCP-@hikkaricp.lib.version@.jar" 30 | 31 | [[platform.java21.dependency]] 32 | path = "./lib/hsqldb-@hsql.connector.version@.jar" 33 | scope = "testOnly" 34 | -------------------------------------------------------------------------------- /build-config/resources/CompilerPlugin.toml: -------------------------------------------------------------------------------- 1 | [plugin] 2 | id = "sql-compiler-plugin" 3 | class = "io.ballerina.stdlib.sql.compiler.SQLCompilerPlugin" 4 | 5 | [[dependency]] 6 | path = "../compiler-plugin/build/libs/sql-compiler-plugin-@project.version@.jar" 7 | -------------------------------------------------------------------------------- /build-config/spotbugs-exclude.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | plugins { 19 | id "com.github.spotbugs" 20 | id "com.github.johnrengelman.shadow" 21 | id "de.undercouch.download" 22 | id "net.researchgate.release" 23 | } 24 | 25 | allprojects { 26 | group = project.group 27 | version = project.version 28 | 29 | apply plugin: 'jacoco' 30 | apply plugin: 'maven-publish' 31 | 32 | repositories { 33 | mavenLocal() 34 | maven { 35 | url = 'https://maven.wso2.org/nexus/content/repositories/releases/' 36 | } 37 | 38 | maven { 39 | url = 'https://maven.wso2.org/nexus/content/groups/wso2-public/' 40 | } 41 | 42 | maven { 43 | url = 'https://repo.maven.apache.org/maven2' 44 | } 45 | 46 | maven { 47 | url = 'https://maven.pkg.github.com/ballerina-platform/*' 48 | credentials { 49 | username System.getenv("packageUser") 50 | password System.getenv("packagePAT") 51 | } 52 | } 53 | } 54 | 55 | ext { 56 | snapshotVersion= '-SNAPSHOT' 57 | timestampedVersionRegex = '.*-\\d{8}-\\d{6}-\\w.*\$' 58 | } 59 | } 60 | 61 | subprojects { 62 | 63 | configurations { 64 | externalJars 65 | ballerinaStdLibs 66 | jbalTools 67 | } 68 | 69 | dependencies { 70 | /* JBallerina Tools */ 71 | jbalTools ("org.ballerinalang:jballerina-tools:${ballerinaLangVersion}") { 72 | transitive = false 73 | } 74 | 75 | ballerinaStdLibs "io.ballerina.stdlib:io-ballerina:${stdlibIoVersion}" 76 | ballerinaStdLibs "io.ballerina.stdlib:os-ballerina:${stdlibOsVersion}" 77 | ballerinaStdLibs "io.ballerina.stdlib:time-ballerina:${stdlibTimeVersion}" 78 | ballerinaStdLibs "io.ballerina.stdlib:log-ballerina:${stdlibLogVersion}" 79 | ballerinaStdLibs "io.ballerina.stdlib:file-ballerina:${stdlibFileVersion}" 80 | 81 | ballerinaStdLibs "io.ballerina.stdlib:constraint-ballerina:${stdlibConstraintVersion}" 82 | ballerinaStdLibs "org.ballerinalang:transaction-ballerina:${stdlibTransactionVersion}" 83 | ballerinaStdLibs "io.ballerina.stdlib:task-ballerina:${stdlibTaskVersion}" 84 | ballerinaStdLibs "io.ballerina.stdlib:crypto-ballerina:${stdlibCryptoVersion}" 85 | ballerinaStdLibs "io.ballerina.stdlib:uuid-ballerina:${stdlibUuidVersion}" 86 | ballerinaStdLibs "io.ballerina.stdlib:mime-ballerina:${stdlibMimeVersion}" 87 | ballerinaStdLibs "io.ballerina.stdlib:cache-ballerina:${stdlibCacheVersion}" 88 | ballerinaStdLibs "io.ballerina.stdlib:auth-ballerina:${stdlibAuthVersion}" 89 | ballerinaStdLibs "io.ballerina.stdlib:jwt-ballerina:${stdlibJwtVersion}" 90 | ballerinaStdLibs "io.ballerina.stdlib:oauth2-ballerina:${stdlibOAuth2Version}" 91 | ballerinaStdLibs "io.ballerina.stdlib:url-ballerina:${stdlibUrlVersion}" 92 | ballerinaStdLibs "io.ballerina.stdlib:http-ballerina:${stdlibHttpVersion}" 93 | ballerinaStdLibs "io.ballerina.stdlib:observe-ballerina:${observeVersion}" 94 | ballerinaStdLibs "io.ballerina:observe-ballerina:${observeInternalVersion}" 95 | ballerinaStdLibs "io.ballerina.lib:data.jsondata-ballerina:${stdlibDataJsonDataVersion}" 96 | 97 | externalJars (group: 'com.zaxxer', name: 'HikariCP', version: "${hikkariLibVersion}") { 98 | transitive = false 99 | } 100 | externalJars (group: 'org.hsqldb', name: 'hsqldb', version: "${hsqlDriverVersion}") { 101 | transitive = false 102 | } 103 | } 104 | } 105 | 106 | def moduleVersion = project.version.replace("-SNAPSHOT", "") 107 | 108 | release { 109 | failOnPublishNeeded = false 110 | failOnSnapshotDependencies = true 111 | 112 | buildTasks = ['build'] 113 | versionPropertyFile = 'gradle.properties' 114 | tagTemplate = 'v$version' 115 | 116 | git { 117 | requireBranch = "release-${moduleVersion}" 118 | pushToRemote = 'origin' 119 | } 120 | } 121 | 122 | task build { 123 | dependsOn(':sql-native:build') 124 | dependsOn(':sql-compiler-plugin:build') 125 | dependsOn(':sql-ballerina:build') 126 | dependsOn(':sql-compiler-plugin-tests:build') 127 | } 128 | 129 | publishToMavenLocal.dependsOn build 130 | publish.dependsOn build 131 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "test-utils/" 3 | 4 | coverage: 5 | precision: 2 6 | round: down 7 | range: "60...80" 8 | status: 9 | project: 10 | default: 11 | target: 80 12 | -------------------------------------------------------------------------------- /compiler-plugin-tests/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | plugins { 20 | id 'java' 21 | id 'checkstyle' 22 | id 'com.github.spotbugs' 23 | id 'jacoco' 24 | } 25 | 26 | description = 'Ballerina - SQL Compiler Plugin Tests' 27 | 28 | configurations { 29 | jacocoRuntime 30 | } 31 | 32 | dependencies { 33 | checkstyle project(':checkstyle') 34 | checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}" 35 | 36 | jacocoRuntime "org.jacoco:org.jacoco.agent:${jacoco.toolVersion}:runtime" 37 | 38 | implementation project(':sql-compiler-plugin') 39 | 40 | testImplementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}" 41 | testImplementation group: 'org.ballerinalang', name: 'ballerina-tools-api', version: "${ballerinaLangVersion}" 42 | testImplementation group: 'org.ballerinalang', name: 'ballerina-parser', version: "${ballerinaLangVersion}" 43 | 44 | implementation group: 'org.testng', name: 'testng', version: "${testngVersion}" 45 | } 46 | 47 | tasks.withType(JavaCompile) { 48 | options.encoding = 'UTF-8' 49 | } 50 | 51 | sourceCompatibility = JavaVersion.VERSION_21 52 | 53 | jacoco { 54 | toolVersion = "0.8.10" 55 | } 56 | 57 | test { 58 | systemProperty "ballerina.offline.flag", "true" 59 | useTestNG() { 60 | suites 'src/test/resources/testng.xml' 61 | } 62 | testLogging.showStandardStreams = true 63 | testLogging { 64 | events "PASSED", "FAILED", "SKIPPED" 65 | afterSuite { desc, result -> 66 | if (!desc.parent) { // will match the outermost suite 67 | def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" 68 | def startItem = '| ', endItem = ' |' 69 | def repeatLength = startItem.length() + output.length() + endItem.length() 70 | println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) 71 | } 72 | } 73 | } 74 | finalizedBy jacocoTestReport 75 | } 76 | 77 | jacocoTestReport { 78 | dependsOn test 79 | reports { 80 | xml.required = true 81 | } 82 | sourceSets project(':sql-compiler-plugin').sourceSets.main 83 | } 84 | 85 | spotbugsTest { 86 | def classLoader = plugins["com.github.spotbugs"].class.classLoader 87 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") 88 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") 89 | effort = SpotBugsEffort.MAX 90 | reportLevel = SpotBugsConfidence.LOW 91 | ignoreFailures = true 92 | reportsDir = file("$project.buildDir/reports/spotbugs") 93 | def excludeFile = file("${rootDir}/build-config/spotbugs-exclude.xml") 94 | if (excludeFile.exists()) { 95 | it.excludeFilter = excludeFile 96 | } 97 | reports { 98 | text.enabled = true 99 | } 100 | } 101 | 102 | spotbugsMain { 103 | enabled false 104 | } 105 | 106 | task validateSpotbugs() { 107 | doLast { 108 | if (spotbugsMain.reports.size() > 0 && 109 | spotbugsMain.reports[0].destination.exists() && 110 | spotbugsMain.reports[0].destination.text.readLines().size() > 0) { 111 | spotbugsMain.reports[0].destination?.eachLine { 112 | println 'Failure: ' + it 113 | } 114 | throw new GradleException("Spotbugs rule violations were found."); 115 | } 116 | } 117 | } 118 | 119 | tasks.withType(Checkstyle) { 120 | exclude '**/module-info.java' 121 | } 122 | 123 | checkstyle { 124 | toolVersion "${project.checkstylePluginVersion}" 125 | configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml") 126 | configProperties = ["suppressionFile": file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] 127 | } 128 | 129 | checkstyleMain { 130 | enabled false 131 | } 132 | 133 | spotbugsTest.finalizedBy validateSpotbugs 134 | checkstyleTest.dependsOn ':checkstyle:downloadCheckstyleRuleFiles' 135 | 136 | compileJava { 137 | doFirst { 138 | options.compilerArgs = [ 139 | '--module-path', classpath.asPath, 140 | ] 141 | classpath = files() 142 | } 143 | } 144 | 145 | test.dependsOn ":sql-ballerina:build" 146 | build.dependsOn ":sql-ballerina:build" 147 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample1/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "sql_test" 3 | name = "sample1" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample1/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/sql; 18 | 19 | type ConnectionPool record { 20 | int connection?; 21 | }; 22 | 23 | int|sql:ConnectionPool pool2 = { 24 | maxOpenConnections: 10, 25 | maxConnectionLifeTime: 10, 26 | minIdleConnections: 2 27 | }; 28 | 29 | public function main() { 30 | 31 | int id = 5; 32 | 33 | int|sql:ConnectionPool pool1 = 5; 34 | 35 | int|sql:ConnectionPool pool2 = { 36 | maxOpenConnections: 0, 37 | maxConnectionLifeTime: 10, 38 | minIdleConnections: -1 39 | }; 40 | 41 | sql:ConnectionPool|int pool3 = { 42 | maxOpenConnections: 1, 43 | maxConnectionLifeTime: 31, 44 | minIdleConnections: 1 45 | }; 46 | 47 | sql:ConnectionPool pool4 = { 48 | maxOpenConnections: -1, 49 | maxConnectionLifeTime: 30, 50 | minIdleConnections: 0 51 | }; 52 | 53 | sql:ConnectionPool pool5 = { 54 | maxConnectionLifeTime: 0 55 | }; 56 | 57 | ConnectionPool pool6 = { 58 | connection: 0 59 | }; 60 | 61 | sql:ConnectionPool pool7 = { 62 | maxConnectionLifeTime: -5 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample2/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "sql_test" 3 | name = "sample2" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample3/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "sql_test" 3 | name = "sample1" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample3/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/sql; 18 | 19 | type ConnectionPool record { 20 | int connection?; 21 | } 22 | 23 | int|sql:ConnectionPool pool2 = { 24 | maxOpenConnections: 10, 25 | maxConnectionLifeTime: 10, 26 | minIdleConnections: 2 27 | }; 28 | 29 | public function main() { 30 | 31 | } 32 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample4/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "sql_test" 3 | name = "sample4" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample4/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/sql; 18 | import ballerina/http; 19 | 20 | public function main() returns error? { 21 | 22 | int connectionNum = 5; 23 | int connectionNumInvalid = -5; 24 | 25 | int|sql:ConnectionPool pool = { 26 | maxOpenConnections: connectionNum 27 | }; 28 | 29 | sql:ConnectionPool|int poolInvalid = { 30 | maxOpenConnections: connectionNumInvalid 31 | }; 32 | 33 | http:Client httpclient = check new ("adasdsasd"); 34 | _ = httpclient.getCookieStore(); 35 | } 36 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/testng.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /compiler-plugin/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | plugins { 20 | id 'java' 21 | id 'checkstyle' 22 | id 'com.github.spotbugs' 23 | } 24 | 25 | description = 'Ballerina - SQL Compiler Plugin' 26 | 27 | dependencies { 28 | checkstyle project(':checkstyle') 29 | checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}" 30 | 31 | implementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}" 32 | implementation group: 'org.ballerinalang', name: 'ballerina-tools-api', version: "${ballerinaLangVersion}" 33 | implementation group: 'org.ballerinalang', name: 'ballerina-parser', version: "${ballerinaLangVersion}" 34 | } 35 | 36 | def excludePattern = '**/module-info.java' 37 | tasks.withType(Checkstyle) { 38 | exclude excludePattern 39 | } 40 | 41 | checkstyle { 42 | toolVersion "${project.checkstylePluginVersion}" 43 | configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml") 44 | configProperties = ["suppressionFile" : file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] 45 | } 46 | 47 | checkstyleMain.dependsOn(":checkstyle:downloadCheckstyleRuleFiles") 48 | 49 | spotbugsMain { 50 | def classLoader = plugins["com.github.spotbugs"].class.classLoader 51 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") 52 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") 53 | effort = SpotBugsEffort.MAX 54 | reportLevel = SpotBugsConfidence.LOW 55 | reportsDir = file("$project.buildDir/reports/spotbugs") 56 | reports { 57 | html.enabled true 58 | text.enabled = true 59 | } 60 | def excludeFile = file("${rootDir}/spotbugs-exclude.xml") 61 | if(excludeFile.exists()) { 62 | excludeFilter = excludeFile 63 | } 64 | } 65 | 66 | compileJava { 67 | doFirst { 68 | options.compilerArgs = [ 69 | '--module-path', classpath.asPath, 70 | ] 71 | classpath = files() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/sql/compiler/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.compiler; 19 | 20 | /** 21 | * Constants used in compiler plugin. 22 | */ 23 | public class Constants { 24 | public static final String BALLERINA = "ballerina"; 25 | public static final String SQL = "sql"; 26 | public static final String CONNECTION_POOL = "ConnectionPool"; 27 | 28 | private Constants() { 29 | } 30 | 31 | /** 32 | * Constants for fields in sql:ConnectionPool. 33 | */ 34 | public static class ConnectionPool { 35 | 36 | private ConnectionPool() { 37 | } 38 | 39 | public static final String MAX_OPEN_CONNECTIONS = "maxOpenConnections"; 40 | public static final String MAX_CONNECTION_LIFE_TIME = "maxConnectionLifeTime"; 41 | public static final String MIN_IDLE_CONNECTIONS = "minIdleConnections"; 42 | } 43 | 44 | /** 45 | * Constants for fields in OutParameter objects. 46 | */ 47 | public static class OutParameter { 48 | 49 | private OutParameter() { 50 | } 51 | 52 | public static final String METHOD_NAME = "get"; 53 | 54 | public static final String CHAR = "CharOutParameter"; 55 | public static final String CHAR_ARRAY = "CharArrayOutParameter"; 56 | public static final String VARCHAR = "VarcharOutParameter"; 57 | public static final String VARCHAR_ARRAY = "VarcharArrayOutParameter"; 58 | public static final String NCHAR = "NCharOutParameter"; 59 | public static final String NVARCHAR = "NVarcharOutParameter"; 60 | public static final String NVARCHAR_ARRAY = "NVarcharArrayOutParameter"; 61 | public static final String BINARY = "BinaryOutParameter"; 62 | public static final String BINARY_ARRAY = "BinaryArrayOutParameter"; 63 | public static final String ARRAY = "ArrayOutParameter"; 64 | public static final String VARBINARY = "VarBinaryOutParameter"; 65 | public static final String VARBINARY_ARRAY = "VarBinaryArrayOutParameter"; 66 | public static final String TEXT = "TextOutParameter"; 67 | public static final String BLOB = "BlobOutParameter"; 68 | public static final String CLOB = "ClobOutParameter"; 69 | public static final String NCLOB = "NClobOutParameter"; 70 | public static final String DATE = "DateOutParameter"; 71 | public static final String DATE_ARRAY = "DateArrayOutParameter"; 72 | public static final String TIME = "TimeOutParameter"; 73 | public static final String TIME_ARRAY = "TimeArrayOutParameter"; 74 | public static final String TIME_WITH_TIMEZONE = "TimeWithTimezoneOutParameter"; 75 | public static final String TIME_WITH_TIMEZONE_ARRAY = "TimeWithTimezoneArrayOutParameter"; 76 | public static final String DATE_TIME = "DateTimeOutParameter"; 77 | public static final String DATE_TIME_ARRAY = "DateTimeArrayOutParameter"; 78 | public static final String TIMESTAMP = "TimestampOutParameter"; 79 | public static final String TIMESTAMP_ARRAY = "TimestampArrayOutParameter"; 80 | public static final String TIMESTAMP_WITH_TIMEZONE = "TimestampWithTimezoneOutParameter"; 81 | public static final String TIMESTAMP_WITH_TIMEZONE_ARRAY = "TimestampWithTimezoneArrayOutParameter"; 82 | public static final String ROW = "RowOutParameter"; 83 | public static final String SMALLINT = "SmallIntOutParameter"; 84 | public static final String SMALL_INT_ARRAY = "SmallIntArrayOutParameter"; 85 | public static final String INTEGER = "IntegerOutParameter"; 86 | public static final String INTEGER_ARRAY = "IntegerArrayOutParameter"; 87 | public static final String BIGINT = "BigIntOutParameter"; 88 | public static final String BIGINT_ARRAY = "BigIntArrayOutParameter"; 89 | public static final String REAL = "RealOutParameter"; 90 | public static final String REAL_ARRAY = "RealArrayOutParameter"; 91 | public static final String FLOAT = "FloatOutParameter"; 92 | public static final String FLOAT_ARRAY = "FloatArrayOutParameter"; 93 | public static final String DOUBLE = "DoubleOutParameter"; 94 | public static final String DOUBLE_ARRAY = "DoubleArrayOutParameter"; 95 | public static final String NUMERIC = "NumericOutParameter"; 96 | public static final String NUMERIC_ARRAY = "NumericArrayOutParameter"; 97 | public static final String DECIMAL = "DecimalOutParameter"; 98 | public static final String DECIMAL_ARRAY = "DecimalArrayOutParameter"; 99 | public static final String BIT = "BitOutParameter"; 100 | public static final String BIT_ARRAY = "BitArrayOutParameter"; 101 | public static final String BOOLEAN = "BooleanOutParameter"; 102 | public static final String BOOLEAN_ARRAY = "BooleanArrayOutParameter"; 103 | public static final String REF = "RefOutParameter"; 104 | public static final String STRUCT = "StructOutParameter"; 105 | public static final String XML = "XMLOutParameter"; 106 | } 107 | 108 | /** 109 | * Constants for regex validation for Ballerina time module record types. 110 | */ 111 | public static class TimeRecordTypes { 112 | 113 | private TimeRecordTypes() { 114 | } 115 | 116 | public static final String PACKAGE_NAME = "ballerina/time"; 117 | public static final String TIME_OF_DAY = "TimeOfDay"; 118 | public static final String DATE = "Date"; 119 | public static final String CIVIL = "Civil"; 120 | public static final String UTC = "Utc"; 121 | } 122 | 123 | public static final String UNNECESSARY_CHARS_REGEX = "\"|\\n"; 124 | } 125 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/sql/compiler/SQLCodeAnalyzer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.compiler; 20 | 21 | import io.ballerina.compiler.syntax.tree.SyntaxKind; 22 | import io.ballerina.projects.plugins.CodeAnalysisContext; 23 | import io.ballerina.projects.plugins.CodeAnalyzer; 24 | import io.ballerina.stdlib.sql.compiler.analyzer.ConnectionPoolConfigAnalyzer; 25 | import io.ballerina.stdlib.sql.compiler.analyzer.MethodAnalyzer; 26 | 27 | import java.util.List; 28 | 29 | /** 30 | * SQL Code Analyzer. 31 | */ 32 | public class SQLCodeAnalyzer extends CodeAnalyzer { 33 | 34 | @Override 35 | public void init(CodeAnalysisContext codeAnalysisContext) { 36 | codeAnalysisContext.addSyntaxNodeAnalysisTask(new ConnectionPoolConfigAnalyzer(), 37 | List.of(SyntaxKind.LOCAL_VAR_DECL, SyntaxKind.MODULE_VAR_DECL)); 38 | codeAnalysisContext.addSyntaxNodeAnalysisTask(new MethodAnalyzer(), SyntaxKind.METHOD_CALL); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/sql/compiler/SQLCompilerPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.compiler; 20 | 21 | import io.ballerina.projects.plugins.CompilerPlugin; 22 | import io.ballerina.projects.plugins.CompilerPluginContext; 23 | 24 | /** 25 | * Compiler plugin for SQL client. 26 | */ 27 | public class SQLCompilerPlugin extends CompilerPlugin { 28 | @Override 29 | public void init(CompilerPluginContext compilerPluginContext) { 30 | compilerPluginContext.addCodeAnalyzer(new SQLCodeAnalyzer()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/sql/compiler/SQLDiagnosticsCodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.compiler; 19 | 20 | import io.ballerina.tools.diagnostics.DiagnosticSeverity; 21 | 22 | import static io.ballerina.tools.diagnostics.DiagnosticSeverity.ERROR; 23 | 24 | /** 25 | * Enum class to hold SQL module diagnostic codes. 26 | */ 27 | public enum SQLDiagnosticsCodes { 28 | SQL_101("SQL_101", "invalid value: expected value is greater than one", ERROR), 29 | SQL_102("SQL_102", "invalid value: expected value is greater than zero", ERROR), 30 | SQL_103("SQL_103", "invalid value: expected value is either 0 or greater than or equal to 30", ERROR), 31 | 32 | // Out parameter return type validations diagnostics 33 | SQL_201("SQL_201", "invalid value: expected value is array", ERROR), 34 | SQL_202("SQL_202", "invalid value: expected value is record", ERROR), 35 | SQL_203("SQL_203", "invalid value: expected value is xml", ERROR), 36 | SQL_204("SQL_204", "invalid value: expected value is byte[]", ERROR), 37 | SQL_211("SQL_211", "invalid value: expected value is either string or json", ERROR), 38 | SQL_212("SQL_212", "invalid value: expected value is either byte[] or string", ERROR), 39 | SQL_213("SQL_213", "invalid value: expected value is either int or string", ERROR), 40 | SQL_214("SQL_214", "invalid value: expected value is either float or string", ERROR), 41 | SQL_215("SQL_215", "invalid value: expected value is either decimal or string", ERROR), 42 | SQL_221("SQL_221", "invalid value: expected value is any one of boolean, int or string", ERROR), 43 | SQL_222("SQL_222", "invalid value: expected value is any one of time:Date, int or string", ERROR), 44 | SQL_223("SQL_223", "invalid value: expected value is any one of time:TimeOfDay, int or string", ERROR), 45 | SQL_231("SQL_231", "invalid value: expected value is any one of time:Civil, time:Utc, int or string", ERROR); 46 | 47 | private final String code; 48 | private final String message; 49 | private final DiagnosticSeverity severity; 50 | 51 | SQLDiagnosticsCodes(String code, String message, DiagnosticSeverity severity) { 52 | this.code = code; 53 | this.message = message; 54 | this.severity = severity; 55 | } 56 | 57 | public String getCode() { 58 | return code; 59 | } 60 | 61 | public String getMessage() { 62 | return message; 63 | } 64 | 65 | public DiagnosticSeverity getSeverity() { 66 | return severity; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/sql/compiler/analyzer/MethodAnalyzer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.compiler.analyzer; 20 | 21 | import io.ballerina.compiler.api.symbols.ModuleSymbol; 22 | import io.ballerina.compiler.api.symbols.Symbol; 23 | import io.ballerina.compiler.api.symbols.TypeDescKind; 24 | import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; 25 | import io.ballerina.compiler.api.symbols.TypeSymbol; 26 | import io.ballerina.compiler.syntax.tree.ExpressionNode; 27 | import io.ballerina.compiler.syntax.tree.FunctionArgumentNode; 28 | import io.ballerina.compiler.syntax.tree.MethodCallExpressionNode; 29 | import io.ballerina.compiler.syntax.tree.SeparatedNodeList; 30 | import io.ballerina.projects.plugins.AnalysisTask; 31 | import io.ballerina.projects.plugins.SyntaxNodeAnalysisContext; 32 | import io.ballerina.stdlib.sql.compiler.Constants; 33 | import io.ballerina.stdlib.sql.compiler.Utils; 34 | import io.ballerina.tools.diagnostics.DiagnosticFactory; 35 | import io.ballerina.tools.diagnostics.DiagnosticInfo; 36 | 37 | import java.util.Optional; 38 | 39 | /** 40 | * Code Analyser for OutParameter get method type validations. 41 | */ 42 | public class MethodAnalyzer implements AnalysisTask { 43 | @Override 44 | public void perform(SyntaxNodeAnalysisContext ctx) { 45 | MethodCallExpressionNode node = (MethodCallExpressionNode) ctx.node(); 46 | if (Utils.hasCompilationErrors(ctx)) { 47 | return; 48 | } 49 | 50 | // Get the object type to validate arguments 51 | ExpressionNode methodExpression = node.expression(); 52 | Optional methodExpReferenceType = ctx.semanticModel().typeOf(methodExpression); 53 | if (methodExpReferenceType.isEmpty()) { 54 | return; 55 | } 56 | if (methodExpReferenceType.get().typeKind() != TypeDescKind.TYPE_REFERENCE) { 57 | return; 58 | } 59 | TypeReferenceTypeSymbol methodExpTypeSymbol = (TypeReferenceTypeSymbol) methodExpReferenceType.get(); 60 | Optional optionalModuleSymbol = methodExpTypeSymbol.getModule(); 61 | if (optionalModuleSymbol.isEmpty()) { 62 | return; 63 | } 64 | ModuleSymbol module = optionalModuleSymbol.get(); 65 | if (!(module.id().orgName().equals(Constants.BALLERINA) && module.id().moduleName().equals(Constants.SQL))) { 66 | return; 67 | } 68 | String objectName = ((TypeReferenceTypeSymbol) methodExpReferenceType.get()).definition().getName().get(); 69 | 70 | // Filter by method name, only OutParameter objects have get method 71 | if (isGetMethod(ctx, node)) { 72 | return; 73 | } 74 | 75 | // Filter by parameters length 76 | SeparatedNodeList arguments = node.arguments(); 77 | if (arguments.size() != 1) { 78 | return; 79 | } 80 | Optional typeDescriptionArgument = ctx.semanticModel().symbol(node.arguments().get(0)); 81 | if (typeDescriptionArgument.isEmpty()) { 82 | return; 83 | } 84 | TypeSymbol argumentTypeSymbol = ((TypeSymbol) typeDescriptionArgument.get()); 85 | 86 | DiagnosticInfo diagnosticsForInvalidTypes = 87 | Utils.addDiagnosticsForInvalidTypes(objectName, argumentTypeSymbol); 88 | if (diagnosticsForInvalidTypes != null) { 89 | ctx.reportDiagnostic(DiagnosticFactory.createDiagnostic(diagnosticsForInvalidTypes, 90 | node.arguments().get(0).location())); 91 | } 92 | } 93 | 94 | private boolean isGetMethod(SyntaxNodeAnalysisContext ctx, MethodCallExpressionNode node) { 95 | Optional methodSymbol = ctx.semanticModel().symbol(node.methodName()); 96 | if (methodSymbol.isEmpty()) { 97 | return true; 98 | } 99 | Optional methodName = methodSymbol.get().getName(); 100 | if (methodName.isEmpty()) { 101 | return true; 102 | } 103 | return !methodName.get().equals(Constants.OutParameter.METHOD_NAME); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | module io.ballerina.stdlib.sql.compiler { 20 | requires io.ballerina.lang; 21 | requires io.ballerina.tools.api; 22 | requires io.ballerina.parser; 23 | requires java.sql; 24 | } 25 | -------------------------------------------------------------------------------- /docs/proposals/map_multiple_fields_to_single_return_field.md: -------------------------------------------------------------------------------- 1 | # Add functionality to map multiple fields in the return query result to a single typed record field 2 | 3 | _Owners_: @daneshk @niveathika 4 | _Reviewers_: @daneshk 5 | _Created_: 2021/10/04 6 | _Updated_: 2021/10/05 7 | _Issues_: [#1924](https://github.com/ballerina-platform/ballerina-standard-library/issues/1924) 8 | 9 | ## Summary 10 | 11 | Users can use this functionality to map multiple returned data columns to a single typed record field during the query operation. It is an n:1 mapping of the results through typed records. 12 | 13 | ## Goals 14 | 15 | - Improve results type mapping to support n:1 mapping of results through typed records. 16 | 17 | ## Non-Goals 18 | 19 | - This is not applied if the query operation returns an anonymous record. 20 | 21 | ## Motivation 22 | 23 | This feature will be convenient when the user wants to return data from multiple tables with a single query. 24 | 25 | ![schema](./resources/schema1.png) 26 | 27 | In the above scenario, If I want to query both the Students and Teachers table. It would be convenient to group `TEACHERs.id` and `TEACHERS.name` into a typed record. It allows for easier manipulation of returned results. 28 | 29 | ## Description 30 | 31 | This proposal is to support n:1 mapping from multiple return columns in the results to a Typed Record. 32 | 33 | If the returned field name contains a period, the module will map it to an inner typed record field. The return type field must have the same name as the prefix of the return field. 34 | 35 | Take the above example, 36 | 37 | ![schema](./resources/schema1.png) 38 | 39 | When the user executes the following query, 40 | ```ballerina 41 | `SELECT * FROM students JOIN teachers ON students.supervisorId = teachers.id`. 42 | ``` 43 | 44 | the returned results will include the following fields, 45 | 46 | 1. Id 47 | 2. name 48 | 3. age 49 | 4. gpa 50 | 5. supervisorId 51 | 6. TEACHERS.id 52 | 7. TEACHERS.name 53 | 54 | Here the TEACHERS.id and TEACHERS.name fields contain a period. If the prefix(teachers) corresponds to a Typed Record field in the returned `Students` record as below, 55 | ```ballerina 56 | public type Students record {| 57 | int id; 58 | string name; 59 | string? age; 60 | float? gpa; 61 | Teachers teachers; 62 | |} 63 | ``` 64 | The module will map the id and name fields to the inner fields of the record teachers of the `Teachers` type. 65 | 66 | Following scenarios are based on whether the Typed Record is an open record or a close record, 67 | 68 | 1. An Open Result Type description DOES NOT contain Typed Record Field with prefix name. 69 | ```ballerina 70 | public type Students record { 71 | int id; 72 | string name; 73 | string? age; 74 | float? gpa; 75 | } 76 | ``` 77 | The module will use the column name to add additional fields. 78 | ```ballerina 79 | public type Students record { 80 | int id; 81 | string name; 82 | string? age; 83 | float? gpa; 84 | int TEACHERS.id; 85 | string TEACHERS.name; 86 | } 87 | ``` 88 | > Note the above definition is for description purposes only. Since ballerina does not allow records to have fields with periods, the above code snippet is not compilable. However, users can access these fields with the map accessor as `student["TEACHERS.id"]`. 89 | 90 | 2. A Closed Result Type description DOES NOT contain Typed Record Field with prefix name. 91 | ```ballerina 92 | public type Students record {| 93 | int id; 94 | string name; 95 | string? age; 96 | float? gpa; 97 | |} 98 | ``` 99 | As per the existing behaviour, the module will throw an error. Here the return type does not contain all columns returned. 100 | 101 | 3. Result Type description contains Typed Record Field with prefix name. 102 | ```ballerina 103 | public type Students record {| 104 | int id; 105 | string name; 106 | string? age; 107 | float? gpa; 108 | Teachers teachers; 109 | |} 110 | ``` 111 | Regardless of the record type (open or close), the module will match the columns with the prefix to the teacher record fields. Here there are additional scenarios considering whether the Typed Record field is closed or not. 112 | - Close Record but DOES NOT contain the fields. The API will throw an error. 113 | ```ballerina 114 | type Teachers record {| 115 | string name; 116 | |} 117 | ``` 118 | - Close Record and contains correct fields as per the result column postfix. The module will map the fields correctly. 119 | ```ballerina 120 | type Teachers record {| 121 | int id; 122 | string name; 123 | |} 124 | ``` 125 | - An Open Record. If the fields are not present, then the module will add the fields as per convention. 126 | ```ballerina 127 | type Teachers record { 128 | string name; 129 | } 130 | ``` 131 | ```ballerina 132 | type Teachers record { 133 | int id; 134 | string name; 135 | } 136 | ``` 137 | -------------------------------------------------------------------------------- /docs/proposals/resources/schema1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerina-sql/37e8f355043835786e007f2c3d555784de054cf8/docs/proposals/resources/schema1.png -------------------------------------------------------------------------------- /docs/proposals/support_annotation_for_column_mapping.md: -------------------------------------------------------------------------------- 1 | # Support Annotations for DB column to Ballerina Record Mapping 2 | 3 | _Owners_: @daneshk @niveathika 4 | _Reviewers_: @daneshk 5 | _Created_: 2022/02/11 6 | _Updated_: 2021/02/11 7 | _Edition_: Swan Lake 8 | _Issues_: [#2652](https://github.com/ballerina-platform/ballerina-standard-library/issues/2652) 9 | 10 | ## Summary 11 | 12 | Enhance `query()` method with the use of Annotations in the return record types to map database columns. 13 | ```ballerina 14 | type Person record { 15 | int id; 16 | string first_name; 17 | string last_name 18 | }; 19 | Stream persons = database->query(`SELECT is, first_name, last_name FROM ATS_PERSON`); 20 | ``` 21 | Annotations will be bound to `Person` record fields to map value from a column of a different name. 22 | 23 | ## History 24 | 25 | The 1.2.x version of SQL packages included mapping support. However, the mapping was limited to only the order of returned columns to the record fields. The package will map The first column of the result will be mapped to the first field in the records. 26 | 27 | This feature held a few setbacks. Since the user now has to keep the order even if the mapping is not needed. 28 | 29 | ## Goals 30 | - Support annotations in the `sql` package 31 | - Support field mapping of DB columns to record fields. 32 | 33 | ## Motivation 34 | 35 | The ability to map table columns to Ballerina record fields in the remote method is efficient. In typical enterprise use cases, it is typical that the user would not have control over the database schema and its naming convention. 36 | 37 | With this support, the user does not need to process the return results to another record or change the query itself to change the metadata. 38 | 39 | ## Description 40 | 41 | Introduce `sql:Column` annotation of `string` type. The user can provide the database column name in the annotation. 42 | 43 | ```ballerina 44 | type Person record { 45 | int id; 46 | @sql:Column { name: "first_name" } 47 | string firstName; 48 | @sql:Column { name: "last_name" } 49 | string lastName 50 | }; 51 | ``` 52 | The above annotation will map the database column `first_name` to the Ballerina record field `firstName`. If the `query()` method does not return `first_name` column, the field will not be populated. 53 | 54 | The annotation will be defined as, 55 | ``` 56 | # Defines the database column name which matches the record field. The default value is the record field name. 57 | # 58 | # + name - The database column name 59 | public type ColumnConfig record {| 60 | string name; 61 | |}; 62 | 63 | # The Annotation used to specify which database column matches the record field. 64 | public annotation ColumnConfig Column on record field; 65 | ``` 66 | 67 | The `Column` annotation's keys' will be defined by the ColumnConfig closed record, which allows only `name` field. 68 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=io.ballerina.stdlib 2 | version=1.17.0-SNAPSHOT 3 | ballerinaLangVersion=2201.13.0-20250428-155600-34c3f5da 4 | 5 | checkstylePluginVersion=10.12.1 6 | spotbugsPluginVersion=6.0.18 7 | downloadPluginVersion=5.4.0 8 | shadowJarPluginVersion=8.1.1 9 | releasePluginVersion=2.8.0 10 | ballerinaGradlePluginVersion=2.3.0 11 | 12 | hikkariLibVersion=3.3.1 13 | hsqlDriverVersion=2.7.1 14 | h2Version=1.4.200 15 | atomikosLibVersion=5.0.8 16 | testngVersion=7.6.1 17 | 18 | # Level 01 19 | stdlibIoVersion=1.8.0 20 | stdlibTimeVersion=2.7.0 21 | stdlibUrlVersion=2.6.0 22 | 23 | # Level 02 24 | stdlibConstraintVersion=1.7.0 25 | stdlibCryptoVersion=2.9.0 26 | stdlibLogVersion=2.12.0 27 | stdlibOsVersion=1.10.0 28 | stdlibTaskVersion=2.7.0 29 | 30 | # Level 03 31 | stdlibCacheVersion=3.10.0 32 | stdlibFileVersion=1.12.0 33 | stdlibMimeVersion=2.12.0 34 | stdlibUuidVersion=1.10.0 35 | 36 | # Level 04 37 | stdlibAuthVersion=2.14.0 38 | stdlibDataJsonDataVersion=1.1.0 39 | stdlibJwtVersion=2.15.0 40 | stdlibOAuth2Version=2.14.0 41 | 42 | # Level 05 43 | stdlibHttpVersion=2.14.0 44 | 45 | # Level 06 46 | stdlibTransactionVersion=1.12.0 47 | 48 | # Ballerinax Observer 49 | observeVersion=1.5.0 50 | observeInternalVersion=1.5.0 51 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerina-sql/37e8f355043835786e007f2c3d555784de054cf8/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /native/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | plugins { 19 | id 'java' 20 | id 'com.github.spotbugs' 21 | id 'checkstyle' 22 | id 'jacoco' 23 | } 24 | 25 | description = 'Ballerina - SQL Java Native' 26 | 27 | configurations { 28 | jacocoRuntime 29 | } 30 | 31 | dependencies { 32 | jacocoRuntime "org.jacoco:org.jacoco.agent:${jacoco.toolVersion}:runtime" 33 | 34 | checkstyle project(":checkstyle") 35 | checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}" 36 | implementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}" 37 | implementation group: 'org.ballerinalang', name: 'ballerina-runtime', version: "${ballerinaLangVersion}" 38 | implementation group: 'io.ballerina.stdlib', name: 'io-native', version: "${stdlibIoVersion}" 39 | implementation group: 'io.ballerina.stdlib', name: 'time-native', version: "${stdlibTimeVersion}" 40 | implementation group: 'com.zaxxer', name: 'HikariCP', version: "${hikkariLibVersion}" 41 | implementation group: 'com.atomikos', name: 'transactions-jdbc', version: "${atomikosLibVersion}" 42 | 43 | implementation group: 'org.testng', name: 'testng', version: "${testngVersion}" 44 | } 45 | 46 | tasks.withType(JavaCompile) { 47 | options.encoding = 'UTF-8' 48 | } 49 | 50 | sourceCompatibility = JavaVersion.VERSION_21 51 | 52 | jacoco { 53 | toolVersion = "0.8.10" 54 | } 55 | 56 | test { 57 | useTestNG() { 58 | suites 'src/test/resources/testng.xml' 59 | } 60 | testLogging.showStandardStreams = true 61 | testLogging { 62 | events "PASSED", "FAILED", "SKIPPED" 63 | afterSuite { desc, result -> 64 | if (!desc.parent) { // will match the outermost suite 65 | def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" 66 | def startItem = '| ', endItem = ' |' 67 | def repeatLength = startItem.length() + output.length() + endItem.length() 68 | println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) 69 | } 70 | } 71 | } 72 | finalizedBy jacocoTestReport 73 | } 74 | 75 | jacocoTestReport { 76 | dependsOn test 77 | reports { 78 | xml.required = true 79 | } 80 | } 81 | 82 | spotbugsMain { 83 | def classLoader = plugins["com.github.spotbugs"].class.classLoader 84 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") 85 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") 86 | effort = SpotBugsEffort.MAX 87 | reportLevel = SpotBugsConfidence.LOW 88 | ignoreFailures = true 89 | reportsDir = file("$project.buildDir/reports/spotbugs") 90 | def excludeFile = file("${rootDir}/build-config/spotbugs-exclude.xml") 91 | if (excludeFile.exists()) { 92 | it.excludeFilter = excludeFile 93 | } 94 | reports { 95 | text.enabled = true 96 | } 97 | } 98 | 99 | spotbugsTest { 100 | enabled = false 101 | } 102 | 103 | task validateSpotbugs() { 104 | doLast { 105 | if (spotbugsMain.reports.size() > 0 && 106 | spotbugsMain.reports[0].destination.exists() && 107 | spotbugsMain.reports[0].destination.text.readLines().size() > 0) { 108 | spotbugsMain.reports[0].destination?.eachLine { 109 | println 'Failure: ' + it 110 | } 111 | throw new GradleException("Spotbugs rule violations were found."); 112 | } 113 | } 114 | } 115 | 116 | checkstyle { 117 | toolVersion "${checkstylePluginVersion}" 118 | configFile file("${rootDir}/build-config/checkstyle/build/checkstyle.xml") 119 | configProperties = ["suppressionFile": file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] 120 | } 121 | 122 | tasks.withType(Checkstyle) { 123 | exclude '**/module-info.java' 124 | } 125 | 126 | spotbugsMain.finalizedBy validateSpotbugs 127 | checkstyleMain.dependsOn ':checkstyle:downloadCheckstyleRuleFiles' 128 | checkstyleTest.dependsOn ':checkstyle:downloadCheckstyleRuleFiles' 129 | 130 | publishing { 131 | publications { 132 | mavenJava(MavenPublication) { 133 | groupId project.group 134 | artifactId "sql-native" 135 | version = project.version 136 | artifact jar 137 | } 138 | } 139 | 140 | repositories { 141 | maven { 142 | name = "GitHubPackages" 143 | url = uri("https://maven.pkg.github.com/ballerina-platform/module-ballerina-sql") 144 | credentials { 145 | username = System.getenv("publishUser") 146 | password = System.getenv("publishPAT") 147 | } 148 | } 149 | } 150 | } 151 | 152 | compileJava { 153 | doFirst { 154 | options.compilerArgs = [ 155 | '--module-path', classpath.asPath, 156 | ] 157 | classpath = files() 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/datasource/PoolKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.datasource; 19 | 20 | import io.ballerina.runtime.api.types.Type; 21 | import io.ballerina.runtime.api.types.TypeTags; 22 | import io.ballerina.runtime.api.utils.TypeUtils; 23 | import io.ballerina.runtime.api.values.BMap; 24 | import io.ballerina.runtime.api.values.BString; 25 | import io.ballerina.runtime.api.values.BValue; 26 | 27 | import java.util.Map; 28 | import java.util.Objects; 29 | 30 | /** 31 | * The key that uniquely identifies a connection pool encapsulated by {@link SQLDatasource}. 32 | * 33 | * @since 1.2.0 34 | */ 35 | public class PoolKey { 36 | private final String jdbcUrl; 37 | private final BMap options; 38 | 39 | public PoolKey(String jdbcUrl, BMap options) { 40 | this.jdbcUrl = jdbcUrl; 41 | this.options = options; 42 | } 43 | 44 | @Override 45 | public boolean equals(Object obj) { 46 | if (obj == this) { 47 | return true; 48 | } 49 | if (!(obj instanceof PoolKey)) { 50 | return false; 51 | } 52 | boolean jdbcUrlEqual = ((PoolKey) obj).jdbcUrl.equals(this.jdbcUrl); 53 | return jdbcUrlEqual && optionsEqual((PoolKey) obj); 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | int hashCode = 17; 59 | hashCode = hashCode * 31 + jdbcUrl.hashCode(); 60 | if (options != null) { 61 | hashCode = 31 * hashCode + calculateDbOptionsHashCode(); 62 | } 63 | return hashCode; 64 | } 65 | 66 | private int calculateDbOptionsHashCode() { 67 | int hashCode = 17; 68 | for (Map.Entry entry : options.entrySet()) { 69 | int keyHashCode = entry.getKey().hashCode(); 70 | Object value = entry.getValue(); 71 | int valueHashCode; 72 | Objects.requireNonNull(value, "type null shouldn't have occurred"); 73 | if (value instanceof BValue || value instanceof Number 74 | || value instanceof String || value instanceof Boolean) { 75 | Type type = TypeUtils.getType(value); 76 | int typeTag = type.getTag(); 77 | switch (typeTag) { 78 | case TypeTags.STRING_TAG: 79 | case TypeTags.DECIMAL_TAG: 80 | valueHashCode = value.hashCode(); 81 | break; 82 | case TypeTags.BYTE_TAG: 83 | case TypeTags.INT_TAG: 84 | // Assert to convince spotbugs that value is a number 85 | assert value instanceof Number; 86 | long longValue = (Long) value; 87 | valueHashCode = (int) (longValue ^ (longValue >>> 32)); 88 | break; 89 | case TypeTags.FLOAT_TAG: 90 | assert value instanceof Double; 91 | long longValueConvertedFromDouble = Double.doubleToLongBits((Double) value); 92 | valueHashCode = (int) (longValueConvertedFromDouble ^ (longValueConvertedFromDouble >>> 32)); 93 | break; 94 | case TypeTags.BOOLEAN_TAG: 95 | assert value instanceof Boolean; 96 | valueHashCode = ((Boolean) value ? 1 : 0); 97 | break; 98 | default: 99 | throw new AssertionError("type " + type.getName() + " shouldn't have occurred"); 100 | } 101 | } else { 102 | valueHashCode = value.hashCode(); 103 | } 104 | 105 | hashCode = hashCode + keyHashCode + valueHashCode; 106 | } 107 | return hashCode; 108 | } 109 | 110 | private boolean optionsEqual(PoolKey anotherPoolKey) { 111 | BMap anotherDbOptions = anotherPoolKey.options; 112 | if (options == null && anotherDbOptions == null) { 113 | return true; 114 | } 115 | if (options == null || anotherDbOptions == null) { 116 | return false; 117 | } 118 | if (this.options.size() != anotherDbOptions.size()) { 119 | return false; 120 | } 121 | for (Map.Entry entry : options.entrySet()) { 122 | if (!entry.getValue().equals(anotherDbOptions.get(entry.getKey()))) { 123 | return false; 124 | } 125 | } 126 | return true; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/exception/ApplicationError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.exception; 19 | 20 | /** 21 | * This exception represents the errors and exception caused due to the application mis configurations. 22 | * 23 | * @since 1.2.0 24 | */ 25 | public class ApplicationError extends Exception { 26 | public ApplicationError(String message) { 27 | super(message); 28 | } 29 | 30 | public ApplicationError(String message, Exception error) { 31 | super(message, error); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/exception/ConversionError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.exception; 19 | 20 | /** 21 | * This exception represents the occurs when a query retrieves a result that is corrupted and cannot be converted to 22 | * expected type. 23 | */ 24 | public class ConversionError extends DataError { 25 | 26 | public ConversionError(int columnIndex, String result, String fieldType, String errorDetails) { 27 | super(String.format("Retrieved column %d result '%s' could not be converted to '%s', %s.", 28 | columnIndex, result, fieldType, errorDetails)); 29 | } 30 | 31 | public ConversionError(String result, String fieldType, String errorDetails) { 32 | super(String.format("Retrieved result '%s' could not be converted to '%s', %s.", 33 | result, fieldType, errorDetails)); 34 | } 35 | 36 | public ConversionError(String message) { 37 | super(message); 38 | } 39 | 40 | public ConversionError(String message, Exception error) { 41 | super(message, error); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/exception/DataError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.exception; 19 | 20 | /** 21 | * This exception represents the errors and exception during the processing of the returned data or parameters. 22 | */ 23 | public class DataError extends ApplicationError { 24 | 25 | public DataError(String message) { 26 | super(message); 27 | } 28 | 29 | public DataError(String message, Exception error) { 30 | super(message, error); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/exception/FieldMismatchError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.exception; 19 | 20 | /** 21 | * This exception represents the error that occurs when a query retrieves a result that cannot be matched to the 22 | * expected record type. 23 | */ 24 | public class FieldMismatchError extends DataError { 25 | 26 | public FieldMismatchError(String bRecordName, int recordFieldCount, int returnedRowCount) { 27 | super(String.format("Record '%s' field count %d and the returned SQL Struct field count " 28 | + "%d are different.", bRecordName, recordFieldCount, returnedRowCount)); 29 | } 30 | 31 | public FieldMismatchError(String message) { 32 | super(message); 33 | } 34 | 35 | public FieldMismatchError(String message, Exception error) { 36 | super(message, error); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/exception/TypeMismatchError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.exception; 19 | 20 | import java.util.Arrays; 21 | 22 | /** 23 | * This exception represents the occurs when a query retrieves a result that differs from the expected result type. 24 | */ 25 | public class TypeMismatchError extends DataError { 26 | 27 | public TypeMismatchError(String sqlType, String typeFound, String typeExpected) { 28 | super(String.format("The ballerina type expected for '%s' type is '%s' but found type '%s'.", 29 | sqlType, typeExpected, typeFound)); 30 | } 31 | 32 | public TypeMismatchError(String sqlType, String typeFound, String[] typeExpected) { 33 | super(String.format("The ballerina type expected for '%s' type are '%s' but found type '%s'.", 34 | sqlType, String.join("', and '", 35 | String.join("', '", Arrays.copyOf(typeExpected, typeExpected.length - 1)), 36 | typeExpected[typeExpected.length - 1]), typeFound)); 37 | } 38 | 39 | public TypeMismatchError(String sqlType, String typeFound) { 40 | super(String.format("SQL Type '%s' cannot be converted to ballerina type '%s'.", sqlType, typeFound)); 41 | } 42 | 43 | public TypeMismatchError(String message) { 44 | super(message); 45 | } 46 | 47 | public TypeMismatchError(String message, Exception error) { 48 | super(message, error); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/exception/UnsupportedTypeError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.exception; 19 | 20 | /** 21 | * This exception represents error that occurs when an unsupported parameter type is added to the query. 22 | */ 23 | public class UnsupportedTypeError extends DataError { 24 | 25 | public UnsupportedTypeError(String unsupportedType, int paramIndex) { 26 | super(String.format( 27 | "ParameterizedQuery parameter %d is of unsupported type '%s'.", paramIndex, unsupportedType)); 28 | } 29 | 30 | public UnsupportedTypeError(String message) { 31 | super(message); 32 | } 33 | 34 | public UnsupportedTypeError(String message, Exception error) { 35 | super(message, error); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/ClientProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.nativeimpl; 20 | 21 | import io.ballerina.runtime.api.values.BError; 22 | import io.ballerina.runtime.api.values.BObject; 23 | import io.ballerina.stdlib.sql.Constants; 24 | import io.ballerina.stdlib.sql.datasource.SQLDatasource; 25 | import io.ballerina.stdlib.sql.utils.Utils; 26 | 27 | import java.util.UUID; 28 | 29 | /** 30 | * This class implements the utility methods for the clients to be used. 31 | * 32 | * @since 0.5.6 33 | */ 34 | public class ClientProcessor { 35 | 36 | private ClientProcessor() { 37 | } 38 | 39 | public static Object close(BObject client) { 40 | Utils.disableHikariLogs(); 41 | Object datasourceObj = client.getNativeData(Constants.DATABASE_CLIENT); 42 | // When an exception is thrown during database endpoint init (eg: driver not present) stop operation 43 | // of the endpoint is automatically called. But at this point, datasource is null therefore to handle that 44 | // situation following null check is needed. 45 | if (datasourceObj != null) { 46 | ((SQLDatasource) datasourceObj).decrementClientCounterAndAttemptPoolShutdown(); 47 | client.addNativeData(Constants.DATABASE_CLIENT_ACTIVE_STATUS, Boolean.FALSE); 48 | } 49 | return null; 50 | } 51 | 52 | /** 53 | * Create the client used to connect with the database. 54 | * 55 | * @param client client object 56 | * @param sqlDatasourceParams datasource parameters required to retrieve the JDBC URL for datasource lookup and 57 | * initialization of the newly created datasource if it doesn't exists 58 | * @return null if client is successfully created else error 59 | */ 60 | public static Object createClient(BObject client, SQLDatasource.SQLDatasourceParams sqlDatasourceParams, 61 | boolean executeGKFlag, boolean batchExecuteGKFlag) { 62 | try { 63 | Utils.disableHikariLogs(); 64 | SQLDatasource sqlDatasource = SQLDatasource.retrieveDatasource(sqlDatasourceParams, executeGKFlag, 65 | batchExecuteGKFlag); 66 | client.addNativeData(Constants.DATABASE_CLIENT, sqlDatasource); 67 | client.addNativeData(Constants.SQL_CONNECTOR_TRANSACTION_ID, UUID.randomUUID().toString()); 68 | client.addNativeData(Constants.DATABASE_CLIENT_ACTIVE_STATUS, Boolean.TRUE); 69 | return null; 70 | } catch (BError errorValue) { 71 | return errorValue; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/transaction/SQLTransactionContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.transaction; 19 | 20 | import io.ballerina.runtime.api.creators.ErrorCreator; 21 | import io.ballerina.runtime.api.utils.StringUtils; 22 | import io.ballerina.runtime.transactions.BallerinaTransactionContext; 23 | 24 | import java.sql.Connection; 25 | import java.sql.SQLException; 26 | 27 | import javax.transaction.xa.XAResource; 28 | 29 | /** 30 | * {@code SQLTransactionContext} transaction context for SQL transactions. 31 | * 32 | * @since 2.0.0 33 | */ 34 | public class SQLTransactionContext implements BallerinaTransactionContext { 35 | private Connection conn; 36 | private XAResource xaResource; 37 | 38 | public SQLTransactionContext(Connection conn, XAResource resource) { 39 | this.conn = conn; 40 | this.xaResource = resource; 41 | } 42 | 43 | public SQLTransactionContext(Connection conn) { 44 | this.conn = conn; 45 | } 46 | 47 | public Connection getConnection() { 48 | return this.conn; 49 | } 50 | 51 | @Override 52 | public void commit() { 53 | try { 54 | conn.commit(); 55 | } catch (SQLException e) { 56 | throw ErrorCreator.createError(StringUtils.fromString("transaction commit failed:" + e.getMessage())); 57 | } 58 | } 59 | 60 | @Override 61 | public void rollback() { 62 | try { 63 | if (!conn.isClosed()) { 64 | conn.rollback(); 65 | } 66 | } catch (SQLException e) { 67 | throw ErrorCreator.createError(StringUtils.fromString("transaction rollback failed:" + e.getMessage())); 68 | } 69 | } 70 | 71 | @Override 72 | public void close() { 73 | try { 74 | if (!conn.isClosed()) { 75 | conn.close(); 76 | } 77 | } catch (SQLException e) { 78 | throw ErrorCreator.createError(StringUtils.fromString("connection close failed:" + e.getMessage())); 79 | } 80 | } 81 | 82 | @Override 83 | public XAResource getXAResource() { 84 | return this.xaResource; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/utils/ColumnDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.utils; 19 | 20 | import io.ballerina.runtime.api.types.Type; 21 | 22 | /** 23 | * This class provides the mapping of the sql columns, its names and types. 24 | * 25 | * @since 1.2.0 26 | */ 27 | public class ColumnDefinition { 28 | private final String ballerinaFieldName; 29 | private final Type ballerinaType; 30 | 31 | protected ColumnDefinition(String ballerinaFieldName, Type ballerinaType) { 32 | this.ballerinaFieldName = ballerinaFieldName; 33 | this.ballerinaType = ballerinaType; 34 | } 35 | 36 | public Type getBallerinaType() { 37 | return ballerinaType; 38 | } 39 | 40 | public String getBallerinaFieldName() { 41 | return ballerinaFieldName; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/utils/ConnectionPoolUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.utils; 19 | 20 | import io.ballerina.runtime.api.values.BMap; 21 | import io.ballerina.runtime.api.values.BString; 22 | import io.ballerina.stdlib.sql.datasource.SQLDatasource; 23 | 24 | import java.util.concurrent.ConcurrentHashMap; 25 | 26 | /** 27 | * This is the util class for handing connection pool. 28 | * 29 | * @since 1.2.0 30 | */ 31 | public class ConnectionPoolUtils { 32 | private ConnectionPoolUtils() { 33 | } 34 | 35 | public static void initGlobalPoolContainer(BMap poolConfig) { 36 | SQLDatasource.putDatasourceContainer(poolConfig, new ConcurrentHashMap<>()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/utils/ModuleUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.utils; 20 | 21 | import io.ballerina.runtime.api.Environment; 22 | import io.ballerina.runtime.api.Module; 23 | import io.ballerina.runtime.api.utils.StringUtils; 24 | import io.ballerina.runtime.api.values.BString; 25 | 26 | /** 27 | * Utility functions relevant to module operations. 28 | * 29 | * @since 2.0.0 30 | */ 31 | public class ModuleUtils { 32 | 33 | private static Module sqlModule; 34 | private static BString pkgIdentifier; 35 | 36 | private ModuleUtils() { 37 | } 38 | 39 | public static void setModule(Environment env) { 40 | sqlModule = env.getCurrentModule(); 41 | pkgIdentifier = StringUtils.fromString(sqlModule.toString()); 42 | } 43 | 44 | public static Module getModule() { 45 | return sqlModule; 46 | } 47 | 48 | public static BString getPkgIdentifier() { 49 | return pkgIdentifier; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/utils/PrimitiveTypeColumnDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.utils; 19 | 20 | import io.ballerina.runtime.api.types.Type; 21 | 22 | /** 23 | * This class provides the mapping of the sql columns, its names and types of grouped columns for inner record type. 24 | **/ 25 | public class PrimitiveTypeColumnDefinition extends ColumnDefinition { 26 | private final String columnName; 27 | private final int sqlType; 28 | private final String sqlTypeName; 29 | private final boolean isNullable; 30 | private final int resultSetColumnIndex; 31 | 32 | public PrimitiveTypeColumnDefinition(String columnName, int sqlType, String sqlTypeName, boolean isNullable, 33 | int resultSetColumnIndex, String ballerinaFieldName, Type ballerinaType) { 34 | super(ballerinaFieldName, ballerinaType); 35 | this.columnName = columnName; 36 | this.sqlType = sqlType; 37 | this.sqlTypeName = sqlTypeName; 38 | this.isNullable = isNullable; 39 | this.resultSetColumnIndex = resultSetColumnIndex; 40 | } 41 | 42 | public String getColumnName() { 43 | return columnName; 44 | } 45 | 46 | public int getSqlType() { 47 | return sqlType; 48 | } 49 | 50 | public String getSqlTypeName() { 51 | return sqlTypeName; 52 | } 53 | 54 | public boolean isNullable() { 55 | return isNullable; 56 | } 57 | 58 | public int getResultSetColumnIndex() { 59 | return resultSetColumnIndex; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/utils/RecordColumnDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.utils; 19 | 20 | import io.ballerina.runtime.api.types.Type; 21 | 22 | import java.util.ArrayList; 23 | 24 | /** 25 | * This class provides the mapping of the sql columns, its names and types of grouped columns for inner record type. 26 | **/ 27 | public class RecordColumnDefinition extends ColumnDefinition { 28 | private final ArrayList innerFields; 29 | 30 | protected RecordColumnDefinition(String ballerinaFieldName, Type ballerinaType, 31 | ArrayList columnDefinitions) { 32 | super(ballerinaFieldName, ballerinaType); 33 | this.innerFields = columnDefinitions; 34 | } 35 | 36 | public ArrayList getInnerFields() { 37 | return innerFields; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/utils/RecordIteratorUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.utils; 19 | 20 | import io.ballerina.runtime.api.types.RecordType; 21 | import io.ballerina.runtime.api.values.BObject; 22 | import io.ballerina.stdlib.sql.Constants; 23 | import io.ballerina.stdlib.sql.exception.ApplicationError; 24 | import io.ballerina.stdlib.sql.parameterprocessor.DefaultResultParameterProcessor; 25 | 26 | import java.sql.Connection; 27 | import java.sql.ResultSet; 28 | import java.sql.SQLException; 29 | import java.sql.Statement; 30 | import java.util.List; 31 | 32 | import static io.ballerina.stdlib.sql.utils.Utils.cleanUpConnection; 33 | 34 | /** 35 | * This class provides functionality for the `RecordIterator` to iterate through the sql result set. 36 | * 37 | * @since 1.2.0 38 | */ 39 | public class RecordIteratorUtils { 40 | public RecordIteratorUtils() { 41 | } 42 | 43 | public static Object nextResult(BObject recordIterator) { 44 | DefaultResultParameterProcessor resultParameterProcessor = DefaultResultParameterProcessor.getInstance(); 45 | return nextResult(recordIterator, resultParameterProcessor); 46 | } 47 | 48 | public static Object nextResult(BObject recordIterator, DefaultResultParameterProcessor resultParameterProcessor) { 49 | ResultSet resultSet = (ResultSet) recordIterator.getNativeData(Constants.RESULT_SET_NATIVE_DATA_FIELD); 50 | try { 51 | if (resultSet.next()) { 52 | RecordType streamConstraint = (RecordType) recordIterator.getNativeData( 53 | Constants.RECORD_TYPE_DATA_FIELD); 54 | List columnDefinitions = (List) recordIterator 55 | .getNativeData(Constants.COLUMN_DEFINITIONS_DATA_FIELD); 56 | return Utils.createBallerinaRecord(streamConstraint, resultParameterProcessor, resultSet, 57 | columnDefinitions); 58 | } 59 | // Stream has reached the end, we clean up the resources, here any error from closing the stream is ignored. 60 | closeResult(recordIterator); 61 | return null; 62 | } catch (SQLException e) { 63 | // Stream throws an error, we clean up the resources, here any error from closing the stream is ignored. 64 | closeResult(recordIterator); 65 | return ErrorGenerator.getSQLDatabaseError(e, "Error when iterating the SQL result"); 66 | } catch (ApplicationError e) { 67 | // Stream throws an error, we clean up the resources, here any error from closing the stream is ignored. 68 | closeResult(recordIterator); 69 | return ErrorGenerator.getSQLApplicationError(e, "Error when iterating the SQL result. "); 70 | } catch (Throwable throwable) { 71 | // Stream throws an error, we clean up the resources, here any error from closing the stream is ignored. 72 | closeResult(recordIterator); 73 | return ErrorGenerator.getSQLApplicationError("Error when iterating through the " + 74 | "SQL result. " + throwable.getMessage()); 75 | } 76 | } 77 | 78 | public static Object closeResult(BObject recordIterator) { 79 | ResultSet resultSet = (ResultSet) recordIterator.getNativeData(Constants.RESULT_SET_NATIVE_DATA_FIELD); 80 | Statement statement = (Statement) recordIterator.getNativeData(Constants.STATEMENT_NATIVE_DATA_FIELD); 81 | Connection connection = (Connection) recordIterator.getNativeData(Constants.CONNECTION_NATIVE_DATA_FIELD); 82 | return cleanUpConnection(recordIterator, resultSet, statement, connection); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/sql/utils/SQLColumnMetadata.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.utils; 19 | 20 | /** 21 | * This class provides the mapping of the sql columns, its names and types. 22 | **/ 23 | public class SQLColumnMetadata { 24 | private final String columnName; 25 | private final int sqlType; 26 | private final String sqlName; 27 | private final boolean isNullable; 28 | private final int resultSetColIndex; 29 | 30 | protected SQLColumnMetadata(String columnName, int sqlType, String sqlName, boolean isNullable, 31 | int resultSetColIndex) { 32 | this.columnName = columnName; 33 | this.sqlType = sqlType; 34 | this.isNullable = isNullable; 35 | this.sqlName = sqlName; 36 | this.resultSetColIndex = resultSetColIndex; 37 | } 38 | 39 | public String getColumnName() { 40 | return columnName; 41 | } 42 | 43 | public int getSqlType() { 44 | return sqlType; 45 | } 46 | 47 | public boolean isNullable() { 48 | return isNullable; 49 | } 50 | 51 | public String getSqlName() { 52 | return sqlName; 53 | } 54 | 55 | public int getResultSetColIndex() { 56 | return resultSetColIndex; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /native/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | module io.ballerina.stdlib.sql { 20 | requires transitive java.sql; 21 | requires com.zaxxer.hikari; 22 | requires io.ballerina.runtime; 23 | requires io.ballerina.lang; 24 | requires io.ballerina.stdlib.io; 25 | requires io.ballerina.stdlib.time; 26 | requires transactions.jdbc; 27 | exports io.ballerina.stdlib.sql; 28 | exports io.ballerina.stdlib.sql.datasource; 29 | exports io.ballerina.stdlib.sql.exception; 30 | exports io.ballerina.stdlib.sql.nativeimpl; 31 | exports io.ballerina.stdlib.sql.parameterprocessor; 32 | exports io.ballerina.stdlib.sql.utils; 33 | } 34 | -------------------------------------------------------------------------------- /native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/sql-native/proxy-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "interfaces": [ 4 | "java.sql.Connection" 5 | ] 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/sql-native/reflect-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "[Lcom.zaxxer.hikari.util.ConcurrentBag$IConcurrentBagEntry;" 4 | }, 5 | { 6 | "name": "[Ljava.sql.Statement;" 7 | }, 8 | { 9 | "name": "com.zaxxer.hikari.HikariConfig", 10 | "allDeclaredFields": true, 11 | "queryAllPublicMethods": true, 12 | "methods": [ 13 | { 14 | "name": "setConnectionTimeout", 15 | "parameterTypes": [ 16 | "long" 17 | ] 18 | }, 19 | { 20 | "name": "setAutoCommit", 21 | "parameterTypes": [ 22 | "boolean" 23 | ] 24 | } 25 | ] 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/sql-native/resource-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | "includes": [ 4 | { 5 | "pattern": "\\QMETA-INF/services/java.sql.Driver\\E" 6 | } 7 | ] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /native/src/test/java/io/ballerina/stdlib/sql/datasource/PoolKeyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.datasource; 20 | 21 | import io.ballerina.runtime.api.values.BMap; 22 | import io.ballerina.runtime.api.values.BString; 23 | import io.ballerina.runtime.api.values.BValue; 24 | import io.ballerina.runtime.internal.values.MapValueImpl; 25 | import io.ballerina.stdlib.sql.TestUtils; 26 | import org.testng.annotations.Test; 27 | 28 | import static io.ballerina.runtime.api.utils.StringUtils.fromString; 29 | import static org.testng.Assert.assertEquals; 30 | import static org.testng.Assert.assertFalse; 31 | import static org.testng.Assert.assertTrue; 32 | 33 | /** 34 | * PoolKey class test. 35 | * 36 | * @since 0.6.0-beta.2 37 | */ 38 | public class PoolKeyTest { 39 | @Test 40 | void poolKeyConstructorTest() { 41 | BMap options = new MapValueImpl<>(); 42 | options.put(fromString("booleanValue"), true); 43 | PoolKey poolKey = new PoolKey("JDBC_URL", options); 44 | assertTrue(poolKey.equals(poolKey)); 45 | } 46 | 47 | @Test 48 | void poolKeyConstructorTest1() { 49 | BMap options = new MapValueImpl<>(); 50 | options.put(fromString("booleanValue"), true); 51 | PoolKey poolKey = new PoolKey("JDBC_URL", options); 52 | assertFalse(poolKey.equals(1)); 53 | } 54 | 55 | @Test 56 | void hashCodeTest() { 57 | BMap options = new MapValueImpl<>(); 58 | options.put(fromString("booleanValue"), true); 59 | PoolKey poolKey = new PoolKey("JDBC_URL", options); 60 | assertEquals(poolKey.hashCode(), 1346265441); 61 | } 62 | 63 | @Test 64 | void hashCodeTest1() { 65 | BMap options = new MapValueImpl<>(); 66 | options.put(fromString("floatValue"), 1.2); 67 | PoolKey poolKey = new PoolKey("JDBC_URL", options); 68 | assertEquals(poolKey.hashCode(), 1581738924); 69 | } 70 | 71 | @Test 72 | void hashCodeTest2() { 73 | BMap options = new MapValueImpl<>(); 74 | options.put(fromString("charValue"), TestUtils.getMockBValueJson()); 75 | PoolKey poolKey = new PoolKey("JDBC_URL", options); 76 | try { 77 | poolKey.hashCode(); 78 | } catch (AssertionError e) { 79 | assertEquals(e.getMessage(), "type json shouldn't have occurred"); 80 | } 81 | } 82 | 83 | @Test 84 | void hashCodeTest3() { 85 | BMap options = new MapValueImpl<>(); 86 | options.put(fromString("floatValue"), 'a'); 87 | PoolKey poolKey = new PoolKey("JDBC_URL", options); 88 | assertEquals(poolKey.hashCode(), 1367829517); 89 | } 90 | 91 | @Test 92 | void optionsEqualTest() { 93 | BMap options = new MapValueImpl<>(); 94 | options.put(fromString("floatValue"), 1.2); 95 | PoolKey poolKey = new PoolKey("JDBC_URL", options); 96 | BMap options1 = new MapValueImpl<>(); 97 | options1.put(fromString("floatValue"), 1.3); 98 | PoolKey poolKey1 = new PoolKey("JDBC_URL", options1); 99 | assertFalse(poolKey.equals(poolKey1)); 100 | 101 | PoolKey poolKey2 = new PoolKey("JDBC_URL", null); 102 | assertFalse(poolKey.equals(poolKey2)); 103 | 104 | BMap options2 = new MapValueImpl<>(); 105 | PoolKey poolKey3 = new PoolKey("JDBC_URL", options2); 106 | assertFalse(poolKey.equals(poolKey3)); 107 | 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /native/src/test/java/io/ballerina/stdlib/sql/exception/ApplicationErrorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.exception; 20 | 21 | import org.testng.annotations.Test; 22 | 23 | import java.sql.SQLException; 24 | 25 | import static org.testng.Assert.assertEquals; 26 | 27 | /** 28 | * ApplicationError class test. 29 | * 30 | * @since 0.6.0-beta.2 31 | */ 32 | public class ApplicationErrorTest { 33 | @Test 34 | void applicationErrorTest1() { 35 | ApplicationError error = new ApplicationError("Application Error", new SQLException("new SQL Exception")); 36 | assertEquals(error.getMessage(), "Application Error"); 37 | } 38 | 39 | @Test 40 | void conversionErrorTest1() { 41 | ConversionError error = new ConversionError("Conversion Error", new SQLException("new SQL Exception")); 42 | assertEquals(error.getMessage(), "Conversion Error"); 43 | } 44 | 45 | @Test 46 | void conversionErrorTest2() { 47 | ConversionError error = new ConversionError("Conversion Error"); 48 | assertEquals(error.getMessage(), "Conversion Error"); 49 | } 50 | 51 | @Test 52 | void conversionErrorTest3() { 53 | ConversionError error = new ConversionError("{}sdf", "JSON", "Expected :"); 54 | assertEquals(error.getMessage(), "Retrieved result '{}sdf' could not be converted to 'JSON', Expected :."); 55 | } 56 | 57 | @Test 58 | void fieldMismatchErrorTest1() { 59 | FieldMismatchError error = new FieldMismatchError("FieldMismatch Error", new SQLException("new SQL Exception")); 60 | assertEquals(error.getMessage(), "FieldMismatch Error"); 61 | } 62 | 63 | @Test 64 | void fieldMismatchErrorTest2() { 65 | FieldMismatchError error = new FieldMismatchError("FieldMismatch Error"); 66 | assertEquals(error.getMessage(), "FieldMismatch Error"); 67 | } 68 | 69 | @Test 70 | void unsupportedTypeErrorTest2() { 71 | UnsupportedTypeError error = new UnsupportedTypeError("Unsupported Error", 72 | new SQLException("new SQL Exception")); 73 | assertEquals(error.getMessage(), "Unsupported Error"); 74 | } 75 | 76 | @Test 77 | void typeMismatchErrorTest1() { 78 | TypeMismatchError error = new TypeMismatchError("TypeMismatch Error", new SQLException("new SQL Exception")); 79 | assertEquals(error.getMessage(), "TypeMismatch Error"); 80 | } 81 | 82 | @Test 83 | void typeMismatchErrorTest2() { 84 | TypeMismatchError error = new TypeMismatchError("SQL Time", "byte", 85 | new String[]{"time:TimeOfDay", "time:Time"}); 86 | assertEquals(error.getMessage(), 87 | "The ballerina type expected for 'SQL Time' type are 'time:TimeOfDay', and 'time:Time' " + 88 | "but found type 'byte'."); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /native/src/test/java/io/ballerina/stdlib/sql/transaction/SQLTransactionContextTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.transaction; 20 | 21 | import io.ballerina.stdlib.sql.TestUtils; 22 | import org.testng.annotations.Test; 23 | 24 | import java.sql.Connection; 25 | 26 | import javax.transaction.xa.XAResource; 27 | 28 | import static org.testng.Assert.assertEquals; 29 | 30 | /** 31 | * SQLTransactionContext class test. 32 | * 33 | * @since 0.6.0-beta.2 34 | */ 35 | public class SQLTransactionContextTest { 36 | XAResource xaResource = TestUtils.getMockXAResource(); 37 | 38 | @Test 39 | void commitTest1() { 40 | Connection connection = TestUtils.getMockConnection(false); 41 | SQLTransactionContext sqlTransactionContext = new SQLTransactionContext(connection, xaResource); 42 | try { 43 | sqlTransactionContext.commit(); 44 | } catch (Exception e) { 45 | assertEquals(e.getMessage(), "transaction commit failed:Commit Error"); 46 | } 47 | } 48 | 49 | @Test 50 | void rollbackTest() { 51 | Connection connection = TestUtils.getMockConnection(false); 52 | SQLTransactionContext sqlTransactionContext = new SQLTransactionContext(connection, xaResource); 53 | try { 54 | sqlTransactionContext.rollback(); 55 | } catch (Exception e) { 56 | assertEquals(e.getMessage(), "transaction rollback failed:Rollback Error"); 57 | } 58 | } 59 | 60 | @Test 61 | void rollbackTest1() { 62 | Connection connection = TestUtils.getMockConnection(true); 63 | SQLTransactionContext sqlTransactionContext = new SQLTransactionContext(connection, xaResource); 64 | try { 65 | sqlTransactionContext.rollback(); 66 | } catch (Exception e) { 67 | assertEquals(e.getMessage(), "transaction rollback failed:Rollback Error"); 68 | } 69 | } 70 | 71 | @Test 72 | void closeTest() { 73 | Connection connection = TestUtils.getMockConnection(false); 74 | SQLTransactionContext sqlTransactionContext = new SQLTransactionContext(connection, xaResource); 75 | try { 76 | sqlTransactionContext.close(); 77 | } catch (Exception e) { 78 | assertEquals(e.getMessage(), "connection close failed:Close Error"); 79 | } 80 | } 81 | 82 | @Test 83 | void closeTest1() { 84 | Connection connection = TestUtils.getMockConnection(true); 85 | SQLTransactionContext sqlTransactionContext = new SQLTransactionContext(connection, xaResource); 86 | try { 87 | sqlTransactionContext.close(); 88 | } catch (Exception e) { 89 | assertEquals(e.getMessage(), "connection close failed:Close Error"); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /native/src/test/java/io/ballerina/stdlib/sql/utils/UtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.utils; 20 | 21 | import io.ballerina.runtime.api.types.StructureType; 22 | import io.ballerina.runtime.api.utils.TypeUtils; 23 | import io.ballerina.stdlib.sql.TestUtils; 24 | import org.testng.annotations.Test; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | import static org.testng.Assert.assertEquals; 30 | 31 | /** 32 | * Utils class test. 33 | * 34 | * @since 0.6.0-beta.2 35 | */ 36 | public class UtilsTest { 37 | 38 | @Test 39 | void createTimeStructTest() { 40 | try { 41 | Utils.createTimeStruct(1400020000); 42 | } catch (UnsupportedOperationException e) { 43 | assertEquals(e.getMessage(), "java.lang.UnsupportedOperationException"); 44 | } 45 | } 46 | 47 | @Test 48 | void getDefaultRecordTypeTest() { 49 | PrimitiveTypeColumnDefinition columnDefinition1 = new TestUtils.ExtendedColumnDefinition("int_type", 50 | 2, "INT", false, 1, null, TypeUtils.getType(4)); 51 | PrimitiveTypeColumnDefinition columnDefinition2 = new TestUtils.ExtendedColumnDefinition("string_type", 52 | 2, "STRING", false, 1, null, TypeUtils.getType(12)); 53 | List list = new ArrayList<>(); 54 | list.add(columnDefinition1); 55 | list.add(columnDefinition2); 56 | StructureType structureType = Utils.getDefaultRecordType(list); 57 | assertEquals(structureType.getFlags(), 0); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /native/src/test/resources/testng.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/6.3/userguide/multi_project_builds.html 8 | */ 9 | 10 | pluginManagement { 11 | plugins { 12 | id "com.github.spotbugs" version "${spotbugsPluginVersion}" 13 | id "com.github.johnrengelman.shadow" version "${shadowJarPluginVersion}" 14 | id "de.undercouch.download" version "${downloadPluginVersion}" 15 | id "net.researchgate.release" version "${releasePluginVersion}" 16 | id "io.ballerina.plugin" version "${ballerinaGradlePluginVersion}" 17 | } 18 | 19 | repositories { 20 | gradlePluginPortal() 21 | maven { 22 | url = 'https://maven.pkg.github.com/ballerina-platform/*' 23 | credentials { 24 | username System.getenv("packageUser") 25 | password System.getenv("packagePAT") 26 | } 27 | } 28 | } 29 | } 30 | 31 | plugins { 32 | id "com.gradle.enterprise" version "3.2" 33 | } 34 | 35 | rootProject.name = 'ballerina-sql' 36 | 37 | include ':checkstyle' 38 | include ':sql-native' 39 | include ':sql-compiler-plugin' 40 | include ':sql-test-utils' 41 | include ':sql-ballerina' 42 | include ':sql-compiler-plugin-tests' 43 | 44 | project(':checkstyle').projectDir = file("build-config${File.separator}checkstyle") 45 | project(':sql-native').projectDir = file('native') 46 | project(':sql-compiler-plugin').projectDir = file('compiler-plugin') 47 | project(':sql-test-utils').projectDir = file('test-utils') 48 | project(':sql-ballerina').projectDir = file('ballerina') 49 | project(':sql-compiler-plugin-tests').projectDir = file('compiler-plugin-tests') 50 | 51 | gradleEnterprise { 52 | buildScan { 53 | termsOfServiceUrl = 'https://gradle.com/terms-of-service' 54 | termsOfServiceAgree = 'yes' 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test-utils/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | plugins { 19 | id 'java' 20 | id 'com.github.spotbugs' 21 | id 'checkstyle' 22 | } 23 | 24 | description = 'Ballerina - SQL test utils' 25 | 26 | dependencies { 27 | checkstyle project(":checkstyle") 28 | checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}" 29 | implementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}" 30 | implementation group: 'org.ballerinalang', name: 'ballerina-runtime', version: "${ballerinaLangVersion}" 31 | implementation project(":sql-native") 32 | } 33 | 34 | spotbugsMain { 35 | def classLoader = plugins["com.github.spotbugs"].class.classLoader 36 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") 37 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") 38 | effort = SpotBugsEffort.MAX 39 | reportLevel = SpotBugsConfidence.LOW 40 | ignoreFailures = true 41 | reportsDir = file("$project.buildDir/reports/spotbugs") 42 | def excludeFile = file("${rootDir}/build-config/spotbugs-exclude.xml") 43 | if (excludeFile.exists()) { 44 | it.excludeFilter = excludeFile 45 | } 46 | reports { 47 | text.enabled = true 48 | } 49 | } 50 | 51 | spotbugsTest { 52 | enabled = false 53 | } 54 | 55 | task validateSpotbugs() { 56 | doLast { 57 | if (spotbugsMain.reports.size() > 0 && 58 | spotbugsMain.reports[0].destination.exists() && 59 | spotbugsMain.reports[0].destination.text.readLines().size() > 0) { 60 | spotbugsMain.reports[0].destination?.eachLine { 61 | println 'Failure: ' + it 62 | } 63 | throw new GradleException("Spotbugs rule violations were found."); 64 | } 65 | } 66 | } 67 | 68 | checkstyle { 69 | toolVersion "${checkstylePluginVersion}" 70 | configFile file("${rootDir}/build-config/checkstyle/build/checkstyle.xml") 71 | configProperties = ["suppressionFile": file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] 72 | } 73 | 74 | tasks.withType(Checkstyle) { 75 | exclude '**/module-info.java' 76 | } 77 | 78 | spotbugsMain.finalizedBy validateSpotbugs 79 | checkstyleMain.dependsOn ':checkstyle:downloadCheckstyleRuleFiles' 80 | checkstyleTest.dependsOn ':checkstyle:downloadCheckstyleRuleFiles' 81 | 82 | compileJava { 83 | doFirst { 84 | options.compilerArgs = [ 85 | '--module-path', classpath.asPath, 86 | ] 87 | classpath = files() 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /test-utils/src/main/java/io/ballerina/stdlib/sql/testutils/CallTestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.testutils; 20 | 21 | import io.ballerina.runtime.api.Environment; 22 | import io.ballerina.runtime.api.values.BArray; 23 | import io.ballerina.runtime.api.values.BObject; 24 | import io.ballerina.stdlib.sql.nativeimpl.CallProcessor; 25 | import io.ballerina.stdlib.sql.parameterprocessor.DefaultResultParameterProcessor; 26 | import io.ballerina.stdlib.sql.parameterprocessor.DefaultStatementParameterProcessor; 27 | 28 | /** 29 | * Native class for test client call method. 30 | */ 31 | public class CallTestUtils { 32 | private CallTestUtils() { 33 | } 34 | 35 | public static Object nativeCall(Environment env, BObject client, BObject paramSQLString, BArray recordTypes) { 36 | return CallProcessor.nativeCall(env, client, paramSQLString, recordTypes, 37 | DefaultStatementParameterProcessor.getInstance(), DefaultResultParameterProcessor.getInstance()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test-utils/src/main/java/io/ballerina/stdlib/sql/testutils/ClientTestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.testutils; 20 | 21 | import io.ballerina.runtime.api.values.BMap; 22 | import io.ballerina.runtime.api.values.BObject; 23 | import io.ballerina.runtime.api.values.BString; 24 | import io.ballerina.stdlib.sql.datasource.SQLDatasource; 25 | import io.ballerina.stdlib.sql.nativeimpl.ClientProcessor; 26 | 27 | /** 28 | * Initialize test client. 29 | */ 30 | public class ClientTestUtils { 31 | 32 | private ClientTestUtils() { 33 | } 34 | 35 | public static Object createSqlClient(BObject client, BMap sqlDatasourceParams, 36 | BMap globalConnectionPool) { 37 | return ClientProcessor.createClient(client, 38 | SQLDatasource.createSQLDatasourceParams(sqlDatasourceParams, globalConnectionPool), true, true); 39 | } 40 | 41 | public static Object close(BObject client) { 42 | return ClientProcessor.close(client); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test-utils/src/main/java/io/ballerina/stdlib/sql/testutils/ExecuteTestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.testutils; 20 | 21 | import io.ballerina.runtime.api.Environment; 22 | import io.ballerina.runtime.api.values.BArray; 23 | import io.ballerina.runtime.api.values.BObject; 24 | import io.ballerina.stdlib.sql.nativeimpl.ExecuteProcessor; 25 | import io.ballerina.stdlib.sql.parameterprocessor.DefaultStatementParameterProcessor; 26 | 27 | /** 28 | * Test client execute native method. 29 | */ 30 | public class ExecuteTestUtils { 31 | private ExecuteTestUtils() { 32 | } 33 | 34 | public static Object nativeExecute(Environment env, BObject client, BObject paramSQLString) { 35 | return ExecuteProcessor.nativeExecute(env, client, paramSQLString, 36 | DefaultStatementParameterProcessor.getInstance()); 37 | } 38 | 39 | public static Object nativeBatchExecute(Environment env, BObject client, BArray paramSQLStrings) { 40 | return ExecuteProcessor.nativeBatchExecute(env, client, paramSQLStrings, 41 | DefaultStatementParameterProcessor.getInstance()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test-utils/src/main/java/io/ballerina/stdlib/sql/testutils/QueryTestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.testutils; 20 | 21 | import io.ballerina.runtime.api.Environment; 22 | import io.ballerina.runtime.api.values.BObject; 23 | import io.ballerina.runtime.api.values.BStream; 24 | import io.ballerina.runtime.api.values.BTypedesc; 25 | import io.ballerina.stdlib.sql.nativeimpl.QueryProcessor; 26 | import io.ballerina.stdlib.sql.parameterprocessor.DefaultResultParameterProcessor; 27 | import io.ballerina.stdlib.sql.parameterprocessor.DefaultStatementParameterProcessor; 28 | 29 | /** 30 | * Test client native query class. 31 | */ 32 | public class QueryTestUtils { 33 | 34 | private QueryTestUtils() { 35 | } 36 | 37 | public static BStream nativeQuery(Environment environment, BObject client, BObject paramSQLString, 38 | BTypedesc recordType) { 39 | DefaultStatementParameterProcessor statementParametersProcessor = DefaultStatementParameterProcessor 40 | .getInstance(); 41 | DefaultResultParameterProcessor resultParametersProcessor = DefaultResultParameterProcessor 42 | .getInstance(); 43 | return QueryProcessor.nativeQuery(environment, client, paramSQLString, recordType, statementParametersProcessor, 44 | resultParametersProcessor); 45 | } 46 | 47 | public static Object nativeQueryRow(Environment env, BObject client, BObject paramSQLString, BTypedesc recordType) { 48 | DefaultStatementParameterProcessor statementParametersProcessor = DefaultStatementParameterProcessor 49 | .getInstance(); 50 | DefaultResultParameterProcessor resultParametersProcessor = DefaultResultParameterProcessor 51 | .getInstance(); 52 | return QueryProcessor.nativeQueryRow(env, client, paramSQLString, recordType, statementParametersProcessor, 53 | resultParametersProcessor); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test-utils/src/main/java/io/ballerina/stdlib/sql/testutils/nativeimpl/Exec.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.testutils.nativeimpl; 20 | 21 | import io.ballerina.runtime.api.values.BMap; 22 | import io.ballerina.runtime.api.values.BString; 23 | import io.ballerina.stdlib.sql.testutils.utils.OSConstants; 24 | import io.ballerina.stdlib.sql.testutils.utils.OSUtils; 25 | 26 | import java.io.File; 27 | import java.io.IOException; 28 | import java.util.ArrayList; 29 | import java.util.Arrays; 30 | import java.util.List; 31 | import java.util.Map; 32 | import java.util.stream.Collectors; 33 | 34 | /** 35 | * Extern function exec. 36 | * 37 | * @since 0.6.0 38 | */ 39 | public final class Exec { 40 | 41 | private Exec() {} 42 | 43 | public static Object exec(BString command, BMap env, Object dir, BString[] args) { 44 | List commandList = new ArrayList<>(); 45 | commandList.add(command.getValue()); 46 | commandList.addAll(Arrays.stream(args).map(BString::getValue).collect(Collectors.toList())); 47 | ProcessBuilder pb = new ProcessBuilder(commandList); 48 | if (dir != null) { 49 | pb.directory(new File(((BString) dir).getValue())); 50 | } 51 | if (env != null) { 52 | Map pbEnv = pb.environment(); 53 | env.entrySet().forEach(entry -> pbEnv.put(entry.getKey().getValue(), entry.getValue().getValue())); 54 | } 55 | try { 56 | return OSUtils.getProcessObject(pb.start()); 57 | } catch (IOException e) { 58 | return OSUtils.getBallerinaError(OSConstants.PROCESS_EXEC_ERROR, e); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test-utils/src/main/java/io/ballerina/stdlib/sql/testutils/nativeimpl/ExitCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.testutils.nativeimpl; 20 | 21 | import io.ballerina.runtime.api.values.BObject; 22 | import io.ballerina.stdlib.sql.testutils.utils.OSConstants; 23 | import io.ballerina.stdlib.sql.testutils.utils.OSUtils; 24 | 25 | /** 26 | * External function for exitCode. 27 | * 28 | * @since 0.6.0 29 | */ 30 | public final class ExitCode { 31 | 32 | private ExitCode() {} 33 | 34 | public static Object exitCode(BObject objVal) { 35 | Process process = OSUtils.processFromObject(objVal); 36 | try { 37 | return process.exitValue(); 38 | } catch (java.lang.IllegalThreadStateException e) { 39 | return OSUtils.getBallerinaError(OSConstants.PROCESS_EXEC_ERROR, e); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test-utils/src/main/java/io/ballerina/stdlib/sql/testutils/nativeimpl/ModuleUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.testutils.nativeimpl; 20 | 21 | import io.ballerina.runtime.api.Environment; 22 | import io.ballerina.runtime.api.Module; 23 | 24 | /** 25 | * This class will hold module related utility functions. 26 | * 27 | * @since 0.6.0 28 | */ 29 | public class ModuleUtils { 30 | 31 | /** 32 | * sql standard library package ID. 33 | */ 34 | private static Module sqlModule = null; 35 | 36 | private ModuleUtils() { 37 | } 38 | 39 | public static void setModule(Environment env) { 40 | sqlModule = env.getCurrentModule(); 41 | } 42 | 43 | public static Module getModule() { 44 | return sqlModule; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test-utils/src/main/java/io/ballerina/stdlib/sql/testutils/nativeimpl/WaitForExit.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.testutils.nativeimpl; 20 | 21 | import io.ballerina.runtime.api.values.BObject; 22 | import io.ballerina.stdlib.sql.testutils.utils.OSConstants; 23 | import io.ballerina.stdlib.sql.testutils.utils.OSUtils; 24 | 25 | /** 26 | * External function for Process.waitForExit. 27 | * 28 | * @since 0.6.0 29 | */ 30 | public final class WaitForExit { 31 | 32 | private WaitForExit() {} 33 | 34 | public static Object waitForExit(BObject objVal) { 35 | Process process = OSUtils.processFromObject(objVal); 36 | try { 37 | return process.waitFor(); 38 | } catch (InterruptedException e) { 39 | return OSUtils.getBallerinaError(OSConstants.PROCESS_EXEC_ERROR, e); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test-utils/src/main/java/io/ballerina/stdlib/sql/testutils/utils/OSConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.sql.testutils.utils; 20 | 21 | /** 22 | * Constants for os related functions. 23 | * 24 | * @since 0.6.0 25 | */ 26 | public class OSConstants { 27 | static final String PROCESS_TYPE = "Process"; 28 | 29 | static final String PROCESS_FIELD = "ProcessField"; 30 | 31 | public static final String PROCESS_EXEC_ERROR = "ProcessExecError"; 32 | 33 | private OSConstants() { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test-utils/src/main/java/io/ballerina/stdlib/sql/testutils/utils/OSUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.sql.testutils.utils; 19 | 20 | import io.ballerina.runtime.api.creators.ErrorCreator; 21 | import io.ballerina.runtime.api.creators.ValueCreator; 22 | import io.ballerina.runtime.api.utils.StringUtils; 23 | import io.ballerina.runtime.api.values.BError; 24 | import io.ballerina.runtime.api.values.BObject; 25 | import io.ballerina.runtime.api.values.BString; 26 | import io.ballerina.stdlib.sql.testutils.nativeimpl.ModuleUtils; 27 | 28 | import java.io.IOException; 29 | 30 | /** 31 | * @since 0.6.0 32 | */ 33 | public final class OSUtils { 34 | 35 | private OSUtils() {} 36 | 37 | private static final BString UNKNOWN_MESSAGE = StringUtils.fromString("Unknown Error"); 38 | 39 | /** 40 | * Returns error object with message. Error type is generic ballerina error type. This utility to construct 41 | * error object from message. 42 | * 43 | * @param typeId The string type ID of the particular error object. 44 | * @param ex Java throwable object to capture description of error struct. If throwable object is null, 45 | * "Unknown Error" sets to message by default. 46 | * @return Ballerina error object. 47 | */ 48 | public static BError getBallerinaError(String typeId, Throwable ex) { 49 | BString errorMsg = ex != null && ex.getMessage() != null ? StringUtils.fromString(ex.getMessage()) : 50 | UNKNOWN_MESSAGE; 51 | return getBallerinaError(typeId, errorMsg); 52 | } 53 | 54 | /** 55 | * Returns error object with message. Error type is generic ballerina error type. This utility to construct error 56 | * object from message. 57 | * 58 | * @param typeId The specific error type ID. 59 | * @param message Java throwable object to capture description of error struct. If throwable object is null, 60 | * "Unknown Error" is set to message by default. 61 | * @return Ballerina error object. 62 | */ 63 | public static BError getBallerinaError(String typeId, BString message) { 64 | return ErrorCreator.createDistinctError(typeId, ModuleUtils.getModule(), message); 65 | } 66 | 67 | public static BObject getProcessObject(Process process) throws IOException { 68 | BObject obj = (BObject) ValueCreator.createObjectValue(ModuleUtils.getModule(), OSConstants.PROCESS_TYPE); 69 | obj.addNativeData(OSConstants.PROCESS_FIELD, process); 70 | return obj; 71 | } 72 | 73 | public static Process processFromObject(BObject objVal) { 74 | return (Process) objVal.getNativeData(OSConstants.PROCESS_FIELD); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /test-utils/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | module io.ballerina.stdlib.sql.testutils { 20 | requires io.ballerina.runtime; 21 | requires io.ballerina.stdlib.sql; 22 | exports io.ballerina.stdlib.sql.testutils; 23 | } 24 | -------------------------------------------------------------------------------- /test-utils/src/main/resources/META-INF/native-image/io.ballerina.stdlib/sql-test-utils/reflect-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "org.hsqldb.jdbc.JDBCCommonDataSource", 4 | "methods": [ 5 | { 6 | "name": "setLoginTimeout", 7 | "parameterTypes": [ 8 | "int" 9 | ] 10 | }, 11 | { 12 | "name": "setPassword", 13 | "parameterTypes": [ 14 | "java.lang.String" 15 | ] 16 | }, 17 | { 18 | "name": "setUrl", 19 | "parameterTypes": [ 20 | "java.lang.String" 21 | ] 22 | }, 23 | { 24 | "name": "setUser", 25 | "parameterTypes": [ 26 | "java.lang.String" 27 | ] 28 | } 29 | ] 30 | }, 31 | { 32 | "name": "org.hsqldb.jdbc.JDBCDataSource", 33 | "queryAllPublicMethods": true, 34 | "methods": [ 35 | { 36 | "name": "", 37 | "parameterTypes": [] 38 | } 39 | ] 40 | }, 41 | { 42 | "name": "org.hsqldb.jdbc.JDBCDriver" 43 | } 44 | ] 45 | -------------------------------------------------------------------------------- /test-utils/src/main/resources/META-INF/native-image/io.ballerina.stdlib/sql-test-utils/resource-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundles": [ 3 | { 4 | "name": "org.hsqldb.resources.sql-state-messages", 5 | "locales": [ 6 | "" 7 | ] 8 | } 9 | ] 10 | } 11 | --------------------------------------------------------------------------------