/* * Globus Toolkit Public License (GTPL) * * Copyright (c) 1999 University of Chicago and The University of * Southern California. All Rights Reserved. * * 1) The "Software", below, refers to the Globus Toolkit (in either * source-code, or binary form and accompanying documentation) and a * "work based on the Software" means a work based on either the * Software, on part of the Software, or on any derivative work of * the Software under copyright law: that is, a work containing all * or a portion of the Software either verbatim or with * modifications. Each licensee is addressed as "you" or "Licensee." * * 2) The University of Southern California and the University of * Chicago as Operator of Argonne National Laboratory are copyright * holders in the Software. The copyright holders and their third * party licensors hereby grant Licensee a royalty-free nonexclusive * license, subject to the limitations stated herein and * U.S. Government license rights. * * 3) A copy or copies of the Software may be given to others, if you * meet the following conditions: * * a) Copies in source code must include the copyright notice and * this license. * * b) Copies in binary form must include the copyright notice and * this license in the documentation and/or other materials * provided with the copy. * * 4) All advertising materials, journal articles and documentation * mentioning features derived from or use of the Software must * display the following acknowledgement: * * "This product includes software developed by and/or derived from * the Globus project (http://www.globus.org/)." * * In the event that the product being advertised includes an intact * Globus distribution (with copyright and license included) then * this clause is waived. * * 5) You are encouraged to package modifications to the Software * separately, as patches to the Software. * * 6) You may make modifications to the Software, however, if you * modify a copy or copies of the Software or any portion of it, * thus forming a work based on the Software, and give a copy or * copies of such work to others, either in source code or binary * form, you must meet the following conditions: * * a) The Software must carry prominent notices stating that you * changed specified portions of the Software. * * b) The Software must display the following acknowledgement: * * "This product includes software developed by and/or derived * from the Globus Project (http://www.globus.org/) to which the * U.S. Government retains certain rights." * * 7) You may incorporate the Software or a modified version of the * Software into a commercial product, if you meet the following * conditions: * * a) The commercial product or accompanying documentation must * display the following acknowledgment: * * "This product includes software developed by and/or derived * from the Globus Project (http://www.globus.org/) to which the * U.S. Government retains a paid-up, nonexclusive, irrevocable * worldwide license to reproduce, prepare derivative works, and * perform publicly and display publicly." * * b) The user of the commercial product must be given the following * notice: * * "[Commercial product] was prepared, in part, as an account of * work sponsored by an agency of the United States Government. * Neither the United States, nor the University of Chicago, nor * University of Southern California, nor any contributors to * the Globus Project or Globus Toolkit nor any of their employees, * makes any warranty express or implied, or assumes any legal * liability or responsibility for the accuracy, completeness, or * usefulness of any information, apparatus, product, or process * disclosed, or represents that its use would not infringe * privately owned rights. * * IN NO EVENT WILL THE UNITED STATES, THE UNIVERSITY OF CHICAGO * OR THE UNIVERSITY OF SOUTHERN CALIFORNIA OR ANY CONTRIBUTORS * TO THE GLOBUS PROJECT OR GLOBUS TOOLKIT BE LIABLE FOR ANY * DAMAGES, INCLUDING DIRECT, INCIDENTAL, SPECIAL, OR CONSEQUENTIAL * DAMAGES RESULTING FROM EXERCISE OF THIS LICENSE AGREEMENT OR * THE USE OF THE [COMMERCIAL PRODUCT]." * * 8) LICENSEE AGREES THAT THE EXPORT OF GOODS AND/OR TECHNICAL DATA * FROM THE UNITED STATES MAY REQUIRE SOME FORM OF EXPORT CONTROL * LICENSE FROM THE U.S. GOVERNMENT AND THAT FAILURE TO OBTAIN SUCH * EXPORT CONTROL LICENSE MAY RESULT IN CRIMINAL LIABILITY UNDER U.S. * LAWS. * * 9) Portions of the Software resulted from work developed under a * U.S. Government contract and are subject to the following license: * the Government is granted for itself and others acting on its * behalf a paid-up, nonexclusive, irrevocable worldwide license in * this computer software to reproduce, prepare derivative works, and * perform publicly and display publicly. * * 10) The Software was prepared, in part, as an account of work * sponsored by an agency of the United States Government. Neither * the United States, nor the University of Chicago, nor The * University of Southern California, nor any contributors to the * Globus Project or Globus Toolkit, nor any of their employees, * makes any warranty express or implied, or assumes any legal * liability or responsibility for the accuracy, completeness, or * usefulness of any information, apparatus, product, or process * disclosed, or represents that its use would not infringe privately * owned rights. * * 11) IN NO EVENT WILL THE UNITED STATES, THE UNIVERSITY OF CHICAGO OR * THE UNIVERSITY OF SOUTHERN CALIFORNIA OR ANY CONTRIBUTORS TO THE * GLOBUS PROJECT OR GLOBUS TOOLKIT BE LIABLE FOR ANY DAMAGES, * INCLUDING DIRECT, INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES * RESULTING FROM EXERCISE OF THIS LICENSE AGREEMENT OR THE USE OF * THE SOFTWARE. * * END OF LICENSE */ package org.griphyn.vdl.annotation; import java.io.*; import java.util.regex.Pattern; import java.text.SimpleDateFormat; import java.text.ParseException; import org.griphyn.vdl.util.Logging; import org.griphyn.vdl.dbschema.Annotation; /** * Parses the input stream and generates a query tree as * output. * * @author Jens-S. Vöckler * @author Yong Zhao * @version $Revision$ * * @see QueryScanner * @see QueryTree */ public class QueryParser { /** * The access to the lexical scanner is stored here. */ private QueryScanner m_scanner = null; /** * Stores the look-ahead symbol. */ private String m_lookAhead = null; /** * Initializes the parser with an input stream to read from. * @param r is the stream opened for reading. */ public QueryParser( java.io.Reader r ) throws IOException, QueryParserException { m_scanner = new QueryScanner(r); m_lookAhead = m_scanner.nextToken(); } /** * Parses the query stream * @return the root node to the parsed query tree */ public QueryTree parse() throws IOException, QueryParserException { QueryTree root = null; while ( m_lookAhead != null ) { if (root == null) { root = expression(); }else expression(); } return root; } /** * The main function to test the parser. */ public static void main(String[] args) throws IOException, QueryParserException { QueryParser parser; if (args.length == 0) parser= new QueryParser(new InputStreamReader(System.in)); else parser= new QueryParser(new FileReader(args[0])); QueryTree root = parser.parse(); if (root != null) { String sql = root.toSQL(Annotation.CLASS_FILENAME, null); System.out.println(sql); } } /** * check a string and guess the type of the attribute from its value */ protected int checkString(String value) { int type = Predicate.TYPE_STRING; int len = value.length(); if (value == null || len == 0) return type; if (len ==1) if (value.equalsIgnoreCase("t") || value.equalsIgnoreCase("f") ) return Predicate.TYPE_BOOL; else return type; //if (value.matches("\\d\\d[/.]\\d\\d[/.]\\d\\d(\\d\\d)?")) if (checkDate(value)) return Predicate.TYPE_DATE; return type; } /** * check a string to see whether it represents a date value */ protected boolean checkDate (String value) { SimpleDateFormat fmt[] = { new SimpleDateFormat("MM/dd/yy HH:mm:ss.SSS"), new SimpleDateFormat("MM/dd/yy HH:mm:ss"), new SimpleDateFormat("MM/dd/yy HH:mm"), new SimpleDateFormat("MM/dd/yy"), new SimpleDateFormat("MM.dd.yy HH:mm:ss.SSS"), new SimpleDateFormat("MM.dd.yy HH:mm:ss"), new SimpleDateFormat("MM.dd.yy HH:mm"), new SimpleDateFormat("MM.dd.yy"), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), new SimpleDateFormat("yyyy-MM-dd HH:mm"), new SimpleDateFormat("yyyy-MM-dd"), new SimpleDateFormat("yyyy.MM.dd HH:mm:ss.SSS"), new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"), new SimpleDateFormat("yyyy.MM.dd HH:mm"), new SimpleDateFormat("yyyy.MM.dd"), }; for( int i = 0; i < fmt.length; i++ ) { try { fmt[i].parse(value); return true; } catch (ParseException e) { continue; } } return false; } /** * check a string to see whether it represents a integer or float value. */ protected int checkNumber (String value) { if (value.matches("^[+-]?\\d+$")) return Predicate.TYPE_INT; if (value.matches("^([+-]?)(?=\\d|\\.\\d)\\d*(\\.\\d*)?([Ee]([+-]?\\d+))?$")) return Predicate.TYPE_FLOAT; return -1; } /** * Parses predicates and returns the corresponding Predicate objects */ protected Predicate predicates() throws IOException, QueryParserException { Predicate p = null; if (m_lookAhead.startsWith("#")) { //identifier String name = m_lookAhead.substring(1); m_lookAhead = m_scanner.nextToken(); if (!m_lookAhead.startsWith("@")) throw new QueryParserException( m_scanner, "A predicate must follow " + name ); if (m_lookAhead.equals("@EX")) { //nothing following exists p = new Predicate(Predicate.EXISTS, name); } else if (m_lookAhead.equals("@CT")) { m_lookAhead = m_scanner.nextToken(); if (!m_lookAhead.startsWith("$")) throw new QueryParserException( m_scanner, "CONTAINS should be followed by a string value" ); String value = m_lookAhead.substring(1); p = new Predicate(Predicate.CONTAINS, name, value); } else if (m_lookAhead.equals("@LK")) { m_lookAhead = m_scanner.nextToken(); if (!m_lookAhead.startsWith("$")) throw new QueryParserException( m_scanner, "LIKE should be followed by a string value" ); String value = m_lookAhead.substring(1); p = new Predicate(Predicate.LIKE, name, value); } else if (m_lookAhead.equals("@BT")) { m_lookAhead = m_scanner.nextToken(); int type; int numType1=-1, numType2=-1; int strType1=-1, strType2=-1; String value1; if (m_lookAhead.startsWith("#")) { type = 0; numType1 = -1; value1 = m_lookAhead.substring(1); if ((numType1 = checkNumber(value1)) == -1) throw new QueryParserException( m_scanner, "the value " + value1 + " is not numeric, use quotes for a string" ); } else if ( m_lookAhead.startsWith("$")) { type = 1; value1 = m_lookAhead.substring(1); strType1 = checkString(value1); } else throw new QueryParserException( m_scanner, "BETWEEN should be followed by a value" ); m_lookAhead = m_scanner.nextToken(); if (!m_lookAhead.equals("AND")) throw new QueryParserException( m_scanner, "BETWEEN should be followed by AND" ); m_lookAhead = m_scanner.nextToken(); if (!m_lookAhead.startsWith("#") && !m_lookAhead.startsWith("$")) { throw new QueryParserException( m_scanner, "BETWEEN should have another value after AND " ); } else if ( (m_lookAhead.startsWith("#") && type == 1) || (m_lookAhead.startsWith("$") && type == 0) ) throw new QueryParserException( m_scanner, "type mismatch in BETWEEN...AND " ); String value2 = m_lookAhead.substring(1); numType2 = -1; if (m_lookAhead.startsWith("#")) { if ((numType2 = checkNumber(value2)) == -1) throw new QueryParserException( m_scanner, "the value " + value2 + " is not numeric, use quotes for a string" ); if (numType1 != numType2) type = Predicate.TYPE_FLOAT; else type = numType1; } else { strType2 = checkString(value2); if (strType1 != strType2) type = Predicate.TYPE_STRING; else type = strType1; } p = new Predicate(Predicate.BETWEEN, name, type, value1, value2); } else { String op = m_lookAhead; m_lookAhead = m_scanner.nextToken(); if (!m_lookAhead.startsWith("#") && !m_lookAhead.startsWith("$")) throw new QueryParserException( m_scanner, "Predicate should be followed by a value" ); String value = m_lookAhead.substring(1); int type = -1; if (m_lookAhead.startsWith("#")) { if ((type = checkNumber(value)) == -1) throw new QueryParserException( m_scanner, "the value " + value + " is not numeric, use quotes for a string" ); } else { type = checkString(value); } int pt = -1; if (op.equals("@EQ")) pt = Predicate.EQ; else if (op.equals("@NE")) pt = Predicate.NE; else if (op.equals("@GT")) pt = Predicate.GT; else if (op.equals("@LT")) pt = Predicate.LT; else if (op.equals("@GE")) pt = Predicate.GE; else if (op.equals("@LE")) pt = Predicate.LE; p = new Predicate(pt, name, type, value); } } return p; } /** * Parses the atoms of the query statement */ public QueryTree atom() throws IOException, QueryParserException { QueryTree ret = null; QueryTree current = null; if (m_lookAhead.startsWith("#")) { Predicate p = predicates(); current = new QueryTree(p); } else if (m_lookAhead.equals("NOT")) { m_lookAhead = m_scanner.nextToken(); Predicate p = new Predicate(Predicate.NOT); current = new QueryTree(p); ret = atom(); if (ret.getPredicate() == Predicate.NOT) current = ret.getRchild(); else current.setRchild(ret); } else if (m_lookAhead.startsWith("(")) { m_lookAhead = m_scanner.nextToken(); current = expression(); if (m_lookAhead == null || !m_lookAhead.startsWith(")")) { throw new QueryParserException( m_scanner, "missing )" ); } } else throw new QueryParserException( m_scanner, "invalid token " + m_lookAhead.substring(1) ); return current; } /** * Parses the expressions of the query statement */ public QueryTree expression() throws IOException, QueryParserException { QueryTree ret = null; ret = atom(); m_lookAhead = m_scanner.nextToken(); while ((m_lookAhead != null) && (m_lookAhead.equals("AND") || m_lookAhead.equals("OR"))) { Predicate p; if (m_lookAhead.equals("AND")) { p = new Predicate(Predicate.AND); } else { p = new Predicate(Predicate.OR); } QueryTree tmp = new QueryTree(p); tmp.addChild(ret); m_lookAhead = m_scanner.nextToken(); ret = atom(); tmp.addChild(ret); m_lookAhead = m_scanner.nextToken(); ret = tmp; } return ret; } }