#line 1 "DBD/SQLite/VirtualTable.pm"
#======================================================================
package DBD::SQLite::VirtualTable;
#======================================================================
use strict;
use warnings;
use Scalar::Util    qw/weaken/;

our $VERSION = '1.50';
our @ISA;


#----------------------------------------------------------------------
# methods for registering/destroying the module
#----------------------------------------------------------------------

sub CREATE_MODULE  { my ($class, $mod_name) = @_; }
sub DESTROY_MODULE { my ($class, $mod_name) = @_; }

#----------------------------------------------------------------------
# methods for creating/destroying instances
#----------------------------------------------------------------------

sub CREATE         { my $class = shift; return $class->NEW(@_); }
sub CONNECT        { my $class = shift; return $class->NEW(@_); }

sub _PREPARE_SELF {
  my ($class, $dbh_ref, $module_name, $db_name, $vtab_name, @args) = @_;

  my @columns;
  my %options;

  # args containing '=' are options; others are column declarations
  foreach my $arg (@args) {
    if ($arg =~ /^([^=\s]+)\s*=\s*(.*)/) {
      my ($key, $val) = ($1, $2);
      $val =~ s/^"(.*)"$/$1/;
      $options{$key} = $val;
    }
    else {
      push @columns, $arg;
    }
  }

  # build $self
  my $self =  {
    dbh_ref     => $dbh_ref,
    module_name => $module_name,
    db_name     => $db_name,
    vtab_name   => $vtab_name,
    columns     => \@columns,
    options     => \%options,
   };
  weaken $self->{dbh_ref};

  return $self;
}

sub NEW {
  my $class = shift;

  my $self  = $class->_PREPARE_SELF(@_);
  bless $self, $class;
}


sub VTAB_TO_DECLARE {
  my $self = shift;

  local $" = ", ";
  my $sql = "CREATE TABLE $self->{vtab_name}(@{$self->{columns}})";

  return $sql;
}

sub DROP       { my $self = shift; }
sub DISCONNECT { my $self = shift; }


#----------------------------------------------------------------------
# methods for initiating a search
#----------------------------------------------------------------------

sub BEST_INDEX {
  my ($self, $constraints, $order_by) = @_;

  my $ix = 0;
  foreach my $constraint (grep {$_->{usable}} @$constraints) {
    $constraint->{argvIndex} = $ix++;
    $constraint->{omit}      = 0;
  }

  # stupid default values -- subclasses should put real values instead
  my $outputs = {
    idxNum           => 1,
    idxStr           => "",
    orderByConsumed  => 0,
    estimatedCost    => 1.0,
    estimatedRows    => undef,
   };

  return $outputs;
}


sub OPEN {
  my $self  = shift;
  my $class = ref $self;

  my $cursor_class = $class . "::Cursor";
  return $cursor_class->NEW($self, @_);
}


#----------------------------------------------------------------------
# methods for insert/delete/update
#----------------------------------------------------------------------

sub _SQLITE_UPDATE {
  my ($self, $old_rowid, $new_rowid, @values) = @_;

  if (! defined $old_rowid) {
    return $self->INSERT($new_rowid, @values);
  }
  elsif (!@values) {
    return $self->DELETE($old_rowid);
  }
  else {
    return $self->UPDATE($old_rowid, $new_rowid, @values);
  }
}

sub INSERT {
  my ($self, $new_rowid, @values) = @_;

  die "INSERT() should be redefined in subclass";
}

sub DELETE {
  my ($self, $old_rowid) = @_;

  die "DELETE() should be redefined in subclass";
}

sub UPDATE {
  my ($self, $old_rowid, $new_rowid, @values) = @_;

  die "UPDATE() should be redefined in subclass";
}

#----------------------------------------------------------------------
# remaining methods of the sqlite API
#----------------------------------------------------------------------

sub BEGIN_TRANSACTION    {return 0}
sub SYNC_TRANSACTION     {return 0}
sub COMMIT_TRANSACTION   {return 0}
sub ROLLBACK_TRANSACTION {return 0}
sub SAVEPOINT            {return 0}
sub RELEASE              {return 0}
sub ROLLBACK_TO          {return 0}
sub FIND_FUNCTION        {return 0}
sub RENAME               {return 0}


#----------------------------------------------------------------------
# utility methods
#----------------------------------------------------------------------

sub dbh {
  my $self = shift;
  return ${$self->{dbh_ref}};
}


sub sqlite_table_info {
  my $self = shift;

  my $sql = "PRAGMA table_info($self->{vtab_name})";
  return $self->dbh->selectall_arrayref($sql, {Slice => {}});
}

#======================================================================
package DBD::SQLite::VirtualTable::Cursor;
#======================================================================
use strict;
use warnings;

sub NEW {
  my ($class, $vtable, @args) = @_;
  my $self = {vtable => $vtable,
              args   => \@args};
  bless $self, $class;
}


sub FILTER {
  my ($self, $idxNum, $idxStr, @values) = @_;
  die "FILTER() should be redefined in cursor subclass";
}

sub EOF {
  my ($self) = @_;
  die "EOF() should be redefined in cursor subclass";
}

sub NEXT {
  my ($self) = @_;
  die "NEXT() should be redefined in cursor subclass";
}

sub COLUMN {
  my ($self, $idxCol) = @_;
  die "COLUMN() should be redefined in cursor subclass";
}

sub ROWID {
  my ($self) = @_;
  die "ROWID() should be redefined in cursor subclass";
}


1;

__END__

#line 825
