BEGIN; LOCK TABLE tb_agent_wallet IN ACCESS EXCLUSIVE MODE; ALTER TABLE tb_agent_wallet ADD COLUMN IF NOT EXISTS credit_enabled boolean NOT NULL DEFAULT false, ADD COLUMN IF NOT EXISTS credit_limit bigint NOT NULL DEFAULT 0; COMMENT ON COLUMN tb_agent_wallet.credit_enabled IS '是否启用代理主钱包信用额度;分佣钱包固定关闭'; COMMENT ON COLUMN tb_agent_wallet.credit_limit IS '代理主钱包信用额度,单位为分;关闭信用时固定为0'; -- 迁移在目标库读取真实约束定义,不依赖归档迁移中的约束名称。 DO $$ DECLARE balance_attnum smallint; constraint_row record; normalized_definition text; BEGIN SELECT attnum INTO balance_attnum FROM pg_attribute WHERE attrelid = 'tb_agent_wallet'::regclass AND attname = 'balance' AND NOT attisdropped; FOR constraint_row IN SELECT conname, conkey, pg_get_constraintdef(oid) AS definition FROM pg_constraint WHERE conrelid = 'tb_agent_wallet'::regclass AND contype = 'c' LOOP normalized_definition := regexp_replace(lower(constraint_row.definition), '[[:space:]()]', '', 'g'); IF (array_length(constraint_row.conkey, 1) = 1 AND constraint_row.conkey[1] = balance_attnum AND normalized_definition LIKE 'check%balance%>=%0%') OR normalized_definition LIKE '%frozen_balance%<=%balance%' THEN RAISE NOTICE '移除代理钱包历史约束 %:%', constraint_row.conname, constraint_row.definition; EXECUTE format('ALTER TABLE tb_agent_wallet DROP CONSTRAINT %I', constraint_row.conname); END IF; END LOOP; END $$; ALTER TABLE tb_agent_wallet DROP CONSTRAINT IF EXISTS chk_agent_wallet_credit_config, DROP CONSTRAINT IF EXISTS chk_agent_wallet_credit_scope, DROP CONSTRAINT IF EXISTS chk_agent_wallet_frozen_nonnegative, DROP CONSTRAINT IF EXISTS chk_agent_wallet_arithmetic_range, DROP CONSTRAINT IF EXISTS chk_agent_wallet_available_balance, DROP CONSTRAINT IF EXISTS chk_agent_wallet_version_nonnegative; -- 历史钱包默认关闭信用;任何既有异常都必须先形成清单并修复,禁止迁移静默改账。 DO $$ DECLARE abnormal_count bigint; BEGIN SELECT COUNT(*) INTO abnormal_count FROM tb_agent_wallet WHERE wallet_type NOT IN ('main', 'commission') OR frozen_balance < 0 OR version < 0 OR credit_enabled OR credit_limit <> 0 OR (wallet_type = 'main' AND balance::numeric - frozen_balance::numeric < 0) OR (wallet_type = 'commission' AND (balance < 0 OR frozen_balance > balance)); IF abnormal_count > 0 THEN RAISE EXCEPTION '代理钱包信用迁移发现 % 条异常数据,请先导出钱包ID、约束定义并修复后重试', abnormal_count; END IF; END $$; ALTER TABLE tb_agent_wallet ADD CONSTRAINT chk_agent_wallet_credit_config CHECK ( (credit_enabled = false AND credit_limit = 0) OR (credit_enabled = true AND credit_limit > 0) ), ADD CONSTRAINT chk_agent_wallet_credit_scope CHECK ( wallet_type = 'main' OR (credit_enabled = false AND credit_limit = 0) ), ADD CONSTRAINT chk_agent_wallet_frozen_nonnegative CHECK (frozen_balance >= 0), ADD CONSTRAINT chk_agent_wallet_arithmetic_range CHECK ( wallet_type <> 'main' OR ( balance > -9223372036854775808::numeric AND balance::numeric - frozen_balance::numeric BETWEEN -9223372036854775808::numeric AND 9223372036854775807::numeric AND balance::numeric - frozen_balance::numeric + CASE WHEN credit_enabled THEN credit_limit::numeric ELSE 0::numeric END BETWEEN -9223372036854775808::numeric AND 9223372036854775807::numeric ) ), ADD CONSTRAINT chk_agent_wallet_available_balance CHECK ( (wallet_type = 'main' AND balance::numeric - frozen_balance::numeric + CASE WHEN credit_enabled THEN credit_limit::numeric ELSE 0::numeric END >= 0) OR (wallet_type = 'commission' AND balance >= 0 AND frozen_balance <= balance) ), ADD CONSTRAINT chk_agent_wallet_version_nonnegative CHECK (version >= 0); CREATE INDEX IF NOT EXISTS idx_agent_wallet_main_credit_enabled ON tb_agent_wallet (shop_id) WHERE wallet_type = 'main' AND credit_enabled = true AND deleted_at IS NULL; COMMENT ON CONSTRAINT chk_agent_wallet_credit_config ON tb_agent_wallet IS '保证信用开关与额度组合一致'; COMMENT ON CONSTRAINT chk_agent_wallet_credit_scope ON tb_agent_wallet IS '保证只有代理主钱包可以启用信用额度'; COMMENT ON CONSTRAINT chk_agent_wallet_frozen_nonnegative ON tb_agent_wallet IS '保证冻结金额不为负数'; COMMENT ON CONSTRAINT chk_agent_wallet_arithmetic_range ON tb_agent_wallet IS '保证现金可用、总可用和欠款金额均可在int64范围内安全计算'; COMMENT ON CONSTRAINT chk_agent_wallet_available_balance ON tb_agent_wallet IS '保证主钱包总可用金额和分佣钱包现金可用金额不为负数'; COMMENT ON CONSTRAINT chk_agent_wallet_version_nonnegative ON tb_agent_wallet IS '保证钱包乐观锁版本不为负数'; COMMENT ON INDEX idx_agent_wallet_main_credit_enabled IS '启用信用额度的有效代理主钱包索引'; COMMIT;