From 0c3d52aa6895140f41366147d0aad48bbd0fb9a6 Mon Sep 17 00:00:00 2001
From: alaskowski <alaskowski@ethz.ch>
Date: Tue, 9 May 2023 13:29:32 +0200
Subject: [PATCH] SSDM-13524: Added array data types and json type to
 properties of collections, samples and datasets. Added new property types to
 history.

---
 .../v3/translator/dataset/DataSetQuery.java   |  22 +++-
 .../experiment/ExperimentQuery.java           |  22 +++-
 .../history/HistoryPropertyRecord.java        |   6 +
 .../history/PropertyHistoryTranslator.java    |  37 ++++--
 .../translator/property/PropertyRecord.java   |   6 +
 .../property/PropertyTranslator.java          |  56 ++++++--
 .../v3/translator/sample/SampleQuery.java     |  23 +++-
 ...istoryPropertyRecordDataObjectBinding.java |  62 +++++++++
 .../PropertyRecordDataObjectBinding.java      |  64 +++++++++
 .../server/dataaccess/PropertyValidator.java  |  15 +--
 .../generic/shared/dto/EntityPropertyPE.java  |  17 ++-
 .../shared/dto/types/TimestampArrayType.java  |   1 -
 .../source/sql/generic/191/schema-191.sql     | 123 +++++++++++++-----
 .../sql/postgresql/191/function-191.sql       | 118 +++++++++++++++--
 14 files changed, 470 insertions(+), 102 deletions(-)
 create mode 100644 server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/HistoryPropertyRecordDataObjectBinding.java
 create mode 100644 server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/PropertyRecordDataObjectBinding.java

diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetQuery.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetQuery.java
index 6a65a8ee667..c5075af9337 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetQuery.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetQuery.java
@@ -26,6 +26,8 @@ import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.PropertyA
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.PropertyRecord;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.SamplePropertyRecord;
 import ch.systemsx.cisd.common.db.mapper.LongSetMapper;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.common.HistoryPropertyRecordDataObjectBinding;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.common.PropertyRecordDataObjectBinding;
 import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
 import it.unimi.dsi.fastutil.longs.LongSet;
 import net.lemnik.eodsql.Select;
@@ -101,7 +103,12 @@ public interface DataSetQuery extends ObjectQuery
                     + "p.value as propertyValue, m.code as materialPropertyValueCode, mt.code as materialPropertyValueTypeCode, "
                     + "s.perm_id as sample_perm_id, s.id as sample_id, "
                     + "cvt.code as vocabularyPropertyValue, "
-                    + "cv.code as vocabularyPropertyValueTypeCode "
+                    + "cv.code as vocabularyPropertyValueTypeCode, "
+                    + "p.integer_array_value as integerArrayPropertyValue, "
+                    + "p.real_array_value as realArrayPropertyValue, "
+                    + "p.string_array_value as stringArrayPropertyValue, "
+                    + "p.timestamp_array_value as timestampArrayPropertyValue, "
+                    + "p.json_value as jsonPropertyValue "
                     + "from data_set_properties p "
                     + "left join samples s on p.samp_prop_id = s.id "
                     + "left join materials m on p.mate_prop_id = m.id "
@@ -110,7 +117,8 @@ public interface DataSetQuery extends ObjectQuery
                     + "left join material_types mt on m.maty_id = mt.id "
                     + "join data_set_type_property_types etpt on p.dstpt_id = etpt.id "
                     + "join property_types pt on etpt.prty_id = pt.id "
-                    + "where p.ds_id = any(?{1})", parameterBindings = { LongSetMapper.class }, fetchSize = FETCH_SIZE)
+                    + "where p.ds_id = any(?{1})", parameterBindings = { LongSetMapper.class },
+            resultSetBinding = PropertyRecordDataObjectBinding.class, fetchSize = FETCH_SIZE)
     public List<PropertyRecord> getProperties(LongSet dataSetIds);
 
     // PropertyQueryGenerator was used to generate this query
@@ -132,11 +140,17 @@ public interface DataSetQuery extends ObjectQuery
 
     // PropertyQueryGenerator was used to generate this query
     @Select(sql =
-            "select ph.id as id, ph.ds_id as objectId, ph.pers_id_author as authorId, case pt.is_managed_internally when FALSE then pt.code else '$' || pt.code end as propertyCode, ph.value as propertyValue, ph.material as materialPropertyValue, ph.sample as samplePropertyValue, ph.vocabulary_term as vocabularyPropertyValue, ph.valid_from_timestamp as validFrom, ph.valid_until_timestamp as validTo "
+            "select ph.id as id, ph.ds_id as objectId, ph.pers_id_author as authorId, case pt.is_managed_internally when FALSE then pt.code else '$' || pt.code end as propertyCode, ph.value as propertyValue, ph.material as materialPropertyValue, ph.sample as samplePropertyValue, ph.vocabulary_term as vocabularyPropertyValue, ph.valid_from_timestamp as validFrom, ph.valid_until_timestamp as validTo, "
+                    + "ph.integer_array_value as integerArrayPropertyValue, "
+                    + "ph.real_array_value as realArrayPropertyValue, "
+                    + "ph.string_array_value as stringArrayPropertyValue, "
+                    + "ph.timestamp_array_value as timestampArrayPropertyValue, "
+                    + "ph.json_value as jsonPropertyValue "
                     + "from data_set_properties_history ph "
                     + "join data_set_type_property_types etpt on ph.dstpt_id = etpt.id "
                     + "join property_types pt on etpt.prty_id = pt.id "
-                    + "where ph.ds_id = any(?{1})", parameterBindings = { LongSetMapper.class }, fetchSize = FETCH_SIZE)
+                    + "where ph.ds_id = any(?{1})", parameterBindings = { LongSetMapper.class },
+            resultSetBinding = HistoryPropertyRecordDataObjectBinding.class, fetchSize = FETCH_SIZE)
     public List<HistoryPropertyRecord> getPropertiesHistory(LongSet dataSetIds);
 
     public static final String RELATIONSHIP_HISTORY_QUERY =
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/experiment/ExperimentQuery.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/experiment/ExperimentQuery.java
index e9dff171603..c13492e0059 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/experiment/ExperimentQuery.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/experiment/ExperimentQuery.java
@@ -25,6 +25,8 @@ import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.PropertyA
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.PropertyRecord;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.SamplePropertyRecord;
 import ch.systemsx.cisd.common.db.mapper.LongSetMapper;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.common.HistoryPropertyRecordDataObjectBinding;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.common.PropertyRecordDataObjectBinding;
 import it.unimi.dsi.fastutil.longs.LongSet;
 import net.lemnik.eodsql.Select;
 
@@ -68,7 +70,12 @@ public interface ExperimentQuery extends ObjectQuery
                     + "p.value as propertyValue, m.code as materialPropertyValueCode, mt.code as materialPropertyValueTypeCode, "
                     + "s.perm_id as sample_perm_id, s.id as sample_id, "
                     + "cvt.code as vocabularyPropertyValue, "
-                    + "cv.code as vocabularyPropertyValueTypeCode "
+                    + "cv.code as vocabularyPropertyValueTypeCode, "
+                    + "p.integer_array_value as integerArrayPropertyValue, "
+                    + "p.real_array_value as realArrayPropertyValue, "
+                    + "p.string_array_value as stringArrayPropertyValue, "
+                    + "p.timestamp_array_value as timestampArrayPropertyValue, "
+                    + "p.json_value as jsonPropertyValue "
                     + "from experiment_properties p "
                     + "left join samples s on p.samp_prop_id = s.id "
                     + "left join materials m on p.mate_prop_id = m.id "
@@ -77,7 +84,8 @@ public interface ExperimentQuery extends ObjectQuery
                     + "left join material_types mt on m.maty_id = mt.id "
                     + "join experiment_type_property_types etpt on p.etpt_id = etpt.id "
                     + "join property_types pt on etpt.prty_id = pt.id "
-                    + "where p.expe_id = any(?{1})", parameterBindings = { LongSetMapper.class }, fetchSize = FETCH_SIZE)
+                    + "where p.expe_id = any(?{1})", parameterBindings = { LongSetMapper.class },
+            resultSetBinding = PropertyRecordDataObjectBinding.class, fetchSize = FETCH_SIZE)
     public List<PropertyRecord> getProperties(LongSet experimentIds);
 
     // PropertyQueryGenerator was used to generate this query
@@ -101,11 +109,17 @@ public interface ExperimentQuery extends ObjectQuery
 
     // PropertyQueryGenerator was used to generate this query
     @Select(sql =
-            "select ph.id as id, ph.expe_id as objectId, ph.pers_id_author as authorId, case pt.is_managed_internally when FALSE then pt.code else '$' || pt.code end as propertyCode, ph.value as propertyValue, ph.material as materialPropertyValue, ph.sample as samplePropertyValue, ph.vocabulary_term as vocabularyPropertyValue, ph.valid_from_timestamp as validFrom, ph.valid_until_timestamp as validTo "
+            "select ph.id as id, ph.expe_id as objectId, ph.pers_id_author as authorId, case pt.is_managed_internally when FALSE then pt.code else '$' || pt.code end as propertyCode, ph.value as propertyValue, ph.material as materialPropertyValue, ph.sample as samplePropertyValue, ph.vocabulary_term as vocabularyPropertyValue, ph.valid_from_timestamp as validFrom, ph.valid_until_timestamp as validTo, "
+                    + "ph.integer_array_value as integerArrayPropertyValue, "
+                    + "ph.real_array_value as realArrayPropertyValue, "
+                    + "ph.string_array_value as stringArrayPropertyValue, "
+                    + "ph.timestamp_array_value as timestampArrayPropertyValue, "
+                    + "ph.json_value as jsonPropertyValue "
                     + "from experiment_properties_history ph "
                     + "join experiment_type_property_types etpt on ph.etpt_id = etpt.id "
                     + "join property_types pt on etpt.prty_id = pt.id "
-                    + "where ph.expe_id = any(?{1})", parameterBindings = { LongSetMapper.class }, fetchSize = FETCH_SIZE)
+                    + "where ph.expe_id = any(?{1})", parameterBindings = { LongSetMapper.class },
+            resultSetBinding = HistoryPropertyRecordDataObjectBinding.class, fetchSize = FETCH_SIZE)
     public List<HistoryPropertyRecord> getPropertiesHistory(LongSet experimentIds);
 
     public static final String RELATIONSHIP_HISTORY_QUERY =
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryPropertyRecord.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryPropertyRecord.java
index 94b86c82741..229aa11f9f0 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryPropertyRecord.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryPropertyRecord.java
@@ -33,6 +33,12 @@ public class HistoryPropertyRecord extends HistoryRecord
 
     public String vocabularyPropertyValue;
 
+    public String[] integerArrayPropertyValue;
+    public String[] realArrayPropertyValue;
+    public String[] stringArrayPropertyValue;
+    public String[] timestampArrayPropertyValue;
+    public String jsonPropertyValue;
+
     public String getPropertyCode()
     {
         return propertyCode;
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/PropertyHistoryTranslator.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/PropertyHistoryTranslator.java
index 71a7d39a1c1..8aaf3577cbe 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/PropertyHistoryTranslator.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/PropertyHistoryTranslator.java
@@ -15,16 +15,7 @@
  */
 package ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -83,6 +74,11 @@ public abstract class PropertyHistoryTranslator extends AbstractCachingTranslato
                 currentPropertyRecord.propertyCode = currentProperty.propertyCode;
                 currentPropertyRecord.propertyValue = currentProperty.propertyValue;
                 currentPropertyRecord.samplePropertyValue = currentProperty.sample_perm_id;
+                currentPropertyRecord.integerArrayPropertyValue = currentProperty.integerArrayPropertyValue;
+                currentPropertyRecord.realArrayPropertyValue = currentProperty.realArrayPropertyValue;
+                currentPropertyRecord.stringArrayPropertyValue = currentProperty.stringArrayPropertyValue;
+                currentPropertyRecord.timestampArrayPropertyValue = currentProperty.timestampArrayPropertyValue;
+                currentPropertyRecord.jsonPropertyValue = currentProperty.jsonPropertyValue;
 
                 if (currentProperty.vocabularyPropertyValue != null && currentProperty.vocabularyPropertyValueTypeCode != null)
                 {
@@ -187,7 +183,22 @@ public abstract class PropertyHistoryTranslator extends AbstractCachingTranslato
         } else if (record.samplePropertyValue != null)
         {
             entry.setPropertyValue(record.samplePropertyValue);
-        } else
+        }else if (record.integerArrayPropertyValue != null)
+        {
+            entry.setPropertyValue(convertArrayToString(record.integerArrayPropertyValue));
+        } else if (record.realArrayPropertyValue != null)
+        {
+            entry.setPropertyValue(convertArrayToString(record.realArrayPropertyValue));
+        } else if (record.stringArrayPropertyValue != null)
+        {
+            entry.setPropertyValue(convertArrayToString(record.stringArrayPropertyValue));
+        } else if (record.timestampArrayPropertyValue != null)
+        {
+            entry.setPropertyValue(convertArrayToString(record.timestampArrayPropertyValue));
+        } else if (record.jsonPropertyValue != null)
+        {
+            entry.setPropertyValue(record.jsonPropertyValue);
+        }  else
         {
             throw new IllegalArgumentException("Unexpected property history entry with all values null");
         }
@@ -200,4 +211,8 @@ public abstract class PropertyHistoryTranslator extends AbstractCachingTranslato
         return entry;
     }
 
+    private String convertArrayToString(String[] array) {
+        return Arrays.stream(array).reduce((a,b) -> a + ", " + b).get();
+    }
+
 }
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyRecord.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyRecord.java
index f59955e26b1..a7d77577376 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyRecord.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyRecord.java
@@ -46,5 +46,11 @@ public class PropertyRecord
     public String sample_perm_id;
 
     public Date modificationTimestamp;
+    public String[] integerArrayPropertyValue;
+    public String[] realArrayPropertyValue;
+    public String[] stringArrayPropertyValue;
+    public String[] timestampArrayPropertyValue;
+    public String jsonPropertyValue;
+
 
 }
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyTranslator.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyTranslator.java
index 33ffc10d2de..1118a451c5b 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyTranslator.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyTranslator.java
@@ -15,12 +15,9 @@
  */
 package ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -33,24 +30,29 @@ import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.sample.ISampleAuth
 /**
  * @author pkupczyk
  */
-public abstract class PropertyTranslator extends AbstractCachingTranslator<Long, ObjectHolder<Map<String, String>>, PropertyFetchOptions>
+public abstract class PropertyTranslator extends
+        AbstractCachingTranslator<Long, ObjectHolder<Map<String, String>>, PropertyFetchOptions>
         implements IPropertyTranslator
 {
     @Autowired
     private ISampleAuthorizationValidator sampleAuthorizationValidator;
 
     @Override
-    protected ObjectHolder<Map<String, String>> createObject(TranslationContext context, Long objectId, PropertyFetchOptions fetchOptions)
+    protected ObjectHolder<Map<String, String>> createObject(TranslationContext context,
+            Long objectId, PropertyFetchOptions fetchOptions)
     {
         return new ObjectHolder<Map<String, String>>();
     }
 
     @Override
-    protected Object getObjectsRelations(TranslationContext context, Collection<Long> objectIds, PropertyFetchOptions fetchOptions)
+    protected Object getObjectsRelations(TranslationContext context, Collection<Long> objectIds,
+            PropertyFetchOptions fetchOptions)
     {
         List<PropertyRecord> records = loadProperties(objectIds);
-        Set<Long> visibaleSamples = sampleAuthorizationValidator.validate(context.getSession().tryGetPerson(),
-                records.stream().filter(r -> r.sample_id != null).map(r -> r.sample_id).collect(Collectors.toSet()));
+        Set<Long> visibaleSamples =
+                sampleAuthorizationValidator.validate(context.getSession().tryGetPerson(),
+                        records.stream().filter(r -> r.sample_id != null).map(r -> r.sample_id)
+                                .collect(Collectors.toSet()));
 
         Map<Long, Map<String, String>> properties = new HashMap<Long, Map<String, String>>();
         for (PropertyRecord record : records)
@@ -68,8 +70,9 @@ public abstract class PropertyTranslator extends AbstractCachingTranslator<Long,
                 objectProperties.put(record.propertyCode, record.propertyValue);
             } else if (record.materialPropertyValueCode != null)
             {
-                objectProperties.put(record.propertyCode, record.materialPropertyValueCode + " (" + record.materialPropertyValueTypeCode
-                        + ")");
+                objectProperties.put(record.propertyCode,
+                        record.materialPropertyValueCode + " (" + record.materialPropertyValueTypeCode
+                                + ")");
             } else if (record.vocabularyPropertyValue != null)
             {
                 objectProperties.put(record.propertyCode, record.vocabularyPropertyValue);
@@ -79,6 +82,25 @@ public abstract class PropertyTranslator extends AbstractCachingTranslator<Long,
                 {
                     objectProperties.put(record.propertyCode, record.sample_perm_id);
                 }
+            } else if (record.integerArrayPropertyValue != null)
+            {
+                objectProperties.put(record.propertyCode,
+                        convertArrayToString(record.integerArrayPropertyValue));
+            } else if (record.realArrayPropertyValue != null)
+            {
+                objectProperties.put(record.propertyCode,
+                        convertArrayToString(record.realArrayPropertyValue));
+            } else if (record.stringArrayPropertyValue != null)
+            {
+                objectProperties.put(record.propertyCode,
+                        convertArrayToString(record.stringArrayPropertyValue));
+            } else if (record.timestampArrayPropertyValue != null)
+            {
+                objectProperties.put(record.propertyCode,
+                        convertArrayToString(record.timestampArrayPropertyValue));
+            } else if (record.jsonPropertyValue != null)
+            {
+                objectProperties.put(record.propertyCode, record.jsonPropertyValue);
             } else
             {
                 // SAMPLE property with deleted sample. Thus, nothing is put to objectProperties
@@ -88,9 +110,17 @@ public abstract class PropertyTranslator extends AbstractCachingTranslator<Long,
         return properties;
     }
 
+    private String convertArrayToString(String[] array)
+    {
+        return Stream.of(array)
+                .reduce((x, y) -> x + ", " + y)
+                .get();
+    }
+
     @SuppressWarnings("unchecked")
     @Override
-    protected void updateObject(TranslationContext context, Long objectId, ObjectHolder<Map<String, String>> result, Object relations,
+    protected void updateObject(TranslationContext context, Long objectId,
+            ObjectHolder<Map<String, String>> result, Object relations,
             PropertyFetchOptions fetchOptions)
     {
         Map<Long, Map<String, String>> properties = (Map<Long, Map<String, String>>) relations;
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleQuery.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleQuery.java
index 5d68cf293d5..0b766b36f3e 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleQuery.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleQuery.java
@@ -24,7 +24,10 @@ import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.MaterialP
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.PropertyAssignmentRecord;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.PropertyRecord;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.SamplePropertyRecord;
+import ch.systemsx.cisd.common.db.mapper.LongArrayMapper;
 import ch.systemsx.cisd.common.db.mapper.LongSetMapper;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.common.HistoryPropertyRecordDataObjectBinding;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.common.PropertyRecordDataObjectBinding;
 import it.unimi.dsi.fastutil.longs.LongSet;
 import net.lemnik.eodsql.Select;
 
@@ -66,7 +69,12 @@ public interface SampleQuery extends ObjectQuery
                     + "p.value as propertyValue, m.code as materialPropertyValueCode, mt.code as materialPropertyValueTypeCode, "
                     + "s.perm_id as sample_perm_id, s.id as sample_id, "
                     + "cvt.code as vocabularyPropertyValue, "
-                    + "cv.code as vocabularyPropertyValueTypeCode "
+                    + "cv.code as vocabularyPropertyValueTypeCode, "
+                    + "p.integer_array_value as integerArrayPropertyValue, "
+                    + "p.real_array_value as realArrayPropertyValue, "
+                    + "p.string_array_value as stringArrayPropertyValue, "
+                    + "p.timestamp_array_value as timestampArrayPropertyValue, "
+                    + "p.json_value as jsonPropertyValue "
                     + "from sample_properties p "
                     + "left join samples s on p.samp_prop_id = s.id "
                     + "left join materials m on p.mate_prop_id = m.id "
@@ -75,7 +83,8 @@ public interface SampleQuery extends ObjectQuery
                     + "left join material_types mt on m.maty_id = mt.id "
                     + "join sample_type_property_types etpt on p.stpt_id = etpt.id "
                     + "join property_types pt on etpt.prty_id = pt.id "
-                    + "where p.samp_id = any(?{1})", parameterBindings = { LongSetMapper.class }, fetchSize = FETCH_SIZE)
+                    + "where p.samp_id = any(?{1})", parameterBindings = { LongSetMapper.class },
+            resultSetBinding = PropertyRecordDataObjectBinding.class,  fetchSize = FETCH_SIZE)
     public List<PropertyRecord> getProperties(LongSet sampleIds);
 
     // PropertyQueryGenerator was used to generate this query
@@ -99,11 +108,17 @@ public interface SampleQuery extends ObjectQuery
 
     // PropertyQueryGenerator was used to generate this query
     @Select(sql =
-            "select ph.id as id, ph.samp_id as objectId, ph.pers_id_author as authorId, case pt.is_managed_internally when FALSE then pt.code else '$' || pt.code end as propertyCode, ph.value as propertyValue, ph.material as materialPropertyValue, ph.sample as samplePropertyValue, ph.vocabulary_term as vocabularyPropertyValue, ph.valid_from_timestamp as validFrom, ph.valid_until_timestamp as validTo "
+            "select ph.id as id, ph.samp_id as objectId, ph.pers_id_author as authorId, case pt.is_managed_internally when FALSE then pt.code else '$' || pt.code end as propertyCode, ph.value as propertyValue, ph.material as materialPropertyValue, ph.sample as samplePropertyValue, ph.vocabulary_term as vocabularyPropertyValue, ph.valid_from_timestamp as validFrom, ph.valid_until_timestamp as validTo, "
+                    + "ph.integer_array_value as integerArrayPropertyValue, "
+                    + "ph.real_array_value as realArrayPropertyValue, "
+                    + "ph.string_array_value as stringArrayPropertyValue, "
+                    + "ph.timestamp_array_value as timestampArrayPropertyValue, "
+                    + "ph.json_value as jsonPropertyValue "
                     + "from sample_properties_history ph "
                     + "join sample_type_property_types etpt on ph.stpt_id = etpt.id "
                     + "join property_types pt on etpt.prty_id = pt.id "
-                    + "where ph.samp_id = any(?{1})", parameterBindings = { LongSetMapper.class }, fetchSize = FETCH_SIZE)
+                    + "where ph.samp_id = any(?{1})", parameterBindings = { LongSetMapper.class },
+            resultSetBinding = HistoryPropertyRecordDataObjectBinding.class, fetchSize = FETCH_SIZE)
     public List<HistoryPropertyRecord> getPropertiesHistory(LongSet sampleIds);
 
     public static final String RELATIONSHIPS_HISTORY_QUERY =
diff --git a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/HistoryPropertyRecordDataObjectBinding.java b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/HistoryPropertyRecordDataObjectBinding.java
new file mode 100644
index 00000000000..2ab0553d45e
--- /dev/null
+++ b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/HistoryPropertyRecordDataObjectBinding.java
@@ -0,0 +1,62 @@
+/*
+ *  Copyright ETH 2023 Zürich, Scientific IT Services
+ *
+ *  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 ch.systemsx.cisd.openbis.generic.server.business.bo.common;
+
+import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history.HistoryPropertyRecord;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.PropertyRecord;
+import net.lemnik.eodsql.EoDException;
+import net.lemnik.eodsql.spi.util.NonUpdateCapableDataObjectBinding;
+
+import java.sql.Array;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+
+public class HistoryPropertyRecordDataObjectBinding extends NonUpdateCapableDataObjectBinding<HistoryPropertyRecord>
+{
+    @Override
+    public void unmarshall(ResultSet row, HistoryPropertyRecord into) throws SQLException, EoDException
+    {
+        into.id = row.getLong("id");
+        into.objectId = row.getLong("objectId");
+        into.authorId = row.getLong("authorId");
+        into.propertyCode = row.getString("propertyCode");
+        into.propertyValue = row.getString("propertyValue");
+        into.materialPropertyValue = row.getString("materialPropertyValue");
+        into.samplePropertyValue = row.getString("samplePropertyValue");
+        into.vocabularyPropertyValue = row.getString("vocabularyPropertyValue");
+        into.validFrom = row.getTimestamp("validFrom");
+        into.validTo = row.getTimestamp("validTo");
+
+        into.integerArrayPropertyValue = convertToStringArray(row.getArray("integerArrayPropertyValue"));
+        into.realArrayPropertyValue = convertToStringArray(row.getArray("realArrayPropertyValue"));
+        into.stringArrayPropertyValue = convertToStringArray(row.getArray("stringArrayPropertyValue"));
+        into.timestampArrayPropertyValue = convertToStringArray(row.getArray("timestampArrayPropertyValue"));
+        into.jsonPropertyValue = row.getString("jsonPropertyValue");
+    }
+
+    private String[] convertToStringArray(Array array) throws SQLException {
+        if(array != null) {
+            Object[] values = (Object[]) array.getArray();
+            return Arrays.stream(values)
+                    .map(Object::toString)
+                    .toArray(String[]::new);
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/PropertyRecordDataObjectBinding.java b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/PropertyRecordDataObjectBinding.java
new file mode 100644
index 00000000000..07df7307e0d
--- /dev/null
+++ b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/PropertyRecordDataObjectBinding.java
@@ -0,0 +1,64 @@
+/*
+ *  Copyright ETH 2023 Zürich, Scientific IT Services
+ *
+ *  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 ch.systemsx.cisd.openbis.generic.server.business.bo.common;
+
+import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.PropertyRecord;
+import net.lemnik.eodsql.EoDException;
+import net.lemnik.eodsql.spi.util.NonUpdateCapableDataObjectBinding;
+
+import java.sql.Array;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+
+public class PropertyRecordDataObjectBinding
+        extends NonUpdateCapableDataObjectBinding<PropertyRecord>
+{
+    @Override
+    public void unmarshall(ResultSet row, PropertyRecord into) throws SQLException, EoDException
+    {
+        into.id = row.getLong("id");
+        into.objectId = row.getLong("objectId");
+        into.authorId = row.getLong("authorId");
+        into.propertyCode = row.getString("propertyCode");
+        into.propertyValue = row.getString("propertyValue");
+        into.materialPropertyValueCode = row.getString("materialPropertyValueCode");
+        into.materialPropertyValueTypeCode = row.getString("materialPropertyValueTypeCode");
+        into.vocabularyPropertyValue = row.getString("vocabularyPropertyValue");
+        into.vocabularyPropertyValueTypeCode = row.getString("vocabularyPropertyValueTypeCode");
+        into.sample_id = row.getLong("sample_id");
+        into.sample_perm_id = row.getString("sample_perm_id");
+        into.modificationTimestamp = row.getTimestamp("modificationTimestamp");
+
+        into.integerArrayPropertyValue = convertToStringArray(row.getArray("integerArrayPropertyValue"));
+        into.realArrayPropertyValue = convertToStringArray(row.getArray("realArrayPropertyValue"));
+        into.stringArrayPropertyValue = convertToStringArray(row.getArray("stringArrayPropertyValue"));
+        into.timestampArrayPropertyValue = convertToStringArray(row.getArray("timestampArrayPropertyValue"));
+        into.jsonPropertyValue = row.getString("jsonPropertyValue");
+    }
+
+    private String[] convertToStringArray(Array array) throws SQLException {
+        if(array != null) {
+            Object[] values = (Object[]) array.getArray();
+            return Arrays.stream(values)
+                    .map(Object::toString)
+                    .toArray(String[]::new);
+        }
+        return null;
+    }
+}
diff --git a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/PropertyValidator.java b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/PropertyValidator.java
index 41774d973e7..1c4878f906d 100644
--- a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/PropertyValidator.java
+++ b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/PropertyValidator.java
@@ -153,9 +153,7 @@ public final class PropertyValidator implements IPropertyValueValidator
             {
                 return null;
             }
-
             //TODO: implement validation for json
-            System.out.println("||> validate json:" + value);
             return value;
         }
     }
@@ -177,18 +175,7 @@ public final class PropertyValidator implements IPropertyValueValidator
             {
                 return null;
             }
-            System.out.println("||> validate array:" + arrayType + " " + value);
-            //TODO: implement validation for array
-            switch (arrayType) {
-                case ARRAY_INTEGER:
-                    break;
-                case ARRAY_REAL:
-                    break;
-                case ARRAY_STRING:
-                    break;
-                case ARRAY_TIMESTAMP:
-                    break;
-            }
+            //TODO: implement validation for array types
             return value;
         }
     }
diff --git a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/EntityPropertyPE.java b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/EntityPropertyPE.java
index e16601608fc..0b4f68b19ed 100644
--- a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/EntityPropertyPE.java
+++ b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/EntityPropertyPE.java
@@ -15,12 +15,13 @@
  */
 package ch.systemsx.cisd.openbis.generic.shared.dto;
 
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.stream.Stream;
 
 import javax.persistence.*;
 
-import ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.JsonMapUserType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.types.*;
 import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -168,7 +169,7 @@ public abstract class EntityPropertyPE extends HibernateAbstractRegistrationHold
         this.material = material;
     }
 
-    @Column(name = ColumnNames.INTEGER_ARRAY_VALUE_COLUMN, columnDefinition = "long_value[]")
+    @Column(name = ColumnNames.INTEGER_ARRAY_VALUE_COLUMN)
     @Type(type = "long_array_type")
     public Long[] getIntegerArrayValue()
     {
@@ -343,7 +344,7 @@ public abstract class EntityPropertyPE extends HibernateAbstractRegistrationHold
             if (getRealArrayValue() != null)
                 return convertArrayToString(this.realArrayValue);
             if (getTimestampArrayValue() != null)
-                return convertArrayToString(this.timestampArrayValue);
+                return convertTimestampArrayToString(this.timestampArrayValue);
             if (getStringArrayValue() != null)
                 return convertArrayToString(this.stringArrayValue);
             if (getJsonValue() != null)
@@ -352,6 +353,16 @@ public abstract class EntityPropertyPE extends HibernateAbstractRegistrationHold
         }
     }
 
+    private String convertTimestampArrayToString(Date[] array) {
+        if (array == null || array.length == 0)
+            return "";
+        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+        return Stream.of(array)
+                .map(dateFormat::format)
+                .reduce((x, y) -> x + ", " + y)
+                .get();
+    }
+
     private String convertArrayToString(Object[] array) {
         if (array == null || array.length == 0)
             return "";
diff --git a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/types/TimestampArrayType.java b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/types/TimestampArrayType.java
index fd959884ea3..79a45046dba 100644
--- a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/types/TimestampArrayType.java
+++ b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/types/TimestampArrayType.java
@@ -62,7 +62,6 @@ public class TimestampArrayType implements UserType
         Array array = rs.getArray(names[0]);
         if (array != null)
         {
-            System.out.println("||> ARRAY_TIMESTAMPS:" + array);
             Object[] values = (Object[]) array.getArray();
             return Arrays.stream(values)
                     .map(Object::toString)
diff --git a/server-application-server/source/sql/generic/191/schema-191.sql b/server-application-server/source/sql/generic/191/schema-191.sql
index 8f296849a0b..7e78f1ba7a6 100644
--- a/server-application-server/source/sql/generic/191/schema-191.sql
+++ b/server-application-server/source/sql/generic/191/schema-191.sql
@@ -39,8 +39,8 @@ CREATE TABLE SAMPLE_PROPERTIES_HISTORY (ID TECH_ID NOT NULL, SAMP_ID TECH_ID NOT
 CREATE TABLE SAMPLE_TYPES (ID TECH_ID NOT NULL,CODE CODE NOT NULL,DESCRIPTION DESCRIPTION_2000, IS_LISTABLE BOOLEAN_CHAR NOT NULL DEFAULT 'T', GENERATED_FROM_DEPTH INTEGER NOT NULL DEFAULT 0, PART_OF_DEPTH INTEGER NOT NULL DEFAULT 0, MODIFICATION_TIMESTAMP TIME_STAMP DEFAULT CURRENT_TIMESTAMP, is_auto_generated_code BOOLEAN_CHAR NOT NULL DEFAULT 'F', generated_code_prefix CODE NOT NULL DEFAULT 'S', is_subcode_unique BOOLEAN_CHAR NOT NULL DEFAULT 'F', INHERIT_PROPERTIES BOOLEAN_CHAR NOT NULL DEFAULT 'F', VALIDATION_SCRIPT_ID TECH_ID, SHOW_PARENT_METADATA BOOLEAN_CHAR NOT NULL DEFAULT 'F');
 CREATE TABLE SAMPLE_TYPE_PROPERTY_TYPES (ID TECH_ID NOT NULL,SATY_ID TECH_ID NOT NULL,PRTY_ID TECH_ID NOT NULL,IS_MANDATORY BOOLEAN_CHAR NOT NULL DEFAULT 'F',IS_MANAGED_INTERNALLY BOOLEAN_CHAR NOT NULL DEFAULT 'F',PERS_ID_REGISTERER TECH_ID NOT NULL,REGISTRATION_TIMESTAMP TIME_STAMP_DFL NOT NULL DEFAULT CURRENT_TIMESTAMP, IS_DISPLAYED BOOLEAN_CHAR NOT NULL DEFAULT 'T', ORDINAL ORDINAL_INT NOT NULL, SECTION DESCRIPTION_2000,SCRIPT_ID TECH_ID,IS_SHOWN_EDIT BOOLEAN_CHAR NOT NULL DEFAULT 'T',SHOW_RAW_VALUE BOOLEAN_CHAR NOT NULL DEFAULT 'F', IS_UNIQUE BOOLEAN_CHAR NOT NULL DEFAULT 'F');
 
-CREATE TABLE DATA_SET_PROPERTIES (ID TECH_ID NOT NULL,DS_ID TECH_ID NOT NULL,DSTPT_ID TECH_ID NOT NULL,VALUE TEXT_VALUE,CVTE_ID TECH_ID, MATE_PROP_ID TECH_ID, SAMP_PROP_ID TECH_ID, PERS_ID_REGISTERER TECH_ID NOT NULL, REGISTRATION_TIMESTAMP TIME_STAMP_DFL NOT NULL DEFAULT CURRENT_TIMESTAMP, PERS_ID_AUTHOR TECH_ID NOT NULL, MODIFICATION_TIMESTAMP TIME_STAMP DEFAULT CURRENT_TIMESTAMP, DASE_FROZEN BOOLEAN_CHAR NOT NULL DEFAULT 'F', TSVECTOR_DOCUMENT TSVECTOR NOT NULL, IS_UNIQUE BOOLEAN_CHAR NOT NULL DEFAULT 'F');
-CREATE TABLE DATA_SET_PROPERTIES_HISTORY (ID TECH_ID NOT NULL, DS_ID TECH_ID NOT NULL, DSTPT_ID TECH_ID NOT NULL, VALUE TEXT_VALUE, VOCABULARY_TERM IDENTIFIER, MATERIAL IDENTIFIER, SAMPLE IDENTIFIER, PERS_ID_AUTHOR TECH_ID NOT NULL, VALID_FROM_TIMESTAMP TIME_STAMP NOT NULL, VALID_UNTIL_TIMESTAMP TIME_STAMP DEFAULT CURRENT_TIMESTAMP);
+CREATE TABLE DATA_SET_PROPERTIES (ID TECH_ID NOT NULL,DS_ID TECH_ID NOT NULL,DSTPT_ID TECH_ID NOT NULL,VALUE TEXT_VALUE,CVTE_ID TECH_ID, MATE_PROP_ID TECH_ID, SAMP_PROP_ID TECH_ID, PERS_ID_REGISTERER TECH_ID NOT NULL, REGISTRATION_TIMESTAMP TIME_STAMP_DFL NOT NULL DEFAULT CURRENT_TIMESTAMP, PERS_ID_AUTHOR TECH_ID NOT NULL, MODIFICATION_TIMESTAMP TIME_STAMP DEFAULT CURRENT_TIMESTAMP, DASE_FROZEN BOOLEAN_CHAR NOT NULL DEFAULT 'F', TSVECTOR_DOCUMENT TSVECTOR NOT NULL, IS_UNIQUE BOOLEAN_CHAR NOT NULL DEFAULT 'F', INTEGER_ARRAY_VALUE LONG_VALUE[], REAL_ARRAY_VALUE DOUBLE_VALUE[], STRING_ARRAY_VALUE TEXT_VALUE[], TIMESTAMP_ARRAY_VALUE TIME_STAMP[], JSON_VALUE JSONB);
+CREATE TABLE DATA_SET_PROPERTIES_HISTORY (ID TECH_ID NOT NULL, DS_ID TECH_ID NOT NULL, DSTPT_ID TECH_ID NOT NULL, VALUE TEXT_VALUE, VOCABULARY_TERM IDENTIFIER, MATERIAL IDENTIFIER, SAMPLE IDENTIFIER, PERS_ID_AUTHOR TECH_ID NOT NULL, VALID_FROM_TIMESTAMP TIME_STAMP NOT NULL, VALID_UNTIL_TIMESTAMP TIME_STAMP DEFAULT CURRENT_TIMESTAMP, INTEGER_ARRAY_VALUE LONG_VALUE[], REAL_ARRAY_VALUE DOUBLE_VALUE[], STRING_ARRAY_VALUE TEXT_VALUE[], TIMESTAMP_ARRAY_VALUE TIME_STAMP[], JSON_VALUE JSONB);
 CREATE TABLE DATA_SET_TYPE_PROPERTY_TYPES (ID TECH_ID NOT NULL,DSTY_ID TECH_ID NOT NULL,PRTY_ID TECH_ID NOT NULL,IS_MANDATORY BOOLEAN_CHAR NOT NULL DEFAULT 'F',IS_MANAGED_INTERNALLY BOOLEAN_CHAR NOT NULL DEFAULT 'F',PERS_ID_REGISTERER TECH_ID NOT NULL,REGISTRATION_TIMESTAMP TIME_STAMP_DFL NOT NULL DEFAULT CURRENT_TIMESTAMP, ORDINAL ORDINAL_INT NOT NULL, SECTION DESCRIPTION_2000,SCRIPT_ID TECH_ID, IS_SHOWN_EDIT BOOLEAN_CHAR NOT NULL DEFAULT 'T',SHOW_RAW_VALUE BOOLEAN_CHAR NOT NULL DEFAULT 'F', IS_UNIQUE BOOLEAN_CHAR NOT NULL DEFAULT 'F');
 
 CREATE TABLE AUTHORIZATION_GROUPS (ID TECH_ID NOT NULL, CODE CODE NOT NULL, DESCRIPTION DESCRIPTION_2000,REGISTRATION_TIMESTAMP TIME_STAMP_DFL NOT NULL DEFAULT CURRENT_TIMESTAMP, PERS_ID_REGISTERER TECH_ID NOT NULL, MODIFICATION_TIMESTAMP TIME_STAMP DEFAULT CURRENT_TIMESTAMP);
@@ -199,7 +199,12 @@ CREATE VIEW sample_history_view AS (
     null as sample,
     pers_id_author,
     valid_from_timestamp,
-    valid_until_timestamp
+    valid_until_timestamp,
+    null as integer_array_value,
+    null as real_array_value,
+    null as string_array_value,
+    null as timestamp_array_value,
+    null as json_value
   FROM
     SAMPLE_RELATIONSHIPS_HISTORY
   WHERE
@@ -224,7 +229,12 @@ UNION
     sample,
     pers_id_author,
     valid_from_timestamp,
-    valid_until_timestamp
+    valid_until_timestamp,
+    integer_array_value,
+    real_array_value,
+    string_array_value,
+    timestamp_array_value,
+    json_value
   FROM
     SAMPLE_PROPERTIES_HISTORY;
     
@@ -254,7 +264,12 @@ CREATE VIEW data_set_history_view AS (
     null as edms_address,
     pers_id_author,
     valid_from_timestamp,
-    valid_until_timestamp
+    valid_until_timestamp,
+    null as integer_array_value,
+    null as real_array_value,
+    null as string_array_value,
+    null as timestamp_array_value,
+    null as json_value
   FROM
     data_set_relationships_history
   WHERE
@@ -285,7 +300,12 @@ UNION
     null as edms_address,
     pers_id_author,
     valid_from_timestamp,
-    valid_until_timestamp
+    valid_until_timestamp,
+    integer_array_value,
+    real_array_value,
+    string_array_value,
+    timestamp_array_value,
+    json_value
   FROM
     data_set_properties_history
  UNION
@@ -314,7 +334,12 @@ UNION
     edms_address,
     pers_id_author,
     valid_from_timestamp,
-    valid_until_timestamp
+    valid_until_timestamp,
+    null as integer_array_value,
+    null as real_array_value,
+    null as string_array_value,
+    null as timestamp_array_value,
+    null as json_value
   FROM
     data_set_copies_history
   WHERE
@@ -337,7 +362,12 @@ CREATE VIEW experiment_history_view AS (
     null as sample,
     pers_id_author,
     valid_from_timestamp,
-    valid_until_timestamp
+    valid_until_timestamp,
+    null as integer_array_value,
+    null as real_array_value,
+    null as string_array_value,
+    null as timestamp_array_value,
+    null as json_value
   FROM
     EXPERIMENT_RELATIONSHIPS_HISTORY
   WHERE valid_until_timestamp IS NOT NULL)
@@ -358,7 +388,12 @@ UNION
     sample,
     pers_id_author,
     valid_from_timestamp,
-    valid_until_timestamp
+    valid_until_timestamp,
+    integer_array_value,
+    real_array_value,
+    string_array_value,
+    timestamp_array_value,
+    json_value
   FROM
     EXPERIMENT_PROPERTIES_HISTORY;
 
@@ -772,28 +807,38 @@ ALTER TABLE EXPERIMENT_PROPERTIES ADD CONSTRAINT EXPR_CK CHECK
      (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NOT NULL)
     );
 ALTER TABLE EXPERIMENT_PROPERTIES_HISTORY ADD CONSTRAINT EXPRH_CK CHECK
-    ((VALUE IS NOT NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL) OR
-     (VALUE IS NULL AND VOCABULARY_TERM IS NOT NULL AND MATERIAL IS NULL AND SAMPLE IS NULL) OR
-     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NOT NULL AND SAMPLE IS NULL) OR
-     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NOT NULL)
+    ((VALUE IS NOT NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NOT NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NOT NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NOT NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NOT NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NOT NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NOT NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NOT NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NOT NULL)
     );
 
 ALTER TABLE SAMPLE_PROPERTIES ADD CONSTRAINT SAPR_CK CHECK 
     ((VALUE IS NOT NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
-         (VALUE IS NULL AND CVTE_ID IS NOT NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
-         (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NOT NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
-         (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NOT NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
-         (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NOT NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
-         (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NOT NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
-         (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NOT NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
-         (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NOT NULL AND JSON_VALUE IS NULL) OR
-         (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NOT NULL)
-        );
+     (VALUE IS NULL AND CVTE_ID IS NOT NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NOT NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NOT NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NOT NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NOT NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NOT NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NOT NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NOT NULL)
+    );
 ALTER TABLE SAMPLE_PROPERTIES_HISTORY ADD CONSTRAINT SAPRH_CK CHECK
-    ((VALUE IS NOT NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL) OR 
-     (VALUE IS NULL AND VOCABULARY_TERM IS NOT NULL AND MATERIAL IS NULL AND SAMPLE IS NULL) OR
-     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NOT NULL AND SAMPLE IS NULL) OR
-     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NOT NULL)
+    ((VALUE IS NOT NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NOT NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NOT NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NOT NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NOT NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NOT NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NOT NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NOT NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NOT NULL)
     );
 ALTER TABLE MATERIAL_PROPERTIES ADD CONSTRAINT MAPR_CK CHECK 
 	((VALUE IS NOT NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL) OR 
@@ -806,16 +851,26 @@ ALTER TABLE MATERIAL_PROPERTIES_HISTORY ADD CONSTRAINT MAPRH_CK CHECK
 	 (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NOT NULL)
 	);
 ALTER TABLE DATA_SET_PROPERTIES ADD CONSTRAINT DSPR_CK CHECK 
-    ((VALUE IS NOT NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL) OR
-     (VALUE IS NULL AND CVTE_ID IS NOT NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL) OR
-     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NOT NULL AND SAMP_PROP_ID IS NULL) OR
-     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NOT NULL)
+    ((VALUE IS NOT NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NOT NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NOT NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NOT NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NOT NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NOT NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NOT NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NOT NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND CVTE_ID IS NULL AND MATE_PROP_ID IS NULL AND SAMP_PROP_ID IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NOT NULL)
     );
 ALTER TABLE DATA_SET_PROPERTIES_HISTORY ADD CONSTRAINT DSPRH_CK CHECK
-    ((VALUE IS NOT NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL) OR
-     (VALUE IS NULL AND VOCABULARY_TERM IS NOT NULL AND MATERIAL IS NULL AND SAMPLE IS NULL) OR
-     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NOT NULL AND SAMPLE IS NULL) OR
-     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NOT NULL)
+    ((VALUE IS NOT NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NOT NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NOT NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NOT NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NOT NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NOT NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NOT NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NOT NULL AND JSON_VALUE IS NULL) OR
+     (VALUE IS NULL AND VOCABULARY_TERM IS NULL AND MATERIAL IS NULL AND SAMPLE IS NULL AND INTEGER_ARRAY_VALUE IS NULL AND REAL_ARRAY_VALUE IS NULL AND TIMESTAMP_ARRAY_VALUE IS NULL AND STRING_ARRAY_VALUE IS NULL AND JSON_VALUE IS NOT NULL)
     );
 ALTER TABLE ATTACHMENTS ADD CONSTRAINT ATTA_ARC_CK CHECK 
 	((EXPE_ID IS NOT NULL AND PROJ_ID IS NULL AND SAMP_ID IS NULL) OR 
diff --git a/server-application-server/source/sql/postgresql/191/function-191.sql b/server-application-server/source/sql/postgresql/191/function-191.sql
index dbf79a93c63..21a69fc4889 100644
--- a/server-application-server/source/sql/postgresql/191/function-191.sql
+++ b/server-application-server/source/sql/postgresql/191/function-191.sql
@@ -999,6 +999,11 @@ CREATE OR REPLACE RULE experiment_properties_update AS
         OR (OLD.CVTE_ID IS NOT NULL AND OLD.CVTE_ID != NEW.CVTE_ID)
         OR (OLD.MATE_PROP_ID IS NOT NULL AND OLD.MATE_PROP_ID != NEW.MATE_PROP_ID)
         OR (OLD.SAMP_PROP_ID IS NOT NULL AND OLD.SAMP_PROP_ID != NEW.SAMP_PROP_ID)
+        OR (OLD.INTEGER_ARRAY_VALUE IS NOT NULL AND OLD.INTEGER_ARRAY_VALUE != NEW.INTEGER_ARRAY_VALUE)
+        OR (OLD.REAL_ARRAY_VALUE IS NOT NULL AND OLD.REAL_ARRAY_VALUE != NEW.REAL_ARRAY_VALUE)
+        OR (OLD.STRING_ARRAY_VALUE IS NOT NULL AND OLD.STRING_ARRAY_VALUE != NEW.STRING_ARRAY_VALUE)
+        OR (OLD.TIMESTAMP_ARRAY_VALUE IS NOT NULL AND OLD.TIMESTAMP_ARRAY_VALUE != NEW.TIMESTAMP_ARRAY_VALUE)
+        OR (OLD.JSON_VALUE IS NOT NULL AND OLD.JSON_VALUE != NEW.JSON_VALUE)
     DO ALSO
        INSERT INTO experiment_properties_history (
          ID,
@@ -1010,7 +1015,12 @@ CREATE OR REPLACE RULE experiment_properties_update AS
          SAMPLE,
          PERS_ID_AUTHOR,
          VALID_FROM_TIMESTAMP,
-         VALID_UNTIL_TIMESTAMP
+         VALID_UNTIL_TIMESTAMP,
+         INTEGER_ARRAY_VALUE,
+         REAL_ARRAY_VALUE,
+         STRING_ARRAY_VALUE,
+         TIMESTAMP_ARRAY_VALUE,
+         JSON_VALUE
        ) VALUES (
          nextval('EXPERIMENT_PROPERTY_ID_SEQ'),
          OLD.EXPE_ID,
@@ -1021,7 +1031,12 @@ CREATE OR REPLACE RULE experiment_properties_update AS
          (select perm_id from samples_all where id = OLD.SAMP_PROP_ID),
          OLD.PERS_ID_AUTHOR,
          OLD.MODIFICATION_TIMESTAMP,
-         NEW.MODIFICATION_TIMESTAMP
+         NEW.MODIFICATION_TIMESTAMP,
+         OLD.INTEGER_ARRAY_VALUE,
+         OLD.REAL_ARRAY_VALUE,
+         OLD.STRING_ARRAY_VALUE,
+         OLD.TIMESTAMP_ARRAY_VALUE,
+         OLD.JSON_VALUE
        );
 
 CREATE OR REPLACE RULE experiment_properties_delete AS
@@ -1030,6 +1045,11 @@ CREATE OR REPLACE RULE experiment_properties_delete AS
         OR OLD.CVTE_ID IS NOT NULL
         OR OLD.MATE_PROP_ID IS NOT NULL
         OR OLD.SAMP_PROP_ID IS NOT NULL
+        OR OLD.INTEGER_ARRAY_VALUE IS NOT NULL
+        OR OLD.REAL_ARRAY_VALUE IS NOT NULL
+        OR OLD.STRING_ARRAY_VALUE IS NOT NULL
+        OR OLD.TIMESTAMP_ARRAY_VALUE IS NOT NULL
+        OR OLD.JSON_VALUE IS NOT NULL
     DO ALSO
        INSERT INTO experiment_properties_history (
          ID,
@@ -1041,7 +1061,12 @@ CREATE OR REPLACE RULE experiment_properties_delete AS
          SAMPLE,
          PERS_ID_AUTHOR,
          VALID_FROM_TIMESTAMP,
-         VALID_UNTIL_TIMESTAMP
+         VALID_UNTIL_TIMESTAMP,
+         INTEGER_ARRAY_VALUE,
+         REAL_ARRAY_VALUE,
+         STRING_ARRAY_VALUE,
+         TIMESTAMP_ARRAY_VALUE,
+         JSON_VALUE
        ) VALUES (
          nextval('EXPERIMENT_PROPERTY_ID_SEQ'),
          OLD.EXPE_ID,
@@ -1052,7 +1077,12 @@ CREATE OR REPLACE RULE experiment_properties_delete AS
          (select perm_id from samples_all where id = OLD.SAMP_PROP_ID),
          OLD.PERS_ID_AUTHOR,
          OLD.MODIFICATION_TIMESTAMP,
-         current_timestamp
+         current_timestamp,
+         OLD.INTEGER_ARRAY_VALUE,
+         OLD.REAL_ARRAY_VALUE,
+         OLD.STRING_ARRAY_VALUE,
+         OLD.TIMESTAMP_ARRAY_VALUE,
+         OLD.JSON_VALUE
        );
 
 -- Sample Properties --
@@ -1064,6 +1094,11 @@ CREATE OR REPLACE RULE sample_properties_update AS
         OR (OLD.CVTE_ID IS NOT NULL AND OLD.CVTE_ID != NEW.CVTE_ID)
         OR (OLD.MATE_PROP_ID IS NOT NULL AND OLD.MATE_PROP_ID != NEW.MATE_PROP_ID)
         OR (OLD.SAMP_PROP_ID IS NOT NULL AND OLD.SAMP_PROP_ID != NEW.SAMP_PROP_ID)
+        OR (OLD.INTEGER_ARRAY_VALUE IS NOT NULL AND OLD.INTEGER_ARRAY_VALUE != NEW.INTEGER_ARRAY_VALUE)
+        OR (OLD.REAL_ARRAY_VALUE IS NOT NULL AND OLD.REAL_ARRAY_VALUE != NEW.REAL_ARRAY_VALUE)
+        OR (OLD.STRING_ARRAY_VALUE IS NOT NULL AND OLD.STRING_ARRAY_VALUE != NEW.STRING_ARRAY_VALUE)
+        OR (OLD.TIMESTAMP_ARRAY_VALUE IS NOT NULL AND OLD.TIMESTAMP_ARRAY_VALUE != NEW.TIMESTAMP_ARRAY_VALUE)
+        OR (OLD.JSON_VALUE IS NOT NULL AND OLD.JSON_VALUE != NEW.JSON_VALUE)
     DO ALSO
        INSERT INTO sample_properties_history (
          ID,
@@ -1075,7 +1110,12 @@ CREATE OR REPLACE RULE sample_properties_update AS
          SAMPLE,
          PERS_ID_AUTHOR,
          VALID_FROM_TIMESTAMP,
-         VALID_UNTIL_TIMESTAMP
+         VALID_UNTIL_TIMESTAMP,
+         INTEGER_ARRAY_VALUE,
+         REAL_ARRAY_VALUE,
+         STRING_ARRAY_VALUE,
+         TIMESTAMP_ARRAY_VALUE,
+         JSON_VALUE
        ) VALUES (
          nextval('SAMPLE_PROPERTY_ID_SEQ'),
          OLD.SAMP_ID,
@@ -1086,14 +1126,24 @@ CREATE OR REPLACE RULE sample_properties_update AS
          (select perm_id from samples_all where id = OLD.SAMP_PROP_ID),
          OLD.PERS_ID_AUTHOR,
          OLD.MODIFICATION_TIMESTAMP,
-         NEW.MODIFICATION_TIMESTAMP
+         NEW.MODIFICATION_TIMESTAMP,
+         OLD.INTEGER_ARRAY_VALUE,
+         OLD.REAL_ARRAY_VALUE,
+         OLD.STRING_ARRAY_VALUE,
+         OLD.TIMESTAMP_ARRAY_VALUE,
+         OLD.JSON_VALUE
        );
 CREATE OR REPLACE RULE sample_properties_delete AS
     ON DELETE TO sample_properties
     WHERE ((OLD.VALUE IS NOT NULL AND decode(replace(substring(OLD.value from 1 for 1), '\', '\\'), 'escape') != E'\\xefbfbd')
         OR OLD.CVTE_ID IS NOT NULL
         OR OLD.MATE_PROP_ID IS NOT NULL
-        OR OLD.SAMP_PROP_ID IS NOT NULL)
+        OR OLD.SAMP_PROP_ID IS NOT NULL
+        OR OLD.INTEGER_ARRAY_VALUE IS NOT NULL
+        OR OLD.REAL_ARRAY_VALUE IS NOT NULL
+        OR OLD.STRING_ARRAY_VALUE IS NOT NULL
+        OR OLD.TIMESTAMP_ARRAY_VALUE IS NOT NULL
+        OR OLD.JSON_VALUE IS NOT NULL)
        AND (SELECT DEL_ID FROM SAMPLES_ALL WHERE ID = OLD.SAMP_ID) IS NULL
      DO ALSO
        INSERT INTO sample_properties_history (
@@ -1106,7 +1156,12 @@ CREATE OR REPLACE RULE sample_properties_delete AS
          SAMPLE,
          PERS_ID_AUTHOR,
          VALID_FROM_TIMESTAMP,
-         VALID_UNTIL_TIMESTAMP
+         VALID_UNTIL_TIMESTAMP,
+         INTEGER_ARRAY_VALUE,
+         REAL_ARRAY_VALUE,
+         STRING_ARRAY_VALUE,
+         TIMESTAMP_ARRAY_VALUE,
+         JSON_VALUE
        ) VALUES (
          nextval('SAMPLE_PROPERTY_ID_SEQ'),
          OLD.SAMP_ID,
@@ -1117,7 +1172,12 @@ CREATE OR REPLACE RULE sample_properties_delete AS
          (select perm_id from samples_all where id = OLD.SAMP_PROP_ID),
          OLD.PERS_ID_AUTHOR,
          OLD.MODIFICATION_TIMESTAMP,
-         current_timestamp
+         current_timestamp,
+         OLD.INTEGER_ARRAY_VALUE,
+         OLD.REAL_ARRAY_VALUE,
+         OLD.STRING_ARRAY_VALUE,
+         OLD.TIMESTAMP_ARRAY_VALUE,
+         OLD.JSON_VALUE
        );
 
 
@@ -1129,6 +1189,11 @@ CREATE OR REPLACE RULE data_set_properties_update AS
         OR (OLD.CVTE_ID IS NOT NULL AND OLD.CVTE_ID != NEW.CVTE_ID)
         OR (OLD.MATE_PROP_ID IS NOT NULL AND OLD.MATE_PROP_ID != NEW.MATE_PROP_ID)
         OR (OLD.SAMP_PROP_ID IS NOT NULL AND OLD.SAMP_PROP_ID != NEW.SAMP_PROP_ID)
+        OR (OLD.INTEGER_ARRAY_VALUE IS NOT NULL AND OLD.INTEGER_ARRAY_VALUE != NEW.INTEGER_ARRAY_VALUE)
+        OR (OLD.REAL_ARRAY_VALUE IS NOT NULL AND OLD.REAL_ARRAY_VALUE != NEW.REAL_ARRAY_VALUE)
+        OR (OLD.STRING_ARRAY_VALUE IS NOT NULL AND OLD.STRING_ARRAY_VALUE != NEW.STRING_ARRAY_VALUE)
+        OR (OLD.TIMESTAMP_ARRAY_VALUE IS NOT NULL AND OLD.TIMESTAMP_ARRAY_VALUE != NEW.TIMESTAMP_ARRAY_VALUE)
+        OR (OLD.JSON_VALUE IS NOT NULL AND OLD.JSON_VALUE != NEW.JSON_VALUE)
     DO ALSO
        INSERT INTO data_set_properties_history (
          ID,
@@ -1140,7 +1205,12 @@ CREATE OR REPLACE RULE data_set_properties_update AS
          SAMPLE,
          PERS_ID_AUTHOR,
          VALID_FROM_TIMESTAMP,
-         VALID_UNTIL_TIMESTAMP
+         VALID_UNTIL_TIMESTAMP,
+         INTEGER_ARRAY_VALUE,
+         REAL_ARRAY_VALUE,
+         STRING_ARRAY_VALUE,
+         TIMESTAMP_ARRAY_VALUE,
+         JSON_VALUE
        ) VALUES (
          nextval('DATA_SET_PROPERTY_ID_SEQ'),
          OLD.DS_ID,
@@ -1151,7 +1221,12 @@ CREATE OR REPLACE RULE data_set_properties_update AS
          (select perm_id from samples_all where id = OLD.SAMP_PROP_ID),
          OLD.PERS_ID_AUTHOR,
          OLD.MODIFICATION_TIMESTAMP,
-         NEW.MODIFICATION_TIMESTAMP
+         NEW.MODIFICATION_TIMESTAMP,
+         OLD.INTEGER_ARRAY_VALUE,
+         OLD.REAL_ARRAY_VALUE,
+         OLD.STRING_ARRAY_VALUE,
+         OLD.TIMESTAMP_ARRAY_VALUE,
+         OLD.JSON_VALUE
        );
 
 CREATE OR REPLACE RULE data_set_properties_delete AS
@@ -1159,7 +1234,12 @@ CREATE OR REPLACE RULE data_set_properties_delete AS
     WHERE ((OLD.VALUE IS NOT NULL AND decode(replace(substring(OLD.value from 1 for 1), '\', '\\'), 'escape') != E'\\xefbfbd')
         OR OLD.CVTE_ID IS NOT NULL
         OR OLD.MATE_PROP_ID IS NOT NULL
-        OR OLD.SAMP_PROP_ID IS NOT NULL)
+        OR OLD.SAMP_PROP_ID IS NOT NULL
+        OR OLD.INTEGER_ARRAY_VALUE IS NOT NULL
+        OR OLD.REAL_ARRAY_VALUE IS NOT NULL
+        OR OLD.STRING_ARRAY_VALUE IS NOT NULL
+        OR OLD.TIMESTAMP_ARRAY_VALUE IS NOT NULL
+        OR OLD.JSON_VALUE IS NOT NULL)
 	   AND (SELECT DEL_ID FROM DATA_ALL WHERE ID = OLD.DS_ID) IS NULL
     DO ALSO
        INSERT INTO data_set_properties_history (
@@ -1172,7 +1252,12 @@ CREATE OR REPLACE RULE data_set_properties_delete AS
          SAMPLE,
          PERS_ID_AUTHOR,
          VALID_FROM_TIMESTAMP,
-         VALID_UNTIL_TIMESTAMP
+         VALID_UNTIL_TIMESTAMP,
+         INTEGER_ARRAY_VALUE,
+         REAL_ARRAY_VALUE,
+         STRING_ARRAY_VALUE,
+         TIMESTAMP_ARRAY_VALUE,
+         JSON_VALUE
        ) VALUES (
          nextval('DATA_SET_PROPERTY_ID_SEQ'),
          OLD.DS_ID,
@@ -1183,7 +1268,12 @@ CREATE OR REPLACE RULE data_set_properties_delete AS
          (select perm_id from samples_all where id = OLD.SAMP_PROP_ID),
          OLD.PERS_ID_AUTHOR,
          OLD.MODIFICATION_TIMESTAMP,
-         current_timestamp
+         current_timestamp,
+         OLD.INTEGER_ARRAY_VALUE,
+         OLD.REAL_ARRAY_VALUE,
+         OLD.STRING_ARRAY_VALUE,
+         OLD.TIMESTAMP_ARRAY_VALUE,
+         OLD.JSON_VALUE
        );
 
 -- End of rules for properties history
-- 
GitLab