|
I am attaching the patch here. Let me know if you have any comments. I will also be adding more test cases with my next patch. Satheesh Satheesh Bandaram wrote:
|
Index: java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java
(working copy)
@@ -596,7 +596,7 @@
public QueryTreeNode
getCreateAliasNode(
Object aliasName,
- String fullStaticMethodName,
+ Object targetName,
Object aliasSpecificInfo,
char aliasType,
Boolean delimitedIdentifier,
@@ -605,37 +605,39 @@
{
int nodeType;
String methodName = null;
- String javaClassName = fullStaticMethodName;
String targetMethodName = null;
String targetClassName = null;
nodeType = C_NodeTypes.CREATE_ALIAS_NODE;
- int lastPeriod;
- int paren = fullStaticMethodName.indexOf('(');
- if (paren == -1) {
- // not a Java signature - split based on last period
- lastPeriod = fullStaticMethodName.lastIndexOf('.');
- } else {
- // a Java signature - split on last period before the '('
- lastPeriod = fullStaticMethodName.substring(0,
paren).lastIndexOf('.');
- }
- if (lastPeriod == -1 || lastPeriod == fullStaticMethodName.length()-1)
{
- throw
StandardException.newException(SQLState.LANG_INVALID_FULL_STATIC_METHOD_NAME,
fullStaticMethodName);
- }
- javaClassName = fullStaticMethodName.substring(0, lastPeriod);
- methodName = fullStaticMethodName.substring(lastPeriod + 1);
+ if (aliasType != AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR)
+ {
+ int lastPeriod;
+ String fullStaticMethodName = (String) targetName;
+ int paren = fullStaticMethodName.indexOf('(');
+ if (paren == -1) {
+ // not a Java signature - split based on last period
+ lastPeriod = fullStaticMethodName.lastIndexOf('.');
+ } else {
+ // a Java signature - split on last period before the '('
+ lastPeriod = fullStaticMethodName.substring(0,
paren).lastIndexOf('.');
+ }
+ if (lastPeriod == -1 || lastPeriod ==
fullStaticMethodName.length()-1) {
+ throw
StandardException.newException(SQLState.LANG_INVALID_FULL_STATIC_METHOD_NAME,
fullStaticMethodName);
+ }
+ String javaClassName = fullStaticMethodName.substring(0,
lastPeriod);
+ methodName = fullStaticMethodName.substring(lastPeriod + 1);
+ targetName = javaClassName;
+ }
return getNode(
nodeType,
aliasName,
- javaClassName,
+ targetName,
methodName,
aliasSpecificInfo,
new Character(aliasType),
delimitedIdentifier,
cm );
}
-
-
}
Index: java/engine/org/apache/derby/impl/sql/compile/DropAliasNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/DropAliasNode.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/compile/DropAliasNode.java
(working copy)
@@ -75,6 +75,10 @@
nameSpace =
AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR;
break;
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
+ nameSpace =
AliasInfo.ALIAS_NAME_SPACE_SYNONYM_AS_CHAR;
+ break;
+
default:
if (SanityManager.DEBUG)
{
@@ -149,6 +153,9 @@
case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:
typeName = "FUNCTION";
break;
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
+ typeName = "SYNONYM";
+ break;
}
return typeName;
}
Index: java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java
(working copy)
@@ -46,6 +46,7 @@
import org.apache.derby.iapi.sql.dictionary.DataDictionary;
import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
+import org.apache.derby.iapi.sql.dictionary.AliasDescriptor;
import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.iapi.sql.execute.ConstantAction;
@@ -60,6 +61,7 @@
import org.apache.derby.iapi.sql.depend.DependencyManager;
import org.apache.derby.iapi.sql.dictionary.AliasDescriptor;
import org.apache.derby.catalog.AliasInfo;
+import org.apache.derby.catalog.types.SynonymAliasInfo;
import java.util.Properties;
import java.util.Vector;
import java.sql.Types;
@@ -1470,6 +1472,46 @@
}
/**
+ * Resolve table/view reference to a synonym. May have to follow a
synonym chain.
+ *
+ * @param tabName to match for a synonym
+ *
+ * @return Synonym TableName if a match is found, NULL otherwise.
+ *
+ * @exception StandardException Thrown on error
+ */
+ public TableName resolveTableToSynonym(TableName tabName) throws
StandardException
+ {
+ DataDictionary dd = getDataDictionary();
+ String nextSynonymTable = tabName.getTableName();
+ String nextSynonymSchema = tabName.getSchemaName();
+ boolean found = false;
+ for (;;)
+ {
+ SchemaDescriptor nextSD =
getSchemaDescriptor(nextSynonymSchema, false);
+ if (nextSD == null || nextSD.getUUID() == null)
+ break;
+
+ AliasDescriptor nextAD =
dd.getAliasDescriptor(nextSD.getUUID().toString(),
+ nextSynonymTable,
AliasInfo.ALIAS_NAME_SPACE_SYNONYM_AS_CHAR);
+ if (nextAD == null)
+ break;
+
+ found = true;
+ SynonymAliasInfo info =
((SynonymAliasInfo)nextAD.getAliasInfo());
+ nextSynonymTable = info.getSynonymTable();
+ nextSynonymSchema = info.getSynonymSchema();
+ }
+
+ if (!found)
+ return null;
+
+ TableName tableName = new TableName();
+ tableName.init(nextSynonymSchema, nextSynonymTable);
+ return tableName;
+ }
+
+ /**
*
* @param javaClassName The name of the java class to resolve.
*
Index: java/engine/org/apache/derby/impl/sql/compile/CreateTableNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/CreateTableNode.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/compile/CreateTableNode.java
(working copy)
@@ -211,6 +211,11 @@
tableElementList.validate(this, dataDictionary,
(TableDescriptor) null);
+ if (resolveTableToSynonym(getObjectName()) != null)
+ throw
StandardException.newException(SQLState.LANG_OBJECT_ALREADY_EXISTS,
+ "Synonym",
+
getObjectName().toString());
+
/* Only 1012 columns allowed per table */
if (tableElementList.countNumberOfColumns() >
Limits.DB2_MAX_COLUMNS_IN_TABLE)
{
Index: java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java
(working copy)
@@ -201,6 +201,11 @@
DataDictionary dataDictionary = getDataDictionary();
+ // check if targetTable is a synonym
+ TableName synonymTab =
resolveTableToSynonym(this.targetTableName);
+ if (synonymTab != null)
+ this.targetTableName = synonymTab;
+
bindTables(dataDictionary);
// wait to bind named target table until the cursor
Index: java/engine/org/apache/derby/impl/sql/compile/LockTableNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/LockTableNode.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/compile/LockTableNode.java
(working copy)
@@ -130,7 +130,16 @@
if (lockTableDescriptor == null)
{
- throw
StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, tableName);
+ // Check if the reference is for a synonym.
+ TableName synonymTab = resolveTableToSynonym(tableName);
+ if (synonymTab == null)
+ throw
StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, tableName);
+ tableName = synonymTab;
+ sd = getSchemaDescriptor(tableName.getSchemaName());
+
+ lockTableDescriptor =
getTableDescriptor(synonymTab.getTableName(), sd);
+ if (lockTableDescriptor == null)
+ throw
StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, tableName);
}
//throw an exception if user is attempting to lock a temporary
table
Index: java/engine/org/apache/derby/impl/sql/compile/FromBaseTable.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/FromBaseTable.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/compile/FromBaseTable.java
(working copy)
@@ -2369,7 +2369,16 @@
}
else
{
- throw
StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, tableName);
+ // Check if the reference is for a synonym.
+ TableName synonymTab = resolveTableToSynonym(tableName);
+ if (synonymTab == null)
+ throw
StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, tableName);
+ tableName = synonymTab;
+ sd = getSchemaDescriptor(tableName.getSchemaName());
+
+ tableDescriptor =
getTableDescriptor(synonymTab.getTableName(), sd);
+ if (tableDescriptor == null)
+ throw
StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, tableName);
}
return tableDescriptor;
Index: java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java
(working copy)
@@ -215,16 +215,23 @@
/*
** Get the TableDescriptor for the table we are
inserting into
*/
- String sntc = targetTableName.getSchemaName();
+ SchemaDescriptor sdtc =
getSchemaDescriptor(targetTableName.getSchemaName());
- SchemaDescriptor sdtc = getSchemaDescriptor(sntc);
-
targetTableDescriptor = getTableDescriptor(
targetTableName.getTableName(), sdtc);
if (targetTableDescriptor == null)
{
- throw
StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, targetTableName);
+ // Check if the reference is for a synonym.
+ TableName synonymTab =
resolveTableToSynonym(targetTableName);
+ if (synonymTab == null)
+ throw
StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, targetTableName);
+ targetTableName = synonymTab;
+ sdtc =
getSchemaDescriptor(targetTableName.getSchemaName());
+
+ targetTableDescriptor =
getTableDescriptor(synonymTab.getTableName(), sdtc);
+ if (targetTableDescriptor == null)
+ throw
StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, targetTableName);
}
// Views are currently not updatable */
Index: java/engine/org/apache/derby/impl/sql/compile/CreateAliasNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/CreateAliasNode.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/compile/CreateAliasNode.java
(working copy)
@@ -36,6 +36,8 @@
import org.apache.derby.iapi.types.TypeId;
import org.apache.derby.iapi.sql.dictionary.DataDictionary;
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
+import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
import org.apache.derby.iapi.error.StandardException;
@@ -48,6 +50,7 @@
import org.apache.derby.catalog.AliasInfo;
import org.apache.derby.catalog.TypeDescriptor;
import org.apache.derby.catalog.types.RoutineAliasInfo;
+import org.apache.derby.catalog.types.SynonymAliasInfo;
import java.lang.reflect.Member;
import java.util.Vector;
@@ -72,7 +75,7 @@
* Initializer for a CreateAliasNode
*
* @param aliasName The name of the alias
- * @param javaClassName The full class name
+ * @param targetObject Target name
* @param methodName The method name
* @param aliasType The alias type
* @param delimitedIdentifier Whether or not to treat the class name
@@ -83,7 +86,7 @@
*/
public void init(
Object aliasName,
- Object javaClassName,
+ Object targetObject,
Object methodName,
Object aliasSpecificInfo,
Object aliasType,
@@ -91,21 +94,20 @@
throws StandardException
{
TableName qn = (TableName) aliasName;
+ this.aliasType = ((Character) aliasType).charValue();
initAndCheck(qn);
-
- this.javaClassName = (String) javaClassName;
- this.methodName = (String) methodName;
- this.aliasType = ((Character) aliasType).charValue();
- this.delimitedIdentifier =
- ((Boolean)
delimitedIdentifier).booleanValue();
-
switch (this.aliasType)
{
case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:
case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:
{
+ this.javaClassName = (String) targetObject;
+ this.methodName = (String) methodName;
+ this.delimitedIdentifier =
+ ((Boolean)
delimitedIdentifier).booleanValue();
+
//routineElements contains the description of
the procedure.
//
// 0 - Object[] 3 element array for parameters
@@ -197,6 +199,14 @@
}
break;
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
+ String targetSchema;
+ TableName t = (TableName) targetObject;
+ if (t.getSchemaName() != null)
+ targetSchema = t.getSchemaName();
+ else targetSchema =
getSchemaDescriptor().getSchemaName();
+ aliasInfo = new SynonymAliasInfo(targetSchema,
t.getTableName());
+ break;
default:
if (SanityManager.DEBUG)
@@ -213,6 +223,8 @@
{
case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:
return "CREATE PROCEDURE";
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
+ return "CREATE SYNONYM";
default:
return "CREATE FUNCTION";
}
@@ -233,8 +245,27 @@
public QueryTreeNode bind() throws StandardException
{
- // Procedures do not check class or method validity until
runtime execution of the procedure.
+ // Procedures and functions do not check class or method
validity until
+ // runtime execution. Synonyms do need some validity checks.
+ if (aliasType != AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR)
+ return this;
+ String targetSchema =
((SynonymAliasInfo)aliasInfo).getSynonymSchema();
+ String targetTable =
((SynonymAliasInfo)aliasInfo).getSynonymTable();
+ if (this.getObjectName().equals(targetSchema, targetTable))
+ throw
StandardException.newException(SQLState.LANG_SYNONYM_REPETITIVE,
+ this.getFullName(),
+ targetSchema+"."+targetTable);
+
+ // Raise error if targetSchema doesn't exists
+ SchemaDescriptor targetSD = getSchemaDescriptor(targetSchema);
+
+ // Synonym can't be defined on temporary tables.
+ TableDescriptor targetTD = getTableDescriptor(targetTable,
targetSD);
+ if (targetTD != null &&
+ targetTD.getTableType() ==
TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE)
+ throw
StandardException.newException(SQLState.LANG_OPERATION_NOT_ALLOWED_ON_SESSION_SCHEMA_TABLES);
+
return this;
}
@@ -251,6 +282,9 @@
case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:
schemaName = getSchemaDescriptor().getSchemaName();
break;
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
+ schemaName = getSchemaDescriptor().getSchemaName();
+ break;
default:
schemaName = null;
}
Index: java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj (revision
179354)
+++ java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj (working copy)
@@ -1868,6 +1868,7 @@
| <SQL_TSI_YEAR: "sql_tsi_year">
| <START: "start">
| <STATEMENT: "statement">
+| <SYNONYM: "synonym">
| <THEN: "then">
| <TIME: "time">
| <TIMESTAMP: "timestamp">
@@ -2413,7 +2414,8 @@
(
statementNode = schemaDefinition() |
statementNode = viewDefinition(beginToken) |
- statementNode = triggerDefinition()
+ statementNode = triggerDefinition() |
+ statementNode = synonymDefinition()
)
{
}
@@ -9048,6 +9050,32 @@
}
}
+QueryTreeNode
+synonymDefinition() throws StandardException :
+{
+ TableName synonymName;
+ TableName targetName;
+}
+{
+ <SYNONYM> synonymName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) <FOR>
+ targetName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)
+ {
+ checkVersion(DataDictionary.DD_VERSION_DERBY_10_1,
+ "CREATE SYNONYM");
+
+ return (StatementNode) getNodeFactory().getCreateAliasNode
+ (
+ synonymName,
+ targetName,
+ null,
+ AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR,
+ Boolean.FALSE,
+ getContextManager()
+ );
+ }
+}
+
+
Boolean
beforeOrAfter() :
{}
@@ -11044,6 +11072,12 @@
{
return dropAliasNode(aliasName,
AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR);
}
+| <SYNONYM> aliasName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)
+ {
+ checkVersion(DataDictionary.DD_VERSION_DERBY_10_1, "DROP
SYNONYM");
+
+ return dropAliasNode(aliasName,
AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR);
+ }
}
QueryTreeNode
@@ -11537,6 +11571,7 @@
| tok = <STABILITY>
| tok = <START>
| tok = <STATEMENT>
+ | tok = <SYNONYM>
| tok = <STYLE>
| tok = <T>
| tok = <THEN>
Index: java/engine/org/apache/derby/impl/sql/compile/CreateViewNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/CreateViewNode.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/compile/CreateViewNode.java
(working copy)
@@ -179,6 +179,11 @@
ResultColumnList qeRCL;
String
duplicateColName;
+ if (resolveTableToSynonym(getObjectName()) != null)
+ throw
StandardException.newException(SQLState.LANG_OBJECT_ALREADY_EXISTS,
+ "Synonym",
+
getObjectName().toString());
+
// bind the query expression
providerInfos = bindViewDefinition
Index:
java/engine/org/apache/derby/impl/sql/execute/DropAliasConstantAction.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/execute/DropAliasConstantAction.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/execute/DropAliasConstantAction.java
(working copy)
@@ -129,7 +129,7 @@
// RESOLVE - fix error message
if (ad == null)
{
- throw
StandardException.newException(SQLState.LANG_OBJECT_NOT_FOUND, "Method alias",
aliasName);
+ throw
StandardException.newException(SQLState.LANG_OBJECT_NOT_FOUND,
ad.getAliasType(nameSpace), aliasName);
}
/* Prepare all dependents to invalidate. (This is their chance
Index:
java/engine/org/apache/derby/impl/sql/execute/CreateAliasConstantAction.java
===================================================================
---
java/engine/org/apache/derby/impl/sql/execute/CreateAliasConstantAction.java
(revision 179354)
+++
java/engine/org/apache/derby/impl/sql/execute/CreateAliasConstantAction.java
(working copy)
@@ -26,6 +26,7 @@
import org.apache.derby.iapi.sql.execute.ConstantAction;
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
import org.apache.derby.iapi.sql.dictionary.AliasDescriptor;
import org.apache.derby.iapi.sql.dictionary.DataDictionary;
import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
@@ -48,6 +49,7 @@
import org.apache.derby.catalog.AliasInfo;
import org.apache.derby.catalog.types.RoutineAliasInfo;
+import org.apache.derby.catalog.types.SynonymAliasInfo;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -76,9 +78,7 @@
* @param aliasName Name of alias.
* @param schemaName Name of alias's schema.
* @param javaClassName Name of java class.
- * @param methodName Name of method.
- * @param targetClassName Name of java class at Target database.
- * @param targetMethodName Name of method at Target database.
+ * @param aliasInfo AliasInfo
* @param aliasType The type of the alias
*/
CreateAliasConstantAction(
@@ -103,6 +103,10 @@
nameSpace =
AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR;
break;
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
+ nameSpace =
AliasInfo.ALIAS_NAME_SPACE_SYNONYM_AS_CHAR;
+ break;
+
default:
if (SanityManager.DEBUG)
{
@@ -132,6 +136,10 @@
type = "CREATE FUNCTION ";
break;
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
+ type = "CREATE SYNONYM ";
+ break;
+
default:
if (SanityManager.DEBUG)
{
@@ -167,6 +175,7 @@
(LanguageConnectionContext.CONTEXT_ID);
}
DataDictionary dd = lcc.getDataDictionary();
+ TransactionController tc = lcc.getTransactionExecute();
/* Verify the method alias:
** Aggregates - just verify the class
@@ -176,7 +185,6 @@
*/
String checkMethodName = null;
-
String checkClassName = javaClassName;
if (aliasInfo != null)
@@ -188,7 +196,9 @@
{
case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:
case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
break;
+
default:
{
@@ -271,7 +281,7 @@
false,
aliasInfo, null);
- // perform duplicate rule checking for routine
+ // perform duplicate rule checking
switch (aliasType) {
case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:
case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:
@@ -296,6 +306,48 @@
}
}
break;
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
+ // If target table/view exists already, error.
+ TableDescriptor targetTD =
dd.getTableDescriptor(aliasName, sd);
+ if (targetTD != null)
+ {
+ throw StandardException.newException(
+
SQLState.LANG_OBJECT_ALREADY_EXISTS,
+
targetTD.getDescriptorType(),
+
targetTD.getDescriptorName());
+ }
+
+ // Detect synonym cycles, if present.
+ String nextSynTable =
((SynonymAliasInfo)aliasInfo).getSynonymTable();
+ String nextSynSchema =
((SynonymAliasInfo)aliasInfo).getSynonymSchema();
+ SchemaDescriptor nextSD;
+ for (;;)
+ {
+ nextSD = dd.getSchemaDescriptor(nextSynSchema,
tc, false);
+ if (nextSD == null)
+ break;
+
+ AliasDescriptor nextAD =
dd.getAliasDescriptor(nextSD.getUUID().toString(),
+ nextSynTable, nameSpace);
+ if (nextAD == null)
+ break;
+
+ SynonymAliasInfo info = (SynonymAliasInfo)
nextAD.getAliasInfo();
+ nextSynTable = info.getSynonymTable();
+ nextSynSchema = info.getSynonymSchema();
+
+ if (aliasName.equals(nextSynTable) &&
schemaName.equals(nextSynSchema))
+ throw
StandardException.newException(SQLState.LANG_SYNONYM_REPETITIVE,
+ aliasName,
((SynonymAliasInfo)aliasInfo).getSynonymTable());
+ }
+
+ // If synonym final target is not present, raise a
warning
+ if (nextSD != null)
+ targetTD = dd.getTableDescriptor(nextSynTable,
nextSD);
+ if (nextSD == null || targetTD == null)
+ activation.addWarning(
+
StandardException.newWarning(SQLState.LANG_SYNONYM_UNDEFINED,
+ aliasName,
nextSynSchema+"."+nextSynTable));
default:
break;
}
@@ -303,5 +355,4 @@
dd.addDescriptor(ads, null,
DataDictionary.SYSALIASES_CATALOG_NUM,
false,
lcc.getTransactionExecute());
}
-
}
Index: java/engine/org/apache/derby/impl/sql/catalog/SYSALIASESRowFactory.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/catalog/SYSALIASESRowFactory.java
(revision 179354)
+++ java/engine/org/apache/derby/impl/sql/catalog/SYSALIASESRowFactory.java
(working copy)
@@ -191,6 +191,7 @@
{
case
AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:
case
AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:
+ case
AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
break;
default:
@@ -370,6 +371,7 @@
{
case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:
case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
break;
default:
@@ -391,6 +393,7 @@
{
case
AliasInfo.ALIAS_NAME_SPACE_PROCEDURE_AS_CHAR:
case
AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR:
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
break;
default:
Index: java/engine/org/apache/derby/iapi/sql/compile/NodeFactory.java
===================================================================
--- java/engine/org/apache/derby/iapi/sql/compile/NodeFactory.java
(revision 179354)
+++ java/engine/org/apache/derby/iapi/sql/compile/NodeFactory.java
(working copy)
@@ -590,7 +590,7 @@
public abstract QueryTreeNode
getCreateAliasNode(
Object aliasName,
- String fullStaticMethodName,
+ Object targetName,
Object aliasSpecificInfo,
char aliasType,
Boolean delimitedIdentifier,
Index: java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java
===================================================================
--- java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java
(revision 179354)
+++ java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java
(working copy)
@@ -288,17 +288,23 @@
/** @see TupleDescriptor#getDescriptorType */
public String getDescriptorType()
{
- switch (aliasType)
+ return getAliasType(aliasType);
+ }
+
+ public static final String getAliasType(char nameSpace)
+ {
+ switch (nameSpace)
{
case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:
return "PROCEDURE";
case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:
return "FUNCTION";
- default:
- return null;
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
+ return "SYNONYM";
}
+ return null;
}
-
+
/** @see TupleDescriptor#getDescriptorName */
public String getDescriptorName()
{
Index: java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java
===================================================================
--- java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java
(revision 179354)
+++ java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java
(working copy)
@@ -514,6 +514,7 @@
/* 451 */ "org.apache.derby.catalog.types.RoutineAliasInfo",
/* 452 */ null,
- /* 453 */
"org.apache.derby.impl.store.raw.log.ChecksumOperation"
+ /* 453 */
"org.apache.derby.impl.store.raw.log.ChecksumOperation",
+ /* 454 */ "org.apache.derby.catalog.types.SynonymAliasInfo"
};
}
Index: java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java
===================================================================
--- java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java
(revision 179354)
+++ java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java
(working copy)
@@ -1384,6 +1384,7 @@
public static final int ROUTINE_INFO_V01_ID = (MIN_ID_2 + 451);
+ public static final int SYNONYM_INFO_V01_ID = (MIN_ID_2 + 454);
/******************************************************************
**
@@ -1806,7 +1807,7 @@
* Make sure this is updated when a new module is added
*/
public static final int MAX_ID_2 =
- (MIN_ID_2 + 453);
+ (MIN_ID_2 + 454);
// DO NOT USE 4 BYTE IDS ANYMORE
static public final int MAX_ID_4 =
Index: java/engine/org/apache/derby/iapi/reference/SQLState.java
===================================================================
--- java/engine/org/apache/derby/iapi/reference/SQLState.java (revision
179354)
+++ java/engine/org/apache/derby/iapi/reference/SQLState.java (working copy)
@@ -630,6 +630,7 @@
String LANG_COL_NOT_NULL
= "01503";
String LANG_INDEX_DUPLICATE
= "01504";
String LANG_VALUE_TRUNCATED =
"01505";
+ String LANG_SYNONYM_UNDEFINED =
"01522";
String LANG_NULL_ELIMINATED_IN_SET_FUNCTION
= "01003";
String LANG_NO_ROW_FOUND
= "02000";
@@ -707,6 +708,7 @@
String LANG_NO_AGGREGATES_IN_WHERE_CLAUSE =
"42903";
String LANG_DB2_VIEW_REQUIRES_COLUMN_NAMES =
"42908";
String LANG_DELETE_RULE_VIOLATION
= "42915";
+ String LANG_SYNONYM_REPETITIVE
= "42916";
String LANG_DB2_ON_CLAUSE_INVALID
= "42972";
String LANG_SYNTAX_ERROR =
"42X01";
String LANG_LEXICAL_ERROR =
"42X02";
Index: java/engine/org/apache/derby/catalog/AliasInfo.java
===================================================================
--- java/engine/org/apache/derby/catalog/AliasInfo.java (revision 179354)
+++ java/engine/org/apache/derby/catalog/AliasInfo.java (working copy)
@@ -28,6 +28,7 @@
* <ul>
* <li>method alias
* <li>class alias
+ * <li>synonym
* <li>user-defined aggregate
* </ul>
*
@@ -39,18 +40,22 @@
*/
public static final char ALIAS_TYPE_PROCEDURE_AS_CHAR = 'P';
public static final char ALIAS_TYPE_FUNCTION_AS_CHAR = 'F';
+ public static final char ALIAS_TYPE_SYNONYM_AS_CHAR = 'S';
public static final String ALIAS_TYPE_PROCEDURE_AS_STRING
= "P";
public static final String ALIAS_TYPE_FUNCTION_AS_STRING
= "F";
+ public static final String ALIAS_TYPE_SYNONYM_AS_STRING
= "S";
/**
* Public statics for the various alias name spaces as both char and
String.
*/
public static final char ALIAS_NAME_SPACE_PROCEDURE_AS_CHAR = 'P';
public static final char ALIAS_NAME_SPACE_FUNCTION_AS_CHAR = 'F';
+ public static final char ALIAS_NAME_SPACE_SYNONYM_AS_CHAR = 'S';
public static final String ALIAS_NAME_SPACE_PROCEDURE_AS_STRING = "P";
public static final String ALIAS_NAME_SPACE_FUNCTION_AS_STRING = "F";
+ public static final String ALIAS_NAME_SPACE_SYNONYM_AS_STRING = "S";
/**
* Get the name of the static method that the alias
Index: java/engine/org/apache/derby/catalog/types/SynonymAliasInfo.java
===================================================================
--- java/engine/org/apache/derby/catalog/types/SynonymAliasInfo.java
(revision 0)
+++ java/engine/org/apache/derby/catalog/types/SynonymAliasInfo.java
(revision 0)
@@ -0,0 +1,107 @@
+/*
+
+ Derby - Class org.apache.derby.catalog.types.SynonymAliasInfo
+
+ Copyright 2003, 2004 The Apache Software Foundation or its licensors, as
applicable.
+
+ 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 org.apache.derby.catalog.types;
+
+import org.apache.derby.iapi.services.io.Formatable;
+import org.apache.derby.iapi.services.io.StoredFormatIds;
+import org.apache.derby.catalog.AliasInfo;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * Describe an S (Synonym) alias.
+ *
+ * @see AliasInfo
+ */
+public class SynonymAliasInfo implements AliasInfo, Formatable
+{
+ private String schemaName = null;
+ private String tableName = null;
+
+ public SynonymAliasInfo() {
+ }
+
+ /**
+ Create a SynonymAliasInfo for synonym.
+ */
+ public SynonymAliasInfo(String schemaName, String tableName)
+ {
+ this.schemaName = schemaName;
+ this.tableName = tableName;
+ }
+
+ public String getSynonymTable() {
+ return tableName;
+ }
+
+ public String getSynonymSchema() {
+ return schemaName;
+ }
+
+ // Formatable methods
+
+ /**
+ * Read this object from a stream of stored objects.
+ *
+ * @param in read this.
+ *
+ * @exception IOException thrown
on error
+ * @exception ClassNotFoundException thrown on error
+ */
+ public void readExternal( ObjectInput in )
+ throws IOException, ClassNotFoundException
+ {
+ schemaName = (String) in.readObject();
+ tableName = (String) in.readObject();
+ }
+
+ /**
+ * Write this object to a stream of stored objects.
+ *
+ * @param out write bytes here.
+ *
+ * @exception IOException thrown on error
+ */
+ public void writeExternal( ObjectOutput out )
+ throws IOException
+ {
+ out.writeObject(schemaName);
+ out.writeObject(tableName);
+ }
+
+ /**
+ * Get the formatID which corresponds to this class.
+ *
+ * @return the formatID of this class
+ */
+ public int getTypeFormatId() { return
StoredFormatIds.SYNONYM_INFO_V01_ID; }
+
+ public String toString() {
+ return "SchemaLen:"+schemaName.length()+"
"+schemaName+tableName;
+ }
+
+ public String getMethodName()
+ {
+ return null;
+ }
+}
+
Property changes on:
java/engine/org/apache/derby/catalog/types/SynonymAliasInfo.java
___________________________________________________________________
Name: svn:eol-style
+ native
Index: java/engine/org/apache/derby/loc/messages_en.properties
===================================================================
--- java/engine/org/apache/derby/loc/messages_en.properties (revision
179354)
+++ java/engine/org/apache/derby/loc/messages_en.properties (working copy)
@@ -351,6 +351,7 @@
01503=The column {0} on table {1} has been modified by adding a not null
constraint.
01504=The new index is a duplicate of an existing index: {0}.
01505=The value {0} may be truncated.
+01522=The newly defined alias ''{0}'' resolved to the object ''{1}'' which is
currently undefined.
01003=Null values were eliminated from the argument of a column function.
0100E=XX Attepmt to return too many result sets
02000=No row was found for FETCH, UPDATE or DELETE; or the result of a query
is an empty table.
@@ -413,6 +414,7 @@
42903=Invalid use of an aggregate function.
42908=The CREATE VIEW statement does not include a column list.
42915=Foreign Key ''{0}'' is invalid because ''{1}''.
+42916=Synonym ''{0}'' cannot be created for ''{1}'' as it would result in a
repetitive synonym chain.
42972=An ON clause associated with a JOIN operator is not valid.
42X01=Syntax error: {0}.
42X02={0}.
Index:
java/testing/org/apache/derbyTesting/functionTests/tests/lang/copyfiles.ant
===================================================================
--- java/testing/org/apache/derbyTesting/functionTests/tests/lang/copyfiles.ant
(revision 179354)
+++ java/testing/org/apache/derbyTesting/functionTests/tests/lang/copyfiles.ant
(working copy)
@@ -186,6 +186,7 @@
supersimple.sql
supersimple_derby.properties
syscat.sql
+synonym.sql
tempRestrictions.sql
triggerBeforeTrig.sql
triggerGeneral.sql
Index: java/testing/org/apache/derbyTesting/functionTests/tests/lang/synonym.sql
===================================================================
--- java/testing/org/apache/derbyTesting/functionTests/tests/lang/synonym.sql
(revision 0)
+++ java/testing/org/apache/derbyTesting/functionTests/tests/lang/synonym.sql
(revision 0)
@@ -0,0 +1,115 @@
+-- tests for synonym support
+
+set schema APP;
+-- negative tests
+-- Create a synonym to itself. Error.
+create synonym syn for syn;
+create synonym syn for APP.syn;
+create synonym APP.syn for syn;
+create synonym APP.syn for APP.syn;
+
+-- Create a simple synonym loop. Error.
+create synonym synonym1 for synonym;
+create synonym synonym for synonym1;
+drop synonym synonym1;
+
+-- Create a larger synonym loop.
+create synonym ts1 for ts;
+create synonym ts2 for ts1;
+create synonym ts3 for ts2;
+create synonym ts4 for ts3;
+create synonym ts5 for ts4;
+create synonym ts6 for ts5;
+create synonym ts for ts6;
+drop synonym App.ts1;
+drop synonym "APP".ts2;
+drop synonym TS3;
+drop synonym ts4;
+drop synonym ts5;
+drop synonym app.ts6;
+
+-- Synonyms and table/view share same namespace. Negative tests for this.
+create table table1 (i int, j int);
+insert into table1 values (1,1), (2,2);
+create view view1 as select i, j from table1;
+
+create synonym table1 for t1;
+create synonym APP.Table1 for t1;
+create synonym app.TABLE1 for "APP"."T";
+
+create synonym APP.VIEW1 for v1;
+create synonym "APP"."VIEW1" for app.v;
+
+-- Synonyms can't be created on temporary tables
+declare global temporary table session.t1 (c1 int) not logged;
+create synonym synForTemp for session.t1;
+create synonym synForTemp for session."T1";
+
+-- Creating a table or a view when a synonym of that name is present. Error.
+create synonym myTable for table1;
+
+create table myTable(i int, j int);
+
+create view myTable as select * from table1;
+
+
+-- Positive test cases
+
+-- Using synonym in DML
+
+select * from table1;
+select * from myTable;
+insert into myTable values (3,3), (4,4);
+
+select * from mytable;
+
+update myTable set i=3 where j=4;
+
+select * from mytable;
+select * from table1;
+
+delete from myTable where i> 2;
+
+select * from "APP"."MYTABLE";
+select * from APP.table1;
+
+-- Try some cursors
+get cursor c1 as 'select * from myTable';
+
+next c1;
+next c1;
+
+close c1;
+
+-- Try updatable cursors
+
+autocommit off;
+get cursor c2 as 'select * from myTable for update';
+
+next c2;
+update myTable set i=5 where current of c2;
+close c2;
+
+autocommit on;
+
+select * from table1;
+
+-- Try updatable cursors, with synonym at the top, base table inside.
+autocommit off;
+get cursor c2 as 'select * from app.table1 for update';
+
+next c2;
+update myTable set i=6 where current of c2;
+close c2;
+
+autocommit on;
+
+select * from table1;
+-- TODO: Add more tests here
+
+-- trigger tests
+-- drop and recreate schema test
+-- More negative tests once dependency checking is added
+
+drop view view1;
+drop table table1;
Property changes on:
java/testing/org/apache/derbyTesting/functionTests/tests/lang/synonym.sql
___________________________________________________________________
Name: svn:eol-style
+ native
Index: java/testing/org/apache/derbyTesting/functionTests/master/synonym.out
===================================================================
--- java/testing/org/apache/derbyTesting/functionTests/master/synonym.out
(revision 0)
+++ java/testing/org/apache/derbyTesting/functionTests/master/synonym.out
(revision 0)
@@ -0,0 +1,186 @@
+ij> -- tests for synonym support
+set schema APP;
+0 rows inserted/updated/deleted
+ij> -- negative tests
+-- Create a synonym to itself. Error.
+create synonym syn for syn;
+ERROR 42916: Synonym 'SYN' cannot be created for 'APP.SYN' as it would result
in a repetitive synonym chain.
+ij> create synonym syn for APP.syn;
+ERROR 42916: Synonym 'SYN' cannot be created for 'APP.SYN' as it would result
in a repetitive synonym chain.
+ij> create synonym APP.syn for syn;
+ERROR 42916: Synonym 'APP.SYN' cannot be created for 'APP.SYN' as it would
result in a repetitive synonym chain.
+ij> create synonym APP.syn for APP.syn;
+ERROR 42916: Synonym 'APP.SYN' cannot be created for 'APP.SYN' as it would
result in a repetitive synonym chain.
+ij> -- Create a simple synonym loop. Error.
+create synonym synonym1 for synonym;
+0 rows inserted/updated/deleted
+WARNING 01522: The newly defined alias 'SYNONYM1' resolved to the object
'APP.SYNONYM' which is currently undefined.
+ij> create synonym synonym for synonym1;
+ERROR 42916: Synonym 'SYNONYM' cannot be created for 'SYNONYM1' as it would
result in a repetitive synonym chain.
+ij> drop synonym synonym1;
+0 rows inserted/updated/deleted
+ij> -- Create a larger synonym loop.
+create synonym ts1 for ts;
+0 rows inserted/updated/deleted
+WARNING 01522: The newly defined alias 'TS1' resolved to the object 'APP.TS'
which is currently undefined.
+ij> create synonym ts2 for ts1;
+0 rows inserted/updated/deleted
+WARNING 01522: The newly defined alias 'TS2' resolved to the object 'APP.TS'
which is currently undefined.
+ij> create synonym ts3 for ts2;
+0 rows inserted/updated/deleted
+WARNING 01522: The newly defined alias 'TS3' resolved to the object 'APP.TS'
which is currently undefined.
+ij> create synonym ts4 for ts3;
+0 rows inserted/updated/deleted
+WARNING 01522: The newly defined alias 'TS4' resolved to the object 'APP.TS'
which is currently undefined.
+ij> create synonym ts5 for ts4;
+0 rows inserted/updated/deleted
+WARNING 01522: The newly defined alias 'TS5' resolved to the object 'APP.TS'
which is currently undefined.
+ij> create synonym ts6 for ts5;
+0 rows inserted/updated/deleted
+WARNING 01522: The newly defined alias 'TS6' resolved to the object 'APP.TS'
which is currently undefined.
+ij> create synonym ts for ts6;
+ERROR 42916: Synonym 'TS' cannot be created for 'TS6' as it would result in a
repetitive synonym chain.
+ij> drop synonym App.ts1;
+0 rows inserted/updated/deleted
+ij> drop synonym "APP".ts2;
+0 rows inserted/updated/deleted
+ij> drop synonym TS3;
+0 rows inserted/updated/deleted
+ij> drop synonym ts4;
+0 rows inserted/updated/deleted
+ij> drop synonym ts5;
+0 rows inserted/updated/deleted
+ij> drop synonym app.ts6;
+0 rows inserted/updated/deleted
+ij> -- Synonyms and table/view share same namespace. Negative tests for this.
+create table table1 (i int, j int);
+0 rows inserted/updated/deleted
+ij> insert into table1 values (1,1), (2,2);
+2 rows inserted/updated/deleted
+ij> create view view1 as select i, j from table1;
+0 rows inserted/updated/deleted
+ij> create synonym table1 for t1;
+ERROR X0Y68: Table/View 'TABLE1' already exists.
+ij> create synonym APP.Table1 for t1;
+ERROR X0Y68: Table/View 'TABLE1' already exists.
+ij> create synonym app.TABLE1 for "APP"."T";
+ERROR X0Y68: Table/View 'TABLE1' already exists.
+ij> create synonym APP.VIEW1 for v1;
+ERROR X0Y68: Table/View 'VIEW1' already exists.
+ij> create synonym "APP"."VIEW1" for app.v;
+ERROR X0Y68: Table/View 'VIEW1' already exists.
+ij> -- Synonyms can't be created on temporary tables
+declare global temporary table session.t1 (c1 int) not logged;
+0 rows inserted/updated/deleted
+ij> create synonym synForTemp for session.t1;
+ERROR XCL51: The requested function can not reference tables in SESSION schema.
+ij> create synonym synForTemp for session."T1";
+ERROR XCL51: The requested function can not reference tables in SESSION schema.
+ij> -- Creating a table or a view when a synonym of that name is present.
Error.
+create synonym myTable for table1;
+0 rows inserted/updated/deleted
+ij> create table myTable(i int, j int);
+ERROR X0Y68: Synonym 'MYTABLE' already exists.
+ij> create view myTable as select * from table1;
+ERROR X0Y68: Synonym 'MYTABLE' already exists.
+ij> -- Positive test cases
+-- Using synonym in DML
+select * from table1;
+I |J
+-----------------------
+1 |1
+2 |2
+ij> select * from myTable;
+I |J
+-----------------------
+1 |1
+2 |2
+ij> insert into myTable values (3,3), (4,4);
+2 rows inserted/updated/deleted
+ij> select * from mytable;
+I |J
+-----------------------
+1 |1
+2 |2
+3 |3
+4 |4
+ij> update myTable set i=3 where j=4;
+1 row inserted/updated/deleted
+ij> select * from mytable;
+I |J
+-----------------------
+1 |1
+2 |2
+3 |3
+3 |4
+ij> select * from table1;
+I |J
+-----------------------
+1 |1
+2 |2
+3 |3
+3 |4
+ij> delete from myTable where i> 2;
+2 rows inserted/updated/deleted
+ij> select * from "APP"."MYTABLE";
+I |J
+-----------------------
+1 |1
+2 |2
+ij> select * from APP.table1;
+I |J
+-----------------------
+1 |1
+2 |2
+ij> -- Try some cursors
+get cursor c1 as 'select * from myTable';
+ij> next c1;
+I |J
+-----------------------
+1 |1
+ij> next c1;
+I |J
+-----------------------
+2 |2
+ij> close c1;
+ij> -- Try updatable cursors
+autocommit off;
+ij> get cursor c2 as 'select * from myTable for update';
+ij> next c2;
+I |J
+-----------------------
+1 |1
+ij> update myTable set i=5 where current of c2;
+1 row inserted/updated/deleted
+ij> close c2;
+ij> autocommit on;
+ij> select * from table1;
+I |J
+-----------------------
+5 |1
+2 |2
+ij> -- Try updatable cursors, with synonym at the top, base table inside.
+autocommit off;
+ij> get cursor c2 as 'select * from app.table1 for update';
+ij> next c2;
+I |J
+-----------------------
+5 |1
+ij> update myTable set i=6 where current of c2;
+1 row inserted/updated/deleted
+ij> close c2;
+ij> autocommit on;
+ij> select * from table1;
+I |J
+-----------------------
+6 |1
+2 |2
+ij> -- TODO: Add more tests here
+-- trigger tests
+-- drop and recreate schema test
+-- More negative tests once dependency checking is added
+drop view view1;
+0 rows inserted/updated/deleted
+ij> drop table table1;
+0 rows inserted/updated/deleted
+ij>
Property changes on:
java/testing/org/apache/derbyTesting/functionTests/master/synonym.out
___________________________________________________________________
Name: svn:eol-style
+ native
