# Copyright (C) 2008 Wes Hardaker
# License: Same as perl. See the LICENSE file for details.
package Ham::Callsign::DB::US;
use Ham::Callsign::DB;
use Ham::Callsign;
our @ISA = qw(Ham::Callsign::DB);
use strict;
sub init {
my ($self) = @_;
# maybe use dbh to prepare a few things
}
sub do_load_data {
my ($self, $place) = @_;
$self->{'import_place'} = $place;
$self->insert_stuff('HD', 50);
$self->insert_stuff('EN', 27);
$self->insert_stuff('AM', 18);
$self->insert_stuff('VC', 6);
}
sub do_lookup {
my ($self, $callsign) = @_;
if (!$self->{'lookupvc'}) {
$self->{'lookupvc'} = $self->{'dbh'}->prepare("
select vc.callsign_requested as thecallsign, *
from PUBACC_VC as vc
left join PUBACC_HD as hd
on hd.unique_system_identifier = vc.unique_system_identifier
left join PUBACC_EN as en
on en.unique_system_identifier = vc.unique_system_identifier
left join PUBACC_AM as am
on am.unique_system_identifier = vc.unique_system_identifier
where vc.callsign_requested = ?
order by vc.unique_system_identifier desc
limit 1
");
$self->{'lookuphd'} = $self->{'dbh'}->prepare("
select hd.call_sign as thecallsign, *
from PUBACC_HD as hd
left join PUBACC_VC as vc
on vc.unique_system_identifier = hd.unique_system_identifier
left join PUBACC_EN as en
on en.unique_system_identifier = hd.unique_system_identifier
left join PUBACC_AM as am
on am.unique_system_identifier = hd.unique_system_identifier
where hd.call_sign = ?
order by hd.unique_system_identifier desc
limit 1
");
}
$self->{'lookupvc'}->execute($callsign);
my $row1 = $self->{'lookupvc'}->fetchrow_hashref;
$self->{'lookupvc'}->finish;
$self->{'lookuphd'}->execute($callsign);
my $row2 = $self->{'lookuphd'}->fetchrow_hashref;
$self->{'lookuphd'}->finish;
my @results;
if ($row1 && $row2 && !$self->{'USmultiple'}) {
# take the most recent ULS file number
if ($row1->{'uls_file_number'} > $row2->{'uls_file_number'}) {
$row2 = undef;
} else {
$row1 = undef;
}
}
if ($row1) {
$row1->{'qth'} = "$row1->{city}, $row1->{state}, USA";
push @results,new Ham::Callsign(%$row1)
}
if ($row2) {
$row2->{'qth'} = "$row2->{city}, $row2->{state}, USA";
push @results,new Ham::Callsign(%$row2) if ($row2);
}
map { $_->{'FromDB'} = 'US' } @results;
return \@results;
}
# from fcc docs:
# EN: Names and Addresses
# HD: Main form 605 that carries over to license
# AM: Amature data
# VC: Vanity Callsign
#
# data can be joined "whenever the column name is the same in both tables"
# - primary column for joining is the call sign
# - joining for application data is the ULS file number (we don't load apps)
# - Each application and license has been assigned a unique 9-digit system id
# This is useful in cases where a call sign has been reassigned.
sub do_create_tables {
my ($self) = @_;
my $dbh = $self->{'dbh'};
# These SQL statements were pulled from the FCC documentation at
# http://wireless.fcc.gov/uls/index.htm?job=transaction&page=weekly
# the FCC updates their schema on a regular basis and this module
# will need to track those changes.
$dbh->do("drop table PUBACC_EN");
$dbh->do("create table PUBACC_EN
(
record_type char(2) not null,
unique_system_identifier numeric(9,0) not null,
uls_file_number char(14) null,
ebf_number varchar(30) null,
call_sign char(10) null,
entity_type char(2) null,
licensee_id char(9) null,
entity_name varchar(200) null,
first_name varchar(20) null,
mi char(1) null,
last_name varchar(20) null,
suffix char(3) null,
phone char(10) null,
fax char(10) null,
email varchar(50) null,
street_address varchar(60) null,
city varchar(20) null,
state char(2) null,
zip_code char(9) null,
po_box varchar(20) null,
attention_line varchar(35) null,
sgin char(3) null,
frn char(10) null,
applicant_type_code char(1) null,
applicant_type_other char(40) null,
status_code char(1) null,
status_date datetime null
)");
$dbh->do("CREATE index callsign_index_en_id on PUBACC_EN(unique_system_identifier)");
$dbh->do("drop table PUBACC_AM");
$dbh->do("create table PUBACC_AM
(
record_type char(2) not null,
unique_system_identifier numeric(9,0) not null,
uls_file_num char(14) null,
ebf_number varchar(30) null,
callsign char(10) null,
operator_class char(1) null,
group_code char(1) null,
region_code tinyint null,
trustee_callsign char(10) null,
trustee_indicator char(1) null,
physician_certification char(1) null,
ve_signature char(1) null,
systematic_callsign_change char(1) null,
vanity_callsign_change char(1) null,
vanity_relationship char(12) null,
previous_callsign char(10) null,
previous_operator_class char(1) null,
trustee_name varchar(50) null
)
");
$dbh->do("CREATE index callsign_index_am_id on PUBACC_AM(unique_system_identifier)");
$dbh->do("drop table PUBACC_HD");
$dbh->do("create table PUBACC_HD
(
record_type char(2) not null,
unique_system_identifier numeric(9,0) not null,
uls_file_number char(14) null,
ebf_number varchar(30) null,
call_sign char(10) null,
license_status char(1) null,
radio_service_code char(2) null,
grant_date char(10) null,
expired_date char(10) null,
cancellation_date char(10) null,
eligibility_rule_num char(10) null,
applicant_type_code_reserved char(1) null,
alien char(1) null,
alien_government char(1) null,
alien_corporation char(1) null,
alien_officer char(1) null,
alien_control char(1) null,
revoked char(1) null,
convicted char(1) null,
adjudged char(1) null,
involved_reserved char(1) null,
common_carrier char(1) null,
non_common_carrier char(1) null,
private_comm char(1) null,
fixed char(1) null,
mobile char(1) null,
radiolocation char(1) null,
satellite char(1) null,
developmental_or_sta char(1) null,
interconnected_service char(1) null,
certifier_first_name varchar(20) null,
certifier_mi char(1) null,
certifier_last_name varchar(20) null,
certifier_suffix char(3) null,
certifier_title char(40) null,
gender char(1) null,
african_american char(1) null,
native_american char(1) null,
hawaiian char(1) null,
asian char(1) null,
white char(1) null,
ethnicity char(1) null,
effective_date char(10) null,
last_action_date char(10) null,
auction_id int null,
reg_stat_broad_serv char(1) null,
band_manager char(1) null,
type_serv_broad_serv char(1) null,
alien_ruling char(1) null,
licensee_name_change char(1) null
)");
$dbh->do("CREATE index callsign_index_hd_id on PUBACC_HD(unique_system_identifier)");
$dbh->do("CREATE index callsign_index_HD_SIGN on PUBACC_HD(call_sign)");
$dbh->do("drop table PUBACC_VC");
$dbh->do("create table PUBACC_VC
(
record_type char(2) null,
unique_system_identifier numeric(9,0) not null,
uls_file_number char(14) null,
ebf_number varchar(30) null,
request_sequence int null,
callsign_requested char(10) null
)
");
$dbh->do("CREATE index callsign_index_VC_SIGN on PUBACC_VC(callsign_requested)");
$dbh->do("CREATE index callsign_index_vc_id on PUBACC_VC(unique_system_identifier)");
}
########################################
# DB insertion code
#
# split doesn't always return the right number of entries... it
# chomps the end for some reason sometimes. This array fills in the blanks.
#
# XXX: this is likely a problem for some other reason and this is a
# possibly broken hack.
my @fill;
for (my $i = 1; $i <= 100; $i++) {
for (my $j = 0; $j < $i; $j++) {
push @{$fill[$i]}, '';
}
}
# a generic function that inserts $num rows into a table
sub insert_stuff {
my ($self, $suffix, $num) = @_;
my $count = 0;
my @parts;
my $dbh = $self->{'dbh'};
my $sth = $dbh->prepare("insert into PUBACC_$suffix values(" .
("?, " x ($num-1)). " ?)");
$| = 1;
print "starting $suffix\n";
open(I,"<$self->{'import_place'}/$suffix.dat");
$dbh->begin_work();
while (<I>) {
chomp;
s/\r//;
@parts = split(/\|/);
# print "parts: $_\n " . join(",",@parts). "\n" if ($count == 0);
my $diff = $num - $#parts - 1;
$sth->execute(@parts, @{$fill[$diff]});
# $sth->execute(@parts);
$count++;
if ($count % 10000 == 0) {
print ".";
$dbh->commit();
$dbh->begin_work();
}
}
$dbh->commit();
print "inserted: $count rows into $suffix\n";
}
1;
=pod
=head1 NAME
=cut