Skip to content

Commit 003b9dc

Browse files
hayssamsclaude
andcommitted
Support DuckDB 2.0 CONNECT and DISCONNECT statements
Adds CONNECT target [AS alias] and DISCONNECT [name], which route a session's queries to a remote database. Oracle's CONNECT BY is unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EqinwHBKuAtPEmtXr3b5P2
1 parent e088fd6 commit 003b9dc

10 files changed

Lines changed: 307 additions & 0 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement;
11+
12+
/**
13+
* DuckDB's {@code CONNECT target [AS alias]}, which routes the session's queries to a remote
14+
* database.
15+
*/
16+
public class ConnectStatement implements Statement {
17+
private String target;
18+
private String alias;
19+
20+
public ConnectStatement() {}
21+
22+
public ConnectStatement(String target) {
23+
this.target = target;
24+
}
25+
26+
public String getTarget() {
27+
return target;
28+
}
29+
30+
public void setTarget(String target) {
31+
this.target = target;
32+
}
33+
34+
public ConnectStatement withTarget(String target) {
35+
setTarget(target);
36+
return this;
37+
}
38+
39+
public String getAlias() {
40+
return alias;
41+
}
42+
43+
public void setAlias(String alias) {
44+
this.alias = alias;
45+
}
46+
47+
public ConnectStatement withAlias(String alias) {
48+
setAlias(alias);
49+
return this;
50+
}
51+
52+
public StringBuilder appendTo(StringBuilder builder) {
53+
builder.append("CONNECT ").append(target);
54+
if (alias != null) {
55+
builder.append(" AS ").append(alias);
56+
}
57+
return builder;
58+
}
59+
60+
@Override
61+
public String toString() {
62+
return appendTo(new StringBuilder()).toString();
63+
}
64+
65+
@Override
66+
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
67+
return statementVisitor.visit(this, context);
68+
}
69+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement;
11+
12+
/**
13+
* DuckDB's {@code DISCONNECT [name]}, the counterpart of {@link ConnectStatement}.
14+
*/
15+
public class DisconnectStatement implements Statement {
16+
private String name;
17+
18+
public DisconnectStatement() {}
19+
20+
public DisconnectStatement(String name) {
21+
this.name = name;
22+
}
23+
24+
public String getName() {
25+
return name;
26+
}
27+
28+
public void setName(String name) {
29+
this.name = name;
30+
}
31+
32+
public DisconnectStatement withName(String name) {
33+
setName(name);
34+
return this;
35+
}
36+
37+
public StringBuilder appendTo(StringBuilder builder) {
38+
builder.append("DISCONNECT");
39+
if (name != null) {
40+
builder.append(" ").append(name);
41+
}
42+
return builder;
43+
}
44+
45+
@Override
46+
public String toString() {
47+
return appendTo(new StringBuilder()).toString();
48+
}
49+
50+
@Override
51+
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
52+
return statementVisitor.visit(this, context);
53+
}
54+
}

‎src/main/java/net/sf/jsqlparser/statement/StatementFeatureVisitor.java‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,20 @@ public <S> Void visit(DetachStatement detachStatement, S context) {
549549
return null;
550550
}
551551

552+
@Override
553+
public <S> Void visit(ConnectStatement connectStatement, S context) {
554+
analysis.claimTopLevel();
555+
analysis.certain(StmtFeature.MODIFIES_SESSION);
556+
return null;
557+
}
558+
559+
@Override
560+
public <S> Void visit(DisconnectStatement disconnectStatement, S context) {
561+
analysis.claimTopLevel();
562+
analysis.certain(StmtFeature.MODIFIES_SESSION);
563+
return null;
564+
}
565+
552566
@Override
553567
public <S> Void visit(PurgeStatement purgeStatement, S context) {
554568
analysis.claimTopLevel();

‎src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,18 @@ default void visit(DetachStatement detachStatement) {
395395
this.visit(detachStatement, null);
396396
}
397397

398+
<S> T visit(ConnectStatement connectStatement, S context);
399+
400+
default void visit(ConnectStatement connectStatement) {
401+
this.visit(connectStatement, null);
402+
}
403+
404+
<S> T visit(DisconnectStatement disconnectStatement, S context);
405+
406+
default void visit(DisconnectStatement disconnectStatement) {
407+
this.visit(disconnectStatement, null);
408+
}
409+
398410
<S> T visit(PurgeStatement purgeStatement, S context);
399411

400412
default void visit(PurgeStatement purgeStatement) {

‎src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,16 @@ public <S> T visit(DetachStatement detachStatement, S context) {
638638
return null;
639639
}
640640

641+
@Override
642+
public <S> T visit(ConnectStatement connectStatement, S context) {
643+
return null;
644+
}
645+
646+
@Override
647+
public <S> T visit(DisconnectStatement disconnectStatement, S context) {
648+
return null;
649+
}
650+
641651
@Override
642652
public <S> T visit(PurgeStatement purgeStatement, S context) {
643653
return null;

‎src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@
213213
import net.sf.jsqlparser.statement.ExtensionStatement;
214214
import net.sf.jsqlparser.statement.AttachStatement;
215215
import net.sf.jsqlparser.statement.DetachStatement;
216+
import net.sf.jsqlparser.statement.ConnectStatement;
217+
import net.sf.jsqlparser.statement.DisconnectStatement;
216218

217219

218220
/**
@@ -2516,6 +2518,28 @@ public void visit(DetachStatement detachStatement) {
25162518
StatementVisitor.super.visit(detachStatement);
25172519
}
25182520

2521+
@Override
2522+
public <S> Void visit(ConnectStatement connectStatement, S context) {
2523+
// no tables involved in this statement
2524+
return null;
2525+
}
2526+
2527+
@Override
2528+
public void visit(ConnectStatement connectStatement) {
2529+
StatementVisitor.super.visit(connectStatement);
2530+
}
2531+
2532+
@Override
2533+
public <S> Void visit(DisconnectStatement disconnectStatement, S context) {
2534+
// no tables involved in this statement
2535+
return null;
2536+
}
2537+
2538+
@Override
2539+
public void visit(DisconnectStatement disconnectStatement) {
2540+
StatementVisitor.super.visit(disconnectStatement);
2541+
}
2542+
25192543
@Override
25202544
public <S> Void visit(PurgeStatement purgeStatement, S context) {
25212545
if (purgeStatement.getPurgeObjectType() == PurgeObjectType.TABLE) {

‎src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@
101101
import net.sf.jsqlparser.statement.ExtensionStatement;
102102
import net.sf.jsqlparser.statement.AttachStatement;
103103
import net.sf.jsqlparser.statement.DetachStatement;
104+
import net.sf.jsqlparser.statement.ConnectStatement;
105+
import net.sf.jsqlparser.statement.DisconnectStatement;
104106

105107
public class StatementDeParser extends AbstractDeParser<Statement>
106108
implements StatementVisitor<StringBuilder> {
@@ -584,6 +586,18 @@ public <S> StringBuilder visit(DetachStatement detachStatement, S context) {
584586
return builder;
585587
}
586588

589+
@Override
590+
public <S> StringBuilder visit(ConnectStatement connectStatement, S context) {
591+
connectStatement.appendTo(builder);
592+
return builder;
593+
}
594+
595+
@Override
596+
public <S> StringBuilder visit(DisconnectStatement disconnectStatement, S context) {
597+
disconnectStatement.appendTo(builder);
598+
return builder;
599+
}
600+
587601
@Override
588602
public <S> StringBuilder visit(PurgeStatement purgeStatement, S context) {
589603
purgeStatement.appendTo(builder);

‎src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@
103103
import net.sf.jsqlparser.statement.ExtensionStatement;
104104
import net.sf.jsqlparser.statement.AttachStatement;
105105
import net.sf.jsqlparser.statement.DetachStatement;
106+
import net.sf.jsqlparser.statement.ConnectStatement;
107+
import net.sf.jsqlparser.statement.DisconnectStatement;
106108

107109
/**
108110
* @author gitmotte
@@ -505,6 +507,18 @@ public <S> Void visit(DetachStatement detachStatement, S context) {
505507
return null;
506508
}
507509

510+
@Override
511+
public <S> Void visit(ConnectStatement connectStatement, S context) {
512+
// TODO: not yet implemented
513+
return null;
514+
}
515+
516+
@Override
517+
public <S> Void visit(DisconnectStatement disconnectStatement, S context) {
518+
// TODO: not yet implemented
519+
return null;
520+
}
521+
508522
@Override
509523
public <S> Void visit(PurgeStatement purgeStatement, S context) {
510524
// TODO: not yet implemented
@@ -737,6 +751,14 @@ public void visit(DetachStatement detachStatement) {
737751
visit(detachStatement, null);
738752
}
739753

754+
public void visit(ConnectStatement connectStatement) {
755+
visit(connectStatement, null);
756+
}
757+
758+
public void visit(DisconnectStatement disconnectStatement) {
759+
visit(disconnectStatement, null);
760+
}
761+
740762
public void visit(PurgeStatement purgeStatement) {
741763
visit(purgeStatement, null);
742764
}

‎src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2952,6 +2952,12 @@ Statement SingleStatement() :
29522952
|
29532953
LOOKAHEAD({ getToken(1).kind == K_DETACH }) stm = DetachStatement()
29542954
|
2955+
LOOKAHEAD({ getToken(1).kind == K_CONNECT && getToken(2).kind != K_BY })
2956+
stm = ConnectStatement()
2957+
|
2958+
LOOKAHEAD({ getToken(1).kind == K_DISCONNECT && getToken(2).kind != K_SESSION })
2959+
stm = DisconnectStatement()
2960+
|
29552961
stm = PurgeStatement()
29562962
|
29572963
stm = SessionStatement()
@@ -4353,6 +4359,43 @@ RenameTableStatement RenameTableStatement(): {
43534359
}
43544360
}
43554361

4362+
/**
4363+
* DuckDB's CONNECT target [AS alias], routing the session to a remote database.
4364+
*/
4365+
ConnectStatement ConnectStatement() #ConnectStatement:
4366+
{
4367+
ConnectStatement connectStatement = new ConnectStatement();
4368+
ObjectNames name;
4369+
Token token;
4370+
}
4371+
{
4372+
<K_CONNECT>
4373+
(
4374+
token=<S_CHAR_LITERAL> { connectStatement.setTarget(token.image); }
4375+
|
4376+
name=RelObjectNames() { connectStatement.setTarget(String.join(".", name.getNames())); }
4377+
)
4378+
[ <K_AS> name=RelObjectNames() { connectStatement.setAlias(String.join(".", name.getNames())); } ]
4379+
{ return connectStatement; }
4380+
}
4381+
4382+
/**
4383+
* DuckDB's DISCONNECT [name].
4384+
*/
4385+
DisconnectStatement DisconnectStatement() #DisconnectStatement:
4386+
{
4387+
DisconnectStatement disconnectStatement = new DisconnectStatement();
4388+
ObjectNames name;
4389+
}
4390+
{
4391+
<K_DISCONNECT>
4392+
[
4393+
LOOKAHEAD(2)
4394+
name=RelObjectNames() { disconnectStatement.setName(String.join(".", name.getNames())); }
4395+
]
4396+
{ return disconnectStatement; }
4397+
}
4398+
43564399
/**
43574400
* DuckDB's ATTACH [DATABASE] [IF NOT EXISTS] path [AS alias] [(options)].
43584401
*/

0 commit comments

Comments
 (0)