aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/exp
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-01-25 21:54:22 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-01-25 21:54:22 +0000
commitaf92e385667da3fc91ac7f9f0867a56c111110b8 (patch)
treec8e8990a2197e33f6fe50a28a16714aafe982102 /libgo/go/exp
parentdf1304ee03f41aed179545d1e8b4684cfd22bbdf (diff)
downloadgcc-af92e385667da3fc91ac7f9f0867a56c111110b8.zip
gcc-af92e385667da3fc91ac7f9f0867a56c111110b8.tar.gz
gcc-af92e385667da3fc91ac7f9f0867a56c111110b8.tar.bz2
libgo: Update to weekly.2012-01-20.
From-SVN: r183540
Diffstat (limited to 'libgo/go/exp')
-rw-r--r--libgo/go/exp/gotype/testdata/test1.go4
-rw-r--r--libgo/go/exp/inotify/inotify_linux_test.go9
-rw-r--r--libgo/go/exp/norm/trie_test.go4
-rw-r--r--libgo/go/exp/proxy/proxy.go12
-rw-r--r--libgo/go/exp/sql/convert.go133
-rw-r--r--libgo/go/exp/sql/convert_test.go173
-rw-r--r--libgo/go/exp/sql/driver/driver.go207
-rw-r--r--libgo/go/exp/sql/driver/types.go219
-rw-r--r--libgo/go/exp/sql/driver/types_test.go61
-rw-r--r--libgo/go/exp/sql/fakedb_test.go597
-rw-r--r--libgo/go/exp/sql/sql.go860
-rw-r--r--libgo/go/exp/sql/sql_test.go305
-rw-r--r--libgo/go/exp/ssh/client.go5
-rw-r--r--libgo/go/exp/ssh/messages.go20
-rw-r--r--libgo/go/exp/ssh/session.go8
-rw-r--r--libgo/go/exp/ssh/tcpip.go31
-rw-r--r--libgo/go/exp/ssh/transport.go36
-rw-r--r--libgo/go/exp/ssh/transport_test.go18
-rw-r--r--libgo/go/exp/types/check_test.go18
-rw-r--r--libgo/go/exp/types/gcimporter.go31
-rw-r--r--libgo/go/exp/utf8string/string.go203
-rw-r--r--libgo/go/exp/utf8string/string_test.go123
22 files changed, 441 insertions, 2636 deletions
diff --git a/libgo/go/exp/gotype/testdata/test1.go b/libgo/go/exp/gotype/testdata/test1.go
index a3298e6..ba8a51f 100644
--- a/libgo/go/exp/gotype/testdata/test1.go
+++ b/libgo/go/exp/gotype/testdata/test1.go
@@ -1,3 +1,7 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package p
func _() {
diff --git a/libgo/go/exp/inotify/inotify_linux_test.go b/libgo/go/exp/inotify/inotify_linux_test.go
index d035ec1..c2160fc 100644
--- a/libgo/go/exp/inotify/inotify_linux_test.go
+++ b/libgo/go/exp/inotify/inotify_linux_test.go
@@ -83,14 +83,15 @@ func TestInotifyClose(t *testing.T) {
watcher, _ := NewWatcher()
watcher.Close()
- done := false
+ done := make(chan bool)
go func() {
watcher.Close()
- done = true
+ done <- true
}()
- time.Sleep(50 * time.Millisecond)
- if !done {
+ select {
+ case <-done:
+ case <-time.After(50 * time.Millisecond):
t.Fatal("double Close() test failed: second Close() call didn't return")
}
diff --git a/libgo/go/exp/norm/trie_test.go b/libgo/go/exp/norm/trie_test.go
index 7308d28..c457c9d 100644
--- a/libgo/go/exp/norm/trie_test.go
+++ b/libgo/go/exp/norm/trie_test.go
@@ -1,3 +1,7 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package norm
import (
diff --git a/libgo/go/exp/proxy/proxy.go b/libgo/go/exp/proxy/proxy.go
index ccd3d1d..b6cfd45 100644
--- a/libgo/go/exp/proxy/proxy.go
+++ b/libgo/go/exp/proxy/proxy.go
@@ -11,7 +11,6 @@ import (
"net"
"net/url"
"os"
- "strings"
)
// A Dialer is a means to establish a connection.
@@ -70,14 +69,11 @@ func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error))
// Dialer for it to make network requests.
func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
var auth *Auth
- if len(u.RawUserinfo) > 0 {
+ if u.User != nil {
auth = new(Auth)
- parts := strings.SplitN(u.RawUserinfo, ":", 1)
- if len(parts) == 1 {
- auth.User = parts[0]
- } else if len(parts) >= 2 {
- auth.User = parts[0]
- auth.Password = parts[1]
+ auth.User = u.User.Username()
+ if p, ok := u.User.Password(); ok {
+ auth.Password = p
}
}
diff --git a/libgo/go/exp/sql/convert.go b/libgo/go/exp/sql/convert.go
deleted file mode 100644
index feb79ae..0000000
--- a/libgo/go/exp/sql/convert.go
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Type conversions for Scan.
-
-package sql
-
-import (
- "errors"
- "exp/sql/driver"
- "fmt"
- "reflect"
- "strconv"
-)
-
-// subsetTypeArgs takes a slice of arguments from callers of the sql
-// package and converts them into a slice of the driver package's
-// "subset types".
-func subsetTypeArgs(args []interface{}) ([]interface{}, error) {
- out := make([]interface{}, len(args))
- for n, arg := range args {
- var err error
- out[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
- if err != nil {
- return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n+1, err)
- }
- }
- return out, nil
-}
-
-// convertAssign copies to dest the value in src, converting it if possible.
-// An error is returned if the copy would result in loss of information.
-// dest should be a pointer type.
-func convertAssign(dest, src interface{}) error {
- // Common cases, without reflect. Fall through.
- switch s := src.(type) {
- case string:
- switch d := dest.(type) {
- case *string:
- *d = s
- return nil
- }
- case []byte:
- switch d := dest.(type) {
- case *string:
- *d = string(s)
- return nil
- case *[]byte:
- *d = s
- return nil
- }
- }
-
- var sv reflect.Value
-
- switch d := dest.(type) {
- case *string:
- sv = reflect.ValueOf(src)
- switch sv.Kind() {
- case reflect.Bool,
- reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
- reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
- reflect.Float32, reflect.Float64:
- *d = fmt.Sprintf("%v", src)
- return nil
- }
- case *bool:
- bv, err := driver.Bool.ConvertValue(src)
- if err == nil {
- *d = bv.(bool)
- }
- return err
- }
-
- if scanner, ok := dest.(ScannerInto); ok {
- return scanner.ScanInto(src)
- }
-
- dpv := reflect.ValueOf(dest)
- if dpv.Kind() != reflect.Ptr {
- return errors.New("destination not a pointer")
- }
-
- if !sv.IsValid() {
- sv = reflect.ValueOf(src)
- }
-
- dv := reflect.Indirect(dpv)
- if dv.Kind() == sv.Kind() {
- dv.Set(sv)
- return nil
- }
-
- switch dv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- s := asString(src)
- i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
- if err != nil {
- return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)
- }
- dv.SetInt(i64)
- return nil
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- s := asString(src)
- u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
- if err != nil {
- return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)
- }
- dv.SetUint(u64)
- return nil
- case reflect.Float32, reflect.Float64:
- s := asString(src)
- f64, err := strconv.ParseFloat(s, dv.Type().Bits())
- if err != nil {
- return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)
- }
- dv.SetFloat(f64)
- return nil
- }
-
- return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)
-}
-
-func asString(src interface{}) string {
- switch v := src.(type) {
- case string:
- return v
- case []byte:
- return string(v)
- }
- return fmt.Sprintf("%v", src)
-}
diff --git a/libgo/go/exp/sql/convert_test.go b/libgo/go/exp/sql/convert_test.go
deleted file mode 100644
index 702ba43..0000000
--- a/libgo/go/exp/sql/convert_test.go
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package sql
-
-import (
- "fmt"
- "reflect"
- "testing"
- "time"
-)
-
-var someTime = time.Unix(123, 0)
-
-type conversionTest struct {
- s, d interface{} // source and destination
-
- // following are used if they're non-zero
- wantint int64
- wantuint uint64
- wantstr string
- wantf32 float32
- wantf64 float64
- wanttime time.Time
- wantbool bool // used if d is of type *bool
- wanterr string
-}
-
-// Target variables for scanning into.
-var (
- scanstr string
- scanint int
- scanint8 int8
- scanint16 int16
- scanint32 int32
- scanuint8 uint8
- scanuint16 uint16
- scanbool bool
- scanf32 float32
- scanf64 float64
- scantime time.Time
-)
-
-var conversionTests = []conversionTest{
- // Exact conversions (destination pointer type matches source type)
- {s: "foo", d: &scanstr, wantstr: "foo"},
- {s: 123, d: &scanint, wantint: 123},
- {s: someTime, d: &scantime, wanttime: someTime},
-
- // To strings
- {s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
- {s: 123, d: &scanstr, wantstr: "123"},
- {s: int8(123), d: &scanstr, wantstr: "123"},
- {s: int64(123), d: &scanstr, wantstr: "123"},
- {s: uint8(123), d: &scanstr, wantstr: "123"},
- {s: uint16(123), d: &scanstr, wantstr: "123"},
- {s: uint32(123), d: &scanstr, wantstr: "123"},
- {s: uint64(123), d: &scanstr, wantstr: "123"},
- {s: 1.5, d: &scanstr, wantstr: "1.5"},
-
- // Strings to integers
- {s: "255", d: &scanuint8, wantuint: 255},
- {s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: strconv.ParseUint: parsing "256": value out of range`},
- {s: "256", d: &scanuint16, wantuint: 256},
- {s: "-1", d: &scanint, wantint: -1},
- {s: "foo", d: &scanint, wanterr: `converting string "foo" to a int: strconv.ParseInt: parsing "foo": invalid syntax`},
-
- // True bools
- {s: true, d: &scanbool, wantbool: true},
- {s: "True", d: &scanbool, wantbool: true},
- {s: "TRUE", d: &scanbool, wantbool: true},
- {s: "1", d: &scanbool, wantbool: true},
- {s: 1, d: &scanbool, wantbool: true},
- {s: int64(1), d: &scanbool, wantbool: true},
- {s: uint16(1), d: &scanbool, wantbool: true},
-
- // False bools
- {s: false, d: &scanbool, wantbool: false},
- {s: "false", d: &scanbool, wantbool: false},
- {s: "FALSE", d: &scanbool, wantbool: false},
- {s: "0", d: &scanbool, wantbool: false},
- {s: 0, d: &scanbool, wantbool: false},
- {s: int64(0), d: &scanbool, wantbool: false},
- {s: uint16(0), d: &scanbool, wantbool: false},
-
- // Not bools
- {s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`},
- {s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`},
-
- // Floats
- {s: float64(1.5), d: &scanf64, wantf64: float64(1.5)},
- {s: int64(1), d: &scanf64, wantf64: float64(1)},
- {s: float64(1.5), d: &scanf32, wantf32: float32(1.5)},
- {s: "1.5", d: &scanf32, wantf32: float32(1.5)},
- {s: "1.5", d: &scanf64, wantf64: float64(1.5)},
-}
-
-func intValue(intptr interface{}) int64 {
- return reflect.Indirect(reflect.ValueOf(intptr)).Int()
-}
-
-func uintValue(intptr interface{}) uint64 {
- return reflect.Indirect(reflect.ValueOf(intptr)).Uint()
-}
-
-func float64Value(ptr interface{}) float64 {
- return *(ptr.(*float64))
-}
-
-func float32Value(ptr interface{}) float32 {
- return *(ptr.(*float32))
-}
-
-func timeValue(ptr interface{}) time.Time {
- return *(ptr.(*time.Time))
-}
-
-func TestConversions(t *testing.T) {
- for n, ct := range conversionTests {
- err := convertAssign(ct.d, ct.s)
- errstr := ""
- if err != nil {
- errstr = err.Error()
- }
- errf := func(format string, args ...interface{}) {
- base := fmt.Sprintf("convertAssign #%d: for %v (%T) -> %T, ", n, ct.s, ct.s, ct.d)
- t.Errorf(base+format, args...)
- }
- if errstr != ct.wanterr {
- errf("got error %q, want error %q", errstr, ct.wanterr)
- }
- if ct.wantstr != "" && ct.wantstr != scanstr {
- errf("want string %q, got %q", ct.wantstr, scanstr)
- }
- if ct.wantint != 0 && ct.wantint != intValue(ct.d) {
- errf("want int %d, got %d", ct.wantint, intValue(ct.d))
- }
- if ct.wantuint != 0 && ct.wantuint != uintValue(ct.d) {
- errf("want uint %d, got %d", ct.wantuint, uintValue(ct.d))
- }
- if ct.wantf32 != 0 && ct.wantf32 != float32Value(ct.d) {
- errf("want float32 %v, got %v", ct.wantf32, float32Value(ct.d))
- }
- if ct.wantf64 != 0 && ct.wantf64 != float64Value(ct.d) {
- errf("want float32 %v, got %v", ct.wantf64, float64Value(ct.d))
- }
- if bp, boolTest := ct.d.(*bool); boolTest && *bp != ct.wantbool && ct.wanterr == "" {
- errf("want bool %v, got %v", ct.wantbool, *bp)
- }
- if !ct.wanttime.IsZero() && !ct.wanttime.Equal(timeValue(ct.d)) {
- errf("want time %v, got %v", ct.wanttime, timeValue(ct.d))
- }
- }
-}
-
-func TestNullableString(t *testing.T) {
- var ns NullableString
- convertAssign(&ns, []byte("foo"))
- if !ns.Valid {
- t.Errorf("expecting not null")
- }
- if ns.String != "foo" {
- t.Errorf("expecting foo; got %q", ns.String)
- }
- convertAssign(&ns, nil)
- if ns.Valid {
- t.Errorf("expecting null on nil")
- }
- if ns.String != "" {
- t.Errorf("expecting blank on nil; got %q", ns.String)
- }
-}
diff --git a/libgo/go/exp/sql/driver/driver.go b/libgo/go/exp/sql/driver/driver.go
deleted file mode 100644
index 0cd2562..0000000
--- a/libgo/go/exp/sql/driver/driver.go
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package driver defines interfaces to be implemented by database
-// drivers as used by package sql.
-//
-// Code simply using databases should use package sql.
-//
-// Drivers only need to be aware of a subset of Go's types. The sql package
-// will convert all types into one of the following:
-//
-// int64
-// float64
-// bool
-// nil
-// []byte
-// string [*] everywhere except from Rows.Next.
-// time.Time
-//
-package driver
-
-import "errors"
-
-// Driver is the interface that must be implemented by a database
-// driver.
-type Driver interface {
- // Open returns a new connection to the database.
- // The name is a string in a driver-specific format.
- //
- // Open may return a cached connection (one previously
- // closed), but doing so is unnecessary; the sql package
- // maintains a pool of idle connections for efficient re-use.
- //
- // The returned connection is only used by one goroutine at a
- // time.
- Open(name string) (Conn, error)
-}
-
-// ErrSkip may be returned by some optional interfaces' methods to
-// indicate at runtime that the fast path is unavailable and the sql
-// package should continue as if the optional interface was not
-// implemented. ErrSkip is only supported where explicitly
-// documented.
-var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")
-
-// Execer is an optional interface that may be implemented by a Conn.
-//
-// If a Conn does not implement Execer, the db package's DB.Exec will
-// first prepare a query, execute the statement, and then close the
-// statement.
-//
-// All arguments are of a subset type as defined in the package docs.
-//
-// Exec may return ErrSkip.
-type Execer interface {
- Exec(query string, args []interface{}) (Result, error)
-}
-
-// Conn is a connection to a database. It is not used concurrently
-// by multiple goroutines.
-//
-// Conn is assumed to be stateful.
-type Conn interface {
- // Prepare returns a prepared statement, bound to this connection.
- Prepare(query string) (Stmt, error)
-
- // Close invalidates and potentially stops any current
- // prepared statements and transactions, marking this
- // connection as no longer in use.
- //
- // Because the sql package maintains a free pool of
- // connections and only calls Close when there's a surplus of
- // idle connections, it shouldn't be necessary for drivers to
- // do their own connection caching.
- Close() error
-
- // Begin starts and returns a new transaction.
- Begin() (Tx, error)
-}
-
-// Result is the result of a query execution.
-type Result interface {
- // LastInsertId returns the database's auto-generated ID
- // after, for example, an INSERT into a table with primary
- // key.
- LastInsertId() (int64, error)
-
- // RowsAffected returns the number of rows affected by the
- // query.
- RowsAffected() (int64, error)
-}
-
-// Stmt is a prepared statement. It is bound to a Conn and not
-// used by multiple goroutines concurrently.
-type Stmt interface {
- // Close closes the statement.
- //
- // Closing a statement should not interrupt any outstanding
- // query created from that statement. That is, the following
- // order of operations is valid:
- //
- // * create a driver statement
- // * call Query on statement, returning Rows
- // * close the statement
- // * read from Rows
- //
- // If closing a statement invalidates currently-running
- // queries, the final step above will incorrectly fail.
- //
- // TODO(bradfitz): possibly remove the restriction above, if
- // enough driver authors object and find it complicates their
- // code too much. The sql package could be smarter about
- // refcounting the statement and closing it at the appropriate
- // time.
- Close() error
-
- // NumInput returns the number of placeholder parameters.
- //
- // If NumInput returns >= 0, the sql package will sanity check
- // argument counts from callers and return errors to the caller
- // before the statement's Exec or Query methods are called.
- //
- // NumInput may also return -1, if the driver doesn't know
- // its number of placeholders. In that case, the sql package
- // will not sanity check Exec or Query argument counts.
- NumInput() int
-
- // Exec executes a query that doesn't return rows, such
- // as an INSERT or UPDATE. The args are all of a subset
- // type as defined above.
- Exec(args []interface{}) (Result, error)
-
- // Exec executes a query that may return rows, such as a
- // SELECT. The args of all of a subset type as defined above.
- Query(args []interface{}) (Rows, error)
-}
-
-// ColumnConverter may be optionally implemented by Stmt if the
-// the statement is aware of its own columns' types and can
-// convert from any type to a driver subset type.
-type ColumnConverter interface {
- // ColumnConverter returns a ValueConverter for the provided
- // column index. If the type of a specific column isn't known
- // or shouldn't be handled specially, DefaultValueConverter
- // can be returned.
- ColumnConverter(idx int) ValueConverter
-}
-
-// Rows is an iterator over an executed query's results.
-type Rows interface {
- // Columns returns the names of the columns. The number of
- // columns of the result is inferred from the length of the
- // slice. If a particular column name isn't known, an empty
- // string should be returned for that entry.
- Columns() []string
-
- // Close closes the rows iterator.
- Close() error
-
- // Next is called to populate the next row of data into
- // the provided slice. The provided slice will be the same
- // size as the Columns() are wide.
- //
- // The dest slice may be populated with only with values
- // of subset types defined above, but excluding string.
- // All string values must be converted to []byte.
- //
- // Next should return io.EOF when there are no more rows.
- Next(dest []interface{}) error
-}
-
-// Tx is a transaction.
-type Tx interface {
- Commit() error
- Rollback() error
-}
-
-// RowsAffected implements Result for an INSERT or UPDATE operation
-// which mutates a number of rows.
-type RowsAffected int64
-
-var _ Result = RowsAffected(0)
-
-func (RowsAffected) LastInsertId() (int64, error) {
- return 0, errors.New("no LastInsertId available")
-}
-
-func (v RowsAffected) RowsAffected() (int64, error) {
- return int64(v), nil
-}
-
-// DDLSuccess is a pre-defined Result for drivers to return when a DDL
-// command succeeds.
-var DDLSuccess ddlSuccess
-
-type ddlSuccess struct{}
-
-var _ Result = ddlSuccess{}
-
-func (ddlSuccess) LastInsertId() (int64, error) {
- return 0, errors.New("no LastInsertId available after DDL statement")
-}
-
-func (ddlSuccess) RowsAffected() (int64, error) {
- return 0, errors.New("no RowsAffected available after DDL statement")
-}
diff --git a/libgo/go/exp/sql/driver/types.go b/libgo/go/exp/sql/driver/types.go
deleted file mode 100644
index d6ba641..0000000
--- a/libgo/go/exp/sql/driver/types.go
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package driver
-
-import (
- "fmt"
- "reflect"
- "strconv"
- "time"
-)
-
-// ValueConverter is the interface providing the ConvertValue method.
-//
-// Various implementations of ValueConverter are provided by the
-// driver package to provide consistent implementations of conversions
-// between drivers. The ValueConverters have several uses:
-//
-// * converting from the subset types as provided by the sql package
-// into a database table's specific column type and making sure it
-// fits, such as making sure a particular int64 fits in a
-// table's uint16 column.
-//
-// * converting a value as given from the database into one of the
-// subset types.
-//
-// * by the sql package, for converting from a driver's subset type
-// to a user's type in a scan.
-type ValueConverter interface {
- // ConvertValue converts a value to a restricted subset type.
- ConvertValue(v interface{}) (interface{}, error)
-}
-
-// Bool is a ValueConverter that converts input values to bools.
-//
-// The conversion rules are:
-// - booleans are returned unchanged
-// - for integer types,
-// 1 is true
-// 0 is false,
-// other integers are an error
-// - for strings and []byte, same rules as strconv.ParseBool
-// - all other types are an error
-var Bool boolType
-
-type boolType struct{}
-
-var _ ValueConverter = boolType{}
-
-func (boolType) String() string { return "Bool" }
-
-func (boolType) ConvertValue(src interface{}) (interface{}, error) {
- switch s := src.(type) {
- case bool:
- return s, nil
- case string:
- b, err := strconv.ParseBool(s)
- if err != nil {
- return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s)
- }
- return b, nil
- case []byte:
- b, err := strconv.ParseBool(string(s))
- if err != nil {
- return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s)
- }
- return b, nil
- }
-
- sv := reflect.ValueOf(src)
- switch sv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- iv := sv.Int()
- if iv == 1 || iv == 0 {
- return iv == 1, nil
- }
- return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", iv)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- uv := sv.Uint()
- if uv == 1 || uv == 0 {
- return uv == 1, nil
- }
- return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", uv)
- }
-
- return nil, fmt.Errorf("sql/driver: couldn't convert %v (%T) into type bool", src, src)
-}
-
-// Int32 is a ValueConverter that converts input values to int64,
-// respecting the limits of an int32 value.
-var Int32 int32Type
-
-type int32Type struct{}
-
-var _ ValueConverter = int32Type{}
-
-func (int32Type) ConvertValue(v interface{}) (interface{}, error) {
- rv := reflect.ValueOf(v)
- switch rv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- i64 := rv.Int()
- if i64 > (1<<31)-1 || i64 < -(1<<31) {
- return nil, fmt.Errorf("sql/driver: value %d overflows int32", v)
- }
- return i64, nil
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- u64 := rv.Uint()
- if u64 > (1<<31)-1 {
- return nil, fmt.Errorf("sql/driver: value %d overflows int32", v)
- }
- return int64(u64), nil
- case reflect.String:
- i, err := strconv.Atoi(rv.String())
- if err != nil {
- return nil, fmt.Errorf("sql/driver: value %q can't be converted to int32", v)
- }
- return int64(i), nil
- }
- return nil, fmt.Errorf("sql/driver: unsupported value %v (type %T) converting to int32", v, v)
-}
-
-// String is a ValueConverter that converts its input to a string.
-// If the value is already a string or []byte, it's unchanged.
-// If the value is of another type, conversion to string is done
-// with fmt.Sprintf("%v", v).
-var String stringType
-
-type stringType struct{}
-
-func (stringType) ConvertValue(v interface{}) (interface{}, error) {
- switch v.(type) {
- case string, []byte:
- return v, nil
- }
- return fmt.Sprintf("%v", v), nil
-}
-
-// IsParameterSubsetType reports whether v is of a valid type for a
-// parameter. These types are:
-//
-// int64
-// float64
-// bool
-// nil
-// []byte
-// time.Time
-// string
-//
-// This is the same list as IsScanSubsetType, with the addition of
-// string.
-func IsParameterSubsetType(v interface{}) bool {
- if IsScanSubsetType(v) {
- return true
- }
- if _, ok := v.(string); ok {
- return true
- }
- return false
-}
-
-// IsScanSubsetType reports whether v is of a valid type for a
-// value populated by Rows.Next. These types are:
-//
-// int64
-// float64
-// bool
-// nil
-// []byte
-// time.Time
-//
-// This is the same list as IsParameterSubsetType, without string.
-func IsScanSubsetType(v interface{}) bool {
- if v == nil {
- return true
- }
- switch v.(type) {
- case int64, float64, []byte, bool, time.Time:
- return true
- }
- return false
-}
-
-// DefaultParameterConverter is the default implementation of
-// ValueConverter that's used when a Stmt doesn't implement
-// ColumnConverter.
-//
-// DefaultParameterConverter returns the given value directly if
-// IsSubsetType(value). Otherwise integer type are converted to
-// int64, floats to float64, and strings to []byte. Other types are
-// an error.
-var DefaultParameterConverter defaultConverter
-
-type defaultConverter struct{}
-
-var _ ValueConverter = defaultConverter{}
-
-func (defaultConverter) ConvertValue(v interface{}) (interface{}, error) {
- if IsParameterSubsetType(v) {
- return v, nil
- }
-
- rv := reflect.ValueOf(v)
- switch rv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return rv.Int(), nil
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
- return int64(rv.Uint()), nil
- case reflect.Uint64:
- u64 := rv.Uint()
- if u64 >= 1<<63 {
- return nil, fmt.Errorf("uint64 values with high bit set are not supported")
- }
- return int64(u64), nil
- case reflect.Float32, reflect.Float64:
- return rv.Float(), nil
- }
- return nil, fmt.Errorf("unsupported type %s", rv.Kind())
-}
diff --git a/libgo/go/exp/sql/driver/types_test.go b/libgo/go/exp/sql/driver/types_test.go
deleted file mode 100644
index 966bc6b..0000000
--- a/libgo/go/exp/sql/driver/types_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package driver
-
-import (
- "reflect"
- "testing"
- "time"
-)
-
-type valueConverterTest struct {
- c ValueConverter
- in interface{}
- out interface{}
- err string
-}
-
-var now = time.Now()
-
-var valueConverterTests = []valueConverterTest{
- {Bool, "true", true, ""},
- {Bool, "True", true, ""},
- {Bool, []byte("t"), true, ""},
- {Bool, true, true, ""},
- {Bool, "1", true, ""},
- {Bool, 1, true, ""},
- {Bool, int64(1), true, ""},
- {Bool, uint16(1), true, ""},
- {Bool, "false", false, ""},
- {Bool, false, false, ""},
- {Bool, "0", false, ""},
- {Bool, 0, false, ""},
- {Bool, int64(0), false, ""},
- {Bool, uint16(0), false, ""},
- {c: Bool, in: "foo", err: "sql/driver: couldn't convert \"foo\" into type bool"},
- {c: Bool, in: 2, err: "sql/driver: couldn't convert 2 into type bool"},
- {DefaultParameterConverter, now, now, ""},
-}
-
-func TestValueConverters(t *testing.T) {
- for i, tt := range valueConverterTests {
- out, err := tt.c.ConvertValue(tt.in)
- goterr := ""
- if err != nil {
- goterr = err.Error()
- }
- if goterr != tt.err {
- t.Errorf("test %d: %s(%T(%v)) error = %q; want error = %q",
- i, tt.c, tt.in, tt.in, goterr, tt.err)
- }
- if tt.err != "" {
- continue
- }
- if !reflect.DeepEqual(out, tt.out) {
- t.Errorf("test %d: %s(%T(%v)) = %v (%T); want %v (%T)",
- i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out)
- }
- }
-}
diff --git a/libgo/go/exp/sql/fakedb_test.go b/libgo/go/exp/sql/fakedb_test.go
deleted file mode 100644
index 70aa68c..0000000
--- a/libgo/go/exp/sql/fakedb_test.go
+++ /dev/null
@@ -1,597 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package sql
-
-import (
- "errors"
- "fmt"
- "io"
- "log"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "exp/sql/driver"
-)
-
-var _ = log.Printf
-
-// fakeDriver is a fake database that implements Go's driver.Driver
-// interface, just for testing.
-//
-// It speaks a query language that's semantically similar to but
-// syntantically different and simpler than SQL. The syntax is as
-// follows:
-//
-// WIPE
-// CREATE|<tablename>|<col>=<type>,<col>=<type>,...
-// where types are: "string", [u]int{8,16,32,64}, "bool"
-// INSERT|<tablename>|col=val,col2=val2,col3=?
-// SELECT|<tablename>|projectcol1,projectcol2|filtercol=?,filtercol2=?
-//
-// When opening a a fakeDriver's database, it starts empty with no
-// tables. All tables and data are stored in memory only.
-type fakeDriver struct {
- mu sync.Mutex
- openCount int
- dbs map[string]*fakeDB
-}
-
-type fakeDB struct {
- name string
-
- mu sync.Mutex
- free []*fakeConn
- tables map[string]*table
-}
-
-type table struct {
- mu sync.Mutex
- colname []string
- coltype []string
- rows []*row
-}
-
-func (t *table) columnIndex(name string) int {
- for n, nname := range t.colname {
- if name == nname {
- return n
- }
- }
- return -1
-}
-
-type row struct {
- cols []interface{} // must be same size as its table colname + coltype
-}
-
-func (r *row) clone() *row {
- nrow := &row{cols: make([]interface{}, len(r.cols))}
- copy(nrow.cols, r.cols)
- return nrow
-}
-
-type fakeConn struct {
- db *fakeDB // where to return ourselves to
-
- currTx *fakeTx
-
- // Stats for tests:
- mu sync.Mutex
- stmtsMade int
- stmtsClosed int
-}
-
-func (c *fakeConn) incrStat(v *int) {
- c.mu.Lock()
- *v++
- c.mu.Unlock()
-}
-
-type fakeTx struct {
- c *fakeConn
-}
-
-type fakeStmt struct {
- c *fakeConn
- q string // just for debugging
-
- cmd string
- table string
-
- closed bool
-
- colName []string // used by CREATE, INSERT, SELECT (selected columns)
- colType []string // used by CREATE
- colValue []interface{} // used by INSERT (mix of strings and "?" for bound params)
- placeholders int // used by INSERT/SELECT: number of ? params
-
- whereCol []string // used by SELECT (all placeholders)
-
- placeholderConverter []driver.ValueConverter // used by INSERT
-}
-
-var fdriver driver.Driver = &fakeDriver{}
-
-func init() {
- Register("test", fdriver)
-}
-
-// Supports dsn forms:
-// <dbname>
-// <dbname>;<opts> (no currently supported options)
-func (d *fakeDriver) Open(dsn string) (driver.Conn, error) {
- parts := strings.Split(dsn, ";")
- if len(parts) < 1 {
- return nil, errors.New("fakedb: no database name")
- }
- name := parts[0]
-
- db := d.getDB(name)
-
- d.mu.Lock()
- d.openCount++
- d.mu.Unlock()
- return &fakeConn{db: db}, nil
-}
-
-func (d *fakeDriver) getDB(name string) *fakeDB {
- d.mu.Lock()
- defer d.mu.Unlock()
- if d.dbs == nil {
- d.dbs = make(map[string]*fakeDB)
- }
- db, ok := d.dbs[name]
- if !ok {
- db = &fakeDB{name: name}
- d.dbs[name] = db
- }
- return db
-}
-
-func (db *fakeDB) wipe() {
- db.mu.Lock()
- defer db.mu.Unlock()
- db.tables = nil
-}
-
-func (db *fakeDB) createTable(name string, columnNames, columnTypes []string) error {
- db.mu.Lock()
- defer db.mu.Unlock()
- if db.tables == nil {
- db.tables = make(map[string]*table)
- }
- if _, exist := db.tables[name]; exist {
- return fmt.Errorf("table %q already exists", name)
- }
- if len(columnNames) != len(columnTypes) {
- return fmt.Errorf("create table of %q len(names) != len(types): %d vs %d",
- name, len(columnNames), len(columnTypes))
- }
- db.tables[name] = &table{colname: columnNames, coltype: columnTypes}
- return nil
-}
-
-// must be called with db.mu lock held
-func (db *fakeDB) table(table string) (*table, bool) {
- if db.tables == nil {
- return nil, false
- }
- t, ok := db.tables[table]
- return t, ok
-}
-
-func (db *fakeDB) columnType(table, column string) (typ string, ok bool) {
- db.mu.Lock()
- defer db.mu.Unlock()
- t, ok := db.table(table)
- if !ok {
- return
- }
- for n, cname := range t.colname {
- if cname == column {
- return t.coltype[n], true
- }
- }
- return "", false
-}
-
-func (c *fakeConn) Begin() (driver.Tx, error) {
- if c.currTx != nil {
- return nil, errors.New("already in a transaction")
- }
- c.currTx = &fakeTx{c: c}
- return c.currTx, nil
-}
-
-func (c *fakeConn) Close() error {
- if c.currTx != nil {
- return errors.New("can't close; in a Transaction")
- }
- if c.db == nil {
- return errors.New("can't close; already closed")
- }
- c.db = nil
- return nil
-}
-
-func checkSubsetTypes(args []interface{}) error {
- for n, arg := range args {
- switch arg.(type) {
- case int64, float64, bool, nil, []byte, string, time.Time:
- default:
- return fmt.Errorf("fakedb_test: invalid argument #%d: %v, type %T", n+1, arg, arg)
- }
- }
- return nil
-}
-
-func (c *fakeConn) Exec(query string, args []interface{}) (driver.Result, error) {
- // This is an optional interface, but it's implemented here
- // just to check that all the args of of the proper types.
- // ErrSkip is returned so the caller acts as if we didn't
- // implement this at all.
- err := checkSubsetTypes(args)
- if err != nil {
- return nil, err
- }
- return nil, driver.ErrSkip
-}
-
-func errf(msg string, args ...interface{}) error {
- return errors.New("fakedb: " + fmt.Sprintf(msg, args...))
-}
-
-// parts are table|selectCol1,selectCol2|whereCol=?,whereCol2=?
-// (note that where where columns must always contain ? marks,
-// just a limitation for fakedb)
-func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
- if len(parts) != 3 {
- return nil, errf("invalid SELECT syntax with %d parts; want 3", len(parts))
- }
- stmt.table = parts[0]
- stmt.colName = strings.Split(parts[1], ",")
- for n, colspec := range strings.Split(parts[2], ",") {
- if colspec == "" {
- continue
- }
- nameVal := strings.Split(colspec, "=")
- if len(nameVal) != 2 {
- return nil, errf("SELECT on table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
- }
- column, value := nameVal[0], nameVal[1]
- _, ok := c.db.columnType(stmt.table, column)
- if !ok {
- return nil, errf("SELECT on table %q references non-existent column %q", stmt.table, column)
- }
- if value != "?" {
- return nil, errf("SELECT on table %q has pre-bound value for where column %q; need a question mark",
- stmt.table, column)
- }
- stmt.whereCol = append(stmt.whereCol, column)
- stmt.placeholders++
- }
- return stmt, nil
-}
-
-// parts are table|col=type,col2=type2
-func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
- if len(parts) != 2 {
- return nil, errf("invalid CREATE syntax with %d parts; want 2", len(parts))
- }
- stmt.table = parts[0]
- for n, colspec := range strings.Split(parts[1], ",") {
- nameType := strings.Split(colspec, "=")
- if len(nameType) != 2 {
- return nil, errf("CREATE table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
- }
- stmt.colName = append(stmt.colName, nameType[0])
- stmt.colType = append(stmt.colType, nameType[1])
- }
- return stmt, nil
-}
-
-// parts are table|col=?,col2=val
-func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
- if len(parts) != 2 {
- return nil, errf("invalid INSERT syntax with %d parts; want 2", len(parts))
- }
- stmt.table = parts[0]
- for n, colspec := range strings.Split(parts[1], ",") {
- nameVal := strings.Split(colspec, "=")
- if len(nameVal) != 2 {
- return nil, errf("INSERT table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
- }
- column, value := nameVal[0], nameVal[1]
- ctype, ok := c.db.columnType(stmt.table, column)
- if !ok {
- return nil, errf("INSERT table %q references non-existent column %q", stmt.table, column)
- }
- stmt.colName = append(stmt.colName, column)
-
- if value != "?" {
- var subsetVal interface{}
- // Convert to driver subset type
- switch ctype {
- case "string":
- subsetVal = []byte(value)
- case "blob":
- subsetVal = []byte(value)
- case "int32":
- i, err := strconv.Atoi(value)
- if err != nil {
- return nil, errf("invalid conversion to int32 from %q", value)
- }
- subsetVal = int64(i) // int64 is a subset type, but not int32
- default:
- return nil, errf("unsupported conversion for pre-bound parameter %q to type %q", value, ctype)
- }
- stmt.colValue = append(stmt.colValue, subsetVal)
- } else {
- stmt.placeholders++
- stmt.placeholderConverter = append(stmt.placeholderConverter, converterForType(ctype))
- stmt.colValue = append(stmt.colValue, "?")
- }
- }
- return stmt, nil
-}
-
-func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
- if c.db == nil {
- panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
- }
- parts := strings.Split(query, "|")
- if len(parts) < 1 {
- return nil, errf("empty query")
- }
- cmd := parts[0]
- parts = parts[1:]
- stmt := &fakeStmt{q: query, c: c, cmd: cmd}
- c.incrStat(&c.stmtsMade)
- switch cmd {
- case "WIPE":
- // Nothing
- case "SELECT":
- return c.prepareSelect(stmt, parts)
- case "CREATE":
- return c.prepareCreate(stmt, parts)
- case "INSERT":
- return c.prepareInsert(stmt, parts)
- default:
- return nil, errf("unsupported command type %q", cmd)
- }
- return stmt, nil
-}
-
-func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter {
- return s.placeholderConverter[idx]
-}
-
-func (s *fakeStmt) Close() error {
- if !s.closed {
- s.c.incrStat(&s.c.stmtsClosed)
- s.closed = true
- }
- return nil
-}
-
-var errClosed = errors.New("fakedb: statement has been closed")
-
-func (s *fakeStmt) Exec(args []interface{}) (driver.Result, error) {
- if s.closed {
- return nil, errClosed
- }
- err := checkSubsetTypes(args)
- if err != nil {
- return nil, err
- }
-
- db := s.c.db
- switch s.cmd {
- case "WIPE":
- db.wipe()
- return driver.DDLSuccess, nil
- case "CREATE":
- if err := db.createTable(s.table, s.colName, s.colType); err != nil {
- return nil, err
- }
- return driver.DDLSuccess, nil
- case "INSERT":
- return s.execInsert(args)
- }
- fmt.Printf("EXEC statement, cmd=%q: %#v\n", s.cmd, s)
- return nil, fmt.Errorf("unimplemented statement Exec command type of %q", s.cmd)
-}
-
-func (s *fakeStmt) execInsert(args []interface{}) (driver.Result, error) {
- db := s.c.db
- if len(args) != s.placeholders {
- panic("error in pkg db; should only get here if size is correct")
- }
- db.mu.Lock()
- t, ok := db.table(s.table)
- db.mu.Unlock()
- if !ok {
- return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
- }
-
- t.mu.Lock()
- defer t.mu.Unlock()
-
- cols := make([]interface{}, len(t.colname))
- argPos := 0
- for n, colname := range s.colName {
- colidx := t.columnIndex(colname)
- if colidx == -1 {
- return nil, fmt.Errorf("fakedb: column %q doesn't exist or dropped since prepared statement was created", colname)
- }
- var val interface{}
- if strvalue, ok := s.colValue[n].(string); ok && strvalue == "?" {
- val = args[argPos]
- argPos++
- } else {
- val = s.colValue[n]
- }
- cols[colidx] = val
- }
-
- t.rows = append(t.rows, &row{cols: cols})
- return driver.RowsAffected(1), nil
-}
-
-func (s *fakeStmt) Query(args []interface{}) (driver.Rows, error) {
- if s.closed {
- return nil, errClosed
- }
- err := checkSubsetTypes(args)
- if err != nil {
- return nil, err
- }
-
- db := s.c.db
- if len(args) != s.placeholders {
- panic("error in pkg db; should only get here if size is correct")
- }
-
- db.mu.Lock()
- t, ok := db.table(s.table)
- db.mu.Unlock()
- if !ok {
- return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
- }
- t.mu.Lock()
- defer t.mu.Unlock()
-
- colIdx := make(map[string]int) // select column name -> column index in table
- for _, name := range s.colName {
- idx := t.columnIndex(name)
- if idx == -1 {
- return nil, fmt.Errorf("fakedb: unknown column name %q", name)
- }
- colIdx[name] = idx
- }
-
- mrows := []*row{}
-rows:
- for _, trow := range t.rows {
- // Process the where clause, skipping non-match rows. This is lazy
- // and just uses fmt.Sprintf("%v") to test equality. Good enough
- // for test code.
- for widx, wcol := range s.whereCol {
- idx := t.columnIndex(wcol)
- if idx == -1 {
- return nil, fmt.Errorf("db: invalid where clause column %q", wcol)
- }
- tcol := trow.cols[idx]
- if bs, ok := tcol.([]byte); ok {
- // lazy hack to avoid sprintf %v on a []byte
- tcol = string(bs)
- }
- if fmt.Sprintf("%v", tcol) != fmt.Sprintf("%v", args[widx]) {
- continue rows
- }
- }
- mrow := &row{cols: make([]interface{}, len(s.colName))}
- for seli, name := range s.colName {
- mrow.cols[seli] = trow.cols[colIdx[name]]
- }
- mrows = append(mrows, mrow)
- }
-
- cursor := &rowsCursor{
- pos: -1,
- rows: mrows,
- cols: s.colName,
- }
- return cursor, nil
-}
-
-func (s *fakeStmt) NumInput() int {
- return s.placeholders
-}
-
-func (tx *fakeTx) Commit() error {
- tx.c.currTx = nil
- return nil
-}
-
-func (tx *fakeTx) Rollback() error {
- tx.c.currTx = nil
- return nil
-}
-
-type rowsCursor struct {
- cols []string
- pos int
- rows []*row
- closed bool
-
- // a clone of slices to give out to clients, indexed by the
- // the original slice's first byte address. we clone them
- // just so we're able to corrupt them on close.
- bytesClone map[*byte][]byte
-}
-
-func (rc *rowsCursor) Close() error {
- if !rc.closed {
- for _, bs := range rc.bytesClone {
- bs[0] = 255 // first byte corrupted
- }
- }
- rc.closed = true
- return nil
-}
-
-func (rc *rowsCursor) Columns() []string {
- return rc.cols
-}
-
-func (rc *rowsCursor) Next(dest []interface{}) error {
- if rc.closed {
- return errors.New("fakedb: cursor is closed")
- }
- rc.pos++
- if rc.pos >= len(rc.rows) {
- return io.EOF // per interface spec
- }
- for i, v := range rc.rows[rc.pos].cols {
- // TODO(bradfitz): convert to subset types? naah, I
- // think the subset types should only be input to
- // driver, but the sql package should be able to handle
- // a wider range of types coming out of drivers. all
- // for ease of drivers, and to prevent drivers from
- // messing up conversions or doing them differently.
- dest[i] = v
-
- if bs, ok := v.([]byte); ok {
- if rc.bytesClone == nil {
- rc.bytesClone = make(map[*byte][]byte)
- }
- clone, ok := rc.bytesClone[&bs[0]]
- if !ok {
- clone = make([]byte, len(bs))
- copy(clone, bs)
- rc.bytesClone[&bs[0]] = clone
- }
- dest[i] = clone
- }
- }
- return nil
-}
-
-func converterForType(typ string) driver.ValueConverter {
- switch typ {
- case "bool":
- return driver.Bool
- case "int32":
- return driver.Int32
- case "string":
- return driver.String
- case "datetime":
- return driver.DefaultParameterConverter
- }
- panic("invalid fakedb column type of " + typ)
-}
diff --git a/libgo/go/exp/sql/sql.go b/libgo/go/exp/sql/sql.go
deleted file mode 100644
index 4e68c3e..0000000
--- a/libgo/go/exp/sql/sql.go
+++ /dev/null
@@ -1,860 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package sql provides a generic interface around SQL (or SQL-like)
-// databases.
-package sql
-
-import (
- "errors"
- "fmt"
- "io"
- "sync"
-
- "exp/sql/driver"
-)
-
-var drivers = make(map[string]driver.Driver)
-
-// Register makes a database driver available by the provided name.
-// If Register is called twice with the same name or if driver is nil,
-// it panics.
-func Register(name string, driver driver.Driver) {
- if driver == nil {
- panic("sql: Register driver is nil")
- }
- if _, dup := drivers[name]; dup {
- panic("sql: Register called twice for driver " + name)
- }
- drivers[name] = driver
-}
-
-// NullableString represents a string that may be null.
-// NullableString implements the ScannerInto interface so
-// it can be used as a scan destination:
-//
-// var s NullableString
-// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)
-// ...
-// if s.Valid {
-// // use s.String
-// } else {
-// // NULL value
-// }
-//
-// TODO(bradfitz): add other types.
-type NullableString struct {
- String string
- Valid bool // Valid is true if String is not NULL
-}
-
-// ScanInto implements the ScannerInto interface.
-func (ms *NullableString) ScanInto(value interface{}) error {
- if value == nil {
- ms.String, ms.Valid = "", false
- return nil
- }
- ms.Valid = true
- return convertAssign(&ms.String, value)
-}
-
-// ScannerInto is an interface used by Scan.
-type ScannerInto interface {
- // ScanInto assigns a value from a database driver.
- //
- // The value will be of one of the following restricted
- // set of types:
- //
- // int64
- // float64
- // bool
- // []byte
- // nil - for NULL values
- //
- // An error should be returned if the value can not be stored
- // without loss of information.
- ScanInto(value interface{}) error
-}
-
-// ErrNoRows is returned by Scan when QueryRow doesn't return a
-// row. In such a case, QueryRow returns a placeholder *Row value that
-// defers this error until a Scan.
-var ErrNoRows = errors.New("sql: no rows in result set")
-
-// DB is a database handle. It's safe for concurrent use by multiple
-// goroutines.
-type DB struct {
- driver driver.Driver
- dsn string
-
- mu sync.Mutex // protects freeConn and closed
- freeConn []driver.Conn
- closed bool
-}
-
-// Open opens a database specified by its database driver name and a
-// driver-specific data source name, usually consisting of at least a
-// database name and connection information.
-//
-// Most users will open a database via a driver-specific connection
-// helper function that returns a *DB.
-func Open(driverName, dataSourceName string) (*DB, error) {
- driver, ok := drivers[driverName]
- if !ok {
- return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
- }
- return &DB{driver: driver, dsn: dataSourceName}, nil
-}
-
-// Close closes the database, releasing any open resources.
-func (db *DB) Close() error {
- db.mu.Lock()
- defer db.mu.Unlock()
- var err error
- for _, c := range db.freeConn {
- err1 := c.Close()
- if err1 != nil {
- err = err1
- }
- }
- db.freeConn = nil
- db.closed = true
- return err
-}
-
-func (db *DB) maxIdleConns() int {
- const defaultMaxIdleConns = 2
- // TODO(bradfitz): ask driver, if supported, for its default preference
- // TODO(bradfitz): let users override?
- return defaultMaxIdleConns
-}
-
-// conn returns a newly-opened or cached driver.Conn
-func (db *DB) conn() (driver.Conn, error) {
- db.mu.Lock()
- if db.closed {
- db.mu.Unlock()
- return nil, errors.New("sql: database is closed")
- }
- if n := len(db.freeConn); n > 0 {
- conn := db.freeConn[n-1]
- db.freeConn = db.freeConn[:n-1]
- db.mu.Unlock()
- return conn, nil
- }
- db.mu.Unlock()
- return db.driver.Open(db.dsn)
-}
-
-func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) {
- db.mu.Lock()
- defer db.mu.Unlock()
- for n, conn := range db.freeConn {
- if conn == wanted {
- db.freeConn[n] = db.freeConn[len(db.freeConn)-1]
- db.freeConn = db.freeConn[:len(db.freeConn)-1]
- return wanted, true
- }
- }
- return nil, false
-}
-
-func (db *DB) putConn(c driver.Conn) {
- db.mu.Lock()
- defer db.mu.Unlock()
- if n := len(db.freeConn); !db.closed && n < db.maxIdleConns() {
- db.freeConn = append(db.freeConn, c)
- return
- }
- db.closeConn(c) // TODO(bradfitz): release lock before calling this?
-}
-
-func (db *DB) closeConn(c driver.Conn) {
- // TODO: check to see if we need this Conn for any prepared statements
- // that are active.
- c.Close()
-}
-
-// Prepare creates a prepared statement for later execution.
-func (db *DB) Prepare(query string) (*Stmt, error) {
- // TODO: check if db.driver supports an optional
- // driver.Preparer interface and call that instead, if so,
- // otherwise we make a prepared statement that's bound
- // to a connection, and to execute this prepared statement
- // we either need to use this connection (if it's free), else
- // get a new connection + re-prepare + execute on that one.
- ci, err := db.conn()
- if err != nil {
- return nil, err
- }
- defer db.putConn(ci)
- si, err := ci.Prepare(query)
- if err != nil {
- return nil, err
- }
- stmt := &Stmt{
- db: db,
- query: query,
- css: []connStmt{{ci, si}},
- }
- return stmt, nil
-}
-
-// Exec executes a query without returning any rows.
-func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
- sargs, err := subsetTypeArgs(args)
- if err != nil {
- return nil, err
- }
-
- ci, err := db.conn()
- if err != nil {
- return nil, err
- }
- defer db.putConn(ci)
-
- if execer, ok := ci.(driver.Execer); ok {
- resi, err := execer.Exec(query, sargs)
- if err != driver.ErrSkip {
- if err != nil {
- return nil, err
- }
- return result{resi}, nil
- }
- }
-
- sti, err := ci.Prepare(query)
- if err != nil {
- return nil, err
- }
- defer sti.Close()
-
- resi, err := sti.Exec(sargs)
- if err != nil {
- return nil, err
- }
- return result{resi}, nil
-}
-
-// Query executes a query that returns rows, typically a SELECT.
-func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
- stmt, err := db.Prepare(query)
- if err != nil {
- return nil, err
- }
- rows, err := stmt.Query(args...)
- if err != nil {
- stmt.Close()
- return nil, err
- }
- rows.closeStmt = stmt
- return rows, nil
-}
-
-// QueryRow executes a query that is expected to return at most one row.
-// QueryRow always return a non-nil value. Errors are deferred until
-// Row's Scan method is called.
-func (db *DB) QueryRow(query string, args ...interface{}) *Row {
- rows, err := db.Query(query, args...)
- return &Row{rows: rows, err: err}
-}
-
-// Begin starts a transaction. The isolation level is dependent on
-// the driver.
-func (db *DB) Begin() (*Tx, error) {
- ci, err := db.conn()
- if err != nil {
- return nil, err
- }
- txi, err := ci.Begin()
- if err != nil {
- db.putConn(ci)
- return nil, fmt.Errorf("sql: failed to Begin transaction: %v", err)
- }
- return &Tx{
- db: db,
- ci: ci,
- txi: txi,
- }, nil
-}
-
-// DriverDatabase returns the database's underlying driver.
-func (db *DB) Driver() driver.Driver {
- return db.driver
-}
-
-// Tx is an in-progress database transaction.
-//
-// A transaction must end with a call to Commit or Rollback.
-//
-// After a call to Commit or Rollback, all operations on the
-// transaction fail with ErrTransactionFinished.
-type Tx struct {
- db *DB
-
- // ci is owned exclusively until Commit or Rollback, at which point
- // it's returned with putConn.
- ci driver.Conn
- txi driver.Tx
-
- // cimu is held while somebody is using ci (between grabConn
- // and releaseConn)
- cimu sync.Mutex
-
- // done transitions from false to true exactly once, on Commit
- // or Rollback. once done, all operations fail with
- // ErrTransactionFinished.
- done bool
-}
-
-var ErrTransactionFinished = errors.New("sql: Transaction has already been committed or rolled back")
-
-func (tx *Tx) close() {
- if tx.done {
- panic("double close") // internal error
- }
- tx.done = true
- tx.db.putConn(tx.ci)
- tx.ci = nil
- tx.txi = nil
-}
-
-func (tx *Tx) grabConn() (driver.Conn, error) {
- if tx.done {
- return nil, ErrTransactionFinished
- }
- tx.cimu.Lock()
- return tx.ci, nil
-}
-
-func (tx *Tx) releaseConn() {
- tx.cimu.Unlock()
-}
-
-// Commit commits the transaction.
-func (tx *Tx) Commit() error {
- if tx.done {
- return ErrTransactionFinished
- }
- defer tx.close()
- return tx.txi.Commit()
-}
-
-// Rollback aborts the transaction.
-func (tx *Tx) Rollback() error {
- if tx.done {
- return ErrTransactionFinished
- }
- defer tx.close()
- return tx.txi.Rollback()
-}
-
-// Prepare creates a prepared statement for use within a transaction.
-//
-// The returned statement operates within the transaction and can no longer
-// be used once the transaction has been committed or rolled back.
-//
-// To use an existing prepared statement on this transaction, see Tx.Stmt.
-func (tx *Tx) Prepare(query string) (*Stmt, error) {
- // TODO(bradfitz): We could be more efficient here and either
- // provide a method to take an existing Stmt (created on
- // perhaps a different Conn), and re-create it on this Conn if
- // necessary. Or, better: keep a map in DB of query string to
- // Stmts, and have Stmt.Execute do the right thing and
- // re-prepare if the Conn in use doesn't have that prepared
- // statement. But we'll want to avoid caching the statement
- // in the case where we only call conn.Prepare implicitly
- // (such as in db.Exec or tx.Exec), but the caller package
- // can't be holding a reference to the returned statement.
- // Perhaps just looking at the reference count (by noting
- // Stmt.Close) would be enough. We might also want a finalizer
- // on Stmt to drop the reference count.
- ci, err := tx.grabConn()
- if err != nil {
- return nil, err
- }
- defer tx.releaseConn()
-
- si, err := ci.Prepare(query)
- if err != nil {
- return nil, err
- }
-
- stmt := &Stmt{
- db: tx.db,
- tx: tx,
- txsi: si,
- query: query,
- }
- return stmt, nil
-}
-
-// Stmt returns a transaction-specific prepared statement from
-// an existing statement.
-//
-// Example:
-// updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")
-// ...
-// tx, err := db.Begin()
-// ...
-// res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
-func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
- // TODO(bradfitz): optimize this. Currently this re-prepares
- // each time. This is fine for now to illustrate the API but
- // we should really cache already-prepared statements
- // per-Conn. See also the big comment in Tx.Prepare.
-
- if tx.db != stmt.db {
- return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
- }
- ci, err := tx.grabConn()
- if err != nil {
- return &Stmt{stickyErr: err}
- }
- defer tx.releaseConn()
- si, err := ci.Prepare(stmt.query)
- return &Stmt{
- db: tx.db,
- tx: tx,
- txsi: si,
- query: stmt.query,
- stickyErr: err,
- }
-}
-
-// Exec executes a query that doesn't return rows.
-// For example: an INSERT and UPDATE.
-func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
- ci, err := tx.grabConn()
- if err != nil {
- return nil, err
- }
- defer tx.releaseConn()
-
- if execer, ok := ci.(driver.Execer); ok {
- resi, err := execer.Exec(query, args)
- if err != nil {
- return nil, err
- }
- return result{resi}, nil
- }
-
- sti, err := ci.Prepare(query)
- if err != nil {
- return nil, err
- }
- defer sti.Close()
-
- sargs, err := subsetTypeArgs(args)
- if err != nil {
- return nil, err
- }
-
- resi, err := sti.Exec(sargs)
- if err != nil {
- return nil, err
- }
- return result{resi}, nil
-}
-
-// Query executes a query that returns rows, typically a SELECT.
-func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
- if tx.done {
- return nil, ErrTransactionFinished
- }
- stmt, err := tx.Prepare(query)
- if err != nil {
- return nil, err
- }
- defer stmt.Close()
- return stmt.Query(args...)
-}
-
-// QueryRow executes a query that is expected to return at most one row.
-// QueryRow always return a non-nil value. Errors are deferred until
-// Row's Scan method is called.
-func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
- rows, err := tx.Query(query, args...)
- return &Row{rows: rows, err: err}
-}
-
-// connStmt is a prepared statement on a particular connection.
-type connStmt struct {
- ci driver.Conn
- si driver.Stmt
-}
-
-// Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines.
-type Stmt struct {
- // Immutable:
- db *DB // where we came from
- query string // that created the Stmt
- stickyErr error // if non-nil, this error is returned for all operations
-
- // If in a transaction, else both nil:
- tx *Tx
- txsi driver.Stmt
-
- mu sync.Mutex // protects the rest of the fields
- closed bool
-
- // css is a list of underlying driver statement interfaces
- // that are valid on particular connections. This is only
- // used if tx == nil and one is found that has idle
- // connections. If tx != nil, txsi is always used.
- css []connStmt
-}
-
-// Exec executes a prepared statement with the given arguments and
-// returns a Result summarizing the effect of the statement.
-func (s *Stmt) Exec(args ...interface{}) (Result, error) {
- _, releaseConn, si, err := s.connStmt()
- if err != nil {
- return nil, err
- }
- defer releaseConn()
-
- // -1 means the driver doesn't know how to count the number of
- // placeholders, so we won't sanity check input here and instead let the
- // driver deal with errors.
- if want := si.NumInput(); want != -1 && len(args) != want {
- return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
- }
-
- // Convert args to subset types.
- if cc, ok := si.(driver.ColumnConverter); ok {
- for n, arg := range args {
- args[n], err = cc.ColumnConverter(n).ConvertValue(arg)
- if err != nil {
- return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
- }
- if !driver.IsParameterSubsetType(args[n]) {
- return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T",
- arg, args[n])
- }
- }
- } else {
- for n, arg := range args {
- args[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
- if err != nil {
- return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
- }
- }
- }
-
- resi, err := si.Exec(args)
- if err != nil {
- return nil, err
- }
- return result{resi}, nil
-}
-
-// connStmt returns a free driver connection on which to execute the
-// statement, a function to call to release the connection, and a
-// statement bound to that connection.
-func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, err error) {
- if err = s.stickyErr; err != nil {
- return
- }
- s.mu.Lock()
- if s.closed {
- s.mu.Unlock()
- err = errors.New("sql: statement is closed")
- return
- }
-
- // In a transaction, we always use the connection that the
- // transaction was created on.
- if s.tx != nil {
- s.mu.Unlock()
- ci, err = s.tx.grabConn() // blocks, waiting for the connection.
- if err != nil {
- return
- }
- releaseConn = func() { s.tx.releaseConn() }
- return ci, releaseConn, s.txsi, nil
- }
-
- var cs connStmt
- match := false
- for _, v := range s.css {
- // TODO(bradfitz): lazily clean up entries in this
- // list with dead conns while enumerating
- if _, match = s.db.connIfFree(cs.ci); match {
- cs = v
- break
- }
- }
- s.mu.Unlock()
-
- // Make a new conn if all are busy.
- // TODO(bradfitz): or wait for one? make configurable later?
- if !match {
- ci, err := s.db.conn()
- if err != nil {
- return nil, nil, nil, err
- }
- si, err := ci.Prepare(s.query)
- if err != nil {
- return nil, nil, nil, err
- }
- s.mu.Lock()
- cs = connStmt{ci, si}
- s.css = append(s.css, cs)
- s.mu.Unlock()
- }
-
- conn := cs.ci
- releaseConn = func() { s.db.putConn(conn) }
- return conn, releaseConn, cs.si, nil
-}
-
-// Query executes a prepared query statement with the given arguments
-// and returns the query results as a *Rows.
-func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
- ci, releaseConn, si, err := s.connStmt()
- if err != nil {
- return nil, err
- }
-
- // -1 means the driver doesn't know how to count the number of
- // placeholders, so we won't sanity check input here and instead let the
- // driver deal with errors.
- if want := si.NumInput(); want != -1 && len(args) != want {
- return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args))
- }
- sargs, err := subsetTypeArgs(args)
- if err != nil {
- return nil, err
- }
- rowsi, err := si.Query(sargs)
- if err != nil {
- s.db.putConn(ci)
- return nil, err
- }
- // Note: ownership of ci passes to the *Rows, to be freed
- // with releaseConn.
- rows := &Rows{
- db: s.db,
- ci: ci,
- releaseConn: releaseConn,
- rowsi: rowsi,
- }
- return rows, nil
-}
-
-// QueryRow executes a prepared query statement with the given arguments.
-// If an error occurs during the execution of the statement, that error will
-// be returned by a call to Scan on the returned *Row, which is always non-nil.
-// If the query selects no rows, the *Row's Scan will return ErrNoRows.
-// Otherwise, the *Row's Scan scans the first selected row and discards
-// the rest.
-//
-// Example usage:
-//
-// var name string
-// err := nameByUseridStmt.QueryRow(id).Scan(&s)
-func (s *Stmt) QueryRow(args ...interface{}) *Row {
- rows, err := s.Query(args...)
- if err != nil {
- return &Row{err: err}
- }
- return &Row{rows: rows}
-}
-
-// Close closes the statement.
-func (s *Stmt) Close() error {
- if s.stickyErr != nil {
- return s.stickyErr
- }
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.closed {
- return nil
- }
- s.closed = true
-
- if s.tx != nil {
- s.txsi.Close()
- } else {
- for _, v := range s.css {
- if ci, match := s.db.connIfFree(v.ci); match {
- v.si.Close()
- s.db.putConn(ci)
- } else {
- // TODO(bradfitz): care that we can't close
- // this statement because the statement's
- // connection is in use?
- }
- }
- }
- return nil
-}
-
-// Rows is the result of a query. Its cursor starts before the first row
-// of the result set. Use Next to advance through the rows:
-//
-// rows, err := db.Query("SELECT ...")
-// ...
-// for rows.Next() {
-// var id int
-// var name string
-// err = rows.Scan(&id, &name)
-// ...
-// }
-// err = rows.Err() // get any error encountered during iteration
-// ...
-type Rows struct {
- db *DB
- ci driver.Conn // owned; must call putconn when closed to release
- releaseConn func()
- rowsi driver.Rows
-
- closed bool
- lastcols []interface{}
- lasterr error
- closeStmt *Stmt // if non-nil, statement to Close on close
-}
-
-// Next prepares the next result row for reading with the Scan method.
-// It returns true on success, false if there is no next result row.
-// Every call to Scan, even the first one, must be preceded by a call
-// to Next.
-func (rs *Rows) Next() bool {
- if rs.closed {
- return false
- }
- if rs.lasterr != nil {
- return false
- }
- if rs.lastcols == nil {
- rs.lastcols = make([]interface{}, len(rs.rowsi.Columns()))
- }
- rs.lasterr = rs.rowsi.Next(rs.lastcols)
- if rs.lasterr == io.EOF {
- rs.Close()
- }
- return rs.lasterr == nil
-}
-
-// Err returns the error, if any, that was encountered during iteration.
-func (rs *Rows) Err() error {
- if rs.lasterr == io.EOF {
- return nil
- }
- return rs.lasterr
-}
-
-// Columns returns the column names.
-// Columns returns an error if the rows are closed, or if the rows
-// are from QueryRow and there was a deferred error.
-func (rs *Rows) Columns() ([]string, error) {
- if rs.closed {
- return nil, errors.New("sql: Rows are closed")
- }
- if rs.rowsi == nil {
- return nil, errors.New("sql: no Rows available")
- }
- return rs.rowsi.Columns(), nil
-}
-
-// Scan copies the columns in the current row into the values pointed
-// at by dest. If dest contains pointers to []byte, the slices should
-// not be modified and should only be considered valid until the next
-// call to Next or Scan.
-func (rs *Rows) Scan(dest ...interface{}) error {
- if rs.closed {
- return errors.New("sql: Rows closed")
- }
- if rs.lasterr != nil {
- return rs.lasterr
- }
- if rs.lastcols == nil {
- return errors.New("sql: Scan called without calling Next")
- }
- if len(dest) != len(rs.lastcols) {
- return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
- }
- for i, sv := range rs.lastcols {
- err := convertAssign(dest[i], sv)
- if err != nil {
- return fmt.Errorf("sql: Scan error on column index %d: %v", i, err)
- }
- }
- return nil
-}
-
-// Close closes the Rows, preventing further enumeration. If the
-// end is encountered, the Rows are closed automatically. Close
-// is idempotent.
-func (rs *Rows) Close() error {
- if rs.closed {
- return nil
- }
- rs.closed = true
- err := rs.rowsi.Close()
- rs.releaseConn()
- if rs.closeStmt != nil {
- rs.closeStmt.Close()
- }
- return err
-}
-
-// Row is the result of calling QueryRow to select a single row.
-type Row struct {
- // One of these two will be non-nil:
- err error // deferred error for easy chaining
- rows *Rows
-}
-
-// Scan copies the columns from the matched row into the values
-// pointed at by dest. If more than one row matches the query,
-// Scan uses the first row and discards the rest. If no row matches
-// the query, Scan returns ErrNoRows.
-func (r *Row) Scan(dest ...interface{}) error {
- if r.err != nil {
- return r.err
- }
- defer r.rows.Close()
- if !r.rows.Next() {
- return ErrNoRows
- }
- err := r.rows.Scan(dest...)
- if err != nil {
- return err
- }
-
- // TODO(bradfitz): for now we need to defensively clone all
- // []byte that the driver returned, since we're about to close
- // the Rows in our defer, when we return from this function.
- // the contract with the driver.Next(...) interface is that it
- // can return slices into read-only temporary memory that's
- // only valid until the next Scan/Close. But the TODO is that
- // for a lot of drivers, this copy will be unnecessary. We
- // should provide an optional interface for drivers to
- // implement to say, "don't worry, the []bytes that I return
- // from Next will not be modified again." (for instance, if
- // they were obtained from the network anyway) But for now we
- // don't care.
- for _, dp := range dest {
- b, ok := dp.(*[]byte)
- if !ok {
- continue
- }
- clone := make([]byte, len(*b))
- copy(clone, *b)
- *b = clone
- }
- return nil
-}
-
-// A Result summarizes an executed SQL command.
-type Result interface {
- LastInsertId() (int64, error)
- RowsAffected() (int64, error)
-}
-
-type result struct {
- driver.Result
-}
diff --git a/libgo/go/exp/sql/sql_test.go b/libgo/go/exp/sql/sql_test.go
deleted file mode 100644
index 3f98a8c..0000000
--- a/libgo/go/exp/sql/sql_test.go
+++ /dev/null
@@ -1,305 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package sql
-
-import (
- "reflect"
- "strings"
- "testing"
- "time"
-)
-
-const fakeDBName = "foo"
-
-var chrisBirthday = time.Unix(123456789, 0)
-
-func newTestDB(t *testing.T, name string) *DB {
- db, err := Open("test", fakeDBName)
- if err != nil {
- t.Fatalf("Open: %v", err)
- }
- if _, err := db.Exec("WIPE"); err != nil {
- t.Fatalf("exec wipe: %v", err)
- }
- if name == "people" {
- exec(t, db, "CREATE|people|name=string,age=int32,photo=blob,dead=bool,bdate=datetime")
- exec(t, db, "INSERT|people|name=Alice,age=?,photo=APHOTO", 1)
- exec(t, db, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2)
- exec(t, db, "INSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday)
- }
- return db
-}
-
-func exec(t *testing.T, db *DB, query string, args ...interface{}) {
- _, err := db.Exec(query, args...)
- if err != nil {
- t.Fatalf("Exec of %q: %v", query, err)
- }
-}
-
-func closeDB(t *testing.T, db *DB) {
- err := db.Close()
- if err != nil {
- t.Fatalf("error closing DB: %v", err)
- }
-}
-
-func TestQuery(t *testing.T) {
- db := newTestDB(t, "people")
- defer closeDB(t, db)
- rows, err := db.Query("SELECT|people|age,name|")
- if err != nil {
- t.Fatalf("Query: %v", err)
- }
- type row struct {
- age int
- name string
- }
- got := []row{}
- for rows.Next() {
- var r row
- err = rows.Scan(&r.age, &r.name)
- if err != nil {
- t.Fatalf("Scan: %v", err)
- }
- got = append(got, r)
- }
- err = rows.Err()
- if err != nil {
- t.Fatalf("Err: %v", err)
- }
- want := []row{
- {age: 1, name: "Alice"},
- {age: 2, name: "Bob"},
- {age: 3, name: "Chris"},
- }
- if !reflect.DeepEqual(got, want) {
- t.Logf(" got: %#v\nwant: %#v", got, want)
- }
-
- // And verify that the final rows.Next() call, which hit EOF,
- // also closed the rows connection.
- if n := len(db.freeConn); n != 1 {
- t.Errorf("free conns after query hitting EOF = %d; want 1", n)
- }
-}
-
-func TestRowsColumns(t *testing.T) {
- db := newTestDB(t, "people")
- defer closeDB(t, db)
- rows, err := db.Query("SELECT|people|age,name|")
- if err != nil {
- t.Fatalf("Query: %v", err)
- }
- cols, err := rows.Columns()
- if err != nil {
- t.Fatalf("Columns: %v", err)
- }
- want := []string{"age", "name"}
- if !reflect.DeepEqual(cols, want) {
- t.Errorf("got %#v; want %#v", cols, want)
- }
-}
-
-func TestQueryRow(t *testing.T) {
- db := newTestDB(t, "people")
- defer closeDB(t, db)
- var name string
- var age int
- var birthday time.Time
-
- err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age)
- if err == nil || !strings.Contains(err.Error(), "expected 2 destination arguments") {
- t.Errorf("expected error from wrong number of arguments; actually got: %v", err)
- }
-
- err = db.QueryRow("SELECT|people|bdate|age=?", 3).Scan(&birthday)
- if err != nil || !birthday.Equal(chrisBirthday) {
- t.Errorf("chris birthday = %v, err = %v; want %v", birthday, err, chrisBirthday)
- }
-
- err = db.QueryRow("SELECT|people|age,name|age=?", 2).Scan(&age, &name)
- if err != nil {
- t.Fatalf("age QueryRow+Scan: %v", err)
- }
- if name != "Bob" {
- t.Errorf("expected name Bob, got %q", name)
- }
- if age != 2 {
- t.Errorf("expected age 2, got %d", age)
- }
-
- err = db.QueryRow("SELECT|people|age,name|name=?", "Alice").Scan(&age, &name)
- if err != nil {
- t.Fatalf("name QueryRow+Scan: %v", err)
- }
- if name != "Alice" {
- t.Errorf("expected name Alice, got %q", name)
- }
- if age != 1 {
- t.Errorf("expected age 1, got %d", age)
- }
-
- var photo []byte
- err = db.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo)
- if err != nil {
- t.Fatalf("photo QueryRow+Scan: %v", err)
- }
- want := []byte("APHOTO")
- if !reflect.DeepEqual(photo, want) {
- t.Errorf("photo = %q; want %q", photo, want)
- }
-}
-
-func TestStatementErrorAfterClose(t *testing.T) {
- db := newTestDB(t, "people")
- defer closeDB(t, db)
- stmt, err := db.Prepare("SELECT|people|age|name=?")
- if err != nil {
- t.Fatalf("Prepare: %v", err)
- }
- err = stmt.Close()
- if err != nil {
- t.Fatalf("Close: %v", err)
- }
- var name string
- err = stmt.QueryRow("foo").Scan(&name)
- if err == nil {
- t.Errorf("expected error from QueryRow.Scan after Stmt.Close")
- }
-}
-
-func TestStatementQueryRow(t *testing.T) {
- db := newTestDB(t, "people")
- defer closeDB(t, db)
- stmt, err := db.Prepare("SELECT|people|age|name=?")
- if err != nil {
- t.Fatalf("Prepare: %v", err)
- }
- var age int
- for n, tt := range []struct {
- name string
- want int
- }{
- {"Alice", 1},
- {"Bob", 2},
- {"Chris", 3},
- } {
- if err := stmt.QueryRow(tt.name).Scan(&age); err != nil {
- t.Errorf("%d: on %q, QueryRow/Scan: %v", n, tt.name, err)
- } else if age != tt.want {
- t.Errorf("%d: age=%d, want %d", n, age, tt.want)
- }
- }
-
-}
-
-// just a test of fakedb itself
-func TestBogusPreboundParameters(t *testing.T) {
- db := newTestDB(t, "foo")
- defer closeDB(t, db)
- exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
- _, err := db.Prepare("INSERT|t1|name=?,age=bogusconversion")
- if err == nil {
- t.Fatalf("expected error")
- }
- if err.Error() != `fakedb: invalid conversion to int32 from "bogusconversion"` {
- t.Errorf("unexpected error: %v", err)
- }
-}
-
-func TestExec(t *testing.T) {
- db := newTestDB(t, "foo")
- defer closeDB(t, db)
- exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
- stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
- if err != nil {
- t.Errorf("Stmt, err = %v, %v", stmt, err)
- }
-
- type execTest struct {
- args []interface{}
- wantErr string
- }
- execTests := []execTest{
- // Okay:
- {[]interface{}{"Brad", 31}, ""},
- {[]interface{}{"Brad", int64(31)}, ""},
- {[]interface{}{"Bob", "32"}, ""},
- {[]interface{}{7, 9}, ""},
-
- // Invalid conversions:
- {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting Exec argument #1's type: sql/driver: value 4294967295 overflows int32"},
- {[]interface{}{"Brad", "strconv fail"}, "sql: converting Exec argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
-
- // Wrong number of args:
- {[]interface{}{}, "sql: expected 2 arguments, got 0"},
- {[]interface{}{1, 2, 3}, "sql: expected 2 arguments, got 3"},
- }
- for n, et := range execTests {
- _, err := stmt.Exec(et.args...)
- errStr := ""
- if err != nil {
- errStr = err.Error()
- }
- if errStr != et.wantErr {
- t.Errorf("stmt.Execute #%d: for %v, got error %q, want error %q",
- n, et.args, errStr, et.wantErr)
- }
- }
-}
-
-func TestTxStmt(t *testing.T) {
- db := newTestDB(t, "")
- defer closeDB(t, db)
- exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
- stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
- if err != nil {
- t.Fatalf("Stmt, err = %v, %v", stmt, err)
- }
- tx, err := db.Begin()
- if err != nil {
- t.Fatalf("Begin = %v", err)
- }
- _, err = tx.Stmt(stmt).Exec("Bobby", 7)
- if err != nil {
- t.Fatalf("Exec = %v", err)
- }
- err = tx.Commit()
- if err != nil {
- t.Fatalf("Commit = %v", err)
- }
-}
-
-// Tests fix for issue 2542, that we release a lock when querying on
-// a closed connection.
-func TestIssue2542Deadlock(t *testing.T) {
- db := newTestDB(t, "people")
- closeDB(t, db)
- for i := 0; i < 2; i++ {
- _, err := db.Query("SELECT|people|age,name|")
- if err == nil {
- t.Fatalf("expected error")
- }
- }
-}
-
-func TestQueryRowClosingStmt(t *testing.T) {
- db := newTestDB(t, "people")
- defer closeDB(t, db)
- var name string
- var age int
- err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age, &name)
- if err != nil {
- t.Fatal(err)
- }
- if len(db.freeConn) != 1 {
- t.Fatalf("expected 1 free conn")
- }
- fakeConn := db.freeConn[0].(*fakeConn)
- if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != closed {
- t.Logf("statement close mismatch: made %d, closed %d", made, closed)
- }
-}
diff --git a/libgo/go/exp/ssh/client.go b/libgo/go/exp/ssh/client.go
index 8df8145..eb6c035 100644
--- a/libgo/go/exp/ssh/client.go
+++ b/libgo/go/exp/ssh/client.go
@@ -306,9 +306,8 @@ type clientChan struct {
stdout *chanReader // receives the payload of channelData messages
stderr *chanReader // receives the payload of channelExtendedData messages
msg chan interface{} // incoming messages
-
- theyClosed bool // indicates the close msg has been received from the remote side
- weClosed bool // incidates the close msg has been sent from our side
+ theyClosed bool // indicates the close msg has been received from the remote side
+ weClosed bool // incidates the close msg has been sent from our side
}
// newClientChan returns a partially constructed *clientChan
diff --git a/libgo/go/exp/ssh/messages.go b/libgo/go/exp/ssh/messages.go
index cebb560..34ad131 100644
--- a/libgo/go/exp/ssh/messages.go
+++ b/libgo/go/exp/ssh/messages.go
@@ -484,6 +484,26 @@ func intLength(n *big.Int) int {
return length
}
+func marshalUint32(to []byte, n uint32) []byte {
+ to[0] = byte(n >> 24)
+ to[1] = byte(n >> 16)
+ to[2] = byte(n >> 8)
+ to[3] = byte(n)
+ return to[4:]
+}
+
+func marshalUint64(to []byte, n uint64) []byte {
+ to[0] = byte(n >> 56)
+ to[1] = byte(n >> 48)
+ to[2] = byte(n >> 40)
+ to[3] = byte(n >> 32)
+ to[4] = byte(n >> 24)
+ to[5] = byte(n >> 16)
+ to[6] = byte(n >> 8)
+ to[7] = byte(n)
+ return to[8:]
+}
+
func marshalInt(to []byte, n *big.Int) []byte {
lengthBytes := to
to = to[4:]
diff --git a/libgo/go/exp/ssh/session.go b/libgo/go/exp/ssh/session.go
index 807dd87..ea4addb 100644
--- a/libgo/go/exp/ssh/session.go
+++ b/libgo/go/exp/ssh/session.go
@@ -70,7 +70,7 @@ type Session struct {
started bool // true once Start, Run or Shell is invoked.
copyFuncs []func() error
- errch chan error // one send per copyFunc
+ errors chan error // one send per copyFunc
// true if pipe method is active
stdinpipe, stdoutpipe, stderrpipe bool
@@ -244,10 +244,10 @@ func (s *Session) start() error {
setupFd(s)
}
- s.errch = make(chan error, len(s.copyFuncs))
+ s.errors = make(chan error, len(s.copyFuncs))
for _, fn := range s.copyFuncs {
go func(fn func() error) {
- s.errch <- fn()
+ s.errors <- fn()
}(fn)
}
return nil
@@ -270,7 +270,7 @@ func (s *Session) Wait() error {
var copyError error
for _ = range s.copyFuncs {
- if err := <-s.errch; err != nil && copyError == nil {
+ if err := <-s.errors; err != nil && copyError == nil {
copyError = err
}
}
diff --git a/libgo/go/exp/ssh/tcpip.go b/libgo/go/exp/ssh/tcpip.go
index bee41ee..e0c47bc 100644
--- a/libgo/go/exp/ssh/tcpip.go
+++ b/libgo/go/exp/ssh/tcpip.go
@@ -9,6 +9,7 @@ import (
"fmt"
"io"
"net"
+ "time"
)
// Dial initiates a connection to the addr from the remote host.
@@ -107,27 +108,25 @@ func (t *tcpchanconn) RemoteAddr() net.Addr {
return t.raddr
}
-// SetTimeout sets the read and write deadlines associated
+// SetDeadline sets the read and write deadlines associated
// with the connection.
-func (t *tcpchanconn) SetTimeout(nsec int64) error {
- if err := t.SetReadTimeout(nsec); err != nil {
+func (t *tcpchanconn) SetDeadline(deadline time.Time) error {
+ if err := t.SetReadDeadline(deadline); err != nil {
return err
}
- return t.SetWriteTimeout(nsec)
+ return t.SetWriteDeadline(deadline)
}
-// SetReadTimeout sets the time (in nanoseconds) that
-// Read will wait for data before returning an error with Timeout() == true.
-// Setting nsec == 0 (the default) disables the deadline.
-func (t *tcpchanconn) SetReadTimeout(nsec int64) error {
- return errors.New("ssh: tcpchan: timeout not supported")
+// SetReadDeadline sets the read deadline.
+// A zero value for t means Read will not time out.
+// After the deadline, the error from Read will implement net.Error
+// with Timeout() == true.
+func (t *tcpchanconn) SetReadDeadline(deadline time.Time) error {
+ return errors.New("ssh: tcpchan: deadline not supported")
}
-// SetWriteTimeout sets the time (in nanoseconds) that
-// Write will wait to send its data before returning an error with Timeout() == true.
-// Setting nsec == 0 (the default) disables the deadline.
-// Even if write times out, it may return n > 0, indicating that
-// some of the data was successfully written.
-func (t *tcpchanconn) SetWriteTimeout(nsec int64) error {
- return errors.New("ssh: tcpchan: timeout not supported")
+// SetWriteDeadline exists to satisfy the net.Conn interface
+// but is not implemented by this type. It always returns an error.
+func (t *tcpchanconn) SetWriteDeadline(deadline time.Time) error {
+ return errors.New("ssh: tcpchan: deadline not supported")
}
diff --git a/libgo/go/exp/ssh/transport.go b/libgo/go/exp/ssh/transport.go
index 2e7c955..e21bc4b 100644
--- a/libgo/go/exp/ssh/transport.go
+++ b/libgo/go/exp/ssh/transport.go
@@ -9,6 +9,7 @@ import (
"crypto"
"crypto/cipher"
"crypto/hmac"
+ "crypto/sha1"
"crypto/subtle"
"errors"
"hash"
@@ -266,7 +267,7 @@ func (c *common) setupKeys(d direction, K, H, sessionId []byte, hashFunc crypto.
generateKeyMaterial(key, d.keyTag, K, H, sessionId, h)
generateKeyMaterial(macKey, d.macKeyTag, K, H, sessionId, h)
- c.mac = truncatingMAC{12, hmac.NewSHA1(macKey)}
+ c.mac = truncatingMAC{12, hmac.New(sha1.New, macKey)}
cipher, err := cipherMode.createCipher(key, iv)
if err != nil {
@@ -328,6 +329,8 @@ func (t truncatingMAC) Size() int {
return t.length
}
+func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
+
// maxVersionStringBytes is the maximum number of bytes that we'll accept as a
// version string. In the event that the client is talking a different protocol
// we need to set a limit otherwise we will keep using more and more memory
@@ -337,7 +340,7 @@ const maxVersionStringBytes = 1024
// Read version string as specified by RFC 4253, section 4.2.
func readVersion(r io.Reader) ([]byte, error) {
versionString := make([]byte, 0, 64)
- var ok, seenCR bool
+ var ok bool
var buf [1]byte
forEachByte:
for len(versionString) < maxVersionStringBytes {
@@ -345,27 +348,22 @@ forEachByte:
if err != nil {
return nil, err
}
- b := buf[0]
-
- if !seenCR {
- if b == '\r' {
- seenCR = true
- }
- } else {
- if b == '\n' {
- ok = true
- break forEachByte
- } else {
- seenCR = false
- }
+ // The RFC says that the version should be terminated with \r\n
+ // but several SSH servers actually only send a \n.
+ if buf[0] == '\n' {
+ ok = true
+ break forEachByte
}
- versionString = append(versionString, b)
+ versionString = append(versionString, buf[0])
}
if !ok {
- return nil, errors.New("failed to read version string")
+ return nil, errors.New("ssh: failed to read version string")
}
- // We need to remove the CR from versionString
- return versionString[:len(versionString)-1], nil
+ // There might be a '\r' on the end which we should remove.
+ if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' {
+ versionString = versionString[:len(versionString)-1]
+ }
+ return versionString, nil
}
diff --git a/libgo/go/exp/ssh/transport_test.go b/libgo/go/exp/ssh/transport_test.go
index b2e2a7f..ab9177f 100644
--- a/libgo/go/exp/ssh/transport_test.go
+++ b/libgo/go/exp/ssh/transport_test.go
@@ -11,7 +11,7 @@ import (
)
func TestReadVersion(t *testing.T) {
- buf := []byte(serverVersion)
+ buf := serverVersion
result, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf)))
if err != nil {
t.Errorf("readVersion didn't read version correctly: %s", err)
@@ -21,6 +21,20 @@ func TestReadVersion(t *testing.T) {
}
}
+func TestReadVersionWithJustLF(t *testing.T) {
+ var buf []byte
+ buf = append(buf, serverVersion...)
+ buf = buf[:len(buf)-1]
+ buf[len(buf)-1] = '\n'
+ result, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf)))
+ if err != nil {
+ t.Error("readVersion failed to handle just a \n")
+ }
+ if !bytes.Equal(buf[:len(buf)-1], result) {
+ t.Errorf("version read did not match expected: got %x, want %x", result, buf[:len(buf)-1])
+ }
+}
+
func TestReadVersionTooLong(t *testing.T) {
buf := make([]byte, maxVersionStringBytes+1)
if _, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))); err == nil {
@@ -29,7 +43,7 @@ func TestReadVersionTooLong(t *testing.T) {
}
func TestReadVersionWithoutCRLF(t *testing.T) {
- buf := []byte(serverVersion)
+ buf := serverVersion
buf = buf[:len(buf)-1]
if _, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))); err == nil {
t.Error("readVersion did not notice \\n was missing")
diff --git a/libgo/go/exp/types/check_test.go b/libgo/go/exp/types/check_test.go
index ea9218f..0e20646 100644
--- a/libgo/go/exp/types/check_test.go
+++ b/libgo/go/exp/types/check_test.go
@@ -47,17 +47,17 @@ var tests = []struct {
var fset = token.NewFileSet()
-// TODO(gri) This functionality should be in token.Fileset.
-func getFile(filename string) *token.File {
- for f := range fset.Files() {
+func getFile(filename string) (file *token.File) {
+ fset.Iterate(func(f *token.File) bool {
if f.Name() == filename {
- return f
+ file = f
+ return false // end iteration
}
- }
- return nil
+ return true
+ })
+ return file
}
-// TODO(gri) This functionality should be in token.Fileset.
func getPos(filename string, offset int) token.Pos {
if f := getFile(filename); f != nil {
return f.Pos(offset)
@@ -65,8 +65,6 @@ func getPos(filename string, offset int) token.Pos {
return token.NoPos
}
-// TODO(gri) Need to revisit parser interface. We should be able to use parser.ParseFiles
-// or a similar function instead.
func parseFiles(t *testing.T, testname string, filenames []string) (map[string]*ast.File, error) {
files := make(map[string]*ast.File)
var errors scanner.ErrorList
@@ -145,8 +143,6 @@ func eliminate(t *testing.T, expected map[token.Pos]string, errors error) {
for _, error := range errors.(scanner.ErrorList) {
// error.Pos is a token.Position, but we want
// a token.Pos so we can do a map lookup
- // TODO(gri) Need to move scanner.Errors over
- // to use token.Pos and file set info.
pos := getPos(error.Pos.Filename, error.Pos.Offset)
if msg, found := expected[pos]; found {
// we expect a message at pos; check if it matches
diff --git a/libgo/go/exp/types/gcimporter.go b/libgo/go/exp/types/gcimporter.go
index 10c56db..a573fbb 100644
--- a/libgo/go/exp/types/gcimporter.go
+++ b/libgo/go/exp/types/gcimporter.go
@@ -460,29 +460,32 @@ func (p *gcParser) parseSignature() *Func {
return &Func{Params: params, Results: results, IsVariadic: isVariadic}
}
-// MethodSpec = ( identifier | ExportedName ) Signature .
+// MethodOrEmbedSpec = Name [ Signature ] .
//
-func (p *gcParser) parseMethodSpec() *ast.Object {
- if p.tok == scanner.Ident {
- p.expect(scanner.Ident)
- } else {
- p.parseExportedName()
+func (p *gcParser) parseMethodOrEmbedSpec() *ast.Object {
+ p.parseName()
+ if p.tok == '(' {
+ p.parseSignature()
+ // TODO(gri) compute method object
+ return ast.NewObj(ast.Fun, "_")
}
- p.parseSignature()
-
- // TODO(gri) compute method object
- return ast.NewObj(ast.Fun, "_")
+ // TODO lookup name and return that type
+ return ast.NewObj(ast.Typ, "_")
}
-// InterfaceType = "interface" "{" [ MethodList ] "}" .
-// MethodList = MethodSpec { ";" MethodSpec } .
+// InterfaceType = "interface" "{" [ MethodOrEmbedList ] "}" .
+// MethodOrEmbedList = MethodOrEmbedSpec { ";" MethodOrEmbedSpec } .
//
func (p *gcParser) parseInterfaceType() Type {
var methods ObjList
parseMethod := func() {
- meth := p.parseMethodSpec()
- methods = append(methods, meth)
+ switch m := p.parseMethodOrEmbedSpec(); m.Kind {
+ case ast.Typ:
+ // TODO expand embedded methods
+ case ast.Fun:
+ methods = append(methods, m)
+ }
}
p.expectKeyword("interface")
diff --git a/libgo/go/exp/utf8string/string.go b/libgo/go/exp/utf8string/string.go
new file mode 100644
index 0000000..da1e2de
--- /dev/null
+++ b/libgo/go/exp/utf8string/string.go
@@ -0,0 +1,203 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package utf8string provides an efficient way to index strings by rune rather than by byte.
+package utf8string
+
+import (
+ "errors"
+ "unicode/utf8"
+)
+
+// String wraps a regular string with a small structure that provides more
+// efficient indexing by code point index, as opposed to byte index.
+// Scanning incrementally forwards or backwards is O(1) per index operation
+// (although not as fast a range clause going forwards). Random access is
+// O(N) in the length of the string, but the overhead is less than always
+// scanning from the beginning.
+// If the string is ASCII, random access is O(1).
+// Unlike the built-in string type, String has internal mutable state and
+// is not thread-safe.
+type String struct {
+ str string
+ numRunes int
+ // If width > 0, the rune at runePos starts at bytePos and has the specified width.
+ width int
+ bytePos int
+ runePos int
+ nonASCII int // byte index of the first non-ASCII rune.
+}
+
+// NewString returns a new UTF-8 string with the provided contents.
+func NewString(contents string) *String {
+ return new(String).Init(contents)
+}
+
+// Init initializes an existing String to hold the provided contents.
+// It returns a pointer to the initialized String.
+func (s *String) Init(contents string) *String {
+ s.str = contents
+ s.bytePos = 0
+ s.runePos = 0
+ for i := 0; i < len(contents); i++ {
+ if contents[i] >= utf8.RuneSelf {
+ // Not ASCII.
+ s.numRunes = utf8.RuneCountInString(contents)
+ _, s.width = utf8.DecodeRuneInString(contents)
+ s.nonASCII = i
+ return s
+ }
+ }
+ // ASCII is simple. Also, the empty string is ASCII.
+ s.numRunes = len(contents)
+ s.width = 0
+ s.nonASCII = len(contents)
+ return s
+}
+
+// String returns the contents of the String. This method also means the
+// String is directly printable by fmt.Print.
+func (s *String) String() string {
+ return s.str
+}
+
+// RuneCount returns the number of runes (Unicode code points) in the String.
+func (s *String) RuneCount() int {
+ return s.numRunes
+}
+
+// IsASCII returns a boolean indicating whether the String contains only ASCII bytes.
+func (s *String) IsASCII() bool {
+ return s.width == 0
+}
+
+// Slice returns the string sliced at rune positions [i:j].
+func (s *String) Slice(i, j int) string {
+ // ASCII is easy. Let the compiler catch the indexing error if there is one.
+ if j < s.nonASCII {
+ return s.str[i:j]
+ }
+ if i < 0 || j > s.numRunes || i > j {
+ panic(sliceOutOfRange)
+ }
+ if i == j {
+ return ""
+ }
+ // For non-ASCII, after At(i), bytePos is always the position of the indexed character.
+ var low, high int
+ switch {
+ case i < s.nonASCII:
+ low = i
+ case i == s.numRunes:
+ low = len(s.str)
+ default:
+ s.At(i)
+ low = s.bytePos
+ }
+ switch {
+ case j == s.numRunes:
+ high = len(s.str)
+ default:
+ s.At(j)
+ high = s.bytePos
+ }
+ return s.str[low:high]
+}
+
+// At returns the rune with index i in the String. The sequence of runes is the same
+// as iterating over the contents with a "for range" clause.
+func (s *String) At(i int) rune {
+ // ASCII is easy. Let the compiler catch the indexing error if there is one.
+ if i < s.nonASCII {
+ return rune(s.str[i])
+ }
+
+ // Now we do need to know the index is valid.
+ if i < 0 || i >= s.numRunes {
+ panic(outOfRange)
+ }
+
+ var r rune
+
+ // Five easy common cases: within 1 spot of bytePos/runePos, or the beginning, or the end.
+ // With these cases, all scans from beginning or end work in O(1) time per rune.
+ switch {
+
+ case i == s.runePos-1: // backing up one rune
+ r, s.width = utf8.DecodeLastRuneInString(s.str[0:s.bytePos])
+ s.runePos = i
+ s.bytePos -= s.width
+ return r
+ case i == s.runePos+1: // moving ahead one rune
+ s.runePos = i
+ s.bytePos += s.width
+ fallthrough
+ case i == s.runePos:
+ r, s.width = utf8.DecodeRuneInString(s.str[s.bytePos:])
+ return r
+ case i == 0: // start of string
+ r, s.width = utf8.DecodeRuneInString(s.str)
+ s.runePos = 0
+ s.bytePos = 0
+ return r
+
+ case i == s.numRunes-1: // last rune in string
+ r, s.width = utf8.DecodeLastRuneInString(s.str)
+ s.runePos = i
+ s.bytePos = len(s.str) - s.width
+ return r
+ }
+
+ // We need to do a linear scan. There are three places to start from:
+ // 1) The beginning
+ // 2) bytePos/runePos.
+ // 3) The end
+ // Choose the closest in rune count, scanning backwards if necessary.
+ forward := true
+ if i < s.runePos {
+ // Between beginning and pos. Which is closer?
+ // Since both i and runePos are guaranteed >= nonASCII, that's the
+ // lowest location we need to start from.
+ if i < (s.runePos-s.nonASCII)/2 {
+ // Scan forward from beginning
+ s.bytePos, s.runePos = s.nonASCII, s.nonASCII
+ } else {
+ // Scan backwards from where we are
+ forward = false
+ }
+ } else {
+ // Between pos and end. Which is closer?
+ if i-s.runePos < (s.numRunes-s.runePos)/2 {
+ // Scan forward from pos
+ } else {
+ // Scan backwards from end
+ s.bytePos, s.runePos = len(s.str), s.numRunes
+ forward = false
+ }
+ }
+ if forward {
+ // TODO: Is it much faster to use a range loop for this scan?
+ for {
+ r, s.width = utf8.DecodeRuneInString(s.str[s.bytePos:])
+ if s.runePos == i {
+ break
+ }
+ s.runePos++
+ s.bytePos += s.width
+ }
+ } else {
+ for {
+ r, s.width = utf8.DecodeLastRuneInString(s.str[0:s.bytePos])
+ s.runePos--
+ s.bytePos -= s.width
+ if s.runePos == i {
+ break
+ }
+ }
+ }
+ return r
+}
+
+var outOfRange = errors.New("utf8.String: index out of range")
+var sliceOutOfRange = errors.New("utf8.String: slice index out of range")
diff --git a/libgo/go/exp/utf8string/string_test.go b/libgo/go/exp/utf8string/string_test.go
new file mode 100644
index 0000000..28511b2
--- /dev/null
+++ b/libgo/go/exp/utf8string/string_test.go
@@ -0,0 +1,123 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8string
+
+import (
+ "math/rand"
+ "testing"
+ "unicode/utf8"
+)
+
+var testStrings = []string{
+ "",
+ "abcd",
+ "☺☻☹",
+ "日a本b語ç日ð本Ê語þ日¥本¼語i日©",
+ "日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©",
+ "\x80\x80\x80\x80",
+}
+
+func TestScanForwards(t *testing.T) {
+ for _, s := range testStrings {
+ runes := []rune(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for i, expect := range runes {
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+func TestScanBackwards(t *testing.T) {
+ for _, s := range testStrings {
+ runes := []rune(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for i := len(runes) - 1; i >= 0; i-- {
+ expect := runes[i]
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+func randCount() int {
+ if testing.Short() {
+ return 100
+ }
+ return 100000
+}
+
+func TestRandomAccess(t *testing.T) {
+ for _, s := range testStrings {
+ if len(s) == 0 {
+ continue
+ }
+ runes := []rune(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for j := 0; j < randCount(); j++ {
+ i := rand.Intn(len(runes))
+ expect := runes[i]
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+func TestRandomSliceAccess(t *testing.T) {
+ for _, s := range testStrings {
+ if len(s) == 0 || s[0] == '\x80' { // the bad-UTF-8 string fools this simple test
+ continue
+ }
+ runes := []rune(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for k := 0; k < randCount(); k++ {
+ i := rand.Intn(len(runes))
+ j := rand.Intn(len(runes) + 1)
+ if i > j { // include empty strings
+ continue
+ }
+ expect := string(runes[i:j])
+ got := str.Slice(i, j)
+ if got != expect {
+ t.Errorf("%s[%d:%d]: expected %q got %q", s, i, j, expect, got)
+ }
+ }
+ }
+}
+
+func TestLimitSliceAccess(t *testing.T) {
+ for _, s := range testStrings {
+ str := NewString(s)
+ if str.Slice(0, 0) != "" {
+ t.Error("failure with empty slice at beginning")
+ }
+ nr := utf8.RuneCountInString(s)
+ if str.Slice(nr, nr) != "" {
+ t.Error("failure with empty slice at end")
+ }
+ }
+}