Posted to tcl by colin at Tue Jan 31 01:52:47 GMT 2012view pretty

oo::class create ::tdbc::skeleton::resultset {
    # columns - a list of the names of the columns in the result.
    method columns {} {
    }

    # nextdict variableName - store the next row of the result set in the given variable
    #        in caller's scope, in the form of a dictionary that maps column names to values.
    method nextdict {variableName} {
    }

    # nextlist variableName - store the next row of the result set in the given variable
    #        in caller's scope, in the form of a list of cells.
    method nextlist {variableName} {
    }

    # rowcount - count of rows affected by the statement,
    # or -1 if the count of rows has not been determined.
    method rowcount {} {
    }

    superclass tdbc::resultset
    constructor {statement args} {
	# Constructor accepts a statement and an optional dictionary of substituted parameters
	# execute the statement against the database.
	# If the dictionary is not supplied, then the default is to get params
	# from variables in the caller's scope).
	next
	if {[llength $args] == 1} {
	    set args [lindex $args 0]
	}
	uplevel 1 [list {*}[namespace code {my init}] $statement {*}$args]
    }
}

oo::class create tdbc::skeleton::statement {
    method params {} {
	# return a description of the names and expected data types of the parameters of [self]
	# MUST be a dictionary whose keys are the names of the parameters, values dictionaries.
	# The keys of the subdictionaries MUST include:
	# name: 
	# type: 
	# precision: 
	# scale: 
	# nullable: 
	# direction: {in out inout}
	variable params
	set result $params
	foreach {n v} $result {
	    if {![llength $v]} {
		# there is no value for this parameter - calculate it
	    }
	}
	return $result
    }

    method paramtype {name args} {
	set args [lassign $args type]
	if {$type in {in out inout}} {
	    set direction $type
	    set args [lassign [$args type]]
	} else {
	    set direction inout
	}

	if {$type ni {bigint binary bit char date
	    decimal double float integer
	    longvarbinary longvarchar numeric real
	    time timestamp smallint tinyint varbinary varchar}} {
	    error "$type invalid"
	}
	set precision 0; set scale 0
	lassign $args precision scale
	# now do something with name, type, direction, precision and scale
	# Implementors of database APIs SHOULD make every effort to do appropriate type introspection
	# so that programmers can avoid needing to include explicit type information in their SQL statements.
    }

    superclass tdbc::statement
    constructor {connection sqlcode args} {
	next

	if {[llength $args] == 1} {
	    set args [lindex $args 0]
	}

	variable params {}
	variable sql $sqlcode
	foreach token [::tdbc::tokenize $sqlcode] {
	    if {[string index $token 0] in {$ : @}} {
		dict set params [string range $token 1 end] {}
	    }
	}
    }
}

oo::class create tdbc::skeleton {
    # Transactions
    method starttransaction {} {
	# Begins an atomic transaction on the database.
	# If the underlying database does not implement atomic transactions or rollback,
	# the starttransaction subcommand MUST throw an error reporting the fact.

	# If the underlying database does not implement nested transactions,
	# a starttransaction command that is executed when there is a transaction already in progress
	# (started, but neither committed nor rolled back) MUST result in an error.
	error "[info object class [self]] does not support transactions"
    }
    method commit {} {
	# Commits a transaction to the database, making the changes durable.
    }
    method rollback {} {
	# Rolls back a transaction against the database, cancelling any changes made during the transaction.
    }

    # Statements

    method preparecall {call} {
	# Some database interfaces have a different API to stored procedures than to ordinary SQL statements.
	# These databases may need a separate type of statement object from the one that implements ordinary 
	# statements. 
	# This object can be managed as a statement owned by the connection by using the preparecall method
    }

    method statementCreate {name self sqlcode} {
	tdbc::skeleton::statement create $name [self] $sqlcode
    }

    # Structure and Configuration

    method configure {args} {
	# args are of the form -option value ....
	# -encoding name
	# -isolation {readuncommitted readcommitted repeatableread serializable readonly}
	# -timeout ms
	# -readonly boolean
    }

    destructor {
	# dismiss the connection to the database and clean up associated system resources
	# If there is an uncommitted transaction, it SHOULD be rolled back.
	# Any handles to other objects associated with the database SHOULD become invalid.
    }

    superclass tdbc::connection
    constructor {args} {
	next

	# perform connection and configuration
    }
}