From 975572c6b7fe784b1c0ee800d615f7cec586ff2e Mon Sep 17 00:00:00 2001
From: CaS Version: 1.1 Date: 2004/04/26 15:13:27 Copyright: (C) 2004 Free Software Foundation, Inc.
+
+ The SQLClient library is designed to provide a simple
+ interface to SQL databases for GNUstep
+ applications. It does not attempt the sort of
+ abstraction provided by the much more
+ sophisticated GDL2 library, but rather allows
+ applications to directly execute SQL queries and
+ statements.
+
+The major features of the SQLClient library are -
+Current backend bundles are -
+
+
+
+
+ The SQLClient class encapsulates dynamic SQL access to
+ relational database systems. A shared instance
+ of the class is used for each database (as identified by
+ the name of the database), and the number of
+ simultanous database connections is managed
+ too.
+
+
+
+
+
+ SQLClient is an abstract base class... when you
+ create an instance of it, you are actually creating
+ an instance of a concrete subclass whose implementation
+ is loaded from a bundle.
+
+
+
+
+
+ Identifier within backend
+
+
+
+ A flag indicating whether this instance is currently
+ connected to the backend database server. This
+ variable must only be set by the
+
+ -backendConnect
+
+
+ or
+
+ -backendDisconnect
+
+
+ methods.
+
+
+
+ The configured database name/host
+
+
+
+ The current debugging level
+
+
+
+ For subclass specific data
+
+
+
+ A flag indicating whether this instance is currently
+ within a transaction. This variable must
+ only be set by the
+
+ -begin
+
+
+ , -commit
+ or
+
+ -rollback
+
+
+ methods.
+
+ Timestamp of last operation.
+
+ Maintain thread-safety
+
+
+
+ Unique identifier for instance
+
+
+
+ The configured password
+
+
+
+ The configured user
+
+
+
+ Returns an array containing all the SQLClient
+ instances.
+
+
+
+ Return an existing SQLClient instance (using
+ +existingClient:) if possible, or creates
+ one, initialises it using
+
+ -initWithConfiguration:name:
+
+
+ , and returns the new instance (autoreleased).
+
+ Return an existing SQLClient instance for the
+ specified name if one exists, otherwise returns
+
+
+ Return the maximum number of simultaneous database
+ connections permitted (set by
+
+ +setMaxConnections:
+
+
+ and defaults to 8)
+
+
+
+
+
+
+ Use this method to reduce the number of database
+ connections currently active so that it is
+ less than the limit set by the
+
+ +setMaxConnections:
+
+
+ method. This mechanism is used internally by the
+ class to ensure that, when it is about to open a
+ new connection, the limit is not exceeded.
+
+
+
+
+
+ If since is not
+
+
+
+
+
+
+
+ Set the maximum number of simultaneous database
+ connections permitted (defaults to 8 and may
+ not be set less than 1).
+
+
+
+
+
+ This value is used by the
+
+ +purgeConnections:
+
+
+ method to determine how many connections should be
+ disconnected when it is called.
+
+
+
+
+
+ Start a transaction for this database client.
+
+ Normally, if you execute an SQL statement
+ without using this method first, the
+ autocommit feature is employed, and the
+ statement takes effect immediately. Use of this
+ method permits you to execute several statements
+ in sequence, and only have them take effect (as a
+ single operation) when you call the
+
+ -commit
+
+
+ method.
+
+
+
+
+
+ NB. You must not execute an SQL
+ statement which would start a transaction
+ directly... use only this method.
+
+
+
+
+
+ Return the client name for this instance.
+
+ Complete a transaction for this database client.
+
+
+ NB. You must not execute an SQL
+ statement which would commit or rollback a
+ transaction directly... use only this method
+ or the
+
+ -rollback
+
+
+ method.
+
+
+
+
+
+ If the connected instance variable is
+
+
+ Return a flag to say whether a connection to the
+ database server is currently live. This is mostly
+ useful for debug/reporting, but is used internally
+ to keep track of active connections.
+
+
+
+ Return the database name for this instance (or
+
+
+ If the connected instance variable is
+
+
+ Perform arbitrary operation
+ which does not return any value. SQLClient documentation
+ Authors
+
+
+ rfm@gnu.org
)
+ Contents -
+
+
+
+ The SQLClient library
+
+ Overview
+
+
+
+
+
+ Backends
+
+
+
+
This is based on a similar code
+ which has been in production use for over eighteen
+ months, so it should be reliable.
+
+
This is the
+ preferred backend as it allows 'SELECT FOR
+ UPDATE', which the ECPG backend cannot support due
+ to limitations in the postgres implementation of
+ cursors. The code is however not as well tested as
+ the ECPG interface.
+
+
I don't use MySQL... but
+ the test program ran successfully with a vanilla
+ install of the MySQL packages for recent Debian
+ unstable.
+
+
Completely untested... may even need some
+ work to compile... but this *is* based on code which
+ was working about a year ago.
No support for
+ BLOBs yet.
+
+
+ Software documentation for the SQLClient class
+
+ SQLClient : NSObject
+
+
+
+
+
+ Instance Variables for SQLClient Class
+ client
+ @private NSString* client;
+
+ connected
+ @private BOOL connected;
+
+ database
+ @private NSString* database;
+
+ debugging
+ @private unsigned int debugging;
+
+ extra
+ @private void* extra;
+
+ inTransaction
+ @private BOOL inTransaction;
+
Are we inside a transaction?
+
+
+ lastOperation
+ @private NSDate* lastOperation;
+
Maintained by
+ the
+
+ -simpleExecute:
+
+
+ and
+
+ -simpleQuery:
+
+
+ methods.
+
+
+ lock
+ @private NSRecursiveLock* lock;
+
+ name
+ @private NSString* name;
+
+ password
+ @private NSString* password;
+
+ user
+ @private NSString* user;
+
+
+ Method summary
+
+
+
+ allClients
+ + (NSArray*) allClients;
+
+ clientWithConfiguration: name:
+ + (SQLClient*) clientWithConfiguration: (NSDictionary*)config name: (NSString*)reference;
+
+ Returns nil
on failure.
+
+
+ existingClient:
+ + (SQLClient*) existingClient: (NSString*)reference;
+ nil
.
+
+
+ maxConnections
+ + (unsigned int) maxConnections;
+
+ purgeConnections:
+ + (void) purgeConnections: (NSDate*)since;
+ nil
, then any
+ connection which has not been used more
+ recently than that date is disconnected anyway.
+
You can (and probably should) use this
+ periodically to purge idle connections, but
+ you can also pass a date in the future to close all
+ connections.
+
+ setMaxConnections:
+ + (void) setMaxConnections: (unsigned int)c;
+
+ begin
+ - (void) begin;
+
+ You must match this with either a
+
+ -commit
+
+
+ or a -rollback
+.
+
+
+
+ clientName
+ - (NSString*) clientName;
+
+ Normally this is useful only for
+ debugging/reporting purposes, but if
+ you are using multiple instances of this class in your
+ application, and you are using embedded SQL,
+ you will need to use this method to fetch the
+ client/connection name and store its
+ C-string representation in a variable
+ 'connectionName' declared to the sql
+ preprocessor, so you can then have statements
+ of the form - 'exec sql at :connectionName...'.
+
+
+ commit
+ - (void) commit;
+
This must match an earlier
+
+ -begin
+
+
+ .
+
+
+ connect
+ - (BOOL) connect;
+ NO
, this method calls
+
+ -backendConnect
+
+
+ to ensure that there is a connection to the database
+ server established. Returns the result.
+ Performs any necessary locking for thread safety.
+
+
+ connected
+ - (BOOL) connected;
+
+ database
+ - (NSString*) database;
+ nil
).
+
+
+ disconnect
+ - (void) disconnect;
+ YES
, this method calls
+
+ -backendDisconnect
+
+
+ to ensure that the connection to the database server is
+ dropped.
Performs any necessary locking for
+ thread safety.
+
+
+ execute: ,...
+ - (void) execute: (NSString*)stmt,...;
+
This
+ arguments to this method are a nil
+ terminated list which are concatenated in the
+ manner of the *
+
+ -prepare:args:
+
+
+ method.
Any string arguments are assumed to
+ have been quoted appropriately already, but non-string
+ arguments are automatically quoted using the
+
+ -quote:
+
+
+ method.
+
+
+ [db execute: @"UPDATE ", table, @" SET Name = ",
+ myName, " WHERE ID = ", myId, nil];
+
+
+
+
+
+ Takes the statement and substitutes in
+ values from the dictionary where markup of
+ the format {key} is found.
Passes the result to
+ the
+
+ -execute:,...
+
+
+ method.
+
+
+ [db execute: @"UPDATE {Table} SET Name = {Name} WHERE ID = {ID}" + with: values]; ++ + Any non-string values in the dictionary will + be replaced by the results of the + + -quote: + + + method.
+
+ Calls
+
+ -initWithConfiguration:name:
+
+
+ passing a nil
reference name.
+
+
+
+ Initialise using the supplied configuration, or
+ if that is nil
, try to use values from
+ NSUserDefaults (and automatically update
+ when the defaults change).
Uses the
+ reference name to determine configuration
+ information... and if a nil
name
+ is supplied, defaults to the value of the SQLClientName
+ as a user default string or 'Database' if no other name
+ is provided.
If a SQLClient instance already
+ exists with the name used for this instance, the
+ receiver is deallocated and the existing instance
+ is retained and returned... there may only ever be one
+ instance for a particular reference
+ name.
The config argument
+ (or the SQLClientReferences user default) is a
+ dictionary with names as keys and dictionaries
+ as its values. Configuration entries from the dictionary
+ corresponding to the database client are used
+ if possible, general entries are used otherwise.
+ Database... is the name of the database to use, if
+ it is missing then 'Database' may be used instead.
+
User... is the name of the database user to
+ use, if it is missing then 'User' may be used instead.
+
Password... is the name of the database user
+ password, if it is missing then 'Password' may be
+ used instead.
ServerType... is the name of the
+ backend server to be used... by convention the name
+ of a bundle containing the interface to that backend. If
+ this is missing then 'Postgres' is used.
+
+
+ + Return the state of the flag indicating whether the + library thinks a transaction is in progress. This + flag is normally maintained by + + -begin + + + , -commit +, and + + -rollback + + + . + +
+
+
+ Returns the date/time stamp of the last database
+ operation performed by the receiver, or
+ nil
if no operation has ever been done
+ by it.
Simply connecting to or disconnecting from
+ the databsse does not count as an operation.
+
+
+
+ Return the database reference name for this instance
+ (or nil
).
+
+
+
+ Return the database password for this instance (or
+ nil
).
+
+
+ + +
++ + Perform arbitrary query + which returns values. +
++ + +
++ + This method has at least one argument, the string + starting the statement to be executed (which + must have the prefix 'select '). +
++ + +
+
+
+ Additional arguments are a nil
+ terminated list which also be strings, and
+ these are appended to the statement.
Any
+ string arguments are assumed to have been quoted
+ appropriately already, but non-string
+ arguments are automatically quoted using the
+
+ -quote:
+
+
+ method.
+
+ + +
+ result = [db query: @"SELECT Name FROM ", table, nil]; ++ + + +
+Upon error, an exception is raised.
++ + +
++ + The query returns an array of records (each of which + is represented by an SQLRecord object). +
++ + +
++ + Each SQLRecord object contains one or more fields, + in the order in which they occurred in the query. + Fields may also be retrieved by name. +
++ + +
++NULL field items are returned as NSNull objects.
++ + +
++ + Most other field items are returned as NSString + objects. +
++ + +
++ + Date and timestamp field items are returned as + NSDate objects. +
++ + +
+
+
+ Takes the query statement and substitutes in
+ values from the dictionary where markup of
+ the format {key} is found.
Passes the result to
+ the
+
+ -query:,...
+
+
+ method to execute.
+
+
+ result = [db query: @"SELECT Name FROM {Table} WHERE ID = {ID}" + with: values]; ++ + Any non-string values in the dictionary will + be replaced by the results of the + + -quote: + + + method.
+
+ Convert an object to a string suitable for use in
+ an SQL query.
Normally the
+
+ -execute:,...
+
+
+ , and
+
+ -query:,...
+
+
+ methods will call this method automatically for
+ everything apart from string objects.
+ Strings have to be handled specially, because they
+ are used both for parts of the SQL command, and as
+ values (where they need to be quoted). So where you
+ need to pass a string value which needs quoting, you
+ must call this method explicitly.
Subclasses
+ may override this method to provide appropriate quoting
+ for types of object which need database backend
+ specific quoting conventions. However, the defalt
+ implementation should be OK for most cases.
+
The base class implementation formats NSDate
+ objects as
YYYY-MM-DD hh:mm:ss.mmm ?ZZZZ
+
NSData objects are not quoted... they must
+ not appear in queries, and where used for insert/update
+ operations, they need to be passed to the
+
+ -backendExecute:
+
+
+ method unchanged.
For a nil
or
+ NSNull object, we return NULL.
For a number,
+ we simply convert directly to a string.
For a
+ date, we convert to the text format used by the
+ database, and add leading and trailing quotes.
+
For a data object, we don't quote... the
+ other parts of the code need to know they have an
+ NSData object and pass it on unchanged to the
+
+ -backendExecute:
+
+
+ method.
For any other type of data, we just
+ produce a quoted string representation.
+
+
+ + Convert a 'C' string to a string suitable for use + in an SQL query. + +
++ + Convert a single character to a string suitable for + use in an SQL query. + +
++ + Convert a float to a string suitable for use in an + SQL query. + +
++ + Convert an integer to a string suitable for use in + an SQL query. + +
+
+
+ Revert a transaction for this database client.
+
This must match an earlier
+
+ -begin
+
+
+ .
+
+
+ + NB. You must not execute an SQL + statement which would commit or rollback a + transaction directly... use only this method + or the + + -rollback + + + method. +
++ + +
+
+
+ Set the database host/name for this object.
This
+ is called automatically to configure the connection...
+ you normally shouldn't need to call it yourself.
+
+
+
+ Set the database reference name for this object. This
+ is used to differentiate between multiple connections to
+ the database.
This is called automatically to
+ configure the connection... you normally
+ shouldn't need to call it yourself.
NB.
+ attempts to change the name of an instance to that
+ of an existing instance are ignored.
+
+
+
+ Set the database password for this object.
This
+ is called automatically to configure the connection...
+ you normally shouldn't need to call it yourself.
+
+
+
+ Set the database user for this object.
This is
+ called automatically to configure the connection...
+ you normally shouldn't need to call it yourself.
+
+
+
+ Calls
+
+ -backendExecute:
+
+
+ in a safe manner.
Handles locking.
+ Maintains
+
+ -lastOperation
+
+
+ date.
+
+
+
+ Calls
+
+ -backendQuery:
+
+
+ in a safe manner.
Handles locking.
+ Maintains
+
+ -lastOperation
+
+
+ date.
+
+
+
+ Return the database user for this instance (or
+ nil
).
+
+
+++
+- Declared in:
+- SQLClient.h
+
+ + An enhanced array to represent a record returned from a + query. You should NOT try to create instances + of this class except via the + + +newWithValues:keys:count: + + + method. + +
++ + Description forthcoming. + +
++ + Description forthcoming. + +
++ + Returns an array containing the names of all the + fields in the record, in the order in which they + occur in the record. + +
++ + Returns the first field in the record whose name + matches the specified key. Uses an exact + match in preference to a case-insensitive match. + +
++++
+- Declared in:
+- SQLClient.h
+
+ + This category contains convenience methods including + those for frequently performed database operations... + message logging etc. + +
+ Method summary + ++ + Executes a query (like the + + -query:,... + + + method) and checks the result (raising an exception + if the query did not contain a single record) and + returns the resulting record. + +
+
+
+ Executes a query (like the
+
+ -query:,...
+
+
+ method) and checks the result.
Raises an
+ exception if the query did not contain a single
+ record, or if the record did not contain a single
+ field.
Returns the resulting field as a
+ string.
+
+
+ + Convenience method to deal with the results of + a query where each record contains a single field... it + converts the array of records returned + by the query to an array containing the fields. + +
++++
+- Declared in:
+- SQLClient.h
+
+ + This category porovides basic methods for logging debug + information. + +
+ Method summary ++ + Return the class-wide debugging level, which is + inherited by all newly created minstances. + +
++ + Set the debugging level to be inherited by + all new instances. + +
+
+
+ The default implementation calls NSLogv to log a debug
+ message.
Override this in a category to
+ provide more sophisticated logging.
+
+
+ + Return the current debugging level. + +
++ + Set the debugging level of this instance... + overrides the default level inherited + from the class. + +
++++
+- Declared in:
+- SQLClient.h
+
+
+ This category contains the methods which a subclass
+ must override to provide a working instance,
+ and helper methods for the backend implementations.
+
Application programmers should not
+ call the backend methods directly.
+
+
+ + When subclassing to produce a backend driver bundle, + please be aware that the subclass must NOT + introduce additional instance variables. Instead + the extra instance variable is provided for + use as a pointer to subclass specific data. +
++ + +
+ Method summary +
+
+ Attempts to establish a connection to the database
+ server.
Returns a flag to indicate whether
+ the connection has been established.
If a
+ connection was already established, returns
+ YES
and does nothing.
You should
+ not need to use this method normally, as it is called
+ for you automatically when necessary.
+
+
+ + Subclasses must implement + this method to establish a connection to the + database server process (and initialise the + extra instance variable if necessary), + setting the connected instance variable + to indicate the state of the object. +
++ + +
++ + This method must call + + +purgeConnections: + + + to ensure that there is a free slot for the new + connection. +
++ + +
+
+
+ Application code must not call this
+ method directly, it is for internal use only. The
+
+ -connect
+
+
+ method calls this method if the connected
+ instance variable is NO
.
+
+ + +
+
+
+ Disconnect from the database unless already
+ disconnected.
+
+
+ + This method is called automatically when the + receiver is deallocated or reconfigured, and may + also be called automatically when there are too many + database connections active. +
++ + +
++ + If the receiver is an instance of a subclass which + uses the extra instance variable, it + must clear that variable in the + + -backendDisconnect + + + method, because a reconfiguration may cause the + class of the receiver to change. +
++ + +
+
+
+ This method must set the connected instance
+ variable to NO
.
+
+ + +
+
+
+ Application code must not call this
+ method directly, it is for internal use only. The
+
+ -disconnect
+
+
+ method calls this method if the connected
+ instance variable is YES
.
+
+ + +
+
+
+ Perform arbitrary operation
+ which does not return any value.
This
+ method has a single argument, an array containing
+ the string representing the statement to be executed as
+ its first object, and an optional sequence of data
+ objects following it.
+
+
+ [db backendExecute: [NSArray arrayWithObject: + @"UPDATE MyTable SET Name = 'The name' WHERE ID = 123"]]; ++ + + +
+
+ The backend implementation is required to perform the
+ SQL statement using the supplied NSData objects at
+ the points in the statement marked by the
+ '''
sequence. The marker saequences
+ are inserted into the statement at an earlier stage
+ by the
+
+ -execute:,...
+
+
+ and
+
+ -execute:with:
+
+
+ methods.
+
+ + +
++ + This method should lock the instance using the + lock instance variable for the duration of + the operation, and unlock it afterwards. +
++ + +
++ + NB. callers (other than the + + -begin + + + , -commit +, and + + -rollback + + + methods) should not pass any statement to this + method which would cause a transaction to begin or + end. +
++ + +
++ + Application code must not call this + method directly, it is for internal use only. +
++ + +
++ + +
++ + Perform arbitrary query + which returns values. +
++ + +
+ result = [db backendQuery: @"SELECT Name FROM Table"]; ++ + + +
+Upon error, an exception is raised.
++ + +
++ + The query returns an array of records (each of which + is represented by an SQLRecord object). +
++ + +
++ + Each SQLRecord object contains one or more fields, + in the order in which they occurred in the query. + Fields may also be retrieved by name. +
++ + +
++NULL field items are returned as NSNull objects.
++ + +
++ + This method should lock the instance using the + lock instance variable for the duration of + the operation, and unlock it afterwards. +
++ + +
++ + Application code must not call this + method directly, it is for internal use only. +
++ + +
+
+
+ This method is only for the use of the
+ -insertBLOBs:intoStatement:length:withMarker:length:giving:
+ method.
Subclasses which need to insert binary data into a statement must implement this method to copy the escaped data into place and return the number of bytes actually copied.
+
+
+ + +
++ + This method is a convenience method provided for + subclasses which need to insert escaped binary + data into an SQL statement before sending + the statement to a backend server process. + This method makes use of the + + -copyEscapedBLOB:into: + + + and + + -lengthOfEscapedBLOB: + + + methods, which must be implemented by + the subclass. +
++ + +
++ + The blobs array is an array containing the + original SQL statement string (unused + by this method) followed by the data items to be + inserted. +
++ + +
++ + The statement and sLength + arguments specify the datastream to be copied + and into which the BLOBs are to be inserted. +
++ + +
++ + The marker and mLength + arguments specify the sequence of + marker bytes in the statement + which indicate a position for insertion of a n + escaped BLOB. +
++ + +
++ + The method returns either the original + statement or a copy containing the + escaped BLOBs. The length of the returned data is + stored in result. +
++ + +
+
+
+ This method is only for the use of the
+ -insertBLOBs:intoStatement:length:withMarker:length:giving:
+ method.
Subclasses which need to insert binary data into a statement must implement this method to return the length of the escaped bytestream which will be inserted.
+
+
+
++ + Exception for when a connection to the server is + lost. + +
++ + Exception for when a query is supposed to return + data and doesn't. + +
++ + Exception raised when an error with the remote + database server occurs. + +
++ + Exception for when an insert/update would break the + uniqueness of a field or index. + +
+