From e4f38c951321c95897069fb26b0ad126a0dc8ed6 Mon Sep 17 00:00:00 2001 From: gmantele <gmantele@ari.uni-heidelberg.de> Date: Fri, 12 Jan 2018 16:14:12 +0100 Subject: [PATCH] [ADQL] Fix the parsing and translation of a concatenation expression. * The parsing did not allow unsigned numerics and SQL SET functions as specified in the ADQL 2.0 grammar * It was even forbidden to put a column whose the type is not String. * The translation of a concatenation expression was always prefixed by the ADQLList's name: CONCAT_STR. Of course, no database likes that... Regarding this last point, this commit fixes the GitHub issue #54 --- src/adql/parser/ADQLParser.java | 396 ++++++++++-------- src/adql/parser/adqlGrammar.jj | 14 +- src/adql/translator/JDBCTranslator.java | 116 +++-- src/adql/translator/PgSphereTranslator.java | 101 ++--- src/adql/translator/PostgreSQLTranslator.java | 40 +- test/adql/db/TestDBChecker.java | 29 +- 6 files changed, 394 insertions(+), 302 deletions(-) diff --git a/src/adql/parser/ADQLParser.java b/src/adql/parser/ADQLParser.java index 7ca0e58..f32d90b 100644 --- a/src/adql/parser/ADQLParser.java +++ b/src/adql/parser/ADQLParser.java @@ -53,7 +53,7 @@ import adql.translator.TranslationException; /** * Parses an ADQL query thanks to the {@link ADQLParser#Query()} function. -* +* * <p> * This parser is able, thanks to a {@link QueryChecker} object, to check each * {@link ADQLQuery} just after its generation. It could be used to check the @@ -62,7 +62,7 @@ import adql.translator.TranslationException; * you must extend {@link QueryChecker} to check semantically all generated * ADQLQuery objects. * </p> -* +* * <p> * To create an object representation of the given ADQL query, this parser uses * a {@link ADQLQueryFactory} object. So if you want customize some object @@ -71,7 +71,7 @@ import adql.translator.TranslationException; * corresponding function of {@link ADQLQueryFactory} * (ie. createContains(...)). * </p> -* +* * <p><b><u>WARNING:</u> * To modify this class it's strongly encouraged to modify the .jj file in the * section between <i>PARSER_BEGIN</i> and <i>PARSER_END</i> and to re-compile @@ -82,7 +82,7 @@ import adql.translator.TranslationException; * @see ADQLQueryFactory * * @author Grégory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de -* @version 1.4 (09/2017) +* @version 1.4 (01/2018) */ public class ADQLParser implements ADQLParserConstants { @@ -320,7 +320,7 @@ public class ADQLParser implements ADQLParserConstants { * <i>ReInit</i> functions. * * @return The object representation of the given ADQL query. - * + * * @throws ParseException If there is at least one syntactic error. * * @see ADQLParser#Query() @@ -339,9 +339,9 @@ public class ADQLParser implements ADQLParserConstants { * Parses the query given in parameter. * * @param q The ADQL query to parse. - * + * * @return The object representation of the given ADQL query. - * + * * @throws ParseException If there is at least one syntactic error. * * @see ADQLParser#ReInit(java.io.InputStream) @@ -363,9 +363,9 @@ public class ADQLParser implements ADQLParserConstants { * Parses the query contained in the stream given in parameter. * * @param stream The stream which contains the ADQL query to parse. - * + * * @return The object representation of the given ADQL query. - * + * * @throws ParseException If there is at least one syntactic error. * * @see ADQLParser#ReInit(java.io.InputStream) @@ -418,11 +418,11 @@ public class ADQLParser implements ADQLParserConstants { /** * Gets the specified ADQL query and parses the given ADQL query. The SQL * translation is then printed if the syntax is correct. - * + * * <p> * <b>ONLY the syntax is checked: the query is NOT EXECUTED !</b> * </p> - * + * * <p>Supplied parameters are: * <ul> * <li>[-debug] -url http://...</li> @@ -432,7 +432,7 @@ public class ADQLParser implements ADQLParserConstants { * </p> * * @param args - + * @throws Exception */ public static final void main(String[] args) throws Exception{ @@ -1847,10 +1847,32 @@ public class ADQLParser implements ADQLParserConstants { } break; } + case SCIENTIFIC_NUMBER: + case UNSIGNED_FLOAT: + case UNSIGNED_INTEGER:{ + op = UnsignedNumeric(); + { + if ("" != null) + return op; + } + break; + } + case AVG: + case MAX: + case MIN: + case SUM: + case COUNT:{ + op = SqlFunction(); + { + if ("" != null) + return op; + } + break; + } case DELIMITED_IDENTIFIER: case REGULAR_IDENTIFIER:{ column = Column(); - column.setExpectedType('S'); + column.setExpectedType('*'); { if ("" != null) return column; @@ -1859,7 +1881,7 @@ public class ADQLParser implements ADQLParserConstants { } case LEFT_PAR:{ left = jj_consume_token(LEFT_PAR); - op = StringExpression(); + op = ValueExpression(); right = jj_consume_token(RIGHT_PAR); WrappedOperand wop = queryFactory.createWrappedOperand(op); wop.setPosition(new TextPosition(left, right)); @@ -2190,9 +2212,17 @@ public class ADQLParser implements ADQLParserConstants { }else{ switch((jj_ntk == -1) ? jj_ntk_f() : jj_ntk){ case LEFT_PAR: + case AVG: + case MAX: + case MIN: + case SUM: + case COUNT: case STRING_LITERAL: case DELIMITED_IDENTIFIER: - case REGULAR_IDENTIFIER:{ + case REGULAR_IDENTIFIER: + case SCIENTIFIC_NUMBER: + case UNSIGNED_FLOAT: + case UNSIGNED_INTEGER:{ op = StringValueExpressionPrimary(); break; } @@ -3948,7 +3978,7 @@ public class ADQLParser implements ADQLParserConstants { } } - private boolean jj_3R_126(){ + private boolean jj_3R_128(){ Token xsp; xsp = jj_scanpos; if (jj_scan_token(99)){ @@ -3962,6 +3992,17 @@ public class ADQLParser implements ADQLParserConstants { return false; } + private boolean jj_3R_129(){ + Token xsp; + xsp = jj_scanpos; + if (jj_3R_135()){ + jj_scanpos = xsp; + if (jj_3R_136()) + return true; + } + return false; + } + private boolean jj_3R_113(){ if (jj_scan_token(LEFT)) return true; @@ -3982,17 +4023,6 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_127(){ - Token xsp; - xsp = jj_scanpos; - if (jj_3R_133()){ - jj_scanpos = xsp; - if (jj_3R_134()) - return true; - } - return false; - } - private boolean jj_3R_54(){ Token xsp; xsp = jj_scanpos; @@ -4047,6 +4077,12 @@ public class ADQLParser implements ADQLParserConstants { return false; } + private boolean jj_3_18(){ + if (jj_3R_16()) + return true; + return false; + } + private boolean jj_3R_55(){ Token xsp; xsp = jj_scanpos; @@ -4058,12 +4094,6 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3_18(){ - if (jj_3R_16()) - return true; - return false; - } - private boolean jj_3R_35(){ Token xsp; xsp = jj_scanpos; @@ -4161,7 +4191,7 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_132(){ + private boolean jj_3R_134(){ if (jj_scan_token(COMMA)) return true; if (jj_3R_51()) @@ -4208,19 +4238,13 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_22(){ - if (jj_3R_43()) - return true; - return false; - } - private boolean jj_3R_120(){ if (jj_3R_51()) return true; Token xsp; while(true){ xsp = jj_scanpos; - if (jj_3R_132()){ + if (jj_3R_134()){ jj_scanpos = xsp; break; } @@ -4228,18 +4252,24 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_148(){ + private boolean jj_3R_22(){ + if (jj_3R_43()) + return true; + return false; + } + + private boolean jj_3R_150(){ if (jj_scan_token(COMMA)) return true; - if (jj_3R_151()) + if (jj_3R_153()) return true; return false; } - private boolean jj_3R_147(){ + private boolean jj_3R_149(){ if (jj_scan_token(COMMA)) return true; - if (jj_3R_151()) + if (jj_3R_153()) return true; return false; } @@ -4254,7 +4284,7 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_125(){ + private boolean jj_3R_127(){ if (jj_scan_token(DOT)) return true; if (jj_3R_14()) @@ -4262,7 +4292,7 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_124(){ + private boolean jj_3R_126(){ if (jj_scan_token(DOT)) return true; if (jj_3R_14()) @@ -4275,10 +4305,10 @@ public class ADQLParser implements ADQLParserConstants { return true; Token xsp; xsp = jj_scanpos; - if (jj_3R_124()) + if (jj_3R_126()) jj_scanpos = xsp; xsp = jj_scanpos; - if (jj_3R_125()) + if (jj_3R_127()) jj_scanpos = xsp; return false; } @@ -4289,14 +4319,14 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_30(){ - if (jj_scan_token(REGULAR_IDENTIFIER)) + private boolean jj_3R_133(){ + if (jj_3R_21()) return true; return false; } - private boolean jj_3R_131(){ - if (jj_3R_21()) + private boolean jj_3R_30(){ + if (jj_scan_token(REGULAR_IDENTIFIER)) return true; return false; } @@ -4315,7 +4345,7 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_139(){ + private boolean jj_3R_141(){ if (jj_3R_112()) return true; return false; @@ -4332,7 +4362,7 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_130(){ + private boolean jj_3R_132(){ if (jj_3R_22()) return true; return false; @@ -4341,9 +4371,9 @@ public class ADQLParser implements ADQLParserConstants { private boolean jj_3R_119(){ Token xsp; xsp = jj_scanpos; - if (jj_3R_130()){ + if (jj_3R_132()){ jj_scanpos = xsp; - if (jj_3R_131()) + if (jj_3R_133()) return true; } return false; @@ -4373,12 +4403,6 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_58(){ - if (jj_3R_78()) - return true; - return false; - } - private boolean jj_3R_104(){ if (jj_scan_token(COT)) return true; @@ -4391,6 +4415,12 @@ public class ADQLParser implements ADQLParserConstants { return false; } + private boolean jj_3R_58(){ + if (jj_3R_78()) + return true; + return false; + } + private boolean jj_3_13(){ if (jj_3R_26()) return true; @@ -4525,7 +4555,7 @@ public class ADQLParser implements ADQLParserConstants { return true; Token xsp; xsp = jj_scanpos; - if (jj_3R_148()) + if (jj_3R_150()) jj_scanpos = xsp; if (jj_scan_token(RIGHT_PAR)) return true; @@ -4553,7 +4583,7 @@ public class ADQLParser implements ADQLParserConstants { return true; Token xsp; xsp = jj_scanpos; - if (jj_3R_147()) + if (jj_3R_149()) jj_scanpos = xsp; if (jj_scan_token(RIGHT_PAR)) return true; @@ -4567,7 +4597,7 @@ public class ADQLParser implements ADQLParserConstants { return true; Token xsp; xsp = jj_scanpos; - if (jj_3R_139()) + if (jj_3R_141()) jj_scanpos = xsp; if (jj_scan_token(RIGHT_PAR)) return true; @@ -4808,14 +4838,6 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_32(){ - if (jj_3R_14()) - return true; - if (jj_scan_token(DOT)) - return true; - return false; - } - private boolean jj_3R_47(){ if (jj_3R_63()) return true; @@ -4839,6 +4861,14 @@ public class ADQLParser implements ADQLParserConstants { return false; } + private boolean jj_3R_32(){ + if (jj_3R_14()) + return true; + if (jj_scan_token(DOT)) + return true; + return false; + } + private boolean jj_3_12(){ if (jj_3R_25()) return true; @@ -4868,7 +4898,7 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_135(){ + private boolean jj_3R_137(){ Token xsp; xsp = jj_scanpos; if (jj_scan_token(11)){ @@ -4876,7 +4906,7 @@ public class ADQLParser implements ADQLParserConstants { if (jj_scan_token(12)) return true; } - if (jj_3R_128()) + if (jj_3R_130()) return true; return false; } @@ -4907,27 +4937,27 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_143(){ + private boolean jj_3R_145(){ if (jj_3R_22()) return true; return false; } - private boolean jj_3R_141(){ + private boolean jj_3R_143(){ if (jj_3R_22()) return true; return false; } - private boolean jj_3R_138(){ + private boolean jj_3R_140(){ if (jj_scan_token(COMMA)) return true; - if (jj_3R_137()) + if (jj_3R_139()) return true; return false; } - private boolean jj_3R_129(){ + private boolean jj_3R_131(){ Token xsp; xsp = jj_scanpos; if (jj_scan_token(9)){ @@ -4945,23 +4975,23 @@ public class ADQLParser implements ADQLParserConstants { return true; if (jj_scan_token(LEFT_PAR)) return true; - if (jj_3R_136()) + if (jj_3R_138()) return true; if (jj_scan_token(COMMA)) return true; - if (jj_3R_137()) + if (jj_3R_139()) return true; if (jj_scan_token(RIGHT_PAR)) return true; return false; } - private boolean jj_3R_128(){ + private boolean jj_3R_130(){ if (jj_3R_24()) return true; Token xsp; xsp = jj_scanpos; - if (jj_3R_135()) + if (jj_3R_137()) jj_scanpos = xsp; return false; } @@ -4978,20 +5008,6 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3_1(){ - if (jj_3R_14()) - return true; - if (jj_scan_token(DOT)) - return true; - Token xsp; - xsp = jj_scanpos; - if (jj_3R_15()) - jj_scanpos = xsp; - if (jj_scan_token(ASTERISK)) - return true; - return false; - } - private boolean jj_3R_19(){ if (jj_3R_24()) return true; @@ -5011,6 +5027,20 @@ public class ADQLParser implements ADQLParserConstants { return false; } + private boolean jj_3_1(){ + if (jj_3R_14()) + return true; + if (jj_scan_token(DOT)) + return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_15()) + jj_scanpos = xsp; + if (jj_scan_token(ASTERISK)) + return true; + return false; + } + private boolean jj_3R_20(){ if (jj_3R_36()) return true; @@ -5024,24 +5054,24 @@ public class ADQLParser implements ADQLParserConstants { return true; if (jj_scan_token(LEFT_PAR)) return true; - if (jj_3R_136()) + if (jj_3R_138()) return true; if (jj_scan_token(COMMA)) return true; - if (jj_3R_137()) + if (jj_3R_139()) return true; if (jj_scan_token(COMMA)) return true; - if (jj_3R_137()) + if (jj_3R_139()) return true; if (jj_scan_token(COMMA)) return true; - if (jj_3R_137()) + if (jj_3R_139()) return true; Token xsp; while(true){ xsp = jj_scanpos; - if (jj_3R_138()){ + if (jj_3R_140()){ jj_scanpos = xsp; break; } @@ -5070,11 +5100,11 @@ public class ADQLParser implements ADQLParserConstants { } private boolean jj_3R_112(){ - if (jj_3R_128()) + if (jj_3R_130()) return true; Token xsp; xsp = jj_scanpos; - if (jj_3R_129()) + if (jj_3R_131()) jj_scanpos = xsp; return false; } @@ -5104,11 +5134,11 @@ public class ADQLParser implements ADQLParserConstants { return true; if (jj_scan_token(LEFT_PAR)) return true; - if (jj_3R_136()) + if (jj_3R_138()) return true; if (jj_scan_token(COMMA)) return true; - if (jj_3R_137()) + if (jj_3R_139()) return true; if (jj_scan_token(COMMA)) return true; @@ -5209,11 +5239,11 @@ public class ADQLParser implements ADQLParserConstants { return true; if (jj_scan_token(LEFT_PAR)) return true; - if (jj_3R_136()) + if (jj_3R_138()) return true; if (jj_scan_token(COMMA)) return true; - if (jj_3R_137()) + if (jj_3R_139()) return true; if (jj_scan_token(COMMA)) return true; @@ -5234,48 +5264,40 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_53(){ - if (jj_scan_token(SELECT)) + private boolean jj_3R_66(){ + if (jj_3R_112()) return true; return false; } - private boolean jj_3R_66(){ - if (jj_3R_112()) + private boolean jj_3R_152(){ + if (jj_3R_22()) return true; return false; } - private boolean jj_3R_150(){ - if (jj_3R_22()) + private boolean jj_3R_53(){ + if (jj_scan_token(SELECT)) return true; return false; } - private boolean jj_3R_123(){ + private boolean jj_3R_125(){ if (jj_scan_token(LEFT_PAR)) return true; - if (jj_3R_29()) + if (jj_3R_51()) return true; if (jj_scan_token(RIGHT_PAR)) return true; return false; } - private boolean jj_3R_142(){ + private boolean jj_3R_144(){ if (jj_3R_59()) return true; return false; } - private boolean jj_3R_16(){ - if (jj_scan_token(LEFT_PAR)) - return true; - if (jj_3R_33()) - return true; - return false; - } - private boolean jj_3R_21(){ Token xsp; xsp = jj_scanpos; @@ -5299,19 +5321,19 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_146(){ + private boolean jj_3R_148(){ if (jj_3R_51()) return true; return false; } - private boolean jj_3R_140(){ + private boolean jj_3R_142(){ if (jj_3R_59()) return true; return false; } - private boolean jj_3R_122(){ + private boolean jj_3R_124(){ if (jj_3R_22()) return true; return false; @@ -5349,36 +5371,62 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_145(){ + private boolean jj_3R_147(){ if (jj_3R_22()) return true; return false; } - private boolean jj_3R_121(){ - if (jj_3R_23()) + private boolean jj_3R_123(){ + if (jj_3R_129()) return true; return false; } - private boolean jj_3R_149(){ + private boolean jj_3R_151(){ if (jj_3R_59()) return true; return false; } - private boolean jj_3R_136(){ + private boolean jj_3R_16(){ + if (jj_scan_token(LEFT_PAR)) + return true; + if (jj_3R_33()) + return true; + return false; + } + + private boolean jj_3R_138(){ if (jj_3R_29()) return true; return false; } + private boolean jj_3R_122(){ + if (jj_3R_128()) + return true; + return false; + } + + private boolean jj_3R_121(){ + if (jj_3R_23()) + return true; + return false; + } + private boolean jj_3R_115(){ if (jj_scan_token(FULL)) return true; return false; } + private boolean jj_3R_146(){ + if (jj_3R_59()) + return true; + return false; + } + private boolean jj_3R_83(){ if (jj_scan_token(LEFT_PAR)) return true; @@ -5389,14 +5437,8 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_144(){ - if (jj_3R_59()) - return true; - return false; - } - private boolean jj_3R_82(){ - if (jj_3R_127()) + if (jj_3R_129()) return true; return false; } @@ -5408,8 +5450,14 @@ public class ADQLParser implements ADQLParserConstants { jj_scanpos = xsp; if (jj_3R_122()){ jj_scanpos = xsp; - if (jj_3R_123()) - return true; + if (jj_3R_123()){ + jj_scanpos = xsp; + if (jj_3R_124()){ + jj_scanpos = xsp; + if (jj_3R_125()) + return true; + } + } } } return false; @@ -5422,13 +5470,7 @@ public class ADQLParser implements ADQLParserConstants { } private boolean jj_3R_80(){ - if (jj_3R_126()) - return true; - return false; - } - - private boolean jj_3R_118(){ - if (jj_scan_token(FULL)) + if (jj_3R_128()) return true; return false; } @@ -5440,17 +5482,17 @@ public class ADQLParser implements ADQLParserConstants { return true; Token xsp; xsp = jj_scanpos; - if (jj_3R_144()){ + if (jj_3R_146()){ jj_scanpos = xsp; - if (jj_3R_145()) + if (jj_3R_147()) return true; } if (jj_scan_token(COMMA)) return true; xsp = jj_scanpos; - if (jj_3R_149()){ + if (jj_3R_151()){ jj_scanpos = xsp; - if (jj_3R_150()) + if (jj_3R_152()) return true; } if (jj_scan_token(RIGHT_PAR)) @@ -5465,9 +5507,9 @@ public class ADQLParser implements ADQLParserConstants { return true; Token xsp; xsp = jj_scanpos; - if (jj_3R_142()){ + if (jj_3R_144()){ jj_scanpos = xsp; - if (jj_3R_143()) + if (jj_3R_145()) return true; } if (jj_scan_token(RIGHT_PAR)) @@ -5482,9 +5524,9 @@ public class ADQLParser implements ADQLParserConstants { return true; Token xsp; xsp = jj_scanpos; - if (jj_3R_140()){ + if (jj_3R_142()){ jj_scanpos = xsp; - if (jj_3R_141()) + if (jj_3R_143()) return true; } if (jj_scan_token(RIGHT_PAR)) @@ -5504,6 +5546,12 @@ public class ADQLParser implements ADQLParserConstants { return false; } + private boolean jj_3R_118(){ + if (jj_scan_token(FULL)) + return true; + return false; + } + private boolean jj_3R_62(){ Token xsp; xsp = jj_scanpos; @@ -5554,7 +5602,7 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_152(){ + private boolean jj_3R_154(){ Token xsp; xsp = jj_scanpos; if (jj_scan_token(9)){ @@ -5565,10 +5613,10 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_151(){ + private boolean jj_3R_153(){ Token xsp; xsp = jj_scanpos; - if (jj_3R_152()) + if (jj_3R_154()) jj_scanpos = xsp; if (jj_scan_token(UNSIGNED_INTEGER)) return true; @@ -5595,7 +5643,7 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_137(){ + private boolean jj_3R_139(){ if (jj_3R_112()) return true; if (jj_scan_token(COMMA)) @@ -5605,7 +5653,7 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_134(){ + private boolean jj_3R_136(){ Token xsp; xsp = jj_scanpos; if (jj_scan_token(49)){ @@ -5631,13 +5679,7 @@ public class ADQLParser implements ADQLParserConstants { return false; } - private boolean jj_3R_117(){ - if (jj_scan_token(RIGHT)) - return true; - return false; - } - - private boolean jj_3R_133(){ + private boolean jj_3R_135(){ if (jj_scan_token(COUNT)) return true; if (jj_scan_token(LEFT_PAR)) @@ -5649,7 +5691,7 @@ public class ADQLParser implements ADQLParserConstants { xsp = jj_scanpos; if (jj_scan_token(11)){ jj_scanpos = xsp; - if (jj_3R_146()) + if (jj_3R_148()) return true; } if (jj_scan_token(RIGHT_PAR)) @@ -5657,6 +5699,12 @@ public class ADQLParser implements ADQLParserConstants { return false; } + private boolean jj_3R_117(){ + if (jj_scan_token(RIGHT)) + return true; + return false; + } + /** Generated Token Manager. */ public ADQLParserTokenManager token_source; SimpleCharStream jj_input_stream; @@ -5685,7 +5733,7 @@ public class ADQLParser implements ADQLParserConstants { } private static void jj_la1_init_1(){ - jj_la1_1 = new int[]{0x0,0x2,0x1000,0x2000,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000,0x18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,0x0,0x0,0x0,0xfc00000,0x10,0xc,0xc,0x10,0x0,0x10,0x10,0x0,0x210,0x400,0xfffe0000,0x0,0x10,0x10,0x0,0x0,0x0,0xfffe0000,0x1e0000,0x0,0x3e0000,0x30000000,0x2000000,0x2000000,0x2000000,0x2000000,0xf0000000,0x0,0xfc00000,0xf0000000,0xf03e0000,0x0,0x0,0x0,0x0,0x0,0xfffe0000,}; + jj_la1_1 = new int[]{0x0,0x2,0x1000,0x2000,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000,0x18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,0x3e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,0x0,0x0,0x3e0000,0xfc00000,0x10,0xc,0xc,0x10,0x0,0x10,0x10,0x0,0x210,0x400,0xfffe0000,0x0,0x10,0x10,0x0,0x0,0x0,0xfffe0000,0x1e0000,0x0,0x3e0000,0x30000000,0x2000000,0x2000000,0x2000000,0x2000000,0xf0000000,0x0,0xfc00000,0xf0000000,0xf03e0000,0x0,0x0,0x0,0x0,0x0,0xfffe0000,}; } private static void jj_la1_init_2(){ @@ -5693,7 +5741,7 @@ public class ADQLParser implements ADQLParserConstants { } private static void jj_la1_init_3(){ - jj_la1_3 = new int[]{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x3,0x0,0x3,0x0,0x3b,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x23,0x0,0x0,0x0,0x3,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38,0x30,0x0,0x0,0x3b,0x3,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x3,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x0,0x0,0x3,0x3,0x3,0x3,0x0,0x0,0x0,0x2,0x3b,0x0,0x0,0x0,0x0,0x0,0x3b,}; + jj_la1_3 = new int[]{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x3,0x0,0x3,0x0,0x3b,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x23,0x0,0x0,0x0,0x3,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38,0x30,0x0,0x0,0x3b,0x3b,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x3b,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x0,0x0,0x3,0x3,0x3,0x3,0x0,0x0,0x0,0x2,0x3b,0x0,0x0,0x0,0x0,0x0,0x3b,}; } final private JJCalls[] jj_2_rtns = new JJCalls[18]; diff --git a/src/adql/parser/adqlGrammar.jj b/src/adql/parser/adqlGrammar.jj index 7e41e7a..72bd887 100644 --- a/src/adql/parser/adqlGrammar.jj +++ b/src/adql/parser/adqlGrammar.jj @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>. * - * Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2012-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institute (ARI) */ @@ -31,7 +31,7 @@ * printed else it will be the message "Correct syntax". * * Author: Grégory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de -* Version: 1.4 (09/2017) +* Version: 1.4 (01/2018) */ /* ########### */ @@ -109,7 +109,7 @@ import adql.translator.TranslationException; * @see ADQLQueryFactory * * @author Grégory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de -* @version 1.4 (09/2017) +* @version 1.4 (01/2018) */ public class ADQLParser { @@ -1191,10 +1191,14 @@ ADQLOperand StringValueExpressionPrimary(): {StringConstant expr; ADQLColumn col try{ (// string expr=String() {return expr;} + // unsigned numeric + | op=UnsignedNumeric() {return op;} + // set_function_specification + | op=SqlFunction() {return op;} // column_reference - | column=Column() {column.setExpectedType('S'); return column;} + | column=Column() {column.setExpectedType('*'); return column;} // LEFT_PAR value_expression RIGHT_PAR - | (left=<LEFT_PAR> (op=StringExpression()) right=<RIGHT_PAR>) { WrappedOperand wop = queryFactory.createWrappedOperand(op); wop.setPosition(new TextPosition(left, right)); return wop; }) + | (left=<LEFT_PAR> (op=ValueExpression()) right=<RIGHT_PAR>) { WrappedOperand wop = queryFactory.createWrappedOperand(op); wop.setPosition(new TextPosition(left, right)); return wop; }) }catch(Exception ex){ throw generateParseException(ex); } diff --git a/src/adql/translator/JDBCTranslator.java b/src/adql/translator/JDBCTranslator.java index 063299f..b78a757 100644 --- a/src/adql/translator/JDBCTranslator.java +++ b/src/adql/translator/JDBCTranslator.java @@ -16,7 +16,7 @@ package adql.translator; * You should have received a copy of the GNU Lesser General Public License * along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>. * - * Copyright 2017 - Astronomisches Rechen Institut (ARI) + * Copyright 2017-2018 - Astronomisches Rechen Institut (ARI) */ import java.util.Iterator; @@ -78,55 +78,47 @@ import adql.query.operand.function.geometry.PolygonFunction; import adql.query.operand.function.geometry.RegionFunction; /** - * <p>Implementation of {@link ADQLTranslator} which translates ADQL queries in SQL queries.</p> + * Implementation of {@link ADQLTranslator} which translates ADQL queries in + * SQL queries. * * <p> - * It is already able to translate all SQL standard features, but lets abstract the translation of all - * geometrical functions. So, this translator must be extended as {@link PostgreSQLTranslator} and - * {@link PgSphereTranslator} are doing. + * It is already able to translate all SQL standard features, but lets abstract + * the translation of all geometrical functions. So, this translator must be + * extended as {@link PostgreSQLTranslator}, {@link PgSphereTranslator}, + * {@link MySQLTranslator} and {@link SQLServerTranslator} are doing. * </p> * * <p><i>Note: - * Its default implementation of the SQL syntax has been inspired by the PostgreSQL one. - * However, it should work also with SQLite and MySQL, but some translations might be needed - * (as it is has been done for PostgreSQL about the mathematical functions). + * Its default implementation of the SQL syntax has been inspired by the + * PostgreSQL one. However, it should work also with other DBMS, although some + * translations might be needed (as it is has been done for PostgreSQL about + * the mathematical functions). * </i></p> * - * <h3>PostgreSQLTranslator and PgSphereTranslator</h3> - * - * <p> - * {@link PgSphereTranslator} extends {@link PostgreSQLTranslator} and is able to translate geometrical - * functions according to the syntax given by PgSphere. But it can also convert geometrical types - * (from and toward the database), translate PgSphere regions into STC expression and vice-versa. - * </p> - * - * <p> - * {@link PostgreSQLTranslator} overwrites the translation of mathematical functions whose some have - * a different name or signature. Besides, it is also implementing the translation of the geometrical - * functions. However, it does not really translate them. It is just returning the ADQL expression - * (by calling {@link #getDefaultADQLFunction(ADQLFunction)}). - * And so, of course, the execution of a SQL query containing geometrical functions and translated - * using this translator will not work. It is just a default implementation in case there is no interest - * of these geometrical functions. - * </p> - * * <h3>SQL with or without case sensitivity?</h3> * * <p> - * In ADQL and in SQL, it is possible to tell the parser to respect the exact case or not of an identifier (schema, table or column name) - * by surrounding it with double quotes. However ADQL identifiers and SQL ones may be different. In that way, the case sensitivity specified - * in ADQL on the different identifiers can not be kept in SQL. That's why this translator lets specify a general rule on which types of - * SQL identifier must be double quoted. This can be done by implementing the abstract function {@link #isCaseSensitive(IdentifierField)}. - * The functions translating column and table names will call this function in order to surround the identifiers by double quotes or not. - * So, <b>be careful if you want to override the functions translating columns and tables!</b> + * In ADQL and in SQL, it is possible to tell the parser to respect the exact + * case or not of an identifier (schema, table or column name) by surrounding + * it with double quotes. However ADQL identifiers and SQL ones may be + * different. In that way, the case sensitivity specified in ADQL on the + * different identifiers can not be kept in SQL. That's why this translator + * lets specify a general rule on which types of SQL identifier must be double + * quoted. This can be done by implementing the abstract function + * {@link #isCaseSensitive(IdentifierField)}. The functions translating column + * and table names will call this function in order to surround the identifiers + * by double quotes or not. So, <b>be careful if you want to override the + * functions translating columns and tables!</b> * </p> * * <h3>Translation of "SELECT TOP"</h3> * * <p> - * The default behavior of this translator is to translate the ADQL "TOP" into the SQL "LIMIT" at the end of the query. - * This is ok for some DBMS, but not all. So, if your DBMS does not know the "LIMIT" keyword, you should override the function - * translating the whole query: {@link #translate(ADQLQuery)}. Here is its current implementation: + * The default behavior of this translator is to translate the ADQL "TOP" into + * the SQL "LIMIT" at the end of the query. This is ok for some DBMS, but not + * all. So, if your DBMS does not know the "LIMIT" keyword, you should override + * the function translating the whole query: {@link #translate(ADQLQuery)}. + * Here is its current implementation: * </p> * <pre> * StringBuffer sql = new StringBuffer(translate(query.getSelect())); @@ -147,29 +139,35 @@ import adql.query.operand.function.geometry.RegionFunction; * <h3>Translation of ADQL functions</h3> * * <p> - * All ADQL functions are by default not translated. Consequently, the SQL translation is - * actually the ADQL expression. Generally the ADQL expression is generic enough. However some mathematical functions may need - * to be translated differently. For instance {@link PostgreSQLTranslator} is translating differently: LOG, LOG10, RAND and TRUNC. + * All ADQL functions are by default not translated. Consequently, the SQL + * translation is actually the ADQL expression. Generally the ADQL expression + * is generic enough. However some mathematical functions may need to be + * translated differently. For instance {@link PostgreSQLTranslator} is + * translating differently: LOG, LOG10, RAND and TRUNC. * </p> * * <p><i>Note: - * Geometrical regions and types have not been managed here. They stay abstract because it is obviously impossible to have a generic - * translation and conversion ; it totally depends from the database system. + * Geometrical regions and types have not been managed here. They stay abstract + * because it is obviously impossible to have a generic translation and + * conversion ; it totally depends from the database system. * </i></p> * * <h3>Translation of "FROM" with JOINs</h3> * * <p> - * The FROM clause is translated into SQL as written in ADQL. There is no differences except the identifiers that are replaced. - * The tables' aliases and their case sensitivity are kept like in ADQL. + * The FROM clause is translated into SQL as written in ADQL. There is no + * differences except the identifiers that are replaced. The tables' aliases + * and their case sensitivity are kept like in ADQL. * </p> * * @author Grégory Mantelet (ARI) - * @version 1.4 (11/2017) + * @version 1.4 (01/2018) * @since 1.4 * * @see PostgreSQLTranslator * @see PgSphereTranslator + * @see MySQLTranslator + * @see SQLServerTranslator */ public abstract class JDBCTranslator implements ADQLTranslator { @@ -389,6 +387,8 @@ public abstract class JDBCTranslator implements ADQLTranslator { return translate((ClauseSelect)list); else if (list instanceof ClauseConstraints) return translate((ClauseConstraints)list); + else if (list instanceof Concatenation) + return getDefaultADQLList(list, false); else return getDefaultADQLList(list); } @@ -396,14 +396,40 @@ public abstract class JDBCTranslator implements ADQLTranslator { /** * Gets the default SQL output for a list of ADQL objects. * + * <p><i>Implementation note:</i> + * This function just calls {@link #getDefaultADQLList(ADQLList, boolean)} + * with the given list in first parameter and <code>true</code> in second + * one. In other words, this function always prefixes the list items by + * the list name. + * </p> + * * @param list List to format into SQL. * * @return The corresponding SQL. * * @throws TranslationException If there is an error during the translation. + * + * @see #getDefaultADQLList(ADQLList, boolean) + */ + protected final String getDefaultADQLList(ADQLList<? extends ADQLObject> list) throws TranslationException{ + return getDefaultADQLList(list, true); + } + + /** + * Gets the default SQL output for a list of ADQL objects. + * + * @param list List to format into SQL. + * @param withNamePrefix Prefix the list by its name or not. + * (e.g. 'false' for a Concatenation) + * + * @return The corresponding SQL. + * + * @throws TranslationException If there is an error during the translation. + * + * @since 1.4 */ - protected String getDefaultADQLList(ADQLList<? extends ADQLObject> list) throws TranslationException{ - String sql = (list.getName() == null) ? "" : (list.getName() + " "); + protected String getDefaultADQLList(ADQLList<? extends ADQLObject> list, final boolean withNamePrefix) throws TranslationException{ + String sql = (list.getName() == null || !withNamePrefix) ? "" : (list.getName() + " "); for(int i = 0; i < list.size(); i++) sql += ((i == 0) ? "" : (" " + list.getSeparator(i) + " ")) + translate(list.get(i)); diff --git a/src/adql/translator/PgSphereTranslator.java b/src/adql/translator/PgSphereTranslator.java index 358d79d..afc5a89 100644 --- a/src/adql/translator/PgSphereTranslator.java +++ b/src/adql/translator/PgSphereTranslator.java @@ -2,20 +2,20 @@ package adql.translator; /* * This file is part of ADQLLibrary. - * + * * ADQLLibrary is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * ADQLLibrary is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>. - * + * * Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -44,10 +44,13 @@ import adql.query.operand.function.geometry.PointFunction; import adql.query.operand.function.geometry.PolygonFunction; /** - * <p>Translates all ADQL objects into the SQL adaptation of Postgres+PgSphere. - * Actually only the geometrical functions are translated in this class. - * The other functions are managed by {@link PostgreSQLTranslator}.</p> - * + * Translates all ADQL objects into the SQL adaptation of Postgres+PgSphere. + * + * <p> + * Actually only the geometrical functions and types are translated in this + * class. The other functions are managed by {@link PostgreSQLTranslator}. + * </p> + * * @author Grégory Mantelet (CDS;ARI) * @version 1.4 (07/2017) */ @@ -62,7 +65,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Builds a PgSphereTranslator which always translates in SQL all identifiers (schema, table and column) in a case sensitive manner ; * in other words, schema, table and column names will be surrounded by double quotes in the SQL translation. - * + * * @see PostgreSQLTranslator#PostgreSQLTranslator() */ public PgSphereTranslator(){ @@ -72,9 +75,9 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Builds a PgSphereTranslator which always translates in SQL all identifiers (schema, table and column) in the specified case sensitivity ; * in other words, schema, table and column names will all be surrounded or not by double quotes in the SQL translation. - * + * * @param allCaseSensitive <i>true</i> to translate all identifiers in a case sensitive manner (surrounded by double quotes), <i>false</i> for case insensitivity. - * + * * @see PostgreSQLTranslator#PostgreSQLTranslator(boolean) */ public PgSphereTranslator(boolean allCaseSensitive){ @@ -83,12 +86,12 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Builds a PgSphereTranslator which will always translate in SQL identifiers with the defined case sensitivity. - * + * * @param catalog <i>true</i> to translate catalog names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise. * @param schema <i>true</i> to translate schema names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise. * @param table <i>true</i> to translate table names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise. * @param column <i>true</i> to translate column names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise. - * + * * @see PostgreSQLTranslator#PostgreSQLTranslator(boolean, boolean, boolean, boolean) */ public PgSphereTranslator(boolean catalog, boolean schema, boolean table, boolean column){ @@ -330,16 +333,16 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * <p>Convert the specified circle into a polygon. * The generated polygon is formatted using the PgSphere syntax.</p> - * + * * <p><i>Note: * The center coordinates and the radius are expected in degrees. * </i></p> - * + * * @param center Center of the circle ([0]=ra and [1]=dec). * @param radius Radius of the circle. - * + * * @return The PgSphere serialization of the corresponding polygon. - * + * * @since 1.3 */ protected String circleToPolygon(final double[] center, final double radius){ @@ -358,13 +361,13 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * <p>Let parse a geometry serialized with the PgSphere syntax.</p> - * + * * <p> * There is one function parseXxx(String) for each supported geometry. * These functions always return a {@link Region} object, * which is the object representation of an STC region. * </p> - * + * * <p>Only the following geometries are supported:</p> * <ul> * <li>spoint => Position</li> @@ -372,12 +375,12 @@ public class PgSphereTranslator extends PostgreSQLTranslator { * <li>sbox => Box</li> * <li>spoly => Polygon</li> * </ul> - * + * * <p> * This parser supports all the known PgSphere representations of an angle. * However, it always returns angle (coordinates, radius, width and height) in degrees. * </p> - * + * * @author Grégory Mantelet (ARI) * @version 1.3 (11/2014) * @since 1.3 @@ -407,7 +410,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Exception sent when the end of the expression * (EOE = End Of Expression) is reached. - * + * * @author Grégory Mantelet (ARI) * @version 1.3 (11/2014) * @since 1.3 @@ -428,7 +431,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Prepare the parser in order to read the given PgSphere expression. - * + * * @param newStcs New PgSphere expression to parse from now. */ private void init(final String newExpr){ @@ -441,7 +444,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Finalize the parsing. * No more characters (except eventually some space characters) should remain in the PgSphere expression to parse. - * + * * @throws ParseException If other non-space characters remains. */ private void end() throws ParseException{ @@ -469,12 +472,12 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * <p>Get the next meaningful word. This word can be a numeric, any string constant or a separator. * This function returns this token but also stores it in the class attribute {@link #token}.</p> - * + * * <p> * In case the end of the expression is reached before getting any meaningful character, * an {@link EOEException} is thrown. * </p> - * + * * @return The full read word/token, or NULL if the end has been reached. */ private String nextToken() throws EOEException{ @@ -504,12 +507,12 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * <p>Tell whether the given character is a separator defined in the syntax.</p> - * + * * <p>Here, the following characters are considered as separators/specials: * ',', 'd', 'h', 'm', 's', '(', ')', '<', '>', '{' and '}'.</p> - * + * * @param c Character to test. - * + * * @return <i>true</i> if the given character must be considered as a separator, <i>false</i> otherwise. */ private static boolean isSyntaxSeparator(final char c){ @@ -519,9 +522,9 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Get the next character and ensure it is the same as the character given in parameter. * If the read character is not matching the expected one, a {@link ParseException} is thrown. - * + * * @param expected Expected character. - * + * * @throws ParseException If the next character is not matching the given one. */ private void nextToken(final char expected) throws ParseException{ @@ -544,11 +547,11 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Parse the given PgSphere geometry as a point. - * + * * @param pgsphereExpr The PgSphere expression to parse as a point. - * + * * @return A {@link Region} implementing a STC Position region. - * + * * @throws ParseException If the PgSphere syntax of the given expression is wrong or does not correspond to a point. */ public Region parsePoint(final String pgsphereExpr) throws ParseException{ @@ -564,11 +567,11 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Internal spoint parsing function. It parses the PgSphere expression stored in this parser as a point. - * + * * @return The ra and dec coordinates (in degrees) of the parsed point. - * + * * @throws ParseException If the PgSphere syntax of the given expression is wrong or does not correspond to a point. - * + * * @see #parseAngle() * @see #parsePoint(String) */ @@ -583,11 +586,11 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Parse the given PgSphere geometry as a circle. - * + * * @param pgsphereExpr The PgSphere expression to parse as a circle. - * + * * @return A {@link Region} implementing a STC Circle region. - * + * * @throws ParseException If the PgSphere syntax of the given expression is wrong or does not correspond to a circle. */ public Region parseCircle(final String pgsphereExpr) throws ParseException{ @@ -610,11 +613,11 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Parse the given PgSphere geometry as a box. - * + * * @param pgsphereExpr The PgSphere expression to parse as a box. - * + * * @return A {@link Region} implementing a STC Box region. - * + * * @throws ParseException If the PgSphere syntax of the given expression is wrong or does not correspond to a box. */ public Region parseBox(final String pgsphereExpr) throws ParseException{ @@ -640,11 +643,11 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * Parse the given PgSphere geometry as a point. - * + * * @param pgsphereExpr The PgSphere expression to parse as a point. - * + * * @return A {@link Region} implementing a STC Position region. - * + * * @throws ParseException If the PgSphere syntax of the given expression is wrong or does not correspond to a point. */ public Region parsePolygon(final String pgsphereExpr) throws ParseException{ @@ -676,7 +679,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator { /** * <p>Read the next tokens as an angle expression and returns the corresponding angle in <b>degrees</b>.</p> - * + * * <p>This function supports the 4 following syntaxes:</p> * <ul> * <li><b>RAD:</b> {number}</li> @@ -684,9 +687,9 @@ public class PgSphereTranslator extends PostgreSQLTranslator { * <li><b>DMS:</b> {number}d {number}m {number}s</li> * <li><b>HMS:</b> {number}h {number}m {number}s</li> * </ul> - * + * * @return The corresponding angle in degrees. - * + * * @throws ParseException If the angle syntax is wrong or not supported. */ private double parseAngle() throws ParseException{ diff --git a/src/adql/translator/PostgreSQLTranslator.java b/src/adql/translator/PostgreSQLTranslator.java index e20690d..68d740a 100644 --- a/src/adql/translator/PostgreSQLTranslator.java +++ b/src/adql/translator/PostgreSQLTranslator.java @@ -2,20 +2,20 @@ package adql.translator; /* * This file is part of ADQLLibrary. - * + * * ADQLLibrary is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * ADQLLibrary is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>. - * + * * Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -26,6 +26,7 @@ import adql.db.STCS.Region; import adql.parser.ParseException; import adql.query.IdentifierField; import adql.query.operand.StringConstant; +import adql.query.operand.function.ADQLFunction; import adql.query.operand.function.MathFunction; import adql.query.operand.function.geometry.AreaFunction; import adql.query.operand.function.geometry.BoxFunction; @@ -41,23 +42,36 @@ import adql.query.operand.function.geometry.PolygonFunction; import adql.query.operand.function.geometry.RegionFunction; /** - * <p>Translates all ADQL objects into an SQL interrogation query designed for PostgreSQL.</p> - * + * Translates all ADQL objects into an SQL interrogation query designed for + * PostgreSQL. + * + * <p> + * It overwrites the translation of mathematical functions whose some have + * a different name or signature. Besides, it is also implementing the + * translation of the geometrical functions. However, it does not really + * translate them. It is just returning the ADQL expression (by calling + * {@link #getDefaultADQLFunction(ADQLFunction)}). And so, of course, the + * execution of a SQL query containing geometrical functions and translated + * using this translator will not work. It is just a default implementation in + * case there is no interest of these geometrical functions. + * </p> + * * <p><i><b>Important</b>: * The geometrical functions are translated exactly as in ADQL. - * You will probably need to extend this translator to correctly manage the geometrical functions. - * An extension is already available for PgSphere: {@link PgSphereTranslator}. + * You will probably need to extend this translator to correctly manage the + * geometrical functions. An extension is already available for PgSphere: + * {@link PgSphereTranslator}. * </i></p> - * + * * @author Grégory Mantelet (CDS;ARI) * @version 1.4 (08/2016) - * + * * @see PgSphereTranslator */ public class PostgreSQLTranslator extends JDBCTranslator { /** <p>Indicate the case sensitivity to apply to each SQL identifier (only SCHEMA, TABLE and COLUMN).</p> - * + * * <p><i>Note: * In this implementation, this field is set by the constructor and never modified elsewhere. * It would be better to never modify it after the construction in order to keep a certain consistency. @@ -76,7 +90,7 @@ public class PostgreSQLTranslator extends JDBCTranslator { /** * Builds a PostgreSQLTranslator which always translates in SQL all identifiers (schema, table and column) in the specified case sensitivity ; * in other words, schema, table and column names will all be surrounded or not by double quotes in the SQL translation. - * + * * @param allCaseSensitive <i>true</i> to translate all identifiers in a case sensitive manner (surrounded by double quotes), <i>false</i> for case insensitivity. */ public PostgreSQLTranslator(final boolean allCaseSensitive){ @@ -85,7 +99,7 @@ public class PostgreSQLTranslator extends JDBCTranslator { /** * Builds a PostgreSQLTranslator which will always translate in SQL identifiers with the defined case sensitivity. - * + * * @param catalog <i>true</i> to translate catalog names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise. * @param schema <i>true</i> to translate schema names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise. * @param table <i>true</i> to translate table names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise. diff --git a/test/adql/db/TestDBChecker.java b/test/adql/db/TestDBChecker.java index 685eaaf..3e675ae 100644 --- a/test/adql/db/TestDBChecker.java +++ b/test/adql/db/TestDBChecker.java @@ -101,7 +101,7 @@ public class TestDBChecker { /* The name of an ADQLClause is got in DBChecker by SearchColumnOutsideGroupByHandler.goInto(...) * and possibly in other locations in the future. If this name is NULL, no NullPointerException * should be thrown. - * + * * This issue can be tested by creating a ConstraintsGroup (i.e. in a constraints location like WHERE or JOIN...ON, * a constraint (or more) between parenthesis). */ ADQLParser parser = new ADQLParser(new DBChecker(tables, new ArrayList<FunctionDef>(0))); @@ -212,6 +212,9 @@ public class TestDBChecker { assertNotNull(parser.parseQuery("SELECT toto FROM foo;")); assertNotNull(parser.parseQuery("SELECT toto * 3 FROM foo;")); assertNotNull(parser.parseQuery("SELECT toto || 'blabla' FROM foo;")); + assertNotNull(parser.parseQuery("SELECT 'toto' || 1 FROM foo;")); + assertNotNull(parser.parseQuery("SELECT 1 || 'toto' FROM foo;")); + assertNotNull(parser.parseQuery("SELECT 'toto' || (-1) FROM foo;")); }catch(ParseException pe){ pe.printStackTrace(); fail(); @@ -221,15 +224,15 @@ public class TestDBChecker { fail(); }catch(ParseException pe){} try{ - parser.parseQuery("SELECT ABS(('toto' || 'blabla')) FROM foo;"); + parser.parseQuery("SELECT 'toto' || -1 FROM foo;"); fail(); }catch(ParseException pe){} try{ - parser.parseQuery("SELECT 'toto' || 1 FROM foo;"); + parser.parseQuery("SELECT -1 || 'toto' FROM foo;"); fail(); }catch(ParseException pe){} try{ - parser.parseQuery("SELECT 1 || 'toto' FROM foo;"); + parser.parseQuery("SELECT ABS(('toto' || 'blabla')) FROM foo;"); fail(); }catch(ParseException pe){} try{ @@ -582,22 +585,16 @@ public class TestDBChecker { fail("This query contains a concatenation between 2 strings: this test should have succeeded!"); } try{ - parser.parseQuery("SELECT colI || 'blabla' FROM foo;"); - fail("This query contains a concatenation between an integer and a string: this test should have failed!"); + assertNotNull(parser.parseQuery("SELECT colI || 'blabla' FROM foo;")); }catch(ParseException e){ - assertTrue(e instanceof UnresolvedIdentifiersException); - UnresolvedIdentifiersException ex = (UnresolvedIdentifiersException)e; - assertEquals(1, ex.getNbErrors()); - assertEquals("Type mismatch! A string value was expected instead of \"colI\".", ex.getErrors().next().getMessage()); + e.printStackTrace(); + fail("This query contains a concatenation between a column (whatever its type) and a string: this test should have succeeded!"); } try{ - parser.parseQuery("SELECT colG || 'blabla' FROM foo;"); - fail("This query contains a concatenation between a geometry and a string: this test should have failed!"); + assertNotNull(parser.parseQuery("SELECT colG || 'blabla' FROM foo;")); }catch(ParseException e){ - assertTrue(e instanceof UnresolvedIdentifiersException); - UnresolvedIdentifiersException ex = (UnresolvedIdentifiersException)e; - assertEquals(1, ex.getNbErrors()); - assertEquals("Type mismatch! A string value was expected instead of \"colG\".", ex.getErrors().next().getMessage()); + e.printStackTrace(); + fail("This query contains a concatenation between a column (whatever its type) and a string: this test should have succeeded!"); } // Test the expected type - GEOMETRY - generated by the parser: -- GitLab