mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
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:
@@ -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
|
||||
(
|
||||
|
@@ -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}).
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user