diff --git a/davical.webprj b/davical.webprj
index b09540bf..3f33787f 100644
--- a/davical.webprj
+++ b/davical.webprj
@@ -185,7 +185,6 @@
-
@@ -258,5 +257,12 @@
+
+
+
+
+
+
+
diff --git a/inc/PdoQuery.php b/inc/PdoQuery.php
new file mode 100644
index 00000000..0217ecd9
--- /dev/null
+++ b/inc/PdoQuery.php
@@ -0,0 +1,362 @@
+pdo_connect.
+*
+* We will die if the database is not currently connected and we fail to find
+* a working connection.
+*
+* @package awl
+* @subpackage PdoQuery
+* @author Andrew McMillan
+* @copyright Morphoss Ltd
+* @license http://gnu.org/copyleft/gpl.html GNU GPL v3
+* @compatibility Requires PHP 5.1 or later
+*/
+
+/**
+* The PdoDialect class handles
+* @package awl
+*/
+class PdoDialect {
+ /**#@+
+ * @access private
+ */
+
+ /**
+ * Holds the name of the database dialect
+ */
+ protected $dialect;
+
+ /**#@-*/
+
+
+ /**
+ * Parses the connection string to ascertain the database dialect. Returns true if the dialect is supported
+ * and fails if the dialect is not supported. All code to support any given database should be within in an
+ * external include.
+ * @param string $connection_string The full PDO connection string
+ */
+ function __construct( $connection_string ) {
+ if ( preg_match( '/^(pgsql):/', $connection_string, $matches ) ) {
+ $this->dialect = $matches[1];
+ }
+ else {
+ trigger_error("Unsupported database connection '".$connection_string."'", E_USER_ERROR);
+ }
+ }
+
+
+
+ /**
+ * Returns the SQL for the current database dialect which will return a two-column resultset containing a
+ * list of fields and their associated data types.
+ * @param string $tablename_string The name of the table we want fields from
+ */
+ function GetFields( $tablename_string ) {
+ if ( !isset($this->dialect) ) {
+ trigger_error("Unsupported database dialect", E_USER_ERROR);
+ }
+
+ switch ( $this->dialect ) {
+ case 'pgsql':
+ $tablename_string = $this->Quote($tablename_string, 'identifier');
+ $sql = "SELECT f.attname, t.typname FROM pg_attribute f ";
+ $sql .= "JOIN pg_class c ON ( f.attrelid = c.oid ) ";
+ $sql .= "JOIN pg_type t ON ( f.atttypid = t.oid ) ";
+ $sql .= "WHERE relname = $tablename_string AND attnum >= 0 order by f.attnum;";
+ return $sql;
+ }
+ }
+
+
+ /**
+ * Translates the given SQL string into a form that will hopefully work for this database dialect. This hook
+ * is expected to be used by developers to provide support for differences in database operation by translating
+ * the query string in an arbitrary way, such as through a file or database lookup.
+ *
+ * The actual translation to other SQL dialects will usually be application-specific, so that any routines
+ * called by this will usually be external to this library, or will use resources external to this library.
+ */
+ function Translate( $sql_string ) {
+ // Noop for the time being...
+ return $sql_string;
+ }
+
+
+
+ /**
+ * Returns $value escaped in an appropriate way for this database dialect.
+ * @param mixed $value The value to be escaped
+ * @param string $value_type The type of escaping desired. If blank this will be worked out from gettype($value). The special
+ * type of 'identifier' can also be used for escaping of SQL identifiers.
+ */
+ function Quote( $value, $value_type = null ) {
+
+ if ( !isset($value_type) ) {
+ $value_type = gettype($value);
+ }
+
+ switch ( $this->dialect ) {
+ case 'pgsql':
+ switch ( $value_type ) {
+ case 'identifier': // special case will only happen if it is passed in.
+ $rv = '"' . str_replace('"', '\\"', $value ) . '"';
+ break;
+ case 'null':
+ $rv = 'NULL';
+ break;
+ case 'integer':
+ case 'double' :
+ return $str;
+ case 'boolean':
+ $rv = $str ? 'TRUE' : 'FALSE';
+ break;
+ case 'string':
+ default:
+ $str = str_replace("'", "''", $str);
+ //PostgreSQL treats a backslash as an escape character.
+ $str = str_replace('\\', '\\\\', $str);
+ $rv = "E'$str'";
+ }
+ break;
+ }
+
+ return $rv;
+
+ }
+
+}
+
+
+/**
+* A variable of this class is normally constructed through a call to PdoDatabase::Query or PdoDatabase::Prepare,
+* associating it on construction with the database which is to be queried.
+* @package awl
+*/
+class PdoQuery {
+
+ /**
+ * Where $db is a PdoDatabase object. This constructs the PdoQuery. If there are further parameters they
+ * will be in turn, the sql, and any positional parameters to replace into that, and will be passed to
+ * $this->Query() before returning.
+ */
+ function __construct( $db, ... ) {
+ }
+
+
+ /**
+ * If the sql is supplied then PDO::prepare will be called with that SQL to prepare the query, and if there
+ * are positional parameters then they will be replaced into the sql_string (with appropriate escaping)
+ * before the call to PDO::prepare.
+ */
+ function Query( $sql_string, ... ) {
+ }
+
+
+ /**
+ * If there are (some) positional parameters in the prepared query, now is the last chance to supply them...
+ * before the query is executed. Returns true on success and false on error.
+ */
+ function Exec( ... ) {
+ }
+
+
+ /**
+ * Will fetch the next row from the query into an object with elements named for the fields in the result.
+ */
+ function Fetch() {
+ }
+
+
+ /**
+ * Will fetch the next row from the query into an array of fields.
+ */
+ function FetchArray() {
+ }
+
+
+ /**
+ * Will fetch all result rows from the query into an array of objects with elements named for the fields in the result.
+ */
+ function FetchAll() {
+ }
+
+
+ /**
+ * An accessor for the number of rows affected when the query was executed.
+ */
+ function Rows() {
+ }
+
+
+ /**
+ * Used to set the maximum duration for this query before it will be logged as a slow query.
+ */
+ function MaxDuration( $seconds_double ) {
+ }
+
+}
+
+
+
+/**
+* Typically there will only be a single instance of the database level class in an application.
+* @package awl
+*/
+class PdoDatabase {
+ /**#@+
+ * @access private
+ */
+
+ /**
+ * Holds the PDO database connection
+ */
+ private $db;
+
+ /**
+ * Holds the dialect object
+ */
+ private $dialect;
+
+ /**
+ * Holds the state of the transaction 0 = not started, 1 = in progress, -1 = error pending rollback/commit
+ */
+ protected $txnstate = 0;
+
+ /**
+ * Holds the count of queries executed so far
+ */
+ protected $querycount = 0;
+
+ /**
+ * Holds the total duration of queries executed so far
+ */
+ protected $querytime = 0;
+
+ /**#@-*/
+
+ /**
+ * The connection string is in the standard PDO format. The database won't actually be connected until the first
+ * database query is run against it.
+ *
+ * The database object will also initialise and hold an PdoDialect object which will be used to provide database
+ * specific SQL for some queries, as well as translation hooks for instances where it is necessary to modify the
+ * SQL in transit to support additional databases.
+ * @param string $connection_string The PDO connection string, in all it's glory
+ * @param string $dbuser The database username to connect as
+ * @param string $dbpass The database password to connect with
+ * @param array $options An array of driver options
+ */
+ function __construct( $connection_string, $dbuser=null, $dbpass=null, $options=null ) {
+ $this->dialect = new PdoDialect( $connection_string );
+ $this->db = new PDO( $connection_string, $dbuser, $dbpass, $options );
+ }
+
+
+ /**
+ * Returns a PdoQuery object created using this database, the supplied SQL string, and any parameters given.
+ */
+ function Prepare( $sql_string, ... ) {
+ }
+
+
+ /**
+ * Construct and execute an SQL statement from the sql_string, replacing the parameters into it. Returns true on
+ * success and false on error.
+ *
+ * While this uses a PdoQuery internally, this is not exposed. It is intended for use with queries which are not
+ * needed after execution to know how many rows are affected, or to be able to process a result set.
+ */
+ function Exec( $sql_string, ... ) {
+ }
+
+
+ /**
+ * Begin a transaction.
+ */
+ function Begin() {
+ }
+
+
+ /**
+ * Complete a transaction.
+ */
+ function Commit() {
+ }
+
+
+ /**
+ * Cancel a transaction in progress.
+ */
+ function Rollback() {
+ }
+
+
+ /**
+ * Returns the current state of a transaction, indicating if we have begun a transaction, whether the transaction
+ * has failed, or if we are not in a transaction.
+ */
+ function TransactionState() {
+ }
+
+
+ /**
+ * Returns the total duration of quries executed so far by this object instance.
+ */
+ function TotalDuration() {
+ }
+
+
+ /**
+ * Returns the total number of quries executed by this object instance.
+ */
+ function TotalQueries() {
+ }
+
+
+ /**
+ * Returns an associative array of field types, keyed by field name, for the requested named table. Internally this
+ * calls PdoDialect::GetFields to get the required SQL and then processes the query in the normal manner.
+ */
+ function GetFields( $tablename_string ) {
+ }
+
+
+ /**
+ * Operates identically to PdoDatabase::Prepare, except that PdoDialect::Translate() will be called on the query
+ * before any processing.
+ */
+ function PrepareTranslated() {
+ }
+
+
+ /**
+ * Switches on or off the processing flag controlling whether subsequent calls to PdoDatabase::Prepare are translated
+ * as if PrepareTranslated() had been called.
+ */
+ function TranslateAll( $onoff_boolean ) {
+ }
+
+}
+