SQL Server catalog
The SQL Server catalog connects Gravitino to a Microsoft SQL Server database over JDBC, exposing SQL Server schemas as schemas and SQL Server tables as tables. Schemas and tables are both read-write.
One catalog reaches exactly one SQL Server database. The database is named in the catalog properties and cannot be changed afterward, so reaching a second database means creating a second catalog.
Quick Start
1. Confirm the driver is present. The Microsoft JDBC driver is bundled with the connector, so there is no separate download step. This differs from the MySQL and PostgreSQL catalogs, which require you to supply a driver yourself.
2. Create the catalog. The database name appears twice, once inside the JDBC URL and once as
jdbc-database, and the two must agree.
- REST
- Java
- Python
GRAVITINO_URL=http://localhost:8090
METALAKE=metalake_demo
curl -X POST -H "Content-Type: application/json" \
-d '{
"name": "sqlserver_catalog",
"type": "RELATIONAL",
"provider": "jdbc-sqlserver",
"comment": "SQL Server catalog",
"properties": {
"jdbc-url": "jdbc:sqlserver://{host}:1433;databaseName={database};encrypt=true;trustServerCertificate=true",
"jdbc-user": "{user}",
"jdbc-password": "{password}",
"jdbc-database": "{database}",
"jdbc-driver": "com.microsoft.sqlserver.jdbc.SQLServerDriver"
}
}' \
"${GRAVITINO_URL}/api/metalakes/${METALAKE}/catalogs"
GravitinoClient client = GravitinoClient.builder("http://localhost:8090")
.withMetalake("metalake_demo")
.build();
Map<String, String> properties = ImmutableMap.<String, String>builder()
.put("jdbc-url", "jdbc:sqlserver://{host}:1433;databaseName={database};encrypt=true;trustServerCertificate=true")
.put("jdbc-user", "{user}")
.put("jdbc-password", "{password}")
.put("jdbc-database", "{database}")
.put("jdbc-driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver")
.build();
Catalog catalog = client.createCatalog(
"sqlserver_catalog",
Catalog.Type.RELATIONAL,
"jdbc-sqlserver",
"SQL Server catalog",
properties);
gravitino_client = GravitinoClient(uri="http://localhost:8090", metalake_name="metalake_demo")
catalog = gravitino_client.create_catalog(
name="sqlserver_catalog",
catalog_type=Catalog.Type.RELATIONAL,
provider="jdbc-sqlserver",
comment="SQL Server catalog",
properties={
"jdbc-url": "jdbc:sqlserver://{host}:1433;databaseName={database};encrypt=true;trustServerCertificate=true",
"jdbc-user": "{user}",
"jdbc-password": "{password}",
"jdbc-database": "{database}",
"jdbc-driver": "com.microsoft.sqlserver.jdbc.SQLServerDriver",
},
)
3. List the schemas. Gravitino returns the SQL Server schemas in that database, with the system schemas filtered out.
Catalog Properties
Five properties are required. The SQL Server catalog defines no properties of its own beyond the JDBC properties every JDBC catalog shares.
| Property | Description | Example |
|---|---|---|
jdbc-url | The SQL Server JDBC connection string | jdbc:sqlserver://localhost:1433;databaseName=demo |
jdbc-user | The SQL Server login Gravitino connects as | sa |
jdbc-password | The password for that login | YourStrong!Passw0rd |
jdbc-database | The database the catalog operates on | demo |
jdbc-driver | The driver class name | com.microsoft.sqlserver.jdbc.SQLServerDriver |
jdbc-database is mandatory and catalog creation fails without it. It must match the databaseName
in the JDBC URL, since Gravitino sets the connection catalog from the property while the driver
opens the connection using the URL.
Connection Encryption
Version 10 and later of the Microsoft driver encrypt connections by default. The encrypt and
trustServerCertificate parameters in the URL control that behavior.
Use trustServerCertificate=true for development only, since it skips certificate validation
entirely. In production, set trustServerCertificate=false and give the server a certificate from
a CA the Gravitino server trusts. SQL Server 2008 supports only TLS 1.0, which the modern driver
declines, so reaching it requires either encrypt=false or TLS configuration on the server.
Schemas
A schema in this catalog is a SQL Server schema, such as dbo, inside the single database named by
jdbc-database. Create, list, load, and drop are supported.
Creation issues CREATE SCHEMA [{name}] AUTHORIZATION [dbo], so a new schema is always owned by
dbo. Schema properties are rejected, and schema comments are unavailable because SQL Server has no
schema comment syntax.
Drop has no cascade. SQL Server does not implement DROP SCHEMA ... CASCADE, so dropping a schema
that still holds objects fails with SQL Server's own error rather than removing them.
Twelve names are reserved and cannot be used for a schema, and the same twelve are filtered out of
schema listings: guest, information_schema, sys, and the nine fixed database roles from
db_owner through db_denydatawriter.
Tables
Table create, load, list, rename, alter, and drop are supported. Purge is not: SQL Server has no equivalent operation, so a purge request is rejected rather than being treated as a drop.
Listing excludes tables SQL Server ships itself, by filtering on is_ms_shipped, so internal tables
such as spt_fallback_db do not appear as user metadata.
Rename goes through sp_rename rather than ALTER TABLE, for both tables and columns.
Table Properties
Table properties are not supported. Creating a table with properties is rejected, and setting or removing a property on an existing table is rejected as well. Comment is the only reserved property entry the catalog recognizes.
Comments
Table and column comments are stored as SQL Server extended properties under the name
MS_Description, not as part of the table definition. Gravitino adds them with
sp_addextendedproperty after the CREATE TABLE statement, and an update checks whether the
property already exists so that it adds or updates as appropriate.
Indexes
Primary key and unique key are the only supported index types, and only at table creation. An index
with a multi-part field name is rejected. A primary key created without a name is given
PK_{table_name}.
Deleting an index through an alter is supported and issues DROP CONSTRAINT, since SQL Server backs
both index types with constraints. Adding an index through an alter is not implemented and fails as
an unsupported change, so an index that was not declared at creation cannot be added through
Gravitino.
Partitioning and Distribution
Neither is supported. A create carrying partitioning is rejected, and a distribution other than none is rejected.
Auto Increment
An auto-increment column is generated as IDENTITY(1,1), so it starts at one and increments by one.
The seed and increment are not configurable. The column type must be one that Gravitino permits for
auto increment.
Supported Table Changes
| Change | Supported |
|---|---|
| Rename table | Yes, through sp_rename |
| Update table comment | Yes |
| Add column | Yes, at the default position only |
| Delete column | Yes |
| Rename column | Yes, through sp_rename |
| Update column type | Yes |
| Update column nullable | Yes |
| Update column default | Yes |
| Update column comment | Yes |
| Delete index | Yes |
| Add index | No |
| Update column position | No |
| Set or remove property | No |
Nested column names are rejected by every column change.
Updating a column default drops the existing default constraint and adds a new one, because SQL Server attaches a default to a named constraint rather than to the column itself.
Identifier Rules
Identifiers are validated against ^[a-zA-Z_\p{L}@#][\w\p{L}@#$]{0,127}$, giving a maximum of 128
characters. A name starts with a letter, an underscore, @, or #, and continues with letters,
digits, underscores, @, #, or $. Letters from any script are accepted, not only ASCII.
Names are treated as case-insensitive, matching SQL Server's default collation behavior. A server configured with a case-sensitive collation is not accounted for.
Gravitino quotes identifiers with square brackets in generated SQL and doubles any ] inside a
name.
Type Mapping
SQL Server to Gravitino
| SQL Server type | Gravitino type |
|---|---|
tinyint | Byte |
smallint | Short |
int | Integer |
bigint | Long |
bit | Boolean |
decimal(p,s) | Decimal(p, s) |
real | Float |
float | Double |
date | Date |
time(p) | Time with precision p |
datetime2(p) | Timestamp without time zone, precision p |
char(n) | Char(n) |
varchar(n) | Varchar(n) |
varchar(max) | External type varchar(max) |
nvarchar | String |
binary(n) | Fixed(n) |
varbinary | Binary |
uniqueidentifier | UUID |
| Any other type | External type carrying the SQL Server name |
An external type keeps its parameters for numeric, nchar, and datetimeoffset, and is recorded
by name alone for everything else.
Gravitino to SQL Server
| Gravitino type | SQL Server type |
|---|---|
| Byte | tinyint |
| Short | smallint |
| Integer | int |
| Long | bigint |
| Boolean | bit |
| Decimal(p, s) | decimal(p,s) |
| Float | real |
| Double | float |
| Date | date |
| Time | time(p), or time when no precision is set |
| Timestamp without time zone | datetime2(p), or datetime2 when no precision is set |
| Char(n) | char(n) |
| Varchar(n) | varchar(n) |
| String | nvarchar(max) |
| Fixed(n) | binary(n) |
| Binary | varbinary(max) |
| UUID | uniqueidentifier |
| External type | The SQL Server type name it carries |
Timestamp with a time zone has no mapping and is rejected, since datetime2 carries no zone. Use an
external type of datetimeoffset when you need that behavior.
Column Default Values
GETDATE() and CURRENT_TIMESTAMP are both recognized as the current timestamp default, and a
current timestamp default is written back as GETDATE(). Any other function expression is written
inside parentheses. A boolean default becomes 1 or 0 to match the bit type. An expression the
converter cannot parse is preserved as an unparsed expression rather than being dropped.
Error Mapping
SQL Server error codes are translated into Gravitino exceptions so a caller sees the same failure types it would from any other catalog.
| SQL Server error | Gravitino exception |
|---|---|
| 2714 object already exists | Table already exists |
| 15032 schema already exists | Schema already exists |
| 208 invalid object name | No such table |
| 3701 cannot drop, object does not exist | No such schema or no such table, from the message |
| 15151 cannot find schema | No such schema |
| 229 permission denied | Forbidden |
| 18456 login failed | Unauthorized |
| 4060 cannot open database | No such schema |
SQL Server reports a duplicate table and a duplicate schema with overlapping codes, so schema creation catches the table-level result and re-raises it as a schema conflict. Any unrecognized code produces a generic runtime exception carrying the SQL Server message.