prestodb/presto · error · ParsingException

No alter routine characteristics specified

Error message

No alter routine characteristics specified

What it means

getAlterRoutineCharacteristics throws ParsingException when an ALTER FUNCTION ... CHARACTERISTICS clause contains no characteristics at all (the alterRoutineCharacteristic list is empty). The grammar allows an empty list, but the builder requires at least one characteristic to alter.

Source

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

                    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");
        }

        NullCallClause nullCallClause = null;

        for (SqlBaseParser.AlterRoutineCharacteristicContext characteristic : context.alterRoutineCharacteristic()) {
            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;
            }
        }

        return new AlterRoutineCharacteristics(Optional.ofNullable(nullCallClause));
    }

    private String typeParameterToString(SqlBaseParser.TypeParameterContext typeParameter)
    {

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Add at least one characteristic, e.g. RETURNS NULL ON NULL INPUT, to the CHARACTERISTICS clause.
  2. Omit the CHARACTERISTICS clause entirely when there is nothing to change.
  3. Make DDL generation emit the clause only if the characteristics set is non-empty.
  4. Guard application code to reject empty characteristics before issuing ALTER FUNCTION.

Example fix

// before
ALTER FUNCTION f() CHARACTERISTICS;
// after
ALTER FUNCTION f() CHARACTERISTICS RETURNS NULL ON NULL INPUT;
Defensive patterns

Strategy: validation

Validate before calling

if (characteristics.isEmpty() && sql.toLowerCase(Locale.ROOT).contains("characteristics")) {
    throw new IllegalArgumentException("CHARACTERISTICS clause requires at least one characteristic");
}

Type guard

boolean canEmitCharacteristics(List<String> characteristics) {
    return characteristics != null && !characteristics.isEmpty();
}

Try / catch

try {
    parser.createStatement(sql);
} catch (ParsingException e) {
    if (e.getMessage().equals("No alter routine characteristics specified")) {
        throw new IllegalArgumentException("ALTER FUNCTION CHARACTERISTICS needs at least one clause", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Parsing 'ALTER FUNCTION f() CHARACTERISTICS' (or equivalent grammar form) with an empty characteristic list.

Common situations: SQL builders that always emit the CHARACTERISTICS keyword even when no settings changed, or users dropping all clauses in an edit.

Related errors


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