📄 dbm.pm
字号:
if ($terms) { unless ($args->{'sort'}) { my $rec = ${ $driver->{serializer}->unserialize($val) }; my $matched = 1; for my $col (keys %$terms) { $matched = 0, last unless defined($rec->{$col}) && $terms->{$col} eq $rec->{$col}; } push(@matched_ids, $join_col ? $rec->{$join_col} : $key) if $matched; } else { for my $id (@these_ids) { my $rec = $db->{$id} or next; $rec = ${ $driver->{serializer}->unserialize($rec) }; my $matched = 1; for my $col (keys %$terms) { $matched = 0, last unless defined($rec->{$col}) && $terms->{$col} eq $rec->{$col}; } push(@matched_ids, $join_col ? $rec->{$join_col} : $id) if $matched; } } } ## Otherwise we can just add these records to the list of ## matches. else { for my $id (@these_ids) { ## We could let the conditional below handle this, but ## it is faster if we handle it here: this way, if we ## are using $join_col, we don't have to pull out the ## record and unserialize it. if ($offset && $j < $offset) { $j++; next; } if ($join_col) { my $rec = $db->{$id} or next; $rec = ${ $driver->{serializer}->unserialize($rec) }; push @matched_ids, $rec->{$join_col}; } else { push @matched_ids, $id; } } } ## Now, loop over all of the matching IDs. If an offset is specified, ## and we have not yet reached that offset, we skip the ID; otherwise ## we add the ID to the final list. for my $id (@matched_ids) { if ($offset && $j < $offset) { $j++; } else { if (!$uniq || !exists $ids{$id}) { push @ids, $id; $ids{$id}++; $i++; } } } } if ($args->{'sort'}) { undef $this_db; untie %$idx; $unlock->(); } @ids;}sub load_iter { my $driver = shift; $driver->run_callbacks($_[0] . '::pre_load', \@_); my($class, $terms, $args) = @_; my $db_file = _db_data($driver, $class); my($DB, $db, $unlock) = $driver->_tie_db_file($db_file, $DB_BTREE, 'r') or return sub { }; my @ids = $driver->_get_ids($DB, $db, $class, $terms, $args); return $driver->error($driver->errstr()) if (!defined($ids[0])) && ($#ids == 0); my $idx = 0; sub { if ($idx > $#ids) { undef $DB; untie %$db; $unlock->(); return; } my $rec = $db->{ $ids[$idx++] } or return; $rec = $driver->{serializer}->unserialize($rec); my $obj = $class->new; $obj->set_values($$rec); $driver->run_callbacks($class . '::post_load', \@_, $obj); $obj; };}sub load { my $driver = shift; $driver->run_callbacks($_[0] . '::pre_load', \@_); my($class, $terms, $args) = @_; my $_terms; if (ref $terms && $terms->{id}) { $_terms = $terms; $terms = $terms->{id}; } my $db_file = _db_data($driver, $class); my($DB, $db, $unlock) = $driver->_tie_db_file($db_file, $DB_BTREE, 'r') or return; my @ids = $driver->_get_ids($DB, $db, $class, $terms, $args); my @objs; OBJECT: for my $id (@ids) { my $rec = $db->{$id} or return; $rec = $driver->{serializer}->unserialize($rec); my $obj = $class->new; $obj->set_values($$rec); foreach (keys %$_terms) { next OBJECT if ($_terms->{$_} ne $obj->column($_)); } $driver->run_callbacks($class . '::post_load', \@_, $obj); $unlock->(), return($obj) unless wantarray; push @objs, $obj; } undef $DB; untie %$db; $unlock->(); @objs;}sub count { my $driver = shift; my($class, $terms, $args) = @_; my $db_file = _db_data($driver, $class); my($DB, $db, $unlock) = $driver->_tie_db_file($db_file, $DB_BTREE, 'r') or return 0; my @ids = $driver->_get_ids($DB, $db, $class, $terms, $args); undef $DB; untie %$db; $unlock->(); scalar @ids;}sub count_group_by { my $driver = shift; my($class, $terms, $args) = @_; my $db_file = _db_data($driver, $class); my($DB, $db, $unlock) = $driver->_tie_db_file($db_file, $DB_BTREE, 'r') or return 0; die "count_group_by is unimplemented in DBM"; my @ids = (); undef $DB; untie %$db; $unlock->();}sub exists { my $driver = shift; my($obj) = @_; return unless $obj->id; my $db_file = _db_data($driver, $obj); my($DB, $db, $unlock) = $driver->_tie_db_file($db_file, $DB_BTREE, 'r') or return 0; my $exists = exists $db->{$obj->id}; undef $DB; untie %$db; $unlock->(); $exists;}sub save { my $driver = shift; my($obj) = @_; my $original; ($original, $obj) = ($obj, $obj->clone()); $driver->run_callbacks((ref$obj) . "::pre_save", $obj, $original); my $db_file = _db_data($driver, $obj); my($DB, $db, $unlock) = $driver->_tie_db_file($db_file, $DB_BTREE, 'rw') or return $driver->error(MT->translate( "Tie '[_1]' failed: [_2]", $db_file, "$!" )); unless ($obj->id || ($obj->id($driver->generate_id($obj)))) { return $driver->error(MT->translate( "Failed to generate unique ID: [_1]", $driver->errstr )); } my $id = $obj->id; $original->id($id); if ($obj->properties->{audit}) { my $blog_id = $obj->blog_id; my @ts = offset_time_list(time, $blog_id); my $ts = sprintf "%04d%02d%02d%02d%02d%02d", $ts[5]+1900, $ts[4]+1, @ts[3,2,1,0]; $obj->created_on($ts) unless CORE::exists($db->{$id}) || $obj->created_on; $obj->modified_on($ts); $original->created_on($obj->created_on); $original->modified_on($obj->modified_on); } ## Grab old values so that we can update indexes on changed columns my $old = $db->{$id}; $old = ${ $driver->{serializer}->unserialize($old) } if $old; $db->{$id} = $driver->{serializer}->serialize(\$obj->column_values); undef $DB; untie %$db; $unlock->(); if (!$no_build_indexes) { $driver->rebuild_index_for_item($obj, $old); } $driver->run_callbacks((ref $obj) . "::post_save", $obj, $original); 1;}sub no_build_indexes { my $class = shift; if (@_) { $no_build_indexes = $_[0]; } $no_build_indexes;}sub rebuild_indexes { my $driver = shift; my $class = shift; my $props = $class->properties; my $indexes = $props->{indexes}; return unless ($indexes && keys %$indexes); my %idx; for my $idx_col (keys %$indexes) { my $idx_file = File::Spec->catfile($driver->cfg->DataSource, $class->datasource . '.' . $idx_col . '.idx'); tie %{ $idx{$idx_col} }, 'DB_File', $idx_file, O_RDWR|O_CREAT, 0666, $DB_BTREE or die "Tie to '$idx_file' failed: $!"; %{ $idx{$idx_col} } = (); } my $iter = $class->load_iter; while (my $obj = $iter->()) { my $id = $obj->id; for my $idx_col (keys %$indexes) { my $idx = $idx{$idx_col}; my $col_value = $obj->$idx_col() || ''; my @cur = split /$;/, $idx->{$col_value} || ''; my %ids = map { $_ => 1 } @cur; next if exists $ids{$id}; $idx->{$col_value} = join $;, keys %ids, $id; } } for my $idx_col (keys %$indexes) { untie %{ $idx{$idx_col} }; }}sub rebuild_index_for_item { my $driver = shift; my ($obj, $old) = @_; my $id = $obj->id; my $indexes = $obj->properties->{indexes}; for my $col (keys %$indexes) { my $idx_file = _db_index($driver, $obj, $col); my($DB, $idx, $unlock) = $driver->_tie_db_file($idx_file, $DB_BTREE, 'rw') or return $driver->error(MT->translate( "Tie '[_1]' failed: [_2]", $idx_file, "$!" )); my $col_value = $obj->$col(); $col_value = '' unless defined $col_value; my %ids = map { $_ => 1 } split /$;/, $idx->{$col_value} || ''; $unlock->(), next if exists $ids{$id}; $idx->{$col_value} = join $;, keys %ids, $id; $old->{$col} = '' unless !$old || defined $old->{$col}; if ($old && $old->{$col} ne $col_value) { _drop_from_index($idx, $id, $old->{$col}); } undef $DB; untie %$idx; $unlock->(); }}sub remove { my $driver = shift; my($obj) = @_; $driver->run_callbacks((ref $obj) . "::pre_remove", @_); my $id = $obj->id; return unless $id; my $indexes = $obj->properties->{indexes}; for my $col (keys %$indexes) { my $idx_file = _db_index($driver, $obj, $col); my($DB, $idx, $unlock) = $driver->_tie_db_file($idx_file, $DB_BTREE, 'rw') or return $driver->error(MT->translate( "Tie '[_1]' failed: [_2]", $idx_file, "$!" )); my $col_value = $obj->$col(); _drop_from_index($idx, $id, $col_value); undef $DB; untie %$idx; $unlock->(); } my $db_file = _db_data($driver, $obj); my($DB, $db, $unlock) = $driver->_tie_db_file($db_file, $DB_BTREE, 'rw') or return $driver->error(MT->translate( "Tie '[_1]' failed: [_2]", $db_file, "$!" )); delete $db->{$obj->id}; undef $DB; untie %$db; $unlock->(); $driver->run_callbacks((ref $obj) . "::post_remove", @_); 1;}sub remove_all { my $driver = shift; my($class) = @_; $driver->run_callbacks($class . "::pre_remove_all", @_); my $indexes = $class->properties->{indexes}; for my $col (keys %$indexes) { my $idx_file = _db_index($driver, $class, $col); next unless -e $idx_file; unlink $idx_file or return $driver->error(MT->translate( "Unlink of '[_1]' failed: [_2]", $idx_file, "$!" )); } my $db_file = _db_data($driver, $class); if (-e $db_file) { unlink $db_file or return $driver->error(MT->translate( "Unlink of '[_1]' failed: [_2]", $db_file, "$!" )); } $driver->run_callbacks($class . "::post_remove_all", @_); 1;}sub _drop_from_index { my($idx, $obj_id, $col_val) = @_; $col_val = '' unless defined $col_val; return unless exists $idx->{$col_val}; my $idx_val = $idx->{$col_val}; $idx_val = '' unless defined $idx_val; my %ids = map { $_ => 1 } split /$;/, $idx_val; delete $ids{$obj_id}; if (%ids) { $idx->{$col_val} = join $;, keys %ids; } else { delete $idx->{$col_val}; }}sub generate_id { my $driver = shift; my($this) = @_; my $class = ref($this) || $this; my $id_file = File::Spec->catfile( $driver->cfg->DataSource, "ids.db"); my($DB, $db, $unlock) = $driver->_tie_db_file($id_file, $DB_HASH, 'rw') or return $driver->error(MT->translate( "Tie '[_1]' failed: [_2]", $id_file, "$!" )); $db->{$class} = 0 unless exists $db->{$class}; my $id = ++$db->{$class}; undef $DB; untie %$db; $unlock->(); $id;}1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -