[interchange-cvs] interchange - markj modified 5 files

interchange-cvs at icdevgroup.org interchange-cvs at icdevgroup.org
Mon May 5 15:14:00 UTC 2008


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;
 }
 







More information about the interchange-cvs mailing list