Package railo.runtime.tag

Source Code of railo.runtime.tag.StoredProc

package railo.runtime.tag;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.jsp.JspException;

import railo.commons.io.IOUtil;
import railo.commons.lang.StringUtil;
import railo.commons.sql.SQLUtil;
import railo.runtime.config.ConfigImpl;
import railo.runtime.config.Constants;
import railo.runtime.db.CFTypes;
import railo.runtime.db.DataSource;
import railo.runtime.db.DataSourceManager;
import railo.runtime.db.DataSourceSupport;
import railo.runtime.db.DatasourceConnection;
import railo.runtime.db.ProcMeta;
import railo.runtime.db.ProcMetaCollection;
import railo.runtime.db.SQLCaster;
import railo.runtime.db.SQLImpl;
import railo.runtime.db.SQLItemImpl;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.DatabaseException;
import railo.runtime.exp.PageException;
import railo.runtime.ext.tag.BodyTagTryCatchFinallySupport;
import railo.runtime.listener.ApplicationContextPro;
import railo.runtime.op.Caster;
import railo.runtime.tag.util.DeprecatedUtil;
import railo.runtime.type.Array;
import railo.runtime.type.ArrayImpl;
import railo.runtime.type.Collection.Key;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.QueryImpl;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.dt.DateTime;
import railo.runtime.type.dt.DateTimeImpl;
import railo.runtime.type.dt.TimeSpan;
import railo.runtime.type.util.KeyConstants;






public class StoredProc extends BodyTagTryCatchFinallySupport {
  //private static final int PROCEDURE_CAT=1;       
  //private static final int PROCEDURE_SCHEM=2;
  //private static final int PROCEDURE_NAME=3;
  //private static final int COLUMN_NAME=4;
  private static final int COLUMN_TYPE=5;
  private static final int DATA_TYPE=6;
  private static final int TYPE_NAME=7;
  //|PRECISION|LENGTH|SCALE|RADIX|NULLABLE|REMARKS|SEQUENCE|OVERLOAD|DEFAULT_VALUE
 

  private static final railo.runtime.type.Collection.Key KEY_SC = KeyImpl.intern("StatusCode");
 
  private static final railo.runtime.type.Collection.Key COUNT = KeyImpl.intern("count_afsdsfgdfgdsfsdfsgsdgsgsdgsasegfwef");
 
  private static final ProcParamBean STATUS_CODE;
  private static final railo.runtime.type.Collection.Key STATUSCODE = KeyImpl.intern("StatusCode");
 
  static{
    STATUS_CODE = new ProcParamBean();
    STATUS_CODE.setType(Types.INTEGER);
    STATUS_CODE.setDirection(ProcParamBean.DIRECTION_OUT);
    STATUS_CODE.setVariable("cfstoredproc.statusCode");
  }
 
 
  private List<ProcParamBean> params=new ArrayList<ProcParamBean>();
  private Array results=new ArrayImpl();

  private String procedure;
  private String datasource=null;
  private String username;
  private String password;
  private int blockfactor=-1;
  private int timeout=-1;
  private boolean debug=true;
  private boolean returncode;
  private String result="cfstoredproc";
 
  private boolean clearCache;
  private DateTimeImpl cachedbefore;
  //private String cachename="";
  private DateTime cachedafter;
  private ProcParamBean returnValue=null;
  //private Map<String,ProcMetaCollection> procedureColumnCache;
 
  public void release() {
    params.clear();
    results.clear();
    returnValue=null;
    procedure=null;
    datasource=null;
    username=null;
    password=null;
    blockfactor=-1;
    timeout=-1;
    debug=true;
    returncode=false;
    result="cfstoredproc";
   

    clearCache=false;
    cachedbefore=null;
    cachedafter=null;
    //cachename="";
   
    super.release();
  }
 
 


  /** set the value cachedafter
  *  This is the age of which the query data can be
  * @param cachedafter value to set
  **/
  public void setCachedafter(DateTime cachedafter)  {
    //railo.print.ln("cachedafter:"+cachedafter);
    this.cachedafter=cachedafter;
  }

  /** set the value cachename
  *  This is specific to JTags, and allows you to give the cache a specific name
  * @param cachename value to set
  **/
  public void setCachename(String cachename)  {
    DeprecatedUtil.tagAttribute(pageContext,"StoredProc", "cachename");
  }

  /** set the value cachedwithin
  * 
  * @param cachedwithin value to set
  **/
  public void setCachedwithin(TimeSpan cachedwithin)  {
    if(cachedwithin.getMillis()>0)
      this.cachedbefore=new DateTimeImpl(pageContext,System.currentTimeMillis()+cachedwithin.getMillis(),false);
    else clearCache=true;
  }

  /**
   * @param blockfactor The blockfactor to set.
   */
  public void setBlockfactor(double blockfactor) {
    this.blockfactor = (int) blockfactor;
  }
 
  /**
   * @param blockfactor
   * @deprecated replaced with setBlockfactor(double)
   */
  public void setBlockfactor(int blockfactor) {
    DeprecatedUtil.tagAttribute(pageContext,"storedproc","blockfactor");
    this.blockfactor = blockfactor;
  }

  /**
   * @param datasource The datasource to set.
   */
  public void setDatasource(String datasource) {
    this.datasource = datasource;
  }

  /**
   * @param username The username to set.
   */
  public void setUsername(String username) {
    this.username = username;
  }

  /**
   * @param password The password to set.
   */
  public void setPassword(String password) {
    this.password = password;
  }

  /**
   * @param debug The debug to set.
   */
  public void setDebug(boolean debug) {
    this.debug = debug;
  }

  /**
   * @param procedure The procedure to set.
   */
  public void setProcedure(String procedure) {
    this.procedure = procedure;
  }

  /**
   * @param result The result to set.
   */
  public void setResult(String result) {
    this.result = result;
  }

  /**
   * @param returncode The returncode to set.
   */
  public void setReturncode(boolean returncode) {
    this.returncode = returncode;
  }

  /**
   * @param dbvarname the dbvarname to set
   */
  public void setDbvarname(String dbvarname) {
    DeprecatedUtil.tagAttribute(pageContext,"storedproc","dbvarname");
  }
  public void setDbtype(String dbtype) {
    DeprecatedUtil.tagAttribute(pageContext,"storedproc","dbtype");
  }

  public void addProcParam(ProcParamBean param) {
    params.add(param);
  }

  public void addProcResult(ProcResultBean result) {
    results.setEL(result.getResultset(),result);
  }

  @Override
  public int doStartTag() throws JspException {
   
    return EVAL_BODY_INCLUDE;
  }

  private void returnValue(DatasourceConnection dc) throws PageException {
    Connection conn = dc.getConnection();
   
   
    if(SQLUtil.isOracle(conn)){
      String name=this.procedure.toUpperCase();
      int index=name.lastIndexOf('.');
     
      String pack=null,scheme=null;
      if(index!=-1){
        pack=name.substring(0,index);
        name=name.substring(index+1);
       
        index=pack.lastIndexOf('.');
        if(index!=-1){
          scheme=pack.substring(index+1);
          pack=pack.substring(0,index);
        }
       
       
      }
     
      try {
        DatabaseMetaData md = conn.getMetaData();
       
        //if(procedureColumnCache==null)procedureColumnCache=new ReferenceMap();
        //ProcMetaCollection coll=procedureColumnCache.get(procedure);
        DataSourceSupport d = ((DataSourceSupport)dc.getDatasource());
        long cacheTimeout = d.getMetaCacheTimeout();
        Map<String, ProcMetaCollection> procedureColumnCache = d.getProcedureColumnCache();
        ProcMetaCollection coll=procedureColumnCache.get(procedure);
       
        if(coll==null || (cacheTimeout>=0 && (coll.created+cacheTimeout)<System.currentTimeMillis())) {
          ResultSet res = md.getProcedureColumns(pack, scheme, name, null);
          coll=createProcMetaCollection(res);
          procedureColumnCache.put(procedure,coll);
        }
       
        index=-1;
        for(int i=0;i<coll.metas.length;i++) {
          index++;
         
          // Return
          if(coll.metas[i].columnType==DatabaseMetaData.procedureColumnReturn) {
            index--;
            ProcResultBean result= getFirstResult();
            ProcParamBean param = new ProcParamBean();
           
            param.setType(coll.metas[i].dataType);
            param.setDirection(ProcParamBean.DIRECTION_OUT);
            if(result!=null)param.setVariable(result.getName());
            returnValue=param;
           
         
          else if(coll.metas[i].columnType==DatabaseMetaData.procedureColumnOut || coll.metas[i].columnType==DatabaseMetaData.procedureColumnInOut) {
            if(coll.metas[i].dataType==CFTypes.CURSOR){
              ProcResultBean result= getFirstResult();
             
              ProcParamBean param = new ProcParamBean();
              param.setType(coll.metas[i].dataType);
              param.setDirection(ProcParamBean.DIRECTION_OUT);
              if(result!=null)param.setVariable(result.getName());
              params.add(index, param);
            }
            else {               
              ProcParamBean param= params.get(index);
              if(coll.metas[i].dataType!=Types.OTHER && coll.metas[i].dataType!=param.getType()){
                param.setType(coll.metas[i].dataType);
              }
            }
          } 
          else if(coll.metas[i].columnType==DatabaseMetaData.procedureColumnIn) { 
            ProcParamBean param=get(params,index);
            if(param!=null && coll.metas[i].dataType!=Types.OTHER && coll.metas[i].dataType!=param.getType()){
              param.setType(coll.metas[i].dataType);
            }
          } 
        }
        contractTo(params,index+1);
       
        //if(res!=null)print.out(new QueryImpl(res,"columns").toString());
      }
      catch (SQLException e) {
          throw new DatabaseException(e,dc);
      }
     
     
    }
   
    // return code
    if(returncode) {
      returnValue=STATUS_CODE;
    }
  }

  private static ProcParamBean get(List<ProcParamBean> params, int index) {
    try{
      return params.get(index);
    }
    catch(Throwable t){
      return null;
    }
   
  }




  private void contractTo(List<ProcParamBean> params, int paramCount) {
    if(params.size()>paramCount){
      for(int i=params.size()-1;i>=paramCount;i--){
        params.remove(i);
      }
    }
  }




  private ProcMetaCollection createProcMetaCollection(ResultSet res) throws SQLException {
    /*
    try {
      print.out(new QueryImpl(res,"qry"));
    } catch (PageException e) {}
    */
    ArrayList<ProcMeta> list=new ArrayList<ProcMeta>();
    while(res.next()) {
      list.add(new ProcMeta(res.getInt(COLUMN_TYPE),getDataType(res)));
    }
    return new ProcMetaCollection(list.toArray(new ProcMeta[list.size()]));
  }




  private int getDataType(ResultSet res) throws SQLException {
    int dataType=res.getInt(DATA_TYPE)
    if(dataType==Types.OTHER) {
      String  strDataType= res.getString(TYPE_NAME);
      if("REF CURSOR".equalsIgnoreCase(strDataType))dataType=CFTypes.CURSOR;
      if("CLOB".equalsIgnoreCase(strDataType))dataType=Types.CLOB;
      if("BLOB".equalsIgnoreCase(strDataType))dataType=Types.BLOB;
    }
    return dataType;
  }




  private ProcResultBean getFirstResult() {
    Iterator<Key> it = results.keyIterator();
    if(!it.hasNext()) return null;
     
    return (ProcResultBean) results.removeEL(it.next());
  }

  @Override
  public int doEndTag() throws JspException {
    long startNS=System.nanoTime();
   
    Object ds=datasource;
    if(StringUtil.isEmpty(datasource)){
      ds=((ApplicationContextPro)pageContext.getApplicationContext()).getDefDataSource();
      if(StringUtil.isEmpty(ds))
        throw new ApplicationException(
            "attribute [datasource] is required, when no default datasource is defined",
            "you can define a default datasource as attribute [defaultdatasource] of the tag "+Constants.CFAPP_NAME+" or as data member of the "+Constants.APP_CFC+" (this.defaultdatasource=\"mydatasource\";)");
    }
   
   
   
      Struct res=new StructImpl();
    DataSourceManager manager = pageContext.getDataSourceManager();
    DatasourceConnection dc = ds instanceof DataSource?
        manager.getConnection(pageContext,(DataSource)ds,username,password):
        manager.getConnection(pageContext,Caster.toString(ds),username,password);
   
    // create returnValue
    returnValue(dc);
   
    // create SQL
    StringBuilder sql=createSQL();
   

    // add returnValue to params
    if(returnValue!=null){
      params.add(0,returnValue);
    }
   
    SQLImpl _sql=new SQLImpl(sql.toString());
    CallableStatement callStat=null;
    try {
        callStat = dc.getConnection().prepareCall(sql.toString());
            //ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
            //ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
       
        if(blockfactor>0)callStat.setFetchSize(blockfactor);
        if(timeout>0)callStat.setQueryTimeout(timeout);
       
  // set IN register OUT
        Iterator<ProcParamBean> it = params.iterator();
      ProcParamBean param;
      int index=1;
        while(it.hasNext()) {
          param= it.next();
          param.setIndex(index);
          _sql.addItems(new SQLItemImpl(param.getValue()));
          if(param.getDirection()!=ProcParamBean.DIRECTION_OUT) {
            SQLCaster.setValue(pageContext.getTimeZone(),callStat, index, param);
          }
          if(param.getDirection()!=ProcParamBean.DIRECTION_IN) {
            registerOutParameter(callStat,param);
          }
          index++;
      }
       
  // cache
        boolean isFromCache=false;
        boolean hasCached=cachedbefore!=null || cachedafter!=null;
        Object cacheValue=null;
        String dsn = ds instanceof DataSource?((DataSource)ds).getName():Caster.toString(ds);
      if(clearCache) {
        hasCached=false;
        pageContext.getQueryCache().remove(pageContext,_sql,dsn,username,password);
      }
      else if(hasCached) {
        cacheValue = pageContext.getQueryCache().get(pageContext,_sql,dsn,username,password,cachedafter);
      }
      int count=0;
      if(cacheValue==null){
        // execute
        boolean isResult=callStat.execute();
       
          Struct cache=hasCached?new StructImpl():null;
 
          // resultsets
          ProcResultBean result;
         
          index=1;
        do {
            if(isResult){
              ResultSet rs=callStat.getResultSet();
              if(rs!=null) {
              try{
                result=(ProcResultBean) results.get(index++,null);
                if(result!=null) {
                  railo.runtime.type.Query q = new QueryImpl(rs,result.getMaxrows(),result.getName(),pageContext.getTimeZone())
                  count+=q.getRecordcount();
                  setVariable(result.getName(), q);
                  if(hasCached)cache.set(KeyImpl.getInstance(result.getName()), q);
                }
              }
              finally{
                IOUtil.closeEL(rs);
              }
            }
            }
          }
          while((isResult=callStat.getMoreResults()) || (callStat.getUpdateCount() != -1));

          // params
          it = params.iterator();
          while(it.hasNext()) {
            param= it.next();
            if(param.getDirection()!=ProcParamBean.DIRECTION_IN){
              Object value=null;
              if(!StringUtil.isEmpty(param.getVariable())){
                try{
                  value=SQLCaster.toCFType(callStat.getObject(param.getIndex()));
                }
                catch(Throwable t){}
                value=emptyIfNull(value);
               
                if(param==STATUS_CODE) res.set(STATUSCODE, value);
                else setVariable(param.getVariable(), value);
                if(hasCached)cache.set(KeyImpl.getInstance(param.getVariable()), value);
              }
            }
        }
          if(hasCached){
            cache.set(COUNT, Caster.toDouble(count));
            pageContext.getQueryCache().set(pageContext,_sql,dsn,username,password,cache,cachedbefore);
          }
         
      }
      else if(cacheValue instanceof Struct) {
        Struct sctCache = (Struct) cacheValue;
        count=Caster.toIntValue(sctCache.removeEL(COUNT),0);
       
        Iterator<Entry<Key, Object>> cit = sctCache.entryIterator();
        Entry<Key, Object> ce;
        while(cit.hasNext()){
          ce = cit.next();
          if(STATUS_CODE.getVariable().equals(ce.getKey().getString()))
            res.set(KEY_SC, ce.getValue());
          else setVariable(ce.getKey().getString(), ce.getValue());
        }
        isFromCache=true;
      }
     
        // result
        long exe;
       
        setVariable(this.result, res);
        res.set(KeyConstants._executionTime,Caster.toDouble(exe=(System.nanoTime()-startNS)));
        res.set(KeyConstants._cached,Caster.toBoolean(isFromCache));
       
        if(pageContext.getConfig().debug() && debug) {
          boolean logdb=((ConfigImpl)pageContext.getConfig()).hasDebugOptions(ConfigImpl.DEBUG_DATABASE);
        if(logdb)
          pageContext.getDebugger().addQuery(null,dsn,procedure,_sql,count,pageContext.getCurrentPageSource(),(int)exe);
      }
       
       
    }
    catch (SQLException e) {
        throw new DatabaseException(e,new SQLImpl(sql.toString()),dc);
    }
    finally {
        if(callStat!=null){
          try {
          callStat.close();
        } catch (SQLException e) {}
        }
        manager.releaseConnection(pageContext,dc);
    }
    return EVAL_PAGE;
  }

  private void setVariable(String name, Object value) throws PageException {
    pageContext.setVariable(name, value);
  }




  private StringBuilder createSQL() {
    StringBuilder sql=new StringBuilder();
    if(returnValue!=null)sql.append("{? = call ");
    else sql.append("{ call ");
    sql.append(procedure);
    sql.append('(');
    int incount=params.size();
   
    for(int i=0;i<incount;i++) {
      if(i==0)sql.append('?');
      else sql.append(",?");
    }
    sql.append(") }");
    return sql;
   
  }




  private Object emptyIfNull(Object object) {
    if(object==null)return "";
    return object;
  }

  private void registerOutParameter(CallableStatement proc, ProcParamBean param) throws SQLException {
    if(param.getScale()==-1)proc.registerOutParameter(param.getIndex(),param.getType());
    else proc.registerOutParameter(param.getIndex(),param.getType(),param.getScale());
  }

  /**
   * @param b
   */
  public void hasBody(boolean b) {
   
  }

  /**
   * @param timeout the timeout to set
   */
  public void setTimeout(double timeout) {
    this.timeout = (int) timeout;
  }
 
 
}

TOP

Related Classes of railo.runtime.tag.StoredProc

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.