mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-30 19:31:29 +08:00
🐛 fix(oceanbase): 修复 OceanBase 协议模式识别与缓存隔离
- 支持 MySQL/Oracle 租户协议在前后端统一解析 - 拒绝 Native 协议并避免误回退为 MySQL - 修复 Oracle 模式下元数据、DDL、SQL 方言识别 - 修复连接缓存键与实际协议解析优先级不一致问题 - 补充前后端协议解析与缓存隔离回归测试
This commit is contained in:
@@ -64,6 +64,13 @@ import { getCustomConnectionDsnValidationMessage } from "../utils/customConnecti
|
||||
import { mergeParsedUriValuesForForm } from "../utils/connectionUriMerge";
|
||||
import { buildRpcConnectionConfig } from "../utils/connectionRpcConfig";
|
||||
import { CUSTOM_CONNECTION_DRIVER_HELP } from "../utils/driverImportGuidance";
|
||||
import {
|
||||
describeUnsupportedOceanBaseProtocol,
|
||||
normalizeOceanBaseProtocol,
|
||||
OCEANBASE_PROTOCOL_PARAM_KEYS,
|
||||
resolveOceanBaseProtocolFromQueryText as resolveOceanBaseProtocolQueryText,
|
||||
type OceanBaseProtocol,
|
||||
} from "../utils/oceanBaseProtocol";
|
||||
import {
|
||||
applyNoAutoCapAttributes,
|
||||
noAutoCapInputProps,
|
||||
@@ -98,7 +105,7 @@ type ChoiceCardOption = {
|
||||
description?: string;
|
||||
};
|
||||
type ClickHouseProtocolChoice = "auto" | "http" | "native";
|
||||
type OceanBaseProtocolChoice = "mysql" | "oracle";
|
||||
type OceanBaseProtocolChoice = OceanBaseProtocol;
|
||||
const MAX_URI_LENGTH = 4096;
|
||||
const MAX_CONNECTION_PARAMS_LENGTH = 4096;
|
||||
const MAX_URI_HOSTS = 32;
|
||||
@@ -122,15 +129,6 @@ const OCEANBASE_PROTOCOL_OPTIONS: Array<{
|
||||
{ value: "mysql", label: "MySQL" },
|
||||
{ value: "oracle", label: "Oracle" },
|
||||
];
|
||||
const OCEANBASE_PROTOCOL_PARAM_KEYS = [
|
||||
"protocol",
|
||||
"oceanBaseProtocol",
|
||||
"oceanbaseProtocol",
|
||||
"tenantMode",
|
||||
"compatMode",
|
||||
"mode",
|
||||
];
|
||||
|
||||
const normalizeClickHouseProtocolValue = (
|
||||
value: unknown,
|
||||
): ClickHouseProtocolChoice => {
|
||||
@@ -144,10 +142,7 @@ const normalizeClickHouseProtocolValue = (
|
||||
const normalizeOceanBaseProtocolValue = (
|
||||
value: unknown,
|
||||
): OceanBaseProtocolChoice => {
|
||||
const text = String(value || "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
return text === "oracle" ? "oracle" : "mysql";
|
||||
return normalizeOceanBaseProtocol(value) || "mysql";
|
||||
};
|
||||
const resolveOceanBaseProtocolValue = (
|
||||
value: unknown,
|
||||
@@ -156,29 +151,12 @@ const resolveOceanBaseProtocolValue = (
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (!text) return undefined;
|
||||
return ["oracle", "oracle-mode", "oracle_mode", "oboracle"].includes(text)
|
||||
? "oracle"
|
||||
: "mysql";
|
||||
return normalizeOceanBaseProtocol(text);
|
||||
};
|
||||
const resolveOceanBaseProtocolFromQueryText = (
|
||||
value: unknown,
|
||||
): OceanBaseProtocolChoice | undefined => {
|
||||
let text = String(value || "").trim();
|
||||
if (!text) return undefined;
|
||||
const queryIndex = text.indexOf("?");
|
||||
if (queryIndex >= 0) {
|
||||
text = text.slice(queryIndex + 1);
|
||||
}
|
||||
const hashIndex = text.indexOf("#");
|
||||
if (hashIndex >= 0) {
|
||||
text = text.slice(0, hashIndex);
|
||||
}
|
||||
const params = new URLSearchParams(text.replace(/^[?&]+/, ""));
|
||||
for (const key of OCEANBASE_PROTOCOL_PARAM_KEYS) {
|
||||
const protocol = resolveOceanBaseProtocolValue(params.get(key));
|
||||
if (protocol) return protocol;
|
||||
}
|
||||
return undefined;
|
||||
return resolveOceanBaseProtocolQueryText(value).protocol;
|
||||
};
|
||||
const resolveOceanBaseProtocolForConfig = (
|
||||
config: Partial<ConnectionConfig>,
|
||||
@@ -1179,7 +1157,12 @@ const ConnectionModal: React.FC<{
|
||||
rawParams: unknown,
|
||||
selectedProtocol: OceanBaseProtocolChoice,
|
||||
) => {
|
||||
const params = new URLSearchParams(normalizeConnectionParamsText(rawParams));
|
||||
const normalizedParamsText = normalizeConnectionParamsText(rawParams);
|
||||
const protocolFromParams = resolveOceanBaseProtocolQueryText(normalizedParamsText);
|
||||
if (protocolFromParams.unsupportedValue) {
|
||||
throw new Error(describeUnsupportedOceanBaseProtocol(protocolFromParams.unsupportedValue));
|
||||
}
|
||||
const params = new URLSearchParams(normalizedParamsText);
|
||||
for (const key of OCEANBASE_PROTOCOL_PARAM_KEYS) {
|
||||
params.delete(key);
|
||||
}
|
||||
@@ -4775,7 +4758,7 @@ const ConnectionModal: React.FC<{
|
||||
<Form.Item
|
||||
name="oceanBaseProtocol"
|
||||
label="OceanBase 协议"
|
||||
help="MySQL 租户选择 MySQL;Oracle 租户选择 Oracle。该选择会同时影响连接测试、浏览表结构和 SQL 方言。"
|
||||
help="MySQL 租户选择 MySQL;Oracle 租户选择 Oracle。OceanBase 租户兼容模式不包含 Native,该选择会同时影响连接测试、浏览表结构和 SQL 方言。"
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<Select
|
||||
|
||||
@@ -5,6 +5,7 @@ import { TabData } from '../types';
|
||||
import { useStore } from '../store';
|
||||
import { DBQuery } from '../../wailsjs/go/app/App';
|
||||
import { buildRpcConnectionConfig } from '../utils/connectionRpcConfig';
|
||||
import { normalizeOceanBaseProtocol } from '../utils/oceanBaseProtocol';
|
||||
|
||||
interface DefinitionViewerProps {
|
||||
tab: TabData;
|
||||
@@ -43,11 +44,11 @@ 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 === 'oceanbase') return 'mysql';
|
||||
if (driver === 'oceanbase') return normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle' ? 'oracle' : 'mysql';
|
||||
if (driver === 'opengauss' || driver === 'open_gauss' || driver === 'open-gauss') return 'opengauss';
|
||||
return driver;
|
||||
}
|
||||
if (type === 'oceanbase' && String(conn?.config?.oceanBaseProtocol || '').trim().toLowerCase() === 'oracle') return 'oracle';
|
||||
if (type === 'oceanbase' && normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle') return 'oracle';
|
||||
if (type === 'mariadb' || type === 'oceanbase' || type === 'diros' || type === 'sphinx') return 'mysql';
|
||||
if (type === 'dameng') return 'dm';
|
||||
return type;
|
||||
|
||||
@@ -48,6 +48,7 @@ import FindInDatabaseModal from './FindInDatabaseModal';
|
||||
import { buildRpcConnectionConfig } from '../utils/connectionRpcConfig';
|
||||
import { noAutoCapInputProps } from '../utils/inputAutoCap';
|
||||
import { normalizeSidebarViewName, resolveSidebarRuntimeDatabase } from '../utils/sidebarMetadata';
|
||||
import { normalizeOceanBaseProtocol } from '../utils/oceanBaseProtocol';
|
||||
import { resolveConnectionHostTokens } from '../utils/tabDisplay';
|
||||
import {
|
||||
findSidebarNodePathByKey,
|
||||
@@ -686,11 +687,11 @@ const Sidebar: React.FC<{ onEditConnection?: (conn: SavedConnection) => void }>
|
||||
if (type === 'custom') {
|
||||
const driver = String(conn?.config?.driver || '').trim().toLowerCase();
|
||||
if (driver === 'diros' || driver === 'doris') return 'mysql';
|
||||
if (driver === 'oceanbase') return 'mysql';
|
||||
if (driver === 'oceanbase') return normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle' ? 'oracle' : 'mysql';
|
||||
if (driver === 'opengauss' || driver === 'open_gauss' || driver === 'open-gauss') return 'opengauss';
|
||||
return driver;
|
||||
}
|
||||
if (type === 'oceanbase' && String(conn?.config?.oceanBaseProtocol || '').trim().toLowerCase() === 'oracle') return 'oracle';
|
||||
if (type === 'oceanbase' && normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle') return 'oracle';
|
||||
if (type === 'mariadb' || type === 'oceanbase' || type === 'diros' || type === 'sphinx') return 'mysql';
|
||||
if (type === 'dameng') return 'dm';
|
||||
return type;
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
type TableOverviewSortField,
|
||||
type TableOverviewSortOrder,
|
||||
} from '../utils/tableOverviewFilter';
|
||||
import { normalizeOceanBaseProtocol } from '../utils/oceanBaseProtocol';
|
||||
|
||||
interface TableOverviewProps {
|
||||
tab: TabData;
|
||||
@@ -57,11 +58,11 @@ const getMetadataDialect = (connType: string, driver?: string, oceanBaseProtocol
|
||||
if (type === 'custom') {
|
||||
const d = (driver || '').trim().toLowerCase();
|
||||
if (d === 'diros' || d === 'doris') return 'mysql';
|
||||
if (d === 'oceanbase') return 'mysql';
|
||||
if (d === 'oceanbase') return normalizeOceanBaseProtocol(oceanBaseProtocol) === 'oracle' ? 'oracle' : 'mysql';
|
||||
if (d === 'opengauss' || d === 'open_gauss' || d === 'open-gauss') return 'opengauss';
|
||||
return d;
|
||||
}
|
||||
if (type === 'oceanbase' && String(oceanBaseProtocol || '').trim().toLowerCase() === 'oracle') return 'oracle';
|
||||
if (type === 'oceanbase' && normalizeOceanBaseProtocol(oceanBaseProtocol) === 'oracle') return 'oracle';
|
||||
if (type === 'mariadb' || type === 'oceanbase' || type === 'diros' || type === 'sphinx') return 'mysql';
|
||||
if (type === 'dameng') return 'dm';
|
||||
return type;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { TabData } from '../types';
|
||||
import { useStore } from '../store';
|
||||
import { DBQuery } from '../../wailsjs/go/app/App';
|
||||
import { buildRpcConnectionConfig } from '../utils/connectionRpcConfig';
|
||||
import { normalizeOceanBaseProtocol } from '../utils/oceanBaseProtocol';
|
||||
|
||||
interface TriggerViewerProps {
|
||||
tab: TabData;
|
||||
@@ -29,11 +30,11 @@ 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 === 'oceanbase') return 'mysql';
|
||||
if (driver === 'oceanbase') return normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle' ? 'oracle' : 'mysql';
|
||||
if (driver === 'opengauss' || driver === 'open_gauss' || driver === 'open-gauss') return 'opengauss';
|
||||
return driver;
|
||||
}
|
||||
if (type === 'oceanbase' && String(conn?.config?.oceanBaseProtocol || '').trim().toLowerCase() === 'oracle') return 'oracle';
|
||||
if (type === 'oceanbase' && normalizeOceanBaseProtocol(conn?.config?.oceanBaseProtocol) === 'oracle') return 'oracle';
|
||||
if (type === 'mariadb' || type === 'oceanbase' || type === 'diros' || type === 'sphinx') return 'mysql';
|
||||
if (type === 'dameng') return 'dm';
|
||||
return type;
|
||||
|
||||
Reference in New Issue
Block a user