Skip to content
Snippets Groups Projects
Commit f4ffbf1d authored by Grégory Mantelet's avatar Grégory Mantelet
Browse files

Revert "[ADQL,TAP] New parser for ADQL-2.1."

This commit reverts commit 89418d13.

The reverted commit will be applied in another branch (probably 'adql-2.1') as
it is part of the next release of ADQL-Lib.
parent 89418d13
No related branches found
No related tags found
No related merge requests found
Showing
with 15831 additions and 3767 deletions
......@@ -4,17 +4,11 @@ README
Preambule
---------
This GitHub repository contains the sources of the library-set named VOLLT. It
contains 3 libraries implementing [IVOA](http://www.ivoa.net/ "International Virtual Observatory Alliance")
standards and protocols:
This GitHub repository contains the sources of 3 libraries implementing [IVOA](http://www.ivoa.net/ "International Virtual Observatory Alliance") standards and protocols:
* [ADQL](http://www.ivoa.net/documents/latest/ADQL.html "Astronomical Data Query Language")
* [UWS-1.1](http://www.ivoa.net/documents/UWS/20161024/index.html "Universal Worker Service pattern")
* [TAP](http://www.ivoa.net/documents/TAP/ "Table Access Protocol")
_**NOTE:** Support of ADQL-2.1 currently under development. For the moment, TAP
is still using ADQL-2.0 by default._
### Documentation
For a complete documentation/tutorial and a demo of the 3 libraries you should visit the following websites: [ADQLTuto](http://cdsportal.u-strasbg.fr/adqltuto), [UWSTuto](http://cdsportal.u-strasbg.fr/uwstuto) and [TAPTuto](http://cdsportal.u-strasbg.fr/taptuto).
......@@ -46,7 +40,7 @@ Below are summed up the dependencies of each library:
| Package `cds.utils` | X | | X |
| Postgres JDBC Driver | X | | X |
| Package `uws` | | X | X |
| JSON library | | X | X |
| JSON library | | X | X |
| HTTP Servlet API | | X | X |
| HTTP Multipart Library | | X | X |
| Packages `cds.*` | | | X |
......
......@@ -2,7 +2,7 @@
<!DOCTYPE project>
<project name="adql" basedir="." default="buildLib">
<property name="version" value="2.0" />
<property name="version" value="1.5" />
<property name="srcDir" value="src" />
<property name="testDir" value="test" />
......
This diff is collapsed.
/* Generated By:JavaCC: Do not edit this line. ADQLParserConstants.java */
package adql.parser;
/**
* Token literal values and constants.
* Generated by org.javacc.parser.OtherFilesGen#start()
*/
public interface ADQLParserConstants {
/** End of File. */
int EOF = 0;
/** RegularExpression Id. */
int SQL_RESERVED_WORD = 2;
/** RegularExpression Id. */
int LEFT_PAR = 3;
/** RegularExpression Id. */
int RIGHT_PAR = 4;
/** RegularExpression Id. */
int DOT = 5;
/** RegularExpression Id. */
int COMMA = 6;
/** RegularExpression Id. */
int EOQ = 7;
/** RegularExpression Id. */
int CONCAT = 8;
/** RegularExpression Id. */
int PLUS = 9;
/** RegularExpression Id. */
int MINUS = 10;
/** RegularExpression Id. */
int ASTERISK = 11;
/** RegularExpression Id. */
int DIVIDE = 12;
/** RegularExpression Id. */
int EQUAL = 13;
/** RegularExpression Id. */
int NOT_EQUAL = 14;
/** RegularExpression Id. */
int LESS_THAN = 15;
/** RegularExpression Id. */
int LESS_EQUAL_THAN = 16;
/** RegularExpression Id. */
int GREATER_THAN = 17;
/** RegularExpression Id. */
int GREATER_EQUAL_THAN = 18;
/** RegularExpression Id. */
int SELECT = 19;
/** RegularExpression Id. */
int QUANTIFIER = 20;
/** RegularExpression Id. */
int TOP = 21;
/** RegularExpression Id. */
int FROM = 22;
/** RegularExpression Id. */
int AS = 23;
/** RegularExpression Id. */
int NATURAL = 24;
/** RegularExpression Id. */
int INNER = 25;
/** RegularExpression Id. */
int OUTER = 26;
/** RegularExpression Id. */
int RIGHT = 27;
/** RegularExpression Id. */
int LEFT = 28;
/** RegularExpression Id. */
int FULL = 29;
/** RegularExpression Id. */
int JOIN = 30;
/** RegularExpression Id. */
int ON = 31;
/** RegularExpression Id. */
int USING = 32;
/** RegularExpression Id. */
int WHERE = 33;
/** RegularExpression Id. */
int AND = 34;
/** RegularExpression Id. */
int OR = 35;
/** RegularExpression Id. */
int NOT = 36;
/** RegularExpression Id. */
int IS = 37;
/** RegularExpression Id. */
int NULL = 38;
/** RegularExpression Id. */
int BETWEEN = 39;
/** RegularExpression Id. */
int LIKE = 40;
/** RegularExpression Id. */
int IN = 41;
/** RegularExpression Id. */
int EXISTS = 42;
/** RegularExpression Id. */
int BY = 43;
/** RegularExpression Id. */
int GROUP = 44;
/** RegularExpression Id. */
int HAVING = 45;
/** RegularExpression Id. */
int ORDER = 46;
/** RegularExpression Id. */
int ASC = 47;
/** RegularExpression Id. */
int DESC = 48;
/** RegularExpression Id. */
int AVG = 49;
/** RegularExpression Id. */
int MAX = 50;
/** RegularExpression Id. */
int MIN = 51;
/** RegularExpression Id. */
int SUM = 52;
/** RegularExpression Id. */
int COUNT = 53;
/** RegularExpression Id. */
int BOX = 54;
/** RegularExpression Id. */
int CENTROID = 55;
/** RegularExpression Id. */
int CIRCLE = 56;
/** RegularExpression Id. */
int POINT = 57;
/** RegularExpression Id. */
int POLYGON = 58;
/** RegularExpression Id. */
int REGION = 59;
/** RegularExpression Id. */
int CONTAINS = 60;
/** RegularExpression Id. */
int INTERSECTS = 61;
/** RegularExpression Id. */
int AREA = 62;
/** RegularExpression Id. */
int COORD1 = 63;
/** RegularExpression Id. */
int COORD2 = 64;
/** RegularExpression Id. */
int COORDSYS = 65;
/** RegularExpression Id. */
int DISTANCE = 66;
/** RegularExpression Id. */
int ABS = 67;
/** RegularExpression Id. */
int CEILING = 68;
/** RegularExpression Id. */
int DEGREES = 69;
/** RegularExpression Id. */
int EXP = 70;
/** RegularExpression Id. */
int FLOOR = 71;
/** RegularExpression Id. */
int LOG = 72;
/** RegularExpression Id. */
int LOG10 = 73;
/** RegularExpression Id. */
int MOD = 74;
/** RegularExpression Id. */
int PI = 75;
/** RegularExpression Id. */
int POWER = 76;
/** RegularExpression Id. */
int RADIANS = 77;
/** RegularExpression Id. */
int RAND = 78;
/** RegularExpression Id. */
int ROUND = 79;
/** RegularExpression Id. */
int SQRT = 80;
/** RegularExpression Id. */
int TRUNCATE = 81;
/** RegularExpression Id. */
int ACOS = 82;
/** RegularExpression Id. */
int ASIN = 83;
/** RegularExpression Id. */
int ATAN = 84;
/** RegularExpression Id. */
int ATAN2 = 85;
/** RegularExpression Id. */
int COS = 86;
/** RegularExpression Id. */
int COT = 87;
/** RegularExpression Id. */
int SIN = 88;
/** RegularExpression Id. */
int TAN = 89;
/** RegularExpression Id. */
int STRING_LITERAL = 93;
/** RegularExpression Id. */
int SCIENTIFIC_NUMBER = 94;
/** RegularExpression Id. */
int UNSIGNED_FLOAT = 95;
/** RegularExpression Id. */
int UNSIGNED_INTEGER = 96;
/** RegularExpression Id. */
int DIGIT = 97;
/** RegularExpression Id. */
int DELIMITED_IDENTIFIER = 100;
/** RegularExpression Id. */
int REGULAR_IDENTIFIER_CANDIDATE = 101;
/** RegularExpression Id. */
int Letter = 102;
/** Lexical state. */
int DEFAULT = 0;
/** Lexical state. */
int WithinString = 1;
/** Lexical state. */
int WithinDelimitedId = 2;
/** Literal token values. */
String[] tokenImage = {
"<EOF>",
"<token of kind 1>",
"<SQL_RESERVED_WORD>",
"\"(\"",
"\")\"",
"\".\"",
"\",\"",
"\";\"",
"\"||\"",
"\"+\"",
"\"-\"",
"\"*\"",
"\"/\"",
"\"=\"",
"<NOT_EQUAL>",
"\"<\"",
"\"<=\"",
"\">\"",
"\">=\"",
"\"SELECT\"",
"<QUANTIFIER>",
"\"TOP\"",
"\"FROM\"",
"\"AS\"",
"\"NATURAL\"",
"\"INNER\"",
"\"OUTER\"",
"\"RIGHT\"",
"\"LEFT\"",
"\"FULL\"",
"\"JOIN\"",
"\"ON\"",
"\"USING\"",
"\"WHERE\"",
"\"AND\"",
"\"OR\"",
"\"NOT\"",
"\"IS\"",
"\"NULL\"",
"\"BETWEEN\"",
"\"LIKE\"",
"\"IN\"",
"\"EXISTS\"",
"\"BY\"",
"\"GROUP\"",
"\"HAVING\"",
"\"ORDER\"",
"\"ASC\"",
"\"DESC\"",
"\"AVG\"",
"\"MAX\"",
"\"MIN\"",
"\"SUM\"",
"\"COUNT\"",
"\"BOX\"",
"\"CENTROID\"",
"\"CIRCLE\"",
"\"POINT\"",
"\"POLYGON\"",
"\"REGION\"",
"\"CONTAINS\"",
"\"INTERSECTS\"",
"\"AREA\"",
"\"COORD1\"",
"\"COORD2\"",
"\"COORDSYS\"",
"\"DISTANCE\"",
"\"ABS\"",
"\"CEILING\"",
"\"DEGREES\"",
"\"EXP\"",
"\"FLOOR\"",
"\"LOG\"",
"\"LOG10\"",
"\"MOD\"",
"\"PI\"",
"\"POWER\"",
"\"RADIANS\"",
"\"RAND\"",
"\"ROUND\"",
"\"SQRT\"",
"\"TRUNCATE\"",
"\"ACOS\"",
"\"ASIN\"",
"\"ATAN\"",
"\"ATAN2\"",
"\"COS\"",
"\"COT\"",
"\"SIN\"",
"\"TAN\"",
"<token of kind 90>",
"\"\\\'\"",
"<token of kind 92>",
"\"\\\'\"",
"<SCIENTIFIC_NUMBER>",
"<UNSIGNED_FLOAT>",
"<UNSIGNED_INTEGER>",
"<DIGIT>",
"\"\\\"\"",
"<token of kind 99>",
"\"\\\"\"",
"<REGULAR_IDENTIFIER_CANDIDATE>",
"<Letter>",
};
}
package adql.parser;
import java.io.IOException;
import java.io.InputStream;
import adql.db.exception.UnresolvedIdentifiersException;
import adql.query.ADQLQuery;
import adql.translator.PostgreSQLTranslator;
import adql.translator.TranslationException;
/**
* Factory of ADQL parsers.
*
* <h3>ADQL versions</h3>
*
* <p>
* It is able to deal with all versions of the ADQL grammar supported by this
* library. All these versions are listed in the enumeration
* {@link ADQLVersion}.
* </p>
*
* <p>
* To create a such factory, an ADQL version must be provided. If none is
* given, the default one will be used (<i>see {@link #DEFAULT_VERSION}</i>).
* </p>
*
* <h3>Runnable class</h3>
*
* <p>
* This class includes a main function and thus, it can be executed directly.
* Its execution allows to parse an ADQL query. Then, in function of the passed
* parameters, it is possible to just check its syntax, translate it into SQL
* or try to fix the query.
* </p>
* <p><i>
* To get help about this program, just run it with the argument
* <code>-h</code> or <code>--help</code>.
* </i></p>
*
* @author Gr&eacute;gory Mantelet (CDS)
* @version 2.0 (04/2019)
* @since 2.0
*/
public class ADQLParserFactory {
/* **********************************************************************
* VERSION MANAGEMENT
* ********************************************************************** */
/**
* Enumeration of all supported versions of the ADQL grammar.
*
* @author Gr&eacute;gory Mantelet (CDS)
* @version 2.0 (04/2019)
* @since 2.0
*/
public static enum ADQLVersion {
/** Version REC-2.0 - <a href="http://www.ivoa.net/documents/cover/ADQL-20081030.html">http://www.ivoa.net/documents/cover/ADQL-20081030.html</a>. */
V2_0,
/** Version PR-2.1 - <a href="http://www.ivoa.net/documents/ADQL/20180112/index.html">http://www.ivoa.net/documents/ADQL/20180112/index.html</a>. */
V2_1; // TODO Move 2.1 as default when it becomes REC
@Override
public String toString() {
return name().toLowerCase().replace('_', '.');
}
/** TODO JUnit for ADQLVersion.parse(String)
* Parse the given string as an ADQL version number.
*
* <p>This function should work with the following syntaxes:</p>
* <ul>
* <li><code>2.0</code></li>
* <li><code>2_0</code></li>
* <li><code>v2.0</code> or <code>V2.0</code></li>
* <li><code>v2_0</code> or <code>V2_0</code></li>
* </ul>
*
* @param str String to parse as an ADQL version specification.
*
* @return The identified ADQL version.
*/
public static ADQLVersion parse(String str) {
if (str == null)
return null;
str = str.trim().toUpperCase();
if (str.isEmpty())
return null;
if (str.charAt(0) != 'V')
str = 'V' + str;
try {
return ADQLVersion.valueOf(str.replaceAll("\\.", "_"));
} catch(IllegalArgumentException iae) {
return null;
}
}
}
/** Version of the ADQL grammar to use when none is specified:
* {@link ADQLVersion#V2_0 2.0}. */
public final static ADQLVersion DEFAULT_VERSION = ADQLVersion.V2_0; // TODO Move 2.1 as default when it becomes REC
/**
* Get the list of all supported ADQL grammar versions.
*
* @return List of all supported ADQL versions.
*
* @see ADQLVersion#values()
*/
public static ADQLVersion[] getSupportedVersions() {
return ADQLVersion.values();
}
/**
* Build on the fly a human list of all supported ADQL grammar versions.
*
* <p><i><b>Example:</b> <code>v2.0</code>, <code>v2.1</code>.</i></p>
*
* @return List of all supported ADQL versions.
*/
public static String getSupportedVersionsAsString() {
StringBuilder buf = new StringBuilder();
for(ADQLVersion v : ADQLVersion.values()) {
if (buf.length() > 0)
buf.append(", ");
buf.append(v.toString());
if (v == DEFAULT_VERSION)
buf.append(" (default)");
}
return buf.toString();
}
/* **********************************************************************
* PARSER CREATION
* ********************************************************************** */
/**
* Builds a parser whose the query to parse will have to be given as a
* String in parameter of
* {@link ADQLParser#parseQuery(java.lang.String) parseQuery(String)}.
*/
public final ADQLParser createParser() {
return createParser(DEFAULT_VERSION);
}
/**
* Builds a parser whose the query to parse will have to be given as a
* String in parameter of
* {@link ADQLParser#parseQuery(java.lang.String) parseQuery(String)}.
*
* @param version Version of the ADQL grammar that the parser must
* implement.
* <i>If NULL, the {@link #DEFAULT_VERSION} will be used.</i>
*/
public ADQLParser createParser(ADQLVersion version) {
// Prevent the NULL value by setting the default version if necessary:
if (version == null)
version = DEFAULT_VERSION;
// Create the appropriate parser in function of the specified version:
switch(version) {
case V2_0:
return new ADQLParser200();
case V2_1:
default:
return new ADQLParser201();
}
}
/* **********************************************************************
* STATIC PARSER CREATION
* ********************************************************************** */
/** Factory to use only when a default parser is asked without any
* {@link ADQLParserFactory} instance.
* @see #createDefaultParser() */
private static volatile ADQLParserFactory defaultFactory = null;
/**
* Create an ADQL parser with the default ADQL grammar version (see
* {@link #DEFAULT_VERSION}).
*
* @return A new parser implementing the default version supported by this
* library.
*/
public final static ADQLParser createDefaultParser() {
// Create the default factory, if not already done:
if (defaultFactory == null) {
synchronized (ADQLParserFactory.class) {
if (defaultFactory == null)
defaultFactory = new ADQLParserFactory();
}
}
// Create a parser implementing the default version of the ADQL grammar:
return defaultFactory.createParser(DEFAULT_VERSION);
}
/* **********************************************************************
* MAIN FUNCTION
* ********************************************************************** */
/**
* Parses the given ADQL query.
*
* <p>The result of the parsing depends of the parameters:</p>
*
* <p>
* <b>ONLY the syntax is checked: the query is NOT EXECUTED !</b>
* </p>
*/
public static final void main(String[] args) throws Exception {
final String USAGE = "Usage:\n adqlParser.jar [-version=...] [-h] [-d] [-v] [-e] [-a|-s] [-f] [<FILE>|<URL>]\n\nNOTE: If no file or URL is given, the ADQL query is expected in the standard\n input. This query must end with a ';' or <Ctrl+D>!\n\nParameters:\n -version=... : Set the version of the ADQL grammar to follow.\n It must be one among: " + getSupportedVersionsAsString() + "\n -h or --help : Display this help.\n -v or --verbose : Print the main steps of the parsing\n -d or --debug : Print stack traces when a grave error occurs\n -e or --explain : Explain the ADQL parsing (or Expand the parsing tree)\n -a or --adql : Display the understood ADQL query\n -s or --sql : Ask the SQL translation of the given ADQL query\n (SQL compatible with PostgreSQL)\n -f or --try-fix : Try fixing the most common ADQL query issues before\n attempting to parse the query.\n\nReturn:\n By default: nothing if the query is correct. Otherwise a message explaining\n why the query is not correct is displayed.\n With the -s option, the SQL translation of the given ADQL query will be\n returned.\n With the -a option, the ADQL query is returned as it has been understood.\n\nExit status:\n 0 OK !\n 1 Parameter error (missing or incorrect parameter)\n 2 File error (incorrect file/url, reading error, ...)\n 3 Parsing error (syntactic or semantic error)\n 4 Translation error (a problem has occurred during the translation of the\n given ADQL query in SQL).";
final String NEED_HELP_MSG = "Try -h or --help to get more help about the usage of this program.";
final String urlRegex = "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
ADQLParser parser;
short mode = -1;
String file = null;
ADQLVersion version = DEFAULT_VERSION;
boolean verbose = false, debug = false, explain = false, tryFix = false;
// Parameters reading:
for(int i = 0; i < args.length; i++) {
if (args[i].startsWith("-version=")) {
String[] parts = args[i].split("=");
if (parts.length <= 1) {
System.err.println("((!)) Missing ADQL version! It must be one among: " + getSupportedVersionsAsString() + ". ((!))\n" + NEED_HELP_MSG);
System.exit(1);
}
String strVersion = parts[1].replaceAll("\\.", "_");
version = ADQLVersion.parse(strVersion);
if (version == null) {
System.err.println("((!)) Incorrect ADQL version: \"" + args[i].split("=")[1] + "\"! It must be one among: " + getSupportedVersionsAsString() + ". ((!))\n" + NEED_HELP_MSG);
System.exit(1);
}
} else 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" + NEED_HELP_MSG);
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" + NEED_HELP_MSG);
System.exit(1);
} else
mode = 2;
} else if (args[i].equalsIgnoreCase("-f") || args[i].equalsIgnoreCase("--try-fix"))
tryFix = true;
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" + NEED_HELP_MSG);
System.exit(1);
} else
file = args[i].trim();
}
try {
// Get the parser for the specified ADQL version:
parser = (new ADQLParserFactory()).createParser(version);
// Try fixing the query, if asked:
InputStream in = null;
if (tryFix) {
if (verbose)
System.out.println("((i)) Trying to automatically fix the query...");
String query;
try {
// get the input stream...
if (file == null || file.length() == 0)
in = System.in;
else if (file.matches(urlRegex))
in = (new java.net.URL(file)).openStream();
else
in = new java.io.FileInputStream(file);
// ...and try fixing the query:
query = parser.tryQuickFix(in);
} finally {
// close the stream (if opened):
if (in != null)
in.close();
in = null;
}
if (verbose)
System.out.println("((i)) SUGGESTED QUERY:\n" + query);
// Initialise the parser with this fixed query:
in = new java.io.ByteArrayInputStream(query.getBytes());
}
// Otherwise, take the query as provided:
else {
// Initialise the parser with the specified input:
if (file == null || file.length() == 0)
in = System.in;
else if (file.matches(urlRegex))
in = (new java.net.URL(file)).openStream();
else
in = new java.io.FileInputStream(file);
}
// Enable/Disable the debugging in function of the parameters:
parser.setDebug(explain);
// Query parsing:
try {
if (verbose)
System.out.print("((i)) Parsing ADQL query...");
ADQLQuery q = parser.parseQuery(in);
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);
}
}
}
This diff is collapsed.
This diff is collapsed.
......@@ -20,11 +20,6 @@
* - addition of a constructor with a TokenMgrError which adds a piece of
* advice to fix the token issue (see buildExpandedMessage(...))
*
* Modified by Gr&eacute;gory Mantelet (ARI), on April 2019
* Modifications:
* - change the way ADQL and SQL reserved keywords are identified for the
* generation of the appropriate HINT in the error message
*
* /!\ DO NOT RE-GENERATE THIS FILE /!\
* In case of re-generation, replace it by ParseException.java.backup (but maybe
* after a diff in case of significant modifications have been done by a new
......@@ -58,7 +53,7 @@ public class ParseException extends Exception {
* a new object of this type with the fields "currentToken",
* "expectedTokenSequences", and "tokenImage" set.
*/
public ParseException(Token currentTokenVal, int[][] expectedTokenSequencesVal, String[] tokenImageVal) {
public ParseException(Token currentTokenVal, int[][] expectedTokenSequencesVal, String[] tokenImageVal){
super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
currentToken = currentTokenVal;
expectedTokenSequences = expectedTokenSequencesVal;
......@@ -77,25 +72,25 @@ public class ParseException extends Exception {
* these constructors.
*/
public ParseException() {
public ParseException(){
super();
}
/** Constructor with message. */
public ParseException(String message) {
public ParseException(String message){
super(message);
}
public ParseException(String message, TextPosition errorPosition) {
public ParseException(String message, TextPosition errorPosition){
this(message);
position = errorPosition;
}
public ParseException(TokenMgrError err) {
public ParseException(TokenMgrError err){
this(buildExpandedMessage(err), new TextPosition(err.getErrorLine(), err.getErrorColumn()));
}
private final static String buildExpandedMessage(final TokenMgrError err) {
private final static String buildExpandedMessage(final TokenMgrError err){
if (err.getMessage().indexOf("<EOF>") > 0)
return err.getMessage() + "! Possible cause: a string between single or double quotes which is never closed (solution: well...just close it!).";
else
......@@ -126,12 +121,44 @@ public class ParseException extends Exception {
/** Line in the ADQL query where the exception occurs. */
protected TextPosition position = null;
/** Regular expression listing all ADQL reserved words.
*
* <p><i>Note 1:
* This list is built NOT from the list given in the ADQL-2.0 standard,
* but from the collation of all words potentially used in an ADQL query
* (including standard function names).
* </i></p>
*
* <p><i>Note 2:
* This regular expression is only used to display an appropriate hint
* to the user in the error message if a such word is at the origin of
* the error. (see {@link #initialise(Token, int[][], String[])} for more
* details).
* </i></p> */
private final static String ADQL_RESERVED_WORDS_REGEX = "(ABS|ACOS|AREA|ASIN|ATAN|ATAN2|BOX|CEILING|CENTROID|CIRCLE|CONTAINS|COORD1|COORD2|COORDSYS|COS|DEGREES|DISTANCE|EXP|FLOOR|INTERSECTS|LOG|LOG10|MOD|PI|POINT|POLYGON|POWER|RADIANS|REGION|RAND|ROUND|SIN|SQRT|TOP|TAN|TRUNCATE|SELECT|TOP|DISTINCT|ALL|AS|COUNT|AVG|MAX|MIN|SUM|FROM|JOIN|CROSS|INNER|OUTER|LEFT|RIGHT|FULL|NATURAL|USING|ON|WHERE|IS|NOT|AND|OR|EXISTS|IN|LIKE|NULL|BETWEEN|ORDER|ASC|DESC|GROUP|BY|HAVING)";
/** Regular expression listing all SQL reserved words.
*
* <p><i>Note 1:
* This list is built from the list given in the ADQL-2.0 standard,
* after removal of all words potentially used in an ADQL query
* (see {@link #ADQL_RESERVED_WORDS_REGEX}).
* </i></p>
*
* <p><i>Note 2:
* This regular expression is only used to display an appropriate hint
* to the user in the error message if a such word is at the origin of
* the error. (see {@link #initialise(Token, int[][], String[])} for more
* details).
* </i></p> */
private final static String SQL_RESERVED_WORDS_REGEX = "(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)";
/**
* Gets the position in the ADQL query of the token which generates this exception.
*
* @return Position or <code>null</code> if unknown.
*/
public final TextPosition getPosition() {
public final TextPosition getPosition(){
return position;
}
......@@ -142,16 +169,16 @@ public class ParseException extends Exception {
* from the parser) the correct error message
* gets displayed.
*/
private static String initialise(Token currentToken, int[][] expectedTokenSequences, String[] tokenImage) {
private static String initialise(Token currentToken, int[][] expectedTokenSequences, String[] tokenImage){
int maxSize = 0;
// Build the list of expected tokens:
StringBuffer expected = new StringBuffer();
for(int i = 0; i < expectedTokenSequences.length; i++) {
if (maxSize < expectedTokenSequences[i].length) {
for(int i = 0; i < expectedTokenSequences.length; i++){
if (maxSize < expectedTokenSequences[i].length){
maxSize = expectedTokenSequences[i].length;
}
for(int j = 0; j < expectedTokenSequences[i].length; j++) {
for(int j = 0; j < expectedTokenSequences[i].length; j++){
expected.append(tokenImage[expectedTokenSequences[i][j]]);
}
expected.append(" ");
......@@ -162,10 +189,10 @@ public class ParseException extends Exception {
msg.append(" Encountered \"");
Token tok = currentToken.next;
StringBuffer tokenName = new StringBuffer();
for(int i = 0; i < maxSize; i++) {
for(int i = 0; i < maxSize; i++){
if (i != 0)
tokenName.append(' ');
if (tok.kind == 0) {
if (tok.kind == 0){
tokenName.append(tokenImage[0]);
break;
}
......@@ -175,21 +202,19 @@ public class ParseException extends Exception {
msg.append(tokenName.toString()).append("\".");
// Append the expected tokens list:
if (expectedTokenSequences.length == 1) {
if (expectedTokenSequences.length == 1){
msg.append(" Was expecting: ");
} else {
}else{
msg.append(" Was expecting one of: ");
}
msg.append(expected);
// Append a hint about reserved words if it is one:
if (maxSize == 1) {
tok = currentToken.next;
if (tok.adqlReserved)
msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(tok.image).append("\" is a reserved ADQL word in " + currentToken.next.adqlVersion + ". To use it as a column/table/schema name/alias, write it between double quotes.)");
else if (tok.sqlReserved)
msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(tok.image).append("\" is not supported in ADQL " + currentToken.next.adqlVersion + ", but is however a reserved word. To use it as a column/table/schema name/alias, write it between double quotes.)");
}
String word = tokenName.toString().trim();
if (word.toUpperCase().matches(ADQL_RESERVED_WORDS_REGEX))
msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(word).append("\" is a reserved ADQL word. To use it as a column/table/schema name/alias, write it between double quotes.)");
else if (word.toUpperCase().matches(SQL_RESERVED_WORDS_REGEX))
msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(word).append("\" is not supported in ADQL, but is however a reserved word. To use it as a column/table/schema name/alias, write it between double quotes.)");
return msg.toString();
/*String eol = System.getProperty("line.separator", "\n");
......@@ -242,11 +267,11 @@ public class ParseException extends Exception {
* when these raw version cannot be used as part of an ASCII
* string literal.
*/
static String add_escapes(String str) {
static String add_escapes(String str){
StringBuffer retval = new StringBuffer();
char ch;
for(int i = 0; i < str.length(); i++) {
switch(str.charAt(i)) {
for(int i = 0; i < str.length(); i++){
switch(str.charAt(i)){
case 0:
continue;
case '\b':
......@@ -274,10 +299,10 @@ public class ParseException extends Exception {
retval.append("\\\\");
continue;
default:
if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e){
String s = "0000" + Integer.toString(ch, 16);
retval.append("\\u" + s.substring(s.length() - 4, s.length()));
} else {
}else{
retval.append(ch);
}
continue;
......
......@@ -20,11 +20,6 @@
* - addition of a constructor with a TokenMgrError which adds a piece of
* advice to fix the token issue (see buildExpandedMessage(...))
*
* Modified by Gr&eacute;gory Mantelet (ARI), on April 2019
* Modifications:
* - change the way ADQL and SQL reserved keywords are identified for the
* generation of the appropriate HINT in the error message
*
* /!\ DO NOT RE-GENERATE THIS FILE /!\
* In case of re-generation, replace it by ParseException.java.backup (but maybe
* after a diff in case of significant modifications have been done by a new
......@@ -58,7 +53,7 @@ public class ParseException extends Exception {
* a new object of this type with the fields "currentToken",
* "expectedTokenSequences", and "tokenImage" set.
*/
public ParseException(Token currentTokenVal, int[][] expectedTokenSequencesVal, String[] tokenImageVal) {
public ParseException(Token currentTokenVal, int[][] expectedTokenSequencesVal, String[] tokenImageVal){
super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
currentToken = currentTokenVal;
expectedTokenSequences = expectedTokenSequencesVal;
......@@ -77,25 +72,25 @@ public class ParseException extends Exception {
* these constructors.
*/
public ParseException() {
public ParseException(){
super();
}
/** Constructor with message. */
public ParseException(String message) {
public ParseException(String message){
super(message);
}
public ParseException(String message, TextPosition errorPosition) {
public ParseException(String message, TextPosition errorPosition){
this(message);
position = errorPosition;
}
public ParseException(TokenMgrError err) {
public ParseException(TokenMgrError err){
this(buildExpandedMessage(err), new TextPosition(err.getErrorLine(), err.getErrorColumn()));
}
private final static String buildExpandedMessage(final TokenMgrError err) {
private final static String buildExpandedMessage(final TokenMgrError err){
if (err.getMessage().indexOf("<EOF>") > 0)
return err.getMessage() + "! Possible cause: a string between single or double quotes which is never closed (solution: well...just close it!).";
else
......@@ -126,12 +121,44 @@ public class ParseException extends Exception {
/** Line in the ADQL query where the exception occurs. */
protected TextPosition position = null;
/** Regular expression listing all ADQL reserved words.
*
* <p><i>Note 1:
* This list is built NOT from the list given in the ADQL-2.0 standard,
* but from the collation of all words potentially used in an ADQL query
* (including standard function names).
* </i></p>
*
* <p><i>Note 2:
* This regular expression is only used to display an appropriate hint
* to the user in the error message if a such word is at the origin of
* the error. (see {@link #initialise(Token, int[][], String[])} for more
* details).
* </i></p> */
private final static String ADQL_RESERVED_WORDS_REGEX = "(ABS|ACOS|AREA|ASIN|ATAN|ATAN2|BOX|CEILING|CENTROID|CIRCLE|CONTAINS|COORD1|COORD2|COORDSYS|COS|DEGREES|DISTANCE|EXP|FLOOR|INTERSECTS|LOG|LOG10|MOD|PI|POINT|POLYGON|POWER|RADIANS|REGION|RAND|ROUND|SIN|SQRT|TOP|TAN|TRUNCATE|SELECT|TOP|DISTINCT|ALL|AS|COUNT|AVG|MAX|MIN|SUM|FROM|JOIN|CROSS|INNER|OUTER|LEFT|RIGHT|FULL|NATURAL|USING|ON|WHERE|IS|NOT|AND|OR|EXISTS|IN|LIKE|NULL|BETWEEN|ORDER|ASC|DESC|GROUP|BY|HAVING)";
/** Regular expression listing all SQL reserved words.
*
* <p><i>Note 1:
* This list is built from the list given in the ADQL-2.0 standard,
* after removal of all words potentially used in an ADQL query
* (see {@link #ADQL_RESERVED_WORDS_REGEX}).
* </i></p>
*
* <p><i>Note 2:
* This regular expression is only used to display an appropriate hint
* to the user in the error message if a such word is at the origin of
* the error. (see {@link #initialise(Token, int[][], String[])} for more
* details).
* </i></p> */
private final static String SQL_RESERVED_WORDS_REGEX = "(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)";
/**
* Gets the position in the ADQL query of the token which generates this exception.
*
* @return Position or <code>null</code> if unknown.
*/
public final TextPosition getPosition() {
public final TextPosition getPosition(){
return position;
}
......@@ -142,16 +169,16 @@ public class ParseException extends Exception {
* from the parser) the correct error message
* gets displayed.
*/
private static String initialise(Token currentToken, int[][] expectedTokenSequences, String[] tokenImage) {
private static String initialise(Token currentToken, int[][] expectedTokenSequences, String[] tokenImage){
int maxSize = 0;
// Build the list of expected tokens:
StringBuffer expected = new StringBuffer();
for(int i = 0; i < expectedTokenSequences.length; i++) {
if (maxSize < expectedTokenSequences[i].length) {
for(int i = 0; i < expectedTokenSequences.length; i++){
if (maxSize < expectedTokenSequences[i].length){
maxSize = expectedTokenSequences[i].length;
}
for(int j = 0; j < expectedTokenSequences[i].length; j++) {
for(int j = 0; j < expectedTokenSequences[i].length; j++){
expected.append(tokenImage[expectedTokenSequences[i][j]]);
}
expected.append(" ");
......@@ -162,10 +189,10 @@ public class ParseException extends Exception {
msg.append(" Encountered \"");
Token tok = currentToken.next;
StringBuffer tokenName = new StringBuffer();
for(int i = 0; i < maxSize; i++) {
for(int i = 0; i < maxSize; i++){
if (i != 0)
tokenName.append(' ');
if (tok.kind == 0) {
if (tok.kind == 0){
tokenName.append(tokenImage[0]);
break;
}
......@@ -175,21 +202,19 @@ public class ParseException extends Exception {
msg.append(tokenName.toString()).append("\".");
// Append the expected tokens list:
if (expectedTokenSequences.length == 1) {
if (expectedTokenSequences.length == 1){
msg.append(" Was expecting: ");
} else {
}else{
msg.append(" Was expecting one of: ");
}
msg.append(expected);
// Append a hint about reserved words if it is one:
if (maxSize == 1) {
tok = currentToken.next;
if (tok.adqlReserved)
msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(tok.image).append("\" is a reserved ADQL word in " + currentToken.next.adqlVersion + ". To use it as a column/table/schema name/alias, write it between double quotes.)");
else if (tok.sqlReserved)
msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(tok.image).append("\" is not supported in ADQL " + currentToken.next.adqlVersion + ", but is however a reserved word. To use it as a column/table/schema name/alias, write it between double quotes.)");
}
String word = tokenName.toString().trim();
if (word.toUpperCase().matches(ADQL_RESERVED_WORDS_REGEX))
msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(word).append("\" is a reserved ADQL word. To use it as a column/table/schema name/alias, write it between double quotes.)");
else if (word.toUpperCase().matches(SQL_RESERVED_WORDS_REGEX))
msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(word).append("\" is not supported in ADQL, but is however a reserved word. To use it as a column/table/schema name/alias, write it between double quotes.)");
return msg.toString();
/*String eol = System.getProperty("line.separator", "\n");
......@@ -242,11 +267,11 @@ public class ParseException extends Exception {
* when these raw version cannot be used as part of an ASCII
* string literal.
*/
static String add_escapes(String str) {
static String add_escapes(String str){
StringBuffer retval = new StringBuffer();
char ch;
for(int i = 0; i < str.length(); i++) {
switch(str.charAt(i)) {
for(int i = 0; i < str.length(); i++){
switch(str.charAt(i)){
case 0:
continue;
case '\b':
......@@ -274,10 +299,10 @@ public class ParseException extends Exception {
retval.append("\\\\");
continue;
default:
if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e){
String s = "0000" + Integer.toString(ch, 16);
retval.append("\\u" + s.substring(s.length() - 4, s.length()));
} else {
}else{
retval.append(ch);
}
continue;
......
/* Generated By:JavaCC: Do not edit this line. Token.java Version 6.0 */
/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true
*
* Modified by Gr&eacute;gory Mantelet (CDS), on April 2019
* Modifications:
* - addition of the attributes: `adqlReserved`, `sqlReserved`,
* `adqlVersion` and `isFunctionName`
*
* /!\ DO NOT RE-GENERATE THIS FILE /!\
* In case of re-generation, replace it by Token.java.backup (but maybe
* after a diff in case of significant modifications have been done by a new
* version of JavaCC).
*
* Modified by Gr&eacute;gory Mantelet (CDS), on March 2017
* Modification: addition of position (line and column) in the original text.
* /!\ DO NOT RE-GENERATE THIS FILE /!\
* In case of re-generation, replace it by
* Token.java.backup (but maybe after a diff
* in case of significant modifications have been done
* by a new version of JavaCC).
*/
package adql.parser;
import adql.parser.ADQLParserFactory.ADQLVersion;
/**
* Describes the input token stream.
*/
public class Token implements java.io.Serializable {
/**
......@@ -72,57 +69,6 @@ public class Token implements java.io.Serializable {
*/
public Token specialToken;
/**
* Indicate whether this token is a reserved ADQL function name.
*
* <p><i><b>Implementation note:</b>
* This piece of information is just used when attempting to fix an ADQL
* query.
* </i></p>
*
* @since 2.0
*/
public boolean isFunctionName = false;
/**
* Indicate whether this token is a reserved keyword in the current version
* of the ADQL language.
*
* <p><i><b>Implementation note:</b>
* This piece of information is just used to add a hint in
* ParseException's messages.
* </i></p>
*
* @since 2.0
*/
public boolean adqlReserved = false;
/**
* Indicate whether this token is a reserved keyword in the current version
* of the ADQL language because it is a valid keyword in SQL (and may have
* unexpected behavior if used because not explicitly defined in ADQL).
*
* <p><i><b>Implementation note:</b>
* This piece of information is just used to add a hint in
* ParseException's messages.
* </i></p>
*
* @since 2.0
*/
public boolean sqlReserved = false;
/**
* Give the version of the ADQL language.
*
* <p><i><b>Implementation note:</b>
* This piece of information is used just for more clarity in
* ParseException's messages.
* </i></p>
*
* @since 2.0
*/
public ADQLVersion adqlVersion = null;
/**
* An optional attribute value of the Token.
* Tokens which are not used as syntactic sugar will often contain
......@@ -131,27 +77,26 @@ public class Token implements java.io.Serializable {
* Any subclass of Token that actually wants to return a non-null value can
* override this method as appropriate.
*/
public Object getValue() {
public Object getValue(){
return null;
}
/**
* No-argument constructor
*/
public Token() {
}
public Token(){}
/**
* Constructs a new token for the specified Image.
*/
public Token(int kind) {
public Token(int kind){
this(kind, null);
}
/**
* Constructs a new token for the specified Image and Kind.
*/
public Token(int kind, String image) {
public Token(int kind, String image){
this.kind = kind;
this.image = image;
}
......@@ -160,7 +105,7 @@ public class Token implements java.io.Serializable {
* Returns the image.
*/
@Override
public String toString() {
public String toString(){
return image;
}
......@@ -176,14 +121,14 @@ public class Token implements java.io.Serializable {
* to the following switch statement. Then you can cast matchedToken
* variable to the appropriate type and use sit in your lexical actions.
*/
public static Token newToken(int ofKind, String image) {
switch(ofKind) {
public static Token newToken(int ofKind, String image){
switch(ofKind){
default:
return new Token(ofKind, image);
}
}
public static Token newToken(int ofKind) {
public static Token newToken(int ofKind){
return newToken(ofKind, null);
}
......
/* Generated By:JavaCC: Do not edit this line. Token.java Version 6.0 */
/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true
*
* Modified by Gr&eacute;gory Mantelet (CDS), on April 2019
* Modifications:
* - addition of the attributes: `adqlReserved`, `sqlReserved`,
* `adqlVersion` and `isFunctionName`
*
* /!\ DO NOT RE-GENERATE THIS FILE /!\
* In case of re-generation, replace it by Token.java.backup (but maybe
* after a diff in case of significant modifications have been done by a new
* version of JavaCC).
*
* Modified by Gr&eacute;gory Mantelet (CDS), on March 2017
* Modification: addition of position (line and column) in the original text.
* /!\ DO NOT RE-GENERATE THIS FILE /!\
* In case of re-generation, replace it by
* Token.java.backup (but maybe after a diff
* in case of significant modifications have been done
* by a new version of JavaCC).
*/
package adql.parser;
import adql.parser.ADQLParserFactory.ADQLVersion;
/**
* Describes the input token stream.
*/
public class Token implements java.io.Serializable {
/**
......@@ -72,57 +69,6 @@ public class Token implements java.io.Serializable {
*/
public Token specialToken;
/**
* Indicate whether this token is a reserved ADQL function name.
*
* <p><i><b>Implementation note:</b>
* This piece of information is just used when attempting to fix an ADQL
* query.
* </i></p>
*
* @since 2.0
*/
public boolean isFunctionName = false;
/**
* Indicate whether this token is a reserved keyword in the current version
* of the ADQL language.
*
* <p><i><b>Implementation note:</b>
* This piece of information is just used to add a hint in
* ParseException's messages.
* </i></p>
*
* @since 2.0
*/
public boolean adqlReserved = false;
/**
* Indicate whether this token is a reserved keyword in the current version
* of the ADQL language because it is a valid keyword in SQL (and may have
* unexpected behavior if used because not explicitly defined in ADQL).
*
* <p><i><b>Implementation note:</b>
* This piece of information is just used to add a hint in
* ParseException's messages.
* </i></p>
*
* @since 2.0
*/
public boolean sqlReserved = false;
/**
* Give the version of the ADQL language.
*
* <p><i><b>Implementation note:</b>
* This piece of information is used just for more clarity in
* ParseException's messages.
* </i></p>
*
* @since 2.0
*/
public ADQLVersion adqlVersion = null;
/**
* An optional attribute value of the Token.
* Tokens which are not used as syntactic sugar will often contain
......@@ -131,27 +77,26 @@ public class Token implements java.io.Serializable {
* Any subclass of Token that actually wants to return a non-null value can
* override this method as appropriate.
*/
public Object getValue() {
public Object getValue(){
return null;
}
/**
* No-argument constructor
*/
public Token() {
}
public Token(){}
/**
* Constructs a new token for the specified Image.
*/
public Token(int kind) {
public Token(int kind){
this(kind, null);
}
/**
* Constructs a new token for the specified Image and Kind.
*/
public Token(int kind, String image) {
public Token(int kind, String image){
this.kind = kind;
this.image = image;
}
......@@ -160,7 +105,7 @@ public class Token implements java.io.Serializable {
* Returns the image.
*/
@Override
public String toString() {
public String toString(){
return image;
}
......@@ -176,14 +121,14 @@ public class Token implements java.io.Serializable {
* to the following switch statement. Then you can cast matchedToken
* variable to the appropriate type and use sit in your lexical actions.
*/
public static Token newToken(int ofKind, String image) {
switch(ofKind) {
public static Token newToken(int ofKind, String image){
switch(ofKind){
default:
return new Token(ofKind, image);
}
}
public static Token newToken(int ofKind) {
public static Token newToken(int ofKind){
return newToken(ofKind, null);
}
......
......@@ -4,9 +4,7 @@
* Modified by Gr&eacute;gory Mantelet (CDS), on Sept. 2017
* Modifications:
* - addition of position (line and column) in the original text
* - adapt the error message so that being more explicit for humans
* and display the incorrect character as a character instead of an
* integer value
* - display the incorrect character as a character instead of an integer
*
* /!\ DO NOT RE-GENERATE THIS FILE /!\
* In case of re-generation, replace it by TokenMgrError.java.backup (but maybe
......
This diff is collapsed.
package adql.query.operand.function.string;
/*
* 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 2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
*/
import adql.query.ADQLObject;
import adql.query.operand.ADQLOperand;
import adql.query.operand.function.ADQLFunction;
/**
* It represents the LOWER function of ADQL.
*
* <p>This function put the given text in lower case.</p>
*
* <p><i><u>Example:</u><br/>
* <code>LOWER('Francis Albert Augustus Charles Emmanuel')</code><br/>
* which should return:<br/>
* <code>francis albert augustus charles emmanuel</code>
* </i></p>
*
* @author Gr&eacute;gory Mantelet (CDS)
* @version 2.0 (04/2019)
* @since 2.0
*/
public class LowerFunction extends ADQLFunction {
/** Constant name of this function. */
protected final String FCT_NAME = "LOWER";
/** The only parameter of this function. */
protected ADQLOperand strParam;
/**
* Builds a LOWER function with its parameter.
*
* @param param Parameter of LOWER.
* @throws NullPointerException If the given operand is <i>null</i>
* or if it's not a string parameter.
*/
public LowerFunction(final ADQLOperand strParam) {
if (strParam == null)
throw new NullPointerException("The function " + FCT_NAME + " must have one non-NULL parameter!");
if (!strParam.isString())
throw new NullPointerException("The ADQL function " + FCT_NAME + " must have one parameter of type VARCHAR (i.e. a String)!");
this.strParam = strParam;
}
@Override
public final boolean isNumeric() {
return false;
}
@Override
public final boolean isString() {
return true;
}
@Override
public final boolean isGeometry() {
return false;
}
@Override
public final String getName() {
return FCT_NAME;
}
@Override
public ADQLObject getCopy() throws Exception {
return new LowerFunction((ADQLOperand)(strParam.getCopy()));
}
@Override
public int getNbParameters() {
return 1;
}
@Override
public final ADQLOperand[] getParameters() {
return new ADQLOperand[]{ strParam };
}
@Override
public ADQLOperand getParameter(final int index) throws ArrayIndexOutOfBoundsException {
if (index == 0)
return strParam;
else
throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + FCT_NAME + "\" !");
}
@Override
public ADQLOperand setParameter(final int index, final ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception {
if (index == 0) {
ADQLOperand replaced = strParam;
if (replacer == null)
throw new NullPointerException("Missing the new parameter of the function \"" + toADQL() + "\"!");
else if (replacer.isString())
strParam = replacer;
else
throw new Exception("Impossible to replace a String parameter by a " + replacer.getClass().getName() + " (" + replacer.toADQL() + ") !");
setPosition(null);
return replaced;
} else
throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + FCT_NAME + "\" !");
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment