/*
* Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software;Designed and Developed mainly by many Chinese
* opensource volunteers. you can redistribute it and/or modify it under the
* terms of the GNU General Public License version 2 only, as published by the
* Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Any questions about this component can be directed to it's project Web address
* https://code.google.com/p/opencloudb/.
*
*/
package com.akiban.sql.parser;
import com.akiban.sql.StandardException;
import java.util.Properties;
/**
* An InsertNode is the top node in a query tree for an
* insert statement.
* <p>
* After parsing, the node contains
* targetTableName: the target table for the insert
* collist: a list of column names, if specified
* queryexpr: the expression being inserted, either
* a values clause or a select form; both
* of these are represented via the SelectNode,
* potentially with a TableOperatorNode such as
* UnionNode above it.
* <p>
* After binding, the node has had the target table's
* descriptor located and inserted, and the queryexpr
* and collist have been massaged so that they are identical
* to the table layout. This involves adding any default
* values for missing columns, and reordering the columns
* to match the table's ordering of them.
* <p>
* After optimizing, ...
*/
public final class InsertNode extends DMLModStatementNode
{
private ResultColumnList targetColumnList;
private Properties targetProperties;
private OrderByList orderByList;
private ValueNode offset;
private ValueNode fetchFirst;
/**
* Initializer for an InsertNode.
*
* @param targetName The name of the table/VTI to insert into
* @param insertColumns A ResultColumnList with the names of the
* columns to insert into. May be null if the
* user did not specify the columns - in this
* case, the binding phase will have to figure
* it out.
* @param queryExpression The query expression that will generate
* the rows to insert into the given table
* @param targetProperties The properties specified on the target table
* @param orderByList The order by list for the source result set, null if
* no order by list
*/
public void init(Object targetName,
Object insertColumns,
Object queryExpression,
Object targetProperties,
Object orderByList,
Object offset,
Object fetchFirst,
Object returningList) {
/* statementType gets set in super() before we've validated
* any properties, so we've kludged the code to get the
* right statementType for a bulk insert replace.
*/
super.init(queryExpression,
getStatementType((Properties)targetProperties));
setTarget((QueryTreeNode)targetName);
targetColumnList = (ResultColumnList)insertColumns;
this.targetProperties = (Properties)targetProperties;
this.orderByList = (OrderByList)orderByList;
this.offset = (ValueNode)offset;
this.fetchFirst = (ValueNode)fetchFirst;
this.returningColumnList = (ResultColumnList)returningList;
/* Remember that the query expression is the source to an INSERT */
getResultSetNode().setInsertSource();
}
/**
* Fill this node with a deep copy of the given node.
*/
public void copyFrom(QueryTreeNode node) throws StandardException {
super.copyFrom(node);
InsertNode other = (InsertNode)node;
this.targetColumnList = (ResultColumnList)
getNodeFactory().copyNode(other.targetColumnList, getParserContext());
this.targetProperties = other.targetProperties; // TODO: Clone?
this.orderByList = (OrderByList)
getNodeFactory().copyNode(other.orderByList, getParserContext());
this.offset = (ValueNode)
getNodeFactory().copyNode(other.offset, getParserContext());
this.fetchFirst = (ValueNode)
getNodeFactory().copyNode(other.fetchFirst, getParserContext());
}
public String statementToString() {
return "INSERT";
}
/**
* Prints the sub-nodes of this object. See QueryTreeNode.java for
* how tree printing is supposed to work.
*
* @param depth The depth of this node in the tree
*/
public void printSubNodes(int depth) {
super.printSubNodes(depth);
if (targetColumnList != null) {
printLabel(depth, "targetColumnList: ");
targetColumnList.treePrint(depth + 1);
}
if (orderByList != null) {
printLabel(depth, "orderByList: ");
orderByList.treePrint(depth + 1);
}
/* RESOLVE - need to print out targetTableDescriptor */
}
/**
* Return the type of statement, something from
* StatementType.
*
* @return the type of statement
*/
protected int getStatementType() {
return StatementType.INSERT;
}
/**
* Return the statement type, where it is dependent on
* the targetProperties. (insertMode = replace causes
* statement type to be BULK_INSERT_REPLACE.
*
* @return the type of statement
*/
static int getStatementType(Properties targetProperties) {
int retval = StatementType.INSERT;
// The only property that we're currently interested in is insertMode
String insertMode = (targetProperties == null) ? null : targetProperties.getProperty("insertMode");
if (insertMode != null) {
if ("REPLACE".equalsIgnoreCase(insertMode)) {
retval = StatementType.BULK_INSERT_REPLACE;
}
}
return retval;
}
public ResultColumnList getTargetColumnList() {
return targetColumnList;
}
public Properties getTargetProperties() {
return targetProperties;
}
public OrderByList getOrderByList() {
return orderByList;
}
public ValueNode getOffset() {
return offset;
}
public ValueNode getFetchFirst() {
return fetchFirst;
}
/**
* Accept the visitor for all visitable children of this node.
*
* @param v the visitor
*
* @exception StandardException on error
*/
void acceptChildren(Visitor v) throws StandardException {
super.acceptChildren(v);
if (targetColumnList != null) {
targetColumnList.accept(v);
}
}
}