feat: add DM (Dameng) database support via ODBC
Connect to DM8 databases using the odbc-api crate with unixODBC. Includes schema browsing, query execution, DDL generation, and full frontend integration with download link to DM ODBC driver.
This commit is contained in:
1 parent
02813f4b9e
commit
4bf4f3b77f
24 files changed
+1111
-122
No files matched your search
@@ -166,7 +166,7 @@ const driverProfiles: Record<
|
||||
label: "CockroachDB",
|
||||
icon: "cockroachdb",
|
||||
},
|
||||
dm: { type: "postgres", port: 5236, user: "SYSDBA", label: "DM (Dameng)", icon: "dm" },
|
||||
dm: { type: "dameng", port: 5236, user: "SYSDBA", label: "DM (Dameng)", icon: "dm" },
|
||||
tdengine: { type: "mysql", port: 6030, user: "root", label: "TDengine", icon: "tdengine" },
|
||||
custom_mysql: {
|
||||
type: "mysql",
|
||||
@@ -322,6 +322,7 @@ const dbOptions = [
|
||||
{ value: "oracle", label: "Oracle" },
|
||||
{ value: "elasticsearch", label: "Elasticsearch" },
|
||||
{ value: "mariadb", label: "MariaDB" },
|
||||
{ value: "dm", label: "DM (Dameng)" },
|
||||
];
|
||||
|
||||
const mysqlCompat = [
|
||||
@@ -340,7 +341,6 @@ const pgCompat = [
|
||||
{ value: "gaussdb", label: "GaussDB" },
|
||||
{ value: "kingbase", label: "KingBase" },
|
||||
{ value: "vastbase", label: "Vastbase" },
|
||||
{ value: "dm", label: "DM (Dameng)" },
|
||||
{ value: "redshift", label: "Redshift" },
|
||||
{ value: "cockroachdb", label: "CockroachDB" },
|
||||
{ value: "custom_postgres", label: "Custom" },
|
||||
@@ -844,6 +844,13 @@ async function browseDbFilePath() {
|
||||
<span />
|
||||
<p class="col-span-3 text-xs text-muted-foreground">
|
||||
{{ t("connection.dmCompatHint") }}
|
||||
<a
|
||||
href="https://eco.dameng.com/download/"
|
||||
target="_blank"
|
||||
class="underline text-primary hover:text-primary/80"
|
||||
>
|
||||
{{ t("connection.dmDownload") }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ const props = defineProps<{
|
||||
focusTableName?: string;
|
||||
}>();
|
||||
|
||||
const SQL_TYPES: DatabaseType[] = ["mysql", "postgres", "sqlite", "sqlserver", "oracle", "redshift"];
|
||||
const SCHEMA_AWARE_TYPES: DatabaseType[] = ["postgres", "sqlserver", "oracle", "redshift"];
|
||||
const SQL_TYPES: DatabaseType[] = ["mysql", "postgres", "sqlite", "sqlserver", "oracle", "redshift", "dameng"];
|
||||
const SCHEMA_AWARE_TYPES: DatabaseType[] = ["postgres", "sqlserver", "oracle", "redshift", "dameng"];
|
||||
const CARD_WIDTH = 270;
|
||||
const COLUMN_ROW_HEIGHT = 24;
|
||||
const CARD_HEADER_HEIGHT = 44;
|
||||
|
||||
@@ -76,7 +76,8 @@ async function resolveSchema(connectionId: string, database: string): Promise<st
|
||||
config?.db_type === "postgres" ||
|
||||
config?.db_type === "sqlserver" ||
|
||||
config?.db_type === "oracle" ||
|
||||
config?.db_type === "redshift";
|
||||
config?.db_type === "redshift" ||
|
||||
config?.db_type === "dameng";
|
||||
if (needsSchema) {
|
||||
const schemas = await api.listSchemas(connectionId, database);
|
||||
return schemas.includes("public") ? "public" : (schemas[0] ?? "");
|
||||
|
||||
@@ -54,7 +54,7 @@ type SearchTableTask = {
|
||||
table: TableInfo;
|
||||
};
|
||||
|
||||
const SCHEMA_AWARE_TYPES = new Set<DatabaseType>(["postgres", "sqlserver", "oracle", "redshift"]);
|
||||
const SCHEMA_AWARE_TYPES = new Set<DatabaseType>(["postgres", "sqlserver", "oracle", "redshift", "dameng"]);
|
||||
const SYSTEM_SCHEMAS = new Set([
|
||||
"information_schema",
|
||||
"pg_catalog",
|
||||
|
||||
@@ -87,7 +87,7 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const sqlFileUnsupportedTypes = new Set(["redis", "mongodb", "elasticsearch"]);
|
||||
const diagramSupportedTypes = new Set(["mysql", "postgres", "sqlite", "sqlserver", "oracle", "redshift"]);
|
||||
const diagramSupportedTypes = new Set(["mysql", "postgres", "sqlite", "sqlserver", "oracle", "redshift", "dameng"]);
|
||||
const databaseSearchSupportedTypes = new Set([
|
||||
"mysql",
|
||||
"postgres",
|
||||
@@ -97,6 +97,7 @@ const databaseSearchSupportedTypes = new Set([
|
||||
"redshift",
|
||||
"duckdb",
|
||||
"clickhouse",
|
||||
"dameng",
|
||||
]);
|
||||
const tableImportSupportedTypes = new Set([
|
||||
"mysql",
|
||||
@@ -109,9 +110,18 @@ const tableImportSupportedTypes = new Set([
|
||||
"doris",
|
||||
"starrocks",
|
||||
"redshift",
|
||||
"dameng",
|
||||
]);
|
||||
const tableStructureSupportedTypes = new Set(["mysql", "postgres", "sqlite", "sqlserver"]);
|
||||
const fieldLineageSupportedTypes = new Set(["mysql", "postgres", "sqlite", "sqlserver", "oracle", "redshift"]);
|
||||
const fieldLineageSupportedTypes = new Set([
|
||||
"mysql",
|
||||
"postgres",
|
||||
"sqlite",
|
||||
"sqlserver",
|
||||
"oracle",
|
||||
"redshift",
|
||||
"dameng",
|
||||
]);
|
||||
const isExportingDatabase = ref(false);
|
||||
|
||||
function currentDatabaseType(): DatabaseType | undefined {
|
||||
@@ -123,7 +133,7 @@ function quoteIdent(name: string): string {
|
||||
}
|
||||
|
||||
function isSchemaAwareDbType(dbType?: DatabaseType): boolean {
|
||||
return dbType === "postgres" || dbType === "oracle" || dbType === "sqlserver";
|
||||
return dbType === "postgres" || dbType === "oracle" || dbType === "sqlserver" || dbType === "dameng";
|
||||
}
|
||||
|
||||
function qualifiedTableName(tableName: string, schema?: string): string {
|
||||
@@ -277,7 +287,11 @@ async function openData() {
|
||||
if (!config) throw new Error("Connection config not found");
|
||||
|
||||
const qualifiedName =
|
||||
(config.db_type === "postgres" || config.db_type === "oracle" || config.db_type === "sqlserver") && node.schema
|
||||
(config.db_type === "postgres" ||
|
||||
config.db_type === "oracle" ||
|
||||
config.db_type === "sqlserver" ||
|
||||
config.db_type === "dameng") &&
|
||||
node.schema
|
||||
? `${quoteIdent(node.schema)}.${quoteIdent(node.label)}`
|
||||
: quoteIdent(node.label);
|
||||
|
||||
@@ -286,7 +300,7 @@ async function openData() {
|
||||
const pks = columns.filter((c) => c.is_primary_key).map((c) => c.name);
|
||||
const order = pks.length ? ` ORDER BY ${pks.map((pk) => `${quoteIdent(pk)} ASC`).join(", ")}` : "";
|
||||
let sql: string;
|
||||
if (config.db_type === "oracle") {
|
||||
if (config.db_type === "oracle" || config.db_type === "dameng") {
|
||||
sql = `SELECT * FROM ${qualifiedName}${order} FETCH FIRST 100 ROWS ONLY`;
|
||||
} else if (config.db_type === "sqlserver") {
|
||||
sql = `SELECT TOP 100 * FROM ${qualifiedName}${order}`;
|
||||
@@ -462,7 +476,7 @@ async function confirmDuplicateStructure() {
|
||||
sql = `CREATE TABLE ${target} (LIKE ${source} INCLUDING ALL);`;
|
||||
} else if (dbType === "sqlserver") {
|
||||
sql = `SELECT TOP 0 * INTO ${target} FROM ${source};`;
|
||||
} else if (dbType === "oracle") {
|
||||
} else if (dbType === "oracle" || dbType === "dameng") {
|
||||
sql = `CREATE TABLE ${target} AS SELECT * FROM ${source} WHERE 1=0`;
|
||||
} else {
|
||||
sql = `CREATE TABLE ${target} AS SELECT * FROM ${source} WHERE 0;`;
|
||||
@@ -653,7 +667,11 @@ async function exportData(format: "csv" | "json" | "sql") {
|
||||
try {
|
||||
await connectionStore.ensureConnected(node.connectionId);
|
||||
const qualifiedName =
|
||||
(config.db_type === "postgres" || config.db_type === "oracle" || config.db_type === "sqlserver") && node.schema
|
||||
(config.db_type === "postgres" ||
|
||||
config.db_type === "oracle" ||
|
||||
config.db_type === "sqlserver" ||
|
||||
config.db_type === "dameng") &&
|
||||
node.schema
|
||||
? `${quoteIdent(node.schema)}.${quoteIdent(node.label)}`
|
||||
: quoteIdent(node.label);
|
||||
const result = await api.executeQuery(node.connectionId, node.database, `SELECT * FROM ${qualifiedName}`);
|
||||
|
||||
@@ -25,7 +25,16 @@ const props = defineProps<{
|
||||
|
||||
const store = useConnectionStore();
|
||||
|
||||
const SQL_TYPES: DatabaseType[] = ["mysql", "postgres", "sqlite", "sqlserver", "oracle", "clickhouse", "duckdb"];
|
||||
const SQL_TYPES: DatabaseType[] = [
|
||||
"mysql",
|
||||
"postgres",
|
||||
"sqlite",
|
||||
"sqlserver",
|
||||
"oracle",
|
||||
"clickhouse",
|
||||
"duckdb",
|
||||
"dameng",
|
||||
];
|
||||
|
||||
const sqlConnections = computed(() => store.connections.filter((c) => SQL_TYPES.includes(c.db_type)));
|
||||
|
||||
@@ -122,7 +131,10 @@ async function loadTables() {
|
||||
try {
|
||||
const config = store.getConfig(sourceConnectionId.value);
|
||||
const needsSchema =
|
||||
config?.db_type === "postgres" || config?.db_type === "sqlserver" || config?.db_type === "oracle";
|
||||
config?.db_type === "postgres" ||
|
||||
config?.db_type === "sqlserver" ||
|
||||
config?.db_type === "oracle" ||
|
||||
config?.db_type === "dameng";
|
||||
if (needsSchema) {
|
||||
const schemas = await api.listSchemas(sourceConnectionId.value, sourceDatabase.value);
|
||||
sourceSchema.value = schemas.includes("public") ? "public" : (schemas[0] ?? "");
|
||||
@@ -210,7 +222,10 @@ async function startTransfer() {
|
||||
// Auto-detect target schema
|
||||
const targetConfig = store.getConfig(targetConnectionId.value);
|
||||
const targetNeedsSchema =
|
||||
targetConfig?.db_type === "postgres" || targetConfig?.db_type === "sqlserver" || targetConfig?.db_type === "oracle";
|
||||
targetConfig?.db_type === "postgres" ||
|
||||
targetConfig?.db_type === "sqlserver" ||
|
||||
targetConfig?.db_type === "oracle" ||
|
||||
targetConfig?.db_type === "dameng";
|
||||
if (targetNeedsSchema && !targetSchema.value) {
|
||||
try {
|
||||
const schemas = await api.listSchemas(targetConnectionId.value, targetDatabase.value);
|
||||
|
||||
Reference in new issue
Block a user