001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.functions.query; 020 021import java.util.Iterator; 022import java.util.Map.Entry; 023 024import lucee.commons.lang.StringUtil; 025import lucee.runtime.PageContext; 026import lucee.runtime.exp.FunctionException; 027import lucee.runtime.exp.PageException; 028import lucee.runtime.functions.BIF; 029import lucee.runtime.op.Caster; 030import lucee.runtime.op.Decision; 031import lucee.runtime.type.Array; 032import lucee.runtime.type.ArrayImpl; 033import lucee.runtime.type.Collection.Key; 034import lucee.runtime.type.Query; 035import lucee.runtime.type.QueryImpl; 036import lucee.runtime.type.Struct; 037import lucee.runtime.type.util.ListUtil; 038import lucee.runtime.type.util.QueryUtil; 039 040/** 041 * Implements the CFML Function querynew 042 */ 043public final class QueryNew extends BIF { 044 045 private static final long serialVersionUID = -4313766961671090938L; 046 047 /** @deprecated used by old lucee archives */ 048 public static lucee.runtime.type.Query call(PageContext pc , String columnNames) throws PageException { 049 return call(pc, (Object)columnNames); 050 } 051 052 /** @deprecated used by old lucee archives */ 053 public static lucee.runtime.type.Query call(PageContext pc , String columnNames, String columnTypes) throws PageException { 054 return call(pc, (Object)columnNames, (Object)columnTypes); 055 } 056 057 /** @deprecated used by old lucee archives */ 058 public static lucee.runtime.type.Query call(PageContext pc , String columnNames, String columnTypes, Object data) throws PageException { 059 return call(pc, (Object)columnNames, (Object)columnTypes,data); 060 } 061 062 063 064 065 public static lucee.runtime.type.Query call(PageContext pc , Object columnNames) throws PageException { 066 return new QueryImpl(toArray(pc,columnNames,1),0,"query"); 067 } 068 069 public static lucee.runtime.type.Query call(PageContext pc , Object columnNames, Object columnTypes) throws PageException { 070 if(StringUtil.isEmpty(columnTypes)) return call(pc, columnNames); 071 return new QueryImpl(toArray(pc,columnNames,1),toArray(pc,columnTypes,2),0,"query"); 072 } 073 074 public static lucee.runtime.type.Query call(PageContext pc , Object columnNames, Object columnTypes, Object data) throws PageException { 075 076 Array cn = toArray(pc, columnNames, 1); 077 lucee.runtime.type.Query qry; 078 if(StringUtil.isEmpty(columnTypes)) 079 qry= new QueryImpl(cn,0,"query"); 080 else 081 qry= new QueryImpl(cn,toArray(pc, columnTypes, 2),0,"query"); 082 083 if(data==null) return qry; 084 return populate(pc, qry, data); 085 } 086 087 @Override 088 public Object invoke(PageContext pc, Object[] args) throws PageException { 089 if(args.length==1)return call(pc,Caster.toString(args[0])); 090 if(args.length==2)return call(pc,Caster.toString(args[0]),Caster.toString(args[1])); 091 return call(pc,Caster.toString(args[0]),Caster.toString(args[1]),args[2]); 092 } 093 094 public static Query populate(PageContext pc, Query qry,Object data) throws PageException { 095 if(Decision.isArray(data)) 096 return _populate(pc,qry,Caster.toArray(data)); 097 else if(Decision.isStruct(data)) 098 return _populate(pc,qry,Caster.toStruct(data)); 099 else 100 throw new FunctionException(pc, "QueryNew", 3, "data", "the date must be defined as array of structs , array of arrays or struct of arrays"); 101 } 102 103 private static Query _populate(PageContext pc, Query qry,Struct data) throws PageException { 104 Iterator<Entry<Key, Object>> it = data.entryIterator(); 105 Entry<Key, Object> e; 106 Object v; 107 Array arr; 108 int rows = qry.getRecordcount(); 109 while(it.hasNext()){ 110 e = it.next(); 111 if(qry.getColumn(e.getKey(),null)!=null) { 112 v=e.getValue(); 113 arr = Caster.toArray(v,null); 114 if(arr==null) arr=new ArrayImpl(new Object[]{v}); 115 populateColumn(qry,e.getKey(),arr,rows); 116 } 117 } 118 return qry; 119 } 120 121 private static void populateColumn(Query qry, Key column, Array data,int rows) throws PageException { 122 Iterator<?> it = data.valueIterator(); 123 int row=rows; 124 while(it.hasNext()){ 125 row++; 126 if(row>qry.getRecordcount()) qry.addRow(); 127 qry.setAt(column, row, it.next()); 128 } 129 } 130 131 private static Query _populate(PageContext pc, Query qry,Array data) throws PageException { 132 // check if the array only contains simple values or mixed 133 Iterator<?> it = data.valueIterator(); 134 Object o; 135 boolean hasSimpleValues=false; 136 while(it.hasNext()){ 137 o=it.next(); 138 if(!Decision.isStruct(o) && !Decision.isArray(o)) hasSimpleValues=true; 139 } 140 141 142 if(hasSimpleValues) { 143 qry.addRow(); 144 populateRow(qry, data); 145 } 146 else { 147 it = data.valueIterator(); 148 while(it.hasNext()){ 149 o=it.next(); 150 qry.addRow(); 151 if(Decision.isStruct(o))populateRow(qry,Caster.toStruct(o)); 152 else if(Decision.isArray(o))populateRow(qry,Caster.toArray(o)); 153 else { 154 populateRow(qry,new ArrayImpl(new Object[]{o})); 155 } 156 } 157 } 158 return qry; 159 } 160 161 private static void populateRow(Query qry, Struct data) throws PageException { 162 Key[] columns = QueryUtil.getColumnNames(qry); 163 int row=qry.getRecordcount(); 164 Object value; 165 for(int i=0;i<columns.length;i++){ 166 value=data.get(columns[i],null); 167 if(value!=null) qry.setAt(columns[i], row, value); 168 } 169 170 } 171 172 private static void populateRow(Query qry, Array data) throws PageException { 173 Iterator<?> it = data.valueIterator(); 174 Key[] columns = QueryUtil.getColumnNames(qry); 175 int row=qry.getRecordcount(); 176 int index=-1; 177 while(it.hasNext()){ 178 index++; 179 if(index>=columns.length) break; 180 qry.setAt(columns[index], row, it.next()); 181 } 182 } 183 184 private static Array toArray(PageContext pc,Object columnNames, int index) throws PageException { 185 if(Decision.isArray(columnNames)) 186 return Caster.toArray(columnNames); 187 String str=Caster.toString(columnNames,null); 188 if(str==null) throw new FunctionException(pc, "QueryNew", index, index==1?"columnNames":"columnTypes", "cannot cast to a array or a string list"); 189 return ListUtil.listToArrayTrim(str,","); 190 } 191}