diff --git a/Ramitta/Database/PostgreSQL.cs b/Ramitta/Database/PostgreSQL.cs index ed732d0..262084a 100644 --- a/Ramitta/Database/PostgreSQL.cs +++ b/Ramitta/Database/PostgreSQL.cs @@ -29,16 +29,37 @@ namespace Ramitta db.Open(); } - // 创建表:根据表名和字段定义创建表 + // 创建表:如果表存在则删除重建 public void CreateTable(string tableName, Dictionary columns) { // 构建列定义的字符串 var columnsDefinition = string.Join(", ", columns.Select(c => $"\"{c.Key}\" {MapDataType(c.Value)}")); - string createTableQuery = $"CREATE TABLE IF NOT EXISTS \"{tableName}\" ({columnsDefinition});"; - using (var cmd = new NpgsqlCommand(createTableQuery, db)) + // 删除表(如果存在)然后创建新表 + string dropQuery = $"DROP TABLE IF EXISTS \"{tableName}\";"; + string createTableQuery = $"CREATE TABLE \"{tableName}\" ({columnsDefinition});"; + + using (var transaction = db.BeginTransaction()) { - cmd.ExecuteNonQuery(); + try + { + using (var dropCmd = new NpgsqlCommand(dropQuery, db)) + { + dropCmd.ExecuteNonQuery(); + } + + using (var createCmd = new NpgsqlCommand(createTableQuery, db)) + { + createCmd.ExecuteNonQuery(); + } + + transaction.Commit(); + } + catch + { + transaction.Rollback(); + throw; + } } } @@ -248,6 +269,41 @@ namespace Ramitta } } + // 删除表:删除指定名称的表 + public bool DeleteTable(string tableName) + { + try + { + // 验证表名是否为空或空白 + if (string.IsNullOrWhiteSpace(tableName)) + { + throw new ArgumentException("表名不能为空", nameof(tableName)); + } + + // 清理表名,移除可能的特殊字符 + string cleanTableName = tableName.Trim(); + + // 使用参数化查询防止SQL注入 + string query = $"DROP TABLE IF EXISTS @tableName CASCADE"; + + using (var cmd = new NpgsqlCommand(query, db)) + { + // 使用参数化方式传递表名 + cmd.Parameters.AddWithValue("@tableName", cleanTableName); + + int rowsAffected = cmd.ExecuteNonQuery(); + + // 在PostgreSQL中,DROP TABLE成功执行后ExecuteNonQuery()返回-1 + return true; + } + } + catch (Exception ex) + { + // 记录日志或重新抛出异常 + throw new InvalidOperationException($"删除表 '{tableName}' 失败: {ex.Message}", ex); + } + } + // 删除数据:根据条件删除指定表中的记录 public void DeleteData(string tableName, string condition) { @@ -350,6 +406,224 @@ namespace Ramitta return insertedCount; } + #region 权限 + // 修改用户/角色对表的权限 + public void GrantTablePermission(string tableName, string userOrRole, + List permissions, bool withGrantOption = false) + { + if (db.State != System.Data.ConnectionState.Open) + { + throw new InvalidOperationException("数据库连接未打开"); + } + + // 支持的权限类型映射 + var validPermissions = new Dictionary + { + { "SELECT", "SELECT" }, + { "INSERT", "INSERT" }, + { "UPDATE", "UPDATE" }, + { "DELETE", "DELETE" }, + { "ALL", "ALL PRIVILEGES" } + }; + + // 验证权限类型 + var validPermList = new List(); + foreach (var perm in permissions) + { + var upperPerm = perm.ToUpper(); + if (validPermissions.ContainsKey(upperPerm)) + { + validPermList.Add(validPermissions[upperPerm]); + } + else + { + throw new ArgumentException($"不支持的权限类型: {perm}"); + } + } + + if (validPermList.Count == 0) + { + throw new ArgumentException("至少需要指定一个权限"); + } + + // 构建权限字符串 + string permissionsStr = string.Join(", ", validPermList); + + // 构建WITH GRANT OPTION部分 + string grantOption = withGrantOption ? " WITH GRANT OPTION" : ""; + + // 构建GRANT语句 + string grantQuery = $"GRANT {permissionsStr} ON TABLE \"{tableName}\" TO \"{userOrRole}\"{grantOption};"; + + using (var cmd = new NpgsqlCommand(grantQuery, db)) + { + cmd.ExecuteNonQuery(); + } + } + + // 撤销用户/角色对表的权限 + public void RevokeTablePermission(string tableName, string userOrRole, + List permissions, bool cascade = false) + { + if (db.State != System.Data.ConnectionState.Open) + { + throw new InvalidOperationException("数据库连接未打开"); + } + + // 支持的权限类型映射 + var validPermissions = new Dictionary + { + { "SELECT", "SELECT" }, + { "INSERT", "INSERT" }, + { "UPDATE", "UPDATE" }, + { "DELETE", "DELETE" }, + { "ALL", "ALL PRIVILEGES" } + }; + + // 验证权限类型 + var validPermList = new List(); + foreach (var perm in permissions) + { + var upperPerm = perm.ToUpper(); + if (validPermissions.ContainsKey(upperPerm)) + { + validPermList.Add(validPermissions[upperPerm]); + } + else + { + throw new ArgumentException($"不支持的权限类型: {perm}"); + } + } + + if (validPermList.Count == 0) + { + throw new ArgumentException("至少需要指定一个权限"); + } + + // 构建权限字符串 + string permissionsStr = string.Join(", ", validPermList); + + // 构建CASCADE选项 + string cascadeOption = cascade ? " CASCADE" : ""; + + // 构建REVOKE语句 + string revokeQuery = $"REVOKE {permissionsStr} ON TABLE \"{tableName}\" FROM \"{userOrRole}\"{cascadeOption};"; + + using (var cmd = new NpgsqlCommand(revokeQuery, db)) + { + cmd.ExecuteNonQuery(); + } + } + + // 查询表的当前权限 + public DataTable GetTablePermissions(string tableName) + { + if (db.State != System.Data.ConnectionState.Open) + { + throw new InvalidOperationException("数据库连接未打开"); + } + + // 查询表的权限信息 + string query = @" + SELECT + grantee as 用户角色, + string_agg(privilege_type, ', ') as 权限列表, + is_grantable as 可授权 + FROM information_schema.role_table_grants + WHERE table_name = @tableName + GROUP BY grantee, is_grantable + ORDER BY grantee;"; + + using (var cmd = new NpgsqlCommand(query, db)) + { + cmd.Parameters.AddWithValue("tableName", tableName); + + using (var reader = cmd.ExecuteReader()) + { + DataTable result = new DataTable(); + result.Load(reader); + return result; + } + } + } + + // 批量设置权限(可设置多个用户/角色) + public void BatchSetPermissions(string tableName, Dictionary> userPermissions, + bool withGrantOption = false) + { + if (db.State != System.Data.ConnectionState.Open) + { + throw new InvalidOperationException("数据库连接未打开"); + } + + using (var transaction = db.BeginTransaction()) + { + try + { + foreach (var kvp in userPermissions) + { + string userOrRole = kvp.Key; + List permissions = kvp.Value; + + // 先撤销所有权限,再重新授予 + RevokeAllPermissions(tableName, userOrRole); + + if (permissions.Count > 0) + { + GrantTablePermission(tableName, userOrRole, permissions, withGrantOption); + } + } + + transaction.Commit(); + } + catch + { + transaction.Rollback(); + throw; + } + } + } + + // 撤销所有权限 + private void RevokeAllPermissions(string tableName, string userOrRole) + { + string revokeQuery = $"REVOKE ALL PRIVILEGES ON TABLE \"{tableName}\" FROM \"{userOrRole}\";"; + + using (var cmd = new NpgsqlCommand(revokeQuery, db)) + { + cmd.ExecuteNonQuery(); + } + } + + // 示例:创建用户/角色(如果需要) + public void CreateRole(string roleName, string password, bool canLogin = false, + bool isSuperuser = false, bool createDb = false, + bool createRole = false) + { + if (db.State != System.Data.ConnectionState.Open) + { + throw new InvalidOperationException("数据库连接未打开"); + } + + // 构建CREATE ROLE语句 + List options = new List(); + + if (canLogin) options.Add("LOGIN"); + if (isSuperuser) options.Add("SUPERUSER"); + if (createDb) options.Add("CREATEDB"); + if (createRole) options.Add("CREATEROLE"); + + string optionsStr = options.Count > 0 ? $" {string.Join(" ", options)}" : ""; + + string createRoleQuery = $"CREATE ROLE \"{roleName}\" WITH PASSWORD '{password}'{optionsStr};"; + + using (var cmd = new NpgsqlCommand(createRoleQuery, db)) + { + cmd.ExecuteNonQuery(); + } + } + #endregion + // 释放资源,关闭数据库连接 public void Dispose() {