From 93b9ff7fc15be6a0dc76fc437eb95e49f721b5c4 Mon Sep 17 00:00:00 2001 From: lukaseder Date: Wed, 19 Apr 2017 16:02:18 +0200 Subject: [PATCH] [#5955] Improved error messages --- .../main/java/org/jooq/impl/ParserImpl.java | 120 ++++++++++-------- 1 file changed, 66 insertions(+), 54 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java index 38b4efdaa6..bf1489f093 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java @@ -340,7 +340,7 @@ class ParserImpl implements Parser { while (parseIf(ctx, ";")); if (!ctx.done()) - throw ctx.exception(); + throw ctx.exception("Unexpected content after end of queries input"); return new QueriesImpl(result); } @@ -351,7 +351,7 @@ class ParserImpl implements Parser { Query result = parseQuery(ctx); if (!ctx.done()) - throw ctx.exception(); + throw ctx.exception("Unexpected content after end of query input"); return result; } @@ -362,7 +362,7 @@ class ParserImpl implements Parser { Table result = parseTable(ctx); if (!ctx.done()) - throw ctx.exception(); + throw ctx.exception("Unexpected content after end of table input"); return result; } @@ -373,7 +373,7 @@ class ParserImpl implements Parser { Field result = parseField(ctx); if (!ctx.done()) - throw ctx.exception(); + throw ctx.exception("Unexpected content after end of field input"); return result; } @@ -384,7 +384,7 @@ class ParserImpl implements Parser { RowN result = parseRow(ctx); if (!ctx.done()) - throw ctx.exception(); + throw ctx.exception("Unexpected content after end of row input"); return result; } @@ -395,7 +395,7 @@ class ParserImpl implements Parser { Condition result = parseCondition(ctx); if (!ctx.done()) - throw ctx.exception(); + throw ctx.exception("Unexpected content after end of condition input"); return result; } @@ -406,7 +406,7 @@ class ParserImpl implements Parser { Name result = parseName(ctx); if (!ctx.done()) - throw ctx.exception(); + throw ctx.exception("Unexpected content after end of name input"); return result; } @@ -508,7 +508,7 @@ class ParserImpl implements Parser { throw ctx.unexpectedToken(); } - throw ctx.exception(); + throw ctx.exception("Unsupported query type"); } // ----------------------------------------------------------------------------------------------------------------- @@ -708,7 +708,7 @@ class ParserImpl implements Parser { List> select = parseSelectList(ctx); if (degree != null && select.size() != degree) - throw ctx.exception(); + throw ctx.exception("Select list must contain " + degree + " columns. Got: " + select.size()); Table into = null; List> from = null; @@ -879,7 +879,7 @@ class ParserImpl implements Parser { List> values = parseFields(ctx); if (fields != null && fields.length != values.size()) - throw ctx.exception(); + throw ctx.exception("Insert field size (" + fields.length + ") must match values size (" + values.size() + ")"); allValues.add(values); parse(ctx, ')'); @@ -910,7 +910,7 @@ class ParserImpl implements Parser { } else if (parseKeywordIf(ctx, "DEFAULT VALUES")) { if (fields != null) - throw ctx.exception(); + throw ctx.notImplemented("DEFAULT VALUES without INSERT field list"); else returning = onDuplicate = ctx.dsl.insertInto(tableName).defaultValues(); } @@ -989,7 +989,7 @@ class ParserImpl implements Parser { Field field = parseFieldName(ctx); if (map.containsKey(field)) - throw ctx.exception(); + throw ctx.exception("Duplicate column in set clause list: " + field); parse(ctx, '='); Field value = parseField(ctx); @@ -1032,14 +1032,14 @@ class ParserImpl implements Parser { parse(ctx, ')'); if (insertColumns.length != insertValues.size()) - throw ctx.exception(); + throw ctx.exception("Insert column size (" + insertColumns.length + ") must match values size (" + insertValues.size() + ")"); } else break; } if (!update && !insert) - throw ctx.exception(); + throw ctx.exception("At least one of UPDATE or INSERT clauses is required"); // TODO support WHERE // TODO support multi clause MERGE @@ -1154,7 +1154,7 @@ class ParserImpl implements Parser { Select select = parseSelect(ctx); if (fields.length > 0 && fields.length != select.getSelect().size()) - throw ctx.exception(); + throw ctx.exception("Select list size (" + select.getSelect().size() + ") must match declared field size (" + fields.length + ")"); return ifNotExists @@ -1320,7 +1320,7 @@ class ParserImpl implements Parser { if (parseKeywordIf(ctx, "PRIMARY KEY")) { if (primary) { - throw ctx.exception(); + throw ctx.exception("Duplicate primary key specification"); } else { primary = true; @@ -1353,7 +1353,7 @@ class ParserImpl implements Parser { parse(ctx, ')'); if (referencing.length != referencedFields.length) - throw ctx.exception(); + throw ctx.exception("Number of referencing columns (" + referencing.length + ") must match number of referenced columns (" + referencedFields.length + ")"); constraints.add(constraint == null ? foreignKey(referencing).references(referencedTable, referencedFields) @@ -1437,7 +1437,7 @@ class ParserImpl implements Parser { parse(ctx, ')'); if (referencing.length != referencedFields.length) - throw ctx.exception(); + throw ctx.exception("Number of referencing columns must match number of referenced columns"); return constraint == null ? s1.add(foreignKey(referencing).references(referencedTable, referencedFields)) @@ -1858,7 +1858,7 @@ class ParserImpl implements Parser { // TODO: Support this for ROW as well if (((Field) left) == null) - throw ctx.exception(); + throw ctx.notImplemented("DISTINCT predicate for rows"); Field right = toField(ctx, parseConcat(ctx, null)); return not ? ((Field) left).isNotDistinctFrom(right) : ((Field) left).isDistinctFrom(right); @@ -1968,7 +1968,7 @@ class ParserImpl implements Parser { } else if (parseKeywordIf(ctx, "UNNEST")) { // TODO - throw ctx.exception(); + throw ctx.notImplemented("UNNEST"); } else if (parseIf(ctx, '(')) { if (peekKeyword(ctx, "SELECT")) { @@ -2153,10 +2153,10 @@ class ParserImpl implements Parser { else if (fieldsOrRows.size() == 1) row = (RowN) fieldsOrRows.get(0); else - throw ctx.exception(); + throw ctx.exception("Unsupported row size"); if (degree != null && row.size() != degree) - throw ctx.exception(); + throw ctx.exception("Expected row of degree: " + degree + ". Got: " + row.size()); parse(ctx, ')'); return row; @@ -2380,9 +2380,9 @@ class ParserImpl implements Parser { if (((Field) part).getDataType().getType() == Boolean.class) return condition((Field) part); else - throw ctx.exception(); + throw ctx.expected("Boolean field"); else - throw ctx.exception(); + throw ctx.expected("Condition"); } private static final FieldOrRow toFieldOrRow(ParserContext ctx, QueryPart part) { @@ -2395,7 +2395,7 @@ class ParserImpl implements Parser { else if (part instanceof Row) return (Row) part; else - throw ctx.exception(); + throw ctx.expected("Field or row"); } private static final Field toField(ParserContext ctx, QueryPart part) { @@ -2406,7 +2406,7 @@ class ParserImpl implements Parser { else if (part instanceof Condition) return field((Condition) part); else - throw ctx.exception(); + throw ctx.expected("Field"); } private static final FieldOrRow parseConcat(ParserContext ctx, Type type) { @@ -2477,7 +2477,7 @@ class ParserImpl implements Parser { for (;;) if (parseIf(ctx, '+')) - sign = 1; + sign = sign == null ? 1 : sign; else if (parseIf(ctx, '-')) sign = sign == null ? -1 : -sign; else @@ -2872,7 +2872,7 @@ class ParserImpl implements Parser { if (peekKeyword(ctx, "SELECT")) { SelectQueryImpl select = parseSelect(ctx); if (select.getSelect().size() > 1) - throw ctx.exception(); + throw ctx.exception("Select list must contain at least one column"); field = field((Select) select); parse(ctx, ')'); @@ -3082,7 +3082,7 @@ class ParserImpl implements Parser { return Timestamp.valueOf(parseStringLiteral(ctx)); } catch (IllegalArgumentException e) { - throw ctx.exception(); + throw ctx.exception("Illegal timestamp literal"); } } @@ -3109,7 +3109,7 @@ class ParserImpl implements Parser { return Time.valueOf(parseStringLiteral(ctx)); } catch (IllegalArgumentException e) { - throw ctx.exception(); + throw ctx.exception("Illegal time literal"); } } @@ -3133,7 +3133,7 @@ class ParserImpl implements Parser { return Date.valueOf(parseStringLiteral(ctx)); } catch (IllegalArgumentException e) { - throw ctx.exception(); + throw ctx.exception("Illegal date literal"); } } @@ -3722,7 +3722,7 @@ class ParserImpl implements Parser { case NULL: return inline((Boolean) null); default: - throw ctx.exception(); + throw ctx.exception("Truth value not supported: " + truth); } } @@ -4186,7 +4186,7 @@ class ParserImpl implements Parser { case REGR_SYY: return regrSYY(arg1, arg2); default: - throw ctx.exception(); + throw ctx.exception("Binary set function not supported: " + type); } } @@ -4450,7 +4450,7 @@ class ParserImpl implements Parser { do { if (!result.add(parseIdentifier(ctx))) - throw ctx.exception(); + throw ctx.exception("Duplicate identifier encountered"); } while (parseIf(ctx, ',')); return new ArrayList(result); @@ -4460,7 +4460,7 @@ class ParserImpl implements Parser { Name result = parseIdentifierIf(ctx); if (result == null) - throw ctx.exception(); + throw ctx.expected("Identifier"); return result; } @@ -4486,14 +4486,11 @@ class ParserImpl implements Parser { if (ctx.position == start) return null; - if (ctx.position - start < 0) - throw ctx.exception(); - String result = new String(ctx.sql, start, ctx.position - start); if (quoteEnd != 0) { if (ctx.character() != quoteEnd) - throw ctx.exception(); + throw ctx.exception("Quoted identifier must terminate in " + quoteEnd); ctx.position = ctx.position + 1; return DSL.quotedName(result); @@ -4584,7 +4581,7 @@ class ParserImpl implements Parser { return DSL.param(parseIdentifier(ctx).last()); default: - throw ctx.exception(); + throw ctx.exception("Illegal bind variable character"); } } @@ -4607,11 +4604,18 @@ class ParserImpl implements Parser { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); char c1 = 0; char c2 = 0; - int i = ctx.position; do { - c1 = ctx.character(i); - c2 = ctx.character(i + 1); + for (;;) { + c1 = ctx.character(ctx.position); + + if (c1 == ' ') + ctx.position = ctx.position + 1; + else + break; + } + + c2 = ctx.character(ctx.position + 1); if (c1 == '\'') break; @@ -4622,17 +4626,17 @@ class ParserImpl implements Parser { buffer.write(Integer.parseInt("" + c1 + c2, 16)); } catch (NumberFormatException e) { - throw ctx.exception(); + throw ctx.exception("Illegal character for binary literal"); } } - while ((i = i + 2) < ctx.sql.length); + while ((ctx.position = ctx.position + 2) < ctx.sql.length); if (c1 == '\'') { - ctx.position = i + 1; + ctx.position = ctx.position + 1; return buffer.toByteArray(); } - throw ctx.exception(); + throw ctx.exception("Binary literal not terminated"); } return null; @@ -4651,7 +4655,7 @@ class ParserImpl implements Parser { case '(': end = ')'; ctx.position = ctx.position + 1; break; case '<': end = '>'; ctx.position = ctx.position + 1; break; default: - throw ctx.exception(); + throw ctx.exception("Illegal quote string character"); } StringBuilder sb = new StringBuilder(); @@ -4670,7 +4674,7 @@ class ParserImpl implements Parser { sb.append(c); } - throw ctx.exception(); + throw ctx.exception("Quoted string literal not terminated"); } private static final String parseUnquotedStringLiteral(ParserContext ctx) { @@ -4693,7 +4697,7 @@ class ParserImpl implements Parser { sb.append(c); } - throw ctx.exception(); + throw ctx.exception("String literal not terminated"); } private static final Field parseFieldUnsignedNumericLiteral(ParserContext ctx, boolean minus) { @@ -4767,7 +4771,7 @@ class ParserImpl implements Parser { Long result = parseUnsignedIntegerIf(ctx); if (result == null) - throw ctx.exception(); + throw ctx.expected("Unsigned integer"); return result; } @@ -5168,11 +5172,19 @@ class ParserImpl implements Parser { } ParserException internalError() { - return new ParserException(mark(), "Internal Error"); + return exception("Internal Error"); } - ParserException exception() { - return new ParserException(mark()); + ParserException expected(String object) { + return new ParserException(mark(), object + " expected"); + } + + ParserException notImplemented(String feature) { + return new ParserException(mark(), feature + " not yet implemented"); + } + + ParserException exception(String message) { + return new ParserException(mark(), message); } ParserException unexpectedToken() {