aster.Web Data / Docs Aster UI ↗

Aster Web Data / Connect your data

OracleCommercial

How Aster Web Data uses Oracle Database, and how Oracle's types, empty strings and results shape what clients receive.

If your data is in Oracle Database, Aster Web Data serves it from your existing tables through Oracle's own Rust driver, with no Instant Client to install. Filters, sorts, pages and counts run in Oracle, and each result is Oracle's own, decoded exactly or refused. Where Oracle's answer differs from OData's, Oracle's stands. The difference users notice first is that VARCHAR2 stores an empty string as null; Departures from OData lists the others.

Two choices need care: the TLS setup, because Oracle's ca_file adds to the public roots rather than replacing them, and the version column that gives a set its ETag, because Oracle has no row version Aster can use.

Connecting

Give the connection's parts, with the password from an environment variable or a file:

databases:
  enterprise:
    kind: oracle
    host: database.example.com
    port: 1522                       # the listener's TCPS port
    user: ASTER_APP
    password_env: ASTER_ORACLE_PASSWORD
    database: FREEPDB1               # the service name
    schema: ASTER_APP                # the user that owns the tables
    tls: verify-full
    ca_file: /etc/aster/oracle-ca.pem

In place of the parts, url_env or url_file can hold a JSON document with user, password and an Easy Connect connect_string. Secrets explains the rules, and the configuration reference lists every key with its default. These behave in a way particular to Oracle:

The tests run on Oracle AI Database 26ai (23.26).

Start-up check

When the service opens the database, it reads the ALL_ catalog views for each data source's table, keeping quoted identifiers and the positions of composite keys, and compares the native types and decimal precision and scale with the configuration. A failed check makes only that database's sets unavailable; A database goes down describes what clients see. To run the check on its own, use the check command.

Types

OData type Column created by recreate Notes
Edm.Int64, enumerations NUMBER(19,0) A value out of range is refused when read, naming the column.
Edm.Decimal(p, s) NUMBER(p,s) Precision and scale are required, with a precision of at most 28. Never converted through a float.
Edm.Double BINARY_DOUBLE NaN, infinities, signed zero and subnormals.
Edm.Boolean NUMBER(1,0) Exactly 0 or 1.
Edm.String VARCHAR2(n CHAR) At most 1,000 characters. The empty string is stored as null.
Edm.Date DATE Midnight, years 1 to 9999.
Edm.TimeOfDay NUMBER(14,0) Nanoseconds since midnight.
Edm.DateTimeOffset TIMESTAMP(9) WITH TIME ZONE Instants in UTC, with nanoseconds.
Edm.Duration NUMBER(25,0) Integral nanoseconds.
Edm.Guid RAW(16) Exactly 16 bytes.
Edm.Binary BLOB An empty value is distinct from null.
128-bit unsigned integer VARCHAR2(39 CHAR) Zero-padded decimal digits.
JSON CLOB UTF-8 text.

Collections are refused, and a float column cannot be read as a decimal. A timestamp stored with a named region is read through SYS_EXTRACT_UTC, keeping its exact instant. TIMESTAMP WITH LOCAL TIME ZONE is not mapped.

Collation and case

Every session sets NLS_COMP and NLS_SORT to BINARY, NLS_NUMERIC_CHARACTERS to ., and TIME_ZONE to +00:00, so comparison and sorting are binary in AL32UTF8 order, and trailing spaces count. Ordinary columns report USING_NLS_COMP, which $metadata keeps; tables the service creates write no COLLATE clause. A column with another named collation is refused.

tolower and toupper are LOWER and UPPER, with Oracle's character mapping. contains, startswith and endswith are LIKE with the pattern bound and a backslash escape.

Where each operation runs

Each OData operator becomes the Oracle operator with the same meaning:

OData Oracle Result
eq, ne, lt, le, gt, ge, in Comparisons and IN OData's rules for nulls are kept.
add, sub, mul, unary - on integers +, -, *, - NUMBER widens past 64 bits; a returned value that does not fit is refused.
div on integers TRUNC(a / b) Truncates toward zero.
mod MOD(a, b) Takes the dividend's sign.
Decimal and double arithmetic +, -, *, / Oracle's precision and special values.
divby BINARY_DOUBLE division INF, -INF or NaN on zero.
round, ceiling, floor ROUND, CEIL, FLOOR
contains, startswith, endswith, like LIKE
tolower, toupper LOWER, UPPER
length LENGTH Characters in AL32UTF8.
substring SUBSTR(s, start + 1, length) Zero-based, as OData is.
indexof INSTR(s, needle) - 1 -1 when absent.
trim, concat TRIM, `
count, sum, avg, min, max Oracle's aggregates Decoded exactly or refused.
Paging and null placement OFFSET ... FETCH, NULLS FIRST and NULLS LAST

These run in the service, within the limits on rows it may hold: regular expressions, general casts, and date and time arithmetic Oracle has no exact form for. mod of doubles and comparisons of BLOB values are not supported. Each $expand level is read by key batches, one statement per level.

Errors

Case Response
ORA-01426 (overflow), ORA-01438 (value too large), ORA-01476 (division by zero), ORA-01722 (invalid number) 400 EvaluationFailed
Constraint violation 409 Conflict
ORA-00060 (deadlock), ORA-08177 (serialisation failure) 409 TransactionConflict, after the atomic group's retries
ORA-01013 (the call was cancelled at the statement timeout) 503 Timeout
ORA-00054, ORA-30006 (the row is locked and the wait ran out) 503 PoolExhausted
Lost connection, such as ORA-03113, ORA-03135 or a listener error 503 ConnectionLost. The connection is discarded.
Any other database error 500 InternalError. The client gets a generic message, and the database's detail goes to the log.

Nulls and ordering

ORDER BY names NULLS FIRST or NULLS LAST as OData asks, with the entity key ending every sort. NaN equals itself and sorts after every other number. $count=true runs the page and a COUNT in one read-only snapshot, so the total agrees with the page.

Departures from OData

Where OData 4.01 defines a result and Oracle gives another, Oracle's result stands. These are the places:

Writes and transactions

Write Statements
POST 3: the type check, the insert, the read by ROWID
POST with $expand 5
Nested insert of a parent and two children 11, each row its own insert
PATCH or PUT with an ETag 2: the lock, then one block that updates and reads the row. A view, a synonym or a large text or binary value takes 3.
PATCH or DELETE without an ETag, DELETE with one 2

Indexes and sort order

Index the columns your screens filter and sort on, as Indexes describes. In the benchmark, equality, prefix and child IN queries used their ordinary indexes, while a text sort with single-column indexes chose a full scan and a sort.

Scaffold

The scaffold command reads the ALL_ catalog views for the tables, columns, keys, defaults, generated columns and comments, and writes a starting data-source configuration for the columns it can map exactly. Connect your own database walks through it.