prestodb/presto · error · ParsingException

Duplicate null-call clause: %s

Error message

Duplicate null-call clause: %s

What it means

Duplicate-clause guard in the routine-characteristics loop of AstBuilder: a CREATE FUNCTION statement specifies the NULL ON INPUT / RETURNS NULL ON NULL INPUT / CALLED ON NULL INPUT clause more than once. The second null-call clause triggers a ParsingException at its location.

Source

Thrown at presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java:3081

                if (language != null) {
                    throw new ParsingException(format("Duplicate language clause: %s", characteristic.language().getText()), getLocation(characteristic.language()));
                }
                if (characteristic.language().SQL() != null) {
                    language = Language.SQL;
                }
                else {
                    language = new Language(((Identifier) visit(characteristic.language().identifier())).getValue());
                }
            }
            else if (characteristic.determinism() != null) {
                if (determinism != null) {
                    throw new ParsingException(format("Duplicate determinism characteristics: %s", characteristic.determinism().getText()), getLocation(characteristic.determinism()));
                }
                determinism = characteristic.determinism().NOT() == null ? DETERMINISTIC : NOT_DETERMINISTIC;
            }
            else if (characteristic.nullCallClause() != null) {
                if (nullCallClause != null) {
                    throw new ParsingException(format("Duplicate null-call clause: %s", characteristic.nullCallClause().getText()), getLocation(characteristic.nullCallClause()));
                }
                nullCallClause = characteristic.nullCallClause().CALLED() != null ? CALLED_ON_NULL_INPUT : RETURNS_NULL_ON_NULL_INPUT;
            }
            else {
                throw new IllegalArgumentException(format("Unsupported RoutineCharacteristic: %s", characteristic.getText()));
            }
        }

        return new RoutineCharacteristics(
                Optional.ofNullable(language),
                Optional.ofNullable(determinism),
                Optional.ofNullable(nullCallClause));
    }

    private AlterRoutineCharacteristics getAlterRoutineCharacteristics(SqlBaseParser.AlterRoutineCharacteristicsContext context)
    {
        if (context.alterRoutineCharacteristic().isEmpty()) {
            throw new ParsingException("No alter routine characteristics specified");

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Emit only one CALLED ON NULL INPUT or RETURNS NULL ON NULL INPUT clause.
  2. Deduplicate characteristics when composing function DDL.
  3. Pre-validate the characteristic list before parsing.
  4. Fix DDL generation to replace, not append, the null-call setting.

Example fix

// before
CREATE FUNCTION f() RETURNS int CALLED ON NULL INPUT RETURNS NULL ON NULL INPUT RETURN 1;
// after
CREATE FUNCTION f() RETURNS int RETURNS NULL ON NULL INPUT RETURN 1;
Defensive patterns

Strategy: validation

Validate before calling

int nullCallClauses = countMatches(sql, "(?i)\\b(CALLED\\s+ON\\s+NULL\\s+INPUT|RETURNS\\s+NULL\\s+ON\\s+NULL\\s+INPUT)\\b");
if (nullCallClauses > 1) {
    throw new IllegalArgumentException("Only one null-call clause allowed");
}

Type guard

boolean hasSingleNullCallClause(String sql) {
    Matcher m = Pattern.compile("(?i)(CALLED ON NULL INPUT|RETURNS NULL ON NULL INPUT)").matcher(sql);
    return count(m) <= 1;
}

Try / catch

try {
    parser.createStatement(sql);
} catch (ParsingException e) {
    if (e.getMessage().startsWith("Duplicate null-call clause")) {
        throw new IllegalArgumentException("Keep only one CALLED/RETURNS NULL ON NULL INPUT clause", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Parsing a CREATE FUNCTION whose routine_characteristic list contains two null-call clauses (e.g. 'RETURNS NULL ON NULL INPUT CALLED ON NULL INPUT' or the same clause twice).

Common situations: Generated function DDL that emits a default null-call clause plus a user-specified one, or concatenated SQL fragments each carrying the clause.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/133914f5caeec077. Report an issue: GitHub.