//// BXPGModificationHandler.mm// BaseTen//// Copyright (C) 2006-2008 Marko Karppinen & Co. LLC.//// Before using this software, please review the available licensing options// by visiting http://basetenframework.org/licensing/ or by contacting// us at sales@karppinen.fi. Without an additional license, this software// may be distributed only in compliance with the GNU General Public License.////// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License, version 2.0,// as published by the Free Software Foundation.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA//// $Id$//#import "BXPGModificationHandler.h"#import "BXEntityDescriptionPrivate.h"#import "BXDatabaseObjectIDPrivate.h"#import "PGTSScannedMemoryAllocator.h"#import "PGTSHOM.h"#import <tr1/unordered_map>typedefstd::tr1::unordered_map<unichar,NSMutableArray*,std::tr1::hash<unichar>,std::equal_to<unichar>,PGTS::scanned_memory_allocator<std::pair<constunichar,NSMutableArray*>>>ChangeMap;@interfacePGTSColumnDescription(BXPGModificationHandlerAdditions)-(NSString*)columnDefinition;@end@implementationPGTSColumnDescription(BXPGModificationHandlerAdditions)-(NSString*)columnDefinition{NSString*retval=nil;PGTSTypeDescription*type=[selftype];NSString*schemaName=[[typeschema]name];if(schemaName)retval=[NSStringstringWithFormat:@"\"%@\"\"%@\".\"%@\"",[selfname],schemaName,[typename]];elseretval=[NSStringstringWithFormat:@"\"%@\"\"%@\"",[selfname],[typename]];returnretval;}@end@implementationBXPGModificationHandler-(void)dealloc{[mQueryStringrelease];[superdealloc];}-(void)prepare{[superprepare];BXPGTableDescription*rel=[mInterfacetableForEntity:mEntity];PGTSIndexDescription*pkey=[relprimaryKey];NSArray*columns=[[[pkeycolumns]allObjects]sortedArrayUsingSelector:@selector(indexCompare:)];NSString*pkeyString=[(id)[[columnsPGTSCollect]columnDefinition]componentsJoinedByString:@", "];NSString*queryFormat=@"SELECT * FROM \"baseten\".modification ($1, $2, $3, $4) "@"AS m ( "@"\"baseten_modification_type\" character (1), "@"\"baseten_modification_timestamp\" timestamp (6) without time zone, "@"\"baseten_modification_insert_timestamp\" timestamp (6) without time zone, "@"%@)";mQueryString=[[NSStringalloc]initWithFormat:queryFormat,pkeyString];}-(void)handleNotification:(PGTSNotification*)notification{intbackendPID=[mEntitygetsChangedByTriggers]?0:[mConnectionbackendPID];[selfcheckModifications:backendPID];}-(void)checkModifications:(int)backendPID{//When observing self-generated modifications, also the ones that still have NULL values for //pgts_modification_timestamp should be included in the query. BOOLisIdle=(PQTRANS_IDLE==[mConnectiontransactionStatus]);PGTSResultSet*res=[mConnectionexecuteQuery:mQueryStringparameters:PGTSOidAsObject(mOid),[NSNumbernumberWithBool:isIdle],mLastCheck,[NSNumbernumberWithInt:backendPID]];BXAssertVoidReturn([resquerySucceeded],@"Expected query to succeed: %@",[reserror]);//Update the timestamp.while([resadvanceRow])[selfsetLastCheck:[resvalueForKey:@"baseten_modification_timestamp"]];//Sort the changes by type.ChangeMap*changes=newChangeMap(3);[resgoBeforeFirstRow];while([resadvanceRow]){NSDictionary*row=[rescurrentRowAsDictionary];unicharmodificationType=[[rowvalueForKey:@"baseten_modification_type"]characterAtIndex:0];NSMutableArray*objectIDs=(*changes)[modificationType];if(!objectIDs){objectIDs=[NSMutableArrayarrayWithCapacity:[rescount]];(*changes)[modificationType]=objectIDs;}BXDatabaseObjectID*objectID=[BXDatabaseObjectIDIDWithEntity:mEntityprimaryKeyFields:row];[objectIDsaddObject:objectID];}//Send changes.ChangeMap::const_iteratoriterator=changes->begin();while(changes->end()!=iterator){unichartype=iterator->first;NSArray*objectIDs=iterator->second;switch(type){case'I':[[mInterfacedatabaseContext]addedObjectsToDatabase:objectIDs];break;case'U':[[mInterfacedatabaseContext]updatedObjectsInDatabase:objectIDsfaultObjects:YES];break;case'D':[[mInterfacedatabaseContext]deletedObjectsFromDatabase:objectIDs];break;default:break;}iterator++;}//Contents have already been autoreleased.deletechanges;}-(void)setOid:(Oid)oid{mOid=oid;}@end