Tuesday, July 15, 2008

migration postgresql => mysql



есть достаточно большое количество statements, которые после запуска не могут быть rollback. список: для 5.0, для 5.1, то есть mysql не является ACID compliant, хотя оно заявлено.


drop table if exists temp_test_one, temp_test_two;

begin;
create table temp_test_one (a int, b int);
rollback;

-- fail here, create table caused implicit commit
create table temp_test_one (a int);


begin;
alter table test1 drop b;
rollback;

-- fail here, because alter table also caused implicit commit
alter table test1 drop b;


по непонятным для меня причинам, второе поле типа timestamp не может принимать значение now() при вставке, что делает возможным создание поля created только с помощью триггера. зато первое поле такого типа по умолчанию апдейтится при каждом обновлении записи. вот такая долбаная магия.


-- fail here, error: Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause (WHY?)
create table temp_test_two (created timestamp default now(), updated timestamp default now());

-- fail here because first timestamp column have default now()
create table temp_test_two (updated timestamp, created timestamp default now());

create table temp_test_two (updated timestamp, created timestamp);

-- now updated column being updated on any update


триггеры может создавать только пользователь с правами super (вроде, в 5.1 они это поправили)


-- fail here if you don't have super privilege (5.0)
create trigger temp_test_two_bcreate before insert on temp_test_two for each row set new.created = now();


чюваки из mysql до сих пор не смогли написать нормального парсера, чтобы разграничивать внутренности процедур от остального sql кода.


-- fail because you don't set delimiter (stupid mysql parser can't recognize trigger end without separation delimiters inside trigger and outside)
create trigger contact_aupdate after update on contact
for each row begin
if new.contact_auth = 'ok' then
update domain set domain_authenticated = true, domain_state = 'auth' where auth_contact_id = new.contact_id;
end if;
end;


теперь про перл

mysql не может запускать сразу два statement в одном do; если сделать fork, то придется создавать новое соединение, так как старое привязано к process id.


my $dbh = DBI->connect;

my $pid = fork;
if ($pid) {
# failed because you can't launch two statements at same time
$dbh->do ('drop table if exists temp_test_one; drop table if exists temp_test_two; ');
} else {
# failed because cloned dbh doesn't work
$dbh->do ('drop table if exists temp_test_one, temp_test_two;');
}


короче, если нет возможности использовать что–то другое, то можно, иначе — нужно как можно быстрее избавляться от mysql в пользу postgresql и/или sqlite.

1 comment:

ivan kurmanov said...

> по непонятным для меня причинам, второе
> поле типа timestamp не может принимать
> значение now() при вставке, что делает
> возможным создание поля created только
> с помощью триггера. зато первое поле
> такого типа по умолчанию апдейтится при
> каждом обновлении записи. вот такая
> долбаная магия.

это вполне документировано. http://dev.mysql.com/doc/refman/5.0/en/timestamp.html

можно сделать так:

create table x (
y int,
created timestamp not null default '0000-00-00 00:00:00',
updated timestamp default '0000-00-00 00:00:00' on update CURRENT_TIMESTAMP );

а потом делать:

INSERT INTO x (y,created) VALUES (1,NULL);

Это помогает.