package railo.runtime.db;
import java.io.ByteArrayInputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import railo.commons.collection.MapFactory;
import railo.commons.lang.StringUtil;
import railo.commons.math.MathUtil;
import railo.runtime.PageContext;
import railo.runtime.exp.DatabaseException;
import railo.runtime.exp.PageException;
import railo.runtime.op.Caster;
import railo.runtime.op.Operator;
import railo.runtime.sql.old.ZConstant;
import railo.runtime.sql.old.ZExp;
import railo.runtime.sql.old.ZExpression;
import railo.runtime.sql.old.ZFromItem;
import railo.runtime.sql.old.ZOrderBy;
import railo.runtime.sql.old.ZQuery;
import railo.runtime.sql.old.ZSelectItem;
import railo.runtime.sql.old.ZqlParser;
import railo.runtime.type.Collection.Key;
import railo.runtime.type.Query;
import railo.runtime.type.QueryColumn;
import railo.runtime.type.QueryImpl;
import railo.runtime.type.util.ListUtil;
import railo.runtime.type.util.QueryUtil;
/**
*
*/
public final class Executer {
/**
* execute a SQL Statement against CFML Scopes
* @param pc PageContext of the Request
* @param sql
* @param maxrows
* @return result
* @throws PageException
*/
public Query execute(Vector statements, PageContext pc,SQL sql, int maxrows) throws PageException {
// parse sql
if(statements.size()!=1) throw new DatabaseException("only one SQL Statement allowed at time",null,null,null);
ZQuery query=(ZQuery) statements.get(0);
// single table
if(query.getFrom().size()==1) {
return testExecute(pc,sql,getSingleTable(pc, query),query,maxrows);
}
// multiple table
throw new DatabaseException("can only work with single tables yet",null,null,null);
}
public Query execute(PageContext pc,SQL sql,String prettySQL, int maxrows) throws PageException {
if(StringUtil.isEmpty(prettySQL))prettySQL=SQLPrettyfier.prettyfie(sql.getSQLString());
ZqlParser parser = new ZqlParser(new ByteArrayInputStream(prettySQL.getBytes()));
Vector statements;
try {
statements=parser.readStatements();
}
catch(Throwable t) {
throw Caster.toPageException(t);
}
return execute(statements,pc, sql, maxrows);
}
private Query testExecute(PageContext pc,SQL sql, Query qr, ZQuery query, int maxrows) throws PageException {
int recCount=qr.getRecordcount();
Vector vSelects=query.getSelect();
int selCount=vSelects.size();
Map<String,Object> selects=MapFactory.<String,Object>getConcurrentMap();
boolean isSMS=false;
// headers
for(int i=0;i<selCount;i++) {
ZSelectItem select=(ZSelectItem) vSelects.get(i);
if(select.isWildcard() || (isSMS=select.getColumn().equals(SQLPrettyfier.PLACEHOLDER_ASTERIX))) {
if(!isSMS && !select.getColumn().equals("*"))
throw new DatabaseException("can't execute this type of query at the moment",null,sql,null);
//Collection.Key[] keys = qr.keys();
Iterator<Key> it = qr.keyIterator();
Key k;
while(it.hasNext()){
k = it.next();
selects.put(k.getString(),k.getString());
}
isSMS=false;
}
else {
//if(SQLPrettyfier.PLACEHOLDER_COUNT.equals(select.getAlias())) select.setAlias("count");
//if(SQLPrettyfier.PLACEHOLDER_COUNT.equals(select.getColumn())) select.setExpression(new ZConstant("count",ZConstant.COLUMNNAME));
String alias=select.getAlias();
String column=select.getColumn();
if(alias==null)alias=column;
alias=alias.toLowerCase();
selects.put(alias,select);
}
}
String[] headers = selects.keySet().toArray(new String[selects.size()]);
// aHeaders.toArray(new String[aHeaders.size()]);
QueryImpl rtn=new QueryImpl(headers,0,"query");
rtn.setSql(sql);
// loop records
Vector orders = query.getOrderBy();
ZExp where = query.getWhere();
//print.out(headers);
// int newRecCount=0;
boolean hasMaxrow=maxrows>-1 && (orders==null || orders.size()==0);
for(int row=1;row<=recCount;row++) {
sql.setPosition(0);
if(hasMaxrow && maxrows<=rtn.getRecordcount())break;
boolean useRow=where==null || Caster.toBooleanValue(executeExp(pc,sql,qr, where, row));
if(useRow) {
rtn.addRow(1);
for(int cell=0;cell<headers.length;cell++){
Object value = selects.get(headers[cell]);
rtn.setAt(
headers[cell],
rtn.getRecordcount(),
getValue(pc,sql,qr,row,headers[cell],value)
//executeExp(qr, selects[cell].getExpression(),row)
);
}
}
}
// Group By
if(query.getGroupBy()!=null)
throw new DatabaseException("group by are not supported at the moment",null,sql,null);
// Order By
if(orders!=null && orders.size()>0) {
int len=orders.size();
for(int i=len-1;i>=0;i--) {
ZOrderBy order=(ZOrderBy) orders.get(i);
ZConstant name=(ZConstant)order.getExpression();
rtn.sort(name.getValue().toLowerCase(),order.getAscOrder()?Query.ORDER_ASC:Query.ORDER_DESC);
}
if(maxrows>-1) {
rtn.cutRowsTo(maxrows);
}
}
// Distinct
if(query.isDistinct()) {
String[] keys=rtn.getColumns();
QueryColumn[] columns=new QueryColumn[keys.length];
for(int i=0;i<columns.length;i++) {
columns[i]=rtn.getColumn(keys[i]);
}
int i;
outer:for(int row=rtn.getRecordcount();row>1;row--) {
for(i=0;i<columns.length;i++) {
if(!Operator.equals(QueryUtil.getValue(columns[i],row),QueryUtil.getValue(columns[i],row-1),true))
continue outer;
}
rtn.removeRow(row);
}
}
// UNION // TODO support it
ZExpression set = query.getSet();
if(set!=null){
ZExp op = set.getOperand(0);
if(op instanceof ZQuery) throw new DatabaseException("union is not supported at the moment",null,sql,null);
//getInvokedTables((ZQuery)op, tablesNames);
}
return rtn;
}
/**
* return value
* @param sql
* @param querySource
* @param row
* @param key
* @param value
* @return value
* @throws PageException
*/
private Object getValue(PageContext pc,SQL sql,Query querySource, int row, String key, Object value) throws PageException {
if(value instanceof ZSelectItem)return executeExp(pc,sql,querySource, ((ZSelectItem)value).getExpression(),row);
return querySource.getAt(key,row);
}
/**
* @param pc Page Context of the Request
* @param query ZQLQuery
* @return Railo Query
* @throws PageException
*/
private Query getSingleTable(PageContext pc, ZQuery query) throws PageException {
return Caster.toQuery(pc.getVariable(((ZFromItem)query.getFrom().get(0)).getFullName()));
}
/**
* Executes a ZEXp
* @param sql
* @param qr Query Result
* @param exp expression to execute
* @param row current row of resultset
* @return result
* @throws PageException
*/
private Object executeExp(PageContext pc,SQL sql,Query qr, ZExp exp, int row) throws PageException {
if(exp instanceof ZConstant) return executeConstant(sql,qr, (ZConstant)exp, row);
else if(exp instanceof ZExpression)return executeExpression(pc,sql,qr, (ZExpression)exp, row);
throw new DatabaseException("unsupported sql statement ["+exp+"]",null,sql,null);
}
/**
* Executes a Expression
* @param sql
* @param qr
* @param expression
* @param row
* @return result
* @throws PageException
*/
private Object executeExpression(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
String op=StringUtil.toLowerCase(expression.getOperator());
int count=expression.nbOperands();
if(op.equals("and")) return executeAnd(pc,sql,qr,expression,row);
else if(op.equals("or")) return executeOr(pc,sql,qr,expression,row);
if(count==0 && op.equals("?")) {
int pos=sql.getPosition();
if(sql.getItems().length<=pos) throw new DatabaseException("invalid syntax for SQL Statement",null,sql,null);
sql.setPosition(pos+1);
return sql.getItems()[pos].getValueForCF();
}
// 11111111111111111111111111111111111111111111111111111
else if(count==1) {
Object value = executeExp( pc,sql,qr,expression.getOperand(0),row);
// Functions
switch(op.charAt(0)) {
case 'a':
if(op.equals("abs")) return new Double(MathUtil.abs(Caster.toDoubleValue(value)));
if(op.equals("acos")) return new Double(Math.acos(Caster.toDoubleValue(value)));
if(op.equals("asin")) return new Double(Math.asin(Caster.toDoubleValue(value)));
if(op.equals("atan")) return new Double(Math.atan(Caster.toDoubleValue(value)));
break;
case 'c':
if(op.equals("ceiling"))return new Double(Math.ceil(Caster.toDoubleValue(value)));
if(op.equals("cos")) return new Double(Math.cos(Caster.toDoubleValue(value)));
break;
case 'e':
if(op.equals("exp")) return new Double(Math.exp(Caster.toDoubleValue(value)));
break;
case 'f':
if(op.equals("floor")) return new Double(Math.floor(Caster.toDoubleValue(value)));
break;
case 'i':
if(op.equals("is not null")) return Boolean.valueOf(value!=null);
if(op.equals("is null")) return Boolean.valueOf(value==null);
break;
case 'u':
if(op.equals("upper") || op.equals("ucase")) return Caster.toString(value).toUpperCase();
break;
case 'l':
if(op.equals("lower")|| op.equals("lcase")) return Caster.toString(value).toLowerCase();
if(op.equals("ltrim")) return StringUtil.ltrim(Caster.toString(value),null);
if(op.equals("length")) return new Double(Caster.toString(value).length());
break;
case 'r':
if(op.equals("rtrim")) return StringUtil.rtrim(Caster.toString(value),null);
break;
case 's':
if(op.equals("sign")) return new Double(MathUtil.sgn(Caster.toDoubleValue(value)));
if(op.equals("sin")) return new Double(Math.sin(Caster.toDoubleValue(value)));
if(op.equals("soundex"))return StringUtil.soundex(Caster.toString(value));
if(op.equals("sin")) return new Double(Math.sqrt(Caster.toDoubleValue(value)));
break;
case 't':
if(op.equals("tan")) return new Double(Math.tan(Caster.toDoubleValue(value)));
if(op.equals("trim")) return Caster.toString(value).trim();
break;
}
}
// 22222222222222222222222222222222222222222222222222222
else if(count==2) {
if(op.equals("=") || op.equals("in")) return executeEQ(pc,sql,qr,expression,row);
else if(op.equals("!=") || op.equals("<>")) return executeNEQ(pc,sql,qr,expression,row);
else if(op.equals("<")) return executeLT(pc,sql,qr,expression,row);
else if(op.equals("<=")) return executeLTE(pc,sql,qr,expression,row);
else if(op.equals(">")) return executeGT(pc,sql,qr,expression,row);
else if(op.equals(">=")) return executeGTE(pc,sql,qr,expression,row);
else if(op.equals("-")) return executeMinus(pc,sql,qr,expression,row);
else if(op.equals("+")) return executePlus(pc,sql,qr,expression,row);
else if(op.equals("/")) return executeDivide(pc,sql,qr,expression,row);
else if(op.equals("*")) return executeMultiply(pc,sql,qr,expression,row);
else if(op.equals("^")) return executeExponent(pc,sql,qr,expression,row);
Object left = executeExp(pc,sql,qr,expression.getOperand(0),row);
Object right = executeExp(pc,sql,qr,expression.getOperand(1),row);
// Functions
switch(op.charAt(0)) {
case 'a':
if(op.equals("atan2"))
return new Double(Math.atan2(Caster.toDoubleValue(left),Caster.toDoubleValue(right)));
break;
case 'b':
if(op.equals("bitand"))
return new Double(Operator.bitand(Caster.toDoubleValue(left),Caster.toDoubleValue(right)));
if(op.equals("bitor"))
return new Double(Operator.bitor(Caster.toDoubleValue(left),Caster.toDoubleValue(right)));
break;
case 'c':
if(op.equals("concat"))
return Caster.toString(left).concat(Caster.toString(right));
break;
case 'l':
if(op.equals("like"))
return executeLike(pc,sql,qr,expression,row);
break;
case 'm':
if(op.equals("mod"))
return new Double(Operator.modulus(Caster.toDoubleValue(left),Caster.toDoubleValue(right)));
break;
}
throw new DatabaseException("unsopprted sql statement ["+op+"]",null,sql,null);
}
// 3333333333333333333333333333333333333333333333333333333333333333333
else if(count==3) {
if(op.equals("between")) return executeBetween(pc,sql,qr,expression,row);
}
if(op.equals("in")) return executeIn(pc,sql,qr,expression,row);
/*
addCustomFunction("cot",1);
addCustomFunction("degrees",1);
addCustomFunction("log",1);
addCustomFunction("log10",1);
addCustomFunction("pi",0);
addCustomFunction("power",2);
addCustomFunction("radians",1);
addCustomFunction("rand",0);
addCustomFunction("round",2);
addCustomFunction("roundmagic",1);
addCustomFunction("truncate",2);
addCustomFunction("ascii",1);
addCustomFunction("bit_length",1);
addCustomFunction("char",1);
addCustomFunction("char_length",1);
addCustomFunction("difference",2);
addCustomFunction("hextoraw",1);
addCustomFunction("insert",4);
addCustomFunction("left",2);
addCustomFunction("locate",3);
addCustomFunction("octet_length",1);
addCustomFunction("rawtohex",1);
addCustomFunction("repeat",2);
addCustomFunction("replace",3);
addCustomFunction("right",2);
addCustomFunction("space",1);
addCustomFunction("substr",3);
addCustomFunction("substring",3);
addCustomFunction("curdate",0);
addCustomFunction("curtime",0);
addCustomFunction("datediff",3);
addCustomFunction("dayname",1);
addCustomFunction("dayofmonth",1);
addCustomFunction("dayofweek",1);
addCustomFunction("dayofyear",1);
addCustomFunction("hour",1);
addCustomFunction("minute",1);
addCustomFunction("month",1);
addCustomFunction("monthname",1);
addCustomFunction("now",0);
addCustomFunction("quarter",1);
addCustomFunction("second",1);
addCustomFunction("week",1);
addCustomFunction("year",1);
addCustomFunction("current_date",1);
addCustomFunction("current_time",1);
addCustomFunction("current_timestamp",1);
addCustomFunction("database",0);
addCustomFunction("user",0);
addCustomFunction("current_user",0);
addCustomFunction("identity",0);
addCustomFunction("ifnull",2);
addCustomFunction("casewhen",3);
addCustomFunction("convert",2);
//addCustomFunction("cast",1);
addCustomFunction("coalesce",1000);
addCustomFunction("nullif",2);
addCustomFunction("extract",1);
addCustomFunction("position",1);
*/
//print(expression);
throw new DatabaseException(
"unsopprted sql statement (op-count:"+expression.nbOperands()+";operator:"+op+") ",null,sql,null);
}
/* *
* @param expression
* /
private void print(ZExpression expression) {
print.ln("Operator:"+expression.getOperator().toLowerCase());
int len=expression.nbOperands();
for(int i=0;i<len;i++) {
print.ln(" ["+i+"]= "+expression.getOperand(i));
}
}/*
/**
*
* execute a and operation
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return
* @throws PageException
*/
private Object executeAnd(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
int len=expression.nbOperands();
//boolean rtn=Caster.toBooleanValue(executeExp(pc,sql,qr,expression.getOperand(0),row));
for(int i=0;i<len;i++) {
//if(!rtn)break;
//rtn=rtn && Caster.toBooleanValue(executeExp(pc,sql,qr,expression.getOperand(i),row));
if(!Caster.toBooleanValue(executeExp(pc,sql,qr,expression.getOperand(i),row))) return Boolean.FALSE;
}
return Boolean.TRUE;
}
/**
*
* execute a and operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeOr(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
int len=expression.nbOperands();
//boolean rtn=Caster.toBooleanValue(executeExp(pc,sql,qr,expression.getOperand(0),row));
for(int i=0;i<len;i++) {
if(Caster.toBooleanValue(executeExp(pc,sql,qr,expression.getOperand(i),row))) return Boolean.TRUE;
//if(rtn)break;
//rtn=rtn || Caster.toBooleanValue(executeExp(pc,sql,qr,expression.getOperand(i),row));
}
return Boolean.FALSE;
}
/**
*
* execute a equal operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeEQ(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return (executeCompare(pc,sql,qr, expression, row)==0)?Boolean.TRUE:Boolean.FALSE;
}
/**
*
* execute a not equal operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeNEQ(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return (executeCompare(pc,sql,qr, expression, row)!=0)?Boolean.TRUE:Boolean.FALSE;
}
/**
*
* execute a less than operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeLT(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return (executeCompare(pc,sql,qr, expression, row)<0)?Boolean.TRUE:Boolean.FALSE;
}
/**
*
* execute a less than or equal operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeLTE(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return (executeCompare(pc,sql,qr, expression, row)<=0)?Boolean.TRUE:Boolean.FALSE;
}
/**
*
* execute a greater than operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeGT(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return (executeCompare(pc,sql,qr, expression, row)>0)?Boolean.TRUE:Boolean.FALSE;
}
/**
*
* execute a greater than or equal operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeGTE(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return (executeCompare(pc,sql,qr, expression, row)>=0)?Boolean.TRUE:Boolean.FALSE;
}
/**
*
* execute a equal operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private int executeCompare(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return
Operator.compare(
executeExp(pc,sql,qr,expression.getOperand(0),row)
,
executeExp(pc,sql,qr,expression.getOperand(1),row)
);
}
private Object executeLike(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return Caster.toBoolean(like(sql,
Caster.toString(executeExp(pc,sql,qr,expression.getOperand(0),row)),
Caster.toString(executeExp(pc,sql,qr,expression.getOperand(1),row))));
}
private boolean like(SQL sql,String haystack, String needle) throws PageException {
return LikeCompare.like(sql,haystack, needle);
}
/**
*
* execute a greater than or equal operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeIn(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
int len=expression.nbOperands();
Object left=executeExp(pc,sql,qr,expression.getOperand(0),row);
for(int i=1;i<len;i++) {
if(Operator.compare(left,executeExp(pc,sql,qr,expression.getOperand(i),row))==0)
return Boolean.TRUE;
}
return Boolean.FALSE;
}
/**
*
* execute a minus operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeMinus(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return
new Double(
Caster.toDoubleValue(executeExp(pc,sql,qr,expression.getOperand(0),row))
-
Caster.toDoubleValue(executeExp(pc,sql,qr,expression.getOperand(1),row))
);
}
/**
*
* execute a divide operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeDivide(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return
new Double(
Caster.toDoubleValue(executeExp(pc,sql,qr,expression.getOperand(0),row))
/
Caster.toDoubleValue(executeExp(pc,sql,qr,expression.getOperand(1),row))
);
}
/**
*
* execute a multiply operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeMultiply(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return
new Double(
Caster.toDoubleValue(executeExp(pc,sql,qr,expression.getOperand(0),row))
*
Caster.toDoubleValue(executeExp(pc,sql,qr,expression.getOperand(1),row))
);
}
/**
*
* execute a multiply operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeExponent(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
return
Integer.valueOf(
Caster.toIntValue(executeExp(pc,sql,qr,expression.getOperand(0),row))
^
Caster.toIntValue(executeExp(pc,sql,qr,expression.getOperand(1),row))
);
}
/**
*
* execute a plus operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executePlus(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
Object left=executeExp(pc,sql,qr,expression.getOperand(0),row);
Object right=executeExp(pc,sql,qr,expression.getOperand(1),row);
try {
return new Double(Caster.toDoubleValue(left)+Caster.toDoubleValue(right));
} catch (PageException e) {
return Caster.toString(left)+Caster.toString(right);
}
}
/**
*
* execute a between operation
* @param sql
* @param qr QueryResult to execute on it
* @param expression
* @param row row of resultset to execute
* @return result
* @throws PageException
*/
private Object executeBetween(PageContext pc,SQL sql,Query qr, ZExpression expression, int row) throws PageException {
Object left=executeExp(pc,sql,qr,expression.getOperand(0),row);
Object right1=executeExp(pc,sql,qr,expression.getOperand(1),row);
Object right2=executeExp(pc,sql,qr,expression.getOperand(2),row);
return (
(Operator.compare(left,right1)<=0)
&&
(Operator.compare(left,right2)>=0)
)?Boolean.TRUE:Boolean.FALSE;
}
/**
* Executes a constant value
* @param sql
* @param qr
* @param constant
* @param row
* @return result
* @throws PageException
*/
private Object executeConstant(SQL sql,Query qr, ZConstant constant, int row) throws PageException {
switch(constant.getType()) {
case ZConstant.COLUMNNAME: {
if(constant.getValue().equals(SQLPrettyfier.PLACEHOLDER_QUESTION)) {
int pos=sql.getPosition();
sql.setPosition(pos+1);
if(sql.getItems().length<=pos) throw new DatabaseException("invalid syntax for SQL Statement",null,sql,null);
return sql.getItems()[pos].getValueForCF();
}
return qr.getAt(ListUtil.last(constant.getValue(),".",true),row);
}
case ZConstant.NULL: return null;
case ZConstant.NUMBER: return Caster.toDouble(constant.getValue());
case ZConstant.STRING: return constant.getValue();
case ZConstant.UNKNOWN:
default: throw new DatabaseException("invalid constant value",null,sql,null);
}
}
}