{"record":{"id":"40860ec4fdced73e","repo":"prestodb/presto","slug":"duplicate-language-clause-s","errorCode":null,"errorMessage":"Duplicate language clause: %s","messagePattern":"Duplicate language clause: (.+?)","errorType":"exception","errorClass":"ParsingException","httpStatus":null,"severity":"error","filePath":"presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java","lineNumber":3064,"sourceCode":"\n        throw new IllegalArgumentException(\"Unsupported type specification: \" + type.getText());\n    }\n\n    private SqlParameterDeclaration getParameterDeclarations(SqlBaseParser.SqlParameterDeclarationContext context)\n    {\n        return new SqlParameterDeclaration((Identifier) visit(context.identifier()), getType(context.type()));\n    }\n\n    private RoutineCharacteristics getRoutineCharacteristics(SqlBaseParser.RoutineCharacteristicsContext context)\n    {\n        Language language = null;\n        Determinism determinism = null;\n        NullCallClause nullCallClause = null;\n\n        for (SqlBaseParser.RoutineCharacteristicContext characteristic : context.routineCharacteristic()) {\n            if (characteristic.language() != null) {\n                if (language != null) {\n                    throw new ParsingException(format(\"Duplicate language clause: %s\", characteristic.language().getText()), getLocation(characteristic.language()));\n                }\n                if (characteristic.language().SQL() != null) {\n                    language = Language.SQL;\n                }\n                else {\n                    language = new Language(((Identifier) visit(characteristic.language().identifier())).getValue());\n                }\n            }\n            else if (characteristic.determinism() != null) {\n                if (determinism != null) {\n                    throw new ParsingException(format(\"Duplicate determinism characteristics: %s\", characteristic.determinism().getText()), getLocation(characteristic.determinism()));\n                }\n                determinism = characteristic.determinism().NOT() == null ? DETERMINISTIC : NOT_DETERMINISTIC;\n            }\n            else if (characteristic.nullCallClause() != null) {\n                if (nullCallClause != null) {\n                    throw new ParsingException(format(\"Duplicate null-call clause: %s\", characteristic.nullCallClause().getText()), getLocation(characteristic.nullCallClause()));\n                }","sourceCodeStart":3046,"sourceCodeEnd":3082,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java#L3046-L3082","documentation":"AstBuilder.visitCreateFunction (routine characteristics loop) throws ParsingException when a CREATE FUNCTION statement specifies the LANGUAGE characteristic more than once. SQL routine characteristics must be unique, so a second LANGUAGE clause is rejected at parse time.","triggerScenarios":"Parsing 'CREATE FUNCTION ... LANGUAGE SQL LANGUAGE SQL ...' or any statement with two LANGUAGE characteristics in the routine_characteristic list.","commonSituations":"Generated SQL that appends characteristics repeatedly, templating bugs that emit the clause per parameter/version, or hand-written functions copied from dialects with repeated clauses.","solutions":["Remove all but one LANGUAGE clause from the function definition.","Deduplicate characteristics in SQL-generating code.","Pre-validate the characteristic list for repeated LANGUAGE keywords before parsing/executing.","Fix templates so each characteristic is emitted at most once."],"exampleFix":"// before\nCREATE FUNCTION f() RETURNS int LANGUAGE SQL LANGUAGE SQL RETURN 1;\n// after\nCREATE FUNCTION f() RETURNS int LANGUAGE SQL RETURN 1;","handlingStrategy":"validation","validationCode":"// dedupe routine characteristics before parsing\ntreeSet.add() ; // e.g. collect LANGUAGE clauses\nlong langs = sqlChars.stream().filter(c -> c.matches(\"(?i)LANGUAGE\\\\s+\")).count();\nif (langs > 1) throw new IllegalArgumentException(\"Duplicate LANGUAGE clause\");","typeGuard":"boolean hasDuplicateCharacteristic(String sql, String keyword) {\n    return Pattern.compile(\"(?i)\\\\b\" + keyword + \"\\\\b\").splitAsStream(sql).count() > 2;\n}","tryCatchPattern":"try {\n    parser.createStatement(sql);\n} catch (ParsingException e) {\n    if (e.getMessage().startsWith(\"Duplicate language clause\")) {\n        throw new IllegalArgumentException(\"Remove extra LANGUAGE clauses from function DDL\", e);\n    }\n    throw e;\n}","preventionTips":["Generate characteristics from a Set so each clause appears once.","Have SQL templates replace rather than append characteristics.","Validate function DDL in unit tests."],"tags":["sql-parser","create-function","duplicate-clause"],"backgroundTag":"duplicate-clause","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}