package dinfo; use Carp; use PApp::SQL; =head1 dinfo - THIS IS A PRIVATE MODULE, DON't COPY =cut BEGIN { $VERSION = 0.1; use 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->{dbh}{mysql_auto_reconnect} = 1;#d# $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 => "hausnr"], [ 9 => "plz"], [10 => "ort"], [11 => "branche"], [12 => "typ"], ); 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") { if ($type eq "exact") { $select .= "$column = ?"; push @args, nummer2str $match, 10; } elsif ($type eq "prefix") { $select .= "($column between ? and ?)"; push @args, (nummer2str $match, 0), (nummer2str $match, 10); } 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) { y/0-9//cd; 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; $r{match} = "exact"; while (1 < length $number) { for ($number, "${number}0") { my $result = $self->search (vorwahl => exact => $prefix, nummer => exact => $_); if ($result->rows > 1) { return { %r, %{$result->fetch} }; } elsif ($result->rows == 1) { return { %r, %{$result->fetch} }; } $r{match} = "approx"; } substr $number, -1, 1, ""; } } #$r{ort} = join ", ", # sql_fetchall $self->{dbh}, # "select distinct ort.data # from row # inner join vorwahl on (vorwahl.id = row.vorwahl) # inner join ort on (ort.id = row.ort) # where vorwahl.data = ?", # $r{vorwahl}; \%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; $r{nummer} = str2nummer $row->[0]; \%r; } else { return (); } } 1;