├── .gitattributes ├── .github ├── CODEOWNERS ├── pull_request_template.md └── workflows │ ├── build-timestamped-master.yml │ ├── build-with-bal-test-graalvm.yml │ ├── central-publish.yml │ ├── daily-build.yml │ ├── process-load-test-result.yml │ ├── publish-release.yml │ ├── pull-request.yml │ ├── trigger-load-tests.yml │ └── trivy-scan.yml ├── .gitignore ├── LICENSE ├── README.md ├── ballerina ├── Ballerina.toml ├── CompilerPlugin.toml ├── Dependencies.toml ├── README.md ├── build.gradle ├── cdc_listener.bal ├── client.bal ├── icon.png ├── init.bal ├── listener_types.bal ├── procedure_params.bal ├── record_types.bal ├── tests │ ├── Config.toml │ ├── batch-execute-query-test.bal │ ├── call-procedures-test.bal │ ├── connection-init-test.bal │ ├── connection-pool-test.bal │ ├── connection-ssl-test.bal │ ├── constants.bal │ ├── error.bal │ ├── execute-basic-test.bal │ ├── execute-params-test.bal │ ├── function-test.bal │ ├── listener_tests.bal │ ├── query-complex-test.bal │ ├── query-params-test.bal │ ├── resources │ │ ├── Dockerfile │ │ ├── compose.yaml │ │ ├── files │ │ │ ├── byteValue.txt │ │ │ └── emptyByteValue.txt │ │ ├── keystore │ │ │ ├── client │ │ │ │ ├── postgresql.crt │ │ │ │ ├── postgresql.pfx │ │ │ │ └── postgresql.pk8 │ │ │ └── server │ │ │ │ ├── root.crt │ │ │ │ ├── server.crt │ │ │ │ └── server.key │ │ └── sql-scripts │ │ │ ├── 01-database-init-script.sql │ │ │ ├── 02-table-init-script.sql │ │ │ ├── 03-connection-pool1-test.sql │ │ │ ├── 04-connection-pool2-test.sql │ │ │ ├── 05-local-transaction-test.sql │ │ │ ├── 06-procedures-test-data.sql │ │ │ ├── 07-function-test-data.sql │ │ │ ├── 08-error-test-data.sql │ │ │ └── 09-cdc-test-data.sql │ └── utils.bal ├── types.bal └── utils.bal ├── build-config ├── checkstyle │ └── build.gradle ├── resources │ ├── Ballerina.toml │ ├── CompilerPlugin.toml │ └── ExamplesBallerina.toml └── spotbugs-exclude.xml ├── build.gradle ├── changelog.md ├── codecov.yml ├── compiler-plugin-tests ├── build.gradle └── src │ └── test │ ├── java │ └── io │ │ └── ballerina │ │ └── stdlib │ │ └── postgresql │ │ └── 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 │ └── sample6 │ │ ├── Ballerina.toml │ │ └── main.bal │ └── testng.xml ├── compiler-plugin ├── build.gradle └── src │ └── main │ └── java │ ├── io │ └── ballerina │ │ └── stdlib │ │ └── postgresql │ │ └── compiler │ │ ├── Constants.java │ │ ├── PostgreSQLCodeAnalyzer.java │ │ ├── PostgreSQLCompilerPlugin.java │ │ ├── PostgreSQLDiagnosticsCode.java │ │ ├── Utils.java │ │ └── analyzer │ │ ├── InitializerParamAnalyzer.java │ │ ├── MethodAnalyzer.java │ │ └── RecordAnalyzer.java │ └── module-info.java ├── docs ├── proposals │ └── default-username-for-client-connections.md └── spec │ └── spec.md ├── examples ├── atomic-batch-operation │ ├── .gitignore │ ├── Ballerina.toml │ ├── Config.toml │ ├── Performing Atomic Batch Operations with PostgreSQL.md │ └── atomic_batch_operation.bal ├── batch-operation │ ├── .gitignore │ ├── Ballerina.toml │ ├── Config.toml │ ├── Performing Batch Operations with PostgreSQL.md │ └── batch_operation.bal ├── build.gradle ├── call-stored-procedures │ ├── .gitignore │ ├── Ballerina.toml │ ├── Calling Stored Procedures with PostgreSQL.md │ ├── Config.toml │ └── stored_procedures.bal ├── complex-queries-operation │ ├── .gitignore │ ├── Ballerina.toml │ ├── Config.toml │ ├── Performing Complex Queries with PostgreSQL.md │ └── complex_queries.bal ├── execute-operation │ ├── .gitignore │ ├── Ballerina.toml │ ├── Config.toml │ ├── Executing Queries with PostgreSQL.md │ └── execute_operation.bal ├── fraud-detection │ ├── .github │ │ └── README.md │ ├── Ballerina.toml │ ├── Fraud Detection.md │ ├── db-scripts │ │ ├── setup.sql │ │ └── test.sql │ ├── docker-compose.yml │ └── main.bal └── query-operation │ ├── .gitignore │ ├── Ballerina.toml │ ├── Config.toml │ ├── Performing Queries with PostgreSQL.md │ └── query_operation.bal ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── load-tests ├── execute_operation │ ├── deployment │ │ ├── deployment-patch.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ └── postgres_deployment.yml │ ├── results │ │ └── summary.csv │ ├── scripts │ │ ├── http-post-request.jmx │ │ └── run.sh │ └── src │ │ ├── Ballerina.toml │ │ ├── Cloud.toml │ │ ├── Config.toml │ │ └── execute_operation.bal ├── query_operation │ ├── deployment │ │ ├── deployment-patch.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ └── postgres_deployment.yml │ ├── results │ │ └── summary.csv │ ├── scripts │ │ ├── http-get-request.jmx │ │ └── run.sh │ └── src │ │ ├── Ballerina.toml │ │ ├── Cloud.toml │ │ ├── Config.toml │ │ └── query_operation.bal └── stored_procedures │ ├── deployment │ ├── deployment-patch.yaml │ ├── ingress.yaml │ ├── kustomization.yaml │ └── postgres_deployment.yml │ ├── results │ └── summary.csv │ ├── scripts │ ├── http-get-request.jmx │ └── run.sh │ └── src │ ├── Ballerina.toml │ ├── Cloud.toml │ ├── Config.toml │ └── stored_procedures.bal ├── native ├── build.gradle └── src │ └── main │ └── java │ ├── io │ └── ballerina │ │ └── stdlib │ │ └── postgresql │ │ ├── Constants.java │ │ ├── nativeimpl │ │ ├── CallProcessorUtils.java │ │ ├── ClientProcessorUtils.java │ │ ├── ExecuteProcessorUtils.java │ │ ├── OutParameterProcessorUtils.java │ │ └── QueryProcessorUtils.java │ │ ├── parameterprocessor │ │ ├── PostgresResultParameterProcessor.java │ │ ├── PostgresStatementParameterProcessor.java │ │ └── StatementParameterUtils.java │ │ └── utils │ │ ├── ConversionHelperUtils.java │ │ ├── ConverterUtils.java │ │ ├── ModuleUtils.java │ │ ├── ProcedureCallResultUtils.java │ │ ├── RecordIteratorUtils.java │ │ └── Utils.java │ └── module-info.java └── settings.gradle /.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 @aashikam @shafreenAnfar 8 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | ## Examples 4 | 5 | ## Checklist 6 | - [ ] Linked to an issue 7 | - [ ] Updated the changelog 8 | - [ ] Added tests 9 | - [ ] Updated the spec 10 | - [ ] Checked native-image compatibility 11 | -------------------------------------------------------------------------------- /.github/workflows/build-timestamped-master.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - 2201.[0-9]+.x 8 | paths-ignore: 9 | - "*.md" 10 | - "docs/**" 11 | - "load-tests/**" 12 | 13 | workflow_dispatch: 14 | 15 | jobs: 16 | call_workflow: 17 | name: Run Build Workflow 18 | if: ${{ github.repository_owner == 'ballerina-platform' }} 19 | uses: ballerina-platform/ballerina-library/.github/workflows/build-timestamp-master-template.yml@main 20 | secrets: inherit 21 | -------------------------------------------------------------------------------- /.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 | - main 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: '${{ 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/daily-build.yml: -------------------------------------------------------------------------------- 1 | name: Daily build 2 | 3 | on: 4 | workflow_dispatch: 5 | repository_dispatch: 6 | types: 7 | check_connector_for_breaking_changes 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Set up JDK 21 17 | uses: actions/setup-java@v3 18 | with: 19 | distribution: 'temurin' 20 | java-version: 21.0.3 21 | 22 | - name: Set environment variable 23 | if: github.event.action == 'check_connector_for_breaking_changes' 24 | run: | 25 | echo "BUILD_USING_DOCKER=-PbuildUsingDocker=nightly" >> $GITHUB_ENV 26 | echo "GRADLE_SKIP_TASKS=-x :postgresql-compiler-plugin-tests:test -x :postgresql-examples:build" >> $GITHUB_ENV 27 | 28 | # Build the project with Gradle 29 | - name: Build with Gradle 30 | env: 31 | packageUser: ${{ github.actor }} 32 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 33 | run: | 34 | ./gradlew clean build $GRADLE_SKIP_TASKS $BUILD_USING_DOCKER 35 | 36 | # Send notification when build fails 37 | - name: Notify failure 38 | if: ${{ failure() }} 39 | run: | 40 | eventType="notify-build-failure" 41 | 42 | if [[ "${{ github.event.action }}" == "check_connector_for_breaking_changes" ]]; then 43 | eventType="notify-ballerinax-connector-build-failure" 44 | fi 45 | 46 | curl -X POST \ 47 | 'https://api.github.com/repos/ballerina-platform/ballerina-release/dispatches' \ 48 | -H 'Accept: application/vnd.github.v3+json' \ 49 | -H 'Authorization: Bearer ${{ secrets.BALLERINA_BOT_TOKEN }}' \ 50 | --data "{ 51 | \"event_type\": \"$eventType\", 52 | \"client_payload\": { 53 | \"repoName\": \"module-ballerinax-postgresql\", 54 | \"workflow\": \"Daily build\" 55 | } 56 | }" 57 | -------------------------------------------------------------------------------- /.github/workflows/process-load-test-result.yml: -------------------------------------------------------------------------------- 1 | name: Process load test results 2 | on: 3 | repository_dispatch: 4 | types: [postgresql-load-test] 5 | 6 | jobs: 7 | call_stdlib_process_load_test_results_workflow: 8 | name: Run StdLib Process Load Test Results Workflow 9 | uses: ballerina-platform/ballerina-library/.github/workflows/process-load-test-results-template.yml@main 10 | with: 11 | results: ${{ toJson(github.event.client_payload.results) }} 12 | secrets: 13 | ballerina_bot_token: ${{ secrets.BALLERINA_BOT_TOKEN }} 14 | ballerina_reviewer_bot_token: ${{ secrets.BALLERINA_REVIEWER_BOT_TOKEN }} 15 | -------------------------------------------------------------------------------- /.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: postgresql 16 | package-org: ballerinax 17 | additional-build-flags: "-x :postgresql-examples:build" 18 | -------------------------------------------------------------------------------- /.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/trigger-load-tests.yml: -------------------------------------------------------------------------------- 1 | name: Trigger Load Tests 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | tests: 7 | description: > 8 | List of test names. This needs to be filled only if you want to run a specific set of tests. Example: foo,bar 9 | required: false 10 | clusterName: 11 | description: 'Cluster name' 12 | default: 'postgresql-perf-cluster-test' 13 | required: false 14 | branch: 15 | description: 'Branch of the given repository' 16 | default: '' 17 | required: false 18 | schedule: 19 | - cron: '0 23 * * *' 20 | 21 | jobs: 22 | call_stdlib_trigger_load_test_workflow: 23 | name: Run StdLib Load Test Workflow 24 | if: ${{ github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository_owner == 'ballerina-platform') }} 25 | uses: ballerina-platform/ballerina-library/.github/workflows/trigger-load-tests-template.yml@main 26 | with: 27 | repo_name: 'module-ballerinax-postgresql' 28 | runtime_artifacts_url: 'https://api.github.com/repos/ballerina-platform/module-ballerinax-postgresql/actions/artifacts' 29 | dispatch_type: 'postgresql-load-test' 30 | cluster_name: ${{ inputs.clusterName }} 31 | tests: ${{ inputs.tests }} 32 | branch: ${{ inputs.branch }} 33 | secrets: 34 | ballerina_bot_token: ${{ secrets.BALLERINA_BOT_TOKEN }} 35 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | 38 | # gradle 39 | .gradle 40 | build/ 41 | gradle-app.setting 42 | !gradle-wrapper.jar 43 | .gradletasknamecache 44 | 45 | # mac 46 | .DS_Store 47 | 48 | .classpath 49 | .project 50 | .settings 51 | .vscode 52 | .cache 53 | 54 | # log files 55 | **/test_log.conf 56 | **/bin 57 | 58 | # Examples 59 | examples/**/Dependencies.toml 60 | -------------------------------------------------------------------------------- /ballerina/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "ballerinax" 3 | name = "postgresql" 4 | version = "1.16.0" 5 | authors = ["Ballerina"] 6 | keywords = ["database", "client", "network", "SQL", "RDBMS", "PostgreSQL"] 7 | repository = "https://github.com/ballerina-platform/module-ballerinax-postgresql" 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 = "postgresql-native" 18 | version = "1.16.0" 19 | path = "../native/build/libs/postgresql-native-1.16.0.jar" 20 | 21 | [[platform.java21.dependency]] 22 | groupId = "io.ballerina.stdlib" 23 | artifactId = "sql-native" 24 | version = "1.16.0" 25 | path = "./lib/sql-native-1.16.0.jar" 26 | 27 | -------------------------------------------------------------------------------- /ballerina/CompilerPlugin.toml: -------------------------------------------------------------------------------- 1 | [plugin] 2 | id = "postgresql-compiler-plugin" 3 | class = "io.ballerina.stdlib.postgresql.compiler.PostgreSQLCompilerPlugin" 4 | 5 | [[dependency]] 6 | path = "../compiler-plugin/build/libs/postgresql-compiler-plugin-1.16.0.jar" 7 | -------------------------------------------------------------------------------- /ballerina/cdc_listener.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). 2 | // 3 | // WSO2 LLC. 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 | import ballerinax/cdc; 17 | 18 | # Represents the Ballerina Postgresql CDC Listener. 19 | public isolated class CdcListener { 20 | *cdc:Listener; 21 | 22 | private final map & readonly config; 23 | private boolean isStarted = false; 24 | private boolean hasAttachedService = false; 25 | 26 | # Initializes the Postgresql listener with the given configuration. 27 | # 28 | # + config - The configuration for the Postgresql connector 29 | public isolated function init(*PostgresListenerConfiguration config) { 30 | map configMap = {}; 31 | cdc:populateDebeziumProperties({ 32 | engineName: config.engineName, 33 | offsetStorage: config.offsetStorage, 34 | internalSchemaStorage: config.internalSchemaStorage, 35 | options: config.options 36 | }, configMap); 37 | cdc:populateDatabaseConfigurations({ 38 | connectorClass: config.database.connectorClass, 39 | hostname: config.database.hostname, 40 | port: config.database.port, 41 | username: config.database.username, 42 | password: config.database.password, 43 | connectTimeout: config.database.connectTimeout, 44 | tasksMax: config.database.tasksMax, 45 | secure: config.database.secure, 46 | includedTables: config.database.includedTables, 47 | excludedTables: config.database.excludedTables, 48 | includedColumns: config.database.includedColumns, 49 | excludedColumns: config.database.excludedColumns 50 | }, configMap); 51 | populatePostgresConfigurations(config.database, configMap); 52 | self.config = configMap.cloneReadOnly(); 53 | } 54 | 55 | # Attaches a CDC service to the Postgresql listener. 56 | # 57 | # + s - The CDC service to attach 58 | # + name - Attachment points 59 | # + return - An error if the service cannot be attached, or `()` if successful 60 | public isolated function attach(cdc:Service s, string[]|string? name = ()) returns cdc:Error? { 61 | check cdc:externAttach(self, s); 62 | } 63 | 64 | # Starts the Postgresql listener. 65 | # 66 | # + return - An error if the listener cannot be started, or `()` if successful 67 | public isolated function 'start() returns cdc:Error? { 68 | check cdc:externStart(self, self.config); 69 | } 70 | 71 | # Detaches a CDC service from the Postgresql listener. 72 | # 73 | # + s - The CDC service to detach 74 | # + return - An error if the service cannot be detached, or `()` if successful 75 | public isolated function detach(cdc:Service s) returns cdc:Error? { 76 | check cdc:externDetach(self, s); 77 | } 78 | 79 | # Stops the Postgresql listener gracefully. 80 | # 81 | # + return - An error if the listener cannot be stopped, or `()` if successful 82 | public isolated function gracefulStop() returns cdc:Error? { 83 | check cdc:externGracefulStop(self); 84 | } 85 | 86 | # Stops the Postgresql listener immediately. 87 | # 88 | # + return - An error if the listener cannot be stopped, or `()` if successful 89 | public isolated function immediateStop() returns cdc:Error? { 90 | check cdc:externImmediateStop(self); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /ballerina/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-postgresql/ebcb8dadb744a0920d885c789050da83c9e26050/ballerina/icon.png -------------------------------------------------------------------------------- /ballerina/init.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 | isolated function init() { 20 | setModule(); 21 | } 22 | 23 | isolated function setModule() = @java:Method { 24 | 'class: "io.ballerina.stdlib.postgresql.utils.ModuleUtils" 25 | } external; 26 | -------------------------------------------------------------------------------- /ballerina/listener_types.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). 2 | // 3 | // WSO2 LLC. 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 | import ballerinax/cdc; 17 | 18 | # Represents the PostgreSQL logical decoding plugins. 19 | # 20 | # + PGOUTPUT - The standard logical decoding output plug-in in PostgreSQL 10+ 21 | # + DECODERBUFS - A logical decoding plugin based on Protobuf and maintained by the Debezium community 22 | public enum PostgreSQLLogicalDecodingPlugin { 23 | PGOUTPUT = "pgoutput", 24 | DECODERBUFS = "decoderbufs" 25 | } 26 | 27 | # Represents the configuration for the Postgres CDC database connection. 28 | # 29 | # + connectorClass - The class name of the PostgreSQL connector implementation to use 30 | # + hostname - The hostname of the PostgreSQL server 31 | # + port - The port number of the PostgreSQL server 32 | # + databaseName - The name of the PostgreSQL database from which to stream the changes. 33 | # + includedSchemas - A list of regular expressions matching fully-qualified schema identifiers to capture changes from 34 | # + excludedSchemas - A list of regular expressions matching fully-qualified schema identifiers to exclude from change capture 35 | # + tasksMax - The PostgreSQL connector always uses a single task and therefore does not use this value, so the default is always acceptable 36 | # + pluginName - The name of the PostgreSQL logical decoding plug-in installed on the server 37 | # + slotName - The name of the PostgreSQL logical decoding slot 38 | # + publicationName - The name of the PostgreSQL publication created for streaming changes when using pgoutput. 39 | public type PostgresDatabaseConnection record {| 40 | *cdc:DatabaseConnection; 41 | string connectorClass = "io.debezium.connector.postgresql.PostgresConnector"; 42 | string hostname = "localhost"; 43 | int port = 5432; 44 | string databaseName; 45 | string|string[] includedSchemas?; 46 | string|string[] excludedSchemas?; 47 | int tasksMax = 1; 48 | PostgreSQLLogicalDecodingPlugin pluginName = PGOUTPUT; 49 | string slotName = "debezium"; 50 | string publicationName = "dbz_publication"; 51 | |}; 52 | 53 | # Represents the configuration for the Postgres CDC listener. 54 | # 55 | # + database - The Postgres database connection configuration 56 | public type PostgresListenerConfiguration record {| 57 | PostgresDatabaseConnection database; 58 | *cdc:ListenerConfiguration; 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 | [ballerina.sql] 20 | maxOpenConnections=10 21 | minIdleConnections=5 22 | -------------------------------------------------------------------------------- /ballerina/tests/constants.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 | string host = "localhost"; 18 | string user = "postgres"; 19 | string password = "postgres"; 20 | 21 | // Ports 5432, 5431, 8000, 8001 will use to connect with Docker containers 22 | int port = 5432; 23 | int limitedPort = 5431; 24 | int connectionPoolPort = 8000; 25 | int sslPort = 8001; 26 | 27 | string connectDB = "postgres"; 28 | string functionsDatabase = "postgres"; 29 | string proceduresDatabase = "postgres"; 30 | string queryComplexDatabase = "postgres"; 31 | string simpleParamsDb = "postgres"; 32 | string executeParamsDatabase = "postgres"; 33 | string executeDb = "postgres"; 34 | string basicExecuteDatabase = "postgres"; 35 | string poolDB_1 = "postgres"; 36 | string poolDB_2 = "postgres"; 37 | string batchExecuteDB = "postgres"; 38 | string sslDb = "postgres"; 39 | string errorDb = "postgres"; 40 | -------------------------------------------------------------------------------- /ballerina/tests/resources/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, WSO2 Inc. (http://wso2.com) All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM postgres 16 | 17 | RUN mkdir -p /etc/ssl 18 | COPY keystore/server/server.crt /etc/ssl/server.crt 19 | COPY keystore/server/server.key /etc/ssl/server.key 20 | COPY keystore/server/root.crt /etc/postgresql/root.crt 21 | 22 | RUN chown -R postgres /etc/ssl 23 | RUN chmod -R 0600 /etc/ssl/server.key 24 | RUN chmod -R 0777 /etc/postgresql/root.crt 25 | -------------------------------------------------------------------------------- /ballerina/tests/resources/compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | image-build: 3 | build: . 4 | image: ballerina/postgres 5 | container_name: ballerina-postgresql-build 6 | 7 | postgres: 8 | image: ballerina/postgres 9 | depends_on: 10 | - image-build 11 | container_name: ballerina-postgresql 12 | environment: 13 | POSTGRES_USER: postgres 14 | POSTGRES_PASSWORD: postgres 15 | POSTGRES_HOST_AUTH_METHOD: trust 16 | ports: 17 | - "5432:5432" 18 | volumes: 19 | - ./sql-scripts:/docker-entrypoint-initdb.d 20 | healthcheck: 21 | test: ["CMD-SHELL", "pg_isready -U postgres"] 22 | interval: 10s 23 | timeout: 5s 24 | retries: 5 25 | 26 | postgres-limited: 27 | image: ballerina/postgres 28 | depends_on: 29 | - image-build 30 | container_name: ballerina-postgresql-limited 31 | environment: 32 | POSTGRES_USER: postgres 33 | POSTGRES_PASSWORD: postgres 34 | POSTGRES_HOST_AUTH_METHOD: trust 35 | ports: 36 | - "5431:5432" 37 | volumes: 38 | - ./sql-scripts:/docker-entrypoint-initdb.d 39 | command: 40 | [ 41 | "postgres", 42 | "-N", "5" 43 | ] 44 | healthcheck: 45 | test: ["CMD-SHELL", "pg_isready -U postgres"] 46 | interval: 10s 47 | timeout: 5s 48 | retries: 5 49 | postgres-pool: 50 | image: ballerina/postgres 51 | depends_on: 52 | - image-build 53 | container_name: ballerina-postgresql-pool 54 | environment: 55 | POSTGRES_USER: postgres 56 | POSTGRES_PASSWORD: postgres 57 | POSTGRES_HOST_AUTH_METHOD: trust 58 | ports: 59 | - "8000:5432" 60 | volumes: 61 | - ./sql-scripts:/docker-entrypoint-initdb.d 62 | healthcheck: 63 | test: ["CMD-SHELL", "pg_isready -U postgres"] 64 | interval: 10s 65 | timeout: 5s 66 | retries: 5 67 | 68 | postgres-ssl: 69 | image: ballerina/postgres 70 | depends_on: 71 | - image-build 72 | container_name: ballerina-postgresql-ssl 73 | environment: 74 | POSTGRES_USER: postgres 75 | POSTGRES_PASSWORD: postgres 76 | POSTGRES_HOST_AUTH_METHOD: trust 77 | ports: 78 | - "8001:5432" 79 | volumes: 80 | - ./sql-scripts:/docker-entrypoint-initdb.d 81 | command: 82 | [ 83 | "postgres", 84 | "-c", "ssl=on", 85 | "-c", "ssl_cert_file=/etc/ssl/server.crt", 86 | "-c", "ssl_key_file=/etc/ssl/server.key", 87 | "-c", "ssl_ca_file=/etc/postgresql/root.crt" 88 | ] 89 | healthcheck: 90 | test: ["CMD-SHELL", "pg_isready -U postgres"] 91 | interval: 10s 92 | timeout: 5s 93 | retries: 5 94 | 95 | postgresql: 96 | image: postgres 97 | container_name: postgresql-cdc 98 | environment: 99 | POSTGRES_USER: "postgres" 100 | POSTGRES_PASSWORD: "root@123" 101 | POSTGRES_DB: "store_db" 102 | ports: 103 | - "5430:5432" 104 | volumes: 105 | - ./sql-scripts/09-cdc-test-data.sql:/docker-entrypoint-initdb.d/09-cdc-test-data.sql 106 | command: [ 107 | "postgres", 108 | "-c", "wal_level=logical", 109 | "-c", "max_replication_slots=10", 110 | "-c", "max_wal_senders=10" 111 | ] 112 | -------------------------------------------------------------------------------- /ballerina/tests/resources/files/byteValue.txt: -------------------------------------------------------------------------------- 1 | wso2 ballerina binary test. -------------------------------------------------------------------------------- /ballerina/tests/resources/files/emptyByteValue.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-postgresql/ebcb8dadb744a0920d885c789050da83c9e26050/ballerina/tests/resources/files/emptyByteValue.txt -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/client/postgresql.crt: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 2 (0x2) 5 | Signature Algorithm: sha256WithRSAEncryption 6 | Issuer: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pq CA 7 | Validity 8 | Not Before: Oct 11 15:10:11 2014 GMT 9 | Not After : Oct 8 15:10:11 2024 GMT 10 | Subject: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pqgosslcert 11 | Subject Public Key Info: 12 | Public Key Algorithm: rsaEncryption 13 | RSA Public Key: (1024 bit) 14 | Modulus (1024 bit): 15 | 00:e3:8c:06:9a:70:54:51:d1:34:34:83:39:cd:a2: 16 | 59:0f:05:ed:8d:d8:0e:34:d0:92:f4:09:4d:ee:8c: 17 | 78:55:49:24:f8:3c:e0:34:58:02:b2:e7:94:58:c1: 18 | e8:e5:bb:d1:af:f6:54:c1:40:b1:90:70:79:0d:35: 19 | 54:9c:8f:16:e9:c2:f0:92:e6:64:49:38:c1:76:f8: 20 | 47:66:c4:5b:4a:b6:a9:43:ce:c8:be:6c:4d:2b:94: 21 | 97:3c:55:bc:d1:d0:6e:b7:53:ae:89:5c:4b:6b:86: 22 | 40:be:c1:ae:1e:64:ce:9c:ae:87:0a:69:e5:c8:21: 23 | 12:be:ae:1d:f6:45:df:16:a7 24 | Exponent: 65537 (0x10001) 25 | X509v3 extensions: 26 | X509v3 Subject Key Identifier: 27 | 9B:25:31:63:A2:D8:06:FF:CB:E3:E9:96:FF:0D:BA:DC:12:7D:04:CF 28 | X509v3 Authority Key Identifier: 29 | keyid:52:93:ED:1E:76:0A:9F:65:4F:DE:19:66:C1:D5:22:40:35:CB:A0:72 30 | 31 | X509v3 Basic Constraints: 32 | CA:FALSE 33 | X509v3 Key Usage: 34 | Digital Signature, Non Repudiation, Key Encipherment 35 | Signature Algorithm: sha256WithRSAEncryption 36 | 3e:f5:f8:0b:4e:11:bd:00:86:1f:ce:dc:97:02:98:91:11:f5: 37 | 65:f6:f2:8a:b2:3e:47:92:05:69:28:c9:e9:b4:f7:cf:93:d1: 38 | 2d:81:5d:00:3c:23:be:da:70:ea:59:e1:2c:d3:25:49:ae:a6: 39 | 95:54:c1:10:df:23:e3:fe:d6:e4:76:c7:6b:73:ad:1b:34:7c: 40 | e2:56:cc:c0:37:ae:c5:7a:11:20:6c:3d:05:0e:99:cd:22:6c: 41 | cf:59:a1:da:28:d4:65:ba:7d:2f:2b:3d:69:6d:a6:c1:ae:57: 42 | bf:56:64:13:79:f8:48:46:65:eb:81:67:28:0b:7b:de:47:10: 43 | b3:80:3c:31:d1:58:94:01:51:4a:c7:c8:1a:01:a8:af:c4:cd: 44 | bb:84:a5:d9:8b:b4:b9:a1:64:3e:95:d9:90:1d:d5:3f:67:cc: 45 | 3b:ba:f5:b4:d1:33:77:ee:c2:d2:3e:7e:c5:66:6e:b7:35:4c: 46 | 60:57:b0:b8:be:36:c8:f3:d3:95:8c:28:4a:c9:f7:27:a4:0d: 47 | e5:96:99:eb:f5:c8:bd:f3:84:6d:ef:02:f9:8a:36:7d:6b:5f: 48 | 36:68:37:41:d9:74:ae:c6:78:2e:44:86:a1:ad:43:ca:fb:b5: 49 | 3e:ba:10:23:09:02:ac:62:d1:d0:83:c8:95:b9:e3:5e:30:ff: 50 | 5b:2b:38:fa 51 | -----BEGIN CERTIFICATE----- 52 | MIIDEzCCAfugAwIBAgIBAjANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEP 53 | MA0GA1UECBMGTmV2YWRhMRIwEAYDVQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdp 54 | dGh1Yi5jb20vbGliL3BxMQ4wDAYDVQQDEwVwcSBDQTAeFw0xNDEwMTExNTEwMTFa 55 | Fw0yNDEwMDgxNTEwMTFaMGQxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGEx 56 | EjAQBgNVBAcTCUxhcyBWZWdhczEaMBgGA1UEChMRZ2l0aHViLmNvbS9saWIvcHEx 57 | FDASBgNVBAMTC3BxZ29zc2xjZXJ0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB 58 | gQDjjAaacFRR0TQ0gznNolkPBe2N2A400JL0CU3ujHhVSST4POA0WAKy55RYwejl 59 | u9Gv9lTBQLGQcHkNNVScjxbpwvCS5mRJOMF2+EdmxFtKtqlDzsi+bE0rlJc8VbzR 60 | 0G63U66JXEtrhkC+wa4eZM6crocKaeXIIRK+rh32Rd8WpwIDAQABo1owWDAdBgNV 61 | HQ4EFgQUmyUxY6LYBv/L4+mW/w263BJ9BM8wHwYDVR0jBBgwFoAUUpPtHnYKn2VP 62 | 3hlmwdUiQDXLoHIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwDQYJKoZIhvcNAQEL 63 | BQADggEBAD71+AtOEb0Ahh/O3JcCmJER9WX28oqyPkeSBWkoyem098+T0S2BXQA8 64 | I77acOpZ4SzTJUmuppVUwRDfI+P+1uR2x2tzrRs0fOJWzMA3rsV6ESBsPQUOmc0i 65 | bM9Zodoo1GW6fS8rPWltpsGuV79WZBN5+EhGZeuBZygLe95HELOAPDHRWJQBUUrH 66 | yBoBqK/EzbuEpdmLtLmhZD6V2ZAd1T9nzDu69bTRM3fuwtI+fsVmbrc1TGBXsLi+ 67 | Nsjz05WMKErJ9yekDeWWmev1yL3zhG3vAvmKNn1rXzZoN0HZdK7GeC5EhqGtQ8r7 68 | tT66ECMJAqxi0dCDyJW5414w/1srOPo= 69 | -----END CERTIFICATE----- 70 | -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/client/postgresql.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-postgresql/ebcb8dadb744a0920d885c789050da83c9e26050/ballerina/tests/resources/keystore/client/postgresql.pfx -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/client/postgresql.pk8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-postgresql/ebcb8dadb744a0920d885c789050da83c9e26050/ballerina/tests/resources/keystore/client/postgresql.pk8 -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/server/root.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDezCCAmOgAwIBAgIUPpSaTMgdObdcGDWOSrvr/L4esmswDQYJKoZIhvcNAQEL 3 | BQAwTTELMAkGA1UEBhMCVVMxDzANBgNVBAgMBk5ldmFkYTEaMBgGA1UECgwRZ2l0 4 | aHViLmNvbS9saWIvcHExETAPBgNVBAMMCHBvc3RncmVzMB4XDTI0MTAyMjA4MjQy 5 | MFoXDTM0MTAyMDA4MjQyMFowTTELMAkGA1UEBhMCVVMxDzANBgNVBAgMBk5ldmFk 6 | YTEaMBgGA1UECgwRZ2l0aHViLmNvbS9saWIvcHExETAPBgNVBAMMCHBvc3RncmVz 7 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjh9Sdv7f+Rdnfp/A8XHe 8 | YtRLsQS/ojVwAnymyymdsQuMB7lBYDFVXVyNFgJfDJmzzpizA3JXX5i53clJBbsy 9 | WKG/e2Gr5dx+6GNshudzaID3zEbOnkLuag0kzSJCYSE4I2jMRxTghhDascxFgz9W 10 | M+LjaVpmspmY+5NiIgsXHL7jwlN/0LjetXKo8MfgEJWHUILk9N3i6pF2FVQm8kWg 11 | KxIvwU9HGOhNqWvPXXeiHR/S71vPBDf+EOecTsXHe+v4KbZzOpNxSmeCe9jL9Ixf 12 | cvYuhsK6AqXzZnA1OdIMnSc3rZng6ki58Cfxt+mI6YDgOgcTM5y5YNayUP18oPT+ 13 | 6wIDAQABo1MwUTAdBgNVHQ4EFgQUay7lol+zxKAdrx/0cedWHwY7X3swHwYDVR0j 14 | BBgwFoAUay7lol+zxKAdrx/0cedWHwY7X3swDwYDVR0TAQH/BAUwAwEB/zANBgkq 15 | hkiG9w0BAQsFAAOCAQEALinA262sTBnzMkLsufWbNBz3MsxL5uvqkXBw/cU3YKyx 16 | U98BTxRtUkoS7I+p+1Mizwzcw/Kzx+mUYcO1zSaPNVHP+lO14xekWx54h5EzOQay 17 | qjNyAXUr9NSf93X0EmBmnDi5pS5RW0svYhL6b/JIQCRWAdk2nqabyMM96dWXLZ8R 18 | WTRkdjwYTPqdJ5BiyUuOzEIv+/QtGZizLQ9X7I50lUrtGFuh/NiEy4e3aQUTc3Fk 19 | UYnuMCEAY9GqI1C/2yV4Rxx3A021GbcqbN2CdM1+GJ1hq3DIBQotijWVCPTynnYk 20 | hyPKleBkYo+yAiYDpZ7z2/qMn5F2mkb6jjdLQlys3g== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/server/server.crt: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 5 | 25:fd:19:f8:c9:7c:1f:5c:64:a2:56:82:ed:0e:26:0c:c1:28:15:9f 6 | Signature Algorithm: sha256WithRSAEncryption 7 | Issuer: C=US, ST=Nevada, O=github.com/lib/pq, CN=postgres 8 | Validity 9 | Not Before: Oct 22 08:25:30 2024 GMT 10 | Not After : Oct 20 08:25:30 2034 GMT 11 | Subject: C=US, ST=Nevada, O=github.com/lib/pq, CN=postgres 12 | Subject Public Key Info: 13 | Public Key Algorithm: rsaEncryption 14 | Public-Key: (2048 bit) 15 | Modulus: 16 | 00:a6:d7:65:14:3f:5b:51:12:93:b9:a1:d6:09:15: 17 | f4:04:bf:cf:5f:28:1b:11:d0:a7:d3:c1:89:45:a4: 18 | 47:d5:4b:8e:d6:b3:63:ef:c5:37:ba:53:0b:58:1c: 19 | 35:75:22:1e:14:f9:99:ae:6c:db:d0:5f:95:36:54: 20 | c2:23:ac:9f:7c:99:d7:89:aa:f6:ae:80:d7:8e:ef: 21 | 80:3e:4e:a9:3a:62:66:1b:89:26:77:75:7d:98:1b: 22 | 40:fc:0c:31:53:e4:d1:1c:49:8e:9c:42:91:61:44: 23 | 93:8e:73:dc:02:20:a6:10:15:c6:65:e3:be:ca:70: 24 | 67:d3:95:c6:6b:e9:c9:a3:67:10:b7:90:b7:06:de: 25 | c0:02:ae:8e:3e:00:32:f4:c8:29:0c:ac:04:0a:80: 26 | 36:05:1e:18:dc:f2:99:81:c3:54:f8:93:46:89:87: 27 | 1e:ad:5d:21:9a:42:6d:5b:b8:f8:7a:52:ff:b7:cd: 28 | 04:80:6a:48:61:69:36:ad:6a:e2:cd:2e:2b:da:a0: 29 | 25:d7:98:e1:da:be:9e:a4:3e:03:23:27:92:f0:22: 30 | ef:bc:49:d5:44:2a:0f:83:90:e8:98:21:8c:a6:ca: 31 | d1:93:84:30:6b:f8:f4:8e:0e:24:35:f9:e7:27:aa: 32 | b8:d3:1b:3a:70:5f:95:98:85:b4:25:c9:e7:5e:28: 33 | 7c:ff 34 | Exponent: 65537 (0x10001) 35 | X509v3 extensions: 36 | X509v3 Subject Key Identifier: 37 | 05:63:E5:C2:0E:7E:1A:FD:7A:79:52:37:06:57:7A:D4:C6:E8:7A:50 38 | X509v3 Authority Key Identifier: 39 | 6B:2E:E5:A2:5F:B3:C4:A0:1D:AF:1F:F4:71:E7:56:1F:06:3B:5F:7B 40 | Signature Algorithm: sha256WithRSAEncryption 41 | Signature Value: 42 | 06:40:5b:d0:d0:75:a9:e8:c9:d0:43:5e:85:fb:94:ad:06:3e: 43 | 74:87:e7:e6:15:a1:ee:d0:93:b3:ee:6d:62:a3:8a:7f:5e:6e: 44 | 2d:cd:3f:ab:ed:7a:d4:3b:74:18:56:8e:c2:a5:44:23:d1:8a: 45 | 1b:51:38:c5:9b:1c:94:a2:18:ed:a5:06:b8:2e:ba:0b:ad:34: 46 | 40:c8:8c:ed:00:33:fb:c6:3e:37:cf:10:ff:22:c4:d4:21:38: 47 | 0d:75:06:61:38:4e:df:3f:8b:30:f2:3c:96:4e:a4:79:5d:f3: 48 | 29:21:39:9d:55:73:4f:d1:34:02:22:7e:30:87:c1:65:a8:84: 49 | 3e:c6:a8:e9:9c:56:e0:71:32:fe:15:d2:e9:6a:38:4e:86:5c: 50 | 25:e2:8c:52:73:68:90:d4:a3:9c:3f:86:d9:a0:a5:6d:e8:89: 51 | ce:ce:6a:6d:4a:d8:a7:6d:ac:08:99:fa:eb:1c:78:e0:39:ef: 52 | e1:a3:29:3d:03:e4:3a:72:48:5f:48:fd:46:0a:63:fb:73:55: 53 | e2:c7:74:f9:d1:b6:41:48:9d:25:e6:d9:ca:3d:95:b1:c3:9b: 54 | fa:57:cc:03:1b:52:c8:c2:45:67:ce:26:7c:6f:50:be:96:5b: 55 | 85:4a:fa:c9:82:03:ed:b5:ed:91:0c:34:03:4d:62:e7:54:4f: 56 | cc:1c:f2:ba 57 | -----BEGIN CERTIFICATE----- 58 | MIIDajCCAlKgAwIBAgIUJf0Z+Ml8H1xkolaC7Q4mDMEoFZ8wDQYJKoZIhvcNAQEL 59 | BQAwTTELMAkGA1UEBhMCVVMxDzANBgNVBAgMBk5ldmFkYTEaMBgGA1UECgwRZ2l0 60 | aHViLmNvbS9saWIvcHExETAPBgNVBAMMCHBvc3RncmVzMB4XDTI0MTAyMjA4MjUz 61 | MFoXDTM0MTAyMDA4MjUzMFowTTELMAkGA1UEBhMCVVMxDzANBgNVBAgMBk5ldmFk 62 | YTEaMBgGA1UECgwRZ2l0aHViLmNvbS9saWIvcHExETAPBgNVBAMMCHBvc3RncmVz 63 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAptdlFD9bURKTuaHWCRX0 64 | BL/PXygbEdCn08GJRaRH1UuO1rNj78U3ulMLWBw1dSIeFPmZrmzb0F+VNlTCI6yf 65 | fJnXiar2roDXju+APk6pOmJmG4kmd3V9mBtA/AwxU+TRHEmOnEKRYUSTjnPcAiCm 66 | EBXGZeO+ynBn05XGa+nJo2cQt5C3Bt7AAq6OPgAy9MgpDKwECoA2BR4Y3PKZgcNU 67 | +JNGiYcerV0hmkJtW7j4elL/t80EgGpIYWk2rWrizS4r2qAl15jh2r6epD4DIyeS 68 | 8CLvvEnVRCoPg5DomCGMpsrRk4Qwa/j0jg4kNfnnJ6q40xs6cF+VmIW0JcnnXih8 69 | /wIDAQABo0IwQDAdBgNVHQ4EFgQUBWPlwg5+Gv16eVI3Bld61MboelAwHwYDVR0j 70 | BBgwFoAUay7lol+zxKAdrx/0cedWHwY7X3swDQYJKoZIhvcNAQELBQADggEBAAZA 71 | W9DQdanoydBDXoX7lK0GPnSH5+YVoe7Qk7PubWKjin9ebi3NP6vtetQ7dBhWjsKl 72 | RCPRihtROMWbHJSiGO2lBrguugutNEDIjO0AM/vGPjfPEP8ixNQhOA11BmE4Tt8/ 73 | izDyPJZOpHld8ykhOZ1Vc0/RNAIifjCHwWWohD7GqOmcVuBxMv4V0ulqOE6GXCXi 74 | jFJzaJDUo5w/htmgpW3oic7Oam1K2KdtrAiZ+usceOA57+GjKT0D5DpySF9I/UYK 75 | Y/tzVeLHdPnRtkFInSXm2co9lbHDm/pXzAMbUsjCRWfOJnxvUL6WW4VK+smCA+21 76 | 7ZEMNANNYudUT8wc8ro= 77 | -----END CERTIFICATE----- 78 | -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/server/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCm12UUP1tREpO5 3 | odYJFfQEv89fKBsR0KfTwYlFpEfVS47Ws2PvxTe6UwtYHDV1Ih4U+ZmubNvQX5U2 4 | VMIjrJ98mdeJqvaugNeO74A+Tqk6YmYbiSZ3dX2YG0D8DDFT5NEcSY6cQpFhRJOO 5 | c9wCIKYQFcZl477KcGfTlcZr6cmjZxC3kLcG3sACro4+ADL0yCkMrAQKgDYFHhjc 6 | 8pmBw1T4k0aJhx6tXSGaQm1buPh6Uv+3zQSAakhhaTatauLNLivaoCXXmOHavp6k 7 | PgMjJ5LwIu+8SdVEKg+DkOiYIYymytGThDBr+PSODiQ1+ecnqrjTGzpwX5WYhbQl 8 | yedeKHz/AgMBAAECggEADxTBSkc/1eA8AjeixUd6u0MrV4qkh8O4p+eCpQzogVtH 9 | Ghk1G2NUWj9PczN5kZD37yVwwteMNxWswzB+LANal0TAuuz9R2DWG1GC4h7yJRjn 10 | 6e1H0NyJ8cnk4eOoQdEZJdlwTqelxIkSXXoTlQ2mdSXCvUsM3/exKusK+I41b9On 11 | ziD5MQkjD+cyheGpFViJ4ROTMaNKp9F27mRJWI++hpqMjkq7t8YtjhfXtO48wE0p 12 | HzVdKx+ICIqd+/UQyFqumH6gRMWnDR4vR0pQfvElX99EoasOkb2rLr3r6rhGtLzq 13 | QFhzjoXmt79UB+puEpoJFeruURDIe3Ce1SgNjjN04QKBgQDQH0FWPvgVLsL1uZui 14 | 05MXRgkZrn1yi1x14GZiMwG0uf7FMsK5bwTBkMeft2M60VLc2B4up6MbDJGDl4wi 15 | hlQPua7+eCOhijgmszrjUZB46ANJ6u0OL3jK1wORKcLlY3y7s1BOaiUdSXT6/mkq 16 | dPLUj03gj+5yW4wPPSKKBwweLQKBgQDNOQhdEGZnXnQMHH+Sw/e9LfEI5w13zZYh 17 | hgCPQTn5Kfa5Tti0piZcvbVS4XEm/iLRnYtiL1lG6TYkimqPTA+RXFoLZWzJ9hFt 18 | gZ+9wUVTuME/Gc14OVPi0ddhxlheclaZXWgW8gjap2Izy0BF5r5NBIk8UYdehKmv 19 | uNIdob2vWwKBgBEtUzYsEkulRWAEhqzkq3IzTJL7DM2EZQgxkiGutghVhYp/CwVE 20 | /W6AZYlwGFeFaUJi7/LH0TVtTyE+Q8mhrpRxrdjAz6gIgWPoTQbv922TMJpMMm6G 21 | SoDrSBcWDEjkcioHvawLJK8LHgWNM97WMiiK/1F2b6aumZu0XwJnXH+tAoGAcEOR 22 | wq81BbkSzIlOdHAFdxTJtXAH2xC43w/aAIPS/e2pzUdHntMBS1xv863l40nErFx9 23 | ojF6qiLrfmPF1SvrnD4j9/X85CJa+EefpgMzNJBuDmHEF89shzj5lMAXGVt86hrB 24 | 1UOD+nD0dJbsSxDl62Xe2QNUhS0XUkxNjO4swN8CgYBOixd2ma5fqHFf5uDaVcCY 25 | ZR7CWl6r/3fpLsJlIpO4r2m52t2oY4MAlZou8sHNiBYXmy3SpadRFZPDFyctD+Kf 26 | 7AwDB8125xpR2qSX/eqSK+kxWvDdCJLW0AW9W5l4beMNaa1r1LMXeLoubEXAI8Tg 27 | ylNcRTGySe451qsKdozK7Q== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/01-database-init-script.sql: -------------------------------------------------------------------------------- 1 | CREATE TYPE complex AS 2 | ( 3 | r numeric, i decimal 4 | ) 5 | ; 6 | CREATE TYPE inventory_item AS 7 | ( 8 | name text, supplierId integer, isExpired boolean 9 | ) 10 | ; 11 | CREATE TYPE value AS ENUM ('value1', 'value2', 'value3'); 12 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/03-connection-pool1-test.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS Customers; 2 | CREATE TABLE IF NOT EXISTS Customers( customerId SERIAL, firstName VARCHAR(300), lastName VARCHAR(300), registrationID INTEGER, creditLimit DOUBLE PRECISION, country VARCHAR(300), PRIMARY KEY (customerId) ); 3 | INSERT INTO 4 | Customers (firstName, lastName, registrationID, creditLimit, country) 5 | VALUES 6 | ( 7 | 'Peter', 'Stuart', 1, 5000.75, 'USA' 8 | ) 9 | ; 10 | INSERT INTO 11 | Customers (firstName, lastName, registrationID, creditLimit, country) 12 | VALUES 13 | ( 14 | 'Dan', 'Brown', 2, 10000, 'UK' 15 | ) 16 | ; 17 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/04-connection-pool2-test.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS Customers; 2 | CREATE TABLE IF NOT EXISTS Customers( customerId SERIAL, firstName VARCHAR(300), lastName VARCHAR(300), registrationID INTEGER, creditLimit DOUBLE PRECISION, country VARCHAR(300), PRIMARY KEY (customerId) ); 3 | INSERT INTO 4 | Customers (firstName, lastName, registrationID, creditLimit, country) 5 | VALUES 6 | ( 7 | 'Peter', 'Stuart', 1, 5000.75, 'USA' 8 | ) 9 | ; 10 | INSERT INTO 11 | Customers (firstName, lastName, registrationID, creditLimit, country) 12 | VALUES 13 | ( 14 | 'Dan', 'Brown', 2, 10000, 'UK' 15 | ) 16 | ; 17 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/05-local-transaction-test.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS Customers( 2 | customerId SERIAL, 3 | firstName VARCHAR(300), 4 | lastName VARCHAR(300), 5 | registrationID INTEGER, 6 | creditLimit DOUBLE PRECISION, 7 | country VARCHAR(300), 8 | PRIMARY KEY (customerId) 9 | ); 10 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/08-error-test-data.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS DataTable; 2 | 3 | CREATE TABLE IF NOT EXISTS DataTable( 4 | row_id INTEGER, 5 | string_type VARCHAR(50), 6 | PRIMARY KEY (row_id) 7 | ); 8 | 9 | INSERT INTO DataTable (row_id, string_type) VALUES(1, '{""q}'); 10 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/09-cdc-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE vendors ( 2 | id INT PRIMARY KEY, 3 | name VARCHAR(255), 4 | contact_info TEXT 5 | ); 6 | 7 | INSERT INTO vendors VALUES 8 | (1, 'Samsung', 'contact@samsung.com'), 9 | (2, 'Apple', 'contact@apple.com'); 10 | 11 | CREATE TABLE products ( 12 | id INT PRIMARY KEY, 13 | name VARCHAR(255), 14 | price DECIMAL(10,2), 15 | description TEXT, 16 | vendor_id INT, 17 | FOREIGN KEY (vendor_id) REFERENCES vendors(id) 18 | ); 19 | 20 | INSERT INTO products VALUES 21 | (1001, 'Samsung Galaxy S24', 999.99, 'Flagship phone with AI camera', 1), 22 | (1002, 'Apple iPhone 15 Pro', 1099.00, 'New titanium design', 2); 23 | 24 | ALTER TABLE vendors REPLICA IDENTITY FULL; 25 | ALTER TABLE products REPLICA IDENTITY FULL; 26 | -------------------------------------------------------------------------------- /ballerina/tests/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 | import ballerina/io; 18 | import ballerinax/postgresql.driver as _; 19 | 20 | isolated function getByteaColumnChannel() returns io:ReadableByteChannel|error { 21 | io:ReadableByteChannel byteChannel = check io:openReadableFile("./tests/resources/files/byteValue.txt"); 22 | return byteChannel; 23 | } 24 | 25 | isolated function getByteaColumnChannel2() returns io:ReadableByteChannel|error { 26 | io:ReadableByteChannel byteChannel = check io:openReadableFile("./tests/resources/files/emptyByteValue.txt"); 27 | return byteChannel; 28 | } 29 | -------------------------------------------------------------------------------- /ballerina/utils.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). 2 | // 3 | // WSO2 LLC. 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 | const string SCHEMA_INCLUDE_LIST = "schema.include.list"; 17 | const string SCHEMA_EXCLUDE_LIST = "schema.exclude.list"; 18 | 19 | const string POSTGRESQL_DATABASE_NAME = "database.dbname"; 20 | const string POSTGRESQL_PLUGIN_NAME = "plugin.name"; 21 | const string POSTGRESQL_SLOT_NAME = "slot.name"; 22 | const string POSTGRESQL_PUBLICATION_NAME = "publication.name"; 23 | 24 | 25 | // Populates PostgreSQL-specific configurations 26 | isolated function populatePostgresConfigurations(PostgresDatabaseConnection connection, map configMap) { 27 | configMap[POSTGRESQL_DATABASE_NAME] = connection.databaseName; 28 | populateSchemaConfigurations(connection, configMap); 29 | configMap[POSTGRESQL_PLUGIN_NAME] = connection.pluginName; 30 | configMap[POSTGRESQL_SLOT_NAME] = connection.slotName; 31 | configMap[POSTGRESQL_PUBLICATION_NAME] = connection.publicationName; 32 | } 33 | 34 | // Populates schema inclusion/exclusion configurations 35 | isolated function populateSchemaConfigurations(PostgresDatabaseConnection connection, map configMap) { 36 | string|string[]? includedSchemas = connection.includedSchemas; 37 | if includedSchemas !is () { 38 | configMap[SCHEMA_INCLUDE_LIST] = includedSchemas is string ? includedSchemas : string:'join(",", ...includedSchemas); 39 | } 40 | 41 | string|string[]? excludedSchemas = connection.excludedSchemas; 42 | if excludedSchemas !is () { 43 | configMap[SCHEMA_EXCLUDE_LIST] = excludedSchemas is string ? excludedSchemas : string:'join(",", ...excludedSchemas); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /build-config/checkstyle/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 "de.undercouch.download" 20 | } 21 | 22 | apply plugin: 'java-library' 23 | 24 | task downloadCheckstyleRuleFiles(type: Download) { 25 | src([ 26 | 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/checkstyle.xml', 27 | 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/suppressions.xml' 28 | ]) 29 | overwrite false 30 | onlyIfNewer true 31 | dest buildDir 32 | } 33 | 34 | jar { 35 | enabled = false 36 | } 37 | 38 | clean { 39 | enabled = false 40 | } 41 | 42 | artifacts.add('default', file("$project.buildDir/checkstyle.xml")) { 43 | builtBy('downloadCheckstyleRuleFiles') 44 | } 45 | 46 | artifacts.add('default', file("$project.buildDir/suppressions.xml")) { 47 | builtBy('downloadCheckstyleRuleFiles') 48 | } 49 | -------------------------------------------------------------------------------- /build-config/resources/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "ballerinax" 3 | name = "postgresql" 4 | version = "@toml.version@" 5 | authors = ["Ballerina"] 6 | keywords = ["database", "client", "network", "SQL", "RDBMS", "PostgreSQL"] 7 | repository = "https://github.com/ballerina-platform/module-ballerinax-postgresql" 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 = "postgresql-native" 18 | version = "@toml.version@" 19 | path = "../native/build/libs/postgresql-native-@project.version@.jar" 20 | 21 | [[platform.java21.dependency]] 22 | groupId = "io.ballerina.stdlib" 23 | artifactId = "sql-native" 24 | version = "@sql.version@" 25 | path = "./lib/sql-native-@sql.native.version@.jar" 26 | 27 | -------------------------------------------------------------------------------- /build-config/resources/CompilerPlugin.toml: -------------------------------------------------------------------------------- 1 | [plugin] 2 | id = "postgresql-compiler-plugin" 3 | class = "io.ballerina.stdlib.postgresql.compiler.PostgreSQLCompilerPlugin" 4 | 5 | [[dependency]] 6 | path = "../compiler-plugin/build/libs/postgresql-compiler-plugin-@project.version@.jar" 7 | -------------------------------------------------------------------------------- /build-config/resources/ExamplesBallerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql" 3 | name = "@example.name@" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /build-config/spotbugs-exclude.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /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 "com.github.spotbugs-base" 20 | id "com.github.johnrengelman.shadow" 21 | id "de.undercouch.download" 22 | id "net.researchgate.release" 23 | } 24 | 25 | description = 'Ballerina - PostgreSQL' 26 | 27 | def packageName = "postgresql" 28 | 29 | ext.ballerinaLangVersion = project.ballerinaLangVersion 30 | 31 | allprojects { 32 | group = project.group 33 | version = project.version 34 | 35 | apply plugin: 'jacoco' 36 | apply plugin: 'maven-publish' 37 | 38 | repositories { 39 | mavenLocal() 40 | maven { 41 | url = 'https://maven.wso2.org/nexus/content/repositories/releases/' 42 | } 43 | 44 | maven { 45 | url = 'https://maven.wso2.org/nexus/content/groups/wso2-public/' 46 | } 47 | 48 | maven { 49 | url = 'https://repo.maven.apache.org/maven2' 50 | } 51 | 52 | maven { 53 | url = 'https://maven.pkg.github.com/ballerina-platform/*' 54 | credentials { 55 | username System.getenv("packageUser") 56 | password System.getenv("packagePAT") 57 | } 58 | } 59 | } 60 | 61 | ext { 62 | snapshotVersion= '-SNAPSHOT' 63 | timestampedVersionRegex = '.*-\\d{8}-\\d{6}-\\w.*\$' 64 | } 65 | } 66 | 67 | subprojects { 68 | 69 | configurations { 70 | externalJars 71 | ballerinaStdLibs 72 | jbalTools 73 | } 74 | 75 | dependencies { 76 | jbalTools ("org.ballerinalang:jballerina-tools:${ballerinaLangVersion}") { 77 | transitive = false 78 | } 79 | ballerinaStdLibs "io.ballerina.stdlib:sql-ballerina:${stdlibSqlVersion}" 80 | ballerinaStdLibs "io.ballerina.stdlib:io-ballerina:${stdlibIoVersion}" 81 | ballerinaStdLibs "io.ballerina.stdlib:constraint-ballerina:${stdlibConstraintVersion}" 82 | ballerinaStdLibs "io.ballerina.stdlib:time-ballerina:${stdlibTimeVersion}" 83 | ballerinaStdLibs "io.ballerina.stdlib:os-ballerina:${stdlibOsVersion}" 84 | ballerinaStdLibs "io.ballerina.stdlib:crypto-ballerina:${stdlibCryptoVersion}" 85 | ballerinaStdLibs "io.ballerina.stdlib:log-ballerina:${stdlibLogVersion}" 86 | ballerinaStdLibs "io.ballerina.stdlib:file-ballerina:${stdlibFileVersion}" 87 | 88 | ballerinaStdLibs "org.ballerinalang:transaction-ballerina:${stdlibTransactionVersion}" 89 | ballerinaStdLibs "io.ballerina.stdlib:task-ballerina:${stdlibTaskVersion}" 90 | ballerinaStdLibs "io.ballerina.stdlib:uuid-ballerina:${stdlibUuidVersion}" 91 | ballerinaStdLibs "io.ballerina.stdlib:mime-ballerina:${stdlibMimeVersion}" 92 | ballerinaStdLibs "io.ballerina.stdlib:cache-ballerina:${stdlibCacheVersion}" 93 | ballerinaStdLibs "io.ballerina.stdlib:auth-ballerina:${stdlibAuthVersion}" 94 | ballerinaStdLibs "io.ballerina.stdlib:jwt-ballerina:${stdlibJwtVersion}" 95 | ballerinaStdLibs "io.ballerina.stdlib:oauth2-ballerina:${stdlibOAuth2Version}" 96 | ballerinaStdLibs "io.ballerina.lib:data.jsondata-ballerina:${stdlibDataJsonDataVersion}" 97 | ballerinaStdLibs "io.ballerina.stdlib:url-ballerina:${stdlibUrlVersion}" 98 | ballerinaStdLibs "io.ballerina.stdlib:http-ballerina:${stdlibHttpVersion}" 99 | ballerinaStdLibs "io.ballerina.stdlib:observe-ballerina:${observeVersion}" 100 | ballerinaStdLibs "io.ballerina:observe-ballerina:${observeInternalVersion}" 101 | ballerinaStdLibs "io.ballerina.stdlib:postgresql.driver-ballerina:${stdlibPostgresqlDriverVersion}" 102 | 103 | ballerinaStdLibs "io.ballerina.lib:cdc-ballerina:${stdlibCdcVersion}" 104 | ballerinaStdLibs "io.ballerina.lib:postgresql.cdc.driver-ballerina:${stdlibPostgresCdcDriverVersion}" 105 | } 106 | } 107 | 108 | def moduleVersion = project.version.replace("-SNAPSHOT", "") 109 | 110 | release { 111 | failOnPublishNeeded = false 112 | failOnSnapshotDependencies = true 113 | 114 | buildTasks = ['build'] 115 | versionPropertyFile = 'gradle.properties' 116 | tagTemplate = 'v$version' 117 | 118 | git { 119 | requireBranch = "release-${moduleVersion}" 120 | pushToRemote = 'origin' 121 | } 122 | } 123 | 124 | task build { 125 | dependsOn("${packageName}-native:build") 126 | dependsOn("${packageName}-compiler-plugin:build") 127 | dependsOn("${packageName}-ballerina:build") 128 | dependsOn("${packageName}-compiler-plugin-tests:build") 129 | dependsOn("${packageName}-examples:build") 130 | } 131 | 132 | publishToMavenLocal.dependsOn build 133 | publish.dependsOn build 134 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | This file contains all the notable changes done to the Ballerina postgresql package through the releases. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ### Added 10 | - [Provide a way to set the current schema when initializing the db connection](https://github.com/ballerina-platform/ballerina-library/issues/7517) 11 | 12 | ## [1.13.2] - 2024-11-11 13 | 14 | ### Added 15 | - [Allow prepareThreshold, preparedStatementCacheQueries and preparedStatementCacheSizeMiB to pass 0 values](https://github.com/ballerina-platform/ballerina-standard-library/issues/7345) 16 | 17 | ## [1.10.0] - 2023-06-30 18 | 19 | ### Added 20 | - [Add compiler plugin validation to validate spread-field config initialization](https://github.com/ballerina-platform/ballerina-standard-library/issues/4594) 21 | 22 | ### Changed 23 | - [Support retrieval of enum types](https://github.com/ballerina-platform/ballerina-standard-library/issues/4588) 24 | 25 | ## [1.7.0] - 2023-02-20 26 | 27 | ### Changed 28 | - [Remove SQL_901 diagnostic hint](https://github.com/ballerina-platform/ballerina-standard-library/issues/3609) 29 | - [Enable non-Hikari logs](https://github.com/ballerina-platform/ballerina-standard-library/issues/3763) 30 | - [Improve API docs based on Best practices](https://github.com/ballerina-platform/ballerina-standard-library/issues/3857) 31 | 32 | ## [1.6.2] - 2023-02-09 33 | 34 | ### Changed 35 | - [Improve API docs based on Best practices](https://github.com/ballerina-platform/ballerina-standard-library/issues/3857) 36 | - [Fix compiler plugin failure when the diagnostic code is null](https://github.com/ballerina-platform/ballerina-standard-library/issues/4054) 37 | 38 | ## [1.6.1] - 2022-12-01 39 | 40 | ### Changed 41 | - [Updated API Docs on `posgresql.driver` usages](https://github.com/ballerina-platform/ballerina-standard-library/issues/3710) 42 | 43 | ## [1.6.0] - 2022-11-29 44 | 45 | ### Changed 46 | - [Updated API Docs](https://github.com/ballerina-platform/ballerina-standard-library/issues/3463) 47 | 48 | ## [1.5.0] - 2022-09-08 49 | 50 | ### Changed 51 | - [Change default username for client initialization to `postgres`](https://github.com/ballerina-platform/ballerina-standard-library/issues/2397) 52 | 53 | ## [1.4.1] - 2022-06-27 54 | 55 | ### Changed 56 | - [Fix NullPointerException when retrieving record with default value](https://github.com/ballerina-platform/ballerina-standard-library/issues/2985) 57 | 58 | ## [1.4.0] - 2022-05-30 59 | 60 | ### Added 61 | - [Improve DB columns to Ballerina record Mapping through Annotation](https://github.com/ballerina-platform/ballerina-standard-library/issues/2652) 62 | 63 | ### Changed 64 | - [Fixed compiler plugin validation for `time` module constructs](https://github.com/ballerina-platform/ballerina-standard-library/issues/2893) 65 | - [Fix incorrect code snippet in SQL api docs](https://github.com/ballerina-platform/ballerina-standard-library/issues/2931) 66 | 67 | ## [1.3.1] - 2022-03-01 68 | 69 | ### Changed 70 | - [Improve API documentation to reflect query usages](https://github.com/ballerina-platform/ballerina-standard-library/issues/2524) 71 | 72 | ## [1.3.0] - 2022-01-29 73 | 74 | ### Changed 75 | - [Fix Compiler plugin crash when variable is passed for `sql:ConnectionPool` and `postgresql:Options`](https://github.com/ballerina-platform/ballerina-standard-library/issues/2536) 76 | 77 | ## [1.2.1] - 2022-02-03 78 | 79 | ### Changed 80 | - [Fix Compiler plugin crash when variable is passed for `sql:ConnectionPool` and `postgresql:Options`](https://github.com/ballerina-platform/ballerina-standard-library/issues/2536) 81 | 82 | ## [1.2.0] - 2021-12-13 83 | 84 | ### Added 85 | - [Tooling support for Postgresql module](https://github.com/ballerina-platform/ballerina-standard-library/issues/2281) 86 | 87 | ## [1.1.0] - 2021-11-20 88 | 89 | ### Changed 90 | - [Change queryRow return type to anydata](https://github.com/ballerina-platform/ballerina-standard-library/issues/2390) 91 | - [Make OutParameter get function parameter optional](https://github.com/ballerina-platform/ballerina-standard-library/issues/2388) 92 | 93 | ## [1.0.0] - 2021-10-09 94 | 95 | ### Changed 96 | - [Improve inout parameter which supports array types for call procedure](https://github.com/ballerina-platform/ballerina-standard-library/issues/1516) 97 | - [Add completion type as nil in SQL query return stream type](https://github.com/ballerina-platform/ballerina-standard-library/issues/1654) 98 | 99 | ### Added 100 | - [Add support for queryRow](https://github.com/ballerina-platform/ballerina-standard-library/issues/1604) 101 | - [Remove support for string parameter in APIs](https://github.com/ballerina-platform/ballerina-standard-library/issues/2010) 102 | 103 | [0.6.0-beta.2] - 2021-06-02 104 | 105 | ### Added 106 | - Basic CRUD functionalities with an PostgreSQL database. 107 | - Insert functionality for PostgreSQL specific data types. 108 | - Select functionality for PostgreSQL specific data types. 109 | - Procedure and Function Operations for PostgreSQL specific data types. 110 | - Add array data types. 111 | - Make the Client class to isolated. 112 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | precision: 2 3 | round: down 4 | range: "60...80" 5 | status: 6 | project: 7 | default: 8 | target: 80 9 | -------------------------------------------------------------------------------- /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-library' 21 | id 'checkstyle' 22 | id 'com.github.spotbugs' 23 | id 'jacoco' 24 | } 25 | 26 | description = 'Ballerina - PostgreSQL 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:0.8.10:runtime" 37 | 38 | implementation project(':postgresql-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 | test { 54 | systemProperty "ballerina.offline.flag", "true" 55 | useTestNG() { 56 | suites 'src/test/resources/testng.xml' 57 | } 58 | testLogging.showStandardStreams = true 59 | testLogging { 60 | events "PASSED", "FAILED", "SKIPPED" 61 | afterSuite { desc, result -> 62 | if (!desc.parent) { // will match the outermost suite 63 | def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" 64 | def startItem = '| ', endItem = ' |' 65 | def repeatLength = startItem.length() + output.length() + endItem.length() 66 | println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) 67 | } 68 | } 69 | } 70 | finalizedBy jacocoTestReport 71 | } 72 | 73 | jacocoTestReport { 74 | dependsOn test 75 | reports { 76 | xml.required = true 77 | } 78 | sourceSets project(':postgresql-compiler-plugin').sourceSets.main 79 | } 80 | 81 | spotbugsTest { 82 | def classLoader = plugins["com.github.spotbugs"].class.classLoader 83 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") 84 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") 85 | effort = SpotBugsEffort.MAX 86 | reportLevel = SpotBugsConfidence.LOW 87 | ignoreFailures = true 88 | reportsDir = file("$project.buildDir/reports/spotbugs") 89 | def excludeFile = file("${rootDir}/build-config/spotbugs-exclude.xml") 90 | if (excludeFile.exists()) { 91 | it.excludeFilter = excludeFile 92 | } 93 | reports { 94 | text.enabled = true 95 | } 96 | } 97 | 98 | spotbugsMain { 99 | enabled false 100 | } 101 | 102 | task validateSpotbugs() { 103 | doLast { 104 | if (spotbugsMain.reports.size() > 0 && 105 | spotbugsMain.reports[0].destination.exists() && 106 | spotbugsMain.reports[0].destination.text.readLines().size() > 0) { 107 | spotbugsMain.reports[0].destination?.eachLine { 108 | println 'Failure: ' + it 109 | } 110 | throw new GradleException("Spotbugs rule violations were found."); 111 | } 112 | } 113 | } 114 | 115 | tasks.withType(Checkstyle) { 116 | exclude '**/module-info.java' 117 | } 118 | 119 | checkstyle { 120 | toolVersion "${project.checkstylePluginVersion}" 121 | configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml") 122 | configProperties = ["suppressionFile": file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] 123 | } 124 | 125 | checkstyleMain { 126 | enabled false 127 | } 128 | 129 | spotbugsTest.finalizedBy validateSpotbugs 130 | checkstyleTest.dependsOn ':checkstyle:downloadCheckstyleRuleFiles' 131 | 132 | compileJava { 133 | doFirst { 134 | options.compilerArgs = [ 135 | '--module-path', classpath.asPath, 136 | ] 137 | classpath = files() 138 | } 139 | } 140 | 141 | test.dependsOn ":postgresql-ballerina:build" 142 | build.dependsOn ":postgresql-ballerina:build" 143 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample1/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql_test" 3 | name = "sample1" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample1/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). All Rights Reserved. 2 | // 3 | // This software is the property of WSO2 LLC. and its suppliers, if any. 4 | // Dissemination of any information or reproduction of any material contained 5 | // herein in any form is strictly forbidden, unless permitted by WSO2 expressly. 6 | // You may not alter or remove any copyright or other notice from copies of this content. 7 | 8 | import ballerinax/postgresql; 9 | import ballerinax/postgresql.driver as _; 10 | 11 | # sql:ConnectionPool parameter record with default optimized values 12 | # 13 | # + maxOpenConnections - The maximum open connections 14 | # + maxConnectionLifeTime - The maximum lifetime of a connection 15 | # + minIdleConnections - The minimum idle time of a connection 16 | type SqlConnectionPoolConfig record {| 17 | int maxOpenConnections = -10; 18 | decimal maxConnectionLifeTime = -180; 19 | int minIdleConnections = -5; 20 | |}; 21 | 22 | # mysql:Options parameter record with default optimized values 23 | # 24 | # + connectTimeout - Timeout to be used when establishing a connection 25 | type MysqlOptionsConfig record {| 26 | decimal connectTimeout = 10; 27 | |}; 28 | 29 | # [Configurable] Allocation MySQL Database 30 | # 31 | # + hostname - database hostname 32 | # + username - database username 33 | # + password - database password 34 | # + database - database name 35 | # + port - database port 36 | # + connectionPool - sql:ConnectionPool configurations, type: SqlConnectionPoolConfig 37 | # + mysqlOptions - mysql:Options configurations, type: MysqlOptionsConfig 38 | type AllocationDatabase record {| 39 | string hostname; 40 | string username; 41 | string password; 42 | string database; 43 | int port = 3306; 44 | SqlConnectionPoolConfig connectionPool; 45 | MysqlOptionsConfig mysqlOptions; 46 | |}; 47 | 48 | configurable AllocationDatabase allocationDatabase = ?; 49 | 50 | final postgresql:Client allocationDbClient = check new ( 51 | host = allocationDatabase.hostname, 52 | username = allocationDatabase.username, 53 | password = allocationDatabase.password, 54 | port = allocationDatabase.port, 55 | database = allocationDatabase.database, 56 | connectionPool = { 57 | ...allocationDatabase.connectionPool 58 | }, 59 | options = { 60 | ssl: { 61 | mode: postgresql:PREFER 62 | }, 63 | connectTimeout: allocationDatabase.mysqlOptions.connectTimeout 64 | } 65 | ); 66 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample2/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql_test" 3 | name = "sample2" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample2/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 ballerinax/postgresql; 18 | 19 | postgresql:Client dbClient = check new postgresql:Client("url", (), (), (), 120, { loginTimeout: -2 }, { maxOpenConnections: -1 }); 20 | 21 | public function main() returns error? { 22 | 23 | postgresql:Client dbClient1 = check new("url", connectionPool = { maxOpenConnections: -1 }); 24 | check dbClient1.close(); 25 | 26 | postgresql:Client dbClient2 = check new("url", options = { loginTimeout: -2 }); 27 | check dbClient2.close(); 28 | 29 | postgresql:Client dbClient3 = check new("url", (), (), (), 120, { loginTimeout: -2 }); 30 | check dbClient3.close(); 31 | } 32 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample3/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql_test" 3 | name = "sample3" 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 ballerinax/postgresql; 18 | 19 | public function main() { 20 | 21 | int id = 5; 22 | 23 | int|postgresql:Options pool1 = 5; 24 | 25 | int|postgresql:Options pool2 = { 26 | loginTimeout: -2, 27 | socketTimeout: -3 28 | }; 29 | 30 | postgresql:Options|int pool3 = { 31 | loginTimeout: -2, 32 | socketTimeout: -3 33 | }; 34 | 35 | postgresql:Options pool4 = { 36 | ssl: { 37 | mode: "PREFER" 38 | }, 39 | connectTimeout: -1, 40 | socketTimeout: -1, 41 | loginTimeout: -1, 42 | cancelSignalTimeout: -1, 43 | rowFetchSize: 0, 44 | cachedMetadataFieldsCount: -1, 45 | cachedMetadataFieldSize: -1, 46 | preparedStatementThreshold: -1, 47 | preparedStatementCacheQueries: -1, 48 | preparedStatementCacheSize: -1 49 | }; 50 | 51 | postgresql:Options pool5 = { 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample4/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql_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 ballerinax/postgresql; 18 | 19 | public function main() returns error? { 20 | postgresql:InetOutParameter inetOut = new(); 21 | string inetVal = check inetOut.get(string); 22 | int intVal = check inetOut.get(int); 23 | 24 | postgresql:CircleOutParameter circleOut = new(); 25 | intVal = check circleOut.get(int); 26 | 27 | postgresql:JsonOutParameter jsonOut = new(); 28 | intVal = check jsonOut.get(int); 29 | 30 | postgresql:PGXmlOutParameter xmlOut = new(); 31 | intVal = check xmlOut.get(int); 32 | } 33 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample6/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql_test" 3 | name = "sample6" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample6/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 ballerinax/postgresql; 18 | 19 | public function main() returns error? { 20 | 21 | decimal loginTimeout = 5; 22 | decimal loginTimeoutInvalid = -5; 23 | 24 | postgresql:Options options1 = { 25 | loginTimeout: loginTimeout 26 | }; 27 | 28 | postgresql:Options options2 = { 29 | loginTimeout: loginTimeoutInvalid 30 | }; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /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-library' 21 | id 'checkstyle' 22 | id 'com.github.spotbugs' 23 | } 24 | 25 | description = 'Ballerina - PostgreSQL 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/postgresql/compiler/PostgreSQLCodeAnalyzer.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.postgresql.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.postgresql.compiler.analyzer.InitializerParamAnalyzer; 25 | import io.ballerina.stdlib.postgresql.compiler.analyzer.MethodAnalyzer; 26 | import io.ballerina.stdlib.postgresql.compiler.analyzer.RecordAnalyzer; 27 | 28 | import java.util.List; 29 | 30 | /** 31 | * PostgreSQL Code Analyzer. 32 | */ 33 | public class PostgreSQLCodeAnalyzer extends CodeAnalyzer { 34 | 35 | @Override 36 | public void init(CodeAnalysisContext ctx) { 37 | ctx.addSyntaxNodeAnalysisTask(new InitializerParamAnalyzer(), 38 | List.of(SyntaxKind.IMPLICIT_NEW_EXPRESSION, SyntaxKind.EXPLICIT_NEW_EXPRESSION)); 39 | ctx.addSyntaxNodeAnalysisTask(new RecordAnalyzer(), 40 | List.of(SyntaxKind.LOCAL_VAR_DECL, SyntaxKind.MODULE_VAR_DECL)); 41 | ctx.addSyntaxNodeAnalysisTask(new MethodAnalyzer(), SyntaxKind.METHOD_CALL); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/postgresql/compiler/PostgreSQLCompilerPlugin.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.postgresql.compiler; 20 | 21 | import io.ballerina.projects.plugins.CompilerPlugin; 22 | import io.ballerina.projects.plugins.CompilerPluginContext; 23 | 24 | /** 25 | * Compiler plugin for JDBC client. 26 | */ 27 | public class PostgreSQLCompilerPlugin extends CompilerPlugin { 28 | @Override 29 | public void init(CompilerPluginContext compilerPluginContext) { 30 | compilerPluginContext.addCodeAnalyzer(new PostgreSQLCodeAnalyzer()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/postgresql/compiler/PostgreSQLDiagnosticsCode.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.postgresql.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 JDBC module diagnostic codes. 26 | */ 27 | public enum PostgreSQLDiagnosticsCode { 28 | 29 | //SQL ConnectionPool Validations at init 30 | // todo See if this can be taken from the dependency. 31 | SQL_101("SQL_101", "invalid value: expected value is greater than one", ERROR), 32 | SQL_102("SQL_102", "invalid value: expected value is greater than zero", ERROR), 33 | SQL_103("SQL_103", "invalid value: expected value is greater than or equal to 30", ERROR), 34 | 35 | POSTGRESQL_101("POSTGRESQL_101", "invalid value: expected value is greater than or equal to zero", ERROR), 36 | POSTGRESQL_102("POSTGRESQL_102", "invalid value: expected value is greater than zero", ERROR), 37 | 38 | // Out parameter return type validations diagnostics 39 | POSTGRESQL_201("POSTGRESQL_201", "invalid value: expected value is string", ERROR), 40 | POSTGRESQL_202("POSTGRESQL_202", "invalid value: expected value is either record or string", ERROR), 41 | POSTGRESQL_203("POSTGRESQL_203", "invalid value: expected value is either json or string", ERROR), 42 | POSTGRESQL_204("POSTGRESQL_204", "invalid value: expected value is either xml or string", ERROR); 43 | 44 | 45 | private final String code; 46 | private final String message; 47 | private final DiagnosticSeverity severity; 48 | 49 | PostgreSQLDiagnosticsCode(String code, String message, DiagnosticSeverity severity) { 50 | this.code = code; 51 | this.message = message; 52 | this.severity = severity; 53 | } 54 | 55 | public String getCode() { 56 | return code; 57 | } 58 | 59 | public String getMessage() { 60 | return message; 61 | } 62 | 63 | public DiagnosticSeverity getSeverity() { 64 | return severity; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/postgresql/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.postgresql.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.postgresql.compiler.Constants; 33 | import io.ballerina.stdlib.postgresql.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.BALLERINAX) 66 | && module.id().moduleName().equals(Constants.POSTGRESQL))) { 67 | return; 68 | } 69 | String objectName = ((TypeReferenceTypeSymbol) methodExpReferenceType.get()).definition().getName().get(); 70 | 71 | // Filter by method name, only OutParameter objects have get method 72 | Optional methodSymbol = ctx.semanticModel().symbol(node.methodName()); 73 | if (methodSymbol.isEmpty()) { 74 | return; 75 | } 76 | Optional methodName = methodSymbol.get().getName(); 77 | if (methodName.isEmpty()) { 78 | return; 79 | } 80 | if (!methodName.get().equals(Constants.OutParameter.METHOD_NAME)) { 81 | return; 82 | } 83 | 84 | // Filter by parameters length 85 | SeparatedNodeList arguments = node.arguments(); 86 | if (arguments.size() != 1) { 87 | return; 88 | } 89 | Optional typeDescriptionArgument = ctx.semanticModel().symbol(node.arguments().get(0)); 90 | if (typeDescriptionArgument.isEmpty()) { 91 | return; 92 | } 93 | TypeSymbol argumentTypeSymbol = ((TypeSymbol) typeDescriptionArgument.get()); 94 | TypeDescKind argTypeKind = argumentTypeSymbol.typeKind(); 95 | DiagnosticInfo diagnosticsForInvalidTypes = Utils.addDiagnosticsForInvalidTypes(objectName, argTypeKind); 96 | if (diagnosticsForInvalidTypes != null) { 97 | ctx.reportDiagnostic(DiagnosticFactory.createDiagnostic(diagnosticsForInvalidTypes, 98 | node.arguments().get(0).location())); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/postgresql/compiler/analyzer/RecordAnalyzer.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.postgresql.compiler.analyzer; 19 | 20 | import io.ballerina.compiler.api.symbols.ModuleSymbol; 21 | import io.ballerina.compiler.api.symbols.Symbol; 22 | import io.ballerina.compiler.api.symbols.TypeDescKind; 23 | import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; 24 | import io.ballerina.compiler.api.symbols.TypeSymbol; 25 | import io.ballerina.compiler.api.symbols.UnionTypeSymbol; 26 | import io.ballerina.compiler.api.symbols.VariableSymbol; 27 | import io.ballerina.compiler.syntax.tree.ExpressionNode; 28 | import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; 29 | import io.ballerina.compiler.syntax.tree.ModuleVariableDeclarationNode; 30 | import io.ballerina.compiler.syntax.tree.VariableDeclarationNode; 31 | import io.ballerina.projects.plugins.AnalysisTask; 32 | import io.ballerina.projects.plugins.SyntaxNodeAnalysisContext; 33 | import io.ballerina.stdlib.postgresql.compiler.Constants; 34 | import io.ballerina.stdlib.postgresql.compiler.Utils; 35 | 36 | import java.util.Optional; 37 | 38 | import static io.ballerina.stdlib.postgresql.compiler.Constants.BALLERINAX; 39 | import static io.ballerina.stdlib.postgresql.compiler.Constants.POSTGRESQL; 40 | import static io.ballerina.stdlib.postgresql.compiler.Utils.validateOptionConfig; 41 | 42 | /** 43 | * Analyser for validation postgresql:Options. 44 | */ 45 | public class RecordAnalyzer implements AnalysisTask { 46 | @Override 47 | public void perform(SyntaxNodeAnalysisContext ctx) { 48 | if (Utils.hasCompilationErrors(ctx)) { 49 | return; 50 | } 51 | Optional varSymOptional = ctx.semanticModel().symbol(ctx.node()); 52 | if (varSymOptional.isPresent()) { 53 | TypeSymbol typeSymbol = ((VariableSymbol) varSymOptional.get()).typeDescriptor(); 54 | 55 | if (isPostgreSQLOptionsRecord(typeSymbol, Constants.Options.NAME)) { 56 | Optional recordNode = getRecordNode(ctx); 57 | if (recordNode.isEmpty()) { 58 | return; 59 | } 60 | validateOptionConfig(ctx, recordNode.get()); 61 | } 62 | } 63 | } 64 | 65 | private Optional getRecordNode(SyntaxNodeAnalysisContext ctx) { 66 | // Initiated with a record 67 | Optional optionalInitializer; 68 | if ((ctx.node() instanceof VariableDeclarationNode)) { 69 | // Function level variables 70 | optionalInitializer = ((VariableDeclarationNode) ctx.node()).initializer(); 71 | } else { 72 | // Module level variables 73 | optionalInitializer = ((ModuleVariableDeclarationNode) ctx.node()).initializer(); 74 | } 75 | if (optionalInitializer.isEmpty()) { 76 | return Optional.empty(); 77 | } 78 | ExpressionNode initializer = optionalInitializer.get(); 79 | if (!(initializer instanceof MappingConstructorExpressionNode)) { 80 | return Optional.empty(); 81 | } 82 | return Optional.of((MappingConstructorExpressionNode) initializer); 83 | } 84 | 85 | private boolean isPostgreSQLOptionsRecord(TypeSymbol type, String recordName) { 86 | if (type.typeKind() == TypeDescKind.UNION) { 87 | return ((UnionTypeSymbol) type).memberTypeDescriptors().stream() 88 | .filter(typeDescriptor -> typeDescriptor instanceof TypeReferenceTypeSymbol) 89 | .map(typeReferenceTypeSymbol -> (TypeReferenceTypeSymbol) typeReferenceTypeSymbol) 90 | .anyMatch(typeReferenceTypeSymbol -> 91 | isPostgreSQLOptionsRecord(typeReferenceTypeSymbol, recordName)); 92 | } 93 | if (type.typeKind() == TypeDescKind.TYPE_REFERENCE) { 94 | return isPostgreSQLOptionsRecord((TypeReferenceTypeSymbol) type, recordName); 95 | } 96 | return false; 97 | } 98 | 99 | private boolean isPostgreSQLOptionsRecord(TypeReferenceTypeSymbol typeSymbol, String recordName) { 100 | if (typeSymbol.typeDescriptor().typeKind() == TypeDescKind.RECORD) { 101 | ModuleSymbol moduleSymbol = typeSymbol.getModule().get(); 102 | return POSTGRESQL.equals(moduleSymbol.getName().get()) && BALLERINAX.equals(moduleSymbol.id().orgName()) 103 | && typeSymbol.definition().getName().get().equals(recordName); 104 | } 105 | return false; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /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.postgresql.compiler { 20 | requires io.ballerina.lang; 21 | requires io.ballerina.tools.api; 22 | requires io.ballerina.parser; 23 | } 24 | -------------------------------------------------------------------------------- /docs/proposals/default-username-for-client-connections.md: -------------------------------------------------------------------------------- 1 | # Define default username for client connections 2 | 3 | _Owners_: @kaneeldias 4 | _Reviewers_: @daneshk @niveathika 5 | _Created_: 2022/04/25 6 | _Updated_: 2022/04/25 7 | _Edition_: Swan Lake 8 | _Issues_: [#2397](https://github.com/ballerina-platform/ballerina-standard-library/issues/2397) 9 | 10 | ## Summary 11 | Define default username to be used when connecting to a PostgreSQL database on client initialization. 12 | 13 | ## History 14 | The 1.3.x versions and below of the PostgreSQL package defaulted to connecting to the database without a username 15 | attached (i.e. an empty string). 16 | 17 | ## Goals 18 | - Define the default username to be used when connecting to a PostgreSQL database on client initialization. 19 | 20 | ## Motivation 21 | The ability to connect to common databases with default credentials (as opposed to manually defining) would make the 22 | developer experience much more quick, simple and user-friendly, especially in testing scenarios. 23 | 24 | ## Description 25 | For PostgreSQL databases, the default username is `postgres`[[1]](https://www3.ntu.edu.sg/home/ehchua/programming/sql/PostgreSQL_GetStarted.html) 26 | 27 | Modify the [client initialization method](https://github.com/ballerina-platform/module-ballerinax-postgresql/blob/ebe926565f151f7ebd0420e26b0771bbeac432f2/ballerina/client.bal#L37-L38) 28 | signature to use `postgres` as the default value for the username instead of `()`. 29 | 30 | ```ballerina 31 | public isolated function init(string host = "localhost", string? username = "postgres", string? password = (), string? database = (), 32 | int port = 5432, Options? options = (), sql:ConnectionPool? connectionPool = ()) returns sql:Error? { 33 | ``` 34 | 35 | ## References 36 | [1] https://www3.ntu.edu.sg/home/ehchua/programming/sql/PostgreSQL_GetStarted.html 37 | -------------------------------------------------------------------------------- /examples/atomic-batch-operation/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | 3 | # Dependency toml file 4 | *Dependencies.toml 5 | -------------------------------------------------------------------------------- /examples/atomic-batch-operation/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql" 3 | name = "atomic_batch_operation" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /examples/atomic-batch-operation/Config.toml: -------------------------------------------------------------------------------- 1 | dbUsername = "postgres" 2 | dbPassword = "postgres" 3 | dbName = "postgres" 4 | port = 5432 5 | -------------------------------------------------------------------------------- /examples/atomic-batch-operation/Performing Atomic Batch Operations with PostgreSQL.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | The `atomic-batch-operation` project demonstrates how to use the PostgreSQL client to execute a batch of DDL/DML operations with the help of a `transaction` to achieve the atomic behaviour. 4 | 5 | # Prerequisite 6 | 7 | * Install the PostgreSQL server and create a database 8 | 9 | * Add required configurations in the `Config.toml` file 10 | 11 | # Run the example 12 | 13 | To run the example, move into the `atomic-batch-operation` project and execute the below command. 14 | 15 | ```shell 16 | bal run 17 | ``` 18 | It will build the `atomic-batch-operation` Ballerina project and then run it. 19 | 20 | # Output of the example 21 | 22 | This gives the following output when running this project. 23 | 24 | ```shell 25 | [ballerina/http] started HTTP/WS listener 192.168.1.10:55471 26 | Error while executing batch command starting with: 'INSERT INTO Students 27 | (firstName, lastName, registrationID, creditLimit, country) 28 | VALUES ( ? , ? , 29 | ? , ? , ? )'.Batch entry 1 INSERT INTO Students 30 | (firstName, lastName, registrationID, creditLimit, country) 31 | VALUES ( 'Peter' , 'Stuart' , 32 | 1 , 5000.75 , 'USA' ) 33 | RETURNING * was aborted: ERROR: duplicate key value violates unique constraint "students_registrationid_key" 34 | Detail: Key (registrationid)=(1) already exists. Call getNextException to see other errors in the batch.. 35 | [{"affectedRowCount":-3,"lastInsertId":null},{"affectedRowCount":-3,"lastInsertId":null},{"affectedRowCount":-3,"lastInsertId":null}] 36 | Rollback transaction. 37 | 38 | Data in Students table: 39 | {"customerid":1,"firstname":"Peter","lastname":"Stuart","registrationid":1,"creditlimit":5000.75,"country":"USA"} 40 | ``` 41 | -------------------------------------------------------------------------------- /examples/atomic-batch-operation/atomic_batch_operation.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/io; 18 | import ballerinax/postgresql; 19 | import ballerina/sql; 20 | import ballerinax/postgresql.driver as _; 21 | 22 | // The username , password and name of the PostgreSQL database 23 | configurable string dbUsername = "postgres"; 24 | configurable string dbPassword = "postgres"; 25 | configurable string dbName = "postgres"; 26 | configurable int port = 5432; 27 | 28 | public function main() returns error? { 29 | // Runs the prerequisite setup for the example. 30 | check beforeExample(); 31 | 32 | // Initializes the PostgreSQL client. 33 | postgresql:Client dbClient = check new (username = dbUsername, 34 | password = dbPassword, database = dbName); 35 | 36 | // Records with the duplicate `registrationID` entry. 37 | // Here it is `registrationID` = 1. 38 | var insertRecords = [ 39 | { 40 | firstName: "Linda", 41 | lastName: "Jones", 42 | registrationID: 4, 43 | creditLimit: 10000.75, 44 | country: "USA" 45 | }, 46 | { 47 | firstName: "Peter", 48 | lastName: "Stuart", 49 | registrationID: 1, 50 | creditLimit: 5000.75, 51 | country: "USA" 52 | }, 53 | { 54 | firstName: "Camellia", 55 | lastName: "Potter", 56 | registrationID: 5, 57 | creditLimit: 2000.25, 58 | country: "USA" 59 | } 60 | ]; 61 | 62 | // Creates a batch parameterized query. 63 | sql:ParameterizedQuery[] insertQueries = 64 | from var data in insertRecords 65 | select `INSERT INTO Students 66 | (firstName, lastName, registrationID, creditLimit, country) 67 | VALUES (${data.firstName}, ${data.lastName}, 68 | ${data.registrationID}, ${data.creditLimit}, ${data.country})`; 69 | 70 | // The transaction block can be used to roll back if any error occurred. 71 | transaction { 72 | var result = dbClient->batchExecute(insertQueries); 73 | if result is sql:BatchExecuteError { 74 | io:println(result.message()); 75 | io:println(result.detail()?.executionResults); 76 | io:println("Rollback transaction.\n"); 77 | rollback; 78 | } else { 79 | error? err = commit; 80 | if err is error { 81 | io:println("Error occurred while committing: ", err); 82 | } 83 | } 84 | } 85 | 86 | // Checks the data after the batch execution. 87 | stream resultStream = 88 | dbClient->query(`SELECT * FROM Students`); 89 | 90 | io:println("Data in Students table:"); 91 | check from record{} result in resultStream 92 | do { 93 | io:println(result.toString()); 94 | }; 95 | 96 | // Closes the PostgreSQL client. 97 | check dbClient.close(); 98 | } 99 | 100 | // Initializes the database as a prerequisite to the example. 101 | function beforeExample() returns sql:Error? { 102 | // Initializes the PostgreSQL client. 103 | postgresql:Client dbClient = check new (username = dbUsername, 104 | password = dbPassword, database = dbName); 105 | 106 | // Creates a table in the database. 107 | _ = check dbClient->execute(`DROP TABLE IF EXISTS Students`); 108 | _ = check dbClient->execute(`CREATE TABLE Students 109 | (customerId SERIAL, firstName VARCHAR(300), lastName VARCHAR(300), 110 | registrationID INTEGER UNIQUE, creditLimit DOUBLE PRECISION, 111 | country VARCHAR(300), PRIMARY KEY (customerId))`); 112 | 113 | // Adds records to the newly-created table. 114 | _ = check dbClient->execute(`INSERT INTO Students 115 | (firstName, lastName, registrationID,creditLimit,country) VALUES 116 | ('Peter', 'Stuart', 1, 5000.75, 'USA')`); 117 | // Closes the PostgreSQL client. 118 | check dbClient.close(); 119 | } 120 | -------------------------------------------------------------------------------- /examples/batch-operation/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | 3 | # Dependency toml file 4 | *Dependencies.toml 5 | -------------------------------------------------------------------------------- /examples/batch-operation/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql" 3 | name = "batch_operation" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /examples/batch-operation/Config.toml: -------------------------------------------------------------------------------- 1 | dbUsername = "postgres" 2 | dbPassword = "postgres" 3 | dbName = "postgres" 4 | port = 5432 5 | -------------------------------------------------------------------------------- /examples/batch-operation/Performing Batch Operations with PostgreSQL.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | The `batch-operation` project demonstrates how to use the PostgreSQL client to execute a batch of DDL/DML operations. 4 | 5 | # Prerequisite 6 | 7 | * Install the PostgreSQL server and create a database 8 | 9 | * Add required configurations in the `Config.toml` file 10 | 11 | # Run the example 12 | 13 | To run the example, move into the `batch-operation` project and execute the below command. 14 | 15 | ```shell 16 | bal run 17 | ``` 18 | It will build the `batch-operation` Ballerina project and then run it. 19 | 20 | # Output of the example 21 | 22 | This gives the following output when running this project. 23 | 24 | ```shell 25 | Insert success, generated IDs are: [1,2,3] 26 | 27 | Data in Customers table: 28 | {"customerid":1,"firstname":"Peter","lastname":"Stuart","registrationid":1,"creditlimit":5000.75,"country":"USA"} 29 | {"customerid":2,"firstname":"Stephanie","lastname":"Mike","registrationid":2,"creditlimit":8000.0,"country":"USA"} 30 | {"customerid":3,"firstname":"Bill","lastname":"John","registrationid":3,"creditlimit":3000.25,"country":"USA"} 31 | ``` 32 | -------------------------------------------------------------------------------- /examples/batch-operation/batch_operation.bal: -------------------------------------------------------------------------------- 1 | import ballerina/io; 2 | import ballerinax/postgresql; 3 | import ballerina/sql; 4 | import ballerinax/postgresql.driver as _; 5 | 6 | // The username , password and name of the PostgreSQL database 7 | configurable string dbUsername = "postgres"; 8 | configurable string dbPassword = "postgres"; 9 | configurable string dbName = "postgres"; 10 | configurable int port = 5432; 11 | 12 | public function main() returns error? { 13 | // Runs the prerequisite setup for the example. 14 | check beforeExample(); 15 | 16 | // Initializes the PostgreSQL client. 17 | postgresql:Client dbClient = check new (username = dbUsername, 18 | password = dbPassword, database = dbName); 19 | 20 | // The records to be inserted. 21 | var insertRecords = [ 22 | { 23 | firstName: "Peter", 24 | lastName: "Stuart", 25 | registrationID: 1, 26 | creditLimit: 5000.75, 27 | country: "USA" 28 | }, 29 | { 30 | firstName: "Stephanie", 31 | lastName: "Mike", 32 | registrationID: 2, 33 | creditLimit: 8000.00, 34 | country: "USA" 35 | }, 36 | { 37 | firstName: "Bill", 38 | lastName: "John", 39 | registrationID: 3, 40 | creditLimit: 3000.25, 41 | country: "USA" 42 | } 43 | ]; 44 | 45 | // Creates a batch parameterized query. 46 | sql:ParameterizedQuery[] insertQueries = 47 | from var data in insertRecords 48 | select `INSERT INTO Customers 49 | (firstName, lastName, registrationID, creditLimit, country) 50 | VALUES (${data.firstName}, ${data.lastName}, 51 | ${data.registrationID}, ${data.creditLimit}, ${data.country})`; 52 | 53 | // Inserts the records with the auto-generated ID. 54 | sql:ExecutionResult[] result = 55 | check dbClient->batchExecute(insertQueries); 56 | 57 | int[] generatedIds = []; 58 | foreach var summary in result { 59 | generatedIds.push(summary.lastInsertId); 60 | } 61 | io:println("\nInsert success, generated IDs are: ", generatedIds, "\n"); 62 | 63 | // Checks the data after the batch execution. 64 | stream resultStream = 65 | dbClient->query(`SELECT * FROM Customers`); 66 | 67 | io:println("Data in Customers table:"); 68 | check from record{} data in resultStream 69 | do { 70 | io:println(data.toString()); 71 | }; 72 | 73 | // Closes the PostgreSQL client. 74 | check dbClient.close(); 75 | } 76 | 77 | // Initializes the database as a prerequisite to the example. 78 | function beforeExample() returns sql:Error? { 79 | // Initializes the PostgreSQL client. 80 | postgresql:Client dbClient = check new (username = dbUsername, 81 | password = dbPassword, database = dbName); 82 | 83 | // Creates a table in the database. 84 | _ = check dbClient->execute(`DROP TABLE IF EXISTS Customers`); 85 | _ = check dbClient->execute(`CREATE TABLE Customers 86 | (customerId SERIAL, firstName VARCHAR(300), lastName VARCHAR(300), 87 | registrationID INTEGER UNIQUE, creditLimit DOUBLE PRECISION, 88 | country VARCHAR(300), PRIMARY KEY (customerId))`); 89 | 90 | // Closes the PostgreSQL client. 91 | check dbClient.close(); 92 | } 93 | -------------------------------------------------------------------------------- /examples/build.gradle: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.taskdefs.condition.Os 2 | 3 | /* 4 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 5 | * 6 | * WSO2 Inc. licenses this file to you under the Apache License, 7 | * Version 2.0 (the "License"); you may not use this file except 8 | * in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, 14 | * software distributed under the License is distributed on an 15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | * KIND, either express or implied. See the License for the 17 | * specific language governing permissions and limitations 18 | * under the License. 19 | */ 20 | 21 | apply plugin: 'java-library' 22 | 23 | description = 'Ballerina - Postgresql Examples' 24 | 25 | def ballerinaDist = "${project.rootDir}/target/ballerina-runtime" 26 | def examples = ["atomic-batch-operation", "batch-operation", "call-stored-procedures", "complex-queries-operation", "execute-operation", "query-operation", 27 | "fraud-detection"] 28 | 29 | clean { 30 | examples.forEach { example -> 31 | delete "${projectDir}/${example}/target" 32 | } 33 | } 34 | 35 | task updateTomlFiles { 36 | doLast { 37 | examples.each { example -> 38 | def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/ExamplesBallerina.toml") 39 | def ballerinaTomlFile = new File("${project.projectDir}/${example}/Ballerina.toml") 40 | def newConfig = ballerinaTomlFilePlaceHolder.text.replace('@example.name@', example.replace("-", "_")) 41 | ballerinaTomlFile.text = newConfig 42 | } 43 | } 44 | } 45 | 46 | task buildExamples { 47 | gradle.taskGraph.whenReady { graph -> 48 | if (graph.hasTask(":java.jdbc-examples:test")) { 49 | buildExamples.enabled = false 50 | } 51 | } 52 | doLast { 53 | examples.each { example -> 54 | try { 55 | exec { 56 | workingDir "${project.projectDir}/${example}" 57 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 58 | commandLine 'cmd', '/c', "${ballerinaDist}/bin/bal.bat pack --offline && exit %%ERRORLEVEL%%" 59 | } else { 60 | commandLine 'sh', '-c', "${ballerinaDist}/bin/bal pack --offline" 61 | } 62 | } 63 | } catch (Exception e) { 64 | println("Example '${example}' Build failed: " + e.message) 65 | throw e 66 | } 67 | } 68 | } 69 | } 70 | 71 | buildExamples.dependsOn ":postgresql-ballerina:build", updateTomlFiles 72 | build.dependsOn buildExamples 73 | -------------------------------------------------------------------------------- /examples/call-stored-procedures/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | 3 | # Dependency toml file 4 | *Dependencies.toml 5 | -------------------------------------------------------------------------------- /examples/call-stored-procedures/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql" 3 | name = "call_stored_procedures" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /examples/call-stored-procedures/Calling Stored Procedures with PostgreSQL.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | The `call-stored-operation` project demonstrates how to use the PostgreSQL client to execute a stored procedure. 4 | 5 | # Prerequisite 6 | 7 | * Install the PostgreSQL server and create a database 8 | 9 | * Add required configurations in the `Config.toml` file 10 | 11 | # Run the example 12 | 13 | To run the example, move into the `call-stored-operation` project and execute the below command. 14 | 15 | ```shell 16 | bal run 17 | ``` 18 | It will build the `call-stored-operation` Ballerina project and then run it. 19 | 20 | # Output of the example 21 | 22 | This gives the following output when running this project. 23 | 24 | ```shell 25 | Call stored procedure `InsertStudent`. 26 | Inserted data: {"id":1,"age":24,"name":"George"} 27 | Call stored procedure `GetCount`. 28 | Age of the student with id '1' : 24 29 | Total student count: 1 30 | ``` 31 | -------------------------------------------------------------------------------- /examples/call-stored-procedures/Config.toml: -------------------------------------------------------------------------------- 1 | dbUsername = "postgres" 2 | dbPassword = "postgres" 3 | dbName = "postgres" 4 | port = 5432 5 | -------------------------------------------------------------------------------- /examples/call-stored-procedures/stored_procedures.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/io; 18 | import ballerinax/postgresql; 19 | import ballerina/sql; 20 | import ballerinax/postgresql.driver as _; 21 | 22 | // The username , password and name of the PostgreSQL database 23 | configurable string dbUsername = "postgres"; 24 | configurable string dbPassword = "postgres"; 25 | configurable string dbName = "postgres"; 26 | configurable int port = 5432; 27 | 28 | public function main() returns error? { 29 | // Runs the prerequisite setup for the example. 30 | check beforeExample(); 31 | 32 | // Initializes the PostgresSQL client. 33 | postgresql:Client dbClient = check new (username = dbUsername, 34 | password = dbPassword, database = dbName); 35 | 36 | // Creates a parameterized query to invoke the procedure. 37 | string personName = "George"; 38 | int personAge = 24; 39 | int personId = 1; 40 | sql:ParameterizedCallQuery sqlQuery = 41 | `CALL InsertStudent(${personId}, ${personName}, ${personAge})`; 42 | 43 | // Invokes the stored procedure `InsertStudent` with the `IN` parameters. 44 | sql:ProcedureCallResult retCall = check dbClient->call(sqlQuery); 45 | stream resultStream = dbClient->query(`SELECT * FROM Student`); 46 | check from record{} result in resultStream 47 | do { 48 | io:println("Call stored procedure `InsertStudent`." + 49 | "\nInserted data: ", result); 50 | }; 51 | check retCall.close(); 52 | 53 | // Initializes the `INOUT` parameters. 54 | int no = 1; 55 | int count = 0; 56 | sql:InOutParameter id = new (no); 57 | sql:InOutParameter totalCount = new (count); 58 | sql:ParameterizedCallQuery sqlQuery2 = 59 | `CALL GetCount(${id}, ${totalCount})`; 60 | 61 | // The stored procedure with the `INOUT` parameters is invoked. 62 | sql:ProcedureCallResult retCall2 = check dbClient->call(sqlQuery2); 63 | io:println("Call stored procedure `GetCount`."); 64 | io:println("Age of the student with id '1' : ", id.get(int)); 65 | io:println("Total student count: ", totalCount.get(int)); 66 | check retCall2.close(); 67 | 68 | // Closes the PostgresSQL client. 69 | check dbClient.close(); 70 | } 71 | 72 | // Initializes the database as a prerequisite to the example. 73 | function beforeExample() returns sql:Error? { 74 | // Initializes the PostgresSQL client. 75 | postgresql:Client dbClient = check new (username = dbUsername, 76 | password = dbPassword, database = dbName); 77 | 78 | // Creates a table in the database. 79 | _ = check dbClient->execute(`DROP TABLE IF EXISTS Student`); 80 | _ = check dbClient->execute(`CREATE TABLE Student 81 | (id bigint, age bigint, name text, 82 | PRIMARY KEY (id))`); 83 | 84 | // Creates the necessary stored procedures using the execute command. 85 | _ = check dbClient->execute(`CREATE OR REPLACE PROCEDURE 86 | InsertStudent (IN id bigint, IN pName text, IN pAge bigint) language plpgsql as $$ 87 | BEGIN INSERT INTO Student(id, age, name) VALUES (id, pAge, pName); END; $$ `); 88 | 89 | _ = check dbClient->execute(`CREATE OR REPLACE PROCEDURE GetCount 90 | (INOUT pID bigint, INOUT totalCount bigint) language plpgsql as $$ 91 | BEGIN 92 | SELECT age INTO pID FROM Student WHERE id = pID; 93 | SELECT COUNT(*) INTO totalCount FROM Student; 94 | END; $$ `); 95 | 96 | // Closes the PostgresSQL client. 97 | check dbClient.close(); 98 | } 99 | -------------------------------------------------------------------------------- /examples/complex-queries-operation/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | 3 | # Dependency toml file 4 | *Dependencies.toml 5 | -------------------------------------------------------------------------------- /examples/complex-queries-operation/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql" 3 | name = "complex_queries_operation" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /examples/complex-queries-operation/Config.toml: -------------------------------------------------------------------------------- 1 | dbUsername = "postgres" 2 | dbPassword = "postgres" 3 | dbName = "postgres" 4 | port = 5432 5 | -------------------------------------------------------------------------------- /examples/complex-queries-operation/Performing Complex Queries with PostgreSQL.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | This example demonstrates how to use the PostgreSQL client with complex data types such as JSON, range and date/time fields. 4 | 5 | # Prerequisite 6 | 7 | * Install the PostgreSQL server and create a database 8 | 9 | * Add required configurations in the `Config.toml` file 10 | 11 | # Run the example 12 | 13 | To run the example, move into the `complex-queries-operation` project and execute the below command. 14 | 15 | ```shell 16 | bal run 17 | ``` 18 | It will build the `complex-queries-operation` Ballerina project and then run it. 19 | 20 | # Output of the example 21 | 22 | This gives the following output when running this project. 23 | 24 | ```shell 25 | Json types Result : 26 | {"row_id":1,"json_type":{"key1":"value","key2":2},"jsonb_type":{"key1":"value","key2":2},"jsonpath_type":"$."floor"[*]."apt"[*]?(@."area" > 40 && @."area" < 90)?(@."rooms" > 1)"} 27 | Range type Result : 28 | {"row_id":1,"int4range_type":{"upper":50,"lower":3,"upperboundInclusive":false,"lowerboundInclusive":true},"int8range_type":{"upper":100,"lower":11,"upperboundInclusive":false,"lowerboundInclusive":true},"numrange_type":{"upper":24,"lower":0,"upperboundInclusive":false,"lowerboundInclusive":false},"tsrange_type":{"upper":"2010-01-01 15:30:00","lower":"2010-01-01 14:30:00","upperboundInclusive":false,"lowerboundInclusive":false},"tstzrange_type":{"upper":"2010-01-01 15:30:00+05:30","lower":"2010-01-01 14:30:00+05:30","upperboundInclusive":false,"lowerboundInclusive":false},"daterange_type":{"upper":"2010-01-03","lower":"2010-01-02","upperboundInclusive":false,"lowerboundInclusive":true}} 29 | DateTime types Result : 30 | {"row_id":1,"time_type":{"hour":4,"minute":5,"second":6},"timetz_type":{"hour":13,"minute":35,"second":6},"timestamp_type":{"year":1999,"month":1,"day":8,"hour":4,"minute":5,"second":6},"timestamptz_type":{"year":2004,"month":10,"day":19,"hour":14,"minute":23,"second":54},"date_type":{"year":1999,"month":1,"day":8},"interval_type":{"years":1,"months":2,"days":3,"hours":4,"minutes":5,"seconds":6.0}} 31 | ``` 32 | -------------------------------------------------------------------------------- /examples/execute-operation/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | 3 | # Dependency toml file 4 | *Dependencies.toml 5 | -------------------------------------------------------------------------------- /examples/execute-operation/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql" 3 | name = "execute_operation" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /examples/execute-operation/Config.toml: -------------------------------------------------------------------------------- 1 | dbUsername = "postgres" 2 | dbPassword = "postgres" 3 | dbName = "postgres" 4 | port = 5432 5 | -------------------------------------------------------------------------------- /examples/execute-operation/Executing Queries with PostgreSQL.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | This example demonstrates how to use the PostgreSQL client with the DDL and DML operations. 4 | 5 | # Prerequisite 6 | 7 | * Install the PostgreSQL server and create a database 8 | 9 | * Add required configurations in the `Config.toml` file 10 | 11 | # Run the example 12 | 13 | To run the example, move into the `execute-batch-operation` project and execute the below command. 14 | 15 | ```shell 16 | bal run 17 | ``` 18 | It will build the `execute-operation` Ballerina project and then run it. 19 | 20 | # Output of the example 21 | 22 | This gives the following output when running this project. 23 | 24 | ```shell 25 | Rows affected: 1 26 | Generated Customer ID: 2 27 | Updated Row count: 1 28 | Deleted Row count: 1 29 | ``` 30 | -------------------------------------------------------------------------------- /examples/execute-operation/execute_operation.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/io; 18 | import ballerinax/postgresql; 19 | import ballerina/sql; 20 | import ballerinax/postgresql.driver as _; 21 | 22 | // The username , password and name of the PostgreSQL database 23 | configurable string dbUsername = "postgres"; 24 | configurable string dbPassword = "postgres"; 25 | configurable string dbName = "postgres"; 26 | configurable int port = 5432; 27 | 28 | public function main() returns error? { 29 | // Runs the prerequisite setup for the example. 30 | check beforeExample(); 31 | 32 | // Initializes the PostgresSQL client. 33 | postgresql:Client dbClient = check new (username = dbUsername, 34 | password = dbPassword, database = dbName); 35 | 36 | float newCreditLimit = 15000.5; 37 | 38 | // Creates a parameterized query for the record update. 39 | sql:ParameterizedQuery updateQuery = 40 | `UPDATE Customers SET creditLimit = ${newCreditLimit} 41 | where customerId = 1`; 42 | 43 | sql:ExecutionResult result = check dbClient->execute(updateQuery); 44 | io:println("Updated Row count: ", result?.affectedRowCount); 45 | 46 | string firstName = "Dan"; 47 | 48 | // Creates a parameterized query for deleting the records. 49 | sql:ParameterizedQuery deleteQuery = 50 | `DELETE FROM Customers WHERE firstName = ${firstName}`; 51 | 52 | result = check dbClient->execute(deleteQuery); 53 | io:println("Deleted Row count: ", result.affectedRowCount); 54 | 55 | // Closes the PostgresSQL client. 56 | check dbClient.close(); 57 | } 58 | 59 | // Initializes the database as a prerequisite to the example. 60 | function beforeExample() returns sql:Error? { 61 | // Initializes the PostgresSQL client. 62 | postgresql:Client dbClient = check new (username = dbUsername, 63 | password = dbPassword, database = dbName); 64 | 65 | //Creates a table in the database. 66 | sql:ExecutionResult result = check dbClient->execute(`DROP TABLE IF EXISTS Customers`); 67 | result = check dbClient->execute(`CREATE TABLE Customers 68 | (customerId SERIAL, firstName 69 | VARCHAR(300), lastName VARCHAR(300), registrationID INTEGER, 70 | creditLimit DOUBLE PRECISION, country VARCHAR(300), 71 | PRIMARY KEY (customerId))`); 72 | 73 | // Inserts data into the table. The result will have the `affectedRowCount` 74 | // and `lastInsertedId` with the auto-generated ID of the last row. 75 | 76 | result = check dbClient->execute(`INSERT INTO Customers 77 | (firstName, lastName, registrationID,creditLimit,country) VALUES 78 | ('Peter','Stuart', 1, 5000.75, 'USA')`); 79 | result = check dbClient->execute(`INSERT INTO Customers 80 | (firstName, lastName, registrationID,creditLimit,country) VALUES 81 | ('Dan', 'Brown', 2, 10000, 'UK')`); 82 | 83 | io:println("Rows affected: ", result.affectedRowCount); 84 | io:println("Generated Customer ID: ", result.lastInsertId); 85 | 86 | // Closes the PostgresSQL client. 87 | check dbClient.close(); 88 | } 89 | -------------------------------------------------------------------------------- /examples/fraud-detection/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Fraud Detection.md -------------------------------------------------------------------------------- /examples/fraud-detection/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql" 3 | name = "fraud_detection" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /examples/fraud-detection/Fraud Detection.md: -------------------------------------------------------------------------------- 1 | # Fraud Detection 2 | 3 | This example demonstrates how to use the `postgresql:CdcListener` to implement a fraud detection system. The system listens to table changes and processes them to identify potential fraudulent activities. 4 | 5 | ## Setup Guide 6 | 7 | ### 1. Postgres Database 8 | 9 | 1. Refer to the [Setup Guide](https://central.ballerina.io/ballerinax/postgresql/latest#setup-guide) for the necessary steps to enable CDC in the Postgresql server. 10 | 11 | 2. Add the necessary schema and data using the `setup.sql` script: 12 | ```bash 13 | psql -U -p < db_scripts/setup.sql 14 | ``` 15 | 16 | ### 2. Configuration 17 | 18 | Configure Postgres Database credentials in the `Config.toml` file located in the example directory: 19 | 20 | ```toml 21 | username = "" 22 | password = "" 23 | ``` 24 | 25 | ## Setup Guide: Using Docker Compose 26 | 27 | You can use Docker Compose to set up Postgres for this example. Follow these steps: 28 | 29 | ### 1. Start the service 30 | 31 | Run the following command to start the Postgres service: 32 | 33 | ```bash 34 | docker-compose up -d 35 | ``` 36 | 37 | ### 2. Verify the service 38 | 39 | Ensure `postgresql` service is in a healthy state: 40 | 41 | ```bash 42 | docker-compose ps 43 | ``` 44 | 45 | ### 3. Configuration 46 | 47 | Ensure the `Config.toml` file is updated with the following credentials: 48 | 49 | ```toml 50 | username = "cdc_user" 51 | password = "cdc_password" 52 | ``` 53 | 54 | ## Run the Example 55 | 56 | 1. Execute the following command to run the example: 57 | 58 | ```bash 59 | bal run 60 | ``` 61 | 62 | 2. Use the provided `test.sql` script to insert sample transactions into the `transactions` table to test the fraud detection system. Use the following SQL command: 63 | ```bash 64 | psql -U -d -f db_scripts/test.sql 65 | ``` 66 | 67 | If using docker services, 68 | 69 | ```bash 70 | docker exec -i postgresql-cdc psql -U cdc_user -d -f /db-scripts/test.sql 71 | ``` -------------------------------------------------------------------------------- /examples/fraud-detection/db-scripts/setup.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Transactions table 3 | CREATE TABLE transactions ( 4 | tx_id SERIAL PRIMARY KEY, 5 | user_id INT, 6 | amount DECIMAL(10,2), 7 | status VARCHAR(50), 8 | created_at TIMESTAMP NOT NULL 9 | ); 10 | 11 | -- Sample data 12 | INSERT INTO transactions (user_id, amount, status, created_at) VALUES 13 | (10, 8500.00, 'COMPLETED', '2025-04-01 08:00:00'), 14 | (11, 11500.00, 'COMPLETED', '2025-04-01 08:10:00'), -- this one should trigger fraud logic 15 | (12, 4000.00, 'PENDING', '2025-04-01 08:30:00'); 16 | 17 | ALTER TABLE transactions REPLICA IDENTITY FULL; 18 | -------------------------------------------------------------------------------- /examples/fraud-detection/db-scripts/test.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO transactions (user_id, amount, status, created_at) VALUES 2 | (11, 2000.00, 'COMPLETED', '2025-04-01 08:10:00'); 3 | 4 | INSERT INTO transactions (user_id, amount, status, created_at) VALUES 5 | (11, 12000.00, 'COMPLETED', '2025-04-01 08:10:00'); 6 | -------------------------------------------------------------------------------- /examples/fraud-detection/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | postgresql: 3 | image: postgres 4 | container_name: postgresql 5 | environment: 6 | POSTGRES_USER: "postgres" 7 | POSTGRES_PASSWORD: "root@123" 8 | POSTGRES_DB: "finance_db" 9 | ports: 10 | - "5432:5432" 11 | volumes: 12 | - ./db-scripts/setup.sql:/docker-entrypoint-initdb.d/setup.sql 13 | command: [ 14 | "postgres", 15 | "-c", "wal_level=logical", 16 | "-c", "max_replication_slots=10", 17 | "-c", "max_wal_senders=10" 18 | ] 19 | -------------------------------------------------------------------------------- /examples/fraud-detection/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. 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 | import ballerina/log; 17 | import ballerina/os; 18 | import ballerinax/cdc; 19 | import ballerinax/postgresql; 20 | import ballerinax/postgresql.cdc.driver as _; 21 | 22 | configurable string username = os:getEnv("DB_USERNAME"); 23 | configurable string password = os:getEnv("DB_PASSWORD"); 24 | 25 | listener postgresql:CdcListener financeDBListener = new ( 26 | database = { 27 | username, 28 | password, 29 | databaseName: "finance_db" 30 | }, 31 | options = { 32 | snapshotMode: cdc:NO_DATA, 33 | skippedOperations: [cdc:NONE] 34 | } 35 | ); 36 | 37 | service cdc:Service on financeDBListener { 38 | isolated remote function onCreate(Transactions trx) returns error? { 39 | log:printInfo(`Create trx event received Transaction Id: ${trx.tx_id}`); 40 | if trx.amount > 10000.00 { 41 | string fraudAlert = string `Fraud detected! Transaction Id: ${trx.tx_id}, User Id: ${trx.user_id}, Amount: $${trx.amount}`; 42 | log:printInfo(`Email sent. Message ID: ${fraudAlert}`); 43 | } 44 | } 45 | 46 | isolated remote function onTruncate() returns error? { 47 | log:printInfo(`Truncate event received.`); 48 | } 49 | 50 | isolated remote function onError(cdc:Error e) { 51 | log:printInfo(`Error occurred: ${e.message()}`); 52 | } 53 | } 54 | 55 | type Transactions record {| 56 | int tx_id; 57 | int user_id; 58 | float amount; 59 | string status; 60 | int created_at; 61 | |}; 62 | -------------------------------------------------------------------------------- /examples/query-operation/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | 3 | # Dependency toml file 4 | *Dependencies.toml 5 | -------------------------------------------------------------------------------- /examples/query-operation/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "postgresql" 3 | name = "query_operation" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /examples/query-operation/Config.toml: -------------------------------------------------------------------------------- 1 | dbUsername = "postgres" 2 | dbPassword = "postgres" 3 | dbName = "postgres" 4 | port = 5432 5 | -------------------------------------------------------------------------------- /examples/query-operation/Performing Queries with PostgreSQL.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | This example demonstrates how to use the PostgreSQL client select query operations with the stream return type. 4 | 5 | # Prerequisite 6 | 7 | * Install the PostgreSQL server and create a database 8 | 9 | * Add required configurations in the `Config.toml` file 10 | 11 | # Run the example 12 | 13 | To run the example, move into the `query-operation` project and execute the below command. 14 | 15 | ```shell 16 | bal run 17 | ``` 18 | It will build the `query-operation` Ballerina project and then run it. 19 | 20 | # Output of the example 21 | 22 | This gives the following output when running this project. 23 | 24 | ```shell 25 | Full Customer details: {"customerid":1,"firstname":"Peter","lastname":"Stuart","registrationid":1,"creditlimit":5000.75,"country":"USA"} 26 | Full Customer details: {"customerid":2,"firstname":"Dan","lastname":"Brown","registrationid":2,"creditlimit":10000.0,"country":"UK"} 27 | Total rows in customer table : 2 28 | Full Customer details: {"customerId":1,"firstName":"Peter","lastName":"Stuart","registrationId":1,"creditLimit":5000.75,"country":"USA"} 29 | Full Customer details: {"customerId":2,"firstName":"Dan","lastName":"Brown","registrationId":2,"creditLimit":10000.0,"country":"UK"} 30 | ``` 31 | -------------------------------------------------------------------------------- /examples/query-operation/query_operation.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/io; 18 | import ballerinax/postgresql; 19 | import ballerina/sql; 20 | import ballerinax/postgresql.driver as _; 21 | 22 | // The username , password and name of the PostgreSQL database 23 | configurable string dbUsername = "postgres"; 24 | configurable string dbPassword = "postgres"; 25 | configurable string dbName = "postgres"; 26 | configurable int port = 5432; 27 | 28 | // Defines a record to load the query result schema as shown below in the 29 | // 'getDataWithTypedQuery' function. In this example, all columns of the 30 | // customer table will be loaded. Therefore, the `Customer` record will be 31 | // created with all the columns. The column name of the result and the 32 | // defined field name of the record will be matched case insensitively. 33 | type Customer record { 34 | int customerId; 35 | string lastName; 36 | string firstName; 37 | int registrationId; 38 | float creditLimit; 39 | string country; 40 | }; 41 | 42 | public function main() returns error? { 43 | // Runs the prerequisite setup for the example. 44 | check beforeExample(); 45 | 46 | // Initializes the PostgreSQL client. 47 | postgresql:Client dbClient = check new (username = dbUsername, 48 | password = dbPassword, database = dbName); 49 | 50 | // Select the rows in the database table via the query remote operation. 51 | // The result is returned as a stream and the elements of the stream can 52 | // be either a record or an error. The name and type of the attributes 53 | // within the record from the `resultStream` will be automatically 54 | // identified based on the column name and type of the query result. 55 | stream resultStream = 56 | dbClient->query(`SELECT * FROM Customers`); 57 | 58 | // If there is any error during the execution of the SQL query or 59 | // iteration of the result stream, the result stream will terminate and 60 | // return the error. 61 | check from Customer result in resultStream 62 | do { 63 | io:println("Full Customer details: ", result); 64 | }; 65 | 66 | // The result of the count operation is provided as a record stream. 67 | stream resultStream2 = 68 | dbClient->query(`SELECT COUNT(*) AS total FROM Customers`); 69 | 70 | // Since the above count query will return only a single row, 71 | // the `next()` operation is sufficient to retrieve the data. 72 | record {Customer value;}? result = check resultStream2.next(); 73 | // Checks the result and retrieves the value for the total. 74 | if result is record {Customer value;} { 75 | io:println("Total rows in customer table : ", result.value["total"]); 76 | } 77 | 78 | // In general cases, the stream will be closed automatically 79 | // when the stream is fully consumed or any error is encountered. 80 | // However, in case if the stream is not fully consumed, the stream 81 | // should be closed specifically. 82 | check resultStream.close(); 83 | check resultStream2.close(); 84 | 85 | // If a `Customer` stream type is defined when calling the query method, 86 | // The result is returned as a `Customer` record stream and the elements 87 | // of the stream can be either a `Customer` record or an error. 88 | stream resultStream3 = 89 | dbClient->query(`SELECT * FROM Customers`); 90 | 91 | // Iterates the customer stream. 92 | check from Customer customer in resultStream3 93 | do { 94 | io:println("Full Customer details: ", customer); 95 | }; 96 | 97 | // Closes the PostgreSQL client. 98 | check dbClient.close(); 99 | } 100 | 101 | // Initializes the database as a prerequisite to the example. 102 | function beforeExample() returns sql:Error? { 103 | // Initializes the PostgreSQL client. 104 | postgresql:Client dbClient = check new (username = dbUsername, 105 | password = dbPassword, database = dbName); 106 | 107 | // Creates a table in the database. 108 | _ = check dbClient->execute(`DROP TABLE IF EXISTS Customers`); 109 | _ = check dbClient->execute(`CREATE TABLE IF NOT EXISTS Customers 110 | (customerId SERIAL, firstName VARCHAR(300), lastName VARCHAR(300), 111 | registrationID INTEGER, creditLimit DOUBLE PRECISION, country VARCHAR(300), 112 | PRIMARY KEY (customerId))`); 113 | 114 | // Adds the records to the newly-created table. 115 | _ = check dbClient->execute(`INSERT INTO Customers 116 | (firstName, lastName, registrationID,creditLimit,country) VALUES 117 | ('Peter','Stuart', 1, 5000.75, 'USA')`); 118 | _ = check dbClient->execute(`INSERT INTO Customers 119 | (firstName, lastName, registrationID,creditLimit,country) VALUES 120 | ('Dan', 'Brown', 2, 10000, 'UK')`); 121 | 122 | // Closes the PostgreSQL client. 123 | check dbClient.close(); 124 | } 125 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=io.ballerina.stdlib 2 | version=1.16.1-SNAPSHOT 3 | ballerinaLangVersion=2201.12.0 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 | postgreSQLDriverVersion=42.6.1 13 | testngVersion=7.6.1 14 | 15 | # Direct Dependencies 16 | # Level 01 17 | stdlibIoVersion=1.8.0 18 | stdlibTimeVersion=2.7.0 19 | 20 | # Level 02 21 | stdlibLogVersion=2.12.0 22 | stdlibOsVersion=1.10.0 23 | 24 | # Level 03 25 | stdlibFileVersion=1.12.0 26 | 27 | # Level 07 28 | stdlibSqlVersion=1.16.0 29 | 30 | # Ballerinax Observer 31 | observeVersion=1.5.0 32 | observeInternalVersion=1.5.0 33 | 34 | # Transitive Dependencies 35 | # Level 01 36 | stdlibUrlVersion=2.6.0 37 | 38 | # Level 02 39 | stdlibConstraintVersion=1.7.0 40 | stdlibCryptoVersion=2.9.0 41 | stdlibTaskVersion=2.7.0 42 | 43 | # Level 03 44 | stdlibCacheVersion=3.10.0 45 | stdlibMimeVersion=2.12.0 46 | stdlibUuidVersion=1.10.0 47 | 48 | # Level 04 49 | stdlibAuthVersion=2.14.0 50 | stdlibJwtVersion=2.15.0 51 | stdlibOAuth2Version=2.14.0 52 | stdlibDataJsonDataVersion=1.1.0 53 | 54 | # Level 05 55 | stdlibHttpVersion=2.14.0 56 | 57 | # Level 06 58 | stdlibTransactionVersion=1.12.0 59 | 60 | # Ballerina extended library 61 | stdlibPostgresqlDriverVersion=1.6.1 62 | stdlibCdcVersion=1.0.2 63 | stdlibPostgresCdcDriverVersion=1.0.0 64 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-postgresql/ebcb8dadb744a0920d885c789050da83c9e26050/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 | -------------------------------------------------------------------------------- /load-tests/execute_operation/deployment/deployment-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "apps/v1" 2 | kind: Deployment 3 | metadata: 4 | name: no-name 5 | spec: 6 | template: 7 | metadata: 8 | labels: 9 | logs: "true" 10 | spec: 11 | containers: 12 | - name: "execute-operation-deployment" 13 | imagePullPolicy: Always 14 | -------------------------------------------------------------------------------- /load-tests/execute_operation/deployment/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: execute-operation 6 | annotations: 7 | kubernetes.io/ingress.class: nginx 8 | spec: 9 | rules: 10 | - host: bal.perf.test 11 | http: 12 | paths: 13 | - path: "/" 14 | pathType: Prefix 15 | backend: 16 | service: 17 | name: execute-operati 18 | port: 19 | number: 9092 20 | -------------------------------------------------------------------------------- /load-tests/execute_operation/deployment/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - execute_operation.yaml 3 | - ingress.yaml 4 | - postgres_deployment.yml 5 | patches: 6 | - path: deployment-patch.yaml 7 | target: 8 | group: apps 9 | version: v1 10 | kind: Deployment 11 | name: execute-operation-deployment 12 | -------------------------------------------------------------------------------- /load-tests/execute_operation/deployment/postgres_deployment.yml: -------------------------------------------------------------------------------- 1 | ## PostgreSQL data storage 2 | kind: PersistentVolumeClaim 3 | apiVersion: v1 4 | metadata: 5 | name: postgres-data-pvc 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 1Gi 13 | --- 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | metadata: 17 | name: postgres-deployment 18 | spec: 19 | selector: 20 | matchLabels: 21 | app: postgres 22 | strategy: 23 | type: Recreate 24 | template: 25 | metadata: 26 | labels: 27 | app: postgres 28 | logs: "true" 29 | spec: 30 | containers: 31 | - name: postgres 32 | image: postgres 33 | env: 34 | - name: POSTGRES_USER 35 | value: postgres 36 | - name: POSTGRES_PASSWORD 37 | value: postgres 38 | ports: 39 | - containerPort: 5432 40 | volumeMounts: 41 | - name: data 42 | mountPath: /var/lib/postgres 43 | volumes: 44 | - name: data 45 | persistentVolumeClaim: 46 | claimName: postgres-data-pvc 47 | --- 48 | ## Service 49 | apiVersion: v1 50 | kind: Service 51 | metadata: 52 | name: postgres-service 53 | labels: 54 | app: postgres-server 55 | spec: 56 | type: NodePort 57 | ports: 58 | - port: 5432 59 | targetPort: 5432 60 | protocol: TCP 61 | selector: 62 | app: postgres 63 | --- 64 | apiVersion: v1 65 | kind: Service 66 | metadata: 67 | name: postgres-deployment 68 | spec: 69 | selector: 70 | app: postgres 71 | ports: 72 | - protocol: TCP 73 | port: 5432 74 | targetPort: 5432 75 | type: LoadBalancer 76 | --- 77 | -------------------------------------------------------------------------------- /load-tests/execute_operation/scripts/http-post-request.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | true 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | continue 17 | 18 | false 19 | -1 20 | 21 | ${__P(users)} 22 | ${__P(rampUpPeriod,60)} 23 | true 24 | ${__P(duration)} 25 | true 26 | 27 | 28 | 29 | 30 | 31 | 32 | ${__P(host,localhost)} 33 | ${__P(port,9092)} 34 | ${__P(protocol,http)} 35 | 36 | customer?id=${random}&newCreditLimit=${randomCredit} 37 | POST 38 | true 39 | false 40 | true 41 | false 42 | 43 | HttpClient4 44 | 10000 45 | 30000 46 | 47 | 48 | 49 | 50 | 200 51 | 52 | 53 | Assertion.response_code 54 | false 55 | 16 56 | 57 | 58 | 59 | 60 | 15 61 | 1 62 | 0 63 | true 64 | 1 65 | random 66 | 67 | 68 | 69 | 15000 70 | 0 71 | 00000.00 72 | true 73 | 1 74 | randomCredit 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /load-tests/execute_operation/scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # Copyright 2021 WSO2 Inc. (http://wso2.org) 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 | # Execution script for ballerina performance tests 18 | # ---------------------------------------------------------------------------- 19 | set -e 20 | source base-scenario.sh 21 | jmeter -n -t "$scriptsDir/"http-post-request.jmx -l "$resultsDir/"original.jtl -Jusers="$concurrent_users" -Jduration=600 -Jhost=bal.perf.test -Jport=80 22 | tail "$resultsDir/"original.jtl 23 | -------------------------------------------------------------------------------- /load-tests/execute_operation/src/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "execute_operation" 4 | version = "0.0.1" 5 | 6 | [build-options] 7 | cloud = "k8s" 8 | 9 | [[platform.java17.dependency]] 10 | groupId = "org.postgresql" 11 | artifactId = "postgresql" 12 | version = "42.2.20" 13 | -------------------------------------------------------------------------------- /load-tests/execute_operation/src/Cloud.toml: -------------------------------------------------------------------------------- 1 | [container.image] 2 | repository = "ballerina" 3 | name = "execute_operation" 4 | 5 | [cloud.deployment] 6 | min_memory = "256Mi" 7 | max_memory = "512Mi" 8 | min_cpu = "200m" 9 | max_cpu="1000m" 10 | 11 | [cloud.deployment.autoscaling] 12 | min_replicas = 1 13 | max_replicas = 1 14 | 15 | [[cloud.config.files]] 16 | file="Config.toml" 17 | -------------------------------------------------------------------------------- /load-tests/execute_operation/src/Config.toml: -------------------------------------------------------------------------------- 1 | dbHost = "postgres-service" 2 | dbUsername = "postgres" 3 | dbPassword = "postgres" 4 | dbName = "postgres" 5 | dbPort = 5432 6 | -------------------------------------------------------------------------------- /load-tests/execute_operation/src/execute_operation.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 ballerinax/postgresql; 18 | import ballerina/sql; 19 | import ballerina/http; 20 | 21 | configurable string dbHost = ?; 22 | configurable string dbUsername = ?; 23 | configurable string dbPassword = ?; 24 | configurable string dbName = ?; 25 | configurable int dbPort = ?; 26 | 27 | type Customer record { 28 | int customerId; 29 | string lastName; 30 | string firstName; 31 | int registrationId; 32 | float creditLimit; 33 | string country; 34 | }; 35 | 36 | final postgresql:Client dbClient = check new(host = dbHost, username = dbUsername, password = dbPassword, port = dbPort, database = dbName); 37 | 38 | public function main() returns error? { 39 | _ = check dbClient->execute(`DROP TABLE IF EXISTS Customers`); 40 | _ = check dbClient->execute(` 41 | CREATE TABLE Customers ( 42 | customerId SERIAL, 43 | firstName VARCHAR(300), 44 | lastName VARCHAR(300), 45 | registrationID INT, 46 | creditLimit FLOAT, 47 | country VARCHAR(300) 48 | ); 49 | `); 50 | 51 | _ = check dbClient->execute(` 52 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 53 | VALUES ('Peter','Stuart', 1, 5000.75, 'USA')`); 54 | _ = check dbClient->execute(` 55 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 56 | VALUES ('Dan', 'Brown', 2, 10000, 'UK')`); 57 | _ = check dbClient->execute(` 58 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 59 | VALUES ('Peter','Stuart', 3, 5000.75, 'USA')`); 60 | _ = check dbClient->execute(` 61 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 62 | VALUES ('Dan', 'Brown', 4, 10000, 'UK')`); 63 | _ = check dbClient->execute(` 64 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 65 | VALUES ('Peter','Stuart', 5, 5000.75, 'USA')`); 66 | _ = check dbClient->execute(` 67 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 68 | VALUES ('Dan', 'Brown', 6, 10000, 'UK')`); 69 | _ = check dbClient->execute(` 70 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 71 | VALUES ('Peter','Stuart', 7, 5000.75, 'USA')`); 72 | _ = check dbClient->execute(` 73 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 74 | VALUES ('Dan', 'Brown', 8, 10000, 'UK')`); 75 | _ = check dbClient->execute(` 76 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 77 | VALUES ('Peter','Stuart', 9, 5000.75, 'USA')`); 78 | _ = check dbClient->execute(` 79 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 80 | VALUES ('Dan', 'Brown', 10, 10000, 'UK')`); 81 | _ = check dbClient->execute(` 82 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 83 | VALUES ('Peter','Stuart', 11, 5000.75, 'USA')`); 84 | _ = check dbClient->execute(` 85 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 86 | VALUES ('Dan', 'Brown', 12, 10000, 'UK')`); 87 | _ = check dbClient->execute(` 88 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 89 | VALUES ('Peter','Stuart', 13, 5000.75, 'USA')`); 90 | _ = check dbClient->execute(` 91 | INSERT INTO Customers (firstName, lastName, registrationID, creditLimit, country) 92 | VALUES ('Dan', 'Brown', 14, 10000, 'UK')`); 93 | } 94 | 95 | isolated service /customer on new http:Listener(9092) { 96 | resource isolated function post .(int id, float newCreditLimit) returns int?|error { 97 | sql:ParameterizedQuery updateQuery = 98 | `UPDATE Customers SET creditLimit = ${newCreditLimit} WHERE customerId = ${id}`; 99 | sql:ExecutionResult result = check dbClient->execute(updateQuery); 100 | return result?.affectedRowCount; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /load-tests/query_operation/deployment/deployment-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "apps/v1" 2 | kind: Deployment 3 | metadata: 4 | name: no-name 5 | spec: 6 | template: 7 | metadata: 8 | labels: 9 | logs: "true" 10 | spec: 11 | containers: 12 | - name: "query-operation-deployment" 13 | imagePullPolicy: Always 14 | -------------------------------------------------------------------------------- /load-tests/query_operation/deployment/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: query-operation 6 | annotations: 7 | kubernetes.io/ingress.class: nginx 8 | spec: 9 | rules: 10 | - host: bal.perf.test 11 | http: 12 | paths: 13 | - path: "/" 14 | pathType: Prefix 15 | backend: 16 | service: 17 | name: query-operation 18 | port: 19 | number: 9092 20 | -------------------------------------------------------------------------------- /load-tests/query_operation/deployment/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - query_operation.yaml 3 | - ingress.yaml 4 | - postgres_deployment.yml 5 | patches: 6 | - path: deployment-patch.yaml 7 | target: 8 | group: apps 9 | version: v1 10 | kind: Deployment 11 | name: query-operation-deployment 12 | -------------------------------------------------------------------------------- /load-tests/query_operation/deployment/postgres_deployment.yml: -------------------------------------------------------------------------------- 1 | ## PostgreSQL data storage 2 | kind: PersistentVolumeClaim 3 | apiVersion: v1 4 | metadata: 5 | name: postgres-data-pvc 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 1Gi 13 | --- 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | metadata: 17 | name: postgres-deployment 18 | spec: 19 | selector: 20 | matchLabels: 21 | app: postgres 22 | strategy: 23 | type: Recreate 24 | template: 25 | metadata: 26 | labels: 27 | app: postgres 28 | logs: "true" 29 | spec: 30 | containers: 31 | - name: postgres 32 | image: postgres 33 | env: 34 | - name: POSTGRES_USER 35 | value: postgres 36 | - name: POSTGRES_PASSWORD 37 | value: postgres 38 | ports: 39 | - containerPort: 5432 40 | volumeMounts: 41 | - name: data 42 | mountPath: /var/lib/postgres 43 | volumes: 44 | - name: data 45 | persistentVolumeClaim: 46 | claimName: postgres-data-pvc 47 | --- 48 | ## Service 49 | apiVersion: v1 50 | kind: Service 51 | metadata: 52 | name: postgres-service 53 | labels: 54 | app: postgres-server 55 | spec: 56 | type: NodePort 57 | ports: 58 | - port: 5432 59 | targetPort: 5432 60 | protocol: TCP 61 | selector: 62 | app: postgres 63 | --- 64 | apiVersion: v1 65 | kind: Service 66 | metadata: 67 | name: postgres-deployment 68 | spec: 69 | selector: 70 | app: postgres 71 | ports: 72 | - protocol: TCP 73 | port: 5432 74 | targetPort: 5432 75 | type: LoadBalancer 76 | --- 77 | -------------------------------------------------------------------------------- /load-tests/query_operation/scripts/http-get-request.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | true 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | continue 17 | 18 | false 19 | -1 20 | 21 | ${__P(users)} 22 | ${__P(rampUpPeriod,60)} 23 | true 24 | ${__P(duration)} 25 | true 26 | 27 | 28 | 29 | 30 | 31 | 32 | ${__P(host,localhost)} 33 | ${__P(port,9092)} 34 | ${__P(protocol,http)} 35 | 36 | customer?id=${random} 37 | GET 38 | true 39 | false 40 | true 41 | false 42 | 43 | HttpClient4 44 | 10000 45 | 30000 46 | 47 | 48 | 49 | 50 | 200 51 | 52 | 53 | Assertion.response_code 54 | false 55 | 16 56 | 57 | 58 | 59 | 60 | 8 61 | 1 62 | 0 63 | true 64 | 1 65 | random 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /load-tests/query_operation/scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # Copyright 2021 WSO2 Inc. (http://wso2.org) 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 | # Execution script for ballerina performance tests 18 | # ---------------------------------------------------------------------------- 19 | set -e 20 | source base-scenario.sh 21 | jmeter -n -t "$scriptsDir/"http-get-request.jmx -l "$resultsDir/"original.jtl -Jusers="$concurrent_users" -Jduration=600 -Jhost=bal.perf.test -Jport=80 22 | tail "$resultsDir/"original.jtl 23 | -------------------------------------------------------------------------------- /load-tests/query_operation/src/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "query_operation" 4 | version = "0.0.1" 5 | 6 | [build-options] 7 | cloud = "k8s" 8 | 9 | [[platform.java17.dependency]] 10 | groupId = "org.postgresql" 11 | artifactId = "postgresql" 12 | version = "42.2.20" 13 | -------------------------------------------------------------------------------- /load-tests/query_operation/src/Cloud.toml: -------------------------------------------------------------------------------- 1 | [container.image] 2 | repository = "ballerina" 3 | name = "query_operation" 4 | 5 | [cloud.deployment] 6 | min_memory = "256Mi" 7 | max_memory = "512Mi" 8 | min_cpu = "200m" 9 | max_cpu="1000m" 10 | 11 | [cloud.deployment.autoscaling] 12 | min_replicas = 1 13 | max_replicas = 1 14 | 15 | [[cloud.config.files]] 16 | file="Config.toml" 17 | -------------------------------------------------------------------------------- /load-tests/query_operation/src/Config.toml: -------------------------------------------------------------------------------- 1 | dbHost = "postgres-service" 2 | dbUsername = "postgres" 3 | dbPassword = "postgres" 4 | dbName = "postgres" 5 | dbPort = 5432 6 | -------------------------------------------------------------------------------- /load-tests/query_operation/src/query_operation.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 ballerinax/postgresql; 18 | import ballerina/http; 19 | 20 | // The username , password and name of the PostgreSQL database 21 | configurable string dbHost = ?; 22 | configurable string dbUsername = ?; 23 | configurable string dbPassword = ?; 24 | configurable string dbName = ?; 25 | configurable int dbPort = ?; 26 | 27 | type Customer record { 28 | int customerId; 29 | string lastName; 30 | string firstName; 31 | int registrationId; 32 | float creditLimit; 33 | string country; 34 | }; 35 | 36 | final postgresql:Client dbClient = check new(host = dbHost, username = dbUsername, password = dbPassword, port = dbPort, database = dbName); 37 | 38 | public function main() returns error? { 39 | _ = check dbClient->execute(` 40 | CREATE TABLE Customers ( 41 | customerId SERIAL, 42 | firstName VARCHAR(300), 43 | lastName VARCHAR(300), 44 | registrationID INT, 45 | creditLimit FLOAT, 46 | country VARCHAR(300) 47 | ); 48 | `); 49 | 50 | _ = check dbClient->execute(` 51 | INSERT INTO Customers(firstName, lastName, registrationID, creditLimit, country) 52 | VALUES ('Peter','Stuart', 1, 5000.75, 'USA')`); 53 | _ = check dbClient->execute(` 54 | INSERT INTO Customers(firstName, lastName, registrationID, creditLimit, country) 55 | VALUES ('Dan', 'Brown', 2, 10000, 'UK')`); 56 | _ = check dbClient->execute(` 57 | INSERT INTO Customers(firstName, lastName, registrationID, creditLimit, country) 58 | VALUES ('Peter','Stuart', 3, 5000.75, 'USA')`); 59 | _ = check dbClient->execute(` 60 | INSERT INTO Customers(firstName, lastName, registrationID, creditLimit, country) 61 | VALUES ('Dan', 'Brown', 4, 10000, 'UK')`); 62 | _ = check dbClient->execute(` 63 | INSERT INTO Customers(firstName, lastName, registrationID, creditLimit, country) 64 | VALUES ('Peter','Stuart', 5, 5000.75, 'USA')`); 65 | _ = check dbClient->execute(` 66 | INSERT INTO Customers(firstName, lastName, registrationID, creditLimit, country) 67 | VALUES ('Dan', 'Brown', 6, 10000, 'UK')`); 68 | _ = check dbClient->execute(` 69 | INSERT INTO Customers(firstName, lastName, registrationID, creditLimit, country) 70 | VALUES ('Peter','Stuart', 7, 5000.75, 'USA')`); 71 | _ = check dbClient->execute(` 72 | INSERT INTO Customers(firstName, lastName, registrationID, creditLimit, country) 73 | VALUES ('Dan', 'Brown', 8, 10000, 'UK')`); 74 | } 75 | 76 | isolated service /customer on new http:Listener(9092) { 77 | resource isolated function get .(int id) returns string|error { 78 | Customer customer = check dbClient->queryRow(`SELECT * FROM Customers WHERE customerId = ${id}`); 79 | return customer.toString(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /load-tests/stored_procedures/deployment/deployment-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "apps/v1" 2 | kind: Deployment 3 | metadata: 4 | name: no-name 5 | spec: 6 | template: 7 | metadata: 8 | labels: 9 | logs: "true" 10 | spec: 11 | containers: 12 | - name: "stored-procedures-deployment" 13 | imagePullPolicy: Always 14 | -------------------------------------------------------------------------------- /load-tests/stored_procedures/deployment/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: stored-procedures 6 | annotations: 7 | kubernetes.io/ingress.class: nginx 8 | spec: 9 | rules: 10 | - host: bal.perf.test 11 | http: 12 | paths: 13 | - path: "/" 14 | pathType: Prefix 15 | backend: 16 | service: 17 | name: stored-procedur 18 | port: 19 | number: 9092 20 | -------------------------------------------------------------------------------- /load-tests/stored_procedures/deployment/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - stored_procedures.yaml 3 | - ingress.yaml 4 | - postgres_deployment.yml 5 | patches: 6 | - path: deployment-patch.yaml 7 | target: 8 | group: apps 9 | version: v1 10 | kind: Deployment 11 | name: stored-procedures-deployment 12 | -------------------------------------------------------------------------------- /load-tests/stored_procedures/deployment/postgres_deployment.yml: -------------------------------------------------------------------------------- 1 | ## PostgreSQL data storage 2 | kind: PersistentVolumeClaim 3 | apiVersion: v1 4 | metadata: 5 | name: postgres-data-pvc 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 1Gi 13 | --- 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | metadata: 17 | name: postgres-deployment 18 | spec: 19 | selector: 20 | matchLabels: 21 | app: postgres 22 | strategy: 23 | type: Recreate 24 | template: 25 | metadata: 26 | labels: 27 | app: postgres 28 | logs: "true" 29 | spec: 30 | containers: 31 | - name: postgres 32 | image: postgres 33 | env: 34 | - name: POSTGRES_USER 35 | value: postgres 36 | - name: POSTGRES_PASSWORD 37 | value: postgres 38 | ports: 39 | - containerPort: 5432 40 | volumeMounts: 41 | - name: data 42 | mountPath: /var/lib/postgres 43 | volumes: 44 | - name: data 45 | persistentVolumeClaim: 46 | claimName: postgres-data-pvc 47 | --- 48 | ## Service 49 | apiVersion: v1 50 | kind: Service 51 | metadata: 52 | name: postgres-service 53 | labels: 54 | app: postgres-server 55 | spec: 56 | type: NodePort 57 | ports: 58 | - port: 5432 59 | targetPort: 5432 60 | protocol: TCP 61 | selector: 62 | app: postgres 63 | --- 64 | apiVersion: v1 65 | kind: Service 66 | metadata: 67 | name: postgres-deployment 68 | spec: 69 | selector: 70 | app: postgres 71 | ports: 72 | - protocol: TCP 73 | port: 5432 74 | targetPort: 5432 75 | type: LoadBalancer 76 | --- 77 | -------------------------------------------------------------------------------- /load-tests/stored_procedures/scripts/http-get-request.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | true 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | continue 17 | 18 | false 19 | -1 20 | 21 | ${__P(users)} 22 | ${__P(rampUpPeriod,60)} 23 | true 24 | ${__P(duration)} 25 | true 26 | 27 | 28 | 29 | 30 | 31 | 32 | ${__P(host,localhost)} 33 | ${__P(port,9092)} 34 | ${__P(protocol,http)} 35 | 36 | student?personId=${random} 37 | GET 38 | true 39 | false 40 | true 41 | false 42 | 43 | HttpClient4 44 | 10000 45 | 30000 46 | 47 | 48 | 49 | 50 | 200 51 | 52 | 53 | Assertion.response_code 54 | false 55 | 16 56 | 57 | 58 | 59 | 60 | 9 61 | 1 62 | 0 63 | true 64 | 1 65 | random 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /load-tests/stored_procedures/scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # Copyright 2021 WSO2 Inc. (http://wso2.org) 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 | # Execution script for ballerina performance tests 18 | # ---------------------------------------------------------------------------- 19 | set -e 20 | source base-scenario.sh 21 | jmeter -n -t "$scriptsDir/"http-get-request.jmx -l "$resultsDir/"original.jtl -Jusers="$concurrent_users" -Jduration=600 -Jhost=bal.perf.test -Jport=80 22 | tail "$resultsDir/"original.jtl 23 | -------------------------------------------------------------------------------- /load-tests/stored_procedures/src/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "stored_procedures" 4 | version = "0.0.1" 5 | 6 | [build-options] 7 | cloud = "k8s" 8 | 9 | [[platform.java17.dependency]] 10 | groupId = "org.postgresql" 11 | artifactId = "postgresql" 12 | version = "42.2.20" 13 | -------------------------------------------------------------------------------- /load-tests/stored_procedures/src/Cloud.toml: -------------------------------------------------------------------------------- 1 | [container.image] 2 | repository = "ballerina" 3 | name = "stored_procedures" 4 | 5 | [cloud.deployment] 6 | min_memory = "256Mi" 7 | max_memory = "512Mi" 8 | min_cpu = "200m" 9 | max_cpu="1000m" 10 | 11 | [cloud.deployment.autoscaling] 12 | min_replicas = 1 13 | max_replicas = 1 14 | 15 | [[cloud.config.files]] 16 | file="Config.toml" 17 | -------------------------------------------------------------------------------- /load-tests/stored_procedures/src/Config.toml: -------------------------------------------------------------------------------- 1 | dbHost = "postgres-service" 2 | dbUsername = "postgres" 3 | dbPassword = "postgres" 4 | dbName = "postgres" 5 | dbPort = 5432 6 | -------------------------------------------------------------------------------- /load-tests/stored_procedures/src/stored_procedures.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 ballerinax/postgresql; 18 | import ballerina/sql; 19 | import ballerina/http; 20 | 21 | configurable string dbHost = ?; 22 | configurable string dbUsername = ?; 23 | configurable string dbPassword = ?; 24 | configurable string dbName = ?; 25 | configurable int dbPort = ?; 26 | 27 | final postgresql:Client dbClient = check new(host = dbHost, username = dbUsername, password = dbPassword, port = dbPort, database = dbName); 28 | 29 | public function main() returns error? { 30 | _ = check dbClient->execute(`DROP TABLE IF EXISTS Student`); 31 | _ = check dbClient->execute(`CREATE TABLE Student 32 | (id bigint, age bigint, name text, 33 | PRIMARY KEY (id))`); 34 | 35 | _ = check dbClient->execute(`INSERT INTO Student(id, age, name) VALUES (1, 24, 'George')`); 36 | _ = check dbClient->execute(`INSERT INTO Student(id, age, name) VALUES (2, 25, 'Tom')`); 37 | _ = check dbClient->execute(`INSERT INTO Student(id, age, name) VALUES (3, 35, 'Michael')`); 38 | _ = check dbClient->execute(`INSERT INTO Student(id, age, name) VALUES (4, 24, 'George')`); 39 | _ = check dbClient->execute(`INSERT INTO Student(id, age, name) VALUES (5, 25, 'Tom')`); 40 | _ = check dbClient->execute(`INSERT INTO Student(id, age, name) VALUES (6, 35, 'Michael')`); 41 | _ = check dbClient->execute(`INSERT INTO Student(id, age, name) VALUES (7, 24, 'George')`); 42 | _ = check dbClient->execute(`INSERT INTO Student(id, age, name) VALUES (8, 25, 'Tom')`); 43 | _ = check dbClient->execute(`INSERT INTO Student(id, age, name) VALUES (9, 35, 'Michael')`); 44 | 45 | _ = check dbClient->execute(`CREATE OR REPLACE PROCEDURE GetCount 46 | (INOUT pID bigint, INOUT totalCount bigint) language plpgsql as $$ 47 | BEGIN 48 | SELECT age INTO pID FROM Student WHERE id = pID; 49 | SELECT COUNT(*) INTO totalCount FROM Student; 50 | END; $$ `); 51 | } 52 | 53 | isolated service /student on new http:Listener(9092) { 54 | resource isolated function get .(int personId) returns record {}|error { 55 | int count = 0; 56 | sql:InOutParameter id = new(personId); 57 | sql:InOutParameter totalCount = new(count); 58 | sql:ProcedureCallResult retCall = check dbClient->call(`CALL GetCount(${id}, ${totalCount})`); 59 | 60 | record {} result = { 61 | "age": check id.get(int), 62 | "totalCount": check totalCount.get(int) 63 | }; 64 | 65 | check retCall.close(); 66 | return result; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /native/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-library' 20 | id 'com.github.spotbugs' 21 | id 'checkstyle' 22 | id 'jacoco' 23 | } 24 | 25 | description = 'Ballerina - PostgreSQL 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-runtime', version: "${ballerinaLangVersion}" 37 | implementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}" 38 | implementation group: 'io.ballerina.stdlib', name: 'sql-native', version: "${stdlibSqlVersion}" 39 | implementation group: 'io.ballerina.stdlib', name: 'time-native', version: "${stdlibTimeVersion}" 40 | implementation group: 'io.ballerina.stdlib', name: 'io-native', version: "${stdlibIoVersion}" 41 | implementation group: 'org.postgresql', name: 'postgresql', version: "${postgreSQLDriverVersion}" 42 | } 43 | 44 | tasks.withType(JavaCompile) { 45 | options.encoding = 'UTF-8' 46 | } 47 | 48 | sourceCompatibility = JavaVersion.VERSION_21 49 | 50 | jacoco { 51 | toolVersion = "0.8.10" 52 | } 53 | 54 | test { 55 | testLogging { 56 | showStackTraces = true 57 | showStandardStreams = true 58 | events "failed" 59 | exceptionFormat "full" 60 | } 61 | jacoco { 62 | enabled = true 63 | destinationFile = file("$buildDir/coverage-reports/jacoco.exec") 64 | includeNoLocationClasses = true 65 | } 66 | } 67 | 68 | spotbugsMain { 69 | def classLoader = plugins["com.github.spotbugs"].class.classLoader 70 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") 71 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") 72 | effort = SpotBugsEffort.MAX 73 | reportLevel = SpotBugsConfidence.LOW 74 | ignoreFailures = true 75 | reportsDir = file("$project.buildDir/reports/spotbugs") 76 | def excludeFile = file("${rootDir}/build-config/spotbugs-exclude.xml") 77 | if (excludeFile.exists()) { 78 | it.excludeFilter = excludeFile 79 | } 80 | reports { 81 | text.enabled = true 82 | } 83 | } 84 | 85 | spotbugsTest { 86 | enabled = false 87 | } 88 | 89 | task validateSpotbugs() { 90 | doLast { 91 | if (spotbugsMain.reports.size() > 0 && 92 | spotbugsMain.reports[0].destination.exists() && 93 | spotbugsMain.reports[0].destination.text.readLines().size() > 0) { 94 | spotbugsMain.reports[0].destination?.eachLine { 95 | println 'Failure: ' + it 96 | } 97 | throw new GradleException("Spotbugs rule violations were found."); 98 | } 99 | } 100 | } 101 | 102 | checkstyle { 103 | toolVersion "${checkstylePluginVersion}" 104 | configFile file("${rootDir}/build-config/checkstyle/build/checkstyle.xml") 105 | configProperties = ["suppressionFile" : file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] 106 | } 107 | 108 | tasks.withType(Checkstyle) { 109 | exclude '**/module-info.java' 110 | } 111 | 112 | spotbugsMain.finalizedBy validateSpotbugs 113 | checkstyleMain.dependsOn(":checkstyle:downloadCheckstyleRuleFiles") 114 | 115 | compileJava { 116 | doFirst { 117 | options.compilerArgs = [ 118 | '--module-path', classpath.asPath, 119 | ] 120 | classpath = files() 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/postgresql/nativeimpl/CallProcessorUtils.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.postgresql.nativeimpl; 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.postgresql.parameterprocessor.PostgresResultParameterProcessor; 25 | import io.ballerina.stdlib.postgresql.parameterprocessor.PostgresStatementParameterProcessor; 26 | 27 | /** 28 | * This class holds the utility methods involved with executing the call statements. 29 | */ 30 | public class CallProcessorUtils { 31 | private CallProcessorUtils() { 32 | 33 | } 34 | 35 | public static Object nativeCall(Environment env, BObject client, BObject paramSQLString, BArray recordTypes) { 36 | 37 | return io.ballerina.stdlib.sql.nativeimpl.CallProcessor.nativeCall(env, client, paramSQLString, recordTypes, 38 | PostgresStatementParameterProcessor.getInstance(), PostgresResultParameterProcessor.getInstance()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/postgresql/nativeimpl/ClientProcessorUtils.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.postgresql.nativeimpl; 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.postgresql.Constants; 25 | import io.ballerina.stdlib.postgresql.utils.Utils; 26 | import io.ballerina.stdlib.sql.datasource.SQLDatasource; 27 | 28 | import java.util.Properties; 29 | 30 | /** 31 | * This class implements the utility methods for the clients to be used. 32 | */ 33 | public class ClientProcessorUtils { 34 | 35 | private ClientProcessorUtils() {} 36 | 37 | public static Object createClient(BObject client, BMap clientConfig, 38 | BMap globalPool) { 39 | String url = Constants.JDBC_URL + clientConfig.getStringValue(Constants.ClientConfiguration.HOST); 40 | Long portValue = clientConfig.getIntValue(Constants.ClientConfiguration.PORT); 41 | if (portValue > 0) { 42 | url += ":" + portValue.intValue(); 43 | } 44 | BString userVal = clientConfig.getStringValue(Constants.ClientConfiguration.USER); 45 | String user = userVal == null ? null : userVal.getValue(); 46 | BString passwordVal = clientConfig.getStringValue(Constants.ClientConfiguration.PASSWORD); 47 | String password = passwordVal == null ? null : passwordVal.getValue(); 48 | url += "/"; 49 | BString databaseVal = clientConfig.getStringValue(Constants.ClientConfiguration.DATABASE); 50 | String database = databaseVal == null ? null : databaseVal.getValue(); 51 | if (database != null && !database.isEmpty()) { 52 | url += database; 53 | } 54 | BMap options = clientConfig.getMapValue(Constants.ClientConfiguration.OPTIONS); 55 | BMap properties = null; 56 | Properties poolProperties = null; 57 | if (options != null) { 58 | properties = Utils.generateOptionsMap(options); 59 | Object connectTimeout = properties.get(Constants.DatabaseProps.CONNECT_TIMEOUT); 60 | if (connectTimeout != null) { 61 | poolProperties = new Properties(); 62 | poolProperties.setProperty(Constants.POOL_CONNECT_TIMEOUT, connectTimeout.toString()); 63 | } 64 | } 65 | BMap connectionPool = clientConfig.getMapValue(Constants.ClientConfiguration.CONNECTION_POOL_OPTIONS); 66 | String datasourceName = Constants.POSTGRESQL_DATASOURCE_NAME; 67 | SQLDatasource.SQLDatasourceParams sqlDatasourceParams = new SQLDatasource.SQLDatasourceParams() 68 | .setUrl(url).setUser(user) 69 | .setPassword(password) 70 | .setDatasourceName(datasourceName) 71 | .setOptions(properties) 72 | .setConnectionPool(connectionPool, globalPool) 73 | .setPoolProperties(poolProperties); 74 | return io.ballerina.stdlib.sql.nativeimpl.ClientProcessor.createClient(client, sqlDatasourceParams, true, true); 75 | } 76 | 77 | public static Object close(BObject client) { 78 | return io.ballerina.stdlib.sql.nativeimpl.ClientProcessor.close(client); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/postgresql/nativeimpl/ExecuteProcessorUtils.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.postgresql.nativeimpl; 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.postgresql.parameterprocessor.PostgresStatementParameterProcessor; 25 | 26 | /** 27 | * This class contains methods for executing SQL queries. 28 | */ 29 | public class ExecuteProcessorUtils { 30 | private ExecuteProcessorUtils() { 31 | 32 | } 33 | 34 | public static Object nativeExecute(Environment env, BObject client, BObject paramSQLString) { 35 | return io.ballerina.stdlib.sql.nativeimpl.ExecuteProcessor.nativeExecute(env, client, paramSQLString, 36 | PostgresStatementParameterProcessor.getInstance()); 37 | } 38 | 39 | public static Object nativeBatchExecute(Environment env, BObject client, BArray paramSQLStrings) { 40 | return io.ballerina.stdlib.sql.nativeimpl.ExecuteProcessor.nativeBatchExecute(env, client, paramSQLStrings, 41 | PostgresStatementParameterProcessor.getInstance()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/postgresql/nativeimpl/OutParameterProcessorUtils.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.postgresql.nativeimpl; 20 | 21 | import io.ballerina.runtime.api.values.BObject; 22 | import io.ballerina.runtime.api.values.BTypedesc; 23 | import io.ballerina.stdlib.postgresql.parameterprocessor.PostgresResultParameterProcessor; 24 | 25 | /** 26 | * This class provides the implementation of processing InOut/Out parameters of procedure calls. 27 | */ 28 | public class OutParameterProcessorUtils { 29 | public static Object getOutParameterValue(BObject result, BTypedesc typeDesc) { 30 | return io.ballerina.stdlib.sql.nativeimpl.OutParameterProcessor 31 | .get(result, typeDesc, PostgresResultParameterProcessor.getInstance(), "OutParameter"); 32 | } 33 | 34 | public static Object getInOutParameterValue(BObject result, BTypedesc typeDesc) { 35 | return io.ballerina.stdlib.sql.nativeimpl.OutParameterProcessor 36 | .get(result, typeDesc, PostgresResultParameterProcessor.getInstance(), "InOutParameter"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/postgresql/nativeimpl/QueryProcessorUtils.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.postgresql.nativeimpl; 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.postgresql.parameterprocessor.PostgresResultParameterProcessor; 26 | import io.ballerina.stdlib.postgresql.parameterprocessor.PostgresStatementParameterProcessor; 27 | 28 | /** 29 | * This class provides the query processing implementation which executes sql queries. 30 | */ 31 | public class QueryProcessorUtils { 32 | 33 | private QueryProcessorUtils() {} 34 | 35 | public static BStream nativeQuery(Environment env, BObject client, BObject paramSQLString, BTypedesc recordType) { 36 | return io.ballerina.stdlib.sql.nativeimpl.QueryProcessor.nativeQuery(env, client, paramSQLString, recordType, 37 | PostgresStatementParameterProcessor.getInstance(), PostgresResultParameterProcessor.getInstance()); 38 | } 39 | 40 | public static Object nativeQueryRow(Environment env, BObject client, BObject paramSQLString, BTypedesc recordType) { 41 | PostgresStatementParameterProcessor statementParametersProcessor = PostgresStatementParameterProcessor 42 | .getInstance(); 43 | PostgresResultParameterProcessor resultParametersProcessor = PostgresResultParameterProcessor.getInstance(); 44 | return io.ballerina.stdlib.sql.nativeimpl.QueryProcessor.nativeQueryRow(env, client, paramSQLString, recordType, 45 | statementParametersProcessor, resultParametersProcessor); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/postgresql/utils/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.postgresql.utils; 20 | 21 | import io.ballerina.runtime.api.Environment; 22 | import io.ballerina.runtime.api.Module; 23 | 24 | /** 25 | * Utility functions relevant to module operations. 26 | * 27 | * @since 0.1.0 28 | */ 29 | public class ModuleUtils { 30 | private static Module postgresqlModule; 31 | private ModuleUtils() {} 32 | 33 | public static void setModule(Environment env) { 34 | postgresqlModule = env.getCurrentModule(); 35 | } 36 | 37 | public static Module getModule() { 38 | return postgresqlModule; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/postgresql/utils/ProcedureCallResultUtils.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.postgresql.utils; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.stdlib.postgresql.parameterprocessor.PostgresResultParameterProcessor; 22 | 23 | /** 24 | * This class provides functionality for the `ProcedureCallResult` to iterate through the PostgreSQL result sets. 25 | */ 26 | public class ProcedureCallResultUtils { 27 | public static Object getNextQueryResult(BObject procedureCallResultset, BObject procedureCallResult) { 28 | return io.ballerina.stdlib.sql.utils.ProcedureCallResultUtils 29 | .getNextQueryResult(procedureCallResult, PostgresResultParameterProcessor.getInstance()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/postgresql/utils/RecordIteratorUtils.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.postgresql.utils; 20 | 21 | import io.ballerina.runtime.api.values.BObject; 22 | import io.ballerina.stdlib.postgresql.parameterprocessor.PostgresResultParameterProcessor; 23 | 24 | /** 25 | * This class provides functionality for the `RecordIterator` to iterate through the PostgreSQL result set. 26 | */ 27 | public class RecordIteratorUtils { 28 | public static Object nextResult(BObject postgresRecordIterator, BObject recordIterator) { 29 | return io.ballerina.stdlib.sql.utils.RecordIteratorUtils 30 | .nextResult(recordIterator, PostgresResultParameterProcessor.getInstance()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /native/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.postgresql { 20 | requires io.ballerina.runtime; 21 | requires io.ballerina.stdlib.io; 22 | requires io.ballerina.stdlib.time; 23 | requires io.ballerina.stdlib.sql; 24 | requires io.ballerina.lang; 25 | requires org.postgresql.jdbc; 26 | requires java.sql; 27 | exports io.ballerina.stdlib.postgresql; 28 | exports io.ballerina.stdlib.postgresql.nativeimpl; 29 | } 30 | -------------------------------------------------------------------------------- /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-base" 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 = 'ballerinax-postgresql' 36 | 37 | include ':checkstyle' 38 | include ':postgresql-native' 39 | include ':postgresql-compiler-plugin' 40 | include ':postgresql-ballerina' 41 | include ':postgresql-compiler-plugin-tests' 42 | include ':postgresql-examples' 43 | 44 | project(':checkstyle').projectDir = file("build-config${File.separator}checkstyle") 45 | project(':postgresql-native').projectDir = file('native') 46 | project(':postgresql-compiler-plugin').projectDir = file('compiler-plugin') 47 | project(':postgresql-ballerina').projectDir = file('ballerina') 48 | project(':postgresql-compiler-plugin-tests').projectDir = file('compiler-plugin-tests') 49 | project(':postgresql-examples').projectDir = file('examples') 50 | 51 | gradleEnterprise { 52 | buildScan { 53 | termsOfServiceUrl = 'https://gradle.com/terms-of-service' 54 | termsOfServiceAgree = 'yes' 55 | } 56 | } 57 | --------------------------------------------------------------------------------