From 864891fed1d099f16c5e2eee04e83e55c112373c Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Wed, 2 Sep 2026 12:04:52 -0700 Subject: [PATCH 1/3] Migrate flow attribute beans to use longs --- .../attribute/AttributeController.java | 22 +++-- .../labkey/flow/persist/AttributeCache.java | 45 +++++----- .../flow/persist/AttributeSetHelper.java | 19 ++-- .../org/labkey/flow/persist/FlowManager.java | 88 +++++++++---------- .../org/labkey/flow/persist/PersistTests.java | 4 +- .../flow/query/AttributeForeignKey.java | 4 +- .../flow/query/BackgroundForeignKey.java | 2 +- .../labkey/flow/query/GraphForeignKey.java | 2 +- .../labkey/flow/query/KeywordForeignKey.java | 2 +- .../flow/query/StatisticForeignKey.java | 2 +- 10 files changed, 98 insertions(+), 92 deletions(-) diff --git a/flow/src/org/labkey/flow/controllers/attribute/AttributeController.java b/flow/src/org/labkey/flow/controllers/attribute/AttributeController.java index 6935319666..0b21a39cad 100644 --- a/flow/src/org/labkey/flow/controllers/attribute/AttributeController.java +++ b/flow/src/org/labkey/flow/controllers/attribute/AttributeController.java @@ -16,8 +16,8 @@ package org.labkey.flow.controllers.attribute; import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.labkey.api.action.ConfirmAction; import org.labkey.api.action.FormViewAction; @@ -255,15 +255,23 @@ public boolean handlePost(EditAttributeForm form, BindException errors) String name = form.getName(); if (name == null || name.isBlank()) { - FlowManager.get().deleteAttribute(getContainer(), - _entry.getType(), _entry.getRowId(), true); + FlowManager.get().deleteAttribute( + getContainer(), + _entry.getType(), + _entry.getRowId(), + true + ); } else { - FlowManager.get().updateAttribute(getContainer(), - _entry.getType(), _entry.getRowId(), form.getName(), - _entry.getAliasedId() == null ? _entry.getRowId() : _entry.getAliasedId(), - true); + FlowManager.get().updateAttribute( + getContainer(), + _entry.getType(), + _entry.getRowId(), + form.getName(), + _entry.getAliasedId() == null ? _entry.getRowId() : _entry.getAliasedId(), + true + ); } return true; diff --git a/flow/src/org/labkey/flow/persist/AttributeCache.java b/flow/src/org/labkey/flow/persist/AttributeCache.java index f39d168480..0e18e044b1 100644 --- a/flow/src/org/labkey/flow/persist/AttributeCache.java +++ b/flow/src/org/labkey/flow/persist/AttributeCache.java @@ -22,11 +22,12 @@ import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NonNull; import org.labkey.api.cache.BlockingCache; import org.labkey.api.cache.CacheLoader; import org.labkey.api.cache.CacheManager; import org.labkey.api.collections.CaseInsensitiveHashMap; -import org.labkey.api.collections.IntHashMap; +import org.labkey.api.collections.LongHashMap; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; import org.labkey.api.data.DbScope; @@ -81,8 +82,8 @@ private static class Attributes, Z extends Entry> private final String _containerId; private final Collection _entries; private final Map _byName; - private final Map _byRowId; - private final MultiValuedMap _aliases; + private final Map _byRowId; + private final MultiValuedMap _aliases; private Attributes(String containerId, Collection all) { @@ -90,8 +91,8 @@ private Attributes(String containerId, Collection all) _entries = all; Map byName = new CaseInsensitiveHashMap<>(); - Map byRowId = new IntHashMap<>(); - MultiValuedMap aliases = new ArrayListValuedHashMap<>(); + Map byRowId = new LongHashMap<>(); + MultiValuedMap aliases = new ArrayListValuedHashMap<>(); for (Z entry : all) { byRowId.put(entry.getRowId(), entry); @@ -112,13 +113,13 @@ private Attributes(String containerId, Collection all) public static abstract class Entry, Z extends Entry> implements Comparable> { private final AttributeType _type; - private final int _rowId; + private final long _rowId; private final String _containerId; private final String _name; private final Q _attribute; - private final Integer _aliasedId; + private final Long _aliasedId; - protected Entry(@NotNull String containerId, @NotNull AttributeType type, int rowId, @NotNull String name, @NotNull Q attribute, @Nullable Integer aliasedId) + protected Entry(@NotNull String containerId, @NotNull AttributeType type, long rowId, @NotNull String name, @NotNull Q attribute, @Nullable Long aliasedId) { _containerId = containerId; _type = type; @@ -134,7 +135,7 @@ public AttributeType getType() return _type; } - public int getRowId() + public long getRowId() { return _rowId; } @@ -166,7 +167,7 @@ public int compareTo(@NotNull Entry other) } /** Get the rowid of the aliased attribute or null if this is the preferred attribute. */ - public Integer getAliasedId() + public Long getAliasedId() { return _aliasedId; } @@ -189,12 +190,12 @@ public Collection getAliases() AttributeCache cache = (AttributeCache) AttributeCache.forType(_type); Attributes attributes = cache._cache.get(_containerId); - Collection aliasIds = attributes._aliases.get(_rowId); + Collection aliasIds = attributes._aliases.get(_rowId); if (aliasIds.isEmpty()) return Collections.emptyList(); ArrayList entries = new ArrayList<>(aliasIds.size()); - for (Integer aliasId : aliasIds) + for (Long aliasId : aliasIds) { Z entry = cache.byRowId(_containerId, aliasId); if (entry != null) @@ -237,7 +238,7 @@ public Map> getAllUsages() public static class KeywordEntry extends Entry { - protected KeywordEntry(@NotNull String containerId, int rowId, @NotNull String name, @Nullable Integer aliased) + protected KeywordEntry(@NotNull String containerId, long rowId, @NotNull String name, @Nullable Long aliased) { super(containerId, AttributeType.keyword, rowId, name, name, aliased); } @@ -257,7 +258,7 @@ public KeywordEntry getAliasedEntry() public static class StatisticEntry extends Entry { - protected StatisticEntry(@NotNull String containerId, int rowId, @NotNull String name, @NotNull StatisticSpec spec, @Nullable Integer aliased) + protected StatisticEntry(@NotNull String containerId, long rowId, @NotNull String name, @NotNull StatisticSpec spec, @Nullable Long aliased) { super(containerId, AttributeType.statistic, rowId, name, spec, aliased); } @@ -277,7 +278,7 @@ public StatisticEntry getAliasedEntry() public static class GraphEntry extends Entry { - protected GraphEntry(@NotNull String containerId, int rowId, @NotNull String name, @NotNull GraphSpec spec, @Nullable Integer aliased) + protected GraphEntry(@NotNull String containerId, long rowId, @NotNull String name, @NotNull GraphSpec spec, @Nullable Long aliased) { super(containerId, AttributeType.graph, rowId, name, spec, aliased); } @@ -312,14 +313,14 @@ private E createEntry(@Nullable FlowEntry entry) assert entry._type == _type; - Integer aliasId = entry.isAlias() ? entry._aliasId : null; + Long aliasId = entry.isAlias() ? entry._aliasId : null; A attribute = _createAttribute(entry._name); return _createEntry(entry._containerId, entry._rowId, entry._name, attribute, aliasId); } - protected abstract E _createEntry(@NotNull String containerId, int rowId, @NotNull String name, @NotNull A attribute, @Nullable Integer aliased); + protected abstract E _createEntry(@NotNull String containerId, long rowId, @NotNull String name, @NotNull A attribute, @Nullable Long aliased); protected abstract A _createAttribute(@NotNull String name); @@ -477,12 +478,12 @@ public E preferred(@NotNull Container c, @NotNull A attr) * Get an AttributeEntry by rowid. */ @Nullable - public E byRowId(@NotNull Container container, int rowId) + public E byRowId(@NotNull Container container, long rowId) { return byRowId(container.getId(), rowId); } - private E byRowId(@NotNull String containerId, int rowId) + private E byRowId(@NotNull String containerId, long rowId) { Attributes attributes = _cache.get(containerId); if (attributes == null) @@ -505,7 +506,7 @@ protected String _createAttribute(@NotNull String name) } @Override - protected KeywordEntry _createEntry(@NotNull String containerId, int rowId, @NotNull String name, @NotNull String attribute, @Nullable Integer aliased) + protected KeywordEntry _createEntry(@NotNull String containerId, long rowId, @NotNull String name, @NonNull String attribute, @Nullable Long aliased) { return new KeywordEntry(containerId, rowId, name, aliased); } @@ -525,7 +526,7 @@ protected StatisticSpec _createAttribute(@NotNull String name) } @Override - protected StatisticEntry _createEntry(@NotNull String containerId, int rowId, @NotNull String name, @NotNull StatisticSpec attribute, @Nullable Integer aliased) + protected StatisticEntry _createEntry(@NotNull String containerId, long rowId, @NotNull String name, @NonNull StatisticSpec attribute, @Nullable Long aliased) { return new StatisticEntry(containerId, rowId, name, attribute, aliased); } @@ -545,7 +546,7 @@ protected GraphSpec _createAttribute(@NotNull String name) } @Override - protected GraphEntry _createEntry(@NotNull String containerId, int rowId, @NotNull String name, @NotNull GraphSpec attribute, @Nullable Integer aliased) + protected GraphEntry _createEntry(@NotNull String containerId, long rowId, @NotNull String name, @NonNull GraphSpec attribute, @Nullable Long aliased) { return new GraphEntry(containerId, rowId, name, attribute, aliased); } diff --git a/flow/src/org/labkey/flow/persist/AttributeSetHelper.java b/flow/src/org/labkey/flow/persist/AttributeSetHelper.java index b05270efe3..f92a5ecc1a 100644 --- a/flow/src/org/labkey/flow/persist/AttributeSetHelper.java +++ b/flow/src/org/labkey/flow/persist/AttributeSetHelper.java @@ -19,7 +19,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; -import org.labkey.api.collections.IntHashMap; +import org.labkey.api.collections.LongHashMap; import org.labkey.api.data.Container; import org.labkey.api.data.DbScope; import org.labkey.api.data.SqlSelector; @@ -42,9 +42,6 @@ import java.util.TreeMap; /** - * User: kevink - * Date: Apr 15, 2011 - * * Static helper methods for reading and saving AttributeSet to/from the database. */ public class AttributeSetHelper @@ -155,8 +152,8 @@ public static void doSave(AttributeSet attrs, User user, ExpData data, @Nullable { AttributeCache.Entry a = AttributeCache.KEYWORDS.byAttribute(c, entry.getKey()); assert a != null : "parepareForSave should have created an entry"; - int preferredId = a.getAliasedId() == null ? a.getRowId() : a.getAliasedId(); - int originalId = a.getRowId(); + long preferredId = a.getAliasedId() == null ? a.getRowId() : a.getAliasedId(); + long originalId = a.getRowId(); paramsList.add(Arrays.asList(obj.getRowId(), preferredId, originalId, entry.getValue())); } Table.batchExecute(mgr.getSchema(), sql, paramsList); @@ -168,7 +165,7 @@ public static void doSave(AttributeSet attrs, User user, ExpData data, @Nullable // Issue 41225: flow: import failure for duplicate aliased statistics // Track the list of statistics and values for each preferredId key. // If there is a duplicate statistic (e.g., two stats that are aliased) verify they have the same value. - Map>> valuesForPreferredId = new IntHashMap<>(); + Map>> valuesForPreferredId = new LongHashMap<>(); String sql = "INSERT INTO " + mgr.getTinfoStatistic() + " (ObjectId, StatisticId, OriginalStatisticId, Value) VALUES (?,?,?,?)"; List> paramsList = new ArrayList<>(); @@ -176,8 +173,8 @@ public static void doSave(AttributeSet attrs, User user, ExpData data, @Nullable { AttributeCache.Entry a = AttributeCache.STATS.byAttribute(c, entry.getKey()); assert a != null : "parepareForSave should have created an entry"; - int preferredId = a.getAliasedId() == null ? a.getRowId() : a.getAliasedId(); - int originalId = a.getRowId(); + long preferredId = a.getAliasedId() == null ? a.getRowId() : a.getAliasedId(); + long originalId = a.getRowId(); var duplicateValues = valuesForPreferredId.computeIfAbsent(preferredId, (k) -> new ArrayList<>()); if (duplicateValues.isEmpty()) @@ -215,8 +212,8 @@ public static void doSave(AttributeSet attrs, User user, ExpData data, @Nullable { AttributeCache.Entry a = AttributeCache.GRAPHS.byAttribute(c, entry.getKey()); assert a != null : "parepareForSave should have created an entry"; - int preferredId = a.getAliasedId() == null ? a.getRowId() : a.getAliasedId(); - int originalId = a.getRowId(); + long preferredId = a.getAliasedId() == null ? a.getRowId() : a.getAliasedId(); + long originalId = a.getRowId(); paramsList.add(Arrays.asList(obj.getRowId(), preferredId, originalId, entry.getValue())); } Table.batchExecute(mgr.getSchema(), sql, paramsList); diff --git a/flow/src/org/labkey/flow/persist/FlowManager.java b/flow/src/org/labkey/flow/persist/FlowManager.java index 07720058d9..c3890b8b73 100644 --- a/flow/src/org/labkey/flow/persist/FlowManager.java +++ b/flow/src/org/labkey/flow/persist/FlowManager.java @@ -261,7 +261,7 @@ private List getAttributeEntryCaseInsensitive(String containerId, Att * DOES NOT USE CACHE */ @Nullable - public FlowEntry getAttributeEntry(@NotNull AttributeType type, int rowId) + public FlowEntry getAttributeEntry(@NotNull AttributeType type, long rowId) { //_log.info("getAttributeEntry(" + type + ", " + rowId + ")"); Map row = new SqlSelector(getSchema(), "SELECT Container, Name, Id FROM " + attributeTable(type) + " WHERE RowId = ?", rowId).getMap(); @@ -302,12 +302,12 @@ public Collection getAttributeEntries(@NotNull String containerId, @N public static class FlowEntry implements Comparable { public final AttributeType _type; - public final int _rowId; + public final long _rowId; public final String _containerId; public final String _name; - public final int _aliasId; + public final long _aliasId; - public FlowEntry(@NotNull AttributeType type, @NotNull int rowId, @NotNull String containerId, @NotNull String name, @NotNull Integer aliasId) + public FlowEntry(@NotNull AttributeType type, long rowId, @NotNull String containerId, @NotNull String name, long aliasId) { _type = type; _rowId = rowId; @@ -339,7 +339,7 @@ public boolean equals(Object o) public int hashCode() { int result = _type.hashCode(); - result = 31 * result + Integer.hashCode(_rowId); + result = 31 * result + Long.hashCode(_rowId); return result; } @@ -363,7 +363,7 @@ public int compareTo(FlowEntry o) * @param allowCaseChangeAlias When true, allow an attribute to be registered as an alias of another attribute if it differs by casing. * @return The RowId of the newly inserted or existing attribute. */ - private int ensureAttributeName(@NotNull Container container, @Nullable String sampleLabel, @NotNull AttributeType type, @NotNull String attr, int aliasId, boolean allowCaseChangeAlias) + private long ensureAttributeName(@NotNull Container container, @Nullable String sampleLabel, @NotNull AttributeType type, @NotNull String attr, long aliasId, boolean allowCaseChangeAlias) { // Get case-sensitivity rule final FlowProtocol protocol = FlowProtocol.getForContainer(container); @@ -399,12 +399,12 @@ private int ensureAttributeName(@NotNull Container container, @Nullable String s if (!caseSensitive) { // Use the first attribute, sorted by case - int rowId = others.getFirst()._rowId; + long rowId = others.getFirst()._rowId; // If more than one attribute matches, check that all are pointing to the same preferred attribute if (others.size() > 1) { - int preferredId = others.getFirst()._aliasId; + long preferredId = others.getFirst()._aliasId; if (others.stream().anyMatch(item -> item._aliasId != preferredId)) throw new FlowCasingMismatchException("Can't create " + type + " with same casing as other " + type + "s when there is more than one preferred attribute.", sampleLabel, type, others, attr); } @@ -450,37 +450,37 @@ private int ensureAttributeName(@NotNull Container container, @Nullable String s return rowId; } - private int ensureAttributeName(Container container, String sampleLabel, AttributeType type, String name) + private long ensureAttributeName(Container container, String sampleLabel, AttributeType type, String name) { return ensureAttributeName(container, sampleLabel, type, name, -1, false); } - public int ensureKeywordName(Container c, String sampleLabel, String name, boolean uncache) + public long ensureKeywordName(Container c, String sampleLabel, String name, boolean uncache) { return ensureAttributeNameAndAliases(c, sampleLabel, keyword, name, Collections.emptyList(), uncache); } - public int ensureStatisticNameAndAliases(Container c, String sampleLabel, String name, Collection aliases, boolean uncache) + public long ensureStatisticNameAndAliases(Container c, String sampleLabel, String name, Collection aliases, boolean uncache) { return ensureAttributeNameAndAliases(c, sampleLabel, AttributeType.statistic, name, aliases, uncache); } - public int ensureKeywordNameAndAliases(Container c, String sampleLabel, String name, Collection aliases, boolean uncache) + public long ensureKeywordNameAndAliases(Container c, String sampleLabel, String name, Collection aliases, boolean uncache) { return ensureAttributeNameAndAliases(c, sampleLabel, keyword, name, aliases, uncache); } - public int ensureGraphNameAndAliases(Container c, String sampleLabel, String name, Collection aliases, boolean uncache) + public long ensureGraphNameAndAliases(Container c, String sampleLabel, String name, Collection aliases, boolean uncache) { return ensureAttributeNameAndAliases(c, sampleLabel, AttributeType.graph, name, aliases, uncache); } - private int ensureAttributeNameAndAliases(Container c, String sampleLabel, AttributeType type, String name, Collection aliases, boolean uncache) + private long ensureAttributeNameAndAliases(Container c, String sampleLabel, AttributeType type, String name, Collection aliases, boolean uncache) { //_log.info("ensureAlias(" + c + ", " + type + ", " + name + ", aliases)"); try @@ -491,7 +491,7 @@ private int ensureAttributeNameAndAliases(Container c, String sampleLabel, Attri names.add(alias.toString()); // Check for an existing alias in the list of new attribute names. - Integer aliasId = null; + Long aliasId = null; for (String s : names) { FlowEntry entry = getAttributeEntryCaseSensitive(c.getId(), type, s); @@ -526,7 +526,7 @@ private int ensureAttributeNameAndAliases(Container c, String sampleLabel, Attri } @NotNull - private FlowEntry getAttributeEntryForAliasing(@NotNull AttributeType type, int rowId) + private FlowEntry getAttributeEntryForAliasing(@NotNull AttributeType type, long rowId) { FlowEntry entry = getAttributeEntry(type, rowId); if (entry == null) @@ -538,7 +538,7 @@ private FlowEntry getAttributeEntryForAliasing(@NotNull AttributeType type, int return entry; } - public void ensureAlias(@NotNull AttributeType type, int rowId, @NotNull String aliasName, boolean allowCaseChangeAlias, boolean transact, boolean uncache) + public void ensureAlias(@NotNull AttributeType type, long rowId, @NotNull String aliasName, boolean allowCaseChangeAlias, boolean transact, boolean uncache) { ensureAlias(getAttributeEntryForAliasing(type, rowId), aliasName, allowCaseChangeAlias, transact, uncache); } @@ -546,7 +546,7 @@ public void ensureAlias(@NotNull AttributeType type, int rowId, @NotNull String private void ensureAlias(@NotNull FlowEntry entry, @NotNull String aliasName, boolean allowCaseChangeAlias, boolean transact, boolean uncache) { final AttributeType type = entry._type; - final int rowId = entry._rowId; + final long rowId = entry._rowId; Container c = ContainerManager.getForId(entry._containerId); if (c == null) @@ -601,7 +601,7 @@ private void ensureAlias(@NotNull FlowEntry entry, @NotNull String aliasName, bo } } - public void updateAttribute(@NotNull Container container, @NotNull AttributeType type, int rowId, @NotNull String name, int aliasId, boolean uncache) + public void updateAttribute(@NotNull Container container, @NotNull AttributeType type, long rowId, @NotNull String name, long aliasId, boolean uncache) { FlowEntry entry = getAttributeEntry(type, rowId); if (entry == null) @@ -610,10 +610,10 @@ public void updateAttribute(@NotNull Container container, @NotNull AttributeType updateAttribute(container, entry, name, aliasId, uncache); } - private void updateAttribute(@NotNull Container container, @NotNull FlowEntry entry, @NotNull String name, int aliasId, boolean uncache) + private void updateAttribute(@NotNull Container container, @NotNull FlowEntry entry, @NotNull String name, long aliasId, boolean uncache) { final AttributeType type = entry._type; - final int rowId = entry._rowId; + final long rowId = entry._rowId; // Validate the name if (name == null || name.isEmpty()) @@ -640,7 +640,7 @@ private void updateAttribute(@NotNull Container container, @NotNull FlowEntry en } // Update any attribute usages of the current rowId to the new rowId, keeping the original id the same - private int updateAttributeValuesPreferredId(@NotNull String containerId, @NotNull AttributeType type, int currentRowId, int newRowId) + private int updateAttributeValuesPreferredId(@NotNull String containerId, @NotNull AttributeType type, long currentRowId, long newRowId) { TableInfo valueTable = valueTable(type); String valueTableAttrIdColumn = valueTableAttrIdColumn(type); @@ -671,7 +671,7 @@ private int updateAttributeValuesPreferredId(@NotNull String containerId, @NotNu return new SqlExecutor(getSchema()).execute(sql); } - public void deleteAttribute(@NotNull Container c, AttributeType type, int rowId, boolean uncache) + public void deleteAttribute(@NotNull Container c, AttributeType type, long rowId, boolean uncache) { FlowEntry entry = getAttributeEntry(type, rowId); if (entry == null) @@ -716,7 +716,7 @@ public FlowEntry getAliased(FlowEntry entry) * Get aliases for the preferred/primary attribute rowId or empty collection if rowId is not a preferred attribute. * DOES NOT USE CACHE */ - public Collection getAliases(final AttributeType type, int rowId) + public Collection getAliases(final AttributeType type, long rowId) { FlowEntry entry = getAttributeEntry(type, rowId); if (entry == null) @@ -872,7 +872,7 @@ private int deleteUnused(@NotNull Container c, AttributeType type) /** * Get a usage count for an attribute and its aliases. */ - public Map getUsageCount(AttributeType type, int rowId) + public Map getUsageCount(AttributeType type, long rowId) { FlowEntry entry = getAttributeEntry(type, rowId); if (entry == null) @@ -883,13 +883,13 @@ public Map getUsageCount(AttributeType type, int rowId) String valueTableOriginalAttrIdColumn = valueTableOriginalAttrIdColumn(type); SQLFragment sql = new SQLFragment() - .append("SELECT val.").append(valueTableOriginalAttrIdColumn).append(" AS OriginalAttrId, COUNT(fo.rowid) AS ObjectCount\n") - .append("FROM ") - .append(valueTable, "val").append(", ") - .append(getTinfoObject(), "fo").append("\n") - .append("WHERE fo.rowid = val.objectid\n") - .append(" AND val.").append(valueTableAttrIdColumn).append(" = ").appendValue(entry._rowId).append("\n") - .append("GROUP BY val.").append(valueTableOriginalAttrIdColumn).append("\n"); + .append("SELECT val.").append(valueTableOriginalAttrIdColumn).append(" AS OriginalAttrId, COUNT(fo.rowid) AS ObjectCount\n") + .append("FROM ") + .append(valueTable, "val").append(", ") + .append(getTinfoObject(), "fo").append("\n") + .append("WHERE fo.rowid = val.objectid\n") + .append(" AND val.").append(valueTableAttrIdColumn).append(" = ").appendValue(entry._rowId).append("\n") + .append("GROUP BY val.").append(valueTableOriginalAttrIdColumn).append("\n"); SqlSelector selector = new SqlSelector(getSchema(), sql); return selector.getValueMap(Long.class); @@ -898,7 +898,7 @@ public Map getUsageCount(AttributeType type, int rowId) /** * Get usages for an attribute, excluding its aliases. */ - public Collection getUsages(AttributeType type, int rowId) + public Collection getUsages(AttributeType type, long rowId) { return getUsages(getAttributeEntry(type, rowId)); } @@ -940,7 +940,7 @@ public Collection getUsages(FlowEntry entry) /** * Get usages for an attribute and its aliases. */ - public Map> getAllUsages(AttributeType type, int rowId) + public Map> getAllUsages(AttributeType type, long rowId) { FlowEntry entry = getAttributeEntry(type, rowId); if (entry == null) @@ -951,14 +951,14 @@ public Map> getAllUsages(AttributeType type, String valueTableOriginalAttrIdColumn = valueTableOriginalAttrIdColumn(type); SQLFragment sql = new SQLFragment() - .append("SELECT fo.rowid, fo.dataid,") - .append(" val.").append(valueTableAttrIdColumn).append(" AS AttrId,") - .append(" val.").append(valueTableOriginalAttrIdColumn).append(" AS OriginalAttrId\n") - .append("FROM ") - .append(valueTable, "val").append(", ") - .append(getTinfoObject(), "fo").append("\n") - .append("WHERE fo.rowid = val.objectid\n") - .append(" AND val.").append(valueTableAttrIdColumn).append(" = ").appendValue(rowId).append("\n"); + .append("SELECT fo.rowid, fo.dataid,") + .append(" val.").append(valueTableAttrIdColumn).append(" AS AttrId,") + .append(" val.").append(valueTableOriginalAttrIdColumn).append(" AS OriginalAttrId\n") + .append("FROM ") + .append(valueTable, "val").append(", ") + .append(getTinfoObject(), "fo").append("\n") + .append("WHERE fo.rowid = val.objectid\n") + .append(" AND val.").append(valueTableAttrIdColumn).append(" = ").appendValue(rowId).append("\n"); final Map> usages = new IntHashMap<>(); SqlSelector selector = new SqlSelector(getSchema(), sql); @@ -1201,8 +1201,8 @@ public void setKeyword(Container c, User user, ExpData data, String keyword, Str AttributeCache.Entry a = AttributeCache.KEYWORDS.byAttribute(c, keyword); assert a != null : "Expected to find keyword entry for '" + keyword + "'"; - int preferredId = a.getAliasedId() == null ? a.getRowId() : a.getAliasedId(); - int originalId = a.getRowId(); + long preferredId = a.getAliasedId() == null ? a.getRowId() : a.getAliasedId(); + long originalId = a.getRowId(); DbSchema schema = getSchema(); try (DbScope.Transaction transaction = schema.getScope().ensureTransaction()) diff --git a/flow/src/org/labkey/flow/persist/PersistTests.java b/flow/src/org/labkey/flow/persist/PersistTests.java index 9ba19d6403..7af37c3865 100644 --- a/flow/src/org/labkey/flow/persist/PersistTests.java +++ b/flow/src/org/labkey/flow/persist/PersistTests.java @@ -697,7 +697,7 @@ public void caseSensitiveSetting() throws Exception final String lower_name = "qq-keyword"; // setup -- create a keyword - int upperId = FlowManager.get().ensureKeywordName(c, "sample", UPPER_NAME, true); + long upperId = FlowManager.get().ensureKeywordName(c, "sample", UPPER_NAME, true); // verify -- when case-sensitive, can't create keyword that only differs by case try @@ -719,7 +719,7 @@ public void caseSensitiveSetting() throws Exception protocol.setCaseSensitiveKeywords(user, false); assertFalse(protocol.isCaseSensitiveKeywords()); - int rowId = FlowManager.get().ensureKeywordName(c, "TEST", lower_name, false); + long rowId = FlowManager.get().ensureKeywordName(c, "TEST", lower_name, false); assertEquals("Expected to get existing " + UPPER_NAME + " keyword when case-sensitivity is turned off", upperId, rowId); } } diff --git a/flow/src/org/labkey/flow/query/AttributeForeignKey.java b/flow/src/org/labkey/flow/query/AttributeForeignKey.java index a8e7cdb862..d564b9b4d4 100644 --- a/flow/src/org/labkey/flow/query/AttributeForeignKey.java +++ b/flow/src/org/labkey/flow/query/AttributeForeignKey.java @@ -100,7 +100,7 @@ public ColumnInfo createLookupColumn(ColumnInfo parent, String displayField) AttributeCache cache = AttributeCache.forType(type()); AttributeCache.Entry entry = cache.byAttribute(_container, attr); AttributeCache.Entry preferred = entry == null ? null : entry.getAliasedEntry(); - int rowId = entry == null ? 0 : entry.getRowId(); + long rowId = entry == null ? 0 : entry.getRowId(); SQLFragment sql = sqlValue(parent, attr, preferred != null ? preferred.getRowId() : rowId); ExprColumn ret = new ExprColumn(parent.getParentTable(), new FieldKey(parent.getFieldKey(), displayField), sql, JdbcType.NULL, parent); @@ -111,7 +111,7 @@ public ColumnInfo createLookupColumn(ColumnInfo parent, String displayField) abstract protected AttributeType type(); abstract protected Collection> getAttributes(); - abstract protected SQLFragment sqlValue(ColumnInfo objectIdColumn, T attrName, int attrId); + abstract protected SQLFragment sqlValue(ColumnInfo objectIdColumn, T attrName, long attrId); abstract protected void initColumn(T attrName, String preferredName, BaseColumnInfo column); abstract protected T attributeFromString(String field); } diff --git a/flow/src/org/labkey/flow/query/BackgroundForeignKey.java b/flow/src/org/labkey/flow/query/BackgroundForeignKey.java index 5b7e5bc1c0..720ef2aac1 100644 --- a/flow/src/org/labkey/flow/query/BackgroundForeignKey.java +++ b/flow/src/org/labkey/flow/query/BackgroundForeignKey.java @@ -90,7 +90,7 @@ protected void initColumn(StatisticSpec stat, String preferredName, BaseColumnIn } @Override - protected SQLFragment sqlValue(ColumnInfo objectIdColumn, StatisticSpec attrName, int attrId) + protected SQLFragment sqlValue(ColumnInfo objectIdColumn, StatisticSpec attrName, long attrId) { ICSMetadata ics = _schema.getProtocol().getICSMetadata(); if (ics == null) diff --git a/flow/src/org/labkey/flow/query/GraphForeignKey.java b/flow/src/org/labkey/flow/query/GraphForeignKey.java index 2ed5b5f12f..cfa64a12b3 100644 --- a/flow/src/org/labkey/flow/query/GraphForeignKey.java +++ b/flow/src/org/labkey/flow/query/GraphForeignKey.java @@ -79,7 +79,7 @@ protected void initColumn(final GraphSpec spec, String preferredName, BaseColumn // Select the string concatenated value of objectId+'~~~'+graphSpec // When rendering the image URL, we will split the values apart again. @Override - protected SQLFragment sqlValue(ColumnInfo objectIdColumn, GraphSpec attrName, int attrId) + protected SQLFragment sqlValue(ColumnInfo objectIdColumn, GraphSpec attrName, long attrId) { final SqlDialect dialect = objectIdColumn.getSqlDialect(); final SQLFragment sepAndGraphSpec = diff --git a/flow/src/org/labkey/flow/query/KeywordForeignKey.java b/flow/src/org/labkey/flow/query/KeywordForeignKey.java index 5864600c66..e8316cb3fa 100644 --- a/flow/src/org/labkey/flow/query/KeywordForeignKey.java +++ b/flow/src/org/labkey/flow/query/KeywordForeignKey.java @@ -69,7 +69,7 @@ protected void initColumn(String attrName, String preferredName, BaseColumnInfo } @Override - protected SQLFragment sqlValue(ColumnInfo objectIdColumn, String attrName, int attrId) + protected SQLFragment sqlValue(ColumnInfo objectIdColumn, String attrName, long attrId) { // SQL server 2000 does not allow a TEXT column (i.e. flow.keyword.value) to appear in this subquery. // For this reason, we cast it to VARCHAR(4000). diff --git a/flow/src/org/labkey/flow/query/StatisticForeignKey.java b/flow/src/org/labkey/flow/query/StatisticForeignKey.java index 7b32d3eee6..9854f97d61 100644 --- a/flow/src/org/labkey/flow/query/StatisticForeignKey.java +++ b/flow/src/org/labkey/flow/query/StatisticForeignKey.java @@ -92,7 +92,7 @@ else if (_type == FlowDataType.CompensationControl) } @Override - protected SQLFragment sqlValue(ColumnInfo objectIdColumn, StatisticSpec attrName, int attrId) + protected SQLFragment sqlValue(ColumnInfo objectIdColumn, StatisticSpec attrName, long attrId) { SQLFragment ret = new SQLFragment("(SELECT flow.Statistic.Value FROM flow.Statistic WHERE flow.Statistic.ObjectId = "); ret.append(objectIdColumn.getValueSql(ExprColumn.STR_TABLE_ALIAS)); From f6ec196cd09ac36d85534a292f83848c7b4e8fed Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Wed, 2 Sep 2026 15:47:20 -0700 Subject: [PATCH 2/3] More int -> long --- .../labkey/flow/persist/AttributeCache.java | 2 +- .../org/labkey/flow/persist/FlowManager.java | 74 +++++++------------ 2 files changed, 28 insertions(+), 48 deletions(-) diff --git a/flow/src/org/labkey/flow/persist/AttributeCache.java b/flow/src/org/labkey/flow/persist/AttributeCache.java index 0e18e044b1..f604f8e470 100644 --- a/flow/src/org/labkey/flow/persist/AttributeCache.java +++ b/flow/src/org/labkey/flow/persist/AttributeCache.java @@ -214,7 +214,7 @@ public Collection getUsages() /** Get a list of usages of this attribute, including usages of this attribute's aliases. */ public Map> getAllUsages() { - Map> usagesMap = FlowManager.get().getAllUsages(_type, _rowId); + Map> usagesMap = FlowManager.get().getAllUsages(_type, _rowId); Map> ret = new HashMap<>(); // Include usages of this attribute diff --git a/flow/src/org/labkey/flow/persist/FlowManager.java b/flow/src/org/labkey/flow/persist/FlowManager.java index c3890b8b73..173f6aac2d 100644 --- a/flow/src/org/labkey/flow/persist/FlowManager.java +++ b/flow/src/org/labkey/flow/persist/FlowManager.java @@ -26,7 +26,7 @@ import org.junit.Before; import org.junit.Test; import org.labkey.api.audit.AuditLogService; -import org.labkey.api.collections.IntHashMap; +import org.labkey.api.collections.LongHashMap; import org.labkey.api.data.Aggregate; import org.labkey.api.data.ColumnInfo; import org.labkey.api.data.CompareType; @@ -36,6 +36,7 @@ import org.labkey.api.data.DbSchemaType; import org.labkey.api.data.DbScope; import org.labkey.api.data.SQLFragment; +import org.labkey.api.data.Selector; import org.labkey.api.data.SimpleFilter; import org.labkey.api.data.Sort; import org.labkey.api.data.SqlExecutor; @@ -64,6 +65,7 @@ import org.labkey.api.security.roles.ReaderRole; import org.labkey.api.util.DateUtil; import org.labkey.api.util.FileUtil; +import org.labkey.api.util.IntegerUtils; import org.labkey.api.util.UnexpectedException; import org.labkey.api.view.ActionURL; import org.labkey.flow.FlowModule; @@ -228,8 +230,8 @@ private FlowEntry getAttributeEntryCaseSensitive(String containerId, AttributeTy return null; String name = rs.getString("Name"); - Integer rowId = rs.getInt("RowId"); - Integer aliasId = rs.getInt("Id"); + long rowId = rs.getLong("RowId"); + long aliasId = rs.getLong("Id"); return new FlowEntry(type, rowId, containerId, name, aliasId); } catch (SQLException e) @@ -282,18 +284,14 @@ public Collection getAttributeEntries(@NotNull String containerId, @N TableInfo table = attributeTable(type); SimpleFilter filter = new SimpleFilter(); filter.addCondition(FieldKey.fromParts("Container"), containerId); - TableSelector selector = new TableSelector(table, filter, null); - final List entries = new ArrayList<>(); - selector.forEachMap(row -> { - Integer rowId = (Integer)row.get("RowId"); - String name = (String)row.get("Name"); - String containerId1 = (String)row.get("Container"); - Integer aliasId = (Integer)row.get("Id"); - FlowEntry entry = new FlowEntry(type, rowId, containerId1, name, aliasId); + return getFlowEntries(new TableSelector(table, filter, null), type); + } - entries.add(entry); - }); + private Collection getFlowEntries(Selector selector, @NotNull final AttributeType type) + { + final List entries = new ArrayList<>(); + selector.forEachMap(row -> entries.add(FlowEntry.fromRow(row, type))); return Collections.unmodifiableList(entries); } @@ -348,6 +346,16 @@ public int compareTo(FlowEntry o) { return _name.compareTo(o._name); } + + private static FlowEntry fromRow(Map row, @NotNull AttributeType type) + { + Integer rowId = (Integer)row.get("RowId"); + String name = (String)row.get("Name"); + String containerId = (String)row.get("Container"); + Integer aliasId = (Integer)row.get("Id"); + + return new FlowEntry(type, rowId, containerId, name, aliasId); + } } /** @@ -738,20 +746,8 @@ public Collection getAliases(final FlowEntry entry) filter.addCondition(table.getColumn("Container"), entry._containerId); filter.addCondition(table.getColumn("Id"), entry._rowId); filter.addCondition(table.getColumn("RowId"), entry._rowId, CompareType.NEQ); - TableSelector selector = new TableSelector(table, filter, null); - final List aliases = new ArrayList<>(); - selector.forEachMap(row -> { - Integer rowId = (Integer)row.get("RowId"); - String name = (String)row.get("Name"); - String containerId = (String)row.get("Container"); - Integer aliasId = (Integer)row.get("Id"); - FlowEntry alias = new FlowEntry(entry._type, rowId, containerId, name, aliasId); - - aliases.add(alias); - }); - - return aliases; + return getFlowEntries(new TableSelector(table, filter, null), entry._type); } public Map> getAliases(Container c, final AttributeType type) @@ -763,11 +759,7 @@ public Map> getAliases(Container c, final Attri final Map> aliasMap = new LinkedHashMap<>(); selector.forEachMap(row -> { - Integer rowId = (Integer)row.get("RowId"); - String name = (String)row.get("Name"); - String containerId = (String)row.get("Container"); - Integer aliasId = (Integer)row.get("Id"); - FlowEntry entry = new FlowEntry(type, rowId, containerId, name, aliasId); + FlowEntry entry = FlowEntry.fromRow(row, type); FlowEntry preferredEntry; if (entry.isAlias()) @@ -811,20 +803,8 @@ public Collection getUnused(@NotNull Container c, @NotNull final Attr .append(" AND attr.rowid IN (SELECT val.").append(valueTableAttrIdColumn).append(" FROM ").append(valueTable, "val").append(")\n") .append(" )\n") .append(")\n"); - SqlSelector selector = new SqlSelector(getSchema(), sql); - - final List unused = new ArrayList<>(); - selector.forEachMap(row -> { - Integer rowId = (Integer)row.get("RowId"); - String name = (String)row.get("Name"); - String containerId = (String)row.get("Container"); - Integer aliasId = (Integer)row.get("Id"); - FlowEntry alias = new FlowEntry(type, rowId, containerId, name, aliasId); - - unused.add(alias); - }); - return Collections.unmodifiableList(unused); + return getFlowEntries(new SqlSelector(getSchema(), sql), type); } public void deleteUnused(@NotNull Container c) @@ -940,7 +920,7 @@ public Collection getUsages(FlowEntry entry) /** * Get usages for an attribute and its aliases. */ - public Map> getAllUsages(AttributeType type, long rowId) + public Map> getAllUsages(AttributeType type, long rowId) { FlowEntry entry = getAttributeEntry(type, rowId); if (entry == null) @@ -960,10 +940,10 @@ public Map> getAllUsages(AttributeType type, .append("WHERE fo.rowid = val.objectid\n") .append(" AND val.").append(valueTableAttrIdColumn).append(" = ").appendValue(rowId).append("\n"); - final Map> usages = new IntHashMap<>(); + final Map> usages = new LongHashMap<>(); SqlSelector selector = new SqlSelector(getSchema(), sql); selector.forEachMap(row -> { - Integer attributeRowId = (Integer)row.get("OriginalAttrId"); + Long attributeRowId = IntegerUtils.asLong(row.get("OriginalAttrId")); Integer dataId = (Integer)row.get("DataId"); Collection datas = usages.computeIfAbsent(attributeRowId, k -> new ArrayList<>()); From 5a6df4386158d99ac2dc0f87fd8ca0fc9cf761cc Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Wed, 2 Sep 2026 16:42:21 -0700 Subject: [PATCH 3/3] NonNull -> NotNull --- flow/src/org/labkey/flow/persist/AttributeCache.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/flow/src/org/labkey/flow/persist/AttributeCache.java b/flow/src/org/labkey/flow/persist/AttributeCache.java index f604f8e470..4f3a4923dc 100644 --- a/flow/src/org/labkey/flow/persist/AttributeCache.java +++ b/flow/src/org/labkey/flow/persist/AttributeCache.java @@ -22,7 +22,6 @@ import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jspecify.annotations.NonNull; import org.labkey.api.cache.BlockingCache; import org.labkey.api.cache.CacheLoader; import org.labkey.api.cache.CacheManager; @@ -506,7 +505,7 @@ protected String _createAttribute(@NotNull String name) } @Override - protected KeywordEntry _createEntry(@NotNull String containerId, long rowId, @NotNull String name, @NonNull String attribute, @Nullable Long aliased) + protected KeywordEntry _createEntry(@NotNull String containerId, long rowId, @NotNull String name, @NotNull String attribute, @Nullable Long aliased) { return new KeywordEntry(containerId, rowId, name, aliased); } @@ -526,7 +525,7 @@ protected StatisticSpec _createAttribute(@NotNull String name) } @Override - protected StatisticEntry _createEntry(@NotNull String containerId, long rowId, @NotNull String name, @NonNull StatisticSpec attribute, @Nullable Long aliased) + protected StatisticEntry _createEntry(@NotNull String containerId, long rowId, @NotNull String name, @NotNull StatisticSpec attribute, @Nullable Long aliased) { return new StatisticEntry(containerId, rowId, name, attribute, aliased); } @@ -546,7 +545,7 @@ protected GraphSpec _createAttribute(@NotNull String name) } @Override - protected GraphEntry _createEntry(@NotNull String containerId, long rowId, @NotNull String name, @NonNull GraphSpec attribute, @Nullable Long aliased) + protected GraphEntry _createEntry(@NotNull String containerId, long rowId, @NotNull String name, @NotNull GraphSpec attribute, @Nullable Long aliased) { return new GraphEntry(containerId, rowId, name, attribute, aliased); }