You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2014/02/07 23:12:24 UTC
svn commit: r1565830 - in /db/derby/code/trunk/java:
engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/loc/
shared/org/apache/derby/shared/common/reference/
testing/org/apache/derbyTesting/functionTests/tests/lang/
Author: rhillegas
Date: Fri Feb 7 22:12:23 2014
New Revision: 1565830
URL: http://svn.apache.org/r1565830
Log:
DERBY-3155: Forbid synonyms in MERGE statement; tests passed cleanly for me on derby-3155-21-ac-cleanupAndForbidSynonyms.diff.
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MatchingClauseNode.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MergeNode.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableName.java
db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml
db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java?rev=1565830&r1=1565829&r2=1565830&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java Fri Feb 7 22:12:23 2014
@@ -1241,20 +1241,31 @@ public class ColumnReference extends Val
void setMergeTableID( int mergeTableID )
{
// Changing the association of a column means we are confused. Shouldn't happen.
- if ( _mergeTableID != MERGE_UNKNOWN )
+ if ( (_mergeTableID != MERGE_UNKNOWN) && (_mergeTableID != mergeTableID) )
{
if (SanityManager.DEBUG)
{
SanityManager.ASSERT
(
(_mergeTableID == mergeTableID),
- "MERGE statement can't re-associate column " + debugName()
+ "MERGE statement can't re-associate column " + getSQLColumnName() +
+ " from " + prettyPrintMergeTableID( _mergeTableID ) +
+ " to " + prettyPrintMergeTableID( mergeTableID )
);
}
}
_mergeTableID = mergeTableID;
}
+ private String prettyPrintMergeTableID( int mergeTableID )
+ {
+ switch ( mergeTableID )
+ {
+ case MERGE_SOURCE: return "SOURCE";
+ case MERGE_TARGET: return "TARGET";
+ default: return "UNKNOWN";
+ }
+ }
/** Get the MERGE table (SOURCE or TARGET) associated with this column */
int getMergeTableID()
@@ -1262,13 +1273,6 @@ public class ColumnReference extends Val
return _mergeTableID;
}
- /** Get the name of this column (for debugging printout) */
- String debugName()
- {
- if ( _qualifiedTableName == null ) { return _columnName; }
- else { return _qualifiedTableName + "." + _columnName; }
- }
-
/**
* Helper class to keep track of remap data when a ColumnReference
* is remapped multiple times. This allows the CR to be UN-
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MatchingClauseNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MatchingClauseNode.java?rev=1565830&r1=1565829&r2=1565830&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MatchingClauseNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MatchingClauseNode.java Fri Feb 7 22:12:23 2014
@@ -294,11 +294,13 @@ public class MatchingClauseNode extends
ResultColumnList setClauses = realiasSetClauses( targetTable );
bindSetClauses( fullFromList, targetTable, setClauses );
+ TableName tableName = targetTable.getTableNameField();
+ FromList selectFromList = fullFromList;
+
SelectNode selectNode = new SelectNode
(
- // _updateColumns,
setClauses,
- fullFromList,
+ selectFromList,
null, // where clause
null, // group by list
null, // having clause
@@ -306,7 +308,7 @@ public class MatchingClauseNode extends
null, // optimizer plan override
getContextManager()
);
- _dml = new UpdateNode( targetTable.getTableNameField(), selectNode, this, getContextManager() );
+ _dml = new UpdateNode( tableName, selectNode, this, getContextManager() );
_dml.bindStatement();
@@ -320,6 +322,7 @@ public class MatchingClauseNode extends
// the full row is the before image, the after image, and a row location
int rowSize = fullUpdateRow.size() / 2;
+ // split the row into before and after images
for ( int i = 0; i < rowSize; i++ )
{
ResultColumn origBeforeRC = fullUpdateRow.elementAt( i );
@@ -351,10 +354,11 @@ public class MatchingClauseNode extends
for ( int i = 0; i < _updateColumns.size(); i++ )
{
ResultColumn setRC = _updateColumns.elementAt( i );
+ TableName tableName = targetTable.getTableName();
ColumnReference newTargetColumn = new ColumnReference
(
setRC.getReference().getColumnName(),
- targetTable.getTableName(),
+ tableName,
getContextManager()
);
newTargetColumn.setMergeTableID( ColumnReference.MERGE_TARGET );
@@ -436,7 +440,7 @@ public class MatchingClauseNode extends
TableDescriptor td = targetTable.getTableDescriptor();
HashSet<String> changedColumns = getChangedColumnNames();
HashSet<String> changedGeneratedColumns = getChangedGeneratedColumnNames( td, changedColumns );
-
+
_thenColumns = fullRow.copyListAndObjects();
//
@@ -1108,7 +1112,7 @@ public class MatchingClauseNode extends
if (SanityManager.DEBUG)
{
- SanityManager.THROWASSERT( "Can't find select list column corresponding to " + bufferedCR.debugName() );
+ SanityManager.THROWASSERT( "Can't find select list column corresponding to " + bufferedCR.getSQLColumnName() );
}
}
else if ( bufferedExpression instanceof CurrentRowLocationNode )
@@ -1134,7 +1138,7 @@ public class MatchingClauseNode extends
SanityManager.ASSERT
(
( (mergeTableID == ColumnReference.MERGE_SOURCE) || (mergeTableID == ColumnReference.MERGE_TARGET) ),
- "Column " + cr.debugName() + " has illegal MERGE table id: " + mergeTableID
+ "Column " + cr.getSQLColumnName() + " has illegal MERGE table id: " + mergeTableID
);
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MergeNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MergeNode.java?rev=1565830&r1=1565829&r2=1565830&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MergeNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MergeNode.java Fri Feb 7 22:12:23 2014
@@ -214,34 +214,23 @@ public final class MergeNode extends DML
throw StandardException.newException( SQLState.LANG_SAME_EXPOSED_NAME );
}
+ // synonyms not allowed
+ forbidSynonyms( dd );
+
FromList dfl = new FromList( getContextManager() );
- dfl.addFromTable( _sourceTable );
- dfl.addFromTable( _targetTable );
+ FromTable dflSource = cloneFromTable( _sourceTable );
+ FromBaseTable dflTarget = (FromBaseTable) cloneFromTable( _targetTable );
+ dfl.addFromTable( dflSource );
+ dfl.addFromTable( dflTarget );
dfl.bindTables( dd, new FromList( getOptimizerFactory().doJoinOrderOptimization(), getContextManager() ) );
- //
- // Bind the WHEN [ NOT ] MATCHED clauses.
- //
- FromList dummyFromList = new FromList( getContextManager() );
- FromBaseTable dummyTargetTable = new FromBaseTable
- (
- _targetTable.getTableNameField(),
- _targetTable.correlationName,
- null,
- null,
- getContextManager()
- );
- FromTable dummySourceTable = cloneSourceTable();
-
- dummyFromList.addFromTable( dummySourceTable );
- dummyFromList.addFromTable( dummyTargetTable );
- dummyFromList.bindTables( dd, new FromList( getOptimizerFactory().doJoinOrderOptimization(), getContextManager() ) );
-
// target table must be a base table
- if ( !targetIsBaseTable( _targetTable ) ) { notBaseTable(); }
+ if ( !targetIsBaseTable( dflTarget ) ) { notBaseTable(); }
for ( MatchingClauseNode mcn : _matchingClauses )
{
+ FromList dummyFromList = cloneFromList( dd, dflTarget );
+ FromBaseTable dummyTargetTable = (FromBaseTable) dummyFromList.elementAt( TARGET_TABLE_INDEX );
mcn.bind( dd, this, dummyFromList, dummyTargetTable );
}
@@ -255,12 +244,54 @@ public final class MergeNode extends DML
}
}
+ /** Create a FromList for binding a WHEN [ NOT ] MATCHED clause */
+ private FromList cloneFromList( DataDictionary dd, FromBaseTable targetTable )
+ throws StandardException
+ {
+ FromList dummyFromList = new FromList( getContextManager() );
+ FromBaseTable dummyTargetTable = new FromBaseTable
+ (
+ targetTable.getTableNameField(),
+ targetTable.correlationName,
+ null,
+ null,
+ getContextManager()
+ );
+ FromTable dummySourceTable = cloneFromTable( _sourceTable );
+
+ dummyFromList.addFromTable( dummySourceTable );
+ dummyFromList.addFromTable( dummyTargetTable );
+ dummyFromList.bindTables( dd, new FromList( getOptimizerFactory().doJoinOrderOptimization(), getContextManager() ) );
+
+ return dummyFromList;
+ }
+
/** Get the exposed name of a FromTable */
private String getExposedName( FromTable ft ) throws StandardException
{
return ft.getTableName().getTableName();
}
+ /** Neither the source nor the target table may be a synonym */
+ private void forbidSynonyms( DataDictionary dd ) throws StandardException
+ {
+ forbidSynonyms( dd, _targetTable.getTableNameField().cloneMe() );
+ if ( _sourceTable instanceof FromBaseTable )
+ {
+ forbidSynonyms( dd, ((FromBaseTable)_sourceTable).getTableNameField().cloneMe() );
+ }
+ }
+ private void forbidSynonyms( DataDictionary dd, TableName tableName ) throws StandardException
+ {
+ tableName.bind( dd );
+
+ TableName synonym = resolveTableToSynonym( tableName );
+ if ( synonym != null )
+ {
+ throw StandardException.newException( SQLState.LANG_NO_SYNONYMS_IN_MERGE );
+ }
+ }
+
/**
* Bind the driving left join select.
* Stuffs the left join SelectNode into the resultSet variable.
@@ -406,7 +437,7 @@ public final class MergeNode extends DML
{
// tell the target table to generate a row location column
_targetTable.setRowLocationColumnName( TARGET_ROW_LOCATION_NAME );
-
+
TableName fromTableName = _targetTable.getTableName();
ColumnReference cr = new ColumnReference
( TARGET_ROW_LOCATION_NAME, fromTableName, getContextManager() );
@@ -458,12 +489,12 @@ public final class MergeNode extends DML
}
}
- /** Clone the source table for binding the MATCHED clauses */
- private FromTable cloneSourceTable() throws StandardException
+ /** Clone a FromTable to avoid binding the original */
+ private FromTable cloneFromTable( FromTable fromTable ) throws StandardException
{
- if ( _sourceTable instanceof FromVTI )
+ if ( fromTable instanceof FromVTI )
{
- FromVTI source = (FromVTI) _sourceTable;
+ FromVTI source = (FromVTI) fromTable;
return new FromVTI
(
@@ -475,9 +506,9 @@ public final class MergeNode extends DML
getContextManager()
);
}
- else if ( _sourceTable instanceof FromBaseTable )
+ else if ( fromTable instanceof FromBaseTable )
{
- FromBaseTable source = (FromBaseTable) _sourceTable;
+ FromBaseTable source = (FromBaseTable) fromTable;
return new FromBaseTable
(
source.tableName,
@@ -508,11 +539,12 @@ public final class MergeNode extends DML
throws StandardException
{
String[] columnNames = getColumns( getExposedName( fromTable ), drivingColumnMap );
-
+ TableName tableName = fromTable.getTableName();
+
for ( int i = 0; i < columnNames.length; i++ )
{
ColumnReference cr = new ColumnReference
- ( columnNames[ i ], fromTable.getTableName(), getContextManager() );
+ ( columnNames[ i ], tableName, getContextManager() );
cr.setMergeTableID( mergeTableID );
ResultColumn rc = new ResultColumn( (String) null, cr, getContextManager() );
selectList.addResultColumn( rc );
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableName.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableName.java?rev=1565830&r1=1565829&r2=1565830&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableName.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableName.java Fri Feb 7 22:12:23 2014
@@ -227,6 +227,12 @@ public class TableName extends QueryTree
}
}
+ /** Clone this TableName */
+ public TableName cloneMe()
+ {
+ return new TableName( schemaName, tableName, getContextManager() );
+ }
+
///////////////////////////////////////////////////////////////////////
//
// BIND METHODS
Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml?rev=1565830&r1=1565829&r2=1565830&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml Fri Feb 7 22:12:23 2014
@@ -2291,6 +2291,11 @@ Guide.
<text>Subqueries are not allowed in the WHEN [ NOT ] MATCHED clauses of MERGE statements.</text>
</msg>
+ <msg>
+ <name>42XAP</name>
+ <text>Synonyms are not allowed as the source or target tables of MERGE statements.</text>
+ </msg>
+
<msg>
<name>42Y00</name>
<text>Class '{0}' does not implement org.apache.derby.iapi.db.AggregateDefinition and thus cannot be used as an aggregate expression.</text>
Modified: db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java?rev=1565830&r1=1565829&r2=1565830&view=diff
==============================================================================
--- db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java (original)
+++ db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java Fri Feb 7 22:12:23 2014
@@ -951,6 +951,7 @@ public interface SQLState {
String LANG_SAME_EXPOSED_NAME = "42XAM";
String LANG_NOT_NULL_CHARACTERISTICS = "42XAN";
String LANG_NO_SUBQUERIES_IN_MATCHED_CLAUSE = "42XAO";
+ String LANG_NO_SYNONYMS_IN_MERGE = "42XAP";
String LANG_INVALID_USER_AGGREGATE_DEFINITION2 = "42Y00";
String LANG_INVALID_CHECK_CONSTRAINT = "42Y01";
// String LANG_NO_ALTER_TABLE_COMPRESS_ON_TARGET_TABLE = "42Y02";
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java?rev=1565830&r1=1565829&r2=1565830&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java Fri Feb 7 22:12:23 2014
@@ -72,6 +72,7 @@ public class MergeStatementTest extends
private static final String NO_ROWS_AFFECTED = "02000";
private static final String NO_DML_IN_BEFORE_TRIGGERS = "42Z9D";
private static final String NO_SUBQUERIES_IN_MATCHED_CLAUSE = "42XAO";
+ private static final String NO_SYNONYMS_IN_MERGE = "42XAP";
private static final String[] TRIGGER_HISTORY_COLUMNS = new String[] { "ACTION", "ACTION_VALUE" };
@@ -4965,6 +4966,75 @@ public class MergeStatementTest extends
goodStatement( aliceConnection, "drop table t1_033" );
}
+ /**
+ * <p>
+ * Synonyms not allowed as source or target tables in MERGE statements.
+ * </p>
+ */
+ public void test_034_noSynonyms()
+ throws Exception
+ {
+ Connection dboConnection = openUserConnection( TEST_DBO );
+
+ //
+ // create schema
+ //
+ goodStatement
+ (
+ dboConnection,
+ "create table t1_034( x int, y int )"
+ );
+ goodStatement
+ (
+ dboConnection,
+ "create table t2_034( x int, y int )"
+ );
+ goodStatement
+ (
+ dboConnection,
+ "create synonym syn_t1_034 for t1_034"
+ );
+ goodStatement
+ (
+ dboConnection,
+ "create synonym syn_t2_034 for t2_034"
+ );
+
+ // verify that synonyms are forbidden
+ expectCompilationError
+ ( dboConnection, NO_SYNONYMS_IN_MERGE,
+ "merge into syn_t1_034\n" +
+ "using t2_034 on syn_t1_034.x = t2_034.x\n" +
+ "when matched then update set syn_t1_034.y = t2_034.y\n"
+ );
+ expectCompilationError
+ ( dboConnection, NO_SYNONYMS_IN_MERGE,
+ "merge into syn_t1_034 a\n" +
+ "using t2_034 on a.x = t2_034.x\n" +
+ "when matched then update set a.y = t2_034.y\n"
+ );
+ expectCompilationError
+ ( dboConnection, NO_SYNONYMS_IN_MERGE,
+ "merge into t1_034\n" +
+ "using syn_t2_034 on t1_034.x = syn_t2_034.x\n" +
+ "when matched then update set t1_034.y = syn_t2_034.y\n"
+ );
+ expectCompilationError
+ ( dboConnection, NO_SYNONYMS_IN_MERGE,
+ "merge into t1_034\n" +
+ "using syn_t2_034 a on t1_034.x = a.x\n" +
+ "when matched then update set t1_034.y = a.y\n"
+ );
+
+ //
+ // drop schema
+ //
+ goodStatement( dboConnection, "drop synonym syn_t2_034" );
+ goodStatement( dboConnection, "drop synonym syn_t1_034" );
+ goodStatement( dboConnection, "drop table t2_034" );
+ goodStatement( dboConnection, "drop table t1_034" );
+ }
+
///////////////////////////////////////////////////////////////////////////////////
//
// ROUTINES