Merged V3.1 to HEAD

14192: Support for variable assignment and replacement in upgrade scripts
   14263 (RECORD ONLY)
   14286: Merged V2.2 to V3.1
      14124: Fixed ETWOTWO-961: FileFolderService.listFolders throws UnsupportedOperationException for AVM nodes
      14277: Fixed ETWOTWO-1228: CLONE -NodeService properties don't support collections of collections for d:any
   14302: Merged DEV/V3.1_UPGRADE_SCRIPTS_2 to V3.1: DB2 scripts and other minor changes
      14126 (RECORD ONLY)
      14193 (RECORD ONLY)
      14205: Next version of DB upgrade scripts for SQLServer and DB2
      14208: Enterprise DB scripts review: Move scripts to correct locations as a first pass
      14211: Carried V2.1-A script change into branch; use STR() function for numeric to string comparison
      14212: Moved script from old SQLServer dialect directory
      14213: Minor script formatting
   14303: Merged DEV/V3.1_UPGRADE_SCRIPTS_2 to V3.1: DB2 scripts and other formatting
      14214: Removed redundant scripts; these are all covered by generic scripts
      14236: Format SQL
      14248: Formatting of SQL to produce meaningful diffs
      14266: Next version of upgrade scripts
      14281: Clean up formatting of SQL scripts using Convert utility
   ___________________________________________________________________
   Modified: svn:mergeinfo
      Merged /alfresco/BRANCHES/DEV/V3.1_UPGRADE_SCRIPTS_2:r14126,14193,14205,14208,14211-14213
      Merged /alfresco/BRANCHES/V2.2:r14124,14130,14277
      Merged /alfresco/BRANCHES/V3.1:r14192,14263,14286,14302-14303


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14652 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-06-11 10:30:57 +00:00
parent 592a2bb2fc
commit 5b6ff13d94
7 changed files with 190 additions and 34 deletions

View File

@@ -18,7 +18,8 @@ UPDATE
FROM
alf_namespace n
WHERE
n.uri = 'http://www.alfresco.org/model/content/1.0'),
n.uri = 'http://www.alfresco.org/model/content/1.0'
),
qname_localname =
(
SELECT
@@ -29,7 +30,8 @@ UPDATE
JOIN alf_namespace n on q.ns_id = n.id
WHERE
p.node_id = alf_child_assoc.child_node_id AND
q.local_name ='userName' AND n.uri = 'http://www.alfresco.org/model/content/1.0'
q.local_name ='userName' AND
n.uri = 'http://www.alfresco.org/model/content/1.0'
)
WHERE exists
(

View File

@@ -24,4 +24,6 @@ schema.update.err.update_failed=Schema auto-update failed
schema.update.err.validation_failed=Schema validation failed
schema.update.err.update_script_not_run=The following schema upgrade script needs to be executed manually: {0}
schema.update.err.script_not_found=The schema script could not be found at location {0}
schema.update.err.statement_var_assignment_before_sql=Variable assignment with '--ASSIGN:' must occur before starting the SQL statement (line {0} of {1}).
schema.update.err.statement_var_assignment_format=Variable assignment uses format '--ASSIGN:x=col' where 'x' is the variable to assign to and 'col' is the column value to extract (line {0} of {1}).
schema.update.err.statement_terminator=Scripts must terminate all statements with ';' (line {0} of {1}).

View File

@@ -1614,7 +1614,61 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, Set<QName> childNodeTypes)
{
throw new UnsupportedOperationException();
/*
* ETWOTWO-961 forced an implementation, but this is just a workaround.
* We do a listing and then keep files or folders looking specifically
* for cm:folder and cm:content types from childNodeTypes.
*/
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
int version = avmVersionPath.getFirst();
String path = avmVersionPath.getSecond();
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
SortedMap<String, AVMNodeDescriptor> children = null;
try
{
children =
fAVMService.getDirectoryListing(version,
path);
}
catch (AVMNotFoundException e)
{
return result;
}
for (Map.Entry<String, AVMNodeDescriptor> entry : children.entrySet())
{
String name = entry.getKey();
AVMNodeDescriptor descriptor = entry.getValue();
if (descriptor.isFile())
{
if (!childNodeTypes.contains(ContentModel.TYPE_CONTENT))
{
continue;
}
}
else if (descriptor.isDirectory())
{
if (!childNodeTypes.contains(ContentModel.TYPE_FOLDER))
{
continue;
}
}
else
{
// Not a file or directory???
continue;
}
result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
nodeRef,
QName.createQName(
NamespaceService.CONTENT_MODEL_1_0_URI,
name),
AVMNodeConverter.ToNodeRef(
version,
AVMNodeConverter.ExtendAVMPath(path, name)),
true,
-1));
}
return result;
}
public List<ChildAssociationRef> getChildrenByName(NodeRef nodeRef, QName assocTypeQName, Collection<String> childNames)

View File

@@ -423,21 +423,6 @@ public class NodePropertyValue implements Cloneable, Serializable
return Integer.valueOf(19);
}
@SuppressWarnings("unchecked")
@Override
protected ValueType getPersistedType(Serializable value)
{
if (value instanceof Collection)
{
Collection collectionValue = (Collection) value;
if (collectionValue.size() == 0)
{
return ValueType.NULL;
}
}
return ValueType.SERIALIZABLE;
}
/**
* @return Returns and empty <tt>Collection</tt> if the value is null
* otherwise it just returns the original value
@@ -569,14 +554,6 @@ public class NodePropertyValue implements Cloneable, Serializable
{
return ValueType.VERSION_NUMBER;
}
else if (value instanceof Collection)
{
return ValueType.COLLECTION;
}
else if (value instanceof MLText)
{
return ValueType.MLTEXT;
}
else if (value instanceof Period)
{
return ValueType.PERIOD;

View File

@@ -39,7 +39,9 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.alfresco.error.AlfrescoRuntimeException;
@@ -125,6 +127,8 @@ public class SchemaBootstrap extends AbstractLifecycleBean
private static final String ERR_VALIDATION_FAILED = "schema.update.err.validation_failed";
private static final String ERR_SCRIPT_NOT_RUN = "schema.update.err.update_script_not_run";
private static final String ERR_SCRIPT_NOT_FOUND = "schema.update.err.script_not_found";
private static final String ERR_STATEMENT_VAR_ASSIGNMENT_BEFORE_SQL = "schema.update.err.statement_var_assignment_before_sql";
private static final String ERR_STATEMENT_VAR_ASSIGNMENT_FORMAT = "schema.update.err.statement_var_assignment_format";
private static final String ERR_STATEMENT_TERMINATOR = "schema.update.err.statement_terminator";
public static final int DEFAULT_LOCK_RETRY_COUNT = 24;
@@ -910,6 +914,9 @@ public class SchemaBootstrap extends AbstractLifecycleBean
int line = 0;
// loop through all statements
StringBuilder sb = new StringBuilder(1024);
String fetchVarName = null;
String fetchColumnName = null;
Map<String, Object> varAssignments = new HashMap<String, Object>(13);
while(true)
{
String sqlOriginal = reader.readLine();
@@ -923,6 +930,25 @@ public class SchemaBootstrap extends AbstractLifecycleBean
// trim it
String sql = sqlOriginal.trim();
// Check for variable assignment
if (sql.startsWith("--ASSIGN:"))
{
if (sb.length() > 0)
{
// This can only be set before a new SQL statement
throw AlfrescoRuntimeException.create(ERR_STATEMENT_VAR_ASSIGNMENT_BEFORE_SQL, (line - 1), scriptUrl);
}
String assignStr = sql.substring(9, sql.length());
String[] assigns = assignStr.split("=");
if (assigns.length != 2 || assigns[0].length() == 0 || assigns[1].length() == 0)
{
throw AlfrescoRuntimeException.create(ERR_STATEMENT_VAR_ASSIGNMENT_FORMAT, (line - 1), scriptUrl);
}
fetchVarName = assigns[0];
fetchColumnName = assigns[1];
continue;
}
// Check for comments
if (sql.length() == 0 ||
sql.startsWith( "--" ) ||
sql.startsWith( "//" ) ||
@@ -978,8 +1004,23 @@ public class SchemaBootstrap extends AbstractLifecycleBean
if (execute)
{
sql = sb.toString();
executeStatement(connection, sql, optional, line, scriptFile);
// Perform variable replacement using the ${var} format
for (Map.Entry<String, Object> entry : varAssignments.entrySet())
{
String var = entry.getKey();
Object val = entry.getValue();
sql = sql.replaceAll("\\$\\{" + var + "\\}", val.toString());
}
Object fetchedVal = executeStatement(connection, sql, fetchColumnName, optional, line, scriptFile);
if (fetchVarName != null && fetchColumnName != null)
{
varAssignments.put(fetchVarName, fetchedVal);
}
sb = new StringBuilder(1024);
fetchVarName = null;
fetchColumnName = null;
}
}
}
@@ -993,8 +1034,16 @@ public class SchemaBootstrap extends AbstractLifecycleBean
/**
* Execute the given SQL statement, absorbing exceptions that we expect during
* schema creation or upgrade.
*
* @param fetchColumnName the name of the column value to return
*/
private void executeStatement(Connection connection, String sql, boolean optional, int line, File file) throws Exception
private Object executeStatement(
Connection connection,
String sql,
String fetchColumnName,
boolean optional,
int line,
File file) throws Exception
{
StringBuilder executedStatements = executedStatementsThreadLocal.get();
if (executedStatements == null)
@@ -1003,15 +1052,25 @@ public class SchemaBootstrap extends AbstractLifecycleBean
}
Statement stmt = connection.createStatement();
Object ret = null;
try
{
if (logger.isDebugEnabled())
{
LogUtil.debug(logger, MSG_EXECUTING_STATEMENT, sql);
}
stmt.execute(sql);
boolean haveResults = stmt.execute(sql);
// Record the statement
executedStatements.append(sql).append(";\n\n");
if (haveResults && fetchColumnName != null)
{
ResultSet rs = stmt.getResultSet();
if (rs.next())
{
// Get the result value
ret = rs.getObject(fetchColumnName);
}
}
}
catch (SQLException e)
{
@@ -1030,6 +1089,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
{
try { stmt.close(); } catch (Throwable e) {}
}
return ret;
}
/**

View File

@@ -32,6 +32,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -1430,6 +1431,7 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
assertTrue("Serialization/deserialization failed", checkPropertyQname instanceof QName);
}
@SuppressWarnings("unchecked")
public void testMultiProp() throws Exception
{
QName undeclaredPropQName = QName.createQName(NAMESPACE, getName());
@@ -1439,7 +1441,7 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
ASSOC_TYPE_QNAME_TEST_CHILDREN,
QName.createQName("pathA"),
TYPE_QNAME_TEST_MULTIPLE_TESTER).getChildRef();
ArrayList<String> values = new ArrayList<String>(1);
ArrayList<Serializable> values = new ArrayList<Serializable>(1);
values.add("ABC");
values.add("DEF");
// test allowable conditions
@@ -1473,6 +1475,62 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
{
try { txn.rollback(); } catch (Throwable e) {}
}
txn = transactionService.getUserTransaction();
try
{
txn.begin();
// Check that multi-valued d:mltext can be collections of MLText
values.clear();
values.add(new MLText("ABC"));
values.add(new MLText("DEF"));
nodeService.setProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE, values);
List<Serializable> checkValues = (List<Serializable>) nodeService.getProperty(
nodeRef, PROP_QNAME_MULTI_ML_VALUE);
assertEquals("Expected 2 MLText values back", 2, checkValues.size());
assertTrue("Incorrect type in collection", checkValues.get(0) instanceof MLText);
assertTrue("Incorrect type in collection", checkValues.get(1) instanceof MLText);
// Check that multi-valued d:any properties can be collections of collections (empty)
// We put ArrayLists and HashSets into the Collection of d:any, so that is exactly what should come out
values.clear();
ArrayList<Serializable> arrayListVal = new ArrayList<Serializable>(2);
HashSet<Serializable> hashSetVal = new HashSet<Serializable>(2);
values.add(arrayListVal);
values.add(hashSetVal);
nodeService.setProperty(nodeRef, PROP_QNAME_ANY_PROP_MULTIPLE, values);
checkValues = (List<Serializable>) nodeService.getProperty(
nodeRef, PROP_QNAME_ANY_PROP_MULTIPLE);
assertEquals("Expected 2 Collection values back", 2, checkValues.size());
assertTrue("Incorrect type in collection", checkValues.get(0) instanceof ArrayList); // ArrayList in - ArrayList out
assertTrue("Incorrect type in collection", checkValues.get(1) instanceof HashSet); // HashSet in - HashSet out
// Check that multi-valued d:any properties can be collections of collections (with values)
// We put ArrayLists and HashSets into the Collection of d:any, so that is exactly what should come out
arrayListVal.add("ONE");
arrayListVal.add("TWO");
hashSetVal.add("ONE");
hashSetVal.add("TWO");
values.clear();
values.add(arrayListVal);
values.add(hashSetVal);
nodeService.setProperty(nodeRef, PROP_QNAME_ANY_PROP_MULTIPLE, values);
checkValues = (List<Serializable>) nodeService.getProperty(
nodeRef, PROP_QNAME_ANY_PROP_MULTIPLE);
assertEquals("Expected 2 Collection values back", 2, checkValues.size());
assertTrue("Incorrect type in collection", checkValues.get(0) instanceof ArrayList); // ArrayList in - ArrayList out
assertTrue("Incorrect type in collection", checkValues.get(1) instanceof HashSet); // HashSet in - HashSet out
assertEquals("First collection incorrect", 2, ((Collection)checkValues.get(0)).size());
assertEquals("Second collection incorrect", 2, ((Collection)checkValues.get(1)).size());
}
catch (DictionaryException e)
{
// expected
}
finally
{
try { txn.rollback(); } catch (Throwable e) {}
}
}
/**

View File

@@ -4425,6 +4425,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
LocaleDAO localeDAO)
{
Serializable result = null;
Collection<Serializable> collectionResult = null;
// A working map. Ordering is not important for this map.
Map<PropertyMapKey, NodePropertyValue> scratch = new HashMap<PropertyMapKey, NodePropertyValue>(3);
// Iterate (sorted) over the map entries and extract values with the same list index
@@ -4456,15 +4457,17 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
{
result = collapsedValue;
}
else if (result instanceof Collection)
else if (collectionResult != null)
{
@SuppressWarnings("unchecked")
Collection<Serializable> collectionResult = (Collection<Serializable>) result;
// We have started a collection, so just add the value to it.
collectionResult.add(collapsedValue);
}
else
{
Collection<Serializable> collectionResult = new ArrayList<Serializable>(20);
// We already had a result, and now have another. A collection has not been
// started. We start a collection and explicitly keep track of it so that
// we don't get mixed up with collections of collections (ETHREEOH-2064).
collectionResult = new ArrayList<Serializable>(20);
collectionResult.add(result); // Add the first result
collectionResult.add(collapsedValue); // Add the new value
result = (Serializable) collectionResult;