Skip to content

improve SQL mutation statements#575

Open
cportele wants to merge 1 commit into
masterfrom
mutation-sql
Open

improve SQL mutation statements#575
cportele wants to merge 1 commit into
masterfrom
mutation-sql

Conversation

@cportele

Copy link
Copy Markdown
Contributor

Mutation SQL is assembled by string concatenation, and numeric-typed columns inlined the value's raw text: SqlMutationSession.encodeLiteral returned value.asText() for INTEGER/FLOAT, and FeatureEncoderSql.onValue only quoted STRING/DATE/DATETIME. A client sending a JSON string (or a wfs:Value) for a numeric column could therefore inject arbitrary SQL into the generated INSERT/UPDATE (e.g. "0 WHERE 1=1; DROP TABLE x --"), without requiring handling=strict. FeatureEncoderSql.onValue also inlined BOOLEAN values raw, and the role-override UPDATE path (formatRoleOverrideValue) had the same shape.

Centralize inline-literal rendering in SqlLiterals and route all three sinks through it:

  • integers are re-rendered from a parsed BigDecimal.toBigIntegerExact()
  • floats are re-rendered via BigDecimal.toPlainString() (also avoids non-portable scientific notation)
  • booleans are normalized to the TRUE/FALSE keywords
  • strings/dates and any unmapped column type are single-quoted with quote-doubling (safe default: never inline raw input)
  • null is preserved

A value that does not match its column type is now rejected with IllegalArgumentException instead of being inlined verbatim, consistent with the existing geometry-literal validation. This is a slightly stricter contract: a malformed numeric/boolean value now fails the write rather than being silently coerced.

Oracle shares this path (FeatureProviderOracle extends FeatureProviderSql and reuses SqlMutationSession/FeatureEncoderSql; SqlDialectOras.escapeString matches the standard quote-doubling), so the guard applies there too.

Adds SqlLiteralsSpec covering quote-doubling, numeric/boolean validation, injection rejection, NULL, and the quoted fallback.

Mutation SQL is assembled by string concatenation, and numeric-typed
columns inlined the value's raw text: SqlMutationSession.encodeLiteral
returned value.asText() for INTEGER/FLOAT, and FeatureEncoderSql.onValue
only quoted STRING/DATE/DATETIME. A client sending a JSON string (or a
wfs:Value) for a numeric column could therefore inject arbitrary SQL into
the generated INSERT/UPDATE (e.g. "0 WHERE 1=1; DROP TABLE x --"), without
requiring handling=strict. FeatureEncoderSql.onValue also inlined BOOLEAN
values raw, and the role-override UPDATE path (formatRoleOverrideValue) had
the same shape.

Centralize inline-literal rendering in SqlLiterals and route all three
sinks through it:
- integers are re-rendered from a parsed BigDecimal.toBigIntegerExact()
- floats are re-rendered via BigDecimal.toPlainString() (also avoids
  non-portable scientific notation)
- booleans are normalized to the TRUE/FALSE keywords
- strings/dates and any unmapped column type are single-quoted with
  quote-doubling (safe default: never inline raw input)
- null is preserved

A value that does not match its column type is now rejected with
IllegalArgumentException instead of being inlined verbatim, consistent
with the existing geometry-literal validation. This is a slightly
stricter contract: a malformed numeric/boolean value now fails the write
rather than being silently coerced.

Oracle shares this path (FeatureProviderOracle extends FeatureProviderSql
and reuses SqlMutationSession/FeatureEncoderSql; SqlDialectOras.escapeString
matches the standard quote-doubling), so the guard applies there too.

Adds SqlLiteralsSpec covering quote-doubling, numeric/boolean validation,
injection rejection, NULL, and the quoted fallback.
@cportele cportele requested a review from azahnen as a code owner July 13, 2026 11:05
@cportele cportele added the bug label Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant