Title: Message
The following is an example of the output from each phase when an 'implied join' is processed.  The hibernate mapping is enclosed.
 
Notes:
1) The 'booleanExpr=>' sub-tree is the resulting tree *after* the analyzer has added any theta-style join clauses.
2) It does not yet add the nodes to the 'FROM' part of the tree, but I'm working on that.
3) I wasn't able to find an API call to get the foreign key column name in the 'origin' part of the join (in this case, the alias 'foo'), hence the {highy-bogus-column-name} token.   ;)  Any hints?
 
HQL =>from eg.Foo foo
where foo.bar.name='Farrels'<=
--- HQL AST ---
 \-'query' [QUERY]
    +-'from' [FROM]
    |  +-'.' [DOT]
    |  |  +-'eg' [IDENT]
    |  |  \-'Foo' [IDENT]
    |  \-'foo' [ALIAS]
    \-'where' [WHERE]
       \-'=' [EQ]
          +-'.' [DOT]
          |  +-'.' [DOT]
          |  |  +-'foo' [IDENT]
          |  |  \-'bar' [IDENT]
          |  \-'name' [IDENT]
          \-''Farrels'' [QUOTED_STRING]
Dec 9, 2003 6:10:00 AM net.sf.hibernate.hql.parser.HqlSqlWalker createColumnRefNode
INFO: Discovered an implied join from eg.Foo.bar to eg.Bar
booleanExpr=>
 \-'AND' [AND]
    +-'=' [EQ]
    |  +-'foo.{highly-bogus-column-name}bar' [COLUMN_REF]
    |  \-'bar1_.ID' [COLUMN_REF]
    \-'=' [EQ]
       +-'bar1_.NAME' [COLUMN_REF]
       \-''Farrels'' [QUOTED_STRING]
--- SQL AST ---
 \-'select' [SELECT]
    +-'from' [FROM]
    |  \-'EG_FOOS AS foo' [TABLE_NAME]
    \-'where' [WHERE]
       \-'AND' [AND]
          +-'=' [EQ]
          |  +-'foo.{highly-bogus-column-name}bar' [COLUMN_REF]
          |  \-'bar1_.ID' [COLUMN_REF]
          \-'=' [EQ]
             +-'bar1_.NAME' [COLUMN_REF]
             \-''Farrels'' [QUOTED_STRING]
SQL =>SELECT * FROM EG_FOOS AS foo WHERE foo.{highly-bogus-column-name}bar = bar1_.ID AND bar1_.NAME = 'Farrels'<=
 
 

HQL =>from eg.Foo foo, eg.Bar bar where foo.bar.name='Farrels'<=
--- HQL AST ---
 \-'query' [QUERY]
    +-'from' [FROM]
    |  +-'.' [DOT]
    |  |  +-'eg' [IDENT]
    |  |  \-'Foo' [IDENT]
    |  +-'foo' [ALIAS]
    |  +-'.' [DOT]
    |  |  +-'eg' [IDENT]
    |  |  \-'Bar' [IDENT]
    |  \-'bar' [ALIAS]
    \-'where' [WHERE]
       \-'=' [EQ]
          +-'.' [DOT]
          |  +-'.' [DOT]
          |  |  +-'foo' [IDENT]
          |  |  \-'bar' [IDENT]
          |  \-'name' [IDENT]
          \-''Farrels'' [QUOTED_STRING]
booleanExpr=>
Dec 9, 2003 6:10:00 AM net.sf.hibernate.hql.parser.HqlSqlWalker createColumnRefNode
INFO: Discovered an implied join from eg.Foo.bar to eg.Bar
 \-'AND' [AND]
    +-'=' [EQ]
    |  +-'foo.{highly-bogus-column-name}bar' [COLUMN_REF]
    |  \-'bar.ID' [COLUMN_REF]
    \-'=' [EQ]
       +-'foo.NAME' [COLUMN_REF]
       \-''Farrels'' [QUOTED_STRING]
--- SQL AST ---
 \-'select' [SELECT]
    +-'from' [FROM]
    |  +-'EG_FOOS AS foo' [TABLE_NAME]
    |  \-'EG_BARS AS bar' [TABLE_NAME]
    \-'where' [WHERE]
       \-'AND' [AND]
          +-'=' [EQ]
          |  +-'foo.{highly-bogus-column-name}bar' [COLUMN_REF]
          |  \-'bar.ID' [COLUMN_REF]
          \-'=' [EQ]
             +-'foo.NAME' [COLUMN_REF]
             \-''Farrels'' [QUOTED_STRING]
SQL =>SELECT * FROM EG_FOOS AS foo, EG_BARS AS bar WHERE foo.{highly-bogus-column-name}bar = bar.ID AND foo.NAME = 'Farrels'<=
-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Joshua Davis
Sent: Monday, December 08, 2003 11:14 PM
To: [EMAIL PROTECTED]
Cc: 'Joshua Davis'
Subject: [Hibernate] AST parser for HQL

Hibernate programmers,
 
I've made some progress with the HQL parser, so here's an update:
 
Design decisions:
1) Use ANTLR to generate the parser.  It has a compatible Open Source licence, and adds only one new library dependency.
2) Use a three phase design:  parse/analyze/generate code - This is a very typical modular compiler design.  The parse phase is implemented as a stream parser, the analysis phase is implemented as a tree parser (tree transform, actually), and the code generation phase is a tree parser that produces an SQL stream.
3) Use the ANTLR generated parsers as base classes, implementing the main semantic / syntax analysis functions in derived classes.  This keeps the grammar files smaller, and alows me to use my favorite Java IDE to write the analysis code.
 
So, what's been done so far?
 
* An HQL grammar / parser which sucessfully parses most of the examples in the Hibernate HQL doco.  A few additional features have been added, as well as a unit test that exercises this phase.
 
* An HQL AST analyzer, which converts the HQL AST into an intermediate, SQL (ish) AST.  This is implemented as a tree parser which normalizes the HQL AST and binds the HQL AST elements to the appropriate Hibernate mapping API objects (e.g. Queryable, etc.).
 
* A very simplistic SQL generator, which walks the intermediate tree and produces an SQL stream.   This is primarly for testing, although it might come in handy later on when integrating all this into Hibernate.
 
* Some initial 'implied join' examples.
 
What's next?
 
* Get implied joins (and 'fake' AST generation to work).
 
* Utilize more of the existing Hibernate API for mappings.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "./resources/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
    <!--
    Hibernate note: Mapped classes should have the following elements, in order:
    1) <id> The primary key.
    2) <discriminator> The column used to distinguish between subclasses.
    3) <timestamp> If needed.
    4) <property> The properties, or attributes of the class.
    5) <many-to-one>, <one-to-many>, <many-to-many> Associations with other classes.
    5) <subclass> The subclasses.
    -->
    <class name="eg.Foo" table="EG_FOOS">
        <id name="id" type="long" unsaved-value="-1" >
            <column name="ID" not-null="true"/>
            <generator class="native">
                <param name="sequence">EG_SEQ</param>
            </generator>
        </id>
        <property name="name" column="NAME" type="string" not-null="true"/>
        <one-to-one name="bar" foreign-key="BARID" class="eg.Bar"/>
    </class>

    <class name="eg.Bar" table="EG_BARS">
        <id name="id" type="long" unsaved-value="-1" >
            <column name="ID" not-null="true"/>
            <generator class="native">
                <param name="sequence">EG_SEQ</param>
            </generator>
        </id>
        <property name="name" column="NAME" type="string" not-null="true"/>
    </class>
</hibernate-mapping>

Reply via email to