Open GoogleCodeExporter opened 9 years ago
Ok, so I did some more digging (trying to access the same database through ODBC
from R) and it looks like it's may be caused by SQLRowCount returning negative
numbers. Here is what I see when I do a manual select in the isql tool:
> select * from people
...
SQLRowCount returns -4294966952
344 rows fetched
Original comment by victor.kryukov
on 12 Nov 2013 at 3:46
Cannot reproduce it here.
Please, run test with this extra line:
diff -r 703276ff5038 column.go
--- a/column.go Fri Nov 01 11:01:50 2013 +1100
+++ b/column.go Tue Nov 12 15:37:36 2013 +1100
@@ -236,6 +236,7 @@
if !c.IsVariableWidth && int(c.Len) != c.Size {
panic(fmt.Errorf("wrong column #%d length %d returned, %d expected", idx, c.Len, c.Size))
}
+ fmt.Printf("%d: c=%+v c.Buffer=%+v\n", idx, c, c.Buffer)
return c.BaseColumn.Value(c.Buffer[:c.Len])
}
and tell use the output just before it fails.
What is your database server? (version and all)
I don't think SQLRowCount has anything to do with it.
Thank you.
Alex
Original comment by alex.bra...@gmail.com
on 12 Nov 2013 at 4:40
Hi Alex, and thanks for the quick response.
Here is the output with the extra line. I'm getting the MS SQL version...
warning: building out-of-date packages:
code.google.com/p/odbc/api
installing these packages with 'go test -i' will speed future tests.
=== RUN TestMSSQLCreateInsertDelete
0: c=&{BaseColumn:0xc200087a40 IsBound:true IsVariableWidth:true Size:21 Len:6
Buffer:[103 108 101 110 100 97 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0
0 0 0 0]} c.Buffer=[103 108 101 110 100 97 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
1: c=&{BaseColumn:0xc200087a80 IsBound:true IsVariableWidth:false Size:4 Len:4
Buffer:[5 0 0 0] smallBuf:[5 0 0 0 0 0 0 0]} c.Buffer=[5 0 0 0]
2: c=&{BaseColumn:0xc200087ac0 IsBound:true IsVariableWidth:false Size:1 Len:1
Buffer:[1] smallBuf:[1 0 0 0 0 0 0 0]} c.Buffer=[1]
3: c=&{BaseColumn:0xc200087b00 IsBound:true IsVariableWidth:false Size:8 Len:8
Buffer:[0 0 0 0 0 0 47 64] smallBuf:[0 0 0 0 0 0 47 64]} c.Buffer=[0 0 0 0 0 0
47 64]
4: c=&{BaseColumn:0xc200087b20 IsBound:true IsVariableWidth:false Size:16
Len:16 Buffer:[208 7 5 0 10 0 11 0 1 0 1 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
c.Buffer=[208 7 5 0 10 0 11 0 1 0 1 0 0 0 0 0]
5: c=&{BaseColumn:0xc200087b40 IsBound:true IsVariableWidth:true Size:10 Len:6
Buffer:[0 0 11 173 192 222 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]} c.Buffer=[0 0
11 173 192 222 0 0 0 0]
6: c=&{BaseColumn:0xc200087b60 IsBound:true IsVariableWidth:true Size:11 Len:2
Buffer:[97 97 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]} c.Buffer=[97 97 0
0 0 0 0 0 0 0 0]
0: c=&{BaseColumn:0xc200087a40 IsBound:true IsVariableWidth:true Size:21 Len:6
Buffer:[103 111 112 104 101 114 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0
0 0 0 0 0]} c.Buffer=[103 111 112 104 101 114 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
1: c=&{BaseColumn:0xc200087a80 IsBound:true IsVariableWidth:false Size:4 Len:4
Buffer:[3 0 0 0] smallBuf:[3 0 0 0 0 0 0 0]} c.Buffer=[3 0 0 0]
2: c=&{BaseColumn:0xc200087ac0 IsBound:true IsVariableWidth:false Size:1 Len:1
Buffer:[0] smallBuf:[0 0 0 0 0 0 0 0]} c.Buffer=[0]
3: c=&{BaseColumn:0xc200087b00 IsBound:true IsVariableWidth:false Size:8 Len:8
Buffer:[31 133 235 81 184 30 58 64] smallBuf:[31 133 235 81 184 30 58 64]}
c.Buffer=[31 133 235 81 184 30 58 64]
4: c=&{BaseColumn:0xc200087b20 IsBound:true IsVariableWidth:false Size:16
Len:16 Buffer:[217 7 5 0 10 0 11 0 1 0 1 0 192 212 84 7] smallBuf:[0 0 0 0 0 0
0 0]} c.Buffer=[217 7 5 0 10 0 11 0 1 0 1 0 192 212 84 7]
5: c=&{BaseColumn:0xc200087b40 IsBound:true IsVariableWidth:true Size:10 Len:1
Buffer:[0 0 11 173 192 222 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]} c.Buffer=[0 0
11 173 192 222 0 0 0 0]
6: c=&{BaseColumn:0xc200087b60 IsBound:true IsVariableWidth:true Size:11 Len:3
Buffer:[98 98 98 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]} c.Buffer=[98 98
98 0 0 0 0 0 0 0 0]
0: c=&{BaseColumn:0xc200087a40 IsBound:true IsVariableWidth:true Size:21 Len:5
Buffer:[99 104 114 105 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0
0 0 0]} c.Buffer=[99 104 114 105 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
1: c=&{BaseColumn:0xc200087a80 IsBound:true IsVariableWidth:false Size:4 Len:4
Buffer:[25 0 0 0] smallBuf:[25 0 0 0 0 0 0 0]} c.Buffer=[25 0 0 0]
2: c=&{BaseColumn:0xc200087ac0 IsBound:true IsVariableWidth:false Size:1 Len:1
Buffer:[0] smallBuf:[0 0 0 0 0 0 0 0]} c.Buffer=[0]
3: c=&{BaseColumn:0xc200087b00 IsBound:true IsVariableWidth:false Size:8 Len:8
Buffer:[0 0 0 0 0 0 73 64] smallBuf:[0 0 0 0 0 0 73 64]} c.Buffer=[0 0 0 0 0 0
73 64]
4: c=&{BaseColumn:0xc200087b20 IsBound:true IsVariableWidth:false Size:16
Len:16 Buffer:[223 7 12 0 25 0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
c.Buffer=[223 7 12 0 25 0 0 0 0 0 0 0 0 0 0 0]
5: c=&{BaseColumn:0xc200087b40 IsBound:true IsVariableWidth:true Size:10 Len:3
Buffer:[99 99 99 173 192 222 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]} c.Buffer=[99
99 99 173 192 222 0 0 0 0]
6: c=&{BaseColumn:0xc200087b60 IsBound:true IsVariableWidth:true Size:11
Len:4294967295 Buffer:[98 98 98 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
c.Buffer=[98 98 98 0 0 0 0 0 0 0 0]
--- FAIL: TestMSSQLCreateInsertDelete (0.07 seconds)
panic: runtime error: slice bounds out of range [recovered]
panic: runtime error: slice bounds out of range
goroutine 4 [running]:
testing.func·004()
/usr/local/src/go/src/pkg/testing/testing.go:348 +0xcd
code.google.com/p/odbc.(*BindableColumn).Value(0xc200070e40, 0xd449000, 0x6,
0x4f37a0, 0xc2000b4440, ...)
/home/oracle/gosrc/src/code.google.com/p/odbc/column.go:240 +0x36a
code.google.com/p/odbc.(*Rows).Next(0xc2000004c8, 0xc200054540, 0x7, 0x7,
0x54ef00, ...)
/home/oracle/gosrc/src/code.google.com/p/odbc/rows.go:34 +0x137
database/sql.(*Rows).Next(0xc20008a300, 0x3)
/usr/local/src/go/src/pkg/database/sql/sql.go:1310 +0xc1
code.google.com/p/odbc.TestMSSQLCreateInsertDelete(0xc200098000)
/home/oracle/gosrc/src/code.google.com/p/odbc/mssql_test.go:270 +0x62f
testing.tRunner(0xc200098000, 0x815780)
/usr/local/src/go/src/pkg/testing/testing.go:353 +0x8a
created by testing.RunTests
/usr/local/src/go/src/pkg/testing/testing.go:433 +0x86b
goroutine 1 [chan receive]:
testing.RunTests(0x583450, 0x815780, 0xf, 0xf, 0x1, ...)
/usr/local/src/go/src/pkg/testing/testing.go:434 +0x88e
testing.Main(0x583450, 0x815780, 0xf, 0xf, 0x824580, ...)
/usr/local/src/go/src/pkg/testing/testing.go:365 +0x8a
main.main()
code.google.com/p/odbc/_test/_testmain.go:73 +0x9a
goroutine 2 [syscall]:
exit status 2
FAIL code.google.com/p/odbc 0.083s
Original comment by victor.kryukov
on 12 Nov 2013 at 5:34
Here is my MS SQL Version:
Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64)
Apr 2 2010 15:48:46
Copyright (c) Microsoft Corporation
Standard Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor)
Original comment by victor.kryukov
on 12 Nov 2013 at 5:38
Incidentally, 4294967295 is 0xFFFFFFFF. I don't know what MS SQL server is
trying to say here...
I checked the dbo.temp table that was created at the server, and it looks OK
with the following 4 records:
glenda 5 1 15.50 2000-05-10 11:01:01.0 00000BADC0DE aa
gopher 3 0 26.12 2009-05-10 11:01:01.123 00 bbb
chris 25 0 50.00 2015-12-25 00:00:00.0 636363
null 0 0 0.00 2015-12-25 01:02:03.0
Original comment by victor.kryukov
on 12 Nov 2013 at 5:46
The following change make the TestMSSQLCreateInsertDelete pass, but now it
hands on TestMSSQLTransactions
diff -r 703276ff5038 column.go
--- a/column.go Fri Nov 01 11:01:50 2013 +1100
+++ b/column.go Tue Nov 12 18:05:28 2013 +0000
@@ -229,13 +229,14 @@
return nil, NewError("SQLGetData", h)
}
}
- if c.Len.IsNull() {
+ if c.Len.IsNull() || c.Len == 0xFFFFFFFF {
// is NULL
return nil, nil
}
if !c.IsVariableWidth && int(c.Len) != c.Size {
panic(fmt.Errorf("wrong column #%d length %d returned, %d expected", idx, c.Len, c.Size))
}
+ fmt.Printf("%d: c=%+v c.Buffer=%+v\n", idx, c, c.Buffer)
return c.BaseColumn.Value(c.Buffer[:c.Len])
}
Original comment by victor.kryukov
on 12 Nov 2013 at 6:06
s/hands/hangs/
Original comment by victor.kryukov
on 12 Nov 2013 at 6:06
May be related:
https://code.google.com/p/pyodbc/issues/detail?id=51
Specifically,
"On Windows, SQLLEN is an int64 and SQL_NULL_DATA is (-1). Assuming the 64-bit
driver
is correctly putting a 64-bit -1 in the field, it should work."
Original comment by victor.kryukov
on 12 Nov 2013 at 6:09
I think you are correct, it is something to do with how ODBC types are defined
on your system. I hate this - that is why I use Go - there is never a question.
:-)
To help us determine what is going on, please change mssql_test.go, like:
diff --git a/mssql_test.go b/mssql_test.go
--- a/mssql_test.go
+++ b/mssql_test.go
@@ -15,6 +15,9 @@
"sync/atomic"
"testing"
"time"
+ "unsafe"
+
+ "code.google.com/p/odbc/api"
)
var (
@@ -1210,3 +1213,11 @@
exec(t, db, "drop table dbo.temp")
}
+
+func TestALEX(t *testing.T) {
+ fmt.Printf("api.SQL_NULL_DATA=%d\n", api.SQL_NULL_DATA)
+ var l api.SQLLEN
+ fmt.Printf("unsafe.Sizeof(api.SQLLEN)=%d\n", unsafe.Sizeof(l))
+ l = api.SQL_NULL_DATA
+ fmt.Printf("l=%d\n", l)
+}
and run it like
go test -run=ALEX
and show us the output.
That is what I see here on windows/amd64:
c:\go\path\src\code.google.com\p\odbc>go test -v -run=ALEX
=== RUN TestALEX
api.SQL_NULL_DATA=-1
unsafe.Sizeof(api.SQLLEN)=8
l=-1
--- PASS: TestALEX (0.00 seconds)
PASS
ok code.google.com/p/odbc 0.050s
Thank you.
Alex
Original comment by alex.bra...@gmail.com
on 13 Nov 2013 at 1:34
Here you are, Alex:
[oracle@custservices odbc]$ go test -run=ALEX
warning: building out-of-date packages:
code.google.com/p/odbc/api
installing these packages with 'go test -i' will speed future tests.
api.SQL_NULL_DATA=-1
unsafe.Sizeof(api.SQLLEN)=8
l=-1
PASS
ok code.google.com/p/odbc 0.016s
Original comment by victor.kryukov
on 13 Nov 2013 at 1:38
Here is another test:
diff -r 703276ff5038 mssql_test.go
--- a/mssql_test.go Fri Nov 01 11:01:50 2013 +1100
+++ b/mssql_test.go Wed Nov 13 01:48:57 2013 +0000
@@ -13,10 +13,14 @@
"strconv"
"strings"
"sync/atomic"
"testing"
"time"
+ "reflect"
+ "unsafe"
+
+ "code.google.com/p/odbc/api"
)
var (
mssrv = flag.String("mssrv", "server", "ms sql server name")
msdb = flag.String("msdb", "dbname", "ms sql server database name")
@@ -1208,5 +1212,21 @@
}
}
exec(t, db, "drop table dbo.temp")
}
+
+func TestALEX(t *testing.T) {
+ fmt.Printf("api.SQL_NULL_DATA=%d\n", api.SQL_NULL_DATA)
+ var l api.SQLLEN
+ fmt.Printf("unsafe.Sizeof(api.SQLLEN)=%d\n", unsafe.Sizeof(l))
+ l = api.SQL_NULL_DATA
+ fmt.Printf("l=%d\n", l)
+}
+
+func TestVICTOR(t *testing.T) {
+ var x api.SQLLEN = 1
+ v := reflect.ValueOf(x)
+ fmt.Println("type:", v.Type())
+ fmt.Println("kind is uint64:", v.Kind() == reflect.Uint64)
+ fmt.Println("kind is int64:", v.Kind() == reflect.Int64)
+}
[oracle@custservices odbc]$ go test -run=VICTOR
warning: building out-of-date packages:
code.google.com/p/odbc/api
installing these packages with 'go test -i' will speed future tests.
type: api.SQLLEN
kind is uint64: false
kind is int64: true
PASS
ok code.google.com/p/odbc 0.015s
Original comment by victor.kryukov
on 13 Nov 2013 at 1:50
Well, could it be that in NewVariableWidthColumn, colWidth is api.SQLULEN, not
api.SQLLEN?
Original comment by victor.kryukov
on 13 Nov 2013 at 1:54
I don't think so. I am thinking - I am a slow thinker.
Alex
Original comment by alex.bra...@gmail.com
on 13 Nov 2013 at 1:58
What about if you make this change:
diff --git a/odbcstmt.go b/odbcstmt.go
--- a/odbcstmt.go
+++ b/odbcstmt.go
@@ -130,7 +130,7 @@
}
// fetch column descriptions
s.Cols = make([]Column, n)
- binding := true
+ binding := false
for i := range s.Cols {
c, err := NewColumn(s.h, i)
if err != nil {
Do tests run OK?
Alex
Original comment by alex.bra...@gmail.com
on 13 Nov 2013 at 6:37
[deleted comment]
No, same problem:
=== RUN TestMSSQLCreateInsertDelete
--- FAIL: TestMSSQLCreateInsertDelete (0.03 seconds)
panic: runtime error: slice bounds out of range [recovered]
panic: runtime error: slice bounds out of range
goroutine 4 [running]:
testing.func·004()
/usr/local/src/go/src/pkg/testing/testing.go:348 +0xcd
code.google.com/p/odbc.(*BindableColumn).Value(0xc200070e40, 0xbaedfd0, 0x6,
0x4f36c0, 0xc200087cc0, ...)
/home/oracle/gosrc/src/code.google.com/p/odbc/column.go:239 +0x283
code.google.com/p/odbc.(*Rows).Next(0xc2000004c8, 0xc200054540, 0x7, 0x7,
0x54ee20, ...)
/home/oracle/gosrc/src/code.google.com/p/odbc/rows.go:34 +0x137
database/sql.(*Rows).Next(0xc20008a300, 0x3)
/usr/local/src/go/src/pkg/database/sql/sql.go:1310 +0xc1
code.google.com/p/odbc.TestMSSQLCreateInsertDelete(0xc200098000)
/home/oracle/gosrc/src/code.google.com/p/odbc/mssql_test.go:270 +0x62f
testing.tRunner(0xc200098000, 0x815780)
/usr/local/src/go/src/pkg/testing/testing.go:353 +0x8a
created by testing.RunTests
/usr/local/src/go/src/pkg/testing/testing.go:433 +0x86b
goroutine 1 [chan receive]:
testing.RunTests(0x583330, 0x815780, 0xf, 0xf, 0x1, ...)
/usr/local/src/go/src/pkg/testing/testing.go:434 +0x88e
testing.Main(0x583330, 0x815780, 0xf, 0xf, 0x824580, ...)
/usr/local/src/go/src/pkg/testing/testing.go:365 +0x8a
main.main()
code.google.com/p/odbc/_test/_testmain.go:73 +0x9a
goroutine 2 [syscall]:
exit status 2
FAIL code.google.com/p/odbc 0.056s
Original comment by victor.kryukov
on 13 Nov 2013 at 4:56
I am still puzzled. I suspect your SQLBindCol and SQLGetData return unexpected
(maybe invalid) values. Can you apply this patch:
diff --git a/column.go b/column.go
--- a/column.go
+++ b/column.go
@@ -13,22 +13,31 @@
"unsafe"
)
-type BufferLen api.SQLLEN
+type BufferLen struct {
+ Pre int64
+ Value api.SQLLEN
+ Post int64
+}
func (l *BufferLen) IsNull() bool {
- return *l == api.SQL_NULL_DATA
+ return l.Value == api.SQL_NULL_DATA
}
func (l *BufferLen) GetData(h api.SQLHSTMT, idx int, ctype api.SQLSMALLINT, buf []byte) api.SQLRETURN {
return api.SQLGetData(h, api.SQLUSMALLINT(idx+1), ctype,
api.SQLPOINTER(unsafe.Pointer(&buf[0])), api.SQLLEN(len(buf)),
- (*api.SQLLEN)(l))
+ &l.Value)
}
func (l *BufferLen) Bind(h api.SQLHSTMT, idx int, ctype api.SQLSMALLINT, buf []byte) api.SQLRETURN {
return api.SQLBindCol(h, api.SQLUSMALLINT(idx+1), ctype,
api.SQLPOINTER(unsafe.Pointer(&buf[0])), api.SQLLEN(len(buf)),
- (*api.SQLLEN)(l))
+ &l.Value)
+}
+
+func (l *BufferLen) ValueBytes() []byte {
+ n := unsafe.Sizeof(l.Value)
+ return (*[100]byte)(unsafe.Pointer(&l.Value))[:n]
}
// Column provides access to row columns.
@@ -224,7 +233,9 @@
func (c *BindableColumn) Value(h api.SQLHSTMT, idx int) (driver.Value, error) {
if !c.IsBound {
+ fmt.Printf("before GetData: c=%+v c.Len.ValueBytes=%+v\n", c,
c.Len.ValueBytes())
ret := c.Len.GetData(h, idx, c.CType, c.Buffer)
+ fmt.Printf("after GetData: c=%+v c.Len.ValueBytes=%+v\n", c,
c.Len.ValueBytes())
if IsError(ret) {
return nil, NewError("SQLGetData", h)
}
@@ -233,10 +244,10 @@
// is NULL
return nil, nil
}
- if !c.IsVariableWidth && int(c.Len) != c.Size {
+ if !c.IsVariableWidth && int(c.Len.Value) != c.Size {
panic(fmt.Errorf("wrong column #%d length %d returned, %d expected", idx, c.Len, c.Size))
}
- return c.BaseColumn.Value(c.Buffer[:c.Len])
+ return c.BaseColumn.Value(c.Buffer[:c.Len.Value])
}
// NonBindableColumn provide access to columns, that can't be bound.
@@ -263,7 +274,7 @@
// is NULL
return nil, nil
}
- total = append(total, b[:l]...)
+ total = append(total, b[:l.Value]...)
break loop
case api.SQL_SUCCESS_WITH_INFO:
err := NewError("SQLGetData", h).(*Error)
@@ -278,12 +289,12 @@
i-- // remove null-termination character
}
total = append(total, b[:i]...)
- if l != api.SQL_NO_TOTAL {
+ if l.Value != api.SQL_NO_TOTAL {
// odbc gives us a hint about remaining data,
// lets get it in one go.
- n := int(l) // total bytes for our data
- n -= i // subtract already received
- n += 2 // room for biggest (wchar) null-terminator
+ n := int(l.Value) // total bytes for our data
+ n -= i // subtract already received
+ n += 2 // room for biggest (wchar) null-terminator
if len(b) < n {
b = make([]byte, n)
}
diff --git a/mssql_test.go b/mssql_test.go
--- a/mssql_test.go
+++ b/mssql_test.go
@@ -1220,3 +1220,20 @@
t.Fatal("comparison fails")
}
}
+
+func TestMSSQLALEX(t *testing.T) {
+ db, sc, err := mssqlConnect()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer closeDB(t, db, sc, sc)
+
+ var s sql.NullString
+ err = db.QueryRow("select cast(null as varchar(10))").Scan(&s)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if s.Valid {
+ t.Errorf("expected NULL string, but received %v", s)
+ }
+}
diff --git a/odbcstmt.go b/odbcstmt.go
--- a/odbcstmt.go
+++ b/odbcstmt.go
@@ -130,7 +130,7 @@
}
// fetch column descriptions
s.Cols = make([]Column, n)
- binding := true
+ binding := false
for i := range s.Cols {
c, err := NewColumn(s.h, i)
if err != nil {
and run TestMSSQLALEX test and provide output here.
Thank you.
Alex
Original comment by alex.bra...@gmail.com
on 15 Nov 2013 at 4:33
Here you are:
=== RUN TestMSSQLALEX
before GetData: c=&{BaseColumn:0xc200087580 IsBound:false IsVariableWidth:true
Size:11 Len:{Pre:0 Value:0 Post:0} Buffer:[0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0
0 0 0 0 0 0]} c.Len.ValueBytes=[0 0 0 0 0 0 0 0]
after GetData: c=&{BaseColumn:0xc200087580 IsBound:false IsVariableWidth:true
Size:11 Len:{Pre:0 Value:4294967295 Post:0} Buffer:[0 0 0 0 0 0 0 0 0 0 0]
smallBuf:[0 0 0 0 0 0 0 0]} c.Len.ValueBytes=[255 255 255 255 0 0 0 0]
--- FAIL: TestMSSQLALEX (0.01 seconds)
panic: runtime error: slice bounds out of range [recovered]
panic: runtime error: slice bounds out of range
goroutine 4 [running]:
testing.func·004()
/usr/local/src/go/src/pkg/testing/testing.go:348 +0xcd
code.google.com/p/odbc.(*BindableColumn).Value(0xc200074230, 0x1d170910, 0x0,
0x1, 0x41ad2a, ...)
/home/oracle/gosrc/src/code.google.com/p/odbc/column.go:250 +0x53e
code.google.com/p/odbc.(*Rows).Next(0xc2000001f0, 0xc200077ff0, 0x1, 0x1, 0x1,
...)
/home/oracle/gosrc/src/code.google.com/p/odbc/rows.go:34 +0x137
database/sql.(*Rows).Next(0xc20008a300, 0x52bce0)
/usr/local/src/go/src/pkg/database/sql/sql.go:1310 +0xc1
database/sql.(*Row).Scan(0xc2000875a0, 0x2abe22b91f50, 0x1, 0x1, 0x0, ...)
/usr/local/src/go/src/pkg/database/sql/sql.go:1424 +0x1ae
code.google.com/p/odbc.TestMSSQLALEX(0xc20009b000)
/home/oracle/gosrc/src/code.google.com/p/odbc/mssql_test.go:1222 +0x1e1
testing.tRunner(0xc20009b000, 0x8168d0)
/usr/local/src/go/src/pkg/testing/testing.go:353 +0x8a
created by testing.RunTests
/usr/local/src/go/src/pkg/testing/testing.go:433 +0x86b
goroutine 1 [chan receive]:
testing.RunTests(0x583e38, 0x816780, 0x10, 0x10, 0x1, ...)
/usr/local/src/go/src/pkg/testing/testing.go:434 +0x88e
testing.Main(0x583e38, 0x816780, 0x10, 0x10, 0x825580, ...)
/usr/local/src/go/src/pkg/testing/testing.go:365 +0x8a
main.main()
code.google.com/p/odbc/_test/_testmain.go:75 +0x9a
goroutine 2 [syscall]:
exit status 2
FAIL code.google.com/p/odbc 0.035s
Original comment by victor.kryukov
on 15 Nov 2013 at 4:39
Please, run this
diff --git a/column.go b/column.go
--- a/column.go
+++ b/column.go
@@ -16,7 +16,7 @@
type BufferLen api.SQLLEN
func (l *BufferLen) IsNull() bool {
- return *l == api.SQL_NULL_DATA
+ return *l == 4294967295
}
func (l *BufferLen) GetData(h api.SQLHSTMT, idx int, ctype api.SQLSMALLINT, buf []byte) api.SQLRETURN {
@@ -224,7 +224,9 @@
func (c *BindableColumn) Value(h api.SQLHSTMT, idx int) (driver.Value, error) {
if !c.IsBound {
+ fmt.Printf("before GetData: c=%+v\n", c)
ret := c.Len.GetData(h, idx, c.CType, c.Buffer)
+ fmt.Printf("after GetData: c=%+v\n", c)
if IsError(ret) {
return nil, NewError("SQLGetData", h)
}
diff --git a/mssql_test.go b/mssql_test.go
--- a/mssql_test.go
+++ b/mssql_test.go
@@ -1220,3 +1220,20 @@
t.Fatal("comparison fails")
}
}
+
+func TestMSSQLALEX(t *testing.T) {
+ db, sc, err := mssqlConnect()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer closeDB(t, db, sc, sc)
+
+ var s sql.NullString
+ err = db.QueryRow("select cast(null as varchar(10))").Scan(&s)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if s.Valid {
+ t.Errorf("expected NULL string, but received %v", s)
+ }
+}
diff --git a/odbcstmt.go b/odbcstmt.go
--- a/odbcstmt.go
+++ b/odbcstmt.go
@@ -130,7 +130,7 @@
}
// fetch column descriptions
s.Cols = make([]Column, n)
- binding := true
+ binding := false
for i := range s.Cols {
c, err := NewColumn(s.h, i)
if err != nil {
diff --git a/param.go b/param.go
--- a/param.go
+++ b/param.go
@@ -47,7 +47,7 @@
buf = nil
size = 1
buflen = 0
- plen = p.StoreStrLen_or_IndPtr(api.SQL_NULL_DATA)
+ plen = p.StoreStrLen_or_IndPtr(4294967295)
sqltype = api.SQL_WCHAR
case string:
ctype = api.SQL_C_WCHAR
Thank you.
Alex
Original comment by alex.bra...@gmail.com
on 15 Nov 2013 at 4:59
Hi Alex, sorry for the long silence. Now everything passes:
=== RUN TestMSSQLALEX
before GetData: c=&{BaseColumn:0xc200087580 IsBound:false IsVariableWidth:true
Size:11 Len:0 Buffer:[0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200087580 IsBound:false IsVariableWidth:true
Size:11 Len:4294967295 Buffer:[0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0
0]}
--- PASS: TestMSSQLALEX (0.01 seconds)
PASS
ok code.google.com/p/odbc 0.020s
Original comment by victor.kryukov
on 7 Dec 2013 at 9:17
When I run the full test suite, though, it hangs at TestMSSQLTransactions:
=== RUN TestMSSQLCreateInsertDelete
before GetData: c=&{BaseColumn:0xc200088a20 IsBound:false IsVariableWidth:true
Size:21 Len:0 Buffer:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0
0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088a20 IsBound:false IsVariableWidth:true
Size:21 Len:6 Buffer:[103 108 101 110 100 97 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088a60 IsBound:false IsVariableWidth:false
Size:4 Len:0 Buffer:[0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088a60 IsBound:false IsVariableWidth:false
Size:4 Len:4 Buffer:[5 0 0 0] smallBuf:[5 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088aa0 IsBound:false IsVariableWidth:false
Size:1 Len:0 Buffer:[0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088aa0 IsBound:false IsVariableWidth:false
Size:1 Len:1 Buffer:[1] smallBuf:[1 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088ae0 IsBound:false IsVariableWidth:false
Size:8 Len:0 Buffer:[0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088ae0 IsBound:false IsVariableWidth:false
Size:8 Len:8 Buffer:[0 0 0 0 0 0 47 64] smallBuf:[0 0 0 0 0 0 47 64]}
before GetData: c=&{BaseColumn:0xc200088b00 IsBound:false IsVariableWidth:false
Size:16 Len:0 Buffer:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0
0]}
after GetData: c=&{BaseColumn:0xc200088b00 IsBound:false IsVariableWidth:false
Size:16 Len:16 Buffer:[208 7 5 0 10 0 11 0 1 0 1 0 0 0 0 0] smallBuf:[0 0 0 0 0
0 0 0]}
before GetData: c=&{BaseColumn:0xc200088b20 IsBound:false IsVariableWidth:true
Size:10 Len:0 Buffer:[0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088b20 IsBound:false IsVariableWidth:true
Size:10 Len:6 Buffer:[0 0 11 173 192 222 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088b40 IsBound:false IsVariableWidth:true
Size:11 Len:0 Buffer:[0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088b40 IsBound:false IsVariableWidth:true
Size:11 Len:2 Buffer:[97 97 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088a20 IsBound:false IsVariableWidth:true
Size:21 Len:6 Buffer:[103 108 101 110 100 97 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088a20 IsBound:false IsVariableWidth:true
Size:21 Len:6 Buffer:[103 111 112 104 101 114 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088a60 IsBound:false IsVariableWidth:false
Size:4 Len:4 Buffer:[5 0 0 0] smallBuf:[5 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088a60 IsBound:false IsVariableWidth:false
Size:4 Len:4 Buffer:[3 0 0 0] smallBuf:[3 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088aa0 IsBound:false IsVariableWidth:false
Size:1 Len:1 Buffer:[1] smallBuf:[1 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088aa0 IsBound:false IsVariableWidth:false
Size:1 Len:1 Buffer:[0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088ae0 IsBound:false IsVariableWidth:false
Size:8 Len:8 Buffer:[0 0 0 0 0 0 47 64] smallBuf:[0 0 0 0 0 0 47 64]}
after GetData: c=&{BaseColumn:0xc200088ae0 IsBound:false IsVariableWidth:false
Size:8 Len:8 Buffer:[31 133 235 81 184 30 58 64] smallBuf:[31 133 235 81 184 30
58 64]}
before GetData: c=&{BaseColumn:0xc200088b00 IsBound:false IsVariableWidth:false
Size:16 Len:16 Buffer:[208 7 5 0 10 0 11 0 1 0 1 0 0 0 0 0] smallBuf:[0 0 0 0 0
0 0 0]}
after GetData: c=&{BaseColumn:0xc200088b00 IsBound:false IsVariableWidth:false
Size:16 Len:16 Buffer:[217 7 5 0 10 0 11 0 1 0 1 0 192 212 84 7] smallBuf:[0 0
0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088b20 IsBound:false IsVariableWidth:true
Size:10 Len:6 Buffer:[0 0 11 173 192 222 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088b20 IsBound:false IsVariableWidth:true
Size:10 Len:1 Buffer:[0 0 11 173 192 222 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088b40 IsBound:false IsVariableWidth:true
Size:11 Len:2 Buffer:[97 97 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088b40 IsBound:false IsVariableWidth:true
Size:11 Len:3 Buffer:[98 98 98 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088a20 IsBound:false IsVariableWidth:true
Size:21 Len:6 Buffer:[103 111 112 104 101 114 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088a20 IsBound:false IsVariableWidth:true
Size:21 Len:5 Buffer:[99 104 114 105 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088a60 IsBound:false IsVariableWidth:false
Size:4 Len:4 Buffer:[3 0 0 0] smallBuf:[3 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088a60 IsBound:false IsVariableWidth:false
Size:4 Len:4 Buffer:[25 0 0 0] smallBuf:[25 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088aa0 IsBound:false IsVariableWidth:false
Size:1 Len:1 Buffer:[0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088aa0 IsBound:false IsVariableWidth:false
Size:1 Len:1 Buffer:[0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088ae0 IsBound:false IsVariableWidth:false
Size:8 Len:8 Buffer:[31 133 235 81 184 30 58 64] smallBuf:[31 133 235 81 184 30
58 64]}
after GetData: c=&{BaseColumn:0xc200088ae0 IsBound:false IsVariableWidth:false
Size:8 Len:8 Buffer:[0 0 0 0 0 0 73 64] smallBuf:[0 0 0 0 0 0 73 64]}
before GetData: c=&{BaseColumn:0xc200088b00 IsBound:false IsVariableWidth:false
Size:16 Len:16 Buffer:[217 7 5 0 10 0 11 0 1 0 1 0 192 212 84 7] smallBuf:[0 0
0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088b00 IsBound:false IsVariableWidth:false
Size:16 Len:16 Buffer:[223 7 12 0 25 0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0
0 0 0]}
before GetData: c=&{BaseColumn:0xc200088b20 IsBound:false IsVariableWidth:true
Size:10 Len:1 Buffer:[0 0 11 173 192 222 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088b20 IsBound:false IsVariableWidth:true
Size:10 Len:3 Buffer:[99 99 99 173 192 222 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088b40 IsBound:false IsVariableWidth:true
Size:11 Len:3 Buffer:[98 98 98 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088b40 IsBound:false IsVariableWidth:true
Size:11 Len:4294967295 Buffer:[98 98 98 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0
0 0]}
before GetData: c=&{BaseColumn:0xc200088a20 IsBound:false IsVariableWidth:true
Size:21 Len:5 Buffer:[99 104 114 105 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088a20 IsBound:false IsVariableWidth:true
Size:21 Len:4 Buffer:[110 117 108 108 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088a60 IsBound:false IsVariableWidth:false
Size:4 Len:4 Buffer:[25 0 0 0] smallBuf:[25 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088a60 IsBound:false IsVariableWidth:false
Size:4 Len:4 Buffer:[0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088aa0 IsBound:false IsVariableWidth:false
Size:1 Len:1 Buffer:[0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088aa0 IsBound:false IsVariableWidth:false
Size:1 Len:1 Buffer:[0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088ae0 IsBound:false IsVariableWidth:false
Size:8 Len:8 Buffer:[0 0 0 0 0 0 73 64] smallBuf:[0 0 0 0 0 0 73 64]}
after GetData: c=&{BaseColumn:0xc200088ae0 IsBound:false IsVariableWidth:false
Size:8 Len:8 Buffer:[0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088b00 IsBound:false IsVariableWidth:false
Size:16 Len:16 Buffer:[223 7 12 0 25 0 0 0 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0
0 0 0]}
after GetData: c=&{BaseColumn:0xc200088b00 IsBound:false IsVariableWidth:false
Size:16 Len:16 Buffer:[223 7 12 0 25 0 1 0 2 0 3 0 0 0 0 0] smallBuf:[0 0 0 0 0
0 0 0]}
before GetData: c=&{BaseColumn:0xc200088b20 IsBound:false IsVariableWidth:true
Size:10 Len:3 Buffer:[99 99 99 173 192 222 0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc200088b20 IsBound:false IsVariableWidth:true
Size:10 Len:4294967295 Buffer:[99 99 99 173 192 222 0 0 0 0] smallBuf:[0 0 0 0
0 0 0 0]}
before GetData: c=&{BaseColumn:0xc200088b40 IsBound:false IsVariableWidth:true
Size:11 Len:4294967295 Buffer:[98 98 98 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0
0 0]}
after GetData: c=&{BaseColumn:0xc200088b40 IsBound:false IsVariableWidth:true
Size:11 Len:4294967295 Buffer:[98 98 98 0 0 0 0 0 0 0 0] smallBuf:[0 0 0 0 0 0
0 0]}
--- PASS: TestMSSQLCreateInsertDelete (0.13 seconds)
=== RUN TestMSSQLTransactions
before GetData: c=&{BaseColumn:0xc2000b4d40 IsBound:false IsVariableWidth:false
Size:4 Len:0 Buffer:[0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc2000b4d40 IsBound:false IsVariableWidth:false
Size:4 Len:4 Buffer:[0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
before GetData: c=&{BaseColumn:0xc2000b4e80 IsBound:false IsVariableWidth:false
Size:4 Len:0 Buffer:[0 0 0 0] smallBuf:[0 0 0 0 0 0 0 0]}
after GetData: c=&{BaseColumn:0xc2000b4e80 IsBound:false IsVariableWidth:false
Size:4 Len:4 Buffer:[1 0 0 0] smallBuf:[1 0 0 0 0 0 0 0]}
Original comment by victor.kryukov
on 7 Dec 2013 at 9:19
victor,
I googled again, and as you pointed yourself earlier
(https://code.google.com/p/pyodbc/issues/detail?id=51), I think there is a
mismatch here somewhere. I suspect your unixODBC is compiled as 64-bit, while
freetds is 32-bit. This http://bugs.mysql.com/bug.php?id=68185 describes
situation similar to yours, but with a different language and different driver.
I don't think I can help you any here. I am no good with Linux, you have to
work out how to rebuild / reinstall your libs.
I don't think we should start investigating TestMSSQLTransactions until you
sore previous problem. Sorry.
Alex
Original comment by alex.bra...@gmail.com
on 9 Dec 2013 at 12:44
Original issue reported on code.google.com by
victor.kryukov
on 12 Nov 2013 at 2:54