Package com.alvazan.orm.parser.antlr

Source Code of com.alvazan.orm.parser.antlr.ScannerSql

package com.alvazan.orm.parser.antlr;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTree;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alvazan.orm.api.z8spi.conv.StandardConverters;
import com.alvazan.orm.api.z8spi.conv.StorageTypeEnum;
import com.alvazan.orm.api.z8spi.meta.DboColumnIdMeta;
import com.alvazan.orm.api.z8spi.meta.DboColumnMeta;
import com.alvazan.orm.api.z8spi.meta.DboColumnToManyMeta;
import com.alvazan.orm.api.z8spi.meta.DboColumnToOneMeta;
import com.alvazan.orm.api.z8spi.meta.DboTableMeta;
import com.alvazan.orm.api.z8spi.meta.TypeInfo;
import com.alvazan.orm.api.z8spi.meta.ViewInfo;
import com.alvazan.orm.api.z8spi.meta.TypedColumn;

public class ScannerSql {

  private static final Logger log = LoggerFactory.getLogger(ScannerSql.class);
 
  @Inject
  private Optimizer optimizer;
 
  public ExpressionNode compileSql(String query, InfoForWiring wiring, MetaFacade facade) {
    CommonTree theTree = parseTree(query);
    walkTheTree(theTree, wiring, facade);
    validateNoPartitionsMissed(theTree, wiring);
    ExpressionNode node = wiring.getAstTree();
   
    facade.setAttributeUserCount(wiring.getAttributeUsedCount());
    ExpressionNode newTree = (ExpressionNode) optimizer.optimize(node, facade, query);
   
    return newTree;
  }
 
  private void validateNoPartitionsMissed(CommonTree theTree, InfoForWiring wiring) {
    ViewInfoImpl noAliasTable = wiring.getNoAliasTable();
    if(noAliasTable != null) {
      if(noAliasTable.getTableMeta().getPartitionedColumns().size() > 0)
        throw new IllegalArgumentException("In your from you have a table defined with no alias" +
            "(ie. no 'as p' part) and your table is partitioned so you " +
            "need to alias and then define PARTITIONS p(:partitionid) SELECT etc. etc.");
    }   
   
    for(ViewInfo view : wiring.getAllViews()) {
      ViewInfoImpl t = (ViewInfoImpl) view;
      DboTableMeta meta = t.getTableMeta();
      if(meta.getPartitionedColumns().size() > 0 && t.getPartition() == null)
        throw new IllegalArgumentException("You are missing a definition of a partition for alias='"+view.getAlias()+"' since table="
      +meta.getColumnFamily()+" IS a partitioned table.  For example, you should have PARTITIONS e(:partitionId) SELECT e FROM TABLE as e....");
    }
  }

  private static CommonTree parseTree(String query) {
        ANTLRStringStream stream = new ANTLRStringStream(query);
        NoSqlLexer lexer = new NoSqlLexer(stream);
        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
        NoSqlParser parser = new NoSqlParser(tokenStream);

        try {
          return (CommonTree) parser.statement().getTree();
        } catch (RecognitionException re) {
          ParseQueryException e = new ParseQueryException(" (Check the token after the one the parse complained about.  Are you missing the 'as' keyword", re);
          throw e;
        }
    }
 
  @SuppressWarnings("unchecked")
  private <T> void walkTheTree(CommonTree tree, InfoForWiring wiring, MetaFacade facade) {
    int type = tree.getType();
    switch (type) {
    //The tree should come in with this order OR we are in BIG TROUBLE as we need the information
    //in the from clause first to get alias and what table the alias maps too
    case NoSqlLexer.FROM_CLAUSE:
      compileFromClause(tree, wiring, facade);
      break;
    case NoSqlLexer.JOIN_CLAUSE:
      compileJoinClause(tree, wiring, facade);
      break;
    case NoSqlLexer.PARTITIONS_CLAUSE:
      compilePartitionsClause(tree, wiring, facade);
      break;
    case NoSqlLexer.SELECT_CLAUSE:
      compileSelectClause(tree, wiring);
      break;
    case NoSqlLexer.TABLE_CLAUSE:
      compileTableClause(tree, wiring, facade);
      break;
    case NoSqlLexer.WHERE:
      //We should try to get rid of the where token in the grammar so we don't need
      //this line of code here....
      CommonTree expression = (CommonTree)tree.getChildren().get(0);
      ExpressionNode node = new ExpressionNode(expression);
      compileExpression(node, wiring, facade);
      wiring.setAstTree(node);
      break;
    case NoSqlLexer.UPDATE_CLAUSE:
      compileUpdateClause(tree, wiring, facade);
      break;
    case NoSqlLexer.UPDATE:
      processUpdate(tree, wiring, facade);
      break;
    case NoSqlLexer.DELETE_COLUMN:
      compileDeleteColumnClause(tree, wiring, facade);
      break;
    case NoSqlLexer.DELETE:
      compileDeleteClause(wiring);
      break;
    case 0: // nil
      List<CommonTree> childrenList = tree.getChildren();
      for (CommonTree child : childrenList) {
        walkTheTree(child, wiring, facade);
      }
      break;
    default:
      break;
    }
  }

  @SuppressWarnings("unchecked")
  private <T> void compileJoinClause(CommonTree tree,
      InfoForWiring wiring, MetaFacade facade) {
    List<CommonTree> children = tree.getChildren();
   
    for(CommonTree child : children) {
      int type = child.getType();
      if(type == NoSqlLexer.LEFT_OUTER_JOIN) {
        compileJoin(child, wiring, facade, JoinType.LEFT_OUTER);
      } else if(type == NoSqlLexer.INNER_JOIN) {
        compileJoin(child, wiring, facade, JoinType.INNER);
      } else
        throw new UnsupportedOperationException("bug?, type="+type+" and we don't process that type for joins");
    }
  }
 
  @SuppressWarnings("unchecked")
  private <T> void compileJoin(CommonTree tree, InfoForWiring wiring, MetaFacade facade, JoinType type) {
    List<CommonTree> children = tree.getChildren();
    CommonTree aliasedColumn = children.get(0);
    CommonTree aliasNode = (CommonTree) aliasedColumn.getChild(0);
    CommonTree newAliasNode = children.get(1);
    String column = aliasedColumn.getText();
    String alias = aliasNode.getText();
    String newAlias = newAliasNode.getText();
   
    ViewInfoImpl tableInfo = wiring.getInfoFromAlias(alias);
    DboTableMeta tableMeta = tableInfo.getTableMeta();
    DboColumnMeta columnMeta = facade.getFkMetaIfExist(tableMeta, column);
    if(!(columnMeta instanceof DboColumnToOneMeta))
      throw new IllegalArgumentException("Column="+column+" on table="+tableMeta.getColumnFamily()+" is NOT a OneToOne NOR ManyToOne relationship according to our meta data");
    else if(!columnMeta.isIndexed())
      throw new IllegalArgumentException("Column="+column+" on table="+tableMeta.getColumnFamily()+" is not indexed.  Add @NoSqlIndex or map/reduce a new index in place and add annotation");
    DboColumnToOneMeta toOne = (DboColumnToOneMeta) columnMeta;
    DboTableMeta fkTableMeta = toOne.getFkToColumnFamily();

    ViewInfoImpl existing = wiring.getInfoFromAlias(newAlias);
    if(existing == null) {
      existing = new ViewInfoImpl(newAlias, fkTableMeta);
      wiring.putAliasTable(newAlias, existing);
    }
   
    //since this is an inner join on primary key, use id column
    DboColumnIdMeta colMeta2 = existing.getTableMeta().getIdColumnMeta();
    JoinInfo join = new JoinInfo(tableInfo, columnMeta, existing, colMeta2, type);
   
    tableInfo.addJoin(join);
    existing.addJoin(join);
  }
 
  @SuppressWarnings("unchecked")
  private <T> void compilePartitionsClause(CommonTree tree,
      InfoForWiring wiring, MetaFacade facade) {
    List<CommonTree> childrenList = tree.getChildren();
    for(CommonTree child : childrenList) {
      compileSinglePartition(wiring, child, facade);
    }
  }

  private void compileSinglePartition(InfoForWiring wiring, CommonTree child, MetaFacade facade) {
    String alias = child.getText();
    ViewInfoImpl info = wiring.getInfoFromAlias(alias);
    if(info == null)
      throw new IllegalArgumentException("In your PARTITIONS clause, you have an alias='"+alias+"' that is not found in your FROM clause");
    else if(info.getPartition() != null)
      throw new IllegalArgumentException("In your PARTITIONS clause, you define a partition for alias='"+alias+"' twice.  you can only define it once");
   
    DboColumnMeta partitionColumn;
    DboTableMeta tableMeta = info.getTableMeta();
    List<DboColumnMeta> partitionedColumns = tableMeta.getPartitionedColumns();
    if(partitionedColumns.size() == 0)
      throw new IllegalArgumentException("The meta data contains no partitions for table="+tableMeta.getColumnFamily()+" so your alias="+alias+" in your query should not be in the PARTITIONS clause.  Delete it!!!!");
    else if(child.getChildCount() > 1) {
      CommonTree columnNode = (CommonTree) child.getChild(1);
      String nameOfColumn = columnNode.getText();
      String withoutQuotes = nameOfColumn.substring(1, nameOfColumn.length()-1)
      partitionColumn = findColumn(partitionedColumns, withoutQuotes);
      if(partitionColumn == null)
        throw new IllegalArgumentException("The meta data specified column="+nameOfColumn+" of having the " +
            "@NoSqlPartitionByThisField but that is not true(at least metadata in database does " +
            "not have that so pick a different column)");
    } else if(partitionedColumns.size() > 1)
      throw new IllegalArgumentException("The meta data/Annotations contains MORE than one partition, so you have to specify something like "+alias+"('<columnThatWePartitionedBy>', :partId)");
    else {
      partitionColumn = partitionedColumns.get(0);
    }
   
    CommonTree partitionIdNode = (CommonTree) child.getChild(0);
    TypeInfo typeInfo = new TypeInfo(partitionColumn);
    ExpressionNode node = new ExpressionNode(partitionIdNode);
    processSide(node, wiring, typeInfo, facade);

    PartitionMeta p = new PartitionMeta(partitionColumn, node);
    info.setPartition(p);
  }
 
  private DboColumnMeta findColumn(List<DboColumnMeta> partitionedColumns, String nameOfColumn) {
    for(DboColumnMeta colMeta : partitionedColumns) {
      if(nameOfColumn.equals(colMeta.getColumnName()))
        return colMeta;
    }
    return null;
  }

  @SuppressWarnings({ "unchecked" })
  private <T> void compileFromClause(CommonTree tree,
      InfoForWiring wiring, MetaFacade facade) {
    List<CommonTree> childrenList = tree.getChildren();
    if (childrenList == null)
      return;
   
    for (CommonTree child : childrenList) {
      int type = child.getType();
      switch (type) {
      case NoSqlLexer.TABLE_NAME:
        loadTableIntoWiringInfo(wiring, child, facade);
        break;
      default:
        break;
      }
    }
  }

  private <T> void loadTableIntoWiringInfo(InfoForWiring wiring, CommonTree tableNode, MetaFacade facade) {
    // What should we add to metaQuery here
    // AND later when we do joins, we need to tell the factory
    // here as well
    String tableName = tableNode.getText();
    String targetTable = wiring.getTargetTable();
    DboTableMeta metaClass = findTable(facade, tableName);
   
    //NOTE: special case for ORM layer only NOT for ad-hoc query!!!
    if(tableName.equals("TABLE") && targetTable != null) {
      metaClass = findTable(facade, targetTable);
    } else if(metaClass == null)
      throw new IllegalArgumentException("Meta data(or Entity)="+tableName+" cannot be found");

    ViewInfoImpl info = new ViewInfoImpl(null, metaClass);
   
    if(tableNode.getChildCount() == 0) {
      if(wiring.getNoAliasTable() != null)
        throw new IllegalArgumentException("This query has two tables with no alias.  This is not allowed");
      wiring.setNoAliasTable(info);
    } else {
      CommonTree aliasNode = (CommonTree) tableNode.getChildren().get(0);
      String alias = aliasNode.getText();
      wiring.putAliasTable(alias, info);
      info.setAlias(alias);
    }

    wiring.addEagerlyJoinedView(info);
   
    //set the very first table as the target table
    if(wiring.getMetaQueryTargetTable() != null)
      throw new RuntimeException("Two tables are not supported at this time.");
   
    wiring.setMetaQueryTargetTable(metaClass);
  }

  private DboTableMeta findTable(MetaFacade facade, String tableName) {
    DboTableMeta metaClass = facade.getColumnFamily(tableName);
    return metaClass;
  }
 
  @SuppressWarnings("unchecked")
  private static <T> void compileSelectClause(CommonTree tree,
      InfoForWiring wiring) {

    List<CommonTree> childrenList = tree.getChildren();
    if (childrenList != null && childrenList.size() > 0) {
      for (CommonTree child : childrenList) {
        switch (child.getType()) {
        case NoSqlLexer.SELECT_RESULTS:
          parseSelectResults(child, wiring);
          break;
        default:
          break;
        }
      }
    }
  }
 
  private void compileDeleteClause(InfoForWiring wiring) {
    wiring.setQueryType("DELETE");
  }

  @SuppressWarnings("unchecked")
  private void compileDeleteColumnClause(CommonTree tree, InfoForWiring wiring, MetaFacade facade) {
    wiring.setQueryType("DELETECOLUMN");
    List<TypedColumn> deleteList = new ArrayList<TypedColumn>();
    List<CommonTree> childrenList = tree.getChildren();
    if (childrenList == null)
      return;
    else {
      TypeInfo columnTypeInfo = processSide(new ExpressionNode(childrenList.get(0)), wiring, null, facade);
      byte[] value = null;
      if (childrenList.size() > 1)
      {
        // value is only relevant if it is *ToOne or *ToMany
        String withQuotes = childrenList.get(1).getText().trim();
        String withoutQuotes = withQuotes.substring(1, withQuotes.length()-1);
        value = StandardConverters.convertToBytes(withoutQuotes);
      }
      TypedColumn columnforDelete = new TypedColumn(columnTypeInfo.getColumnInfo(), columnTypeInfo.getColumnInfo().getColumnNameAsBytes(), value, null);
      deleteList.add(columnforDelete);
    }
    wiring.setUpdateList(deleteList);
  }

  @SuppressWarnings("unchecked")
  private <T> void compileUpdateClause(CommonTree tree,
      InfoForWiring wiring, MetaFacade facade) {
    List<TypedColumn> updateList = new ArrayList<TypedColumn>();
    List<CommonTree> childrenList = tree.getChildren();
    for (CommonTree child : childrenList) {
      ExpressionNode node = new ExpressionNode(child);
      compileExpression(node, wiring, facade);
      TypeInfo columnTypeInfo = processSide(node.getChild(ChildSide.LEFT), wiring, null, facade);
      byte[] value = retrieveValue(columnTypeInfo.getColumnInfo(), node.getChild(ChildSide.RIGHT));
      TypedColumn columnforUpdate = new TypedColumn(columnTypeInfo.getColumnInfo(), columnTypeInfo.getColumnInfo().getColumnNameAsBytes(), value, null);
      updateList.add(columnforUpdate);
    }
    wiring.setUpdateList(updateList);
  }

  @SuppressWarnings("unchecked")
  private <T> void compileTableClause(CommonTree tree,
      InfoForWiring wiring, MetaFacade facade) {
    List<CommonTree> childrenList = tree.getChildren();
    if (childrenList == null)
      return;
    for (CommonTree child : childrenList) {
      int type = child.getType();
      switch (type) {
      case NoSqlLexer.TABLE_NAME:
        loadTableIntoWiringInfo(wiring, child, facade);
        break;
      default:
        break;
      }
    }
  }

  private <T> void processUpdate(CommonTree tree,
      InfoForWiring wiring, MetaFacade facade) {
    wiring.setQueryType("UPDATE");
    // NEed to re-visit again if Update can really be done here
  }
  // the alias part is silly due to not organize right in .g file
  @SuppressWarnings({ "unchecked" })
  private static <T> void parseSelectResults(CommonTree tree,
      InfoForWiring wiring) {
    List<CommonTree> childrenList = tree.getChildren();
    if (childrenList == null)
      return;
     
    for (CommonTree child : childrenList) {
      switch (child.getType()) {
      case NoSqlLexer.STAR:
        wiring.setSelectStarDefined(true);
        break;
      case NoSqlLexer.ATTR_NAME:
       
        String columnNameOrAlias = child.getText();
        ViewInfoImpl info = wiring.getInfoFromAlias(columnNameOrAlias);
        if(info != null) {
          wiring.setSelectStarDefined(true);
          continue;
        }
       
        String alias = null;
        List<CommonTree> children = child.getChildren();
        if(children == null) //It must be an alias if there are no children!!!
          throw new IllegalArgumentException("You have an alias of="+columnNameOrAlias+" that does not exist in the FROM part of the select statement.  query="+wiring.getQuery());
        if(children.size() > 0) { //we have an alias too!!!
          CommonTree aliasNode = children.get(0);
          alias = aliasNode.getText();
         
          String fullName = alias+"."+columnNameOrAlias;
          if(wiring.getInfoFromAlias(alias) == null)
            throw new RuntimeException("The select portion has an attribute="+fullName+" with an alias that was not defined in the from section");         
        } else {
          //later made need to add attributeName information to metaQuery here
         
          if(wiring.getNoAliasTable() == null)
            throw new RuntimeException("The select portion has an attribute="+columnNameOrAlias+" with no alias but there is no table with no alias in from section");         
        }
       
        break;
      case NoSqlLexer.ALIAS:
        break;

      default:
        break;
      }
    }
  }

  @SuppressWarnings("unchecked")
  private static <T> void compileExpression(ExpressionNode node, InfoForWiring wiring, MetaFacade facade) {
    CommonTree expression = node.getASTNode();
    int type = expression.getType();
    if(log.isDebugEnabled())
      log.debug("where type:" + expression.getType());
    switch (type) {
    case NoSqlLexer.AND:
    case NoSqlLexer.OR:
      node.setState("ANDORnode", null);
      List<CommonTree> children = expression.getChildren();
      processSide(node, wiring, children, 0, ChildSide.LEFT, facade);
      processSide(node, wiring, children, 1, ChildSide.RIGHT, facade);
     
      break;
    case NoSqlLexer.EQ:
    case NoSqlLexer.NE:
    case NoSqlLexer.GT:
    case NoSqlLexer.LT:
    case NoSqlLexer.GE:
    case NoSqlLexer.LE:
      compileComparator(node, wiring, facade, expression);
      break;
    case NoSqlLexer.IN:
       compileComparatorIn(node, wiring, facade, expression);
       break;
    case NoSqlLexer.BETWEEN:
      throw new UnsupportedOperationException("not supported yet, use <= and >= intead for now");
    default:
      break;
    }
  }

  private static void compileComparator(ExpressionNode node,
      InfoForWiring wiring, MetaFacade facade, CommonTree expression) {

    //The right side could be value/constant or variable or true or false, or decimal, etc. etc.
    CommonTree leftSide = (CommonTree) expression.getChild(0);
    CommonTree rightSide = (CommonTree) expression.getChild(1);
   
    //This is a VERY difficult issue.  We basically want the type information
    //first either from the constant OR from the column name, then we want to use
    //that NOW or later to verify the type of the other side of the equation, BUT which
    //one has the type information as he needs to go first.  If both are parameters
    //that are passed in, we have no type information, correct?  :name and :something
    //could be any types and may not match at all so first let's disallow param to param
    //matching since developers can do that BEFORE they run the query anyways in the
    //java code.  ie. FIRST, let's find the side with type information
   
    //screw it, we deleted that code and force you to have one side be a column for now!!!!
    if(isAttribute(rightSide)) {
      expression.setChild(0, rightSide);
      expression.setChild(1, leftSide);
      CommonTree temp = rightSide;
      rightSide = leftSide;
      leftSide = temp;       
    } else if(!isAttribute(leftSide)) {
      throw new IllegalArgumentException("Currently, each param in the where clause must be compared to an attribute.  bad query="+wiring.getQuery()+" bad piece="+node);
    }
   
    ExpressionNode left  = new ExpressionNode(leftSide);
    ExpressionNode right = new ExpressionNode(rightSide);
    node.setChild(ChildSide.LEFT, left);
    node.setChild(ChildSide.RIGHT, right);
   
    TypeInfo typeInfo = processSide(left, wiring, null, facade);
    processSide(right, wiring, typeInfo, facade);
   
    Object state = left.getState();
    if(state instanceof StateAttribute) {
      StateAttribute st = (StateAttribute) state;
      ViewInfoImpl tableInfo = st.getViewInfo();
      node.setState(tableInfo, null);
    }
  }

  @SuppressWarnings("unchecked")
  private static void compileComparatorIn(ExpressionNode node,
      InfoForWiring wiring, MetaFacade facade, CommonTree expression) {
      CommonTree leftSide = (CommonTree) expression.getChild(0);
      CommonTree rightSide = (CommonTree) expression.getChild(1);
      ExpressionNode left  = new ExpressionNode(leftSide);
      ExpressionNode right = new ExpressionNode(rightSide);
      node.setChild(ChildSide.LEFT, left);
      node.setChild(ChildSide.RIGHT, right);
      TypeInfo typeInfo = processSide(left, wiring, null, facade);
      List<ParsedNode> keyList = new ArrayList<ParsedNode>();
      List<CommonTree> keys= rightSide.getChildren();
      for(CommonTree keyNode: keys) {
        ExpressionNode rightNode = new ExpressionNode(keyNode);
        processSide(rightNode, wiring, typeInfo, facade);
        keyList.add(rightNode);
      }
      node.setChildrenForIn(keyList);

      Object state = left.getState();
      if(state instanceof StateAttribute) {
        StateAttribute st = (StateAttribute) state;
        ViewInfoImpl tableInfo = st.getViewInfo();
        node.setState(tableInfo, null);
      }
    }

  private static <T> ExpressionNode processSide(ExpressionNode node, InfoForWiring wiring,
      List<CommonTree> children, int i, ChildSide side, MetaFacade facade) {
    CommonTree child = children.get(i);
    ExpressionNode childNode = new ExpressionNode(child);
    node.setChild(side, childNode);
    compileExpression(childNode, wiring, facade);
    return childNode;
  }

 
  private static boolean isAttribute(CommonTree node) {
    if(node.getType() == NoSqlLexer.ATTR_NAME)
      return true;
    return false;
  }

//  private static boolean hasTypeInfo(CommonTree node) {
//    if(node.getType() == NoSqlLexer.ATTR_NAME || node.getType() == NoSqlLexer.DECIMAL
//        || node.getType() == NoSqlLexer.INT_VAL || node.getType() == NoSqlLexer.STR_VAL)
//      return true;
//    return false;
//  }

  private static TypeInfo processSide(ExpressionNode node, InfoForWiring wiring, TypeInfo typeInfo, MetaFacade facade) {
    if(node.getType() == NoSqlLexer.ATTR_NAME) {
      return processColumnName(node, wiring, typeInfo, facade);
    } else if(node.isParameter()) {
      return processParam(node, wiring, typeInfo);
    } else if(node.isConstant()) {
      return processConstant(node, wiring, typeInfo);
    } else
      throw new RuntimeException("bug, type not supported yet="+node.getType());
  }

  private static TypeInfo processConstant(ExpressionNode node, InfoForWiring wiring, TypeInfo typeInfo) {
    String constant = node.getASTNode().getText();
   
    StorageTypeEnum ourType;
    if(node.getType() == NoSqlLexer.DECIMAL || node.getType() == NoSqlLexer.DEC_VAL){
      ourType = StorageTypeEnum.DECIMAL;
      BigDecimal dec = new BigDecimal(constant);
      node.setState(dec, constant);
    } else if(node.getType() == NoSqlLexer.STR_VAL){
      String withoutQuotes = constant.substring(1, constant.length()-1);   
      ourType = StorageTypeEnum.STRING;
      node.setState(withoutQuotes, constant);
    } else if(node.getType() == NoSqlLexer.INT_VAL){
      ourType = StorageTypeEnum.INTEGER;
      BigInteger bigInt = new BigInteger(constant);
      node.setState(bigInt, constant);
    } else if(node.getType() == NoSqlLexer.BOOL_VAL) {
      ourType = StorageTypeEnum.BOOLEAN;
      boolean boolVal = Boolean.parseBoolean(constant);
      node.setState(boolVal, constant);
    } else if(node.getType() == NoSqlLexer.NULL) {
      ourType = StorageTypeEnum.NULL;
      node.setState(null, constant);
    }
     
    else
      throw new RuntimeException("bug, not supported type(please fix)="+node.getType());
   
    if(typeInfo == null) //no types to check against so return...
      return new TypeInfo(ourType);

    //we must compare type info so this next stuff is pure validation
    if(typeInfo.getColumnInfo() != null) {
      validateTypes(wiring, ourType, typeInfo);
    } else {
      StorageTypeEnum constantType = typeInfo.getConstantType();
      if(constantType != ourType)
        throw new IllegalArgumentException("Types do not match in namedquery="+wiring.getQuery());
    }
    return null;
  }

  private static void validateTypes(InfoForWiring wiring, StorageTypeEnum constantType, TypeInfo typeInfo) {
    DboColumnMeta info = typeInfo.getColumnInfo();
    if(info instanceof DboColumnToManyMeta)
      throw new IllegalArgumentException("Cannot use column="+info.getColumnName()+" since that is a toMany relationship");
    else if(constantType == StorageTypeEnum.NULL)
      return; //null is any type so no need to match
    else if(info.isJodaType())
      return;
    else if(constantType != info.getStorageType())
      throw new IllegalArgumentException("Types do not match in namedquery="+wiring.getQuery()+" for column="+info.getColumnName()+" type1="+constantType+" type2="+info.getStorageType());
  }
 

  private static TypeInfo processColumnName(
      ExpressionNode attributeNode2, InfoForWiring wiring, TypeInfo otherSideType, MetaFacade facade) {
    ViewInfoImpl tableInfo;
   
    CommonTree colNameNode = attributeNode2.getASTNode();
    String columnName = colNameNode.getText();
    String textInSql = columnName;
    if (colNameNode.getChildCount() > 0) {
      String aliasEntity = colNameNode.getChild(0).getText();
     
      tableInfo = wiring.getInfoFromAlias(aliasEntity);
      textInSql = aliasEntity+"."+columnName;
      if(tableInfo == null)
        throw new RuntimeException("The where clause attribute="
            +textInSql+" has an alias that does not exist in from clause");
    } else {
      tableInfo = wiring.getNoAliasTable();
      if(tableInfo == null)
        throw new RuntimeException("The where clause attribute="
            +textInSql+" has no alias and from clause only has tables with alias");
    }
   
    DboTableMeta metaClass = tableInfo.getTableMeta();
    //At this point, we have looked up the metaClass associated with the alias
    DboColumnMeta colMeta = facade.getColumnMeta(metaClass, columnName);
    if (colMeta == null) {
      //okay, there is no column found, but maybe the column name for the id matches(id is a special case)
      colMeta = metaClass.getIdColumnMeta();
      if(!colMeta.getColumnName().equals(columnName)) {
        List<String> names = metaClass.getColumnNameList();
        throw new IllegalArgumentException("There is no column=" + columnName + " that exists for table "
            + metaClass.getColumnFamily()+" potential columns are="+names+"  rowkey col="+colMeta.getColumnName());
      }
    }
   
    wiring.addEagerlyJoinedView(tableInfo);
    StateAttribute attr = new StateAttribute(tableInfo, colMeta, textInSql);
    attributeNode2.setState(attr, textInSql);
    wiring.incrementAttributesCount(textInSql);
   
    TypeInfo typeInfo = new TypeInfo(colMeta);
   
    if(otherSideType == null)
      return typeInfo;
   
    if(otherSideType.getConstantType() != null) {
      validateTypes(wiring, otherSideType.getConstantType(), typeInfo);
    } else {
      Class<?> classType = otherSideType.getColumnInfo().getClassType();
      if(!classType.equals(colMeta.getClassType()))
        throw new IllegalArgumentException("Types are not the same for query="+wiring.getQuery()+" types="+classType+" and "+colMeta.getClassType());
    }

    return null;
  }
 
  private static TypeInfo processParam(ExpressionNode parameterNode2, InfoForWiring wiring, TypeInfo typeInfo) {
    CommonTree parameterNode = parameterNode2.getASTNode();
    String parameter = parameterNode.getText();
   
    wiring.getParameterFieldMap().put(parameter, typeInfo);
   
    parameterNode2.setState(parameter, ":"+parameter);
    return null;
  }

  private byte[] retrieveValue(DboColumnMeta info, ExpressionNode node) {
    if(node.isConstant()) {
      Object constant = node.getState();
      return info.convertToStorage2(constant);
    } else
      throw new UnsupportedOperationException("type not supported="+node.getType());
  }

}
TOP

Related Classes of com.alvazan.orm.parser.antlr.ScannerSql

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.