/*
* 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;
}
}