/* * Copyright 2014-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the “License”); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an “AS IS” BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.wplatform.ddal.command.dml; import java.util.ArrayList; import java.util.HashMap; import com.wplatform.ddal.command.Command; import com.wplatform.ddal.command.CommandInterface; import com.wplatform.ddal.command.Prepared; import com.wplatform.ddal.command.expression.Expression; import com.wplatform.ddal.command.expression.Parameter; import com.wplatform.ddal.dbobject.table.Column; import com.wplatform.ddal.dbobject.table.Table; import com.wplatform.ddal.engine.Session; import com.wplatform.ddal.message.DbException; import com.wplatform.ddal.message.ErrorCode; import com.wplatform.ddal.result.ResultInterface; import com.wplatform.ddal.util.New; import com.wplatform.ddal.util.StatementBuilder; /** * This class represents the statement * INSERT */ public class Insert extends Prepared { private final ArrayList<Expression[]> list = New.arrayList(); private Table table; private Column[] columns; private Query query; private boolean sortedInsertMode; private int rowNumber; private boolean insertFromSelect; /** * For MySQL-style INSERT ... ON DUPLICATE KEY UPDATE .... */ private HashMap<Column, Expression> duplicateKeyAssignmentMap; public Insert(Session session) { super(session); } @Override public void setCommand(Command command) { super.setCommand(command); if (query != null) { query.setCommand(command); } } public void setTable(Table table) { this.table = table; } public void setColumns(Column[] columns) { this.columns = columns; } public void setQuery(Query query) { this.query = query; } /** * Keep a collection of the columns to pass to update if a duplicate key * happens, for MySQL-style INSERT ... ON DUPLICATE KEY UPDATE .... * * @param column the column * @param expression the expression */ public void addAssignmentForDuplicate(Column column, Expression expression) { if (duplicateKeyAssignmentMap == null) { duplicateKeyAssignmentMap = New.hashMap(); } if (duplicateKeyAssignmentMap.containsKey(column)) { throw DbException.get(ErrorCode.DUPLICATE_COLUMN_NAME_1, column.getName()); } duplicateKeyAssignmentMap.put(column, expression); } /** * Add a row to this merge statement. * * @param expr the list of values */ public void addRow(Expression[] expr) { list.add(expr); } @Override public String getPlanSQL() { StatementBuilder buff = new StatementBuilder("INSERT INTO "); buff.append(table.getSQL()).append('('); for (Column c : columns) { buff.appendExceptFirst(", "); buff.append(c.getSQL()); } buff.append(")\n"); if (insertFromSelect) { buff.append("DIRECT "); } if (sortedInsertMode) { buff.append("SORTED "); } if (list.size() > 0) { buff.append("VALUES "); int row = 0; if (list.size() > 1) { buff.append('\n'); } for (Expression[] expr : list) { if (row++ > 0) { buff.append(",\n"); } buff.append('('); buff.resetCount(); for (Expression e : expr) { buff.appendExceptFirst(", "); if (e == null) { buff.append("DEFAULT"); } else { buff.append(e.getSQL()); } } buff.append(')'); } } else { buff.append(query.getPlanSQL()); } return buff.toString(); } @Override public void prepare() { if (columns == null) { if (list.size() > 0 && list.get(0).length == 0) { // special case where table is used as a sequence columns = new Column[0]; } else { columns = table.getColumns(); } } if (list.size() > 0) { for (Expression[] expr : list) { if (expr.length != columns.length) { throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); } for (int i = 0, len = expr.length; i < len; i++) { Expression e = expr[i]; if (e != null) { e = e.optimize(session); if (e instanceof Parameter) { Parameter p = (Parameter) e; p.setColumn(columns[i]); } expr[i] = e; } } } } else { query.prepare(); if (query.getColumnCount() != columns.length) { throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); } } } @Override public boolean isTransactional() { return true; } @Override public ResultInterface queryMeta() { return null; } public void setSortedInsertMode(boolean sortedInsertMode) { this.sortedInsertMode = sortedInsertMode; } @Override public int getType() { return CommandInterface.INSERT; } public void setInsertFromSelect(boolean value) { this.insertFromSelect = value; } @Override public boolean isCacheable() { return duplicateKeyAssignmentMap == null || duplicateKeyAssignmentMap.isEmpty(); } public ArrayList<Expression[]> getList() { return list; } public Table getTable() { return table; } public Column[] getColumns() { return columns; } public Query getQuery() { return query; } public boolean isSortedInsertMode() { return sortedInsertMode; } public int getRowNumber() { return rowNumber; } public boolean isInsertFromSelect() { return insertFromSelect; } public HashMap<Column, Expression> getDuplicateKeyAssignmentMap() { return duplicateKeyAssignmentMap; } }