eXate MariaDB JDBC Driver
Installing the Driver
Add the following dependency to your Maven pom.xml:
<dependency>
<groupId>com.exate</groupId>
<artifactId>exate-mariadb-jdbc</artifactId>
<version>X.XX</version>
</dependency>
Repository Configuration
The driver is hosted on an Azure Artifacts Maven feed. Configure your Maven repository settings:
<repository>
<id>eXate-Maven</id>
<url>https://pkgs.dev.azure.com/exatetechnology/data-science/_packaging/{YOUR_FEED}/maven/v1</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
Your project will be provided with a specific feed URL and access token.
Driver Class
When configuring your JDBC client (e.g. DBeaver, Denodo), register the following driver class:
com.exate.mariadb.ExateDriver
The JDBC URL format is:
jdbc:mariadb://host:3306/database
Authentication
A JWT token must be available for authentication. The token can be provided in three ways:
1. Environment Variable
export EXATE_TOKEN=your_jwt_token_here
2. Query-Level Token
Include the token as a SQL comment prefixed to your query:
-- EXATE_TOKEN: your_jwt_token_here
SELECT *
FROM Employee;
3. Denodo Users
Use the Init SQL statements feature in the datasource configuration:
SET SESSION EXATE_TOKEN TO @{your_jwt_token_here}
The token passed via Init SQL statements or Query-Level Token always takes precedence over the environment variable.
Configuring the Driver
API Gateway URI
The driver communicates with the APIgator service for all encryption and decryption operations. Configure the
apigator.uri driver property in your JDBC client (e.g. DBeaver, Denodo), or set the environment variable:
export APIGATOR_URI=your-apigator-endpoint
# With a custom port:
export APIGATOR_URI=your-apigator-endpoint:port
- If no port is supplied, the driver defaults to TLS port 443.
- The
apigator.uridriver property takes precedence over the environment variable. - If neither is set, the driver defaults to
localhost. - Do not include a protocol prefix (
http:///https://). The driver always connects to APIgator over TLS.
Additional Claims (Matching Rules)
Claims are extracted from the JWT token. Additional claims can be supplied via the MATCHING_RULES environment variable
as a JSON array:
export MATCHING_RULES='[{"attributeName":"department","attributeValue":"finance"},{"attributeName":"region","attributeValue":"eu"}]'
Protection Modes
The driver supports three protection modes, controlled by the EXATE_PROTECTION_TYPE environment variable:
| Mode | Value | Write (INSERT/UPDATE) | Read (SELECT) |
|---|---|---|---|
| Cryptographic (default) | cryptographic |
Pseudonymise (reversible encrypt) | Reconstruct (decrypt) |
| Mask-Read | maskread |
Pass-through (no write protection) | Datamasking (one-way mask) |
| Mask-Write | maskwrite |
Datamasking (one-way mask) | Pass-through (no read decryption) |
export EXATE_PROTECTION_TYPE=cryptographic # default
export EXATE_PROTECTION_TYPE=maskread
export EXATE_PROTECTION_TYPE=maskwrite
Entitlements
For any table requiring encryption or decryption, create an eXate Datagator entitlement named using the following format:
{database_name}.{schema_name}
MariaDB note: MariaDB does not have a separate schema namespace — the schema and the database are the same concept. Use the database name for both components. For example, for database
mydb:mydb.mydb
Columns matching the configured attributes will be:
- Encrypted on
INSERTandUPDATEoperations. - Decrypted on
SELECTqueries.
Refer to the eXate User Guide for details on configuring entitlements within eXate Datagator.
Row-Level Access Control (RLAC)
When an eXate manifest includes a WHERE clause filter, the driver automatically injects it into every SELECT. Example:
SELECT *
FROM Employee
WHERE FirstName = 'John'
-- becomes (transparently):
SELECT *
FROM Employee
WHERE FirstName = '⟨ciphertext⟩'
AND department = 'Sales'
Querying Encrypted Data
SELECT
-- EXATE_TOKEN: your_jwt_token_here
SELECT *
FROM Employee;
INSERT
-- EXATE_TOKEN: your_jwt_token_here
INSERT INTO Employee (EmployeeID, FirstName, LastName)
VALUES (1, 'John', 'Doe');
UPDATE
-- EXATE_TOKEN: your_jwt_token_here
UPDATE Employee
SET FirstName = 'Jane'
WHERE EmployeeID = 1;
Exact Match Searches
Encrypted columns support exact match WHERE clause filtering:
-- EXATE_TOKEN: your_jwt_token_here
SELECT *
FROM Employee
WHERE FirstName = 'John';
Unsupported Queries
Partial match searches using LIKE are not supported for encrypted columns.
Stored Procedures
The driver supports transparent encryption and decryption through stored procedure calls using standard JDBC callable
statement escape syntax: {CALL ProcedureName(...)}.
No-Parameter Call
String sql = "--EXATE_TOKEN: " + token + "\n{CALL GetAllEmployees}";
try(
CallableStatement cstmt = connection.prepareCall(sql);
ResultSet rs = cstmt.executeQuery()){
while(rs.
next()){
System.out.
println(rs.getString("FirstName")); // decrypted
}
}
IN Parameter (Encrypted Before Execution)
String sql = "--EXATE_TOKEN: " + token + "\n{CALL GetEmployeesByFirstName(?)}";
try(
CallableStatement cstmt = connection.prepareCall(sql)){
cstmt.
setString(1,"John"); // encrypted transparently
try(
ResultSet rs = cstmt.executeQuery()){
while(rs.
next()){
System.out.
println(rs.getString("FirstName")); // decrypted
}
}
}
OUT Parameters (Decrypted on Return)
Define your stored procedure with OUT parameters:
CREATE PROCEDURE GetEmployeeSummaryWithOutParams(
OUT p_FirstName VARCHAR (100),
OUT p_Count INT
)
BEGIN
SELECT FirstName
INTO p_FirstName
FROM Employee
ORDER BY EmployeeID ASC LIMIT 1;
SELECT COUNT(*)
INTO p_Count
FROM Employee;
END;
Invoke via JDBC:
String sql = "--EXATE_TOKEN: " + token + "\n{CALL GetEmployeeSummaryWithOutParams(?, ?)}";
try(
CallableStatement cstmt = connection.prepareCall(sql)){
cstmt.
registerOutParameter(1,Types.VARCHAR); // p_FirstName — decrypted
cstmt.
registerOutParameter(2,Types.INTEGER); // p_Count
cstmt.
execute();
// Consume any result sets before reading OUT params
while(cstmt.
getMoreResults()){ /* drain */ }
String firstName = cstmt.getString(1); // cleartext
int total = cstmt.getInt(2);
}
Note: Only a single OUT parameter per statement is supported. Consume all result sets before reading OUT parameter values.
Advanced Features
Self-JOIN and CTE Support
Fully supported. Each alias in a self-join is an independent Apigator group. CTE aliases resolve to base tables.
Reconstruct Coalescer
Batches concurrent reconstruct (decrypt) calls to reduce gRPC round-trips:
export EXATE_COALESCE_ENABLED=true
export EXATE_COALESCE_WINDOW_MS=2
export EXATE_COALESCE_MAX_BATCH=20
Environment Variable Reference
Core Settings
| Variable | Default | Description |
|---|---|---|
EXATE_TOKEN |
(required) | Apigator bearer token |
APIGATOR_URI |
(required) | Apigator gRPC host:port |
EXATE_PROTECTION_TYPE |
cryptographic |
cryptographic, maskread, or maskwrite |
MATCHING_RULES |
null |
JSON array of additional claim matchers |
USE_TLS |
true |
TLS for gRPC |
gRPC Channel Tuning
| Variable | Default | Description |
|---|---|---|
EXATE_GRPC_CHANNEL_POOL |
true |
Reuse gRPC channels |
EXATE_GRPC_POOL_IDLE_MINUTES |
10 |
Idle channel eviction (minutes) |
EXATE_GRPC_KEEPALIVE_SECS |
300 |
Keepalive ping interval (seconds) |
EXATE_GRPC_KEEPALIVE_TIMEOUT_SECS |
20 |
Keepalive ping timeout (seconds) |
EXATE_GRPC_KEEPALIVE_WITHOUT_CALLS |
false |
Ping even with no active RPCs |
EXATE_GRPC_MAX_INBOUND_MB |
20 |
Max inbound message (MB) |
Coalescer
| Variable | Default | Description |
|---|---|---|
EXATE_COALESCE_ENABLED |
false |
Batch concurrent reconstruct calls |
EXATE_COALESCE_WINDOW_MS |
2 |
Batch window (ms) |
EXATE_COALESCE_MAX_BATCH |
20 |
Max per batch |
Optional Job Config Overrides
| Variable | Default | Description |
|---|---|---|
EXATE_SNAPSHOT_DATE |
null |
Point-in-time snapshot date |
EXATE_DATA_OWNING_COUNTRY_CODE |
null |
ISO country code of data owner |
EXATE_COUNTRY_CODE |
null |
ISO country code override |
EXATE_DATA_USAGE_ID |
null |
Data usage identifier |
EXATE_THIRD_PARTY_ID |
null |
Third-party identifier |
EXATE_EXECUTION_CONTEXT |
null |
Execution context label |
EXATE_SILENT_MODE |
null |
Suppress protection errors silently |
EXATE_PROTECT_NULL_VALUES |
null |
Encrypt NULL values |
EXATE_PRESERVE_STRING_LENGTH |
null |
Preserve ciphertext length |
EXATE_USE_RESTRICTED_TEXT |
null |
Replace unreadable with restricted text |
EXATE_RESTRICTED_TEXT |
null |
Custom restricted text |
EXATE_DATA_CONSISTENT_ACROSS_ORG |
null |
Org-wide deterministic encryption |
Observability
| Variable | Default | Description |
|---|---|---|
EXATE_ENABLE_METRICS |
true |
Log cache/latency metrics at shutdown |
Further Information
For more details, refer to the official eXate documentation or contact support.