package dinfo; use Carp; use PApp::SQL; =head1 dinfo - THIS IS A PRIVATE MODULE, DON't COPY =cut BEGIN { $VERSION = 0.1; require XSLoader; XSLoader::load __PACKAGE__, $VERSION; } sub new { my ($class, $dsn, $user, $pass) = @_; my $self = bless { dbh => (PApp::SQL::connect_cached "dinfo::", $dsn, $user, $pass), }, $class; $self; } =item $result = $dinfo->search (column => type => value, ...) Initiate a search on the given columns. C can be one of C, C, C, C or C, which specifies the sql-search mode used. For C-columns, only C and C are supported. Returns a C object. my $r = $dinfo->search(name => like => "Marc%"); my $r = $dinfo->search(plz => exact => 76139, branche => match => "psychologe"); Not all types are efficient on all columns.. check your indices! :) =cut my @cols = ( [ 1 => "name"], [ 2 => "vorname"], [ 3 => "zusatz1"], [ 4 => "zusatz2"], [ 5 => "zusatz3"], [ 6 => "vorwahl"], [ 7 => "strasse"], [ 8 => "haus"], [ 9 => "plz"], [10 => "ort"], [11 => "branche"], ); sub search { my ($self, @pred) = @_; my @args; my $select = "select\n nummer, " . (join ", ", map "$_->[1].data", @cols) . "\n" . "from row\n". (join "", map " inner join $_->[1] on (row.$_->[1] = $_->[1].id)\n", @cols) . "where (1=1)\n"; while (@pred) { my ($column, $type, $match) = splice @pred, 0, 3, (); $select .= " and "; if ($column eq "nummer") { $select .= "($column between ? and ?)"; if ($type eq "exact") { push @args, (pack "H*", (substr "${match}000000000000", 0, 12) . sprintf "%x0", 12 - length $match), (pack "H*", (substr "${match}000000000000", 0, 12) . sprintf "%xf", 12 - length $match); } elsif ($type eq "prefix") { push @args, (pack "H*", (substr "${match}00000000000000", 0, 14)), (pack "H*", (substr "${match}a0000000000000", 0, 14)); } else { croak "illegal search type '$type', must be one of exact, prefix"; } } else { push @args, $match; if ($type eq "exact") { $select .= "($column.data = ?)"; } elsif ($type eq "like") { $select .= "($column.data like ?)"; } elsif ($type eq "prefix") { $select .= "($column.data like ?)"; $args[-1] .= "%"; } elsif ($type eq "regexp") { $select .= "($column.data regexp ?)"; } elsif ($type eq "match") { $select .= "(match $column.data against (?)"; } else { croak "illegal search type '$type', must be one of exact, like, regexp or match"; } } } my $st = sql_exec $self->{dbh}, $select, @args or die "sql_exec returned no statement handle"; return bless { dinfo => $self, st => $st, }, dinfo::result; } =item my ($prefix, $local) = $dinfo->split_number($number) split a number into prefix and local part. =cut sub split_number { my ($self, $number) = @_; for ($number) { s/^/0/ unless /^0/; for (3..6) { my $prefix = substr $number, 0, $_; my $isprefix = $cache{$prefix} ||= sql_fetch $self->{dbh}, "select 1 + count(*) from vorwahl where data = ?", $prefix; return ($prefix, substr $number, $_) if $isprefix == 2; } return (); } } =item my $hash = $dinfo->identify_number ($number) Try to find out as much as possible about the given number. =cut sub identify_number { my ($self, $number) = @_; my %r; my ($prefix, $number) = $self->split_number ($number); if ($prefix) { $r{vorwahl} = $prefix; while (1 < length $number) { for ($number, "${number}0") { my $result = $self->search (vorwahl => exact => $prefix, nummer => exact => $_); if ($result->rows > 1) { return $result->fetch; } elsif ($result->rows == 1) { return $result->fetch; } } substr $number, -1, 1, ""; } } #my @orte = sql_fetchall $self->{dbh}, \%r; } =head2 dinfo::result =item $count = $result->rows =cut sub dinfo::result::rows { $_[0]{st}->rows; } =item $hash = $result->fetch Fetch and return the next result row. =cut my %typ; sub dinfo::result::fetch { my ($self) = @_; my $row = $self->{st}->fetchrow_arrayref; if ($row) { my %r; $r{$_->[1]} = $row->[$_->[0]] for @cols; my $nummer = unpack "H*", $row->[0]; my $len = hex substr $nummer, -2, 1; my $typ = hex substr $nummer, -1, 1; $r{nummer} = substr $nummer, 0, 12 - $len; $r{typ} = $typ{$typ} ||= sql_fetch $self->{dinfo}{dbh}, "select data from typ where id = ?", $typ; \%r; } else { return (); } } 1;