1 2 12 package com.versant.core.jdbc.ejbql; 13 14 import com.versant.core.jdbc.JdbcStorageManager; 15 import com.versant.core.jdbc.metadata.JdbcField; 16 import com.versant.core.jdbc.fetch.FetchSpec; 17 import com.versant.core.jdbc.fetch.SqlBuffer; 18 import com.versant.core.jdbc.sql.exp.SqlExp; 19 import com.versant.core.jdbc.sql.exp.SelectExp; 20 import com.versant.core.jdbc.sql.exp.SqlParamUsage; 21 import com.versant.core.jdbc.sql.exp.ColumnExp; 22 import com.versant.core.jdbc.query.JdbcCompiledQuery; 23 import com.versant.core.metadata.ModelMetaData; 24 import com.versant.core.metadata.ClassMetaData; 25 import com.versant.core.jdo.QueryDetails; 26 import com.versant.core.ejb.query.*; 27 import com.versant.core.common.BindingSupportImpl; 28 import com.versant.core.common.Debug; 29 import com.versant.core.common.CmdBitSet; 30 31 import java.io.StringReader ; 32 33 36 public class JdbcEJBQLCompiler { 37 38 private final JdbcStorageManager sm; 39 private final ModelMetaData jmd; 40 41 public JdbcEJBQLCompiler(JdbcStorageManager sm) { 42 this.sm = sm; 43 this.jmd = sm.getJmd(); 44 } 45 46 49 public JdbcCompiledQuery compile(QueryDetails q) { 50 Node tree = parse(q); 51 if (Debug.DEBUG) { 52 System.out.println("\n%%% parsed:\n" + tree + "\n"); 53 } 54 55 ResolveContext rc = new ResolveContext(jmd); 56 tree.resolve(rc); 57 if (Debug.DEBUG) { 58 System.out.println("%%% resolved:\n" + tree + "\n"); 59 rc.dump(System.out); 60 System.out.println(); 61 } 62 63 EJBQLNodeToSqlExp converter = new EJBQLNodeToSqlExp(rc, 64 sm.getSqlDriver()); 65 SqlExp sqlExp = converter.toSqlExp(tree, null); 66 if (!(sqlExp instanceof SelectExp)) { 67 throw BindingSupportImpl.getInstance().internal("not supported"); 68 } 69 SelectExp root = (SelectExp)sqlExp; 70 FetchSpec spec = root.fetchSpec; 71 compileParams(rc, spec); 72 if (Debug.DEBUG) { 73 System.out.println("%%% root:"); 74 root.dump(" "); 75 System.out.println("\n%%% root.fetchSpec"); 76 spec.printPlan(System.out, " "); 77 } 78 79 ClassMetaData candidateCMD = rc.getRoot(0).getNavClassMetaData(); 80 JdbcCompiledQueryEJBQL cq = new JdbcCompiledQueryEJBQL(candidateCMD, 81 q, spec); 82 83 CmdBitSet bits = new CmdBitSet(jmd); 84 for (int i = rc.getRootCount() - 1; i >= 0; i--) { 85 rc.getRoot(i).addInvolvedClasses(bits); 86 } 87 int[] a = q.getExtraEvictClasses(); 88 if (a != null) { 89 for (int i = a.length - 1; i >= 0; i--) { 90 bits.add(jmd.classes[a[i]]); 91 } 92 } 93 cq.setFilterClsIndexs(bits.toArray()); 94 cq.setEvictionClassBits(bits.getBits()); 95 cq.setEvictionClassIndexes(bits.getIndexes()); 96 97 return cq; 98 } 99 100 private Node parse(QueryDetails q) { 101 String filter = q.getFilter(); 102 if (filter == null) { 103 throw BindingSupportImpl.getInstance().invalidOperation( 104 "EJBQL query string (filter) is null"); 105 } 106 StringReader r = new StringReader (filter); 107 EJBQLParser p = new EJBQLParser(r); 108 try { 109 return p.ejbqlQuery(); 110 } catch (ParseException e) { 111 throw BindingSupportImpl.getInstance().invalidOperation( 112 e.getMessage()); 113 } 114 } 115 116 131 private void compileParams(ResolveContext rc, FetchSpec spec) { 132 ResolveContext.ParamUsage[] params = rc.getParameters(); 133 if (params == null) { 134 return; 135 } 136 SqlBuffer.Param list = null; 137 SqlBuffer.Param pos = null; 138 int np = params.length; 139 for (int i = 0; i < np; i++) { 140 for (ResolveContext.ParamUsage rcUsage = params[i]; 141 rcUsage != null; rcUsage = rcUsage.getNext()) { 142 SqlParamUsage usage = (SqlParamUsage)rcUsage.storeObject; 143 144 SqlBuffer.Param param = new SqlBuffer.Param( 146 rcUsage.getParamNode().getName()); 147 if (pos == null) { 148 pos = list = param; 149 } else { 150 pos = pos.next = param; 151 } 152 153 param.declaredParamIndex = rcUsage.getIndex(); 155 JdbcField jdbcField = usage.jdbcField; 156 if (jdbcField == null) { 157 param.classIndex = usage.classIndex; 158 param.fieldNo = -1; 159 param.javaTypeCode = usage.javaTypeCode; 160 param.jdbcType = usage.jdbcType; 162 param.col = usage.col; 163 } else { 164 param.classIndex = jdbcField.fmd.classMetaData.index; 165 param.fieldNo = jdbcField.stateFieldNo; 166 param.col = usage.col; 167 } 168 param.mod = usage.mod; 169 170 if (usage.expCount > 0) { 172 SqlBuffer.CharSpan cspos = null; 173 SqlBuffer.CharSpan[] a 174 = new SqlBuffer.CharSpan[usage.expCount]; 175 boolean multicol = usage.expCount > 1; 176 int j = 0; 177 int removeCount = 0; 178 for (SqlExp e = usage.expList; j < a.length; j++) { 179 SqlBuffer.CharSpan cs = a[j] = 180 new SqlBuffer.CharSpan(); 181 if (multicol && mustBeRemovedIfNull(e)) { 182 if (++removeCount == a.length) { 183 multicol = false; 186 e = usage.expList; 187 j = -1; 188 cspos = null; 189 continue; 190 } 191 cs.firstCharIndex = e.getPreFirstCharIndex(); 192 if (e.next == null) { cs.lastCharIndex = e.getLastCharIndex(); 194 for (int k = j - 1; k >= 0; k--) { 196 if (a[k].type != SqlBuffer.CharSpan.TYPE_REMOVE) { 197 a[k + 1].firstCharIndex -= 4; break; 199 } 200 } 201 } else { cs.lastCharIndex = e.next.getPreFirstCharIndex(); 203 } 204 cs.type = SqlBuffer.CharSpan.TYPE_REMOVE; 205 } else { 206 cs.firstCharIndex = e.getFirstCharIndex(); 207 cs.lastCharIndex = e.getLastCharIndex(); 208 cs.type = e.isNegative() 209 ? SqlBuffer.CharSpan.TYPE_NOT_NULL 210 : SqlBuffer.CharSpan.TYPE_NULL; 211 } 212 213 if (cspos == null) { 214 cspos = param.charSpanList = cs; 215 param.firstCharIndex = cs.firstCharIndex; 216 } else { 217 cspos = cspos.next = cs; 218 } 219 220 e = e.next; 221 } 222 } else { 223 param.firstCharIndex = usage.expList.getFirstCharIndex(); 224 } 225 } 226 } 227 if (list != null) { 228 spec.setParamList(sortParams(list)); 229 } 230 } 231 232 236 private static boolean mustBeRemovedIfNull(SqlExp e) { 237 if (!e.isNegative() && e.childList instanceof ColumnExp) { 238 ColumnExp ce = (ColumnExp)e.childList; 239 return !ce.col.isForUpdate(); 240 } 241 return false; 242 } 243 244 247 private static SqlBuffer.Param sortParams(SqlBuffer.Param list) { 248 if (list.next == null) return list; 249 for (; ;) { 251 boolean changed = false; 252 SqlBuffer.Param p0 = null; 253 for (SqlBuffer.Param p1 = list; ;) { 254 SqlBuffer.Param p2 = p1.next; 255 if (p2 == null) break; 256 if (p1.firstCharIndex > p2.firstCharIndex) { 257 p1.next = p2.next; 259 p2.next = p1; 260 if (p0 == null) { 261 list = p2; 262 } else { 263 p0.next = p2; 264 } 265 p0 = p2; 266 changed = true; 267 } else { 268 p0 = p1; 269 p1 = p2; 270 } 271 } 272 if (!changed) return list; 273 } 274 } 275 276 308 309 } 310 311 | Popular Tags |