| # simpledb.tcl -- provides a simple tcl database. |
| |
| # Copyright 2003-2004 The Apache Software Foundation |
| |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| # $Id$ |
| |
| package provide simpledb 0.1 |
| |
| namespace eval ::simpledb { |
| set oid 0 |
| } |
| |
| # simpledb::createtable -- |
| # |
| # Creates a table and its associated columns. |
| # |
| # Arguments: |
| # table - name of the table. |
| # args - column names. |
| # |
| # Side Effects: |
| # Creates internal namespace and arrays. |
| # |
| # Results: |
| # None. |
| |
| proc simpledb::createtable { table args } { |
| namespace eval $table {} |
| array set ${table}::cols {} |
| # Currently active oids. |
| array set ${table}::goodoids {} |
| |
| foreach col $args { |
| # Each key gets its own namespace. |
| namespace eval ${table}::${col} {} |
| # In that namespace we have an array that maps oids->data. |
| array set ${table}::${col}::data {} |
| # And an array that maps data->oids. |
| array set ${table}::${col}::values {} |
| set ${table}::cols($col) 1 |
| } |
| } |
| |
| |
| # simpledb::deltable -- |
| # |
| # Delete table. |
| # |
| # Arguments: |
| # table - table to delete. |
| # |
| # Side Effects: |
| # Deletes table namespace. |
| # |
| # Results: |
| # None. |
| |
| proc simpledb::deltable { table } { |
| namespace delete $table |
| } |
| |
| |
| # simpledb::tables -- |
| # |
| # Return a list of all tables. |
| # |
| # Arguments: |
| # None. |
| # |
| # Side Effects: |
| # None. |
| # |
| # Results: |
| # A list of all tables that exist in the database. |
| |
| proc simpledb::tables {} { |
| set res {} |
| foreach ns [namespace children [namespace current]] { |
| lappend res [namespace tail $ns] |
| } |
| return $res |
| } |
| |
| |
| # simpledb::createitem -- |
| # |
| # Create an item in the table. |
| # |
| # Arguments: |
| # table - table name. |
| # properties - a list of keys and their corresponding values. |
| # Keys must correspond to those listed in 'createtable'. |
| # |
| # Side Effects: |
| # Creates a new table item. |
| # |
| # Results: |
| # None. |
| |
| proc simpledb::createitem { table properties } { |
| variable oid |
| incr oid |
| set ${table}::goodoids($oid) 1 |
| foreach {col data} $properties { |
| set ${table}::${col}::data($oid) $data |
| lappend ${table}::${col}::values($data) $oid |
| } |
| return $oid |
| } |
| |
| # simpledb::getitem -- |
| # |
| # Fetches an item from the database based on its oid. |
| # |
| # Arguments: |
| # table - table name. |
| # oid - identity of the item to fetch. |
| # |
| # Side Effects: |
| # None. |
| # |
| # Results: |
| # Returns information as a list suitable to pass to 'array set'. |
| |
| proc simpledb::getitem { table oid } { |
| foreach col [array names ${table}::cols] { |
| lappend res $col [set ${table}::${col}::data($oid)] |
| } |
| return $res |
| } |
| |
| |
| # simpledb::setitem -- |
| # |
| # Set the values of given keys. |
| # |
| # Arguments: |
| # table - table name. |
| # oid - item's unique id. |
| # properties - list of keys and values. |
| # |
| # Side Effects: |
| # The old value of the item is lost. |
| # |
| # Results: |
| # None. |
| |
| proc simpledb::setitem { table oid properties } { |
| upvar $properties props |
| foreach {col data} $properties { |
| if { [info exists ${table}::${col}::data($oid)] } { |
| set oldval [set ${table}::${col}::data($oid)] |
| set item [lsearch [set ${table}::${col}::values($oldval)] $oid] |
| if { $item >= 0 } { |
| set ${table}::${col}::values($oldval) \ |
| [lreplace ${table}::${col}::values($oldval) $item $item] |
| } |
| if { [llength [set ${table}::${col}::values($oldval)]] == 0 } { |
| unset ${table}::${col}::values($oldval) |
| } |
| } |
| |
| set ${table}::${col}::data($oid) $data |
| lappend ${table}::${col}::values($data) $oid |
| } |
| return $oid |
| } |
| |
| |
| # simpledb::delitem -- |
| # |
| # Delete an item from the database. This is slow because of the |
| # lsearch. |
| # |
| # Arguments: |
| # table - table name. |
| # oid - object's unique id. |
| # |
| # Side Effects: |
| # Deletes item from the database. |
| # |
| # Results: |
| # None. |
| |
| proc simpledb::delitem { table oid properties } { |
| upvar $properties props |
| |
| foreach col [array names ${table}::cols] { |
| unset ${table}::${col}::data($oid) |
| set item [lsearch ${table}::${col}::values($props($col)) $oid] |
| set ${table}::${col}::values($props($col)) \ |
| [lreplace ${table}::${col}::values($props($col)) $item $item] |
| } |
| unset ${table}::goodoids($oid) |
| return $oid |
| } |
| |
| |
| # simpledb::finditems -- |
| # |
| # Find items that match the given "properties" - a list of keys |
| # and the sought values. Glob patterns are accepted as |
| # 'values'. |
| # |
| # Arguments: |
| # table - table name. |
| # propertymatch - list of keys and values to search on. |
| # |
| # Side Effects: |
| # None. |
| # |
| # Results: |
| # A list of the id's of matching item. |
| |
| proc simpledb::finditems { table propertymatch } { |
| array set res {} |
| foreach {col value} $propertymatch { |
| foreach {value oids} [array get ${table}::${col}::values $value] { |
| foreach oid $oids { |
| if { [info exists res($oid)] } { |
| incr res($oid) |
| } else { |
| set res($oid) 1 |
| } |
| } |
| } |
| } |
| set retlist {} |
| foreach {oid num} [array get res] { |
| if { $res($oid) == [llength $propertymatch] / 2 } { |
| lappend retlist $oid |
| } |
| } |
| return $retlist |
| } |
| |
| |
| # simpledb::items -- |
| # |
| # Fetch all the items from a particular table. |
| # |
| # Arguments: |
| # table. |
| # |
| # Side Effects: |
| # None. |
| # |
| # Results: |
| # A list of lists, with the sublists being key/value lists of |
| # column names and their value for the oid in question. |
| |
| proc simpledb::items {table} { |
| set reslist {} |
| set collist [array names ${table}::cols] |
| foreach oid [array names ${table}::goodoids] { |
| set oidlist {} |
| foreach col $collist { |
| if { [info exists ${table}::${col}::data($oid)] } { |
| lappend oidlist $col [set ${table}::${col}::data($oid)] |
| } |
| } |
| lappend reslist $oidlist |
| } |
| |
| return $reslist |
| } |
| |
| |
| # simpledb::synctostorage -- |
| # |
| # Writes the database to a file. The storage format, for the |
| # moment is Tcl code, which isn't space efficient, but is easy |
| # to reload. |
| # |
| # Arguments: |
| # savefile - file to save database in. |
| # |
| # Side Effects: |
| # None. |
| # |
| # Results: |
| # None. |
| |
| proc simpledb::synctostorage {savefile} { |
| set fl [open $savefile w] |
| foreach ns [namespace children] { |
| # Let's store the goodoids array. |
| set collist [array names ${ns}::cols] |
| puts $fl "namespace eval $ns \{" |
| puts $fl " array set cols \{ [array get ${ns}::cols] \}" |
| puts $fl " array set goodoids \{ [array get ${ns}::goodoids] \}" |
| foreach col $collist { |
| puts $fl " namespace eval ${col} \{" |
| puts $fl " array set data [list [array get ${ns}::${col}::data]]" |
| puts $fl " array set values [list [array get ${ns}::${col}::values]]" |
| puts $fl " \}" |
| } |
| puts $fl "\}" |
| } |
| close $fl |
| } |
| |
| |
| # simpledb::syncfromstorage -- |
| # |
| # Reloads database from file. |
| # |
| # Arguments: |
| # savefile - file to read. |
| # |
| # Side Effects: |
| # Creates database. |
| # |
| # Results: |
| # None. |
| |
| proc simpledb::syncfromstorage {savefile} { |
| source $savefile |
| } |
| |