Skip to content

Commit fc2c2bf

Browse files
committed
fix: support mysql-compatible databases that only support constant values in set statements
1 parent cb9d0b3 commit fc2c2bf

File tree

4 files changed

+96
-3
lines changed

4 files changed

+96
-3
lines changed

crates/atuin-desktop-runtime/src/blocks/mysql.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ pub struct Mysql {
3333

3434
#[builder(default = 0)]
3535
pub auto_refresh: u32,
36+
37+
#[builder(default = false)]
38+
pub skip_sql_mode_init: bool,
3639
}
3740

3841
impl FromDocument for Mysql {
@@ -78,6 +81,12 @@ impl FromDocument for Mysql {
7881
.and_then(|v| v.as_u64())
7982
.unwrap_or(0) as u32,
8083
)
84+
.skip_sql_mode_init(
85+
props
86+
.get("skipSqlModeInit")
87+
.and_then(|v| v.as_bool())
88+
.unwrap_or(false),
89+
)
8190
.build();
8291

8392
Ok(mysql)
@@ -170,7 +179,14 @@ impl SqlBlockBehavior for Mysql {
170179
}
171180

172181
async fn create_pool(&self, uri: String) -> Result<Self::Pool, SqlBlockError> {
173-
let opts = MySqlConnectOptions::from_str(&uri)?;
182+
let mut opts = MySqlConnectOptions::from_str(&uri)?;
183+
184+
// Skip sql_mode initialization for databases that don't support dynamic SET statements
185+
// (e.g., StarRocks, Apache Doris)
186+
if self.skip_sql_mode_init {
187+
opts = opts.pipes_as_concat(false).no_engine_substitution(false);
188+
}
189+
174190
Ok(MySqlPool::connect_with(opts).await?)
175191
}
176192

src/components/runbooks/editor/blocks/MySQL/MySQL.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { DatabaseIcon } from "lucide-react";
2+
import { Switch } from "@heroui/react";
23

34
// @ts-ignore
45
import { createReactBlockSpec } from "@blocknote/react";
@@ -25,6 +26,7 @@ interface SQLProps {
2526
setAutoRefresh: (autoRefresh: number) => void;
2627
setName: (name: string) => void;
2728
setDependency: (dependency: DependencySpec) => void;
29+
setSkipSqlModeInit: (skip: boolean) => void;
2830
onCodeMirrorFocus?: () => void;
2931
}
3032

@@ -38,8 +40,28 @@ const MySQL = ({
3840
collapseQuery,
3941
setCollapseQuery,
4042
setDependency,
43+
setSkipSqlModeInit,
4144
onCodeMirrorFocus,
4245
}: SQLProps) => {
46+
const settingsContent = (
47+
<div className="flex items-center justify-between gap-4">
48+
<div className="flex flex-col">
49+
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
50+
Skip SQL mode initialization
51+
</span>
52+
<span className="text-xs text-gray-500 dark:text-gray-400">
53+
Enable for MySQL-compatible databases like StarRocks or Doris
54+
</span>
55+
</div>
56+
<Switch
57+
size="sm"
58+
isSelected={mysql.skipSqlModeInit}
59+
onValueChange={setSkipSqlModeInit}
60+
isDisabled={!isEditable}
61+
/>
62+
</div>
63+
);
64+
4365
return (
4466
<SQL
4567
block={mysql}
@@ -59,6 +81,8 @@ const MySQL = ({
5981
setCollapseQuery={setCollapseQuery}
6082
setDependency={setDependency}
6183
onCodeMirrorFocus={onCodeMirrorFocus}
84+
settingsContent={settingsContent}
85+
settingsTitle="MySQL Settings"
6286
/>
6387
);
6488
};
@@ -72,6 +96,7 @@ export default createReactBlockSpec(
7296
uri: { default: "" },
7397
autoRefresh: { default: 0 },
7498
dependency: { default: "{}" },
99+
skipSqlModeInit: { default: false },
75100
},
76101
content: "none",
77102
},
@@ -133,6 +158,13 @@ export default createReactBlockSpec(
133158
});
134159
};
135160

161+
const setSkipSqlModeInit = (skip: boolean) => {
162+
editor.updateBlock(block, {
163+
// @ts-ignore
164+
props: { ...block.props, skipSqlModeInit: skip },
165+
});
166+
};
167+
136168
let dependency = DependencySpec.deserialize(block.props.dependency);
137169
let mysql = new MySqlBlock(
138170
block.id,
@@ -141,6 +173,7 @@ export default createReactBlockSpec(
141173
block.props.query,
142174
block.props.uri,
143175
block.props.autoRefresh,
176+
block.props.skipSqlModeInit,
144177
);
145178

146179
return (
@@ -154,6 +187,7 @@ export default createReactBlockSpec(
154187
collapseQuery={collapseQuery}
155188
setCollapseQuery={setCollapseQuery}
156189
setDependency={setDependency}
190+
setSkipSqlModeInit={setSkipSqlModeInit}
157191
onCodeMirrorFocus={handleCodeMirrorFocus}
158192
/>
159193
);

src/lib/blocks/common/SQL.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import {
1212
ButtonGroup,
1313
Tooltip,
1414
DropdownSection,
15+
Modal,
16+
ModalContent,
17+
ModalHeader,
18+
ModalBody,
1519
} from "@heroui/react";
1620
import {
1721
ArrowDownToLineIcon,
@@ -24,6 +28,7 @@ import {
2428
RefreshCwIcon,
2529
Maximize2,
2630
Minimize2,
31+
SettingsIcon,
2732
} from "lucide-react";
2833
import CodeMirror, { Extension } from "@uiw/react-codemirror";
2934
import { langs } from "@uiw/codemirror-extensions-langs";
@@ -77,6 +82,10 @@ interface SQLProps {
7782
setName: (name: string) => void;
7883
setDependency: (dependency: DependencySpec) => void;
7984
onCodeMirrorFocus?: () => void;
85+
86+
// Optional settings content - if provided, shows settings icon + modal
87+
settingsContent?: React.ReactNode;
88+
settingsTitle?: string;
8089
}
8190

8291
const autoRefreshChoices = [
@@ -111,12 +120,15 @@ const SQL = ({
111120
sqlType,
112121
extensions = [],
113122
onCodeMirrorFocus,
123+
settingsContent,
124+
settingsTitle,
114125
}: SQLProps) => {
115126
let editor = useBlockNoteEditor();
116127
const [results, setResults] = useState<SqlBlockExecutionResult | null>(null);
117128
const [queryCount, setQueryCount] = useState<Option<number>>(None);
118129
const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
119130
const [isFullscreenQueryCollapsed, setIsFullscreenQueryCollapsed] = useState<boolean>(false);
131+
const [settingsOpen, setSettingsOpen] = useState<boolean>(false);
120132
const { incrementBadge, decrementBadge } = useContext(TabsContext);
121133

122134
const execution = useBlockExecution(block.id);
@@ -261,6 +273,16 @@ const SQL = ({
261273
<EditableHeading initialText={name} onTextChange={(text) => setName(text)} />
262274
</h1>
263275
<div className="flex flex-row items-center gap-2">
276+
{settingsContent && (
277+
<Tooltip content="Settings">
278+
<button
279+
onClick={() => setSettingsOpen(true)}
280+
className="p-2 hover:bg-default-100 rounded-md"
281+
>
282+
<SettingsIcon size={20} />
283+
</button>
284+
</Tooltip>
285+
)}
264286
<Tooltip content={isFullscreen ? "Exit fullscreen" : "Open in fullscreen"}>
265287
<button
266288
onClick={() => setIsFullscreen(!isFullscreen)}
@@ -583,6 +605,24 @@ const SQL = ({
583605
</div>
584606
</div>
585607
)}
608+
609+
{/* Settings Modal */}
610+
{settingsContent && (
611+
<Modal
612+
isOpen={settingsOpen}
613+
onClose={() => setSettingsOpen(false)}
614+
size="sm"
615+
>
616+
<ModalContent>
617+
<ModalHeader className="text-base font-medium">
618+
{settingsTitle || "Settings"}
619+
</ModalHeader>
620+
<ModalBody className="pb-6">
621+
{settingsContent}
622+
</ModalBody>
623+
</ModalContent>
624+
</Modal>
625+
)}
586626
</Block>
587627
);
588628
};

src/lib/workflow/blocks/mysql.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ export class MySqlBlock extends Block {
55
query: string;
66
uri: string;
77
autoRefresh: number;
8+
skipSqlModeInit: boolean;
89

910
get typeName() {
1011
return "mysql";
1112
}
1213

13-
constructor(id: string, name: string, dependency: DependencySpec, query: string, uri: string, autoRefresh: number) {
14+
constructor(id: string, name: string, dependency: DependencySpec, query: string, uri: string, autoRefresh: number, skipSqlModeInit: boolean = false) {
1415
super(id, name, dependency);
1516

1617
this.query = query;
1718
this.uri = uri;
1819
this.autoRefresh = autoRefresh;
20+
this.skipSqlModeInit = skipSqlModeInit;
1921
}
2022

2123
object() {
@@ -25,6 +27,7 @@ export class MySqlBlock extends Block {
2527
query: this.query,
2628
uri: this.uri,
2729
autoRefresh: this.autoRefresh,
30+
skipSqlModeInit: this.skipSqlModeInit,
2831
};
2932
}
3033

@@ -34,6 +37,6 @@ export class MySqlBlock extends Block {
3437

3538
static deserialize(json: string) {
3639
const data = JSON.parse(json);
37-
return new MySqlBlock(data.id, data.name, data.dependency, data.query, data.uri, data.autoRefresh);
40+
return new MySqlBlock(data.id, data.name, data.dependency, data.query, data.uri, data.autoRefresh, data.skipSqlModeInit ?? false);
3841
}
3942
}

0 commit comments

Comments
 (0)