Hi Adam,
What exactly does this do? Thanks Scott HotWax Media http://www.hotwaxmedia.com On 13/11/2009, at 12:23 PM, [hidden email] wrote: > Author: doogie > Date: Thu Nov 12 23:23:12 2009 > New Revision: 835637 > > URL: http://svn.apache.org/viewvc?rev=835637&view=rev > Log: > Start of new sql parsing code. Not completely tested. It *does* > parse > a test SELECT; what is not tested is actually running the built > DynamicViewEntity. > > Added: > ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/ > ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/Parser.jjt > ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/ > SQLSelect.java > Modified: > ofbiz/trunk/framework/entity/build.xml > > Modified: ofbiz/trunk/framework/entity/build.xml > URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/build.xml?rev=835637&r1=835636&r2=835637&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- ofbiz/trunk/framework/entity/build.xml (original) > +++ ofbiz/trunk/framework/entity/build.xml Thu Nov 12 23:23:12 2009 > @@ -38,6 +38,10 @@ > <fileset dir="../base/lib/scripting" includes="*.jar"/> > <fileset dir="../base/build/lib" includes="*.jar"/> > </path> > + <path id="src-path"> > + <pathelement location="build/gen-src/javacc"/> > + <pathelement location="build/gen-src/jjtree"/> > + </path> > > <patternset id="src.exc.set"> > <exclude name="org/ofbiz/entity/connection/ > XaPoolConnectionFactory.java"/> > @@ -48,7 +52,11 @@ > <!-- Compilation of the source > files > --> > <!-- > ================================================================== --> > > - <target name="classes" depends="prepare"> > + <target name="gen-src"> > + <ofbiz-jjtree dir="org/ofbiz/entity/sql" file="Parser"/> > + </target> > + > + <target name="classes" depends="prepare,gen-src"> > <javac15/> > </target> > > > Added: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/ > Parser.jjt > URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/Parser.jjt?rev=835637&view=auto > = > = > = > = > = > = > = > = > ====================================================================== > --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/Parser.jjt > (added) > +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/Parser.jjt > Thu Nov 12 23:23:12 2009 > @@ -0,0 +1,414 @@ > +options { > + JAVA_UNICODE_ESCAPE = false; > + ERROR_REPORTING = true; > + STATIC = false; > + MULTI = true; > + JDK_VERSION = "1.5"; > + VISITOR = true; > + BUILD_NODE_FILES = true; > + NODE_FACTORY = false; > + NODE_USES_PARSER = true; > +// NODE_SCOPE_HOOK = true; > + NODE_PREFIX = "SQL"; > +// DEBUG_PARSER = true; > +// DEBUG_LOOKAHEAD = true; > +// DEBUG_TOKEN_MANAGER = true; > + LOOKAHEAD = 1; > +// CHOICE_AMBIGUITY_CHECK = 3; > +// OTHER_AMBIGUITY_CHECK = 3; > + IGNORE_CASE = true; > +} > +PARSER_BEGIN(Parser) > + > +package org.ofbiz.entity.sql; > + > +import java.io.*; > +import java.util.List; > +import java.util.LinkedList; > +import java.util.Set; > + > +import javolution.util.FastList; > +import javolution.util.FastSet; > + > +import org.ofbiz.base.conversion.ConversionException; > +import org.ofbiz.base.conversion.Converter; > +import org.ofbiz.base.conversion.Converters; > +import org.ofbiz.entity.condition.EntityComparisonOperator; > +import org.ofbiz.entity.condition.EntityCondition; > +import org.ofbiz.entity.condition.EntityConditionValue; > +import org.ofbiz.entity.condition.EntityFieldValue; > +import org.ofbiz.entity.condition.EntityOperator; > +import org.ofbiz.entity.model.DynamicViewEntity; > +import org.ofbiz.entity.model.ModelKeyMap; > + > +public class Parser { > +} > + > +PARSER_END(Parser) > +TOKEN_MGR_DECLS: { > + private final LinkedList<Integer> stack = new LinkedList<Integer>(); > + > + void pushState(int newState) { > + stack.add(curLexState); > + SwitchTo(newState); > + } > + > + void popState() { > + SwitchTo(stack.removeLast()); > + } > +} > + > +TOKEN: { > + <OPEN_PAREN: "("> > +| <CLOSE_PAREN: ")"> > +| <AND: "AND"> > +| <OR: "OR"> > +| <PERIOD: "."> > +| <JOIN: "JOIN"> > +| <LEFT: "LEFT"> > +| <RIGHT: "RIGHT"> > +| <AS: "AS"> > +| <WHERE: "WHERE"> > +| <HAVING: "HAVING"> > +| <GROUP: "GROUP"> > +| <ORDER: "ORDER"> > +| <UNION: "UNION"> > +| <BY: "BY"> > +| <ON: "ON"> > +| <LIMIT: "LIMIT"> > +| <OFFSET: "OFFSET"> > +| <SELECT: "SELECT"> > +| <DELETE: "DELETE"> > +| <UPDATE: "UPDATE"> > +| <SET: "SET"> > +| <FROM: "FROM"> > +| <SEMI: ";"> > +| <STAR: "*"> > +| <COMMA: ","> > +| <START_DQUOTE: "\""> { pushState(IN_DQUOTE); } > +| <START_SQUOTE: "'"> { pushState(IN_SQUOTE); } > +| <INTEGER: > + "0" ( > + "x" (["0"-"9","a"-"b"])+ > + | (["0"-"7"])+ > + ) > + | ["1"-"9"] (["0"-"9"])* > + > > +| <NAME: (["a"-"z"])+> > +//| <WORD: (~["'", "\"", "/", " ", "\f", "\n", "\r", "\t", "*"])+> > +} > + > +<DEFAULT> > +SKIP: { > + <SPACE: " " | "\f" | "\n" | "\r" | "\t"> > +} > + > +<*> > +MORE: { > + <COMMENT_START: "/*"> { if (curLexState != IN_COMMENT) > pushState(IN_COMMENT); } > +} > + > +<IN_COMMENT> > +MORE: { > + <(~[])> > +| <COMMENT_END: ("\n" | "\r" | "\r\n")> { popState(); } > +} > + > +<IN_DQUOTE,IN_SQUOTE> > +TOKEN: { > + <ESCAPED: "\\" ["r", "n", "b", "t", "f"]> > +} > + > +<IN_DQUOTE> > +TOKEN: { > + <END_DQUOTE: "\""> { popState(); } > +} > + > +<IN_SQUOTE> > +TOKEN: { > + <ESCAPE_SQUOTE: "''"> > +| <END_SQUOTE: "'"> { popState(); } > +} > + > +<DEFAULT,IN_DQUOTE,IN_SQUOTE> > +TOKEN: { > + <TEXT: (~[])> > +} > + > +// ------------------- > + > + > +SQLSelect Select(): > +{ > + EntityCondition condition; > + int i; > + DynamicViewEntity dve = new DynamicViewEntity(); > +} > +{ > + <SELECT> FieldDefs(dve) > + <FROM> Table(dve) > + ( <WHERE> condition=ConditionExpression() > { jjtThis.setWhereCondition(condition); } )? > + ( <HAVING> condition=ConditionExpression() > { jjtThis.setHavingCondition(condition); } )? > + ( <GROUP> <BY> FieldList() )? > + ( <ORDER> <BY> FieldList() )? > + ( <OFFSET> i=Integer() { jjtThis.setOffset(i); } )? > + ( <LIMIT> i=Integer() { jjtThis.setLimit(i); } )? > + <SEMI> > + { return jjtThis; } > +} > +/* > +CSSUpdate Update(): > +{} > +{ > + <UPDATE> Table() > + ( Set() )+ > + ( <FROM> TableList() )? > + ( <WHERE> ConditionExpression() )? > + <SEMI> > +} > + > +CSSDelete Delete(): > +{} > +{ > + <DELETE> <FROM> Table() > + ( <USING> TableList() )? > + ( <WHERE> ConditionExpression() )? > + <SEMI> > +} > +*/ > + > +private void Table(DynamicViewEntity dve) #void: > +{ > + String leftAlias, rightAlias; > + Boolean relOptional; > + Set<String> availableAliases = FastSet.newInstance(); > + List<ModelKeyMap> keyMaps; > +} > +{ > + leftAlias=TableName(dve) { availableAliases.add(leftAlias); } > + ( > + relOptional=Joiner() rightAlias=TableName(dve) > { availableAliases.add(rightAlias); } > + <ON> keyMaps=KeyMaps(leftAlias, rightAlias) { > + dve.addViewLink(leftAlias, rightAlias, relOptional, keyMaps); > + } > + > + )* > + > +} > + > +private List<ModelKeyMap> KeyMaps(String leftAlias, String > rightAlias) #void: > +{ > + List<ModelKeyMap> keyMaps = FastList.newInstance(); > + ModelKeyMap keyMap; > +} > +{ > + keyMap=KeyMap(leftAlias, rightAlias) { keyMaps.add(keyMap); } > + ( <AND> keyMap=KeyMap(leftAlias, rightAlias) )* > { keyMaps.add(keyMap); } > + { return keyMaps; } > +} > + > +private ModelKeyMap KeyMap(String leftAlias, String rightAlias) > #void: > +{ > + String alias1, field1; > + String alias2, field2; > + EntityComparisonOperator op; > +} > +{ > + alias1=NamePart() <PERIOD> field1=NamePart() > + op=ComparisonOperator() > + alias2=NamePart() <PERIOD> field2=NamePart() > + { > + if (op != EntityOperator.EQUALS) throw new > IllegalArgumentException(op + " not supported"); > + if (alias1.equals(leftAlias)) { > + if (!alias2.equals(rightAlias)) throw new > IllegalArgumentException("invalid right alias(" + alias2 + "), > expected(" + rightAlias + ")"); > + return new ModelKeyMap(field1, field2); > + } else if (alias1.equals(rightAlias)) { > + if (!alias2.equals(leftAlias)) throw new > IllegalArgumentException("invalid left alias(" + alias2 + "), > expected(" + leftAlias + ")"); > + return new ModelKeyMap(field2, field1); > + } else { > + throw new IllegalArgumentException("invalid aliases, expected(" > + leftAlias + " or " + rightAlias + ")"); > + } > + } > +} > + > +private String TableName(DynamicViewEntity dve) #void: > +{ > + String name, alias = null; > +} > +{ > + name=NamePart() ( (<AS>)? alias=NamePart() )? > + { > + if (alias == null) alias = name; > + dve.addMemberEntity(alias, name); > + return alias; > + } > +} > + > +private Boolean Joiner() #void: > +{} > +{ > + <LEFT> <JOIN> { return Boolean.TRUE; } > +| <JOIN> { return Boolean.FALSE; } > +} > +private void FieldDefs(DynamicViewEntity dve) #void: > +{} > +{ > + FieldDef(dve) ( <COMMA> FieldDef(dve) )* > +} > + > +private void FieldDef(DynamicViewEntity dve) #void: > +{} > +{ > + LOOKAHEAD(AllField()) AllField(dve) > +| FieldSpec(dve) > +} > + > +private void AllField(DynamicViewEntity dve) #void: > +{ > + String n; > +} > +{ > + n=NamePart() <PERIOD> > + <STAR> > + { dve.addAliasAll(n, null); } > +} > + > +private String NamePart() #void: > +{} > +{ > + ( LOOKAHEAD(2) <NAME>)+ { return getToken(0).image; } > +} > + > +private void FieldSpec(DynamicViewEntity dve) #void: > +{ > + List<String> fieldUse; > + String tableAlias, fieldName, fieldAlias = null; > +} > +{ > + tableAlias=NamePart() <PERIOD> fieldName=NamePart() > + ( <AS> fieldAlias=NamePart() )? > + { > + if (fieldAlias == null) { > + dve.addAlias(tableAlias, fieldName); > + } else { > + dve.addAlias(tableAlias, fieldAlias, fieldName, null, null, > null, null); > + } > + } > +} > + > +private String DQuoted() #void: > +{ StringBuilder sb = new StringBuilder(); } > +{ > + <START_DQUOTE> (<TEXT> { sb.append(getToken(0).image); } | > <ESCAPED> { sb.append(getToken(0).image); })* <END_DQUOTE> > + { return sb.toString(); } > +} > + > +private String SQuoted() #void: > +{ StringBuilder sb = new StringBuilder(); } > +{ > + <START_SQUOTE> ( > + <TEXT> { sb.append(getToken(0).image); } > + | <ESCAPED> { sb.append(getToken(0).image); } > + | <ESCAPE_SQUOTE> { sb.append("'"); } > + )* <END_SQUOTE> > + { return sb.toString(); } > +} > + > +private void FieldList(): > +{} > +{ > + FieldUse() ( <COMMA> FieldUse() )* > +} > + > +private List<String> FieldUse() #void: > +{ > + List<String> list = FastList.newInstance(); > + String s; > +} > +{ > + s=NamePart() { list.add(s); } > + ( <PERIOD> s=NamePart() { list.add(s); } )? > + { return list; } > +} > + > +private Integer Integer() #void: > +{} > +{ > + <INTEGER> { > + try { > + Converter<String, Integer> converter = > Converters.getConverter(String.class, Integer.class); > + return converter.convert(getToken(0).image); > + } catch (ClassNotFoundException e) { > + return null; > + } catch (ConversionException e) { > + return null; > + } > + } > +} > + > +private Object Expression() #void: > +{ > + EntityConditionValue ecv; > + String s; > + List<String> fieldUse; > + int i; > +} > +{ > + fieldUse=FieldUse() { > + if (fieldUse.size() == 1) return > EntityFieldValue.makeFieldValue(fieldUse.get(0)); > + if (fieldUse.size() == 2) return > EntityFieldValue.makeFieldValue(fieldUse.get(1), fieldUse.get(1), > null, null); > + return null; > +} > +| i=Integer() { return i; } > +| s=SQuoted() { return s; } > +} > + > +private EntityCondition ConditionExpression() #void: > +{ EntityCondition ec; } > +{ > + ec=AndExpression() { return ec; } > +} > + > +private EntityCondition AndExpression() #void: > +{ > + List<EntityCondition> list = FastList.newInstance(); > + EntityCondition ec; > +} > +{ > + ec=OrExpression() { list.add(ec); } > + ( <AND> ec=OrExpression() { list.add(ec); } )* > + { > + if (list.size() == 1) return list.get(0); > + return EntityCondition.makeCondition(list, EntityOperator.AND); > + } > +} > + > +private EntityCondition OrExpression() #void: > +{ > + List<EntityCondition> list = FastList.newInstance(); > + EntityCondition ec; > +} > +{ > + ec=BooleanExpression() { list.add(ec); } > + ( <OR> ec=BooleanExpression() { list.add(ec); } )* > + { > + if (list.size() == 1) return list.get(0); > + return EntityCondition.makeCondition(list, EntityOperator.OR); > + } > +} > + > +private EntityCondition BooleanExpression() #void: > +{ > + Object v1, v2; > + EntityComparisonOperator op; > +} > +{ > + v1=Expression() op=ComparisonOperator() v2=Expression() > + { return EntityCondition.makeCondition(v1, op, v2); } > +} > + > +private EntityComparisonOperator ComparisonOperator() #void: > +{} > +{ > + ( <TEXT> )+ { return > EntityOperator.lookupComparison(getToken(0).image); } > +} > > Added: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/ > SQLSelect.java > URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/SQLSelect.java?rev=835637&view=auto > = > = > = > = > = > = > = > = > ====================================================================== > --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/ > SQLSelect.java (added) > +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/ > SQLSelect.java Thu Nov 12 23:23:12 2009 > @@ -0,0 +1,116 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one > + * or more contributor license agreements. See the NOTICE file > + * distributed with this work for additional information > + * regarding copyright ownership. The ASF licenses this file > + * to you under the Apache License, Version 2.0 (the > + * "License"); you may not use this file except in compliance > + * with the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, > + * software distributed under the License is distributed on an > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > + * KIND, either express or implied. See the License for the > + * specific language governing permissions and limitations > + * under the License. > + */ > +package org.ofbiz.entity.sql; > + > +import org.ofbiz.entity.Delegator; > +import org.ofbiz.entity.GenericEntityException; > +import org.ofbiz.entity.condition.EntityCondition; > +import org.ofbiz.entity.model.DynamicViewEntity; > +import org.ofbiz.entity.util.EntityListIterator; > + > +public class SQLSelect extends SimpleNode { > + private DynamicViewEntity dve; > + private EntityCondition whereCondition; > + private EntityCondition havingCondition; > + private int offset = -1; > + private int limit = -1; > + > + public SQLSelect(int id) { > + super(id); > + } > + > + public SQLSelect(Parser p, int id) { > + super(p, id); > + } > + > + > + /** Accept the visitor. **/ > + public Object jjtAccept(ParserVisitor visitor, Object data) { > + return visitor.visit(this, data); > + } > + > + public EntityListIterator getEntityListIterator(Delegator > delegator) throws GenericEntityException { > + return delegator.findListIteratorByCondition(dve, > whereCondition, havingCondition, null, null, null); > + } > + > + void setDynamicViewEntity(DynamicViewEntity dve) { > + this.dve = dve; > + } > + > + public DynamicViewEntity getDynamicViewEntity() { > + return dve; > + } > + > + void setWhereCondition(EntityCondition whereCondition) { > + this.whereCondition = whereCondition; > + } > + > + public EntityCondition getWhereCondition() { > + return whereCondition; > + } > + > + void setHavingCondition(EntityCondition havingCondition) { > + this.havingCondition = havingCondition; > + } > + > + public EntityCondition getHavingCondition() { > + return havingCondition; > + } > + > + void setOffset(int offset) { > + this.offset = offset; > + } > + > + public int getOffset() { > + return offset; > + } > + > + void setLimit(int limit) { > + this.limit = limit; > + } > + > + public int getLimit() { > + return limit; > + } > + > + public String toString() { > + StringBuilder sb = new StringBuilder(); > + sb.append("dve=" + dve); > + if (whereCondition != null) { > + if (sb.length() > 0) sb.append(", "); > + sb.append("where=(").append(whereCondition).append(")"); > + } > + if (havingCondition != null) { > + if (sb.length() > 0) sb.append(", "); > + > sb.append("having=(").append(havingCondition).append(")"); > + } > + if (offset != -1) { > + if (sb.length() > 0) sb.append(", "); > + sb.append("offset=").append(offset); > + } > + if (limit != -1) { > + if (sb.length() > 0) sb.append(", "); > + sb.append("limit=").append(limit); > + } > + sb.append("]"); > + sb.insert(0, "[").insert(0, super.toString()); > + return sb.toString(); > + } > +} > +/* JavaCC - OriginalChecksum=49309c1a721b16d029f160d2568a03bc (do > not edit this line) */ > > smime.p7s (4K) Download Attachment |
Scott Gray wrote:
> Hi Adam, > > What exactly does this do? In a nutshell, and just to get you guys all excited and wet, here's the string I've been testing this with: == select a.*, b.firstName, b.lastName FROM Party a JOIN Person b ON a.partyId = b.partyId WHERE a.partyId='foo' OFFSET 5 LIMIT 10 ; == ps: My previous versions of this were based on an oracle grammar, that had no real license applied. This new version I wrote completely from scratch today, based on my knowledge of javacc/jjtree, and postgres sql syntax. |
In reply to this post by Scott Gray-2
I'm wondering that too.
Btw, in the "classic" visitor pattern, the code should be: /** Accept the visitor. **/ public Object jjtAccept(ParserVisitor visitor) { return visitor.visit(this); } The SQLSelect class shouldn't be concerned with (or know about) Object data. -Adrian Scott Gray wrote: > Hi Adam, > > What exactly does this do? > > Thanks > Scott > > HotWax Media > http://www.hotwaxmedia.com > > On 13/11/2009, at 12:23 PM, [hidden email] wrote: > >> Author: doogie >> Date: Thu Nov 12 23:23:12 2009 >> New Revision: 835637 >> >> URL: http://svn.apache.org/viewvc?rev=835637&view=rev >> Log: >> Start of new sql parsing code. Not completely tested. It *does* parse >> a test SELECT; what is not tested is actually running the built >> DynamicViewEntity. >> >> Added: >> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/ >> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/Parser.jjt >> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/SQLSelect.java >> Modified: >> ofbiz/trunk/framework/entity/build.xml >> >> Modified: ofbiz/trunk/framework/entity/build.xml >> URL: >> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/build.xml?rev=835637&r1=835636&r2=835637&view=diff >> >> ============================================================================== >> >> --- ofbiz/trunk/framework/entity/build.xml (original) >> +++ ofbiz/trunk/framework/entity/build.xml Thu Nov 12 23:23:12 2009 >> @@ -38,6 +38,10 @@ >> <fileset dir="../base/lib/scripting" includes="*.jar"/> >> <fileset dir="../base/build/lib" includes="*.jar"/> >> </path> >> + <path id="src-path"> >> + <pathelement location="build/gen-src/javacc"/> >> + <pathelement location="build/gen-src/jjtree"/> >> + </path> >> >> <patternset id="src.exc.set"> >> <exclude >> name="org/ofbiz/entity/connection/XaPoolConnectionFactory.java"/> >> @@ -48,7 +52,11 @@ >> <!-- Compilation of the source >> files >> --> >> <!-- >> ================================================================== --> >> >> - <target name="classes" depends="prepare"> >> + <target name="gen-src"> >> + <ofbiz-jjtree dir="org/ofbiz/entity/sql" file="Parser"/> >> + </target> >> + >> + <target name="classes" depends="prepare,gen-src"> >> <javac15/> >> </target> >> >> >> Added: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/Parser.jjt >> URL: >> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/Parser.jjt?rev=835637&view=auto >> >> ============================================================================== >> >> --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/Parser.jjt >> (added) >> +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/Parser.jjt >> Thu Nov 12 23:23:12 2009 >> @@ -0,0 +1,414 @@ >> +options { >> + JAVA_UNICODE_ESCAPE = false; >> + ERROR_REPORTING = true; >> + STATIC = false; >> + MULTI = true; >> + JDK_VERSION = "1.5"; >> + VISITOR = true; >> + BUILD_NODE_FILES = true; >> + NODE_FACTORY = false; >> + NODE_USES_PARSER = true; >> +// NODE_SCOPE_HOOK = true; >> + NODE_PREFIX = "SQL"; >> +// DEBUG_PARSER = true; >> +// DEBUG_LOOKAHEAD = true; >> +// DEBUG_TOKEN_MANAGER = true; >> + LOOKAHEAD = 1; >> +// CHOICE_AMBIGUITY_CHECK = 3; >> +// OTHER_AMBIGUITY_CHECK = 3; >> + IGNORE_CASE = true; >> +} >> +PARSER_BEGIN(Parser) >> + >> +package org.ofbiz.entity.sql; >> + >> +import java.io.*; >> +import java.util.List; >> +import java.util.LinkedList; >> +import java.util.Set; >> + >> +import javolution.util.FastList; >> +import javolution.util.FastSet; >> + >> +import org.ofbiz.base.conversion.ConversionException; >> +import org.ofbiz.base.conversion.Converter; >> +import org.ofbiz.base.conversion.Converters; >> +import org.ofbiz.entity.condition.EntityComparisonOperator; >> +import org.ofbiz.entity.condition.EntityCondition; >> +import org.ofbiz.entity.condition.EntityConditionValue; >> +import org.ofbiz.entity.condition.EntityFieldValue; >> +import org.ofbiz.entity.condition.EntityOperator; >> +import org.ofbiz.entity.model.DynamicViewEntity; >> +import org.ofbiz.entity.model.ModelKeyMap; >> + >> +public class Parser { >> +} >> + >> +PARSER_END(Parser) >> +TOKEN_MGR_DECLS: { >> + private final LinkedList<Integer> stack = new LinkedList<Integer>(); >> + >> + void pushState(int newState) { >> + stack.add(curLexState); >> + SwitchTo(newState); >> + } >> + >> + void popState() { >> + SwitchTo(stack.removeLast()); >> + } >> +} >> + >> +TOKEN: { >> + <OPEN_PAREN: "("> >> +| <CLOSE_PAREN: ")"> >> +| <AND: "AND"> >> +| <OR: "OR"> >> +| <PERIOD: "."> >> +| <JOIN: "JOIN"> >> +| <LEFT: "LEFT"> >> +| <RIGHT: "RIGHT"> >> +| <AS: "AS"> >> +| <WHERE: "WHERE"> >> +| <HAVING: "HAVING"> >> +| <GROUP: "GROUP"> >> +| <ORDER: "ORDER"> >> +| <UNION: "UNION"> >> +| <BY: "BY"> >> +| <ON: "ON"> >> +| <LIMIT: "LIMIT"> >> +| <OFFSET: "OFFSET"> >> +| <SELECT: "SELECT"> >> +| <DELETE: "DELETE"> >> +| <UPDATE: "UPDATE"> >> +| <SET: "SET"> >> +| <FROM: "FROM"> >> +| <SEMI: ";"> >> +| <STAR: "*"> >> +| <COMMA: ","> >> +| <START_DQUOTE: "\""> { pushState(IN_DQUOTE); } >> +| <START_SQUOTE: "'"> { pushState(IN_SQUOTE); } >> +| <INTEGER: >> + "0" ( >> + "x" (["0"-"9","a"-"b"])+ >> + | (["0"-"7"])+ >> + ) >> + | ["1"-"9"] (["0"-"9"])* >> + > >> +| <NAME: (["a"-"z"])+> >> +//| <WORD: (~["'", "\"", "/", " ", "\f", "\n", "\r", "\t", "*"])+> >> +} >> + >> +<DEFAULT> >> +SKIP: { >> + <SPACE: " " | "\f" | "\n" | "\r" | "\t"> >> +} >> + >> +<*> >> +MORE: { >> + <COMMENT_START: "/*"> { if (curLexState != IN_COMMENT) >> pushState(IN_COMMENT); } >> +} >> + >> +<IN_COMMENT> >> +MORE: { >> + <(~[])> >> +| <COMMENT_END: ("\n" | "\r" | "\r\n")> { popState(); } >> +} >> + >> +<IN_DQUOTE,IN_SQUOTE> >> +TOKEN: { >> + <ESCAPED: "\\" ["r", "n", "b", "t", "f"]> >> +} >> + >> +<IN_DQUOTE> >> +TOKEN: { >> + <END_DQUOTE: "\""> { popState(); } >> +} >> + >> +<IN_SQUOTE> >> +TOKEN: { >> + <ESCAPE_SQUOTE: "''"> >> +| <END_SQUOTE: "'"> { popState(); } >> +} >> + >> +<DEFAULT,IN_DQUOTE,IN_SQUOTE> >> +TOKEN: { >> + <TEXT: (~[])> >> +} >> + >> +// ------------------- >> + >> + >> +SQLSelect Select(): >> +{ >> + EntityCondition condition; >> + int i; >> + DynamicViewEntity dve = new DynamicViewEntity(); >> +} >> +{ >> + <SELECT> FieldDefs(dve) >> + <FROM> Table(dve) >> + ( <WHERE> condition=ConditionExpression() { >> jjtThis.setWhereCondition(condition); } )? >> + ( <HAVING> condition=ConditionExpression() { >> jjtThis.setHavingCondition(condition); } )? >> + ( <GROUP> <BY> FieldList() )? >> + ( <ORDER> <BY> FieldList() )? >> + ( <OFFSET> i=Integer() { jjtThis.setOffset(i); } )? >> + ( <LIMIT> i=Integer() { jjtThis.setLimit(i); } )? >> + <SEMI> >> + { return jjtThis; } >> +} >> +/* >> +CSSUpdate Update(): >> +{} >> +{ >> + <UPDATE> Table() >> + ( Set() )+ >> + ( <FROM> TableList() )? >> + ( <WHERE> ConditionExpression() )? >> + <SEMI> >> +} >> + >> +CSSDelete Delete(): >> +{} >> +{ >> + <DELETE> <FROM> Table() >> + ( <USING> TableList() )? >> + ( <WHERE> ConditionExpression() )? >> + <SEMI> >> +} >> +*/ >> + >> +private void Table(DynamicViewEntity dve) #void: >> +{ >> + String leftAlias, rightAlias; >> + Boolean relOptional; >> + Set<String> availableAliases = FastSet.newInstance(); >> + List<ModelKeyMap> keyMaps; >> +} >> +{ >> + leftAlias=TableName(dve) { availableAliases.add(leftAlias); } >> + ( >> + relOptional=Joiner() rightAlias=TableName(dve) { >> availableAliases.add(rightAlias); } >> + <ON> keyMaps=KeyMaps(leftAlias, rightAlias) { >> + dve.addViewLink(leftAlias, rightAlias, relOptional, >> keyMaps); >> + } >> + >> + )* >> + >> +} >> + >> +private List<ModelKeyMap> KeyMaps(String leftAlias, String >> rightAlias) #void: >> +{ >> + List<ModelKeyMap> keyMaps = FastList.newInstance(); >> + ModelKeyMap keyMap; >> +} >> +{ >> + keyMap=KeyMap(leftAlias, rightAlias) { keyMaps.add(keyMap); } >> + ( <AND> keyMap=KeyMap(leftAlias, rightAlias) )* { >> keyMaps.add(keyMap); } >> + { return keyMaps; } >> +} >> + >> +private ModelKeyMap KeyMap(String leftAlias, String rightAlias) #void: >> +{ >> + String alias1, field1; >> + String alias2, field2; >> + EntityComparisonOperator op; >> +} >> +{ >> + alias1=NamePart() <PERIOD> field1=NamePart() >> + op=ComparisonOperator() >> + alias2=NamePart() <PERIOD> field2=NamePart() >> + { >> + if (op != EntityOperator.EQUALS) throw new >> IllegalArgumentException(op + " not supported"); >> + if (alias1.equals(leftAlias)) { >> + if (!alias2.equals(rightAlias)) throw new >> IllegalArgumentException("invalid right alias(" + alias2 + "), >> expected(" + rightAlias + ")"); >> + return new ModelKeyMap(field1, field2); >> + } else if (alias1.equals(rightAlias)) { >> + if (!alias2.equals(leftAlias)) throw new >> IllegalArgumentException("invalid left alias(" + alias2 + "), >> expected(" + leftAlias + ")"); >> + return new ModelKeyMap(field2, field1); >> + } else { >> + throw new IllegalArgumentException("invalid aliases, >> expected(" + leftAlias + " or " + rightAlias + ")"); >> + } >> + } >> +} >> + >> +private String TableName(DynamicViewEntity dve) #void: >> +{ >> + String name, alias = null; >> +} >> +{ >> + name=NamePart() ( (<AS>)? alias=NamePart() )? >> + { >> + if (alias == null) alias = name; >> + dve.addMemberEntity(alias, name); >> + return alias; >> + } >> +} >> + >> +private Boolean Joiner() #void: >> +{} >> +{ >> + <LEFT> <JOIN> { return Boolean.TRUE; } >> +| <JOIN> { return Boolean.FALSE; } >> +} >> +private void FieldDefs(DynamicViewEntity dve) #void: >> +{} >> +{ >> + FieldDef(dve) ( <COMMA> FieldDef(dve) )* >> +} >> + >> +private void FieldDef(DynamicViewEntity dve) #void: >> +{} >> +{ >> + LOOKAHEAD(AllField()) AllField(dve) >> +| FieldSpec(dve) >> +} >> + >> +private void AllField(DynamicViewEntity dve) #void: >> +{ >> + String n; >> +} >> +{ >> + n=NamePart() <PERIOD> >> + <STAR> >> + { dve.addAliasAll(n, null); } >> +} >> + >> +private String NamePart() #void: >> +{} >> +{ >> + ( LOOKAHEAD(2) <NAME>)+ { return getToken(0).image; } >> +} >> + >> +private void FieldSpec(DynamicViewEntity dve) #void: >> +{ >> + List<String> fieldUse; >> + String tableAlias, fieldName, fieldAlias = null; >> +} >> +{ >> + tableAlias=NamePart() <PERIOD> fieldName=NamePart() >> + ( <AS> fieldAlias=NamePart() )? >> + { >> + if (fieldAlias == null) { >> + dve.addAlias(tableAlias, fieldName); >> + } else { >> + dve.addAlias(tableAlias, fieldAlias, fieldName, null, >> null, null, null); >> + } >> + } >> +} >> + >> +private String DQuoted() #void: >> +{ StringBuilder sb = new StringBuilder(); } >> +{ >> + <START_DQUOTE> (<TEXT> { sb.append(getToken(0).image); } | >> <ESCAPED> { sb.append(getToken(0).image); })* <END_DQUOTE> >> + { return sb.toString(); } >> +} >> + >> +private String SQuoted() #void: >> +{ StringBuilder sb = new StringBuilder(); } >> +{ >> + <START_SQUOTE> ( >> + <TEXT> { sb.append(getToken(0).image); } >> + | <ESCAPED> { sb.append(getToken(0).image); } >> + | <ESCAPE_SQUOTE> { sb.append("'"); } >> + )* <END_SQUOTE> >> + { return sb.toString(); } >> +} >> + >> +private void FieldList(): >> +{} >> +{ >> + FieldUse() ( <COMMA> FieldUse() )* >> +} >> + >> +private List<String> FieldUse() #void: >> +{ >> + List<String> list = FastList.newInstance(); >> + String s; >> +} >> +{ >> + s=NamePart() { list.add(s); } >> + ( <PERIOD> s=NamePart() { list.add(s); } )? >> + { return list; } >> +} >> + >> +private Integer Integer() #void: >> +{} >> +{ >> + <INTEGER> { >> + try { >> + Converter<String, Integer> converter = >> Converters.getConverter(String.class, Integer.class); >> + return converter.convert(getToken(0).image); >> + } catch (ClassNotFoundException e) { >> + return null; >> + } catch (ConversionException e) { >> + return null; >> + } >> + } >> +} >> + >> +private Object Expression() #void: >> +{ >> + EntityConditionValue ecv; >> + String s; >> + List<String> fieldUse; >> + int i; >> +} >> +{ >> + fieldUse=FieldUse() { >> + if (fieldUse.size() == 1) return >> EntityFieldValue.makeFieldValue(fieldUse.get(0)); >> + if (fieldUse.size() == 2) return >> EntityFieldValue.makeFieldValue(fieldUse.get(1), fieldUse.get(1), >> null, null); >> + return null; >> +} >> +| i=Integer() { return i; } >> +| s=SQuoted() { return s; } >> +} >> + >> +private EntityCondition ConditionExpression() #void: >> +{ EntityCondition ec; } >> +{ >> + ec=AndExpression() { return ec; } >> +} >> + >> +private EntityCondition AndExpression() #void: >> +{ >> + List<EntityCondition> list = FastList.newInstance(); >> + EntityCondition ec; >> +} >> +{ >> + ec=OrExpression() { list.add(ec); } >> + ( <AND> ec=OrExpression() { list.add(ec); } )* >> + { >> + if (list.size() == 1) return list.get(0); >> + return EntityCondition.makeCondition(list, EntityOperator.AND); >> + } >> +} >> + >> +private EntityCondition OrExpression() #void: >> +{ >> + List<EntityCondition> list = FastList.newInstance(); >> + EntityCondition ec; >> +} >> +{ >> + ec=BooleanExpression() { list.add(ec); } >> + ( <OR> ec=BooleanExpression() { list.add(ec); } )* >> + { >> + if (list.size() == 1) return list.get(0); >> + return EntityCondition.makeCondition(list, EntityOperator.OR); >> + } >> +} >> + >> +private EntityCondition BooleanExpression() #void: >> +{ >> + Object v1, v2; >> + EntityComparisonOperator op; >> +} >> +{ >> + v1=Expression() op=ComparisonOperator() v2=Expression() >> + { return EntityCondition.makeCondition(v1, op, v2); } >> +} >> + >> +private EntityComparisonOperator ComparisonOperator() #void: >> +{} >> +{ >> + ( <TEXT> )+ { return >> EntityOperator.lookupComparison(getToken(0).image); } >> +} >> >> Added: >> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/SQLSelect.java >> URL: >> http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/SQLSelect.java?rev=835637&view=auto >> >> ============================================================================== >> >> --- >> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/SQLSelect.java >> (added) >> +++ >> ofbiz/trunk/framework/entity/src/org/ofbiz/entity/sql/SQLSelect.java >> Thu Nov 12 23:23:12 2009 >> @@ -0,0 +1,116 @@ >> +/* >> + * Licensed to the Apache Software Foundation (ASF) under one >> + * or more contributor license agreements. See the NOTICE file >> + * distributed with this work for additional information >> + * regarding copyright ownership. The ASF licenses this file >> + * to you under the Apache License, Version 2.0 (the >> + * "License"); you may not use this file except in compliance >> + * with the License. You may obtain a copy of the License at >> + * >> + * http://www.apache.org/licenses/LICENSE-2.0 >> + * >> + * Unless required by applicable law or agreed to in writing, >> + * software distributed under the License is distributed on an >> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >> + * KIND, either express or implied. See the License for the >> + * specific language governing permissions and limitations >> + * under the License. >> + */ >> +package org.ofbiz.entity.sql; >> + >> +import org.ofbiz.entity.Delegator; >> +import org.ofbiz.entity.GenericEntityException; >> +import org.ofbiz.entity.condition.EntityCondition; >> +import org.ofbiz.entity.model.DynamicViewEntity; >> +import org.ofbiz.entity.util.EntityListIterator; >> + >> +public class SQLSelect extends SimpleNode { >> + private DynamicViewEntity dve; >> + private EntityCondition whereCondition; >> + private EntityCondition havingCondition; >> + private int offset = -1; >> + private int limit = -1; >> + >> + public SQLSelect(int id) { >> + super(id); >> + } >> + >> + public SQLSelect(Parser p, int id) { >> + super(p, id); >> + } >> + >> + >> + /** Accept the visitor. **/ >> + public Object jjtAccept(ParserVisitor visitor, Object data) { >> + return visitor.visit(this, data); >> + } >> + >> + public EntityListIterator getEntityListIterator(Delegator >> delegator) throws GenericEntityException { >> + return delegator.findListIteratorByCondition(dve, >> whereCondition, havingCondition, null, null, null); >> + } >> + >> + void setDynamicViewEntity(DynamicViewEntity dve) { >> + this.dve = dve; >> + } >> + >> + public DynamicViewEntity getDynamicViewEntity() { >> + return dve; >> + } >> + >> + void setWhereCondition(EntityCondition whereCondition) { >> + this.whereCondition = whereCondition; >> + } >> + >> + public EntityCondition getWhereCondition() { >> + return whereCondition; >> + } >> + >> + void setHavingCondition(EntityCondition havingCondition) { >> + this.havingCondition = havingCondition; >> + } >> + >> + public EntityCondition getHavingCondition() { >> + return havingCondition; >> + } >> + >> + void setOffset(int offset) { >> + this.offset = offset; >> + } >> + >> + public int getOffset() { >> + return offset; >> + } >> + >> + void setLimit(int limit) { >> + this.limit = limit; >> + } >> + >> + public int getLimit() { >> + return limit; >> + } >> + >> + public String toString() { >> + StringBuilder sb = new StringBuilder(); >> + sb.append("dve=" + dve); >> + if (whereCondition != null) { >> + if (sb.length() > 0) sb.append(", "); >> + sb.append("where=(").append(whereCondition).append(")"); >> + } >> + if (havingCondition != null) { >> + if (sb.length() > 0) sb.append(", "); >> + sb.append("having=(").append(havingCondition).append(")"); >> + } >> + if (offset != -1) { >> + if (sb.length() > 0) sb.append(", "); >> + sb.append("offset=").append(offset); >> + } >> + if (limit != -1) { >> + if (sb.length() > 0) sb.append(", "); >> + sb.append("limit=").append(limit); >> + } >> + sb.append("]"); >> + sb.insert(0, "[").insert(0, super.toString()); >> + return sb.toString(); >> + } >> +} >> +/* JavaCC - OriginalChecksum=49309c1a721b16d029f160d2568a03bc (do not >> edit this line) */ >> >> > |
Adrian Crum wrote:
> I'm wondering that too. > > Btw, in the "classic" visitor pattern, the code should be: > > /** Accept the visitor. **/ > public Object jjtAccept(ParserVisitor visitor) { > return visitor.visit(this); > } > > The SQLSelect class shouldn't be concerned with (or know about) Object > data. I can't change that. jjtree auto-generates missing node classes, and this is the pattern is uses. I only have to override the nodes that need special functionality. |
In reply to this post by Adam Heath-2
I'd be careful with the limit/offset, support tends to vary among
vendors, e.g. http://blogs.sun.com/kah/entry/derby_10_5_preview_fetch I like the concept, but to be honest I have to deal with raw sql so rarely these days that given the choice I probably wouldn't use it. Regards Scott On 13/11/2009, at 12:43 PM, Adam Heath wrote: > Scott Gray wrote: >> Hi Adam, >> >> What exactly does this do? > > In a nutshell, and just to get you guys all excited and wet, here's > the string I've been testing this with: > == > select > a.*, > b.firstName, > b.lastName > FROM > Party a JOIN Person b ON a.partyId = b.partyId > WHERE > a.partyId='foo' > OFFSET 5 > LIMIT 10 > ; > == > > ps: My previous versions of this were based on an oracle grammar, that > had no real license applied. This new version I wrote completely from > scratch today, based on my knowledge of javacc/jjtree, and postgres > sql syntax. smime.p7s (4K) Download Attachment |
In reply to this post by Adam Heath-2
Adam Heath wrote:
> Adrian Crum wrote: >> I'm wondering that too. >> >> Btw, in the "classic" visitor pattern, the code should be: >> >> /** Accept the visitor. **/ >> public Object jjtAccept(ParserVisitor visitor) { >> return visitor.visit(this); >> } >> >> The SQLSelect class shouldn't be concerned with (or know about) Object >> data. > > I can't change that. jjtree auto-generates missing node classes, and > this is the pattern is uses. I only have to override the nodes that > need special functionality. Thanks. I figured that out after I pressed Send. |
In reply to this post by Scott Gray-2
Scott Gray wrote:
> I'd be careful with the limit/offset, support tends to vary among > vendors, e.g. http://blogs.sun.com/kah/entry/derby_10_5_preview_fetch You are mistaken. This does *not* send raw sql to the database. It parses the sql into a DynamicViewEntity, which ofbiz then reconverts back to whatever sql dialect is required by the underlying database. Offset/limit can be completely handled in java. Besides, I currently don't have them fully implemented. And EntityFindOptions has a maxRows option. > I like the concept, but to be honest I have to deal with raw sql so > rarely these days that given the choice I probably wouldn't use it. Which is easier; editting a <view-entity> xml definition, or creating a sql string? Consider the case when you have option parts of a query you have to deal with. In addition, I'll be adding helper methods to parse *just* entity conditions. It's mostly there, I just haven't made the methods public. |
On 13/11/2009, at 1:10 PM, Adam Heath wrote:
> Scott Gray wrote: >> I'd be careful with the limit/offset, support tends to vary among >> vendors, e.g. http://blogs.sun.com/kah/entry/derby_10_5_preview_fetch > > You are mistaken. This does *not* send raw sql to the database. It > parses the sql into a DynamicViewEntity, which ofbiz then reconverts > back to whatever sql dialect is required by the underlying database. > Offset/limit can be completely handled in java. > > Besides, I currently don't have them fully implemented. And > EntityFindOptions has a maxRows option. just trying to point out that offset isn't currently supported by the entity engine and that adding support for it could be problematic. > >> I like the concept, but to be honest I have to deal with raw sql so >> rarely these days that given the choice I probably wouldn't use it. > > Which is easier; editting a <view-entity> xml definition, or creating > a sql string? Consider the case when you have option parts of a query > you have to deal with. > > In addition, I'll be adding helper methods to parse *just* entity > conditions. It's mostly there, I just haven't made the methods > public. could be useful there in some situations, but will these sql statements be reusable in the same way that view entities are? Also I actually like the java-ness of constructing dynamic view entities rather that building a string, it makes the code easier to read IMO. smime.p7s (4K) Download Attachment |
Scott Gray wrote:
> I could see that it doesn't send the raw sql to the database I was just > trying to point out that offset isn't currently supported by the entity > engine and that adding support for it could be problematic. Offset is simple, relatively. Just need to issue a bunch of rs.next() calls early, and then a flag to EntityListIterator to forbid calling rs.previous() past the beginning. > I agree view-entity definitions can at times be quite verbose and it > could be useful there in some situations, but will these sql statements > be reusable in the same way that view entities are? Also I actually > like the java-ness of constructing dynamic view entities rather that > building a string, it makes the code easier to read IMO. Absolutely. It's rather trival to extend the parser, to have multiple selects defined in some global .sql file, giving each a NAME, then also extending the condition parser to have a ?NAME type syntax. Maybe using this api(brainstorming): eli = EntitySql.getListIterator(delegator, "path/to/resource.sql", "my-special-query", Map<String, Object> params) |
In reply to this post by Adrian Crum
Adam,
I just committed a minor change to the Converters class that will help simplify your code. You can create a static instance of StringToInteger and eliminate the factory method call. The factory method is intended to be used when you don't know the source and target classes at compile time. -Adrian Adrian Crum wrote: > Adam Heath wrote: >> Adrian Crum wrote: >>> I'm wondering that too. >>> >>> Btw, in the "classic" visitor pattern, the code should be: >>> >>> /** Accept the visitor. **/ >>> public Object jjtAccept(ParserVisitor visitor) { >>> return visitor.visit(this); >>> } >>> >>> The SQLSelect class shouldn't be concerned with (or know about) Object >>> data. >> >> I can't change that. jjtree auto-generates missing node classes, and >> this is the pattern is uses. I only have to override the nodes that >> need special functionality. > > Thanks. I figured that out after I pressed Send. > > |
In reply to this post by Adam Heath-2
On 13/11/2009, at 1:27 PM, Adam Heath wrote:
> Scott Gray wrote: >> I could see that it doesn't send the raw sql to the database I was >> just >> trying to point out that offset isn't currently supported by the >> entity >> engine and that adding support for it could be problematic. > > Offset is simple, relatively. Just need to issue a bunch of rs.next() > calls early, and then a flag to EntityListIterator to forbid calling > rs.previous() past the beginning. advantage I see to using offset is to avoid the need to stream unneeded results, especially for jdbc drivers that don't support cursors. > >> I agree view-entity definitions can at times be quite verbose and it >> could be useful there in some situations, but will these sql >> statements >> be reusable in the same way that view entities are? Also I actually >> like the java-ness of constructing dynamic view entities rather that >> building a string, it makes the code easier to read IMO. > > Absolutely. It's rather trival to extend the parser, to have multiple > selects defined in some global .sql file, giving each a NAME, then > also extending the condition parser to have a ?NAME type syntax. > > Maybe using this api(brainstorming): > > eli = EntitySql.getListIterator(delegator, "path/to/resource.sql", > "my-special-query", Map<String, Object> params) generating a view entity xml definition from a sql query. smime.p7s (4K) Download Attachment |
Scott Gray wrote:
> What would be cool and what I would use is a tool that is capable of > generating a view entity xml definition from a sql query. While not related at all to sql parsing, I just committed a good start at this in 835764. |
Free forum by Nabble | Edit this page |