
interchange-cvs at icdevgroup
May 5, 2008, 8:14 AM
Post #1 of 1
(28 views)
Permalink
|
|
interchange - markj modified 5 files
|
|
User: markj Date: 2008-05-05 15:14:00 GMT Modified: lib/Vend Data.pm Modified: lib/Vend/Table Common.pm DBI.pm DBI_CompositeKey.pm LDAP.pm Log: Extend set_slice() to allow control of upsert behavior. Calls to set_slice() are forced to use the upsert model of data manipulation. This can be a highly desirable editing model, but it also has disadvantages, particularly in the context of the 'set' and 'autoset' form actions, which imply--but don't enforce--a distinction between insert and update at the data-storage level. The effects on insert can be particularly insidious, where one faces having the assumed behavior on duplicate primary keys thwarted by a surreptitious conversion to a SQL update. In such an instance, instead of existing data being protected by a duplicate PK error, the extant record is replaced by the data from the insert. Detecting this condition, particularly on a large table, is virtually impossible. While the results of an update-to-insert adjustment are more benign, it still presents a nuisance if a strict update is intended. To correct it, one merely needs to delete the newly created, unanticipated row, and such behavior does not destroy existing data. To enforce update or insert, set_slice()'s $key arg can be optionally passed as an array ref, essentially replacing the existing call: set_slice($key,$fary,$vary) with set_slice([$opt, $key],$fary,$vary) where $opt->{dml} is set to the desired value. $opt as a hash ref is used so that any possible future opt-style params can simply be loaded into the existing calling structure. Change details: * Default behavior for set_slice() is 'upsert'. If you do nothing to your code or catalog, the behavior remains unchanged. * $opt->{dml} can be 'insert', 'update', or anything else. If it's anything else, it has no specific behavior currently. It defaults the value 'upsert' just to be somewhat self-documenting and open up the possibility of behaviors based on that value in the future. * Despite the decision to key it off of 'dml', this has no effect on deletes. Deletes have no ambiguous behavior, reflected in the fact that deletes have their own dedicated method. * Change only has core impact when processing requests through Vend::Data::update_data(). However, any direct calls to set_slice() may avail themselves of the new feature simply by overloading the $key arg in the same fashion. * Behavior of Vend::Data::update_data() can be in three modes, controllable by the new 'dml' pragma. + No pragma setting works in current mode, with upsert behavior. + Pragma 'dml=preserve' restricts inserts to insert-only, but allows the fall-through behavior from update to insert. As the name preserve implies, it means no existing data can be clobbered. The advantage to preserve is the easy use of set_slice() as a record-cloning operation. In the table editor, one can clone a record by simply changing the PK. Without this behavior, one must completely re-enter existing data to the new key's name to clone. + Pragma 'dml=strict' forces update or insert to only perform the requested action. Revision Changes Path 2.67 interchange/lib/Vend/Data.pm rev 2.67, prev_rev 2.66 Index: Data.pm =================================================================== RCS file: /var/cvs/interchange/lib/Vend/Data.pm,v retrieving revision 2.66 retrieving revision 2.67 diff -u -r2.66 -r2.67 --- Data.pm 25 Mar 2008 17:13:21 -0000 2.66 +++ Data.pm 5 May 2008 15:14:00 -0000 2.67 @@ -1,6 +1,6 @@ # Vend::Data - Interchange databases # -# $Id: Data.pm,v 2.66 2008-03-25 17:13:21 jon Exp $ +# $Id: Data.pm,v 2.67 2008-05-05 15:14:00 markj Exp $ # # Copyright (C) 2002-2008 Interchange Development Group # Copyright (C) 1996-2002 Red Hat, Inc. @@ -2274,13 +2274,18 @@ $brec->{$f} = $value if $brec; } + my $dml = { dml => 'upsert' }; + $dml->{dml} = $function + if $::Pragma->{dml} eq 'strict' + || $function eq 'insert' && $::Pragma->{dml} eq 'preserve'; + for(keys %$qd) { #::logDebug("update_data: Getting ready to set_slice"); my $k = $multikey ? undef : $key; - $qret = $qd->{$_}->set_slice($k, $qf->{$_}, $qv->{$_}); + $qret = $qd->{$_}->set_slice([$dml, $k], $qf->{$_}, $qv->{$_}); $rows_set[$i] = $qret unless $rows_set[$i]; } - if($blob) { + if($blob && $rows_set[$i]) { $brec->{mv_data_fields} = join " ", @fields; my $string = uneval_it($blob); #::logDebug("update_data: blob saving string=$string"); 2.49 interchange/lib/Vend/Table/Common.pm rev 2.49, prev_rev 2.48 Index: Common.pm =================================================================== RCS file: /var/cvs/interchange/lib/Vend/Table/Common.pm,v retrieving revision 2.48 retrieving revision 2.49 diff -u -r2.48 -r2.49 --- Common.pm 25 Mar 2008 17:13:21 -0000 2.48 +++ Common.pm 5 May 2008 15:14:00 -0000 2.49 @@ -1,6 +1,6 @@ # Vend::Table::Common - Common access methods for Interchange databases # -# $Id: Common.pm,v 2.48 2008-03-25 17:13:21 jon Exp $ +# $Id: Common.pm,v 2.49 2008-05-05 15:14:00 markj Exp $ # # Copyright (C) 2002-2008 Interchange Development Group # Copyright (C) 1996-2002 Red Hat, Inc. @@ -23,7 +23,7 @@ # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, # MA 02110-1301 USA. -$VERSION = substr(q$Revision: 2.48 $, 10); +$VERSION = substr(q$Revision: 2.49 $, 10); use strict; package Vend::Table::Common; @@ -391,7 +391,7 @@ } sub set_slice { - my ($s, $key, $fary, $vary) = @_; + my ($s, $key, $fary, $vary) = @_; $s = $s->import_db() if ! defined $s->[$TIE_HASH]; if($s->[$CONFIG]{Read_only}) { @@ -403,6 +403,17 @@ return undef; } + my $opt; + if (ref ($key) eq 'ARRAY') { + $opt = shift @$key; + $key = shift @$key; + } + $opt = {} + unless ref ($opt) eq 'HASH'; + + $opt->{dml} = 'upsert' + unless defined $opt->{dml}; + if(ref $fary ne 'ARRAY') { my $href = $fary; if(ref $href ne 'HASH') { @@ -423,8 +434,23 @@ my @current; - @current = $s->row($key) - if $s->record_exists($key); + if ($s->record_exists($key)) { + if ($opt->{dml} eq 'insert') { + $s->log_error( + "Duplicate key on set_slice insert for key '$key' on table %s", + $s->[$CONFIG]{name}, + ); + return undef; + } + @current = $s->row($key); + } + elsif ($opt->{dml} eq 'update') { + $s->log_error( + "No record to update set_slice for key '$key' on table %s", + $s->[$CONFIG]{name}, + ); + return undef; + } @current[ map { $s->column_index($_) } @$fary ] = @$vary; 2.85 interchange/lib/Vend/Table/DBI.pm rev 2.85, prev_rev 2.84 Index: DBI.pm =================================================================== RCS file: /var/cvs/interchange/lib/Vend/Table/DBI.pm,v retrieving revision 2.84 retrieving revision 2.85 diff -u -r2.84 -r2.85 --- DBI.pm 25 Mar 2008 17:13:21 -0000 2.84 +++ DBI.pm 5 May 2008 15:14:00 -0000 2.85 @@ -1,6 +1,6 @@ # Vend::Table::DBI - Access a table stored in an DBI/DBD database # -# $Id: DBI.pm,v 2.84 2008-03-25 17:13:21 jon Exp $ +# $Id: DBI.pm,v 2.85 2008-05-05 15:14:00 markj Exp $ # # Copyright (C) 2002-2008 Interchange Development Group # Copyright (C) 1996-2002 Red Hat, Inc. @@ -21,7 +21,7 @@ # MA 02110-1301 USA. package Vend::Table::DBI; -$VERSION = substr(q$Revision: 2.84 $, 10); +$VERSION = substr(q$Revision: 2.85 $, 10); use strict; no warnings qw(uninitialized numeric); @@ -1213,6 +1213,17 @@ return undef; } + my $opt; + if (ref ($key) eq 'ARRAY') { + $opt = shift @$key; + $key = shift @$key; + } + $opt = {} + unless ref ($opt) eq 'HASH'; + + $opt->{dml} = 'upsert' + unless defined $opt->{dml}; + my $tkey; my $sql; @@ -1257,8 +1268,15 @@ $tkey = $s->quote($key, $s->[$KEY]) if defined $key; #::logDebug("tkey now $tkey"); - - if ( defined $tkey and $s->record_exists($key) ) { + my $force_insert = + $opt->{dml} eq 'insert'; + my $force_update = + $opt->{dml} eq 'update'; + + if ( + $force_update or + !$force_insert and defined $tkey and $s->record_exists($key) + ) { unless (@$fary) { # as there are no data columns, we can safely skip the update return $key; 1.12 interchange/lib/Vend/Table/DBI_CompositeKey.pm rev 1.12, prev_rev 1.11 Index: DBI_CompositeKey.pm =================================================================== RCS file: /var/cvs/interchange/lib/Vend/Table/DBI_CompositeKey.pm,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- DBI_CompositeKey.pm 9 Aug 2007 13:40:56 -0000 1.11 +++ DBI_CompositeKey.pm 5 May 2008 15:14:00 -0000 1.12 @@ -1,6 +1,6 @@ # Vend::Table::DBI - Access a table stored in an DBI/DBD database # -# $Id: DBI_CompositeKey.pm,v 1.11 2007-08-09 13:40:56 pajamian Exp $ +# $Id: DBI_CompositeKey.pm,v 1.12 2008-05-05 15:14:00 markj Exp $ # # Copyright (C) 2002-2007 Interchange Development Group # Copyright (C) 1996-2002 Red Hat, Inc. @@ -21,7 +21,7 @@ # MA 02110-1301 USA. package Vend::Table::DBI_CompositeKey; -$VERSION = substr(q$Revision: 1.11 $, 10); +$VERSION = substr(q$Revision: 1.12 $, 10); use strict; @@ -317,6 +317,16 @@ return undef; } + my $opt; + if (ref ($key) eq 'ARRAY' && ref ($key->[0]) eq 'HASH') { + $opt = shift @$key; + $key = shift @$key; + } + $opt ||= {}; + + $opt->{dml} = 'upsert' + unless defined $opt->{dml}; + my @key; my $exists; if($key) { @@ -403,7 +413,12 @@ } } - if ( $exists ) { + my $force_insert = + $opt->{dml} eq 'insert'; + my $force_update = + $opt->{dml} eq 'update'; + + if ( $force_update or !$force_insert and $exists ) { unless (@$fary) { # as there are no data columns, we can safely skip the update return $key; 2.16 interchange/lib/Vend/Table/LDAP.pm rev 2.16, prev_rev 2.15 Index: LDAP.pm =================================================================== RCS file: /var/cvs/interchange/lib/Vend/Table/LDAP.pm,v retrieving revision 2.15 retrieving revision 2.16 diff -u -r2.15 -r2.16 --- LDAP.pm 9 Aug 2007 13:40:56 -0000 2.15 +++ LDAP.pm 5 May 2008 15:14:00 -0000 2.16 @@ -1,6 +1,6 @@ # Vend::Table::LDAP - Interchange LDAP pseudo-table access # -# $Id: LDAP.pm,v 2.15 2007-08-09 13:40:56 pajamian Exp $ +# $Id: LDAP.pm,v 2.16 2008-05-05 15:14:00 markj Exp $ # # Copyright (C) 2002-2007 Interchange Development Group # Copyright (C) 1996-2002 Red Hat, Inc. @@ -25,7 +25,7 @@ package Vend::Table::LDAP; @ISA = qw/Vend::Table::Common/; -$VERSION = substr(q$Revision: 2.15 $, 10); +$VERSION = substr(q$Revision: 2.16 $, 10); use strict; use vars qw( @@ -300,9 +300,38 @@ return undef; } + my $opt; + if (ref ($key) eq 'ARRAY') { + $opt = shift @$key; + $key = shift @$key; + } + $opt = {} + unless ref ($opt) eq 'HASH'; + + $opt->{dml} = 'upsert' + unless defined $opt->{dml}; + + if ($s->record_exists($key)) { + if ($opt->{dml} eq 'insert') { + $s->log_error( + "Duplicate key on set_slice insert for key '$key' on table %s", + $s->[$CONFIG]{name}, + ); + return undef; + } + } + elsif ($opt->{dml} eq 'update') { + $s->log_error( + "No record to update set_slice for key '$key' on table %s", + $s->[$CONFIG]{name}, + ); + return undef; + } + for( my $i = 0; $i < @$fary; $i++) { $s->set_field($key, $fary->[$i], $vary->[$i]); } + return 1; } _______________________________________________ interchange-cvs mailing list interchange-cvs[at]icdevgroup.org http://www.icdevgroup.org/mailman/listinfo/interchange-cvs
|