- 「ドメイン(Domain)」による型制限
PostgreSQLには、既存のデータ型にチェック制約(CHECK)を付与して、独自の型を作成する**「ドメイン」**という機能があります。
もし対象のカラムが VARCHAR ではなく、システム固有のカスタム型(例: postal_code など)になっている場合、そのドメイン自体に文字数制限がかけられている可能性が高いです。
調査用SQL
以下のSQLを実行すると、データベース内に定義されているドメインと、その制約条件(length(VALUE) <= 3 など)の一覧を確認できます。
SELECT
d.typname AS domain_name,
b.typname AS base_type,
c.consrc AS constraint_check
FROM pg_catalog.pg_type d
JOIN pg_catalog.pg_type b ON d.typbasetype = b.oid
JOIN pg_catalog.pg_constraint c ON d.oid = c.contypid;
- 「トリガー(Trigger)」による自動カット・バリデーション
データが INSERT または UPDATE される直前にトリガーが走り、関数内で文字列が切り落とされたり、エラーを発生させているパターンです。
「特定の文字数を超えたら SUBSTRING(NEW.column FROM 1 FOR 3) で切り詰めて格納する」といった処理が、PL/pgSQLなどのトリガー関数内に隠れているケースがあります。
調査用SQL
対象のテーブルにどんなトリガーが設定されているかは、以下のSQLで確認できます。
SELECT tgname, tgfoid::regproc AS function_name
FROM pg_trigger
WHERE tgrelid = 'あなたのテーブル名'::regclass;
不審なトリガー関数が見つかった場合は、その関数の中身(pg_get_functiondef などで確認可能)をチェックしてみましょう。
3. 「ストアドプロシージャ / 関数」の引数・変数制限
アプリケーション側がテーブルに直接 INSERT しておらず、データベース側に定義された関数(Function)やプロシージャを経由してデータを操作している場合に発生します。
テーブル定義が TEXT であっても、それを受け取る関数の引数や、内部で処理する変数の型が VARCHAR(3) や CHAR(3) のように制限されていると、その時点で文字数が削られます。
調査方法
該当の関数・プロシージャの定義(引数や DECLARE ブロックの変数定義)を確認してください。
- 【番外編】「アプリケーション側」のバリデーション・ORマッパー
データベース層ではなく、DBにデータを送っているアプリケーション(Python, Node.js, Java, Goなど)側で制限がかかっているオチです。
ORマッパーのモデル定義: SQLAlchemy、Django ORM、Prisma、Sequelizeなどのモデル側で max_length=3 が指定されている。
バリデーションロジック: フォームバリデーションやAPI DTO(Data Transfer Object)の段階で3桁制限のバリデータが動いている。