001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019: package org.netbeans.modules.sql.framework.codegen.jdbc;
020:
021: import java.util.ArrayList;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Set;
027:
028: import org.apache.velocity.VelocityContext;
029: import org.netbeans.modules.sql.framework.codegen.AbstractDB;
030: import org.netbeans.modules.sql.framework.codegen.ColumnIdentifier;
031: import org.netbeans.modules.sql.framework.codegen.ResolvedMapping;
032: import org.netbeans.modules.sql.framework.codegen.StatementContext;
033: import org.netbeans.modules.sql.framework.codegen.TemplateBuilder;
034: import org.netbeans.modules.sql.framework.codegen.base.BaseStatements;
035: import org.netbeans.modules.sql.framework.model.SQLCondition;
036: import org.netbeans.modules.sql.framework.model.SQLConstants;
037: import org.netbeans.modules.sql.framework.model.SQLPredicate;
038: import org.netbeans.modules.sql.framework.model.SourceColumn;
039: import org.netbeans.modules.sql.framework.model.TargetColumn;
040: import org.netbeans.modules.sql.framework.model.TargetTable;
041:
042: import com.sun.sql.framework.exception.BaseException;
043: import com.sun.sql.framework.jdbc.SQLPart;
044: import com.sun.sql.framework.jdbc.SQLUtils;
045: import com.sun.sql.framework.utils.RuntimeAttribute;
046:
047: /**
048: * For JDBC or ANSI standard Database code generations.
049: * @author Girish Patil
050: * @version $Revision $
051: */
052: public class JdbcStatements extends BaseStatements {
053: private static final String RUNTIME_INPUTS_MAP = "runtimeInputsMap";
054: private static final String DIRECTLY_MAPPED_SRC_COLS_EVAL = "directlyMappedSrcColsEval";
055: private static final String MAPPINGS = "mappings";
056: private static final String ADDITIONAL_SRC_COLS = "additionalSrcCols";
057:
058: public JdbcStatements(AbstractDB database) {
059: super (database);
060: }
061:
062: protected void populateContextForUpdate(TargetTable targetTable,
063: StatementContext context, VelocityContext vContext)
064: throws BaseException {
065: final boolean excludeJoinKeyColumns = false;
066: // SELECT START
067: StatementContext localContext = new StatementContext();
068: if (context != null) {
069: localContext.putAll(context);
070: }
071:
072: //Use the Table Qualification flag to suppress column prefix
073: localContext.setSuppressingTablePrefixForTargetColumn(true);
074: List rMappings = createResolvedMappingsForUpdate(targetTable,
075: excludeJoinKeyColumns, localContext);
076: localContext.setSuppressingTablePrefixForTargetColumn(false);
077:
078: String targetTableSql = this .genFactory.generate(targetTable,
079: localContext);
080:
081: localContext.putClientProperty(
082: StatementContext.USE_SOURCE_TABLE_ALIAS_NAME,
083: Boolean.TRUE);
084: localContext.putClientProperty(
085: StatementContext.USE_TARGET_TABLE_ALIAS_NAME,
086: Boolean.TRUE);
087:
088: vContext.put("targetTable", targetTableSql);
089: vContext.put("fromContent", getFromStatementContentForTarget(
090: targetTable, SQLConstants.INNER_JOIN, localContext));
091: vContext.put("nestedIndent", " ");
092:
093: vContext.put("useUpdateWhere", Boolean.FALSE);
094:
095: String condition = getWhereCondition(targetTable, localContext);
096:
097: context.putClientProperty(
098: StatementContext.USE_SOURCE_TABLE_ALIAS_NAME,
099: Boolean.TRUE);
100: context.putClientProperty(
101: StatementContext.USE_TARGET_TABLE_ALIAS_NAME,
102: Boolean.TRUE);
103:
104: String updateWhereClause = getWhereClauseForUpdate(targetTable,
105: context);
106: if (condition != null && !condition.equals("")) {
107: condition += " AND " + updateWhereClause;
108: } else {
109: condition = updateWhereClause;
110: }
111:
112: context.putClientProperty(
113: StatementContext.USE_TARGET_TABLE_ALIAS_NAME,
114: Boolean.FALSE);
115: vContext.put("tgtCondition", getWhereClauseForUpdate(
116: targetTable, context));
117: context.putClientProperty(
118: StatementContext.USE_TARGET_TABLE_ALIAS_NAME,
119: Boolean.TRUE);
120:
121: if (condition != null && !condition.equals("")) {
122: vContext.put("useUpdateWhere", Boolean.TRUE);
123: vContext.put("condition", condition);
124: }
125: // SELECT END
126:
127: vContext.put(JdbcStatements.MAPPINGS, rMappings);
128:
129: // exception when
130: localContext.putClientProperty("nestedIndent", "");
131: localContext.putClientProperty("valueIdentifiers", vContext
132: .get("sourceColumnIdentifiers"));
133: }
134:
135: public List createResolvedMappingsForUpdate(
136: TargetTable targetTable, boolean excludeKeyColumns,
137: StatementContext context) throws BaseException {
138: ArrayList mappings = new ArrayList();
139: String targetJoin = getTargetJoinClause(targetTable,
140: SQLConstants.INNER_JOIN, context);
141:
142: StatementContext localContext = new StatementContext();
143: localContext.putAll(context);
144: localContext.putClientProperty(
145: StatementContext.USE_SOURCE_TABLE_ALIAS_NAME,
146: Boolean.TRUE);
147:
148: Iterator it = targetTable.getMappedColumns().iterator();
149: int aliasCount = 1;
150:
151: while (it.hasNext()) {
152: TargetColumn column = (TargetColumn) it.next();
153: if (column.getValue() != null) {
154: String tSql = this .genFactory.generate(column, context);
155: if (targetJoin.indexOf(tSql) != -1 && excludeKeyColumns) {
156: continue;
157: }
158:
159: String sSql = this .genFactory.generate(column
160: .getValue(), localContext);
161:
162: ColumnIdentifier sId = new ColumnIdentifier(null, sSql);
163: ColumnIdentifier tId = new ColumnIdentifier(null, tSql);
164: ResolvedMapping rm = new ResolvedMapping(sId, tId);
165: mappings.add(rm);
166: aliasCount++;
167: }
168: }
169:
170: return mappings;
171: }
172:
173: private List evaluateSourceColumnList(List srcColListtargetTable,
174: StatementContext context) throws BaseException {
175: List srcColEvals = new ArrayList();
176: Map srcExpToJdbcTypeMap = (Map) context
177: .getClientProperty(BaseStatements.SRC_EXP_TO_JDBC_TYPE_MAP);
178: if (srcExpToJdbcTypeMap == null) {
179: srcExpToJdbcTypeMap = new HashMap();
180: context.putClientProperty(
181: BaseStatements.SRC_EXP_TO_JDBC_TYPE_MAP,
182: srcExpToJdbcTypeMap);
183: }
184:
185: StatementContext localContext = new StatementContext();
186: localContext.putAll(context);
187: localContext.putClientProperty(
188: StatementContext.USE_SOURCE_TABLE_ALIAS_NAME,
189: Boolean.TRUE);
190:
191: Iterator it = srcColListtargetTable.iterator();
192: String sSql = null;
193: SourceColumn column = null;
194:
195: while (it.hasNext()) {
196: column = (SourceColumn) it.next();
197: if (column != null) {
198: sSql = this .genFactory.generate(column, localContext);
199: srcColEvals.add(sSql);
200: srcExpToJdbcTypeMap
201: .put(sSql, "" + column.getJdbcType());
202: }
203: }
204:
205: return srcColEvals;
206: }
207:
208: private String getWhereClauseForUpdate(TargetTable targetTable,
209: StatementContext context) throws BaseException {
210:
211: SQLCondition joinCondition = targetTable.getJoinCondition();
212: SQLPredicate joinPredicate = null;
213: if (joinCondition != null) {
214: joinPredicate = joinCondition.getRootPredicate();
215: }
216:
217: if (joinPredicate == null) {
218: throw new BaseException("Missing merge condition.");
219: }
220: return this .genFactory.generate(joinPredicate, context);
221:
222: }
223:
224: /**
225: * Returns list of integer or String. If element is integer it represent Datum posiotion in the result set else
226: * it is RunTimeInput symbol name.
227: *
228: * @param sql
229: * @param mappedList
230: * @param additionalSelectCols
231: * @param riMap
232: * @return List of items to be populated into update statement.
233: */
234: private String mapDestinationCols(String sql,
235: StatementContext context) {
236: List symbolList = new ArrayList();
237: List destinationsSource = new ArrayList();
238: List newBindingVariables = new ArrayList();
239: String symbol = null;
240: int mappedCols = 0;
241: RuntimeAttribute ra = null;
242: List directlyMappedSrcColsEval = (List) context
243: .getClientProperty(JdbcStatements.DIRECTLY_MAPPED_SRC_COLS_EVAL);
244: List additionalSelectColsEval = (List) context
245: .getClientProperty(JdbcStatements.ADDITIONAL_SRC_COLS);
246: List jdbcTypeList = (List) context
247: .getClientProperty(SQLPart.ATTR_JDBC_TYPE_LIST);
248: List mappings = (List) context.getClientProperty(MAPPINGS);
249: Map riMap = (Map) context.getClientProperty(RUNTIME_INPUTS_MAP);
250: Map symbol2JdbcTypeMap = (Map) context
251: .getClientProperty(BaseStatements.SRC_EXP_TO_JDBC_TYPE_MAP);
252: context.putClientProperty(SQLPart.ATTR_DESTS_SRC,
253: destinationsSource);
254:
255: if (mappings != null) {
256: mappedCols = mappings.size();
257: }
258:
259: if (directlyMappedSrcColsEval != null) {
260: symbolList.addAll(directlyMappedSrcColsEval);
261: }
262:
263: if (additionalSelectColsEval != null) {
264: symbolList.addAll(additionalSelectColsEval);
265: }
266:
267: for (int i = 1; i <= mappedCols; i++) {
268: destinationsSource.add(i - 1, "" + i);
269: }
270:
271: // RuntimeAttributes needed in Where clause
272: if (riMap != null) {
273: Set keys = riMap.keySet();
274: Iterator itr = keys.iterator();
275: while (itr.hasNext()) {
276: ra = (RuntimeAttribute) riMap.get(itr.next());
277: symbolList.add("$" + ra.getAttributeName());
278: symbol2JdbcTypeMap.put("$" + ra.getAttributeName(), ""
279: + ra.getJdbcType());
280: }
281: }
282: //return sourcSymbolOrder;
283:
284: // Get order of symbols in the statement and replace symbols with "?".
285: sql = SQLUtils.createPreparedStatement(sql, symbolList,
286: newBindingVariables);
287: Iterator itr = newBindingVariables.iterator();
288:
289: while (itr.hasNext()) {
290: symbol = (String) itr.next();
291: if ((symbol != null) && (symbol.startsWith("$"))) {
292: destinationsSource.add(symbol);
293: } else {
294: destinationsSource.add(""
295: + (symbolList.indexOf(symbol) + 1));
296: }
297: jdbcTypeList.add(symbol2JdbcTypeMap.get(symbol));
298: }
299:
300: return sql;
301: }
302:
303: // TODO Voilates Statements interface pattern, need to redesign the interfaces.
304: public Map getCorrelatedUpdateStatement(TargetTable targetTable,
305: final StatementContext sc) throws BaseException {
306: StatementContext context = new StatementContext();
307: context.putAll(sc);
308: Map ret = null;
309: Map runtimeInputsMap = (Map) context
310: .getClientProperty(RUNTIME_INPUTS_MAP); // No I18N
311: List directSourceColumns = new ArrayList();
312: VelocityContext vContext = new VelocityContext();
313: String templateName = "";
314: String sqlSelect = null;
315: String sqlUpdate = null;
316: SQLPart select = null;
317: SQLPart update = null;
318:
319: if (targetTable.getSourceTableList().size() != 0) {
320: List srcColDirectlyMapped = getSourceColsDirectlyMapped(
321: targetTable, context);
322: List columnsTobeAliased = getConditionColumnsNotInList(
323: targetTable.getJoinCondition(),
324: srcColDirectlyMapped, context);
325: directSourceColumns.addAll(srcColDirectlyMapped);
326: directSourceColumns.addAll(columnsTobeAliased);
327: List directlyMappedSrcColsEval = evaluateSourceColumnList(
328: srcColDirectlyMapped, context);
329: List additionalSrcColsEval = evaluateSourceColumnList(
330: columnsTobeAliased, context);
331:
332: populateContextForUpdate(targetTable, context, vContext);
333: vContext.put(JdbcStatements.ADDITIONAL_SRC_COLS,
334: additionalSrcColsEval);
335: templateName = this .db
336: .getTemplateFileName("correlatedSelect"); // NOI18N
337: sqlSelect = TemplateBuilder.generateSql(templateName,
338: vContext);
339: templateName = this .db
340: .getTemplateFileName("correlatedUpdate"); // NOI18N
341: sqlUpdate = TemplateBuilder.generateSql(templateName,
342: vContext);
343:
344: // Context already has JDCB type for all the selected columns
345: context.putClientProperty(JdbcStatements.MAPPINGS, vContext
346: .get(JdbcStatements.MAPPINGS));
347: context.putClientProperty(
348: JdbcStatements.ADDITIONAL_SRC_COLS,
349: additionalSrcColsEval);
350: context.putClientProperty(
351: JdbcStatements.DIRECTLY_MAPPED_SRC_COLS_EVAL,
352: directlyMappedSrcColsEval);
353: context
354: .putClientProperty(
355: JdbcStatements.RUNTIME_INPUTS_MAP,
356: runtimeInputsMap);
357: sqlUpdate = mapDestinationCols(sqlUpdate, context);
358:
359: select = createSQLPart(sqlSelect,
360: SQLPart.STMT_CORRELATED_SELECT);
361: update = createSQLPart(sqlUpdate,
362: SQLPart.STMT_CORRELATED_UPDATE);
363: update.setAttribute(SQLPart.ATTR_JDBC_TYPE_LIST, context
364: .getClientProperty(SQLPart.ATTR_JDBC_TYPE_LIST));
365: update.setAttribute(SQLPart.ATTR_DESTS_SRC, context
366: .getClientProperty(SQLPart.ATTR_DESTS_SRC));
367:
368: ret = new HashMap();
369: ret.put(SQLPart.STMT_CORRELATED_SELECT, select);
370: ret.put(SQLPart.STMT_CORRELATED_UPDATE, update);
371: } else {
372: // We should not be generating correlated Update statement here...
373: throw new BaseException("Illegal execution path.");
374: }
375:
376: return ret;
377: }
378:
379: public SQLPart getUpdateStatement(TargetTable targetTable,
380: StatementContext context) throws BaseException {
381: VelocityContext vContext = new VelocityContext();
382: String templateName = "";
383:
384: if (targetTable.getSourceTableList().size() != 0) {
385: throw new IllegalStateException(
386: "Internal Error. For JDBC eWay DB single Update may not work. Use Corelated queries.");
387: } else {
388: populateContextForStaticUpdate(targetTable, context,
389: vContext);
390: templateName = this .db.getTemplateFileName("updateStatic"); // NOI18N
391: }
392: String result = TemplateBuilder.generateSql(templateName,
393: vContext);
394:
395: return createSQLPart(result, SQLPart.STMT_UPDATE); // NOI18N
396: }
397:
398: public SQLPart getMergeStatement(TargetTable targetTable,
399: StatementContext context) throws BaseException {
400: if (context == null) {
401: context = new StatementContext();
402: }
403:
404: VelocityContext vContext = new VelocityContext();
405: StatementContext localContext = new StatementContext();
406: localContext.putAll(context);
407: localContext.putClientProperty(
408: StatementContext.USE_TARGET_TABLE_ALIAS_NAME,
409: Boolean.TRUE);
410: localContext.putClientProperty("nestedIndent", "");
411:
412: populateAnsiMergeStatement(targetTable, localContext, vContext);
413: localContext.setUseSourceColumnAliasName(true);
414: vContext.put("nestedIndent", "");
415: vContext
416: .put("exceptionWhen", TemplateBuilder.generateSql(
417: this .db.getTemplateFileName("exceptionWhen"),
418: vContext));
419:
420: String result = TemplateBuilder.generateSql(this .db
421: .getTemplateFileName("merge"), vContext); // NOI18N
422: return createSQLPart(result, SQLPart.STMT_MERGE); // NOI18N
423: }
424:
425: }
|