Skip to content

Commit d1b11b6

Browse files
committed
Add maximum columns per table limit
1 parent 48e0812 commit d1b11b6

4 files changed

Lines changed: 46 additions & 7 deletions

File tree

core/src/main/java/io/questdb/client/cutlass/qwp/protocol/QwpConstants.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ public final class QwpConstants {
6969
* Magic bytes for QWP v1 message: "QWP1" (ASCII).
7070
*/
7171
public static final int MAGIC_MESSAGE = 0x31505751; // "QWP1" in little-endian
72+
/**
73+
* Maximum columns per table. Must match the server-side constant of
74+
* the same name so the client can produce an error before sending to
75+
* the server and finding out.
76+
*/
77+
public static final int MAX_COLUMNS_PER_TABLE = 2048;
7278
/**
7379
* Schema mode: Full schema included.
7480
*/

core/src/main/java/io/questdb/client/cutlass/qwp/protocol/QwpTableBuffer.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,11 @@ private static void assertColumnType(CharSequence name, byte type, ColumnBuffer
371371
}
372372

373373
private ColumnBuffer createColumn(CharSequence name, byte type, boolean useNullBitmap) {
374+
if (columns.size() >= MAX_COLUMNS_PER_TABLE) {
375+
throw new LineSenderException("column count exceeds maximum: " + (columns.size() + 1) +
376+
" (max " + MAX_COLUMNS_PER_TABLE + ")"
377+
);
378+
}
374379
ColumnBuffer col = new ColumnBuffer(Chars.toString(name), type, useNullBitmap);
375380
try {
376381
col.sender = sender;
@@ -1533,6 +1538,13 @@ private static int checkedElementCount(long product) {
15331538
return (int) product;
15341539
}
15351540

1541+
private static int checkedStringOffset(long offset) {
1542+
if (offset > Integer.MAX_VALUE) {
1543+
throw new LineSenderException("string column data exceeds 2 GiB per batch, flush more frequently");
1544+
}
1545+
return (int) offset;
1546+
}
1547+
15361548
private void allocateStorage(byte type) {
15371549
switch (type) {
15381550
case TYPE_BOOLEAN:
@@ -1737,13 +1749,6 @@ private int getOrAddLocalSymbol(CharSequence value) {
17371749
return idx;
17381750
}
17391751

1740-
private static int checkedStringOffset(long offset) {
1741-
if (offset > Integer.MAX_VALUE) {
1742-
throw new LineSenderException("string column data exceeds 2 GiB per batch, flush more frequently");
1743-
}
1744-
return (int) offset;
1745-
}
1746-
17471752
private void markNull(int index) {
17481753
long longAddr = nullBufPtr + ((long) (index >>> 6)) * 8;
17491754
int bitIndex = index & 63;

core/src/test/java/io/questdb/client/test/cutlass/qwp/protocol/QwpConstantsTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,9 @@ public void testMagicBytesValue() {
158158
Assert.assertEquals((byte) ((MAGIC_MESSAGE >> 16) & 0xFF), expected[2]);
159159
Assert.assertEquals((byte) ((MAGIC_MESSAGE >> 24) & 0xFF), expected[3]);
160160
}
161+
162+
@Test
163+
public void testMaxColumnsPerTable() {
164+
Assert.assertEquals(2048, MAX_COLUMNS_PER_TABLE);
165+
}
161166
}

core/src/test/java/io/questdb/client/test/cutlass/qwp/protocol/QwpTableBufferTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,29 @@ public void testGetOrCreateColumnConflictingTypeSlowPath() throws Exception {
980980
});
981981
}
982982

983+
@Test
984+
public void testGetOrCreateColumnThrowsWhenExceedingMaxColumnCount() throws Exception {
985+
assertMemoryLeak(() -> {
986+
try (QwpTableBuffer table = new QwpTableBuffer("test")) {
987+
for (int i = 0; i < QwpConstants.MAX_COLUMNS_PER_TABLE; i++) {
988+
table.getOrCreateColumn("c" + i, QwpConstants.TYPE_LONG, false);
989+
}
990+
assertEquals(QwpConstants.MAX_COLUMNS_PER_TABLE, table.getColumnCount());
991+
try {
992+
table.getOrCreateColumn("overflow", QwpConstants.TYPE_LONG, false);
993+
fail("Expected LineSenderException for exceeding max column count");
994+
} catch (LineSenderException e) {
995+
assertEquals(
996+
"column count exceeds maximum: " + (QwpConstants.MAX_COLUMNS_PER_TABLE + 1)
997+
+ " (max " + QwpConstants.MAX_COLUMNS_PER_TABLE + ")",
998+
e.getMessage()
999+
);
1000+
}
1001+
assertEquals(QwpConstants.MAX_COLUMNS_PER_TABLE, table.getColumnCount());
1002+
}
1003+
});
1004+
}
1005+
9831006
@Test
9841007
public void testLongArrayMultipleRows() throws Exception {
9851008
assertMemoryLeak(() -> {

0 commit comments

Comments
 (0)