Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion source/common/src/tdatablock.c
Original file line number Diff line number Diff line change
Expand Up @@ -2496,7 +2496,10 @@ static void colDataKeepFirstNRows(SColumnInfoData* pColInfoData, size_t n, size_
}
}
if (newLen <= -1) {
uFatal("colDataKeepFirstNRows: newLen:%d old:%d", newLen, pColInfoData->varmeta.length);
// All kept rows are NULL — no valid var data belongs to them.
uDebug("colDataKeepFirstNRows: all kept rows are NULL, newLen:%d old:%d, reset length to 0",
newLen, pColInfoData->varmeta.length);
pColInfoData->varmeta.length = 0;
} else {
pColInfoData->varmeta.length = newLen;
}
Comment thread
facetosea marked this conversation as resolved.
Outdated
Expand Down
4 changes: 3 additions & 1 deletion source/libs/decimal/src/detail/intx/int128.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,9 @@ struct numeric_limits<intx::uint<N>>
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr int digits = CHAR_BIT * sizeof(type);
static constexpr int digits10 = int(0.3010299956639812 * digits);
// Maximum number of base-10 digits that can be represented by this type.
// Computed as floor(digits * log10(2)) where log10(2) ≈ 0.30102999566398119.
static constexpr int digits10 = static_cast<int>(0.30102999566398119521373889472449 * digits);
static constexpr int max_digits10 = 0;
static constexpr int radix = 2;
static constexpr int min_exponent = 0;
Expand Down
74 changes: 74 additions & 0 deletions test/cases/01-DataTypes/test_null_column.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,80 @@ def test_null_column(self):
self.NullColSma()
tdStream.dropAllStreamsAndDbs()

def test_null_varchar_limit(self):
"""NULL: varchar column with LIMIT triggers blockDataKeepFirstNRows all-NULL path

When the first N rows of a variable-length column are all NULL and a
LIMIT N query is executed, blockDataKeepFirstNRows must set
varmeta.length to 0 instead of keeping the stale value.

Since: v3.0.0.0

Labels: common,ci

Jira: TD-32818

History:
- 2026-4-3 Added to cover colDataKeepFirstNRows all-NULL var-data fix

"""

tdSql.prepare("db_null_limit", drop=True)
tdSql.execute("use db_null_limit")

# Create a table with multiple var-length column types
tdSql.execute(
"create table t_var_null (ts timestamp, c1 varchar(64), c2 nchar(64), c3 int)"
)

# Insert rows: first 5 rows have NULL varchar/nchar, last 3 have values
tdSql.execute("insert into t_var_null values ('2024-01-01 00:00:01', NULL, NULL, 1)")
tdSql.execute("insert into t_var_null values ('2024-01-01 00:00:02', NULL, NULL, 2)")
tdSql.execute("insert into t_var_null values ('2024-01-01 00:00:03', NULL, NULL, 3)")
tdSql.execute("insert into t_var_null values ('2024-01-01 00:00:04', NULL, NULL, 4)")
tdSql.execute("insert into t_var_null values ('2024-01-01 00:00:05', NULL, NULL, 5)")
tdSql.execute("insert into t_var_null values ('2024-01-01 00:00:06', 'hello', 'world', 6)")
tdSql.execute("insert into t_var_null values ('2024-01-01 00:00:07', 'foo', 'bar', 7)")
tdSql.execute("insert into t_var_null values ('2024-01-01 00:00:08', 'test', 'data', 8)")

# LIMIT 3: keep only the first 3 rows (all NULL in c1/c2)
# This triggers blockDataKeepFirstNRows where all kept var-data rows are NULL
tdSql.query("select * from t_var_null order by ts limit 3")
tdSql.checkRows(3)
tdSql.checkData(0, 1, None)
tdSql.checkData(1, 1, None)
tdSql.checkData(2, 1, None)
tdSql.checkData(0, 2, None)
tdSql.checkData(1, 2, None)
tdSql.checkData(2, 2, None)
tdSql.checkData(0, 3, 1)
tdSql.checkData(1, 3, 2)
tdSql.checkData(2, 3, 3)

# LIMIT 5: all 5 NULL rows
tdSql.query("select * from t_var_null order by ts limit 5")
tdSql.checkRows(5)
for i in range(5):
tdSql.checkData(i, 1, None)
tdSql.checkData(i, 2, None)

# LIMIT 6: 5 NULL + 1 non-NULL — boundary case
tdSql.query("select * from t_var_null order by ts limit 6")
tdSql.checkRows(6)
for i in range(5):
tdSql.checkData(i, 1, None)
tdSql.checkData(5, 1, "hello")
tdSql.checkData(5, 2, "world")

# Also test with OFFSET to hit blockDataTrimFirstRows + blockDataKeepFirstNRows
tdSql.query("select * from t_var_null order by ts limit 2 offset 4")
tdSql.checkRows(2)
tdSql.checkData(0, 1, None) # row index 4 — still NULL
tdSql.checkData(1, 1, "hello") # row index 5

tdLog.info("test_null_varchar_limit passed")
tdStream.dropAllStreamsAndDbs()

def ComputeNull(self):
dbPrefix = "db"
tbPrefix = "tb"
Expand Down
Loading