fix(mysql): show scheduled events in the sidebar

This commit is contained in:
Melody Ruch
2026-08-19 20:49:32 +08:00
committed by GitHub
parent 5011468a9a
commit 2b11af94ba
26 changed files with 137 additions and 33 deletions
+3 -2
View File
@@ -2161,12 +2161,13 @@ async function handleQuickOpenSelect(item: any) {
tableName: item.objectName || item.tableName,
tableType: item.type === "view" ? "VIEW" : item.type === "materialized_view" ? "MATERIALIZED_VIEW" : "TABLE",
});
} else if (item.type === "procedure" || item.type === "function" || item.type === "trigger" || item.type === "sequence" || item.type === "package" || item.type === "package-body" || item.type === "type" || item.type === "type-body") {
} else if (item.type === "procedure" || item.type === "function" || item.type === "trigger" || item.type === "event" || item.type === "sequence" || item.type === "package" || item.type === "package-body" || item.type === "type" || item.type === "type-body") {
// Open the object source in a source tab
const objectTypeMap: Record<string, ObjectSourceKind> = {
procedure: "PROCEDURE",
function: "FUNCTION",
trigger: "TRIGGER",
event: "EVENT",
sequence: "SEQUENCE",
package: "PACKAGE",
"package-body": "PACKAGE_BODY",
@@ -2193,7 +2194,7 @@ async function handleQuickOpenSelect(item: any) {
});
const tabId = queryStore.createTab(item.connectionId, item.database, `Source - ${objectName}`);
queryStore.updateSql(tabId, editableSource);
if (item.type !== "sequence" && item.type !== "trigger" && item.type !== "type" && item.type !== "type-body") {
if (item.type !== "sequence" && item.type !== "trigger" && item.type !== "event" && item.type !== "type" && item.type !== "type-body") {
queryStore.setObjectSource(tabId, {
schema,
name: objectName,
@@ -317,9 +317,9 @@ watch([deferredSearchQuery, regexMode], ([newQuery, isRegexMode], [oldQuery, was
});
});
const searchableObjectGroupTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
const searchableObjectGroupTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-events", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
const simpleObjectParentTypes = new Set<TreeNodeType>(["database", "schema", "linked-server-schema"]);
const simpleObjectChildTypes = new Set<TreeNodeType>(["table", "view", "materialized_view", "procedure", "function", "trigger", "sequence", "synonym", "package", "package-body", "type", "type-body", "load-more"]);
const simpleObjectChildTypes = new Set<TreeNodeType>(["table", "view", "materialized_view", "procedure", "function", "trigger", "event", "sequence", "synonym", "package", "package-body", "type", "type-body", "load-more"]);
function isSimpleObjectSearchParent(node: TreeNode): boolean {
return settingsStore.editorSettings.sidebarObjectDisplay === "simple" && simpleObjectParentTypes.has(node.type) && node.isExpanded === true && (!!node.children?.some((child) => simpleObjectChildTypes.has(child.type)) || !!store.sidebarTableSearchQueries[node.id]?.trim());
@@ -593,6 +593,7 @@ const groupTypes: Set<TreeNodeType> = new Set([
"group-indexes",
"group-fkeys",
"group-triggers",
"group-events",
"group-constraints",
"group-table-partitions",
"group-table-subpartitions",
@@ -5252,7 +5253,7 @@ function buildObjectSidebarMenu(context: SidebarMenuFactoryContext): boolean {
return true;
}
if (node.type === "sequence") {
if (node.type === "sequence" || node.type === "event") {
items.push({ label: t("contextMenu.viewSource"), action: () => openObjectSourceDialog(false), icon: Code2 });
items.push({ label: t("contextMenu.copyName"), action: copyName, icon: Copy, shortcut: shortcutCopyName.value });
items.push({ label: t("contextMenu.changeOpenMode"), action: () => emit("open-settings", "navigation"), icon: Settings2 });
@@ -16,6 +16,7 @@ import {
Link,
Link2,
Zap,
Clock,
ListTree,
FileCode,
Network,
@@ -252,6 +253,8 @@ function getIconInfo(node: TreeNode): { icon: any; colorClass: string } | null {
return { icon: Link, colorClass: "text-blue-400" };
case "group-triggers":
return { icon: Zap, colorClass: "text-orange-400" };
case "group-events":
return { icon: Clock, colorClass: "text-orange-400" };
case "group-constraints":
return { icon: Key, colorClass: "text-amber-500" };
case "group-table-partitions":
@@ -279,6 +282,8 @@ function getIconInfo(node: TreeNode): { icon: any; colorClass: string } | null {
return { icon: Link, colorClass: "text-blue-300" };
case "trigger":
return { icon: Zap, colorClass: "text-orange-300" };
case "event":
return { icon: Clock, colorClass: "text-orange-300" };
case "redis-db":
return { icon: Database, colorClass: "text-red-400" };
case "mq-tenant":
@@ -1418,6 +1423,7 @@ function onKeydown(event: KeyboardEvent) {
node.type === 'group-procedures' ||
node.type === 'group-functions' ||
node.type === 'group-triggers' ||
node.type === 'group-events' ||
node.type === 'group-sequences' ||
node.type === 'group-synonyms' ||
node.type === 'group-packages' ||
@@ -431,6 +431,24 @@ describe("TreeItem load-more activation", () => {
});
});
describe("TreeItem object counts", () => {
it("renders the event group count", async () => {
const node: TreeNode = {
id: "connection-1:app:__events",
label: "tree.events",
type: "group-events",
connectionId: "connection-1",
database: "app",
objectCount: 17,
children: [],
};
const { row } = await mountTreeItem(node);
expect(row.textContent).toContain("17");
});
});
describe("TreeItem searched connection activation", () => {
function searchedConnection(): TreeNode {
const filtered = filterSidebarTree(
+1
View File
@@ -3027,6 +3027,7 @@ export default {
indexes: "Indexes",
foreignKeys: "Foreign Keys",
triggers: "Triggers",
events: "Events",
constraints: "Constraints",
tables: "Tables",
doltSystemTables: "Dolt System Tables",
+1
View File
@@ -2956,6 +2956,7 @@ export default withEnglishFallback({
indexes: "Índices",
foreignKeys: "Claves foráneas",
triggers: "Disparadores",
events: "Eventos",
constraints: "Restricciones",
tables: "Tablas",
tableNameFilterActive: "filtrado",
+1
View File
@@ -2954,6 +2954,7 @@ export default withEnglishFallback({
indexes: "Indici",
foreignKeys: "Chiavi Esterne",
triggers: "Trigger",
events: "Eventi",
constraints: "Vincoli",
tables: "Tabelle",
tableNameFilterActive: "filtrato",
+1
View File
@@ -2980,6 +2980,7 @@ export default withEnglishFallback({
indexes: "インデックス",
foreignKeys: "外部キー",
triggers: "トリガー",
events: "イベント",
constraints: "制約",
tables: "テーブル",
tableNameFilterActive: "フィルターあり",
+1
View File
@@ -2859,6 +2859,7 @@ export default withEnglishFallback({
indexes: "인덱스",
foreignKeys: "외래 키",
triggers: "트리거",
events: "이벤트",
constraints: "제약 조건",
tables: "테이블",
tableNameFilterActive: "필터됨",
+1
View File
@@ -2957,6 +2957,7 @@ export default withEnglishFallback({
indexes: "Índices",
foreignKeys: "Chaves estrangeiras",
triggers: "Triggers",
events: "Eventos",
constraints: "Restrições",
tables: "Tabelas",
tableNameFilterActive: "filtrado",
+1
View File
@@ -2951,6 +2951,7 @@ export default withEnglishFallback({
indexes: "索引",
foreignKeys: "外键",
triggers: "触发器",
events: "事件",
constraints: "约束",
tables: "表",
doltSystemTables: "Dolt 系统表",
+1
View File
@@ -2956,6 +2956,7 @@ export default withEnglishFallback({
indexes: "索引",
foreignKeys: "外鍵",
triggers: "觸發器",
events: "事件",
constraints: "約束",
tables: "資料表",
doltSystemTables: "Dolt 系統資料表",
@@ -39,8 +39,8 @@ describe("databaseObjectCapabilities", () => {
});
it("exposes triggers only for native MySQL among MySQL-compatible paths", () => {
expect(sidebarObjectKindsForDatabase("mysql")).toEqual(["TABLE", "VIEW", "PROCEDURE", "FUNCTION", "TRIGGER"]);
expect(databaseObjectCapabilities("mysql").sourceReadable).toEqual(["VIEW", "PROCEDURE", "FUNCTION", "TRIGGER"]);
expect(sidebarObjectKindsForDatabase("mysql")).toEqual(["TABLE", "VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "EVENT"]);
expect(databaseObjectCapabilities("mysql").sourceReadable).toEqual(["VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "EVENT"]);
expect(sidebarObjectKindsForDatabase("doris")).toEqual(["TABLE", "VIEW"]);
expect(sidebarObjectKindsForDatabase("starrocks")).toEqual(["TABLE", "VIEW", "MATERIALIZED_VIEW"]);
+10
View File
@@ -248,6 +248,16 @@ describe("programmable database objects", () => {
]);
});
it("groups MySQL scheduled events under a dedicated Events group", () => {
const objects: ObjectInfo[] = [{ name: "event_daily_middle_db_sync", object_type: "EVENT", schema: "shop" }];
const groups = buildGroupedObjectTreeNodes({ ...context, schema: "shop", objects, databaseType: "mysql" });
const eventGroup = groups.find((node) => node.type === "group-events");
expect(eventGroup).toEqual(expect.objectContaining({ objectCount: 1, label: "tree.events" }));
expect(eventGroup?.children).toEqual([expect.objectContaining({ type: "event", objectName: "event_daily_middle_db_sync" })]);
});
it("keeps table-scoped Kingbase triggers distinct and source-addressable", () => {
const objects: ObjectInfo[] = [
{ name: "audit_before", object_type: "TRIGGER", schema: "public", parent_schema: "public", parent_name: "items" },
@@ -1,6 +1,6 @@
import type { DatabaseType } from "@/types/database";
export type SidebarObjectKind = "TABLE" | "VIEW" | "MATERIALIZED_VIEW" | "PROCEDURE" | "FUNCTION" | "TRIGGER" | "SEQUENCE" | "SYNONYM" | "PACKAGE" | "PACKAGE_BODY" | "TYPE" | "TYPE_BODY";
export type SidebarObjectKind = "TABLE" | "VIEW" | "MATERIALIZED_VIEW" | "PROCEDURE" | "FUNCTION" | "TRIGGER" | "EVENT" | "SEQUENCE" | "SYNONYM" | "PACKAGE" | "PACKAGE_BODY" | "TYPE" | "TYPE_BODY";
export interface DatabaseObjectCapabilities {
sidebarObjects: SidebarObjectKind[];
@@ -12,7 +12,7 @@ const TABLE_VIEW_OBJECTS: SidebarObjectKind[] = ["TABLE", "VIEW"];
const TABLE_VIEW_MV_OBJECTS: SidebarObjectKind[] = ["TABLE", "VIEW", "MATERIALIZED_VIEW"];
const ROUTINE_OBJECTS: SidebarObjectKind[] = ["TABLE", "VIEW", "PROCEDURE", "FUNCTION"];
const MYSQL_OBJECTS: SidebarObjectKind[] = ["TABLE", "VIEW", "PROCEDURE", "FUNCTION", "TRIGGER"];
const MYSQL_OBJECTS: SidebarObjectKind[] = ["TABLE", "VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "EVENT"];
// PostgreSQL-family databases with a verified pg_type listing path. TYPE only
// covers user-created types (enum/domain/composite/range/multirange/base);
@@ -157,6 +157,7 @@ export function normalizeSidebarObjectKind(type: string): SidebarObjectKind {
if (normalized.includes("TYPE_BODY")) return "TYPE_BODY";
if (normalized.includes("PACKAGE")) return "PACKAGE";
if (normalized.includes("TRIGGER")) return "TRIGGER";
if (normalized.includes("EVENT")) return "EVENT";
if (normalized.includes("TYPE")) return "TYPE";
if (normalized.includes("MATERIALIZED_VIEW")) return "MATERIALIZED_VIEW";
if (value.includes("VIEW")) return "VIEW";
@@ -54,11 +54,11 @@ const objectBrowserNodeTypes = new Set<TreeNodeType>(["database", "schema", "obj
export function shouldOpenObjectBrowserOnSingleClick(type: TreeNodeType, enabled: boolean): boolean {
return enabled && objectBrowserNodeTypes.has(type);
}
const sourceNodeTypes = new Set<TreeNodeType>(["materialized_view", "procedure", "function", "trigger", "sequence", "synonym", "package", "package-body", "type", "type-body"]);
const sourceNodeTypes = new Set<TreeNodeType>(["materialized_view", "procedure", "function", "trigger", "event", "sequence", "synonym", "package", "package-body", "type", "type-body"]);
const savedSqlNodeTypes = new Set<TreeNodeType>(["saved-sql-file"]);
const tableChildGroupNodeTypes = new Set<TreeNodeType>(["group-columns", "group-indexes", "group-fkeys", "group-triggers", "group-constraints", "group-partitions", "group-table-partitions", "group-table-subpartitions"]);
const databaseChildGroupNodeTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
const displayPathObjectNodeTypes = new Set<TreeNodeType>(["table", "view", "materialized_view", "procedure", "function", "trigger"]);
const databaseChildGroupNodeTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-events", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
const displayPathObjectNodeTypes = new Set<TreeNodeType>(["table", "view", "materialized_view", "procedure", "function", "trigger", "event"]);
export function objectSourceKindForTreeNode(type: TreeNodeType): ObjectSourceKind | null {
if (type === "view") return "VIEW";
@@ -66,6 +66,7 @@ export function objectSourceKindForTreeNode(type: TreeNodeType): ObjectSourceKin
if (type === "procedure") return "PROCEDURE";
if (type === "function") return "FUNCTION";
if (type === "trigger") return "TRIGGER";
if (type === "event") return "EVENT";
if (type === "sequence") return "SEQUENCE";
if (type === "synonym") return "SYNONYM";
if (type === "package") return "PACKAGE";
@@ -5,6 +5,7 @@ const treeGroupNodeTypes = new Set<TreeNodeType>([
"group-indexes",
"group-fkeys",
"group-triggers",
"group-events",
"group-constraints",
"group-table-partitions",
"group-table-subpartitions",
+5 -1
View File
@@ -1,5 +1,5 @@
import type { Component } from "vue";
import { Archive, Braces, Columns3, Database, Eye, FileCode, FolderClosed, FolderOpen, Gauge, Key, Link, Link2, ListTree, Network, Package, Plus, ScrollText, Server, ShieldCheck, Table, TableProperties, UsersRound, Zap } from "@lucide/vue";
import { Archive, Braces, Clock, Columns3, Database, Eye, FileCode, FolderClosed, FolderOpen, Gauge, Key, Link, Link2, ListTree, Network, Package, Plus, ScrollText, Server, ShieldCheck, Table, TableProperties, UsersRound, Zap } from "@lucide/vue";
import type { ColumnInfo, TreeNode } from "@/types/database";
export type TreeNodeIconInfo = {
@@ -68,6 +68,10 @@ export function getTreeNodeIconInfo(node: TreeNode): TreeNodeIconInfo | null {
return { icon: Zap, colorClass: "text-orange-400" };
case "trigger":
return { icon: Zap, colorClass: "text-orange-300" };
case "group-events":
return { icon: Clock, colorClass: "text-orange-400" };
case "event":
return { icon: Clock, colorClass: "text-orange-300" };
case "group-constraints":
case "constraint":
return { icon: Key, colorClass: "text-amber-500" };
+10 -2
View File
@@ -634,7 +634,7 @@ export function buildSimpleObjectTreeNodes({ nodeId, connectionId, database, sch
for (const obj of coalesceXuguPackageObjects(objects, databaseType)) {
const objectType = normalizeObjectType(obj.object_type);
if (!["TABLE", "VIEW", "MATERIALIZED_VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "SEQUENCE", "SYNONYM", "PACKAGE", "PACKAGE_BODY", "TYPE", "TYPE_BODY"].includes(objectType)) {
if (!["TABLE", "VIEW", "MATERIALIZED_VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "EVENT", "SEQUENCE", "SYNONYM", "PACKAGE", "PACKAGE_BODY", "TYPE", "TYPE_BODY"].includes(objectType)) {
continue;
}
@@ -700,6 +700,7 @@ function simpleObjectNodeType(objectType: DatabaseObjectTreeKind): TreeNodeType
if (objectType === "PROCEDURE") return "procedure";
if (objectType === "FUNCTION") return "function";
if (objectType === "TRIGGER") return "trigger";
if (objectType === "EVENT") return "event";
if (objectType === "SEQUENCE") return "sequence";
if (objectType === "SYNONYM") return "synonym";
if (objectType === "PACKAGE_BODY") return "package-body";
@@ -752,6 +753,13 @@ const groupDefs: Array<{
nodeType: "group-triggers",
childType: "trigger",
},
{
key: "__events",
label: "tree.events",
objectTypes: ["EVENT"],
nodeType: "group-events",
childType: "event",
},
{
key: "__sequences",
label: "tree.sequences",
@@ -782,7 +790,7 @@ const groupDefs: Array<{
},
];
const objectGroupNodeTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
const objectGroupNodeTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-events", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
export function buildObjectGroupPlaceholderNodes({
nodeId,
+1 -1
View File
@@ -1303,7 +1303,7 @@ export const useConnectionStore = defineStore("connection", () => {
// recurse into raw objects, its `meta` too), mirroring the markRaw() treatment
// queryStore already applies to result rows. Containers stay reactive so their
// children / isExpanded / isLoading mutations still drive the UI.
const LEAF_TREE_NODE_TYPES = new Set<TreeNode["type"]>(["column", "index", "fkey", "trigger", "type-member"]);
const LEAF_TREE_NODE_TYPES = new Set<TreeNode["type"]>(["column", "index", "fkey", "trigger", "event", "type-member"]);
function markRawLeafTreeNodes(nodes: TreeNode[]): TreeNode[] {
for (const node of nodes) {
+3 -1
View File
@@ -470,7 +470,7 @@ export interface ObjectStatistics {
total_bytes?: number | null;
}
export type ObjectSourceKind = "VIEW" | "MATERIALIZED_VIEW" | "PROCEDURE" | "FUNCTION" | "TRIGGER" | "SEQUENCE" | "SYNONYM" | "PACKAGE" | "PACKAGE_BODY" | "TYPE" | "TYPE_BODY";
export type ObjectSourceKind = "VIEW" | "MATERIALIZED_VIEW" | "PROCEDURE" | "FUNCTION" | "TRIGGER" | "EVENT" | "SEQUENCE" | "SYNONYM" | "PACKAGE" | "PACKAGE_BODY" | "TYPE" | "TYPE_BODY";
export interface ObjectSource {
name: string;
@@ -911,6 +911,7 @@ export type TreeNodeType =
| "group-indexes"
| "group-fkeys"
| "group-triggers"
| "group-events"
| "group-constraints"
| "group-table-partitions"
| "group-table-subpartitions"
@@ -945,6 +946,7 @@ export type TreeNodeType =
| "index"
| "fkey"
| "trigger"
| "event"
| "constraint"
| "partition"
| "subpartition"
+1
View File
@@ -347,6 +347,7 @@ fn object_type_keyword(object_type: &ObjectSourceKind) -> &'static str {
ObjectSourceKind::Procedure => "PROCEDURE",
ObjectSourceKind::Function => "FUNCTION",
ObjectSourceKind::Trigger => "TRIGGER",
ObjectSourceKind::Event => "EVENT",
ObjectSourceKind::Sequence => "SEQUENCE",
ObjectSourceKind::Synonym => "SYNONYM",
ObjectSourceKind::Package => "PACKAGE",
+53 -13
View File
@@ -2771,16 +2771,16 @@ mod tests {
dameng_object_statistics_rows_only_sql, dameng_object_statistics_user_segments_sql, deduplicate_column_infos,
ephemeral_agent_metadata_session_id, external_driver_uses_mysql_ddl, filter_mongodb_agent_collections,
filter_mysql_system_databases_for_config, filter_object_infos, filter_table_infos, filter_visible_schema_names,
gaussdb_m_view_object_source_sql, gbase8a_object_statistics_sql, is_agent_postgres_metadata_fallback_config,
is_mysql_external_driver_config, is_retryable_metadata_error, metadata_error_action,
metadata_name_or_comment_matches, mysql_database_list_timeout, mysql_external_driver_ddl_from_query_result,
mysql_external_driver_ddl_sql, mysql_object_source_ddl_column_index, mysql_object_source_sql,
mysql_table_list_source_for_config, mysql_table_metadata_catalog, normalize_information_schema_table_type,
oracle_columns_from_query_result, oracle_columns_sql, oracle_object_statistics_dba_segments_sql,
oracle_object_statistics_from_query_result, oracle_object_statistics_rows_only_sql,
oracle_object_statistics_sql, oracle_object_statistics_user_segments_sql,
oracle_table_comment_from_query_result, oracle_table_comment_sql, oracle_table_comments_sql,
presto_like_columns_from_query_result, presto_like_information_schema_columns_sql,
finalize_object_source, gaussdb_m_view_object_source_sql, gbase8a_object_statistics_sql,
is_agent_postgres_metadata_fallback_config, is_mysql_external_driver_config, is_retryable_metadata_error,
metadata_error_action, metadata_name_or_comment_matches, mysql_database_list_timeout,
mysql_external_driver_ddl_from_query_result, mysql_external_driver_ddl_sql,
mysql_object_source_ddl_column_index, mysql_object_source_sql, mysql_table_list_source_for_config,
mysql_table_metadata_catalog, normalize_information_schema_table_type, oracle_columns_from_query_result,
oracle_columns_sql, oracle_object_statistics_dba_segments_sql, oracle_object_statistics_from_query_result,
oracle_object_statistics_rows_only_sql, oracle_object_statistics_sql,
oracle_object_statistics_user_segments_sql, oracle_table_comment_from_query_result, oracle_table_comment_sql,
oracle_table_comments_sql, presto_like_columns_from_query_result, presto_like_information_schema_columns_sql,
presto_like_information_schema_tables_sql, presto_like_tables_from_query_result, replace_metadata_runtime,
should_query_oracle_columns_via_sql_first, table_comments_from_query_result, table_name_filter_matches,
tdengine_table_comment_like_pattern, tdengine_table_comment_sql, tdengine_table_comments_sql,
@@ -3345,6 +3345,27 @@ mod tests {
);
}
#[test]
fn mysql_object_source_sql_emits_show_create_event() {
assert_eq!(
mysql_object_source_sql("tenant_db", "event_daily_sync", &db::ObjectSourceKind::Event),
"SHOW CREATE EVENT `tenant_db`.`event_daily_sync`"
);
}
#[test]
fn mysql_event_object_source_is_read_only() {
let source = finalize_object_source(db::ObjectSource {
name: "event_daily_sync".to_string(),
object_type: db::ObjectSourceKind::Event,
schema: None,
source: "CREATE EVENT event_daily_sync ON SCHEDULE EVERY 1 DAY DO SELECT 1".to_string(),
editable: None,
});
assert_eq!(source.editable, Some(false));
}
#[test]
fn mysql_object_source_sql_emits_show_create_materialized_view() {
// Regression for the review comment: Doris / StarRocks ride on the MySQL
@@ -3373,6 +3394,10 @@ mod tests {
assert_eq!(mysql_object_source_ddl_column_index(&db::ObjectSourceKind::Procedure), 2);
assert_eq!(mysql_object_source_ddl_column_index(&db::ObjectSourceKind::Function), 2);
assert_eq!(mysql_object_source_ddl_column_index(&db::ObjectSourceKind::Trigger), 2);
// SHOW CREATE EVENT returns (Event, sql_mode, time_zone, Create Event, …) —
// one extra time_zone column before the DDL, verified against a real MySQL
// 8.0 instance (`SHOW CREATE EVENT` for a live event).
assert_eq!(mysql_object_source_ddl_column_index(&db::ObjectSourceKind::Event), 3);
}
#[test]
@@ -7235,6 +7260,7 @@ fn sqlite_object_type(kind: &db::ObjectSourceKind) -> &'static str {
db::ObjectSourceKind::Procedure
| db::ObjectSourceKind::Function
| db::ObjectSourceKind::Trigger
| db::ObjectSourceKind::Event
| db::ObjectSourceKind::Sequence
| db::ObjectSourceKind::Synonym
| db::ObjectSourceKind::Package
@@ -7250,7 +7276,8 @@ fn sqlserver_object_type_filter(kind: &db::ObjectSourceKind) -> &'static str {
db::ObjectSourceKind::Procedure => "'P'",
db::ObjectSourceKind::Function => "'FN','IF','TF','FS','FT'",
db::ObjectSourceKind::Trigger => "'TR'",
db::ObjectSourceKind::Sequence
db::ObjectSourceKind::Event
| db::ObjectSourceKind::Sequence
| db::ObjectSourceKind::Synonym
| db::ObjectSourceKind::Package
| db::ObjectSourceKind::PackageBody
@@ -7488,6 +7515,7 @@ fn postgres_object_source_sql_inner(
)
}
db::ObjectSourceKind::Trigger
| db::ObjectSourceKind::Event
| db::ObjectSourceKind::Synonym
| db::ObjectSourceKind::Package
| db::ObjectSourceKind::PackageBody
@@ -7503,6 +7531,7 @@ pub fn oracle_object_source_sql(schema: &str, name: &str, kind: &db::ObjectSourc
db::ObjectSourceKind::Procedure => "PROCEDURE",
db::ObjectSourceKind::Function => "FUNCTION",
db::ObjectSourceKind::Trigger => "TRIGGER",
db::ObjectSourceKind::Event => "EVENT",
db::ObjectSourceKind::Sequence => "SEQUENCE",
db::ObjectSourceKind::Synonym => "SYNONYM",
db::ObjectSourceKind::Package => "PACKAGE",
@@ -7559,6 +7588,7 @@ pub fn mysql_object_source_sql(database: &str, name: &str, kind: &db::ObjectSour
db::ObjectSourceKind::Procedure => format!("SHOW CREATE PROCEDURE {qualified_name}"),
db::ObjectSourceKind::Function => format!("SHOW CREATE FUNCTION {qualified_name}"),
db::ObjectSourceKind::Trigger => format!("SHOW CREATE TRIGGER {qualified_name}"),
db::ObjectSourceKind::Event => format!("SHOW CREATE EVENT {qualified_name}"),
db::ObjectSourceKind::Sequence
| db::ObjectSourceKind::Synonym
| db::ObjectSourceKind::Package
@@ -7585,6 +7615,8 @@ pub fn mysql_object_source_sql(database: &str, name: &str, kind: &db::ObjectSour
/// `(Name, DDL)` → DDL at index `1`.
/// - `SHOW CREATE PROCEDURE`, `SHOW CREATE FUNCTION`, `SHOW CREATE TRIGGER` →
/// `(Name, sql_mode, DDL, …)` → DDL at index `2`.
/// - `SHOW CREATE EVENT` → `(Event, sql_mode, time_zone, Create Event, …)` →
/// DDL at index `3` (it has an extra `time_zone` column before the DDL).
///
/// Encoded as a function so the index can be unit-tested without a live DB.
pub(crate) fn mysql_object_source_ddl_column_index(kind: &db::ObjectSourceKind) -> usize {
@@ -7599,6 +7631,7 @@ pub(crate) fn mysql_object_source_ddl_column_index(kind: &db::ObjectSourceKind)
| db::ObjectSourceKind::PackageBody
| db::ObjectSourceKind::Type
| db::ObjectSourceKind::TypeBody => 2,
db::ObjectSourceKind::Event => 3,
}
}
@@ -7804,7 +7837,7 @@ pub async fn get_object_source_core(
signature: Option<&str>,
relation_name: Option<&str>,
) -> Result<db::ObjectSource, String> {
let mut source = retry_metadata_connection(state, connection_id, Some(database), || {
let source = retry_metadata_connection(state, connection_id, Some(database), || {
get_object_source_once(
state,
connection_id,
@@ -7817,10 +7850,17 @@ pub async fn get_object_source_core(
)
})
.await?;
Ok(finalize_object_source(source))
}
fn finalize_object_source(mut source: db::ObjectSource) -> db::ObjectSource {
if matches!(source.object_type, db::ObjectSourceKind::Procedure | db::ObjectSourceKind::Function) {
source.source = normalize_routine_object_source(source.source);
}
Ok(source)
if matches!(source.object_type, db::ObjectSourceKind::Event) {
source.editable = Some(false);
}
source
}
async fn get_object_source_once(
+4 -3
View File
@@ -7468,9 +7468,10 @@ where
| db::ObjectSourceKind::Synonym
| db::ObjectSourceKind::Package
| db::ObjectSourceKind::PackageBody => object.source.clone(),
db::ObjectSourceKind::Trigger | db::ObjectSourceKind::Type | db::ObjectSourceKind::TypeBody => {
object.source.clone()
}
db::ObjectSourceKind::Trigger
| db::ObjectSourceKind::Event
| db::ObjectSourceKind::Type
| db::ObjectSourceKind::TypeBody => object.source.clone(),
};
let statements = build_executable_object_source_statements(EditableObjectSourceSqlInput {
database_type: DatabaseType::Postgres,
+1
View File
@@ -122,6 +122,7 @@ pub enum ObjectSourceKind {
Procedure,
Function,
Trigger,
Event,
Sequence,
Synonym,
Package,