PostgreSQL (8.4) と SQLite3 で出たとある違い


NOT NULL な column を追加しようとしたとき,PostgreSQL と SQLite3 で差が出た.

rails new sqlite3test
cd sqlite3test
rails g model item name:string # 適当に model 作る
rake db:migrate
rails g migration add_price_to_item price:integer # column を追加する
vim db/migrate/xxxxxxxxxxxx_add_price_to_item.rb # price に null: false を設定
rake db:migrate

すると以下のエラーが出る.

rake aborted!
An error has occurred, this and all later migrations canceled:

SQLite3::SQLException: Cannot add a NOT NULL column with default value NULL: ALTER TABLE "items" ADD "price" integer NOT NULL

当然である.NOT NULL な column なのに default を指定しなければ,もし行が既に存在した場合その column (今回は price) が NULL にならざるを得ないではないか.

しかし PostgreSQL だとこれが通るのである.先のコマンドを以下のように変えて見ると分かる.

rails new pgtest -d postgresql
cd pgtest
... # 以下同じ

ただし,1 つでも行が items に存在する場合は,SQLite3 と同様にエラーが発生する.

# 1 度目の rake db:migrate の直後
rails runner 'Item.create'
rails g migration add_price... # 以下同様に
rake aborted!
An error has occurred, this and all later migrations canceled:

PG::Error: ERROR:  column "price" contains null values
: ALTER TABLE "items" ALTER "price" SET NOT NULL

つまり PostgreSQL の方が少しお利口さんなのですね.