Skip to content

Commit e6792e2

Browse files
committed
fix(core): prevent authorization error immediately after table created via ILP
1 parent 3e8a461 commit e6792e2

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

core/src/main/java/io/questdb/cairo/CairoEngine.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,7 @@ public void configureThreadLocalReaderPoolSupervisor(@NotNull ResourcePoolSuperv
512512
boolean inVolume
513513
) {
514514
securityContext.authorizeMatViewCreate();
515-
final TableToken matViewToken = createTableOrMatViewUnsecure(mem, blockFileWriter, path, ifNotExists, struct, keepLock, inVolume);
516-
getDdlListener(matViewToken).onTableOrMatViewCreated(securityContext, matViewToken, TableUtils.TABLE_KIND_REGULAR_TABLE);
515+
final TableToken matViewToken = createTableOrMatViewUnsecure(securityContext, mem, blockFileWriter, path, ifNotExists, struct, keepLock, inVolume, TableUtils.TABLE_KIND_REGULAR_TABLE);
517516
final MatViewDefinition matViewDefinition = struct.getMatViewDefinition();
518517
try {
519518
if (matViewGraph.addView(matViewDefinition)) {
@@ -569,9 +568,7 @@ public void configureThreadLocalReaderPoolSupervisor(@NotNull ResourcePoolSuperv
569568
.put(']');
570569
}
571570
securityContext.authorizeTableCreate(tableKind);
572-
final TableToken tableToken = createTableOrMatViewUnsecure(mem, null, path, ifNotExists, struct, keepLock, inVolume);
573-
getDdlListener(tableToken).onTableOrMatViewCreated(securityContext, tableToken, tableKind);
574-
return tableToken;
571+
return createTableOrMatViewUnsecure(securityContext, mem, null, path, ifNotExists, struct, keepLock, inVolume, tableKind);
575572
}
576573

577574
// The reader will ignore close() calls until attached back.
@@ -1659,13 +1656,15 @@ private void createTableOrMatViewUnsafe(MemoryMARW mem, @Nullable BlockFileWrite
16591656
}
16601657

16611658
private @NotNull TableToken createTableOrMatViewUnsecure(
1659+
SecurityContext securityContext,
16621660
MemoryMARW mem,
16631661
@Nullable BlockFileWriter blockFileWriter,
16641662
Path path,
16651663
boolean ifNotExists,
16661664
TableStructure struct,
16671665
boolean keepLock,
1668-
boolean inVolume
1666+
boolean inVolume,
1667+
int tableKind
16691668
) {
16701669
assert !struct.isWalEnabled() || PartitionBy.isPartitioned(struct.getPartitionBy()) : "WAL is only supported for partitioned tables";
16711670
final CharSequence tableName = struct.getTableName();
@@ -1713,6 +1712,7 @@ private void createTableOrMatViewUnsafe(MemoryMARW mem, @Nullable BlockFileWrite
17131712
locked = false;
17141713
LOG.info().$("unlocked [table=").$(tableToken).$("]").$();
17151714
}
1715+
getDdlListener(tableToken).onTableOrMatViewCreated(securityContext, tableToken, tableKind);
17161716
tableNameRegistry.registerName(tableToken);
17171717
} catch (Throwable e) {
17181718
keepLock = false;

core/src/test/java/io/questdb/test/cutlass/http/line/LineHttpSenderTest.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@
2929
import io.questdb.ServerMain;
3030
import io.questdb.cairo.CairoEngine;
3131
import io.questdb.cairo.ColumnType;
32+
import io.questdb.cairo.DefaultDdlListener;
3233
import io.questdb.cairo.MicrosTimestampDriver;
3334
import io.questdb.cairo.NanosTimestampDriver;
35+
import io.questdb.cairo.SecurityContext;
3436
import io.questdb.cairo.TableToken;
3537
import io.questdb.cairo.sql.TableMetadata;
3638
import io.questdb.client.Sender;
@@ -62,6 +64,7 @@
6264
import java.lang.reflect.Array;
6365
import java.time.Instant;
6466
import java.time.temporal.ChronoUnit;
67+
import java.util.concurrent.atomic.AtomicBoolean;
6568

6669
import static io.questdb.PropertyKey.DEBUG_FORCE_RECV_FRAGMENTATION_CHUNK_SIZE;
6770
import static io.questdb.PropertyKey.LINE_HTTP_ENABLED;
@@ -874,6 +877,50 @@ public void testCreateTimestampColumnsWithDesignatedNanosV2() throws Exception {
874877
"1.111\t2025-11-19T10:55:24.123456789Z\t2025-11-19T10:55:24.123456Z\t2025-11-19T10:55:24.123000Z\t2025-11-19T10:55:24.123456799Z\t2025-11-20T10:55:24.123456789Z");
875878
}
876879

880+
@Test
881+
public void testDdlListenerOnTableCreated() throws Exception {
882+
TestUtils.assertMemoryLeak(() -> {
883+
try (final TestServerMain questdb = startWithEnvVariables()) {
884+
final AtomicBoolean failed = new AtomicBoolean();
885+
final CairoEngine engine = questdb.getEngine();
886+
engine.setDdlListener(new DefaultDdlListener() {
887+
@Override
888+
public void onTableOrMatViewCreated(SecurityContext securityContext, TableToken tableToken, int tableKind) {
889+
try {
890+
// assert that this is the expected table name and id
891+
final int tableId = (int) engine.getTableIdGenerator().getCurrentId();
892+
Assert.assertEquals("tab", tableToken.getTableName());
893+
Assert.assertEquals(tableId, tableToken.getTableId());
894+
895+
// assert that the table is not available to others for reading yet
896+
Assert.assertNull(engine.getTableTokenIfExists("tab"));
897+
898+
// assert that others competing to create the same table, cannot lock the table name
899+
Assert.assertNull(engine.lockTableName("tab", tableId, false, true));
900+
} catch (Throwable th) {
901+
th.printStackTrace(System.out);
902+
failed.set(true);
903+
}
904+
}
905+
});
906+
907+
try (Sender sender = Sender.builder(Sender.Transport.HTTP)
908+
.address("localhost:" + questdb.getHttpServerPort())
909+
.build()
910+
) {
911+
sender.table("tab").longColumn("col", 1).atNow();
912+
} catch (Throwable e) {
913+
e.printStackTrace(System.out);
914+
Assert.fail("Failed to ingest data, check log for exception");
915+
}
916+
917+
if (failed.get()) {
918+
Assert.fail("Failed in DDL listener, check log for exception");
919+
}
920+
}
921+
});
922+
}
923+
877924
@Test
878925
public void testEmptyArraysMultiDimensional() throws Exception {
879926
TestUtils.assertMemoryLeak(() -> {

0 commit comments

Comments
 (0)