Newer
Older
/*
* 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-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
gmantele
committed
* Astronomisches Rechen Institute (ARI)
* This JavaCC file implements the BNF definition of ADQL v2.0
* (IVOA Recommendation 30 Oct 2008 - http://www.ivoa.net/Documents/cover/ADQL-20081030.html).
*
* To generate the parser with this file use JavaCC. This .jj file has been
* successfully tested with JavaCC 6.0.
*
* The generated parser checks the syntax of the given ADQL query and generates
* an object representation but no coherence with any database is done.
* If the syntax is not conform to the ADQL definition an error message is
* printed else it will be the message "Correct syntax".
gmantele
committed
* Author: Grégory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
* Version: 1.4 (01/2018)
*/
/* ########### */
/* # OPTIONS # */
/* ########### */
options {
STATIC = false;
IGNORE_CASE = true;
DEBUG_PARSER = true;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
}
/* ########## */
/* # PARSER # */
/* ########## */
PARSER_BEGIN(ADQLParser)
package adql.parser;
import java.util.Stack;
import java.util.Vector;
import java.util.ArrayList;
import java.util.Collection;
import java.io.FileReader;
import java.io.IOException;
import adql.db.exception.UnresolvedIdentifiersException;
import adql.parser.IdentifierItems.IdentifierItem;
import adql.parser.ADQLQueryFactory.JoinType;
import adql.query.*;
import adql.query.from.*;
import adql.query.constraint.*;
import adql.query.operand.*;
import adql.query.operand.function.*;
import adql.query.operand.function.geometry.*;
import adql.query.operand.function.geometry.GeometryFunction.GeometryValue;
import adql.translator.PostgreSQLTranslator;
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
* consistency between the ADQL query to parse and the "database" on which the
* query must be executed. By default, there is no {@link QueryChecker}. Thus
* 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
* (ie. CONTAINS) of this representation you just have to extend the
* corresponding default object (ie. ContainsFunction) and to extend the
* 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
* it with JavaCC.
* </b></p>
*
* @see QueryChecker
* @see ADQLQueryFactory
*
gmantele
committed
* @author Grégory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
* @version 1.4 (01/2018)
*/
public class ADQLParser {
/** Tools to build the object representation of the ADQL query. */
private ADQLQueryFactory queryFactory = new ADQLQueryFactory();
/** The stack of queries (because there may be some sub-queries). */
private Stack<ADQLQuery> stackQuery = new Stack<ADQLQuery>();
/** The object representation of the ADQL query to parse.
* (ONLY USED DURING THE PARSING, else it is always <i>null</i>). */
private ADQLQuery query = null;
/** Checks each {@link ADQLQuery} (sub-query or not) just after their
* generation. */
private QueryChecker queryChecker = null;
/** The first token of a table/column name. This token is extracted by
* {@link #Identifier()}. */
private Token currentIdentifierToken = null;
/**
* Builds an ADQL parser without a query to parse.
*/
public ADQLParser(){
this(new java.io.ByteArrayInputStream("".getBytes()));
setDebug(false);
* Builds an ADQL parser without a query to parse but with a
* {@link QueryChecker} and a {@link ADQLQueryFactory}.
* @param checker The object to use to check each {@link ADQLQuery}.
* @param factory The object to use to build an object representation of
* the given ADQL query.
*/
public ADQLParser(QueryChecker checker, ADQLQueryFactory factory) {
this();
queryChecker = checker;
if (factory != null)
queryFactory = factory;
}
/**
* Builds an ADQL parser without a query to parse but with a
* {@link QueryChecker}.
* @param checker The object to use to check each {@link ADQLQuery}.
*/
public ADQLParser(QueryChecker checker) {
this(checker, null);
}
/**
* Builds an ADQL parser without a query to parse but with a
* {@link ADQLQueryFactory}.
* @param factory The object to use to build an object representation of
* the given ADQL query.
*/
public ADQLParser(ADQLQueryFactory factory) {
this((QueryChecker)null, factory);
}
/**
* Builds a parser with a stream containing the query to parse.
*
* @param stream The stream in which the ADQL query to parse is given.
* @param checker The object to use to check each {@link ADQLQuery}.
* @param factory The object to use to build an object representation of
* the given ADQL query.
*/
public ADQLParser(java.io.InputStream stream, QueryChecker checker, ADQLQueryFactory factory) {
this(stream);
gmantele
committed
setDebug(false);
setDebug(false);
queryChecker = checker;
if (factory != null)
queryFactory = factory;
}
/**
* Builds a parser with a stream containing the query to parse.
*
* @param stream The stream in which the ADQL query to parse is given.
* @param checker The object to use to check each {@link ADQLQuery}.
*/
public ADQLParser(java.io.InputStream stream, QueryChecker checker) {
this(stream, checker, null);
}
/**
* Builds a parser with a stream containing the query to parse.
*
* @param stream The stream in which the ADQL query to parse is given.
* @param factory The object to use to build an object representation of
* the given ADQL query.
*/
public ADQLParser(java.io.InputStream stream, ADQLQueryFactory factory) {
this(stream, (QueryChecker)null, factory);
}
/**
* Builds a parser with a stream containing the query to parse.
*
* @param stream The stream in which the ADQL query to parse is given.
* @param encoding The supplied encoding.
* @param checker The object to use to check each {@link ADQLQuery}.
* @param factory The object to use to build an object representation
* of the given ADQL query.
*/
public ADQLParser(java.io.InputStream stream, String encoding, QueryChecker checker, ADQLQueryFactory factory) {
this(stream, encoding);
gmantele
committed
setDebug(false);
queryChecker = checker;
if (factory != null)
queryFactory = factory;
}
/**
* Builds a parser with a stream containing the query to parse.
*
* @param stream The stream in which the ADQL query to parse is given.
* @param encoding The supplied encoding.
* @param checker The object to use to check each {@link ADQLQuery}.
*/
public ADQLParser(java.io.InputStream stream, String encoding, QueryChecker checker) {
this(stream, encoding, checker, null);
}
/**
* Builds a parser with a stream containing the query to parse.
*
* @param stream The stream in which the ADQL query to parse is given.
* @param encoding The supplied encoding.
* @param factory The object to use to build an object representation
* of the given ADQL query.
*/
public ADQLParser(java.io.InputStream stream, String encoding, ADQLQueryFactory factory) {
this(stream, encoding, null, factory);
}
/**
* Builds a parser with a reader containing the query to parse.
*
* @param reader The reader in which the ADQL query to parse is given.
* @param checker The object to use to check each {@link ADQLQuery}.
* @param factory The object to use to build an object representation
* of the given ADQL query.
*/
public ADQLParser(java.io.Reader reader, QueryChecker checker, ADQLQueryFactory factory) {
this(reader);
gmantele
committed
setDebug(false);
setDebug(false);
queryChecker = checker;
if (factory != null)
queryFactory = factory;
}
/**
* Builds a parser with a reader containing the query to parse.
*
* @param reader The reader in which the ADQL query to parse is given.
* @param checker The object to use to check each {@link ADQLQuery}.
*/
public ADQLParser(java.io.Reader reader, QueryChecker checker) {
this(reader, checker, null);
}
/**
* Builds a parser with a reader containing the query to parse.
*
* @param reader The reader in which the ADQL query to parse is given.
* @param factory The object to use to build an object representation
* of the given ADQL query.
*/
public ADQLParser(java.io.Reader reader, ADQLQueryFactory factory) {
this(reader, null, factory);
}
/**
* Builds a parser with another token manager.
*
* @param tm The manager which associates a token to a numeric code.
* @param checker The object to use to check each {@link ADQLQuery }.
* @param factory The object to use to build an object representation
* of the given ADQL query.
*/
public ADQLParser(ADQLParserTokenManager tm, QueryChecker checker, ADQLQueryFactory factory) {
this(tm);
gmantele
committed
setDebug(false);
setDebug(false);
queryChecker = checker;
if (factory != null)
queryFactory = factory;
}
/**
* Builds a parser with another token manager.
*
* @param tm The manager which associates a token to a numeric code.
* @param checker The object to use to check each {@link ADQLQuery}.
*/
public ADQLParser(ADQLParserTokenManager tm, QueryChecker checker) {
this(tm, checker, null);
}
/**
* Builds a parser with another token manager.
*
* @param tm The manager which associates a token to a numeric code.
* @param factory The object to use to build an object representation of
* the given ADQL query.
*/
public ADQLParser(ADQLParserTokenManager tm, ADQLQueryFactory factory) {
this(tm, null, factory);
}
/**
* Parses the query given at the creation of this parser or in the
* <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()
*/
public final ADQLQuery parseQuery() throws ParseException {
stackQuery.clear();
query = null;
try {
return Query();
}catch(TokenMgrError tme) {
throw new ParseException(tme.getMessage(), new TextPosition(tme.getErrorLine(), tme.getErrorColumn()));
}
}
/**
* 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)
* @see ADQLParser#setDebug(boolean)
* @see ADQLParser#Query()
*/
public final ADQLQuery parseQuery(String q) throws ParseException {
stackQuery.clear();
query = null;
ReInit(new java.io.ByteArrayInputStream(q.getBytes()));
try {
return Query();
}catch(TokenMgrError tme) {
throw new ParseException(tme.getMessage(), new TextPosition(tme.getErrorLine(), tme.getErrorColumn()));
}
}
/**
* 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)
* @see ADQLParser#setDebug(boolean)
* @see ADQLParser#Query()
*/
public final ADQLQuery parseQuery(java.io.InputStream stream) throws ParseException {
stackQuery.clear();
query = null;
ReInit(stream);
try {
return Query();
}catch(TokenMgrError tme) {
throw new ParseException(tme.getMessage(), new TextPosition(tme.getErrorLine(), tme.getErrorColumn()));
}
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
}
public final void setDebug(boolean debug){
if (debug) enable_tracing();
else disable_tracing();
}
public final QueryChecker getQueryChecker(){
return queryChecker;
}
public final void setQueryChecker(QueryChecker checker){
queryChecker = checker;
}
public final ADQLQueryFactory getQueryFactory(){
return queryFactory;
}
public final void setQueryFactory(ADQLQueryFactory factory){
queryFactory = (factory!=null)?factory:(new ADQLQueryFactory());
}
private final ParseException generateParseException(Exception ex){
if (!(ex instanceof ParseException)){
ParseException pex = new ParseException("["+ex.getClass().getName()+"] "+ex.getMessage());
pex.setStackTrace(ex.getStackTrace());
return pex;
}else
return (ParseException)ex;
}
/**
* 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>
* <li>[-debug] -file ...</li>
* <li>[-debug] -query SELECT...</li>
* </ul>
* </p>
*
* @param args
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
* @throws Exception
*/
public static final void main(String[] args) throws Exception {
final String USAGE = "Usage:\n\tadqlParser.jar [-d] [-v] [-e] [-a|-s] [<FILE>|<URL>]\n\nNOTE: If no file or URL is given, the ADQL query is expected in the standard input. This query must end with a ';' !\n\nParameters:\n\t-v or --verbose : Print the main steps of the parsing\n\t-d or --debug : Print stack traces when a grave error occurs\n\t-e or --explain : Explain the ADQL parsing (or Expand the parsing tree)\n\t-a or --adql : Display the understood ADQL query\n\t-s or --sql : Ask the SQL translation of the given ADQL query (SQL compatible with PostgreSQL)\n\nReturn:\n\tBy default: nothing if the query is correct. Otherwise a message explaining why the query is not correct is displayed.\n\tWith the -s option, the SQL translation of the given ADQL query will be returned.\n\tWith the -a option, the ADQL query is returned as it has been understood.\n\nExit status:\n\t0\tOK !\n\t1\tParameter error (missing or incorrect parameter)\n\t2\tFile error (incorrect file/url, reading error, ...)\n\t3\tParsing error (syntactic or semantic error)\n\t4\tTranslation error (a problem has occurred during the translation of the given ADQL query in SQL).";
ADQLParser parser;
final String urlRegex = "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
String file = null, metaFile = null;
short mode = -1;
boolean verbose=false, debug=false, explain=false;
// Parameters reading:
for(int i=0; i<args.length; i++){
if (args[i].equalsIgnoreCase("-d") || args[i].equalsIgnoreCase("--debug"))
debug = true;
else if (args[i].equalsIgnoreCase("-v") || args[i].equalsIgnoreCase("--verbose"))
verbose = true;
else if (args[i].equalsIgnoreCase("-e") || args[i].equalsIgnoreCase("--explain"))
explain = true;
else if (args[i].equalsIgnoreCase("-a") || args[i].equalsIgnoreCase("--adql")){
if (mode != -1){
System.err.println("((!)) Too much parameter: you must choose between -s, -c, -a or nothing ((!))\n"+USAGE);
System.exit(1);
}else
mode = 1;
}else if (args[i].equalsIgnoreCase("-s") || args[i].equalsIgnoreCase("--sql")){
if (mode != -1){
System.err.println("((!)) Too much parameter: you must choose between -s, -c, -a or nothing ((!))\n"+USAGE);
System.exit(1);
}else
mode = 2;
}else if (args[i].equalsIgnoreCase("-h") || args[i].equalsIgnoreCase("--help")){
System.out.println(USAGE);
System.exit(0);
}else if (args[i].startsWith("-")){
System.err.println("((!)) Unknown parameter: \""+args[i]+"\" ((!))\u005cn"+USAGE);
System.exit(1);
}else
file = args[i].trim();
}
try{
if (file == null || file.length()==0)
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
parser = new ADQLParser(System.in);
else if (file.matches(urlRegex))
parser = new ADQLParser((new java.net.URL(file)).openStream());
else
parser = new ADQLParser(new FileReader(file));
parser.setDebug(explain);
// Query parsing:
try{
if (verbose) System.out.print("((i)) Parsing ADQL query...");
ADQLQuery q = parser.parseQuery();
if (verbose) System.out.println("((i)) CORRECT ADQL QUERY ((i))");
if (mode==2){
PostgreSQLTranslator translator = new PostgreSQLTranslator();
if (verbose) System.out.print("((i)) Translating in SQL...");
String sql = translator.translate(q);
if (verbose) System.out.println("ok");
System.out.println(sql);
}else if (mode==1){
System.out.println(q.toADQL());
}
}catch(UnresolvedIdentifiersException uie){
System.err.println("((X)) "+uie.getNbErrors()+" unresolved identifiers:");
for(ParseException pe : uie)
System.err.println("\t - at "+pe.getPosition()+": "+uie.getMessage());
if (debug) uie.printStackTrace(System.err);
System.exit(3);
}catch(ParseException pe){
System.err.println("((X)) Syntax error: "+pe.getMessage()+" ((X))");
if (debug) pe.printStackTrace(System.err);
System.exit(3);
}catch(TranslationException te){
if (verbose) System.out.println("error");
System.err.println("((X)) Translation error: "+te.getMessage()+" ((X))");
if (debug) te.printStackTrace(System.err);
System.exit(4);
}
}catch(IOException ioe){
System.err.println("\n((X)) Error while reading the file \""+file+"\": "+ioe.getMessage()+" ((X))");
if (debug) ioe.printStackTrace(System.err);
System.exit(2);
}
}
}
PARSER_END(ADQLParser)
/* ########### */
/* # GRAMMAR # */
/* ########### */
/* ******************** */
/* Characters to ignore */
/* ******************** */
SKIP : { < " " | "\t" | "\n" | "\r" | "\r\n" > }
/* ************************************************************************** */
/* Reserved SQL words */
/* */
/* NOTE: */
/* This list is the one provided by the ADQL-2.0 standard after removal of */
/* all ADQL used words (e.g. SELECT, AS, LIKE, AVG, ABS, COS, POINT). */
/* (see ParseException.initialise(Token, int[][], String[]) for more */
/* details) */
/* ************************************************************************** */
TOKEN : {
< SQL_RESERVED_WORD: ("ABSOLUTE"|"ACTION"|"ADD"|"ALLOCATE"|"ALTER"|"ANY"|"ARE"|"ASSERTION"|"AT"|"AUTHORIZATION"|"BEGIN"|"BIT"|"BIT_LENGTH"|"BOTH"|"CASCADE"|"CASCADED"|"CASE"|"CAST"|"CATALOG"|"CHAR"|"CHARACTER"|"CHAR_LENGTH"|"CHARACTER_LENGTH"|"CHECK"|"CLOSE"|"COALESCE"|"COLLATE"|"COLLATION"|"COLUMN"|"COMMIT"|"CONNECT"|"CONNECTION"|"CONSTRAINT"|"CONSTRAINTS"|"CONTINUE"|"CONVERT"|"CORRESPONDING"|"CREATE"|"CURRENT"|"CURRENT_DATE"|"CURRENT_TIME"|"CURRENT_TIMESTAMP"|"CURRENT_USER"|"CURSOR"|"DATE"|"DAY"|"DEALLOCATE"|"DECIMAL"|"DECLARE"|"DEFAULT"|"DEFERRABLE"|"DEFERRED"|"DELETE"|"DESCRIBE"|"DESCRIPTOR"|"DIAGNOSTICS"|"DISCONNECT"|"DOMAIN"|"DOUBLE"|"DROP"|"ELSE"|"END"|"END-EXEC"|"ESCAPE"|"EXCEPT"|"EXCEPTION"|"EXEC"|"EXECUTE"|"EXTERNAL"|"EXTRACT"|"FALSE"|"FETCH"|"FIRST"|"FLOAT"|"FOR"|"FOREIGN"|"FOUND"|"GET"|"GLOBAL"|"GO"|"GOTO"|"GRANT"|"HOUR"|"IDENTITY"|"IMMEDIATE"|"INDICATOR"|"INITIALLY"|"INPUT"|"INSENSITIVE"|"INSERT"|"INT"|"INTEGER"|"INTERSECT"|"INTERVAL"|"INTO"|"ISOLATION"|"KEY"|"LANGUAGE"|"LAST"|"LEADING"|"LEVEL"|"LOCAL"|"LOWER"|"MATCH"|"MINUTE"|"MODULE"|"MONTH"|"NAMES"|"NATIONAL"|"NCHAR"|"NEXT"|"NO"|"NULLIF"|"NUMERIC"|"OCTET_LENGTH"|"OF"|"ONLY"|"OPEN"|"OPTION"|"OUTPUT"|"OVERLAPS"|"PAD"|"PARTIAL"|"POSITION"|"PRECISION"|"PREPARE"|"PRESERVE"|"PRIMARY"|"PRIOR"|"PRIVILEGES"|"PROCEDURE"|"PUBLIC"|"READ"|"REAL"|"REFERENCES"|"RELATIVE"|"RESTRICT"|"REVOKE"|"ROLLBACK"|"ROWS"|"SCHEMA"|"SCROLL"|"SECOND"|"SECTION"|"SESSION"|"SESSION_USER"|"SET"|"SIZE"|"SMALLINT"|"SOME"|"SPACE"|"SQL"|"SQLCODE"|"SQLERROR"|"SQLSTATE"|"SUBSTRING"|"SYSTEM_USER"|"TABLE"|"TEMPORARY"|"THEN"|"TIME"|"TIMESTAMP"|"TIMEZONE_HOUR"|"TIMEZONE_MINUTE"|"TO"|"TRAILING"|"TRANSACTION"|"TRANSLATE"|"TRANSLATION"|"TRIM"|"TRUE"|"UNION"|"UNIQUE"|"UNKNOWN"|"UPDATE"|"UPPER"|"USAGE"|"USER"|"VALUE"|"VALUES"|"VARCHAR"|"VARYING"|"VIEW"|"WHEN"|"WHENEVER"|"WITH"|"WORK"|"WRITE"|"YEAR"|"ZONE") >
}
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
/* *********** */
/* Punctuation */
/* *********** */
TOKEN : {
< LEFT_PAR: "(" >
| < RIGHT_PAR: ")" >
| < DOT: "." >
| < COMMA: "," >
| < EOQ: ";">
| < CONCAT: "||" >
}
/* ******************** */
/* Arithmetic operators */
/* ******************** */
TOKEN : {
< PLUS: "+" >
| < MINUS: "-" >
| < ASTERISK: "*" >
| < DIVIDE: "/" >
}
/* ******************** */
/* Comparison operators */
/* ******************** */
TOKEN : {
< EQUAL: "=" >
| < NOT_EQUAL: "<>" | "!=" >
| < LESS_THAN: "<" >
| < LESS_EQUAL_THAN: "<=" >
| < GREATER_THAN: ">" >
| < GREATER_EQUAL_THAN: ">=" >
}
/* *************** */
/* SELECT's tokens */
/* *************** */
TOKEN : {
< SELECT: "SELECT" >
| < QUANTIFIER: "DISTINCT" | "ALL" >
| < TOP: "TOP" >
}
/* ************* */
/* FROM's tokens */
/* ************* */
TOKEN : {
< FROM: "FROM" >
| < AS: "AS" >
| < NATURAL: "NATURAL" >
| < INNER: "INNER" >
| < OUTER: "OUTER" >
| < RIGHT: "RIGHT" >
| < LEFT: "LEFT" >
| < FULL: "FULL" >
| < JOIN: "JOIN" >
| < ON: "ON" >
| < USING: "USING" >
}
/* ************** */
/* WHERE's tokens */
/* ************** */
TOKEN : {
< WHERE: "WHERE" >
| < AND: "AND" >
| < OR: "OR" >
| < NOT: "NOT" >
| < IS: "IS" >
| < NULL: "NULL" >
| < BETWEEN: "BETWEEN" >
| < LIKE: "LIKE" >
| < IN: "IN" >
| < EXISTS: "EXISTS" >
}
/* ********************* */
/* Other clauses' tokens */
/* ********************* */
TOKEN : {
< BY: "BY" >
| < GROUP: "GROUP" >
| < HAVING: "HAVING" >
| < ORDER: "ORDER" >
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
| < ASC: "ASC" >
| < DESC: "DESC" >
}
/* ************* */
/* SQL functions */
/* ************* */
TOKEN : {
< AVG: "AVG" >
| < MAX: "MAX" >
| < MIN: "MIN" >
| < SUM: "SUM" >
| < COUNT: "COUNT" >
}
/* ************** */
/* ADQL functions */
/* ************** */
TOKEN : {
< BOX: "BOX" >
| < CENTROID: "CENTROID" >
| < CIRCLE: "CIRCLE" >
| < POINT: "POINT" >
| < POLYGON: "POLYGON" >
| < REGION: "REGION" >
| < CONTAINS: "CONTAINS" >
| < INTERSECTS: "INTERSECTS" >
| < AREA: "AREA" >
| < COORD1: "COORD1" >
| < COORD2: "COORD2" >
| < COORDSYS: "COORDSYS" >
| < DISTANCE: "DISTANCE" >
}
/* ********************** */
/* Mathematical functions */
/* ********************** */
TOKEN : {
< ABS: "ABS" >
| < CEILING: "CEILING" >
| < DEGREES: "DEGREES" >
| < EXP: "EXP" >
| < FLOOR: "FLOOR" >
| < LOG: "LOG" >
| < LOG10: "LOG10" >
| < MOD: "MOD" >
| < PI: "PI" >
| < POWER: "POWER" >
| < RADIANS: "RADIANS" >
| < RAND: "RAND" >
| < ROUND: "ROUND" >
| < SQRT: "SQRT" >
| < TRUNCATE: "TRUNCATE" >
}
/* ************************* */
/* Trigonometrical functions */
/* ************************* */
TOKEN : {
< ACOS: "ACOS" >
| < ASIN: "ASIN" >
| < ATAN: "ATAN" >
| < ATAN2: "ATAN2" >
| < COS: "COS" >
| < COT: "COT" >
| < SIN: "SIN" >
| < TAN: "TAN" >
}
/* ******* */
/* Comment */
/* ******* */
SKIP : { < <MINUS><MINUS> (~["\n","\r"])* ("\n"|"\r"|"\r\n")? > }
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
/* ****** */
/* String */
/* ****** */
<DEFAULT> MORE : { "'" : WithinString }
<WithinString> MORE : { < ~["'"] | ("''") > }
<WithinString> TOKEN : { < STRING_LITERAL: "'" >: DEFAULT }
/* ************************************************* */
/* Identifier (column, tables, ...) */
/* ************************************************* */
<DEFAULT> MORE : { "\"" : WithinDelimitedId }
<WithinDelimitedId> MORE : { < ~["\""] | ("\"\"") > }
<WithinDelimitedId> TOKEN : { < DELIMITED_IDENTIFIER: "\"" >: DEFAULT }
TOKEN : {
< REGULAR_IDENTIFIER: (<Letter>)+ (<DIGIT> | <Letter> | "_")* >
| < #Letter: ["a"-"z","A"-"Z"] >
}
/* *************** */
/* Primary numbers */
/* *************** */
TOKEN : {
< SCIENTIFIC_NUMBER: (<UNSIGNED_FLOAT>|<UNSIGNED_INTEGER>) "E" (<PLUS>|<MINUS>)? <UNSIGNED_INTEGER> >
| < UNSIGNED_FLOAT: (<UNSIGNED_INTEGER> <DOT> (<UNSIGNED_INTEGER>)?) | (<DOT> <UNSIGNED_INTEGER>) >
| < UNSIGNED_INTEGER: (<DIGIT>)+ >
| < #DIGIT: ["0"-"9"] >
}
/* ########## */
/* # SYNTAX # */
/* ########## */
/* ******************* */
/* GENERAL ADQL SYNTAX */
/* ******************* */
/**
* Parses the ADQL query given at the parser creation or in the {@link ADQLParser#ReInit(java.io.InputStream)}
* or in the <i>parseQuery</i> functions.
*
* @return The object representation of the query.
* @throws ParseException If the query syntax is incorrect.
*/
ADQLQuery Query(): {ADQLQuery q = null;}{
q=QueryExpression() (<EOF> | <EOQ>)
gmantele
committed
{
// check the query:
if (queryChecker != null)
queryChecker.check(q);
return q;
}
ADQLQuery QueryExpression(): {TextPosition endPos = null;} {
{
try{
// create the query:
query = queryFactory.createQuery();
stackQuery.push(query);
}catch(Exception ex){
throw generateParseException(ex);
}
}
Select()
From() {endPos = query.getFrom().getPosition();}
[Where() {endPos = query.getWhere().getPosition();}]
[GroupBy() {endPos = query.getGroupBy().getPosition();}]
[Having() {endPos = query.getHaving().getPosition();}]
[OrderBy() {endPos = query.getOrderBy().getPosition();}]
// set the position of the query:
query.setPosition(new TextPosition(query.getSelect().getPosition(), endPos));
// get the previous query (!= null if the current query is a sub-query):
ADQLQuery previousQuery = stackQuery.pop();
if (stackQuery.isEmpty())
query = null;
else
query = stackQuery.peek();
return previousQuery;
}
}
ADQLQuery SubQueryExpression(): {ADQLQuery q = null; Token start, end;} {
start=<LEFT_PAR> q=QueryExpression() end=<RIGHT_PAR>
{
q.setPosition(new TextPosition(start, end));
return q;
}
void Select(): {ClauseSelect select = query.getSelect(); SelectItem item=null; Token start,t = null;} {
start=<SELECT>
[t=<QUANTIFIER> {select.setDistinctColumns(t.image.equalsIgnoreCase("DISTINCT"));}]
[<TOP> t=<UNSIGNED_INTEGER>
{
try{
select.setLimit(Integer.parseInt(t.image));
}catch(NumberFormatException nfe){
throw new ParseException("[l."+t.beginLine+";c."+t.beginColumn+"] The TOP limit (\""+t.image+"\") isn't a regular unsigned integer !");
}
}
]
item=SelectItem() {select.add(item);}
(<COMMA> item=SelectItem() {select.add(item);})*
{
TextPosition lastItemPos = query.getSelect().get(query.getSelect().size()-1).getPosition();
select.setPosition(new TextPosition(start.beginLine, start.beginColumn, lastItemPos.endLine, lastItemPos.endColumn));
}
SelectItem SelectItem(): {IdentifierItems identifiers = new IdentifierItems(true); IdentifierItem id = null, label = null; ADQLOperand op = null; SelectItem item; Token starToken;} {
( starToken=<ASTERISK>
{
item = new SelectAllColumns(query);
item.setPosition(new TextPosition(starToken));
return item;
}
)
|LOOKAHEAD(7)
(
id=Identifier() <DOT> { identifiers.append(id); }
(
id=Identifier() <DOT> { identifiers.append(id); }
(
id=Identifier() <DOT> { identifiers.append(id); }
)?
)?
starToken=<ASTERISK>
try{
item = new SelectAllColumns( queryFactory.createTable(identifiers, null) );
TextPosition firstPos = identifiers.get(0).position;
item.setPosition(new TextPosition(firstPos.beginLine, firstPos.beginColumn, starToken.endLine, (starToken.endColumn < 0) ? -1 : (starToken.endColumn + 1)));
return item;
}catch(Exception ex) {
throw generateParseException(ex);
}
}
)
|
(op=ValueExpression()[[<AS>] label=Identifier()])
)
{
try{
item = queryFactory.createSelectItem(op, (label==null)?null:label.identifier);
if (label != null){
item.setCaseSensitive(label.caseSensitivity);
item.setPosition(new TextPosition(op.getPosition(), label.position));
}else
item.setPosition(new TextPosition(op.getPosition()));
return item;
}catch(Exception ex){
throw generateParseException(ex);
}
}
}
void From():{FromContent content = null, content2 = null;}{
try{
<FROM> content=TableRef()
(<COMMA> content2=TableRef()
{
TextPosition startPos = content.getPosition(), endPos = content2.getPosition();
content = queryFactory.createJoin(JoinType.CROSS, content, content2);
content.setPosition(new TextPosition(startPos, endPos));
}
)*
{ query.setFrom(content); }
}catch(Exception ex){
throw generateParseException(ex);
}
}
void Where(): {ClauseConstraints where = query.getWhere(); ADQLConstraint condition; Token start;} {
start=<WHERE> ConditionsList(where)
{
TextPosition endPosition = where.getPosition();
where.setPosition(new TextPosition(start.beginLine, start.beginColumn, endPosition.endLine, endPosition.endColumn));
}
void GroupBy(): {ClauseADQL<ADQLColumn> groupBy = query.getGroupBy(); ADQLColumn colRef = null; Token start;} {
start=<GROUP> <BY> colRef=Column() { groupBy.add(colRef); }
( <COMMA> colRef=Column() { groupBy.add(colRef); } )*
{ groupBy.setPosition(new TextPosition(start.beginLine, start.beginColumn, colRef.getPosition().endLine, colRef.getPosition().endColumn)); }
void Having(): {ClauseConstraints having = query.getHaving(); Token start;} {
start=<HAVING> ConditionsList(having)
{
TextPosition endPosition = having.getPosition();
having.setPosition(new TextPosition(start.beginLine, start.beginColumn, endPosition.endLine, endPosition.endColumn));
}
void OrderBy(): {ClauseADQL<ADQLOrder> orderBy = query.getOrderBy(); ADQLOrder order = null; Token start;} {
start=<ORDER> <BY> order=OrderItem() {orderBy.add(order);}
( <COMMA> order=OrderItem() {orderBy.add(order);} )*
{ orderBy.setPosition(new TextPosition(start, token)); }
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
/* *************************** */
/* COLUMN AND TABLE REFERENCES */
/* *************************** */
IdentifierItem Identifier(): {Token t;} {
(
t=<REGULAR_IDENTIFIER>
{ return new IdentifierItem(t, false); }
|
t=<DELIMITED_IDENTIFIER>
{ return new IdentifierItem(t, true); }
)
}
/**
* Extracts the name of a table with its possible catalog and schema prefixes.
*
* @return A {@link IdentifierItems} which contains at most three items: catalogName, schemaName and tableName.
*/
IdentifierItems TableName(): {IdentifierItems identifiers=new IdentifierItems(true); IdentifierItem id=null;} {
(
id=Identifier() {identifiers.append(id);} // catalog
(LOOKAHEAD(1) <DOT> id=Identifier() {identifiers.append(id);})? // schema
(LOOKAHEAD(1) <DOT> id=Identifier() {identifiers.append(id);})? // table
)
{ return identifiers; }
}
/**
* Extracts the name of a column with its possible catalog, schema and table prefixes.
*
* @return A {@link IdentifierItems} which contains at most four items: catalogName, schemaName, tableName and columnName.
*/
IdentifierItems ColumnName(): {IdentifierItem id; IdentifierItems table=null, identifiers=new IdentifierItems(false);} {
( id=Identifier() (LOOKAHEAD(1) <DOT> table=TableName())? )
{
identifiers.append(id);
if (table != null){
for(int i=0; i<table.size(); i++)
identifiers.append(table.get(i));
}
return identifiers;
}
}
ADQLColumn Column(): {IdentifierItems identifiers;} {
identifiers = ColumnName()
{
try{
return queryFactory.createColumn(identifiers);
}catch(Exception ex){
throw generateParseException(ex);
}
}
}
gmantele
committed
ADQLOrder OrderItem(): {IdentifierItem identifier = null; Token ind = null, desc = null;}{