├── .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 ├── tests │ ├── Config.toml │ ├── batch-execute-query-test.bal │ ├── call-procedures-test.bal │ ├── complex-query-test.bal │ ├── connection-init-test.bal │ ├── connection-pool-test.bal │ ├── connection-ssl-test.bal │ ├── error.bal │ ├── execute-basic-test.bal │ ├── execute-params-query-test.bal │ ├── init-container.bal │ ├── listener_tests.bal │ ├── local-transaction-test.bal │ ├── numerical-query-test.bal │ ├── resources │ │ ├── compose.yaml │ │ ├── files │ │ │ ├── blobValue.txt │ │ │ ├── byteValue.txt │ │ │ └── clobValue.txt │ │ ├── keystore │ │ │ ├── client │ │ │ │ ├── client-keystore.p12 │ │ │ │ └── client-truststore.p12 │ │ │ └── server │ │ │ │ ├── ca.pem │ │ │ │ ├── client-cert.pem │ │ │ │ ├── client-key.pem │ │ │ │ ├── server-cert.pem │ │ │ │ └── server-key.pem │ │ ├── my.cnf │ │ ├── mysql-ssl.cnf │ │ └── sql-scripts │ │ │ ├── batch-execute-test-data.sql │ │ │ ├── complex-test-data.sql │ │ │ ├── connection-pool-test-data.sql │ │ │ ├── connections-test-data.sql │ │ │ ├── error-test-data.sql │ │ │ ├── execute-params-test-data.sql │ │ │ ├── execute-test-data.sql │ │ │ ├── local-transaction-test-data.sql │ │ │ ├── mysql-cdc-setup.sql │ │ │ ├── numerical-test-data.sql │ │ │ ├── secureSocket-test-data.sql │ │ │ ├── simple-params-test-data.sql │ │ │ ├── stored-procedure-test-data.sql │ │ │ ├── xa-transaction-test-data-1.sql │ │ │ └── xa-transaction-test-data-2.sql │ ├── simple-params-query-test.bal │ ├── utils.bal │ └── xa-transactions-test.bal ├── types.bal └── utils.bal ├── build-config ├── checkstyle │ └── build.gradle ├── resources │ ├── Ballerina.toml │ └── CompilerPlugin.toml └── spotbugs-exclude.xml ├── build.gradle ├── changelog.md ├── codecov.yml ├── compiler-plugin-tests ├── build.gradle └── src │ └── test │ ├── java │ └── io │ │ └── ballerina │ │ └── stdlib │ │ └── mysql │ │ └── compiler │ │ ├── CompilerPluginTest.java │ │ └── staticcodeanalyzer │ │ ├── ProcessOutputGobbler.java │ │ └── StaticCodeAnalyzerTest.java │ └── resources │ ├── diagnostics │ ├── sample1 │ │ ├── Ballerina.toml │ │ └── main.bal │ ├── sample2 │ │ ├── Ballerina.toml │ │ └── main.bal │ ├── sample3 │ │ ├── Ballerina.toml │ │ └── main.bal │ ├── sample4 │ │ ├── Ballerina.toml │ │ └── main.bal │ ├── sample5 │ │ ├── Ballerina.toml │ │ └── main.bal │ └── sample6 │ │ ├── Ballerina.toml │ │ └── main.bal │ ├── static_code_analyzer │ ├── ballerina_packages │ │ └── rule1 │ │ │ ├── Ballerina.toml │ │ │ └── main.bal │ └── expected_output │ │ └── rule1.json │ └── testng.xml ├── compiler-plugin ├── build.gradle └── src │ └── main │ ├── java │ ├── io │ │ └── ballerina │ │ │ └── stdlib │ │ │ └── mysql │ │ │ └── compiler │ │ │ ├── Constants.java │ │ │ ├── MySQLCodeAnalyzer.java │ │ │ ├── MySQLCompilerPlugin.java │ │ │ ├── MySQLDiagnosticsCode.java │ │ │ ├── Utils.java │ │ │ ├── analyzer │ │ │ ├── InitializerParamAnalyzer.java │ │ │ └── RecordAnalyzer.java │ │ │ └── staticcodeanalyzer │ │ │ ├── MySQLRule.java │ │ │ ├── MySQLStaticCodeAnalyzer.java │ │ │ ├── RuleFactory.java │ │ │ ├── RuleImpl.java │ │ │ └── SecurePasswordAnalyzer.java │ └── module-info.java │ └── resources │ └── rules.json ├── docs ├── proposals │ ├── add-MySQL-server-failover-support.md │ ├── add-option-noAccessToProcedureBodies.md │ └── default-username-for-client-connections.md └── spec │ └── spec.md ├── examples ├── build.gradle ├── employees-db │ ├── Config.toml │ ├── Working with a MySQL Database.md │ ├── service │ │ ├── Ballerina.toml │ │ └── service.bal │ └── setup │ │ ├── Ballerina.toml │ │ └── setup.bal └── fraud-detection │ ├── .github │ └── README.md │ ├── Ballerina.toml │ ├── Fraud Detection.md │ ├── db-scripts │ ├── setup.sql │ └── test.sql │ ├── docker-compose.yml │ └── main.bal ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── load-tests ├── delete │ ├── deployment │ │ ├── deployment-patch.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ └── mysql_deployment.yml │ ├── results │ │ └── summary.csv │ ├── scripts │ │ ├── http-delete-request.jmx │ │ ├── init.sql │ │ └── run.sh │ └── src │ │ ├── Ballerina.toml │ │ ├── Cloud.toml │ │ ├── Config.toml │ │ └── delete.bal ├── insert │ ├── deployment │ │ ├── deployment-patch.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ └── mysql_deployment.yml │ ├── results │ │ └── summary.csv │ ├── scripts │ │ ├── http-post-request.jmx │ │ ├── init.sql │ │ └── run.sh │ └── src │ │ ├── Ballerina.toml │ │ ├── Cloud.toml │ │ ├── Config.toml │ │ └── insert.bal ├── select │ ├── deployment │ │ ├── deployment-patch.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ └── mysql_deployment.yml │ ├── results │ │ └── summary.csv │ ├── scripts │ │ ├── http-get-request.jmx │ │ ├── init.sql │ │ └── run.sh │ └── src │ │ ├── Ballerina.toml │ │ ├── Cloud.toml │ │ ├── Config.toml │ │ └── select.bal └── update │ ├── deployment │ ├── deployment-patch.yaml │ ├── ingress.yaml │ ├── kustomization.yaml │ └── mysql_deployment.yml │ ├── results │ └── summary.csv │ ├── scripts │ ├── http-put-request.jmx │ ├── init.sql │ └── run.sh │ └── src │ ├── Ballerina.toml │ ├── Cloud.toml │ ├── Config.toml │ └── udate.bal ├── native ├── build.gradle └── src │ └── main │ └── java │ ├── io │ └── ballerina │ │ └── stdlib │ │ └── mysql │ │ ├── Constants.java │ │ ├── Utils.java │ │ ├── nativeimpl │ │ ├── CallProcessor.java │ │ ├── ClientProcessor.java │ │ ├── ExecuteProcessor.java │ │ └── QueryProcessor.java │ │ ├── parameterprocessor │ │ ├── MysqlResultParameterProcessor.java │ │ └── MysqlStatementParameterProcessor.java │ │ └── utils │ │ ├── ModuleUtils.java │ │ ├── MysqlRecordIteratorUtils.java │ │ └── ProcedureCallResultUtils.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 @RDPerera @shafreenAnfar 8 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | Fixes: 4 | 5 | ## Examples 6 | 7 | ## Checklist 8 | - [ ] Linked to an issue 9 | - [ ] Updated the specification 10 | - [ ] Updated the changelog 11 | - [ ] Added tests 12 | - [ ] Checked native-image compatibility 13 | -------------------------------------------------------------------------------- /.github/workflows/build-timestamped-master.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - 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 build will be skipped) 12 | required: false 13 | default: '' 14 | native_image_options: 15 | description: Default native-image options 16 | required: false 17 | default: '' 18 | schedule: 19 | - cron: '30 18 * * *' 20 | pull_request: 21 | branches: 22 | - master 23 | types: [opened, synchronize, reopened, labeled, unlabeled] 24 | 25 | concurrency: 26 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} 27 | cancel-in-progress: true 28 | 29 | jobs: 30 | call_stdlib_workflow: 31 | name: Run StdLib Workflow 32 | if: ${{ github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository_owner == 'ballerina-platform') }} 33 | uses: ballerina-platform/ballerina-library/.github/workflows/build-with-bal-test-graalvm-template.yml@main 34 | with: 35 | lang_tag: ${{ inputs.lang_tag }} 36 | lang_version: ${{ inputs.lang_version }} 37 | native_image_options: '-J-Xmx7G ${{ inputs.native_image_options }}' 38 | additional_windows_build_flags: '-x test' 39 | -------------------------------------------------------------------------------- /.github/workflows/central-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to the Ballerina central 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | environment: 7 | type: choice 8 | description: Select Environment 9 | required: true 10 | options: 11 | - DEV CENTRAL 12 | - STAGE CENTRAL 13 | 14 | jobs: 15 | call_workflow: 16 | name: Run Central Publish Workflow 17 | if: ${{ github.repository_owner == 'ballerina-platform' }} 18 | uses: ballerina-platform/ballerina-library/.github/workflows/central-publish-template.yml@main 19 | secrets: inherit 20 | with: 21 | environment: ${{ github.event.inputs.environment }} 22 | -------------------------------------------------------------------------------- /.github/workflows/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 :mysql-compiler-plugin-tests:test -x :mysql-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-mysql\", 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: [mysql-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: mysql 16 | package-org: ballerinax 17 | additional-build-flags: "-x :mysql-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: 'mysql-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 22 * * *' 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-mysql' 28 | runtime_artifacts_url: 'https://api.github.com/repos/ballerina-platform/module-ballerinax-mysql/actions/artifacts' 29 | dispatch_type: 'mysql-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 | with: 15 | additional-build-flags: "-x :mysql-examples:build" 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # Ballerina 26 | Ballerina.lock 27 | 28 | #Idea files 29 | .idea 30 | *.iml 31 | *.ipr 32 | *.iws 33 | 34 | # generated files 35 | target 36 | .ballerina 37 | /compiler-plugin-tests/bin/ 38 | 39 | # gradle 40 | .gradle 41 | build/ 42 | gradle-app.setting 43 | !gradle-wrapper.jar 44 | .gradletasknamecache 45 | 46 | # mac 47 | .DS_Store 48 | 49 | .classpath 50 | .project 51 | .settings 52 | .vscode 53 | 54 | #Ignore examples auto generated files 55 | examples/**/Dependencies.toml 56 | examples/**/Config.toml 57 | 58 | compiler-plugin-test/**/target 59 | -------------------------------------------------------------------------------- /ballerina/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "ballerinax" 3 | name = "mysql" 4 | version = "1.16.0" 5 | authors = ["Ballerina"] 6 | keywords = ["database", "client", "network", "SQL", "RDBMS", "MySQL"] 7 | repository = "https://github.com/ballerina-platform/module-ballerinax-mysql" 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 = "mysql-native" 18 | version = "1.16.0" 19 | path = "../native/build/libs/mysql-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 | -------------------------------------------------------------------------------- /ballerina/CompilerPlugin.toml: -------------------------------------------------------------------------------- 1 | [plugin] 2 | id = "mysql-compiler-plugin" 3 | class = "io.ballerina.stdlib.mysql.compiler.MySQLCompilerPlugin" 4 | 5 | [[dependency]] 6 | path = "../compiler-plugin/build/libs/mysql-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 MySQL 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 MySQL listener with the given configuration. 27 | # 28 | # + config - The configuration for the MySQL connector 29 | public isolated function init(*MySqlListenerConfiguration 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 | populateMySqlConfigurations(config.database, configMap); 52 | self.config = configMap.cloneReadOnly(); 53 | } 54 | 55 | # Attaches a CDC service to the MySQL 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 MySQL 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 MySQL 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 MySQL 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 MySQL 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-mysql/254f83e7242f1a7d510de8664d620465e9c8e817/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.mysql.utils.ModuleUtils" 25 | } external; 26 | -------------------------------------------------------------------------------- /ballerina/tests/Config.toml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | # 4 | # WSO2 Inc. licenses this file to you under the Apache License, 5 | # Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | # 18 | 19 | [ballerina.sql] 20 | maxOpenConnections=10 21 | maxConnectionLifeTime=2000.5 22 | minIdleConnections=5 23 | -------------------------------------------------------------------------------- /ballerina/tests/batch-execute-query-test.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/sql; 18 | import ballerina/test; 19 | 20 | string batchExecuteDB = "BATCH_EXECUTE_DB"; 21 | 22 | @test:Config { 23 | groups: ["batch-execute"] 24 | } 25 | function batchInsertIntoDataTable() returns error? { 26 | var data = [ 27 | {intVal: 3, longVal: 9223372036854774807, floatVal: 123.34}, 28 | {intVal: 4, longVal: 9223372036854774807, floatVal: 123.34}, 29 | {intVal: 5, longVal: 9223372036854774807, floatVal: 123.34} 30 | ]; 31 | sql:ParameterizedQuery[] sqlQueries = 32 | from var row in data 33 | select `INSERT INTO DataTable (int_type, long_type, float_type) VALUES (${row.intVal}, ${row.longVal}, ${row.floatVal})`; 34 | validateBatchExecutionResult(check batchExecuteQueryMySQLClient(sqlQueries), [1, 1, 1], [2,3,4]); 35 | } 36 | 37 | @test:Config { 38 | groups: ["batch-execute"], 39 | dependsOn: [batchInsertIntoDataTable] 40 | } 41 | function batchInsertIntoDataTable2() returns error? { 42 | int intType = 6; 43 | sql:ParameterizedQuery sqlQuery = `INSERT INTO DataTable (int_type) VALUES(${intType})`; 44 | sql:ParameterizedQuery[] sqlQueries = [sqlQuery]; 45 | validateBatchExecutionResult(check batchExecuteQueryMySQLClient(sqlQueries), [1], [5]); 46 | } 47 | 48 | @test:Config { 49 | groups: ["batch-execute"], 50 | dependsOn: [batchInsertIntoDataTable2] 51 | } 52 | function batchInsertIntoDataTableFailure() { 53 | var data = [ 54 | {intVal: 7, longVal: 9223372036854774807, floatVal: 123.34}, 55 | {intVal: 1, longVal: 9223372036854774807, floatVal: 123.34}, 56 | {intVal: 9, longVal: 9223372036854774807, floatVal: 123.34} 57 | ]; 58 | sql:ParameterizedQuery[] sqlQueries = 59 | from var row in data 60 | select `INSERT INTO DataTable (int_type, long_type, float_type) VALUES (${row.intVal}, ${row.longVal}, ${row.floatVal})`; 61 | sql:ExecutionResult[]|error result = batchExecuteQueryMySQLClient(sqlQueries); 62 | test:assertTrue(result is error); 63 | 64 | if result is sql:BatchExecuteError { 65 | sql:BatchExecuteErrorDetail errorDetails = result.detail(); 66 | test:assertEquals(errorDetails.executionResults.length(), 3); 67 | test:assertEquals(errorDetails.executionResults[0].affectedRowCount, 1); 68 | test:assertEquals(errorDetails.executionResults[1].affectedRowCount, -3); 69 | test:assertEquals(errorDetails.executionResults[2].affectedRowCount, 1); 70 | } else { 71 | test:assertFail("Database Error expected."); 72 | } 73 | } 74 | 75 | isolated function validateBatchExecutionResult(sql:ExecutionResult[] results, int[] rowCount, int[] lastId) { 76 | test:assertEquals(results.length(), rowCount.length()); 77 | 78 | int i = 0; 79 | while i < results.length() { 80 | test:assertEquals(results[i].affectedRowCount, rowCount[i]); 81 | int|string? lastInsertIdVal = results[i].lastInsertId; 82 | if lastId[i] == -1 { 83 | test:assertNotEquals(lastInsertIdVal, ()); 84 | } else if lastInsertIdVal is int { 85 | test:assertTrue(lastInsertIdVal > 1, "Last Insert Id is nil."); 86 | } else { 87 | test:assertFail("The last insert id should be an integer."); 88 | } 89 | i = i + 1; 90 | } 91 | } 92 | 93 | function batchExecuteQueryMySQLClient(sql:ParameterizedQuery[] sqlQueries) returns sql:ExecutionResult[]|error { 94 | Client dbClient = check new (host, user, password, batchExecuteDB, port); 95 | sql:ExecutionResult[] result = check dbClient->batchExecute(sqlQueries); 96 | check dbClient.close(); 97 | return result; 98 | } 99 | -------------------------------------------------------------------------------- /ballerina/tests/connection-ssl-test.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, 10 | // software distributed under the License is distributed on an 11 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 12 | // KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations 14 | // under the License. 15 | 16 | import ballerina/file; 17 | import ballerina/lang.'string as strings; 18 | import ballerina/sql; 19 | import ballerina/test; 20 | 21 | int sslPort = 3307; 22 | string sslDB = "SSL_CONNECT_DB"; 23 | 24 | string clientStorePath = check file:getAbsolutePath("./tests/resources/keystore/client/client-keystore.p12"); 25 | string trustStorePath = check file:getAbsolutePath("./tests/resources/keystore/client/client-truststore.p12"); 26 | 27 | @test:Config { 28 | groups: ["connection", "ssl"] 29 | } 30 | function testSSLVerifyCert() returns error? { 31 | Options options = { 32 | ssl: { 33 | mode: SSL_VERIFY_CA, 34 | key: { 35 | path: clientStorePath, 36 | password: "password" 37 | }, 38 | cert: { 39 | path: trustStorePath, 40 | password: "password" 41 | } 42 | } 43 | }; 44 | Client dbClient = check new (user = user, password = password, database = sslDB, 45 | port = sslPort, options = options); 46 | test:assertEquals(dbClient.close(), ()); 47 | } 48 | 49 | @test:Config { 50 | groups: ["connection", "ssl"] 51 | } 52 | function testSSLPreferred() returns error? { 53 | Options options = { 54 | ssl: { 55 | mode: SSL_PREFERRED, 56 | key: { 57 | path: clientStorePath, 58 | password: "password" 59 | }, 60 | cert: { 61 | path: trustStorePath, 62 | password: "password" 63 | } 64 | } 65 | }; 66 | Client dbClient = check new (user = user, password = password, database = sslDB, 67 | port = sslPort, options = options); 68 | test:assertEquals(dbClient.close(), ()); 69 | } 70 | 71 | @test:Config { 72 | groups: ["connection", "ssl"] 73 | } 74 | function testSSLRequiredWithClientCert() returns error? { 75 | Options options = { 76 | ssl: { 77 | mode: SSL_REQUIRED, 78 | key: { 79 | path: clientStorePath, 80 | password: "password" 81 | } 82 | } 83 | }; 84 | Client dbClient = check new (user = user, password = password, database = sslDB, 85 | port = sslPort, options = options); 86 | test:assertEquals(dbClient.close(), ()); 87 | } 88 | 89 | @test:Config { 90 | groups: ["connection", "ssl"] 91 | } 92 | function testSSLVerifyIdentity() { 93 | Options options = { 94 | ssl: { 95 | mode: SSL_VERIFY_IDENTITY, 96 | key: { 97 | path: clientStorePath, 98 | password: "password" 99 | }, 100 | cert: { 101 | path: trustStorePath, 102 | password: "password" 103 | } 104 | } 105 | }; 106 | Client|sql:Error dbClient = new (user = user, password = password, database = sslDB, 107 | port = sslPort, options = options); 108 | test:assertTrue(dbClient is error); 109 | error dbError = dbClient; 110 | test:assertTrue(strings:includes(dbError.message(), "Common Name 'MySQL_Server_8.0.21_Auto_Generated_Server_Certificate'" + 111 | " does not match 'localhost'."), dbError.message()); 112 | } 113 | -------------------------------------------------------------------------------- /ballerina/tests/init-container.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/test; 19 | import ballerina/file; 20 | 21 | string resourcePath = check file:getAbsolutePath("tests/resources"); 22 | 23 | string host = "localhost"; 24 | string user = "root"; 25 | string user1 = "newuser"; 26 | string password = "Test123#"; 27 | int port = 3305; 28 | 29 | @test:BeforeSuite 30 | isolated function beforeSuite() { 31 | io:println("Test suite initiated"); 32 | } 33 | 34 | @test:AfterSuite {} 35 | isolated function afterSuite() { 36 | io:println("Test suite finished"); 37 | } 38 | -------------------------------------------------------------------------------- /ballerina/tests/resources/compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | mysql: 3 | image: mysql:8.0.40 4 | container_name: ballerina-mysql 5 | environment: 6 | MYSQL_ROOT_PASSWORD: Test123# 7 | ports: 8 | - "3305:3306" 9 | volumes: 10 | - ./sql-scripts:/docker-entrypoint-initdb.d 11 | - ./keystore/server/:/etc/ssl/ 12 | - ./my.cnf:/etc/my.cnf 13 | healthcheck: 14 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pTest123#"] 15 | interval: 10s 16 | timeout: 5s 17 | retries: 5 18 | 19 | mysql-limited: 20 | image: mysql:8.0.40 21 | container_name: ballerina-mysql-limited 22 | environment: 23 | MYSQL_ROOT_PASSWORD: Test123# 24 | ports: 25 | - "3303:3306" 26 | volumes: 27 | - ./sql-scripts:/docker-entrypoint-initdb.d 28 | - ./keystore/server/:/etc/ssl/ 29 | - ./my.cnf:/etc/my.cnf 30 | healthcheck: 31 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pTest123#"] 32 | interval: 10s 33 | timeout: 5s 34 | retries: 5 35 | 36 | mysql-ssl: 37 | image: mysql:8.0.40 38 | container_name: ballerina-mysql-ssl 39 | environment: 40 | MYSQL_ROOT_PASSWORD: Test123# 41 | ports: 42 | - "3307:3306" 43 | volumes: 44 | - ./sql-scripts:/docker-entrypoint-initdb.d 45 | - ./keystore/server:/etc/ssl 46 | - ./mysql-ssl.cnf:/etc/my.cnf 47 | healthcheck: 48 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pTest123#"] 49 | interval: 10s 50 | timeout: 5s 51 | retries: 5 52 | 53 | mysql-trx: 54 | image: mysql:8.0.40 55 | container_name: ballerina-mysql-trx 56 | environment: 57 | MYSQL_ROOT_PASSWORD: Test123# 58 | ports: 59 | - "3304:3306" 60 | volumes: 61 | - ./sql-scripts:/docker-entrypoint-initdb.d 62 | - ./keystore/server/:/etc/ssl/ 63 | - ./my.cnf:/etc/my.cnf 64 | healthcheck: 65 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pTest123#"] 66 | interval: 10s 67 | timeout: 5s 68 | retries: 5 69 | 70 | mysql-cdc: 71 | image: mysql:8.0 72 | container_name: mysql-cdc 73 | ports: 74 | - "3308:3306" 75 | environment: 76 | MYSQL_ROOT_PASSWORD: root 77 | MYSQL_DATABASE: store_db 78 | volumes: 79 | - ./sql-scripts/mysql-cdc-setup.sql:/docker-entrypoint-initdb.d/cdc-setup.sql 80 | healthcheck: 81 | test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ] 82 | interval: 10s 83 | timeout: 5s 84 | retries: 5 85 | -------------------------------------------------------------------------------- /ballerina/tests/resources/files/blobValue.txt: -------------------------------------------------------------------------------- 1 | wso2 ballerina blob test. -------------------------------------------------------------------------------- /ballerina/tests/resources/files/byteValue.txt: -------------------------------------------------------------------------------- 1 | wso2 ballerina binary test. -------------------------------------------------------------------------------- /ballerina/tests/resources/files/clobValue.txt: -------------------------------------------------------------------------------- 1 | very long text -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/client/client-keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mysql/254f83e7242f1a7d510de8664d620465e9c8e817/ballerina/tests/resources/keystore/client/client-keystore.p12 -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/client/client-truststore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mysql/254f83e7242f1a7d510de8664d620465e9c8e817/ballerina/tests/resources/keystore/client/client-truststore.p12 -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/server/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDAzCCAeugAwIBAgIBATANBgkqhkiG9w0BAQsFADA8MTowOAYDVQQDDDFNeVNR 3 | TF9TZXJ2ZXJfOC4wLjIxX0F1dG9fR2VuZXJhdGVkX0NBX0NlcnRpZmljYXRlMB4X 4 | DTIyMDMyNDE1NDk1MloXDTMyMDMyMTE1NDk1MlowPDE6MDgGA1UEAwwxTXlTUUxf 5 | U2VydmVyXzguMC4yMV9BdXRvX0dlbmVyYXRlZF9DQV9DZXJ0aWZpY2F0ZTCCASIw 6 | DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMGUobtCNGRbruXFMjJG/jH8/c5 7 | rkS3nH8Rwh5MDU6DwZ3uA4PcDQWMRJ0TBcYiWqTa6Ex0Volh3scnOSx3NHThSbWb 8 | PILcK8JALZHERQSV7ganpSbPWHCN/G/QGTq47FfreMsxqWOfAifd1fHpUhTFnSYE 9 | KKgWrf2Ur+80EdOgrEalEKZ+29+6N3rVczialAegEDSioBdwma4Aagq1psaHQQY9 10 | 3uJDEnGFk59E5/9ahU+Nyf1aMq8gM2jtLdmLhlBpZNpJzqy7my+b6BMD3jkjg6VS 11 | iA2UfE2BnqMbd+h7Yqho/cBt11/RnBxPG76UUvGAefClISJucpnAfAY88rkCAwEA 12 | AaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVcXEoNln4BaT 13 | O54jMh03PsVmEMoLpA+4nlsdLWnm86QiVReznpzjQLRI43mEyl8aJ1eM2wDMn/d/ 14 | pldgMolhUuaSOT6vjJIuJQt7+RKxuSA6vBqCU6PZvxuo9zsFgNJ26XFY1EckaSTx 15 | wL+jr14qiiv5oTUHR7jAPqXFQuhYSMCblAAWtv1dLwWjYhIpqTdGg9mHiNZAyrnj 16 | 5Uq+85QTkvvMCdabW/TJVz+4o0ut4mHKfTaYGPk+1ZukM+aDOgLsLVF7huS2X+jx 17 | U7uoPyPqAtMB0DX4ups9Sgp2v+StCY0/Wy3cAan8V0qBz1NsBhHqf3gUTUZWtaI6 18 | U7yhsY8YIQ== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/server/client-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDBDCCAeygAwIBAgIBAzANBgkqhkiG9w0BAQsFADA8MTowOAYDVQQDDDFNeVNR 3 | TF9TZXJ2ZXJfOC4wLjIxX0F1dG9fR2VuZXJhdGVkX0NBX0NlcnRpZmljYXRlMB4X 4 | DTIyMDMyNDE1NDk1MloXDTMyMDMyMTE1NDk1MlowQDE+MDwGA1UEAww1TXlTUUxf 5 | U2VydmVyXzguMC4yMV9BdXRvX0dlbmVyYXRlZF9DbGllbnRfQ2VydGlmaWNhdGUw 6 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+5FKR4Rmo+Nn7VD7V3J+v 7 | bcZci7ydDqEQ80U5wEmIY4abDjaP0K8xBcnM+m08KQbKcIt/Yli3Dy5mq+97zB8H 8 | n1JdfEYMfcw8oJYhl+DGrXhckm6O8Z/st1ho7f2yIMcXRNtGh8CndyctLMDnu9No 9 | PBH71TvKyTIdNqxl0NwyocKBkrsUzCSNnqtw/f1JjXhsazR9reJ5KrtJejs/VtM6 10 | 8XfRnmF311AkWLcFc6BsxNrwh7hGPBEptYiON/IgxrTYx6xaLWAPMksXp/YX4S6o 11 | 0p2x6sTPET4mrdmDi6bIRR2W8YFJub7vHNYxVLqk35MAfBrBSwGA2+isdqDGh2bd 12 | AgMBAAGjDTALMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggEBAFlJqZasTSM+ 13 | /q5/4xWK8ZPjpt8Hfe0ma5e5PjNhVqEBOFmSN23vyq37lNeWNgfGPhAItAbcGMKp 14 | ErnvWOIzX+ScxuuShLg6p5/HJG4FP9B09zA8ntvDQyLLb+xlH+qfmUEv3MEsY2Hx 15 | Vte1y7TR/mH3lTizic7tD3wF/HwkjNJa+yBLBhQFzLTxujV4kUVU7ZwNBd2VKriT 16 | iZBDEklm6qIfBLWWNX9kHGO8LjEC2YevUkv75utgrplqxaGVa2IjOfVeDxECUUnS 17 | 5yUgyyaC1bxJogSDLOj9KarxKxdvc7K4jyxKbYt/E79jvto99i8sFDepcDLtcYL4 18 | xm1J9Mi15Zc= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/server/client-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAvuRSkeEZqPjZ+1Q+1dyfr23GXIu8nQ6hEPNFOcBJiGOGmw42 3 | j9CvMQXJzPptPCkGynCLf2JYtw8uZqvve8wfB59SXXxGDH3MPKCWIZfgxq14XJJu 4 | jvGf7LdYaO39siDHF0TbRofAp3cnLSzA57vTaDwR+9U7yskyHTasZdDcMqHCgZK7 5 | FMwkjZ6rcP39SY14bGs0fa3ieSq7SXo7P1bTOvF30Z5hd9dQJFi3BXOgbMTa8Ie4 6 | RjwRKbWIjjfyIMa02MesWi1gDzJLF6f2F+EuqNKdserEzxE+Jq3Zg4umyEUdlvGB 7 | Sbm+7xzWMVS6pN+TAHwawUsBgNvorHagxodm3QIDAQABAoIBAHF2cQW4kHH5CEf0 8 | +SxQ6LFzRFY50LBhw6a5kkoTWyGwVo/PUOsGlTtEP4CQ0WDS2fB2GNRsdmLIqUHp 9 | rH0fBMqZDnH2rgQ6uazHnrT0+2vcLBCKESDxyacAC5LC8upvxSa1jMhNZFul3Sli 10 | 0n5rC+uG2QGg6ttL33exyaLzFA8bQgdUpLR6HNMqLnpvD/LW0t48hMbC2ensDdtN 11 | PlN29qWHvWFakE44aoFI8tTJnREqUynljbLAxmy5pdpokNgpOtdlLWLqjkOI/TBI 12 | YQo+Ee1bf90qlnxhURV5+VD+stxDyo3FSe6RbZOJ2d543JqMmXMPWL+PzokIE59h 13 | UEWDhZkCgYEA+s+krfLX53oAjYLIoeE0N9j6K20m9xu7yVFz3eTFdAxUimgf340E 14 | 0c8jlQBby1jqQj/8dGnWvq7vGNSNrarNp15Cps3rFLnW5MWVCaBkfSfYmKBFuNG9 15 | NREyAzJoncv2ZSDU94bD8sZDm3o34YLqJRuszASlM82VLlo/H3Olo9cCgYEAwtdV 16 | HGKW5YSbhE2EN3/pBSIUwopHlqzLmL2N7mqOJp8YJMeC8Gymque1/jfZ5m9uGypv 17 | HSnwyEbbZZdRXkiPlLkmNgIUXMZHj6LU6ofRQkW6g7eiNce6wdBDE9K4d4SQZO+c 18 | 6iiQsfUyki89ytlsf4WQtJGBoaMXpIusyeyV9GsCgYAGJWx9rsPHsl+tGBVekiw7 19 | ah/HTKd1ysIxTsOuHlsQWvT/Z0nQqp4BnjfbAOU++HDVKsg++hD/Hz5Qt3S5WsQr 20 | Y83yVH18RomTlZvvXnTX9FAEfXj37Hvcfw1gsq2JoGPrWoCdiDnpCx7BAp+38QNX 21 | 4XO8lCiQOmt7dU6ysJzQhQKBgQCjtf6jfQtBCm0Je4BuiaEnWP2MgFeqeMIRMqRB 22 | AXMzbFYDAUg573ETBOJcGl2SS2p+lOcL4COahD7wW3ZY/Cr4UaGTm6e0VD3oqG6y 23 | KTBguOoAppk7CvkWxIC39URd2BrjVJnJ/g+mF1pIjj0jZhDODVILBn+fasQA1AN5 24 | HrrYxQKBgDYldVCgLB6/O8CAVmdktgqhTefjAKEVDxkyMc3X4FkT7G+8ZQKJA2L4 25 | YIMP4fmnUC57lJ1etY9M43hX8hGqDL/mjEPBoalAS0el0dp5K0CI87EOa7SRgL7l 26 | tUADKu3kLmj1UViM2zaCi5L7na23dPIPQ43oxw6IheUi5vb4PqM7 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/server/server-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDBDCCAeygAwIBAgIBAjANBgkqhkiG9w0BAQsFADA8MTowOAYDVQQDDDFNeVNR 3 | TF9TZXJ2ZXJfOC4wLjIxX0F1dG9fR2VuZXJhdGVkX0NBX0NlcnRpZmljYXRlMB4X 4 | DTIyMDMyNDE1NDk1MloXDTMyMDMyMTE1NDk1MlowQDE+MDwGA1UEAww1TXlTUUxf 5 | U2VydmVyXzguMC4yMV9BdXRvX0dlbmVyYXRlZF9TZXJ2ZXJfQ2VydGlmaWNhdGUw 6 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJqRX4M5pPC+VAu/Ih7h9B 7 | ajM2xubHPML1Gq442xDGAh6BMI9j7XDsSBJWvgP9Tmo4O4HTzTeqeXM2+U0nREke 8 | N1OXZysSdL5gUopxoCLrlYaCpcYlh/PnKAlWhETLkR/dkQkfHGBsmhhbvIppxDbv 9 | Z7JKHBDJe5vOnauiIY7TshV3WPY8fNk6v20AsxI1IUuJiwalKh7DZbhy21jvtDl+ 10 | Hq+VM+3gcqBHIic0ppiQ23T+PkdVUw/z6XIfC6YX3NUtyQUK82BoLyKsr2tr4121 11 | GHGof1/qRrxXmGNCFf2pMbyv05szphdVgAU+ZaN6sivUMT2UpXkChQaElINpfLxT 12 | AgMBAAGjDTALMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggEBAC3qs9sxIs4n 13 | 86xwmEnTlwLGHJTssOmtNVm0iD7kvnYZSfMX2BsNyoKt9ohGXAGLKQKgcf6I7iVB 14 | nRFxH/v+ddH4HLr484uS6sWNxMogUDtwhzkfELvW3NLjjNGcZv7CK5HqHr5MVgC4 15 | WejI4mEddLsvG9jcDY8Wvvw9KvK1sXk9uNJV/0siejRESQlSf5brzFhztKbO90+T 16 | T+nxBpw3WTvGjDscz5p7DYtwhILv2Qtrz+mMOqySbtAXDgnhiBXXLKKvswWRrjna 17 | jzYCW3vPk5R3/6vUpxe/4Tl1Zbl7FeRbxOLC/W88hCZkGge5ONNA4LwXAULTB81f 18 | 8Dj+RLR2u+I= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /ballerina/tests/resources/keystore/server/server-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEAyakV+DOaTwvlQLvyIe4fQWozNsbmxzzC9RquONsQxgIegTCP 3 | Y+1w7EgSVr4D/U5qODuB0803qnlzNvlNJ0RJHjdTl2crEnS+YFKKcaAi65WGgqXG 4 | JYfz5ygJVoREy5Ef3ZEJHxxgbJoYW7yKacQ272eyShwQyXubzp2roiGO07IVd1j2 5 | PHzZOr9tALMSNSFLiYsGpSoew2W4cttY77Q5fh6vlTPt4HKgRyInNKaYkNt0/j5H 6 | VVMP8+lyHwumF9zVLckFCvNgaC8irK9ra+NdtRhxqH9f6ka8V5hjQhX9qTG8r9Ob 7 | M6YXVYAFPmWjerIr1DE9lKV5AoUGhJSDaXy8UwIDAQABAoIBAQC7nrMv/2K71Idw 8 | 2OwIIXG2/MW1WwzvpVqFjFM31qkecG5NKA7gm9MKImvdhGBV1hUBSGwb0LzPwLsv 9 | FHdx5xhYIoWFQZlTTIarO2BPIvwaTz2cY/ucg4arNBasBdezxcvt6rif11jm8d9j 10 | ymDE0qeByeqZBM+hhX2KmCtNZwdpcIkjYiuX9pjmNkjCOrOYMNBOFZHmcUHIuSj8 11 | jENm5kOMGUYgDf6ihU6DDVfBOVAGphHvMLkDP764sDg3ieHYQd1/ucc+w0a7BHCf 12 | XsprBnROQsRpZZDFchXAWCmJKNM9ApiXqS8l+xFPl7EbxcejJwDaTwLNwb5QIn77 13 | SsHko+lBAoGBAO+D/INuUgxyFvkNzGFviApUnb4A6lJ5sYjzWDlHFQ8f2QcHwTXV 14 | CJQShml4c+cTtgQOIC7V9SYz0YNL4Slxovx7kJE7eddAVWJb9GhdWJJ7P6d7UahN 15 | EPDKMFrD0Y+E8aCwb34bJWOHWpW/CX8gxDih0Ow887jQo/61T679mdAxAoGBANeK 16 | Ie8UqM1RXW4LJ2yEYrsTzRkY/PcURy03H+eYZEZ63nD3kbWdnXMtOl2rvEGoUJ/l 17 | r4omvdLxNk0XQcqOack9LW5xRldcLy8dZuiDvFj0z3dbII7zlAvyg+lrMBDXzfyz 18 | am7nK1mAPAVE3vYwXrSGOJhcgOetmxH6tS9ymtfDAoGBANWz49e41Qg5u3mX8CV3 19 | h9//w4bF9kyEO/0/chYY8BdAiTmWl7NaUn8bUEZGrNMeaSaRG/HuAP+G+Ia3azy5 20 | IX05GrIaaQm/Yu+RsC52KxL3WMIsa51ItbbCEAbL9Oyi55xCEBhqTB/TouU9QFHn 21 | gGwvJOPDNopNziTyzRgLOfPhAoGBALfFAVu7rJSqC9PYVLu0QA2rO1JruLrdIjaN 22 | 6njmuJBTEDcXDbfgc68Q39Ofqfn9DQjXp4xNrckdeiPOcXzHYbB/pa2ljMjNQzmT 23 | gvs53qulxwHHw4G+cfqhwhCRIEEsDmenfVajaJV9vS7s4oDbCtQ2ICjfrdRac32n 24 | 2TVkLFtLAoGBANyaS2IuHkG1TkCrzrT6z4PzXcfMTHmWS1FgLioQ7J+V9/BdrBNk 25 | udaxzMS/UQ9QwS4DMBu9QXRo79C7Icqw+wWHm+j3fyoJJ4/plfuRQhozG9Yi/vPq 26 | 7ZZoIHvgK/MhwC3t6vJK0KxnkD+1QoY9nVZG++YLto1uclklgYdx8Mda 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /ballerina/tests/resources/my.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | ssl_ca=/etc/ssl/ca.pem 3 | ssl_cert=/etc/ssl/server-cert.pem 4 | ssl_key=/etc/ssl/server-key.pem 5 | -------------------------------------------------------------------------------- /ballerina/tests/resources/mysql-ssl.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | ssl-cipher=DHE-RSA-AES256-SHA 3 | ssl_ca=/etc/ssl/ca.pem 4 | ssl_cert=/etc/ssl/server-cert.pem 5 | ssl_key=/etc/ssl/server-key.pem 6 | 7 | [client] 8 | ssl-mode=PREFERRED 9 | ssl_cert=/etc/ssl/client-cert.pem 10 | ssl_key=/etc/ssl/client-key.pem -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/batch-execute-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS BATCH_EXECUTE_DB; 2 | 3 | USE BATCH_EXECUTE_DB; 4 | 5 | DROP TABLE IF EXISTS DataTable; 6 | 7 | CREATE TABLE DataTable( 8 | id INT AUTO_INCREMENT, 9 | int_type INTEGER UNIQUE, 10 | long_type BIGINT, 11 | float_type FLOAT, 12 | PRIMARY KEY (id) 13 | ); 14 | 15 | INSERT INTO DataTable (int_type, long_type, float_type) 16 | VALUES(1, 9223372036854774807, 123.34); 17 | 18 | 19 | INSERT INTO DataTable (int_type, long_type, float_type) 20 | VALUES(2, 9372036854774807, 124.34); 21 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/connection-pool-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS POOL_DB_1; 2 | 3 | USE POOL_DB_1; 4 | 5 | DROP TABLE IF EXISTS Customers; 6 | 7 | CREATE TABLE IF NOT EXISTS Customers( 8 | customerId INTEGER NOT NULL AUTO_INCREMENT, 9 | firstName VARCHAR(300), 10 | lastName VARCHAR(300), 11 | registrationID INTEGER, 12 | creditLimit DOUBLE, 13 | country VARCHAR(300), 14 | PRIMARY KEY (customerId) 15 | ); 16 | 17 | INSERT INTO Customers (firstName,lastName,registrationID,creditLimit,country) 18 | VALUES ('Peter', 'Stuart', 1, 5000.75, 'USA'); 19 | 20 | INSERT INTO Customers (firstName,lastName,registrationID,creditLimit,country) 21 | VALUES ('Dan', 'Brown', 2, 10000, 'UK'); 22 | 23 | CREATE DATABASE IF NOT EXISTS POOL_DB_2; 24 | 25 | USE POOL_DB_2; 26 | 27 | DROP TABLE IF EXISTS Customers; 28 | 29 | CREATE TABLE IF NOT EXISTS Customers( 30 | customerId INTEGER NOT NULL AUTO_INCREMENT, 31 | firstName VARCHAR(300), 32 | lastName VARCHAR(300), 33 | registrationID INTEGER, 34 | creditLimit DOUBLE, 35 | country VARCHAR(300), 36 | PRIMARY KEY (customerId) 37 | ); 38 | 39 | INSERT INTO Customers (firstName,lastName,registrationID,creditLimit,country) 40 | VALUES ('Peter', 'Stuart', 1, 5000.75, 'USA'); 41 | 42 | INSERT INTO Customers (firstName,lastName,registrationID,creditLimit,country) 43 | VALUES ('Dan', 'Brown', 2, 10000, 'UK'); -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/connections-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS CONNECT_DB; 2 | 3 | USE CONNECT_DB; 4 | 5 | DROP TABLE IF EXISTS Customers; 6 | 7 | CREATE TABLE Customers( 8 | customerId INTEGER NOT NULL AUTO_INCREMENT, 9 | firstName VARCHAR(300), 10 | lastName VARCHAR(300), 11 | registrationID INTEGER, 12 | creditLimit DOUBLE, 13 | country VARCHAR(300), 14 | PRIMARY KEY (customerId) 15 | ); 16 | 17 | INSERT INTO Customers (firstName,lastName,registrationID,creditLimit,country) 18 | VALUES ('Peter', 'Stuart', 1, 5000.75, 'USA'); 19 | INSERT INTO Customers (firstName,lastName,registrationID,creditLimit,country) 20 | VALUES ('Tom', 'John', 2, 6000.75, 'UK'); 21 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/error-test-data.sql: -------------------------------------------------------------------------------- 1 | DROP DATABASE IF EXISTS ERROR_DB; 2 | 3 | CREATE DATABASE IF NOT EXISTS ERROR_DB; 4 | 5 | USE ERROR_DB; 6 | 7 | DROP TABLE IF EXISTS DataTable; 8 | 9 | CREATE TABLE IF NOT EXISTS DataTable( 10 | row_id INTEGER, 11 | string_type VARCHAR(50), 12 | PRIMARY KEY (row_id) 13 | ); 14 | 15 | INSERT INTO DataTable (row_id, string_type) VALUES(1, '{""q}'); 16 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/execute-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS EXECUTE_DB; 2 | 3 | USE EXECUTE_DB; 4 | 5 | DROP TABLE IF EXISTS NumericTypes; 6 | 7 | CREATE TABLE NumericTypes ( 8 | id INT AUTO_INCREMENT, 9 | int_type INT, 10 | bigint_type BIGINT, 11 | smallint_type SMALLINT, 12 | tinyint_type TINYINT, 13 | bit_type BIT, 14 | decimal_type DECIMAL(10,2), 15 | numeric_type NUMERIC(10,2), 16 | float_type FLOAT, 17 | real_type REAL, 18 | PRIMARY KEY (id) 19 | ); 20 | 21 | INSERT INTO NumericTypes (int_type) VALUES (10); 22 | 23 | DROP TABLE IF EXISTS StringTypes; 24 | 25 | CREATE TABLE StringTypes ( 26 | id INT, 27 | varchar_type VARCHAR(255), 28 | charmax_type CHAR(10), 29 | char_type CHAR, 30 | charactermax_type CHARACTER(10), 31 | character_type CHARACTER, 32 | nvarcharmax_type NVARCHAR(255), 33 | longvarchar_type VARCHAR(511), 34 | clob_type TEXT, 35 | PRIMARY KEY (id) 36 | ); 37 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/local-transaction-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS LOCAL_TRANSACTION; 2 | 3 | USE LOCAL_TRANSACTION; 4 | 5 | CREATE TABLE IF NOT EXISTS Customers( 6 | customerId INTEGER NOT NULL AUTO_INCREMENT, 7 | firstName VARCHAR(300), 8 | lastName VARCHAR(300), 9 | registrationID INTEGER, 10 | creditLimit DOUBLE, 11 | country VARCHAR(300), 12 | PRIMARY KEY (customerId) 13 | ); 14 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/mysql-cdc-setup.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS store_db; 2 | USE store_db; 3 | 4 | CREATE TABLE vendors ( 5 | id INT PRIMARY KEY, 6 | name VARCHAR(255), 7 | contact_info TEXT 8 | ); 9 | 10 | INSERT INTO vendors VALUES 11 | (1, 'Samsung', 'contact@samsung.com'), 12 | (2, 'Apple', 'contact@apple.com'); 13 | 14 | CREATE TABLE products ( 15 | id INT PRIMARY KEY, 16 | name VARCHAR(255), 17 | price DECIMAL(10,2), 18 | description TEXT, 19 | vendor_id INT, 20 | FOREIGN KEY (vendor_id) REFERENCES vendors(id) 21 | ); 22 | 23 | INSERT INTO products VALUES 24 | (1001, 'Samsung Galaxy S24', 999.99, 'Flagship phone with AI camera', 1), 25 | (1002, 'Apple iPhone 15 Pro', 1099.00, 'New titanium design', 2); 26 | 27 | CREATE TABLE product_reviews ( 28 | review_id INT PRIMARY KEY, 29 | product_id INT, 30 | rating INT CHECK (rating BETWEEN 1 AND 5), 31 | comment TEXT, 32 | FOREIGN KEY (product_id) REFERENCES products(id) 33 | ); 34 | 35 | INSERT INTO product_reviews VALUES 36 | (1, 1001, 5, 'Amazing camera'), 37 | (2, 1001, 4, 'Great battery life'), 38 | (3, 1002, 5, 'Best iPhone yet'); 39 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/numerical-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS QUERY_NUMERIC_PARAMS_DB; 2 | 3 | USE QUERY_NUMERIC_PARAMS_DB; 4 | 5 | DROP TABLE IF EXISTS NumericTypes; 6 | 7 | CREATE TABLE NumericTypes ( 8 | ID INT AUTO_INCREMENT, 9 | INT_TYPE INT NOT NULL, 10 | BIGINT_TYPE BIGINT NOT NULL, 11 | SMALLINT_TYPE SMALLINT NOT NULL , 12 | TINYINT_TYPE TINYINT NOT NULL , 13 | BIT_TYPE BIT NOT NULL , 14 | DECIMAL_TYPE DECIMAL(10,3) NOT NULL , 15 | NUMERIC_TYPE NUMERIC(10,3) NOT NULL , 16 | FLOAT_TYPE FLOAT NOT NULL , 17 | REAL_TYPE REAL NOT NULL , 18 | PRIMARY KEY (id) 19 | ); 20 | 21 | INSERT INTO NumericTypes (ID, INT_TYPE, BIGINT_TYPE, SMALLINT_TYPE, TINYINT_TYPE, BIT_TYPE, DECIMAL_TYPE, NUMERIC_TYPE, 22 | FLOAT_TYPE, REAL_TYPE) VALUES (1, 2147483647, 9223372036854774807, 32767, 127, 1, 1234.567, 1234.567, 1234.567, 23 | 1234.567); 24 | 25 | DROP TABLE IF EXISTS NumericNullTypes; 26 | 27 | CREATE TABLE NumericNullTypes ( 28 | ID INT AUTO_INCREMENT, 29 | INT_TYPE INT, 30 | BIGINT_TYPE BIGINT, 31 | SMALLINT_TYPE SMALLINT, 32 | TINYINT_TYPE TINYINT, 33 | BIT_TYPE BIT, 34 | DECIMAL_TYPE DECIMAL(10,3), 35 | NUMERIC_TYPE NUMERIC(10,3), 36 | FLOAT_TYPE FLOAT, 37 | REAL_TYPE REAL, 38 | PRIMARY KEY (ID) 39 | ); 40 | 41 | INSERT INTO NumericNullTypes (ID, INT_TYPE, BIGINT_TYPE, SMALLINT_TYPE, TINYINT_TYPE, BIT_TYPE, DECIMAL_TYPE, NUMERIC_TYPE, 42 | FLOAT_TYPE, REAL_TYPE) VALUES (1, 2147483647, 9223372036854774807, 32767, 127, 1, 1234.567, 1234.567, 1234.567, 43 | 1234.567); 44 | 45 | INSERT INTO NumericNullTypes (ID, INT_TYPE, BIGINT_TYPE, SMALLINT_TYPE, TINYINT_TYPE, BIT_TYPE, DECIMAL_TYPE, NUMERIC_TYPE, 46 | FLOAT_TYPE, REAL_TYPE) VALUES (2, null , null , null , null , null , null , null , null , 47 | null ); 48 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/secureSocket-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS SSL_CONNECT_DB; 2 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/simple-params-test-data.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS QUERY_SIMPLE_PARAMS_DB; 2 | 3 | USE QUERY_SIMPLE_PARAMS_DB; 4 | 5 | DROP TABLE IF EXISTS DataTable; 6 | 7 | CREATE TABLE IF NOT EXISTS DataTable( 8 | row_id INTEGER, 9 | int_type INTEGER, 10 | long_type BIGINT, 11 | float_type FLOAT, 12 | double_type DOUBLE, 13 | boolean_type BOOLEAN, 14 | string_type VARCHAR(50), 15 | decimal_type DECIMAL(20, 2), 16 | PRIMARY KEY (row_id) 17 | ); 18 | 19 | INSERT INTO DataTable (row_id, int_type, long_type, float_type, double_type, boolean_type, string_type, decimal_type) 20 | VALUES(1, 1, 9223372036854774807, 123.34, 2139095039, TRUE, 'Hello', 23.45); 21 | 22 | INSERT INTO DataTable (row_id) VALUES (2); 23 | 24 | INSERT INTO DataTable (row_id, int_type, long_type, float_type, double_type, boolean_type, string_type, decimal_type) 25 | VALUES(3, 1, 9372036854774807, 124.34, 29095039, false, '1', 25.45); 26 | 27 | DROP TABLE IF EXISTS ComplexTypes; 28 | 29 | CREATE TABLE IF NOT EXISTS ComplexTypes( 30 | row_id INTEGER NOT NULL, 31 | tinyblob_type TINYBLOB, 32 | blob_type BLOB, 33 | mediumblob_type MEDIUMBLOB, 34 | longblob_type LONGBLOB, 35 | tinytext_type TINYTEXT, 36 | text_type TEXT, 37 | mediumtext_type MEDIUMTEXT, 38 | longtext_type LONGTEXT, 39 | binary_type BINARY(27), 40 | var_binary_type VARBINARY(27), 41 | PRIMARY KEY (row_id) 42 | ); 43 | 44 | INSERT INTO ComplexTypes (row_id, tinyblob_type, blob_type, mediumblob_type, longblob_type, tinytext_type, text_type, 45 | mediumtext_type, longtext_type, binary_type, var_binary_type) VALUES 46 | (1, X'77736F322062616C6C6572696E6120626C6F6220746573742E', X'77736F322062616C6C6572696E6120626C6F6220746573742E', 47 | X'77736F322062616C6C6572696E6120626C6F6220746573742E', X'77736F322062616C6C6572696E6120626C6F6220746573742E', 48 | 'very long text', 'very long text','very long text','very long text', 49 | X'77736F322062616C6C6572696E612062696E61727920746573742E', X'77736F322062616C6C6572696E612062696E61727920746573742E'); 50 | 51 | INSERT INTO ComplexTypes (row_id, tinyblob_type, blob_type, mediumblob_type, longblob_type, tinytext_type, text_type, 52 | mediumtext_type, longtext_type, binary_type, var_binary_type) VALUES 53 | (2, null, null, null, null, null, null, null, null, null, null); 54 | 55 | DROP TABLE IF EXISTS NumericTypes; 56 | 57 | CREATE TABLE NumericTypes ( 58 | id INT AUTO_INCREMENT, 59 | int_type INT NOT NULL, 60 | bigint_type BIGINT NOT NULL, 61 | smallint_type SMALLINT NOT NULL , 62 | mediumint_type MEDIUMINT NOT NULL , 63 | tinyint_type TINYINT NOT NULL , 64 | bit_type BIT NOT NULL , 65 | decimal_type DECIMAL(10,3) NOT NULL , 66 | numeric_type NUMERIC(10,3) NOT NULL , 67 | float_type FLOAT NOT NULL , 68 | real_type REAL NOT NULL , 69 | PRIMARY KEY (id) 70 | ); 71 | 72 | INSERT INTO NumericTypes (id, int_type, bigint_type, smallint_type, mediumint_type, tinyint_type, bit_type, decimal_type, numeric_type, 73 | float_type, real_type) VALUES (1, 2147483647, 9223372036854774807, 32767, 8388607, 127, 1, 1234.567, 1234.567, 1234.567, 74 | 1234.567); 75 | 76 | INSERT INTO NumericTypes (id, int_type, bigint_type, smallint_type, mediumint_type, tinyint_type, bit_type, decimal_type, numeric_type, 77 | float_type, real_type) VALUES (2, 2147483647, 9223372036854774807, 32767, 8388607, 127, 1, 1234, 1234, 1234, 78 | 1234); 79 | 80 | DROP TABLE IF EXISTS DateTimeTypes; 81 | 82 | CREATE TABLE IF NOT EXISTS DateTimeTypes( 83 | row_id INTEGER NOT NULL, 84 | date_type DATE, 85 | time_type TIME, 86 | timestamp_type TIMESTAMP, 87 | datetime_type DATETIME, 88 | PRIMARY KEY (row_id) 89 | ); 90 | 91 | INSERT INTO DateTimeTypes (row_id, date_type, time_type, datetime_type, timestamp_type) VALUES 92 | (1,'2017-02-03', '11:35:45', '2017-02-03 11:53:00', '2017-02-03 11:53:00'); 93 | 94 | DROP TABLE IF EXISTS ENUMTable; 95 | 96 | CREATE TABLE ENUMTable ( 97 | id integer NOT NULL, 98 | enum_type ENUM('admin','doctor','housekeeper') DEFAULT NULL, 99 | PRIMARY KEY (id) 100 | ); 101 | 102 | INSERT INTO ENUMTable(id, enum_type) VALUES (1, 'doctor'); 103 | 104 | DROP TABLE IF EXISTS SetTable; 105 | 106 | CREATE TABLE SetTable ( 107 | row_id INTEGER NOT NULL, 108 | set_type SET('a', 'b', 'c', 'd') 109 | ); 110 | 111 | INSERT INTO SetTable (row_id, set_type) VALUES (1, 'a,d'), (2, 'd,a'), (3, 'a,d,a'); 112 | 113 | DROP TABLE IF EXISTS GEOTable; 114 | 115 | CREATE TABLE GEOTable( 116 | id INTEGER NOT NULL , 117 | geom GEOMETRY 118 | ); 119 | 120 | INSERT INTO GEOTable (id, geom) values (1, ST_GeomFromText('POINT(7 52)')); 121 | 122 | DROP TABLE IF EXISTS JsonTable; 123 | 124 | CREATE TABLE JsonTable( 125 | id INTEGER NOT NULL , 126 | json_type JSON 127 | ); 128 | 129 | INSERT INTO JsonTable (id, json_type) values (1, JSON_OBJECT('id', 100, 'name', 'Joe', 'groups', JSON_ARRAY(2,5))); 130 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/xa-transaction-test-data-1.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS XA_TRANSACTION_1; 2 | 3 | USE XA_TRANSACTION_1; 4 | 5 | CREATE TABLE IF NOT EXISTS Customers( 6 | customerId INTEGER, 7 | name VARCHAR(300), 8 | creditLimit DOUBLE, 9 | country VARCHAR(300) 10 | ); 11 | 12 | CREATE TABLE IF NOT EXISTS CustomersTrx( 13 | customerId INTEGER, 14 | name VARCHAR(300), 15 | creditLimit DOUBLE, 16 | country VARCHAR(300), 17 | PRIMARY KEY (customerId) 18 | ); 19 | 20 | INSERT INTO CustomersTrx VALUES (30, 'Oliver', 200000, 'UK'); 21 | -------------------------------------------------------------------------------- /ballerina/tests/resources/sql-scripts/xa-transaction-test-data-2.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS XA_TRANSACTION_2; 2 | 3 | USE XA_TRANSACTION_2; 4 | 5 | CREATE TABLE IF NOT EXISTS Salary ( 6 | ID INTEGER, 7 | VALUE DOUBLE 8 | ); 9 | 10 | CREATE TABLE IF NOT EXISTS SalaryTrx ( 11 | ID INTEGER, 12 | VALUE DOUBLE, 13 | PRIMARY KEY (ID) 14 | ); 15 | 16 | INSERT INTO SalaryTrx VALUES (20, 30000); 17 | 18 | -------------------------------------------------------------------------------- /ballerina/tests/utils.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerinax/mysql.driver as _; 19 | 20 | isolated function getUntaintedData(record {}? value, string fieldName) returns anydata { 21 | if value is record {} { 22 | return value[fieldName]; 23 | } 24 | return {}; 25 | } 26 | 27 | isolated function getByteColumnChannel() returns io:ReadableByteChannel|error { 28 | io:ReadableByteChannel byteChannel = check io:openReadableFile("./tests/resources/files/byteValue.txt"); 29 | return byteChannel; 30 | } 31 | 32 | isolated function getBlobColumnChannel() returns io:ReadableByteChannel|error { 33 | io:ReadableByteChannel byteChannel = check io:openReadableFile("./tests/resources/files/blobValue.txt"); 34 | return byteChannel; 35 | } 36 | 37 | isolated function getClobColumnChannel() returns io:ReadableCharacterChannel|error { 38 | io:ReadableByteChannel byteChannel = check io:openReadableFile("./tests/resources/files/clobValue.txt"); 39 | io:ReadableCharacterChannel sourceChannel = new (byteChannel, "UTF-8"); 40 | return sourceChannel; 41 | } 42 | 43 | isolated function getTextColumnChannel() returns io:ReadableCharacterChannel|error { 44 | io:ReadableByteChannel byteChannel = check io:openReadableFile("./tests/resources/files/clobValue.txt"); 45 | io:ReadableCharacterChannel sourceChannel = new (byteChannel, "UTF-8"); 46 | return sourceChannel; 47 | } 48 | -------------------------------------------------------------------------------- /ballerina/types.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 | import ballerina/random; 19 | import ballerina/sql; 20 | import ballerinax/cdc; 21 | 22 | # The iterator for the stream returned in `query` function to be used to override the default behaviour of `sql:ResultIterator`. 23 | public distinct class CustomResultIterator { 24 | *sql:CustomResultIterator; 25 | 26 | public isolated function nextResult(sql:ResultIterator iterator) returns record {}|sql:Error? = @java:Method { 27 | 'class: "io.ballerina.stdlib.mysql.utils.MysqlRecordIteratorUtils", 28 | paramTypes: ["io.ballerina.runtime.api.values.BObject", "io.ballerina.runtime.api.values.BObject"] 29 | } external; 30 | 31 | public isolated function getNextQueryResult(sql:ProcedureCallResult callResult) returns boolean|sql:Error = @java:Method { 32 | 'class: "io.ballerina.stdlib.mysql.utils.ProcedureCallResultUtils", 33 | paramTypes: ["io.ballerina.runtime.api.values.BObject", "io.ballerina.runtime.api.values.BObject"] 34 | } external; 35 | } 36 | 37 | # Represents the configuration for the MySQL CDC listener. 38 | # 39 | # + database - The MySQL database connection configuration 40 | public type MySqlListenerConfiguration record {| 41 | MySqlDatabaseConnection database; 42 | *cdc:ListenerConfiguration; 43 | |}; 44 | 45 | # Represents the configuration for the MySQL CDC database connection. 46 | # 47 | # + connectorClass - The class name of the MySQL connector implementation to use 48 | # + hostname - The hostname of the MySQL server 49 | # + port - The port number of the MySQL server 50 | # + databaseServerId - The unique identifier for the MySQL server 51 | # + includedDatabases - A list of regular expressions matching fully-qualified database identifiers to capture changes from (should not be used alongside databaseExclude) 52 | # + excludedDatabases - A list of regular expressions matching fully-qualified database identifiers to exclude from change capture (should not be used alongside databaseInclude) 53 | # + tasksMax - The maximum number of tasks to create for this connector. Because the MySQL connector always uses a single task, changing the default value has no effect 54 | # + secure - The connector establishes an encrypted connection if the server supports secure connections 55 | public type MySqlDatabaseConnection record {| 56 | *cdc:DatabaseConnection; 57 | string connectorClass = "io.debezium.connector.mysql.MySqlConnector"; 58 | string hostname = "localhost"; 59 | int port = 3306; 60 | string databaseServerId = (checkpanic random:createIntInRange(0, 100000)).toString(); 61 | string|string[] includedDatabases?; 62 | string|string[] excludedDatabases?; 63 | int tasksMax = 1; 64 | cdc:SecureDatabaseConnection secure = {}; 65 | |}; 66 | -------------------------------------------------------------------------------- /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 | 17 | const string MYSQL_DATABASE_SERVER_ID = "database.server.id"; 18 | const string MYSQL_DATABASE_INCLUDE_LIST = "database.include.list"; 19 | const string MYSQL_DATABASE_EXCLUDE_LIST = "database.exclude.list"; 20 | 21 | // Populates MySQL-specific configurations 22 | isolated function populateMySqlConfigurations(MySqlDatabaseConnection connection, map configMap) { 23 | configMap[MYSQL_DATABASE_SERVER_ID] = connection.databaseServerId.toString(); 24 | 25 | string|string[]? includedDatabases = connection.includedDatabases; 26 | if includedDatabases !is () { 27 | configMap[MYSQL_DATABASE_INCLUDE_LIST] = includedDatabases is string ? includedDatabases : string:'join(",", ...includedDatabases); 28 | } 29 | 30 | string|string[]? excludedDatabases = connection.excludedDatabases; 31 | if excludedDatabases !is () { 32 | configMap[MYSQL_DATABASE_EXCLUDE_LIST] = excludedDatabases is string ? excludedDatabases : string:'join(",", ...excludedDatabases); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /build-config/checkstyle/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | plugins { 19 | id "de.undercouch.download" 20 | } 21 | 22 | apply plugin: 'java' 23 | 24 | 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 = "mysql" 4 | version = "@toml.version@" 5 | authors = ["Ballerina"] 6 | keywords = ["database", "client", "network", "SQL", "RDBMS", "MySQL"] 7 | repository = "https://github.com/ballerina-platform/module-ballerinax-mysql" 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 = "mysql-native" 18 | version = "@toml.version@" 19 | path = "../native/build/libs/mysql-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 | -------------------------------------------------------------------------------- /build-config/resources/CompilerPlugin.toml: -------------------------------------------------------------------------------- 1 | [plugin] 2 | id = "mysql-compiler-plugin" 3 | class = "io.ballerina.stdlib.mysql.compiler.MySQLCompilerPlugin" 4 | 5 | [[dependency]] 6 | path = "../compiler-plugin/build/libs/mysql-compiler-plugin-@project.version@.jar" 7 | -------------------------------------------------------------------------------- /build-config/spotbugs-exclude.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "load-tests" 3 | 4 | coverage: 5 | precision: 2 6 | round: down 7 | range: "60...80" 8 | status: 9 | project: 10 | default: 11 | target: 80 12 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/java/io/ballerina/stdlib/mysql/compiler/staticcodeanalyzer/ProcessOutputGobbler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. 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.mysql.compiler.staticcodeanalyzer; 20 | 21 | import java.io.BufferedReader; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.io.InputStreamReader; 25 | import java.nio.charset.StandardCharsets; 26 | 27 | /** 28 | * Helper class to consume the process streams. 29 | */ 30 | public class ProcessOutputGobbler implements Runnable { 31 | private final InputStream inputStream; 32 | private final StringBuilder output; 33 | private int exitCode; 34 | 35 | public ProcessOutputGobbler(InputStream inputStream) { 36 | this.inputStream = inputStream; 37 | this.output = new StringBuilder(); 38 | } 39 | 40 | @Override 41 | public void run() { 42 | try (BufferedReader reader = new BufferedReader( 43 | new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { 44 | String line; 45 | while ((line = reader.readLine()) != null) { 46 | output.append(line).append("\n"); 47 | } 48 | } catch (IOException e) { 49 | this.output.append(e.getMessage()); 50 | } 51 | } 52 | 53 | public String getOutput() { 54 | return output.toString(); 55 | } 56 | 57 | public int getExitCode() { 58 | return exitCode; 59 | } 60 | 61 | public void setExitCode(int exitCode) { 62 | this.exitCode = exitCode; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample1/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "mysql_test" 3 | name = "sample1" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample1/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerinax/mysql; 18 | 19 | mysql:Client dbClient 20 | mysql:Client dbClient = check new mysql:Client("url", (), (), (), 120, { connectTimeout: -1 }, { maxOpenConnections: -1 }); 21 | 22 | public function main() returns error? { 23 | } 24 | 25 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample2/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "mysql_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/mysql; 18 | 19 | mysql:Client dbClient = check new mysql:Client("url", (), (), (), 120, { connectTimeout: -1 }, { maxOpenConnections: -1 }); 20 | 21 | public function main() returns error? { 22 | 23 | mysql:Client dbClient1 = check new("url", connectionPool = { maxOpenConnections: -1 }); 24 | check dbClient1.close(); 25 | 26 | mysql:Client dbClient2 = check new("url", options = { connectTimeout: -1 }); 27 | check dbClient2.close(); 28 | 29 | mysql:Client dbClient3 = check new("url", (), (), (), 120, { connectTimeout: -1 }); 30 | check dbClient3.close(); 31 | } 32 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample3/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "mysql_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/mysql; 18 | 19 | public function main() { 20 | 21 | int id = 5; 22 | 23 | int|mysql:Options pool1 = 5; 24 | 25 | int|mysql:Options pool2 = { 26 | connectTimeout: -2, 27 | socketTimeout: -3 28 | }; 29 | 30 | mysql:Options|int pool3 = { 31 | connectTimeout: -2, 32 | socketTimeout: -3 33 | }; 34 | 35 | mysql:Options pool4 = { 36 | connectTimeout: -2, 37 | socketTimeout: -3, 38 | failoverConfig: { 39 | failoverServers:[], 40 | timeBeforeRetry: -2, 41 | queriesBeforeRetry: 0 42 | } 43 | }; 44 | 45 | mysql:Options pool5 = { 46 | failoverConfig: { 47 | failoverServers:[], 48 | queriesBeforeRetry: 0 49 | } 50 | }; 51 | 52 | mysql:FailoverConfig pool6 = { 53 | failoverServers:[], 54 | queriesBeforeRetry: -2, 55 | timeBeforeRetry: -4 56 | }; 57 | 58 | mysql:FailoverConfig pool7 = { 59 | failoverServers:[], 60 | timeBeforeRetry: -8 61 | }; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample4/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "mysql_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/mysql; 18 | 19 | public function main() { 20 | 21 | decimal connectTimeout = 5; 22 | decimal connectTimeoutInvalid = -5; 23 | 24 | mysql:Options options1 = { 25 | connectTimeout: connectTimeout 26 | }; 27 | 28 | mysql:Options options2 = { 29 | connectTimeout: connectTimeoutInvalid 30 | }; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample5/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "mysql_test" 3 | name = "sample5" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample5/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/mysql; 9 | import ballerinax/mysql.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 mysql:Client allocationDbClient = check new ( 51 | host = allocationDatabase.hostname, 52 | user = 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: mysql:SSL_PREFERRED 62 | }, 63 | connectTimeout: allocationDatabase.mysqlOptions.connectTimeout 64 | } 65 | ); 66 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample6/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "mysql_test" 3 | name = "sample6" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/diagnostics/sample6/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/mysql; 9 | import ballerinax/mysql.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 mysql:Client allocationDbClient = check new ( 51 | host = allocationDatabase.hostname, 52 | user = 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: mysql:SSL_PREFERRED 62 | }, 63 | connectTimeout: allocationDatabase.mysqlOptions.connectTimeout 64 | } 65 | ); 66 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "sachink" 3 | name = "rule1" 4 | version = "0.1.0" 5 | distribution = "2201.11.0-20250127-101700-a4b67fe5" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/static_code_analyzer/ballerina_packages/rule1/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 | 17 | import ballerinax/mysql; 18 | import ballerina/io; 19 | 20 | configurable string user = ?; 21 | configurable string host = ?; 22 | configurable int port = ?; 23 | configurable string database = ?; 24 | 25 | public function main() { 26 | mysql:Client|error dbClient = new (host = host, 27 | user = user, 28 | password = "", 29 | port = port, 30 | database = database 31 | ); 32 | io:println("Result 1: ", dbClient); 33 | } 34 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/static_code_analyzer/expected_output/rule1.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "location" : { 3 | "filePath" : "main.bal", 4 | "startLine" : 9, 5 | "endLine" : 9, 6 | "startColumn" : 28, 7 | "endColumn" : 44, 8 | "startOffset" : 762, 9 | "length" : 16 10 | }, 11 | "rule" : { 12 | "id" : "ballerina/mysql:1", 13 | "numericId" : 1, 14 | "description" : "A secure password should be used when connecting to a database", 15 | "ruleKind" : "VULNERABILITY" 16 | }, 17 | "source" : "BUILT_IN", 18 | "fileName" : "rule1/main.bal", 19 | "filePath" : "/Users/sachink/Desktop/module-ballerinax-mysql/compiler-plugin-test/src/test/resources/static_code_analyzer/ballerina_packages/rule1/main.bal" 20 | } ] 21 | -------------------------------------------------------------------------------- /compiler-plugin-tests/src/test/resources/testng.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /compiler-plugin/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | plugins { 20 | id 'java' 21 | id 'checkstyle' 22 | id 'com.github.spotbugs' 23 | } 24 | 25 | description = 'Ballerina - MySQL 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 | implementation group: 'io.ballerina.scan', name: 'scan-command', version: "${balScanVersion}" 35 | } 36 | 37 | def excludePattern = '**/module-info.java' 38 | tasks.withType(Checkstyle) { 39 | exclude excludePattern 40 | } 41 | 42 | checkstyle { 43 | toolVersion "${project.checkstylePluginVersion}" 44 | configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml") 45 | configProperties = ["suppressionFile" : file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] 46 | } 47 | 48 | checkstyleMain.dependsOn(":checkstyle:downloadCheckstyleRuleFiles") 49 | 50 | spotbugsMain { 51 | def classLoader = plugins["com.github.spotbugs"].class.classLoader 52 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") 53 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") 54 | effort = SpotBugsEffort.MAX 55 | reportLevel = SpotBugsConfidence.LOW 56 | reportsDir = file("$project.buildDir/reports/spotbugs") 57 | reports { 58 | html.enabled true 59 | text.enabled = true 60 | } 61 | def excludeFile = file("${rootDir}/spotbugs-exclude.xml") 62 | if(excludeFile.exists()) { 63 | excludeFilter = excludeFile 64 | } 65 | } 66 | 67 | compileJava { 68 | doFirst { 69 | options.compilerArgs = [ 70 | '--module-path', classpath.asPath, 71 | ] 72 | classpath = files() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/mysql/compiler/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.mysql.compiler; 19 | 20 | /** 21 | * Constants for MySQL compiler plugin. 22 | */ 23 | public class Constants { 24 | public static final String BALLERINAX = "ballerinax"; 25 | public static final String MYSQL = "mysql"; 26 | public static final String CONNECTION_POOL_PARAM_NAME = "connectionPool"; 27 | public static final String OPTIONS_PARAM_NAME = "options"; 28 | public static final String SCANNER_CONTEXT = "ScannerContext"; 29 | 30 | private Constants() { 31 | } 32 | 33 | /** 34 | * Constants related to Client object. 35 | */ 36 | public static class Client { 37 | public static final String CLIENT = "Client"; 38 | 39 | private Client() { 40 | } 41 | } 42 | 43 | /** 44 | * Constants for fields in sql:ConnectionPool. 45 | */ 46 | public static class ConnectionPool { 47 | public static final String MAX_OPEN_CONNECTIONS = "maxOpenConnections"; 48 | public static final String MAX_CONNECTION_LIFE_TIME = "maxConnectionLifeTime"; 49 | public static final String MIN_IDLE_CONNECTIONS = "minIdleConnections"; 50 | 51 | private ConnectionPool() { 52 | } 53 | } 54 | 55 | /** 56 | * Constants for fields in mysql:Options. 57 | */ 58 | public static class Options { 59 | public static final String NAME = "Options"; 60 | public static final String CONNECTION_TIMEOUT = "connectTimeout"; 61 | public static final String SOCKET_TIMEOUT = "socketTimeout"; 62 | public static final String FAILOVER = "failoverConfig"; 63 | 64 | private Options() { 65 | } 66 | } 67 | 68 | /** 69 | * Constants for fields in mysql:FailoverConfig. 70 | */ 71 | public static class FailOver { 72 | public static final String NAME = "FailoverConfig"; 73 | public static final String TIME_BEFORE_RETRY = "timeBeforeRetry"; 74 | public static final String QUERY_BEFORE_RETRY = "queriesBeforeRetry"; 75 | 76 | private FailOver() { 77 | } 78 | } 79 | 80 | public static final String UNNECESSARY_CHARS_REGEX = "\"|\\n"; 81 | 82 | } 83 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/mysql/compiler/MySQLCodeAnalyzer.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.mysql.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.mysql.compiler.analyzer.InitializerParamAnalyzer; 25 | import io.ballerina.stdlib.mysql.compiler.analyzer.RecordAnalyzer; 26 | 27 | import java.util.List; 28 | 29 | /** 30 | * MySQL Code Analyzer. 31 | */ 32 | public class MySQLCodeAnalyzer extends CodeAnalyzer { 33 | @Override 34 | public void init(CodeAnalysisContext ctx) { 35 | ctx.addSyntaxNodeAnalysisTask(new InitializerParamAnalyzer(), 36 | List.of(SyntaxKind.IMPLICIT_NEW_EXPRESSION, SyntaxKind.EXPLICIT_NEW_EXPRESSION)); 37 | ctx.addSyntaxNodeAnalysisTask(new RecordAnalyzer(), 38 | List.of(SyntaxKind.LOCAL_VAR_DECL, SyntaxKind.MODULE_VAR_DECL)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/mysql/compiler/MySQLCompilerPlugin.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.mysql.compiler; 20 | 21 | import io.ballerina.projects.plugins.CompilerPlugin; 22 | import io.ballerina.projects.plugins.CompilerPluginContext; 23 | import io.ballerina.scan.ScannerContext; 24 | import io.ballerina.stdlib.mysql.compiler.staticcodeanalyzer.MySQLStaticCodeAnalyzer; 25 | 26 | import static io.ballerina.stdlib.mysql.compiler.Constants.SCANNER_CONTEXT; 27 | 28 | /** 29 | * Compiler plugin for MySQL client. 30 | */ 31 | public class MySQLCompilerPlugin extends CompilerPlugin { 32 | @Override 33 | public void init(CompilerPluginContext compilerPluginContext) { 34 | compilerPluginContext.addCodeAnalyzer(new MySQLCodeAnalyzer()); 35 | Object object = compilerPluginContext.userData().get(SCANNER_CONTEXT); 36 | if (object instanceof ScannerContext scannerContext) { 37 | compilerPluginContext.addCodeAnalyzer(new MySQLStaticCodeAnalyzer(scannerContext.getReporter())); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/mysql/compiler/MySQLDiagnosticsCode.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.mysql.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 MySQL module diagnostic codes. 26 | */ 27 | public enum MySQLDiagnosticsCode { 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 | MYSQL_101("MYSQL_101", "invalid value: expected value is greater than or equal to zero", ERROR); 36 | 37 | private final String code; 38 | private final String message; 39 | private final DiagnosticSeverity severity; 40 | 41 | MySQLDiagnosticsCode(String code, String message, DiagnosticSeverity severity) { 42 | this.code = code; 43 | this.message = message; 44 | this.severity = severity; 45 | } 46 | 47 | public String getCode() { 48 | return code; 49 | } 50 | 51 | public String getMessage() { 52 | return message; 53 | } 54 | 55 | public DiagnosticSeverity getSeverity() { 56 | return severity; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/mysql/compiler/staticcodeanalyzer/MySQLRule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. 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.mysql.compiler.staticcodeanalyzer; 20 | 21 | import io.ballerina.scan.Rule; 22 | 23 | import static io.ballerina.scan.RuleKind.VULNERABILITY; 24 | import static io.ballerina.stdlib.mysql.compiler.staticcodeanalyzer.RuleFactory.createRule; 25 | 26 | /** 27 | * Represents static code rules specific to the Ballerina MySQL package. 28 | */ 29 | public enum MySQLRule { 30 | USE_SECURE_PASSWORD(createRule(1, "A secure password should be used when connecting " + 31 | "to a database", VULNERABILITY)); 32 | 33 | private final Rule rule; 34 | 35 | MySQLRule(Rule rule) { 36 | this.rule = rule; 37 | } 38 | 39 | public int getId() { 40 | return this.rule.numericId(); 41 | } 42 | 43 | public Rule getRule() { 44 | return this.rule; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "{\"id\":" + this.getId() + ", \"kind\":\"" + this.rule.kind() + "\"," + 50 | " \"description\" : \"" + this.rule.description() + "\"}"; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/mysql/compiler/staticcodeanalyzer/MySQLStaticCodeAnalyzer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 LLC. 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.mysql.compiler.staticcodeanalyzer; 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.scan.Reporter; 25 | 26 | /** 27 | * MySQL Code Analyzer. 28 | */ 29 | public class MySQLStaticCodeAnalyzer extends CodeAnalyzer { 30 | private final Reporter reporter; 31 | 32 | public MySQLStaticCodeAnalyzer(Reporter reporter) { 33 | this.reporter = reporter; 34 | } 35 | 36 | @Override 37 | public void init(CodeAnalysisContext ctx) { 38 | ctx.addSyntaxNodeAnalysisTask(new SecurePasswordAnalyzer(reporter), SyntaxKind.FUNCTION_CALL); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/mysql/compiler/staticcodeanalyzer/RuleFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. 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.mysql.compiler.staticcodeanalyzer; 20 | 21 | import io.ballerina.scan.Rule; 22 | import io.ballerina.scan.RuleKind; 23 | 24 | /** 25 | * {@code RuleFactory} contains the logic to create a {@link Rule}. 26 | */ 27 | public class RuleFactory { 28 | public static Rule createRule(int id, String description, RuleKind kind) { 29 | return new RuleImpl(id, description, kind); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/mysql/compiler/staticcodeanalyzer/RuleImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. 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.mysql.compiler.staticcodeanalyzer; 20 | 21 | import io.ballerina.scan.Rule; 22 | import io.ballerina.scan.RuleKind; 23 | 24 | /** 25 | * {@code RuleImpl} is the implementation of the {@link Rule} interface. 26 | */ 27 | public class RuleImpl implements Rule { 28 | private final int id; 29 | private final String description; 30 | private final RuleKind kind; 31 | 32 | RuleImpl(int id, String description, RuleKind kind) { 33 | this.id = id; 34 | this.description = description; 35 | this.kind = kind; 36 | } 37 | 38 | @Override 39 | public String id() { 40 | return Integer.toString(this.id); 41 | } 42 | 43 | @Override 44 | public int numericId() { 45 | return this.id; 46 | } 47 | 48 | @Override 49 | public String description() { 50 | return this.description; 51 | } 52 | 53 | @Override 54 | public RuleKind kind() { 55 | return this.kind; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/java/io/ballerina/stdlib/mysql/compiler/staticcodeanalyzer/SecurePasswordAnalyzer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); 6 | * You may not use this file except 7 | * in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package io.ballerina.stdlib.mysql.compiler.staticcodeanalyzer; 21 | 22 | import io.ballerina.compiler.syntax.tree.BasicLiteralNode; 23 | import io.ballerina.compiler.syntax.tree.ExpressionNode; 24 | import io.ballerina.compiler.syntax.tree.FunctionArgumentNode; 25 | import io.ballerina.compiler.syntax.tree.FunctionCallExpressionNode; 26 | import io.ballerina.compiler.syntax.tree.NamedArgumentNode; 27 | import io.ballerina.compiler.syntax.tree.SeparatedNodeList; 28 | import io.ballerina.compiler.syntax.tree.SimpleNameReferenceNode; 29 | import io.ballerina.projects.Document; 30 | import io.ballerina.projects.plugins.AnalysisTask; 31 | import io.ballerina.projects.plugins.SyntaxNodeAnalysisContext; 32 | import io.ballerina.scan.Reporter; 33 | import io.ballerina.tools.diagnostics.Location; 34 | 35 | /** 36 | * Analyzer to detect insecure password vulnerabilities. 37 | */ 38 | public class SecurePasswordAnalyzer implements AnalysisTask { 39 | private final Reporter reporter; 40 | 41 | public SecurePasswordAnalyzer(Reporter reporter) { 42 | this.reporter = reporter; 43 | } 44 | 45 | @Override 46 | public void perform(SyntaxNodeAnalysisContext context) { 47 | if (!(context.node() instanceof FunctionCallExpressionNode functionCall)) { 48 | return; 49 | } 50 | SeparatedNodeList arguments = functionCall.arguments(); 51 | boolean hasSecurePassword = false; 52 | for (FunctionArgumentNode argument : arguments) { 53 | if (argument instanceof NamedArgumentNode namedArgument) { 54 | if ("password".equals(namedArgument.argumentName().toString())) { 55 | ExpressionNode expression = namedArgument.expression(); 56 | if (expression instanceof BasicLiteralNode basicLiteralNode) { 57 | String passwordValue = basicLiteralNode.literalToken().text(); 58 | passwordValue = passwordValue.substring(1, passwordValue.length() - 1); 59 | // Check if password is empty or weak 60 | if (passwordValue.isEmpty()) { 61 | reportPasswordVulnerability(context, functionCall); 62 | } else { 63 | hasSecurePassword = true; 64 | } 65 | } else if (expression instanceof SimpleNameReferenceNode) { 66 | String passwordValue = ((SimpleNameReferenceNode) expression).name().toString(); 67 | if (passwordValue.isEmpty()) { 68 | reportPasswordVulnerability(context, functionCall); 69 | } else { 70 | hasSecurePassword = true; 71 | } 72 | } else { 73 | reportPasswordVulnerability(context, functionCall); 74 | } 75 | } 76 | } 77 | } 78 | if (!hasSecurePassword) { 79 | reportPasswordVulnerability(context, functionCall); 80 | } 81 | } 82 | 83 | private void reportPasswordVulnerability(SyntaxNodeAnalysisContext context, 84 | FunctionCallExpressionNode functionCall) { 85 | Document document = getDocument(context); 86 | Location location = functionCall.location(); 87 | this.reporter.reportIssue(document, location, MySQLRule.USE_SECURE_PASSWORD.getId()); 88 | } 89 | 90 | public static Document getDocument(SyntaxNodeAnalysisContext context) { 91 | return context.currentPackage().module(context.moduleId()).document(context.documentId()); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /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.mysql.compiler { 20 | requires io.ballerina.scan; 21 | requires io.ballerina.lang; 22 | requires io.ballerina.tools.api; 23 | requires io.ballerina.parser; 24 | } 25 | -------------------------------------------------------------------------------- /compiler-plugin/src/main/resources/rules.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "kind": "VULNERABILITY", 5 | "description": "A secure password should be used when connecting to a database" 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /docs/proposals/add-MySQL-server-failover-support.md: -------------------------------------------------------------------------------- 1 | # Add MySQL Server Failover Support 2 | 3 | _Owners_: @daneshk @niveathika 4 | _Reviewers_: @anupama-pathirage @BuddhiWathsala 5 | _Created_: 2021/10/15 6 | _Updated_: 2021/11/03 7 | _Issues_: [#2053](https://github.com/ballerina-platform/ballerina-standard-library/issues/2053) 8 | 9 | ## Summary 10 | 11 | Currently, the ballerina SQL client can only connect to one MySQL server. The user has to handle connection errors by switching to the secondary replicated database or retrying. We can support MySQL server failovers so that the user does not need to maintain multiple clients to switch between secondary databases. 12 | 13 | ## Goals 14 | Allow ballerina client to connect to secondary databases in case of connection errors using the MySQL server Failover feature. 15 | 16 | ## Motivation 17 | The user can easily connect between database replicas without using complex logic. 18 | 19 | ## Description 20 | `FailoverConfig ` configuration will be introduced to `mysql:Options`. 21 | ```ballerina 22 | # Configuration for failover servers 23 | # 24 | # + host - Hostname of the secondary database to be connected 25 | # + port - Port of the secondary database to connect 26 | public type FailoverServer record {| 27 | string host; 28 | int port; 29 | |}; 30 | 31 | # Configuration to be used for Server Failover. 32 | # 33 | # + secondaries - Array of host & port tuple for the secondary databases 34 | # + timeBeforeRetry - Time the driver waits before trying to fall back to the primary host 35 | # + queriesBeforeRetry - Number of queries that are executed before the driver tries to fall back to the primary host 36 | # + failoverReadOnly - Open connection to secondary host with READ ONLY mode. 37 | public type FailoverConfig record {| 38 | FailoverServer[] failoverServers; 39 | int timeBeforeRetry?; 40 | int queriesBeforeRetry?; 41 | boolean failoverReadOnly = true; 42 | |}; 43 | 44 | public type Options record {| 45 | .... 46 | FailoverConfig failoverConfig?; 47 | |}; 48 | ``` 49 | 50 | Failover configuration usage will be, 51 | ```ballerina 52 | Options option = { 53 | failoverConfig: { 54 | failoverServers: [ 55 | { 56 | host: "localhost" 57 | port: 5506 58 | }, 59 | { 60 | host: "localhost", 61 | port: 3305 62 | } 63 | ], 64 | timeBeforeRetry: 10, 65 | queriesBeforeRetry: 10, 66 | failoverReadOnly: false 67 | } 68 | }; 69 | Client dbClient = check new (host, "root", "111", "mydb", 4406, option); 70 | ``` 71 | 72 | ## Testing 73 | 74 | Since a replication MySQL server is needed as a prerequisite for testing, this feature is manually tested. A docker-based MySQL replication is used for testing. [Prerequisite Reference](https://hackernoon.com/mysql-master-slave-replication-using-docker-3pp3u97) 75 | 76 | After the docker images are set up following code can be used for testing, 77 | ```ballerina 78 | import ballerina/test; 79 | import ballerina/sql; 80 | import ballerina/io; 81 | import ballerina/lang.runtime; 82 | 83 | @test:Config { 84 | groups: ["query-1"] 85 | } 86 | function queryReplica() returns error? { 87 | sql:ParameterizedQuery sqlQuery = `SELECT * from Code;`; 88 | 89 | Options option = { 90 | failoverConfig: { 91 | failoverServers: [ 92 | { 93 | host: "localhost", 94 | port: 5506 95 | } 96 | ], 97 | timeBeforeRetry: 10, 98 | queriesBeforeRetry: 10, 99 | failoverReadOnly: false 100 | } 101 | }; 102 | 103 | Client dbClient = check new (host, "root", "111", "mydb", 4406, option); 104 | int code = check dbClient->queryRow(sqlQuery); 105 | 106 | test:assertEquals(code, 100); 107 | 108 | io:println("Sleep"); 109 | runtime:sleep(30); 110 | 111 | code = check dbClient->queryRow(sqlQuery); 112 | test:assertEquals(code, 100); 113 | } 114 | ``` 115 | 116 | While the program is sleeping master node should be shut down to verify the failover. 117 | 118 | ## Reference 119 | 120 | [MySQL Server Failover](https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-config-failover.html) 121 | -------------------------------------------------------------------------------- /docs/proposals/add-option-noAccessToProcedureBodies.md: -------------------------------------------------------------------------------- 1 | # Add option to set `noAccessToProcedureBodies` driver property 2 | 3 | _Owners_: @daneshk @niveathika 4 | _Reviewers_: @daneshk 5 | _Created_: 2021/10/15 6 | _Updated_: 2021/10/15 7 | _Issues_: [#2048](https://github.com/ballerina-platform/ballerina-standard-library/issues/2048) 8 | 9 | ## Summary 10 | 11 | Only the user who created the MySQL stored procedure can access the procedure's metadata. In case the stored procedure contains out parameters, the metadata is needed to evoke the stored procedure. A lesser privileged user needs to enable MySQL driver property, noAccessToProcedureBodies, to execute a stored procedure with INOUT parameters. From the ballerina SQL client option, this needs to be exposed. 12 | 13 | ## Motivation 14 | 15 | This option allows a lesser privileged user to evoke stored procedures through the ballerina SQL module. 16 | 17 | ## Goals 18 | 19 | Allow users to connect to MySQL replication servers to take advantage of Server Failover behaviour. 20 | 21 | ## Description 22 | 23 | This feature adds the below option, 24 | ```ballerina 25 | public type Options record {| 26 | ..... 27 | boolean noAccessToProcedureBodies = false; 28 | |}; 29 | ``` 30 | 31 | Here the `noAccessToProcedureBodies` can be used to set driver property of the same name. 32 | 33 | This can be used as follows, 34 | ```ballerina 35 | Options options = { 36 | noAccessToProcedureBodies: true 37 | }; 38 | 39 | Client dbClient = check new (user = "newuser", password = "admin", database = "testdb", options = options); 40 | ``` 41 | -------------------------------------------------------------------------------- /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/22 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 MySQL database on client initialization. 12 | 13 | ## History 14 | The 1.3.x versions and below of the MySQL 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 MySQL 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 MySQL databases, the default username is `root`[[1]](https://dev.mysql.com/doc/refman/8.0/en/default-privileges.html) 26 | 27 | Modify the [client initialization method](https://github.com/ballerina-platform/module-ballerinax-mysql/blob/c2651da46c098ea6ef4a79079dc26cbd4d7cf54b/ballerina/client.bal#L36-L37) 28 | signature to use `root` as the default value for the username instead of `()`. 29 | 30 | ```ballerina 31 | public isolated function init(string host = "localhost", string? user = "root", string? password = (), string? database = (), 32 | int port = 1433, string instance = "", Options? options = (), sql:ConnectionPool? connectionPool = ()) returns sql:Error? { 33 | ``` 34 | 35 | ## References 36 | [1] https://dev.mysql.com/doc/refman/8.0/en/default-privileges.html 37 | -------------------------------------------------------------------------------- /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' 22 | 23 | description = 'Ballerina - MySQL Examples' 24 | 25 | def ballerinaDist = "${project.rootDir}/target/ballerina-runtime" 26 | def examples = ["employees-db/setup", "employees-db/service", "fraud-detection"] 27 | 28 | clean { 29 | examples.forEach { example -> 30 | delete "${projectDir}/${example}/target" 31 | delete "${projectDir}/${example}/Dependencies.toml" 32 | } 33 | } 34 | 35 | def graalvmFlag = "" 36 | 37 | task testExamples { 38 | if (project.hasProperty('balGraalVMTest')) { 39 | graalvmFlag = '--graalvm' 40 | } 41 | 42 | doLast { 43 | examples.each { example -> 44 | try { 45 | exec { 46 | workingDir "${project.projectDir}/${example}" 47 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 48 | commandLine 'cmd', '/c', "${ballerinaDist}/bin/bal.bat test ${graalvmFlag} && exit %%ERRORLEVEL%%" 49 | } else { 50 | commandLine 'sh', '-c', "${ballerinaDist}/bin/bal test ${graalvmFlag}" 51 | } 52 | } 53 | } catch (Exception e) { 54 | println("Example '${example}' Build failed: " + e.message) 55 | throw e 56 | } 57 | } 58 | } 59 | } 60 | 61 | task buildExamples { 62 | gradle.taskGraph.whenReady { graph -> 63 | if (graph.hasTask(":mysql-examples:test")) { 64 | buildExamples.enabled = false 65 | } 66 | } 67 | doLast { 68 | examples.each { example -> 69 | try { 70 | exec { 71 | workingDir project.projectDir 72 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 73 | commandLine 'cmd', '/c', "${ballerinaDist}/bin/bal.bat pack ${example} && exit %%ERRORLEVEL%%" 74 | } else { 75 | commandLine 'sh', '-c', "${ballerinaDist}/bin/bal pack ${example}" 76 | } 77 | } 78 | } catch (Exception e) { 79 | println("Example '${example}' Build failed: " + e.message) 80 | throw e 81 | } 82 | } 83 | } 84 | } 85 | 86 | testExamples.dependsOn ":mysql-ballerina:build" 87 | test.dependsOn testExamples 88 | buildExamples.dependsOn ":mysql-ballerina:build" 89 | build.dependsOn buildExamples 90 | -------------------------------------------------------------------------------- /examples/employees-db/Config.toml: -------------------------------------------------------------------------------- 1 | USER="root" 2 | PASSWORD="Test123#" 3 | HOST="localhost" 4 | PORT=3305 5 | -------------------------------------------------------------------------------- /examples/employees-db/service/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "employees_example_service" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /examples/employees-db/service/service.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/time; 18 | import ballerina/http; 19 | import ballerinax/mysql; 20 | import ballerina/sql; 21 | import ballerinax/mysql.driver as _; 22 | 23 | configurable string USER = ?; 24 | configurable string PASSWORD = ?; 25 | configurable string HOST = ?; 26 | configurable int PORT = ?; 27 | 28 | public type Employee record { 29 | int employee_id?; 30 | string first_name; 31 | string last_name; 32 | string email; 33 | string phone; 34 | time:Date hire_date; 35 | int? manager_id; 36 | string job_title; 37 | }; 38 | 39 | final mysql:Client dbClient = check new (host = HOST, user = USER, password = PASSWORD, port = PORT, 40 | database = "EmployeesDB", connectionPool = {maxOpenConnections: 3, minIdleConnections: 1}); 41 | 42 | isolated service /employees on new http:Listener(8080) { 43 | 44 | isolated resource function get .() returns Employee[]|error? { 45 | Employee[] employees = []; 46 | stream resultStream = dbClient->query(`SELECT * FROM Employees`); 47 | check from Employee employee in resultStream 48 | do { 49 | employees.push(employee); 50 | }; 51 | check resultStream.close(); 52 | return employees; 53 | } 54 | 55 | isolated resource function get [int id]() returns Employee|error? { 56 | Employee employee = check dbClient->queryRow(`SELECT * FROM Employees WHERE employee_id = ${id}`); 57 | return employee; 58 | } 59 | 60 | isolated resource function post .(@http:Payload Employee emp) returns string|int|error? { 61 | sql:ExecutionResult result = check dbClient->execute(` 62 | INSERT INTO Employees (employee_id, first_name, last_name, email, phone, hire_date, manager_id, job_title) 63 | VALUES (${emp.employee_id}, ${emp.first_name}, ${emp.last_name}, ${emp.email}, ${emp.phone}, ${emp.hire_date}, 64 | ${emp.manager_id}, ${emp.job_title}) 65 | `); 66 | int|string? lastInsertId = result.lastInsertId; 67 | if lastInsertId is int { 68 | return lastInsertId; 69 | } else { 70 | return error("Unable to obtain last insert ID"); 71 | } 72 | } 73 | 74 | isolated resource function put .(@http:Payload Employee emp) returns int|error? { 75 | sql:ExecutionResult result = check dbClient->execute(` 76 | UPDATE Employees 77 | SET first_name = ${emp.first_name}, last_name = ${emp.last_name}, email = ${emp.email}, 78 | phone = ${emp.phone}, hire_date = ${emp.hire_date}, manager_id = ${emp.manager_id}, 79 | job_title = ${emp.job_title} 80 | WHERE employee_id = ${emp.employee_id} 81 | `); 82 | int|string? lastInsertId = result.lastInsertId; 83 | if lastInsertId is int { 84 | return lastInsertId; 85 | } else { 86 | return error("Unable to obtain last insert ID"); 87 | } 88 | } 89 | 90 | isolated resource function delete [int id]() returns int|error? { 91 | sql:ExecutionResult result = check dbClient->execute(`DELETE FROM Employees WHERE employee_id = ${id}`); 92 | return result.affectedRowCount; 93 | } 94 | 95 | isolated resource function get count() returns int|error? { 96 | int count = check dbClient->queryRow(`SELECT COUNT(*) FROM Employees`); 97 | return count; 98 | } 99 | 100 | isolated resource function get subordinates/[int id]() returns Employee[]|error? { 101 | Employee[] employees = []; 102 | stream resultStream = dbClient->query(`SELECT * FROM Employees WHERE manager_id = ${id}`); 103 | check from Employee employee in resultStream 104 | do { 105 | employees.push(employee); 106 | }; 107 | check resultStream.close(); 108 | return employees; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /examples/employees-db/setup/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "employees_example_setup" 4 | version = "0.1.0" 5 | -------------------------------------------------------------------------------- /examples/employees-db/setup/setup.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/time; 18 | import ballerinax/mysql; 19 | import ballerina/sql; 20 | import ballerinax/mysql.driver as _; 21 | 22 | configurable string USER = ?; 23 | configurable string PASSWORD = ?; 24 | configurable string HOST = ?; 25 | configurable int PORT = ?; 26 | 27 | public type Employee record { 28 | int employee_id?; 29 | string first_name; 30 | string last_name; 31 | string email; 32 | string phone; 33 | time:Date hire_date; 34 | int? manager_id; 35 | string job_title; 36 | }; 37 | 38 | public function main() returns error? { 39 | check createDatabase(); 40 | check createAndPopulateEmployeesTable(); 41 | } 42 | 43 | function createDatabase() returns error? { 44 | mysql:Client dbClient = check new (host = HOST, user = USER, password = PASSWORD, port = PORT); 45 | _ = check dbClient->execute(`DROP DATABASE IF EXISTS EmployeesDB`); 46 | _ = check dbClient->execute(`CREATE DATABASE EmployeesDB`); 47 | } 48 | 49 | function createAndPopulateEmployeesTable() returns error? { 50 | mysql:Client dbClient = check new (host = HOST, user = USER, password = PASSWORD, port = PORT, database = "EmployeesDB"); 51 | _ = check dbClient->execute(`DROP TABLE IF EXISTS Employees`); 52 | 53 | _ = check dbClient->execute(` 54 | CREATE TABLE Employees ( 55 | employee_id INTEGER AUTO_INCREMENT PRIMARY KEY, 56 | first_name VARCHAR(255) NOT NULL, 57 | last_name VARCHAR(255) NOT NULL, 58 | email VARCHAR(255) NOT NULL, 59 | phone VARCHAR(50) NOT NULL , 60 | hire_date DATE NOT NULL, 61 | manager_id INTEGER REFERENCES Employees(employee_id), 62 | job_title VARCHAR(255) NOT NULL 63 | ) 64 | `); 65 | 66 | Employee[] employees = [ 67 | { 68 | employee_id: 1, 69 | first_name: "Michael", 70 | last_name: "Scott", 71 | email: "michael.scott@example.com", 72 | phone: "737 299 2772", 73 | hire_date: {year: 1994, month: 2, day: 29}, 74 | manager_id: (), 75 | job_title: "CEO" 76 | }, 77 | { 78 | employee_id: 2, 79 | first_name: "Jane", 80 | last_name: "McIntyre", 81 | email: "jane.mcintyre@example.com", 82 | phone: "737 299 1111", 83 | hire_date: {year: 1996, month: 12, day: 15}, 84 | manager_id: 1, 85 | job_title: "Vice President - Marketing" 86 | }, 87 | { 88 | employee_id: 3, 89 | first_name: "Tom", 90 | last_name: "Scott", 91 | email: "tom.scott@example.com", 92 | phone: "439 882 099", 93 | hire_date: {year: 1998, month: 3, day: 23}, 94 | manager_id: 1, 95 | job_title: "Vice President - Sales" 96 | }, 97 | { 98 | employee_id: 4, 99 | first_name: "Elizabeth", 100 | last_name: "Queen", 101 | email: "elizabeth.queen@example.com", 102 | phone: "881 299 1123", 103 | hire_date: {year: 1978, month: 8, day: 19}, 104 | manager_id: 2, 105 | job_title: "Marketing Executive" 106 | }, 107 | { 108 | employee_id: 5, 109 | first_name: "Sam", 110 | last_name: "Smith", 111 | email: "sam.smith@example.com", 112 | phone: "752 479 2991", 113 | hire_date: {year: 2001, month: 5, day: 29}, 114 | manager_id: 3, 115 | job_title: "Sales Intern" 116 | } 117 | ]; 118 | 119 | sql:ParameterizedQuery[] insertQueries = 120 | from var emp in employees 121 | select ` 122 | INSERT INTO Employees 123 | (employee_id, first_name, last_name, email, phone, hire_date, manager_id, job_title) 124 | VALUES 125 | (${emp.employee_id}, ${emp.first_name}, ${emp.last_name}, ${emp.email}, ${emp.phone}, ${emp.hire_date}, 126 | ${emp.manager_id}, ${emp.job_title}) 127 | `; 128 | 129 | _ = check dbClient->batchExecute(insertQueries); 130 | } 131 | -------------------------------------------------------------------------------- /examples/fraud-detection/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Fraud Detection.md -------------------------------------------------------------------------------- /examples/fraud-detection/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "fraud_detection" 4 | version = "0.1.0" 5 | distribution = "2201.12.2" 6 | -------------------------------------------------------------------------------- /examples/fraud-detection/Fraud Detection.md: -------------------------------------------------------------------------------- 1 | # Fraud Detection 2 | 3 | This example demonstrates how to use the `mysql: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. MySQL Database 8 | 9 | 1. Refer to the [Setup Guide](https://central.ballerina.io/ballerinax/mysql/latest#setup-guide) for the necessary steps to enable CDC in the MySQL server. 10 | 11 | 2. Add the necessary schema and data using the `setup.sql` script: 12 | ```bash 13 | mysql -u -p < db_scripts/setup.sql 14 | ``` 15 | 16 | ### 2. Configuration 17 | 18 | Configure MySQL Database and Gmail API credentials in the `Config.toml` file located in the example directory: 19 | 20 | ```toml 21 | username = "" 22 | password = "" 23 | 24 | refreshToken = "" 25 | clientId = "" 26 | clientSecret = "" 27 | recipient = "" 28 | sender = "" 29 | ``` 30 | 31 | Replace `` and `` with your MySQL database credentials. 32 | 33 | Replace the Gmail API placeholders (``, ``, ``, ``, ``) with your Gmail API credentials and email addresses. 34 | 35 | ## Setup Guide: Using Docker Compose 36 | 37 | You can use Docker Compose to set up MySQL for this example. Follow these steps: 38 | 39 | ### 1. Start the service 40 | 41 | Run the following command to start the MySQL service: 42 | 43 | ```bash 44 | docker-compose up -d 45 | ``` 46 | 47 | ### 2. Verify the service 48 | 49 | Ensure `mysql` service is in a healthy state: 50 | 51 | ```bash 52 | docker-compose ps 53 | ``` 54 | 55 | ### 3. Configuration 56 | 57 | Ensure the `Config.toml` file is updated with the following credentials: 58 | 59 | ```toml 60 | username = "cdc_user" 61 | password = "cdc_password" 62 | 63 | refreshToken = "" 64 | clientId = "" 65 | clientSecret = "" 66 | recipient = "" 67 | sender = "" 68 | ``` 69 | 70 | Replace the Gmail API placeholders (``, ``, ``, ``, ``) with your Gmail API credentials and email addresses. 71 | 72 | ## Run the Example 73 | 74 | 1. Execute the following command to run the example: 75 | 76 | ```bash 77 | bal run 78 | ``` 79 | 80 | 2. Use the provided `test.sql` script to insert a sample transactions into the `trx` table to test the fraud detection system. Use the following SQL command: 81 | 82 | ```bash 83 | mysql -u -p < db_scripts/test.sql 84 | ``` 85 | 86 | If using docker services, 87 | 88 | ```bash 89 | docker exec -i mysql-cdc mysql -u cdc_user -pcdc_password < db-scripts/test.sql 90 | ``` 91 | -------------------------------------------------------------------------------- /examples/fraud-detection/db-scripts/setup.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS finance_db; 2 | USE finance_db; 3 | 4 | -- transactions table 5 | CREATE TABLE transactions ( 6 | tx_id INT AUTO_INCREMENT PRIMARY KEY, 7 | user_id INT, 8 | amount DECIMAL(10,2), 9 | status VARCHAR(50), 10 | created_at DATETIME 11 | ); 12 | 13 | -- Sample data 14 | INSERT INTO transactions (user_id, amount, status, created_at) VALUES 15 | (10, 9000.00, 'COMPLETED', '2025-04-01 08:00:00'), 16 | (11, 12000.00, 'COMPLETED', '2025-04-01 08:10:00'), -- this one should trigger fraud logic 17 | (12, 4500.00, 'PENDING', '2025-04-01 08:30:00'); 18 | -------------------------------------------------------------------------------- /examples/fraud-detection/db-scripts/test.sql: -------------------------------------------------------------------------------- 1 | USE finance_db; 2 | 3 | INSERT INTO transactions (user_id, amount, status, created_at) VALUES 4 | (11, 2000.00, 'COMPLETED', '2025-04-01 08:10:00'); 5 | 6 | INSERT INTO transactions (user_id, amount, status, created_at) VALUES 7 | (11, 12000.00, 'COMPLETED', '2025-04-01 08:10:00'); 8 | -------------------------------------------------------------------------------- /examples/fraud-detection/docker-compose.yml: -------------------------------------------------------------------------------- 1 | name: fraud-detection-example 2 | 3 | services: 4 | mysql: 5 | image: mysql:8.0 6 | container_name: mysql-cdc 7 | ports: 8 | - "3306:3306" 9 | environment: 10 | MYSQL_ROOT_PASSWORD: root 11 | MYSQL_DATABASE: finance_db 12 | MYSQL_USER: cdc_user 13 | MYSQL_PASSWORD: cdc_password 14 | volumes: 15 | - ./db-scripts/setup.sql:/docker-entrypoint-initdb.d/setup.sql 16 | healthcheck: 17 | test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ] 18 | interval: 10s 19 | timeout: 5s 20 | retries: 5 21 | -------------------------------------------------------------------------------- /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/googleapis.gmail; 20 | import ballerinax/mysql; 21 | import ballerinax/mysql.cdc.driver as _; 22 | 23 | configurable string refreshToken = os:getEnv("REFRESH_TOKEN"); 24 | configurable string clientId = os:getEnv("CLIENT_ID"); 25 | configurable string clientSecret = os:getEnv("CLIENT_SECRET"); 26 | configurable string recipient = os:getEnv("RECIPIENT"); 27 | configurable string sender = os:getEnv("SENDER"); 28 | 29 | configurable string username = os:getEnv("DB_USERNAME"); 30 | configurable string password = os:getEnv("DB_PASSWORD"); 31 | 32 | listener mysql:CdcListener financeDBListener = new ( 33 | database = { 34 | username, 35 | password, 36 | includedDatabases: "finance_db", 37 | includedTables: "finance_db.transactions" 38 | }, 39 | options = { 40 | snapshotMode: cdc:NO_DATA, 41 | skippedOperations: [cdc:TRUNCATE, cdc:UPDATE, cdc:DELETE] 42 | } 43 | ); 44 | 45 | final gmail:Client gmail = check new ({ 46 | auth: { 47 | refreshToken, 48 | clientId, 49 | clientSecret 50 | } 51 | }); 52 | 53 | service cdc:Service on financeDBListener { 54 | isolated remote function onCreate(Transactions trx) returns error? { 55 | log:printInfo(`Create trx event received Transaction Id: ${trx.tx_id}`); 56 | if trx.amount > 10000.00 { 57 | string fraudAlert = string `Fraud detected! Transaction Id: ${trx.tx_id}, User Id: ${trx.user_id}, Amount: $${trx.amount}`; 58 | 59 | gmail:MessageRequest message = { 60 | to: [recipient], 61 | subject: "Fraud Alert: Suspicious Transaction Detected", 62 | bodyInText: fraudAlert 63 | }; 64 | 65 | gmail:Message sendResult = check gmail->/users/me/messages/send.post(message); 66 | log:printInfo(`Email sent. Message ID: ${sendResult.id}`); 67 | } 68 | } 69 | 70 | isolated remote function onError(cdc:Error e) { 71 | log:printInfo(`Error occurred: ${e.message()}`); 72 | } 73 | } 74 | 75 | type Transactions record {| 76 | int tx_id; 77 | int user_id; 78 | float amount; 79 | string status; 80 | int created_at; 81 | |}; 82 | -------------------------------------------------------------------------------- /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 | testngVersion=7.6.1 12 | 13 | stdlibSqlVersion=1.16.0 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 | # Ballerinax Observer 28 | observeVersion=1.5.0 29 | observeInternalVersion=1.5.0 30 | 31 | # Transitive Dependencies 32 | # Level 01 33 | stdlibUrlVersion=2.6.0 34 | 35 | # Level 02 36 | stdlibConstraintVersion=1.7.0 37 | stdlibCryptoVersion=2.9.0 38 | stdlibTaskVersion=2.7.0 39 | stdlibRandomVersion=1.7.0 40 | 41 | # Level 03 42 | stdlibCacheVersion=3.10.0 43 | stdlibMimeVersion=2.12.0 44 | stdlibUuidVersion=1.10.0 45 | 46 | # Level 04 47 | stdlibAuthVersion=2.14.0 48 | stdlibJwtVersion=2.15.0 49 | stdlibOAuth2Version=2.14.0 50 | stdlibDataJsonDataVersion=1.1.0 51 | 52 | # Level 05 53 | stdlibHttpVersion=2.14.0 54 | 55 | # Level 06 56 | stdlibTransactionVersion=1.12.0 57 | 58 | # Ballerina library 59 | stdlibMysqlDriverVersion=1.8.0 60 | stdlibCdcVersion=1.0.1 61 | stdlibMySQLCdcDriverVersion=1.0.1 62 | 63 | jacocoVersion=0.8.10 64 | balScanVersion=0.5.0 65 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mysql/254f83e7242f1a7d510de8664d620465e9c8e817/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/delete/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: "mysql-delete-deployment" 13 | imagePullPolicy: Always 14 | -------------------------------------------------------------------------------- /load-tests/delete/deployment/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: mysql-delete 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: delete-svc 18 | port: 19 | number: 9092 20 | -------------------------------------------------------------------------------- /load-tests/delete/deployment/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - delete.yaml 3 | - ingress.yaml 4 | - mysql_deployment.yml 5 | patches: 6 | - path: deployment-patch.yaml 7 | target: 8 | group: apps 9 | version: v1 10 | kind: Deployment 11 | name: mysql-update-deployment 12 | -------------------------------------------------------------------------------- /load-tests/delete/deployment/mysql_deployment.yml: -------------------------------------------------------------------------------- 1 | ## Initialization script storage 2 | kind: PersistentVolumeClaim 3 | apiVersion: v1 4 | metadata: 5 | name: init-script-pvc 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 50Mi 13 | --- 14 | ## MySQL data storage 15 | kind: PersistentVolumeClaim 16 | apiVersion: v1 17 | metadata: 18 | name: mysql-data-pvc 19 | spec: 20 | accessModes: 21 | - ReadWriteOnce 22 | volumeMode: Filesystem 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | --- 27 | apiVersion: apps/v1 28 | kind: Deployment 29 | metadata: 30 | name: mysql-deployment 31 | spec: 32 | selector: 33 | matchLabels: 34 | app: mysql8 35 | strategy: 36 | type: Recreate 37 | template: 38 | metadata: 39 | labels: 40 | app: mysql8 41 | logs: "true" 42 | spec: 43 | initContainers: 44 | - name: init-script-downloader 45 | image: appropriate/curl 46 | args: 47 | - "-o" 48 | - "/tmp/data/init.sql" 49 | - "https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mysql/master/load-tests/delete/scripts/init.sql" 50 | volumeMounts: 51 | - name: init-script 52 | mountPath: /tmp/data 53 | containers: 54 | - name: mysql8 55 | image: mysql:8.0.22 56 | env: 57 | - name: MYSQL_ROOT_PASSWORD 58 | value: password 59 | ports: 60 | - containerPort: 3306 61 | volumeMounts: 62 | - name: data 63 | mountPath: /var/lib/mysql 64 | - name: init-script 65 | mountPath: /docker-entrypoint-initdb.d 66 | volumes: 67 | - name: init-script 68 | persistentVolumeClaim: 69 | claimName: init-script-pvc 70 | - name: data 71 | persistentVolumeClaim: 72 | claimName: mysql-data-pvc 73 | --- 74 | ## Service 75 | apiVersion: v1 76 | kind: Service 77 | metadata: 78 | name: mysql8-service 79 | labels: 80 | app: mysql8 81 | spec: 82 | type: NodePort 83 | ports: 84 | - port: 3306 85 | targetPort: 3306 86 | protocol: TCP 87 | selector: 88 | app: mysql8 89 | --- 90 | -------------------------------------------------------------------------------- /load-tests/delete/scripts/http-delete-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 | db?id=${random} 37 | DELETE 38 | false 39 | true 40 | true 41 | false 42 | 43 | HttpClient4 44 | 60000 45 | 60000 46 | 47 | 48 | 49 | 50 | 200 51 | 52 | 53 | Assertion.response_code 54 | false 55 | 16 56 | 57 | 58 | 59 | 60 | 300 61 | 1 62 | 000 63 | true 64 | 1 65 | random 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /load-tests/delete/scripts/init.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS petdb; 2 | 3 | USE petdb; 4 | 5 | CREATE TABLE IF NOT EXISTS pet ( 6 | id INTEGER NOT NULL AUTO_INCREMENT, 7 | name VARCHAR(300), 8 | category VARCHAR(300), 9 | price INTEGER, 10 | PRIMARY KEY (id) 11 | ); 12 | 13 | INSERT INTO pet(`name`, `category`, `price`) 14 | VALUES ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 15 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 16 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 17 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 18 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 19 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 20 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 21 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 22 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 23 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 24 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 25 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 26 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 27 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 28 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 29 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 30 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 31 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 32 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 33 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 34 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 35 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 36 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 37 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 38 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 39 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 40 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 41 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 42 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 43 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 44 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 45 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 46 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 47 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 48 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 49 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 50 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 51 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 52 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 53 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 54 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 55 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 56 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 57 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 58 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000); 59 | -------------------------------------------------------------------------------- /load-tests/delete/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-delete-request.jmx -l "$resultsDir/"original.jtl -Jusers="$concurrent_users" -Jduration=600 -Jhost=bal.perf.test -Jport=80 -Jprotocol=http 22 | -------------------------------------------------------------------------------- /load-tests/delete/src/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "delete" 4 | version = "0.0.1" 5 | 6 | [build-options] 7 | cloud = "k8s" 8 | -------------------------------------------------------------------------------- /load-tests/delete/src/Cloud.toml: -------------------------------------------------------------------------------- 1 | [container.image] 2 | repository = "ballerina" 3 | name = "delete" 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/delete/src/Config.toml: -------------------------------------------------------------------------------- 1 | host = "mysql8-service" 2 | username = "root" 3 | password = "password" 4 | port = 3306 5 | -------------------------------------------------------------------------------- /load-tests/delete/src/delete.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/http; 18 | import ballerinax/mysql; 19 | import ballerinax/mysql.driver as _; 20 | import ballerina/sql; 21 | 22 | configurable string host = ?; 23 | configurable string username = ?; 24 | configurable string password = ?; 25 | configurable int port = ?; 26 | 27 | final mysql:Client dbClient = check new(host = host, user = username, password = password, port = port); 28 | 29 | isolated service /db on new http:Listener(9092) { 30 | resource isolated function delete .(http:Caller caller, int id) returns error? { 31 | int count = 0; 32 | sql:ParameterizedQuery deleteQuery = `DELETE FROM petdb.pet WHERE id = ${id}`; 33 | sql:ExecutionResult|error result = dbClient->execute(deleteQuery); 34 | http:Response response = new; 35 | if result is error { 36 | response.statusCode = 500; 37 | response.setPayload(result.toString()); 38 | } else { 39 | response.statusCode = 200; 40 | int? deleteRowCount = result?.affectedRowCount; 41 | if (deleteRowCount is int) { 42 | count = deleteRowCount; 43 | } 44 | response.setPayload("Affected row:" + count.toString()); 45 | } 46 | _ = check caller->respond(response); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /load-tests/insert/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: "mysql-insert-deployment" 13 | imagePullPolicy: Always 14 | -------------------------------------------------------------------------------- /load-tests/insert/deployment/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: mysql-insert 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: insert-svc 18 | port: 19 | number: 9092 20 | -------------------------------------------------------------------------------- /load-tests/insert/deployment/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - insert.yaml 3 | - ingress.yaml 4 | - mysql_deployment.yml 5 | patches: 6 | - path: deployment-patch.yaml 7 | target: 8 | group: apps 9 | version: v1 10 | kind: Deployment 11 | name: mysql-insert-deployment 12 | -------------------------------------------------------------------------------- /load-tests/insert/deployment/mysql_deployment.yml: -------------------------------------------------------------------------------- 1 | ## Initialization script storage 2 | kind: PersistentVolumeClaim 3 | apiVersion: v1 4 | metadata: 5 | name: init-script-pvc 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 50Mi 13 | --- 14 | ## MySQL data storage 15 | kind: PersistentVolumeClaim 16 | apiVersion: v1 17 | metadata: 18 | name: mysql-data-pvc 19 | spec: 20 | accessModes: 21 | - ReadWriteOnce 22 | volumeMode: Filesystem 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | --- 27 | apiVersion: apps/v1 28 | kind: Deployment 29 | metadata: 30 | name: mysql-deployment 31 | spec: 32 | selector: 33 | matchLabels: 34 | app: mysql8 35 | strategy: 36 | type: Recreate 37 | template: 38 | metadata: 39 | labels: 40 | app: mysql8 41 | logs: "true" 42 | spec: 43 | initContainers: 44 | - name: init-script-downloader 45 | image: appropriate/curl 46 | args: 47 | - "-o" 48 | - "/tmp/data/init.sql" 49 | - "https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mysql/master/load-tests/insert/scripts/init.sql" 50 | volumeMounts: 51 | - name: init-script 52 | mountPath: /tmp/data 53 | containers: 54 | - name: mysql8 55 | image: mysql:8.0.22 56 | env: 57 | - name: MYSQL_ROOT_PASSWORD 58 | value: password 59 | ports: 60 | - containerPort: 3306 61 | volumeMounts: 62 | - name: data 63 | mountPath: /var/lib/mysql 64 | - name: init-script 65 | mountPath: /docker-entrypoint-initdb.d 66 | volumes: 67 | - name: init-script 68 | persistentVolumeClaim: 69 | claimName: init-script-pvc 70 | - name: data 71 | persistentVolumeClaim: 72 | claimName: mysql-data-pvc 73 | --- 74 | ## Service 75 | apiVersion: v1 76 | kind: Service 77 | metadata: 78 | name: mysql8-service 79 | labels: 80 | app: mysql8 81 | spec: 82 | type: NodePort 83 | ports: 84 | - port: 3306 85 | targetPort: 3306 86 | protocol: TCP 87 | selector: 88 | app: mysql8 89 | --- 90 | -------------------------------------------------------------------------------- /load-tests/insert/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 | 10 26 | 27 | true 28 | 29 | 30 | 31 | 32 | 33 | 34 | ${__P(host,localhost)} 35 | ${__P(port,9092)} 36 | ${__P(protocol,http)} 37 | 38 | ${__P(path)} 39 | POST 40 | false 41 | true 42 | true 43 | false 44 | 45 | HttpClient4 46 | 10000 47 | 30000 48 | 49 | 50 | 51 | 52 | 200 53 | 54 | 55 | Assertion.response_code 56 | false 57 | 16 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /load-tests/insert/scripts/init.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS petdb; 2 | 3 | USE petdb; 4 | 5 | CREATE TABLE IF NOT EXISTS pet ( 6 | id INTEGER NOT NULL AUTO_INCREMENT, 7 | name VARCHAR(300), 8 | category VARCHAR(300), 9 | price INTEGER, 10 | PRIMARY KEY (id) 11 | ); 12 | -------------------------------------------------------------------------------- /load-tests/insert/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 -Jprotocol=http -Jpath=db 22 | -------------------------------------------------------------------------------- /load-tests/insert/src/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "insert" 4 | version = "0.0.1" 5 | 6 | [build-options] 7 | cloud = "k8s" 8 | -------------------------------------------------------------------------------- /load-tests/insert/src/Cloud.toml: -------------------------------------------------------------------------------- 1 | [container.image] 2 | repository = "ballerina" 3 | name = "insert" 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/insert/src/Config.toml: -------------------------------------------------------------------------------- 1 | host = "mysql8-service" 2 | username = "root" 3 | password = "password" 4 | port = 3306 5 | -------------------------------------------------------------------------------- /load-tests/insert/src/insert.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/http; 18 | import ballerinax/mysql; 19 | import ballerinax/mysql.driver as _; 20 | import ballerina/sql; 21 | 22 | configurable string host = ?; 23 | configurable string username = ?; 24 | configurable string password = ?; 25 | configurable int port = ?; 26 | 27 | final string name = "Bella"; 28 | final string category = "Cat"; 29 | final int price = 3000; 30 | 31 | final mysql:Client dbClient = check new (host = host, user = username, password = password, port = port); 32 | 33 | isolated service /db on new http:Listener(9092) { 34 | resource isolated function post .(http:Caller caller) returns error? { 35 | sql:ParameterizedQuery query = `INSERT INTO petdb.pet (Name, Category, Price) 36 | VALUES (${name}, ${category}, ${price})`; 37 | sql:ExecutionResult|error result = dbClient->execute(query); 38 | http:Response response = new; 39 | if result is error { 40 | response.statusCode = 500; 41 | response.setPayload(result.toString()); 42 | } else { 43 | response.statusCode = 200; 44 | response.setPayload("Records inserted successfully"); 45 | } 46 | _ = check caller->respond(response); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /load-tests/select/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: "mysql-select-deployment" 13 | imagePullPolicy: Always 14 | -------------------------------------------------------------------------------- /load-tests/select/deployment/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: mysql-select 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: select-svc 18 | port: 19 | number: 9092 20 | -------------------------------------------------------------------------------- /load-tests/select/deployment/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - select.yaml 3 | - ingress.yaml 4 | - mysql_deployment.yml 5 | patches: 6 | - path: deployment-patch.yaml 7 | target: 8 | group: apps 9 | version: v1 10 | kind: Deployment 11 | name: mysql-select-deployment 12 | -------------------------------------------------------------------------------- /load-tests/select/deployment/mysql_deployment.yml: -------------------------------------------------------------------------------- 1 | ## Initialization script storage 2 | kind: PersistentVolumeClaim 3 | apiVersion: v1 4 | metadata: 5 | name: init-script-pvc 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 50Mi 13 | --- 14 | ## MySQL data storage 15 | kind: PersistentVolumeClaim 16 | apiVersion: v1 17 | metadata: 18 | name: mysql-data-pvc 19 | spec: 20 | accessModes: 21 | - ReadWriteOnce 22 | volumeMode: Filesystem 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | --- 27 | apiVersion: apps/v1 28 | kind: Deployment 29 | metadata: 30 | name: mysql-deployment 31 | spec: 32 | selector: 33 | matchLabels: 34 | app: mysql8 35 | strategy: 36 | type: Recreate 37 | template: 38 | metadata: 39 | labels: 40 | app: mysql8 41 | logs: "true" 42 | spec: 43 | initContainers: 44 | - name: init-script-downloader 45 | image: appropriate/curl 46 | args: 47 | - "-o" 48 | - "/tmp/data/init.sql" 49 | - "https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mysql/master/load-tests/select/scripts/init.sql" 50 | volumeMounts: 51 | - name: init-script 52 | mountPath: /tmp/data 53 | containers: 54 | - name: mysql8 55 | image: mysql:8.0.22 56 | env: 57 | - name: MYSQL_ROOT_PASSWORD 58 | value: password 59 | ports: 60 | - containerPort: 3306 61 | volumeMounts: 62 | - name: data 63 | mountPath: /var/lib/mysql 64 | - name: init-script 65 | mountPath: /docker-entrypoint-initdb.d 66 | volumes: 67 | - name: init-script 68 | persistentVolumeClaim: 69 | claimName: init-script-pvc 70 | - name: data 71 | persistentVolumeClaim: 72 | claimName: mysql-data-pvc 73 | --- 74 | ## Service 75 | apiVersion: v1 76 | kind: Service 77 | metadata: 78 | name: mysql8-service 79 | labels: 80 | app: mysql8 81 | spec: 82 | type: NodePort 83 | ports: 84 | - port: 3306 85 | targetPort: 3306 86 | protocol: TCP 87 | selector: 88 | app: mysql8 89 | --- 90 | -------------------------------------------------------------------------------- /load-tests/select/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 | ${__P(path)} 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 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /load-tests/select/scripts/init.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS petdb; 2 | 3 | USE petdb; 4 | 5 | CREATE TABLE IF NOT EXISTS pet ( 6 | id INTEGER NOT NULL AUTO_INCREMENT, 7 | name VARCHAR(300), 8 | category VARCHAR(300), 9 | price INTEGER, 10 | PRIMARY KEY (id) 11 | ); 12 | 13 | INSERT INTO pet(`name`, `category`, `price`) 14 | VALUES ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 15 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 16 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 17 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 18 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 19 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 20 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 21 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 22 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 23 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 24 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 25 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 26 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 27 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 28 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 29 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 30 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 31 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 32 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 33 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 34 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 35 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 36 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 37 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 38 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 39 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 40 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 41 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 42 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 43 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 44 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 45 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 46 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 47 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 48 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 49 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 50 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 51 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 52 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 53 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 54 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 55 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 56 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000), 57 | ('Benny', 'Cat', 1000), ('Tigger', 'Cat', 2000), ('Emma', 'Cat', 1000), ('John', 'Cat', 1000), 58 | ('John', 'Dog', 2000), ('John', 'Cat', 1000), ('John', 'Dog', 2000), ('Tommy', 'Dog', 1000), ('Harry', 'Dog', 2000); 59 | -------------------------------------------------------------------------------- /load-tests/select/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 -Jprotocol=http -Jpath=db 22 | -------------------------------------------------------------------------------- /load-tests/select/src/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "select" 4 | version = "0.0.1" 5 | 6 | [build-options] 7 | cloud = "k8s" 8 | -------------------------------------------------------------------------------- /load-tests/select/src/Cloud.toml: -------------------------------------------------------------------------------- 1 | [container.image] 2 | repository = "ballerina" 3 | name = "select" 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/select/src/Config.toml: -------------------------------------------------------------------------------- 1 | host = "mysql8-service" 2 | username = "root" 3 | password = "password" 4 | port = 3306 5 | -------------------------------------------------------------------------------- /load-tests/select/src/select.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/http; 18 | import ballerinax/mysql; 19 | import ballerinax/mysql.driver as _; 20 | import ballerina/sql; 21 | 22 | configurable string host = ?; 23 | configurable string username = ?; 24 | configurable string password = ?; 25 | configurable int port = ?; 26 | 27 | final mysql:Client dbClient = check new(host = host, user = username, password = password, port = port); 28 | 29 | isolated service /db on new http:Listener(9092) { 30 | resource isolated function get .(http:Caller caller) returns error? { 31 | sql:ParameterizedQuery query = `SELECT COUNT(*) AS total FROM petdb.pet`; 32 | stream resultStream = dbClient->query(query); 33 | 34 | record {|record {} value;|}|error? result = resultStream.next(); 35 | _ = check resultStream.close(); 36 | http:Response response = new; 37 | if result is error { 38 | response.statusCode = 500; 39 | response.setPayload(result.toString()); 40 | } else { 41 | response.statusCode = 200; 42 | if result is record {|record {} value;|} { 43 | response.setPayload("Total count: " + result.value["total"].toString()); 44 | } else { 45 | response.setPayload("Total count: "); 46 | } 47 | } 48 | _ = check caller->respond(response); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /load-tests/update/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: "mysql-update-deployment" 13 | imagePullPolicy: Always 14 | -------------------------------------------------------------------------------- /load-tests/update/deployment/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: mysql-update 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: update-svc 18 | port: 19 | number: 9092 20 | -------------------------------------------------------------------------------- /load-tests/update/deployment/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - update.yaml 3 | - ingress.yaml 4 | - mysql_deployment.yml 5 | patches: 6 | - path: deployment-patch.yaml 7 | target: 8 | group: apps 9 | version: v1 10 | kind: Deployment 11 | name: mysql-update-deployment 12 | -------------------------------------------------------------------------------- /load-tests/update/deployment/mysql_deployment.yml: -------------------------------------------------------------------------------- 1 | ## Initialization script storage 2 | kind: PersistentVolumeClaim 3 | apiVersion: v1 4 | metadata: 5 | name: init-script-pvc 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | volumeMode: Filesystem 10 | resources: 11 | requests: 12 | storage: 50Mi 13 | --- 14 | ## MySQL data storage 15 | kind: PersistentVolumeClaim 16 | apiVersion: v1 17 | metadata: 18 | name: mysql-data-pvc 19 | spec: 20 | accessModes: 21 | - ReadWriteOnce 22 | volumeMode: Filesystem 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | --- 27 | apiVersion: apps/v1 28 | kind: Deployment 29 | metadata: 30 | name: mysql-deployment 31 | spec: 32 | selector: 33 | matchLabels: 34 | app: mysql8 35 | strategy: 36 | type: Recreate 37 | template: 38 | metadata: 39 | labels: 40 | app: mysql8 41 | logs: "true" 42 | spec: 43 | initContainers: 44 | - name: init-script-downloader 45 | image: appropriate/curl 46 | args: 47 | - "-o" 48 | - "/tmp/data/init.sql" 49 | - "https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mysql/master/load-tests/update/scripts/init.sql" 50 | volumeMounts: 51 | - name: init-script 52 | mountPath: /tmp/data 53 | containers: 54 | - name: mysql8 55 | image: mysql:8.0.22 56 | env: 57 | - name: MYSQL_ROOT_PASSWORD 58 | value: password 59 | ports: 60 | - containerPort: 3306 61 | volumeMounts: 62 | - name: data 63 | mountPath: /var/lib/mysql 64 | - name: init-script 65 | mountPath: /docker-entrypoint-initdb.d 66 | volumes: 67 | - name: init-script 68 | persistentVolumeClaim: 69 | claimName: init-script-pvc 70 | - name: data 71 | persistentVolumeClaim: 72 | claimName: mysql-data-pvc 73 | --- 74 | ## Service 75 | apiVersion: v1 76 | kind: Service 77 | metadata: 78 | name: mysql8-service 79 | labels: 80 | app: mysql8 81 | spec: 82 | type: NodePort 83 | ports: 84 | - port: 3306 85 | targetPort: 3306 86 | protocol: TCP 87 | selector: 88 | app: mysql8 89 | --- 90 | -------------------------------------------------------------------------------- /load-tests/update/scripts/http-put-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 | db?id=${random} 37 | PUT 38 | false 39 | true 40 | true 41 | false 42 | 43 | HttpClient4 44 | 60000 45 | 60000 46 | 47 | 48 | 49 | 50 | 200 51 | 52 | 53 | Assertion.response_code 54 | false 55 | 16 56 | 57 | 58 | 59 | 60 | 300 61 | 1 62 | 000 63 | true 64 | 1 65 | random 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /load-tests/update/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-put-request.jmx -l "$resultsDir/"original.jtl -Jusers="$concurrent_users" -Jduration=600 -Jhost=bal.perf.test -Jport=80 -Jprotocol=http 22 | -------------------------------------------------------------------------------- /load-tests/update/src/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "update" 4 | version = "0.0.1" 5 | 6 | [build-options] 7 | cloud = "k8s" 8 | -------------------------------------------------------------------------------- /load-tests/update/src/Cloud.toml: -------------------------------------------------------------------------------- 1 | [container.image] 2 | repository = "ballerina" 3 | name = "update" 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/update/src/Config.toml: -------------------------------------------------------------------------------- 1 | host = "mysql8-service" 2 | username = "root" 3 | password = "password" 4 | port = 3306 5 | -------------------------------------------------------------------------------- /load-tests/update/src/udate.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/http; 18 | import ballerinax/mysql; 19 | import ballerinax/mysql.driver as _; 20 | import ballerina/sql; 21 | 22 | configurable string host = ?; 23 | configurable string username = ?; 24 | configurable string password = ?; 25 | configurable int port = ?; 26 | final string price = "1400"; 27 | 28 | final mysql:Client dbClient = check new (host = host, user = username, password = password, port = port); 29 | 30 | isolated service /db on new http:Listener(9092) { 31 | resource isolated function put .(http:Caller caller, int id) returns error? { 32 | int count = 0; 33 | sql:ParameterizedQuery updateQuery = `UPDATE petdb.pet SET Price = ${price} where id = ${id}`; 34 | 35 | sql:ExecutionResult|error result = dbClient->execute(updateQuery); 36 | http:Response response = new; 37 | if result is error { 38 | response.statusCode = 500; 39 | response.setPayload(result.toString()); 40 | } else { 41 | response.statusCode = 200; 42 | int? updateRowCount = result?.affectedRowCount; 43 | if (updateRowCount is int) { 44 | count = updateRowCount; 45 | } 46 | response.setPayload("Affected row:" + count.toString()); 47 | } 48 | _ = check caller->respond(response); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /native/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | plugins { 19 | id 'java' 20 | id 'com.github.spotbugs' 21 | id 'checkstyle' 22 | id 'jacoco' 23 | } 24 | 25 | description = 'Ballerina - MySQL 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: 'io.ballerina.stdlib', name: 'sql-native', version: "${stdlibSqlVersion}" 38 | implementation group: 'io.ballerina.stdlib', name: 'time-native', version: "${stdlibTimeVersion}" 39 | } 40 | 41 | tasks.withType(JavaCompile) { 42 | options.encoding = 'UTF-8' 43 | } 44 | 45 | sourceCompatibility = JavaVersion.VERSION_21 46 | 47 | jacoco { 48 | toolVersion = "0.8.5" 49 | } 50 | 51 | test { 52 | testLogging { 53 | showStackTraces = true 54 | showStandardStreams = true 55 | events "failed" 56 | exceptionFormat "full" 57 | } 58 | jacoco { 59 | enabled = true 60 | destinationFile = file("$buildDir/coverage-reports/jacoco.exec") 61 | includeNoLocationClasses = true 62 | } 63 | } 64 | 65 | spotbugsMain { 66 | def classLoader = plugins["com.github.spotbugs"].class.classLoader 67 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") 68 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") 69 | effort = SpotBugsEffort.MAX 70 | reportLevel = SpotBugsConfidence.LOW 71 | ignoreFailures = true 72 | reportsDir = file("$project.buildDir/reports/spotbugs") 73 | def excludeFile = file("${rootDir}/build-config/spotbugs-exclude.xml") 74 | if (excludeFile.exists()) { 75 | it.excludeFilter = excludeFile 76 | } 77 | reports { 78 | text.enabled = true 79 | } 80 | } 81 | 82 | spotbugsTest { 83 | enabled = false 84 | } 85 | 86 | task validateSpotbugs() { 87 | doLast { 88 | if (spotbugsMain.reports.size() > 0 && 89 | spotbugsMain.reports[0].destination.exists() && 90 | spotbugsMain.reports[0].destination.text.readLines().size() > 0) { 91 | spotbugsMain.reports[0].destination?.eachLine { 92 | println 'Failure: ' + it 93 | } 94 | throw new GradleException("Spotbugs rule violations were found."); 95 | } 96 | } 97 | } 98 | 99 | checkstyle { 100 | toolVersion "${checkstylePluginVersion}" 101 | configFile file("${rootDir}/build-config/checkstyle/build/checkstyle.xml") 102 | configProperties = ["suppressionFile" : file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] 103 | } 104 | 105 | tasks.withType(Checkstyle) { 106 | exclude '**/module-info.java' 107 | } 108 | 109 | spotbugsMain.finalizedBy validateSpotbugs 110 | checkstyleMain.dependsOn ':checkstyle:downloadCheckstyleRuleFiles' 111 | 112 | compileJava { 113 | doFirst { 114 | options.compilerArgs = [ 115 | '--module-path', classpath.asPath, 116 | ] 117 | classpath = files() 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/mysql/nativeimpl/CallProcessor.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.mysql.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.mysql.parameterprocessor.MysqlResultParameterProcessor; 25 | import io.ballerina.stdlib.mysql.parameterprocessor.MysqlStatementParameterProcessor; 26 | 27 | /** 28 | * This class holds the utility methods involved with executing the call statements. 29 | * 30 | * @since 1.2.0 31 | */ 32 | public class CallProcessor { 33 | private CallProcessor() { 34 | } 35 | 36 | public static Object nativeCall(Environment env, BObject client, BObject paramSQLString, BArray recordTypes) { 37 | return io.ballerina.stdlib.sql.nativeimpl.CallProcessor.nativeCall(env, client, paramSQLString, 38 | recordTypes, MysqlStatementParameterProcessor.getInstance(), 39 | MysqlResultParameterProcessor.getInstance()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/mysql/nativeimpl/ExecuteProcessor.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.mysql.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.mysql.parameterprocessor.MysqlStatementParameterProcessor; 25 | 26 | /** 27 | * This class contains methods for executing SQL queries. 28 | * 29 | * @since 1.2.0 30 | */ 31 | public class ExecuteProcessor { 32 | private ExecuteProcessor() { 33 | } 34 | 35 | public static Object nativeExecute(Environment env, BObject client, BObject paramSQLString) { 36 | return io.ballerina.stdlib.sql.nativeimpl.ExecuteProcessor.nativeExecute(env, client, paramSQLString, 37 | MysqlStatementParameterProcessor.getInstance()); 38 | } 39 | 40 | public static Object nativeBatchExecute(Environment env, BObject client, BArray paramSQLStrings) { 41 | return io.ballerina.stdlib.sql.nativeimpl.ExecuteProcessor.nativeBatchExecute(env, client, paramSQLStrings, 42 | MysqlStatementParameterProcessor.getInstance()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/mysql/nativeimpl/QueryProcessor.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.mysql.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.mysql.parameterprocessor.MysqlResultParameterProcessor; 26 | import io.ballerina.stdlib.mysql.parameterprocessor.MysqlStatementParameterProcessor; 27 | 28 | /** 29 | * This class provides the methods for query processing which executes sql queries. 30 | * 31 | * @since 1.2.0 32 | */ 33 | public class QueryProcessor { 34 | private QueryProcessor() { 35 | } 36 | 37 | public static BStream nativeQuery(Environment env, BObject client, BObject paramSQLString, 38 | BTypedesc recordType) { 39 | MysqlStatementParameterProcessor statementParametersProcessor = MysqlStatementParameterProcessor 40 | .getInstance(); 41 | MysqlResultParameterProcessor resultParametersProcessor = MysqlResultParameterProcessor.getInstance(); 42 | return io.ballerina.stdlib.sql.nativeimpl.QueryProcessor.nativeQuery(env, client, paramSQLString, recordType, 43 | statementParametersProcessor, resultParametersProcessor); 44 | } 45 | 46 | public static Object nativeQueryRow(Environment env, BObject client, BObject paramSQLString, BTypedesc recordType) { 47 | MysqlStatementParameterProcessor statementParametersProcessor = MysqlStatementParameterProcessor 48 | .getInstance(); 49 | MysqlResultParameterProcessor resultParametersProcessor = MysqlResultParameterProcessor.getInstance(); 50 | return io.ballerina.stdlib.sql.nativeimpl.QueryProcessor.nativeQueryRow(env, client, paramSQLString, recordType, 51 | statementParametersProcessor, resultParametersProcessor); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/mysql/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.mysql.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.7.0 28 | */ 29 | public class ModuleUtils { 30 | private static Module mysqlModule; 31 | private ModuleUtils() {} 32 | 33 | public static void setModule(Environment env) { 34 | mysqlModule = env.getCurrentModule(); 35 | } 36 | 37 | public static Module getModule() { 38 | return mysqlModule; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/mysql/utils/MysqlRecordIteratorUtils.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.mysql.utils; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.stdlib.mysql.parameterprocessor.MysqlResultParameterProcessor; 22 | import io.ballerina.stdlib.sql.utils.RecordIteratorUtils; 23 | 24 | /** 25 | * This class provides functionality for the `RecordIterator` to iterate through the MySQL result set. 26 | */ 27 | public class MysqlRecordIteratorUtils extends RecordIteratorUtils { 28 | 29 | private MysqlRecordIteratorUtils() { 30 | } 31 | 32 | public static Object nextResult(BObject mysqlRecordIterator, BObject recordIterator) { 33 | return nextResult(recordIterator, MysqlResultParameterProcessor.getInstance()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/mysql/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.mysql.utils; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.stdlib.mysql.parameterprocessor.MysqlResultParameterProcessor; 22 | 23 | /** 24 | * This class provides functionality for the `ProcedureCallResult` to iterate through the MySQL result sets. 25 | */ 26 | public class ProcedureCallResultUtils { 27 | 28 | private ProcedureCallResultUtils() { 29 | } 30 | 31 | public static Object getNextQueryResult(BObject procedureCallResultSet, BObject procedureCallResult) { 32 | return io.ballerina.stdlib.sql.utils.ProcedureCallResultUtils 33 | .getNextQueryResult(procedureCallResult, MysqlResultParameterProcessor.getInstance()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | module io.ballerina.stdlib.mysql { 20 | requires io.ballerina.runtime; 21 | requires io.ballerina.stdlib.sql; 22 | requires io.ballerina.stdlib.time; 23 | exports io.ballerina.stdlib.mysql; 24 | } 25 | -------------------------------------------------------------------------------- /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 = 'ballerina-mysql' 36 | 37 | include ':checkstyle' 38 | include ':mysql-native' 39 | include ':mysql-compiler-plugin' 40 | include ':mysql-ballerina' 41 | include ':mysql-compiler-plugin-tests' 42 | include ':mysql-examples' 43 | 44 | project(':checkstyle').projectDir = file("build-config${File.separator}checkstyle") 45 | project(':mysql-native').projectDir = file('native') 46 | project(':mysql-compiler-plugin').projectDir = file('compiler-plugin') 47 | project(':mysql-ballerina').projectDir = file('ballerina') 48 | project(':mysql-compiler-plugin-tests').projectDir = file('compiler-plugin-tests') 49 | project(':mysql-examples').projectDir = file('examples') 50 | 51 | gradleEnterprise { 52 | buildScan { 53 | termsOfServiceUrl = 'https://gradle.com/terms-of-service' 54 | termsOfServiceAgree = 'yes' 55 | } 56 | } 57 | --------------------------------------------------------------------------------