001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdbc;
012:
013: import com.versant.core.jdo.query.*;
014: import com.versant.core.metadata.MDStatics;
015: import com.versant.core.metadata.FieldMetaData;
016: import com.versant.core.metadata.MDStaticUtils;
017: import com.versant.core.common.BindingSupportImpl;
018: import com.versant.core.jdbc.sql.SqlDriver;
019: import com.versant.core.util.IntArray;
020:
021: /**
022: * This is a class that knows how to decode a result or projection query.
023: */
024: public class ProjectionQueryDecoder {
025: private static final int[] EMPTY_INT_ARRAY = new int[0];
026:
027: public static final int TYPE_THIS = 1;
028: public static final int TYPE_AGGRETATE = 2;
029: public static final int TYPE_FIELD = 3;
030: public static final int TYPE_EXP = 4;
031: public static final int TYPE_VAR = 5;
032:
033: private int[] typeMap;
034: private Object[] fmdMap;
035: private int[] typeCodeMap;
036: private int[] refIndexes;
037: private int firstThisColumn = -1;
038: private boolean containsOnlyThis;
039: private boolean containsThis;
040: private boolean aggregateOnly = true;
041: private boolean containsAggregate;
042: private SqlDriver driver;
043:
044: public ProjectionQueryDecoder(ResultNode resultNode,
045: SqlDriver driver) {
046: int size = resultNode.getResultSize();
047: typeMap = new int[size];
048: fmdMap = new Object[size];
049: typeCodeMap = new int[size];
050: refIndexes = new int[size];
051: this .driver = driver;
052: calculateTypes(size, resultNode);
053: }
054:
055: private void calculateTypes(int size, ResultNode resultNode) {
056: int counter = 0;
057: IntArray refIndexArray = new IntArray();
058: for (Node n = resultNode.childList; n != null; n = n.next) {
059: if (n instanceof ReservedFieldNode) {
060: typeCodeMap[counter] = MDStatics.OID;
061: typeMap[counter] = TYPE_THIS;
062: containsThis = true;
063: aggregateOnly = false;
064: if (firstThisColumn == -1) {
065: firstThisColumn = counter;
066: }
067: } else if (n instanceof AggregateNode) {
068: typeMap[counter] = TYPE_AGGRETATE;
069: containsAggregate = true;
070: typeCodeMap[counter] = getTypeCode((AggregateNode) n,
071: driver);
072: } else if (n instanceof AddNode
073: || n instanceof MultiplyNode) {
074: typeMap[counter] = TYPE_EXP;
075: typeCodeMap[counter] = getTypeCode(n.childList);
076: } else {
077: typeMap[counter] = TYPE_FIELD;
078: if (n instanceof FieldNode) {
079: fmdMap[counter] = ((FieldNode) n).fmd;
080: typeCodeMap[counter] = ((FieldMetaData) fmdMap[counter]).typeCode;
081: } else if (n instanceof FieldNavNode) {
082: fmdMap[counter] = ((FieldNavNode) n).getResultFmd();
083: typeCodeMap[counter] = ((FieldMetaData) fmdMap[counter]).typeCode;
084: } else if (n instanceof VarNodeIF) {
085: typeMap[counter] = TYPE_VAR;
086: typeCodeMap[counter] = MDStatics.OID;
087: fmdMap[counter] = ((VarNodeIF) n).getVarNode()
088: .getCmd();
089: } else {
090: throw BindingSupportImpl.getInstance().internal("");
091: }
092:
093: //calculate if ref field.
094: if (typeMap[counter] == TYPE_FIELD
095: && (((FieldMetaData) fmdMap[counter]).category == MDStatics.CATEGORY_REF || ((FieldMetaData) fmdMap[counter]).category == MDStatics.CATEGORY_POLYREF)) {
096: refIndexArray.add(counter);
097: typeCodeMap[counter] = MDStatics.OID;
098: }
099: aggregateOnly = false;
100: }
101: counter++;
102: }
103:
104: if (size == 1 && containsThis == true) {
105: containsOnlyThis = true;
106: }
107:
108: if (refIndexArray.size() == 0) {
109: refIndexes = EMPTY_INT_ARRAY;
110: } else {
111: refIndexes = refIndexArray.toArray();
112: }
113: }
114:
115: private int getTypeCode(AggregateNode node, SqlDriver driver) {
116: int type = node.getType();
117: if (type == AggregateNode.TYPE_COUNT
118: || node instanceof AggregateCountStarNode) {
119:
120: return MDStatics.LONGW;
121:
122: }
123: return driver.getAggregateTypeCode(type,
124: getTypeCode(node.childList));
125: }
126:
127: public boolean containsThis() {
128: return containsThis;
129: }
130:
131: public boolean containsAggregate() {
132: return containsAggregate;
133: }
134:
135: public boolean aggregateOnly() {
136: return aggregateOnly;
137: }
138:
139: public int[] getResultTypeArray() {
140: return typeMap;
141: }
142:
143: public Object[] getFmdArray() {
144: return fmdMap;
145: }
146:
147: public int[] getTypeCodes() {
148: return typeCodeMap;
149: }
150:
151: /**
152: * The index of the first occur. of 'this' in the projection.
153: */
154: public int getFirstThisIndex() {
155: return firstThisColumn;
156: }
157:
158: /**
159: * Array containing the index pos of ref fields.
160: * return null if no ref fields.
161: */
162: public int[] getRefIndexArray() {
163: return refIndexes;
164: }
165:
166: /**
167: * If this is a result that only contains 'this' and no other
168: * fields in the projection.
169: */
170: public boolean isContainsThisOnly() {
171: return containsOnlyThis;
172: }
173:
174: /**
175: * The wrapper typecode of the exp. If the field eval to a primitive then the
176: * wrapper for that type is returned.
177: */
178: public static int getTypeCode(Node fn) {
179: if (fn instanceof AddNode || fn instanceof MultiplyNode) {
180: return getTypeCode(fn.childList);
181: }
182:
183: int typeCode = MDStatics.BYTEW;
184:
185: for (Node n = fn; n != null; n = n.next) {
186:
187: int tmpCode = MDStaticUtils.primToNumberMapping[getTypeCodeImp(n)];
188:
189: if (tmpCode > typeCode) {
190: typeCode = tmpCode;
191: }
192: }
193: return typeCode;
194: }
195:
196: public static int getTypeCodeImp(Node n) {
197: if (n instanceof FieldNode) {
198: return ((FieldNode) n).fmd.typeCode;
199: } else if (n instanceof FieldNavNode) {
200: return getTypeCodeImp(n.childList);
201: } else {
202: throw BindingSupportImpl.getInstance().internal(
203: "Expecting either a fieldNode or a FieldNavNode.");
204: }
205: }
206: }
|