mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-05 13:27:55 +08:00
@@ -101,6 +101,18 @@ describe('ConnectionModal data source registry', () => {
|
||||
expect(source).toContain('? "gaussdb"');
|
||||
expect(source).toContain('dbType === "gaussdb"');
|
||||
});
|
||||
|
||||
it('exposes GoldenDB in the create-connection picker with MySQL-compatible defaults', () => {
|
||||
expect(source).toContain("case 'goldendb':");
|
||||
expect(source).toContain('return 1523;');
|
||||
expect(source).toContain("key: 'goldendb'");
|
||||
expect(source).toContain("name: 'GoldenDB'");
|
||||
expect(source).toContain('type === "goldendb"');
|
||||
expect(source).toContain("return 'MySQL 兼容 / 分布式事务';");
|
||||
expect(source).toContain('dbType === "goldendb" ? "goldendb" : "mysql"');
|
||||
expect(source).toContain('type === "goldendb" ? "goldendb" : "mysql"');
|
||||
expect(source).toContain('? "goldendb"');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ConnectionModal Redis Sentinel configuration', () => {
|
||||
|
||||
@@ -1458,6 +1458,9 @@ const ConnectionModal: React.FC<{
|
||||
const mysqlDefaultPort = getDefaultPortByType(type);
|
||||
const parsed =
|
||||
parseMultiHostUri(trimmedUri, "mysql") ||
|
||||
parseMultiHostUri(trimmedUri, "goldendb") ||
|
||||
parseMultiHostUri(trimmedUri, "greatdb") ||
|
||||
parseMultiHostUri(trimmedUri, "gdb") ||
|
||||
parseMultiHostUri(trimmedUri, "jdbc:mysql") ||
|
||||
parseMultiHostUri(trimmedUri, "oceanbase") ||
|
||||
parseMultiHostUri(trimmedUri, "jdbc:oceanbase") ||
|
||||
@@ -1909,7 +1912,7 @@ const ConnectionModal: React.FC<{
|
||||
if (isMySQLCompatibleType(dbType)) {
|
||||
const defaultPort = getDefaultPortByType(dbType);
|
||||
const scheme =
|
||||
dbType === "diros" ? "doris" : dbType === "starrocks" ? "starrocks" : dbType === "oceanbase" ? "oceanbase" : "mysql";
|
||||
dbType === "diros" ? "doris" : dbType === "starrocks" ? "starrocks" : dbType === "oceanbase" ? "oceanbase" : dbType === "goldendb" ? "goldendb" : "mysql";
|
||||
if (dbType === "oceanbase") {
|
||||
return `${scheme}://sys%40oracle001:pass@127.0.0.1:${defaultPort}/SERVICE_NAME?protocol=oracle`;
|
||||
}
|
||||
@@ -2053,7 +2056,7 @@ const ConnectionModal: React.FC<{
|
||||
const dbPath = database ? `/${encodeURIComponent(database)}` : "/";
|
||||
const query = params.toString();
|
||||
const scheme =
|
||||
type === "diros" ? "doris" : type === "starrocks" ? "starrocks" : type === "oceanbase" ? "oceanbase" : "mysql";
|
||||
type === "diros" ? "doris" : type === "starrocks" ? "starrocks" : type === "oceanbase" ? "oceanbase" : type === "goldendb" ? "goldendb" : "mysql";
|
||||
return `${scheme}://${encodedAuth}${hosts.join(",")}${dbPath}${query ? `?${query}` : ""}`;
|
||||
}
|
||||
|
||||
@@ -2450,6 +2453,7 @@ const ConnectionModal: React.FC<{
|
||||
: primaryAddress?.port || Number(config.port || defaultPort);
|
||||
const mysqlReplicaHosts =
|
||||
configType === "mysql" ||
|
||||
configType === "goldendb" ||
|
||||
configType === "mariadb" ||
|
||||
configType === "oceanbase" ||
|
||||
configType === "diros" ||
|
||||
|
||||
@@ -514,7 +514,7 @@ const DataViewer: React.FC<{ tab: TabData; isActive?: boolean }> = React.memo(({
|
||||
|
||||
const dbType = resolveDataSourceType(config);
|
||||
const dbTypeLower = String(dbType || '').trim().toLowerCase();
|
||||
const isMySQLFamily = dbTypeLower === 'mysql' || dbTypeLower === 'mariadb' || dbTypeLower === 'oceanbase' || dbTypeLower === 'diros';
|
||||
const isMySQLFamily = dbTypeLower === 'mysql' || dbTypeLower === 'goldendb' || dbTypeLower === 'mariadb' || dbTypeLower === 'oceanbase' || dbTypeLower === 'diros';
|
||||
const normalizedQuickWhereCondition = normalizeQuickWhereCondition(quickWhereCondition);
|
||||
const quickWhereValidation = validateQuickWhereCondition(normalizedQuickWhereCondition);
|
||||
if (!quickWhereValidation.ok) {
|
||||
|
||||
@@ -53,6 +53,13 @@ describe('DatabaseIcons', () => {
|
||||
expect(markup).toContain('>GS</text>');
|
||||
});
|
||||
|
||||
it('includes GoldenDB in the selectable database icons', () => {
|
||||
expect(DB_ICON_TYPES).toContain('goldendb');
|
||||
expect(getDbIconLabel('goldendb')).toBe('GoldenDB');
|
||||
const markup = renderToStaticMarkup(<>{getDbIcon('goldendb', undefined, 22)}</>);
|
||||
expect(markup).toContain('>GD</text>');
|
||||
});
|
||||
|
||||
it('wraps database icons in a consistent frame for sidebar sizing', () => {
|
||||
const mysqlMarkup = renderToStaticMarkup(<>{getDbIcon('mysql', undefined, 22)}</>);
|
||||
const jvmMarkup = renderToStaticMarkup(<>{getDbIcon('jvm', undefined, 22)}</>);
|
||||
|
||||
@@ -47,6 +47,7 @@ const DB_DEFAULT_COLORS: Record<string, string> = {
|
||||
vastbase: '#0066CC',
|
||||
opengauss: '#2446A8',
|
||||
gaussdb: '#0B7FAB',
|
||||
goldendb: '#D97706',
|
||||
highgo: '#00A86B',
|
||||
iris: '#1F6FEB',
|
||||
tdengine: '#2962FF',
|
||||
@@ -177,6 +178,9 @@ const OpenGaussIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
const GaussDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.gaussdb} label="GS" />
|
||||
);
|
||||
const GoldenDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.goldendb} label="GD" />
|
||||
);
|
||||
const HighGoIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.highgo} label="HG" />
|
||||
);
|
||||
@@ -249,6 +253,7 @@ const DB_ICON_MAP: Record<string, React.FC<DbIconProps>> = {
|
||||
vastbase: VastBaseIcon,
|
||||
opengauss: OpenGaussIcon,
|
||||
gaussdb: GaussDBIcon,
|
||||
goldendb: GoldenDBIcon,
|
||||
highgo: HighGoIcon,
|
||||
iris: IrisIcon,
|
||||
tdengine: TDengineIcon,
|
||||
@@ -264,7 +269,7 @@ const DB_ICON_MAP: Record<string, React.FC<DbIconProps>> = {
|
||||
export const DB_ICON_TYPES: string[] = [
|
||||
'mysql', 'mariadb', 'oceanbase', 'postgres', 'redis', 'mongodb', 'jvm',
|
||||
'oracle', 'sqlserver', 'sqlite', 'duckdb', 'clickhouse', 'starrocks',
|
||||
'kingbase', 'dameng', 'vastbase', 'opengauss', 'gaussdb', 'highgo', 'iris', 'tdengine', 'iotdb', 'kafka', 'chroma', 'qdrant', 'elasticsearch', 'custom',
|
||||
'kingbase', 'dameng', 'vastbase', 'opengauss', 'gaussdb', 'goldendb', 'highgo', 'iris', 'tdengine', 'iotdb', 'kafka', 'chroma', 'qdrant', 'elasticsearch', 'custom',
|
||||
];
|
||||
|
||||
/** 该类型是否有品牌 SVG 文件 */
|
||||
@@ -286,7 +291,7 @@ export const getDbIconLabel = (type: string): string => {
|
||||
sqlserver: 'SQL Server', clickhouse: 'ClickHouse', sqlite: 'SQLite',
|
||||
starrocks: 'StarRocks',
|
||||
duckdb: 'DuckDB', kingbase: '金仓', dameng: '达梦',
|
||||
vastbase: 'VastBase', opengauss: 'OpenGauss', gaussdb: 'GaussDB', highgo: '瀚高', iris: 'InterSystems IRIS', tdengine: 'TDengine', iotdb: 'Apache IoTDB', kafka: 'Kafka',
|
||||
vastbase: 'VastBase', opengauss: 'OpenGauss', gaussdb: 'GaussDB', goldendb: 'GoldenDB', highgo: '瀚高', iris: 'InterSystems IRIS', tdengine: 'TDengine', iotdb: 'Apache IoTDB', kafka: 'Kafka',
|
||||
chroma: 'Chroma',
|
||||
qdrant: 'Qdrant',
|
||||
elasticsearch: 'Elasticsearch',
|
||||
|
||||
@@ -96,13 +96,14 @@ const DefinitionViewer: React.FC<DefinitionViewerProps> = ({ tab }) => {
|
||||
if (type === 'custom') {
|
||||
const driver = String(conn?.config?.driver || '').trim().toLowerCase();
|
||||
if (driver === 'diros' || driver === 'doris') return 'mysql';
|
||||
if (driver === 'goldendb' || driver === 'greatdb' || driver === 'gdb') return 'mysql';
|
||||
if (driver === 'oceanbase') return normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle' ? 'oracle' : 'mysql';
|
||||
if (driver === 'opengauss' || driver === 'open_gauss' || driver === 'open-gauss') return 'opengauss';
|
||||
if (driver === 'gaussdb' || driver === 'gauss_db' || driver === 'gauss-db') return 'gaussdb';
|
||||
return driver;
|
||||
}
|
||||
if (type === 'oceanbase' && normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle') return 'oracle';
|
||||
if (type === 'mariadb' || type === 'oceanbase' || type === 'diros' || type === 'sphinx') return 'mysql';
|
||||
if (type === 'goldendb' || type === 'mariadb' || type === 'oceanbase' || type === 'diros' || type === 'sphinx') return 'mysql';
|
||||
if (type === 'dameng') return 'dm';
|
||||
return type;
|
||||
};
|
||||
|
||||
@@ -186,7 +186,7 @@ const isSystemMetadataQueryResult = (tableRef: QueryResultTableRef, dbType: stri
|
||||
const metadataDbName = stripQueryIdentifierQuotes(tableRef.metadataDbName).toLowerCase();
|
||||
const metadataTableName = stripQueryIdentifierQuotes(tableRef.metadataTableName).toLowerCase();
|
||||
|
||||
if (['mysql', 'mariadb', 'oceanbase', 'diros', 'starrocks', 'sphinx', 'tidb'].includes(normalizedDbType)) {
|
||||
if (['mysql', 'goldendb', 'mariadb', 'oceanbase', 'diros', 'starrocks', 'sphinx', 'tidb'].includes(normalizedDbType)) {
|
||||
return MYSQL_SYSTEM_METADATA_SCHEMAS.has(metadataDbName);
|
||||
}
|
||||
if (['postgres', 'kingbase', 'highgo', 'vastbase', 'opengauss', 'gaussdb'].includes(normalizedDbType)) {
|
||||
|
||||
@@ -120,13 +120,14 @@ const getMetadataDialect = (connType: string, driver?: string, oceanBaseProtocol
|
||||
if (type === 'custom') {
|
||||
const d = (driver || '').trim().toLowerCase();
|
||||
if (d === 'diros' || d === 'doris') return 'mysql';
|
||||
if (d === 'goldendb' || d === 'greatdb' || d === 'gdb') return 'mysql';
|
||||
if (d === 'oceanbase') return normalizeOceanBaseProtocol(oceanBaseProtocol) === 'oracle' ? 'oracle' : 'mysql';
|
||||
if (d === 'opengauss' || d === 'open_gauss' || d === 'open-gauss') return 'opengauss';
|
||||
if (d === 'gaussdb' || d === 'gauss_db' || d === 'gauss-db') return 'gaussdb';
|
||||
return d;
|
||||
}
|
||||
if (type === 'oceanbase' && normalizeOceanBaseProtocol(oceanBaseProtocol) === 'oracle') return 'oracle';
|
||||
if (type === 'mariadb' || type === 'oceanbase' || type === 'diros' || type === 'sphinx') return 'mysql';
|
||||
if (type === 'goldendb' || type === 'mariadb' || type === 'oceanbase' || type === 'diros' || type === 'sphinx') return 'mysql';
|
||||
if (type === 'dameng') return 'dm';
|
||||
return type;
|
||||
};
|
||||
|
||||
@@ -136,13 +136,14 @@ const TriggerViewer: React.FC<TriggerViewerProps> = ({ tab }) => {
|
||||
if (type === 'custom') {
|
||||
const driver = String(conn?.config?.driver || '').trim().toLowerCase();
|
||||
if (driver === 'diros' || driver === 'doris') return 'mysql';
|
||||
if (driver === 'goldendb' || driver === 'greatdb' || driver === 'gdb') return 'mysql';
|
||||
if (driver === 'oceanbase') return normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle' ? 'oracle' : 'mysql';
|
||||
if (driver === 'opengauss' || driver === 'open_gauss' || driver === 'open-gauss') return 'opengauss';
|
||||
if (driver === 'gaussdb' || driver === 'gauss_db' || driver === 'gauss-db') return 'gaussdb';
|
||||
return driver;
|
||||
}
|
||||
if (type === 'oceanbase' && normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle') return 'oracle';
|
||||
if (type === 'mariadb' || type === 'oceanbase' || type === 'diros' || type === 'sphinx') return 'mysql';
|
||||
if (type === 'goldendb' || type === 'mariadb' || type === 'oceanbase' || type === 'diros' || type === 'sphinx') return 'mysql';
|
||||
if (type === 'dameng') return 'dm';
|
||||
return type;
|
||||
};
|
||||
|
||||
@@ -5,12 +5,14 @@ import { supportsTableTruncateAction } from './tableDataDangerActions';
|
||||
describe('tableDataDangerActions', () => {
|
||||
it('supports native truncate for known relational dialects', () => {
|
||||
expect(supportsTableTruncateAction('mysql')).toBe(true);
|
||||
expect(supportsTableTruncateAction('goldendb')).toBe(true);
|
||||
expect(supportsTableTruncateAction('oceanbase')).toBe(true);
|
||||
expect(supportsTableTruncateAction('postgres')).toBe(true);
|
||||
expect(supportsTableTruncateAction('opengauss')).toBe(true);
|
||||
expect(supportsTableTruncateAction('gaussdb')).toBe(true);
|
||||
expect(supportsTableTruncateAction('iris')).toBe(true);
|
||||
expect(supportsTableTruncateAction('custom', 'postgresql')).toBe(true);
|
||||
expect(supportsTableTruncateAction('custom', 'greatdb')).toBe(true);
|
||||
expect(supportsTableTruncateAction('custom', 'gauss_db')).toBe(true);
|
||||
expect(supportsTableTruncateAction('custom', 'kingbase8')).toBe(true);
|
||||
expect(supportsTableTruncateAction('custom', 'intersystemsiris')).toBe(true);
|
||||
|
||||
@@ -17,6 +17,10 @@ const resolveCustomDriverDialect = (driver: string): string => {
|
||||
case 'gauss_db':
|
||||
case 'gauss-db':
|
||||
return 'gaussdb';
|
||||
case 'goldendb':
|
||||
case 'greatdb':
|
||||
case 'gdb':
|
||||
return 'goldendb';
|
||||
case 'dm':
|
||||
case 'dameng':
|
||||
case 'dm8':
|
||||
@@ -54,6 +58,7 @@ const resolveCustomDriverDialect = (driver: string): string => {
|
||||
|
||||
if (normalized.includes('opengauss') || normalized.includes('open_gauss') || normalized.includes('open-gauss')) return 'opengauss';
|
||||
if (normalized.includes('gaussdb') || normalized.includes('gauss_db') || normalized.includes('gauss-db')) return 'gaussdb';
|
||||
if (normalized.includes('goldendb') || normalized.includes('greatdb')) return 'goldendb';
|
||||
if (normalized.includes('postgres')) return 'postgres';
|
||||
if (normalized.includes('oceanbase')) return 'oceanbase';
|
||||
if (normalized.includes('kingbase')) return 'kingbase';
|
||||
@@ -78,6 +83,7 @@ export const resolveTableDataActionDBType = (type: string, driver?: string): str
|
||||
export const supportsTableTruncateAction = (type: string, driver?: string): boolean => {
|
||||
switch (resolveTableDataActionDBType(type, driver)) {
|
||||
case 'mysql':
|
||||
case 'goldendb':
|
||||
case 'mariadb':
|
||||
case 'oceanbase':
|
||||
case 'starrocks':
|
||||
|
||||
@@ -279,6 +279,7 @@ const resolveOceanBaseProtocol = (
|
||||
};
|
||||
const SUPPORTED_CONNECTION_TYPES = new Set([
|
||||
"mysql",
|
||||
"goldendb",
|
||||
"mariadb",
|
||||
"oceanbase",
|
||||
"doris",
|
||||
@@ -309,6 +310,7 @@ const SUPPORTED_CONNECTION_TYPES = new Set([
|
||||
]);
|
||||
const SSL_SUPPORTED_CONNECTION_TYPES = new Set([
|
||||
"mysql",
|
||||
"goldendb",
|
||||
"mariadb",
|
||||
"oceanbase",
|
||||
"diros",
|
||||
@@ -338,6 +340,8 @@ const getDefaultPortByType = (type: string): number => {
|
||||
case "mysql":
|
||||
case "mariadb":
|
||||
return 3306;
|
||||
case "goldendb":
|
||||
return 1523;
|
||||
case "oceanbase":
|
||||
return 2881;
|
||||
case "doris":
|
||||
@@ -529,6 +533,9 @@ const normalizeConnectionType = (value: unknown): string => {
|
||||
if (type === "gaussdb" || type === "gauss_db" || type === "gauss-db") {
|
||||
return "gaussdb";
|
||||
}
|
||||
if (type === "goldendb" || type === "greatdb" || type === "gdb") {
|
||||
return "goldendb";
|
||||
}
|
||||
if (type === "kafka" || type === "apache-kafka" || type === "apache_kafka") {
|
||||
return "kafka";
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ describe('connectionDriverType', () => {
|
||||
expect(normalizeDriverType('doris')).toBe('diros');
|
||||
expect(normalizeDriverType('open-gauss')).toBe('opengauss');
|
||||
expect(normalizeDriverType('gauss-db')).toBe('gaussdb');
|
||||
expect(normalizeDriverType('greatdb')).toBe('goldendb');
|
||||
expect(normalizeDriverType('gdb')).toBe('goldendb');
|
||||
expect(normalizeDriverType('InterSystemsIRIS')).toBe('iris');
|
||||
});
|
||||
|
||||
@@ -31,6 +33,7 @@ describe('connectionDriverType', () => {
|
||||
expect(resolveConnectionDriverType('custom', 'postgresql')).toBe('postgres');
|
||||
expect(resolveConnectionDriverType('custom', 'open_gauss')).toBe('opengauss');
|
||||
expect(resolveConnectionDriverType('custom', 'gauss_db')).toBe('gaussdb');
|
||||
expect(resolveConnectionDriverType('custom', 'goldendb')).toBe('goldendb');
|
||||
expect(resolveConnectionDriverType('custom', '')).toBe('');
|
||||
});
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@ export const normalizeDriverType = (value: string): string => {
|
||||
normalized === 'gauss_db' ||
|
||||
normalized === 'gauss-db'
|
||||
) return 'gaussdb';
|
||||
if (
|
||||
normalized === 'goldendb' ||
|
||||
normalized === 'greatdb' ||
|
||||
normalized === 'gdb'
|
||||
) return 'goldendb';
|
||||
if (
|
||||
normalized === 'intersystems' ||
|
||||
normalized === 'intersystemsiris' ||
|
||||
|
||||
@@ -67,6 +67,7 @@ describe('connectionModalPresentation', () => {
|
||||
it('assigns card-based configuration sections to every supported data source type', () => {
|
||||
const allTypes = [
|
||||
'mysql',
|
||||
'goldendb',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'doris',
|
||||
@@ -117,6 +118,15 @@ describe('connectionModalPresentation', () => {
|
||||
'credentials',
|
||||
'databaseScope',
|
||||
]);
|
||||
expect(resolveConnectionConfigLayout('goldendb').sections).toEqual([
|
||||
'identity',
|
||||
'uri',
|
||||
'target',
|
||||
'connectionMode',
|
||||
'replica',
|
||||
'credentials',
|
||||
'databaseScope',
|
||||
]);
|
||||
expect(resolveConnectionConfigLayout('mongodb').sections).toEqual([
|
||||
'identity',
|
||||
'uri',
|
||||
|
||||
@@ -58,6 +58,7 @@ type ConnectionConfigSectionCopy = {
|
||||
|
||||
const mysqlCompatibleTypes = new Set([
|
||||
'mysql',
|
||||
'goldendb',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'doris',
|
||||
|
||||
@@ -29,6 +29,7 @@ describe('connectionTypeCapabilities', () => {
|
||||
expect(supportsSSLForType('MongoDB')).toBe(true);
|
||||
expect(supportsSSLForType('elasticsearch')).toBe(true);
|
||||
expect(supportsSSLForType('gaussdb')).toBe(true);
|
||||
expect(supportsSSLForType('greatdb')).toBe(true);
|
||||
expect(supportsSSLForType('chroma')).toBe(true);
|
||||
expect(supportsSSLForType('qdrant')).toBe(true);
|
||||
expect(supportsSSLForType('kafka')).toBe(true);
|
||||
@@ -68,6 +69,7 @@ describe('connectionTypeCapabilities', () => {
|
||||
expect(isFileDatabaseType('duckdb')).toBe(true);
|
||||
expect(isFileDatabaseType('DuckDB')).toBe(false);
|
||||
expect(isMySQLCompatibleType('mysql')).toBe(true);
|
||||
expect(isMySQLCompatibleType('goldendb')).toBe(true);
|
||||
expect(isMySQLCompatibleType('oceanbase')).toBe(true);
|
||||
expect(isMySQLCompatibleType('diros')).toBe(true);
|
||||
expect(isMySQLCompatibleType('postgres')).toBe(false);
|
||||
@@ -75,6 +77,7 @@ describe('connectionTypeCapabilities', () => {
|
||||
|
||||
it('keeps advanced connection params enabled only for supported database types', () => {
|
||||
expect(supportsConnectionParamsForType('mysql')).toBe(true);
|
||||
expect(supportsConnectionParamsForType('gdb')).toBe(true);
|
||||
expect(supportsConnectionParamsForType('postgres')).toBe(true);
|
||||
expect(supportsConnectionParamsForType('gaussdb')).toBe(true);
|
||||
expect(supportsConnectionParamsForType('oracle')).toBe(true);
|
||||
|
||||
@@ -19,12 +19,23 @@ export const singleHostUriSchemesByType: Record<string, string[]> = {
|
||||
};
|
||||
|
||||
const normalizeConnectionType = (type: string) =>
|
||||
String(type || "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
{
|
||||
const normalized = String(type || "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
switch (normalized) {
|
||||
case "goldendb":
|
||||
case "greatdb":
|
||||
case "gdb":
|
||||
return "goldendb";
|
||||
default:
|
||||
return normalized;
|
||||
}
|
||||
};
|
||||
|
||||
const sslSupportedTypes = new Set([
|
||||
"mysql",
|
||||
"goldendb",
|
||||
"mariadb",
|
||||
"oceanbase",
|
||||
"doris",
|
||||
@@ -55,6 +66,7 @@ export const supportsSSLForType = (type: string) =>
|
||||
|
||||
const sslCAPathSupportedTypes = new Set([
|
||||
"mysql",
|
||||
"goldendb",
|
||||
"mariadb",
|
||||
"oceanbase",
|
||||
"diros",
|
||||
@@ -78,6 +90,7 @@ const sslCAPathSupportedTypes = new Set([
|
||||
|
||||
const sslClientCertificateSupportedTypes = new Set([
|
||||
"mysql",
|
||||
"goldendb",
|
||||
"mariadb",
|
||||
"oceanbase",
|
||||
"diros",
|
||||
@@ -116,13 +129,14 @@ export const isFileDatabaseType = (type: string) =>
|
||||
type === "sqlite" || type === "duckdb";
|
||||
|
||||
export const isMySQLCompatibleType = (type: string) =>
|
||||
type === "mysql" ||
|
||||
type === "mariadb" ||
|
||||
type === "oceanbase" ||
|
||||
type === "doris" ||
|
||||
type === "diros" ||
|
||||
type === "starrocks" ||
|
||||
type === "sphinx";
|
||||
normalizeConnectionType(type) === "mysql" ||
|
||||
normalizeConnectionType(type) === "goldendb" ||
|
||||
normalizeConnectionType(type) === "mariadb" ||
|
||||
normalizeConnectionType(type) === "oceanbase" ||
|
||||
normalizeConnectionType(type) === "doris" ||
|
||||
normalizeConnectionType(type) === "diros" ||
|
||||
normalizeConnectionType(type) === "starrocks" ||
|
||||
normalizeConnectionType(type) === "sphinx";
|
||||
|
||||
export const supportsConnectionParamsForType = (type: string) =>
|
||||
isMySQLCompatibleType(type) ||
|
||||
|
||||
@@ -23,6 +23,7 @@ describe('connectionTypeCatalog', () => {
|
||||
expect(keys).toContain('mysql');
|
||||
expect(keys).toContain('oceanbase');
|
||||
expect(keys).toContain('gaussdb');
|
||||
expect(keys).toContain('goldendb');
|
||||
expect(keys).toContain('mongodb');
|
||||
expect(keys).toContain('redis');
|
||||
expect(keys).toContain('elasticsearch');
|
||||
@@ -38,6 +39,7 @@ describe('connectionTypeCatalog', () => {
|
||||
it('returns the existing default port mapping for supported connection types', () => {
|
||||
expect(getConnectionTypeDefaultPort('mysql')).toBe(3306);
|
||||
expect(getConnectionTypeDefaultPort('oceanbase')).toBe(2881);
|
||||
expect(getConnectionTypeDefaultPort('goldendb')).toBe(1523);
|
||||
expect(getConnectionTypeDefaultPort('diros')).toBe(9030);
|
||||
expect(getConnectionTypeDefaultPort('postgres')).toBe(5432);
|
||||
expect(getConnectionTypeDefaultPort('gaussdb')).toBe(5432);
|
||||
@@ -63,6 +65,7 @@ describe('connectionTypeCatalog', () => {
|
||||
expect(getConnectionTypeHint('iotdb')).toContain('Timeseries');
|
||||
expect(getConnectionTypeHint('kafka')).toContain('Consumer Group');
|
||||
expect(getConnectionTypeHint('oceanbase')).toBe('MySQL / Oracle 租户');
|
||||
expect(getConnectionTypeHint('goldendb')).toBe('MySQL 兼容 / 分布式事务');
|
||||
expect(getConnectionTypeHint('duckdb')).toBe('本地文件连接');
|
||||
expect(getConnectionTypeHint('mysql')).toBe('标准连接配置');
|
||||
});
|
||||
|
||||
@@ -36,6 +36,7 @@ export const CONNECTION_TYPE_GROUPS: ConnectionTypeCatalogGroup[] = [
|
||||
{ key: 'vastbase', name: 'Vastbase (海量)' },
|
||||
{ key: 'opengauss', name: 'OpenGauss' },
|
||||
{ key: 'gaussdb', name: 'GaussDB' },
|
||||
{ key: 'goldendb', name: 'GoldenDB' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -83,6 +84,8 @@ export const getConnectionTypeDefaultPort = (type: string): number => {
|
||||
return 3306;
|
||||
case 'oceanbase':
|
||||
return 2881;
|
||||
case 'goldendb':
|
||||
return 1523;
|
||||
case 'doris':
|
||||
case 'diros':
|
||||
case 'starrocks':
|
||||
@@ -157,6 +160,8 @@ export const getConnectionTypeHint = (type: string): string => {
|
||||
return 'Broker / Topic / Consumer Group';
|
||||
case 'oceanbase':
|
||||
return 'MySQL / Oracle 租户';
|
||||
case 'goldendb':
|
||||
return 'MySQL 兼容 / 分布式事务';
|
||||
case 'sqlite':
|
||||
case 'duckdb':
|
||||
return '本地文件连接';
|
||||
|
||||
@@ -30,6 +30,24 @@ describe('dataSourceCapabilities', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('treats GoldenDB as an editable MySQL-family datasource with database-level DDL actions', () => {
|
||||
expect(getDataSourceCapabilities({ type: 'goldendb' })).toMatchObject({
|
||||
type: 'goldendb',
|
||||
supportsQueryEditor: true,
|
||||
supportsSqlQueryExport: true,
|
||||
supportsCopyInsert: true,
|
||||
supportsCreateDatabase: true,
|
||||
supportsRenameDatabase: false,
|
||||
supportsDropDatabase: true,
|
||||
forceReadOnlyQueryResult: false,
|
||||
});
|
||||
expect(getDataSourceCapabilities({ type: 'custom', driver: 'greatdb' })).toMatchObject({
|
||||
type: 'goldendb',
|
||||
supportsQueryEditor: true,
|
||||
supportsCopyInsert: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps StarRocks as an independent SQL datasource capability', () => {
|
||||
expect(getDataSourceCapabilities({ type: 'starrocks' })).toMatchObject({
|
||||
type: 'starrocks',
|
||||
|
||||
@@ -20,6 +20,10 @@ const normalizeDataSourceToken = (raw: string): string => {
|
||||
case 'gauss_db':
|
||||
case 'gauss-db':
|
||||
return 'gaussdb';
|
||||
case 'goldendb':
|
||||
case 'greatdb':
|
||||
case 'gdb':
|
||||
return 'goldendb';
|
||||
case 'dm':
|
||||
return 'dameng';
|
||||
case 'elastic':
|
||||
@@ -66,6 +70,7 @@ export const resolveDataSourceType = (config: ConnectionLike): string => {
|
||||
|
||||
const SQL_QUERY_EXPORT_TYPES = new Set([
|
||||
'mysql',
|
||||
'goldendb',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'diros',
|
||||
@@ -89,6 +94,7 @@ const SQL_QUERY_EXPORT_TYPES = new Set([
|
||||
|
||||
const COPY_INSERT_TYPES = new Set([
|
||||
'mysql',
|
||||
'goldendb',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'diros',
|
||||
@@ -132,6 +138,7 @@ export type DataSourceCapabilities = {
|
||||
|
||||
const CREATE_DATABASE_TYPES = new Set([
|
||||
'mysql',
|
||||
'goldendb',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'diros',
|
||||
@@ -159,6 +166,7 @@ const RENAME_DATABASE_TYPES = new Set([
|
||||
|
||||
const DROP_DATABASE_TYPES = new Set([
|
||||
'mysql',
|
||||
'goldendb',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'diros',
|
||||
|
||||
@@ -18,6 +18,7 @@ const resolveDdlFormatterLanguage = (dbType: string): SqlLanguage => {
|
||||
case 'mariadb':
|
||||
return 'mariadb';
|
||||
case 'mysql':
|
||||
case 'goldendb':
|
||||
case 'sphinx':
|
||||
return 'mysql';
|
||||
case 'sqlserver':
|
||||
|
||||
@@ -5,6 +5,7 @@ import { applyQueryAutoLimit } from './queryAutoLimit';
|
||||
describe('applyQueryAutoLimit', () => {
|
||||
const limitDialects = [
|
||||
'mysql',
|
||||
'goldendb',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'diros',
|
||||
|
||||
@@ -25,6 +25,7 @@ describe('sidebarMetadata', () => {
|
||||
});
|
||||
|
||||
it('uses MySQL metadata queries for custom MySQL-compatible domestic drivers', () => {
|
||||
expect(resolveSidebarMetadataDialect('goldendb')).toBe('mysql');
|
||||
expect(resolveSidebarMetadataDialect('custom', 'gdb')).toBe('mysql');
|
||||
expect(resolveSidebarMetadataDialect('custom', 'goldendb')).toBe('mysql');
|
||||
expect(resolveSidebarMetadataDialect('custom', 'greatdb')).toBe('mysql');
|
||||
|
||||
@@ -64,6 +64,11 @@ describe('quoteQualifiedIdent', () => {
|
||||
.toBe('"logs.app-1"');
|
||||
});
|
||||
|
||||
it('quotes GoldenDB identifiers with MySQL-style backticks', () => {
|
||||
expect(quoteQualifiedIdent('goldendb', 'ledger.entries'))
|
||||
.toBe('`ledger`.`entries`');
|
||||
});
|
||||
|
||||
it('does not split dots inside quoted DuckDB identifiers', () => {
|
||||
expect(quoteQualifiedIdent('duckdb', '"daily.events"."2026.06"'))
|
||||
.toBe('"daily.events"."2026.06"');
|
||||
|
||||
@@ -29,7 +29,7 @@ export const quoteIdentPart = (dbType: string, ident: string) => {
|
||||
if (!raw) return raw;
|
||||
const dbTypeLower = (dbType || '').toLowerCase();
|
||||
|
||||
if (dbTypeLower === 'mysql' || dbTypeLower === 'mariadb' || dbTypeLower === 'oceanbase' || dbTypeLower === 'diros' || dbTypeLower === 'starrocks' || dbTypeLower === 'sphinx' || dbTypeLower === 'tdengine' || dbTypeLower === 'iotdb' || dbTypeLower === 'clickhouse') {
|
||||
if (dbTypeLower === 'mysql' || dbTypeLower === 'goldendb' || dbTypeLower === 'mariadb' || dbTypeLower === 'oceanbase' || dbTypeLower === 'diros' || dbTypeLower === 'starrocks' || dbTypeLower === 'sphinx' || dbTypeLower === 'tdengine' || dbTypeLower === 'iotdb' || dbTypeLower === 'clickhouse') {
|
||||
return `\`${raw.replace(/`/g, '``')}\``;
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ export const buildOrderBySQL = (
|
||||
// 部分数据源在无显式排序需求时强制 ORDER BY(即使按主键)会显著放大大表预览成本:
|
||||
// MySQL/MariaDB 可能触发 filesort 和 sort memory 错误,DuckDB 大文件可能被排序拖到连接超时。
|
||||
// 因此仅在用户主动点击排序时下发 ORDER BY,默认分页查询不加兜底排序。
|
||||
if (dbTypeLower === 'mysql' || dbTypeLower === 'mariadb' || dbTypeLower === 'oceanbase' || dbTypeLower === 'diros' || dbTypeLower === 'starrocks' || dbTypeLower === 'duckdb') {
|
||||
if (dbTypeLower === 'mysql' || dbTypeLower === 'goldendb' || dbTypeLower === 'mariadb' || dbTypeLower === 'oceanbase' || dbTypeLower === 'diros' || dbTypeLower === 'starrocks' || dbTypeLower === 'duckdb') {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ func normalizeRunConfig(config connection.ConnectionConfig, dbName string) conne
|
||||
if !isOceanBaseOracleProtocol(config) {
|
||||
runConfig.Database = name
|
||||
}
|
||||
case "mysql", "mariadb", "diros", "starrocks", "sphinx", "postgres", "kingbase", "highgo", "vastbase", "opengauss", "gaussdb", "sqlserver", "iris", "intersystems", "intersystemsiris", "inter-systems", "inter-systems-iris", "mongodb", "tdengine", "iotdb", "clickhouse":
|
||||
case "mysql", "mariadb", "goldendb", "greatdb", "gdb", "diros", "starrocks", "sphinx", "postgres", "kingbase", "highgo", "vastbase", "opengauss", "gaussdb", "sqlserver", "iris", "intersystems", "intersystemsiris", "inter-systems", "inter-systems-iris", "mongodb", "tdengine", "iotdb", "clickhouse":
|
||||
// 这些类型的 dbName 表示"数据库",需要写入连接配置以选择目标库。
|
||||
runConfig.Database = name
|
||||
case "dameng":
|
||||
|
||||
@@ -216,6 +216,19 @@ func TestNormalizeRunConfig_StarRocksUsesDatabaseFromTree(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeRunConfig_GoldenDBUsesDatabaseFromTree(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runConfig := normalizeRunConfig(connection.ConnectionConfig{
|
||||
Type: "goldendb",
|
||||
Database: "legacy_default",
|
||||
}, "finance_core")
|
||||
|
||||
if runConfig.Database != "finance_core" {
|
||||
t.Fatalf("expected GoldenDB database from tree, got %q", runConfig.Database)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeRunConfig_IRISUsesNamespaceFromTree(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -203,6 +203,8 @@ func defaultPortByType(driverType string) int {
|
||||
switch strings.ToLower(strings.TrimSpace(driverType)) {
|
||||
case "mysql", "mariadb":
|
||||
return 3306
|
||||
case "goldendb", "greatdb", "gdb":
|
||||
return 1523
|
||||
case "oceanbase":
|
||||
return 2881
|
||||
case "diros":
|
||||
|
||||
@@ -224,6 +224,9 @@ func resolveDDLDBType(config connection.ConnectionConfig) string {
|
||||
if dbType == "gauss_db" || dbType == "gauss-db" {
|
||||
return "gaussdb"
|
||||
}
|
||||
if dbType == "goldendb" || dbType == "greatdb" || dbType == "gdb" {
|
||||
return "mysql"
|
||||
}
|
||||
if dbType == "kingbase8" || dbType == "kingbasees" || dbType == "kingbasev8" {
|
||||
return "kingbase"
|
||||
}
|
||||
@@ -245,6 +248,8 @@ func resolveDDLDBType(config connection.ConnectionConfig) string {
|
||||
return "opengauss"
|
||||
case "gaussdb", "gauss_db", "gauss-db":
|
||||
return "gaussdb"
|
||||
case "goldendb", "greatdb", "gdb":
|
||||
return "mysql"
|
||||
case "dm", "dameng", "dm8":
|
||||
return "dameng"
|
||||
case "sqlite3", "sqlite":
|
||||
@@ -274,6 +279,8 @@ func resolveDDLDBType(config connection.ConnectionConfig) string {
|
||||
return "opengauss"
|
||||
case strings.Contains(driver, "gaussdb"), strings.Contains(driver, "gauss_db"), strings.Contains(driver, "gauss-db"):
|
||||
return "gaussdb"
|
||||
case strings.Contains(driver, "goldendb"), strings.Contains(driver, "greatdb"):
|
||||
return "mysql"
|
||||
case strings.Contains(driver, "postgres"):
|
||||
return "postgres"
|
||||
case strings.Contains(driver, "kingbase"):
|
||||
|
||||
@@ -115,6 +115,20 @@ func TestResolveDDLDBType_IRISTypeAlias(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveDDLDBType_GoldenDBUsesMySQLDialect(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if got := resolveDDLDBType(connection.ConnectionConfig{Type: "goldendb"}); got != "mysql" {
|
||||
t.Fatalf("expected goldendb type to resolve to mysql, got %q", got)
|
||||
}
|
||||
if got := resolveDDLDBType(connection.ConnectionConfig{Type: "custom", Driver: "greatdb"}); got != "mysql" {
|
||||
t.Fatalf("expected greatdb custom driver to resolve to mysql, got %q", got)
|
||||
}
|
||||
if got := resolveDDLDBType(connection.ConnectionConfig{Type: "custom", Driver: "gdb"}); got != "mysql" {
|
||||
t.Fatalf("expected gdb custom driver to resolve to mysql, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeSchemaAndTableByType_PGLikeQuotedQualifiedName(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -338,6 +338,7 @@ const builtinDriverManifestJSON = `{
|
||||
"engine": "go",
|
||||
"drivers": {
|
||||
"mysql": { "engine": "go", "version": "1.9.3", "checksumPolicy": "off" },
|
||||
"goldendb": { "engine": "go", "version": "1.9.3", "checksumPolicy": "off" },
|
||||
"mariadb": { "engine": "go", "version": "1.9.3", "checksumPolicy": "off", "downloadUrl": "builtin://activate/mariadb" },
|
||||
"oceanbase": { "engine": "go", "version": "1.9.3", "checksumPolicy": "off", "downloadUrl": "builtin://activate/oceanbase" },
|
||||
"doris": { "engine": "go", "version": "1.9.3", "checksumPolicy": "off", "downloadUrl": "builtin://activate/doris" },
|
||||
@@ -402,6 +403,7 @@ var pinnedDriverPackageMap = map[string]pinnedDriverPackage{
|
||||
|
||||
var latestDriverVersionMap = map[string]string{
|
||||
"mysql": "1.9.3",
|
||||
"goldendb": "1.9.3",
|
||||
"mariadb": "1.9.3",
|
||||
"oceanbase": "1.9.3",
|
||||
"diros": "1.9.3",
|
||||
@@ -428,6 +430,7 @@ var latestDriverVersionMap = map[string]string{
|
||||
}
|
||||
|
||||
var driverGoModulePathMap = map[string]string{
|
||||
"goldendb": "github.com/go-sql-driver/mysql",
|
||||
"mariadb": "github.com/go-sql-driver/mysql",
|
||||
"oceanbase": "github.com/go-sql-driver/mysql",
|
||||
"diros": "github.com/go-sql-driver/mysql",
|
||||
@@ -1427,6 +1430,8 @@ func normalizeDriverType(driverType string) string {
|
||||
return "opengauss"
|
||||
case "gaussdb", "gauss_db", "gauss-db":
|
||||
return "gaussdb"
|
||||
case "goldendb", "greatdb", "gdb":
|
||||
return "goldendb"
|
||||
case "kafka", "apache-kafka", "apache_kafka":
|
||||
return "kafka"
|
||||
case "intersystems", "intersystemsiris", "inter-systems-iris", "inter-systems":
|
||||
@@ -1494,6 +1499,7 @@ func resolveDriverDefinitionWithPackages(driverType string, packages map[string]
|
||||
func allDriverDefinitionsWithPackages(packages map[string]pinnedDriverPackage) []driverDefinition {
|
||||
return []driverDefinition{
|
||||
{Type: "mysql", Name: "MySQL", Engine: driverEngineGo, BuiltIn: true},
|
||||
{Type: "goldendb", Name: "GoldenDB", Engine: driverEngineGo, BuiltIn: true},
|
||||
{Type: "oracle", Name: "Oracle", Engine: driverEngineGo, BuiltIn: true},
|
||||
{Type: "redis", Name: "Redis", Engine: driverEngineGo, BuiltIn: true},
|
||||
{Type: "postgres", Name: "PostgreSQL", Engine: driverEngineGo, BuiltIn: true},
|
||||
|
||||
@@ -518,6 +518,28 @@ func TestKafkaDriverDefinitionIsBuiltIn(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoldenDBDriverDefinitionIsBuiltIn(t *testing.T) {
|
||||
definition, ok := resolveDriverDefinition("greatdb")
|
||||
if !ok {
|
||||
t.Fatal("expected goldendb driver definition")
|
||||
}
|
||||
if definition.Name != "GoldenDB" {
|
||||
t.Fatalf("unexpected goldendb driver name: %q", definition.Name)
|
||||
}
|
||||
if !definition.BuiltIn {
|
||||
t.Fatal("expected goldendb to be a built-in driver")
|
||||
}
|
||||
if definition.PinnedVersion != "" || definition.DefaultDownloadURL != "" {
|
||||
t.Fatalf("expected goldendb builtin definition to omit optional metadata: %#v", definition)
|
||||
}
|
||||
if latestDriverVersionMap["goldendb"] != "1.9.3" {
|
||||
t.Fatalf("unexpected goldendb pinned version: %q", latestDriverVersionMap["goldendb"])
|
||||
}
|
||||
if driverGoModulePathMap["goldendb"] != "github.com/go-sql-driver/mysql" {
|
||||
t.Fatalf("unexpected goldendb go module path: %q", driverGoModulePathMap["goldendb"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGaussDBDriverDefinitionUsesOptionalAgent(t *testing.T) {
|
||||
definition, ok := resolveDriverDefinition("gaussdb")
|
||||
if !ok {
|
||||
|
||||
@@ -471,6 +471,9 @@ var databaseFactories = map[string]databaseFactory{
|
||||
"mysql": func() Database {
|
||||
return &MySQLDB{}
|
||||
},
|
||||
"goldendb": func() Database {
|
||||
return &MySQLDB{}
|
||||
},
|
||||
"postgres": func() Database {
|
||||
return &PostgresDB{}
|
||||
},
|
||||
@@ -521,6 +524,8 @@ func normalizeDatabaseType(dbType string) string {
|
||||
return "opengauss"
|
||||
case "gaussdb", "gauss_db", "gauss-db":
|
||||
return "gaussdb"
|
||||
case "goldendb", "greatdb", "gdb":
|
||||
return "goldendb"
|
||||
case "intersystems", "intersystemsiris", "inter-systems-iris", "inter-systems":
|
||||
return "iris"
|
||||
case "chromadb", "chroma-db":
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
// coreBuiltinDrivers 是始终内置可用的核心驱动,无需额外安装即可使用。
|
||||
var coreBuiltinDrivers = map[string]struct{}{
|
||||
"mysql": {},
|
||||
"goldendb": {},
|
||||
"redis": {},
|
||||
"oracle": {},
|
||||
"postgres": {},
|
||||
@@ -69,6 +70,8 @@ func normalizeRuntimeDriverType(driverType string) string {
|
||||
return "opengauss"
|
||||
case "gaussdb", "gauss_db", "gauss-db":
|
||||
return "gaussdb"
|
||||
case "goldendb", "greatdb", "gdb":
|
||||
return "goldendb"
|
||||
case "intersystems", "intersystemsiris", "inter-systems-iris", "inter-systems":
|
||||
return "iris"
|
||||
case "elastic":
|
||||
@@ -90,6 +93,8 @@ func driverDisplayName(driverType string) string {
|
||||
switch normalizeRuntimeDriverType(driverType) {
|
||||
case "mysql":
|
||||
return "MySQL"
|
||||
case "goldendb":
|
||||
return "GoldenDB"
|
||||
case "oracle":
|
||||
return "Oracle"
|
||||
case "redis":
|
||||
|
||||
@@ -34,6 +34,11 @@ func TestBuiltinLikeDriversRemainAvailable(t *testing.T) {
|
||||
if !supported {
|
||||
t.Fatalf("kafka 应始终可用,reason=%s", reason)
|
||||
}
|
||||
|
||||
supported, reason = DriverRuntimeSupportStatus("goldendb")
|
||||
if !supported {
|
||||
t.Fatalf("goldendb 应始终可用,reason=%s", reason)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionalDriverAgentRevisionsGeneratedForOptionalDrivers(t *testing.T) {
|
||||
@@ -58,6 +63,12 @@ func TestKingbaseRuntimeAliasesNormalizeToKingbase(t *testing.T) {
|
||||
if got := normalizeDatabaseType("kingbasees"); got != "kingbase" {
|
||||
t.Fatalf("expected kingbasees database alias to normalize to kingbase, got %q", got)
|
||||
}
|
||||
if got := normalizeRuntimeDriverType("greatdb"); got != "goldendb" {
|
||||
t.Fatalf("expected greatdb runtime alias to normalize to goldendb, got %q", got)
|
||||
}
|
||||
if got := normalizeDatabaseType("gdb"); got != "goldendb" {
|
||||
t.Fatalf("expected gdb database alias to normalize to goldendb, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagedDriverRequiresInstallMarker(t *testing.T) {
|
||||
@@ -145,3 +156,13 @@ func TestMySQLBuiltinRuntimeSupportAvailable(t *testing.T) {
|
||||
t.Fatalf("mysql 属于免安装内置驱动,应可用,reason=%s", reason)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoldenDBBuiltinDatabaseFactoryUsesMySQLImplementation(t *testing.T) {
|
||||
dbInst, err := NewDatabase("goldendb")
|
||||
if err != nil {
|
||||
t.Fatalf("expected goldendb database factory, got err=%v", err)
|
||||
}
|
||||
if _, ok := dbInst.(*MySQLDB); !ok {
|
||||
t.Fatalf("expected goldendb to reuse MySQLDB implementation, got %T", dbInst)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,3 +472,54 @@ func TestMySQLDSN_URIParamsAndExplicitParamsPrecedence(t *testing.T) {
|
||||
t.Fatalf("internal topology parameter should not be passed to driver: %v", query)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyMySQLURI_GoldenDBSchemeUsesDefaultPort(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
config := applyMySQLURI(connection.ConnectionConfig{
|
||||
Type: "goldendb",
|
||||
URI: "goldendb://glzc:secret@gdb.local/core_ledger?characterEncoding=utf8",
|
||||
})
|
||||
|
||||
if config.Host != "gdb.local" {
|
||||
t.Fatalf("expected goldendb host from URI, got %q", config.Host)
|
||||
}
|
||||
if config.Port != 1523 {
|
||||
t.Fatalf("expected goldendb default port 1523, got %d", config.Port)
|
||||
}
|
||||
if config.Database != "core_ledger" {
|
||||
t.Fatalf("expected goldendb database from URI, got %q", config.Database)
|
||||
}
|
||||
if config.User != "glzc" {
|
||||
t.Fatalf("expected goldendb user from URI, got %q", config.User)
|
||||
}
|
||||
if config.Password != "secret" {
|
||||
t.Fatalf("expected goldendb password from URI, got %q", config.Password)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMySQLDSN_AcceptsGoldenDBURICompatibilityParams(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
m := &MySQLDB{}
|
||||
dsn, err := m.getDSN(connection.ConnectionConfig{
|
||||
Type: "goldendb",
|
||||
Host: "gdb.local",
|
||||
Port: 1523,
|
||||
User: "glzc",
|
||||
Password: "secret",
|
||||
Database: "core_ledger",
|
||||
URI: "goldendb://glzc:secret@gdb.local/core_ledger?characterEncoding=utf8&useSSL=false",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("getDSN failed: %v", err)
|
||||
}
|
||||
|
||||
query := parseMySQLDSNQueryForTest(t, dsn)
|
||||
if got := query.Get("charset"); got != "utf8" {
|
||||
t.Fatalf("goldendb URI characterEncoding should map to charset=utf8, got=%q", got)
|
||||
}
|
||||
if got := query.Get("tls"); got != "false" {
|
||||
t.Fatalf("goldendb URI useSSL=false should map to tls=false, got=%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,14 +27,39 @@ type MySQLDB struct {
|
||||
|
||||
const (
|
||||
defaultMySQLPort = 3306
|
||||
defaultGoldenDBPort = 1523
|
||||
defaultMySQLInsertBatchSize = 1000
|
||||
maxMySQLInsertBatchArgs = 60000
|
||||
)
|
||||
|
||||
var mysqlCompatibleURISchemes = []string{
|
||||
"mysql",
|
||||
"mariadb",
|
||||
"doris",
|
||||
"diros",
|
||||
"oceanbase",
|
||||
"starrocks",
|
||||
"goldendb",
|
||||
"greatdb",
|
||||
"gdb",
|
||||
}
|
||||
|
||||
func parseMySQLCompatibleURI(raw string, allowedSchemes ...string) (*url.URL, bool) {
|
||||
return parseConnectionURI(raw, allowedSchemes...)
|
||||
}
|
||||
|
||||
func resolveMySQLCompatibleDefaultPort(config connection.ConnectionConfig) int {
|
||||
if config.Port > 0 {
|
||||
return config.Port
|
||||
}
|
||||
switch strings.ToLower(strings.TrimSpace(config.Type)) {
|
||||
case "goldendb", "greatdb", "gdb":
|
||||
return defaultGoldenDBPort
|
||||
default:
|
||||
return defaultMySQLPort
|
||||
}
|
||||
}
|
||||
|
||||
func mysqlConnectionParamsFromText(raw string) url.Values {
|
||||
return connectionParamsFromText(raw)
|
||||
}
|
||||
@@ -319,7 +344,7 @@ func hasMySQLConnectionParam(config connection.ConnectionConfig, names ...string
|
||||
return false
|
||||
}
|
||||
|
||||
if parsed, ok := parseMySQLCompatibleURI(config.URI, "mysql", "mariadb", "doris", "diros", "oceanbase", "starrocks"); ok && hasMatchingKey(parsed.Query()) {
|
||||
if parsed, ok := parseMySQLCompatibleURI(config.URI, mysqlCompatibleURISchemes...); ok && hasMatchingKey(parsed.Query()) {
|
||||
return true
|
||||
}
|
||||
return hasMatchingKey(mysqlConnectionParamsFromText(config.ConnectionParams))
|
||||
@@ -368,7 +393,7 @@ func buildMySQLCompatibleDSNWithOptions(config connection.ConnectionConfig, prot
|
||||
defaultMultiStatements = *options.defaultMultiStatements
|
||||
}
|
||||
params.Set("multiStatements", strconv.FormatBool(defaultMultiStatements))
|
||||
if parsed, ok := parseMySQLCompatibleURI(config.URI, "mysql", "doris", "diros", "oceanbase"); ok {
|
||||
if parsed, ok := parseMySQLCompatibleURI(config.URI, mysqlCompatibleURISchemes...); ok {
|
||||
mergeMySQLConnectionParams(params, parsed.Query())
|
||||
}
|
||||
mergeMySQLConnectionParams(params, mysqlConnectionParamsFromText(config.ConnectionParams))
|
||||
@@ -625,7 +650,7 @@ func applyMySQLURI(config connection.ConnectionConfig) connection.ConnectionConf
|
||||
if uriText == "" {
|
||||
return config
|
||||
}
|
||||
parsed, ok := parseMySQLCompatibleURI(uriText, "mysql")
|
||||
parsed, ok := parseMySQLCompatibleURI(uriText, mysqlCompatibleURISchemes...)
|
||||
if !ok {
|
||||
return config
|
||||
}
|
||||
@@ -643,10 +668,7 @@ func applyMySQLURI(config connection.ConnectionConfig) connection.ConnectionConf
|
||||
config.Database = dbName
|
||||
}
|
||||
|
||||
defaultPort := config.Port
|
||||
if defaultPort <= 0 {
|
||||
defaultPort = defaultMySQLPort
|
||||
}
|
||||
defaultPort := resolveMySQLCompatibleDefaultPort(config)
|
||||
|
||||
hostsFromURI := make([]string, 0, 4)
|
||||
hostText := strings.TrimSpace(parsed.Host)
|
||||
@@ -682,10 +704,7 @@ func applyMySQLURI(config connection.ConnectionConfig) connection.ConnectionConf
|
||||
}
|
||||
|
||||
func collectMySQLAddresses(config connection.ConnectionConfig) []string {
|
||||
defaultPort := config.Port
|
||||
if defaultPort <= 0 {
|
||||
defaultPort = defaultMySQLPort
|
||||
}
|
||||
defaultPort := resolveMySQLCompatibleDefaultPort(config)
|
||||
|
||||
candidates := make([]string, 0, len(config.Hosts)+1)
|
||||
if len(config.Hosts) > 0 {
|
||||
@@ -757,11 +776,12 @@ func (m *MySQLDB) Connect(config connection.ConnectionConfig) error {
|
||||
if len(addresses) == 0 {
|
||||
return fmt.Errorf("连接建立后验证失败:未找到可用的 MySQL 地址")
|
||||
}
|
||||
defaultPort := resolveMySQLCompatibleDefaultPort(runConfig)
|
||||
|
||||
var errorDetails []string
|
||||
for index, address := range addresses {
|
||||
candidateConfig := runConfig
|
||||
host, port, ok := parseHostPortWithDefault(address, defaultMySQLPort)
|
||||
host, port, ok := parseHostPortWithDefault(address, defaultPort)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user