Author: rfm
Date: Fri Aug 8 10:07:06 2014
New Revision: 38041
URL: http://svn.gna.org/viewcvs/gnustep?rev=38041&view=rev
Log:
first attempt at merge code
Modified:
libs/sqlclient/trunk/ChangeLog
libs/sqlclient/trunk/SQLClient.h
libs/sqlclient/trunk/SQLClient.m
Modified: libs/sqlclient/trunk/ChangeLog
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/ChangeLog?rev=38041&r1=38040&r2=38041&view=diff
==============================================================================
--- libs/sqlclient/trunk/ChangeLog (original)
+++ libs/sqlclient/trunk/ChangeLog Fri Aug 8 10:07:06 2014
@@ -1,3 +1,9 @@
+2014-08-08 Richard Frith-Macdonald <[email protected]>
+
+ * SQLClient.h:
+ * SQLClient.m:
+ Add merging of insert/update statements in a transaction.
+
2014-07-17 Yavor Doganov <[email protected]>
Install bundles in a versioned directory.
Modified: libs/sqlclient/trunk/SQLClient.h
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/SQLClient.h?rev=38041&r1=38040&r2=38041&view=diff
==============================================================================
--- libs/sqlclient/trunk/SQLClient.h (original)
+++ libs/sqlclient/trunk/SQLClient.h Fri Aug 8 10:07:06 2014
@@ -1572,7 +1572,7 @@
- (id) copyWithZone: (NSZone*)z;
/**
- * Returns the number of individual statements ond/r subsidiary transactions
+ * Returns the number of individual statements and/or subsidiary transactions
* which have been added to the receiver. For a count of the total number
* of statements, use the -totalCount method.
*/
@@ -1648,6 +1648,40 @@
* database client as the receiver.
*/
- (void) insertTransaction: (SQLTransaction*)trn atIndex: (unsigned)index;
+
+/**
+ * Like -add:... but, if the new statement can be merged with a recently
+ * added one, this does that rather than adding as a separate statement.
+ * <p>You may use this with an insert statement of the form:<br />
+ * INSERT INTO table (fieldnames) VALUES (values);<br />
+ * For databases which support multiline inserts such that they can be
+ * merged into something of the form:
+ * INSERT INTO table (fieldnames) VALUES (values1),(values2),...;
+ * </p>
+ * <p>Or may use this with an update statement of the form:<br />
+ * UPDATE table SET settings WHERE condition;<br />
+ * So that statements may be merged into:<br />
+ * UPDATE table SET setting WHERE (condition1) OR (condition2) OR ...;
+ * </p>
+ * If no opportunity for merging is found, the new statement is simply
+ * added to the transaction.<br />
+ * Caveats:<br />
+ * 1. databases may not actually support multiline insert.<br />
+ * 2. Only the most recent five statements in a transaction are checked
+ * for eligibility.<br />
+ * 3. Merging is done only if the statement up to the string 'VALUES'
+ * (for insert) or 'WHERE' (for update) matches.<br />
+ * 4. This is a simple text match rather than sql syntactic analysis,
+ * so it's possible to confuse the process with complex statements.
+ */
+- (void) merge: (NSString*)stmt,...;
+
+/**
+ * Like -add:with: but, if the new statement can be merged with a recently
+ * added one, this does that rather than adding as a separate statement.
+ * See -merge:,... for meore details.
+ */
+- (void) merge: (NSString*)stmt with: (NSDictionary*)values;
/** Remove the index'th transaction or statement from the receiver.
*/
Modified: libs/sqlclient/trunk/SQLClient.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/SQLClient.m?rev=38041&r1=38040&r2=38041&view=diff
==============================================================================
--- libs/sqlclient/trunk/SQLClient.m (original)
+++ libs/sqlclient/trunk/SQLClient.m Fri Aug 8 10:07:06 2014
@@ -650,9 +650,9 @@
@interface SQLClient (Private)
- (void) _configure: (NSNotification*)n;
- (void) _populateCache: (CacheQuery*)a;
-- (NSArray*) _prepare: (NSString*)stmt args: (va_list)args;
+- (NSMutableArray*) _prepare: (NSString*)stmt args: (va_list)args;
- (void) _recordMainThread;
-- (NSArray*) _substitute: (NSString*)str with: (NSDictionary*)vals;
+- (NSMutableArray*) _substitute: (NSString*)str with: (NSDictionary*)vals;
+ (void) _tick: (NSTimer*)t;
@end
@@ -2236,7 +2236,7 @@
* any NSData objects following. The NSData objects appear in the
* statement strings as the marker sequence - <code>'?'''?'</code>
*/
-- (NSArray*) _prepare: (NSString*)stmt args: (va_list)args
+- (NSMutableArray*) _prepare: (NSString*)stmt args: (va_list)args
{
NSMutableArray *ma = [NSMutableArray arrayWithCapacity: 2];
NSString *tmp = va_arg(args, NSString*);
@@ -2290,7 +2290,7 @@
* any NSData objects following. The NSData objects appear in the
* statement strings as the marker sequence - <code>'?'''?'</code>
*/
-- (NSArray*) _substitute: (NSString*)str with: (NSDictionary*)vals
+- (NSMutableArray*) _substitute: (NSString*)str with: (NSDictionary*)vals
{
unsigned int l = [str length];
NSRange r;
@@ -3202,6 +3202,183 @@
[trn release];
}
+/* Try to merge the prepared statement p with an earlier statement in the
+ * transaction. We search up to 5 earlier statements and we merge if;
+ * a. We have something like 'INSERT INTO table (fields) VALUES (values)'
+ * where everything up to 'VALUES' is the same, so we can built a multiline
+ * insert like 'INSERT INTO table (fields) VALUES (values1),(values2),...'
+ * b. We have something like 'UPDATE table SET settings WHERE condition'
+ * where everything up to the condition is the same, so we can build
+ * 'UPDATE table SET settings WHERE condition1 OR (condition2) OR ...'
+ */
+- (void) _merge: (NSMutableArray*)p
+{
+ if (_count > 0)
+ {
+ static NSCharacterSet *w = nil;
+ NSString *s;
+ NSRange r;
+
+ s = [p objectAtIndex: 0]; // Get SQL part of array
+
+ if (nil == w)
+ {
+ w = [[NSCharacterSet whitespaceAndNewlineCharacterSet] retain];
+ }
+
+ r = [s rangeOfString: @"INSERT" options: NSCaseInsensitiveSearch];
+ if (r.length > 0 && 0 == r.location)
+ {
+ r = [s rangeOfString: @"VALUES" options: NSCaseInsensitiveSearch];
+ if (r.length > 0)
+ {
+ NSUInteger l = [s length];
+ NSUInteger pos = NSMaxRange(r);
+
+ while (pos < l
+ && [w characterIsMember: [s characterAtIndex: pos]])
+ {
+ pos++;
+ }
+ if (pos < l && [s characterAtIndex: pos] == '(')
+ {
+ NSString *t = [s substringToIndex: pos];
+ NSUInteger index = _count;
+ NSUInteger attempts = 0;
+
+ s = [s substringFromIndex: pos];
+ while (index-- > 0 && attempts++ < 5)
+ {
+ NSMutableArray *o;
+ NSString *os;
+
+ o = [_info objectAtIndex: index];
+ os = [o objectAtIndex: 0];
+ if ([os hasPrefix: t])
+ {
+ NSMutableString *m;
+
+ if ([os isKindOfClass: [NSMutableString class]])
+ {
+ m = (NSMutableString*)os;
+ }
+ else
+ {
+ m = [[os mutableCopy] autorelease];
+ }
+ [m appendString: @","];
+ [m appendString: s];
+ [o replaceObjectAtIndex: 0 withObject: m];
+ for (index = 1; index < [p count]; index++)
+ {
+ [o addObject: [p objectAtIndex: index]];
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ r = [s rangeOfString: @"UPDATE" options: NSCaseInsensitiveSearch];
+ if (r.length > 0 && 0 == r.location)
+ {
+ r = [s rangeOfString: @"WHERE" options: NSCaseInsensitiveSearch];
+ if (r.length > 0)
+ {
+ NSUInteger l = [s length];
+ NSUInteger pos = NSMaxRange(r);
+
+ while (pos < l
+ && [w characterIsMember: [s characterAtIndex: pos]])
+ {
+ pos++;
+ }
+ if (pos < l && [s characterAtIndex: pos] == '(')
+ {
+ NSString *t = [s substringToIndex: pos];
+ NSUInteger index = _count;
+ NSUInteger attempts = 0;
+
+ /* Get the condition after the WHERE and if it's not
+ * in brackets, add them so the merge can work.
+ */
+ s = [s substringFromIndex: pos];
+ if ([s characterAtIndex: 0] != '(')
+ {
+ s = [NSString stringWithFormat: @"(%@)", s];
+ }
+
+ while (index-- > 0 && attempts++ < 5)
+ {
+ NSMutableArray *o;
+ NSString *os;
+
+ o = [_info objectAtIndex: index];
+ os = [o objectAtIndex: 0];
+ if ([os hasPrefix: t])
+ {
+ NSMutableString *m;
+
+ l = [os length];
+ if ([os characterAtIndex: l - 1] == ')')
+ {
+ if ([os isKindOfClass: [NSMutableString class]])
+ {
+ m = (NSMutableString*)os;
+ }
+ else
+ {
+ m = [[os mutableCopy] autorelease];
+ }
+ }
+ else
+ {
+ /* The condition of the WHERE clause was not
+ * bracketed, so we extract it and build a
+ * new statement in which it is bracketed.
+ */
+ os = [os substringFromIndex: pos];
+ m = [NSMutableString stringWithFormat:
+ @"%@(%@)", t, os];
+ }
+ [m appendString: @" OR "];
+ [m appendString: s];
+ [o replaceObjectAtIndex: 0 withObject: m];
+ for (index = 1; index < [p count]; index++)
+ {
+ [o addObject: [p objectAtIndex: index]];
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ [_info addObject: p];
+ _count++;
+}
+
+- (void) merge: (NSString*)stmt,...
+{
+ va_list ap;
+ NSMutableArray *p;
+
+ va_start (ap, stmt);
+ p = [_db _prepare: stmt args: ap];
+ va_end (ap);
+ [self _merge: p];
+}
+
+- (void) merge: (NSString*)stmt with: (NSDictionary*)values
+{
+ NSMutableArray *p;
+
+ p = [_db _substitute: stmt with: values];
+ [self _merge: p];
+}
+
- (void) removeTransactionAtIndex: (unsigned)index
{
id o;
_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs