package Tripletail::DB::Backend::SQLite::Dbh;
use strict;
use warnings;
use Hash::Util qw(lock_hash);
use Scalar::Lazy;
use Tripletail;
our @ISA = qw(Tripletail::DB::Dbh);

sub connect {
    my $this = shift;

    my $opts = {
        dbname => $TL->INI->get_reloc($this->{inigroup} => 'dbname'),
    };

    no warnings 'redefine';
    $DBI::installed_drh{SQLite} or DBI->install_driver('SQLite');
    my $orig = \&DBD::SQLite::db::_login;
    local $Tripletail::Error::LAST_DB_ERROR;
    local *DBD::SQLite::db::_login = sub{
        my @ret = wantarray ? &$orig : scalar(&$orig);
        if (!$ret[0]) {
            # $_[0]がdbh.
            # 保持してしまうとその後のエラーメッセージがでなくなり,
            # リファレンスではundefに消されてしまうので
            # ここでエラー情報を作成.
            my $e = $this->_errinfo($_[0]);
            $Tripletail::Error::LAST_DB_ERROR = lazy { $e } 'init';
        }
        return wantarray ? @ret : $ret[0];
    };

    $this->{type} = 'sqlite';
    $this->{dbh } = DBI->connect(
        'dbi:SQLite:' . join(';', map { "$_=$opts->{$_}" } keys %$opts),
        $TL->INI->get($this->{inigroup} => 'user'     => undef),
        $TL->INI->get($this->{inigroup} => 'password' => undef), {
            AutoCommit => 1,
            PrintError => 0,
            RaiseError => 1,
        });

    if (!$this->{dbh}) {
        die __PACKAGE__."#connect: DBI->connect failed. (DBI->connectに失敗しました)\n";
    }

    return $this;
}

sub getLastInsertId {
    my $this = shift;
    my $obj  = shift;

    return $this->{dbh}->func('last_insert_rowid');
}

# エラー情報のDB別固有エラーコードから共通コードへのマッピング(sqlite).
my %ERROR_KEY_OF = (
    # http://www.sqlite.org/c3ref/c_abort.html
    0 => 'NO_ERROR',
    5 => 'DEADLOCK_DETECTED',
    6 => 'DEADLOCK_DETECTED'
   );
lock_hash %ERROR_KEY_OF;

sub _last_error_info {
    my $this = shift;
    my $dbh  = shift || $this->{dbh};

    my $errno  = $dbh->err || 0;
    my $errstr = $dbh->errstr;
    my $errkey = (exists $ERROR_KEY_OF{$errno}
                       ? $ERROR_KEY_OF{$errno}
                       : 'COMMON_ERROR');

    if ($errno == 1) {
        # ちゃんとエラー番号が返ってこない?
        if ($errstr =~ /^no such table:/) {
            $errkey = 'NO_SUCH_OBJECT';
        }
        elsif ($errstr =~ /^unable to open database file/) {
            $errkey = $!{EACCES} ? 'CONNECT_DENIED' : 'CONNECT_NO_SERVER';
        }
        elsif ($errstr =~ /^attempt to write a readonly database/) {
            $errkey = 'ACCESS_DENIED';
        }
    }

    return +{
        errno  => $errno,
        errstr => $errstr,
        errkey => $errkey
       };
}

1;

__END__

=encoding utf-8

=head1 NAME

Tripletail::DB::Backend::SQLite - 内部用

=head1 SEE ALSO

L<Tripletail::DB>

=head1 AUTHOR INFORMATION

=over 4

Copyright 2011 YMIRLINK Inc.

This framework is free software; you can redistribute it and/or modify it under the same terms as Perl itself

このフレームワークはフリーソフトウェアです。あなたは Perl と同じライセンスの 元で再配布及び変更を行うことが出来ます。

Address bug reports and comments to: tl@tripletail.jp

HP : http://tripletail.jp/

=back

=cut
