面试宝典:介绍下Oracle数据库动态性能视图 V$SQLFN_ARG_METADATA

在这里插入图片描述

🧠 Oracle 19C V$SQLFN_ARG_METADATA 视图详解

1. 视图概述与作用

V$SQLFN_ARG_METADATA 是 Oracle 19C 数据库中一个较为特殊的动态性能视图,它提供了SQL函数参数元数据信息。这个视图主要用于数据库内部管理和优化,记录了SQL函数调用时参数的详细元数据信息。

核心作用:

  1. 函数参数元数据管理:存储和管理SQL函数参数的元数据信息
  2. 查询优化支持:为优化器提供函数参数的类型和特性信息
  3. 执行计划生成:协助生成更准确的SQL执行计划
  4. 函数调用分析:提供函数调用时的参数特性信息

2. 字段含义详解

下表详细说明了 V$SQLFN_ARG_METADATA 视图中的各个字段:

字段名 (Column Name)数据类型 (Datatype)描述 (Description)
FUNC_IDNUMBER函数的唯一标识符。标识特定的SQL函数。
ARG_NUMNUMBER参数序号。标识参数在函数参数列表中的位置(从1开始)。
DATATYPENUMBER参数的数据类型代码。对应Oracle数据类型的内部编码。
PRECISIONNUMBER参数的精度。对于数字类型,表示总位数。
SCALENUMBER参数的小数位数。对于数字类型,表示小数部分的位数。
LENGTHNUMBER参数的长度。对于字符类型,表示最大长度。
CHARSETIDNUMBER字符集标识符。指定参数的字符集。
CHARSETFORMNUMBER字符集格式。指定字符集的格式。
FLAGSNUMBER参数的特性标志位。包含各种参数特性的位掩码。
ARG_NAMEVARCHAR2(30)参数名称。如果参数有命名,则显示参数名。
DEFAULT_VALUEVARCHAR2(4000)参数的默认值。如果参数有默认值,则显示默认值。
IS_OPTIONALNUMBER指示参数是否为可选
• 0: 必需参数
• 1: 可选参数
IS_RETURNNUMBER指示是否为返回值参数
• 0: 输入参数
• 1: 返回值参数
CON_IDNUMBER容器ID。在多租户环境中标识所属容器。

3. 使用场景

V$SQLFN_ARG_METADATA 在以下场景中非常重要:

  1. 查询优化分析:分析函数参数特性以优化查询性能
  2. 函数行为研究:研究内置SQL函数的行为和参数要求
  3. 元数据管理:管理SQL函数参数的元数据信息
  4. 调试和诊断:诊断函数相关的性能问题或错误
  5. 开发工具支持:为SQL开发工具提供函数参数信息

4. 底层原理与相关知识点

4.1 SQL函数处理机制

Oracle 处理SQL函数调用的过程:

  1. 语法解析:识别函数调用和参数
  2. 语义分析:验证参数类型和数量
  3. 元数据获取:从V$SQLFN_ARG_METADATA等视图获取参数信息
  4. 执行计划生成:基于参数特性生成最优执行计划
  5. 函数执行:执行函数并返回结果

4.2 参数元数据存储

函数参数元数据存储在共享池中:

  • 函数标识:每个函数有唯一的FUNC_ID
  • 参数序列:参数按位置顺序存储
  • 类型信息:完整的数据类型信息
  • 特性标志:参数的各種特性通过位掩码存储

4.3 数据类型编码

Oracle 使用内部编码表示数据类型:

数据类型代码数据类型描述
1VARCHAR2变长字符串
2NUMBER数字类型
12DATE日期类型
23RAW原始二进制数据
96CHAR定长字符串
180TIMESTAMP时间戳

5. 相关视图

视图名称主要用途描述
V$SQLFN_METADATASQL函数的元数据信息
DBA_ARGUMENTS存储过程和函数的参数信息
V$SQLSQL语句的执行信息
V$SQL_BIND_METADATASQL绑定变量的元数据信息
DBA_TAB_COLS表列的元数据信息

6. 基表信息

VSQLFNARGMETADATA基于底层的∗∗XSQLFN_ARG_METADATA 基于底层的 **XSQLFNARGMETADATA基于底层的X 表**构建,这些表是Oracle内部的虚拟内存表。根据内部结构,它很可能基于 **XKQLFXA∗∗或类似的XKQLFXA** 或类似的XKQLFXA或类似的X表。

重要提示:X表是Oracle的内部结构,没有官方文档支持,其结构和命名可能随版本变化。强烈建议不要直接查询X表是Oracle的内部结构,没有官方文档支持,其结构和命名可能随版本变化。强烈建议不要直接查询X表是Oracle的内部结构,没有官方文档支持,其结构和命名可能随版本变化。强烈建议不要直接查询X表,而是通过公开的V$视图获取信息。

7. 常用查询 SQL

7.1 查看函数的参数信息

SELECT 
    func_id,
    arg_num,
    arg_name,
    (SELECT name FROM v$sqlfn_metadata WHERE func_id = arg.func_id) as function_name,
    CASE datatype
        WHEN 1 THEN 'VARCHAR2'
        WHEN 2 THEN 'NUMBER'
        WHEN 12 THEN 'DATE'
        WHEN 96 THEN 'CHAR'
        WHEN 180 THEN 'TIMESTAMP'
        ELSE 'UNKNOWN(' || datatype || ')'
    END as data_type,
    precision,
    scale,
    length,
    CASE is_optional WHEN 0 THEN 'NO' WHEN 1 THEN 'YES' END as is_optional,
    default_value
FROM 
    v$sqlfn_arg_metadata arg
WHERE 
    func_id IN (SELECT func_id FROM v$sqlfn_metadata WHERE name LIKE '%TO_CHAR%')
ORDER BY 
    func_id, arg_num;

7.2 分析数字函数的参数特性

SELECT 
    fn.name as function_name,
    arg.arg_num,
    arg.arg_name,
    arg.precision,
    arg.scale,
    arg.is_optional,
    arg.default_value
FROM 
    v$sqlfn_arg_metadata arg
JOIN 
    v$sqlfn_metadata fn ON arg.func_id = fn.func_id
WHERE 
    arg.datatype = 2  -- NUMBER type
    AND arg.arg_num > 0
ORDER BY 
    fn.name, arg.arg_num;

7.3 查找具有默认值的参数

SELECT 
    fn.name as function_name,
    arg.arg_num,
    arg.arg_name,
    arg.default_value,
    CASE arg.datatype
        WHEN 1 THEN 'VARCHAR2(' || arg.length || ')'
        WHEN 2 THEN 'NUMBER(' || arg.precision || ',' || arg.scale || ')'
        ELSE 'TYPE#' || arg.datatype
    END as data_type
FROM 
    v$sqlfn_arg_metadata arg
JOIN 
    v$sqlfn_metadata fn ON arg.func_id = fn.func_id
WHERE 
    arg.default_value IS NOT NULL
ORDER BY 
    fn.name, arg.arg_num;

7.4 分析字符串函数的参数特性

SELECT 
    fn.name as function_name,
    arg.arg_num,
    arg.arg_name,
    arg.length as max_length,
    arg.charsetid,
    arg.charsetform,
    CASE arg.is_optional WHEN 0 THEN 'REQUIRED' ELSE 'OPTIONAL' END as requirement
FROM 
    v$sqlfn_arg_metadata arg
JOIN 
    v$sqlfn_metadata fn ON arg.func_id = fn.func_id
WHERE 
    arg.datatype IN (1, 96)  -- VARCHAR2 or CHAR
ORDER BY 
    fn.name, arg.arg_num;

7.5 函数参数统计信息

SELECT 
    (SELECT name FROM v$sqlfn_metadata WHERE func_id = arg.func_id) as function_name,
    COUNT(*) as parameter_count,
    SUM(CASE WHEN is_optional = 1 THEN 1 ELSE 0 END) as optional_parameters,
    SUM(CASE WHEN default_value IS NOT NULL THEN 1 ELSE 0 END) as parameters_with_defaults,
    LISTAGG(
        CASE 
            WHEN arg_name IS NOT NULL THEN arg_name 
            ELSE 'arg#' || arg_num 
        END, ', '
    ) WITHIN GROUP (ORDER BY arg_num) as parameter_names
FROM 
    v$sqlfn_arg_metadata arg
GROUP BY 
    func_id
HAVING 
    COUNT(*) > 0
ORDER BY 
    parameter_count DESC;

8. 最佳实践与注意事项

  1. 理解内部使用:V$SQLFN_ARG_METADATA 主要用于Oracle内部,普通DBA很少需要直接使用
  2. 性能考虑:查询此视图可能对性能有轻微影响,避免在高负载时频繁查询
  3. 版本兼容性:不同Oracle版本的函数和参数可能有所变化
  4. 多租户环境:在CDB环境中,注意CON_ID字段以区分不同容器
  5. 元数据准确性:视图中的信息是Oracle内部的元数据,应保持其准确性

9. 实际应用示例

9.1 创建函数参数文档

SELECT 
    fn.name as "Function",
    arg.arg_num as "Position",
    NVL(arg.arg_name, 'parameter_' || arg.arg_num) as "Name",
    CASE arg.datatype
        WHEN 1 THEN 'VARCHAR2(' || arg.length || ')'
        WHEN 2 THEN 'NUMBER(' || NVL(TO_CHAR(arg.precision), '*') || 
                   ',' || NVL(TO_CHAR(arg.scale), '*') || ')'
        WHEN 12 THEN 'DATE'
        WHEN 96 THEN 'CHAR(' || arg.length || ')'
        WHEN 180 THEN 'TIMESTAMP'
        ELSE 'UNKNOWN(' || arg.datatype || ')'
    END as "DataType",
    CASE arg.is_optional WHEN 0 THEN 'No' WHEN 1 THEN 'Yes' END as "Optional",
    arg.default_value as "DefaultValue"
FROM 
    v$sqlfn_arg_metadata arg
JOIN 
    v$sqlfn_metadata fn ON arg.func_id = fn.func_id
WHERE 
    fn.name LIKE 'TO_%'
ORDER BY 
    fn.name, arg.arg_num;

9.2 分析转换函数的参数模式

SELECT 
    fn.name as function_name,
    COUNT(*) as param_count,
    ROUND(AVG(arg.precision), 2) as avg_precision,
    ROUND(AVG(arg.scale), 2) as avg_scale,
    ROUND(AVG(arg.length), 2) as avg_length,
    SUM(CASE WHEN arg.datatype = 2 THEN 1 ELSE 0 END) as number_params,
    SUM(CASE WHEN arg.datatype = 1 THEN 1 ELSE 0 END) as varchar2_params
FROM 
    v$sqlfn_arg_metadata arg
JOIN 
    v$sqlfn_metadata fn ON arg.func_id = fn.func_id
WHERE 
    fn.name LIKE '%CONVERT%' OR fn.name LIKE '%TO_%'
GROUP BY 
    fn.name
ORDER BY 
    param_count DESC;

通过正确理解和使用 V$SQLFN_ARG_METADATA 视图,DBA和开发者可以更好地理解Oracle内置SQL函数的参数特性和行为,虽然这个视图在日常运维中使用频率较低,但在深度性能分析和问题诊断时可能发挥重要作用。

欢迎关注我的公众号《IT小Chen

void MainWindow::on_actionRefresh_triggered() { if (db.isEmpty()) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("没有任何连接")); return; } // 遍历所有数据库连接 for (const QString& connectName : db) { QSqlDatabase m_db = QSqlDatabase::database(connectName); if (!m_db.isOpen()) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("连接已关闭: %1").arg(connectName)); continue; } // 获取连接类型 int dbType = connectType.contains(connectName) ? connectType[connectName] : 1; // 查找连接对应的用户节点和连接节点 QString user; QTreeWidgetItem* connectItem = nullptr; // 遍历树结构查找连接节点 for (int i = 0; i < ui->connectionTree->topLevelItemCount(); ++i) { QTreeWidgetItem* userNode = ui->connectionTree->topLevelItem(i); // 一级节点:用户 if (!userNode) continue; // 从用户节点获取用户名 user = userNode->data(0, Qt::UserRole).toString(); // 遍历连接节点(二级节点) for (int j = 0; j < userNode->childCount(); ++j) { QTreeWidgetItem* childConnect = userNode->child(j); if (!childConnect) continue; // 从连接节点获取连接名 QString connectNameFromNode = childConnect->data(0, Qt::UserRole).toString(); if (connectNameFromNode == connectName) { connectItem = childConnect; break; } } if (connectItem) break; } if (!connectItem) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("未找到连接节点: %1").arg(connectName)); continue; } if (user.isEmpty()) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("无法确定用户: %1").arg(connectName)); continue; } // Kingbase数据库需要处理多个模式 if (dbType == 3) { // Kingbase数据库 // 获取所有模式 QSqlQuery schemaQuery(m_db); if (!schemaQuery.exec("SELECT nspname FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema' ORDER BY nspname")) { // 如果查询失败,尝试创建扩展 schemaQuery.exec("create extension if not exists dbms_metadata"); schemaQuery.exec("SELECT nspname FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema' ORDER BY nspname"); } if (schemaQuery.isActive()) { while (schemaQuery.next()) { QString schemaName = schemaQuery.value(0).toString(); if(schemaName == "sys" || schemaName == "anon") continue; // 查找或创建模式节点 QTreeWidgetItem* schemaNode = nullptr; QString schemaDisplayName = QString::fromLocal8Bit("模式:%1").arg(schemaName); for (int i = 0; i < connectItem->childCount(); ++i) { QTreeWidgetItem* child = connectItem->child(i); if (child && child->text(0) == schemaDisplayName) { schemaNode = child; break; } } // 如果模式节点不存在,创建它 if (!schemaNode) { schemaNode = new QTreeWidgetItem(connectItem); schemaNode->setText(0, schemaDisplayName); schemaNode->setData(0, Qt::UserRole, QString::fromLocal8Bit("模式:") + schemaName); // 创建各类数据库对象的父节点 QTreeWidgetItem *tablesItem = new QTreeWidgetItem(schemaNode); tablesItem->setText(0, QString::fromLocal8Bit("表")); tablesItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:表")); QTreeWidgetItem *functionsItem = new QTreeWidgetItem(schemaNode); functionsItem->setText(0, QString::fromLocal8Bit("函数")); functionsItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:函数")); QTreeWidgetItem *proceduresItem = new QTreeWidgetItem(schemaNode); proceduresItem->setText(0, QString::fromLocal8Bit("过程")); proceduresItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:过程")); QTreeWidgetItem *triggersItem = new QTreeWidgetItem(schemaNode); triggersItem->setText(0, QString::fromLocal8Bit("触发器")); triggersItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:触发器")); QTreeWidgetItem *sequencesItem = new QTreeWidgetItem(schemaNode); sequencesItem->setText(0, QString::fromLocal8Bit("序列")); sequencesItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:序列")); QTreeWidgetItem *viewsItem = new QTreeWidgetItem(schemaNode); viewsItem->setText(0, QString::fromLocal8Bit("视图")); viewsItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:视图")); } // 切换至对应模式 QString turnSql = QString("SET search_path TO %1, public").arg(schemaName); QSqlQuery turnQuery(m_db); if (!turnQuery.exec(turnSql)) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("无法切换至模式:%1").arg(schemaName)); continue; } // 构建分类节点映射(表、视图等五级节点) QMap<QString, QTreeWidgetItem*> childTypeMap; for (int i = 0; i < schemaNode->childCount(); ++i) { QTreeWidgetItem* childItem = schemaNode->child(i); if (childItem) { childTypeMap[childItem->text(0)] = childItem; } } // 刷新表节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("表"), "TABLE", true, childTypeMap, m_db, schemaName); // 刷新视图节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("视图"), "VIEW", true, childTypeMap, m_db, schemaName); // 刷新函数节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("函数"), "FUNCTION", true, childTypeMap, m_db, schemaName); // 刷新存储过程节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("过程"), "PROCEDURE", true, childTypeMap, m_db, schemaName); // 刷新触发器节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("触发器"), "TRIGGER", true, childTypeMap, m_db, schemaName); // 刷新序列节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("序列"), "SEQUENCE", true, childTypeMap, m_db, schemaName); } } } else { // 非Kingbase数据库Oracle或DM8):处理单个模式 QString schemaName = user; // 使用用户名作为模式名 // 查找模式节点 QTreeWidgetItem* schemaNode = nullptr; QString schemaDisplayName = QString::fromLocal8Bit("模式:%1").arg(schemaName); for (int i = 0; i < connectItem->childCount(); ++i) { QTreeWidgetItem* child = connectItem->child(i); if (child && child->text(0) == schemaDisplayName) { schemaNode = child; break; } } if (!schemaNode) { // 如果模式节点不存在,创建它 schemaNode = new QTreeWidgetItem(connectItem); schemaNode->setText(0, schemaDisplayName); schemaNode->setData(0, Qt::UserRole, QString::fromLocal8Bit("模式:") + schemaName); // 创建各类数据库对象的父节点 QTreeWidgetItem *tablesItem = new QTreeWidgetItem(schemaNode); tablesItem->setText(0, QString::fromLocal8Bit("表")); tablesItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:表")); QTreeWidgetItem *functionsItem = new QTreeWidgetItem(schemaNode); functionsItem->setText(0, QString::fromLocal8Bit("函数")); functionsItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:函数")); QTreeWidgetItem *proceduresItem = new QTreeWidgetItem(schemaNode); proceduresItem->setText(0, QString::fromLocal8Bit("过程")); proceduresItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:过程")); QTreeWidgetItem *triggersItem = new QTreeWidgetItem(schemaNode); triggersItem->setText(0, QString::fromLocal8Bit("触发器")); triggersItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:触发器")); QTreeWidgetItem *sequencesItem = new QTreeWidgetItem(schemaNode); sequencesItem->setText(0, QString::fromLocal8Bit("序列")); sequencesItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:序列")); QTreeWidgetItem *viewsItem = new QTreeWidgetItem(schemaNode); viewsItem->setText(0, QString::fromLocal8Bit("视图")); viewsItem->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:视图")); } // 构建分类节点映射(表、视图等五级节点) QMap<QString, QTreeWidgetItem*> childTypeMap; for (int i = 0; i < schemaNode->childCount(); ++i) { QTreeWidgetItem* childItem = schemaNode->child(i); if (childItem) { childTypeMap[childItem->text(0)] = childItem; } } // 刷新表节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("表"), "TABLE", false, childTypeMap, m_db); // 刷新视图节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("视图"), "VIEW", false, childTypeMap, m_db); // 刷新函数节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("函数"), "FUNCTION", false, childTypeMap, m_db); // 刷新存储过程节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("过程"), "PROCEDURE", false, childTypeMap, m_db); // 刷新触发器节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("触发器"), "TRIGGER", false, childTypeMap, m_db); // 刷新序列节点 refreshObjectType(connectName, user, schemaName, QString::fromLocal8Bit("序列"), "SEQUENCE", false, childTypeMap, m_db); } } MessageDialog::information(this, QString::fromLocal8Bit("刷新完成"), QString::fromLocal8Bit("所有数据库连接已同步最新状态")); } void MainWindow::refreshObjectType(const QString& connectName, const QString& user, const QString& schemaName, const QString& typeName, const QString& objectType, bool isKingbase, QMap<QString, QTreeWidgetItem*>& childTypeMap, QSqlDatabase& db, const QString& kingbaseSchemaName) { if (!childTypeMap.contains(typeName)) { return; } QTreeWidgetItem* typeItem = childTypeMap[typeName]; // 清空现有节点 qDeleteAll(typeItem->takeChildren()); // 清空缓存 if (typeName == QString::fromLocal8Bit("表")) { if (tables.contains(user) && tables[user].contains(connectName)) { tables[user][connectName].remove(schemaName); } } else if (typeName == QString::fromLocal8Bit("视图")) { if (views.contains(user) && views[user].contains(connectName)) { views[user][connectName].remove(schemaName); } } else if (typeName == QString::fromLocal8Bit("函数")) { if (funcs.contains(user) && funcs[user].contains(connectName)) { funcs[user][connectName].remove(schemaName); } } else if (typeName == QString::fromLocal8Bit("过程")) { if (procs.contains(user) && procs[user].contains(connectName)) { procs[user][connectName].remove(schemaName); } } else if (typeName == QString::fromLocal8Bit("触发器")) { if (triggers.contains(user) && triggers[user].contains(connectName)) { triggers[user][connectName].remove(schemaName); } } else if (typeName == QString::fromLocal8Bit("序列")) { if (seqs.contains(user) && seqs[user].contains(connectName)) { seqs[user][connectName].remove(schemaName); } } // 执行查询 QSqlQuery query(db); QString queryStr; if (isKingbase) { // Kingbase 查询 if (objectType == "TABLE") { queryStr = "SELECT tablename FROM pg_tables WHERE schemaname = ? ORDER BY tablename"; query.prepare(queryStr); query.addBindValue(kingbaseSchemaName); } else if (objectType == "VIEW") { queryStr = "SELECT viewname FROM pg_views WHERE schemaname = ? ORDER BY viewname"; query.prepare(queryStr); query.addBindValue(kingbaseSchemaName); } else if (objectType == "FUNCTION") { queryStr = "SELECT proname FROM pg_proc WHERE pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = ?) ORDER BY proname"; query.prepare(queryStr); query.addBindValue(kingbaseSchemaName); } else if (objectType == "PROCEDURE") { queryStr = "SELECT proname FROM pg_proc WHERE pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = ?) AND prokind = 'p' ORDER BY proname"; query.prepare(queryStr); query.addBindValue(kingbaseSchemaName); } else if (objectType == "TRIGGER") { queryStr = "SELECT tgname FROM pg_trigger WHERE tgrelid IN (SELECT oid FROM pg_class WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = ?)) ORDER BY tgname"; query.prepare(queryStr); query.addBindValue(kingbaseSchemaName); } else if (objectType == "SEQUENCE") { queryStr = "SELECT sequencename FROM pg_sequences WHERE schemaname = ? ORDER BY sequencename"; query.prepare(queryStr); query.addBindValue(kingbaseSchemaName); } } else { // Oracle/DM8 查询 if (objectType == "TABLE") { queryStr = "SELECT table_name FROM user_tables ORDER BY table_name"; query.prepare(queryStr); } else if (objectType == "VIEW") { queryStr = "SELECT view_name FROM user_views ORDER BY view_name"; query.prepare(queryStr); } else if (objectType == "FUNCTION") { queryStr = "SELECT object_name FROM user_objects WHERE object_type = 'FUNCTION' ORDER BY object_name"; query.prepare(queryStr); } else if (objectType == "PROCEDURE") { queryStr = "SELECT object_name FROM user_objects WHERE object_type = 'PROCEDURE' ORDER BY object_name"; query.prepare(queryStr); } else if (objectType == "TRIGGER") { queryStr = "SELECT trigger_name FROM user_triggers ORDER BY trigger_name"; query.prepare(queryStr); } else if (objectType == "SEQUENCE") { queryStr = "SELECT sequence_name FROM user_sequences ORDER BY sequence_name"; query.prepare(queryStr); } } if (query.exec()) { while (query.next()) { QString objectName = query.value(0).toString(); QString ddl = getEntityDDL(connectName, objectType, objectName, isKingbase, isKingbase ? kingbaseSchemaName : ""); // 检查是否获取成功 if (ddl.contains(QString::fromLocal8Bit("获取失败"))) { continue; } // 特殊处理Oracle/DM8的表和函数 if (!isKingbase) { if (objectType == "TABLE" || objectType == "FUNCTION") { if (ddl.contains("DBMS_METADATA.GET_DDL") && ddl.contains("Unable to execute statement")) { continue; } } } // 更新缓存 if (typeName == QString::fromLocal8Bit("表")) { tables[user][connectName][schemaName].insert(objectName, ddl); } else if (typeName == QString::fromLocal8Bit("视图")) { views[user][connectName][schemaName].insert(objectName, ddl); } else if (typeName == QString::fromLocal8Bit("函数")) { funcs[user][connectName][schemaName].insert(objectName, ddl); } else if (typeName == QString::fromLocal8Bit("过程")) { procs[user][connectName][schemaName].insert(objectName, ddl); } else if (typeName == QString::fromLocal8Bit("触发器")) { triggers[user][connectName][schemaName].insert(objectName, ddl); } else if (typeName == QString::fromLocal8Bit("序列")) { seqs[user][connectName][schemaName].insert(objectName, ddl); } // 添加新节点 QTreeWidgetItem* objectItem = new QTreeWidgetItem(typeItem); objectItem->setText(0, objectName); } } else { MessageDialog::warning(nullptr, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("查询%1失败: %2").arg(typeName).arg(query.lastError().text())); qDebug()<<"the loser is"<<connectName<<user<<schemaName<<typeName<<objectType<<isKingbase<<childTypeMap<<db<<kingbaseSchemaName; } }此逻辑为由于用户之前并没有考虑到DM8已经更新到模式与用户之间已构成M:N关系编写,固根据修改后的连接初始化逻辑更新此更新逻辑
09-26
void MainWindow::on_actionRefresh_triggered() { if (db.isEmpty()) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("没有任何连接")); return; } // 遍历所有数据库连接 for (const QString& connectName : db) { QSqlDatabase m_db = QSqlDatabase::database(connectName); if (!m_db.isOpen()) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("连接已关闭: %1").arg(connectName)); continue; } // 获取连接类型 int dbType = connectType.contains(connectName) ? connectType[connectName] : 1; bool isKingbase = (dbType == 3); // Kingbase数据库 bool isDM8 = (dbType == 2); // DM8数据库 bool isOracle = (dbType == 1); // Oracle数据库 // 查找连接对应的用户节点和连接节点 QString user; QTreeWidgetItem* connectItem = findConnectionItem(connectName, user); if (!connectItem || user.isEmpty()) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("未找到连接节点或用户: %1").arg(connectName)); continue; } // ================= 多模式数据库处理 (Kingbase 或 DM8) ================= if (isKingbase || isDM8) { QStringList schemaNames; // 根据不同数据库类型获取模式列表 if (isKingbase) { schemaNames = getKingbaseSchemas(m_db); } else { // DM8 schemaNames = getDM8Schemas(m_db); } foreach (const QString& schemaName, schemaNames) { // 跳过系统模式 if (shouldSkipSchema(schemaName, isKingbase, isDM8)) continue; // 查找或创建模式节点 QTreeWidgetItem* schemaNode = findOrCreateSchemaNode( connectItem, schemaName, isKingbase, isDM8); // 切换至对应模式 if (!switchToSchema(m_db, schemaName, isKingbase, isDM8)) { continue; } // 刷新当前模式下的所有对象类型 refreshAllObjectsInSchema(connectName, user, schemaName, isKingbase, isDM8, schemaNode, m_db); } } // ================= 单模式数据库处理 (Oracle) ================= else if (isOracle) { QString schemaName = user; // 使用用户名作为模式名 QTreeWidgetItem* schemaNode = findOrCreateSchemaNode( connectItem, schemaName, false, false); // 刷新Oracle模式下的所有对象 refreshAllObjectsInSchema(connectName, user, schemaName, false, false, schemaNode, m_db); } } MessageDialog::information(this, QString::fromLocal8Bit("刷新完成"), QString::fromLocal8Bit("所有数据库连接已同步最新状态")); } // 查找连接节点工具函数 QTreeWidgetItem* MainWindow::findConnectionItem(const QString& connectName, QString& user) { for (int i = 0; i < ui->connectionTree->topLevelItemCount(); ++i) { QTreeWidgetItem* userNode = ui->connectionTree->topLevelItem(i); if (!userNode) continue; user = userNode->data(0, Qt::UserRole).toString(); for (int j = 0; j < userNode->childCount(); ++j) { QTreeWidgetItem* child = userNode->child(j); if (!child) continue; QString nameFromNode = child->data(0, Qt::UserRole).toString(); if (nameFromNode == connectName) { return child; } } } return nullptr; } // 获取Kingbase模式列表 QStringList MainWindow::getKingbaseSchemas(QSqlDatabase& db) { QStringList schemas; QSqlQuery query(db); // 尝试创建扩展(如果不存在) query.exec("create extension if not exists dbms_metadata"); if (query.exec("SELECT nspname FROM pg_namespace " "WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema' " "ORDER BY nspname")) { while (query.next()) { schemas << query.value(0).toString(); } } return schemas; } // 获取DM8模式列表 QStringList MainWindow::getDM8Schemas(QSqlDatabase& db) { QStringList schemas; QSqlQuery query(db); // 使用DBA_OBJECTS或ALL_OBJECTS获取模式列表 QString queryStr = "SELECT DISTINCT OWNER FROM DBA_OBJECTS " "WHERE OWNER NOT IN ('SYS','SYSTEM','SYSAUDITOR','SYSSSO','SYSDBO') " "ORDER BY OWNER"; if (!query.exec(queryStr)) { queryStr = "SELECT DISTINCT OWNER FROM ALL_OBJECTS " "WHERE OWNER NOT IN ('SYS','SYSTEM','SYSAUDITOR','SYSSSO','SYSDBO') " "ORDER BY OWNER"; query.exec(queryStr); } while (query.next()) { schemas << query.value(0).toString(); } return schemas; } // 判断是否跳过模式 bool MainWindow::shouldSkipSchema(const QString& schemaName, bool isKingbase, bool isDM8) { if (isKingbase) { return (schemaName == "sys" || schemaName == "anon"); } else if (isDM8) { return (schemaName == "SYS" || schemaName == "SYSTEM" || schemaName == "SYSAUDITOR" || schemaName == "SYSSSO" || schemaName == "SYSDBO"); } return false; } // 查找或创建模式节点 QTreeWidgetItem* MainWindow::findOrCreateSchemaNode(QTreeWidgetItem* connectItem, const QString& schemaName, bool isKingbase, bool isDM8) { QString displayName = QString::fromLocal8Bit("模式:%1").arg(schemaName); // 查找现有节点 for (int i = 0; i < connectItem->childCount(); ++i) { QTreeWidgetItem* child = connectItem->child(i); if (child && child->text(0) == displayName) { return child; } } // 创建新节点 QTreeWidgetItem* schemaNode = new QTreeWidgetItem(connectItem); schemaNode->setText(0, displayName); schemaNode->setData(0, Qt::UserRole, QString::fromLocal8Bit("模式:") + schemaName); // 设置工具提示 if (isKingbase) { schemaNode->setToolTip(0, QString::fromLocal8Bit("Kingbase模式 - SET search_path TO %1, public").arg(schemaName)); } else if (isDM8) { schemaNode->setToolTip(0, QString::fromLocal8Bit("DM8模式 - ALTER SESSION SET CURRENT_SCHEMA = %1").arg(schemaName)); } else { schemaNode->setToolTip(0, QString::fromLocal8Bit("Oracle用户模式")); } // 创建对象分类节点(表、视图、函数等) createObjectCategoryNodes(schemaNode); return schemaNode; } // 创建对象分类节点 void MainWindow::createObjectCategoryNodes(QTreeWidgetItem* schemaNode) { const QStringList categories = { QString::fromLocal8Bit("表"), QString::fromLocal8Bit("视图"), QString::fromLocal8Bit("函数"), QString::fromLocal8Bit("过程"), QString::fromLocal8Bit("触发器"), QString::fromLocal8Bit("序列") }; foreach (const QString& category, categories) { QTreeWidgetItem* item = new QTreeWidgetItem(schemaNode); item->setText(0, category); item->setData(0, Qt::UserRole, QString::fromLocal8Bit("类型:") + category); } } // 切换到指定模式 bool MainWindow::switchToSchema(QSqlDatabase& db, const QString& schemaName, bool isKingbase, bool isDM8) { QString sql; if (isKingbase) { sql = QString("SET search_path TO %1, public").arg(schemaName); } else if (isDM8) { sql = QString("ALTER SESSION SET CURRENT_SCHEMA = \"%1\"").arg(schemaName); } else { // Oracle不需要切换 return true; } QSqlQuery query(db); if (!query.exec(sql)) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("无法切换至模式:%1\n错误:%2") .arg(schemaName) .arg(query.lastError().text())); return false; } return true; } // 刷新模式下的所有对象 void MainWindow::refreshAllObjectsInSchema(const QString& connectName, const QString& user, const QString& schemaName, bool isKingbase, bool isDM8, QTreeWidgetItem* schemaNode, QSqlDatabase& db) { // 构建分类节点映射 QMap<QString, QTreeWidgetItem*> categoryMap; for (int i = 0; i < schemaNode->childCount(); ++i) { QTreeWidgetItem* child = schemaNode->child(i); if (child) { categoryMap[child->text(0)] = child; } } // 刷新每种对象类型 QVector<QPair<QString, QString>> objectTypes = { {QString::fromLocal8Bit("表"), "TABLE"}, {QString::fromLocal8Bit("视图"), "VIEW"}, {QString::fromLocal8Bit("函数"), "FUNCTION"}, {QString::fromLocal8Bit("过程"), "PROCEDURE"}, {QString::fromLocal8Bit("触发器"), "TRIGGER"}, {QString::fromLocal8Bit("序列"), "SEQUENCE"} }; foreach (const auto& type, objectTypes) { if (categoryMap.contains(type.first)) { refreshObjectType( connectName, user, schemaName, type.first, type.second, isKingbase || isDM8, categoryMap[type.first], db, schemaName ); } } } // 刷新特定类型的对象 void MainWindow::refreshObjectType(const QString& connectName, const QString& user, const QString& schemaName, const QString& typeName, const QString& objectType, bool isMultiSchema, // 指示是否为多模式数据库 QTreeWidgetItem* typeItem, QSqlDatabase& db, const QString& objectSchema) { // 清空现有节点和缓存 clearExistingItemsAndCache(user, connectName, schemaName, typeName); // 构建查询 QString queryStr = buildObjectQuery(objectType, isMultiSchema, objectSchema); // 执行查询 QSqlQuery query(db); // 多模式数据库需要绑定模式参数 if (isMultiSchema) { query.prepare(queryStr); query.addBindValue(objectSchema); } else { query.prepare(queryStr); } if (!query.exec()) { handleQueryError(typeName, query.lastError()); return; } // 处理查询结果 while (query.next()) { QString objectName = query.value(0).toString(); QString ddl = getEntityDDL(connectName, objectType, objectName, isMultiSchema, objectSchema); // 检查DDL是否有效 if (!isValidDDL(ddl, isMultiSchema)) { continue; } // 更新缓存 updateObjectCache(user, connectName, schemaName, typeName, objectName, ddl); // 添加树节点 addObjectToTree(typeItem, objectName); } } // 清除现有项和缓存 void MainWindow::clearExistingItemsAndCache(const QString& user, const QString& connectName, const QString& schemaName, const QString& typeName) { // 清空树节点 qDeleteAll(typeItem->takeChildren()); // 清空缓存 QMap<QString, QMap<QString, QMap<QString, QString>>>* cacheMap = nullptr; if (typeName == QString::fromLocal8Bit("表")) { cacheMap = &tables; } else if (typeName == QString::fromLocal8Bit("视图")) { cacheMap = &views; } else if (typeName == QString::fromLocal8Bit("函数")) { cacheMap = &funcs; } else if (typeName == QString::fromLocal8Bit("过程")) { cacheMap = &procs; } else if (typeName == QString::fromLocal8Bit("触发器")) { cacheMap = &triggers; } else if (typeName == QString::fromLocal8Bit("序列")) { cacheMap = &seqs; } if (cacheMap && cacheMap->contains(user) && (*cacheMap)[user].contains(connectName)) { (*cacheMap)[user][connectName].remove(schemaName); } } // 构建对象查询 QString MainWindow::buildObjectQuery(const QString& objectType, bool isMultiSchema, const QString& schemaName) { if (isMultiSchema) { // Kingbase/DM8查询 static QMap<QString, QString> multiSchemaQueries = { {"TABLE", "SELECT tablename FROM pg_tables WHERE schemaname = ? ORDER BY tablename"}, {"VIEW", "SELECT viewname FROM pg_views WHERE schemaname = ? ORDER BY viewname"}, {"FUNCTION", "SELECT proname FROM pg_proc WHERE pronamespace = " "(SELECT oid FROM pg_namespace WHERE nspname = ?) ORDER BY proname"}, {"PROCEDURE", "SELECT proname FROM pg_proc WHERE pronamespace = " "(SELECT oid FROM pg_namespace WHERE nspname = ?) " "AND prokind = 'p' ORDER BY proname"}, {"TRIGGER", "SELECT tgname FROM pg_trigger WHERE tgrelid IN " "(SELECT oid FROM pg_class WHERE relnamespace = " "(SELECT oid FROM pg_namespace WHERE nspname = ?)) ORDER BY tgname"}, {"SEQUENCE", "SELECT sequencename FROM pg_sequences WHERE schemaname = ? ORDER BY sequencename"} }; return multiSchemaQueries.value(objectType, ""); } else { // Oracle查询 static QMap<QString, QString> oracleQueries = { {"TABLE", "SELECT table_name FROM user_tables ORDER BY table_name"}, {"VIEW", "SELECT view_name FROM user_views ORDER BY view_name"}, {"FUNCTION", "SELECT object_name FROM user_objects WHERE object_type = 'FUNCTION' ORDER BY object_name"}, {"PROCEDURE", "SELECT object_name FROM user_objects WHERE object_type = 'PROCEDURE' ORDER BY object_name"}, {"TRIGGER", "SELECT trigger_name FROM user_triggers ORDER BY trigger_name"}, {"SEQUENCE", "SELECT sequence_name FROM user_sequences ORDER BY sequence_name"} }; return oracleQueries.value(objectType, ""); } } // 处理查询错误 void MainWindow::handleQueryError(const QString& typeName, const QSqlError& error) { MessageDialog::warning(nullptr, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("查询%1失败: %2").arg(typeName).arg(error.text())); qDebug() << "Query failed:" << typeName << error.text(); } // 检查DDL是否有效 bool MainWindow::isValidDDL(const QString& ddl, bool isMultiSchema) { if (ddl.contains(QString::fromLocal8Bit("获取失败"))) { return false; } // Oracle特定检查 if (!isMultiSchema && ddl.contains("DBMS_METADATA.GET_DDL") && ddl.contains("Unable to execute statement")) { return false; } return true; } // 更新对象缓存 void MainWindow::updateObjectCache(const QString& user, const QString& connectName, const QString& schemaName, const QString& typeName, const QString& objectName, const QString& ddl) { if (typeName == QString::fromLocal8Bit("表")) { tables[user][connectName][schemaName].insert(objectName, ddl); } else if (typeName == QString::fromLocal8Bit("视图")) { views[user][connectName][schemaName].insert(objectName, ddl); } else if (typeName == QString::fromLocal8Bit("函数")) { funcs[user][connectName][schemaName].insert(objectName, ddl); } else if (typeName == QString::fromLocal8Bit("过程")) { procs[user][connectName][schemaName].insert(objectName, ddl); } else if (typeName == QString::fromLocal8Bit("触发器")) { triggers[user][connectName][schemaName].insert(objectName, ddl); } else if (typeName == QString::fromLocal8Bit("序列")) { seqs[user][connectName][schemaName].insert(objectName, ddl); } } void Main能否在此基础上继续生成未完成的内容
09-26
bool MainWindow::setConnectionInfo(bool ifODBC, const QString &host, const QString &port, const QString &service, const QString &user, const QString &password, const QString &connectname, const QString &driver, bool ifDM8) { // 检查连接名是否已存在 QList<QTreeWidgetItem*> foundItems = ui->connectionTree->findItems(connectname, Qt::MatchRecursive, 0); if (!foundItems.isEmpty()) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("已存在同名连接")); return false; } if (QSqlDatabase::contains(connectname)) { QSqlDatabase::removeDatabase(connectname); } // 设置连接类型 this->ifDM8 = ifDM8; m_currentConnectionName = connectname; if(ifODBC){ if(ifDM8) connectType[connectname] = 2; else connectType[connectname] = 3; // Kingbase 数据库 } else connectType[connectname] = 1; this->ifODBC = ifODBC; QSqlDatabase m_db; // 建立数据库连接 if (ifODBC) { m_db = QSqlDatabase::addDatabase("QODBC", connectname); QString connStr = QString("DRIVER={%1};" "SERVER=%2;" "PORT=%3;" "DATABASE=%4;" "UID=%5;" "PWD=%6") .arg(driver) .arg(host) .arg(port) .arg(service) .arg(user) .arg(password); m_db.setDatabaseName(connStr); } else { m_db = QSqlDatabase::addDatabase("QOCI", connectname); m_db.setHostName(host); m_db.setPort(port.toInt()); m_db.setDatabaseName(service); m_db.setUserName(user); m_db.setPassword(password); } this->host = host; this->port = port; this->dbName = service; this->user = user; this->password = password; this->driver = driver; if (!m_db.open()) { MessageDialog::warning(this,QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("数据库连接失败!")); return false; } if(!m_first){ MessageDialog::information(this,QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("数据库连接成功!")); } // 1. 创建一级节点(用户节点) QString userDisplayName = QString::fromLocal8Bit("数据库:%1").arg(service) + QString::fromLocal8Bit(" 用户:%1").arg(user); QTreeWidgetItem *userNode = nullptr; QList<QTreeWidgetItem*> userItems = ui->connectionTree->findItems(userDisplayName, Qt::MatchExactly, 0); if (userItems.isEmpty()) { userNode = new QTreeWidgetItem(ui->connectionTree); userNode->setText(0, userDisplayName); userNode->setData(0, Qt::UserRole, user); if(!ifODBC) userNode->setToolTip(0, "Oracle"); else if(ifDM8) userNode->setToolTip(0, QString::fromLocal8Bit("DM8")); else userNode->setToolTip(0, "KingBase R8 V6"); } else { userNode = userItems.first(); } // 2. 创建二级节点(连接节点) QString connectDisplayName = QString::fromLocal8Bit("连接:%1").arg(connectname); QTreeWidgetItem *connectNode = new QTreeWidgetItem(userNode); connectNode->setText(0, connectDisplayName); connectNode->setData(0, Qt::UserRole, connectname); // 设置连接节点的提示信息 if(ifODBC){ if(ifDM8) connectNode->setToolTip(0, QString::fromLocal8Bit("DM8连接:%1@%2:%3").arg(user).arg(host).arg(port)); else connectNode->setToolTip(0, QString::fromLocal8Bit("KingBase R8 V6连接:%1@%2:%3").arg(user).arg(host).arg(port)); } else connectNode->setToolTip(0, QString::fromLocal8Bit("Oracle连接:%1@%2:%3").arg(user).arg(host).arg(port)); // 3. 处理不同数据库类型的模式 if (connectType[connectname] == 3) { // Kingbase 数据库:获取所有模式 handleKingbaseSchemas(m_db, connectname, user, connectNode); } else if (connectType[connectname] == 2) { // DM8 数据库:获取所有模式 handleDM8Schemas(m_db, connectname, user, connectNode); } else { // Oracle 数据库:单用户模式 handleOracleSingleSchema(m_db, connectname, user, connectNode); } // 添加到连接列表 db.append(connectname); // 保存连接信息到XML ConnectionInfo info; info.ifODBC = ifODBC; info.host = host; info.port = port; info.service = service; info.user = user; info.password = password; info.connectname = connectname; info.driver = driver; info.ifDM8 = ifDM8; // 先移除可能存在的旧信息(避免重复) removeConnectionFromList(connectname); // 添加新信息 savedConnections.append(info); // 写入XML文件 if (!m_first) { saveConnectionsToXml(); } // 展开所有节点以便查看 ui->connectionTree->expandItem(userNode); ui->connectionTree->expandItem(connectNode); return true; } // Kingbase 数据库模式处理 void MainWindow::handleKingbaseSchemas(QSqlDatabase &db, const QString &connectname, const QString &user, QTreeWidgetItem *connectNode) { QSqlQuery schemaQuery(db); schemaQuery.exec("create extension dbms_metadata"); if (schemaQuery.exec("SELECT nspname FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema' ORDER BY nspname")) { while (schemaQuery.next()) { QString schemaName = schemaQuery.value(0).toString(); if(schemaName == "sys" || schemaName == "anon") continue; // 创建三级节点(模式节点) QString schemaDisplayName = QString::fromLocal8Bit("模式:%1").arg(schemaName); QTreeWidgetItem *schemaNode = new QTreeWidgetItem(connectNode); schemaNode->setText(0, schemaDisplayName); schemaNode->setData(0, Qt::UserRole, schemaName); schemaNode->setToolTip(0, QString::fromLocal8Bit("Kingbase模式 - SET search_path TO %1, public").arg(schemaName)); // 创建各类数据库对象的父节点 createSchemaObjectNodes(schemaNode); // 切换至对应模式 QString turnSql = QString("SET search_path TO %1, public").arg(schemaName); QSqlQuery turnQuery(db); if (!turnQuery.exec(turnSql)) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("无法切换至模式:%1").arg(schemaName)); continue; } // 加载模式下的所有对象 loadSchemaObjects(db, connectname, user, schemaName, schemaNode); } } } // DM8 数据库模式处理 void MainWindow::handleDM8Schemas(QSqlDatabase &db, const QString &connectname, const QString &user, QTreeWidgetItem *connectNode) { QSqlQuery schemaQuery(db); bool ifconnect = true; // DM8获取所有模式的SQL(排除系统模式) QString schemaQueryStr = QString( "SELECT DISTINCT OWNER FROM DBA_OBJECTS " "WHERE OWNER NOT IN ('SYS','SYSTEM','SYSAUDITOR','SYSSSO','SYSDBO') " "ORDER BY OWNER" ); if (!schemaQuery.exec(schemaQueryStr)) { schemaQueryStr = QString( "SELECT DISTINCT OWNER FROM ALL_OBJECTS " "WHERE OWNER NOT IN ('SYS','SYSTEM','SYSAUDITOR','SYSSSO','SYSDBO') " "ORDER BY OWNER" ); if(!schemaQuery.exec(schemaQueryStr)) { ifconnect = false; MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("查询DM8模式失败: %1").arg(schemaQuery.lastError().text())); } } if (ifconnect) { while (schemaQuery.next()) { QString schemaName = schemaQuery.value(0).toString(); // 创建三级节点(模式节点) QString schemaDisplayName = QString::fromLocal8Bit("模式:%1").arg(schemaName); QTreeWidgetItem *schemaNode = new QTreeWidgetItem(connectNode); schemaNode->setText(0, schemaDisplayName); schemaNode->setData(0, Qt::UserRole, schemaName); schemaNode->setToolTip(0, QString::fromLocal8Bit("DM8模式 - ALTER SESSION SET CURRENT_SCHEMA = %1").arg(schemaName)); // 创建各类数据库对象的父节点 createSchemaObjectNodes(schemaNode); // DM8切换模式 QString turnSql = QString("ALTER SESSION SET CURRENT_SCHEMA = \"%1\"").arg(schemaName); QSqlQuery turnQuery(db); if (!turnQuery.exec(turnSql)) { MessageDialog::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("无法切换至DM8模式:%1").arg(schemaName)); continue; } // 加载模式下的所有对象 loadDM8SchemaObjects(db, connectname, user, schemaName, schemaNode); } } } // Oracle 数据库单模式处理 void MainWindow::handleOracleSingleSchema(QSqlDatabase &db, const QString &connectname, const QString &user, QTreeWidgetItem *connectNode) { QString schemaName = user; // 使用用户名作为模式名 QString schemaDisplayName = QString::fromLocal8Bit("模式:%1").arg(schemaName); QTreeWidgetItem *schemaNode = new QTreeWidgetItem(connectNode); schemaNode->setText(0, schemaDisplayName); schemaNode->setData(0, Qt::UserRole, schemaName); schemaNode->setToolTip(0, QString::fromLocal8Bit("Oracle用户模式")); // 创建各类数据库对象的父节点 createSchemaObjectNodes(schemaNode); // 加载Oracle用户模式下的所有对象 loadOracleSchemaObjects(db, connectname, user, schemaName, schemaNode); } // 创建模式下的对象分类节点 void MainWindow::createSchemaObjectNodes(QTreeWidgetItem *schemaNode) { QTreeWidgetItem *tablesItem = new QTreeWidgetItem(schemaNode); tablesItem->setText(0, QString::fromLocal8Bit("表")); QTreeWidgetItem *functionsItem = new QTreeWidgetItem(schemaNode); functionsItem->setText(0, QString::fromLocal8Bit("函数")); QTreeWidgetItem *proceduresItem = new QTreeWidgetItem(schemaNode); proceduresItem->setText(0, QString::fromLocal8Bit("过程")); QTreeWidgetItem *triggersItem = new QTreeWidgetItem(schemaNode); triggersItem->setText(0, QString::fromLocal8Bit("触发器")); QTreeWidgetItem *sequencesItem = new QTreeWidgetItem(schemaNode); sequencesItem->setText(0, QString::fromLocal8Bit("序列")); QTreeWidgetItem *viewsItem = new QTreeWidgetItem(schemaNode); viewsItem->setText(0, QString::fromLocal8Bit("视图")); } // 加载Kingbase模式对象 void MainWindow::loadSchemaObjects(QSqlDatabase &m_db, const QString &connectname, const QString &user, const QString &schemaName, QTreeWidgetItem *schemaNode) { // 查找对象分类节点 QTreeWidgetItem *tablesItem = nullptr; QTreeWidgetItem *viewsItem = nullptr; QTreeWidgetItem *functionsItem = nullptr; QTreeWidgetItem *proceduresItem = nullptr; QTreeWidgetItem *triggersItem = nullptr; QTreeWidgetItem *sequencesItem = nullptr; for (int i = 0; i < schemaNode->childCount(); ++i) { QTreeWidgetItem *child = schemaNode->child(i); QString text = child->text(0); if (text == QString::fromLocal8Bit("表")) tablesItem = child; else if (text == QString::fromLocal8Bit("视图")) viewsItem = child; else if (text == QString::fromLocal8Bit("函数")) functionsItem = child; else if (text == QString::fromLocal8Bit("过程")) proceduresItem = child; else if (text == QString::fromLocal8Bit("触发器")) triggersItem = child; else if (text == QString::fromLocal8Bit("序列")) sequencesItem = child; } // 获取当前模式下的表 QSqlQuery tableQuery(m_db); tableQuery.prepare("SELECT tablename FROM pg_tables WHERE schemaname = ? ORDER BY tablename"); tableQuery.addBindValue(schemaName); if (tableQuery.exec()) { while (tableQuery.next()) { QString tableName = tableQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "TABLE", tableName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { // 使用新的数据结构存储:tables[用户名][连接名][模式名][表名] = DDL tables[user][connectname][schemaName].insert(tableName, ddl); QTreeWidgetItem* tableItem = new QTreeWidgetItem(tablesItem); tableItem->setText(0, tableName); } } } // 获取当前模式下的视图 QSqlQuery viewQuery(m_db); viewQuery.prepare("SELECT viewname FROM pg_views WHERE schemaname = ? ORDER BY viewname"); viewQuery.addBindValue(schemaName); if (viewQuery.exec()) { while (viewQuery.next()) { QString viewName = viewQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "VIEW", viewName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { views[user][connectname][schemaName].insert(viewName, ddl); QTreeWidgetItem *viewItem = new QTreeWidgetItem(viewsItem); viewItem->setText(0, viewName); } } } // 获取当前模式下的函数 QSqlQuery funcQuery(m_db); funcQuery.prepare("SELECT proname FROM pg_proc WHERE pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = ?) ORDER BY proname"); funcQuery.addBindValue(schemaName); if (funcQuery.exec()) { while (funcQuery.next()) { QString funcName = funcQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "FUNCTION", funcName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { funcs[user][connectname][schemaName].insert(funcName, ddl); QTreeWidgetItem *funcItem = new QTreeWidgetItem(functionsItem); funcItem->setText(0, funcName); } } } // 获取当前模式下的存储过程 QSqlQuery procQuery(m_db); procQuery.prepare("SELECT proname FROM pg_proc WHERE pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = ?) AND prokind = 'p' ORDER BY proname"); procQuery.addBindValue(schemaName); if (procQuery.exec()) { while (procQuery.next()) { QString procName = procQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "PROCEDURE", procName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { procs[user][connectname][schemaName].insert(procName, ddl); QTreeWidgetItem *procItem = new QTreeWidgetItem(proceduresItem); procItem->setText(0, procName); } } } // 获取当前模式下的触发器 QSqlQuery triggerQuery(m_db); triggerQuery.prepare("SELECT tgname FROM pg_trigger WHERE tgrelid IN (SELECT oid FROM pg_class WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = ?)) ORDER BY tgname"); triggerQuery.addBindValue(schemaName); if (triggerQuery.exec()) { while (triggerQuery.next()) { QString triggerName = triggerQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "TRIGGER", triggerName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { triggers[user][connectname][schemaName].insert(triggerName, ddl); QTreeWidgetItem *triggerItem = new QTreeWidgetItem(triggersItem); triggerItem->setText(0, triggerName); } } } // 获取当前模式下的序列 QSqlQuery seqQuery(m_db); seqQuery.prepare("SELECT sequencename FROM pg_sequences WHERE schemaname = ? ORDER BY sequencename"); seqQuery.addBindValue(schemaName); if (seqQuery.exec()) { while (seqQuery.next()) { QString seqName = seqQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "SEQUENCE", seqName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { seqs[user][connectname][schemaName].insert(seqName, ddl); QTreeWidgetItem *seqItem = new QTreeWidgetItem(sequencesItem); seqItem->setText(0, seqName); } } } } // 加载DM8模式对象 void MainWindow::loadDM8SchemaObjects(QSqlDatabase &db, const QString &connectname, const QString &user, const QString &schemaName, QTreeWidgetItem *schemaNode) { // 查找对象分类节点 QTreeWidgetItem *tablesItem = nullptr; QTreeWidgetItem *viewsItem = nullptr; QTreeWidgetItem *functionsItem = nullptr; QTreeWidgetItem *proceduresItem = nullptr; QTreeWidgetItem *triggersItem = nullptr; QTreeWidgetItem *sequencesItem = nullptr; for (int i = 0; i < schemaNode->childCount(); ++i) { QTreeWidgetItem *child = schemaNode->child(i); QString text = child->text(0); if (text == QString::fromLocal8Bit("表")) tablesItem = child; else if (text == QString::fromLocal8Bit("视图")) viewsItem = child; else if (text == QString::fromLocal8Bit("函数")) functionsItem = child; else if (text == QString::fromLocal8Bit("过程")) proceduresItem = child; else if (text == QString::fromLocal8Bit("触发器")) triggersItem = child; else if (text == QString::fromLocal8Bit("序列")) sequencesItem = child; } // 加载DM8表 if (tablesItem) { QSqlQuery tableQuery(db); QString tableQueryStr = QString( "SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = '%1' ORDER BY TABLE_NAME" ).arg(schemaName); if (tableQuery.exec(tableQueryStr)) { while (tableQuery.next()) { QString tableName = tableQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "TABLE", tableName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { tables[user][connectname][schemaName].insert(tableName, ddl); QTreeWidgetItem* tableItem = new QTreeWidgetItem(tablesItem); tableItem->setText(0, tableName); } } } } // 加载DM8视图 if (viewsItem) { QSqlQuery viewQuery(db); QString viewQueryStr = QString( "SELECT VIEW_NAME FROM ALL_VIEWS WHERE OWNER = '%1' ORDER BY VIEW_NAME" ).arg(schemaName); if (viewQuery.exec(viewQueryStr)) { while (viewQuery.next()) { QString viewName = viewQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "VIEW", viewName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { views[user][connectname][schemaName].insert(viewName, ddl); QTreeWidgetItem *viewItem = new QTreeWidgetItem(viewsItem); viewItem->setText(0, viewName); } } } } // 加载DM8函数 if (functionsItem) { QSqlQuery funcQuery(db); QString funcQueryStr = QString( "SELECT OBJECT_NAME FROM ALL_OBJECTS WHERE OWNER = '%1' AND OBJECT_TYPE = 'FUNCTION' ORDER BY OBJECT_NAME" ).arg(schemaName); if (funcQuery.exec(funcQueryStr)) { while (funcQuery.next()) { QString funcName = funcQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "FUNCTION", funcName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { funcs[user][connectname][schemaName].insert(funcName, ddl); QTreeWidgetItem *funcItem = new QTreeWidgetItem(functionsItem); funcItem->setText(0, funcName); } } } } // 加载DM8存储过程 if (proceduresItem) { QSqlQuery procQuery(db); QString procQueryStr = QString( "SELECT OBJECT_NAME FROM ALL_OBJECTS WHERE OWNER = '%1' AND OBJECT_TYPE = 'PROCEDURE' ORDER BY OBJECT_NAME" ).arg(schemaName); if (procQuery.exec(procQueryStr)) { while (procQuery.next()) { QString procName = procQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "PROCEDURE", procName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { procs[user][connectname][schemaName].insert(procName, ddl); QTreeWidgetItem *procItem = new QTreeWidgetItem(proceduresItem); procItem->setText(0, procName); } } } } // 加载DM8触发器 if (triggersItem) { QSqlQuery triggerQuery(db); QString triggerQueryStr = QString( "SELECT TRIGGER_NAME FROM ALL_TRIGGERS WHERE OWNER = '%1' ORDER BY TRIGGER_NAME" ).arg(schemaName); if (triggerQuery.exec(triggerQueryStr)) { while (triggerQuery.next()) { QString triggerName = triggerQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "TRIGGER", triggerName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { triggers[user][connectname][schemaName].insert(triggerName, ddl); QTreeWidgetItem *triggerItem = new QTreeWidgetItem(triggersItem); triggerItem->setText(0, triggerName); } } } } // 加载DM8序列 if (sequencesItem) { QSqlQuery seqQuery(db); QString seqQueryStr = QString( "SELECT SEQUENCE_NAME FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER = '%1' ORDER BY SEQUENCE_NAME" ).arg(schemaName); if (seqQuery.exec(seqQueryStr)) { while (seqQuery.next()) { QString seqName = seqQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "SEQUENCE", seqName, true, schemaName); if (!ddl.contains(QString::fromLocal8Bit("获取失败"))) { seqs[user][connectname][schemaName].insert(seqName, ddl); QTreeWidgetItem *seqItem = new QTreeWidgetItem(sequencesItem); seqItem->setText(0, seqName); } } } } } // 加载Oracle模式对象(原有逻辑) void MainWindow::loadOracleSchemaObjects(QSqlDatabase &m_db, const QString &connectname, const QString &user, const QString &schemaName, QTreeWidgetItem *schemaNode) { // 创建各类数据库对象的父节点 QTreeWidgetItem *tablesItem = new QTreeWidgetItem(schemaNode); tablesItem->setText(0, QString::fromLocal8Bit("表")); QTreeWidgetItem *functionsItem = new QTreeWidgetItem(schemaNode); functionsItem->setText(0, QString::fromLocal8Bit("函数")); QTreeWidgetItem *proceduresItem = new QTreeWidgetItem(schemaNode); proceduresItem->setText(0, QString::fromLocal8Bit("过程")); QTreeWidgetItem *triggersItem = new QTreeWidgetItem(schemaNode); triggersItem->setText(0, QString::fromLocal8Bit("触发器")); QTreeWidgetItem *sequencesItem = new QTreeWidgetItem(schemaNode); sequencesItem->setText(0, QString::fromLocal8Bit("序列")); QTreeWidgetItem *viewsItem = new QTreeWidgetItem(schemaNode); viewsItem->setText(0, QString::fromLocal8Bit("视图")); // 获取表 QSqlQuery tableQuery(m_db); if (tableQuery.exec("SELECT table_name FROM user_tables ORDER BY table_name")) { while (tableQuery.next()) { QString tableName = tableQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "TABLE", tableName, false); if(ddl != QString::fromLocal8Bit("获取失败:未找到对象或不允许查询系统定义的内部索引\n-20008: DBMS_METADATA.GET_DDL line 2400 QODBC3: Unable to execute statement")){ tables[user][connectname][schemaName].insert(tableName, ddl); QTreeWidgetItem* tableItem = new QTreeWidgetItem(tablesItem); tableItem->setText(0, tableName); } } } // 获取视图 QSqlQuery viewQuery(m_db); if (viewQuery.exec("SELECT view_name FROM user_views ORDER BY view_name")) { while (viewQuery.next()) { QString viewName = viewQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "VIEW", viewName, false); views[user][connectname][schemaName].insert(viewName, ddl); QTreeWidgetItem *viewItem = new QTreeWidgetItem(viewsItem); viewItem->setText(0, viewName); } } // 获取函数 QSqlQuery funcQuery(m_db); if (funcQuery.exec("SELECT object_name FROM user_objects WHERE object_type = 'FUNCTION' ORDER BY object_name")) { while (funcQuery.next()) { QString funcName = funcQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "FUNCTION", funcName, false); if(ddl != QString::fromLocal8Bit("获取失败:未找到对象或不允许查询系统定义的内部索引\n-20008: DBMS_METADATA.GET_DDL line 2400 QODBC3: Unable to execute statement")){ funcs[user][connectname][schemaName].insert(funcName, ddl); QTreeWidgetItem *funcItem = new QTreeWidgetItem(functionsItem); funcItem->setText(0, funcName); } } } // 获取存储过程 QSqlQuery procQuery(m_db); if (procQuery.exec("SELECT object_name FROM user_objects WHERE object_type = 'PROCEDURE' ORDER BY object_name")) { while (procQuery.next()) { QString procName = procQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "PROCEDURE", procName, false); procs[user][connectname][schemaName].insert(procName, ddl); QTreeWidgetItem *procItem = new QTreeWidgetItem(proceduresItem); procItem->setText(0, procName); } } // 获取触发器 QSqlQuery triggerQuery(m_db); if (triggerQuery.exec("SELECT trigger_name FROM user_triggers ORDER BY trigger_name")) { while (triggerQuery.next()) { QString triggerName = triggerQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "TRIGGER", triggerName, false); triggers[user][connectname][schemaName].insert(triggerName, ddl); QTreeWidgetItem *triggerItem = new QTreeWidgetItem(triggersItem); triggerItem->setText(0, triggerName); } } // 获取序列 QSqlQuery seqQuery(m_db); if (seqQuery.exec("SELECT sequence_name FROM user_sequences ORDER BY sequence_name")) { while (seqQuery.next()) { QString seqName = seqQuery.value(0).toString().toUpper(); QString ddl = getEntityDDL(connectname, "SEQUENCE", seqName, false); seqs[user][connectname][schemaName].insert(seqName, ddl); QTreeWidgetItem *seqItem = new QTreeWidgetItem(sequencesItem); seqItem->setText(0, seqName); } } } 分析并理解此逻辑
09-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值