Skip to content

Commit df09030

Browse files
committed
LDEV-5820 initial version CockroachDB JDBC ext
https://luceeserver.atlassian.net/browse/LDEV-5820
1 parent d4059f0 commit df09030

File tree

10 files changed

+1095
-0
lines changed

10 files changed

+1095
-0
lines changed

.github/workflows/main.yml

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
name: Java CI Combined
2+
3+
on:
4+
push:
5+
pull_request:
6+
workflow_dispatch:
7+
workflow_call:
8+
inputs:
9+
LUCEE_TEST_JAVA_VERSION:
10+
required: true
11+
type: string
12+
default: '21'
13+
LUCEE_VERSION_QUERY:
14+
required: true
15+
type: string
16+
default: '["6.2/snapshot/light","7/snapshot/light"]'
17+
18+
jobs:
19+
setup:
20+
runs-on: ubuntu-latest
21+
outputs:
22+
version: ${{ steps.extract-version.outputs.VERSION }}
23+
lucee-versions: ${{ steps.convert-lucee-versions.outputs.LUCEE_VERSIONS }}
24+
steps:
25+
- name: Checkout repository
26+
uses: actions/checkout@v4
27+
28+
- name: Set up JDK 17
29+
uses: actions/setup-java@v4
30+
with:
31+
distribution: 'temurin'
32+
java-version: '17'
33+
34+
- name: Cache Maven packages
35+
uses: actions/cache@v4
36+
with:
37+
path: ~/.m2
38+
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
39+
restore-keys: |
40+
${{ runner.os }}-maven-
41+
42+
- name: Extract version number
43+
id: extract-version
44+
run: |
45+
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
46+
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
47+
48+
- name: Convert Lucee versions
49+
id: convert-lucee-versions
50+
env:
51+
REPO_VERSIONS: ${{ vars.LUCEE_TEST_VERSIONS_PLUS }}
52+
INPUT_VERSIONS: ${{ inputs.LUCEE_VERSION_QUERY }}
53+
run: |
54+
# Use input versions if provided, otherwise use repo versions
55+
SIMPLE_VERSIONS="${INPUT_VERSIONS:-$REPO_VERSIONS}"
56+
# Convert simple format to complex format
57+
echo "$SIMPLE_VERSIONS" | jq -c 'map({version: ("light-" + split("/")[0] + ".0.0-SNAPSHOT"), query: .})' > lucee_versions.json
58+
LUCEE_VERSIONS=$(cat lucee_versions.json)
59+
echo "LUCEE_VERSIONS=$LUCEE_VERSIONS" >> $GITHUB_OUTPUT
60+
61+
- name: Cache Lucee files
62+
uses: actions/cache@v4
63+
with:
64+
path: ~/work/_actions/lucee/script-runner/main/lucee-download-cache
65+
key: lucee-downloads
66+
67+
- name: Import GPG key
68+
run: |
69+
echo "$GPG_PRIVATE_KEY" | base64 --decode | gpg --batch --import
70+
env:
71+
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
72+
73+
build:
74+
runs-on: ubuntu-latest
75+
needs: setup
76+
steps:
77+
- uses: actions/checkout@v4
78+
79+
- name: Set up JDK 21
80+
uses: actions/setup-java@v4
81+
with:
82+
java-version: ${{ inputs.LUCEE_TEST_JAVA_VERSION || '21' }}
83+
distribution: 'temurin'
84+
85+
- name: Cache Maven packages
86+
uses: actions/cache@v4
87+
with:
88+
path: ~/.m2
89+
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
90+
restore-keys: |
91+
${{ runner.os }}-maven-
92+
93+
- name: Build and Install with Maven
94+
run: |
95+
echo "------- Maven Install -------";
96+
mvn -B -e -f pom.xml clean install
97+
98+
- name: Upload Artifact
99+
uses: actions/upload-artifact@v4
100+
with:
101+
name: cockroachdb-lex
102+
path: target/*.lex
103+
104+
test:
105+
runs-on: ubuntu-latest
106+
needs: [setup, build]
107+
strategy:
108+
fail-fast: false
109+
matrix:
110+
lucee: ${{ fromJSON(needs.setup.outputs.lucee-versions) }}
111+
steps:
112+
- uses: actions/checkout@v4
113+
114+
- name: Start CockroachDB
115+
run: |
116+
docker run -d --name cockroachdb \
117+
-p 26257:26257 -p 8080:8080 \
118+
cockroachdb/cockroach:v23.1.11 start-single-node --insecure
119+
120+
- name: Wait for CockroachDB and setup database
121+
run: |
122+
# Download cockroach CLI
123+
curl -L https://binaries.cockroachdb.com/cockroach-v23.1.11.linux-amd64.tgz | tar -xz
124+
sudo cp cockroach-v23.1.11.linux-amd64/cockroach /usr/local/bin/
125+
126+
# Wait for CockroachDB to be ready
127+
for i in {1..10}; do
128+
cockroach sql --insecure --host=localhost:26257 --execute="SELECT 1;" && break || sleep 5;
129+
done
130+
131+
# Create database
132+
cockroach sql --insecure --host=localhost:26257 --execute="CREATE DATABASE IF NOT EXISTS testdb;"
133+
134+
- name: Download built artifact
135+
uses: actions/download-artifact@v4
136+
with:
137+
name: cockroachdb-lex
138+
path: target/
139+
140+
- name: Checkout Lucee
141+
uses: actions/checkout@v4
142+
with:
143+
repository: lucee/lucee
144+
path: lucee
145+
146+
- name: Run Lucee Test Suite
147+
uses: lucee/script-runner@main
148+
with:
149+
webroot: ${{ github.workspace }}/lucee/test
150+
execute: /bootstrap-tests.cfm
151+
luceeVersionQuery: ${{ matrix.lucee.query }}
152+
extensionDir: ${{ github.workspace }}/target
153+
env:
154+
testLabels: cockroachdb
155+
testServices: none # we don't need any services for this test, avoid errors due to bundle download
156+
LUCEE_ENABLE_BUNDLE_DOWNLOAD: false # we want to test the extension we just built
157+
COCKROACHDB_HOST: localhost
158+
COCKROACHDB_USERNAME: root
159+
COCKROACHDB_PORT: 26257
160+
COCKROACHDB_DATABASE: testdb
161+
LUCEE_LOGGING_FORCE_APPENDER: console
162+
LUCEE_LOGGING_FORCE_LEVEL: info
163+
testAdditional: ${{ github.workspace }}/tests
164+
165+
deploy:
166+
runs-on: ubuntu-latest
167+
needs: [test]
168+
if: always() && needs.test.result == 'success' && github.ref == 'refs/heads/main'
169+
steps:
170+
- name: Checkout repository
171+
uses: actions/checkout@v4
172+
173+
- name: Set up JDK 17
174+
uses: actions/setup-java@v4
175+
with:
176+
distribution: 'temurin'
177+
java-version: '17'
178+
179+
- name: Cache Maven packages
180+
uses: actions/cache@v4
181+
with:
182+
path: ~/.m2
183+
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
184+
restore-keys: |
185+
${{ runner.os }}-maven-
186+
187+
- name: Import GPG key
188+
run: |
189+
echo "$GPG_PRIVATE_KEY" | base64 --decode | gpg --batch --import
190+
env:
191+
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
192+
193+
- name: Build and Deploy with Maven
194+
env:
195+
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
196+
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
197+
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
198+
run: |
199+
if [[ "${{ needs.setup.outputs.version }}" == *-SNAPSHOT ]]; then
200+
echo "------- Maven Deploy snapshot on ${{ github.event_name }} -------";
201+
mvn -B -e -f pom.xml clean deploy --settings maven-settings.xml
202+
else
203+
echo "------- Maven Deploy release on ${{ github.event_name }} -------";
204+
mvn -B -e -f pom.xml clean deploy -DperformRelease=true --settings maven-settings.xml
205+
fi

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/dist
2+
/notUsedYet
3+
**/Test.java
4+
**/.DS_Store
5+
**/.svn/
6+
/*.project
7+
va specific
8+
*.class
9+
target
10+
target/*
11+
*.lock
12+
*.DS_Store

.vscode/settings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"workbench.colorCustomizations": {
3+
"activityBar.background": "#023608",
4+
"titleBar.activeBackground": "#034B0B",
5+
"titleBar.activeForeground": "#ECFEEE"
6+
}
7+
}

CockroachDB.cfc

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
component extends="types.Driver" output="no" implements="types.IDatasource" {
2+
3+
fields = array(
4+
field("SSL Mode", "sslmode", "disable,require,verify-ca,verify-full", "disable", "SSL mode to use for the connection.", "radio"),
5+
field("Application Name", "application_name", "", false, "Optional application name for the connection."),
6+
field("Timezone", "timezone", "", false, "Set the session timezone for the connection."),
7+
field("Retry Transient Errors", "retryTransientErrors", "true,false", "false", "Automatically retry serialization failures during transactions.", "radio"),
8+
field("Implicit SELECT FOR UPDATE", "implicitSelectForUpdate", "true,false", "false", "Automatically append FOR UPDATE to qualified SELECT statements to reduce contention.", "radio"),
9+
field("Rewrite Batched Inserts", "reWriteBatchedInserts", "true,false", "false", "Enable array-based rewrites for bulk INSERT operations.", "radio"),
10+
field("Rewrite Batched Updates", "reWriteBatchedUpdates", "true,false", "false", "Enable array-based rewrites for bulk UPDATE operations.", "radio"),
11+
field("Rewrite Batched Upserts", "reWriteBatchedUpserts", "true,false", "false", "Enable array-based rewrites for bulk UPSERT operations.", "radio"),
12+
field("Retry Max Attempts", "retryMaxAttempts", "", "15", "Maximum number of retry attempts for transient errors (default: 15)."),
13+
field("Retry Max Backoff Time", "retryMaxBackoffTime", "", "30s", "Maximum backoff time between retries (default: 30s).")
14+
);
15+
16+
this.type.port = this.TYPE_FREE;
17+
this.value.host = "localhost";
18+
this.value.port = 26257;
19+
this.className = "{class-name}";
20+
this.bundleName = "{bundle-name}";
21+
this.dsn = "{connString}";
22+
23+
/**
24+
* Custom parameter syntax for CockroachDB JDBC URLs
25+
*/
26+
public struct function customParameterSyntax() {
27+
return {leadingdelimiter:'?', delimiter:'&', separator:'='};
28+
}
29+
30+
/**
31+
* Validate field combinations before saving
32+
*/
33+
public void function onBeforeUpdate() {
34+
// Validate retry settings
35+
if (len(form.custom_retryMaxAttempts ?: "")) {
36+
var attempts = val(form.custom_retryMaxAttempts);
37+
if (attempts < 1 || attempts > 100) {
38+
throw message="Retry Max Attempts must be between 1 and 100";
39+
}
40+
}
41+
42+
// Validate backoff time format
43+
if (len(form.custom_retryMaxBackoffTime ?: "")) {
44+
var backoffTime = form.custom_retryMaxBackoffTime;
45+
if (!reFindNoCase("^\d+[smh]?$", backoffTime)) {
46+
throw message="Retry Max Backoff Time must be in format like '30s', '5m', or '1h'";
47+
}
48+
}
49+
}
50+
51+
/**
52+
* returns display name of the driver
53+
*/
54+
public string function getName() {
55+
return "{label}";
56+
}
57+
58+
/**
59+
* returns the id of the driver
60+
*/
61+
public string function getId() {
62+
return "{id}";
63+
}
64+
65+
/**
66+
* returns the description of the driver
67+
*/
68+
public string function getDescription() {
69+
return "{description}";
70+
}
71+
72+
/**
73+
* returns array of fields
74+
*/
75+
public array function getFields() {
76+
return fields;
77+
}
78+
79+
public boolean function literalTimestampWithTSOffset() {
80+
return false;
81+
}
82+
83+
public boolean function alwaysSetTimeout() {
84+
return true;
85+
}
86+
}

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Lucee CockroachDB JDBC Extension
2+
3+
![CockroachDB Logo](logo.png)
4+
5+
[![Java CI](https://github.com/lucee/extension-jdbc-cockroachdb/actions/workflows/main.yml/badge.svg)](https://github.com/lucee/extension-jdbc-cockroachdb/actions/workflows/main.yml)
6+
7+
Issues: https://luceeserver.atlassian.net/issues/?jql=labels%20%3D%20cockroachdb
8+
9+
## Coackroach DB
10+
11+
https://www.cockroachlabs.com/product/overview/
12+
13+
## JDBC client
14+
15+
While you can just use the Postgres JDBC client, this JDBC client adds some extra Cockroachdb specific support (it does bundle the postgres jdbc client and extends it)
16+
17+
https://github.com/cloudneutral/cockroachdb-jdbc
18+
19+
## Requirements
20+
21+
**Java 17 or higher** is required for this extension due to the CockroachDB JDBC driver 2.0.1+ dependency.
22+
**Lucee 6.2.2.91 or newer**

0 commit comments

Comments
 (0)