001 package railo.runtime.type; 002 003 import java.io.ByteArrayInputStream; 004 import java.io.IOException; 005 import java.io.InputStream; 006 import java.io.ObjectInput; 007 import java.io.ObjectOutput; 008 import java.io.Reader; 009 import java.io.StringReader; 010 import java.io.UnsupportedEncodingException; 011 import java.math.BigDecimal; 012 import java.net.URL; 013 import java.sql.Blob; 014 import java.sql.Clob; 015 import java.sql.NClob; 016 import java.sql.PreparedStatement; 017 import java.sql.Ref; 018 import java.sql.ResultSet; 019 import java.sql.ResultSetMetaData; 020 import java.sql.RowId; 021 import java.sql.SQLException; 022 import java.sql.SQLWarning; 023 import java.sql.SQLXML; 024 import java.sql.Statement; 025 import java.sql.Time; 026 import java.sql.Timestamp; 027 import java.sql.Types; 028 import java.util.Arrays; 029 import java.util.Calendar; 030 import java.util.Comparator; 031 import java.util.HashMap; 032 import java.util.HashSet; 033 import java.util.Iterator; 034 import java.util.Map; 035 import java.util.Map.Entry; 036 import java.util.Set; 037 import java.util.TimeZone; 038 039 import railo.commons.db.DBUtil; 040 import railo.commons.io.IOUtil; 041 import railo.commons.lang.StringUtil; 042 import railo.commons.sql.SQLUtil; 043 import railo.loader.engine.CFMLEngineFactory; 044 import railo.runtime.PageContext; 045 import railo.runtime.config.NullSupportHelper; 046 import railo.runtime.converter.ScriptConverter; 047 import railo.runtime.db.CFTypes; 048 import railo.runtime.db.DataSourceUtil; 049 import railo.runtime.db.DatasourceConnection; 050 import railo.runtime.db.DatasourceConnectionImpl; 051 import railo.runtime.db.SQL; 052 import railo.runtime.db.SQLCaster; 053 import railo.runtime.db.SQLItem; 054 import railo.runtime.dump.DumpData; 055 import railo.runtime.dump.DumpProperties; 056 import railo.runtime.engine.ThreadLocalPageContext; 057 import railo.runtime.exp.ApplicationException; 058 import railo.runtime.exp.DatabaseException; 059 import railo.runtime.exp.ExpressionException; 060 import railo.runtime.exp.PageException; 061 import railo.runtime.exp.PageRuntimeException; 062 import railo.runtime.interpreter.CFMLExpressionInterpreter; 063 import railo.runtime.op.Caster; 064 import railo.runtime.op.Decision; 065 import railo.runtime.op.Duplicator; 066 import railo.runtime.op.ThreadLocalDuplication; 067 import railo.runtime.op.date.DateCaster; 068 import railo.runtime.query.caster.Cast; 069 import railo.runtime.type.comparator.NumberSortRegisterComparator; 070 import railo.runtime.type.comparator.SortRegister; 071 import railo.runtime.type.comparator.SortRegisterComparator; 072 import railo.runtime.type.dt.DateTime; 073 import railo.runtime.type.dt.DateTimeImpl; 074 import railo.runtime.type.it.CollectionIterator; 075 import railo.runtime.type.it.EntryIterator; 076 import railo.runtime.type.it.ForEachQueryIterator; 077 import railo.runtime.type.it.KeyIterator; 078 import railo.runtime.type.it.StringIterator; 079 import railo.runtime.type.sql.BlobImpl; 080 import railo.runtime.type.sql.ClobImpl; 081 import railo.runtime.type.util.ArrayUtil; 082 import railo.runtime.type.util.CollectionUtil; 083 import railo.runtime.type.util.KeyConstants; 084 import railo.runtime.type.util.ListUtil; 085 import railo.runtime.type.util.MemberUtil; 086 import railo.runtime.type.util.QueryUtil; 087 088 /** 089 * implementation of the query interface 090 */ 091 /** 092 * 093 */ 094 public class QueryImpl implements Query,Objects { 095 096 private static final long serialVersionUID = 1035795427320192551L; 097 098 099 /** 100 * @return the template 101 */ 102 public String getTemplate() { 103 return template; 104 } 105 106 public static final Collection.Key GENERATED_KEYS = KeyImpl.intern("GENERATED_KEYS"); 107 public static final Collection.Key GENERATEDKEYS = KeyImpl.intern("GENERATEDKEYS"); 108 public static final Collection.Key ID = KeyImpl.intern("ID"); 109 110 111 112 //private static int count=0; 113 private QueryColumnImpl[] columns; 114 private Collection.Key[] columnNames; 115 private SQL sql; 116 private ArrayInt arrCurrentRow=new ArrayInt(); 117 private int recordcount=0; 118 private int columncount; 119 private long exeTime=0; 120 private boolean isCached=false; 121 private String name; 122 private int updateCount; 123 private QueryImpl generatedKeys; 124 private String template; 125 126 127 @Override 128 public int executionTime() { 129 return (int) exeTime; 130 } 131 132 /** 133 * create a QueryImpl from a SQL Resultset 134 * @param result SQL Resultset 135 * @param maxrow 136 * @param name 137 * @throws PageException 138 */ 139 public QueryImpl(ResultSet result, int maxrow, String name, TimeZone tz) throws PageException { 140 this.name=name; 141 //Stopwatch stopwatch=new Stopwatch(); 142 //stopwatch.start(); 143 long start=System.nanoTime(); 144 try { 145 fillResult(null,result,maxrow,false,false,tz); 146 } catch (SQLException e) { 147 throw new DatabaseException(e,null); 148 } catch (IOException e) { 149 throw Caster.toPageException(e); 150 } 151 exeTime=System.nanoTime()-start; 152 } 153 154 /** 155 * Constructor of the class 156 * only for internal usage (cloning/deserialize) 157 */ 158 public QueryImpl() { 159 } 160 161 162 public QueryImpl(ResultSet result, String name,TimeZone tz) throws PageException { 163 this.name=name; 164 165 try { 166 fillResult(null,result,-1,true,false,tz); 167 } 168 catch (SQLException e) { 169 throw new DatabaseException(e,null); 170 } 171 catch (Exception e) { 172 throw Caster.toPageException(e); 173 } 174 } 175 176 /** 177 * constructor of the class, to generate a resultset from a sql query 178 * @param dc Connection to a database 179 * @param name 180 * @param sql sql to execute 181 * @param maxrow maxrow for the resultset 182 * @throws PageException 183 */ 184 public QueryImpl(PageContext pc, DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,int timeout, String name) throws PageException { 185 this(pc,dc, sql, maxrow, fetchsize, timeout, name,null,false,true); 186 } 187 188 189 public QueryImpl(PageContext pc, DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,int timeout, String name,String template) throws PageException { 190 this(pc,dc, sql, maxrow, fetchsize, timeout, name,template,false,true); 191 } 192 193 public QueryImpl(PageContext pc, DatasourceConnection dc,SQL sql,int maxrow, int fetchsize,int timeout, String name,String template,boolean createUpdateData, boolean allowToCachePreperadeStatement) throws PageException { 194 this.name=name; 195 this.template=template; 196 this.sql=sql; 197 TimeZone tz = ThreadLocalPageContext.getTimeZone(pc); 198 //ResultSet result=null; 199 Statement stat=null; 200 // check SQL Restrictions 201 if(dc.getDatasource().hasSQLRestriction()) { 202 QueryUtil.checkSQLRestriction(dc,sql); 203 } 204 // check if datasource support Generated Keys 205 boolean createGeneratedKeys=createUpdateData; 206 if(createUpdateData){ 207 DatasourceConnectionImpl dci=(DatasourceConnectionImpl) dc; 208 if(!dci.supportsGetGeneratedKeys())createGeneratedKeys=false; 209 } 210 211 212 //Stopwatch stopwatch=new Stopwatch(); 213 long start=System.nanoTime(); 214 //stopwatch.start(); 215 boolean hasResult=false; 216 //boolean closeStatement=true; 217 try { 218 SQLItem[] items=sql.getItems(); 219 if(items.length==0) { 220 stat=dc.getConnection().createStatement(); 221 setAttributes(stat,maxrow,fetchsize,timeout); 222 // some driver do not support second argument 223 //hasResult=createGeneratedKeys?stat.execute(sql.getSQLString(),Statement.RETURN_GENERATED_KEYS):stat.execute(sql.getSQLString()); 224 hasResult=QueryUtil.execute(pc,stat,createGeneratedKeys,sql); 225 } 226 else { 227 // some driver do not support second argument 228 PreparedStatement preStat = dc.getPreparedStatement(sql, createGeneratedKeys,allowToCachePreperadeStatement); 229 //closeStatement=false; 230 stat=preStat; 231 setAttributes(preStat,maxrow,fetchsize,timeout); 232 setItems(ThreadLocalPageContext.getTimeZone(pc),preStat,items); 233 hasResult=QueryUtil.execute(pc,preStat); 234 } 235 int uc; 236 ResultSet res; 237 do { 238 if(hasResult) { 239 res=stat.getResultSet(); 240 if(fillResult(dc,res, maxrow, true,createGeneratedKeys,tz))break; 241 } 242 else if((uc=setUpdateCount(stat))!=-1){ 243 if(uc>0 && createGeneratedKeys)setGeneratedKeys(dc, stat,tz); 244 } 245 else break; 246 try{ 247 hasResult=stat.getMoreResults(Statement.CLOSE_CURRENT_RESULT); 248 } 249 catch(Throwable t){ 250 break; 251 } 252 } 253 while(true); 254 } 255 catch (SQLException e) { 256 throw new DatabaseException(e,sql,dc); 257 } 258 catch (Throwable e) { 259 throw Caster.toPageException(e); 260 } 261 finally { 262 //if(closeStatement) 263 DBUtil.closeEL(stat); 264 } 265 exeTime=System.nanoTime()-start; 266 267 if(columncount==0) { 268 if(columnNames==null) columnNames=new Collection.Key[0]; 269 if(columns==null) columns=new QueryColumnImpl[0]; 270 } 271 } 272 273 private int setUpdateCount(Statement stat) { 274 try{ 275 int uc=stat.getUpdateCount(); 276 if(uc>-1){ 277 updateCount+=uc; 278 return uc; 279 } 280 } 281 catch(Throwable t){} 282 return -1; 283 } 284 285 private boolean setGeneratedKeys(DatasourceConnection dc,Statement stat, TimeZone tz) { 286 try{ 287 ResultSet rs = stat.getGeneratedKeys(); 288 setGeneratedKeys(dc, rs,tz); 289 return true; 290 } 291 catch(Throwable t) {t.printStackTrace(); 292 return false; 293 } 294 } 295 296 private void setGeneratedKeys(DatasourceConnection dc,ResultSet rs, TimeZone tz) throws PageException { 297 generatedKeys=new QueryImpl(rs,"",tz); 298 299 // ACF compatibility action 300 if(generatedKeys.getColumnCount()==1 && DataSourceUtil.isMSSQL(dc)) { 301 generatedKeys.renameEL(GENERATED_KEYS,KeyConstants._IDENTITYCOL); 302 generatedKeys.renameEL(GENERATEDKEYS,KeyConstants._IDENTITYCOL); 303 generatedKeys.renameEL(ID,KeyConstants._IDENTITYCOL); 304 } 305 } 306 307 /*private void setUpdateData(Statement stat, boolean createGeneratedKeys, boolean createUpdateCount) { 308 309 // update Count 310 if(createUpdateCount){ 311 try{ 312 updateCount=stat.getUpdateCount(); 313 } 314 catch(Throwable t){ 315 t.printStackTrace(); 316 } 317 } 318 // generated keys 319 if(createGeneratedKeys){ 320 try{ 321 ResultSet rs = stat.getGeneratedKeys(); 322 generatedKeys=new QueryImpl(rs,""); 323 } 324 catch(Throwable t){ 325 t.printStackTrace(); 326 } 327 } 328 }*/ 329 330 331 private void setItems(TimeZone tz,PreparedStatement preStat, SQLItem[] items) throws DatabaseException, PageException, SQLException { 332 for(int i=0;i<items.length;i++) { 333 SQLCaster.setValue(tz,preStat,i+1,items[i]); 334 } 335 } 336 337 public int getUpdateCount() { 338 return updateCount; 339 } 340 public Query getGeneratedKeys() { 341 return generatedKeys; 342 } 343 344 private void setAttributes(Statement stat,int maxrow, int fetchsize,int timeout) throws SQLException { 345 if(maxrow>-1) stat.setMaxRows(maxrow); 346 if(fetchsize>0)stat.setFetchSize(fetchsize); 347 if(timeout>0)stat.setQueryTimeout(timeout); 348 } 349 350 private boolean fillResult(DatasourceConnection dc, ResultSet result, int maxrow, boolean closeResult,boolean createGeneratedKeys, TimeZone tz) throws SQLException, IOException, PageException { 351 if(result==null) return false; 352 recordcount=0; 353 ResultSetMetaData meta = result.getMetaData(); 354 columncount=meta.getColumnCount(); 355 356 // set header arrays 357 Collection.Key[] tmpColumnNames = new Collection.Key[columncount]; 358 int count=0; 359 Collection.Key key; 360 String columnName; 361 for(int i=0;i<columncount;i++) { 362 columnName=QueryUtil.getColumnName(meta,i+1); 363 if(StringUtil.isEmpty(columnName))columnName="column_"+i; 364 key=KeyImpl.init(columnName); 365 int index=getIndexFrom(tmpColumnNames,key,0,i); 366 if(index==-1) { 367 tmpColumnNames[i]=key; 368 count++; 369 } 370 } 371 372 373 columncount=count; 374 columnNames=new Collection.Key[columncount]; 375 columns=new QueryColumnImpl[columncount]; 376 Cast[] casts = new Cast[columncount]; 377 378 // get all used ints 379 int[] usedColumns=new int[columncount]; 380 count=0; 381 for(int i=0;i<tmpColumnNames.length;i++) { 382 if(tmpColumnNames[i]!=null) { 383 usedColumns[count++]=i; 384 } 385 } 386 387 // set used column names 388 int[] types=new int[columns.length]; 389 for(int i=0;i<usedColumns.length;i++) { 390 columnNames[i]=tmpColumnNames[usedColumns[i]]; 391 columns[i]=new QueryColumnImpl(this,columnNames[i],types[i]=meta.getColumnType(usedColumns[i]+1)); 392 393 if(types[i]==Types.TIMESTAMP) casts[i]=Cast.TIMESTAMP; 394 else if(types[i]==Types.TIME) casts[i]=Cast.TIME; 395 else if(types[i]==Types.DATE) casts[i]=Cast.DATE; 396 else if(types[i]==Types.CLOB) casts[i]=Cast.CLOB; 397 else if(types[i]==Types.BLOB) casts[i]=Cast.BLOB; 398 else if(types[i]==Types.BIT) casts[i]=Cast.BIT; 399 else if(types[i]==Types.ARRAY) casts[i]=Cast.ARRAY; 400 //else if(types[i]==Types.TINYINT) casts[i]=Cast.ARRAY; 401 402 else if(types[i]==CFTypes.OPAQUE){ 403 if(SQLUtil.isOracle(result.getStatement().getConnection())) 404 casts[i]=Cast.ORACLE_OPAQUE; 405 else 406 casts[i]=Cast.OTHER; 407 408 } 409 else casts[i]=Cast.OTHER; 410 } 411 412 if(createGeneratedKeys && columncount==1 && columnNames[0].equals(GENERATED_KEYS) && dc!=null && DataSourceUtil.isMSSQLDriver(dc)) { 413 columncount=0; 414 columnNames=null; 415 columns=null; 416 setGeneratedKeys(dc, result,tz); 417 return false; 418 } 419 420 421 // fill data 422 //Object o; 423 while(result.next()) { 424 if(maxrow>-1 && recordcount>=maxrow) { 425 break; 426 } 427 for(int i=0;i<usedColumns.length;i++) { 428 columns[i].add(casts[i].toCFType(tz,types[i], result, usedColumns[i]+1)); 429 } 430 ++recordcount; 431 } 432 if(closeResult)result.close(); 433 return true; 434 } 435 436 private Object toBytes(Blob blob) throws IOException, SQLException { 437 return IOUtil.toBytes((blob).getBinaryStream()); 438 } 439 440 private static Object toString(Clob clob) throws IOException, SQLException { 441 return IOUtil.toString(clob.getCharacterStream()); 442 } 443 444 private static int getIndexFrom(Collection.Key[] tmpColumnNames, Collection.Key key, int from, int to) { 445 for(int i=from;i<to;i++) { 446 if(tmpColumnNames[i]!=null && tmpColumnNames[i].equalsIgnoreCase(key))return i; 447 } 448 return -1; 449 } 450 451 /** 452 * constructor of the class, to generate a empty resultset (no database execution) 453 * @param strColumns columns for the resultset 454 * @param rowNumber count of rows to generate (empty fields) 455 * @param name 456 * @deprecated use instead <code>QueryImpl(Collection.Key[] columnKeys, int rowNumber,String name)</code> 457 */ 458 public QueryImpl(String[] strColumns, int rowNumber,String name) { 459 this.name=name; 460 columncount=strColumns.length; 461 recordcount=rowNumber; 462 columnNames=new Collection.Key[columncount]; 463 columns=new QueryColumnImpl[columncount]; 464 for(int i=0;i<strColumns.length;i++) { 465 columnNames[i]=KeyImpl.init(strColumns[i].trim()); 466 columns[i]=new QueryColumnImpl(this,columnNames[i],Types.OTHER,recordcount); 467 } 468 } 469 470 /** 471 * constructor of the class, to generate a empty resultset (no database execution) 472 * @param strColumns columns for the resultset 473 * @param rowNumber count of rows to generate (empty fields) 474 * @param name 475 */ 476 public QueryImpl(Collection.Key[] columnKeys, int rowNumber,String name) throws DatabaseException { 477 this.name=name; 478 columncount=columnKeys.length; 479 recordcount=rowNumber; 480 columnNames=new Collection.Key[columncount]; 481 columns=new QueryColumnImpl[columncount]; 482 for(int i=0;i<columnKeys.length;i++) { 483 columnNames[i]=columnKeys[i]; 484 columns[i]=new QueryColumnImpl(this,columnNames[i],Types.OTHER,recordcount); 485 } 486 validateColumnNames(columnNames); 487 } 488 489 /** 490 * constructor of the class, to generate a empty resultset (no database execution) 491 * @param strColumns columns for the resultset 492 * @param strTypes array of the types 493 * @param rowNumber count of rows to generate (empty fields) 494 * @param name 495 * @throws DatabaseException 496 */ 497 public QueryImpl(String[] strColumns, String[] strTypes, int rowNumber, String name) throws DatabaseException { 498 this.name=name; 499 columncount=strColumns.length; 500 if(strTypes.length!=columncount) throw new DatabaseException("columns and types has not the same count",null,null,null); 501 recordcount=rowNumber; 502 columnNames=new Collection.Key[columncount]; 503 columns=new QueryColumnImpl[columncount]; 504 for(int i=0;i<strColumns.length;i++) { 505 columnNames[i]=KeyImpl.init(strColumns[i].trim()); 506 columns[i]=new QueryColumnImpl(this,columnNames[i],SQLCaster.toIntType(strTypes[i]),recordcount); 507 } 508 } 509 510 /** 511 * constructor of the class, to generate a empty resultset (no database execution) 512 * @param strColumns columns for the resultset 513 * @param strTypes array of the types 514 * @param rowNumber count of rows to generate (empty fields) 515 * @param name 516 * @throws DatabaseException 517 */ 518 public QueryImpl(Collection.Key[] columnNames, String[] strTypes, int rowNumber, String name) throws DatabaseException { 519 this.name=name; 520 this.columnNames=columnNames; 521 columncount=columnNames.length; 522 if(strTypes.length!=columncount) throw new DatabaseException("columns and types has not the same count",null,null,null); 523 recordcount=rowNumber; 524 columns=new QueryColumnImpl[columncount]; 525 for(int i=0;i<columnNames.length;i++) { 526 columns[i]=new QueryColumnImpl(this,columnNames[i],SQLCaster.toIntType(strTypes[i]),recordcount); 527 } 528 validateColumnNames(columnNames); 529 } 530 531 /** 532 * constructor of the class, to generate a empty resultset (no database execution) 533 * @param arrColumns columns for the resultset 534 * @param rowNumber count of rows to generate (empty fields) 535 * @param name 536 * @throws DatabaseException 537 */ 538 public QueryImpl(Array arrColumns, int rowNumber, String name) throws DatabaseException { 539 this.name=name; 540 columncount=arrColumns.size(); 541 recordcount=rowNumber; 542 columnNames=new Collection.Key[columncount]; 543 columns=new QueryColumnImpl[columncount]; 544 for(int i=0;i<columncount;i++) { 545 columnNames[i]=KeyImpl.init(arrColumns.get(i+1,"").toString().trim()); 546 columns[i]=new QueryColumnImpl(this,columnNames[i],Types.OTHER,recordcount); 547 } 548 validateColumnNames(columnNames); 549 } 550 551 /** 552 * constructor of the class, to generate a empty resultset (no database execution) 553 * @param arrColumns columns for the resultset 554 * @param arrTypes type of the columns 555 * @param rowNumber count of rows to generate (empty fields) 556 * @param name 557 * @throws PageException 558 */ 559 public QueryImpl(Array arrColumns, Array arrTypes, int rowNumber, String name) throws PageException { 560 this.name=name; 561 columncount=arrColumns.size(); 562 if(arrTypes.size()!=columncount) throw new DatabaseException("columns and types has not the same count",null,null,null); 563 recordcount=rowNumber; 564 columnNames=new Collection.Key[columncount]; 565 columns=new QueryColumnImpl[columncount]; 566 for(int i=0;i<columncount;i++) { 567 columnNames[i]=KeyImpl.init(arrColumns.get(i+1,"").toString().trim()); 568 columns[i]=new QueryColumnImpl(this,columnNames[i],SQLCaster.toIntType(Caster.toString(arrTypes.get(i+1,""))),recordcount); 569 } 570 validateColumnNames(columnNames); 571 } 572 573 /** 574 * constructor of the class 575 * @param columnNames columns definition as String Array 576 * @param arrColumns values 577 * @param name 578 * @throws DatabaseException 579 */ 580 581 public QueryImpl(String[] strColumnNames, Array[] arrColumns, String name) throws DatabaseException { 582 this(_toKeys(strColumnNames),arrColumns,name); 583 } 584 585 private static void validateColumnNames(Key[] columnNames) throws DatabaseException { 586 Set<String> testMap=new HashSet<String>(); 587 for(int i=0 ;i<columnNames.length;i++) { 588 589 // Only allow column names that are valid variable name 590 //if(!Decision.isSimpleVariableName(columnNames[i])) 591 // throw new DatabaseException("invalid column name ["+columnNames[i]+"] for query", "column names must start with a letter and can be followed by letters numbers and underscores [_]. RegExp:[a-zA-Z][a-zA-Z0-9_]*",null,null,null); 592 593 if(testMap.contains(columnNames[i].getLowerString())) 594 throw new DatabaseException("invalid parameter for query, ambiguous column name "+columnNames[i],"columnNames: "+ListUtil.arrayToListTrim( _toStringKeys(columnNames),","),null,null,null); 595 testMap.add(columnNames[i].getLowerString()); 596 } 597 } 598 599 600 private static Collection.Key[] _toKeys(String[] strColumnNames) { 601 Collection.Key[] columnNames=new Collection.Key[strColumnNames.length]; 602 for(int i=0 ;i<columnNames.length;i++) { 603 columnNames[i]=KeyImpl.init(strColumnNames[i].trim()); 604 } 605 return columnNames; 606 } 607 private static String[] _toStringKeys(Collection.Key[] columnNames) { 608 String[] strColumnNames=new String[columnNames.length]; 609 for(int i=0 ;i<strColumnNames.length;i++) { 610 strColumnNames[i]=columnNames[i].getString(); 611 } 612 return strColumnNames; 613 } 614 615 /*public QueryImpl(Collection.Key[] columnNames, QueryColumn[] columns, String name,long exeTime, boolean isCached,SQL sql) throws DatabaseException { 616 this.columnNames=columnNames; 617 this.columns=columns; 618 this.exeTime=exeTime; 619 this.isCached=isCached; 620 this.name=name; 621 this.columncount=columnNames.length; 622 this.recordcount=columns.length==0?0:columns[0].size(); 623 this.sql=sql; 624 625 }*/ 626 627 public QueryImpl(Collection.Key[] columnNames, Array[] arrColumns, String name) throws DatabaseException { 628 this.name=name; 629 630 if(columnNames.length!=arrColumns.length) 631 throw new DatabaseException("invalid parameter for query, not the same count from names and columns","names:"+columnNames.length+";columns:"+arrColumns.length,null,null,null); 632 int len=0; 633 columns=new QueryColumnImpl[arrColumns.length]; 634 if(arrColumns.length>0) { 635 // test columns 636 len=arrColumns[0].size(); 637 for(int i=0;i<arrColumns.length;i++) { 638 if(arrColumns[i].size()!=len) 639 throw new DatabaseException("invalid parameter for query, all columns must have the same size","column[1]:"+len+"<>column["+(i+1)+"]:"+arrColumns[i].size(),null,null,null); 640 //columns[i]=new QueryColumnTypeFlex(arrColumns[i]); 641 columns[i]=new QueryColumnImpl(this,columnNames[i],arrColumns[i],Types.OTHER); 642 } 643 // test keys 644 validateColumnNames(columnNames); 645 } 646 647 columncount=columns.length; 648 recordcount=len; 649 this.columnNames=columnNames; 650 } 651 652 /** 653 * constructor of the class 654 * @param columnList 655 * @param data 656 * @param name 657 * @throws DatabaseException 658 */ 659 public QueryImpl(String[] strColumnList, Object[][] data,String name) throws DatabaseException { 660 661 this(toCollKeyArr(strColumnList),data.length,name); 662 663 for(int iRow=0;iRow<data.length;iRow++) { 664 Object[] row=data[iRow]; 665 for(int iCol=0;iCol<row.length;iCol++) { 666 //print.ln(columnList[iCol]+":"+iRow+"="+row[iCol]); 667 setAtEL(columnNames[iCol],iRow+1,row[iCol]); 668 } 669 } 670 } 671 672 private static Collection.Key[] toCollKeyArr(String[] strColumnList) { 673 Collection.Key[] columnList=new Collection.Key[strColumnList.length]; 674 for(int i=0 ;i<columnList.length;i++) { 675 columnList[i]=KeyImpl.init(strColumnList[i].trim()); 676 } 677 return columnList; 678 } 679 680 @Override 681 public int size() { 682 return columncount; 683 } 684 685 @Override 686 public Collection.Key[] keys() { 687 return columnNames; 688 } 689 690 @Override 691 public Object removeEL(Collection.Key key) { 692 return setEL(key,null); 693 } 694 695 @Override 696 public Object remove(Collection.Key key) throws PageException { 697 return set(key,null); 698 } 699 700 @Override 701 public void clear() { 702 for(int i=0;i<columns.length;i++) { 703 columns[i].clear(); 704 } 705 recordcount=0; 706 } 707 708 @Override 709 public Object get(String key, Object defaultValue) { 710 return getAt(key, 711 arrCurrentRow.get(getPid(), 1), 712 defaultValue); 713 } 714 715 //private static int pidc=0; 716 private int getPid() { 717 718 PageContext pc = ThreadLocalPageContext.get(); 719 if(pc==null) { 720 pc=CFMLEngineFactory.getInstance().getThreadPageContext(); 721 if(pc==null)throw new RuntimeException("cannot get pid for current thread"); 722 } 723 return pc.getId(); 724 } 725 726 @Override 727 public Object get(Collection.Key key, Object defaultValue) { 728 return getAt(key, 729 arrCurrentRow.get(getPid(), 1), 730 defaultValue); 731 } 732 733 @Override 734 public Object get(String key) throws PageException { 735 return getAt(key, 736 arrCurrentRow.get(getPid(), 1) 737 ); 738 } 739 740 @Override 741 public Object get(Collection.Key key) throws PageException { 742 return getAt(key, 743 arrCurrentRow.get(getPid(), 1) 744 ); 745 } 746 747 @Override 748 public Object getAt(String key, int row, Object defaultValue) { 749 return getAt(KeyImpl.init(key), row, defaultValue); 750 } 751 752 public Object getAt(Collection.Key key, int row, Object defaultValue) { 753 int index=getIndexFromKey(key); 754 if(index!=-1) { 755 return columns[index].get(row,defaultValue); 756 } 757 if(key.getString().length()>0) { 758 char c=key.lowerCharAt(0); 759 if(c=='r') { 760 if(key.equals(KeyConstants._RECORDCOUNT)) return new Double(getRecordcount()); 761 } 762 else if(c=='c') { 763 if(key.equals(KeyConstants._CURRENTROW)) return new Double(row); 764 else if(key.equals(KeyConstants._COLUMNLIST)) return getColumnlist(true); 765 } 766 } 767 return defaultValue; 768 } 769 770 @Override 771 public Object getAt(String key, int row) throws PageException { 772 return getAt(KeyImpl.init(key), row); 773 } 774 775 @Override 776 public Object getAt(Collection.Key key, int row) throws PageException { 777 int index=getIndexFromKey(key); 778 if(index!=-1) { 779 if(NullSupportHelper.full()) return columns[index].get(row, null); 780 Object v = columns[index].get(row, null); 781 return v==null?"":v; 782 } 783 if(key.getString().length()>0) { 784 char c=key.lowerCharAt(0); 785 if(c=='r') { 786 if(key.equals(KeyConstants._RECORDCOUNT)) return new Double(getRecordcount()); 787 } 788 else if(c=='c') { 789 if(key.equals(KeyConstants._CURRENTROW)) return new Double(row); 790 else if(key.equals(KeyConstants._COLUMNLIST)) return getColumnlist(true); 791 } 792 } 793 throw new DatabaseException("column ["+key+"] not found in query, columns are ["+getColumnlist(false)+"]",null,sql,null); 794 } 795 796 @Override 797 public synchronized int removeRow(int row) throws PageException { 798 //disconnectCache(); 799 800 for(int i=0;i<columns.length;i++) { 801 columns[i].removeRow(row); 802 } 803 return --recordcount; 804 } 805 806 @Override 807 public int removeRowEL(int row) { 808 //disconnectCache(); 809 810 try { 811 return removeRow(row); 812 } catch (PageException e) { 813 return recordcount; 814 } 815 } 816 817 @Override 818 public QueryColumn removeColumn(String key) throws DatabaseException { 819 return removeColumn(KeyImpl.init(key)); 820 } 821 822 @Override 823 public QueryColumn removeColumn(Collection.Key key) throws DatabaseException { 824 //disconnectCache(); 825 826 QueryColumn removed = removeColumnEL(key); 827 if(removed==null) { 828 if(key.equals(KeyConstants._RECORDCOUNT) || 829 key.equals(KeyConstants._CURRENTROW) || 830 key.equals(KeyConstants._COLUMNLIST)) 831 throw new DatabaseException("can't remove "+key+" this is not a row","existing rows are ["+getColumnlist(false)+"]",null,null,null); 832 throw new DatabaseException("can't remove row ["+key+"], this row doesn't exist", 833 "existing rows are ["+getColumnlist(false)+"]",null,null,null); 834 } 835 return removed; 836 } 837 838 @Override 839 public synchronized QueryColumn removeColumnEL(String key) { 840 return removeColumnEL(KeyImpl.init(key)); 841 } 842 843 public QueryColumn removeColumnEL(Collection.Key key) { 844 //disconnectCache(); 845 846 int index=getIndexFromKey(key); 847 if(index!=-1) { 848 int current=0; 849 QueryColumn removed=null; 850 Collection.Key[] newColumnNames=new Collection.Key[columnNames.length-1]; 851 QueryColumnImpl[] newColumns=new QueryColumnImpl[columns.length-1]; 852 for(int i=0;i<columns.length;i++) { 853 if(i==index) { 854 removed=columns[i]; 855 } 856 else { 857 newColumnNames[current]=columnNames[i]; 858 newColumns[current++]=columns[i]; 859 } 860 } 861 columnNames=newColumnNames; 862 columns=newColumns; 863 columncount--; 864 return removed; 865 } 866 return null; 867 } 868 869 @Override 870 public Object setEL(String key, Object value) { 871 return setEL(KeyImpl.init(key),value); 872 } 873 874 @Override 875 public Object setEL(Collection.Key key, Object value) { 876 return setAtEL(key, 877 arrCurrentRow.get(getPid(), 1), 878 value); 879 } 880 881 @Override 882 public Object set(String key, Object value) throws PageException { 883 return set(KeyImpl.init(key),value); 884 } 885 886 @Override 887 public Object set(Collection.Key key, Object value) throws PageException { 888 return setAt(key, 889 arrCurrentRow.get(getPid(), 1), 890 value); 891 } 892 893 @Override 894 public Object setAt(String key,int row, Object value) throws PageException { 895 return setAt(KeyImpl.init(key), row, value); 896 } 897 898 public Object setAt(Collection.Key key, int row, Object value) throws PageException { 899 int index=getIndexFromKey(key); 900 if(index!=-1) { 901 return columns[index].set(row,value); 902 } 903 throw new DatabaseException("column ["+key+"] does not exist","columns are ["+getColumnlist(false)+"]",null,sql,null); 904 } 905 906 @Override 907 public Object setAtEL(String key,int row, Object value) { 908 return setAtEL(KeyImpl.init(key), row, value); 909 } 910 911 public Object setAtEL(Collection.Key key, int row, Object value) { 912 int index=getIndexFromKey(key); 913 if(index!=-1) { 914 return columns[index].setEL(row,value); 915 } 916 return null; 917 } 918 919 @Override 920 public boolean next() { 921 return next(getPid()); 922 } 923 924 @Override 925 public boolean next(int pid) { 926 if(recordcount>=(arrCurrentRow.set(pid,arrCurrentRow.get(pid,0)+1))) { 927 return true; 928 } 929 arrCurrentRow.set(pid,0); 930 return false; 931 } 932 933 @Override 934 public void reset() { 935 reset(getPid()); 936 } 937 938 public void reset(int pid) { 939 arrCurrentRow.set(pid,0); 940 } 941 942 @Override 943 public int getRecordcount() { 944 return recordcount; 945 } 946 947 @Override 948 public int getCurrentrow(int pid) { 949 return arrCurrentRow.get(pid,1); 950 } 951 952 953 /** 954 * return a string list of all columns 955 * @return string list 956 */ 957 public String getColumnlist(boolean upperCase) { 958 959 StringBuffer sb=new StringBuffer(); 960 for(int i=0;i<columnNames.length;i++) { 961 if(i>0)sb.append(','); 962 sb.append(upperCase?columnNames[i].getUpperString():columnNames[i].getString()); 963 } 964 return sb.toString(); 965 } 966 public String getColumnlist() { 967 return getColumnlist(true); 968 } 969 970 public boolean go(int index) { 971 return go(index,getPid()); 972 } 973 974 public boolean go(int index, int pid) { 975 if(index>0 && index<=recordcount) { 976 arrCurrentRow.set(pid, index); 977 return true; 978 } 979 arrCurrentRow.set(pid, 0); 980 return false; 981 } 982 983 @Override 984 public boolean isEmpty() { 985 return recordcount+columncount==0; 986 } 987 988 @Override 989 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 990 return QueryUtil.toDumpData(this, pageContext, maxlevel, dp); 991 } 992 993 /** 994 * sorts a query by a column 995 * @param column colun to sort 996 * @throws PageException 997 */ 998 public void sort(String column) throws PageException { 999 sort(column,Query.ORDER_ASC); 1000 } 1001 1002 @Override 1003 public void sort(Collection.Key column) throws PageException { 1004 sort(column,Query.ORDER_ASC); 1005 } 1006 1007 /** 1008 * sorts a query by a column 1009 * @param strColumn column to sort 1010 * @param order sort type (Query.ORDER_ASC or Query.ORDER_DESC) 1011 * @throws PageException 1012 */ 1013 public synchronized void sort(String strColumn, int order) throws PageException { 1014 //disconnectCache(); 1015 sort(getColumn(strColumn),order); 1016 } 1017 1018 @Override 1019 public synchronized void sort(Collection.Key keyColumn, int order) throws PageException { 1020 //disconnectCache(); 1021 sort(getColumn(keyColumn),order); 1022 } 1023 1024 private void sort(QueryColumn column, int order) throws PageException { 1025 int type = column.getType(); 1026 1027 SortRegister[] arr= ArrayUtil.toSortRegisterArray(column); 1028 1029 Arrays.sort(arr, 1030 ( 1031 type==Types.BIGINT || 1032 type==Types.BIT || 1033 type==Types.INTEGER || 1034 type==Types.SMALLINT || 1035 type==Types.TINYINT || 1036 type==Types.DECIMAL || 1037 type==Types.DOUBLE || 1038 type==Types.NUMERIC || 1039 type==Types.REAL)? 1040 1041 (Comparator)new NumberSortRegisterComparator(order==ORDER_ASC):(Comparator)new SortRegisterComparator(order==ORDER_ASC,true) 1042 ); 1043 1044 for(int i=0;i<columns.length;i++) { 1045 column=columns[i]; 1046 int len=column.size(); 1047 QueryColumnImpl newCol=new QueryColumnImpl(this,columnNames[i],columns[i].getType(),len); 1048 for(int y=1;y<=len;y++) { 1049 newCol.set(y,column.get(arr[y-1].getOldPosition()+1,null)); 1050 } 1051 columns[i]=newCol; 1052 } 1053 } 1054 1055 @Override 1056 public synchronized boolean addRow(int count) { 1057 //disconnectCache(); 1058 1059 for(int i=0;i<columns.length;i++) { 1060 QueryColumnPro column = columns[i]; 1061 column.addRow(count); 1062 } 1063 recordcount+=count; 1064 return true; 1065 } 1066 1067 @Override 1068 public boolean addColumn(String columnName, Array content) throws DatabaseException { 1069 return addColumn(columnName,content,Types.OTHER); 1070 } 1071 1072 public boolean addColumn(Collection.Key columnName, Array content) throws PageException { 1073 return addColumn(columnName,content,Types.OTHER); 1074 } 1075 1076 @Override 1077 public synchronized boolean addColumn(String columnName, Array content, int type) throws DatabaseException { 1078 return addColumn(KeyImpl.init(columnName.trim()), content, type); 1079 } 1080 1081 @Override 1082 public boolean addColumn(Collection.Key columnName, Array content, int type) throws DatabaseException { 1083 //disconnectCache(); 1084 // TODO Meta type 1085 content=(Array) Duplicator.duplicate(content,false); 1086 1087 if(getIndexFromKey(columnName)!=-1) 1088 throw new DatabaseException("column name ["+columnName.getString()+"] already exist",null,sql,null); 1089 if(content.size()!=getRecordcount()) { 1090 //throw new DatabaseException("array for the new column has not the same size like the query (arrayLen!=query.recordcount)"); 1091 if(content.size()>getRecordcount()) addRow(content.size()-getRecordcount()); 1092 else content.setEL(getRecordcount(),""); 1093 } 1094 QueryColumnImpl[] newColumns=new QueryColumnImpl[columns.length+1]; 1095 Collection.Key[] newColumnNames=new Collection.Key[columns.length+1]; 1096 boolean logUsage=false; 1097 for(int i=0;i<columns.length;i++) { 1098 newColumns[i]=columns[i]; 1099 newColumnNames[i]=columnNames[i]; 1100 if(!logUsage && columns[i] instanceof DebugQueryColumn) logUsage=true; 1101 } 1102 newColumns[columns.length]=new QueryColumnImpl(this,columnName,content,type); 1103 newColumnNames[columns.length]=columnName; 1104 columns=newColumns; 1105 columnNames=newColumnNames; 1106 1107 columncount++; 1108 1109 if(logUsage)enableShowQueryUsage(); 1110 1111 return true; 1112 } 1113 1114 1115 /* * 1116 * if this query is still connected with cache (same query also in cache) 1117 * it will disconnetd from cache (clone object and add clone to cache) 1118 */ 1119 //protected void disconnectCache() {} 1120 1121 1122 @Override 1123 public Object clone() { 1124 return cloneQuery(true); 1125 } 1126 1127 @Override 1128 public Collection duplicate(boolean deepCopy) { 1129 return cloneQuery(true); 1130 } 1131 1132 1133 1134 1135 /** 1136 * @return clones the query object 1137 */ 1138 public QueryImpl cloneQuery(boolean deepCopy) { 1139 QueryImpl newResult=new QueryImpl(); 1140 ThreadLocalDuplication.set(this, newResult); 1141 try{ 1142 if(columnNames!=null){ 1143 newResult.columnNames=new Collection.Key[columnNames.length]; 1144 newResult.columns=new QueryColumnImpl[columnNames.length]; 1145 for(int i=0;i<columnNames.length;i++) { 1146 newResult.columnNames[i]=columnNames[i]; 1147 newResult.columns[i]=columns[i].cloneColumnImpl(deepCopy); 1148 } 1149 } 1150 newResult.sql=sql; 1151 newResult.template=template; 1152 newResult.recordcount=recordcount; 1153 newResult.columncount=columncount; 1154 newResult.isCached=isCached; 1155 newResult.name=name; 1156 newResult.exeTime=exeTime; 1157 newResult.updateCount=updateCount; 1158 if(generatedKeys!=null)newResult.generatedKeys=generatedKeys.cloneQuery(false); 1159 return newResult; 1160 } 1161 finally { 1162 // ThreadLocalDuplication.remove(this); removed "remove" to catch sisters and brothers 1163 } 1164 } 1165 1166 @Override 1167 public synchronized int[] getTypes() { 1168 int[] types=new int[columns.length]; 1169 for(int i=0;i<columns.length;i++) { 1170 types[i]=columns[i].getType(); 1171 } 1172 return types; 1173 } 1174 1175 @Override 1176 public synchronized Map<Collection.Key,String> getTypesAsMap() { 1177 1178 Map<Collection.Key,String> map=new HashMap<Collection.Key,String>(); 1179 for(int i=0;i<columns.length;i++) { 1180 map.put(columnNames[i],columns[i].getTypeAsString()); 1181 } 1182 return map; 1183 } 1184 1185 @Override 1186 public QueryColumn getColumn(String key) throws DatabaseException { 1187 return getColumn(KeyImpl.init(key.trim())); 1188 } 1189 1190 @Override 1191 public QueryColumn getColumn(Collection.Key key) throws DatabaseException { 1192 int index=getIndexFromKey(key); 1193 if(index!=-1) return columns[index]; 1194 1195 if(key.getString().length()>0) { 1196 char c=key.lowerCharAt(0); 1197 if(c=='r') { 1198 if(key.equals(KeyConstants._RECORDCOUNT)) return new QueryColumnRef(this,key,Types.INTEGER); 1199 } 1200 if(c=='c') { 1201 if(key.equals(KeyConstants._CURRENTROW)) return new QueryColumnRef(this,key,Types.INTEGER); 1202 else if(key.equals(KeyConstants._COLUMNLIST)) return new QueryColumnRef(this,key,Types.INTEGER); 1203 } 1204 } 1205 throw new DatabaseException("key ["+key.getString()+"] not found in query, columns are ["+getColumnlist(false)+"]",null,sql,null); 1206 } 1207 1208 1209 private void renameEL(Collection.Key src, Collection.Key trg) { 1210 int index=getIndexFromKey(src); 1211 if(index!=-1){ 1212 columnNames[index]=trg; 1213 columns[index].setKey(trg); 1214 } 1215 } 1216 1217 public synchronized void rename(Collection.Key columnName,Collection.Key newColumnName) throws ExpressionException { 1218 int index=getIndexFromKey(columnName); 1219 if(index==-1) throw new ExpressionException("invalid column name definitions"); 1220 columnNames[index]=newColumnName; 1221 columns[index].setKey(newColumnName); 1222 } 1223 1224 1225 @Override 1226 public QueryColumn getColumn(String key, QueryColumn defaultValue) { 1227 return getColumn(KeyImpl.init(key.trim()),defaultValue); 1228 } 1229 1230 @Override 1231 public QueryColumn getColumn(Collection.Key key, QueryColumn defaultValue) { 1232 int index=getIndexFromKey(key); 1233 if(index!=-1) return columns[index]; 1234 if(key.length()>0) { 1235 char c=key.lowerCharAt(0); 1236 if(c=='r') { 1237 if(key.equals(KeyConstants._RECORDCOUNT)) return new QueryColumnRef(this,key,Types.INTEGER); 1238 } 1239 if(c=='c') { 1240 if(key.equals(KeyConstants._CURRENTROW)) return new QueryColumnRef(this,key,Types.INTEGER); 1241 else if(key.equals(KeyConstants._COLUMNLIST)) return new QueryColumnRef(this,key,Types.INTEGER); 1242 } 1243 } 1244 return defaultValue; 1245 } 1246 1247 @Override 1248 public String toString() { 1249 Collection.Key[] keys=keys(); 1250 1251 StringBuffer sb=new StringBuffer(); 1252 1253 sb.append("Query\n"); 1254 sb.append("---------------------------------------------------\n"); 1255 1256 if(sql!=null) { 1257 sb.append(sql+"\n"); 1258 sb.append("---------------------------------------------------\n"); 1259 } 1260 1261 if(exeTime>0) { 1262 sb.append("Execution Time (ns): "+exeTime+"\n"); 1263 sb.append("---------------------------------------------------\n"); 1264 } 1265 1266 sb.append("Recordcount: "+getRecordcount()+"\n"); 1267 sb.append("---------------------------------------------------\n"); 1268 String trenner=""; 1269 for(int i=0;i<keys.length;i++) { 1270 trenner+="+---------------------"; 1271 } 1272 trenner+="+\n"; 1273 sb.append(trenner); 1274 1275 // Header 1276 for(int i=0;i<keys.length;i++) { 1277 sb.append(getToStringField(keys[i].getString())); 1278 } 1279 sb.append("|\n"); 1280 sb.append(trenner); 1281 sb.append(trenner); 1282 1283 // body 1284 for(int i=0;i<recordcount;i++) { 1285 for(int y=0;y<keys.length;y++) { 1286 try { 1287 Object o=getAt(keys[y],i+1); 1288 if(o instanceof String)sb.append(getToStringField(o.toString())); 1289 else if(o instanceof Number) sb.append(getToStringField(Caster.toString(((Number)o).doubleValue()))); 1290 else if(o instanceof Clob) sb.append(getToStringField(Caster.toString(o))); 1291 else sb.append(getToStringField(o.toString())); 1292 } catch (PageException e) { 1293 sb.append(getToStringField("[empty]")); 1294 } 1295 } 1296 sb.append("|\n"); 1297 sb.append(trenner); 1298 } 1299 return sb.toString(); 1300 } 1301 1302 private String getToStringField(String str) { 1303 if(str==null) return "| "; 1304 else if(str.length()<21) { 1305 String s="|"+str; 1306 for(int i=str.length();i<21;i++)s+=" "; 1307 return s; 1308 } 1309 else if(str.length()==21) return "|"+str; 1310 else return "|"+str.substring(0,18)+"..."; 1311 } 1312 1313 /** 1314 * 1315 * @param type 1316 * @return return String represetation of a Type from int type 1317 */ 1318 public static String getColumTypeName(int type) { 1319 switch(type) { 1320 case Types.ARRAY: return "OBJECT"; 1321 case Types.BIGINT: return "BIGINT"; 1322 case Types.BINARY: return "BINARY"; 1323 case Types.BIT: return "BIT"; 1324 case Types.BLOB: return "OBJECT"; 1325 case Types.BOOLEAN: return "BOOLEAN"; 1326 case Types.CHAR: return "CHAR"; 1327 case Types.NCHAR: return "NCHAR"; 1328 case Types.CLOB: return "OBJECT"; 1329 case Types.NCLOB: return "OBJECT"; 1330 case Types.DATALINK: return "OBJECT"; 1331 case Types.DATE: return "DATE"; 1332 case Types.DECIMAL: return "DECIMAL"; 1333 case Types.DISTINCT: return "OBJECT"; 1334 case Types.DOUBLE: return "DOUBLE"; 1335 case Types.FLOAT: return "DOUBLE"; 1336 case Types.INTEGER: return "INTEGER"; 1337 case Types.JAVA_OBJECT: return "OBJECT"; 1338 case Types.LONGVARBINARY: return "LONGVARBINARY"; 1339 case Types.LONGVARCHAR: return "LONGVARCHAR"; 1340 case Types.NULL: return "OBJECT"; 1341 case Types.NUMERIC: return "NUMERIC"; 1342 case Types.OTHER: return "OBJECT"; 1343 case Types.REAL: return "REAL"; 1344 case Types.REF: return "OBJECT"; 1345 case Types.SMALLINT: return "SMALLINT"; 1346 case Types.STRUCT: return "OBJECT"; 1347 case Types.TIME: return "TIME"; 1348 case Types.TIMESTAMP: return "TIMESTAMP"; 1349 case Types.TINYINT: return "TINYINT"; 1350 case Types.VARBINARY: return "VARBINARY"; 1351 case Types.NVARCHAR: return "NVARCHAR"; 1352 case Types.SQLXML: return "SQLXML"; 1353 case Types.VARCHAR: return "VARCHAR"; 1354 default : return "VARCHAR"; 1355 } 1356 } 1357 1358 private int getIndexFromKey(String key) { 1359 String lc = StringUtil.toLowerCase(key); 1360 for(int i=0;i<columnNames.length;i++) { 1361 if(columnNames[i].getLowerString().equals(lc)) return i; 1362 } 1363 return -1; 1364 } 1365 1366 private int getIndexFromKey(Collection.Key key) { 1367 1368 for(int i=0;i<columnNames.length;i++) { 1369 if(columnNames[i].equalsIgnoreCase(key)) return i; 1370 } 1371 return -1; 1372 } 1373 1374 @Override 1375 public void setExecutionTime(long exeTime) { 1376 this.exeTime=exeTime; 1377 } 1378 1379 /** 1380 * @param maxrows 1381 * @return has cutted or not 1382 */ 1383 public synchronized boolean cutRowsTo(int maxrows) { 1384 //disconnectCache(); 1385 1386 if(maxrows>-1 && maxrows<getRecordcount()) { 1387 for(int i=0;i<columns.length;i++) { 1388 QueryColumn column = columns[i]; 1389 column.cutRowsTo(maxrows); 1390 } 1391 recordcount=maxrows; 1392 return true; 1393 } 1394 return false; 1395 } 1396 1397 @Override 1398 public void setCached(boolean isCached) { 1399 this.isCached=isCached; 1400 } 1401 1402 @Override 1403 public boolean isCached() { 1404 return isCached; 1405 } 1406 1407 1408 1409 @Override 1410 public int addRow() { 1411 addRow(1); 1412 return getRecordcount(); 1413 } 1414 1415 1416 public Key getColumnName(int columnIndex) { 1417 Key[] keys = keys(); 1418 if(columnIndex<1 || columnIndex>keys.length) return null; 1419 return keys[columnIndex-1]; 1420 } 1421 1422 @Override 1423 public int getColumnIndex(String coulmnName) { 1424 Collection.Key[] keys = keys(); 1425 for(int i=0;i<keys.length;i++) { 1426 if(keys[i].getString().equalsIgnoreCase(coulmnName)) return i+1; 1427 } 1428 return -1; 1429 } 1430 1431 1432 1433 @Override 1434 public String[] getColumns() { 1435 return getColumnNamesAsString(); 1436 } 1437 1438 @Override 1439 public Collection.Key[] getColumnNames() { 1440 Collection.Key[] keys = keys(); 1441 Collection.Key[] rtn=new Collection.Key[keys.length]; 1442 System.arraycopy(keys,0,rtn,0,keys.length); 1443 return rtn; 1444 } 1445 1446 public void setColumnNames(Collection.Key[] trg) throws PageException { 1447 columncount=trg.length; 1448 Collection.Key[] src = keys(); 1449 1450 // target < source 1451 if(trg.length<src.length){ 1452 this.columnNames=new Collection.Key[trg.length]; 1453 QueryColumnImpl[] tmp=new QueryColumnImpl[trg.length]; 1454 for(int i=0;i<trg.length;i++){ 1455 this.columnNames[i]=trg[i]; 1456 tmp[i]=this.columns[i]; 1457 tmp[i].setKey(trg[i]); 1458 } 1459 this.columns=tmp; 1460 return; 1461 } 1462 1463 if(trg.length>src.length){ 1464 int recordcount=getRecordcount(); 1465 for(int i=src.length;i<trg.length;i++){ 1466 1467 Array arr=new ArrayImpl(); 1468 for(int r=1;r<=recordcount;r++){ 1469 arr.setE(i,""); 1470 } 1471 addColumn(trg[i], arr); 1472 } 1473 src = keys(); 1474 } 1475 1476 for(int i=0;i<trg.length;i++){ 1477 this.columnNames[i]=trg[i]; 1478 this.columns[i].setKey(trg[i]); 1479 } 1480 } 1481 1482 1483 1484 @Override 1485 public String[] getColumnNamesAsString() { 1486 return CollectionUtil.keysAsString(this); 1487 } 1488 1489 public int getColumnCount() { 1490 return columncount; 1491 } 1492 1493 @Override 1494 public String getData(int row, int col) throws IndexOutOfBoundsException { 1495 Collection.Key[] keys = keys(); 1496 if(col<1 || col>keys.length) { 1497 new IndexOutOfBoundsException("invalid column index to retrieve Data from query, valid index goes from 1 to "+keys.length); 1498 } 1499 1500 Object o=getAt(keys[col-1],row,NullSupportHelper.NULL()); 1501 if(o==NullSupportHelper.NULL()) 1502 throw new IndexOutOfBoundsException("invalid row index to retrieve Data from query, valid index goes from 1 to "+getRecordcount()); 1503 return Caster.toString( o,NullSupportHelper.full()?null:""); 1504 } 1505 1506 1507 1508 @Override 1509 public String getName() { 1510 return this.name; 1511 } 1512 1513 1514 1515 @Override 1516 public int getRowCount() { 1517 return getRecordcount(); 1518 } 1519 1520 1521 1522 @Override 1523 public void setData(int row, int col, String value) throws IndexOutOfBoundsException { 1524 Collection.Key[] keys = keys(); 1525 if(col<1 || col>keys.length) { 1526 new IndexOutOfBoundsException("invalid column index to retrieve Data from query, valid index goes from 1 to "+keys.length); 1527 } 1528 try { 1529 setAt(keys[col-1],row,value); 1530 } 1531 catch (PageException e) { 1532 throw new IndexOutOfBoundsException("invalid row index to retrieve Data from query, valid index goes from 1 to "+getRecordcount()); 1533 } 1534 } 1535 1536 @Override 1537 public boolean containsKey(String key) { 1538 return getColumn(key,null)!=null; 1539 } 1540 1541 @Override 1542 public boolean containsKey(Collection.Key key) { 1543 return getColumn(key,null)!=null; 1544 } 1545 1546 @Override 1547 public String castToString() throws ExpressionException { 1548 throw new ExpressionException("Can't cast Complex Object Type Query to String", 1549 "Use Built-In-Function \"serialize(Query):String\" to create a String from Query"); 1550 } 1551 1552 @Override 1553 public String castToString(String defaultValue) { 1554 return defaultValue; 1555 } 1556 1557 1558 @Override 1559 public boolean castToBooleanValue() throws ExpressionException { 1560 throw new ExpressionException("Can't cast Complex Object Type Query to a boolean value"); 1561 } 1562 1563 @Override 1564 public Boolean castToBoolean(Boolean defaultValue) { 1565 return defaultValue; 1566 } 1567 1568 1569 @Override 1570 public double castToDoubleValue() throws ExpressionException { 1571 throw new ExpressionException("Can't cast Complex Object Type Query to a number value"); 1572 } 1573 1574 @Override 1575 public double castToDoubleValue(double defaultValue) { 1576 return defaultValue; 1577 } 1578 1579 1580 @Override 1581 public DateTime castToDateTime() throws ExpressionException { 1582 throw new ExpressionException("Can't cast Complex Object Type Query to a Date"); 1583 } 1584 1585 @Override 1586 public DateTime castToDateTime(DateTime defaultValue) { 1587 return defaultValue; 1588 } 1589 1590 @Override 1591 public int compareTo(boolean b) throws ExpressionException { 1592 throw new ExpressionException("can't compare Complex Object Type Query with a boolean value"); 1593 } 1594 1595 @Override 1596 public int compareTo(DateTime dt) throws PageException { 1597 throw new ExpressionException("can't compare Complex Object Type Query with a DateTime Object"); 1598 } 1599 1600 @Override 1601 public int compareTo(double d) throws PageException { 1602 throw new ExpressionException("can't compare Complex Object Type Query with a numeric value"); 1603 } 1604 1605 @Override 1606 public int compareTo(String str) throws PageException { 1607 throw new ExpressionException("can't compare Complex Object Type Query with a String"); 1608 } 1609 1610 public synchronized Array getMetaDataSimple() { 1611 Array cols=new ArrayImpl(); 1612 Struct column; 1613 for(int i=0;i<columns.length;i++) { 1614 column=new StructImpl(); 1615 column.setEL(KeyConstants._name,columnNames[i].getString()); 1616 column.setEL("isCaseSensitive",Boolean.FALSE); 1617 column.setEL("typeName",columns[i].getTypeAsString()); 1618 cols.appendEL(column); 1619 } 1620 return cols; 1621 } 1622 1623 /*public synchronized Struct _getMetaData() { 1624 1625 Struct cols=new StructImpl(); 1626 for(int i=0;i<columns.length;i++) { 1627 cols.setEL(columnNames[i],columns[i].getTypeAsString()); 1628 } 1629 1630 Struct sct=new StructImpl(); 1631 sct.setEL(KeyConstants._NAME,getName()); 1632 sct.setEL(KeyConstants._COLUMNS,cols); 1633 sct.setEL(KeyConstants._SQL,sql==null?"":sql.toString()); 1634 sct.setEL(KeyConstants._executionTime,new Double(exeTime)); 1635 sct.setEL(KeyConstants._RECORDCOUNT,new Double(getRowCount())); 1636 sct.setEL(KeyConstants._cached,Caster.toBoolean(isCached())); 1637 return sct; 1638 1639 }*/ 1640 1641 /** 1642 * @return the sql 1643 */ 1644 public SQL getSql() { 1645 return sql; 1646 } 1647 1648 /** 1649 * @param sql the sql to set 1650 */ 1651 public void setSql(SQL sql) { 1652 this.sql = sql; 1653 } 1654 1655 1656 @Override 1657 public Object getObject(String columnName) throws SQLException { 1658 int currentrow; 1659 if((currentrow=arrCurrentRow.get(getPid(),0))==0) return null; 1660 return getAt(columnName,currentrow,null); 1661 } 1662 1663 @Override 1664 public Object getObject(int columnIndex) throws SQLException { 1665 if(columnIndex>0 && columnIndex<=columncount) return getObject(this.columnNames[columnIndex-1].getString()); 1666 return null; 1667 } 1668 1669 @Override 1670 public String getString(int columnIndex) throws SQLException { 1671 Object rtn = getObject(columnIndex); 1672 if(rtn==null)return null; 1673 if(Decision.isCastableToString(rtn)) return Caster.toString(rtn,null); 1674 throw new SQLException("can't cast value to string"); 1675 } 1676 1677 @Override 1678 public String getString(String columnName) throws SQLException { 1679 Object rtn = getObject(columnName); 1680 if(rtn==null)return null; 1681 if(Decision.isCastableToString(rtn)) return Caster.toString(rtn,null); 1682 throw new SQLException("can't cast value to string"); 1683 } 1684 1685 @Override 1686 public boolean getBoolean(int columnIndex) throws SQLException { 1687 Object rtn = getObject(columnIndex); 1688 if(rtn==null)return false; 1689 if(Decision.isCastableToBoolean(rtn)) return Caster.toBooleanValue(rtn,false); 1690 throw new SQLException("can't cast value to boolean"); 1691 } 1692 1693 @Override 1694 public boolean getBoolean(String columnName) throws SQLException { 1695 Object rtn = getObject(columnName); 1696 if(rtn==null)return false; 1697 if(Decision.isCastableToBoolean(rtn)) return Caster.toBooleanValue(rtn,false); 1698 throw new SQLException("can't cast value to boolean"); 1699 } 1700 1701 1702 // --------------------------------------- 1703 1704 @Override 1705 public Object call(PageContext pc, Key methodName, Object[] arguments) throws PageException { 1706 return MemberUtil.call(pc, this, methodName, arguments, railo.commons.lang.CFTypes.TYPE_QUERY, "query"); 1707 //return Reflector.callMethod(this,methodName,arguments); 1708 } 1709 1710 @Override 1711 public Object callWithNamedValues(PageContext pc, Key methodName, Struct args) throws PageException { 1712 return MemberUtil.callWithNamedValues(pc, this, methodName, args,railo.commons.lang.CFTypes.TYPE_QUERY, "query"); 1713 } 1714 1715 @Override 1716 public Object get(PageContext pc, Key key, Object defaultValue) { 1717 return getAt(key,arrCurrentRow.get( 1718 pc.getId(),1),defaultValue); 1719 } 1720 1721 @Override 1722 public Object get(PageContext pc, Key key) throws PageException { 1723 return getAt(key,arrCurrentRow.get(pc.getId(),1)); 1724 } 1725 1726 public boolean isInitalized() { 1727 return true; 1728 } 1729 1730 @Override 1731 public Object set(PageContext pc, Key propertyName, Object value) throws PageException { 1732 return setAt(propertyName,arrCurrentRow.get(pc.getId(),1),value); 1733 } 1734 1735 @Override 1736 public Object setEL(PageContext pc, Key propertyName, Object value) { 1737 return setAtEL(propertyName,arrCurrentRow.get(pc.getId(),1),value); 1738 } 1739 1740 @Override 1741 public boolean wasNull() { 1742 throw new PageRuntimeException(new ApplicationException("method [wasNull] is not supported")); 1743 } 1744 1745 @Override 1746 public boolean absolute(int row) throws SQLException { 1747 if(recordcount==0) { 1748 if(row!=0) throw new SQLException("invalid row ["+row+"], query is Empty"); 1749 return false; 1750 } 1751 //row=row%recordcount; 1752 1753 if(row>0) arrCurrentRow.set(getPid(),row); 1754 else arrCurrentRow.set(getPid(),(recordcount+1)+row); 1755 return true; 1756 } 1757 1758 @Override 1759 public void afterLast() throws SQLException { 1760 arrCurrentRow.set(getPid(),recordcount+1); 1761 } 1762 1763 @Override 1764 public void beforeFirst() throws SQLException { 1765 arrCurrentRow.set(getPid(),0); 1766 } 1767 1768 @Override 1769 public void cancelRowUpdates() throws SQLException { 1770 // ignored 1771 } 1772 1773 @Override 1774 public void clearWarnings() throws SQLException { 1775 // ignored 1776 } 1777 1778 @Override 1779 public void close() throws SQLException { 1780 // ignored 1781 } 1782 1783 @Override 1784 public void deleteRow() throws SQLException { 1785 try { 1786 removeRow(arrCurrentRow.get(getPid())); 1787 } catch (Exception e) { 1788 throw new SQLException(e.getMessage()); 1789 } 1790 } 1791 1792 @Override 1793 public int findColumn(String columnName) throws SQLException { 1794 int index= getColumnIndex(columnName); 1795 if(index==-1) throw new SQLException("invald column definitions ["+columnName+"]"); 1796 return index; 1797 } 1798 1799 @Override 1800 public boolean first() throws SQLException { 1801 return absolute(1); 1802 } 1803 1804 public java.sql.Array getArray(int i) throws SQLException { 1805 throw new SQLException("method is not implemented"); 1806 } 1807 1808 public java.sql.Array getArray(String colName) throws SQLException { 1809 throw new SQLException("method is not implemented"); 1810 } 1811 1812 @Override 1813 public InputStream getAsciiStream(int columnIndex) throws SQLException { 1814 String res = getString(columnIndex); 1815 if(res==null)return null; 1816 return new ByteArrayInputStream(res.getBytes()); 1817 } 1818 1819 @Override 1820 public InputStream getAsciiStream(String columnName) throws SQLException { 1821 String res = getString(columnName); 1822 if(res==null)return null; 1823 return new ByteArrayInputStream(res.getBytes()); 1824 } 1825 1826 @Override 1827 public BigDecimal getBigDecimal(int columnIndex) throws SQLException { 1828 return new BigDecimal(getDouble(columnIndex)); 1829 } 1830 1831 @Override 1832 public BigDecimal getBigDecimal(String columnName) throws SQLException { 1833 return new BigDecimal(getDouble(columnName)); 1834 } 1835 1836 @Override 1837 public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { 1838 return new BigDecimal(getDouble(columnIndex)); 1839 } 1840 1841 @Override 1842 public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException { 1843 return new BigDecimal(getDouble(columnName)); 1844 } 1845 1846 @Override 1847 public InputStream getBinaryStream(int columnIndex) throws SQLException { 1848 Object obj = getObject(columnIndex); 1849 if(obj==null)return null; 1850 try { 1851 return Caster.toInputStream(obj); 1852 } catch (Exception e) { 1853 throw new SQLException(e.getMessage()); 1854 } 1855 } 1856 1857 @Override 1858 public InputStream getBinaryStream(String columnName) throws SQLException { 1859 Object obj = getObject(columnName); 1860 if(obj==null)return null; 1861 try { 1862 return Caster.toInputStream(obj); 1863 } catch (Exception e) { 1864 throw new SQLException(e.getMessage()); 1865 } 1866 } 1867 1868 @Override 1869 public Blob getBlob(int i) throws SQLException { 1870 byte[] bytes = getBytes(i); 1871 if(bytes==null) return null; 1872 try { 1873 return BlobImpl.toBlob(bytes); 1874 } 1875 catch (PageException e) { 1876 throw new SQLException(e.getMessage()); 1877 } 1878 } 1879 1880 @Override 1881 public Blob getBlob(String colName) throws SQLException { 1882 byte[] bytes = getBytes(colName); 1883 if(bytes==null) return null; 1884 try { 1885 return BlobImpl.toBlob(bytes); 1886 } catch (PageException e) { 1887 throw new SQLException(e.getMessage()); 1888 } 1889 } 1890 1891 @Override 1892 public byte getByte(int columnIndex) throws SQLException { 1893 Object obj = getObject(columnIndex); 1894 if(obj==null) return (byte)0; 1895 try { 1896 return Caster.toByteValue(obj); 1897 } catch (PageException e) { 1898 throw new SQLException(e.getMessage()); 1899 } 1900 } 1901 1902 @Override 1903 public byte getByte(String columnName) throws SQLException { 1904 Object obj = getObject(columnName); 1905 if(obj==null) return (byte)0; 1906 try { 1907 return Caster.toByteValue(obj); 1908 } catch (PageException e) { 1909 throw new SQLException(e.getMessage()); 1910 } 1911 } 1912 1913 @Override 1914 public byte[] getBytes(int columnIndex) throws SQLException { 1915 Object obj = getObject(columnIndex); 1916 if(obj==null) return null; 1917 try { 1918 return Caster.toBytes(obj); 1919 } catch (Exception e) { 1920 throw new SQLException(e.getMessage()); 1921 } 1922 } 1923 1924 @Override 1925 public byte[] getBytes(String columnName) throws SQLException { 1926 Object obj = getObject(columnName); 1927 if(obj==null) return null; 1928 try { 1929 return Caster.toBytes(obj); 1930 } catch (Exception e) { 1931 throw new SQLException(e.getMessage()); 1932 } 1933 } 1934 1935 @Override 1936 public Reader getCharacterStream(int columnIndex) throws SQLException { 1937 String str=getString(columnIndex); 1938 if(str==null) return null; 1939 return new StringReader(str); 1940 } 1941 1942 @Override 1943 public Reader getCharacterStream(String columnName) throws SQLException { 1944 String str=getString(columnName); 1945 if(str==null) return null; 1946 return new StringReader(str); 1947 } 1948 1949 @Override 1950 public Clob getClob(int i) throws SQLException { 1951 String str=getString(i); 1952 if(str==null) return null; 1953 return ClobImpl.toClob(str); 1954 } 1955 1956 @Override 1957 public Clob getClob(String colName) throws SQLException { 1958 String str=getString(colName); 1959 if(str==null) return null; 1960 return ClobImpl.toClob(str); 1961 } 1962 1963 @Override 1964 public int getConcurrency() throws SQLException { 1965 return 0; 1966 } 1967 1968 @Override 1969 public String getCursorName() throws SQLException { 1970 return null; 1971 } 1972 1973 @Override 1974 public java.sql.Date getDate(int columnIndex) throws SQLException { 1975 Object obj=getObject(columnIndex); 1976 if(obj==null) return null; 1977 try { 1978 return new java.sql.Date(Caster.toDate(obj, false, null).getTime()); 1979 } catch (PageException e) { 1980 throw new SQLException(e.getMessage()); 1981 } 1982 } 1983 1984 @Override 1985 public java.sql.Date getDate(String columnName) throws SQLException { 1986 Object obj=getObject(columnName); 1987 if(obj==null) return null; 1988 try { 1989 return new java.sql.Date(Caster.toDate(obj, false, null).getTime()); 1990 } catch (PageException e) { 1991 throw new SQLException(e.getMessage()); 1992 } 1993 } 1994 1995 @Override 1996 public java.sql.Date getDate(int columnIndex, Calendar cal)throws SQLException { 1997 return getDate(columnIndex); // TODO impl 1998 } 1999 2000 @Override 2001 public java.sql.Date getDate(String columnName, Calendar cal) throws SQLException { 2002 return getDate(columnName);// TODO impl 2003 } 2004 2005 @Override 2006 public double getDouble(int columnIndex) throws SQLException { 2007 Object obj=getObject(columnIndex); 2008 if(obj==null) return 0; 2009 try { 2010 return Caster.toDoubleValue(obj); 2011 } catch (PageException e) { 2012 throw new SQLException(e.getMessage()); 2013 } 2014 } 2015 2016 @Override 2017 public double getDouble(String columnName) throws SQLException { 2018 Object obj=getObject(columnName); 2019 if(obj==null) return 0; 2020 try { 2021 return Caster.toDoubleValue(obj); 2022 } catch (PageException e) { 2023 throw new SQLException(e.getMessage()); 2024 } 2025 } 2026 2027 @Override 2028 public int getFetchDirection() throws SQLException { 2029 return 1000; 2030 } 2031 2032 @Override 2033 public int getFetchSize() throws SQLException { 2034 return 0; 2035 } 2036 2037 @Override 2038 public float getFloat(int columnIndex) throws SQLException { 2039 Object obj=getObject(columnIndex); 2040 if(obj==null) return 0; 2041 try { 2042 return Caster.toFloatValue(obj); 2043 } catch (PageException e) { 2044 throw new SQLException(e.getMessage()); 2045 } 2046 } 2047 2048 @Override 2049 public float getFloat(String columnName) throws SQLException { 2050 Object obj=getObject(columnName); 2051 if(obj==null) return 0; 2052 try { 2053 return Caster.toFloatValue(obj); 2054 } catch (PageException e) { 2055 throw new SQLException(e.getMessage()); 2056 } 2057 } 2058 2059 @Override 2060 public int getInt(int columnIndex) throws SQLException { 2061 Object obj=getObject(columnIndex); 2062 if(obj==null) return 0; 2063 try { 2064 return Caster.toIntValue(obj); 2065 } catch (PageException e) { 2066 throw new SQLException(e.getMessage()); 2067 } 2068 } 2069 2070 @Override 2071 public int getInt(String columnName) throws SQLException { 2072 Object obj=getObject(columnName); 2073 if(obj==null) return 0; 2074 try { 2075 return Caster.toIntValue(obj); 2076 } catch (PageException e) { 2077 throw new SQLException(e.getMessage()); 2078 } 2079 } 2080 2081 @Override 2082 public long getLong(int columnIndex) throws SQLException { 2083 Object obj=getObject(columnIndex); 2084 if(obj==null) return 0; 2085 try { 2086 return Caster.toLongValue(obj); 2087 } catch (PageException e) { 2088 throw new SQLException(e.getMessage()); 2089 } 2090 } 2091 2092 @Override 2093 public long getLong(String columnName) throws SQLException { 2094 Object obj=getObject(columnName); 2095 if(obj==null) return 0; 2096 try { 2097 return Caster.toLongValue(obj); 2098 } catch (PageException e) { 2099 throw new SQLException(e.getMessage()); 2100 } 2101 } 2102 2103 @Override 2104 public Object getObject(int i, Map map) throws SQLException { 2105 throw new SQLException("method is not implemented"); 2106 } 2107 2108 @Override 2109 public Object getObject(String colName, Map map) throws SQLException { 2110 throw new SQLException("method is not implemented"); 2111 } 2112 2113 // used only with java 7, do not set @Override 2114 public <T> T getObject(int columnIndex, Class<T> type) throws SQLException { 2115 return (T) QueryUtil.getObject(this,columnIndex, type); 2116 } 2117 2118 // used only with java 7, do not set @Override 2119 public <T> T getObject(String columnLabel, Class<T> type) throws SQLException { 2120 return (T) QueryUtil.getObject(this,columnLabel, type); 2121 } 2122 2123 @Override 2124 public Ref getRef(int i) throws SQLException { 2125 throw new SQLException("method is not implemented"); 2126 } 2127 2128 @Override 2129 public Ref getRef(String colName) throws SQLException { 2130 throw new SQLException("method is not implemented"); 2131 } 2132 2133 @Override 2134 public int getRow() throws SQLException { 2135 return arrCurrentRow.get(getPid(),0); 2136 } 2137 2138 @Override 2139 public short getShort(int columnIndex) throws SQLException { 2140 Object obj=getObject(columnIndex); 2141 if(obj==null) return 0; 2142 try { 2143 return Caster.toShortValue(obj); 2144 } catch (PageException e) { 2145 throw new SQLException(e.getMessage()); 2146 } 2147 } 2148 2149 @Override 2150 public short getShort(String columnName) throws SQLException { 2151 Object obj=getObject(columnName); 2152 if(obj==null) return 0; 2153 try { 2154 return Caster.toShortValue(obj); 2155 } catch (PageException e) { 2156 throw new SQLException(e.getMessage()); 2157 } 2158 } 2159 2160 public Statement getStatement() throws SQLException { 2161 throw new SQLException("method is not implemented"); 2162 } 2163 2164 @Override 2165 public Time getTime(int columnIndex) throws SQLException { 2166 Object obj=getObject(columnIndex); 2167 if(obj==null) return null; 2168 try { 2169 return new Time(DateCaster.toTime(null, obj).getTime()); 2170 } catch (PageException e) { 2171 throw new SQLException(e.getMessage()); 2172 } 2173 } 2174 2175 @Override 2176 public Time getTime(String columnName) throws SQLException { 2177 Object obj=getObject(columnName); 2178 if(obj==null) return null; 2179 try { 2180 return new Time(DateCaster.toTime(null, obj).getTime()); 2181 } catch (PageException e) { 2182 throw new SQLException(e.getMessage()); 2183 } 2184 } 2185 2186 @Override 2187 public Time getTime(int columnIndex, Calendar cal) throws SQLException { 2188 return getTime(columnIndex);// TODO impl 2189 } 2190 2191 @Override 2192 public Time getTime(String columnName, Calendar cal) throws SQLException { 2193 return getTime(columnName);// TODO impl 2194 } 2195 2196 @Override 2197 public Timestamp getTimestamp(int columnIndex) throws SQLException { 2198 Object obj=getObject(columnIndex); 2199 if(obj==null) return null; 2200 try { 2201 return new Timestamp(DateCaster.toTime(null, obj).getTime()); 2202 } catch (PageException e) { 2203 throw new SQLException(e.getMessage()); 2204 } 2205 } 2206 2207 @Override 2208 public Timestamp getTimestamp(String columnName) throws SQLException { 2209 Object obj=getObject(columnName); 2210 if(obj==null) return null; 2211 try { 2212 return new Timestamp(DateCaster.toTime(null, obj).getTime()); 2213 } catch (PageException e) { 2214 throw new SQLException(e.getMessage()); 2215 } 2216 } 2217 2218 @Override 2219 public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { 2220 return getTimestamp(columnIndex);// TODO impl 2221 } 2222 2223 @Override 2224 public Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException { 2225 return getTimestamp(columnName);// TODO impl 2226 } 2227 2228 @Override 2229 public int getType() throws SQLException { 2230 return 0; 2231 } 2232 2233 @Override 2234 public URL getURL(int columnIndex) throws SQLException { 2235 throw new SQLException("method is not implemented"); 2236 } 2237 2238 @Override 2239 public URL getURL(String columnName) throws SQLException { 2240 throw new SQLException("method is not implemented"); 2241 } 2242 2243 @Override 2244 public InputStream getUnicodeStream(int columnIndex) throws SQLException { 2245 String str=getString(columnIndex); 2246 if(str==null) return null; 2247 try { 2248 return new ByteArrayInputStream(str.getBytes("UTF-8")); 2249 } 2250 catch (UnsupportedEncodingException e) { 2251 throw new SQLException(e.getMessage()); 2252 } 2253 } 2254 2255 @Override 2256 public InputStream getUnicodeStream(String columnName) throws SQLException { 2257 String str=getString(columnName); 2258 if(str==null) return null; 2259 try { 2260 return new ByteArrayInputStream(str.getBytes("UTF-8")); 2261 } 2262 catch (UnsupportedEncodingException e) { 2263 throw new SQLException(e.getMessage()); 2264 } 2265 } 2266 2267 @Override 2268 public SQLWarning getWarnings() throws SQLException { 2269 throw new SQLException("method is not implemented"); 2270 } 2271 2272 @Override 2273 public void insertRow() throws SQLException { 2274 throw new SQLException("method is not implemented"); 2275 } 2276 2277 @Override 2278 public boolean isAfterLast() throws SQLException { 2279 return getCurrentrow(ThreadLocalPageContext.get().getId())>recordcount; 2280 } 2281 2282 @Override 2283 public boolean isBeforeFirst() throws SQLException { 2284 return arrCurrentRow.get(getPid(),0)==0; 2285 } 2286 2287 @Override 2288 public boolean isFirst() throws SQLException { 2289 return arrCurrentRow.get(getPid(),0)==1; 2290 } 2291 2292 public boolean isLast() throws SQLException { 2293 return arrCurrentRow.get(getPid(),0)==recordcount; 2294 } 2295 2296 public boolean last() throws SQLException { 2297 return absolute(recordcount); 2298 } 2299 2300 public void moveToCurrentRow() throws SQLException { 2301 // ignore 2302 } 2303 2304 public void moveToInsertRow() throws SQLException { 2305 // ignore 2306 } 2307 2308 2309 public boolean previous() { 2310 return previous(getPid()); 2311 } 2312 2313 public boolean previous(int pid) { 2314 if(0<(arrCurrentRow.set(pid,arrCurrentRow.get(pid,0)-1))) { 2315 return true; 2316 } 2317 arrCurrentRow.set(pid,0); 2318 return false; 2319 } 2320 2321 public void refreshRow() throws SQLException { 2322 // ignore 2323 2324 } 2325 2326 @Override 2327 public boolean relative(int rows) throws SQLException { 2328 return absolute(getRow()+rows); 2329 } 2330 2331 @Override 2332 public boolean rowDeleted() throws SQLException { 2333 return false; 2334 } 2335 2336 @Override 2337 public boolean rowInserted() throws SQLException { 2338 return false; 2339 } 2340 2341 @Override 2342 public boolean rowUpdated() throws SQLException { 2343 return false; 2344 } 2345 2346 public void setFetchDirection(int direction) throws SQLException { 2347 // ignore 2348 } 2349 2350 public void setFetchSize(int rows) throws SQLException { 2351 // ignore 2352 } 2353 2354 @Override 2355 public void updateArray(int columnIndex, java.sql.Array x)throws SQLException { 2356 updateObject(columnIndex, x.getArray()); 2357 } 2358 2359 @Override 2360 public void updateArray(String columnName, java.sql.Array x)throws SQLException { 2361 updateObject(columnName, x.getArray()); 2362 } 2363 2364 @Override 2365 public void updateAsciiStream(int columnIndex, InputStream x, int length)throws SQLException { 2366 updateBinaryStream(columnIndex, x, length); 2367 } 2368 2369 @Override 2370 public void updateAsciiStream(String columnName, InputStream x, int length)throws SQLException { 2371 updateBinaryStream(columnName, x, length); 2372 } 2373 2374 @Override 2375 public void updateBigDecimal(int columnIndex, BigDecimal x)throws SQLException { 2376 updateObject(columnIndex, x.toString()); 2377 } 2378 2379 @Override 2380 public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException { 2381 updateObject(columnName, x.toString()); 2382 } 2383 2384 @Override 2385 public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { 2386 try { 2387 updateObject(columnIndex, IOUtil.toBytesMax(x, length)); 2388 } catch (IOException e) { 2389 throw new SQLException(e.getMessage()); 2390 } 2391 } 2392 2393 @Override 2394 public void updateBinaryStream(String columnName, InputStream x, int length) throws SQLException { 2395 try { 2396 updateObject(columnName, IOUtil.toBytesMax(x, length)); 2397 } catch (IOException e) { 2398 throw new SQLException(e.getMessage()); 2399 } 2400 } 2401 2402 @Override 2403 public void updateBlob(int columnIndex, Blob x) throws SQLException { 2404 try { 2405 updateObject(columnIndex, toBytes(x)); 2406 } catch (IOException e) { 2407 throw new SQLException(e.getMessage()); 2408 } 2409 } 2410 2411 @Override 2412 public void updateBlob(String columnName, Blob x) throws SQLException { 2413 try { 2414 updateObject(columnName, toBytes(x)); 2415 } catch (IOException e) { 2416 throw new SQLException(e.getMessage()); 2417 } 2418 } 2419 2420 @Override 2421 public void updateBoolean(int columnIndex, boolean x) throws SQLException { 2422 updateObject(columnIndex, Caster.toBoolean(x)); 2423 } 2424 2425 @Override 2426 public void updateBoolean(String columnName, boolean x) throws SQLException { 2427 updateObject(columnName, Caster.toBoolean(x)); 2428 } 2429 2430 @Override 2431 public void updateByte(int columnIndex, byte x) throws SQLException { 2432 updateObject(columnIndex, new Byte(x)); 2433 } 2434 2435 @Override 2436 public void updateByte(String columnName, byte x) throws SQLException { 2437 updateObject(columnName, new Byte(x)); 2438 } 2439 2440 @Override 2441 public void updateBytes(int columnIndex, byte[] x) throws SQLException { 2442 updateObject(columnIndex, x); 2443 } 2444 2445 @Override 2446 public void updateBytes(String columnName, byte[] x) throws SQLException { 2447 updateObject(columnName, x); 2448 } 2449 2450 @Override 2451 public void updateCharacterStream(int columnIndex, Reader reader, int length)throws SQLException { 2452 try { 2453 updateObject(columnIndex, IOUtil.toString(reader)); 2454 } catch (Exception e) { 2455 throw new SQLException(e.getMessage()); 2456 } 2457 } 2458 2459 @Override 2460 public void updateCharacterStream(String columnName, Reader reader,int length) throws SQLException { 2461 try { 2462 updateObject(columnName, IOUtil.toString(reader)); 2463 } catch (Exception e) { 2464 throw new SQLException(e.getMessage()); 2465 } 2466 } 2467 2468 @Override 2469 public void updateClob(int columnIndex, Clob x) throws SQLException { 2470 try { 2471 updateObject(columnIndex, toString(x)); 2472 } catch (IOException e) { 2473 throw new SQLException(e.getMessage()); 2474 } 2475 } 2476 2477 @Override 2478 public void updateClob(String columnName, Clob x) throws SQLException { 2479 try { 2480 updateObject(columnName, toString(x)); 2481 } catch (IOException e) { 2482 throw new SQLException(e.getMessage()); 2483 } 2484 } 2485 2486 @Override 2487 public void updateDate(int columnIndex, java.sql.Date x)throws SQLException { 2488 updateObject(columnIndex, Caster.toDate(x, false, null, null)); 2489 } 2490 2491 @Override 2492 public void updateDate(String columnName, java.sql.Date x)throws SQLException { 2493 updateObject(columnName, Caster.toDate(x, false, null, null)); 2494 } 2495 2496 @Override 2497 public void updateDouble(int columnIndex, double x) throws SQLException { 2498 updateObject(columnIndex, Caster.toDouble(x)); 2499 } 2500 2501 @Override 2502 public void updateDouble(String columnName, double x) throws SQLException { 2503 updateObject(columnName, Caster.toDouble(x)); 2504 } 2505 2506 @Override 2507 public void updateFloat(int columnIndex, float x) throws SQLException { 2508 updateObject(columnIndex, Caster.toDouble(x)); 2509 } 2510 2511 @Override 2512 public void updateFloat(String columnName, float x) throws SQLException { 2513 updateObject(columnName, Caster.toDouble(x)); 2514 } 2515 2516 @Override 2517 public void updateInt(int columnIndex, int x) throws SQLException { 2518 updateObject(columnIndex, Caster.toDouble(x)); 2519 } 2520 2521 @Override 2522 public void updateInt(String columnName, int x) throws SQLException { 2523 updateObject(columnName, Caster.toDouble(x)); 2524 } 2525 2526 @Override 2527 public void updateLong(int columnIndex, long x) throws SQLException { 2528 updateObject(columnIndex, Caster.toDouble(x)); 2529 } 2530 2531 @Override 2532 public void updateLong(String columnName, long x) throws SQLException { 2533 updateObject(columnName, Caster.toDouble(x)); 2534 } 2535 2536 @Override 2537 public void updateNull(int columnIndex) throws SQLException { 2538 updateObject(columnIndex, null); 2539 } 2540 2541 @Override 2542 public void updateNull(String columnName) throws SQLException { 2543 updateObject(columnName, null); 2544 } 2545 2546 @Override 2547 public void updateObject(int columnIndex, Object x) throws SQLException { 2548 try { 2549 set(getColumnName(columnIndex), x); 2550 } catch (PageException e) { 2551 throw new SQLException(e.getMessage()); 2552 } 2553 } 2554 2555 @Override 2556 public void updateObject(String columnName, Object x) throws SQLException { 2557 try { 2558 set(KeyImpl.init(columnName), x); 2559 } catch (PageException e) { 2560 throw new SQLException(e.getMessage()); 2561 } 2562 } 2563 2564 @Override 2565 public void updateObject(int columnIndex, Object x, int scale)throws SQLException { 2566 updateObject(columnIndex, x); 2567 } 2568 2569 @Override 2570 public void updateObject(String columnName, Object x, int scale)throws SQLException { 2571 updateObject(columnName, x); 2572 } 2573 2574 @Override 2575 public void updateRef(int columnIndex, Ref x) throws SQLException { 2576 updateObject(columnIndex, x.getObject()); 2577 } 2578 2579 @Override 2580 public void updateRef(String columnName, Ref x) throws SQLException { 2581 updateObject(columnName, x.getObject()); 2582 } 2583 2584 public void updateRow() throws SQLException { 2585 throw new SQLException("method is not implemented"); 2586 } 2587 2588 @Override 2589 public void updateShort(int columnIndex, short x) throws SQLException { 2590 updateObject(columnIndex, Caster.toDouble(x)); 2591 } 2592 2593 @Override 2594 public void updateShort(String columnName, short x) throws SQLException { 2595 updateObject(columnName, Caster.toDouble(x)); 2596 } 2597 2598 @Override 2599 public void updateString(int columnIndex, String x) throws SQLException { 2600 updateObject(columnIndex, x); 2601 } 2602 2603 @Override 2604 public void updateString(String columnName, String x) throws SQLException { 2605 updateObject(columnName, x); 2606 } 2607 2608 @Override 2609 public void updateTime(int columnIndex, Time x) throws SQLException { 2610 updateObject(columnIndex, new DateTimeImpl(x.getTime(),false)); 2611 } 2612 2613 @Override 2614 public void updateTime(String columnName, Time x) throws SQLException { 2615 updateObject(columnName, new DateTimeImpl(x.getTime(),false)); 2616 } 2617 2618 @Override 2619 public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { 2620 updateObject(columnIndex, new DateTimeImpl(x.getTime(),false)); 2621 } 2622 2623 @Override 2624 public void updateTimestamp(String columnName, Timestamp x) throws SQLException { 2625 updateObject(columnName, new DateTimeImpl(x.getTime(),false)); 2626 } 2627 2628 @Override 2629 public ResultSetMetaData getMetaData() throws SQLException { 2630 throw new SQLException("method is not implemented"); 2631 } 2632 2633 @Override 2634 public Iterator<Collection.Key> keyIterator() { 2635 return new KeyIterator(keys()); 2636 } 2637 2638 @Override 2639 public Iterator<String> keysAsStringIterator() { 2640 return new StringIterator(keys()); 2641 } 2642 2643 @Override 2644 public Iterator<Entry<Key, Object>> entryIterator() { 2645 return new EntryIterator(this, keys()); 2646 } 2647 2648 public Iterator<Object> valueIterator() { 2649 return new CollectionIterator(keys(),this); 2650 } 2651 2652 public void readExternal(ObjectInput in) throws IOException { 2653 try { 2654 QueryImpl other=(QueryImpl) new CFMLExpressionInterpreter().interpret(ThreadLocalPageContext.get(),in.readUTF()); 2655 this.arrCurrentRow=other.arrCurrentRow; 2656 this.columncount=other.columncount; 2657 this.columnNames=other.columnNames; 2658 this.columns=other.columns; 2659 this.exeTime=other.exeTime; 2660 this.generatedKeys=other.generatedKeys; 2661 this.isCached=other.isCached; 2662 this.name=other.name; 2663 this.recordcount=other.recordcount; 2664 this.sql=other.sql; 2665 this.updateCount=other.updateCount; 2666 2667 } catch (PageException e) { 2668 throw new IOException(e.getMessage()); 2669 } 2670 } 2671 2672 public void writeExternal(ObjectOutput out) { 2673 try { 2674 out.writeUTF(new ScriptConverter().serialize(this)); 2675 } 2676 catch (Throwable t) {} 2677 } 2678 2679 public int getHoldability() throws SQLException { 2680 throw notSupported(); 2681 } 2682 2683 public boolean isClosed() throws SQLException { 2684 return false; 2685 } 2686 2687 public void updateNString(int columnIndex, String nString)throws SQLException { 2688 updateString(columnIndex, nString); 2689 } 2690 2691 public void updateNString(String columnLabel, String nString)throws SQLException { 2692 updateString(columnLabel, nString); 2693 } 2694 2695 2696 2697 public String getNString(int columnIndex) throws SQLException { 2698 return getString(columnIndex); 2699 } 2700 2701 public String getNString(String columnLabel) throws SQLException { 2702 return getString(columnLabel); 2703 } 2704 2705 public Reader getNCharacterStream(int columnIndex) throws SQLException { 2706 return getCharacterStream(columnIndex); 2707 } 2708 2709 public Reader getNCharacterStream(String columnLabel) throws SQLException { 2710 return getCharacterStream(columnLabel); 2711 } 2712 2713 public void updateNCharacterStream(int columnIndex, Reader x, long length)throws SQLException { 2714 updateCharacterStream(columnIndex, x, length); 2715 } 2716 2717 public void updateNCharacterStream(String columnLabel, Reader reader,long length) throws SQLException { 2718 throw notSupported(); 2719 } 2720 2721 public void updateAsciiStream(int columnIndex, InputStream x, long length)throws SQLException { 2722 throw notSupported(); 2723 } 2724 2725 public void updateBinaryStream(int columnIndex, InputStream x, long length)throws SQLException { 2726 throw notSupported(); 2727 } 2728 2729 public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { 2730 throw notSupported(); 2731 } 2732 2733 public void updateAsciiStream(String columnLabel, InputStream x, long length)throws SQLException { 2734 throw notSupported(); 2735 } 2736 2737 public void updateBinaryStream(String columnLabel, InputStream x,long length) throws SQLException { 2738 throw notSupported(); 2739 } 2740 2741 public void updateCharacterStream(String columnLabel, Reader reader,long length) throws SQLException { 2742 throw notSupported(); 2743 } 2744 2745 public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException { 2746 throw notSupported(); 2747 } 2748 2749 public void updateBlob(String columnLabel, InputStream inputStream,long length) throws SQLException { 2750 throw notSupported(); 2751 } 2752 2753 public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { 2754 throw notSupported(); 2755 } 2756 2757 public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { 2758 throw notSupported(); 2759 } 2760 2761 public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { 2762 updateClob(columnIndex, reader, length); 2763 } 2764 2765 public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { 2766 updateClob(columnLabel, reader,length); 2767 } 2768 2769 public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { 2770 updateCharacterStream(columnIndex, x); 2771 } 2772 2773 public void updateNCharacterStream(String columnLabel, Reader reader)throws SQLException { 2774 throw notSupported(); 2775 } 2776 2777 public void updateAsciiStream(int columnIndex, InputStream x)throws SQLException { 2778 throw notSupported(); 2779 } 2780 2781 public void updateBinaryStream(int columnIndex, InputStream x)throws SQLException { 2782 throw notSupported(); 2783 } 2784 2785 public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { 2786 throw notSupported(); 2787 } 2788 2789 public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { 2790 throw notSupported(); 2791 } 2792 2793 public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { 2794 throw notSupported(); 2795 } 2796 2797 public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { 2798 throw notSupported(); 2799 } 2800 2801 public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { 2802 throw notSupported(); 2803 } 2804 2805 public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { 2806 throw notSupported(); 2807 } 2808 2809 public void updateClob(int columnIndex, Reader reader) throws SQLException { 2810 throw notSupported(); 2811 } 2812 2813 public void updateClob(String columnLabel, Reader reader) throws SQLException { 2814 throw notSupported(); 2815 } 2816 2817 public void updateNClob(int columnIndex, Reader reader) throws SQLException { 2818 updateClob(columnIndex, reader); 2819 } 2820 2821 public void updateNClob(String columnLabel, Reader reader) throws SQLException { 2822 updateClob(columnLabel, reader); 2823 } 2824 2825 public <T> T unwrap(Class<T> iface) throws SQLException { 2826 throw notSupported(); 2827 } 2828 2829 public boolean isWrapperFor(Class<?> iface) throws SQLException { 2830 throw notSupported(); 2831 } 2832 2833 2834 2835 //JDK6: uncomment this for compiling with JDK6 2836 2837 public void updateNClob(int columnIndex, NClob nClob) throws SQLException { 2838 throw notSupported(); 2839 } 2840 2841 public void updateNClob(String columnLabel, NClob nClob) throws SQLException { 2842 throw notSupported(); 2843 } 2844 2845 public NClob getNClob(int columnIndex) throws SQLException { 2846 throw notSupported(); 2847 } 2848 2849 public NClob getNClob(String columnLabel) throws SQLException { 2850 throw notSupported(); 2851 } 2852 2853 public SQLXML getSQLXML(int columnIndex) throws SQLException { 2854 throw notSupported(); 2855 } 2856 2857 public SQLXML getSQLXML(String columnLabel) throws SQLException { 2858 throw notSupported(); 2859 } 2860 2861 public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { 2862 throw notSupported(); 2863 } 2864 2865 public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { 2866 throw notSupported(); 2867 } 2868 2869 public RowId getRowId(int columnIndex) throws SQLException { 2870 throw notSupported(); 2871 } 2872 2873 public RowId getRowId(String columnLabel) throws SQLException { 2874 throw notSupported(); 2875 } 2876 2877 public void updateRowId(int columnIndex, RowId x) throws SQLException { 2878 throw notSupported(); 2879 } 2880 2881 public void updateRowId(String columnLabel, RowId x) throws SQLException { 2882 throw notSupported(); 2883 } 2884 2885 public void removeRows(int index, int count) throws PageException { 2886 QueryUtil.removeRows(this,index,count); 2887 } 2888 2889 2890 private SQLException notSupported() { 2891 return new SQLException("this feature is not supported"); 2892 } 2893 2894 public synchronized void enableShowQueryUsage() { 2895 if(columns!=null)for(int i=0;i<columns.length;i++){ 2896 columns[i]=columns[i]._toDebugColumn(); 2897 } 2898 } 2899 2900 @Override 2901 public long getExecutionTime() { 2902 return exeTime; 2903 } 2904 2905 public static QueryImpl cloneQuery(Query qry,boolean deepCopy) { 2906 QueryImpl newResult=new QueryImpl(); 2907 ThreadLocalDuplication.set(qry, newResult); 2908 try{ 2909 newResult.columnNames=qry.getColumnNames(); 2910 newResult.columns=new QueryColumnImpl[newResult.columnNames.length]; 2911 QueryColumn col; 2912 for(int i=0;i<newResult.columnNames.length;i++) { 2913 col = qry.getColumn(newResult.columnNames[i],null); 2914 newResult.columns[i]=QueryUtil.duplicate2QueryColumnImpl(newResult,col,deepCopy); 2915 } 2916 2917 2918 newResult.sql=qry.getSql(); 2919 newResult.template=qry.getTemplate(); 2920 newResult.recordcount=qry.getRecordcount(); 2921 newResult.columncount=newResult.columnNames.length; 2922 newResult.isCached=qry.isCached(); 2923 newResult.name=qry.getName(); 2924 newResult.exeTime=qry.getExecutionTime(); 2925 newResult.updateCount=qry.getUpdateCount(); 2926 if(qry.getGeneratedKeys()!=null)newResult.generatedKeys=((QueryImpl)qry.getGeneratedKeys()).cloneQuery(false); 2927 return newResult; 2928 } 2929 finally { 2930 // ThreadLocalDuplication.remove(qry); removed "remove" to catch sisters and brothers 2931 } 2932 } 2933 2934 @Override 2935 public java.util.Iterator getIterator() { 2936 return new ForEachQueryIterator(this, ThreadLocalPageContext.get().getId()); 2937 } 2938 2939 @Override 2940 public boolean equals(Object obj){ 2941 if(!(obj instanceof Collection)) return false; 2942 return CollectionUtil.equals(this,(Collection)obj); 2943 } 2944 2945 @Override 2946 public int hashCode() { 2947 return CollectionUtil.hashCode(this); 2948 } 2949 }