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