Permalink
Browse files

Implement CSVTuple and make HeapTuple interface.

Currently the catalog data is CSV.  It is desirable to make all low-layer
access interface and pluggable, so that sometime (such like in test) CSV
can be one option.
Add a simple test, too.  The go test command sits in the package directory
when executing, so the test data resides below access.
  • Loading branch information...
umitanuki committed Jan 30, 2013
1 parent dd30e4a commit 1afc992cea094c78cfb910f1312caae0459ebaf1
Showing with 121 additions and 20 deletions.
  1. +78 −17 src/bigpot/access/common.go
  2. +39 −2 src/bigpot/access/common_test.go
  3. +2 −0 src/bigpot/access/testdata/1259
  4. +2 −1 src/bigpot/system/types.go
@@ -1,7 +1,14 @@
package access
+import "encoding/csv"
+import "os"
+import "path/filepath"
+import "strconv"
+
import "bigpot/system"
+var DatabaseDir = "."
+
type Attribute struct {
AttName system.Name
AttType system.Oid
@@ -40,10 +47,6 @@ type Relation struct {
RelDesc *TupleDesc
}
-type HeapTuple struct {
-
-}
-
type Datum interface{}
type ScanKey struct {
AttNum int32
@@ -54,6 +57,17 @@ type RelationScan struct {
Relation *Relation
Forward bool
ScanKeys []ScanKey // non-pointer, as usually this is short life
+ Reader *csv.Reader
+ File *os.File
+}
+
+type HeapTuple interface {
+ Get(attnum int32) Datum
+}
+
+type CSVTuple struct {
+ Scan *RelationScan
+ Values []string
}
func HeapOpen(relid system.Oid) (*Relation, error) {
@@ -83,8 +97,12 @@ func HeapOpen(relid system.Oid) (*Relation, error) {
{Anum_class_oid, Datum(relid)},
}
- class_scan := class_rel.BeginScan(scan_keys)
- class_tuple := class_scan.Next()
+ class_scan, err := class_rel.BeginScan(scan_keys)
+ if err != nil {
+ return nil, err
+ }
+ defer class_scan.EndScan()
+ class_tuple, err := class_scan.Next()
_ = class_tuple
// relation = &Relation{
// RelId: relid,
@@ -99,11 +117,23 @@ func HeapOpen(relid system.Oid) (*Relation, error) {
{Anum_attribute_attrelid, Datum(relid)},
}
- attr_scan := attr_rel.BeginScan(scan_keys)
+ attr_scan, err := attr_rel.BeginScan(scan_keys)
+ if err != nil {
+ return nil, err
+ }
+ defer attr_scan.EndScan()
var attributes []*Attribute
- for attr_tuple := attr_scan.Next();
- attr_tuple != nil;
- attr_tuple = attr_scan.Next() {
+ for {
+ attr_tuple, err := attr_scan.Next()
+ if err != nil {
+ return nil, err
+ }
+ if attr_tuple == nil {
+ break
+ }
+// for attr_tuple := attr_scan.Next();
+// attr_tuple != nil;
+// attr_tuple = attr_scan.Next() {
attribute := &Attribute{
AttName: attr_tuple.Get(Anum_attribute_attname).(system.Name),
AttType: attr_tuple.Get(Anum_attribute_atttype).(system.Oid),
@@ -118,25 +148,56 @@ func HeapOpen(relid system.Oid) (*Relation, error) {
}
func (relation *Relation) Close() {
-
}
-func (relation *Relation) BeginScan(keys []ScanKey) *RelationScan{
+func (relation *Relation) BeginScan(keys []ScanKey) (*RelationScan, error) {
+ filepath := filepath.Join(DatabaseDir, strconv.Itoa(int(relation.RelId)))
+ file, err := os.Open(filepath)
+ if err != nil {
+ return nil, err
+ }
scan := &RelationScan{
Relation: relation,
Forward: true,
ScanKeys: keys,
+ Reader: csv.NewReader(file),
+ File: file,
}
- return scan
+ return scan, nil
}
-func (scan *RelationScan) Next() *HeapTuple {
-// htuple := &HeapTuple{}
+func (scan *RelationScan) Next() (HeapTuple, error) {
+ values, err := scan.Reader.Read()
+ if err != nil {
+ return nil, err
+ }
- return nil
+ if values == nil {
+ return nil, nil
+ }
+
+ return HeapTuple(&CSVTuple{
+ Scan: scan,
+ Values: values,
+ }), nil
}
-func (htuple *HeapTuple) Get(attnum int32) Datum {
+func (scan *RelationScan) EndScan() {
+ scan.File.Close()
+}
+
+func (tuple *CSVTuple) Get(attnum int32) Datum {
+ value := tuple.Values[attnum - 1]
+ switch tuple.Scan.Relation.RelDesc.Attrs[attnum - 1].AttType {
+ case system.OidType:
+ num, _ := strconv.Atoi(value)
+ return Datum(system.Oid(num))
+ case system.NameType:
+ return Datum(system.Name(value))
+ case system.Int4Type:
+ num, _ := strconv.Atoi(value)
+ return Datum(system.Int4(num))
+ }
return nil
}
@@ -3,8 +3,15 @@ package access
import (
. "launchpad.net/gocheck"
"testing"
+ "fmt"
+ "strconv"
+ "bigpot/system"
)
+func init() {
+ DatabaseDir = "testdata"
+}
+
func Test(t *testing.T) {
TestingT(t)
}
@@ -15,7 +22,7 @@ var _ = Suite(&AccessSuite{})
func (s *AccessSuite) TestHeapOpen_class(c *C) {
relation, err := HeapOpen(ClassRelId)
if err != nil {
- c.Error("HeapOpen failed")
+ c.Error(err)
}
c.Check(relation.RelId, Equals, ClassRelId)
c.Check(len(relation.RelDesc.Attrs), Equals, 2)
@@ -24,8 +31,38 @@ func (s *AccessSuite) TestHeapOpen_class(c *C) {
func (s *AccessSuite) TestHeapOpen_attribute(c *C) {
relation, err := HeapOpen(AttributeRelId)
if err != nil {
- c.Error("HeapOpen failed")
+ c.Error(err)
}
c.Check(relation.RelId, Equals, AttributeRelId)
c.Check(len(relation.RelDesc.Attrs), Equals, 4)
}
+
+func ExampleHeapScan_class() {
+ relation, err := HeapOpen(ClassRelId)
+ if err != nil {
+ fmt.Printf("%s", err)
+ }
+ defer relation.Close()
+
+ scan, err := relation.BeginScan(nil)
+ if err != nil {
+ fmt.Printf("%s", err)
+ return
+ }
+
+ defer scan.EndScan()
+ for i := 0; ; i++ {
+ tuple, err := scan.Next()
+ if err != nil {
+ break
+ }
+ fmt.Printf("%d,%d:%s\n", i, 1, strconv.Itoa(int(tuple.Get(1).(system.Oid))))
+ fmt.Printf("%d,%d:%s\n", i, 2, tuple.Get(2).(system.Name))
+ }
+
+ // OUTPUT:
+ // 0,1:1259
+ // 0,2:bp_class
+ // 1,1:1249
+ // 1,2:bp_attribute
+}
@@ -0,0 +1,2 @@
+1259,bp_class
+1249,bp_attribute
@@ -1,7 +1,8 @@
package system
-type Oid uint32
type Name string
+type Oid uint32
+type Int4 int32
var BoolType Oid = 16
var ByteType Oid = 17

0 comments on commit 1afc992

Please sign in to comment.