SQLite::VirtualTable::Pivot # Proof-of-concept implementation. # Table with columns named "entity", "attribute", "value". package Test::Pivot; use DBI; use DBIx::Simple; use Data::Dumper; use base 'SQLite::VirtualTable'; use strict; { my ($sth, @row, @last_row, %queued, $first, $last, $done, $db ); sub CREATE { # Create a new table. my ( $class, $module, $caller, $table, $base_table, @opts ) = @_; $db ||= DBIx::Simple->connect( "dbi:SQLite:dbname=dbfile.db", "", "" ) or die DBIx::Simple->error; my @columns = ("entity", $db->query("select distinct(attribute) from $base_table;")->flat); return bless { table => $table, base_table => $base_table, columns => \@columns }, $class; } sub DECLARE_SQL { # Declare the columns. my $self = shift; return sprintf "CREATE TABLE %s (%s)", $self->{table}, (join ',', @{ $self->{columns} } ); } sub OPEN { # Open a cursor my $self = shift; $sth = $db->dbh->prepare( "select entity,attribute,value from $self->{base_table} order by entity") or die $DBI::errstr; $sth->execute or die $DBI::errstr; $last = !( @row = $sth->fetchrow_array ); ($done,$first) = (0,1); $self->NEXT(); return 1; } sub NEXT { # Advance the cursor one row. return if $done; $done = $last; while ($first || $row[0]==$last_row[0]) { $first = 0; $queued{ $row[1] } = $row[2]; $queued{entity} = $row[0]; @last_row = @row; $last = !( @row = $sth->fetchrow_array ); last if $last; } @last_row = @row; } sub COLUMN { # Retrieve the value in a column. my ($self, $cur, $n) = @_; return delete $queued{$self->{columns}[$n]}; } sub EOF { # Is the cursor done? $done; } sub ROWID { } sub CLOSE { } sub DISCONNECT { } sub BEST_INDEX { (0, "", undef, 0) } sub FILTER { } sub DROP { } *DESTROY = \&DISCONNECT; *CONNECT = \&CREATE; } 1;