Skip to content

Commit 577bf50

Browse files
committed
implement Rows.HasNextResultSet and Rows.NextResultSet
Fixes alexbrainman#81 Fixes alexbrainman#127
1 parent 47bdeef commit 577bf50

File tree

5 files changed

+176
-0
lines changed

5 files changed

+176
-0
lines changed

api/api.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ type (
5858
//sys SQLGetData(statementHandle SQLHSTMT, colOrParamNum SQLUSMALLINT, targetType SQLSMALLINT, targetValuePtr SQLPOINTER, bufferLength SQLLEN, vallen *SQLLEN) (ret SQLRETURN) = odbc32.SQLGetData
5959
//sys SQLGetDiagRec(handleType SQLSMALLINT, handle SQLHANDLE, recNumber SQLSMALLINT, sqlState *SQLWCHAR, nativeErrorPtr *SQLINTEGER, messageText *SQLWCHAR, bufferLength SQLSMALLINT, textLengthPtr *SQLSMALLINT) (ret SQLRETURN) = odbc32.SQLGetDiagRecW
6060
//sys SQLNumParams(statementHandle SQLHSTMT, parameterCountPtr *SQLSMALLINT) (ret SQLRETURN) = odbc32.SQLNumParams
61+
//sys SQLMoreResults(statementHandle SQLHSTMT) (ret SQLRETURN) = odbc32.SQLMoreResults
6162
//sys SQLNumResultCols(statementHandle SQLHSTMT, columnCountPtr *SQLSMALLINT) (ret SQLRETURN) = odbc32.SQLNumResultCols
6263
//sys SQLPrepare(statementHandle SQLHSTMT, statementText *SQLWCHAR, textLength SQLINTEGER) (ret SQLRETURN) = odbc32.SQLPrepareW
6364
//sys SQLRowCount(statementHandle SQLHSTMT, rowCountPtr *SQLLEN) (ret SQLRETURN) = odbc32.SQLRowCount

api/zapi_unix.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ func SQLNumParams(statementHandle SQLHSTMT, parameterCountPtr *SQLSMALLINT) (ret
9595
return SQLRETURN(r)
9696
}
9797

98+
func SQLMoreResults(statementHandle SQLHSTMT) (ret SQLRETURN) {
99+
r := C.SQLMoreResults(C.SQLHSTMT(statementHandle))
100+
return SQLRETURN(r)
101+
}
102+
98103
func SQLNumResultCols(statementHandle SQLHSTMT, columnCountPtr *SQLSMALLINT) (ret SQLRETURN) {
99104
r := C.SQLNumResultCols(C.SQLHSTMT(statementHandle), (*C.SQLSMALLINT)(columnCountPtr))
100105
return SQLRETURN(r)

api/zapi_windows.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ var (
5454
procSQLGetData = mododbc32.NewProc("SQLGetData")
5555
procSQLGetDiagRecW = mododbc32.NewProc("SQLGetDiagRecW")
5656
procSQLNumParams = mododbc32.NewProc("SQLNumParams")
57+
procSQLMoreResults = mododbc32.NewProc("SQLMoreResults")
5758
procSQLNumResultCols = mododbc32.NewProc("SQLNumResultCols")
5859
procSQLPrepareW = mododbc32.NewProc("SQLPrepareW")
5960
procSQLRowCount = mododbc32.NewProc("SQLRowCount")
@@ -151,6 +152,12 @@ func SQLNumParams(statementHandle SQLHSTMT, parameterCountPtr *SQLSMALLINT) (ret
151152
return
152153
}
153154

155+
func SQLMoreResults(statementHandle SQLHSTMT) (ret SQLRETURN) {
156+
r0, _, _ := syscall.Syscall(procSQLMoreResults.Addr(), 1, uintptr(statementHandle), 0, 0)
157+
ret = SQLRETURN(r0)
158+
return
159+
}
160+
154161
func SQLNumResultCols(statementHandle SQLHSTMT, columnCountPtr *SQLSMALLINT) (ret SQLRETURN) {
155162
r0, _, _ := syscall.Syscall(procSQLNumResultCols.Addr(), 2, uintptr(statementHandle), uintptr(unsafe.Pointer(columnCountPtr)), 0)
156163
ret = SQLRETURN(r0)

mssql_test.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,3 +1733,146 @@ func TestMSSQLMarkBeginBadConn(t *testing.T) {
17331733
testFn(next.label, next.fn)
17341734
}
17351735
}
1736+
1737+
func testMSSQLNextResultSet(t *testing.T, verifyBatch func(rows *sql.Rows)) {
1738+
db, sc, err := mssqlConnect()
1739+
if err != nil {
1740+
t.Fatal(err)
1741+
}
1742+
defer closeDB(t, db, sc, sc)
1743+
1744+
db.Exec("drop table dbo.temp")
1745+
exec(t, db, `create table dbo.temp (name varchar(50))`)
1746+
exec(t, db, `insert into dbo.temp (name) values ('russ')`)
1747+
exec(t, db, `insert into dbo.temp (name) values ('brad')`)
1748+
1749+
rows, err := db.Query(`
1750+
select name from dbo.temp where name = 'russ';
1751+
select name from dbo.temp where name = 'brad';
1752+
`)
1753+
if err != nil {
1754+
t.Fatal(err)
1755+
}
1756+
defer rows.Close()
1757+
1758+
verifyBatch(rows)
1759+
1760+
exec(t, db, "drop table dbo.temp")
1761+
}
1762+
1763+
func TestMSSQLNextResultSet(t *testing.T) {
1764+
checkName := func(rows *sql.Rows, name string) {
1765+
if !rows.Next() {
1766+
if err := rows.Err(); err != nil {
1767+
t.Fatalf("executing Next for %q failed: %v", name, err)
1768+
}
1769+
t.Fatalf("checking %q: at least one row expected", name)
1770+
}
1771+
var have string
1772+
err := rows.Scan(&have)
1773+
if err != nil {
1774+
t.Fatalf("executing Scan for %q failed: %v", name, err)
1775+
}
1776+
if name != have {
1777+
t.Fatalf("want %q, but %q found", name, have)
1778+
}
1779+
}
1780+
testMSSQLNextResultSet(t,
1781+
func(rows *sql.Rows) {
1782+
checkName(rows, "russ")
1783+
if !rows.NextResultSet() {
1784+
if err := rows.Err(); err != nil {
1785+
t.Fatal(err)
1786+
}
1787+
t.Fatal("more result sets expected")
1788+
}
1789+
checkName(rows, "brad")
1790+
if rows.NextResultSet() {
1791+
if !isFreeTDS() { // not sure why it does not work on FreeTDS
1792+
t.Fatal("unexpected result set found")
1793+
}
1794+
} else {
1795+
if err := rows.Err(); err != nil {
1796+
t.Fatal(err)
1797+
}
1798+
}
1799+
})
1800+
}
1801+
1802+
func TestMSSQLHasNextResultSet(t *testing.T) {
1803+
checkName := func(rows *sql.Rows, name string) {
1804+
var reccount int
1805+
for rows.Next() { // reading till the end of data set to trigger call into HasNextResultSet
1806+
var have string
1807+
err := rows.Scan(&have)
1808+
if err != nil {
1809+
t.Fatalf("executing Scan for %q failed: %v", name, err)
1810+
}
1811+
if name != have {
1812+
t.Fatalf("want %q, but %q found", name, have)
1813+
}
1814+
reccount++
1815+
}
1816+
if err := rows.Err(); err != nil {
1817+
t.Fatalf("executing Next for %q failed: %v", name, err)
1818+
}
1819+
if reccount != 1 {
1820+
t.Fatalf("checking %q: expected 1 row returned, but %v found", name, reccount)
1821+
}
1822+
}
1823+
testMSSQLNextResultSet(t,
1824+
func(rows *sql.Rows) {
1825+
checkName(rows, "russ")
1826+
if !rows.NextResultSet() {
1827+
if err := rows.Err(); err != nil {
1828+
t.Fatal(err)
1829+
}
1830+
t.Fatal("more result sets expected")
1831+
}
1832+
checkName(rows, "brad")
1833+
if rows.NextResultSet() {
1834+
t.Fatal("unexpected result set found")
1835+
} else {
1836+
if err := rows.Err(); err != nil {
1837+
t.Fatal(err)
1838+
}
1839+
}
1840+
})
1841+
}
1842+
1843+
func TestMSSQLIssue127(t *testing.T) {
1844+
db, sc, err := mssqlConnect()
1845+
if err != nil {
1846+
t.Fatal(err)
1847+
}
1848+
defer closeDB(t, db, sc, sc)
1849+
1850+
db.Exec("drop table dbo.temp")
1851+
exec(t, db, "create table dbo.temp (id int, a varchar(255))")
1852+
1853+
tx, err := db.Begin()
1854+
if err != nil {
1855+
t.Fatal(err)
1856+
}
1857+
1858+
stmt, err := tx.Prepare(`
1859+
DECLARE @id INT, @a VARCHAR(255)
1860+
SELECT @id = ?, @a = ?
1861+
UPDATE dbo.temp SET a = @a WHERE id = @id
1862+
IF @@ROWCOUNT = 0
1863+
INSERT INTO dbo.temp (id, a) VALUES (@id, @a)
1864+
`)
1865+
if err != nil {
1866+
t.Fatal(err)
1867+
}
1868+
if _, err = stmt.Exec(1, "test"); err != nil {
1869+
t.Errorf("Failed to insert record with ID 1: %s", err)
1870+
}
1871+
if _, err = stmt.Exec(1, "test2"); err != nil {
1872+
t.Errorf("Failed to update record with ID 1: %s", err)
1873+
}
1874+
1875+
if err = tx.Commit(); err != nil {
1876+
t.Fatal(err)
1877+
}
1878+
}

rows.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,23 @@ func (r *Rows) Next(dest []driver.Value) error {
4444
func (r *Rows) Close() error {
4545
return r.os.closeByRows()
4646
}
47+
48+
func (r *Rows) HasNextResultSet() bool {
49+
return true
50+
}
51+
52+
func (r *Rows) NextResultSet() error {
53+
ret := api.SQLMoreResults(r.os.h)
54+
if ret == api.SQL_NO_DATA {
55+
return io.EOF
56+
}
57+
if IsError(ret) {
58+
return NewError("SQLMoreResults", r.os.h)
59+
}
60+
// TODO: !!!!!!!!!!!!!!! maybe need to call r.os.BindColumns here !!!!!
61+
//err := r.os.BindColumns()
62+
//if err != nil {
63+
// return err
64+
//}
65+
return nil
66+
}

0 commit comments

Comments
 (0)