// Range Transaction over a DBConnection: Updating in a IndexedDBView 

const TIMESTAMP_STRUCT chrysalis = {2002, 4, 3, 0, 0, 0, 0};
const TIMESTAMP_STRUCT mikero = {2001, 11, 2, 0, 0, 0, 0};
const TIMESTAMP_STRUCT victory = {2001, 3, 10, 0, 0, 0, 0};

// range update
void RangeIndexUpdateExample()
{
	DBConnection conn;
        conn.Connect("UID=example;PWD=example;DSN=example;");

	typedef DBView DBV;

	DBV view("DB_EXAMPLE", DefaultBCA(), 
	   "", DefaultBPA >(), DefaultSelValidate(),
	   DefaultInsValidate(), conn);

	view.set_io_handler(AlwaysThrowsHandler());

	IndexedDBView idxview(view, 
		"PrimaryIndex; STRING_VALUE; UNIQUE AlternateIndex; EXAMPLE_LONG, EXAMPLE_DATE",
		BOUND);

	cout << "Examples in view before attempted range insert:" << endl;

	copy(idxview.begin(), idxview.end(), ostream_iterator(cout, "\n"));

	vector read_from_DB_before;

	copy(idxview.begin(), idxview.end(), back_inserter(read_from_DB_before));

	// examples that we want to insert into the DB ...
	// we want an all or nothing on these guys!
	// string indicates key of element to replace, Example is object to replace the object
	// to replace with
	map all_or_nothing_examples;

	// third element will fail to be updated, should force rollback
	all_or_nothing_examples["Bedazzled"] = Example(79, "FUBAR", 2.2, 99, mikero);
	all_or_nothing_examples["Corwin"] = Example(81, "All Messed Up", 21.09, 75, chrysalis);
	all_or_nothing_examples["Jordan"] = Example(85, "Bad Boy", -21.22, 11, victory);
	all_or_nothing_examples["Mirror Image"] = Example(99, "Good One", 77.99, 41, victory);
	
	// must update all the elements to succeed in the transaction
	// else we rollback

	IndexedDBView tmp(idxview); // make copy so we can rollback to idxview on failure

	// march through vector and replace elements appropriately
	try {
	  map::iterator map_it;
	  
	  for (map_it = all_or_nothing_examples.begin(); 
	       map_it != all_or_nothing_examples.end(); 
		   map_it++)
		  {	  
		     IndexedDBView::iterator find_it = idxview.find((*map_it).first);

			 if (find_it != idxview.end())
				 idxview.replace(find_it, (*map_it).second);
		  }

          conn.CommitAll(); // we assume commit and rollback must always succeed to avoid two-phase commit type logic
	}
        catch(RootException &ex) 
	{ 
	  cout << ex << endl;
	  idxview.swap(tmp); // this will rollback to original results in memory
          conn.RollbackAll(); 
	}

	cout << "Examples in view after attempted range update:" << endl;

	copy(idxview.begin(), idxview.end(), ostream_iterator(cout, "\n"));

	vector read_from_DB_after;

	copy(idxview.begin(), idxview.end(), back_inserter(read_from_DB_after));

	cout << "Changes resulting from attempted range update:" << endl;
   
        TableDiff(cout, read_from_DB_before, read_from_DB_after);
}