306 lines
6.8 KiB
Perl
306 lines
6.8 KiB
Perl
#! /usr/bin/perl
|
|
# $OpenBSD: Inserter.pm,v 1.42 2023/06/16 04:54:20 espie Exp $
|
|
#
|
|
# Copyright (c) 2006-2010 Marc Espie <espie@openbsd.org>
|
|
#
|
|
# Permission to use, copy, modify, and distribute this software for any
|
|
# purpose with or without fee is hereby granted, provided that the above
|
|
# copyright notice and this permission notice appear in all copies.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
use v5.36;
|
|
use Sql;
|
|
|
|
package Inserter;
|
|
# this is the object to use to put stuff into the db...
|
|
sub new($class, $db, $i, $verbose, $create)
|
|
{
|
|
$db->do("PRAGMA foreign_keys=ON");
|
|
bless {
|
|
db => $db,
|
|
transaction => 0,
|
|
threshold => $i,
|
|
vars => {},
|
|
created => {},
|
|
create => $create,
|
|
errors => [],
|
|
done => {},
|
|
todo => {},
|
|
verbose => $verbose,
|
|
}, $class;
|
|
}
|
|
|
|
# $self->add_error($msg)
|
|
sub add_error($, $)
|
|
{
|
|
}
|
|
|
|
sub current_path($self)
|
|
{
|
|
return $self->{current_path};
|
|
}
|
|
|
|
sub create_tables($self, $vars)
|
|
{
|
|
my $t = $self->{ports_table} = Sql::Create::Table->new("_Ports");
|
|
my $v = $self->{ports_view} = Sql::Create::View->new("Ports",
|
|
origin => '_Ports');
|
|
$self->create_path_table;
|
|
# XXX sort it
|
|
for my $i (sort keys %$vars) {
|
|
$vars->{$i}->prepare_tables($self, $i);
|
|
}
|
|
|
|
$t->sort;
|
|
$self->{varlist} = [$t->column_names];
|
|
$t->prepend(AnyVar->fullpkgpath);
|
|
|
|
$v->sort;
|
|
$v->prepend(AnyVar->pathref);
|
|
$self->create_meta;
|
|
$self->create_schema;
|
|
print '-'x50, "\n" if $self->{verbose};
|
|
}
|
|
|
|
sub add_to_ports_table($self, @column)
|
|
{
|
|
$self->{ports_table}->add(@column);
|
|
}
|
|
|
|
sub add_to_ports_view($self, @o)
|
|
{
|
|
$self->{ports_view}->add(@o);
|
|
}
|
|
|
|
sub make_ordered_view($self, $class)
|
|
{
|
|
my $view = $self->view_name($class->table."_ordered");
|
|
my @subselect = $class->subselect;
|
|
my @select = (Sql::Column::View->new('FullPkgPath')->group_by,
|
|
Sql::Column::View::Concat->new("Value"), $class->select);
|
|
Sql::Create::View->new($view, origin => 'o')->add(
|
|
Sql::With->new('o', origin => $self->table_name($class->table))
|
|
->add(@subselect),
|
|
@select);
|
|
}
|
|
|
|
sub set($self, $ref)
|
|
{
|
|
$self->{ref} = $ref;
|
|
}
|
|
|
|
sub db($self)
|
|
{
|
|
return $self->{db};
|
|
}
|
|
|
|
sub last_id($self)
|
|
{
|
|
return $self->db->func('last_insert_rowid');
|
|
}
|
|
|
|
sub insert_done($self)
|
|
{
|
|
$self->{transaction}++;
|
|
}
|
|
|
|
sub new_sql($self, $sql)
|
|
{
|
|
my $n = $sql->name;
|
|
return if defined $self->{created}{$n};
|
|
$self->{created}{$n} = 1;
|
|
my $drop = $sql->drop;
|
|
# print "$drop\n" if $self->{verbose};
|
|
$self->db->do($drop);
|
|
my $request = $sql->stringize;
|
|
print "$request\n" if $self->{verbose};
|
|
$self->db->do($request);
|
|
}
|
|
|
|
sub create_schema($self)
|
|
{
|
|
if ($self->{create}) {
|
|
for my $t (Sql::Create->all_tables) {
|
|
$self->new_sql($t);
|
|
}
|
|
for my $t (Sql::Create->all_tables) {
|
|
my $i = $t->inserter;
|
|
print $i, "\n";
|
|
$self->{insert}{$t->name} = $self->prepare($i);
|
|
}
|
|
for my $i (Sql::Create->all_indices) {
|
|
$self->new_sql($i);
|
|
}
|
|
}
|
|
for my $v (Sql::Create->all_views) {
|
|
$self->new_sql($v);
|
|
}
|
|
$self->commit_to_db;
|
|
}
|
|
|
|
sub prepare($self, $s)
|
|
{
|
|
return $self->db->prepare($s);
|
|
}
|
|
|
|
sub finish_port($self)
|
|
{
|
|
my @values = ($self->ref);
|
|
for my $i (@{$self->{varlist}}) {
|
|
push(@values, $self->{vars}{$i});
|
|
}
|
|
$self->insert('_Ports', @values);
|
|
$self->{vars} = {};
|
|
if ($self->{transaction} >= $self->{threshold}) {
|
|
$self->commit_to_db;
|
|
$self->{transaction} = 0;
|
|
}
|
|
}
|
|
|
|
sub add_to_port($self, $var, $value)
|
|
{
|
|
$self->{vars}{$var} = $value;
|
|
}
|
|
|
|
sub ref($self)
|
|
{
|
|
return $self->{ref};
|
|
}
|
|
|
|
sub insert($self, $table, @p)
|
|
{
|
|
$self->{insert}{$table}->execute(@p);
|
|
$self->insert_done;
|
|
}
|
|
|
|
sub add_var($self, $v)
|
|
{
|
|
$v->add($self);
|
|
}
|
|
|
|
sub create_canonical_depends($self, $class)
|
|
{
|
|
my $t = $self->table_name($class->table);
|
|
my $p = $self->table_name("Paths");
|
|
Sql::Create::View->new("_canonical_depends", origin=>$t)->add(
|
|
Sql::Column::View->new("FullPkgPath", origin=>"Id")
|
|
->join(Sql::Join->new($p)
|
|
->add(Sql::Equal->new("Canonical", "FullPkgPath"))),
|
|
Sql::Column::View->new("DependsPath", origin=>"Canonical")
|
|
->join(Sql::Join->new($p)
|
|
->add(Sql::Equal->new("Id", "DependsPath"))),
|
|
Sql::Column::View->new("Type"));
|
|
|
|
Sql::Create::View->new("canonical_depends", origin=>$t)->add(
|
|
Sql::Column::View->new("FullPkgPath")
|
|
->join(Sql::Join->new($p)
|
|
->add(Sql::Equal->new("Canonical", "FullPkgPath"))),
|
|
Sql::Column::View->new("DependsPath", origin=>"FullPkgPath")
|
|
->join(Sql::Join->new($p)
|
|
->add(Sql::Equal->new("Id", "DependsPath")),
|
|
Sql::Join->new($p)
|
|
->add(Sql::Equal->new("Id", "canonical"))),
|
|
Sql::Column::View->new("Type"));
|
|
}
|
|
|
|
sub commit_to_db($self)
|
|
{
|
|
$self->db->commit;
|
|
}
|
|
|
|
sub table_name($class, $name)
|
|
{
|
|
return "_$name";
|
|
}
|
|
|
|
sub view_name($class, $name)
|
|
{
|
|
return $name;
|
|
}
|
|
|
|
sub adjust($self)
|
|
{
|
|
return $self->{adjust} //= $self->prepare("UPDATE _Paths set Canonical=? where Id=?");
|
|
}
|
|
|
|
sub create_meta($)
|
|
{
|
|
Sql::Create::Table->new("Meta")->add(
|
|
Sql::Column::Text->new("SchemaVersion"),
|
|
Sql::Column::Text->new("Hash"),
|
|
Sql::Column::CurrentDate->new("CreationDate"));
|
|
}
|
|
|
|
sub create_path_table($)
|
|
{
|
|
my $t = "_Paths";
|
|
my $v = "Paths";
|
|
Sql::Create::Table->new($t)->add(
|
|
Sql::Column::Key->new("Id")->noautoincrement,
|
|
Sql::Column::Text->new("FullPkgPath")->notnull->unique,
|
|
Sql::Column::Integer->new("PkgPath")->references($t),
|
|
Sql::Column::Integer->new("Canonical")->references($t)->indexed);
|
|
|
|
Sql::Create::View->new($v, origin => $t)->add(
|
|
Sql::Column::View->new("PathId", origin => "Id"),
|
|
Sql::Column::View->new("FullPkgPath"),
|
|
Sql::Column::View->new("PkgPath", origin => "FullPkgPath")
|
|
->join(Sql::Join->new($t)->add(
|
|
Sql::Equal->new("Id", "PkgPath"))),
|
|
Sql::Column::View->new("Canonical", origin => "FullPkgPath")
|
|
->join(Sql::Join->new($t)->add(
|
|
Sql::Equal->new("Id", "Canonical")))
|
|
);
|
|
}
|
|
|
|
my $path_cache = {};
|
|
my $newid = 1;
|
|
sub find_pathkey($self, $key)
|
|
{
|
|
if (!defined $key or $key eq '') {
|
|
say STDERR "Empty pathkey";
|
|
return 0;
|
|
}
|
|
if (defined $path_cache->{$key}) {
|
|
return $path_cache->{$key};
|
|
}
|
|
|
|
# if none, we create one
|
|
my $path = $key;
|
|
$path =~ s/\,.*//;
|
|
if ($path ne $key) {
|
|
$path = $self->find_pathkey($path);
|
|
} else {
|
|
$path = $newid;
|
|
}
|
|
$self->insert('_Paths', $newid, $key, $path, $newid);
|
|
my $r = $self->last_id;
|
|
$path_cache->{$key} = $r;
|
|
$newid++;
|
|
return $r;
|
|
}
|
|
|
|
sub add_path($self, $key, $alias)
|
|
{
|
|
$self->adjust->execute($path_cache->{$alias}, $path_cache->{$key});
|
|
}
|
|
|
|
sub set_newkey($self, $key)
|
|
{
|
|
$self->set($self->find_pathkey($key));
|
|
$self->{current_path} = $key;
|
|
}
|
|
|
|
# $self->write_log($fh)
|
|
sub write_log($, $)
|
|
{
|
|
}
|
|
|
|
1;
|