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.derby;
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: import org.apache.velocity.VelocityContext;
028: import org.netbeans.modules.sql.framework.codegen.AbstractDB;
029: import org.netbeans.modules.sql.framework.codegen.ColumnIdentifier;
030: import org.netbeans.modules.sql.framework.codegen.ResolvedMapping;
031: import org.netbeans.modules.sql.framework.codegen.StatementContext;
032: import org.netbeans.modules.sql.framework.codegen.TemplateBuilder;
033: import org.netbeans.modules.sql.framework.codegen.base.BaseStatements;
034: import org.netbeans.modules.sql.framework.model.SQLCondition;
035: import org.netbeans.modules.sql.framework.model.SQLConstants;
036: import org.netbeans.modules.sql.framework.model.SQLDBTable;
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: import com.sun.sql.framework.exception.BaseException;
042: import com.sun.sql.framework.jdbc.SQLPart;
043: import com.sun.sql.framework.jdbc.SQLUtils;
044: import com.sun.sql.framework.utils.RuntimeAttribute;
045: import com.sun.sql.framework.utils.StringUtil;
046:
047: /**
048: * For Derby Database code generations using from JDBC Code generation.
049: * @author karthik
050: */
051: public class DerbyStatements extends BaseStatements {
052:
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 DerbyStatements(AbstractDB database) {
059: super (database);
060: }
061:
062: @Override
063: protected void populateContextForUpdate(TargetTable targetTable,
064: StatementContext context, VelocityContext vContext)
065: throws BaseException {
066: final boolean excludeJoinKeyColumns = false;
067: // SELECT START
068: StatementContext localContext = new StatementContext();
069: if (context != null) {
070: localContext.putAll(context);
071: }
072:
073: //Use the Table Qualification flag to suppress column prefix
074: localContext.setSuppressingTablePrefixForTargetColumn(true);
075: List rMappings = createResolvedMappingsForUpdate(targetTable,
076: excludeJoinKeyColumns, localContext);
077: localContext.setSuppressingTablePrefixForTargetColumn(false);
078:
079: String targetTableSql = this .genFactory.generate(targetTable,
080: localContext);
081:
082: localContext.putClientProperty(
083: StatementContext.USE_SOURCE_TABLE_ALIAS_NAME,
084: Boolean.TRUE);
085: localContext.putClientProperty(
086: StatementContext.USE_TARGET_TABLE_ALIAS_NAME,
087: Boolean.TRUE);
088:
089: vContext.put("targetTable", targetTableSql);
090: vContext.put("fromContent", getFromStatementContentForTarget(
091: targetTable, SQLConstants.INNER_JOIN, localContext));
092: vContext.put("nestedIndent", " ");
093:
094: vContext.put("useUpdateWhere", Boolean.FALSE);
095:
096: String condition = getWhereCondition(targetTable, localContext);
097:
098: context.putClientProperty(
099: StatementContext.USE_SOURCE_TABLE_ALIAS_NAME,
100: Boolean.TRUE);
101: context.putClientProperty(
102: StatementContext.USE_TARGET_TABLE_ALIAS_NAME,
103: Boolean.TRUE);
104:
105: String updateWhereClause = getWhereClauseForUpdate(targetTable,
106: context);
107: if (condition != null && !condition.equals("")) {
108: condition += " AND " + updateWhereClause;
109: } else {
110: condition = updateWhereClause;
111: }
112:
113: context.putClientProperty(
114: StatementContext.USE_TARGET_TABLE_ALIAS_NAME,
115: Boolean.FALSE);
116: vContext.put("tgtCondition", getWhereClauseForUpdate(
117: targetTable, context));
118: context.putClientProperty(
119: StatementContext.USE_TARGET_TABLE_ALIAS_NAME,
120: Boolean.TRUE);
121:
122: if (condition != null && !condition.equals("")) {
123: vContext.put("useUpdateWhere", Boolean.TRUE);
124: vContext.put("condition", condition);
125: }
126: // SELECT END
127: vContext.put(DerbyStatements.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: List<ResolvedMapping> mappings = new ArrayList<ResolvedMapping>();
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<String> evaluateSourceColumnList(
174: List srcColListtargetTable, StatementContext context)
175: throws BaseException {
176: List<String> srcColEvals = new ArrayList<String>();
177: @SuppressWarnings(value="unchecked")
178: Map<String, String> srcExpToJdbcTypeMap = (Map) context
179: .getClientProperty(BaseStatements.SRC_EXP_TO_JDBC_TYPE_MAP);
180: if (srcExpToJdbcTypeMap == null) {
181: srcExpToJdbcTypeMap = new HashMap<String, String>();
182: context.putClientProperty(
183: BaseStatements.SRC_EXP_TO_JDBC_TYPE_MAP,
184: srcExpToJdbcTypeMap);
185: }
186:
187: StatementContext localContext = new StatementContext();
188: localContext.putAll(context);
189: localContext.putClientProperty(
190: StatementContext.USE_SOURCE_TABLE_ALIAS_NAME,
191: Boolean.TRUE);
192:
193: Iterator it = srcColListtargetTable.iterator();
194: String sSql = null;
195: SourceColumn column = null;
196:
197: while (it.hasNext()) {
198: column = (SourceColumn) it.next();
199: if (column != null) {
200: sSql = this .genFactory.generate(column, localContext);
201: srcColEvals.add(sSql);
202: srcExpToJdbcTypeMap
203: .put(sSql, "" + column.getJdbcType());
204: }
205: }
206:
207: return srcColEvals;
208: }
209:
210: @Override
211: public SQLPart getTableExistsStatement(SQLDBTable table,
212: StatementContext context) throws BaseException {
213: if (context == null) {
214: context = new StatementContext();
215: }
216:
217: VelocityContext vContext = new VelocityContext();
218:
219: // WT 63392: Need to replace characters normally used to escape table
220: // names with single-quotes in context of using the table name as a String.
221: vContext.put("tableName", getUnqualifiedTableName(table,
222: context));
223:
224: // If schemaName is supplied in the context, use that value rather than the name
225: // associated
226: // with the target table - table may be a SourceTable but the appropriate schema
227: // to use may
228: // not be the value obtained from table.getSchema().
229: String schemaName = (String) context
230: .getClientProperty("targetSchema");
231: if (StringUtil.isNullString(schemaName)) {
232: String uSchema = table.getUserDefinedSchemaName();
233: if (StringUtil.isNullString(uSchema)) {
234: if (!StringUtil.isNullString(table.getSchema())) {
235: schemaName = table.getSchema().toUpperCase();
236: }
237: } else {
238: schemaName = uSchema.toUpperCase();
239: }
240: }
241: vContext.put("schemaName", schemaName);
242:
243: String result = TemplateBuilder.generateSql(this .db
244: .getTemplateFileName("tableExists"), vContext); // NOI18N
245: return createSQLPart(result, SQLPart.STMT_CHECKTABLEEXISTS); // NOI18N;;
246: }
247:
248: private String getWhereClauseForUpdate(TargetTable targetTable,
249: StatementContext context) throws BaseException {
250:
251: SQLCondition joinCondition = targetTable.getJoinCondition();
252: SQLPredicate joinPredicate = null;
253: if (joinCondition != null) {
254: joinPredicate = joinCondition.getRootPredicate();
255: }
256:
257: if (joinPredicate == null) {
258: throw new BaseException("Missing merge condition.");
259: }
260: return this .genFactory.generate(joinPredicate, context);
261: }
262:
263: /**
264: * Returns list of integer or String. If element is integer it represent Datum posiotion in the result set else
265: * it is RunTimeInput symbol name.
266: *
267: * @param sql
268: * @param mappedList
269: * @param additionalSelectCols
270: * @param riMap
271: * @return List of items to be populated into update statement.
272: */
273: @SuppressWarnings(value="unchecked")
274: private String mapDestinationCols(String sql,
275: StatementContext context) {
276: List symbolList = new ArrayList();
277: List destinationsSource = new ArrayList();
278: List newBindingVariables = new ArrayList();
279: String symbol = null;
280: int mappedCols = 0;
281: RuntimeAttribute ra = null;
282: List directlyMappedSrcColsEval = (List) context
283: .getClientProperty(DerbyStatements.DIRECTLY_MAPPED_SRC_COLS_EVAL);
284: List additionalSelectColsEval = (List) context
285: .getClientProperty(DerbyStatements.ADDITIONAL_SRC_COLS);
286: List jdbcTypeList = (List) context
287: .getClientProperty(SQLPart.ATTR_JDBC_TYPE_LIST);
288: List mappings = (List) context.getClientProperty(MAPPINGS);
289: Map riMap = (Map) context.getClientProperty(RUNTIME_INPUTS_MAP);
290: Map symbol2JdbcTypeMap = (Map) context
291: .getClientProperty(BaseStatements.SRC_EXP_TO_JDBC_TYPE_MAP);
292: context.putClientProperty(SQLPart.ATTR_DESTS_SRC,
293: destinationsSource);
294:
295: if (mappings != null) {
296: mappedCols = mappings.size();
297: }
298:
299: if (directlyMappedSrcColsEval != null) {
300: symbolList.addAll(directlyMappedSrcColsEval);
301: }
302:
303: if (additionalSelectColsEval != null) {
304: symbolList.addAll(additionalSelectColsEval);
305: }
306:
307: for (int i = 1; i <= mappedCols; i++) {
308: destinationsSource.add(i - 1, "" + i);
309: }
310:
311: // RuntimeAttributes needed in Where clause
312: if (riMap != null) {
313: Set keys = riMap.keySet();
314: Iterator itr = keys.iterator();
315: while (itr.hasNext()) {
316: ra = (RuntimeAttribute) riMap.get(itr.next());
317: symbolList.add("$" + ra.getAttributeName());
318: symbol2JdbcTypeMap.put("$" + ra.getAttributeName(), ""
319: + ra.getJdbcType());
320: }
321: }
322: //return sourcSymbolOrder;
323: // Get order of symbols in the statement and replace symbols with "?".
324: sql = SQLUtils.createPreparedStatement(sql, symbolList,
325: newBindingVariables);
326: Iterator itr = newBindingVariables.iterator();
327:
328: while (itr.hasNext()) {
329: symbol = (String) itr.next();
330: if ((symbol != null) && (symbol.startsWith("$"))) {
331: destinationsSource.add(symbol);
332: } else {
333: destinationsSource.add(""
334: + (symbolList.indexOf(symbol) + 1));
335: }
336: jdbcTypeList.add(symbol2JdbcTypeMap.get(symbol));
337: }
338:
339: return sql;
340: }
341:
342: // TODO Voilates Statements interface pattern, need to redesign the interfaces.
343: @Override
344: @SuppressWarnings(value="unchecked")
345: public Map getCorrelatedUpdateStatement(TargetTable targetTable,
346: final StatementContext sc) throws BaseException {
347: StatementContext context = new StatementContext();
348: context.putAll(sc);
349: Map ret = null;
350: Map runtimeInputsMap = (Map) context
351: .getClientProperty(RUNTIME_INPUTS_MAP); // No I18N
352: List directSourceColumns = new ArrayList();
353: VelocityContext vContext = new VelocityContext();
354: String templateName = "";
355: String sqlSelect = null;
356: String sqlUpdate = null;
357: SQLPart select = null;
358: SQLPart update = null;
359:
360: if (targetTable.getSourceTableList().size() != 0) {
361: List srcColDirectlyMapped = getSourceColsDirectlyMapped(
362: targetTable, context);
363: List columnsTobeAliased = getConditionColumnsNotInList(
364: targetTable.getJoinCondition(),
365: srcColDirectlyMapped, context);
366: directSourceColumns.addAll(srcColDirectlyMapped);
367: directSourceColumns.addAll(columnsTobeAliased);
368: List directlyMappedSrcColsEval = evaluateSourceColumnList(
369: srcColDirectlyMapped, context);
370: List additionalSrcColsEval = evaluateSourceColumnList(
371: columnsTobeAliased, context);
372:
373: populateContextForUpdate(targetTable, context, vContext);
374: vContext.put(DerbyStatements.ADDITIONAL_SRC_COLS,
375: additionalSrcColsEval);
376: templateName = this .db
377: .getTemplateFileName("correlatedSelect"); // NOI18N
378: sqlSelect = TemplateBuilder.generateSql(templateName,
379: vContext);
380: templateName = this .db
381: .getTemplateFileName("correlatedUpdate"); // NOI18N
382: sqlUpdate = TemplateBuilder.generateSql(templateName,
383: vContext);
384:
385: // Context already has JDCB type for all the selected columns
386: context.putClientProperty(DerbyStatements.MAPPINGS,
387: vContext.get(DerbyStatements.MAPPINGS));
388: context.putClientProperty(
389: DerbyStatements.ADDITIONAL_SRC_COLS,
390: additionalSrcColsEval);
391: context.putClientProperty(
392: DerbyStatements.DIRECTLY_MAPPED_SRC_COLS_EVAL,
393: directlyMappedSrcColsEval);
394: context.putClientProperty(
395: DerbyStatements.RUNTIME_INPUTS_MAP,
396: runtimeInputsMap);
397: sqlUpdate = mapDestinationCols(sqlUpdate, context);
398:
399: select = createSQLPart(sqlSelect,
400: SQLPart.STMT_CORRELATED_SELECT);
401: update = createSQLPart(sqlUpdate,
402: SQLPart.STMT_CORRELATED_UPDATE);
403: update.setAttribute(SQLPart.ATTR_JDBC_TYPE_LIST, context
404: .getClientProperty(SQLPart.ATTR_JDBC_TYPE_LIST));
405: update.setAttribute(SQLPart.ATTR_DESTS_SRC, context
406: .getClientProperty(SQLPart.ATTR_DESTS_SRC));
407:
408: ret = new HashMap();
409: ret.put(SQLPart.STMT_CORRELATED_SELECT, select);
410: ret.put(SQLPart.STMT_CORRELATED_UPDATE, update);
411: } else {
412: // We should not be generating correlated Update statement here...
413: throw new BaseException("Illegal execution path.");
414: }
415:
416: return ret;
417: }
418:
419: @Override
420: public SQLPart getUpdateStatement(TargetTable targetTable,
421: StatementContext context) throws BaseException {
422: VelocityContext vContext = new VelocityContext();
423: String templateName = "";
424:
425: if (targetTable.getSourceTableList().size() != 0) {
426: throw new IllegalStateException(
427: "Internal Error. For JDBC eWay DB single Update may not work. Use Corelated queries.");
428: } else {
429: populateContextForStaticUpdate(targetTable, context,
430: vContext);
431: templateName = this .db.getTemplateFileName("updateStatic"); // NOI18N
432: }
433: String result = TemplateBuilder.generateSql(templateName,
434: vContext);
435:
436: return createSQLPart(result, SQLPart.STMT_UPDATE); // NOI18N
437: }
438:
439: @Override
440: public SQLPart getMergeStatement(TargetTable targetTable,
441: StatementContext context) throws BaseException {
442: if (context == null) {
443: context = new StatementContext();
444: }
445:
446: VelocityContext vContext = new VelocityContext();
447: StatementContext localContext = new StatementContext();
448: localContext.putAll(context);
449: localContext.putClientProperty(
450: StatementContext.USE_TARGET_TABLE_ALIAS_NAME,
451: Boolean.TRUE);
452: localContext.putClientProperty("nestedIndent", "");
453:
454: populateAnsiMergeStatement(targetTable, localContext, vContext);
455: localContext.setUseSourceColumnAliasName(true);
456: vContext.put("nestedIndent", "");
457: vContext
458: .put("exceptionWhen", TemplateBuilder.generateSql(
459: this .db.getTemplateFileName("exceptionWhen"),
460: vContext));
461:
462: String result = TemplateBuilder.generateSql(this .db
463: .getTemplateFileName("merge"), vContext); // NOI18N
464: return createSQLPart(result, SQLPart.STMT_MERGE); // NOI18N
465: }
466: }
|