Hierarchy Queries
Creating a Transitive Closure to Optimize Rollups
Data Warehouse Extract Transform and Load (ETL) processing requires loading hierarchy descriptions. These include chart-of-accounts (COA), organization, geography as examples. These hierarchies are not easily dictated like a time hierarchy; these are discovered from hierarchies in other reporting applications.
A hierarchy is a transitive relationship between a parent and a number of children. In a relational database this is most often modeled as children with a foreign key references to their common parent.
If this transitive relationship is of arbitrary depth, it is notoriously difficult to process in SQL. Each query requires an arbitrary number of joins to locate all parents of a child or all children of a parent. The usual work-around is to limit the depth (for example to 8 levels); this limits the queries to at most 8 joins.
Another common solution is to create a "transitive closure". This "closes" or pre-joins all levels of the hierarchy, creating all possible paths. This transitive closure can be used for all queries using a single SELECT to find all parents of a child or all children of a parent. We will assign "subtree range numbers" to each node during the transitive closure. These subtree range numbers are based on the Heap data structure described in the Cormen/Leiserson/Rivest/Stein: Introduction to Algorithms.
The only constraint on the transitive closure is that it is kept in synchronization with the actual parent-child relationships. When a hierarchy is changed, the transitive closure must be recomputed.
This document presents overall requirements, design of the transitive closure algorith, and the implementation of both transitive closure and the data generator.
This demonstration creates a transitive closure on hierarchical data kept in a relational database. The parent-child table is scanned to create the transitive closure in a separate table.
Proper subtree range numbers have the following properties. Assume a three level tree of g, p1, p2, and c1a, c1b. Each node has two attributes, l and h.
The tree has the following form.
g
/ \
p1 p2
/ \
c1a c1b
The following strict ordering applies among the subtree numbers:
g.l <= p1.l <= c1a.l <= c1a.h < c1b.l <= c1b.h <= p1.h < p2.l <= p2.h <= g.h
The parent-child relationship can be summarized as p.l <= all children <= p.h.
This leads to very simple queries for locating parents or children:
By adding an additional attribute of level number, we can locate the immediate parent or child of a node, using the relationship parent.level+1 = child.level. Given the immediate parent, we can locate siblings (all nodes of our level that share our immediate parent).
Two separate programs are defined. One creates the database and then loads a hierarchy into the pc table. For a quick supply of sample data, a file directory structure is scanned to load a hierarchy. The other program scans the parent-child table and creates the transitive closure.
The essence of transitive closure is a traversal of the parent-child tree. This can be based on the Visitor design pattern. The Visitor patterns suggests that we design a class to contain the structure being visited and a separate family of related classes for the operations that will be performed on the various elements of this structure.
The structure that will be visited is the parent-child hierarchy represented in the relational database. We define a TreeTable class to contain the basic operations for working with this structure. This class also provides the basic visit methods. The are a variety of alternative orderings to the elements of a structure. In our case, we are interested in traversal that visits each parent node before visiting all the children and after visiting all the children. This could be called a pre-and-post-order depth-first traversal.
There are a wide variety of possible operations that can be performed when traversing the hierarchy. We will focus on two: reporting and assigning subtree range numbers. The reporting operation simply prints each node in the hierarchy. The assignment of subtree range numbers is done by saving the first number on descending to a child node, and the last number on ascending from a child node. This is used to set the number of a parent node.
A simple extension allows selective renumbering of a portion of a tree. This must be done after an insert; it can be done to balance numbers after a delete. The procedure is as follows.
The main program can have the following general form.
f= TreeTable("hier_db")
s= SetNumbers(5)
f.prep(s)
f.visit(s)
f.finish(s)
A TreeTable instance, f includes a database connection to the named database. A SetNumbers visitor instance, s is used to assign subtree numbers. The prep method clears the transitive closure result table. The visit step applies the visitor, s, to each node in the tree. The finish step commits the result.
This quick and dirty demonstration was implemented as two Python programs: hierarchyDB.py and transclose.py.
The hierarchyDB.py program creates test data. It defines the SampleDB class which contains methods to create and load a database. The main driver uses an instance of this class to create and load the database.
This program has the following structure.
"hierarchyDB.py" (1) =
→DB Shell Escape (4)
→DB DOC String (2)
→DB CVS Cruft and pyweb generator warning (5)
→DB Imports (3)
→DB SampleDB class defines methods to create and load a database (6)
→DB Main Driver to create and load our test database (7)
◊ "hierarchyDB.py" (1).
Overheads includes the following: the shell escape, the doc string, any CVS cruft, and the imports.
The doc string identifies the module source.
DB DOC String (2) =
"""HierarchyDB.py
Create a hierarchy database by traversing a directory tree.
"""
◊ DB DOC String (2). Used by hierarchyDB.py (1) .
The following imports are used by this module. The os module provides information on a directory tree, used to populate the database. The time module is used to decode the time stamps on each file. The pprint module is used to create nice listings of complex Python data structures. The gadfly module provides a simple relational database.
DB Imports (3) =
import sys, os, time, pprint
import gadfly
◊ DB Imports (3). Used by hierarchyDB.py (1) .
DB Shell Escape (4) =
#!/usr/local/bin/python
◊ DB Shell Escape (4). Used by hierarchyDB.py (1) .
DB CVS Cruft and pyweb generator warning (5) =
__version__ = """$Revision$"""
### DO NOT EDIT THIS FILE!
### It was created by /usr/local/bin/pyweb.py, __version__='$Revision$'.
### From source transclose.w modified Sat Mar 15 16:16:25 2003.
### In working directory '/Users/slott/Documents/Projects/transclose'.
◊ DB CVS Cruft and pyweb generator warning (5). Used by hierarchyDB.py (1) .
The SampleDB class performs all of the processing to create and populate a database. This class has the following instance variables and methods.
DB SampleDB class defines methods to create and load a database (6) =
class SampleDB:
"""Manage a simple database for transitive closure demonstration."""
def __init__( self, name_=r".\hierarchy" ):
self.dbDir, self.dbName= os.path.split(name_)
self.connection= None
self.sequence= 0
def execute( self, statement ):
"""Execute a simple non-query statement."""
cursor= self.connection.cursor()
cursor.execute( statement )
cursor.close()
def query( self, statement ):
"""Execute a simple query."""
cursor= self.connection.cursor()
cursor.execute( statement )
print cursor.pp()
cursor.close()
def create( self ):
"""Create the database and schema."""
self.connection= gadfly.gadfly()
self.connection.startup( self.dbName, self.dbDir )
self.execute( "CREATE TABLE pc( key integer, dirName varchar, fileName varchar, mtime varchar, size integer )" )
self.execute( "CREATE TABLE trans( key integer, level integer, low integer, high integer )" )
self.connection.commit()
self.query( "select * from __table_names__ where is_view = 0" )
self.connection.close()
print "Create Complete",self.dbName
def load( self, fromDirectory ):
"""Load the parent-child tree into the pc table."""
self.connection= gadfly.gadfly( self.dbName, self.dbDir )
# traverse a directory tree to create some sample data
os.path.walk( fromDirectory, SampleDB.visit, self )
self.connection.commit()
self.query( "select * from pc" )
self.connection.commit()
self.connection.close()
print "Load Complete",self.dbName
def visit( self, dirname, names ):
"""A quick hack that would fail if a directory name matched a file name."""
#print dirname
#pprint.pprint( names )
path,base=os.path.split(dirname)
for f in names:
mtime= time.asctime( time.localtime( os.path.getmtime( os.path.join(dirname,f) ) ) )
size= os.path.getsize( os.path.join(dirname,f) )
self.sequence += 1
# A quick hack to exclude file names that have quotes.
if "'" not in base and "'" not in f:
self.execute( "insert into pc(key,dirName,fileName,mtime,size) values(%s,'%s','%s','%s',%s)"%(self.sequence,base,f,mtime,size) )
◊ DB SampleDB class defines methods to create and load a database (6). Used by hierarchyDB.py (1) .
Note that there is a subtle bug in database design and the load method. This design has a file using the parent directory's name as the foreign key. It should use the assigned surrogate key instead. File and directory names are not guaranteed to be unique, and the surrogate key is essential to correctly constructing a tree representing directories.
The main driver creates a database and loads it. It sets s to an instance of SampleDB. It then invokes the create method to create a new, empty database. It invokes the load method to populate this database using the L: drive or ~/Documents directory structure.
DB Main Driver to create and load our test database (7) =
def main():
s= SampleDB("hier_db")
s.create()
rootDirectory= "/Users/slott/Documents/projects/transclose"
if sys.platform.startswith("win"):
rootDirectory= r"L:\\"
s.load(rootDirectory)
if __name__ == "__main__":
main()
◊ DB Main Driver to create and load our test database (7). Used by hierarchyDB.py (1) .
The transclose.py program demonstrates the transitive closure algorithm. This program defines the basic TreeTable class that manages a parent-child tree structure in a relational table. The program also defines a Visitor class hierarchy that can be used to construct a transitive closure of a tree structure, assigning subtree numbers to speed up processing.
This program has the following structure.
"transclose.py" (8) =
→TC Shell Escape (11)
→TC DOC String (9)
→TC CVS Cruft and pyweb generator warning (12)
→TC Imports (10)
→TC Visitor base class definition (13)
→TC TreeTable class to process a parent-child relationship table (14)
→TC ShowDirectory subclass of Visitor to report on a structure (16)
→TC SetNumbers subclass of Visitor to assign numbers (17)
→TC Main Driver (18)
◊ "transclose.py" (8).
TC DOC String (9) =
"""Transitive Closure Demo.
This application does a transitive closure on a hierarchy.
This will do a depth-first traversal of the data, assigning node numbers in such
a way that for a given node, n, the following are true.
If c is a child of n, then n.low <= c.low <= c.high <= n.high.
If p is a parent of n, then p.low <= n.low <= n.high <= p.high.
This allows simple SQL queries to locate all children or all parents of a given node.
>
"""
◊ TC DOC String (9). Used by transclose.py (8) .
The following imports are used by this module. The os module is used to separate the database name into path and filename components. The gadfly module provides a simple relational database.
TC Imports (10) =
import os
import gadfly
◊ TC Imports (10). Used by transclose.py (8) .
TC Shell Escape (11) =
#!/usr/local/bin/python
◊ TC Shell Escape (11). Used by transclose.py (8) .
TC CVS Cruft and pyweb generator warning (12) =
__version__ = """$Revision$"""
### DO NOT EDIT THIS FILE!
### It was created by /usr/local/bin/pyweb.py, __version__='$Revision$'.
### From source transclose.w modified Sat Mar 15 16:16:25 2003.
### In working directory '/Users/slott/Documents/Projects/transclose'.
◊ TC CVS Cruft and pyweb generator warning (12). Used by transclose.py (8) .
The Visitor base class provides the superclass for all TreeTable visitors.
This class has the following instance variables.
TC Visitor base class definition (13) =
class Visitor:
def __init__( self, step=1 ):
self.step= step
self.count= 0
self.stack= [0]
def prep( self, connection ):
"""Override this to prepare for visiting."""
pass
def finish( self, connection ):
"""Override this to finalize after visiting."""
pass
def depth( self ):
return len(self.stack)
def start( self ):
return self.stack[-1]
def end( self ):
return self.count+self.step # leave a gap after my last child
def leaf( self, *args ):
self.count += self.step
def enter( self, *args ):
self.count += self.step # me
self.stack.append( self.count+self.step ) # my first child
return 1 # to descend
def exit( self, *args ):
self.count += self.step
self.stack.pop()
◊ TC Visitor base class definition (13). Used by transclose.py (8) .
The TreeTable class defines several functions for working with a tree defined in a relational table.
Additionally, there are reporting methods, shown below, that show typical queries based on the transitive closure information built by the SetNumbers visitor.
TC TreeTable class to process a parent-child relationship table (14) =
class TreeTable:
def __init__( self, name_=r".\hierarchy" ):
self.dbDir, self.dbName= os.path.split(name_)
self.connection= gadfly.gadfly( self.dbName, self.dbDir )
def hasChildren( self, fromDir="" ):
c= self.connection.cursor()
c.execute( "SELECT count(*) FROM pc WHERE dirName='%s'" % fromDir )
r= c.fetchone()[0]
c.close()
return r
def prep( self, visitor ):
visitor.prep( self.connection )
def finish( self, visitor ):
visitor.finish( self.connection )
def visit( self, visitor, fromDir="" ):
print "visiting",fromDir
c= self.connection.cursor()
c.execute( "SELECT key, fileName, mtime, size FROM pc WHERE dirName='%s' ORDER BY 2" % fromDir )
for row in c.fetchall():
key, fileName, mtime, size = row
if self.hasChildren(fileName):
filter= visitor.enter( self.connection, fromDir, key, fileName )
if filter:
self.visit( visitor, fileName )
visitor.exit( self.connection, fromDir, key, fileName )
else:
visitor.leaf( self.connection, fromDir, key, fileName, mtime, size )
c.close()
→TC Queries using the transitive closure information (15)
◊ TC TreeTable class to process a parent-child relationship table (14). Used by transclose.py (8) .
TC Queries using the transitive closure information (15) =
def targets( self, aName ):
sqlTarget= """
SELECT trans.low, trans.high
FROM pc, trans
WHERE fileName='%s' AND pc.key = trans.key"""
tgt= self.connection.cursor()
tgt.execute( sqlTarget % aName )
return tgt.fetchall()
def parentsOf( self, aName ):
sqlParents= """
SELECT *
FROM pc, trans
WHERE %s BETWEEN trans.low AND trans.high
AND trans.low <> trans.high
AND pc.key = trans.key
ORDER BY level ASC"""
for f in self.targets(aName):
print aName, 'has path:'
par= self.connection.cursor()
par.execute( sqlParents % f[0] )
for p in par.fetchall():
print p
def childrenOf( self, aName ):
sqlChildren= """
SELECT *
FROM pc, trans
WHERE trans.low BETWEEN %s AND %s
AND pc.key = trans.key
ORDER BY level ASC"""
for f in self.targets(aName):
print aName, 'has children:'
par= self.connection.cursor()
par.execute( sqlChildren % f )
for p in par.fetchall():
print p
◊ TC Queries using the transitive closure information (15). Used by TC TreeTable class to process a parent-child relationship table (14) .
The ShowDirectory class overrides functions in the Visitor base class to write an indented report of the tree structure.
TC ShowDirectory subclass of Visitor to report on a structure (16) =
class ShowDirectory( Visitor ):
def enter( self, connection, parent, key, child ):
Visitor.enter( self )
print self.depth()*' ', child, self.count
return 1
def exit( self, connection, parent, key, child ):
print self.depth()*' ', child, self.start(), self.end()
Visitor.exit( self )
def leaf( self, connection, parent, key, child, mtime, size ):
Visitor.leaf( self )
print self.depth()*' ', child, self.count, size, mtime
◊ TC ShowDirectory subclass of Visitor to report on a structure (16). Used by transclose.py (8) .
The SetNumbers class overrides functions in the Visitor base class to assign subtree range numbers to the tree structure.
TC SetNumbers subclass of Visitor to assign numbers (17) =
class SetNumbers( Visitor ):
def exit( self, connection, parent, key, child ):
c= connection.cursor()
c.execute( "INSERT INTO trans(key,level,low,high) values (%s,%s,%s,%s)"%(key,self.depth(),self.start(),self.end()) )
c.close()
Visitor.exit( self )
def leaf( self, connection, parent, key, child, mtime, size ):
Visitor.leaf( self )
c= connection.cursor()
c.execute( "INSERT INTO trans(key,level,low,high) values (%s,%s,%s,%s)"%(key,self.depth(),self.count,self.count) )
c.close()
def prep( self, connection ):
c= connection.cursor()
c.execute( "delete from trans" )
c.close()
connection.commit()
def finish( self, connection ):
connection.commit()
cursor= connection.cursor()
cursor.execute( "select * from trans" )
print cursor.pp()
cursor.close()
◊ TC SetNumbers subclass of Visitor to assign numbers (17). Used by transclose.py (8) .
The main driver is broken into two functions. The main function assigns numbers to the tree. The report function uses the assigned subtree numbers to report on selected elements of the tree.
The main function creates a TreeTable instance, f. It also creates a SetNumbers visitor, s, which populates the trans table with the transitive closure of the tree in the tree table. The basic visit procedure is to call the TreeTable's prep, visit and finish for the given visitor.
The report function creates a TreeTable instance, f. It requests the parents of "__init__.py"; this file occurs several times, with separate different lists of parents. It requests the children of "test".
TC Main Driver (18) =
def main():
f= TreeTable("./hier_db")
print "directory tree"
s= SetNumbers(5)
f.prep(s)
f.visit(s,"transclose")
f.finish(s)
def report():
f= TreeTable("./hier_db")
print "reports"
f.parentsOf( "__init__.py" )
f.childrenOf( "test" )
if __name__ == "__main__":
main()
report()
◊ TC Main Driver (18). Used by transclose.py (8) .
IS_VIEW | TABLE_NAME
====================
0 | TRANS
0 | PC
Create Complete hier_db
FILENAME | KEY | MTIME | SIZE | DIRNAME
==============================================================================
.DS_Store | 1 | Sat Mar 15 14:47:03 2003 | 6148 | transclose
gadfly-1.0.0 | 2 | Sat Mar 15 14:34:49 2003 | 432 | transclose
gadfly-1.0.0.tar.gz | 3 | Sat Mar 15 14:27:26 2003 | 309201 | transclose
generate.sh | 4 | Sat Mar 15 14:16:11 2003 | 173 | transclose
hier_db.gfd | 5 | Sat Mar 15 16:16:37 2003 | 654 | transclose
hierarchy.log | 6 | Sat Mar 15 16:16:36 2003 | 0 | transclose
hierarchyDB.py | 7 | Sat Mar 15 16:16:36 2003 | 3044 | transclose
PC.grl | 8 | Sat Mar 15 16:16:37 2003 | 93 | transclose
pyweb.css | 9 | Mon Jun 24 09:53:07 2002 | 1179 | transclose
TRANS.grl | 10 | Sat Mar 15 16:16:37 2003 | 76 | transclose
transclose.html | 11 | Sat Mar 15 16:11:59 2003 | 70039 | transclose
transclose.log | 12 | Sat Mar 15 16:11:58 2003 | 23261 | transclose
transclose.py | 13 | Sat Mar 15 16:16:36 2003 | 5808 | transclose
transclose.w | 14 | Sat Mar 15 16:16:25 2003 | 27259 | transclose
build | 15 | Sat Mar 15 14:34:49 2003 | 92 | gadfly-1.0.0
CHANGES.txt | 16 | Wed Jul 10 03:44:41 2002 | 1180 | gadfly-1.0.0
COPYRIGHT.txt | 17 | Mon May 6 03:31:09 2002 | 1422 | gadfly-1.0.0
doc | 18 | Wed Jul 10 03:45:39 2002 | 500 | gadfly-1.0.0
gadfly | 19 | Sat Mar 15 14:29:43 2003 | 1248 | gadfly-1.0.0
kjbuckets | 20 | Wed Jul 10 03:45:39 2002 | 194 | gadfly-1.0.0
PKG-INFO | 21 | Wed Jul 10 03:45:39 2002 | 250 | gadfly-1.0.0
README.txt | 22 | Mon May 6 18:31:31 2002 | 565 | gadfly-1.0.0
run_tests | 23 | Mon May 6 03:31:09 2002 | 299 | gadfly-1.0.0
setup.py | 24 | Wed Jul 10 03:42:09 2002 | 4748 | gadfly-1.0.0
test | 25 | Sat Mar 15 14:29:42 2003 | 398 | gadfly-1.0.0
TODO.txt | 26 | Thu May 16 01:20:35 2002 | 350 | gadfly-1.0.0
lib | 27 | Sat Mar 15 14:34:49 2003 | 58 | build
scripts | 28 | Sat Mar 15 14:34:49 2003 | 92 | build
gadfly | 29 | Sat Mar 15 14:34:49 2003 | 704 | lib
__init__.py | 30 | Fri May 10 22:59:04 2002 | 1238 | gadfly
bindings.py | 31 | Fri May 10 22:59:04 2002 | 13578 | gadfly
client.py | 32 | Sat May 11 08:17:42 2002 | 3239 | gadfly
database.py | 33 | Tue May 14 19:52:54 2002 | 15278 | gadfly
gfsocket.py | 34 | Sat May 11 09:28:35 2002 | 7814 | gadfly
grammar.py | 35 | Fri May 10 22:59:04 2002 | 12741 | gadfly
introspection.py | 36 | Fri May 10 22:59:04 2002 | 5670 | gadfly
kjbuckets0.py | 37 | Fri May 10 22:59:05 2002 | 28404 | gadfly
kjbuckets_select.py | 38 | Fri May 10 22:59:05 2002 | 769 | gadfly
kjParseBuild.py | 39 | Fri May 10 22:59:04 2002 | 46881 | gadfly
kjParser.py | 40 | Fri May 10 22:59:05 2002 | 49701 | gadfly
kjSet.py | 41 | Fri May 10 22:59:05 2002 | 7081 | gadfly
operations.py | 42 | Fri May 10 22:59:05 2002 | 23640 | gadfly
scripts | 43 | Sat Mar 15 14:34:49 2003 | 126 | gadfly
semantics.py | 44 | Fri May 10 22:59:05 2002 | 93686 | gadfly
serialize.py | 45 | Fri May 10 22:59:05 2002 | 2271 | gadfly
server.py | 46 | Sat May 11 07:41:22 2002 | 16156 | gadfly
sql.py | 47 | Fri May 10 22:59:05 2002 | 1396 | gadfly
sql_mar.py | 48 | Sat May 11 09:06:15 2002 | 55428 | gadfly
store.py | 49 | Fri May 10 22:59:05 2002 | 47643 | gadfly
__init__.py | 50 | Sat May 11 08:09:20 2002 | 0 | scripts
gfplus.py | 51 | Wed Jul 10 03:45:07 2002 | 9277 | scripts
gfserver.py | 52 | Sat May 11 09:28:35 2002 | 3417 | scripts
gfplus | 53 | Sat Mar 15 14:35:10 2003 | 71 | scripts
gfserver | 54 | Sat Mar 15 14:35:10 2003 | 73 | scripts
announcement.txt | 55 | Wed Jul 10 03:42:04 2002 | 1541 | doc
build_html.py | 56 | Tue May 7 21:39:11 2002 | 782 | doc
demo | 57 | Wed Jul 10 03:45:39 2002 | 92 | doc
faq.txt | 58 | Mon May 6 03:31:10 2002 | 19047 | doc
gadfly.txt | 59 | Mon May 6 19:27:09 2002 | 18838 | doc
gfplus.txt | 60 | Sat May 11 19:30:31 2002 | 2993 | doc
index.txt | 61 | Sat May 11 21:44:43 2002 | 3266 | doc
installation.txt | 62 | Wed Jul 10 03:32:06 2002 | 3173 | doc
kjbuckets.txt | 63 | Mon May 6 03:31:10 2002 | 29240 | doc
kwParsing.txt | 64 | Sat May 11 19:32:06 2002 | 41325 | doc
network.txt | 65 | Sun May 12 20:01:31 2002 | 10523 | doc
recover.txt | 66 | Mon May 6 03:31:10 2002 | 6083 | doc
sql.txt | 67 | Thu May 23 23:13:10 2002 | 9105 | doc
structure.txt | 68 | Mon May 6 03:31:10 2002 | 1881 | doc
kjbuckets | 69 | Wed Jul 10 03:45:39 2002 | 228 | demo
kjParsing | 70 | Wed Jul 10 03:45:39 2002 | 228 | demo
kjfactor.py | 71 | Mon May 6 03:31:10 2002 | 1550 | kjbuckets
kjtest.py | 72 | Tue May 7 21:39:13 2002 | 8265 | kjbuckets
relalg.py | 73 | Tue May 7 21:39:13 2002 | 5406 | kjbuckets
trigram.py | 74 | Tue May 7 21:39:13 2002 | 6603 | kjbuckets
tsort.py | 75 | Tue May 7 21:39:13 2002 | 1046 | kjbuckets
tsort2.py | 76 | Tue May 7 21:39:13 2002 | 1055 | kjbuckets
DLispShort.py | 77 | Tue May 7 21:39:11 2002 | 5055 | kjParsing
DumbLispGen.py | 78 | Tue May 7 21:39:11 2002 | 6952 | kjParsing
idl.py | 79 | Tue May 7 21:39:11 2002 | 12241 | kjParsing
pygram.py | 80 | Tue May 7 21:39:12 2002 | 32779 | kjParsing
pylint.py | 81 | Tue May 7 21:39:12 2002 | 15651 | kjParsing
relalg.py | 82 | Tue May 7 21:39:13 2002 | 12258 | kjParsing
__init__.py | 83 | Fri May 10 22:59:04 2002 | 1238 | gadfly
__init__.pyc | 84 | Sat Mar 15 14:29:41 2003 | 427 | gadfly
bindings.py | 85 | Fri May 10 22:59:04 2002 | 13578 | gadfly
bindings.pyc | 86 | Sat Mar 15 14:29:42 2003 | 29706 | gadfly
client.py | 87 | Sat May 11 08:17:42 2002 | 3239 | gadfly
database.py | 88 | Tue May 14 19:52:54 2002 | 15278 | gadfly
database.pyc | 89 | Sat Mar 15 14:29:41 2003 | 15609 | gadfly
gfsocket.py | 90 | Sat May 11 09:28:35 2002 | 7814 | gadfly
grammar.py | 91 | Fri May 10 22:59:04 2002 | 12741 | gadfly
grammar.pyc | 92 | Sat Mar 15 14:29:42 2003 | 12529 | gadfly
introspection.py | 93 | Fri May 10 22:59:04 2002 | 5670 | gadfly
introspection.pyc | 94 | Sat Mar 15 14:29:43 2003 | 8324 | gadfly
kjbuckets0.py | 95 | Fri May 10 22:59:05 2002 | 28404 | gadfly
kjbuckets0.pyc | 96 | Sat Mar 15 14:29:41 2003 | 36632 | gadfly
kjbuckets_select.py | 97 | Fri May 10 22:59:05 2002 | 769 | gadfly
kjbuckets_select.pyc | 98 | Sat Mar 15 14:29:41 2003 | 488 | gadfly
kjParseBuild.py | 99 | Fri May 10 22:59:04 2002 | 46881 | gadfly
kjParseBuild.pyc | 100 | Sat Mar 15 14:29:42 2003 | 43522 | gadfly
kjParser.py | 101 | Fri May 10 22:59:05 2002 | 49701 | gadfly
kjParser.pyc | 102 | Sat Mar 15 14:29:42 2003 | 50836 | gadfly
kjSet.py | 103 | Fri May 10 22:59:05 2002 | 7081 | gadfly
kjSet.pyc | 104 | Sat Mar 15 14:29:42 2003 | 8973 | gadfly
operations.py | 105 | Fri May 10 22:59:05 2002 | 23640 | gadfly
operations.pyc | 106 | Sat Mar 15 14:29:42 2003 | 30967 | gadfly
scripts | 107 | Wed Jul 10 03:45:39 2002 | 126 | gadfly
semantics.py | 108 | Fri May 10 22:59:05 2002 | 93686 | gadfly
semantics.pyc | 109 | Sat Mar 15 14:29:42 2003 | 119872 | gadfly
serialize.py | 110 | Fri May 10 22:59:05 2002 | 2271 | gadfly
serialize.pyc | 111 | Sat Mar 15 14:29:41 2003 | 1687 | gadfly
server.py | 112 | Sat May 11 07:41:22 2002 | 16156 | gadfly
sql.py | 113 | Fri May 10 22:59:05 2002 | 1396 | gadfly
sql.pyc | 114 | Sat Mar 15 14:29:42 2003 | 861 | gadfly
sql_mar.py | 115 | Sat May 11 09:06:15 2002 | 55428 | gadfly
sql_mar.pyc | 116 | Sat Mar 15 14:29:43 2003 | 45880 | gadfly
store.py | 117 | Fri May 10 22:59:05 2002 | 47643 | gadfly
store.pyc | 118 | Sat Mar 15 14:29:41 2003 | 58070 | gadfly
__init__.py | 119 | Sat May 11 08:09:20 2002 | 0 | scripts
gfplus.py | 120 | Wed Jul 10 03:45:07 2002 | 9277 | scripts
gfserver.py | 121 | Sat May 11 09:28:35 2002 | 3417 | scripts
2.0 | 122 | Wed Jul 10 03:45:39 2002 | 92 | kjbuckets
2.1 | 123 | Wed Jul 10 03:45:39 2002 | 92 | kjbuckets
2.2 | 124 | Wed Jul 10 03:45:39 2002 | 58 | kjbuckets
kjbucketsmodule.c | 125 | Tue May 21 04:24:20 2002 | 106205 | kjbuckets
setup.py | 126 | Mon May 6 03:31:10 2002 | 187 | kjbuckets
kjbuckets.pyd | 127 | Mon May 6 19:19:16 2002 | 57344 | 2.0
semantics.py-patch | 128 | Mon May 6 03:31:10 2002 | 3046 | 2.0
kjbuckets.pyd | 129 | Mon May 6 19:19:16 2002 | 40960 | 2.1
kjbucketsmodule.c | 130 | Mon May 6 03:31:10 2002 | 109776 | 2.1
kjbuckets.pyd | 131 | Mon May 6 19:19:16 2002 | 45056 | 2.2
__init__.py | 132 | Tue May 7 21:39:16 2002 | 2164 | test
__init__.pyc | 133 | Sat Mar 15 14:29:41 2003 | 1147 | test
gfstest.py | 134 | Sat May 11 08:18:51 2002 | 6538 | test
test_gadfly.py | 135 | Sat May 18 21:54:24 2002 | 43432 | test
test_gadfly.pyc | 136 | Sat Mar 15 14:29:41 2003 | 49301 | test
test_kjbuckets.py | 137 | Tue May 7 21:39:16 2002 | 9790 | test
test_kjbuckets.pyc | 138 | Sat Mar 15 14:29:41 2003 | 10009 | test
test_kjParseBuild.py | 139 | Fri May 10 22:59:05 2002 | 8087 | test
test_kjParseBuild.pyc | 140 | Sat Mar 15 14:29:41 2003 | 7689 | test
test_sqlgrammar.py | 141 | Tue May 7 21:39:16 2002 | 1968 | test
test_sqlgrammar.pyc | 142 | Sat Mar 15 14:29:42 2003 | 1779 | test
Load Complete hier_db
directory tree
visiting transclose
visiting gadfly-1.0.0
visiting build
visiting lib
visiting gadfly
visiting scripts
visiting scripts
visiting scripts
visiting doc
visiting demo
visiting kjParsing
visiting kjbuckets
visiting 2.0
visiting 2.1
visiting 2.2
visiting gadfly
visiting scripts
visiting scripts
visiting kjbuckets
visiting 2.0
visiting 2.1
visiting 2.2
visiting test
LEVEL | KEY | LOW | HIGH
=========================
1 | 1 | 5 | 5
1 | 8 | 10 | 10
1 | 10 | 15 | 15
2 | 16 | 25 | 25
2 | 17 | 30 | 30
2 | 21 | 35 | 35
2 | 22 | 40 | 40
2 | 26 | 45 | 45
5 | 30 | 65 | 65
5 | 83 | 70 | 70
5 | 84 | 75 | 75
5 | 31 | 80 | 80
5 | 85 | 85 | 85
5 | 86 | 90 | 90
5 | 32 | 95 | 95
5 | 87 | 100 | 100
5 | 33 | 105 | 105
5 | 88 | 110 | 110
5 | 89 | 115 | 115
5 | 34 | 120 | 120
5 | 90 | 125 | 125
5 | 35 | 130 | 130
5 | 91 | 135 | 135
5 | 92 | 140 | 140
5 | 36 | 145 | 145
5 | 93 | 150 | 150
5 | 94 | 155 | 155
5 | 39 | 160 | 160
5 | 99 | 165 | 165
5 | 100 | 170 | 170
5 | 40 | 175 | 175
5 | 101 | 180 | 180
5 | 102 | 185 | 185
5 | 41 | 190 | 190
5 | 103 | 195 | 195
5 | 104 | 200 | 200
5 | 37 | 205 | 205
5 | 95 | 210 | 210
5 | 96 | 215 | 215
5 | 38 | 220 | 220
5 | 97 | 225 | 225
5 | 98 | 230 | 230
5 | 42 | 235 | 235
5 | 105 | 240 | 240
5 | 106 | 245 | 245
6 | 50 | 255 | 255
6 | 119 | 260 | 260
6 | 53 | 265 | 265
6 | 51 | 270 | 270
6 | 120 | 275 | 275
6 | 54 | 280 | 280
6 | 52 | 285 | 285
6 | 121 | 290 | 290
6 | 43 | 255 | 295
6 | 50 | 305 | 305
6 | 119 | 310 | 310
6 | 53 | 315 | 315
6 | 51 | 320 | 320
6 | 120 | 325 | 325
6 | 54 | 330 | 330
6 | 52 | 335 | 335
6 | 121 | 340 | 340
6 | 107 | 305 | 345
5 | 44 | 350 | 350
5 | 108 | 355 | 355
5 | 109 | 360 | 360
5 | 45 | 365 | 365
5 | 110 | 370 | 370
5 | 111 | 375 | 375
5 | 46 | 380 | 380
5 | 112 | 385 | 385
5 | 47 | 390 | 390
5 | 113 | 395 | 395
5 | 114 | 400 | 400
5 | 48 | 405 | 405
5 | 115 | 410 | 410
5 | 116 | 415 | 415
5 | 49 | 420 | 420
5 | 117 | 425 | 425
5 | 118 | 430 | 430
5 | 29 | 65 | 435
4 | 27 | 60 | 440
4 | 50 | 450 | 450
4 | 119 | 455 | 455
4 | 53 | 460 | 460
4 | 51 | 465 | 465
4 | 120 | 470 | 470
4 | 54 | 475 | 475
4 | 52 | 480 | 480
4 | 121 | 485 | 485
4 | 28 | 450 | 490
3 | 15 | 55 | 495
3 | 55 | 505 | 505
3 | 56 | 510 | 510
5 | 77 | 525 | 525
5 | 78 | 530 | 530
5 | 79 | 535 | 535
5 | 80 | 540 | 540
5 | 81 | 545 | 545
5 | 82 | 550 | 550
5 | 70 | 525 | 555
6 | 127 | 570 | 570
6 | 128 | 575 | 575
6 | 122 | 570 | 580
6 | 129 | 590 | 590
6 | 130 | 595 | 595
6 | 123 | 590 | 600
6 | 131 | 610 | 610
6 | 124 | 610 | 615
5 | 125 | 620 | 620
5 | 71 | 625 | 625
5 | 72 | 630 | 630
5 | 73 | 635 | 635
5 | 126 | 640 | 640
5 | 74 | 645 | 645
5 | 75 | 650 | 650
5 | 76 | 655 | 655
5 | 69 | 565 | 660
4 | 57 | 520 | 665
3 | 58 | 670 | 670
3 | 59 | 675 | 675
3 | 60 | 680 | 680
3 | 61 | 685 | 685
3 | 62 | 690 | 690
3 | 63 | 695 | 695
3 | 64 | 700 | 700
3 | 65 | 705 | 705
3 | 66 | 710 | 710
3 | 67 | 715 | 715
3 | 68 | 720 | 720
3 | 18 | 505 | 725
3 | 30 | 735 | 735
3 | 83 | 740 | 740
3 | 84 | 745 | 745
3 | 31 | 750 | 750
3 | 85 | 755 | 755
3 | 86 | 760 | 760
3 | 32 | 765 | 765
3 | 87 | 770 | 770
3 | 33 | 775 | 775
3 | 88 | 780 | 780
3 | 89 | 785 | 785
3 | 34 | 790 | 790
3 | 90 | 795 | 795
3 | 35 | 800 | 800
3 | 91 | 805 | 805
3 | 92 | 810 | 810
3 | 36 | 815 | 815
3 | 93 | 820 | 820
3 | 94 | 825 | 825
3 | 39 | 830 | 830
3 | 99 | 835 | 835
3 | 100 | 840 | 840
3 | 40 | 845 | 845
3 | 101 | 850 | 850
3 | 102 | 855 | 855
3 | 41 | 860 | 860
3 | 103 | 865 | 865
3 | 104 | 870 | 870
3 | 37 | 875 | 875
3 | 95 | 880 | 880
3 | 96 | 885 | 885
3 | 38 | 890 | 890
3 | 97 | 895 | 895
3 | 98 | 900 | 900
3 | 42 | 905 | 905
3 | 105 | 910 | 910
3 | 106 | 915 | 915
4 | 50 | 925 | 925
4 | 119 | 930 | 930
4 | 53 | 935 | 935
4 | 51 | 940 | 940
4 | 120 | 945 | 945
4 | 54 | 950 | 950
4 | 52 | 955 | 955
4 | 121 | 960 | 960
4 | 43 | 925 | 965
4 | 50 | 975 | 975
4 | 119 | 980 | 980
4 | 53 | 985 | 985
4 | 51 | 990 | 990
4 | 120 | 995 | 995
4 | 54 | 1000 | 1000
4 | 52 | 1005 | 1005
4 | 121 | 1010 | 1010
4 | 107 | 975 | 1015
3 | 44 | 1020 | 1020
3 | 108 | 1025 | 1025
3 | 109 | 1030 | 1030
3 | 45 | 1035 | 1035
3 | 110 | 1040 | 1040
3 | 111 | 1045 | 1045
3 | 46 | 1050 | 1050
3 | 112 | 1055 | 1055
3 | 47 | 1060 | 1060
3 | 113 | 1065 | 1065
3 | 114 | 1070 | 1070
3 | 48 | 1075 | 1075
3 | 115 | 1080 | 1080
3 | 116 | 1085 | 1085
3 | 49 | 1090 | 1090
3 | 117 | 1095 | 1095
3 | 118 | 1100 | 1100
3 | 19 | 735 | 1105
4 | 127 | 1120 | 1120
4 | 128 | 1125 | 1125
4 | 122 | 1120 | 1130
4 | 129 | 1140 | 1140
4 | 130 | 1145 | 1145
4 | 123 | 1140 | 1150
4 | 131 | 1160 | 1160
4 | 124 | 1160 | 1165
3 | 125 | 1170 | 1170
3 | 71 | 1175 | 1175
3 | 72 | 1180 | 1180
3 | 73 | 1185 | 1185
3 | 126 | 1190 | 1190
3 | 74 | 1195 | 1195
3 | 75 | 1200 | 1200
3 | 76 | 1205 | 1205
3 | 20 | 1115 | 1210
2 | 23 | 1215 | 1215
2 | 24 | 1220 | 1220
3 | 132 | 1230 | 1230
3 | 133 | 1235 | 1235
3 | 134 | 1240 | 1240
3 | 135 | 1245 | 1245
3 | 136 | 1250 | 1250
3 | 139 | 1255 | 1255
3 | 140 | 1260 | 1260
3 | 137 | 1265 | 1265
3 | 138 | 1270 | 1270
3 | 141 | 1275 | 1275
3 | 142 | 1280 | 1280
3 | 25 | 1230 | 1285
2 | 2 | 25 | 1290
1 | 3 | 1295 | 1295
1 | 4 | 1300 | 1300
1 | 5 | 1305 | 1305
1 | 6 | 1310 | 1310
1 | 7 | 1315 | 1315
1 | 9 | 1320 | 1320
1 | 11 | 1325 | 1325
1 | 12 | 1330 | 1330
1 | 13 | 1335 | 1335
1 | 14 | 1340 | 1340
reports
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('build', 92, 3, 'Sat Mar 15 14:34:49 2003', 55, 'gadfly-1.0.0', 495, 15, 15)
('lib', 58, 4, 'Sat Mar 15 14:34:49 2003', 60, 'build', 440, 27, 27)
('gadfly', 704, 5, 'Sat Mar 15 14:34:49 2003', 65, 'lib', 435, 29, 29)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('build', 92, 3, 'Sat Mar 15 14:34:49 2003', 55, 'gadfly-1.0.0', 495, 15, 15)
('lib', 58, 4, 'Sat Mar 15 14:34:49 2003', 60, 'build', 440, 27, 27)
('gadfly', 704, 5, 'Sat Mar 15 14:34:49 2003', 65, 'lib', 435, 29, 29)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('build', 92, 3, 'Sat Mar 15 14:34:49 2003', 55, 'gadfly-1.0.0', 495, 15, 15)
('lib', 58, 4, 'Sat Mar 15 14:34:49 2003', 60, 'build', 440, 27, 27)
('gadfly', 704, 5, 'Sat Mar 15 14:34:49 2003', 65, 'lib', 435, 29, 29)
('scripts', 126, 6, 'Sat Mar 15 14:34:49 2003', 255, 'gadfly', 295, 43, 43)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('build', 92, 3, 'Sat Mar 15 14:34:49 2003', 55, 'gadfly-1.0.0', 495, 15, 15)
('lib', 58, 4, 'Sat Mar 15 14:34:49 2003', 60, 'build', 440, 27, 27)
('gadfly', 704, 5, 'Sat Mar 15 14:34:49 2003', 65, 'lib', 435, 29, 29)
('scripts', 126, 6, 'Sat Mar 15 14:34:49 2003', 255, 'gadfly', 295, 43, 43)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('build', 92, 3, 'Sat Mar 15 14:34:49 2003', 55, 'gadfly-1.0.0', 495, 15, 15)
('lib', 58, 4, 'Sat Mar 15 14:34:49 2003', 60, 'build', 440, 27, 27)
('gadfly', 704, 5, 'Sat Mar 15 14:34:49 2003', 65, 'lib', 435, 29, 29)
('scripts', 126, 6, 'Wed Jul 10 03:45:39 2002', 305, 'gadfly', 345, 107, 107)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('build', 92, 3, 'Sat Mar 15 14:34:49 2003', 55, 'gadfly-1.0.0', 495, 15, 15)
('lib', 58, 4, 'Sat Mar 15 14:34:49 2003', 60, 'build', 440, 27, 27)
('gadfly', 704, 5, 'Sat Mar 15 14:34:49 2003', 65, 'lib', 435, 29, 29)
('scripts', 126, 6, 'Wed Jul 10 03:45:39 2002', 305, 'gadfly', 345, 107, 107)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('build', 92, 3, 'Sat Mar 15 14:34:49 2003', 55, 'gadfly-1.0.0', 495, 15, 15)
('scripts', 92, 4, 'Sat Mar 15 14:34:49 2003', 450, 'build', 490, 28, 28)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('build', 92, 3, 'Sat Mar 15 14:34:49 2003', 55, 'gadfly-1.0.0', 495, 15, 15)
('scripts', 92, 4, 'Sat Mar 15 14:34:49 2003', 450, 'build', 490, 28, 28)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('gadfly', 1248, 3, 'Sat Mar 15 14:29:43 2003', 735, 'gadfly-1.0.0', 1105, 19, 19)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('gadfly', 1248, 3, 'Sat Mar 15 14:29:43 2003', 735, 'gadfly-1.0.0', 1105, 19, 19)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('gadfly', 1248, 3, 'Sat Mar 15 14:29:43 2003', 735, 'gadfly-1.0.0', 1105, 19, 19)
('scripts', 126, 4, 'Sat Mar 15 14:34:49 2003', 925, 'gadfly', 965, 43, 43)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('gadfly', 1248, 3, 'Sat Mar 15 14:29:43 2003', 735, 'gadfly-1.0.0', 1105, 19, 19)
('scripts', 126, 4, 'Sat Mar 15 14:34:49 2003', 925, 'gadfly', 965, 43, 43)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('gadfly', 1248, 3, 'Sat Mar 15 14:29:43 2003', 735, 'gadfly-1.0.0', 1105, 19, 19)
('scripts', 126, 4, 'Wed Jul 10 03:45:39 2002', 975, 'gadfly', 1015, 107, 107)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('gadfly', 1248, 3, 'Sat Mar 15 14:29:43 2003', 735, 'gadfly-1.0.0', 1105, 19, 19)
('scripts', 126, 4, 'Wed Jul 10 03:45:39 2002', 975, 'gadfly', 1015, 107, 107)
__init__.py has path:
('gadfly-1.0.0', 432, 2, 'Sat Mar 15 14:34:49 2003', 25, 'transclose', 1290, 2, 2)
('test', 398, 3, 'Sat Mar 15 14:29:42 2003', 1230, 'gadfly-1.0.0', 1285, 25, 25)
test has children:
('__init__.py', 2164, 3, 'Tue May 7 21:39:16 2002', 1230, 'test', 1230, 132, 132)
('__init__.pyc', 1147, 3, 'Sat Mar 15 14:29:41 2003', 1235, 'test', 1235, 133, 133)
('gfstest.py', 6538, 3, 'Sat May 11 08:18:51 2002', 1240, 'test', 1240, 134, 134)
('test_gadfly.py', 43432, 3, 'Sat May 18 21:54:24 2002', 1245, 'test', 1245, 135, 135)
('test_gadfly.pyc', 49301, 3, 'Sat Mar 15 14:29:41 2003', 1250, 'test', 1250, 136, 136)
('test_kjParseBuild.py', 8087, 3, 'Fri May 10 22:59:05 2002', 1255, 'test', 1255, 139, 139)
('test_kjParseBuild.pyc', 7689, 3, 'Sat Mar 15 14:29:41 2003', 1260, 'test', 1260, 140, 140)
('test_kjbuckets.py', 9790, 3, 'Tue May 7 21:39:16 2002', 1265, 'test', 1265, 137, 137)
('test_kjbuckets.pyc', 10009, 3, 'Sat Mar 15 14:29:41 2003', 1270, 'test', 1270, 138, 138)
('test_sqlgrammar.py', 1968, 3, 'Tue May 7 21:39:16 2002', 1275, 'test', 1275, 141, 141)
('test_sqlgrammar.pyc', 1779, 3, 'Sat Mar 15 14:29:42 2003', 1280, 'test', 1280, 142, 142)
('test', 398, 3, 'Sat Mar 15 14:29:42 2003', 1230, 'gadfly-1.0.0', 1285, 25, 25)
Created by /usr/local/bin/pyweb.py at Sat Mar 15 16:17:08 2003.
pyweb.__version__ '$Revision$'.
Source transclose.w modified Sat Mar 15 16:16:25 2003.
Working directory '/Users/slott/Documents/Projects/transclose'.